1 /** 
  2  * @constructor Ajax implentation of a request processor - still very basic : more to flesh here
  3  * @private
  4  * Used by RequestProcessor
  5  */
  6 if (typeof(MyOpenSpace.Ajax) == "undefined") MyOpenSpace.Ajax = {};
  7 
  8 /**
  9  * Ajax is the XMLHTTP implementation for fetching REST data.
 10  * HTTP stack has a limit of 2 XHR requests at a time, so we will be operating serially - one for API, one for content
 11  * Leveraged by RequestProcessor
 12  * @class
 13  * @name MyOpenSpace.Ajax
 14  * @private
 15  */
 16 MyOpenSpace.Ajax = {
 17     /**
 18     * getConnection will return a valid XMLHttpRequest object, determined by browser capabilities.
 19     * @function
 20     * @return {XMLHttpRequest} A valid XMLHttpRequest object as supported by client's browser OR false if no XmlHttpRequest objects were created.
 21     * @private
 22     */
 23     getConnection: function() {
 24         return Try.these(
 25                   function() { return new XMLHttpRequest() },
 26                   function() { return new ActiveXObject("MSXML2.XMLHTTP.3.0") },
 27                   function() { return new ActiveXObject("Msxml2.XMLHTTP") },
 28                   function() { return new ActiveXObject("Microsoft.XMLHTTP") }
 29                   ) || false;
 30     },
 31 
 32     /**
 33     * connection is the internal connection object for content requests. 
 34     * not instantiated until getConnection is invoked.
 35     * @private
 36     */
 37     contentConnection: [],
 38     /**
 39     * activeContentConnections stops duplicate url/params/method calls to allow polling mechanisms to only occupy one connection
 40     * @type Number
 41     * @private
 42     */
 43     activeContentConnections: [],
 44     /**
 45     * openConnections holds the current number of connections in use by the Ajax class.
 46     * @type Number
 47     * @private
 48     */
 49     openConnections: 0,
 50     /**
 51     * openConnections holds the current number of connections in use by the Ajax class.
 52     * @type Number
 53     * @private
 54     */
 55     openContentConnections: 0,
 56     /**
 57     * connection is the internal connection object. 
 58     * not instantiated until getConnection is invoked.
 59     * @private
 60     */
 61     connection: [],
 62 
 63     /**
 64     * async determines if the Ajax request will be asynchronous or not.
 65     * @type Boolean
 66     * @private
 67     */
 68     async: true,
 69     Completed: [],
 70     Errored: [],
 71     content_Completed: [],
 72     content_Errored: [],
 73 
 74     /**
 75     * sendRequest will dispatch a request using XmlHttpRequest and execute the completion or error callback upon return.
 76     * @param {opensocial.DataRequest} dataRequest The DataRequest associated with this call.
 77     * @param {String} key The unique key name to associate the DataRequest and DataResponse.
 78     * @param {function} onComplete The function to execute when the call completes.
 79     * @param {function} onError The function to execute when the call results in an error
 80     * @param {Boolean} async Sets the mode for XmlHttpRequest; true = asyncronous / false = syncronous
 81     * @private
 82     */
 83     sendRequest: function(dataRequest, type, onComplete, onError, async, opt_key) {
 84         var key = opt_key ? opt_key : type;
 85 
 86         this.Completed[key] = onComplete;
 87         this.Errored[key] = onError;
 88         if (async == null) async = true;
 89         var ptr = this;
 90         this.connection[key] = this.getConnection();
 91 
 92         try {
 93             this.connection[key].open(dataRequest.method, dataRequest.endPoint, async);
 94             this.connection[key].setRequestHeader("X-OpenSocial-Authorization", "OPENSOCIAL opensocial_token=\"" + dataRequest.osToken_ + "\"");
 95             this.connection[key].setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 96             this.connection[key].setRequestHeader("Content-length", dataRequest.params.length);
 97             this.connection[key].setRequestHeader("Connection", "close");
 98             this.connection[key].onreadystatechange = function() { ptr.readyStateChanged(type, key, opt_key) };
 99 
100             this.connection[key].send(dataRequest.params);
101 
102         }
103         catch (err) {
104             // Permission denied, not implemented, etc
105             this.Errored[key]({ "errorCode": opensocial.ResponseItem.Error.INTERNAL_ERROR, "errorMessage": err }, opt_key); //TODO: or is this BAD_REQUEST?
106         }
107     },
108 
109     /**
110     * sendContentRequest will dispatch a request to a third party server using XmlHttpRequest and execute the completion or error callback upon return.
111     * @param {String} url The URL to retrieve content from
112     * @param {Function} callback The function to call with the data from the URL once it is fetched
113     * @param {Map.<String, Object>} params Additional parameters to pass to the request
114     *
115     * @private
116     */
117     sendContentRequest: function(url, onComplete, onError, params) {
118         var block = false;
119 
120         for (var i = 0; i < this.activeContentConnections.length; i++) {
121             if (this.activeContentConnections[i].url === url) {
122                 if (this.activeContentConnections[i].params.authType !== params.authType) break;
123                 if (this.activeContentConnections[i].params.contentType !== params.contentType) break;
124                 if (this.activeContentConnections[i].params.method !== params.method) break;
125                 if (this.activeContentConnections[i].params.postData !== params.postData) break;
126                 if (this.activeContentConnections[i].params.postDataLength !== params.postDataLength) break;
127                 if (this.activeContentConnections[i].params.headers !== params.headers) break;
128                 if (this.activeContentConnections[i].params.numEntries !== params.numEntries) break;
129                 if (this.activeContentConnections[i].params.summariesOnly !== params.summariesOnly) break;
130 
131                 block = true;
132             }
133         }
134         if (!!block) return;
135 
136         var keyDate = new Date();
137         var contentConnectionID = keyDate.getTime();
138 
139         if (url.indexOf("?") > 0) {
140             url += "&ts=" + contentConnectionID;
141         }
142         else {
143             url = "?ts=" + contentConnectionID;
144         }
145 
146         this.activeContentConnections.push({ url: url, params: params });
147 
148         while (this.contentConnection[contentConnectionID] != null) { contentConnectionID = contentConnectionID + "_"; }
149         this.contentConnection[contentConnectionID] = this.getConnection();
150 
151         this.content_Completed[contentConnectionID] = onComplete;
152         this.content_Errored[contentConnectionID] = onError;
153         var ptr = this;
154         try {
155             this.contentConnection[contentConnectionID].open(params.method, url, true);
156 
157             if (params.headers != null) {
158                 for (var i in params.headers) {
159                     this.contentConnection[contentConnectionID].setRequestHeader(i, params.headers[i]);
160                 }
161             }
162 
163             this.contentConnection[contentConnectionID].setRequestHeader("Content-type", "application/x-www-form-urlencoded");
164             this.contentConnection[contentConnectionID].setRequestHeader("Content-Length", params.postDataLength);
165             this.contentConnection[contentConnectionID].setRequestHeader("Connection", "close");
166             this.contentConnection[contentConnectionID].onreadystatechange = function() { ptr.content_readyStateChanged(url, params, contentConnectionID) };
167             this.contentConnection[contentConnectionID].send(params.postData);
168         }
169         catch (err) {
170             this.contentConnection[contentConnectionID] = null;
171             delete this.contentConnection[contentConnectionID];
172             // Permission denied, not implemented, etc
173             this.content_Errored({ "errorCode": opensocial.ResponseItem.Error.INTERNAL_ERROR, "errorMessage": err }); //TODO: or is this BAD_REQUEST?
174         }
175     },
176 
177     /**
178     * content_readyStateChanged is the event handler for when the XmlHttpRequest's state changes when requesting outside the container API endpoints.
179     * @param {String} url The url associated with the content 
180     * @private
181     */
182     content_readyStateChanged: function(url, params, contentConnectionID) {
183         if (this.contentConnection[contentConnectionID].readyState === 4) {
184             var status, statusText;
185             try {
186                 statusText = this.contentConnection[contentConnectionID].statusText;
187                 status = this.contentConnection[contentConnectionID].status;
188             }
189             catch (err) {
190                 statusText = "An error occurred.";
191                 status = 500;
192             }
193             if (status === 200) {
194                 for (var i = 0; i < this.activeContentConnections.length; i++) {
195                     if (this.activeContentConnections[i].url === url) {
196                         if (this.activeContentConnections[i].params.authType !== params.authType) break;
197                         if (this.activeContentConnections[i].params.contentType !== params.contentType) break;
198                         if (this.activeContentConnections[i].params.method !== params.method) break;
199                         if (this.activeContentConnections[i].params.postData !== params.postData) break;
200                         if (this.activeContentConnections[i].params.postDataLength !== params.postDataLength) break;
201                         if (this.activeContentConnections[i].params.headers !== params.headers) break;
202                         if (this.activeContentConnections[i].params.numEntries !== params.numEntries) break;
203                         if (this.activeContentConnections[i].params.summariesOnly !== params.summariesOnly) break;
204 
205                         this.activeContentConnections.splice(i, 1);
206                     }
207                 }
208 
209                 var response = {};
210                 response.responseXML = this.contentConnection[contentConnectionID].responseXML;
211                 response.responseText = this.contentConnection[contentConnectionID].responseText;
212                 response.readyState = this.contentConnection[contentConnectionID].readyState;
213                 response.status = status;
214                 response.connectionID = contentConnectionID;
215                 this.contentConnection[contentConnectionID] = null;
216                 delete this.contentConnection[contentConnectionID];
217                 this.content_Completed[contentConnectionID](response, url, params);
218             }
219             else {
220                 var error = this.getResponseError_(status, statusText);
221                 this.contentConnection[contentConnectionID] = null;
222                 delete this.contentConnection[contentConnectionID];
223                 this.content_Errored[contentConnectionID](error);
224             }
225         }
226     },
227     /**
228     * getResponseError_ Create an error object mapping the status code to the matching
229     * ResponseItem.Error value.
230     * @param {integer} statusCode response status code
231     * @param {String} statusDescription response status description
232     * @private
233     */
234     getResponseError_: function(statusCode, statusDescription) {
235         var errorCode;
236         if ("undefined" !== typeof (opensocial)) {
237             switch (statusCode) {
238                 case 400:
239                     errorCode = opensocial.ResponseItem.Error.BAD_REQUEST;
240                     break;
241                 case 403:
242                     errorCode = opensocial.ResponseItem.Error.FORBIDDEN;
243                     break;
244                 case 501:
245                     errorCode = opensocial.ResponseItem.Error.NOT_IMPLEMENTED;
246                     break;
247                 case 401:
248                     errorCode = opensocial.ResponseItem.Error.UNAUTHORIZED;
249                     break;
250                 default:
251                     errorCode = opensocial.ResponseItem.Error.INTERNAL_ERROR;
252                     break;
253             }
254         }
255         else {
256             errorCode = "Document is probably unloading.";
257         }
258         var error = { "errorCode": errorCode, "errorMessage": statusDescription };
259         return error;
260     },
261     /**
262     * readyStateChanged is the event handler for when the XmlHttpRequest's state changes.
263     * @param {String} key The unique key name to associate the DataRequest and DataResponse.
264     * @private
265     */
266     readyStateChanged: function(type, key, opt_key) {
267         if (this.connection[key].readyState === 4) {
268             var status, statusText;
269             try {
270                 statusText = this.connection[key].statusText;
271                 status = this.connection[key].status;
272             }
273             catch (err) {
274                 statusText = "An error occurred.";
275                 status = 500;
276             }
277             if (200 === status || 201 === status) {
278                 var response = {};
279                 response.responseXML = this.connection[key].responseXML;
280                 response.responseText = this.connection[key].responseText;
281 
282                 this.connection[key] = null;
283                 delete this.connection[key];
284                 this.Completed[key](response, type, opt_key);
285             }
286             else {
287                 var error = this.getResponseError_(status, statusText);
288                 this.Errored[key](error, opt_key);
289             }
290         }
291     }
292 };/* ================================================================
293  * MyOpenSpace.Album
294  * ================================================================
295  */
296  
297  /**
298  * A class representing an album.
299  * @constructor
300  * @private
301  * @name MyOpenSpace.Album
302  */
303 MyOpenSpace.Album = function() {};
304 /**
305  * The fields for MyOpenSpace.Album
306  * @class
307  * @name MyOpenSpace.Album.Field
308  * @static
309  */
310 MyOpenSpace.Album.Field = {
311     /**
312      * A number representing an Album's unique identifier.
313      * @memberOf MyOpenSpace.Album.Field
314      */
315     ALBUM_ID:"ALBUM_ID",
316     
317     /**
318      * The RESTFUL URI with which to access the album on the API.
319      * @memberOf MyOpenSpace.Album.Field
320      */
321     ALBUM_URI:"ALBUM_URI",
322     
323     /**
324      * The album's title.
325      * @memberOf MyOpenSpace.Album.Field
326      */
327     TITLE:"TITLE",
328     
329     /**
330      * The geographic location where the album's pictures were taken.
331      * @memberOf MyOpenSpace.Album.Field
332      */
333     LOCATION:"LOCATION",
334     
335     /**
336      * A URL for the album's default image.
337      * @memberOf MyOpenSpace.Album.Field
338      */
339     DEFAULT_IMAGE:"DEFAULT_IMAGE",
340     
341     /**
342      * A string representing the album's privacy setting, such as "Public" or "Private"
343      * @memberOf MyOpenSpace.Album.Field
344      */
345     PRIVACY:"PRIVACY",
346     
347     /**
348      * An integer representing the total number of photos in the album (not the number of photos actually contained within the current object).
349      * @memberOf MyOpenSpace.Album.Field
350      */
351     PHOTO_COUNT:"PHOTO_COUNT",
352     
353     /**
354      * A RESTFUL URI with which to access the photos contained in the album.
355      * @memberOf MyOpenSpace.Album.Field
356      */
357     PHOTOS_URI:"PHOTOS_URI"
358 };
359 
360 /**
361  * Returns the field specified by key
362  * @param {String} key The key to search by
363  * @return {MyOpenSpace.Album || undefined} The album if found, nothing otherwise.
364  */
365 MyOpenSpace.Album.prototype.getField = function(key) { return this[key]; };
366 /**
367  * Writes a value to the field specified by the key
368  * @param {String} key The key to search by.
369  * @param {String} val The value to set.
370  * @private
371  * @private
372  */
373 MyOpenSpace.Album.prototype.setField_ = function(key,val) { this[key] = val; };/* ================================================================
374  * MyOpenSpace.Application
375  * ================================================================
376  */
377 
378  /**
379  * A class representing an Application.
380  * @constructor
381  * @name MyOpenSpace.Application
382  * @private
383  */
384 MyOpenSpace.Application = function(opt_params){
385 	this.fields_ = opt_params || {};
386 };
387 /**
388  * @static
389  * @class
390  * All of the fields that a Application has. These are the supported keys for the
391  * <a href="MyOpenSpace.Application.html#getField">Application.getField()</a> method.
392  *
393  * @name MyOpenSpace.Application.Field
394  */
395 MyOpenSpace.Application.Field = {
396   /**
397    * A string ID that can be permanently associated with this Application.
398    * @member MyOpenSpace.Application.Field
399    */
400   ID : 'ID',
401 
402   /**
403    * A opensocial.Name object containing the Application's name.
404    * @member MyOpenSpace.Application.Field
405    */
406   NAME : 'NAME',
407 
408   /**
409    * Application's small icon URL, as a string.
410    * This URL must be fully qualified. Relative URLs will not work in gadgets.
411    * @member MyOpenSpace.Application.Field
412    */
413   ICON_SMALL : 'ICON_SMALL',
414 
415   /**
416    * Application's large icon URL, as a string.
417    * This URL must be fully qualified. Relative URLs will not work in gadgets.
418    * @member MyOpenSpace.Application.Field
419    */
420   ICON_LARGE : 'ICON_LARGE',
421 
422   /**
423    * Application's profile URL, specified as a String.
424    * This URL must be fully qualified. Relative URLs will not work in gadgets.
425    * Not supported by all containers.
426    * @member MyOpenSpace.Application.Field
427    */
428   PROFILE_URL : 'PROFILE_URL',
429 
430   /**
431    * Application's installation URL, specified as a String.
432    * This URL must be fully qualified. Relative URLs will not work in gadgets.
433    * Not supported by all containers.
434    * @member MyOpenSpace.Application.Field
435    */
436   INSTALL_URL : 'INSTALL_URL',
437 
438   /**
439    * URLs related to the Application, their webpages, or feeds. Specified as an
440    * Array of opensocial.Url.
441    * Not supported by all containers.
442    *
443    * @member MyOpenSpace.Application.Field
444    */
445   URLS : 'URLS',
446 
447   /**
448   * Url of the canvas page
449   *
450   * @member MyOpenSpace.Application.Field
451   */
452   
453   CANVAS_URL : 'CANVAS_URL',
454   
455   /**
456    * Arbitrary tags about the application, specified as an Array of Strings.
457    * Not supported by all containers.
458    *
459    * @member MyOpenSpace.Application.Field
460    */
461   TAGS : 'TAGS'
462 
463 };
464 
465 
466 /**
467  * Gets the activity data that's associated with the specified key.
468  *
469  * @param {String} key The key to get data for;
470  *   see the <a href="MyOpenSpace.Application.Field.html">Field</a> class
471  * for possible values
472  * @return {String} The data
473  * @member MyOpenSpace.Application
474  */
475 MyOpenSpace.Application.prototype.getField = function(key) {
476   return this.fields_[key];
477 };
478 
479 
480 /**
481  * Sets data for this activity associated with the given key.
482  *
483  * @param {String} key The key to set data for
484  * @param {String} data The data to set
485  */
486 MyOpenSpace.Application.prototype.setField = function(key, data) {
487   return this.fields_[key] = data;
488 };
489 
490 
491 /**
492  * Gets an ID that can be permanently associated with this application.
493  *
494  * @return {String} The ID
495  * @member MyOpenSpace.Application
496  */
497 MyOpenSpace.Application.prototype.getId = function() {
498   return this.getField(MyOpenSpace.Application.Field.ID);
499 };
500 
501 /**
502  * Gets the display name for this application
503  *
504  * @return {String} The Display Name
505  * @member MyOpenSpace.Application
506  */
507 MyOpenSpace.Application.prototype.getDisplayName = function() {
508   return this.getField(MyOpenSpace.Application.Field.NAME);
509 };/**
510  * Copyright 2007 Fox Interactive Media
511  * <DISCLAIMER HERE>
512  * @fileoverview Interface for container and associated classes; everything needed to query/update MySpace API data via OpenSocial interface.
513  * 
514  * @author mnewbould [_at_] myspace [_dot_] com (Max Newbould)
515  * @author crussell [_at_] myspace [_dot_] com (Chad Russell)
516  * @author jreyes [_at_] myspace [_dot_] com (Jorge Reyes)
517  * @author jmay [_at_] myspace [_dot_] com (Justin May)
518  */
519  
520 if (typeof(MyOpenSpace) == "undefined") 
521 /**
522  * Namespace for top level MyOpenSpace functions.
523  * @constructor (note: a constructor for JsDoc purposes)
524  */
525 	MyOpenSpace = { Version: "0.8" };
526 /**
527  * @private
528  */
529 MyOpenSpace.PrefetchParameters = { params_: {} };
530 /**
531  * 
532  * @param {Object} key
533  * @param {Object} value
534  * @private
535  */
536 MyOpenSpace.PrefetchParameters.registerParam = function(key, value) {
537     this.params_[key] = value;
538     //gadgets.views.getParams()[key] = value;
539 };
540 /**
541  * @private
542  */
543 MyOpenSpace.PrefetchParameters.syncParams = function() {
544     for (var key in this.params_) {
545         if (typeof(gadgets.views.getParams()[key]) === "undefined") gadgets.views.getParams()[key] = this.params_[key];  
546     }
547 };
548 /**
549  * 
550  * @param {Object} key
551  * @private
552  */
553 MyOpenSpace.PrefetchParameters.getParam = function(key) {
554     if (typeof (gadgets.views.getParams()[key]) !== "undefined") {
555         return gadgets.views.getParams()[key];
556     } else {
557         return this.params_[key];
558     }
559 };
560 
561 /**
562  * Defines the default page size for paginated requests.
563  * Used as max/default for MAX of pagination.
564  * @static
565  * @constant
566  */
567 MyOpenSpace.DefaultPageSize = 20;
568 
569 /**
570  * Defines the type of idSpec mapping value
571  * @static
572  * @class
573  * @name MyOpenSpace.IdSpecMapping_
574  * @constructor (note: a constructor for JsDoc purposes)
575  * @private
576  */
577 MyOpenSpace.IdSpecMapping_ = {
578     /**
579      * The idSpec mapping for viewer friends.
580      * @memberOf MyOpenSpace.IdSpecMapping_
581      * @constant
582      * @private
583      */
584     VIEWER_FRIENDS:"VIEWER_FRIENDS",
585     
586     /**
587      * The idSpec mapping for owner friends.
588      * @memberOf MyOpenSpace.IdSpecMapping_
589      * @constant
590      * @private
591      */
592     OWNER_FRIENDS:"OWNER_FRIENDS",
593 	/**
594      * The idSpec mapping for viewer.
595      * @memberOf MyOpenSpace.IdSpecMapping_
596      * @constant
597      * @private
598      */
599 	VIEWER : "VIEWER",
600 	/**
601      * The idSpec mapping for owner.
602      * @memberOf MyOpenSpace.IdSpecMapping_
603      * @constant
604      * @private
605      */	
606 	OWNER : "OWNER"
607 };
608 
609 /**
610  * <p>Enumerates the types of requests that can be made.</p>
611  * <p>It is used to retreive ResponseItems if opt_key was not 
612  * set when adding the request.</p>
613  * <p> 
614  * If more that one request of the same type is made, the first item can be retrieve 
615  * directly using the enumeration value, the rest will have a "_#" postfix added 
616  * to the enumeration value where # will be a sequential number starting with 1.</p>
617  * @static
618  * @class
619  * @name MyOpenSpace.RequestType
620  * @example
621  * var container = opensocial.Container.get();
622  * var request = this.container.newDataRequest();
623  * var fetchViewer = request.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER);
624  * var fetchOwner = request.newFetchPersonRequest(opensocial.IdSpec.PersonId.OWNER);
625  * request.add(fetchViewer); // opt_key not set
626  * request.add(fetchOwner); // opt_key not set
627  * request.send(callback);
628  * function callback(response){
629  *      var viewer = response.get(MyOpenSpace.RequestType.FETCH_PERSON);
630  *      var owner = response.get(MyOpenSpace.RequestType.FETCH_PERSON + “_1”);
631  * }
632  */
633 MyOpenSpace.RequestType = {
634     /**
635      * Default key to retreive the opensocial.ResponseItem from an
636      * opensocial.newFetchPerson.
637      * @memberOf MyOpenSpace.RequestType
638      * @constant
639      */
640     FETCH_PERSON:"FETCH_PERSON",
641     /**
642      * Default key to retreive the opensocial.ResponseItem from an
643      * opensocial.DataRequest.newFetchPeople.
644      * @memberOf MyOpenSpace.RequestType
645      * @constant
646      */
647 	FETCH_PEOPLE:"FETCH_PEOPLE",
648 	/**
649 	 * Default key to retreive the opensocial.ResponseItem from an
650      * opensocial.DataRequest.newFetchPersonAppDataRequest.
651      * @memberOf MyOpenSpace.RequestType
652      * @constant
653      */
654 	FETCH_PERSON_DATA:"FETCH_PERSON_DATA",
655 	/**
656      * Default key to retreive the opensocial.ResponseItem from an
657      * opensocial.DataRequest.newFetchPersonAppDataRequest.
658      * @memberOf MyOpenSpace.RequestType
659      * @constant
660      */
661 	UPDATE_PERSON_DATA:"UPDATE_PERSON_DATA",
662 	/**
663      * Default key to retreive the opensocial.ResponseItem from an
664      * opensocial.DataRequest.newRemovePersonAppDataRequest.
665      * @memberOf MyOpenSpace.RequestType
666      * @constant
667      */
668 	REMOVE_PERSON_DATA:"REMOVE_PERSON_DATA",
669 	/**
670      * Default key to retreive the opensocial.ResponseItem from an
671      * opensocial.DataRequest.newFetchActivitiesRequest.
672      * @memberOf MyOpenSpace.RequestType
673      * @constant
674      */
675 	FETCH_ACTIVITIES:"FETCH_ACTIVITIES",
676 	/**
677      * Default key to retreive the opensocial.ResponseItem from an
678      * MyOpenSpace.DataRequest.newFetchAlbumsRequest.
679      * @memberOf MyOpenSpace.RequestType
680      * @constant
681      */
682     FETCH_ALBUMS:"FETCH_ALBUMS",
683     /**
684      * Default key to retreive the opensocial.ResponseItem from an
685      * MyOpenSpace.DataRequest.newFetchAlbumRequest.
686      * @memberOf MyOpenSpace.RequestType
687      * @constant
688      */
689     FETCH_ALBUM:"FETCH_ALBUM",
690     /**
691      * Default key to retreive the opensocial.ResponseItem from an
692      * MyOpenSpace.DataRequest.newFetchVideosRequest.
693      * @memberOf MyOpenSpace.RequestType
694      * @constant
695      */
696     FETCH_VIDEOS:"FETCH_VIDEOS",
697     /**
698      * Default key to retreive the opensocial.ResponseItem from an
699      * MyOpenSpace.DataRequest.newFetchVideoRequest.
700      * @memberOf MyOpenSpace.RequestType
701      * @constant
702      */
703     FETCH_VIDEO:"FETCH_VIDEO",
704     /**
705      * Default key to retreive the opensocial.ResponseItem from an
706      * MyOpenSpace.DataRequest.newFetchPhotosRequest.
707      * @memberOf MyOpenSpace.RequestType
708      * @constant
709      */
710     FETCH_PHOTOS:"FETCH_PHOTOS",
711     /**
712      * Default key to retreive the opensocial.ResponseItem from an
713      * MyOpenSpace.DataRequest.newFetchPhotoRequest.
714      * @memberOf MyOpenSpace.RequestType
715      * @constant
716      */
717     FETCH_PHOTO:"FETCH_PHOTO",
718     /**
719      * Default key to retreive the opensocial.ResponseItem from an
720      * MyOpenSpace.DataRequest.newFetchIndicatorsRequest.
721      * @memberOf MyOpenSpace.RequestType
722      * @constant
723      */
724     FETCH_INDICATORS:"FETCH_INDICATORS",
725     
726     /**
727      * Default key to retreive the opensocial.ResponseItem from an
728      * MyOpenSpace.DataRequest.newFetchPersonStatusRequest.
729      * @memberOf MyOpenSpace.RequestType
730      * @constant
731      */
732     FETCH_PERSON_STATUS:"FETCH_PERSON_STATUS",
733     
734     /**
735      * Default key to retreive the opensocial.ResponseItem from an
736      * MyOpenSpace.DataRequest.newFetchPersonMoodRequest.
737      * @memberOf MyOpenSpace.RequestType
738      * @constant
739      */
740     FETCH_PERSON_MOOD:"FETCH_PERSON_MOOD",
741     
742     /**
743      * Default key to retreive the opensocial.ResponseItem from an
744      * MyOpenSpace.DataRequest.newPeopleFriendshipRequest.
745      * @memberOf MyOpenSpace.RequestType
746      * @constant
747      */
748     FETCH_PEOPLE_FRIENDSHIP: "FETCH_PEOPLE_FRIENDSHIP",
749     
750     /**
751      * Default key to retreive the opensocial.ResponseItem from an
752      * MyOpenSpace.DataRequest.newPersonFriendshipRequest.
753      * @memberOf MyOpenSpace.RequestType
754      * @constant
755      */
756     FETCH_PERSON_FRIENDSHIP: "FETCH_PERSON_FRIENDSHIP"
757 };
758 if (typeof(MyOpenSpace.ClientLibraries) == "undefined") MyOpenSpace.ClientLibraries = function () {};
759  
760 /**
761  * Enum of client libraries supported for optional external include
762  */
763 MyOpenSpace.ClientLibraries.Scripts = {
764     PROTOTYPE: 			"prototype",
765     JQUERY: 			"jquery",
766 	MYSPACE_WIDGETS:	"myopensocial.widgets",
767 	SCRIPTACULOUS:		"scriptaculous",
768     SILVERLIGHT:		"silverlight",
769     MOOTOOLS: 			"mootools",
770     AIR:	 			"adobeair"
771 };
772  
773 /**
774  * Dynamically include optional client libraries
775  * @param {Object} script
776  */
777 MyOpenSpace.ClientLibraries.includeScript = function (scriptRef) {
778  	var srcPath = "/OpenSocial/";
779 	var extSource = srcPath + "JSExtensions/";
780 	
781 	var root;
782 	try{
783 	    root = document.getElementsByTagName('head').item(0);
784 		if(!root){
785 			root = document.getElementsByTagName("body")[0];
786 		}
787 	}
788 	catch(ex){	}
789 	
790 	if(!root){
791 		throw "Malformed markup - no head or body element found";
792 	}
793 	
794 	var src = null;
795 	var libs = MyOpenSpace.ClientLibraries.Scripts;
796 	
797 	switch(scriptRef){
798 		case libs.MYSPACE_WIDGETS:
799 			src = srcPath + "MyOpenSpace002.Widgets.js";
800 			break;
801 		case libs.PROTOTYPE:
802 			src = extSource + "prototype/prototype.js";
803 			break;
804 		case libs.JQUERY:
805 			src = extSource + "jquery/jquery-1.2.3.min.js";
806 			break;
807 		case libs.SCRIPTACULOUS:
808 			src = extSource + "scriptaculous/scriptaculous-full-1.8.1.js";
809 			break;
810 		case libs.SILVERLIGHT:
811 			src = extSource + "silverlight/Silverlight.js";
812 			break;
813 		case libs.MOOTOOLS:
814 			src = extSource + "mootools/mootools-release-1.11.js";
815 			break;
816 		case libs.AIR:
817 			src = extSource + "air/AIRAliases.js";
818 			break;
819 	}
820 	
821 	if(!src){
822 		throw "Source script not found in supported list";
823 	}
824 	
825     var scriptTag = document.createElement('script');
826     scriptTag.setAttribute('language', 'javascript');
827     scriptTag.setAttribute('type', 'text/javascript');
828     scriptTag.setAttribute('src', src); 
829     root.appendChild(scriptTag);
830  };/**
831  * Copyright 2007 Fox Interactive Media
832  * <DISCLAIMER HERE>
833  * @fileoverview Interface for container and associated classes; everything needed to query/update MySpace API data via OpenSocial interface.
834  * 
835  * @author mnewbould [_at_] myspace [_dot_] com (Max Newbould)
836  * @author crussell [_at_] myspace [_dot_] com (Chad Russell)
837  * @author jreyes [_at_] myspace [_dot_] com (Jorge Reyes)
838  */
839  
840 /**
841  * Maps JSON responses from the API into the various objects
842  * @class
843  * @constructor
844  * @name MyOpenSpace.DataMapper_
845  * @private
846  */
847 MyOpenSpace.DataMapper_ = function() {
848 	this.mapData[MyOpenSpace.RequestType.FETCH_PEOPLE_FRIENDSHIP] = this.mapPeopleFriendship_;
849     this.mapData[MyOpenSpace.RequestType.FETCH_PERSON_FRIENDSHIP] = this.mapPersonFriendship_;
850     this.mapData[MyOpenSpace.RequestType.FETCH_PERSON] = this.mapPerson_;
851     this.mapData[MyOpenSpace.RequestType.FETCH_INDICATORS] = this.mapIndicators_;
852     this.mapData[MyOpenSpace.RequestType.FETCH_PERSON_STATUS] = this.mapPersonStatus_;
853     this.mapData[MyOpenSpace.RequestType.FETCH_PERSON_MOOD] = this.mapPersonMood_;
854     this.mapData[MyOpenSpace.RequestType.FETCH_PEOPLE] = this.mapPeople_;
855     this.mapData[MyOpenSpace.RequestType.FETCH_ALBUMS] = this.mapAlbums_;
856     this.mapData[MyOpenSpace.RequestType.FETCH_ALBUM] = this.mapAlbum_;
857     this.mapData[MyOpenSpace.RequestType.FETCH_VIDEOS] = this.mapVideos_;
858     this.mapData[MyOpenSpace.RequestType.FETCH_VIDEO] = this.mapVideo_;
859     this.mapData[MyOpenSpace.RequestType.FETCH_PHOTOS] = this.mapPhotos_;
860     this.mapData[MyOpenSpace.RequestType.FETCH_PHOTO] = this.mapPhoto_;
861     this.mapData[MyOpenSpace.RequestType.FETCH_PERSON_DATA] = this.mapPersonAppData_;
862     this.mapData[MyOpenSpace.RequestType.FETCH_ACTIVITIES] = this.mapActivities_;
863 	this.mapData['mapSimplePersonData_'] = this.mapSimplePersonData_;
864 	this.mapData['mapPersonData_'] = this.mapPersonData_;
865 };
866 
867 
868 MyOpenSpace.DataMapper_.prototype = {
869 	/**
870 	 * Object that contains the mapping of MyOpenSpace.RequestType Enum element to the function that will
871 	 * map the server response data.
872 	 * @memberOf MyOpenSpace.DataMapper_
873 	 * @private
874 	 * @private
875 	 */
876     mapData: {},
877     /**
878     * Maps a server response into a opensocial.Collection of MyOpenSpace.Photo objects
879     * @function
880     * @return {opensocial.Collection}
881     * @param {XMLHttpRequest} obj The response from the server
882     * @memberOf MyOpenSpace.DataMapper_
883     * @private
884     */
885     mapPhotos_: function(obj) {
886         try {
887             var unmapped = gadgets.json.parse(obj.responseText);
888         }
889         catch (err) {
890             return null;
891         }
892         var photos = [];
893         var photo;
894         var ns = MyOpenSpace.Photo.Field;
895 
896         if (unmapped.photos) {
897             for (var i = 0; i < unmapped.photos.length; i++) {
898                 photo = new opensocial.Container.get().newPhoto();
899                 photo.setField_(ns.PHOTO_ID, unmapped.photos[i].id);
900                 photo.setField_(ns.PHOTO_URI, unmapped.photos[i].photoUri);
901                 photo.setField_(ns.IMAGE_URI, unmapped.photos[i].imageUri);
902                 photo.setField_(ns.CAPTION, unmapped.photos[i].caption);
903                 //photo.setField_(ns.COMMENTS_COUNT,unmapped.photos[i].commentsCount);
904                 photos.push(photo);
905             }
906         }
907 
908         return opensocial.Container.get().newCollection(photos, 0, unmapped.count);
909     },
910 
911     /**
912     * Maps a server response into a MyOpenSpace.Photo object
913     * @function
914     * @return {MyOpenSpace.Photo}
915     * @param {XMLHttpRequest} obj The response from the server
916     * @private
917     */
918     mapPhoto_: function(obj) {
919         try {
920             var unmapped = gadgets.json.parse(obj.responseText);
921         }
922         catch (err) {
923             return null;
924         }
925         var photo = new opensocial.Container.get().newPhoto();
926         var ns = MyOpenSpace.Photo.Field;
927 
928         if (unmapped) {
929             photo.setField_(ns.PHOTO_ID, unmapped.id);
930             photo.setField_(ns.PHOTO_URI, unmapped.photoUri);
931             photo.setField_(ns.IMAGE_URI, unmapped.imageUri);
932             photo.setField_(ns.CAPTION, unmapped.caption);
933             //photo.setField_(ns.COMMENTS_COUNT,unmapped.commentsCount);
934         }
935 
936         return photo;
937     },
938    /**
939     * Maps a server response into a valid JSON Object.
940     * @function
941     * @return {Object}
942     * @param {XMLHttpRequest} obj The response from the server
943     * @param {opensocial.EscapeType}encoding Enum value to determine if the results will be html escape or not
944     * @private
945     */
946     mapPersonAppData_: function(obj, encoding) {
947         var appDataXML = obj.responseXML;
948 
949         if (null === appDataXML || "undefined" === typeof (appDataXML)) return null;
950 
951         var userCount = appDataXML.childNodes.length;
952         var userNode = appDataXML.firstChild;
953         var userId;
954         var appDataNode;
955         var appDataCount = 0;
956         for (var i = 0; i < userNode.childNodes.length; i++) {
957             if ("userid" === userNode.childNodes[i].nodeName)
958                 userId = userNode.childNodes[i].firstChild.nodeValue;
959             if ("appdata" === userNode.childNodes[i].nodeName)
960                 appDataNode = userNode.childNodes[i];
961             if ("appdatafriends" === userNode.childNodes[i].nodeName)
962                 appDataNode = userNode.childNodes[i];
963         }
964         i = 0;
965         var personAppData = {};
966 
967         if ("appdatafriends" === appDataNode.nodeName) {
968             var friendId = 0;
969             var friendNode;
970             var friendAppDataNode;
971             for (var k = 0; k < appDataNode.childNodes.length; k++) {
972                 friendNode = appDataNode.childNodes[k];
973                 for (var m = 0; m < friendNode.childNodes.length; m++) {
974                     if ("friendid" === friendNode.childNodes[m].nodeName) {
975                         friendId = friendNode.childNodes[m].firstChild.nodeValue;
976                     }
977                     if ("appdata" === friendNode.childNodes[m].nodeName) {
978                         friendAppDataNode = friendNode.childNodes[m];
979                     }
980                 }
981                 personAppData[friendId] = {};
982                 appDataCount = friendAppDataNode.getAttribute("count");
983                 for (var j = 0; j < friendAppDataNode.childNodes.length; j++) {
984                     personAppData[friendId][friendAppDataNode.childNodes[j].getAttribute("name")] = friendAppDataNode.childNodes[j].getAttribute("value");
985                 }
986             }
987         } else {
988             personAppData[userId] = {};
989             appDataCount = appDataNode.getAttribute("count");
990             for (var i = 0; i < appDataNode.childNodes.length; i++) {
991                 if ("key" === appDataNode.childNodes[i].nodeName) {
992                     var dataKey = appDataNode.childNodes[i].getAttribute("name");
993                     var dataValue = gadgets.json.parse(appDataNode.childNodes[i].getAttribute("value"));
994                     if (encoding !== opensocial.EscapeType.NONE){
995                         dataValue = gadgets.util.escape(dataValue);
996                     }
997                     personAppData[userId][dataKey] = dataValue;
998                 }
999             }
1000         }
1001         return personAppData;
1002     },
1003     /**
1004     * Maps a server response into a opensocial.Collection of MyOpenSpace.Album objects
1005     * @function
1006     * @return {opensocial.Collection}
1007     * @param {XMLHttpRequest} obj The response from the server
1008     * @private
1009     */
1010     mapAlbums_: function(obj) {
1011         try {
1012             var unmapped = gadgets.json.parse(obj.responseText);
1013         }
1014         catch (err) {
1015             return null;
1016         }
1017         var albums = [];
1018         var album;
1019         var ns = MyOpenSpace.Album.Field;
1020 
1021         if (unmapped.albums) {
1022             for (var i = 0; i < unmapped.albums.length; i++) {
1023                 album = new opensocial.Container.get().newAlbum();
1024                 album.setField_(ns.ALBUM_ID, unmapped.albums[i].id);
1025                 album.setField_(ns.ALBUM_URI, unmapped.albums[i].albumUri);
1026                 album.setField_(ns.TITLE, unmapped.albums[i].title);
1027                 album.setField_(ns.LOCATION, unmapped.albums[i].location);
1028                 album.setField_(ns.DEFAULT_IMAGE, unmapped.albums[i].defaultImage);
1029                 album.setField_(ns.PRIVACY, unmapped.albums[i].privacy);
1030                 album.setField_(ns.PHOTO_COUNT, unmapped.albums[i].photoCount);
1031                 album.setField_(ns.PHOTOS_URI, unmapped.albums[i].photosUri);
1032                 albums.push(album);
1033             }
1034         }
1035 
1036         return opensocial.Container.get().newCollection(albums, 0, unmapped.count);
1037     },
1038 
1039     /**
1040     * Maps a server response into a MyOpenSpace.Indicator object
1041     * @function
1042     * @return {MyOpenSpace.Indicators}
1043     * @param {XMLHttpRequest} obj The response from the server
1044     * @private
1045     */
1046     mapIndicators_: function(obj) {
1047         try {
1048             var unmapped = gadgets.json.parse(obj.responseText);
1049         }
1050         catch (err) {
1051             return null;
1052         }
1053         var indicators = new opensocial.Container.get().newIndicators();
1054         var ns = MyOpenSpace.Indicators.Field;
1055 
1056         if (unmapped) {
1057             indicators.setField_(ns.MAIL, unmapped.mailurl ? true : false);
1058             indicators.setField_(ns.MAIL_URL, unmapped.mailurl);
1059 
1060             indicators.setField_(ns.BIRTHDAY, unmapped.birthdayurl ? true : false);
1061             indicators.setField_(ns.BIRTHDAY_URL, unmapped.birthdayurl);
1062 
1063             indicators.setField_(ns.BLOG_COMMENT, unmapped.blogcommenturl ? true : false);
1064             indicators.setField_(ns.BLOG_COMMENT_URL, unmapped.blogcommenturl);
1065 
1066             indicators.setField_(ns.BLOG_SUBSCRIPTION_POST, unmapped.blogsubscriptionposturl ? true : false);
1067             indicators.setField_(ns.BLOG_SUBSCRIPTION_POST_URL, unmapped.blogsubscriptionposturl);
1068 
1069             indicators.setField_(ns.COMMENT, unmapped.commenturl ? true : false);
1070             indicators.setField_(ns.COMMENT_URL, unmapped.commenturl);
1071 
1072             indicators.setField_(ns.EVENT_INVITATION, unmapped.eventinvitationurl ? true : false);
1073             indicators.setField_(ns.EVENT_INVITATION_URL, unmapped.eventinvitationurl);
1074 
1075             indicators.setField_(ns.FRIEND_REQUEST, unmapped.friendsrequesturl ? true : false);
1076             indicators.setField_(ns.FRIEND_REQUEST_URL, unmapped.friendsrequesturl);
1077 
1078             indicators.setField_(ns.GROUP_NOTIFICATION, unmapped.groupnotificationurl ? true : false);
1079             indicators.setField_(ns.GROUP_NOTIFICATION_URL, unmapped.groupnotificationurl);
1080 
1081             indicators.setField_(ns.PHOTO_TAG_APPROVAL, unmapped.phototagapprovalurl ? true : false);
1082             indicators.setField_(ns.PHOTO_TAG_APPROVAL_URL, unmapped.phototagapprovalurl);
1083 
1084             indicators.setField_(ns.PICTURE_COMMENT, unmapped.picturecommenturl ? true : false);
1085             indicators.setField_(ns.PICTURE_COMMENT_URL, unmapped.picturecommenturl);
1086 
1087             indicators.setField_(ns.RECENTLY_ADDED_FRIEND, unmapped.recentlyaddedfriendurl ? true : false);
1088             indicators.setField_(ns.RECENTLY_ADDED_FRIEND_URL, unmapped.recentlyaddedfriendurl);
1089 
1090             indicators.setField_(ns.VIDEO_COMMENT, unmapped.videocommenturl ? true : false);
1091             indicators.setField_(ns.VIDEO_COMMENT_URL, unmapped.videocommenturl);
1092 
1093             indicators.setField_(ns.VIDEO_PROCESS, unmapped.videoprocessurl ? true : false);
1094             indicators.setField_(ns.VIDEO_PROCESS_URL, unmapped.videoprocessurl);
1095 
1096         }
1097 
1098         return indicators;
1099     },
1100 
1101     /**
1102     * Maps a server response into a MyOpenSpace.PersonStatus object
1103     * @function
1104     * @return {MyOpenSpace.PersonStatus}
1105     * @param {XMLHttpRequest} obj The response from the server
1106     * @private
1107     */
1108     mapPersonStatus_: function(obj) {
1109         try {
1110             var unmapped = gadgets.json.parse(obj.responseText);
1111         }
1112         catch (err) {
1113             return null;
1114         }
1115         var personStatus = new opensocial.Container.get().newPersonStatus();
1116         var ns = MyOpenSpace.PersonStatus.Field;
1117 
1118         if (unmapped) {
1119             personStatus.setField_(ns.STATUS, unmapped.status);
1120         }
1121 
1122         return personStatus;
1123     },
1124 
1125     /**
1126     * Maps a server response into a MyOpenSpace.PersonMood object
1127     * @function
1128     * @return {MyOpenSpace.PersonMood}
1129     * @param {XMLHttpRequest} obj The response from the server
1130     * @private
1131     */
1132     mapPersonMood_: function(obj) {
1133         try {
1134             var unmapped = gadgets.json.parse(obj.responseText);
1135         }
1136         catch (err) {
1137             return null;
1138         }
1139         var personMood = new opensocial.Container.get().newPersonMood();
1140         var ns = MyOpenSpace.PersonMood.Field;
1141 
1142         if (unmapped) {
1143             personMood.setField_(ns.MOOD, unmapped.mood);
1144             personMood.setField_(ns.MOOD_IMAGE_URL, unmapped.moodImageUrl);
1145             personMood.setField_(ns.MOOD_LAST_UPDATED, unmapped.moodLastUpdated);
1146         }
1147 
1148         return personMood;
1149     },
1150 
1151     /**
1152     * Maps a server response into a MyOpenSpace.Album object
1153     * @function
1154     * @return {MyOpenSpace.Album}
1155     * @param {XMLHttpRequest} obj The response from the server
1156     * @private
1157     */
1158     mapAlbum_: function(obj) {
1159         try {
1160             var unmapped = gadgets.json.parse(obj.responseText);
1161         }
1162         catch (err) {
1163             return null;
1164         }
1165         var album = new opensocial.Container.get().newAlbum();
1166         var ns = MyOpenSpace.Album.Field;
1167 
1168         if (unmapped) {
1169             album.setField_(ns.ALBUM_ID, unmapped.id);
1170             album.setField_(ns.ALBUM_URI, unmapped.albumUri);
1171             album.setField_(ns.TITLE, unmapped.title);
1172             album.setField_(ns.LOCATION, unmapped.location);
1173             album.setField_(ns.DEFAULT_IMAGE, unmapped.defaultImage);
1174             album.setField_(ns.PRIVACY, unmapped.privacy);
1175             album.setField_(ns.PHOTO_COUNT, unmapped.photoCount);
1176             album.setField_(ns.PHOTOS_URI, unmapped.photosUri);
1177         }
1178 
1179         return album;
1180     },
1181 
1182     /**
1183     * Maps a server response into a opensocial.Collection of MyOpenSpace.Friendship objects
1184     * @function
1185     * @return {opensocial.Collection}
1186     * @param {XMLHttpRequest} obj The response from the server
1187     * @private
1188     */
1189     mapPersonFriendship_: function(obj) {
1190         var unmapped;
1191         try {
1192             unmapped = gadgets.json.parse(obj.responseText);
1193         }
1194         catch (err) {
1195             return null;
1196         }
1197         var friendship = new opensocial.Container.get().newFriendship();
1198         var ns = MyOpenSpace.Friendship.Field;
1199 
1200         if (unmapped.friendship) {
1201 
1202             friendship.setField_(ns.IS_FRIEND, unmapped.friendship[0].areFriends);
1203             friendship.setField_(ns.FRIEND_ID, unmapped.friendship[0].friendId);
1204 
1205         }
1206 
1207         return friendship;
1208     },
1209 
1210     /**
1211     * Maps a server response into a opensocial.Collection of MyOpenSpace.Friendship objects
1212     * @function
1213     * @return {opensocial.Collection}
1214     * @param {XMLHttpRequest} obj The response from the server
1215     * @private
1216     */
1217     mapPeopleFriendship_: function(obj) {
1218         try {
1219             var unmapped = gadgets.json.parse(obj.responseText);
1220         }
1221         catch (err) {
1222             return null;
1223         }
1224         var friendships = [];
1225         var ns = MyOpenSpace.Friendship.Field;
1226 
1227         if (unmapped.friendship) {
1228             for (var i = 0; i < unmapped.friendship.length; i++) {
1229                 var friendship = new opensocial.Container.get().newFriendship();
1230                 friendship.setField_(ns.IS_FRIEND, unmapped.friendship[i].areFriends);
1231                 friendship.setField_(ns.FRIEND_ID, unmapped.friendship[i].friendId);
1232                 friendships.push(friendship);
1233             }
1234         }
1235 
1236         return opensocial.Container.get().newCollection(friendships, 0, friendships.length);
1237     },
1238 
1239 
1240     /**
1241     * Maps a server response into a opensocial.Collection of MyOpenSpace.Video objects
1242     * @function
1243     * @return {opensocial.Collection}
1244     * @param {XMLHttpRequest} obj The response from the server
1245     * @private
1246     */
1247     mapVideos_: function(obj) {
1248         try {
1249             var unmapped = gadgets.json.parse(obj.responseText);
1250         }
1251         catch (err) {
1252             return null;
1253         }
1254         var videos = [];
1255         var video;
1256         var ns = MyOpenSpace.Video.Field;
1257 
1258         if (unmapped.videos) {
1259             for (var i = 0; i < unmapped.videos.length; i++) {
1260                 video = new opensocial.Container.get().newVideo();
1261                 video.setField_(ns.VIDEO_ID, unmapped.videos[i].id);
1262                 video.setField_(ns.VIDEO_URI, unmapped.videos[i].videoUri);
1263                 video.setField_(ns.TITLE, unmapped.videos[i].title);
1264                 video.setField_(ns.DATE_CREATED, unmapped.videos[i].datecreated);
1265                 video.setField_(ns.LAST_UPDATE, unmapped.videos[i].dateupdated);
1266                 video.setField_(ns.MEDIA_TYPE, unmapped.videos[i].mediatype);
1267                 video.setField_(ns.THUMB_URI, unmapped.videos[i].thumbnail);
1268                 video.setField_(ns.DESCRIPTION, unmapped.videos[i].description);
1269                 video.setField_(ns.MEDIA_STATUS, unmapped.videos[i].mediastatus);
1270                 video.setField_(ns.RUN_TIME, unmapped.videos[i].runtime);
1271                 video.setField_(ns.TOTAL_VIEWS, unmapped.videos[i].totalviews);
1272                 video.setField_(ns.TOTAL_COMMENTS, unmapped.videos[i].totalcomments);
1273                 video.setField_(ns.TOTAL_RATING, unmapped.videos[i].totalrating);
1274                 video.setField_(ns.TOTAL_VOTES, unmapped.videos[i].totalvotes);
1275                 video.setField_(ns.COUNTRY, unmapped.videos[i].country);
1276                 video.setField_(ns.LANGUAGE, unmapped.videos[i].language);
1277                 videos.push(video);
1278             }
1279         }
1280 
1281         return opensocial.Container.get().newCollection(videos, 0, unmapped.count);
1282     },
1283 
1284     /**
1285     * Maps a server response into a MyOpenSpace.Video object
1286     * @function
1287     * @return {MyOpenSpace.Video}
1288     * @param {XMLHttpRequest} obj The response from the server
1289     * @private
1290     * @private
1291     */
1292     mapVideo_: function(obj) {
1293         try {
1294             var unmapped = gadgets.json.parse(obj.responseText);
1295         }
1296         catch (err) {
1297             return null;
1298         }
1299         var video = new opensocial.Container.get().newVideo();
1300         var ns = MyOpenSpace.Video.Field;
1301 
1302         if (unmapped) {
1303             video.setField_(ns.VIDEO_ID, unmapped.id);
1304             video.setField_(ns.VIDEO_URI, unmapped.videoUri);
1305             video.setField_(ns.TITLE, unmapped.title);
1306             video.setField_(ns.DATE_CREATED, unmapped.datecreated);
1307             video.setField_(ns.LAST_UPDATE, unmapped.dateupdated);
1308             video.setField_(ns.MEDIA_TYPE, unmapped.mediatype);
1309             video.setField_(ns.THUMB_URI, unmapped.thumbnail);
1310             video.setField_(ns.DESCRIPTION, unmapped.description);
1311             video.setField_(ns.MEDIA_STATUS, unmapped.mediastatus);
1312             video.setField_(ns.RUN_TIME, unmapped.runtime);
1313             video.setField_(ns.TOTAL_VIEWS, unmapped.totalviews);
1314             video.setField_(ns.TOTAL_COMMENTS, unmapped.totalcomments);
1315             video.setField_(ns.TOTAL_RATING, unmapped.totalrating);
1316             video.setField_(ns.TOTAL_VOTES, unmapped.totalvotes);
1317             video.setField_(ns.COUNTRY, unmapped.country);
1318             video.setField_(ns.LANGUAGE, unmapped.language);
1319         }
1320 
1321         return video;
1322     },
1323 
1324     /**
1325     * Maps a server response into a opensocial.Collection of MyOpenSpace.Person objects
1326     * @function
1327     * @return {opensocial.Collection}
1328     * @param {XMLHttpRequest} obj The response from the server
1329     * @private
1330     * @private
1331     */
1332     mapPeople_: function(obj) {
1333         try {
1334             var unmapped = gadgets.json.parse(obj.responseText);
1335         }
1336         catch (err) {
1337             return null;
1338         }
1339         var friends = [];
1340         var person;
1341         var unmappedData;
1342 		
1343 		
1344 		if (typeof(unmapped.users) !== 'undefined'){
1345 			unmappedData = [];
1346 			for (var j in unmapped.users){
1347 				unmappedData[j] ={
1348 					"id": "myspace.com:" + unmapped.users[j].userId,
1349 					"nickname" : unmapped.users[j].name,
1350 					"thumbnailUrl" : unmapped.users[j].image,
1351 					"profileUrl" : unmapped.users[j].webUri
1352 				};
1353 			}
1354 		}
1355 		else if (typeof(unmapped.entry) === 'undefined'){
1356 			return opensocial.Container.get().newCollection([], 0, 0);
1357 		}
1358 		else if (unmapped.entry.constructor == Array){
1359 			unmappedData = unmapped.entry;
1360 		}
1361 		else{
1362 			unmappedData = [unmapped.entry];
1363 		}
1364 		
1365 		var person;
1366 		var friends = [];
1367 		for (var i in unmappedData){
1368 			person = this.mapSimplePersonData_(unmappedData[i]);
1369 			friends[i] = person;
1370 		}
1371         return opensocial.Container.get().newCollection(friends, 0, unmapped.count);
1372     },
1373     /**
1374     * Maps server response data object to a MyOpenSpace.Person object filling ID, Thumbnail,
1375     * nickname, profileUrl and name fiedls 
1376     * @function
1377     * @return {MyOpenSpace.Person}
1378     * @param {Object} unmappedData The response person object from the server
1379     * @private
1380     */
1381 	mapSimplePersonData_:function(unmappedData){
1382 		var isOwner = false;
1383         var isViewer = false; 
1384 		if (typeof(unmappedData.id) !== 'undefined'){
1385 			var id = unmappedData.id.split(":")[1];
1386 			var viewerId = gadgets.views.getParams().viewerId;
1387 			var ownerId = gadgets.views.getParams().ownerId;
1388 			isOwner = (id === ownerId);
1389 	        isViewer = (id === viewerId);
1390 		}
1391 		
1392         var person = new opensocial.Container.get().newPerson(null, isOwner, isViewer);
1393         var ns = opensocial.Person.Field;
1394 		/**
1395 		 * Generic method Populates person field specify by personField if obj is different from undefined.
1396 		 * @param {Object} personField Field to map.
1397 		 * @param {Object} obj Data to map
1398 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1399 		 * @private
1400 		 */
1401 		var mapGeneric = function(personField, obj, explicitPerson){
1402 			if (typeof(obj) === 'undefined') return;
1403 			var personObject = person || explicitPerson;
1404 			personObject.setField_(personField, obj);
1405 		};
1406 		/**
1407 		 * Populates person HAS_APP field if hasApp parameter is present.
1408 		 * @param {Object} hasApp Value to map.
1409 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1410 		 * @private
1411 		 */
1412 		var mapHasApp = function(hasApp, explicitPerson){
1413 			if (typeof(hasApp) === 'undefined') return;
1414             var personObject = person || explicitPerson;
1415 			var hasAppObj = (('' + hasApp).toLowerCase() === 'true');
1416 			personObject.setField_(ns.HAS_APP, hasAppObj);
1417 		};
1418 		/**
1419 		 * Populates person Name field with the information provided in name, familyName, givenName.
1420 		 * @param {Object} name Display name
1421 		 * @param {Object} familyName Family name
1422 		 * @param {Object} givenName Given Name
1423 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1424 		 * @private
1425 		 */
1426 		var mapName = function(name, familyName, givenName, explicitPerson) {
1427 			if (typeof(name) === 'undefined' && typeof(familyName) === 'undefined' && typeof(givenName) === 'undefined') return;
1428 			var personObject = person || explicitPerson;
1429             var nameParams = {};
1430             if (typeof(name) !== 'undefined') nameParams[opensocial.Name.Field.UNSTRUCTURED] = name;
1431 			if (typeof(givenName) !== 'undefined') nameParams[opensocial.Name.Field.GIVEN_NAME] = givenName;
1432 			if (typeof(familyName) !== 'undefined') nameParams[opensocial.Name.Field.FAMILY_NAME] = familyName;
1433             var personName = new opensocial.Name(nameParams);
1434             personObject.setField_(ns.NAME, personName);
1435         };
1436 		
1437 		mapGeneric(ns.ID, unmappedData.id);
1438 		mapGeneric(ns.THUMBNAIL_URL, unmappedData.thumbnailUrl);
1439 		mapGeneric(ns.NICKNAME, unmappedData.nickname);
1440 		mapGeneric(ns.PROFILE_URL, unmappedData.profileUrl);
1441 		mapName(unmappedData.displayName, unmappedData.familyName, unmappedData.givenName);
1442 		mapHasApp(unmappedData.hasApp);
1443 		
1444 		return person;
1445 	},
1446     /**
1447     * Maps a server response data object to a MyOpenSpace.Person object
1448     * @function
1449     * @return {MyOpenSpace.Person}
1450     * @param {Object}  The response person object from the server
1451     * @private
1452     */
1453 	mapPersonData_:function(unmappedData){
1454 
1455         var person = this.mapSimplePersonData_(unmappedData);
1456         var ns = opensocial.Person.Field;
1457 		var mns = MyOpenSpace.Person.Field;
1458 		/**
1459 		 * Generic method Populates person field specify by personField if obj is different from undefined.
1460 		 * @param {Object} personField Field to map.
1461 		 * @param {Object} obj data to map
1462 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1463 		 * @private
1464 		 */
1465 		var mapGeneric = function(personField, obj, explicitPerson){
1466 			if (typeof(obj) === 'undefined') return;
1467 			var personObject = person || explicitPerson;
1468 			personObject.setField_(personField, obj);
1469 		};
1470 		/**
1471 		 * Populates BODY_TYPE person field if bodyType is different from undefined.
1472 		 * @param {Object} bodyType Body type value.
1473 		 * @param {Object} explicitPerson pPerson object to use. If undefined the default person object will be used.
1474 		 * @private
1475 		 */
1476 		var mapBodyType = function(bodyType, explicitPerson){
1477 			if (typeof(bodyType) === 'undefined') return;
1478 			var personObject = person || explicitPerson;
1479 			var bodyTypeParams = {};
1480 			bodyTypeParams[opensocial.BodyType.Field.BUILD] = bodyType.build;
1481 			bodyTypeParams[opensocial.BodyType.Field.HEIGHT] = bodyType.height;
1482 			var bodyTypeObj = new opensocial.BodyType(bodyTypeParams);
1483 			personObject.setField_(ns.BODY_TYPE, bodyTypeObj);
1484 		};
1485 		/**
1486 		 * Populates CURRENT_LOCATION  person field if currentLocation is different from undefined.
1487 		 * @param {Object} currentLocation Current location value.
1488 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1489 		 * @private
1490 		 */
1491 		var mapCurrentLocation = function(currentLocation, explicitPerson){
1492 			if (typeof(currentLocation) === 'undefined') return;
1493 			var personObject = person || explicitPerson;
1494             var addressParams = {};
1495             addressParams[opensocial.Address.Field.REGION] = currentLocation.region;
1496             addressParams[opensocial.Address.Field.POSTAL_CODE] = currentLocation.postalCode;
1497             addressParams[opensocial.Address.Field.COUNTRY] = currentLocation.country;
1498             var currentLocationObj = new opensocial.Address(addressParams);
1499 			personObject.setField_(ns.CURRENT_LOCATION, currentLocationObj);
1500 		};
1501 		/**
1502 		 * Populates DATE_OF_BIRTH person field if dateOfBirth is different from undefined.
1503 		 * The date should be formatted yyyy-MM-ddTHH:mm:ss-00:00:00
1504 		 * @param {Object} dateOfBirth Formated date of birth value.
1505 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1506 		 * @private
1507 		 */
1508 		var mapDateOfBirth = function(dateOfBirth, explicitPerson){
1509 			if (typeof(dateOfBirth) === 'undefined') return;
1510 			var personObject = person || explicitPerson;
1511 			var dateOfBirthObj = new Date();
1512 			dateOfBirthObj.setDate(dateOfBirth.substr(8,2));
1513 			dateOfBirthObj.setMonth(dateOfBirth.substr(5,2));
1514 			dateOfBirthObj.setFullYear(dateOfBirth.substr(0,4));
1515 			dateOfBirthObj.setHours(0);
1516 			dateOfBirthObj.setMinutes(0);
1517 			dateOfBirthObj.setSeconds(0);
1518 			dateOfBirthObj.setMilliseconds(0);
1519 			personObject.setField_(ns.DATE_OF_BIRTH, dateOfBirthObj);
1520 		};
1521 		/**
1522 		 * Populates DRINKER person field if drinker is different from undefined.
1523 		 * @param {Object} drinker Drinker value object.
1524 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1525 		 * @private
1526 		 */
1527 		var mapDrinker = function(drinker, explicitPerson){
1528 			if (typeof(drinker) === 'undefined') return;
1529 			if (typeof(drinker.key) === 'undefined' && drinker.value === 'undefined') return;
1530 			var personObject = person || explicitPerson;
1531 			var drinkerKey = null;
1532 			var drinkerValue = drinker.value;
1533 			if (drinker.key !== null && typeof(drinker.key) !== 'undefined') {
1534 				if (drinker.key.toLowerCase() === 'yes') drinkerKey = opensocial.Enum.Drinker.YES;
1535 				else if (drinker.key.toLowerCase() === 'no') drinkerKey = opensocial.Enum.Drinker.NO;
1536 				else if (drinker.key.toLowerCase() === 'heavily') drinkerKey = opensocial.Enum.Drinker.HEAVILY;
1537 				else if (drinker.key.toLowerCase() === 'occasionally') drinkerKey = opensocial.Enum.Drinker.OCCASIONALLY;
1538 				else if (drinker.key.toLowerCase() === 'quit') drinkerKey = opensocial.Enum.Drinker.QUIT;
1539 				else if (drinker.key.toLowerCase() === 'quitting') drinkerKey = opensocial.Enum.Drinker.QUITTING;
1540 				else if (drinker.key.toLowerCase() === 'regularly') drinkerKey = opensocial.Enum.Drinker.REGULARLY;
1541 				else if (drinker.key.toLowerCase() === 'socially') drinkerKey = opensocial.Enum.Drinker.SOCIALLY;
1542 			};
1543 			personObject.setField_(ns.DRINKER, new opensocial.Enum(drinkerKey, drinkerValue));
1544 		};
1545 		/**
1546 		 * Populates GENDER person field if gender is different from undefined.
1547 		 * @param {Object} gender Gender value object
1548 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1549 		 * @private
1550 		 */
1551         var mapGender = function(gender, explicitPerson) {
1552 			if (typeof(gender) === 'undefined') return;
1553             var personObject = person || explicitPerson;
1554             var genderObj;
1555 			if (gender.toLowerCase() === "male") genderObj = opensocial.Enum.Gender.MALE;
1556 			else if (gender.toLowerCase() === "female") genderObj = opensocial.Enum.Gender.FEMALE;
1557 			if (typeof(genderObj) !== 'undefined')
1558 	            personObject.setField_(ns.GENDER, new opensocial.Enum(genderObj, genderObj));
1559         };
1560 		/**
1561 		 * Populates JOBS person field if jobs is different from undefined.
1562 		 * @param {Object} jobs Array of jobs objects to map.
1563 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1564 		 * @private
1565 		 */
1566 		var mapJobs = function(jobs, explicitPerson){
1567 			if (typeof(jobs) === 'undefined') return;
1568 			var personObject = person || explicitPerson;
1569 			var jobsObj = [];
1570 			for (var i in jobs){
1571 				var organizationParams = {};
1572 				organizationParams[opensocial.Organization.Field.NAME] = jobs[i].name;
1573 				organizationParams[opensocial.Organization.Field.TITLE] = jobs[i].title;
1574 				jobsObj[i] = new opensocial.Organization(organizationParams);
1575 			}
1576 			personObject.setField_(ns.JOBS, jobsObj);
1577 		};
1578 		/**
1579 		 * Populates NETWORK_PRESENCE person field if networkPresence is different from undefined.
1580 		 * @param {Object} networkPresence Network presence value object
1581 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1582 		 * @private
1583 		 */
1584 		var mapNetworkPresence = function(networkPresence, explicitPerson){
1585 			if (typeof(networkPresence) === 'undefined') return;
1586 			if (typeof(networkPresence.key) === 'undefined' && typeof(networkPresence.value) === 'undefined') return;
1587 			var personObject = person || explicitPerson;
1588 			var networkPresenceKey = null;
1589 			var networkValue = networkPresence.value;
1590 			if (networkPresence.key != null && typeof(networkPresence.key) !== 'undefined' ) {
1591 				if (networkPresence.key.toLowerCase() === 'offline') networkPresenceKey = opensocial.Enum.Presence.OFFLINE;
1592 				else if (networkPresence.key.toLowerCase() === 'online') networkPresenceKey = opensocial.Enum.Presence.ONLINE;
1593 				else if (networkPresence.key.toLowerCase() === 'away') networkPresenceKey = opensocial.Enum.Presence.AWAY;
1594 				else if (networkPresence.key.toLowerCase() === 'chat') networkPresenceKey = opensocial.Enum.Presence.CHAT;
1595 				else if (networkPresence.key.toLowerCase() === 'dnd') networkPresenceKey = opensocial.Enum.Presence.DND;
1596 				else if (networkPresence.key.toLowerCase() === 'xa') networkPresenceKey = opensocial.Enum.Presence.XA;
1597 			}
1598 			personObject.setField_(ns.NETWORK_PRESENCE, new opensocial.Enum(networkPresenceKey, networkValue));
1599 		};
1600 		/**
1601 		 * Populates PROFILE_SONG person field if profileSong is different from undefined.
1602 		 * @param {Object} profileSong Profile song value.
1603 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1604 		 * @private
1605 		 */
1606 		var mapProfileSong = function(profileSong, explicitPerson){
1607 			if (typeof(profileSong) === 'undefined') return;
1608 			var personObject = person || explicitPerson;
1609 			var urlParams = {};
1610 			urlParams[opensocial.Url.Field.LINK_TEXT] = profileSong;
1611 			var urlObj = new opensocial.Url(urlParams);
1612 			personObject.setField_(ns.PROFILE_SONG, urlObj);
1613 		};
1614 		/**
1615 		 * Populates LOOKING_FOR person field if lookingFor is different from undefined.
1616 		 * @param {Object} lookingFor Looking for value.
1617 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1618 		 * @private
1619 		 */
1620 		var mapLookingFor = function(lookingFor, explicitPerson){
1621 			if (typeof(lookingFor) === 'undefined') return;
1622 			var personObject = person || explicitPerson;
1623 			personObject.setField_(ns.LOOKING_FOR, new opensocial.Enum(null, lookingFor));
1624 		};
1625 		/**
1626 		 * Populates SMOKER person field if smoker is different from undefined.
1627 		 * @param {Object} smoker smoker value object.
1628 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1629 		 * @private
1630 		 */
1631 		var mapSmoker = function(smoker, explicitPerson){
1632 			if (typeof(smoker) === 'undefined') return;
1633 			if (typeof(smoker.key) === 'undefined' && somoker.value === 'undefined') return;
1634 			var personObject = person || explicitPerson;
1635 			var smokerKey = null;
1636 			var smokerValue = smoker.value;
1637 			if (smoker.key !== null && typeof(smoker.key) !== 'undefined') {
1638 				if (smoker.key.toLowerCase() === 'heavily') smokerKey = opensocial.Enum.Smoker.HEAVILY;
1639 				else if (smoker.key.toLowerCase() === 'no') smokerKey = opensocial.Enum.Smoker.NO;
1640 				else if (smoker.key.toLowerCase() === 'occasionally') smokerKey = opensocial.Enum.Smoker.OCCASIONALLY;
1641 				else if (smoker.key.toLowerCase() === 'quit') smokerKey = opensocial.Enum.Smoker.QUIT;
1642 				else if (smoker.key.toLowerCase() === 'quitting') smokerKey = opensocial.Enum.Smoker.QUITTING;
1643 				else if (smoker.key.toLowerCase() === 'regularly') smokerKey = opensocial.Enum.Smoker.REGULARLY;
1644 				else if (smoker.key.toLowerCase() === 'socially') smokerKey = opensocial.Enum.Smoker.SOCIALLY;
1645 				else if (smoker.key.toLowerCase() === 'yes') smokerKey = opensocial.Enum.Smoker.YES;
1646 			}
1647 			
1648 			personObject.setField_(ns.SMOKER, new opensocial.Enum(smokerKey, smokerValue));
1649 		};
1650 		/**
1651 		 * Populates URLS person field if urls is different from undefined.
1652 		 * @param {Object} urls Array of urls objects.
1653 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1654 		 * @private
1655 		 */
1656 		var mapUrls = function(urls, explicitPerson){
1657 			if (typeof(urls) === 'undefined') return;
1658 			var personObject = person || explicitPerson;
1659 			var urlsObj =[];
1660 			for (var i in urls){
1661 				var urlParams = {};
1662 				urlParams[opensocial.Url.Field.ADDRESS] = urls[i].value;
1663 				urlParams[opensocial.Url.Field.TYPE] = urls[i].type;
1664 				urlsObj[i] = new opensocial.Url(urlParams);
1665 			}
1666 			personObject.setField_(ns.URLS, urlsObj);
1667 		};
1668 		/**
1669 		 * Populates the MySpace LARGE_IMAGE and MEDIUM_IMAGE extensions fields if photos is different from undefined.
1670 		 * @param {Object} photos photos value object.
1671 		 * @param {Object} explicitPerson Person object to use. If undefined the default person object will be used.
1672 		 * @private
1673 		 */
1674 		var mapPhotos = function(photos, explicitPerson){
1675 			if (typeof(photos) === 'undefined') return;
1676 			var personObject = person || explicitPerson;
1677 			var image;
1678 			var urlParams;
1679 			for (var i in photos){
1680 				var type = photos[i].type;
1681 				var val = photos[i].value;
1682 				if (type === 'medium' && typeof(val) !== 'undefined'){
1683 					urlParams = {};
1684 					urlParams[opensocial.Url.Field.ADDRESS] = val;
1685 					urlParams[opensocial.Url.Field.TYPE] = 'medium image';
1686 					personObject.setField_(mns.MEDIUM_IMAGE, new opensocial.Url(urlParams));
1687 				}
1688 				else if (type === 'large' && typeof(val) !== 'undefined'){
1689 					urlParams = {};
1690 					urlParams[opensocial.Url.Field.ADDRESS] = val;
1691 					urlParams[opensocial.Url.Field.TYPE] = 'large image';
1692 					personObject.setField_(mns.LARGE_IMAGE, new opensocial.Url(urlParams));
1693 				}
1694 			}
1695 		}
1696 
1697         var addressns = opensocial.Address.Field;
1698 		mapGeneric(ns.ABOUT_ME, unmappedData.aboutMe);
1699 		mapGeneric(ns.AGE, unmappedData.age);
1700 		mapBodyType(unmappedData.bodyType);
1701 		mapGeneric(ns.BOOKS, unmappedData.books);
1702 		mapGeneric(ns.CHILDREN, unmappedData.children);
1703 		mapCurrentLocation(unmappedData.currentLocation);
1704 		mapDateOfBirth(unmappedData.dateOfBirth);
1705 		mapDrinker(unmappedData.drinker);
1706 		mapGeneric(ns.ETHNICITY, unmappedData.ethnicity);
1707 		mapGender(unmappedData.gender);
1708 
1709 		mapGeneric(ns.HEROES, unmappedData.heroes);
1710 		
1711 		mapGeneric(ns.INTERESTS, unmappedData.interests);
1712 		mapJobs(unmappedData.organizations);
1713 		mapGeneric(ns.MOVIES, unmappedData.movies);
1714 		mapGeneric(ns.MUSIC, unmappedData.music);
1715 		mapNetworkPresence(unmappedData.networkPresence);
1716 
1717 		mapLookingFor(unmappedData.lookingFor);
1718 		mapProfileSong(unmappedData.profileSong);
1719 
1720 		mapGeneric(ns.RELATIONSHIP_STATUS, unmappedData.relationshipStatus);
1721 		mapGeneric(ns.RELIGION, unmappedData.religion);
1722 		mapGeneric(ns.SEXUAL_ORIENTATION, unmappedData.sexualOrientation);
1723 		mapSmoker(unmappedData.smoker);
1724 		mapGeneric(ns.STATUS, unmappedData.status);
1725 
1726 		mapGeneric(ns.TV_SHOWS, unmappedData.tvShows);
1727 		mapUrls(unmappedData.urls);
1728 		//MySpace Extensions
1729 		mapPhotos(unmappedData.photos);
1730 		
1731         return person;
1732 	},
1733     /**
1734     * Maps a server response into a MyOpenSpace.Person object
1735     * @function
1736     * @return {MyOpenSpace.Person}
1737     * @param {XMLHttpRequest} obj The response from the server
1738     * @private
1739     */
1740     mapPerson_: function(obj) {
1741         try {
1742             var unmapped = gadgets.json.parse(obj.responseText);
1743         }
1744         catch (err) {
1745             return null;
1746         }
1747         if (typeof (unmapped) === 'undefined') 	return null;
1748 		if (typeof (unmapped.entry) === 'undefined' && typeof (unmapped.users) === 'undefined') return null;
1749 		if (typeof (unmapped.users) !== 'undefined'){
1750 			unmappedData ={
1751 				"id": "myspace.com:" + unmapped.users[0].userId,
1752 				"nickname" : unmapped.users[0].name,
1753 				"thumbnailUrl" : unmapped.users[0].image,
1754 				"displayName" : unmapped.users[0].name,
1755 				"profileUrl" : unmapped.users[0].webUri
1756 			};
1757 		}
1758 		else{
1759 			unmappedData = unmapped.entry[0] || unmapped.entry;			
1760 		}
1761 
1762 		return this.mapPersonData_(unmappedData);
1763     },
1764 
1765     /**
1766     * Maps a server response into a opensocial.Collection of opensocial.Activity objects
1767     * @function
1768     * @return {opensocial.Collection}
1769     * @param {XMLHttpRequest} obj The response from the server
1770     * @private
1771     */
1772     mapActivities_: function(obj) {
1773         if(!obj){
1774             return null;
1775         }
1776         
1777         if(obj && (!obj.responseText || obj.responseText.length < 1)){
1778             return opensocial.Container.get().newCollection([], 0, 0);
1779         }
1780         
1781         try{
1782             var unmapped = gadgets.json.parse(obj.responseText);
1783         }
1784         catch(err){
1785             return null;
1786         }
1787         
1788         if(!unmapped){
1789             return null;
1790         }
1791 
1792         var activities = [];
1793         var activity;
1794         var ns = opensocial.Activity.Field;
1795 
1796         if (unmapped.entry) {
1797             for (var i = 0; i < unmapped.entry.length; i++) {
1798                 activity = new opensocial.newActivity();
1799                 activity.setField(ns.APP_ID, unmapped.entry[i].appId);
1800                 activity.setField(ns.USER_ID, unmapped.entry[i].userId);
1801                 activity.setField(ns.BODY, unmapped.entry[i].body);
1802                 activity.setField(ns.POSTED_TIME, unmapped.entry[i].postedTime);
1803                 activity.setField(ns.STREAM_FAVICON_URL, unmapped.entry[i].streamFavIconUrl);
1804                 activity.setField(ns.TITLE, unmapped.entry[i].title);
1805                 activity.setField(ns.TITLE_ID, unmapped.entry[i].titleId);
1806                 activities.push(activity);
1807             }
1808         }
1809         return opensocial.Container.get().newCollection(activities, 0, unmapped.count);
1810     }
1811 };/**
1812 * An extension of opensocial.DataRequest, used to facilitate extended entity calls.
1813 * @class
1814 * @name MyOpenSpace.DataRequest
1815 */
1816 //MyOpenSpace.DataRequest = function() { };
1817 
1818 /**  
1819 * @constructor Creates a new DataRequest factory and execution model
1820 * @param {String} osToken OpenSocial token
1821 * @param {MyOpenSpace.EndPoint} endPoint MyOpenSpace.EndPoint object for service endpoints
1822 * @class
1823 * @name opensocial.DataRequest
1824 * @private
1825 * @internal
1826 * DataRequest is the internal MySpace implementation of an OpenSocial DataRequest
1827 */
1828 
1829 MyOpenSpace.DataRequest = function(osToken, endPoint) {
1830     //this.init.apply(this, arguments);
1831     //this.requestProcessor_ = new MyOpenSpace.RequestProcessor_();
1832     this.osToken_ = osToken;
1833     this.endPoint_ = endPoint;
1834     
1835     this.requestProcessor_ = new MyOpenSpace.RequestProcessor_();
1836     this.requestObjects_ = new MyOpenSpace.Hash();
1837     this.requestObjectCount_ = 0;
1838     this.busy_ = false;
1839     this.authTemplate_ = null;
1840 
1841 };
1842 
1843 MyOpenSpace.DataRequest.prototype = new opensocial.DataRequest();
1844 
1845 
1846 /**
1847 * Enumerates the extended filter types
1848 * @static
1849 * @class
1850 * @name MyOpenSpace.DataRequest.FilterType
1851 */
1852 MyOpenSpace.DataRequest.FilterType = {
1853     /**
1854     * The friends that are currently online.
1855     * @memberOf MyOpenSpace.DataRequest.FilterType
1856     */
1857     ONLINE_FRIENDS: "ONLINE_FRIENDS"
1858 };
1859 /**
1860 * Enumerates the extended sort order types
1861 * @static
1862 * @class
1863 * @name MyOpenSpace.DataRequest.SortOrder
1864 */
1865 MyOpenSpace.DataRequest.SortOrder = {
1866     /**
1867     * The friends that are currently online.
1868     * @memberOf MyOpenSpace.DataRequest.FilterType
1869     */
1870     ID: "ID"
1871 };
1872 
1873 /**
1874 * Enumerates cache control mechanism for API calls
1875 * @static
1876 * @class
1877 * @name MyOpenSpace.DataRequest.CacheControl
1878 */
1879 MyOpenSpace.DataRequest.CacheControl = {
1880     /**
1881     * Enable/disable the cache layer - boolean
1882     * @memberOf MyOpenSpace.DataRequest.CacheControl
1883     */
1884     USE_CACHE: "USE_CACHE",
1885     /**
1886     * Specify a TTL for the item in cache - specified in seconds: 0 means no expiration
1887     * @memberOf MyOpenSpace.DataRequest.CacheControl
1888     */
1889     REFRESH_INTERVAL: "REFRESH_INTERVAL"
1890 };
1891 
1892 /**
1893 * Enumerates the request fields used by the Photo entity
1894 * @static
1895 * @class
1896 * @name MyOpenSpace.DataRequest.PhotoRequestFields
1897 */
1898 MyOpenSpace.DataRequest.PhotoRequestFields = {
1899     /**
1900     * Used to filter a photos request by album id, returns all photos for a particular album.
1901     * @memberOf MyOpenSpace.DataRequest.PhotoRequestFields
1902     */
1903     ALBUM_ID: "ALBUM_ID"
1904 };
1905 
1906 /**
1907 * Creates an object to be used when sending to the server.
1908 * @param {String} id The ID (VIEWER or OWNER) of the person who owns the photo
1909 * @param {Number} photo_id The ID of the photo to fetch
1910 * @param {undefined} opt_params Not used at this time.
1911 * @return {Object} A request object
1912 * @static
1913 * @memberOf MyOpenSpace.DataRequest
1914 */
1915 MyOpenSpace.DataRequest.newFetchPhotoRequest = function(id, photo_id, opt_params) {
1916     return opensocial.Container.get().newFetchPhotoRequest(id, photo_id, opt_params);
1917 };
1918 
1919 /**
1920 * Creates an object to be used when sending to the server
1921 * @param {String} id The ID (VIEWER or OWNER) of the person who owns the photos
1922 * @param {Map<opensocial.DataRequest.PeopleRequestFields.FIRST || opensocial.DataRequest.PeopleRequestFields.MAX>} opt_params Optional parameters specified when creating the photos.
1923 * @return {Object} A request object
1924 * @static
1925 * @memberOf MyOpenSpace.DataRequest
1926 */
1927 MyOpenSpace.DataRequest.newFetchPhotosRequest = function(id, photo_id, opt_params) {
1928     return opensocial.Container.get().newFetchPhotosRequest(id, photo_id, opt_params);
1929 };
1930 
1931 /**
1932 * Creates an object to be used when sending to the server
1933 * @param {String} id The ID (VIEWER or OWNER) of the person who owns the album
1934 * @param {Number} album_id The ID of the photo to fetch
1935 * @param {undefined} opt_params Not used at this time.
1936 * @return {Object} A request object
1937 * @static
1938 * @memberOf MyOpenSpace.DataRequest
1939 */
1940 MyOpenSpace.DataRequest.newFetchAlbumRequest = function(id, photo_id, opt_params) {
1941     return opensocial.Container.get().newFetchAlbumRequest(id, photo_id, opt_params);
1942 };
1943 
1944 /**
1945 * Creates an object to be used when sending to the server
1946 * @param {String} id The ID (VIEWER or OWNER) of the person who owns the albums
1947 * @param {Map<opensocial.DataRequest.PeopleRequestFields.FIRST || opensocial.DataRequest.PeopleRequestFields.MAX>} opt_params Optional parameters specified when creating the albums.
1948 * @return {Object} A request object
1949 * @static
1950 * @memberOf MyOpenSpace.DataRequest
1951 */
1952 MyOpenSpace.DataRequest.newFetchAlbumsRequest = function(id, photo_id, opt_params) {
1953     return opensocial.Container.get().newFetchAlbumsRequest(id, photo_id, opt_params);
1954 };
1955 
1956 /**
1957 * Creates an object to be used when sending to the server
1958 * @param {String} id The ID (VIEWER or OWNER) of the person who owns the album
1959 * @param {Number} video_id The ID of the photo to fetch
1960 * @param {undefined} opt_params Not used at this time.
1961 * @return {Object} A request object
1962 * @static
1963 * @memberOf MyOpenSpace.DataRequest
1964 */
1965 MyOpenSpace.DataRequest.newFetchVideoRequest = function(id, photo_id, opt_params) {
1966     return opensocial.Container.get().newFetchVideoRequest(id, photo_id, opt_params);
1967 };
1968 
1969 /**
1970 * Creates an object to be used when sending to the server
1971 * @param {String} id The ID (VIEWER or OWNER) of the person
1972 * @param {undefined} opt_params Not used at this time.
1973 * @return {Object} A request object
1974 * @static
1975 * @memberOf MyOpenSpace.DataRequest
1976 */
1977 MyOpenSpace.DataRequest.newFetchIndicatorsRequest = function(id, opt_params) {
1978     return opensocial.Container.get().newFetchIndicatorsRequest(id, opt_params);
1979 };
1980 
1981 /**
1982 * Creates an object to be used when sending to the server
1983 * @param {String} id The ID (VIEWER or OWNER) of the person
1984 * @param {undefined} opt_params Not used at this time.
1985 * @return {Object} A request object
1986 * @static
1987 * @memberOf MyOpenSpace.DataRequest
1988 */
1989 MyOpenSpace.DataRequest.newFetchPersonStatusRequest = function(id, opt_params) {
1990     return opensocial.Container.get().newFetchPersonStatusRequest(id, opt_params);
1991 };
1992 
1993 /**
1994 * Creates an object to be used when sending to the server
1995 * @param {String} id The ID (VIEWER or OWNER) of the person
1996 * @param {undefined} opt_params Not used at this time.
1997 * @return {Object} A request object
1998 * @static
1999 * @memberOf MyOpenSpace.DataRequest
2000 */
2001 MyOpenSpace.DataRequest.newFetchPersonMoodRequest = function(id, opt_params) {
2002     return opensocial.Container.get().newFetchPersonMoodRequest(id, opt_params);
2003 };
2004 
2005 /**
2006 * Creates an object to be used when sending to the server
2007 * @param {String} id The ID (VIEWER or OWNER) of the person
2008 * @param {String} key The ID of the person to verify friendship
2009 * @param {undefined} opt_params Not used at this time.
2010 * @return {Object} A request object
2011 * @static
2012 * @memberOf MyOpenSpace.DataRequest
2013 */
2014 MyOpenSpace.DataRequest.newFetchPersonFriendshipRequest = function(id, key, opt_parms) {
2015     return opensocial.Container.get().newFetchPersonFriendshipRequest(id, key, opt_parms);
2016 };
2017 
2018 /**
2019 * Creates an object to be used when sending to the server
2020 * @param {String} id The ID (VIEWER or OWNER) of the person
2021 * @param {Array} key The array of IDs of the people to verify friendship.
2022 * @param {undefined} opt_params Not used at this time.
2023 * @return {Object} A request object
2024 * @static
2025 * @memberOf MyOpenSpace.DataRequest
2026 */
2027 MyOpenSpace.DataRequest.newFetchPeopleFriendshipRequest = function(id, key, opt_parms) {
2028     return opensocial.Container.get().newFetchPeopleFriendshipRequest(id, key, opt_parms);
2029 };
2030 
2031 /**
2032 * Creates an object to be used when sending to the server
2033 * @param {String} id The ID (VIEWER or OWNER) of the person who owns the albums
2034 * @param {Map<opensocial.DataRequest.PeopleRequestFields.FIRST || opensocial.DataRequest.PeopleRequestFields.MAX>} opt_params Optional parameters specified when creating the videos.
2035 * @return {Object} A request object
2036 * @static
2037 * @memberOf MyOpenSpace.DataRequest
2038 */
2039 MyOpenSpace.DataRequest.newFetchVideosRequest = function(id, photo_id, opt_params) {
2040     return opensocial.Container.get().newFetchVideosRequest(id, photo_id, opt_params);
2041 };
2042 
2043 MyOpenSpace.DataRequest.prototype = {
2044     //maxRequestObjects: 40,
2045     //setAuthorization: function(template) {
2046         //opensocial.Container.get().getRequestProcessor().setAuthorization(template);
2047 	//},
2048 
2049 	allRequestsCompleteCallback_: function() {},
2050 
2051 	getRequestObjects: function() {
2052 		return this.requestObjects_;
2053 	},
2054 	
2055 	add: function(request, opt_key) { // was: add: function(request, priority) {
2056         if(!this.busy_){
2057             //priority = priority || MyOpenSpace.RequestProcessor_.WorkItem.Priority.NORMAL;
2058             //if(!opt_key) opt_key = request.type + "-" + request.parameters.id;
2059             opt_key ? request.key = opt_key : request.key = null;
2060             if("undefined" === typeof(opt_key) || !this.requestObjects_.has(opt_key)){ // check for duplicate entry
2061                 //opensocial.Container.get().getRequestProcessor().addWorkItem(request);
2062                 this.requestProcessor_.addWorkItem(request);
2063                 var id = request.type;
2064                 if(request.parameters){
2065                     if(request.parameters.id) id += "-" + request.parameters.id;
2066                     else if(request.parameters.idSpec) id += "-" + request.parameters.idSpec;
2067                 }
2068                 opt_key ? this.requestObjects_.add(opt_key, request) : this.requestObjects_.add(id, request);
2069                 this.requestObjectCount_++;
2070             }
2071         }
2072     },
2073 	send: function(opt_callback) { //TODO: is callback optional? why send a request if there's no callback?
2074 		if(!this.busy_ && this.requestObjectCount_ > 0){
2075             this.busy_ = true;
2076 		    if(opt_callback) this.allRequestsCompleteCallback_ = opt_callback;
2077             
2078 		    opensocial.Container.get().requestData(this, opt_callback);
2079 		}
2080 		
2081 	},
2082 	newFetchPersonRequest: function(id, opt_params) {
2083 	    return opensocial.Container.get().newFetchPersonRequest(id, opt_params);
2084 	},
2085 	newFetchPeopleRequest: function(id, opt_params) {
2086 	    return opensocial.Container.get().newFetchPeopleRequest(id, opt_params);
2087 	},
2088 	newFetchGlobalAppDataRequest: function() {
2089 	    return opensocial.Container.get().newFetchGlobalAppDataRequest();
2090 	},
2091 	newFetchInstanceAppDataRequest: function() {
2092 	    return opensocial.Container.get().newFetchInstanceAppDataRequest();
2093 	},
2094 	newUpdateInstanceAppDataRequest: function() {
2095 	    return opensocial.Container.get().newUpdateInstanceAppDataRequest();
2096 	},
2097 	newFetchPersonAppDataRequest: function(id, keys, opt_params) {
2098 	    return opensocial.Container.get().newFetchPersonAppDataRequest(id, keys, opt_params);
2099 	},
2100 	newUpdatePersonAppDataRequest: function(id, key, value) {
2101 	    return opensocial.Container.get().newUpdatePersonAppDataRequest(id, key, value);
2102 	},
2103 	newFetchActivitiesRequest: function(idSpec, opt_params) {
2104 	    return opensocial.Container.get().newFetchActivitiesRequest(idSpec, opt_params);
2105 	},
2106 	newRemovePersonAppDataRequest: function(id,keys){
2107 		return opensocial.Container.get().newRemovePersonAppDataRequest(id,keys);
2108 	}
2109 };
2110 
2111 /**
2112  * @constructor
2113  * @name MyOpenSpace.DataRequest.RequestActions_
2114  * @internal
2115  */
2116 MyOpenSpace.DataRequest.RequestActions_ = function(dataRequest) {
2117 	this.dataRequest_ = dataRequest;
2118 	this.itemsProcessed_ = 0;
2119 	this.dataResponseValues_ = {};
2120 };
2121 
2122 /**
2123  * Does the logic for the requests and sets up callbacks
2124  * @memberOf MyOpenSpace.DataRequest
2125  * @private
2126  * @internal
2127  */
2128 MyOpenSpace.DataRequest.RequestActions_.prototype = {
2129     itemsProcessed_: 0,
2130     dataResponseValues_: {},
2131     errored_: false,
2132     getRequestId_: function getRequestId_(id) {
2133         var table = this.dataRequest_.ReqestIdTable_;
2134         if (typeof table === 'undefined' || table === null) {
2135             this.dataRequest_.ReqestIdTable_ = {};
2136             table = this.dataRequest_.ReqestIdTable_;
2137         }
2138         var requestId = table[id];
2139         if (typeof requestId === 'undefined') {
2140             table[id] = 0;
2141             requestId = "";
2142         }
2143         else {
2144             table[id] += 1;
2145             requestId = "_" + table[id];
2146         }
2147         return requestId;
2148     },
2149     isViewerDenied: function(type, key) {
2150         if (gadgets.views.getParams().denyViewer) {
2151             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.UNAUTHORIZED, "errorMessage": "Permission denied to all viewer resources." }, type, true, key);
2152             return true;
2153         }
2154         else {
2155             return false;
2156         }
2157     },
2158 	/**
2159 	 * Internal method that handles fetch person requests
2160 	 * @internal
2161 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2162 	 * @param {Object} workitem
2163 	 */
2164     "FETCH_PERSON": function FETCH_PERSON(workitem) {
2165         var personId = workitem.parameters.id;
2166         var type = MyOpenSpace.RequestType.FETCH_PERSON;
2167 		
2168         var url;
2169 		var profileDetail = workitem.parameters.profileDetail;
2170 		if (profileDetail.unsupported != null){
2171             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "errorMessage": "Request contains not implemented fields:" +  profileDetail.unsupported}, workitem.key, true);
2172             return;
2173         }
2174 
2175         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2176             url = this.dataRequest_.endPoint_.Person.Viewer.replace("{DETAIL_TYPE}", profileDetail.fields);
2177             if (this.isViewerDenied(type, workitem.key)) return;
2178         }
2179         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2180             url = this.dataRequest_.endPoint_.Person.Owner.replace("{DETAIL_TYPE}", profileDetail.fields);
2181         }
2182         else {
2183 			var results = ('' + personId).match(/^(?:myspace\.com:)?(\d+)$/);
2184             if (results === null || results.length === 0) {
2185 	            this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, type, true, workitem.key);
2186     	        return;
2187             }
2188 			url = this.dataRequest_.endPoint_.Person.ID.replace("{PERSON_ID}", results[1]);
2189         }
2190         this.invoke_(this, url, type, workitem.key);
2191     },
2192 	/**
2193 	 * Internal method that handles fetch people requests
2194 	 * @internal
2195 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2196 	 * @param {Object} workitem
2197 	 */
2198 	"FETCH_PEOPLE": function FETCH_PEOPLE(workitem) {
2199         var idSpec = idSpecMap(workitem.parameters.idSpec);
2200         var type = MyOpenSpace.RequestType.FETCH_PEOPLE;
2201 		
2202         var url;
2203         if (typeof (idSpec.errorCode) !== 'undefined') {
2204             this.addResponseItem_(idSpec, type, true, workitem.key);
2205             return;
2206         }
2207 		
2208         var first = workitem.parameters.first;
2209         var max = workitem.parameters.max;
2210         var filter = workitem.parameters.filter;
2211         var sort = workitem.parameters.sortOrder;
2212 		var details = workitem.parameters.details;
2213 		var sortToken = "";
2214         var filterToken = "";
2215 
2216 		//details
2217 		if (typeof(details) !== 'undefined'){
2218 			this.addResponseItem_({
2219 					"errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED,
2220 					"errorMessage": "opensocial.DataRequest.PeopleRequestFields.PROFILE_DETAILS is not implemented."
2221 				}, type, true, workitem.key);
2222 				return;
2223 		}
2224 		
2225 		// paging
2226         var pagingError = this.getPagingError(first,max);
2227         if(pagingError !== "")
2228         {
2229             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": pagingError}, 
2230 				type, true, workitem.key);
2231             return;
2232         }
2233         var paging = this.mapPagingParams_(workitem.parameters.first, workitem.parameters.max);
2234 
2235 		// sorting
2236 		if (typeof(sort) !== 'undefined') {
2237 			if (opensocial.DataRequest.SortOrder.NAME === sort) {
2238 				sortToken = this.dataRequest_.endPoint_.SortQueryString.replace("{SORT_BY}", "nickName").replace("{SORT_ORDER}", "asc");
2239 			}
2240 			else if (MyOpenSpace.DataRequest.SortOrder.ID === sort){
2241 				sortToken = this.dataRequest_.endPoint_.SortQueryString.replace("{SORT_BY}", "id").replace("{SORT_ORDER}", "asc");				
2242 			}
2243 			else if (opensocial.DataRequest.SortOrder.TOP_FRIENDS === sort) {
2244 				this.addResponseItem_({
2245 					"errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED,
2246 					"errorMessage": "Sort order value opensocial.DataRequest.SortOrder.TOP_FRIENDS is not implemented. If you want to filter top friends use opensocial.DataRequest.PeopleRequestFields.FILTER instead."
2247 				}, type, true,  workitem.key);
2248 				return;
2249 			}
2250 			else {
2251 				this.addResponseItem_({
2252 					"errorCode": opensocial.ResponseItem.Error.BAD_REQUEST,
2253 					"errorMessage": "Invalid sort order value."
2254 				}, type, true, workitem.key);
2255 				return;
2256 			}
2257 		}
2258 		
2259 		// filter
2260 
2261 
2262         // we can only have one filter at a time, so if more than one are specified we need to create an order of precedence
2263         if (filter) {
2264             if (opensocial.DataRequest.FilterType.HAS_APP === filter) filterToken = "app"; 
2265             else if (MyOpenSpace.DataRequest.FilterType.ONLINE_FRIENDS === filter) filterToken = "online"; 
2266             else if (opensocial.DataRequest.FilterType.TOP_FRIENDS === filter) filterToken = "top"; 
2267             else if (opensocial.DataRequest.FilterType.ALL === filter) filterToken = "all"; 
2268 			else if (opensocial.DataRequest.FilterType.IS_FRIENDS_WITH === filter){
2269 				this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "errorMessage": "opensocial.DataRequest.FilterType.IS_FRIENDS_WITH is not implemented." }, 
2270 				type, true, workitem.key);
2271 				return;
2272 			}
2273 			else{
2274 				this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "invalid filter." }, 
2275 				type, true, workitem.key);
2276 				return;
2277 			}
2278 			filterToken = this.dataRequest_.endPoint_.FilterQueryString.replace("{FILTER}", filterToken);
2279         }
2280 
2281         if ("number" === typeof (idSpec) || !isNaN(parseInt(idSpec, 10))) {
2282             url = this.dataRequest_.endPoint_.People.ID.replace("{PERSON_ID}", idSpec);
2283         }
2284         else if (idSpec === MyOpenSpace.IdSpecMapping_.VIEWER_FRIENDS) {
2285             url = this.dataRequest_.endPoint_.People.ViewerFriends.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]) + filterToken + sortToken;
2286             if (this.isViewerDenied(type, workitem.key)) return;
2287         }
2288         else if (idSpec === MyOpenSpace.IdSpecMapping_.OWNER_FRIENDS) {
2289             url = this.dataRequest_.endPoint_.People.OwnerFriends.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]) + filterToken + sortToken;
2290         }
2291         else if (idSpec === MyOpenSpace.IdSpecMapping_.OWNER) {
2292             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, 
2293 				"errorMessage": "Unsupported idSpec. To get owner information use fetchPersonRequest." },type, true, workitem.key);
2294             return;
2295         }
2296         else if (idSpec === MyOpenSpace.IdSpecMapping_.VIEWER) {
2297             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, 
2298 				"errorMessage": "Unsupported idSpec To get viewer information use fetchPersonRequest." }, 
2299 				type, true, workitem.key);
2300         }
2301         else {
2302             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, 
2303 				"errorMessage": "Unsupported idSpec" }, 
2304 				type, true, workitem.key);
2305             return;
2306         }
2307         
2308         this.invoke_(this, url, type, workitem.key);
2309     },
2310 	/**
2311 	 * Internal method that handles fetch indicators requests
2312 	 * @internal
2313 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2314 	 * @param {Object} workitem
2315 	 */
2316     "FETCH_INDICATORS": function FETCH_INDICATORS(workitem) {
2317         var personId = workitem.parameters.id;
2318         var type = MyOpenSpace.RequestType.FETCH_INDICATORS;
2319 		
2320         var url;
2321 
2322         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2323             url = this.dataRequest_.endPoint_.Indicators.Viewer;
2324             if (this.isViewerDenied(type, workitem.key)) return;
2325         }
2326         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2327             url = this.dataRequest_.endPoint_.Indicators.Owner;
2328         }
2329         else {
2330             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" },type, true, workitem.key);
2331             return;
2332         }
2333         this.invoke_(this, url, type, workitem.key);
2334     },
2335 	/**
2336 	 * Internal method that handles fetch person status requests
2337 	 * @internal
2338 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2339 	 * @param {Object} workitem
2340 	 */
2341     "FETCH_PERSON_STATUS": function FETCH_PERSON_STATUS(workitem) {
2342         var personId = workitem.parameters.id;
2343         var type = MyOpenSpace.RequestType.FETCH_PERSON_STATUS;
2344 		
2345         var url;
2346 
2347         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2348             url = this.dataRequest_.endPoint_.PersonStatus.Viewer;
2349             if (this.isViewerDenied(type, workitem.key)) return;
2350         }
2351         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2352             url = this.dataRequest_.endPoint_.PersonStatus.Owner;
2353         }
2354         else {
2355             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, 
2356 				type, true,workitem.key);
2357             return;
2358         }
2359         this.invoke_(this, url, type, workitem.key);
2360     },
2361 	/**
2362 	 * Internal method that handles fetch person mood requests
2363 	 * @internal
2364 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2365 	 * @param {Object} workitem
2366 	 */
2367     "FETCH_PERSON_MOOD": function FETCH_PERSON_MOOD(workitem) {
2368 
2369         var personId = workitem.parameters.id;
2370         var type = MyOpenSpace.RequestType.FETCH_PERSON_MOOD;
2371 		
2372         var url;
2373 
2374         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2375             url = this.dataRequest_.endPoint_.PersonMood.Viewer;
2376 
2377             if (this.isViewerDenied(type, workitem.key)) return;
2378         }
2379         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2380             url = this.dataRequest_.endPoint_.PersonMood.Owner;
2381         }
2382         else {
2383             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, 
2384 				type, true, workitem.key);
2385             return;
2386         }
2387         this.invoke_(this, url, type, workitem.key);
2388     },
2389 	/**
2390 	 * Internal method that handles fetch person friendship requests
2391 	 * @internal
2392 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2393 	 * @param {Object} workitem
2394 	 */
2395     "FETCH_PERSON_FRIENDSHIP": function FETCH_PERSON_FRIENDSHIP(workitem) {
2396         var personId = workitem.parameters.id;
2397         var key = workitem.parameters.key;
2398         var type = MyOpenSpace.RequestType.FETCH_PERSON_FRIENDSHIP;
2399 		
2400         var url;
2401 
2402         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2403             url = this.dataRequest_.endPoint_.Friendship.Viewer.replace("{PERSON_IDS}", key);
2404             if (this.isViewerDenied(type, workitem.key)) return;
2405         }
2406         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2407             url = this.dataRequest_.endPoint_.Friendship.Owner.replace("{PERSON_IDS}", key);
2408         }
2409         else {
2410             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, 
2411 				type, true, workitem.key);
2412             return;
2413         }
2414         this.invoke_(this, url, type, workitem.key);
2415 
2416     },
2417 	/**
2418 	 * Internal method that handles fetch people friendship requests
2419 	 * @internal
2420 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2421 	 * @param {Object} workitem
2422 	 */
2423     "FETCH_PEOPLE_FRIENDSHIP": function FETCH_PEOPLE_FRIENDSHIP(workitem) {
2424         var personId = workitem.parameters.id;
2425         var type = MyOpenSpace.RequestType.FETCH_PEOPLE_FRIENDSHIP;
2426 		
2427         var key = workitem.parameters.key;
2428         var url;
2429 
2430         if (key.constructor != Array) {
2431             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Key must be an array." }, 
2432 				type, true, workitem.key);
2433             return;
2434         }
2435         if (key.length === 0) {
2436             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, 
2437 				"errorMessage": "Key must be an array with at least one element." }, type, true, workitem.key);
2438             return;
2439         }
2440 		var idArray = [];
2441         for (var i = 0; i < key.length; i++) {
2442 			
2443 
2444 			var results = ('' + key[i]).match(/^(?:myspace\.com:)?(\d+)$/);
2445             if (results === null || results.length === 0) {
2446                 this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, 
2447 					"errorMessage": "Key user array element is not an user Id." },
2448 					type, true, workitem.key);
2449 					return;
2450             }
2451             idArray[i] = results[1];
2452         }
2453 
2454         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2455             url = this.dataRequest_.endPoint_.Friendship.Viewer.replace("{PERSON_IDS}", idArray.join(";"));
2456             if (this.isViewerDenied(type, workitem.key)) return;
2457         }
2458         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2459             url = this.dataRequest_.endPoint_.Friendship.Owner.replace("{PERSON_IDS}", idArray.join(";"));
2460         }
2461         else {
2462             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, 
2463 				type, true, workitem.key);
2464             return;
2465         }
2466         this.invoke_(this, url, type, workitem.key);
2467     },
2468 	/**
2469 	 * Internal method that handles fetch photo requests
2470 	 * @internal
2471 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2472 	 * @param {Object} workitem
2473 	 */
2474     "FETCH_PHOTO": function FETCH_PHOTO(workitem) {
2475         var personId = workitem.parameters.id;
2476         var type = MyOpenSpace.RequestType.FETCH_PHOTO;
2477 
2478         var url;
2479 
2480         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2481             url = this.dataRequest_.endPoint_.Photo.Viewer.replace("{PHOTO_ID}", workitem.parameters.photo_id);
2482             if (this.isViewerDenied(type, workitem.key)) return;
2483         }
2484         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2485             url = this.dataRequest_.endPoint_.Photo.Owner.replace("{PHOTO_ID}", workitem.parameters.photo_id);
2486         }
2487         else {
2488             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, 
2489 				type, true, workitem.key);
2490             return;
2491         }
2492         this.invoke_(this, url, type, workitem.key);
2493     },
2494 	/**
2495 	 * Internal method that handles fetch photos requests
2496 	 * @internal
2497 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2498 	 * @param {Object} workitem
2499 	 */
2500     "FETCH_PHOTOS": function FETCH_PHOTOS(workitem) {
2501         var personId = workitem.parameters.id;
2502         var albumId = workitem.parameters.album_id;
2503         var type = MyOpenSpace.RequestType.FETCH_PHOTOS;
2504         
2505         //test to see if the page request is in the form first = a(n) +1 where n = max;
2506         var first = workitem.parameters.first;
2507         var max = workitem.parameters.max;  
2508         var pagingError = this.getPagingError(first,max);
2509         if(pagingError !== "")
2510         {
2511             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": pagingError}, 
2512 				type, true, workitem.key);
2513             return;
2514         }
2515         var paging = this.mapPagingParams_(workitem.parameters.first, workitem.parameters.max);
2516         var url;
2517 
2518         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2519             if (null !== albumId) {
2520                 url = this.dataRequest_.endPoint_.AlbumPhotos.Viewer.replace("{ALBUM_ID}", albumId).replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2521             }
2522             else {
2523                 url = this.dataRequest_.endPoint_.Photos.Viewer.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2524             }
2525 
2526             if (this.isViewerDenied(type, workitem.key)) return;
2527         }
2528         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2529             if (null !== albumId) {
2530                 url = this.dataRequest_.endPoint_.AlbumPhotos.Owner.replace("{ALBUM_ID}", albumId).replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2531             }
2532             else {
2533                 url = this.dataRequest_.endPoint_.Photos.Owner.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2534             }
2535         }
2536         else {
2537             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, 
2538 				type, true, workitem.key);
2539             return;
2540         }
2541 
2542         this.invoke_(this, url, type, workitem.key);
2543     },
2544 	/**
2545 	 * Internal method that handles fetch album requests
2546 	 * @internal
2547 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2548 	 * @param {Object} workitem
2549 	 */
2550     "FETCH_ALBUM": function FETCH_ALBUM(workitem) {
2551         var personId = workitem.parameters.id;
2552         var type = MyOpenSpace.RequestType.FETCH_ALBUM;
2553 		
2554         var url;
2555 
2556         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2557             url = this.dataRequest_.endPoint_.Album.Viewer.replace("{ALBUM_ID}", workitem.parameters.album_id);
2558             if (this.isViewerDenied(type, workitem.key)) return;
2559         }
2560         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2561             url = this.dataRequest_.endPoint_.Album.Owner.replace("{ALBUM_ID}", workitem.parameters.album_id);
2562         }
2563         else {
2564             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported id" }, 
2565 				type, true, workitem.key);
2566             return;
2567         }
2568         this.invoke_(this, url, type, workitem.key);
2569     },
2570 	/**
2571 	 * Internal method that handles fetch people albums requests
2572 	 * @internal
2573 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2574 	 * @param {Object} workitem
2575 	 */
2576     "FETCH_ALBUMS": function FETCH_ALBUMS(workitem) {
2577         var personId = workitem.parameters.id;
2578         var type = MyOpenSpace.RequestType.FETCH_ALBUMS;
2579         //test to see if the page request is in the form first = a(n) +1 where n = max;
2580         var first = workitem.parameters.first;
2581         var max = workitem.parameters.max;  
2582         var pagingError = this.getPagingError(first,max);
2583         if(pagingError !== "")
2584         {
2585             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": pagingError}, 
2586 				type, true, workitem.key);
2587             return;
2588         }
2589         var paging = this.mapPagingParams_(workitem.parameters.first, workitem.parameters.max);
2590         var url;
2591 
2592 
2593         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2594             url = this.dataRequest_.endPoint_.Albums.Viewer.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2595 
2596             if (this.isViewerDenied(type, workitem.key)) return;
2597         }
2598         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2599             url = this.dataRequest_.endPoint_.Albums.Owner.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2600         }
2601         else {
2602             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported idSpec" }, 
2603 				type, true, workitem.key);
2604             return;
2605         }
2606         this.invoke_(this, url, type, workitem.key);
2607     },
2608 	/**
2609 	 * Internal method that handles fetch video requests
2610 	 * @internal
2611 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2612 	 * @param {Object} workitem
2613 	 */
2614     "FETCH_VIDEO": function FETCH_VIDEO(workitem) {
2615         var personId = workitem.parameters.id;
2616         var url;
2617         var type = MyOpenSpace.RequestType.FETCH_VIDEO;
2618 
2619         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2620             url = this.dataRequest_.endPoint_.Video.Viewer.replace("{VIDEO_ID}", workitem.parameters.video_id);
2621             if (this.isViewerDenied(type, workitem.key)) return;
2622         }
2623         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2624             url = this.dataRequest_.endPoint_.Video.Owner.replace("{VIDEO_ID}", workitem.parameters.video_id);
2625         }
2626         else {
2627             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported idSpec" }, 
2628 				type, true, workitem.key);
2629             return;
2630         }
2631         this.invoke_(this, url, type, workitem.key);
2632     },
2633 	/**
2634 	 * Internal method that handles fetch videos requests
2635 	 * @internal
2636 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2637 	 * @param {Object} workitem
2638 	 */
2639     "FETCH_VIDEOS": function FETCH_VIDEOS(workitem) {
2640         var personId = workitem.parameters.id;
2641         var type = MyOpenSpace.RequestType.FETCH_VIDEOS;
2642 		
2643         var first = workitem.parameters.first;
2644         var max = workitem.parameters.max;  
2645         var pagingError = this.getPagingError(first,max);
2646 
2647 		
2648         if(pagingError !== "")
2649         {
2650             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": pagingError},
2651 				type, true,  workitem.key);
2652             return;
2653         }
2654         var paging = this.mapPagingParams_(workitem.parameters.first, workitem.parameters.max);
2655         var url;
2656 
2657         if (personId === opensocial.IdSpec.PersonId.VIEWER) {
2658             url = this.dataRequest_.endPoint_.Videos.Viewer.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2659             if (this.isViewerDenied(type, workitem.key)) return;
2660         }
2661         else if (personId === opensocial.IdSpec.PersonId.OWNER) {
2662             url = this.dataRequest_.endPoint_.Videos.Owner.replace("{PAGE}", paging[0]).replace("{SIZE}", paging[1]);
2663         }
2664         else {
2665             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported idSpec" }, 
2666 				type, true, workitem.key);
2667             return;
2668         }
2669         this.invoke_(this, url, type, workitem.key);
2670     },
2671 	/**
2672 	 * Internal method that handles fetch person data requests
2673 	 * @internal
2674 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2675 	 * @param {Object} workitem
2676 	 */
2677     "FETCH_PERSON_DATA": function FETCH_PERSON_DATA(workitem) {
2678         var idSpec = idSpecMap(workitem.parameters.idSpec);
2679         var type = MyOpenSpace.RequestType.FETCH_PERSON_DATA;
2680 		
2681         if (typeof (idSpec.errorCode) !== 'undefined') {
2682             this.addResponseItem_(idSpec, type, true, workitem.key);
2683             return;
2684         }
2685 
2686         var keys = workitem.parameters.keys || "";
2687         var opt_params = workitem.parameters.opt_params;
2688         var getId = false;
2689         var requestId;
2690         var url;
2691 
2692         var group;
2693         var arrayError = false;
2694         if (keys === "*") {
2695             keys = "";
2696         }
2697         else if (keys.constructor === Array) {
2698             for (var i = 0; i < keys.length; i++) {
2699                 if (keys[i] === "" || keys[i] === "*") {
2700                     arrayError = true;
2701                     break;
2702                 }
2703             }
2704             keys = "/" + keys.join(';');
2705         }
2706         else {
2707             requestId = "_" + keys;
2708             keys = "/" + keys;
2709         }
2710 
2711         var pointer = this;
2712 
2713         if (idSpec === MyOpenSpace.IdSpecMapping_.VIEWER) {
2714             url = this.dataRequest_.endPoint_.PersonAppData.Viewer.replace("{KEYS}", keys);
2715             if (this.isViewerDenied(type, workitem.key)) return;
2716         }
2717         else if (idSpec === MyOpenSpace.IdSpecMapping_.VIEWER_FRIENDS) {
2718             url = this.dataRequest_.endPoint_.PersonAppData.ViewerFriends.replace("{KEYS}", keys);
2719             if (this.isViewerDenied(type, workitem.key)) return;
2720         }
2721         else if (idSpec === MyOpenSpace.IdSpecMapping_.OWNER) {
2722             group = MyOpenSpace.Group.OWNER_APP_DATA + fetchOwnerAppDataRequestId;
2723             url = this.dataRequest_.endPoint_.PersonAppData.Owner.replace("{KEYS}", keys);
2724         }
2725         else if (idSpec === MyOpenSpace.IdSpecMapping_.OWNER_FRIENDS) {
2726             url = this.dataRequest_.endPoint_.PersonAppData.OwnerFriends.replace("{KEYS}", keys);
2727         }
2728         else {
2729             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported idSpec" }, 
2730 				type, true, workitem.key);
2731             return;
2732         }
2733         if (arrayError) {
2734             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, 
2735 				"errorMessage": "Invalid key array element. Array can contain neither empty string nor '*'. " }, type, true, workitem.key);
2736             return;
2737         }
2738         this.invoke_(this, url, type, workitem.key, opt_params);
2739     },
2740 	/**
2741 	 * Internal method that handles update person data requests
2742 	 * @internal
2743 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2744 	 * @param {Object} workitem
2745 	 */
2746     "UPDATE_PERSON_DATA": function UPDATE_PERSON_DATA(workitem) {
2747         var idSpec = workitem.parameters.id;
2748         var type = MyOpenSpace.RequestType.UPDATE_PERSON_DATA;
2749 
2750         var url;
2751 				
2752         if (!validateAppDataKeyName(workitem.parameters.key)) { // bad key name
2753             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, 
2754 				"errorMessage": "AppData key names can only consist of alphanumerics, dots, dashes and underscores." }, type, true, workitem.key);
2755             return;
2756         }
2757         
2758         var getInvalidJsonErrorObject = function(){
2759             return { "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "AppData value must be valid JSON." };
2760         };
2761 
2762         //if it's an object, stringify it, then try to jsonify it
2763         if("object" === typeof(workitem.parameters.value)){
2764             workitem.parameters.value = gadgets.json.stringify(workitem.parameters.value);
2765             if(!gadgets.json.parse(workitem.parameters.value)) {
2766                 this.addResponseItem_(getInvalidJsonErrorObject(), workitem.parameters.key, true);
2767                 return;
2768             }
2769         }
2770         else if("string" === typeof(workitem.parameters.value)){
2771             if (!gadgets.json.parse(workitem.parameters.value)) {
2772                 this.addResponseItem_(getInvalidJsonErrorObject(), type, true, workitem.parameters.key);
2773                 return;
2774             }
2775         }
2776         else{
2777             this.addResponseItem_(getInvalidJsonErrorObject(), type, true, workitem.parameters.key);
2778             return;
2779         }
2780 
2781 
2782 
2783         this.dataRequest_.params = workitem.parameters.key + "=" + workitem.parameters.value;
2784         if (idSpec === opensocial.IdSpec.PersonId.VIEWER) {
2785             url = this.dataRequest_.endPoint_.PersonAppData.Viewer.replace("{KEYS}", "");
2786 
2787             if (this.isViewerDenied(type, workitem.key)) return;
2788         }
2789         else {
2790             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "errorMessage": "Unsupported idSpec" }, 
2791 				type, true, workitem.key);
2792             return;
2793         }
2794         this.invoke_(this, url, type, workitem.key);
2795     },
2796 	/**
2797 	 * Internal method that handles remove person data requests
2798 	 * @internal
2799 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2800 	 * @param {Object} workitem
2801 	 */
2802     "REMOVE_PERSON_DATA": function REMOVE_PERSON_DATA(workitem) {
2803         var keys = workitem.parameters.keys || "";
2804         var type = MyOpenSpace.RequestType.REMOVE_PERSON_DATA;
2805 		
2806         var requestId;
2807         var url;
2808 
2809 
2810         if (keys === "*" || keys === "") {
2811             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, 
2812 				"errorMessage": "You must supply a key or an array of keys to remove, note that * isn't implemented." }, 
2813 				type, true, workitem.key);
2814             return;
2815         }
2816         else if (keys.constructor === Array) {
2817             keys = "/" + keys.join(';');
2818         }
2819         else {
2820             requestId = "_" + keys;
2821             keys = "/" + keys;
2822         }
2823 
2824         var id = workitem.parameters.id;
2825         var pointer = this;
2826 
2827         if (id === opensocial.IdSpec.PersonId.VIEWER) {
2828             url = this.dataRequest_.endPoint_.PersonAppData.Viewer.replace("{KEYS}", keys);
2829             if (this.isViewerDenied(type, workitem.key)) return;
2830         }
2831         else {
2832             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "errorMessage": "Unsupported idSpec" }, 
2833 				type, true, workitem.key);
2834             return;
2835         }
2836         this.invoke_(this, url, type, workitem.key);
2837     },
2838 	/**
2839 	 * Internal method that handles fetch activities requests
2840 	 * @internal
2841 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2842 	 * @param {Object} workitem
2843 	 */
2844     "FETCH_ACTIVITIES": function FETCH_ACTIVITIES(workitem) {
2845         var idSpec = idSpecMap(workitem.parameters.idSpec);
2846         var type = MyOpenSpace.RequestType.FETCH_ACTIVITIES;
2847 
2848         if (typeof (idSpec.errorCode) !== 'undefined') {
2849             this.addResponseItem_(idSpec, type, true, workitem.key);
2850             return;
2851         }
2852         
2853         var url;
2854 
2855         if (idSpec === MyOpenSpace.IdSpecMapping_.VIEWER) {
2856             url = this.dataRequest_.endPoint_.Activities.Viewer;
2857             if (this.isViewerDenied(type, workitem.key)) return;
2858         }
2859         else if (idSpec === MyOpenSpace.IdSpecMapping_.OWNER) {
2860             url = this.dataRequest_.endPoint_.Activities.Owner;
2861         }
2862         else if (idSpec === MyOpenSpace.IdSpecMapping_.VIEWER_FRIENDS) {
2863             url = this.dataRequest_.endPoint_.Activities.ViewerFriends;
2864             if (this.isViewerDenied(type, workitem.key)) return;
2865         }
2866         else if (idSpec === MyOpenSpace.IdSpecMapping_.OWNER_FRIENDS) {
2867             url = this.dataRequest_.endPoint_.Activities.OwnerFriends;
2868         }
2869         else {
2870             this.addResponseItem_({ "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Unsupported idSpec" }, 
2871 				type, true, workitem.key);
2872             return;
2873         }
2874         this.invoke_(this, url, type, workitem.key);
2875         //this.addResponseItem_({"errorCode":opensocial.ResponseItem.Error.NOT_IMPLEMENTED,"errorMessage":"Fetch activities not implemented."},"FETCH_ACTIVITIES",true);
2876     },
2877     /**
2878 	 * Internal utility method that handles verify pagin values
2879 	 * @internal
2880 	 * @memberOf MyOpenSpace.DataRequest.RequestActions_
2881      * @param {Object} first
2882      * @param {Object} max
2883      */
2884     getPagingError : function(first,max)
2885     { 
2886         if(isNaN(first) && first !=="")
2887         {
2888             return ("Paging Error: first must be an integer");
2889         }
2890 
2891         if(isNaN(max) && max !=="")
2892         {
2893             return ("Paging Error: max must be an integer");
2894         }
2895 
2896         if(first <=0 && first !=="")
2897         {
2898             return ("Paging Error: first must be a positive integer greater than zero");;
2899         }
2900          
2901         if(max <= 0 && max !=="")
2902         {
2903             return ("Paging Error: max must be a positive integer greater than zero");;
2904         }
2905         
2906         if(((first%max !==1) && max != 1 && !(first === "" ||  max === "")))
2907         {
2908             return ("Paging Error: paging data must be in the form of max = n and first = x(n) + 1 where x is any positive integer. i.e max=5, first= 2(5)+1 =11");
2909         }
2910 
2911         return "";
2912     },
2913     
2914     mapPagingParams_: function(first, max) {
2915         if (first === null || typeof (first) === "undefined" || first < 1) first = 1;
2916         if (max === null || typeof (max) === "undefined" || max < 1 || max > MyOpenSpace.DefaultPageSize) max = MyOpenSpace.DefaultPageSize;
2917 
2918         // page is not 0 indexed, it starts at 1	    
2919         var page_size = max;
2920         var page = Math.floor(first / page_size);
2921         if((first%page_size) !== 0) 
2922             page += 1;
2923         return [page, page_size];
2924     },
2925     invoke_: function(requestActions, url, type, opt_key, opt_params) {
2926         var callback = function(user, errored, opt_key) {
2927             requestActions.addResponseItem_(user, type, errored, opt_key);
2928         };
2929         var dataRequestAction = requestActions.dataRequest_;
2930 		var method = "GET";
2931 		if (type === MyOpenSpace.RequestType.UPDATE_PERSON_DATA) method = "PUT";
2932 		if (type === MyOpenSpace.RequestType.REMOVE_PERSON_DATA) method = "DELETE";
2933 
2934         dataRequestAction.method = method;
2935         dataRequestAction.endPoint = url;
2936         if (method !== "PUT") {
2937             dataRequestAction.params = {};
2938         }
2939 
2940         if (opt_params && opt_params.useCache) {
2941             if (APICache.isCached(dataRequestAction.endPoint)) {
2942                 var lifetime = opt_params.refreshInterval || 0;
2943                 if (opt_params.refreshInterval > 0) {
2944                     lifetime = opt_params.refreshInterval * 1000;
2945                 }
2946                 if (!APICache.isExpired(dataRequestAction.endPoint, lifetime)) {
2947                     callback(APICache.retrieve(dataRequestAction.endPoint), false, opt_key);
2948                     return;
2949                 }
2950             }
2951         }
2952 
2953         MyOpenSpace.Ajax.sendRequest(dataRequestAction, type, completed_, errored_, true, opt_key);
2954         function completed_(response, type, opt_key) {
2955             var error = null;
2956             var result = null;
2957             var map = new MyOpenSpace.DataMapper_();
2958 			if (type === MyOpenSpace.RequestType.REMOVE_PERSON_DATA || type === MyOpenSpace.RequestType.UPDATE_PERSON_DATA ){
2959                 callback(null, false, opt_key);
2960                 return;
2961             }
2962 			else if(type === MyOpenSpace.RequestType.FETCH_PERSON_DATA){
2963 				var encoding = opensocial.EscapeType.HTML_ESCAPE;
2964                 if (typeof (opt_params) !== "undefined") {
2965                     encoding = opt_params[opensocial.DataRequest.DataRequestFields.ESCAPE_TYPE];
2966                     if (typeof (opt_params) === "undefined") {
2967                         encoding = opensocial.EscapeType.HTML_ESCAPE;
2968                     }
2969                 }
2970                 result = map.mapData[MyOpenSpace.RequestType.FETCH_PERSON_DATA](response, encoding);
2971 			}
2972 			else{
2973 				result = map.mapData[type](response);
2974 			}
2975             if (null === result) {
2976                 callback({ "errorCode": opensocial.ResponseItem.Error.INTERNAL_ERROR, "errorMessage": "Unable to map entity" }, true, opt_key);
2977             } else {
2978                 // short circuit for only cachable types here
2979                 APICache.add(dataRequestAction.endPoint, result);
2980                 callback(result, false, opt_key); //callback:pointer.addResponseItem_(user, 'VIEWER_FRIENDS');
2981             }
2982         }
2983 
2984         function errored_(response, opt_key) {
2985             callback(response, true, opt_key);
2986         }
2987 
2988     },
2989     
2990     
2991     addResponseItem_: function(item, type, errored, opt_key) {
2992         var ri;
2993         if (errored) {
2994             //this._addError(item,key);
2995             ri = opensocial.Container.get().newResponseItem(this.dataRequest_, null, item.errorCode, item.errorMessage); // TODO: what to send in for data?
2996             this.errored_ = true;
2997         }
2998         else
2999             ri = opensocial.Container.get().newResponseItem(this.dataRequest_, item, "", "");
3000 
3001 		var responseKey;
3002 		if (typeof(opt_key) === 'undefined' || opt_key === null){
3003 			responseKey = type + this.getRequestId_(type);
3004 		}
3005 		else{
3006 			responseKey = opt_key;
3007 		}
3008         this.dataResponseValues_[responseKey] = ri;
3009         this.itemsProcessed_++;
3010 
3011         //check to see if we're all done		
3012         if (this.itemsProcessed_ === this.dataRequest_.requestObjectCount_) {
3013             this.dataRequest_.ReqestIdTable_ = null;
3014             this.dataRequest_.requestObjectCount_ = 0;
3015             this.dataRequest_.requestObjects_ = new MyOpenSpace.Hash();
3016             this.dataRequest_.busy_ = false;
3017             this.dataRequest_.allRequestsCompleteCallback_(opensocial.Container.get().newDataResponse(this.dataResponseValues_, this.errored_));
3018         }
3019         else if (this.dataRequest_.requestProcessor_.executionModel_ === MyOpenSpace.RequestProcessor_.ExecutionModel_.SERIAL)
3020             this.dataRequest_.requestProcessor_.startProcessing();
3021     }
3022 };
3023 /**
3024  * @constructor MyOpenSpace.EndPoint - namespace definition only
3025  */
3026 if (typeof(MyOpenSpace.EndPoint) == "undefined") MyOpenSpace.EndPoint = {};
3027 
3028 /**
3029  * @class
3030  * @name MyOpenSpace.EndPoint
3031  * @internal
3032  * Represents myspace's api endpoints, which are secured outside and around the container.
3033  * Tokenization is to be removed once tokens are implemented.
3034  */
3035 MyOpenSpace.EndPoint = {
3036     /**
3037     * @internal
3038     * @memberOf MyOpenSpace.EndPoint
3039     * Top level Domain for api endpoints.
3040     */
3041     Server: {
3042         /**
3043         * @internal
3044         * @memberOf MyOpenSpace.EndPoint.Server
3045         * Domain used for testing locally.
3046         */
3047         Localhost: "http://localhost",
3048 
3049         /**
3050         * @internal
3051         * @memberOf MyOpenSpace.EndPoint.Server
3052         * Domain used for testing locally.
3053         */
3054         Development: "http://local-api.myspace.com",
3055 
3056         /**
3057         * @internal
3058         * @memberOf MyOpenSpace.EndPoint.Server
3059         * Domain used for running apps on production.
3060         */
3061         Production: "http://{SUBDOMAIN}api.msappspace.com"
3062     },
3063     ServerApiMySpace:{
3064 		/**
3065         * @internal
3066         * @memberOf MyOpenSpace.EndPoint.ServerApiMySpace
3067         * Domain used for testing locally.
3068         */
3069         Localhost: "http://localhost",
3070 		/**
3071         * @internal
3072         * @memberOf MyOpenSpace.EndPoint.ServerApiMySpace
3073         * Domain used for testing locally.
3074         */
3075         Development: "http://local-api.myspace.com",
3076         /**
3077         * @internal
3078         * @memberOf MyOpenSpace.EndPoint.ServerApiMySpace
3079         * Domain used for running apps on production.
3080         */
3081         Production: "http://api.myspace.com"
3082     },
3083     /**
3084     * @internal
3085     * @memberOf MyOpenSpace.EndPoint
3086     * RESTFUL endpoint for People
3087     */
3088     People: {
3089         Viewer: "/api-v2.svc/json/people/@me/@self",
3090         Owner: "/api-v2.svc/json/people/{PERSON_ID}/@self",
3091 //		ID: "/api-v2.svc/json/people/{PERSON_ID}/@self", 
3092 		ID: "/opensocial-api-v1.svc/JSON/opensocial/users/{PERSON_ID}",
3093         ViewerFriends: "/api-v2.svc/json/people/@me/@friends",
3094         OwnerFriends: "/api-v2.svc/json/people/{PERSON_ID}/@friends"
3095         
3096     },
3097     /**
3098     * @internal
3099     * @memberOf MyOpenSpace.EndPoint
3100     * RESTFUL endpoint for People
3101     */
3102     Person: {
3103         Viewer: "/api-v2.svc/json/people/@me/@self",
3104         Owner: "/api-v2.svc/json/people/{PERSON_ID}/@self",
3105 		ID: "/opensocial-api-v1.svc/JSON/opensocial/users/{PERSON_ID}"
3106     },
3107     /**
3108     * @internal
3109     * @memberOf MyOpenSpace.EndPoint
3110     * RESTFUL endpoint for Indicators
3111     */
3112     Indicators: {
3113         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/indicators",
3114         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/indicators"
3115     },
3116     /**
3117     * @internal
3118     * @memberOf MyOpenSpace.EndPoint
3119     * RESTFUL endpoint for friendship status
3120     */
3121     Friendship: {
3122         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/friendship/{PERSON_IDS}",
3123         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/friendship/{PERSON_IDS}"
3124     },
3125     /**
3126     * @internal
3127     * @memberOf MyOpenSpace.EndPoint
3128     * RESTFUL endpoint for status
3129     */
3130     PersonStatus: {
3131         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/status",
3132         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/status"
3133     },
3134     /**
3135     * @internal
3136     * @memberOf MyOpenSpace.EndPoint
3137     * RESTFUL endpoint for mood
3138     */
3139     PersonMood: {
3140         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/mood",
3141         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/mood"
3142     },
3143     /**
3144     * @internal
3145     * @memberOf MyOpenSpace.EndPoint
3146     * RESTFUL endpoint for Albums
3147     */
3148     Albums: {
3149         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/albums",
3150         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/albums"
3151     },
3152     /**
3153     * @internal
3154     * @memberOf MyOpenSpace.EndPoint
3155     * RESTFUL endpoint for Album
3156     */
3157     Album: {
3158         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/albums/{ALBUM_ID}",
3159         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/albums/{ALBUM_ID}"
3160     },
3161     /**
3162     * @internal
3163     * @memberOf MyOpenSpace.EndPoint
3164     * RESTFUL endpoint for Videos
3165     */
3166     Videos: {
3167         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/videos",
3168         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/videos"
3169     },
3170     /**
3171     * @internal
3172     * @memberOf MyOpenSpace.EndPoint
3173     * RESTFUL endpoint for Video
3174     */
3175     Video: {
3176         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/videos/{VIDEO_ID}",
3177         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/videos/{VIDEO_ID}"
3178     },
3179     /**
3180     * @internal
3181     * @memberOf MyOpenSpace.EndPoint
3182     * RESTFUL endpoint for Photos
3183     */
3184     Photos: {
3185         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/photos",
3186         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/photos"
3187     },
3188     /**
3189     * @internal
3190     * @memberOf MyOpenSpace.EndPoint
3191     * RESTFUL endpoint for Photos from a particular album
3192     */
3193     AlbumPhotos: {
3194         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/albums/{ALBUM_ID}/photos",
3195         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/albums/{ALBUM_ID}/photos"
3196     },
3197     /**
3198     * @internal
3199     * @memberOf MyOpenSpace.EndPoint
3200     * RESTFUL endpoint for Photo
3201     */
3202     Photo: {
3203         Viewer: "/opensocial-api-v1.svc/JSON/opensocial/{VIEWER}/photos/{PHOTO_ID}",
3204         Owner: "/opensocial-api-v1.svc/JSON/opensocial/{OWNER}/photos/{PHOTO_ID}"
3205     },
3206     /**
3207     * @internal
3208     * @memberOf MyOpenSpace.EndPoint
3209     * JSONP endpoint for permissions
3210     */
3211     Permissions: {
3212         Viewer: "/v1/users/{PERSON_ID}/apps.jsnp",
3213         Owner: "/v1/users/{PERSON_ID}/apps.jsnp"
3214     },
3215     /**
3216     * @internal
3217     * @memberOf MyOpenSpace.EndPoint
3218     * RESTFUL endpoint for activities
3219     */
3220     Activities: {
3221         Viewer: "/api-v2.svc/json/activities/@me/@self",
3222         Owner: "/api-v2.svc/json/activities/{PERSON_ID}/@self",
3223         ViewerFriends: "/api-v2.svc/json/activities/@me/@friends",
3224         OwnerFriends: "/api-v2.svc/json/activities/{PERSON_ID}/@friends",
3225         ViewerInsert: "/api-v2.svc/json/activities/@me/@self"
3226     },
3227     /**
3228     * @internal
3229     * @memberOf MyOpenSpace.EndPoint
3230     * RESTFUL endpoint for Data Persistence
3231     */
3232     PersonAppData: {
3233         Viewer: "/opensocial-api-v1.svc/XML/opensocial/{VIEWER}/appdata{KEYS}",
3234         ViewerFriends: "/opensocial-api-v1.svc/XML/opensocial/{VIEWER}/friends/appdata{KEYS}",
3235         Owner: "/opensocial-api-v1.svc/XML/opensocial/{OWNER}/appdata{KEYS}",
3236         OwnerFriends: "/opensocial-api-v1.svc/XML/opensocial/{OWNER}/friends/appdata{KEYS}",
3237         Global: "/opensocial-api-v1.svc/XML/opensocial/appdata/global{KEYS}"
3238     },
3239     /**
3240     * @internal
3241     * @memberOf MyOpenSpace.EndPoint
3242     * Tokenized query string containing common params
3243     */
3244     CommonQueryString: "opensocial_surface={OS_MODE}&ts={TIME_STAMP}",
3245     /**
3246     * @internal
3247     * @memberOf MyOpenSpace.EndPoint
3248     * Tokenized query string containing detail type used in Person/Profile endpoint
3249     */
3250     DetailQueryString: "&fields={DETAIL_TYPE}",
3251     /**
3252     * @internal
3253     * @memberOf MyOpenSpace.EndPoint
3254     * Tokenized query string containing paging parameters
3255     */
3256     PagingQueryString: "&page={PAGE}&page_size={SIZE}",
3257 	/**
3258     * @internal
3259     * @memberOf MyOpenSpace.EndPoint
3260     * Tokenized query string containing paging parameters for v2
3261     */
3262     PagingQueryStringV2: "&startIndex={PAGE}&count={SIZE}",
3263     /**
3264     * @internal
3265     * @memberOf MyOpenSpace.EndPoint
3266     * Tokenized query string containing filters: top, all, app, online -- used for Friends and TopFriends endpoints
3267     */
3268     FilterQueryString: "&filterBy={FILTER}",
3269     /**
3270     * @internal
3271     * @memberOf MyOpenSpace.EndPoint
3272     * Tokenized query string containing filters: top, all, app, online -- used for Friends and TopFriends endpoints
3273     */
3274     SortQueryString: "&sortBy={SORT_BY}&sortOrder={SORT_ORDER}",	
3275     /**
3276     * @internal
3277     * @memberOf MyOpenSpace.EndPoint
3278     * Tokenized query string containing the format for v2 endpoints
3279     */
3280     FormatQueryString: "&format=JSON",
3281     /**
3282     * @internal
3283     * @param {MyOpenSpace.EndPoint} endPoint The MyOpenSpace.EndPoint object to populate
3284     * @param {opensocial.DataRequest.PersonId} userInfo Should be an enum containing VIEWER and OWNER
3285     * @param {MyOpenSpace.Formats} format Currently being forced to JSON, as opposed to XML
3286     * @param {MyOpenSpace.OperationModes} operationMode The domain thats being used in this app
3287     * @param {String} osToken The authorization token for this request
3288     * @param {opensocial.Surface} osMode The surface the app is being rendered on
3289     * Inserts tokens into the various tokenized endpoint URIs
3290     */
3291     Tokenized: function(endPoint, userInfo, osToken, osMode) {
3292         var server;
3293         var serverMySpace;
3294 
3295 
3296         var subdomain ="";
3297 	    var domainParts = location.hostname.split('.'); 
3298 	    var numericExpression = /^[0-9]+$/;
3299 	    if(domainParts[0].match(numericExpression))
3300 	    {
3301             subdomain = domainParts[0] + ".";
3302         } 
3303 
3304         if (location.hostname.match(/^localhost/)) {
3305             server = endPoint.Server.Localhost;
3306             serverMySpace = endPoint.ServerApiMySpace.Localhost;
3307         }
3308         else if (location.hostname.match(/^local-/)) {
3309             server = endPoint.Server.Development;
3310             serverMySpace = endPoint.ServerApiMySpace.Development;
3311         }
3312         else 
3313         {
3314             server = endPoint.Server.Production;
3315             serverMySpace = endPoint.ServerApiMySpace.Production;
3316         }
3317         
3318         server = server.replace("{SUBDOMAIN}",subdomain);
3319         
3320         var timeStamp = new Date().getTime();
3321 
3322         var params = gadgets.views.getParams();
3323         var ownerId = MyOpenSpace.PrefetchParameters.getParam("ownerid");
3324         if ("undefined" === typeof (ownerId) && params) {
3325             ownerId = params.ownerId;
3326         }
3327 
3328         endPoint.CommonQueryString = endPoint.CommonQueryString.replace("{OS_MODE}", osMode.getName()).replace("{TIME_STAMP}", timeStamp);
3329 
3330         endPoint.Person.Viewer = server + endPoint.Person.Viewer                                + "?" + endPoint.CommonQueryString + endPoint.DetailQueryString + endPoint.FormatQueryString;
3331         endPoint.Person.Owner  = server + endPoint.Person.Owner.replace("{PERSON_ID}", ownerId) + "?" + endPoint.CommonQueryString + endPoint.DetailQueryString + endPoint.FormatQueryString;
3332 		
3333 		endPoint.People.ID     = server + endPoint.People.ID                                                  + "?" + endPoint.CommonQueryString + endPoint.FormatQueryString;
3334         endPoint.People.Viewer = server + endPoint.People.Viewer                                              + "?" + endPoint.CommonQueryString + endPoint.FormatQueryString;
3335         endPoint.People.Owner  = server + endPoint.People.Owner.replace("{PERSON_ID}", ownerId)               + "?" + endPoint.CommonQueryString + endPoint.FormatQueryString;
3336         endPoint.People.ViewerFriends = server + endPoint.People.ViewerFriends                                + "?" + endPoint.CommonQueryString + endPoint.PagingQueryStringV2 + endPoint.FormatQueryString;
3337         endPoint.People.OwnerFriends  = server + endPoint.People.OwnerFriends.replace("{PERSON_ID}", ownerId) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryStringV2 + endPoint.FormatQueryString;
3338         
3339 		
3340         endPoint.Indicators.Viewer = server + endPoint.Indicators.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3341         endPoint.Indicators.Owner = server + endPoint.Indicators.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3342         endPoint.PersonStatus.Viewer = server + endPoint.PersonStatus.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3343         endPoint.PersonStatus.Owner = server + endPoint.PersonStatus.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3344         endPoint.PersonMood.Viewer = server + endPoint.PersonMood.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3345         endPoint.PersonMood.Owner = server + endPoint.PersonMood.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3346         endPoint.Friendship.Viewer = server + endPoint.Friendship.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3347         endPoint.Friendship.Owner = server + endPoint.Friendship.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3348 		
3349 
3350 		
3351         endPoint.Albums.Viewer = server + endPoint.Albums.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3352         endPoint.Albums.Owner = server + endPoint.Albums.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3353         endPoint.Album.Viewer = server + endPoint.Album.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3354         endPoint.Album.Owner = server + endPoint.Album.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3355         endPoint.Videos.Viewer = server + endPoint.Videos.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3356         endPoint.Videos.Owner = server + endPoint.Videos.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3357         endPoint.Video.Viewer = server + endPoint.Video.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3358         endPoint.Video.Owner = server + endPoint.Video.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3359         endPoint.Photos.Viewer = server + endPoint.Photos.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3360         endPoint.Photos.Owner = server + endPoint.Photos.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3361         endPoint.Photo.Viewer = server + endPoint.Photo.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3362         endPoint.Photo.Owner = server + endPoint.Photo.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3363         endPoint.AlbumPhotos.Viewer = server + endPoint.AlbumPhotos.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3364         endPoint.AlbumPhotos.Owner = server + endPoint.AlbumPhotos.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString + endPoint.PagingQueryString;
3365         endPoint.Activities.Viewer = server + endPoint.Activities.Viewer + "?" + endPoint.CommonQueryString,
3366         endPoint.Activities.Owner = server + endPoint.Activities.Owner.replace("{PERSON_ID}", ownerId) + "?" + endPoint.CommonQueryString,
3367         endPoint.Activities.ViewerFriends = server + endPoint.Activities.ViewerFriends.replace("{PERSON_ID}", ownerId) + "?" + endPoint.CommonQueryString,
3368         endPoint.Activities.OwnerFriends = server + endPoint.Activities.OwnerFriends.replace("{PERSON_ID}", ownerId) + "?" + endPoint.CommonQueryString,
3369         endPoint.Activities.ViewerInsert = server + endPoint.Activities.ViewerInsert.replace("{PERSON_ID}", ownerId) + "?" + endPoint.CommonQueryString,
3370         endPoint.PersonAppData.Viewer = server + endPoint.PersonAppData.Viewer.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3371         endPoint.PersonAppData.ViewerFriends = server + endPoint.PersonAppData.ViewerFriends.replace("{VIEWER}", userInfo.VIEWER) + "?" + endPoint.CommonQueryString;
3372         endPoint.PersonAppData.Owner = server + endPoint.PersonAppData.Owner.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3373         endPoint.PersonAppData.OwnerFriends = server + endPoint.PersonAppData.OwnerFriends.replace("{OWNER}", userInfo.OWNER) + "?" + endPoint.CommonQueryString;
3374         endPoint.PersonAppData.Global = server + endPoint.PersonAppData.Global + "?" + endPoint.CommonQueryString;
3375         endPoint.Permissions.Viewer = serverMySpace + endPoint.Permissions.Viewer;
3376         endPoint.Permissions.Owner = serverMySpace + endPoint.Permissions.Owner;
3377 
3378         return endPoint;
3379     }
3380 };
3381 /**
3382  * MySpace extension of the opensocial.Environment object.
3383  * @constructor
3384  * @param {Array<string>} supportedPostToTargets A string array of supported PostTo targets
3385  * @param {MyOpenSpace.Application} app An object representing the current application executing in the container
3386  * @class
3387  * @name MyOpenSpace.Environment
3388  * @private
3389  * @internal
3390  */
3391 MyOpenSpace.Environment = function(supportedPostToTargets, app){
3392 	 var supportedMapped = [];
3393      for (var i in supportedPostToTargets) {
3394         switch (supportedPostToTargets[i]){
3395 			case MyOpenSpace.PostTo.Targets.SEND_MESSAGE:
3396 				supportedMapped.push(opensocial.Message.Type.PRIVATE_MESSAGE);
3397 				break;
3398 			case MyOpenSpace.PostTo.Targets.BULLETINS:
3399 				supportedMapped.push(opensocial.Message.Type.NOTIFICATION);
3400 				break;
3401 			case MyOpenSpace.PostTo.Targets.COMMENTS:
3402 				supportedMapped.push(opensocial.Message.Type.PUBLIC_MESSAGE);
3403 				break;
3404 			default:
3405 				supportedMapped.push(supportedPostToTargets[i]);
3406 				break;
3407 		}
3408     }
3409     this.supportedPostToTargets = supportedMapped;
3410 	this.currentApplication = app;
3411 };
3412 
3413 /**
3414  * Accessor for the supportedPostToTargets array
3415  * @memberOf MyOpenSpace.Environment
3416  * @private
3417  */
3418 MyOpenSpace.Environment.prototype.getSupportedPostToTargets = function(){
3419     return this.supportedPostToTargets;
3420 };
3421 /**
3422  * Accessor for the current Application executing in the environment
3423  * @memberOf MyOpenSpace.Environment
3424  * @private
3425  */
3426 MyOpenSpace.Environment.prototype.getApplication = function(){
3427     return this.currentApplication;
3428 };
3429 
3430 
3431 
3432 /**
3433  * The types of extended objects in this container.
3434  * @static
3435  * @class
3436  * @name MyOpenSpace.Environment.ObjectType
3437  */
3438 MyOpenSpace.Environment.ObjectType = {
3439     /**
3440      * @member MyOpenSpace.Environment.ObjectType
3441      */
3442     VIDEO : "VIDEO",
3443     /**
3444      * @member MyOpenSpace.Environment.ObjectType
3445      */
3446     PHOTO : "PHOTO",
3447     /**
3448      * @member MyOpenSpace.Environment.ObjectType
3449      */
3450     ALBUM : "ALBUM",
3451     /**
3452      * @member MyOpenSpace.Environment.ObjectType
3453      */
3454     PERSON : "PERSON"
3455 };/**
3456  * RSS Support methods
3457  * @private
3458  */
3459  if (typeof(MyOpenSpace.Feed) == "undefined") MyOpenSpace.Feed = { "Supported" : "RSS2.0", RSS2 : {} };
3460  MyOpenSpace.Feed.RSS2 = {
3461     Channel : function (xmlFeed, summaryOnly, numEntries) {
3462         this.title;
3463         this.link;
3464         this.description;
3465           this.language;
3466             this.copyright;
3467             this.managingEditor;
3468             this.webMaster;
3469             this.pubDate;
3470             this.lastBuildDate;
3471             this.generator;
3472             this.docs;
3473             this.ttl;
3474             this.rating;
3475         
3476             var chanElement = xmlFeed.getElementsByTagName("channel")[0];
3477             var properties = new Array("title", "link", "description");
3478             var tmpElement = null;
3479             for (var i=0; i<properties.length; i++)
3480             {
3481                 tmpElement = chanElement.getElementsByTagName(properties[i])[0];
3482                 if (tmpElement!= null)
3483                     this[properties[i]]=tmpElement.childNodes[0].nodeValue;
3484             }
3485     
3486             numEntries = numEntries || 3; //default as in opensocialreference
3487          
3488 
3489             /*optional object properties*/
3490             this.category;
3491             this.image;
3492             if (!summaryOnly) {
3493                 this.items = new Array();
3494 //                var chanElement = xmlFeed.getElementsByTagName("channel")[0];
3495                 var itemElements = xmlFeed.getElementsByTagName("item");
3496                 numEntries = (numEntries < itemElements.length) ? numEntries : itemElements.length;
3497                 for (var i=0; i<numEntries; i++)
3498                 {
3499                     Item = new MyOpenSpace.Feed.RSS2.Item(itemElements[i]);
3500                     this.items.push(Item);
3501                 }
3502             }
3503             var properties = ["title", "link", "description", "language", "copyright", "managingEditor", "webMaster", "pubDate", "lastBuildDate", "generator", "docs", "ttl", "rating"];
3504             var tmpElement = null;
3505             for (var i=0; i<properties.length; i++)
3506             {
3507                 tmpElement = chanElement.getElementsByTagName(properties[i])[0];
3508                 if (tmpElement!= null)
3509                     this[properties[i]] =tmpElement.childNodes[0].nodeValue;
3510             }
3511 
3512             this.category = new MyOpenSpace.Feed.RSS2.Category(chanElement.getElementsByTagName("category")[0]);
3513             this.image = new MyOpenSpace.Feed.RSS2.Image(chanElement.getElementsByTagName("image")[0]);
3514         
3515     },
3516     Category : function(categoryNode)
3517     {
3518         if (categoryNode == null) {
3519             this.domain = null;
3520             this.value = null;
3521         } else {
3522             this.domain = categoryNode.getAttribute("domain");
3523             this.value = categoryNode.childNodes[0].nodeValue;
3524         }
3525     },
3526     Image : function(imgElement)
3527     {
3528         if (imgElement == null) {
3529             this.url = null;
3530             this.link = null;
3531             this.width = null;
3532             this.height = null;
3533             this.description = null;
3534         } else {
3535             imgAttribs = ["url","title","link","width","height","description"];
3536             for (var i=0; i<imgAttribs.length; i++)
3537                 if (imgElement.getAttribute(imgAttribs[i]) != null)
3538                     this[imgAttribs[i]] = imgElement.getAttribute(imgAttribs[i]);
3539         }
3540     },
3541     Item : function(itemxml)
3542     {
3543         /*required*/
3544         this.title;
3545         this.link;
3546         this.description;
3547 
3548         /*optional*/
3549         this.author;
3550         this.comments;
3551         this.pubDate;
3552         this.category;
3553         this.enclosure;
3554         this.guid;
3555         this.source;
3556 
3557         var properties = ["title", "link", "description", "author", "comments", "pubDate"];
3558         var tmpElement = null;
3559         for (var i=0; i<properties.length; i++)
3560         {
3561             tmpElement = itemxml.getElementsByTagName(properties[i])[0];
3562             if (tmpElement != null)
3563                 this[properties[i]] = tmpElement.childNodes[0].nodeValue;
3564         }
3565 
3566         this.category = new MyOpenSpace.Feed.RSS2.Category(itemxml.getElementsByTagName("category")[0]);
3567         this.enclosure = new MyOpenSpace.Feed.RSS2.Enclosure(itemxml.getElementsByTagName("enclosure")[0]);
3568         this.guid = new MyOpenSpace.Feed.RSS2.Guid(itemxml.getElementsByTagName("guid")[0]);
3569         this.source = new MyOpenSpace.Feed.RSS2.Source(itemxml.getElementsByTagName("source")[0]);
3570     },
3571     Enclosure : function(encElement)
3572     {
3573         if (encElement == null) {
3574             this.url = null;
3575             this.length = null;
3576             this.type = null;
3577         } else {
3578             this.url = encElement.getAttribute("url");
3579             this.length = encElement.getAttribute("length");
3580             this.type = encElement.getAttribute("type");
3581         }
3582     },
3583     Guid : function(guidElement)
3584     {
3585         if (guidElement == null) {
3586             this.isPermaLink = null;
3587             this.value = null;
3588         } else {
3589             this.isPermaLink = guidElement.getAttribute("isPermaLink");
3590             this.value = guidElement.childNodes[0].nodeValue;
3591         }
3592     },
3593     Source : function(srcElement)
3594     {
3595         if (srcElement == null) {
3596             this.url = null;
3597             this.value = null;
3598         } else {
3599             this.url = srcElement.getAttribute("url");
3600             this.value = srcElement.childNodes[0].nodeValue;
3601         }
3602     }
3603 };/**
3604  * A class representing an FriendshipStatus.
3605  * @constructor
3606  * @private
3607  */
3608 MyOpenSpace.Friendship = function() {};
3609 
3610 /**
3611  * The fields for MyOpenSpace.Friendship
3612  * @class
3613  * @name MyOpenSpace.Friendship.Field
3614  * @static
3615  */
3616 MyOpenSpace.Friendship.Field = {
3617     /**
3618      * A boolean indicating if the person is friend.
3619      * @memberOf MyOpenSpace.Friendship.Field
3620      */
3621     IS_FRIEND:"IS_FRIEND",
3622     
3623     /**
3624      * A string indicating the friend id.
3625      * @memberOf MyOpenSpace.Friendship.Field
3626      */
3627     FRIEND_ID:"FRIEND_ID"
3628 };
3629 
3630 /**
3631  * Returns the field specified by key
3632  * @param {String} key The key to search by
3633  * @return {MyOpenSpace.Friendship || undefined} The Frienship Field value if found, nothing otherwise.
3634  */
3635 MyOpenSpace.Friendship.prototype.getField = function(key) { return this[key]; };
3636 
3637 /**
3638  * Writes a value to the field specified by the key
3639  * @param {String} key The key to search by.
3640  * @param {String} val The value to set.
3641  * @private
3642  * @private
3643  */
3644 MyOpenSpace.Friendship.prototype.setField_ = function(key,val) { this[key] = val; };/**
3645  * Internal implementation of a simple hash table.
3646  * @private
3647  */
3648 MyOpenSpace.Hash = function(){ 
3649     this._hash = {};
3650     this._num = 0;
3651 };
3652 MyOpenSpace.Hash.prototype = {
3653     _hash:null,
3654     _num:null,
3655 	/**
3656 	 * Add element to the hash
3657 	 * @param {Object} key
3658 	 * @param {Object} value
3659 	 * @private
3660 	 */
3661     add:function(key, value){
3662         this._hash[key] = value;
3663         this._num++;
3664     },
3665 	/**
3666 	 * Remove element from the hash
3667 	 * @param {Object} key
3668 	 * @private
3669 	 */
3670     remove:function(key){
3671         var val = null;
3672         if("undefined" !== typeof(this._hash[key])){
3673             val = this._hash[key];
3674             delete this._hash[key];
3675             this._num--;
3676         }
3677         return val;
3678     },
3679 	/**
3680 	 * 
3681 	 * @param {Object} key
3682 	 * @private
3683 	 */
3684     get:function(key){
3685         return _hash[key];
3686     },
3687 	/**
3688 	 * @private
3689 	 */
3690     size:function(){
3691         return this._num;
3692     },
3693 	/**
3694 	 * 
3695 	 * @param {Object} key
3696 	 * @private
3697 	 */
3698     has:function(key){
3699         if(!key) return false;
3700         return "undefined" !== typeof(this._hash[key]);
3701     }
3702 };/* ================================================================
3703  * MyOpenSpace.Indicators
3704  * ================================================================
3705  */
3706 
3707 
3708  /**
3709  * A class representing an Indicators.
3710  * @constructor
3711  * @private
3712  */
3713 MyOpenSpace.Indicators = function() {};
3714 /**
3715  * The fields for MyOpenSpace.Indicators
3716  * @class
3717  * @name MyOpenSpace.Indicators.Field
3718  * @static
3719  */
3720 MyOpenSpace.Indicators.Field = {
3721     /**
3722      * A boolean indicating the peroson has a mail.
3723      * @memberOf MyOpenSpace.Indicators.Field
3724      */
3725     MAIL:"MAIL",
3726     
3727     /**
3728      * A string containing the mail url.
3729      * @memberOf MyOpenSpace.Indicators.Field
3730      */
3731     MAIL_URL:"MAIL_URL",
3732     
3733     /**
3734      * A boolean indication the person has a birthday.
3735      * @memberOf MyOpenSpace.Indicators.Field
3736      */
3737     BIRTHDAY:"BIRTHDAY",
3738     
3739     /**
3740      * A string containing the birthday url.
3741      * @memberOf MyOpenSpace.Indicators.Field
3742      */
3743     BIRTHDAY_URL:"BIRTHDAY_URL",
3744 
3745     /**
3746      * A boolean indicating the person has a blog comment.
3747      * @memberOf MyOpenSpace.Indicators.Field
3748      */
3749     BLOG_COMMENT:"BLOG_COMMENT",
3750     
3751     /**
3752      * A string containing the blog comment url.
3753      * @memberOf MyOpenSpace.Indicators.Field
3754      */
3755     BLOG_COMMENT_URL:"BLOG_COMMENT_URL",
3756     
3757     /**
3758      * A boolean indicating the person has a blog subscrition post.
3759      * @memberOf MyOpenSpace.Indicators.Field
3760      */
3761     BLOG_SUBSCRIPTION_POST:"BLOG_SUBSCRIPTION_POST",
3762     
3763     /**
3764      * A string containing the blog subscription post url.
3765      * @memberOf MyOpenSpace.Indicators.Field
3766      */
3767     BLOG_SUBSCRIPTION_POST_URL:"BLOG_SUBSCRIPTION_POST_URL",
3768     
3769     /**
3770      * A boolean indicating the person has a comment.
3771      * @memberOf MyOpenSpace.Indicators.Field
3772      */
3773     COMMENT:"COMMENT",
3774     
3775     /**
3776      * A string containing the comment url.
3777      * @memberOf MyOpenSpace.Indicators.Field
3778      */
3779     COMMENT_URL:"COMMENT_URL",
3780     
3781     /**
3782      * A boolean indicating the person has a event invitation.
3783      * @memberOf MyOpenSpace.Indicators.Field
3784      */
3785     EVENT_INVITATION:"EVENT_INVITATION",
3786     
3787     /**
3788      * A string containing the event invitation url.
3789      * @memberOf MyOpenSpace.Indicators.Field
3790      */
3791     EVENT_INVITATION_URL:"EVENT_INVITATION_URL",
3792     
3793     /**
3794      * A boolean indicating the person has a friend request.
3795      * @memberOf MyOpenSpace.Indicators.Field
3796      */
3797     FRIEND_REQUEST:"FRIEND_REQUEST",
3798     
3799     /**
3800      * A string containing the friend request invitation url.
3801      * @memberOf MyOpenSpace.Indicators.Field
3802      */
3803     FRIEND_REQUEST_URL:"FRIEND_REQUEST_URL",
3804     
3805     /**
3806      * A boolean indicating the person has a group notification.
3807      * @memberOf MyOpenSpace.Indicators.Field
3808      */
3809     GROUP_NOTIFICATION:"GROUP_NOTIFICATION",
3810     
3811     /**
3812      * A string containing the group notification url.
3813      * @memberOf MyOpenSpace.Indicators.Field
3814      */
3815     GROUP_NOTIFICATION_URL:"GROUP_NOTIFICATION_URL",
3816     
3817     /**
3818      * A boolean indicating the person has a photo tag approval.
3819      * @memberOf MyOpenSpace.Indicators.Field
3820      */
3821     PHOTO_TAG_APPROVAL:"PHOTO_TAG_APPROVAL",
3822     
3823     /**
3824      * A string containing the photo tag approval url.
3825      * @memberOf MyOpenSpace.Indicators.Field
3826      */
3827     PHOTO_TAG_APPROVAL_URL:"PHOTO_TAG_APPROVAL_URL",
3828     
3829     /**
3830      * A boolean indicating the person has a picture comment.
3831      * @memberOf MyOpenSpace.Indicators.Field
3832      */
3833     PICTURE_COMMENT:"PICTURE_COMMENT",
3834     
3835     /**
3836      * A string containing the picture comment url.
3837      * @memberOf MyOpenSpace.Indicators.Field
3838      */
3839     PICTURE_COMMENT_URL:"PICTURE_COMMENT_URL",
3840     
3841     /**
3842      * A boolean indicating the person has a recently added friend.
3843      * @memberOf MyOpenSpace.Indicators.Field
3844      */
3845     RECENTLY_ADDED_FRIEND:"RECENTLY_ADDED_FRIEND",
3846     
3847     /**
3848      * A string containing the recently added friend url.
3849      * @memberOf MyOpenSpace.Indicators.Field
3850      */
3851     RECENTLY_ADDED_FRIEND_URL:"RECENTLY_ADDED_FRIEND_URL",
3852     
3853     /**
3854      * A boolean indicating the person has a video comment.
3855      * @memberOf MyOpenSpace.Indicators.Field
3856      */
3857     VIDEO_COMMENT:"VIDEO_COMMENT",
3858     
3859     /**
3860      * A string containing the video comment url.
3861      * @memberOf MyOpenSpace.Indicators.Field
3862      */
3863     VIDEO_COMMENT_URL:"VIDEO_COMMENT_URL",
3864     
3865     /**
3866      * A boolean indicating the person has a video process.
3867      * @memberOf MyOpenSpace.Indicators.Field
3868      */
3869     VIDEO_PROCESS:"VIDEO_PROCESS",
3870     
3871     /**
3872      * A string containing the video process url.
3873      * @memberOf MyOpenSpace.Indicators.Field
3874      */
3875     VIDEO_PROCESS_URL:"VIDEO_PROCESS_URL"
3876 };
3877 
3878 /**
3879  * Returns the field specified by key
3880  * @param {String} key The key to search by
3881  * @return {MyOpenSpace.Indicators || undefined} The indicators if found, nothing otherwise.
3882  */
3883 MyOpenSpace.Indicators.prototype.getField = function(key) { return this[key]; };
3884 /**
3885  * Writes a value to the field specified by the key
3886  * @param {String} key The key to search by.
3887  * @param {String} val The value to set.
3888  * @private
3889  * @private
3890  */
3891 MyOpenSpace.Indicators.prototype.setField_ = function(key,val) { this[key] = val; };//------------------------------------------//
3892 // Non namespaced global functions below
3893 //------------------------------------------//
3894 
3895 /**
3896 * @ignore
3897 */
3898 window.alert = function() { };
3899 
3900 /**
3901 * @ignore
3902 */
3903 window.confirm = function() { };
3904 
3905 /**
3906 * @ignore
3907 */
3908 function validateAppDataKeyName(keyName) {
3909     var validRE = /^([a-z0-9\-_\.])+$/i;
3910     return validRE.test(keyName);
3911 }
3912 
3913 /**
3914  * @ignore
3915  */
3916 Function.prototype.inherits = function(parentCtor) {
3917   function tempCtor() {};
3918   tempCtor.prototype = parentCtor.prototype;
3919   this.superClass_ = parentCtor.prototype;
3920   this.prototype = new tempCtor();
3921   this.prototype.constructor = this;
3922 };
3923 
3924 /** 
3925 * @ignore 
3926 * debugging utilities - reflect through an object's properties and trace values
3927 */
3928 function reflect(obj, opt_dept, opt_currentDept){
3929 	opt_dept = (opt_dept == undefined) ? 0 : opt_dept;
3930 	opt_currentDept = (opt_currentDept == undefined) ? 0 : opt_currentDept;
3931 	//trace(obj);
3932 	if (typeof(obj) == "object"){
3933 		for (var i in obj){
3934 			var levelPrefix = '';
3935 			for (var j = 0; j < opt_currentDept + 1; j++){
3936 				levelPrefix += "      "
3937 			}
3938 			trace( levelPrefix + i + " -> " + obj[i] + "\n");
3939 			if (typeof(obj[i]) == "object"){
3940 				if (opt_dept > opt_currentDept){
3941 						reflect(obj[i], opt_dept, opt_currentDept + 1);
3942 				}
3943 			}
3944 		}
3945 	}
3946 }
3947 
3948 var batchTrace = "";
3949 /**
3950  * @ignore
3951  */
3952 function tracePublicMembers(obj, propertyDepth) {
3953     propertyDepth = propertyDepth || 0;
3954     for (var prop in obj) {
3955         if (typeof(obj[prop]) == "function") return;
3956        
3957         if (typeof(obj[prop]) == "object")
3958         {
3959             traceIndent(propertyDepth);
3960             dumpToBatch("<b>" + prop + "</b><BR>", propertyDepth);
3961             tracePublicMembers(obj[prop], propertyDepth+1);
3962         }
3963         else
3964         {
3965             if (prop.substring(prop.length-3) != "___") {
3966                  traceIndent(propertyDepth);
3967                  dumpToBatch("<i>" + prop + "</i>: " + obj[prop] + "<BR>", propertyDepth);
3968                  }
3969         }
3970     }
3971     if (propertyDepth == 0) flushBatchTrace();
3972 }
3973 
3974 /**
3975  * @ignore
3976  */
3977 function flushBatchTrace() {
3978     trace(batchTrace);
3979     batchTrace="";
3980 }
3981 /**
3982  * @ignore
3983  */
3984 function dumpToBatch(msg, depth) {
3985     if (depth == 0) {
3986         batchTrace = msg + batchTrace;
3987     }
3988     else
3989     {
3990         batchTrace += msg;
3991     }
3992 }
3993 /**
3994  * @ignore
3995  */
3996 function traceIndent(depth) {
3997     if (depth>0) {
3998         dumpToBatch("|", depth);
3999         for (var i = 0;i<depth;i++) dumpToBatch("----", depth);
4000         dumpToBatch(">", depth); 
4001     }
4002 }
4003 
4004 var debugMessageDiv;
4005 var debugElementEnable;
4006 
4007 /**
4008  * @ignore
4009  */
4010 function trace(msg, opt_no_break) {
4011     if (typeof (debugElementEnable) === 'undefined') {
4012         debugMessageDiv = document.getElementById('debugMessages');
4013         if (debugMessageDiv) {
4014             debugElementEnable = true;
4015         }
4016         else {
4017             debugElementEnable = false;
4018         }
4019     }
4020 
4021     if (debugElementEnable) {
4022          opt_no_break = (opt_no_break) ? "" : "<BR>";
4023          debugMessageDiv.innerHTML += opt_no_break + msg;  
4024     }
4025 }
4026 
4027 /**
4028 * @ignore
4029 */
4030 function jsonp(url, name, query, allowCaching) {
4031     if (url.indexOf("?") > -1)
4032         url += "&jsonp="
4033     else
4034         url += "?jsonp="
4035     url += name + "&";
4036     if (query)
4037         url += encodeURIComponent(query);
4038     if (allowCaching === false){
4039 		url += "&";
4040     	url += new Date().getTime().toString(); // prevent caching        		
4041 	}
4042 
4043     var script = document.createElement("script");
4044     script.setAttribute("src", url);
4045     script.setAttribute("type", "text/javascript");
4046     document.getElementsByTagName("head")[0].appendChild(script);
4047 }
4048 
4049 /**
4050 * @ignore
4051 */
4052 function idSpecMap(idspec) {
4053 
4054     if (typeof (idspec.getField) === 'undefined') {
4055         
4056         return { "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Invalid idSpec." };
4057     }
4058     if (
4059 		typeof(idspec.getField(opensocial.IdSpec.Field.USER_ID)) === 'undefined') {
4060         return { "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "USER_ID was not provided." };
4061     }
4062 
4063 	var userId = idspec.getField(opensocial.IdSpec.Field.USER_ID);
4064     var networkDistance = 0;
4065     if (typeof(idspec.getField(opensocial.IdSpec.Field.NETWORK_DISTANCE)) !== 'undefined') {
4066 		if (typeof(idspec.getField(opensocial.IdSpec.Field.NETWORK_DISTANCE)) !== 'number') {
4067 			return {
4068 				"errorCode": opensocial.ResponseItem.Error.BAD_REQUEST,
4069 				"errorMessage": "NETWORK_DISTANCE must be an integer."
4070 			};
4071 		}
4072 		networkDistance = idspec.getField(opensocial.IdSpec.Field.NETWORK_DISTANCE);
4073 		if (networkDistance < 0 || networkDistance > 1) {
4074 			return {
4075 				"errorCode": opensocial.ResponseItem.Error.BAD_REQUEST,
4076 				"errorMessage": "NETWORK_DISTANCE must be 0 or 1."
4077 			};
4078 		}
4079 	}
4080 	else if (typeof(idspec.getField(opensocial.IdSpec.Field.GROUP_ID)) !== 'undefined') {
4081 		var groupId = idspec.getField(opensocial.IdSpec.Field.GROUP_ID);
4082 		if (groupId === "FRIENDS"){
4083 			networkDistance = 1;
4084 		}
4085 		else if (groupId === "SELF"){
4086 			networkDistance = 0;
4087 		}
4088 		else{
4089 			return {
4090 				"errorCode": opensocial.ResponseItem.Error.BAD_REQUEST,
4091 				"errorMessage": "GROUP_ID is not valid accepted values are FRIENDS or SELF."};
4092 		}
4093 	}
4094 
4095     if (userId === opensocial.IdSpec.PersonId.OWNER) {
4096         if (networkDistance === 0) {
4097             return MyOpenSpace.IdSpecMapping_.OWNER;
4098         }
4099         else if (networkDistance === 1) {
4100             return MyOpenSpace.IdSpecMapping_.OWNER_FRIENDS;
4101         }
4102     }
4103     else if (userId === opensocial.IdSpec.PersonId.VIEWER) {
4104         if (networkDistance === 0) {
4105             return MyOpenSpace.IdSpecMapping_.VIEWER;
4106         }
4107         else if (networkDistance === 1) {
4108             return MyOpenSpace.IdSpecMapping_.VIEWER_FRIENDS;
4109         }
4110     }
4111     else if (userId.constructor === Array) {
4112         if (networkDistance > 0) {
4113             return { "errorCode": opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "errorMessage": "NETWORK_DISTANCE greater than 0 is not been implemented for arrays of Ids." };
4114         }
4115         var idArray = [];
4116         for (var i in userId) {
4117             var results = ('' + userId[i]).match(/^(?:myspace\.com:)?(\d+)$/);
4118             if (results === null || results.length === 0) {
4119                 return { "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "opensocial.IdSpec.Field.USER_ID array contains invalid elements." };
4120             }
4121             idArray[i] = results[1];
4122         }
4123         return idArray;
4124     }
4125     else {
4126         var results = ('' + userId).match(/^(?:myspace\.com:)?(\d+)$/);
4127         if (results === null || results.length === 0) {
4128             return { "errorCode": opensocial.ResponseItem.Error.BAD_REQUEST, "errorMessage": "Invalid opensocial.IdSpec.Field.USER_ID value." };
4129         }
4130         return results[1];
4131     }
4132     
4133 }
4134 
4135 /**
4136  * Borrowed from prototype
4137  * @ignore
4138  */
4139 var Try = {
4140     /**
4141      * @function
4142      * @param Array of statements to evaluate for returnValues.
4143      * @ignore
4144      */
4145   these: function() {
4146     var returnValue;
4147 
4148     for (var i = 0, length = arguments.length; i < length; i++) {
4149       var lambda = arguments[i];
4150       try {
4151         returnValue = lambda();
4152         break;
4153       } catch (e) {}
4154     }
4155 
4156     return returnValue;
4157   }
4158 };
4159 
4160 /*
4161 * API cache hashtable, used for REST calls to API only
4162 * @class
4163 * @private
4164 * @static
4165 */
4166 var APICache = {
4167     init: function() {
4168         if (this.cache == null) {
4169             this.cache = new MyOpenSpace.Hash();
4170             this.timestamps = {};
4171         }
4172     },
4173     add: function(key, value) {
4174         if (!key || !value) return;
4175         this.cache[key] = value;
4176         this.timestamps[key] = new Date().getTime();
4177         
4178     },
4179     isCached : function(key) {
4180          if(!key) return false;
4181          return "undefined" !== typeof(this.cache[key]);
4182     },
4183     retrieve : function (key) {
4184         if (!key) return;
4185         return this.cache[key];
4186     },
4187     isExpired : function(key, timeToLive) {
4188         if(!key || !timeToLive) return;
4189         if (timeToLive == 0) return false;
4190         var lifespan = new Date().getTime() - this.timestamps[key];
4191         return (lifespan > timeToLive) ? true : false;
4192     }
4193     
4194     
4195 };/**
4196  * The MySpace container class, extends opensocial.Container.  Use opensocial.Container.get() to retrieve this singleton.
4197  * @constructor
4198  */
4199 MyOpenSpace.MySpaceContainer = function() {
4200     if (gadgets.util.getUrlParameters().opensocial_surface) {
4201         //HACK-ISH
4202         gadgets.util.getUrlParameters().views = gadgets.util.getUrlParameters().opensocial_surface.toUpperCase();
4203     }
4204     else {
4205         gadgets.util.getUrlParameters().views = "";
4206     }
4207 
4208     var config = {};
4209     var supported_views = {};
4210     supported_views["default"] = new gadgets.views.View(gadgets.views.ViewType.CANVAS, true);
4211     supported_views[gadgets.views.ViewType.CANVAS] = new gadgets.views.View(gadgets.views.ViewType.CANVAS, true);
4212     supported_views[gadgets.views.ViewType.PROFILE] = new gadgets.views.View(gadgets.views.ViewType.PROFILE, false);
4213     supported_views[gadgets.views.ViewType.HOME] = new gadgets.views.View(gadgets.views.ViewType.HOME, false);
4214     config["views"] = supported_views;
4215 
4216     var uriFragment = window.location.hash;
4217     if (uriFragment && uriFragment.length >= 0) {
4218         uriFragment = uriFragment.substring(1, uriFragment.length);
4219         if (uriFragment.indexOf("&") >= 0) {
4220             uriFragment = uriFragment.substring(0, uriFragment.indexOf("&"));
4221         }
4222     }
4223     this.osToken_ = uriFragment || gadgets.util.getUrlParameters().opensocial_token;
4224 
4225     var io_config = {};
4226 
4227     var proxyUrl = "/proxy/relay.proxy?opensocial_token=" + this.osToken_ + "&refresh=%refresh%&opensocial_url=%url%";
4228     io_config["proxyUrl"] = proxyUrl;
4229     //Note: we do not use the jsonProxyUrl in our code.
4230     io_config["jsonProxyUrl"] = proxyUrl; //"relay/relay.proxy";  
4231     config["core.io"] = io_config;
4232 
4233     gadgets.config.init(config);
4234 
4235     this.prefs = new gadgets.Prefs();
4236 
4237     APICache.init();
4238 
4239     this.osMode_ = gadgets.views.getCurrentView();
4240 
4241     this.params_ = {};
4242 
4243     var urlParams = gadgets.util.getUrlParameters();
4244 
4245     if (urlParams.p) {
4246         this.registerParam("appParams", gadgets.json.parse(urlParams.p));
4247     }
4248 
4249     if (urlParams.ownerId) {
4250         this.registerParam("ownerId", gadgets.util.getUrlParameters().ownerId);
4251     }
4252 
4253     if (urlParams.viewerId) {
4254         this.registerParam("viewerId", urlParams.viewerId);
4255     }
4256 
4257     if (urlParams.perm) {
4258         var perm = gadgets.json.parse('{"permissions":' + urlParams.perm + '}');
4259         this.registerParam("ownerPerm", perm.permissions);
4260         if (urlParams.viewerId === urlParams.ownerId) {
4261             this.registerParam("viewerPerm", perm.permissions);
4262         }
4263         else if (urlParams.viewer_perm) {
4264             perm = gadgets.json.parse('"permissions":' + urlParams.viewer_perm);
4265             this.registerParam("viewerPerm", perm.permissions);
4266         }
4267     }
4268 
4269     if (urlParams.userBlockedApp || urlParams.userLoggedOut || "0" === urlParams.installState) {
4270         this.registerParam("denyViewer", true);
4271     }
4272     else {
4273         this.registerParam("denyViewer", false);
4274     }
4275 
4276     if (urlParams.installState) {
4277         this.registerParam("installState", urlParams.installState);
4278     }
4279 
4280     var supportedPostToTargets = "";
4281     if (urlParams && urlParams.pto) {
4282         supportedPostToTargets = urlParams.pto.split(",");
4283         this.myspaceenvironment_ = this.newMySpaceEnvironment(supportedPostToTargets);
4284     }
4285 
4286     var supportedPersonFields = {};
4287     supportedPersonFields[opensocial.Person.Field.ABOUT_ME] = true;
4288     supportedPersonFields[opensocial.Person.Field.AGE] = true;
4289     supportedPersonFields[opensocial.Person.Field.BODY_TYPE] = true;
4290     supportedPersonFields[opensocial.Person.Field.BOOKS] = true;
4291     supportedPersonFields[opensocial.Person.Field.CHILDREN] = true;
4292     supportedPersonFields[opensocial.Person.Field.CURRENT_LOCATION] = true;
4293     supportedPersonFields[opensocial.Person.Field.DATE_OF_BIRTH] = true;
4294     supportedPersonFields[opensocial.Person.Field.DRINKER] = true;
4295     supportedPersonFields[opensocial.Person.Field.ETHNICITY] = true;
4296     supportedPersonFields[opensocial.Person.Field.GENDER] = true;
4297     supportedPersonFields[opensocial.Person.Field.HAS_APP] = true;
4298     supportedPersonFields[opensocial.Person.Field.HEROES] = true;
4299     supportedPersonFields[opensocial.Person.Field.ID] = true;
4300     supportedPersonFields[opensocial.Person.Field.INTERESTS] = true;
4301     supportedPersonFields[opensocial.Person.Field.JOBS] = true;
4302     supportedPersonFields[opensocial.Person.Field.LOOKING_FOR] = true;
4303     supportedPersonFields[opensocial.Person.Field.MOVIES] = true;
4304     supportedPersonFields[opensocial.Person.Field.MUSIC] = true;
4305     supportedPersonFields[opensocial.Person.Field.NAME] = true;
4306     supportedPersonFields[opensocial.Person.Field.NETWORK_PRESENCE] = true;
4307     supportedPersonFields[opensocial.Person.Field.NICKNAME] = true;
4308     supportedPersonFields[opensocial.Person.Field.PROFILE_SONG] = true;
4309     supportedPersonFields[opensocial.Person.Field.PROFILE_URL] = true;
4310     supportedPersonFields[opensocial.Person.Field.RELATIONSHIP_STATUS] = true;
4311     supportedPersonFields[opensocial.Person.Field.RELIGION] = true;
4312     supportedPersonFields[opensocial.Person.Field.SEXUAL_ORIENTATION] = true;
4313     supportedPersonFields[opensocial.Person.Field.SMOKER] = true;
4314     supportedPersonFields[opensocial.Person.Field.STATUS] = true;
4315     supportedPersonFields[opensocial.Person.Field.THUMBNAIL_URL] = true;
4316     supportedPersonFields[opensocial.Person.Field.TV_SHOWS] = true;
4317     supportedPersonFields[opensocial.Person.Field.URLS] = true;
4318     supportedPersonFields[MyOpenSpace.Person.Field.MEDIUM_IMAGE] = true;
4319     supportedPersonFields[MyOpenSpace.Person.Field.LARGE_IMAGE] = true;
4320 
4321     var supportedFilters = {};
4322     supportedFilters[opensocial.DataRequest.FilterType.ALL] = true;
4323     supportedFilters[opensocial.DataRequest.FilterType.HAS_APP] = true;
4324     //supportedFilters[opensocial.DataRequest.FilterType.IS_FRIENDS_WITH] = false;
4325     supportedFilters[opensocial.DataRequest.FilterType.TOP_FRIENDS] = true;
4326     //supportedFilters[MyOpenSpace.DataRequest.FilterType.ONLINE_FRIENDS] = true;
4327 
4328     var supportedFields = {};
4329     supportedFields[opensocial.Environment.ObjectType.PERSON] = supportedPersonFields;
4330     supportedFields[MyOpenSpace.Environment.ObjectType.PERSON] = supportedPersonFields;
4331     supportedFields[MyOpenSpace.Environment.ObjectType.VIDEO] = MyOpenSpace.Video.Field;
4332     supportedFields[MyOpenSpace.Environment.ObjectType.ALBUM] = MyOpenSpace.Album.Field;
4333     supportedFields[MyOpenSpace.Environment.ObjectType.PHOTO] = MyOpenSpace.Photo.Field;
4334     supportedFields[opensocial.Environment.ObjectType.FILTER_TYPE] = supportedFilters;
4335 
4336     this.environment_ = this.newEnvironment("myspace.com", supportedFields);
4337 
4338     this.endPoint_ = MyOpenSpace.EndPoint.Tokenized(MyOpenSpace.EndPoint, opensocial.IdSpec.PersonId, this.osToken_, this.osMode_);
4339 
4340     /* Expose as property for now */
4341     MyOpenSpace.MySpaceContainer.OSToken = this.osToken_;
4342 
4343     opensocial.Container.call(this, false);
4344     opensocial.Container.setContainer(this);
4345 };
4346 MyOpenSpace.MySpaceContainer.inherits(opensocial.Container);
4347 
4348 /**
4349  * The parameters that are passed between surfaces.
4350  * @private
4351  * @private
4352  */
4353 MyOpenSpace.MySpaceContainer.prototype.params_ = null;
4354 
4355 /**
4356  * Private instance of the request processor, use MySpaceContainer.getRequestProcessor to access.
4357  * @type {MyOpenSpace.RequestProcessor_}
4358  * @private
4359  * @private
4360  */
4361 MyOpenSpace.MySpaceContainer.prototype.requestProcessor_ = null;
4362 
4363 /**
4364  * Private instance of the environment, use MySpaceContainer.getEnvironment to access.
4365  * @type {opensocial.Environment}
4366  * @private
4367  * @private
4368  */
4369 MyOpenSpace.MySpaceContainer.prototype.environment_ = null;
4370 
4371 /**
4372  * Private instance of the MySpace environment, use MySpaceContainer.getMySpaceEnvironment to access.
4373  * @type {MyOpenSpace.Environment}
4374  * @private
4375  * @private
4376  */
4377 MyOpenSpace.MySpaceContainer.prototype.myspaceenvironment_ = null;
4378 
4379 /**
4380  * Returns the container's MySpace environment object
4381  * @return {MyOpenSpace.Environment}
4382  */
4383 MyOpenSpace.MySpaceContainer.prototype.getMySpaceEnvironment = function() { return this.myspaceenvironment_; };
4384 
4385 /**
4386  * Returns the container's request processor
4387  * @return {MyOpenSpace.RequestProcessor_}
4388  * @private
4389  */
4390 MyOpenSpace.MySpaceContainer.prototype.getRequestProcessor = function() { return this.requestProcessor_; };
4391 
4392 /**
4393  * Returns the container's environment object.
4394  * @return {opensocial.Environment}
4395  * @private
4396  */
4397 MyOpenSpace.MySpaceContainer.prototype.getEnvironment = function() { return this.environment_; };
4398 
4399 /**
4400  * Returns a new MyOpenSpace.Person instance
4401  * @param {Map<opensocial.DataRequest.PeopleRequestFields>} opt_params Optional parameters specified when creating the person.
4402  * @param {Boolean} opt_isViewer True if this is the viewer of the page otherwise, false.
4403  * @param {Boolean} opt_isOwner True if this is the owner of the page otherwise, false.
4404  * @return {MyOpenSpace.Person} The person object
4405  * @private
4406  */
4407 MyOpenSpace.MySpaceContainer.prototype.newPerson = function(opt_params, opt_isOwner, opt_isViewer){
4408     return new MyOpenSpace.Person(opt_params, opt_isOwner, opt_isViewer);
4409 };
4410 
4411 MyOpenSpace.MySpaceContainer.prototype.newName = function(opt_params){
4412     return new opensocial.Name(opt_params);
4413 };
4414 
4415 
4416 /**
4417  * Returns a new MyOpenSpace.Album instance
4418  * @param {undefined} opt_params Unused at this time.
4419  * @return {MyOpenSpace.Album} The album object
4420  */
4421 MyOpenSpace.MySpaceContainer.prototype.newAlbum = function(opt_params){
4422     return new MyOpenSpace.Album(opt_params);
4423 };
4424 
4425 /**
4426  * Returns a new MyOpenSpace.Indicators instance
4427  * @param {undefined} opt_params Unused at this time.
4428  * @return {MyOpenSpace.Indicators} The indicators object
4429  */
4430 MyOpenSpace.MySpaceContainer.prototype.newIndicators = function(opt_params){
4431     return new MyOpenSpace.Indicators(opt_params);
4432 };
4433 /**
4434  * Returns a new MyOpenSpace.PersonStatus instance
4435  * @param {undefined} opt_params Unused at this time.
4436  * @return {MyOpenSpace.PersonStatus} The PersonStatus object
4437  */
4438 MyOpenSpace.MySpaceContainer.prototype.newPersonStatus = function(opt_params){
4439     return new MyOpenSpace.PersonStatus(opt_params);
4440 };
4441 /**
4442  * Returns a new MyOpenSpace.PersonMood instance
4443  * @param {undefined} opt_params Unused at this time.
4444  * @return {MyOpenSpace.PersonStatus} The PersonMood object
4445  */
4446 MyOpenSpace.MySpaceContainer.prototype.newPersonMood = function(opt_params){
4447     return new MyOpenSpace.PersonMood(opt_params);
4448 };
4449 /**
4450  * Returns a new MyOpenSpace.Friendship instance
4451  * @param {undefined} opt_params Unused at this time.
4452  * @return {MyOpenSpace.Friendship} The Friendship object
4453  */
4454 MyOpenSpace.MySpaceContainer.prototype.newFriendship = function(opt_params){
4455     return new MyOpenSpace.Friendship(opt_params);
4456 };
4457 
4458 /**
4459  * Returns a new MyOpenSpace.Video instance
4460  * @param {undefined} opt_params Unused at this time.
4461  * @return {MyOpenSpace.Video} The album object
4462  */
4463 MyOpenSpace.MySpaceContainer.prototype.newVideo = function(opt_params){
4464     return new MyOpenSpace.Video(opt_params);
4465 };
4466 
4467 
4468 /**
4469  * Returns a new MyOpenSpace.Photo instance
4470  * @param {undefined} opt_params Unused at this time.
4471  * @return {MyOpenSpace.Photo} The photo object
4472  */
4473 MyOpenSpace.MySpaceContainer.prototype.newPhoto = function(opt_params){
4474     return new MyOpenSpace.Photo(opt_params);
4475 };
4476 
4477 /**
4478  * Returns a new opensocial.DataRequest instance, which is overridden locally
4479  * @function
4480  * @return {opensocial.DataRequest} The data request object
4481  * @private
4482  */
4483 MyOpenSpace.MySpaceContainer.prototype.newDataRequest = function(){
4484     return new MyOpenSpace.DataRequest(this.osToken_, this.endPoint_);
4485 };
4486 
4487 /**
4488  * Returns a new opensocial.ResponseItem instance
4489  * @function
4490  * @param {opensocial.DataRequest} originalDataRequest The ID of the photo to fetch
4491  * @param {Object || null} data The object retrieved, can be any entity, or null if nothing was found.
4492  * @param {String} opt_errorCode A code defining the error that occurred, if any.
4493  * @param {String} opt_errorMessage A message detailing the error that occurred, if any.
4494  * @return {opensocial.ResponseItem} The response item object
4495  * @private
4496  */
4497 MyOpenSpace.MySpaceContainer.prototype.newResponseItem = function(originalDataRequest, data, opt_errorCode, opt_errorMessage) {
4498     return new opensocial.ResponseItem(originalDataRequest, data, opt_errorCode, opt_errorMessage);
4499 };
4500 
4501 /**
4502  * Creates an object to be used when sending to the server.
4503  * @param {String} id The ID (VIEWER or OWNER) of the person.
4504  * @param {undefined} opt_params Not used at this time.
4505  * @return {Object} A request object.
4506  * @private
4507  */
4508 MyOpenSpace.MySpaceContainer.prototype.newFetchPersonRequest = function(id, opt_params) {
4509 	opt_params = opt_params || {};
4510     return {
4511 		type: MyOpenSpace.RequestType.FETCH_PERSON,
4512 		parameters: {
4513 			id:id,
4514 			profileDetail: this.mapPersonDetails_(opt_params),
4515             useCache: (opt_params[MyOpenSpace.DataRequest.CacheControl.USE_CACHE] || true),
4516             refreshInterval: (opt_params[MyOpenSpace.DataRequest.CacheControl.REFRESH_INTERVAL] || 0)
4517 		}
4518 	};
4519 };
4520 
4521 /**
4522  * Creates an object to be used when sending to the server.
4523  * @param {String} id The ID (VIEWER or OWNER) of the person who owns the photo
4524  * @param {Number} photo_id The ID of the photo to fetch
4525  * @param {undefined} opt_params Not used at this time.
4526  * @return {Object} A request object
4527  * @private
4528  */
4529 MyOpenSpace.MySpaceContainer.prototype.newFetchPhotoRequest = function(id, photo_id, opt_params){
4530     return {
4531 		type: MyOpenSpace.RequestType.FETCH_PHOTO,
4532 		parameters: {
4533 			id:id,
4534 			photo_id:photo_id
4535 		}
4536 	};
4537 };
4538 
4539 /**
4540  * Creates an object to be used when sending to the server
4541  * @param {String} id The ID (VIEWER or OWNER) of the person who owns the photos
4542  * @param {Map<opensocial.DataRequest.PeopleRequestFields.FIRST || opensocial.DataRequest.PeopleRequestFields.MAX>} opt_params Optional parameters specified when creating the photos.
4543  * @return {Object} A request object
4544  * @private
4545  */
4546 MyOpenSpace.MySpaceContainer.prototype.newFetchPhotosRequest = function(id, opt_params){
4547     opt_params = opt_params || {};
4548     return {
4549 		type: MyOpenSpace.RequestType.FETCH_PHOTOS,
4550 		parameters: {
4551 			id:id,
4552 			album_id: opt_params[MyOpenSpace.DataRequest.PhotoRequestFields.ALBUM_ID] || null,
4553 			first: opt_params[opensocial.DataRequest.PeopleRequestFields.FIRST] || 1,
4554 			max: opt_params[opensocial.DataRequest.PeopleRequestFields.MAX] || MyOpenSpace.DefaultPageSize
4555 		}
4556 	};
4557 };
4558 
4559 /**
4560  * Creates an object to be used when sending to the server
4561  * @param {String} id The ID (VIEWER or OWNER) of the person who owns the album
4562  * @param {Number} album_id The ID of the photo to fetch
4563  * @param {undefined} opt_params Not used at this time.
4564  * @return {Object} A request object
4565  * @private
4566  */
4567 MyOpenSpace.MySpaceContainer.prototype.newFetchAlbumRequest = function(id, album_id, opt_params){
4568     return {
4569 		type: MyOpenSpace.RequestType.FETCH_ALBUM,
4570 		parameters: {
4571 			id:id,
4572 			album_id:album_id
4573 		}
4574 	};
4575 };
4576 
4577 /**
4578  * Creates an object to be used when sending to the server
4579  * @param {String} id The ID (VIEWER or OWNER) of the person who owns the albums
4580  * @param {Map<opensocial.DataRequest.PeopleRequestFields.FIRST || opensocial.DataRequest.PeopleRequestFields.MAX>} opt_params Optional parameters specified when creating the albums.
4581  * @return {Object} A request object
4582  * @private
4583  */
4584 MyOpenSpace.MySpaceContainer.prototype.newFetchAlbumsRequest = function(id, opt_params){
4585     opt_params = opt_params || {};
4586     return {
4587 		type: MyOpenSpace.RequestType.FETCH_ALBUMS,
4588 		parameters: {
4589 			id:id,
4590 			first: opt_params[opensocial.DataRequest.PeopleRequestFields.FIRST] || 1,
4591 			max: opt_params[opensocial.DataRequest.PeopleRequestFields.MAX] || MyOpenSpace.DefaultPageSize
4592 		}
4593 	};
4594 };
4595 
4596 /**
4597  * Creates an object to be used when sending to the server
4598  * @param {String} id The ID (VIEWER or OWNER) of the person who owns the album
4599  * @param {Number} video_id The ID of the photo to fetch
4600  * @param {undefined} opt_params Not used at this time.
4601  * @return {Object} A request object
4602  * @private
4603  */
4604 MyOpenSpace.MySpaceContainer.prototype.newFetchVideoRequest = function(id, video_id, opt_params){
4605     return {
4606 		type: MyOpenSpace.RequestType.FETCH_VIDEO,
4607 		parameters: {
4608 			id:id,
4609 			video_id:video_id
4610 		}
4611 	};
4612 };
4613 
4614 /**
4615  * Creates an object to be used when sending to the server
4616  * @param {String} id The ID (VIEWER or OWNER) of the person.
4617  * @param {Map<opensocial.DataRequest.PeopleRequestFields.FIRST || opensocial.DataRequest.PeopleRequestFields.MAX>} opt_params Optional parameters specified when creating the videos.
4618  * @return {Object} A request object
4619  * @private
4620  */
4621 MyOpenSpace.MySpaceContainer.prototype.newFetchVideosRequest = function(id, opt_params){
4622     opt_params = opt_params || {};
4623     return {
4624 		type: MyOpenSpace.RequestType.FETCH_VIDEOS,
4625 		parameters: {
4626 			id:id,
4627 			first: opt_params[opensocial.DataRequest.PeopleRequestFields.FIRST] || 1,
4628 			max: opt_params[opensocial.DataRequest.PeopleRequestFields.MAX] || MyOpenSpace.DefaultPageSize
4629 		}
4630 	};
4631 };
4632 
4633 /**
4634  * Creates an object to be used when sending to the server.
4635  * @param {String} id The ID (VIEWER or OWNER) of the person.
4636  * @param {undefined} opt_params Not used at this time.
4637  * @return {Object} A request object.
4638  * @private
4639  */
4640 MyOpenSpace.MySpaceContainer.prototype.newFetchIndicatorsRequest = function(id, opt_parms){
4641 	return {
4642 		type: MyOpenSpace.RequestType.FETCH_INDICATORS,
4643 		parameters: {
4644 			id: id
4645 		}
4646 	};
4647 };
4648 
4649 /**
4650  * Creates an object to be used when sending to the server.
4651  * @param {String} id The ID (VIEWER or OWNER) of the person.
4652  * @param {undefined} opt_params Not used at this time.
4653  * @return {Object} A request object.
4654  * @private
4655  */
4656 MyOpenSpace.MySpaceContainer.prototype.newFetchPersonStatusRequest = function(id, opt_parms){
4657 	return {
4658 		type: MyOpenSpace.RequestType.FETCH_PERSON_STATUS,
4659 		parameters: {
4660 			id: id
4661 		}
4662 	};
4663 };
4664 
4665 /**
4666  * Creates an object to be used when sending to the server.
4667  * @param {String} id The ID (VIEWER or OWNER) of the person.
4668  * @param {undefined} opt_params Not used at this time.
4669  * @return {Object} A request object.
4670  * @private
4671  */
4672 MyOpenSpace.MySpaceContainer.prototype.newFetchPersonMoodRequest = function(id, opt_parms){
4673 	return {
4674 		type: MyOpenSpace.RequestType.FETCH_PERSON_MOOD,
4675 		parameters: {
4676 			id: id
4677 		}
4678 	};
4679 };
4680 
4681 /**
4682  * Creates an object to be used when sending to the server.
4683  * @param {String} id The ID (VIEWER or OWNER) of the person.
4684  * @param {String} person id.
4685  * @param {undefined} opt_params Not used at this time.
4686  * @return {Object} A request object.
4687  * @private
4688  */
4689 MyOpenSpace.MySpaceContainer.prototype.newFetchPersonFriendshipRequest = function(id, key, opt_parms){
4690 	return {
4691 		type: MyOpenSpace.RequestType.FETCH_PERSON_FRIENDSHIP,
4692 		parameters: {
4693 			id: id,
4694 			key: key
4695 		}
4696 	};
4697 };
4698 
4699 /**
4700  * Creates an object to be used when sending to the server.
4701  * @param {String} id The ID (VIEWER or OWNER) of the person.
4702  * @param {Array} array of person ids.
4703  * @param {undefined} opt_params Not used at this time.
4704  * @return {Object} A request object.
4705  * @private
4706  */
4707 MyOpenSpace.MySpaceContainer.prototype.newFetchPeopleFriendshipRequest = function(id, key, opt_parms){
4708 	return {
4709 		type: MyOpenSpace.RequestType.FETCH_PEOPLE_FRIENDSHIP,
4710 		parameters: {
4711 			id: id,
4712 			key: key
4713 		}
4714 	};
4715 };
4716 
4717 /**
4718  * Creates an item to request friends from the server.
4719  * When processed, returns an opensocial.Collection<MyOpenSpace.Person> object.
4720  * @param {Array.<String> | String} idSpec An ID reference used to specify which people to fetch; the supported keys VIEWER_FRIENDS or OWNER_FRIENDS.
4721  * @param {Map.<opensocial.DataRequest.PeopleRequestFields} opt_params Additional opensocial.DataRequest.PeopleRequestFields params to pass to the request.
4722  * @return {Object} A request object.
4723  * @private
4724  */
4725 MyOpenSpace.MySpaceContainer.prototype.newFetchPeopleRequest = function(idSpec, opt_params) {
4726     opt_params = opt_params || {};
4727 	var fields = opensocial.DataRequest.PeopleRequestFields;
4728 	var groups = opensocial.DataRequest.Group;
4729 	var type = MyOpenSpace.RequestType.FETCH_PEOPLE;
4730 	
4731 	return {
4732 	    type: type,
4733 		parameters: {
4734 		    idSpec:idSpec,
4735 			sortOrder:opt_params[fields.SORT_ORDER],
4736 		    details:opt_params[fields.PROFILE_DETAILS],
4737 		    filter:opt_params[fields.FILTER] || opensocial.DataRequest.FilterType.ALL,
4738 		    first:opt_params[fields.FIRST] || 1,
4739 		    max:opt_params[fields.MAX] || MyOpenSpace.DefaultPageSize
4740 		}
4741 	};
4742 };
4743 
4744 /**
4745  * Determines if the requested Person will be mapped internally to BASIC, FULL or EXTENDED
4746  * @function
4747  * @return {MyOpenSpace.DetailType} The detail type of the requested person
4748  * @private
4749  * @private
4750  */
4751 MyOpenSpace.MySpaceContainer.prototype.mapPersonDetails_ = function(params) {
4752     var details = params && params[opensocial.DataRequest.PeopleRequestFields.PROFILE_DETAILS];
4753 	if(!details) return {fields:"id,name,familyName,givenName,nickname,thumbnailUrl,profileUrl",unsupported:null};
4754 	
4755 	var fields =[];
4756 	var unsupported =[];
4757 	
4758 	fields[opensocial.Person.Field.ID] = opensocial.Person.Field.ID;
4759 	fields[opensocial.Person.Field.NAME] = 'name,familyName,givenName';
4760 	fields[opensocial.Person.Field.NICKNAME] = opensocial.Person.Field.NICKNAME;
4761 	fields[opensocial.Person.Field.THUMBNAIL_URL] = opensocial.Person.Field.THUMBNAIL_URL;
4762 	fields[opensocial.Person.Field.PROFILE_URL] = opensocial.Person.Field.PROFILE_URL;
4763 	
4764 	var environment = opensocial.getEnvironment();
4765 	
4766 	for(var i = 0; i < details.length; i++){
4767 		switch (details[i]){
4768 			case opensocial.Person.Field.NAME:
4769 				fields[opensocial.Person.Field.NAME] = 'name,familyName,givenName';
4770 				break;
4771 			case opensocial.Person.Field.JOBS:
4772 				fields[opensocial.Person.Field.JOBS] = 'organizations';
4773 				break;
4774 			case MyOpenSpace.Person.Field.LARGE_IMAGE:
4775 			case MyOpenSpace.Person.Field.MEDIUM_IMAGE:
4776 				fields['photos'] = 'photos';
4777 				break;
4778 			default: 
4779 				if  (environment.supportsField(opensocial.Environment.ObjectType.PERSON, details[i])){
4780 					fields[details[i]] = details[i];
4781 				}
4782 				else{
4783 					unsupported[details[i]] = true;
4784 				}
4785 			break;
4786 		}
4787 	}
4788 
4789 	unsupportedStr = '';
4790 	for (var i in unsupported) unsupportedStr += i + ', ';
4791 	if (unsupportedStr === '') {
4792 		unsupportedStr = null;
4793 	}
4794 	else {
4795 		unsupportedStr = unsupportedStr.substr(0, unsupportedStr.length - 2);
4796 	}
4797 
4798 	
4799 	var fieldsStr = '';
4800 	for (var i in fields) fieldsStr += fields[i] + ',';
4801 	fieldsStr = fieldsStr.substr(0, fieldsStr.length - 1);
4802 	return {fields:fieldsStr,unsupported:unsupportedStr};
4803 };
4804 
4805 
4806 
4807 /**
4808  * Get a new MySpace environment object.
4809  * @return {MyOpenSpace.Environment} the MySpace environment object
4810  * @private
4811  */
4812 MyOpenSpace.MySpaceContainer.prototype.newMySpaceEnvironment = function(supportedPostToTargets, app) {
4813   return new MyOpenSpace.Environment(supportedPostToTargets, app);
4814 };
4815 
4816 /**
4817  * Starts the sending process
4818  * @param {opensocial.DataRequest} dataRequest The request to get processed and sent
4819  * @private
4820  */
4821 MyOpenSpace.MySpaceContainer.prototype.requestData = function(dataRequest, callback) {
4822     dataRequest.requestProcessor_.prepareForSend(dataRequest);
4823     dataRequest.requestProcessor_.startProcessing();
4824 };
4825 
4826 MyOpenSpace.MySpaceContainer.prototype.enableCaja = function() {
4827     opensocial.Container.prototype.enableCaja();
4828 
4829     ___.allowCall(MyOpenSpace.Album.prototype, 'getField');
4830     ___.allowCall(MyOpenSpace.Album.prototype, 'setField_');
4831     
4832     ___.allowCall(MyOpenSpace.Video.prototype, 'getField');
4833     ___.allowCall(MyOpenSpace.Video.prototype, 'setField_');
4834     
4835     ___.allowCall(MyOpenSpace.Photo.prototype, 'getField');
4836     ___.allowCall(MyOpenSpace.Photo.prototype, 'setField_');
4837 };
4838 
4839 /**
4840  * Kicks off the request processor
4841  * @private
4842  * @private
4843  */
4844 MyOpenSpace.MySpaceContainer.prototype.startProcessor_ = function(){ //TODO: rework how we are unspooling requestactions??
4845     //if (this.requestProcessor_._readyToSend)
4846         //this.requestProcessor_.startProcessing();
4847 };
4848 
4849 MyOpenSpace.MySpaceContainer.prototype.newFetchGlobalAppDataRequest = function() {
4850     return {
4851 		type: MyOpenSpace.RequestType.FETCH_GLOBAL_DATA
4852 	};
4853 };
4854 
4855 MyOpenSpace.MySpaceContainer.prototype.newFetchInstanceAppDataRequest = function() {
4856     return {
4857 		type: MyOpenSpace.RequestType.FETCH_INSTANCE_DATA
4858 	};
4859 };
4860 
4861 MyOpenSpace.MySpaceContainer.prototype.newUpdateInstanceAppDataRequest = function() {
4862     return {
4863 		type: MyOpenSpace.RequestType.UPDATE_INSTANCE_DATA
4864 	};
4865 };
4866 
4867 MyOpenSpace.MySpaceContainer.prototype.newFetchPersonAppDataRequest = function(idSpec, keys, opt_params) {
4868     return {
4869 		type: MyOpenSpace.RequestType.FETCH_PERSON_DATA,
4870 		parameters : {
4871 		    idSpec: idSpec,
4872 		    keys: keys,
4873 		    opt_params: opt_params
4874 		}
4875 	};
4876 };
4877 
4878 MyOpenSpace.MySpaceContainer.prototype.newUpdatePersonAppDataRequest = function(id, key, value) {
4879     return {
4880 		type: MyOpenSpace.RequestType.UPDATE_PERSON_DATA,
4881 		parameters : {
4882 		    id: id,
4883 		    key : key,
4884 		    value : value
4885 		}
4886 	};
4887 };
4888 
4889 MyOpenSpace.MySpaceContainer.prototype.newRemovePersonAppDataRequest = function(id, keys) {
4890     return {
4891 		type: MyOpenSpace.RequestType.REMOVE_PERSON_DATA,
4892 		parameters : {
4893 		    id: id,
4894 		    keys: keys
4895 		}
4896 	};
4897 };
4898 
4899 MyOpenSpace.MySpaceContainer.prototype.newFetchActivitiesRequest = function(idSpec, opt_params) {
4900     return {
4901         type: MyOpenSpace.RequestType.FETCH_ACTIVITIES,
4902 		parameters : {
4903 		    idSpec: idSpec
4904 		}
4905 	};
4906 } ;
4907 
4908 MyOpenSpace.MySpaceContainer.prototype.requestCreateActivity = function(activity, priority, opt_callback) {
4909     var goodResult = function(response) {
4910         var callbackWithError = function(errorCode, errorMessage) {
4911             opt_callback(opensocial.Container.get().newResponseItem(null, null, errorCode, errorMessage));
4912         };
4913         
4914         if (response) {
4915             try{
4916                 response = eval("(" + response.responseText + ")");
4917             }
4918             catch (err) {
4919                 callbackWithError(opensocial.ResponseItem.Error.INTERNAL_ERROR, "Error parsing response.");
4920                 return;
4921             }
4922             
4923             if(response && "posted" === response.postactivitystatus){
4924                 opt_callback(opensocial.Container.get().newResponseItem(null, response, "", ""));
4925                 return;
4926             }
4927         }
4928         callbackWithError(opensocial.ResponseItem.Error.INTERNAL_ERROR, "Error parsing response.");
4929     };
4930     var badResult = function(response) {
4931         opt_callback(opensocial.Container.get().newResponseItem(null, null, response.errorCode, response.errorMessage));
4932     };
4933 
4934     if (!activity.getField(opensocial.Activity.Field.TITLE_ID)) {
4935         var ri = opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.BAD_REQUEST, "You must supply a TITLE_ID.");
4936         opt_callback(ri);
4937         return;
4938     }
4939 
4940     var dataRequestAction = {};
4941     dataRequestAction.method = "POST";
4942     dataRequestAction.endPoint = this.endPoint_.Activities.ViewerInsert;
4943     dataRequestAction.params = "templateId=";
4944     dataRequestAction.params += escape(activity.getField(opensocial.Activity.Field.TITLE_ID));
4945 
4946     if (activity.getField(opensocial.Activity.Field.TEMPLATE_PARAMS)) {
4947         dataRequestAction.params += "&templateParameters=";
4948         dataRequestAction.params += escape(gadgets.json.stringify(activity.getField(opensocial.Activity.Field.TEMPLATE_PARAMS)));
4949     }
4950 
4951     if (activity.getField(opensocial.Activity.Field.MEDIA_ITEMS)) {
4952         dataRequestAction.params += "&mediaItems=";
4953         var mediaItemsOld = activity.getField(opensocial.Activity.Field.MEDIA_ITEMS);
4954         var mediaItemsNew = "{";
4955 
4956         for (var i = 0; i < mediaItemsOld.length; i++) {
4957             if (0 !== i) {
4958                 mediaItemsNew += ",";
4959             }
4960             mediaItemsNew += "\"" + mediaItemsOld[i].getField(opensocial.MediaItem.Field.URL) + "\"";
4961         }
4962         mediaItemsNew += "}";
4963 
4964         dataRequestAction.params += escape(mediaItemsNew);
4965     }
4966 
4967     dataRequestAction.osToken_ = this.osToken_;
4968     MyOpenSpace.Ajax.sendRequest(dataRequestAction, "INSERT_ACTIVITIES-VIEWER", goodResult, badResult, true, null);
4969 };
4970 
4971 /**
4972  * TODO: comment this once finalized
4973  * IFPC support inside container
4974  * @private
4975  */
4976 var _IFPC = window["_IFPC"];
4977 MyOpenSpace.MySpaceContainer.prototype.registerParam = function(key, value) {
4978 
4979     /*if("appParams" === key){
4980         // unspool the opt_key params and put them in the base params_ list with the others.
4981         for(var i in value){
4982             this.params_[i] = value[i];
4983             gadgets.views.getParams()[i] = value[i];
4984         }
4985     }
4986     else*/ if("ptoString" === key){
4987         opensocial.Container.get().myspaceenvironment_ = this.newMySpaceEnvironment(value.split(","));
4988     }
4989     else{
4990         this.params_[key] = value;
4991         gadgets.views.getParams()[key] = value;
4992         //if("appid" === key){
4993             //this.prefs.parseUrl(value);
4994         //}
4995     }
4996 };
4997 
4998 MyOpenSpace.MySpaceContainer.prototype.requestPermission = function(permissions, reason, opt_callback){
4999 	var supportedPermissions = [
5000 		MyOpenSpace.Permission.VIEWER_DISPLAY_ON_PROFILE,
5001 		MyOpenSpace.Permission.VIEWER_DISPLAY_ON_HOME,
5002 		MyOpenSpace.Permission.VIEWER_SEND_UPDATES_TO_FRIENDS,
5003 		MyOpenSpace.Permission.VIEWER_ACCESS_TO_PRIVATE_VIDEOS_PHOTOS,
5004 		MyOpenSpace.Permission.VIEWER_ACCESS_TO_PUBLIC_VIDEOS_PHOTOS,
5005 		MyOpenSpace.Permission.VIEWER_SHOW_UPDATES_FROM_FRIENDS
5006 	];
5007 	
5008     if(gadgets.views.ViewType.CANVAS === gadgets.views.getCurrentView().getName()){
5009         var validatedPermissions = new Array();
5010         if(permissions && permissions instanceof Array) {
5011             for(i=0;i<permissions.length;i++) {
5012 				//Check that is a valid permission object
5013 				if (typeof(permissions[i].user) !== 'undefined' && 
5014 					typeof(permissions[i].permission) !== 'undefined'){
5015 					//Check if the permission is supported	
5016 					for (var supported  in supportedPermissions){
5017 						if (supportedPermissions[supported].user === permissions[i].user &&
5018 							supportedPermissions[supported].permission === permissions[i].permission){
5019 							//check if the user doesn't have the requested permission.
5020 							if (!this.hasPermission(permissions[i])){
5021 				                validatedPermissions.push(permissions[i].permission);									
5022 							}
5023 							break;
5024 						}
5025 					}
5026 
5027 				}
5028             }
5029         }
5030         
5031         var userGrantedPermissions_sync = function (permissionState){
5032             if(permissionState){
5033 				var currentContainer = opensocial.Container.get();
5034 				var currentPermissions = gadgets.views.getParams().viewerPerm;
5035 				var permissionsGranted = [];
5036                 for(var key in permissionState){
5037 					var permObj = null;
5038 					var granted = permissionState[key];
5039 					for (var permIdex in supportedPermissions){
5040 						if (supportedPermissions[permIdex].permission.toLowerCase() === key.toLowerCase()){
5041 							permObj = supportedPermissions[permIdex];
5042 							break;
5043 						}
5044 					}
5045 					if (permObj !== null){
5046 						if (granted) {
5047 							permissionsGranted.push(permObj);
5048 						}
5049 						var permissionExist = false;
5050 						var permissionIndex = 0;
5051 						//Add permission to viewerPerm if is not there
5052 						for (var permIndex in currentPermissions){
5053 							if (currentPermissions[permIdex] === permObj.permissionIndicator){
5054 								permissionExist = true;
5055 								permissionIndex = permIndex;
5056 								break;
5057 							}
5058 						}
5059 						if (!permissionExist && granted) {
5060 							currentPermissions.push(permObj.permissionIndicator);
5061 							currentContainer.registerParam("viewerPerm", currentPermissions);
5062 						}
5063 						else if (permissionExist && !granted){
5064 							currentPermissions.splice(permissionIndex, 1);
5065 							currentContainer.registerParam("viewerPerm", currentPermissions);
5066 						}
5067 					}
5068                 }
5069 				if (opt_callback) {
5070 					if (permissionsGranted.length > 0) {	
5071 						opt_callback(opensocial.Container.get().newResponseItem(null, permissionsGranted, "", ""));
5072 					}
5073 					else {
5074 						opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.INTERNAL_ERROR, "No new permissions were granted."));
5075 					}
5076 					return;
5077 				}
5078             }
5079             else{
5080                 if(opt_callback) opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.INTERNAL_ERROR, "No new permissions were granted."));
5081 				return;
5082             }
5083         };
5084         
5085 		if (validatedPermissions.length === 0) {
5086 			if(opt_callback) opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.INTERNAL_ERROR, "No new permissions were granted."));
5087 			return;
5088 		}
5089 		_IFPC.call(this.params_.panelId, 
5090 			"requestPermission", 
5091 			[this.params_.appid, validatedPermissions, reason], 
5092 			this.params_.remoteRelay, 
5093 			userGrantedPermissions_sync, 
5094 			this.params_.localRelay, 
5095 			null);
5096     }
5097 };
5098 
5099 
5100 
5101 MyOpenSpace.MySpaceContainer.prototype.requestSendMessage = function(recipients, message, opt_callback, opt_params){
5102 	//Only can run on canvas
5103 	if (gadgets.views.ViewType.CANVAS !== gadgets.views.getCurrentView().getName()) {
5104 		if (opt_callback) {
5105 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "requestSendMessage does not support this view, only the canvas view is supported."));
5106 		}
5107 		return;
5108 	}
5109 
5110 	var target_is_supported = false;
5111     var supported = opensocial.Container.get().getMySpaceEnvironment().getSupportedPostToTargets();
5112 	var messageType = message.getField(opensocial.Message.Field.TYPE);
5113 	for (var i = 0; i < supported.length; i++) {
5114         if (supported[i] === messageType) {
5115             target_is_supported = true;
5116             break;
5117         }
5118     }
5119 
5120     if (!target_is_supported || messageType == MyOpenSpace.PostTo.Targets.SHARE_APP) {
5121 		if (opt_callback) {
5122 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "MessageType is not supported."));
5123 		}
5124 		return;
5125 	}
5126 	
5127     if(opt_params){
5128         if(opt_params[opensocial.NavigationParameters.DestinationType.RECIPIENT_DESTINATION]){
5129 			if (opt_callback) {
5130 				opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "opensocial.NavigationParameters.DestinationType.RECIPIENT_DESTINATION is not supported."));
5131 			}
5132 			return;
5133         }
5134         else if (opt_params[opensocial.NavigationParameters.DestinationType.VIEWER_DESTINATION]) {
5135 			if (opt_callback) {
5136 				opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "opensocial.NavigationParameters.DestinationType.VIEWER_DESTINATION is not supported."));
5137 			}
5138 			return;
5139         }
5140     }
5141 
5142 
5143     if(recipients.constructor === Array){
5144 		if (opt_callback) {
5145 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "Unsupported idSpec, only VIEWER, OWNER or one friend ID is allowed."));
5146 		}
5147 		return;
5148     }
5149 	if (recipients !== opensocial.IdSpec.PersonId.VIEWER && recipients !== opensocial.IdSpec.PersonId.OWNER) {
5150 		var results = ("" + recipients).match(/^(?:myspace\.com:)?(\d+)$/);
5151 		if (results === null || results.length === 0) {
5152 			if (opt_callback) {
5153 				opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.BAD_REQUEST, "Unsupported idSpec, only VIEWER, OWNER or one friend ID is allowed."));
5154 			}
5155 			return;
5156 		}
5157 	}
5158 
5159     var request = opensocial.newDataRequest();
5160     request.add(request.newFetchPersonRequest(recipients));
5161     request.message = message;
5162     request.opt_callback = opt_callback;
5163     request.send(opensocial.Container.get().requestSendMessageWrapper);
5164 };
5165 
5166 MyOpenSpace.MySpaceContainer.prototype.requestShareApp = function(recipients, reason, opt_callback, opt_params) {
5167 	 if (gadgets.views.ViewType.CANVAS !== gadgets.views.getCurrentView().getName()) {
5168 		if (opt_callback) {
5169 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "requestShareApp does not support this view, only the canvas view is supported."));
5170 		}
5171 		return;
5172 	}
5173     if (opt_params) {
5174         if (opt_params[opensocial.NavigationParameters.DestinationType.RECIPIENT_DESTINATION]) {
5175 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "opensocial.NavigationParameters.DestinationType.RECIPIENT_DESTINATION is not supported."));
5176 			return;
5177         }
5178         else if (opt_params[opensocial.NavigationParameters.DestinationType.VIEWER_DESTINATION]) {
5179 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "opensocial.NavigationParameters.DestinationType.VIEWER_DESTINATION is not supported."));
5180 			return;
5181         }
5182     }
5183 
5184 	if (recipients.constructor === Array){
5185 		if (opt_params) {
5186 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.NOT_IMPLEMENTED, "Unsupported id, only one friend ID is allowed."));
5187 		}
5188 		return;
5189 	}
5190 	var results = ('' + recipients).match(/^(?:myspace\.com:)?(\d+)$/);
5191     if (results === null || results.length === 0) {
5192 		if (opt_params) {
5193 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.BAD_REQUEST, "Invalid id."));
5194 		}
5195 		return;
5196     }
5197     
5198     var request = opensocial.newDataRequest();
5199     request.add(request.newFetchPersonRequest(results[1]));
5200     reason.setField(opensocial.Message.Field.TYPE, MyOpenSpace.PostTo.Targets.SHARE_APP);
5201     request.message = reason;
5202     request.opt_callback = opt_callback;
5203     request.send(opensocial.Container.get().requestSendMessageWrapper);
5204 
5205 };
5206 
5207 MyOpenSpace.MySpaceContainer.prototype.requestSendMessageWrapper = function(response){
5208 
5209     var responseItem = response.get(MyOpenSpace.RequestType.FETCH_PERSON);
5210 	var originalRequest = responseItem.getOriginalDataRequest();
5211     var opt_callback = originalRequest.opt_callback;
5212 	if (response.hadError()) {
5213 		if (opt_callback) {
5214 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.INTERNAL_ERROR, "Error requesting person object. " + responseItem.getErrorMessage()));
5215 		}
5216 		return;
5217 	}
5218 	var person = responseItem.getData();
5219 	var message = originalRequest.message;
5220 
5221     opensocial.Container.get().requestSendMessageWrapperEx("", message, person, opt_callback);
5222 };
5223 
5224 /**
5225  * Takes some content from the app and sends it up to the site to be posted.
5226  * @param {String} os_token The token, this gets passed up so we can verify who's sending the request.
5227  * @param {opensocial.Message} message The content to be posted, the message type refers to the target of the post.
5228  * @param {opensocial.Person} opt_person An optional opensocial.Person object, used when a recipient is required, e.g. when posting a comment, this person will get the comment.
5229  * @param {Function} opt_callback Callback function, right now just for success/fail.
5230  * @private
5231  */
5232 MyOpenSpace.MySpaceContainer.prototype.requestSendMessageWrapperEx = function(os_token, message, opt_person, opt_callback) {
5233 
5234 
5235     var messageSubject = "", messageBody, messageType = MyOpenSpace.PostTo.Targets.PROFILE;
5236     if (null !== message && "undefined" !== typeof (message)) {
5237         messageSubject = message.getField(opensocial.Message.Field.TITLE);
5238         messageBody = message.getField(opensocial.Message.Field.BODY);
5239         messageType = message.getField(opensocial.Message.Field.TYPE);
5240     }
5241     else {
5242 		if (opt_callback) {
5243 			opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.BAD_REQUEST, "You must supply a valid opensocial.Message object."));
5244 		}
5245 		return;
5246     }
5247 	
5248     // subject and type are optional params for opensocial.newMessage, so define defaults here, i just randomly picked profile.
5249     var personId, personName, personImage, personProfile;
5250     if (null !== opt_person && "undefined" !== typeof (opt_person)) {
5251         personId = opt_person.getId();
5252 		personId = ('' + personId).match(/^(?:myspace\.com:)?(\d+)$/)[1];
5253         personName = opt_person.getDisplayName();
5254         personImage = opt_person.getField(opensocial.Person.Field.THUMBNAIL_URL);
5255         personProfile = opt_person.getField(opensocial.Person.Field.PROFILE_URL);
5256     }
5257 
5258     var mappedMessageType;
5259     switch (messageType) {
5260         case opensocial.Message.Type.PRIVATE_MESSAGE:
5261             mappedMessageType = MyOpenSpace.PostTo.Targets.SEND_MESSAGE;
5262             break;
5263         case opensocial.Message.Type.NOTIFICATION:
5264             mappedMessageType = MyOpenSpace.PostTo.Targets.BULLETINS;
5265             break;
5266         case opensocial.Message.Type.PUBLIC_MESSAGE:
5267             mappedMessageType = MyOpenSpace.PostTo.Targets.COMMENTS;
5268             break;
5269         default:
5270             mappedMessageType = messageType;
5271             break;
5272     }
5273 	
5274 	var messageSend_sync = function (postToResults){
5275         if (typeof(postToResults) === 'undefined') {
5276 			if (opt_callback) {
5277 				opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.INTERNAL_ERROR, "Error sending request."));
5278 			}
5279 			return;
5280 		}
5281 		
5282 		if (opt_callback) {
5283 			switch (postToResults){
5284 				case MyOpenSpace.PostTo.Result.ERROR:
5285 					opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.INTERNAL_ERROR, "Error sending request."));
5286 				break;
5287 				case MyOpenSpace.PostTo.Result.CANCELLED:
5288 				case MyOpenSpace.PostTo.Result.SUCCESS:
5289 					opt_callback(opensocial.Container.get().newResponseItem(null, postToResults, "", ""));
5290 					break;
5291 				default:
5292 					opt_callback(opensocial.Container.get().newResponseItem(null, null, opensocial.ResponseItem.Error.INTERNAL_ERROR, "Error sending request."));
5293 			}
5294 		}
5295 
5296     };
5297 	
5298 	
5299     _IFPC.call(
5300             this.params_.panelId,
5301             "postTo",
5302             [MyOpenSpace.MySpaceContainer.OSToken, mappedMessageType,
5303             messageSubject, messageBody, personId, personImage,
5304             personName, personProfile],
5305             this.params_.remoteRelay,
5306             messageSend_sync,
5307             this.params_.localRelay,
5308             null);
5309 
5310 
5311 };
5312 
5313 MyOpenSpace.MySpaceContainer.container_ = new MyOpenSpace.MySpaceContainer();
5314 /**
5315 * A helper class used to coordinate the app's body onload
5316 * @constructor
5317 * @private
5318 * @private
5319 */
5320 MyOpenSpace.OnLoad = function() { };
5321 
5322 
5323 /**
5324 * Run on body onload, this executes all the registered onload handlers and calls
5325 * gadgets.util.runOnLoadHandlers (the public facing onload handler) when complete.
5326 * @static
5327 * @private
5328 * @memberOf MyOpenSpace.OnLoad
5329 */
5330 MyOpenSpace.OnLoad.runOnLoadHandlers = function() {
5331     MyOpenSpace.OnLoad.raiseLoadedEvent();
5332     gadgets.util.runOnLoadHandlers();
5333 };
5334 
5335 /**
5336 * Function to alert the parent page that the app has finished loaded
5337 * @static
5338 * @private
5339 * @memberOf MyOpenSpace.OnLoad
5340 */
5341 MyOpenSpace.OnLoad.raiseLoadedEvent = function(){
5342     if(gadgets.views.getCurrentView().getName() !== gadgets.views.ViewType.HOME) return;
5343     
5344     var p = gadgets.views.getParams();
5345     var surface = gadgets.views.getCurrentView().getName();
5346     _IFPC.call(
5347                 p.panelId,
5348                 "requestShowApp",
5349                 [p.appid, surface.toLowerCase()],
5350                 p.remoteRelay,
5351                 null,
5352                 p.localRelay,
5353                 null);
5354 };/**
5355 * An extension of opensocial.Permission
5356 * @constructor
5357 * @private
5358 */
5359 MyOpenSpace.Permission = function() { };
5360 
5361 /**
5362 * The available permission types
5363 * @class
5364 * @name MyOpenSpace.Permission.Field
5365 * @static
5366 * @private
5367 */
5368 MyOpenSpace.Permission.Field = {
5369     DISPLAY_ON_PROFILE: "DisplayOnProfile",
5370     DISPLAY_ON_HOME: "DisplayOnHome",
5371     SEND_UPDATES_TO_FRIENDS: "SendUpdatesToFriends",
5372     SHOW_UPDATES_FROM_FRIENDS: "ShowUpdatesFromFriends",
5373     //ALLOW_SENDING_EMAILS: "AllowSendingEmails",
5374     ACCESS_TO_PRIVATE_VIDEOS_PHOTOS: "AccessToPrivateVideosPhotos",
5375     ACCESS_TO_PUBLIC_VIDEOS_PHOTOS: "AccessToPublicVideosPhotos"
5376 };
5377 
5378 
5379 /**
5380 * The available permission settings that can be checked
5381 * @class
5382 * @name MyOpenSpace.Permission
5383 * @static
5384 */
5385 MyOpenSpace.Permission = {
5386     /**
5387     * An object representing the permission to allow the app to appear on the viewer's profile.
5388     * @memberOf MyOpenSpace.Permission
5389     */
5390     VIEWER_DISPLAY_ON_PROFILE: {
5391         user: opensocial.IdSpec.PersonId.VIEWER,
5392         permission: MyOpenSpace.Permission.Field.DISPLAY_ON_PROFILE,
5393 		permissionIndicator : "DP"
5394     },
5395     /**
5396     * An object representing the permission to allow the app to appear on the viewer's home page.
5397     * @memberOf MyOpenSpace.Permission
5398     */
5399     VIEWER_DISPLAY_ON_HOME: {
5400         user: opensocial.IdSpec.PersonId.VIEWER,
5401         permission: MyOpenSpace.Permission.Field.DISPLAY_ON_HOME,
5402 		permissionIndicator : "DH"
5403     },
5404     /**
5405     * An object representing the permission to allow the app to send updates/notifications to the viewer's friends.
5406     * @memberOf MyOpenSpace.Permission
5407     */
5408     VIEWER_SEND_UPDATES_TO_FRIENDS: {
5409         user: opensocial.IdSpec.PersonId.VIEWER,
5410         permission: MyOpenSpace.Permission.Field.SEND_UPDATES_TO_FRIENDS,
5411 		permissionIndicator : "UT"
5412     },
5413     /**
5414     * An object representing the permission to allow the app to show updates/notifications from the viewer's friends.
5415     * @memberOf MyOpenSpace.Permission
5416     */
5417     VIEWER_SHOW_UPDATES_FROM_FRIENDS: {
5418         user: opensocial.IdSpec.PersonId.VIEWER,
5419         permission: MyOpenSpace.Permission.Field.SHOW_UPDATES_FROM_FRIENDS,
5420 		permissionIndicator : "UF"
5421     },
5422     /**
5423     * An object representing the permission to allow the app access to the viewer's private videos and photos.
5424     * @memberOf MyOpenSpace.Permission
5425     */
5426     VIEWER_ACCESS_TO_PRIVATE_VIDEOS_PHOTOS: {
5427         user: opensocial.IdSpec.PersonId.VIEWER,
5428         permission: MyOpenSpace.Permission.Field.ACCESS_TO_PRIVATE_VIDEOS_PHOTOS,
5429 		permissionIndicator : "PR"
5430     },
5431     /**
5432     * An object representing the permission to allow the app access to the viewer's public videos and photos.
5433     * @memberOf MyOpenSpace.Permission
5434     */
5435     VIEWER_ACCESS_TO_PUBLIC_VIDEOS_PHOTOS: {
5436         user: opensocial.IdSpec.PersonId.VIEWER,
5437         permission: MyOpenSpace.Permission.Field.ACCESS_TO_PUBLIC_VIDEOS_PHOTOS,
5438 		permissionIndicator : "PB"
5439     }//,
5440 //    /**
5441 //    * An object representing the permission to allow the app to appear on the owner's profile.
5442 //    * @memberOf MyOpenSpace.Permission
5443 //    * @ignore
5444 //    */
5445 //    OWNER_DISPLAY_ON_PROFILE: {
5446 //        user: opensocial.IdSpec.PersonId.OWNER,
5447 //        permission: MyOpenSpace.Permission.Field.DISPLAY_ON_PROFILE,
5448 //		  permissionIndicator : "DP"
5449 //    },
5450 //    /**
5451 //    * An object representing the permission to allow the app to appear on the owner's home page.
5452 //    * @memberOf MyOpenSpace.Permission
5453 //    * @ignore
5454 //    */
5455 //    OWNER_DISPLAY_ON_HOME: {
5456 //        user: opensocial.IdSpec.PersonId.OWNER,
5457 //        permission: MyOpenSpace.Permission.Field.DISPLAY_ON_HOME,
5458 //        permissionIndicator : "DH"
5459 //    },
5460 //    /**
5461 //    * An object representing the permission to allow the app to send updates/notifications to the owner's friends.
5462 //    * @memberOf MyOpenSpace.Permission
5463 //    * @ignore
5464 //    */
5465 //    OWNER_SEND_UPDATES_TO_FRIENDS: {
5466 //        user: opensocial.IdSpec.PersonId.OWNER,
5467 //        permission: MyOpenSpace.Permission.Field.SEND_UPDATES_TO_FRIENDS,
5468 //        permissionIndicator : "UT"
5469 //    },
5470 //    /**
5471 //    * An object representing the permission to allow the app to show updates/notifications from the owner's friends.
5472 //    * @memberOf MyOpenSpace.Permission
5473 //    * @ignore
5474 //    */
5475 //    OWNER_SHOW_UPDATES_FROM_FRIENDS: {
5476 //        user: opensocial.IdSpec.PersonId.OWNER,
5477 //        permission: MyOpenSpace.Permission.Field.SHOW_UPDATES_FROM_FRIENDS,
5478 //        permissionIndicator : "UF"
5479 //    },
5480 //    /**
5481 //    * An object representing the permission to allow the app access to the owner's private videos and photos.
5482 //    * @memberOf MyOpenSpace.Permission
5483 //    * @ignore
5484 //    */
5485 //    OWNER_ACCESS_TO_PRIVATE_VIDEOS_PHOTOS: {
5486 //        user: opensocial.IdSpec.PersonId.OWNER,
5487 //        permission: MyOpenSpace.Permission.Field.ACCESS_TO_PRIVATE_VIDEOS_PHOTOS,
5488 //        permissionIndicator : "PR"
5489 //    },
5490 //    /**
5491 //    * An object representing the permission to allow the app access to the owner's public videos and photos.
5492 //    * @memberOf MyOpenSpace.Permission
5493 //    * @ignore
5494 //    */
5495 //    OWNER_ACCESS_TO_PUBLIC_VIDEOS_PHOTOS: {
5496 //        user: opensocial.IdSpec.PersonId.OWNER,
5497 //        permission: MyOpenSpace.Permission.Field.ACCESS_TO_PUBLIC_VIDEOS_PHOTOS,
5498 //        permissionIndicator : "PB"
5499 //    }
5500 };
5501 
5502 /**
5503 * Returns true if the current gadget has access to the specified
5504 * permission. If the gadget calls opensocial.requestPermission and permissions
5505 * are granted then this function must return true on all subsequent calls.
5506 *
5507 * @param {opensocial.Permission} permission
5508 *    The <a href="opensocial.Permission.html">permission</a>
5509 * @return {Boolean}
5510 *    True if the gadget has access for the permission; false if it doesn't
5511 *
5512 * @member opensocial
5513 * @private
5514 * @private
5515 */
5516 MyOpenSpace.MySpaceContainer.prototype.hasPermission = function(permission) {
5517 	var viewerDeny = gadgets.views.getParams().denyViewer;
5518 	
5519 	//TODO this may not be true any more we need to checkt for BasicInformation.
5520 	if (viewerDeny){
5521 		return false;
5522 	}
5523 	
5524     if (permission === opensocial.Permission.VIEWER) {
5525         return true;
5526     }
5527 	
5528     var userPermissions;
5529 	
5530     if (permission && permission.user === opensocial.IdSpec.PersonId.VIEWER) {
5531 		userPermissions = gadgets.views.getParams().viewerPerm;
5532     }
5533     else if (permission && permission.user === opensocial.IdSpec.PersonId.OWNER) {
5534 		userPermissions = gadgets.views.getParams().ownerPerm;
5535     }
5536     else {
5537         throw "Invalid permission object."
5538         return;
5539     }
5540 
5541     for (var i in userPermissions) {
5542         if (userPermissions[i] === permission.permissionIndicator) {
5543             return true;
5544         }
5545     }
5546 
5547     return false;
5548 }
5549 
5550 /**
5551  * An extension of opensocial.Person
5552  * @constructor
5553  * @private
5554  * @param {Array<opensocial.Person.Field || MyOpenSpace.Person.Field>} opt_params Contains an Array with opensocial.Person.Field or MyOpenSpace.Person.Field values with which to populate the object
5555  * @param {Boolean} opt_isOwner Sets the person as the owner
5556  * @param {Boolean} opt_isOwner Sets the person as the viewer
5557  */
5558 MyOpenSpace.Person = function(opt_params, opt_isOwner, opt_isViewer) {
5559     opensocial.Person.call(this, opt_params, opt_isOwner, opt_isViewer);
5560     this["setField_"] = function(key,val) { this.fields_[key] = val; }; //TODO: find a better way to extend
5561     this._type = 0;
5562 };
5563 
5564 /**
5565  * The fields for the extended MyOpenSpace.Person
5566  * @class
5567  * @name MyOpenSpace.Person.Field
5568  * @static
5569  */
5570 MyOpenSpace.Person.Field = opensocial.Person.Field;
5571 
5572 /**
5573  * The URL of the medium version of the user's thumbnail
5574  * @memberOf MyOpenSpace.Person.Field
5575  */
5576 MyOpenSpace.Person.Field.MEDIUM_IMAGE = "medimImage";
5577 /**
5578  * The URL of the large version of the user's thumbnail
5579  * @memberOf MyOpenSpace.Person.Field
5580  */
5581 MyOpenSpace.Person.Field.LARGE_IMAGE ="largeImage";
5582 	
5583 
5584 MyOpenSpace.Person.inherits(opensocial.Person);
5585 
5586 /**
5587  * A class representing an PersonMood.
5588  * @constructor
5589  * @private
5590  */
5591 MyOpenSpace.PersonMood = function() {};
5592 /**
5593  * The fields for MyOpenSpace.PersonMood
5594  * @class
5595  * @name MyOpenSpace.PersonMood.Field
5596  * @static
5597  */
5598 MyOpenSpace.PersonMood.Field = {
5599     /**
5600      * A string indicating the person mood.
5601      * @memberOf MyOpenSpace.PersonMood.Field
5602      */
5603     MOOD:"MOOD",
5604     /**
5605      * A string indicating the person mood image url.
5606      * @memberOf MyOpenSpace.PersonMood.Field
5607      */
5608     MOOD_IMAGE_URL:"MOOD_IMAGE_URL",
5609     /**
5610      * A string indicating the last date time the mood was modified.
5611      * @memberOf MyOpenSpace.PersonMood.Field
5612      */
5613     MOOD_LAST_UPDATED:"MOOD_LAST_UPDATED"
5614 };
5615 
5616 /**
5617  * Returns the field specified by key
5618  * @param {String} key The key to search by
5619  * @return {MyOpenSpace.PersonMood || undefined} The PersonMood if found, nothing otherwise.
5620  */
5621 MyOpenSpace.PersonMood.prototype.getField = function(key) { return this[key]; };
5622 
5623 /**
5624  * Writes a value to the field specified by the key
5625  * @param {String} key The key to search by.
5626  * @param {String} val The value to set.
5627  * @private
5628  * @private
5629  */
5630 MyOpenSpace.PersonMood.prototype.setField_ = function(key,val) { this[key] = val; };/**
5631  * A class representing an PersonStatus.
5632  * @constructor
5633  * @private
5634  */
5635 MyOpenSpace.PersonStatus = function() {};
5636 /**
5637  * The fields for MyOpenSpace.PersonStatus
5638  * @class
5639  * @name MyOpenSpace.PersonStatus.Field
5640  * @static
5641  */
5642 MyOpenSpace.PersonStatus.Field = {
5643     /**
5644      * A string indicating the person status.
5645      * @memberOf MyOpenSpace.PersonStatus.Field
5646      */
5647     STATUS:"STATUS"
5648 };
5649 /**
5650  * Returns the field specified by key
5651  * @param {String} key The key to search by
5652  * @return {MyOpenSpace.PersonStatus || undefined} The PersonStatus if found, nothing otherwise.
5653  */
5654 MyOpenSpace.PersonStatus.prototype.getField = function(key) { return this[key]; };
5655 /**
5656  * Writes a value to the field specified by the key
5657  * @param {String} key The key to search by.
5658  * @param {String} val The value to set.
5659  * @private
5660  * @private
5661  */
5662 MyOpenSpace.PersonStatus.prototype.setField_ = function(key,val) { this[key] = val; };/**
5663  * A class representing a photo.
5664  * @constructor
5665  * @private
5666  */
5667 MyOpenSpace.Photo = function() {};
5668 
5669 /**
5670  * The fields for MyOpenSpace.Photo
5671  * @class
5672  * @name MyOpenSpace.Photo.Field
5673  * @static
5674  */
5675 MyOpenSpace.Photo.Field = {
5676     /**
5677      * A number representing a Photo's unique identifier.
5678      * @memberOf MyOpenSpace.Photo.Field
5679      */
5680     PHOTO_ID:"PHOTO_ID",
5681     
5682     /**
5683      * The RESTFUL URI with which to access the photo on the API.
5684      * @memberOf MyOpenSpace.Photo.Field
5685      */
5686     PHOTO_URI:"PHOTO_URI",
5687       
5688     /**
5689      * The URL of the photo.
5690      * @memberOf MyOpenSpace.Photo.Field
5691      */
5692     IMAGE_URI:"IMAGE_URI",
5693     
5694     /**
5695      * The photo's caption.
5696      * @memberOf MyOpenSpace.Photo.Field
5697      */
5698     CAPTION:"CAPTION"
5699 };
5700 
5701 /**
5702  * Returns the field specified by key
5703  * @param {String} key The key to search by
5704  * @return {MyOpenSpace.Photo || undefined} The photo if found, nothing otherwise.
5705  */
5706 MyOpenSpace.Photo.prototype.getField = function(key) { return this[key]; };
5707 
5708 /**
5709  * Writes a value to the field specified by the key
5710  * @param {String} key The key to search by.
5711  * @param {String} val The value to set.
5712  * @private
5713  * @private
5714  */
5715 MyOpenSpace.Photo.prototype.setField_ = function(key,val) { this[key] = val; };/**
5716  * Just a place-holder in order to extend MyOpenSpace.PostTo
5717  * @ignore
5718  */
5719 MyOpenSpace.PostTo = {};
5720 
5721 /**
5722  * Enumerates the targets for PostTo
5723  * @static
5724  * @class
5725  * @private
5726  * @name MyOpenSpace.PostTo.Targets
5727  */
5728 MyOpenSpace.PostTo.Targets = {
5729     /**
5730      * A user's profile, the specific section is specified on the Post To UI
5731      * @memberOf MyOpenSpace.PostTo.Targets
5732      */
5733     PROFILE:"PROFILE",
5734     
5735     /**
5736      * A message to another user's inbox
5737      * @memberOf MyOpenSpace.PostTo.Targets
5738      */
5739     SEND_MESSAGE:"SEND_MESSAGE",
5740     
5741     /**
5742      * A user's comments
5743      * @memberOf MyOpenSpace.PostTo.Targets
5744      */
5745     COMMENTS:"COMMENTS",
5746     
5747     /**
5748      * A user's bulletins
5749      * @memberOf MyOpenSpace.PostTo.Targets
5750      */
5751     BULLETINS:"BULLETINS",
5752     
5753     /**
5754      * A user's blog
5755      * @memberOf MyOpenSpace.PostTo.Targets
5756      */
5757     BLOG:"BLOG",
5758 
5759     /**
5760      * Request to share an app with another user
5761      * @memberOf MyOpenSpace.PostTo.Targets
5762      */
5763     SHARE_APP:"SHARE_APP"
5764 };
5765 
5766 
5767 /**
5768  * Enumerates the PostTo result
5769  * @static
5770  * @class
5771  * @name MyOpenSpace.PostTo.Result
5772  */
5773 MyOpenSpace.PostTo.Result = {
5774     /**
5775      * An error occurred in postTo request
5776      * @memberOf MyOpenSpace.PostTo.Result
5777      */
5778 	ERROR: -1,
5779 	
5780     /**
5781      * User pressed cancel before completion
5782      * @memberOf MyOpenSpace.PostTo.Result
5783      */
5784 	CANCELLED: 0,
5785 	
5786     /**
5787      * Successful postTo request completed
5788      * @memberOf MyOpenSpace.PostTo.Result
5789      */
5790 	SUCCESS: 1
5791 };/**
5792  * @class
5793  * @name MyOpenSpace.RequestProcessor_
5794  * @private
5795  * @private
5796  * MySpace's implementation of a data request manager; linking security, queueing, callbacks, responses, and request actions all together.
5797  * Created to abstract away from OpenSocial's base objects so MySpace can link in EXTENDED entities/methods more easily.
5798  * 
5799  */
5800 if (typeof(MyOpenSpace.RequestProcessor_) == "undefined") MyOpenSpace.RequestProcessor_ = {};
5801 
5802 /**
5803  * Do not instantiate.  Each DataRequest will create its' own RequestProcessor_ and direct work items through it automatically.
5804  * @private
5805  * @private
5806  * @constructor MyOpenSpace.RequestProcessor_
5807  */
5808 MyOpenSpace.RequestProcessor_ = function(){
5809     //this._resultCache = new QuickHash();
5810     this.executionInterval_ = 200;
5811     //this.executionModel_ = MyOpenSpace.RequestProcessor_.ExecutionModel_.ASYNC;
5812     this.executionModel_ = MyOpenSpace.RequestProcessor_.ExecutionModel_.SERIAL;
5813     //this.executionModel_ = MyOpenSpace.RequestProcessor_.ExecutionModel_.THROTTLED
5814     this.requestActions_ = null;
5815     this.TotalWorkItems;
5816     this.WorkItemsToProcess;
5817     this.WorkItemsProcessed;
5818     //this._readyToSend = false;
5819     this.paused_ = false;
5820     this.aborted_ = false;
5821     this.authorizationSchemaSet_ = false;
5822     
5823     this.init();
5824 };
5825 
5826 /**
5827  * Specifies how the RequestProcessor will process the queue of work items.
5828  * @static
5829  * @class
5830  * @name MyOpenSpace.RequestProcessor_.ExecutionModel_.
5831  * @private
5832  * @private
5833  */
5834 MyOpenSpace.RequestProcessor_.ExecutionModel_ = { 
5835     /**
5836      * @property {int} SERIAL Executes the queue async one after each other.  Essentially a blocking async.
5837      * @private
5838      */
5839     SERIAL: "SERIAL",
5840     
5841     /**
5842      * Not currently supported.
5843      * @property {int} ASYNC Executes the queue async one after each other, without blocking.
5844      * @private
5845      */
5846     ASYNC: "ASYNC",
5847     
5848     /**
5849      * Not currently supported.
5850      * @property {int} THROTTLED Same as SERIAL, but with a delay between each work item processed.  Use throttleProcessingSpeed(msDelay) to set delay time.
5851      * @private
5852      */
5853     THROTTLED: "THROTTLED"
5854 }; 
5855 
5856 /**
5857  * @class
5858  * @name MyOpenSpace.RequestProcessor_
5859  * @private
5860  * @private
5861  */
5862 MyOpenSpace.RequestProcessor_.prototype = {
5863      /**
5864      * Init handles all initialization for the RequestProcessor_.
5865      * @memberOf MyOpenSpace.RequestProcessor_
5866      * @private
5867      */
5868     init: function() {
5869         this.workItemPool_ = new this.delayShiftQueue();
5870     },
5871     
5872     /**
5873      * prepareForSend will setup the queue in preparation for processing the work items.
5874      * @param {opensocial.DataRequest} ptr Pointer to DataRequest
5875      * @memberOf MyOpenSpace.RequestProcessor_
5876      * @private
5877      */
5878     prepareForSend : function(ptr) {
5879         //this._readyToSend = true;
5880         this.requestActions_ = new MyOpenSpace.DataRequest.RequestActions_(ptr);
5881         //startProcessing();
5882         //this.workItemPool_.prioritize();
5883     },
5884     
5885      /**
5886      * setAuthorization sets the authorization template used to verify/set authorizations on each DataRequest's request.
5887      * @memberOf MyOpenSpace.RequestProcessor_
5888      * @param {Object} template The authorization template to apply to this DataRequest.
5889      * @private
5890      */
5891     setAuthorization: function(template) {
5892         this.authTemplate_ = template;
5893 	    this.authorizationSchemaSet_ = true;
5894 	},
5895 	
5896 	 /**
5897      * addWorkItem will add a work item to the RequestProcessor's queue.
5898      * @memberOf MyOpenSpace.RequestProcessor_
5899      * @param {MyOpenSpace.RequestProcessor_.WorkItem} workItem The work item to add to the queue.
5900      * @private
5901      */
5902     addWorkItem: function(workItem) { // was:addWorkItem: function(workItem, priority) {
5903         //if (!this._readyToSend){
5904             //TODO: put hasPermission/requestPermission here
5905             //workItem.priority = priority;
5906             this.workItemPool_.push(workItem);
5907             
5908         //}
5909     },
5910     
5911      /**
5912      * startProcessing will being executing work items from the queue, as defined by the ExecutionModel_.
5913      * @memberOf MyOpenSpace.RequestProcessor_
5914      * @private
5915      */
5916     startProcessing: function() {
5917         switch (this.executionModel_) {
5918             case MyOpenSpace.RequestProcessor_.ExecutionModel_.SERIAL: //one after the other
5919                 this.process();
5920                 break;
5921             case MyOpenSpace.RequestProcessor_.ExecutionModel_.ASYNC: // all async at once
5922                 for (var i=0;i<=this.workItemPool_.size();i++)
5923                 {
5924                     var workItem = this.workItemPool_.pop();
5925                     this.process(workItem);
5926                 }
5927                 break;
5928             case MyOpenSpace.RequestProcessor_.ExecutionModel_.THROTTLED: // one after the other + delay
5929                 this.processWithDelay();
5930                 break;
5931         }
5932     },
5933     
5934     /**
5935      * process will execute a workItem
5936      * @param {MyOpenSpace.RequestProcessor_.WorkItem} workItem to process; if omitted - pop the next work item from queue.
5937      * @memberOf MyOpenSpace.RequestProcessor_
5938      * @private
5939      */
5940     process: function(workItem) {
5941         if (workItem) {
5942             this.requestActions_[workItem.type](workItem);
5943             return;
5944         }
5945         
5946         workItem = this.workItemPool_.pop();
5947         if(workItem)
5948             this.requestActions_[workItem.type](workItem);
5949         
5950         if(this.executionModel_ === MyOpenSpace.RequestProcessor_.ExecutionModel_.THROTTLED)
5951             this.processWithDelay();
5952         //else if (this.workItemPool_.size() > 0 && !this.paused_ && !this.aborted_)
5953             //this.process(); // queue up next work item immediately
5954     },
5955     
5956     /**
5957      * processWithDelay will execute a workItem, then set an interval of executionInterval before executing the next work item; so long as pauseProcessing() or abortProcessing() has not be invoked.
5958      * @param {MyOpenSpace.RequestProcessor_.WorkItem} workItem to process; if omitted - pop the next work item from queue.
5959      * @memberOf MyOpenSpace.RequestProcessor_
5960      * @private
5961      */
5962     processWithDelay: function() {
5963         //var workItem = this.workItemPool_.pop();
5964         var pointer = this;
5965         if (pointer.workItemPool_.size() > 0 && !pointer.paused_ && !pointer.aborted_)
5966             setTimeout(function () { pointer.process(); }, pointer.executionInterval_); // queue up next work item after executionInterval ms
5967         //this.requestActions_[workItem.type](workItem);
5968     },
5969     
5970     /**
5971      * pauseProcessing will pause the execution of SERIAL and THROTTLED execution models, resumeProcessing() will continue execution.
5972      * @memberOf MyOpenSpace.RequestProcessor_
5973      * @private
5974      */
5975     pauseProcessing: function() {
5976         this.paused_ = true;
5977     },
5978     
5979     /**
5980      * abortProcessing will stop the execution of SERIAL and THROTTLED execution models, with no option to recover.
5981      * @memberOf MyOpenSpace.RequestProcessor_
5982      * @private
5983      */
5984     abortProcessing: function() {
5985         this.aborted_ = true;
5986     },
5987     
5988     /**
5989      * resumeProcessing will unpause the execution of SERIAL and THROTTLED execution models.
5990      * @memberOf MyOpenSpace.RequestProcessor_
5991      * @private
5992      */
5993     resumeProcessing: function() {
5994         this.paused_ = false;
5995     },
5996     
5997     /**
5998      * throttleProcessingSpeed sets the delay between work item processing in THROTTLED execution model.
5999      * @memberOf MyOpenSpace.RequestProcessor_
6000      * @private
6001      */
6002     throttleProcessingSpeed: function(msDelay) {
6003         this.executionInterval_ = msDelay;
6004     },
6005     
6006     /**
6007      * delayShiftQueue is a delay shift queue implementation.  Only shifts queue after (len/2) pops to save cycles.
6008      * @memberOf MyOpenSpace.RequestProcessor_
6009      * @private
6010      */
6011     delayShiftQueue: function(){ 
6012         var q=new Array();
6013         var qSpace=0;
6014         
6015         /**
6016          * push will add a work item to the queue
6017          * @param {MyOpenSpace.RequestProcessor_.WorkItem} element Work item to add to the queue. 
6018          * @private
6019          */
6020         this.push=function(element){
6021             q.push(element);
6022         };
6023         
6024         /**
6025          * pop will return the next work item in the queue.  Queue will be shifted once length/2 calls have been made to this function.
6026          * @private
6027          */
6028         this.pop=function(){
6029             if (q.length){
6030                 var element=q[qSpace];
6031                 if (++qSpace*2 >= q.length){
6032                     for (var i=qSpace;i<q.length;i++) q[i-qSpace]=q[i];
6033                     q.length-=qSpace;
6034                     qSpace=0;
6035                 }
6036                 return element;
6037             } else {
6038                 return undefined;
6039             }
6040         };
6041         
6042         /**
6043          * size will return the number of work items in the queue.
6044          * @private
6045          */
6046         this.size=function(){
6047             return q.length;
6048         };
6049         
6050         /**
6051          * prioritize will sort the queue based on priority (critical, high, normal, low)
6052          * @private
6053          */
6054         this.prioritize=function(){
6055             q.sort(this.prioritySort_);
6056         };
6057         
6058         /**
6059          * prioritySort_ is an internal comparer for ordering work items based on priority.
6060          * @private
6061          */
6062         this.prioritySort_=function(a,b){
6063             if (a.priority > b.priority) return -1;
6064             if (a.priority == b.priority) return 0;
6065             if (a.priority < b.priority) return 1;
6066         };
6067    }
6068 };
6069 
6070 /**
6071  * Adds work item properties to a DataRequest for processing within the queue.
6072  * @class
6073  * @name MyOpenSpace.RequestProcessor_.WorkItem
6074  * @private
6075  */
6076 if (typeof(MyOpenSpace.RequestProcessor_.WorkItem) == "undefined") MyOpenSpace.RequestProcessor_.WorkItem = {};
6077 
6078 /**
6079  * @constructor MyOpenSpace.RequestProcessor_.WorkItem
6080  * @param {MyOpenSpace._DataRequest} request The datarequest associated with the work item.
6081  * @private
6082  */
6083 MyOpenSpace.RequestProcessor_.WorkItem = new function(request){
6084     this.Request = request;
6085     this.CreationTime = new Date().getTime(); //ms in epoch time
6086     this.QueueTime = null;
6087     this.WorkItemType = null;
6088     this.ProcessStartTime = null;
6089     this.ProcessEndTime = null;
6090     this.Priority = MyOpenSpace.RequestProcessor_.WorkItem.NORMAL;
6091 };
6092 
6093 /**
6094  * Defines level of priority for work items.  Processed in this order: CRITICAL -> HIGH -> NORMAL -> LOW
6095  * Allows for a queue's priority to be calculated as a sum of all work item's priorities.
6096  * We may want to add in a dependency object for work items, so one may process first if another depends on it
6097  * Note: Currently we don't use priorities for anything.
6098  * @static
6099  * @class
6100  * @name Priority
6101  * @private
6102  */
6103 MyOpenSpace.RequestProcessor_.WorkItem.Priority = { 
6104     /**
6105      * The integer weight for a low priority item.  Decreases queue priority.
6106      * @memberOf MyOpenSpace.RequestProcessor_.WorkItem.Priority
6107      * @private
6108      */
6109     "LOW": -1,
6110     
6111     /**
6112      * The integer weight for a normal priority item.  Does not affect queue priority.
6113      * @memberOf MyOpenSpace.RequestProcessor_.WorkItem.Priority
6114      * @private
6115      */
6116     "NORMAL": 0,
6117     
6118     /**
6119      * The integer weight for a high priority item.  Increases queue's priority.
6120      * @memberOf MyOpenSpace.RequestProcessor_.WorkItem.Priority
6121      * @private
6122      */
6123     "HIGH": 1,
6124     
6125     /**
6126      * The integer weight for a critical priority item.  Increases queue's priority by twice magnitude of high.
6127      * @memberOf MyOpenSpace.RequestProcessor_.WorkItem.Priority
6128      * @private
6129      */
6130     "CRITICAL": 2
6131 };/**
6132  * A stringbuilder implementation similar to .net - use in place of += for any strcat operations
6133  * @constructor
6134  * @name MyOpenSpace.StringBuilder
6135  */
6136  MyOpenSpace.StringBuilder = function(value) {
6137     this.strings_ = [];
6138     this.append(value);
6139  };
6140  /**
6141  * Appends a string
6142  * @member MyOpenSpace.StringBuilder
6143  */
6144  MyOpenSpace.StringBuilder.prototype.append = function (value) {
6145     if (value) this.strings_.push(value);
6146  };
6147  
6148  /**
6149  * Clears the stringbuilder
6150  * @member MyOpenSpace.StringBuilder
6151  */
6152  MyOpenSpace.StringBuilder.prototype.clear = function () {
6153     this.strings_.length = 0;
6154  };
6155  
6156  /**
6157  * Returns the string built
6158  * @member MyOpenSpace.StringBuilder
6159  */
6160  MyOpenSpace.StringBuilder.prototype.toString = function () {
6161     return this.strings_.join("");
6162  };/**
6163  * A class representing a video.
6164  * @constructor
6165  * @private
6166  */
6167 MyOpenSpace.Video = function() {};
6168 
6169 /**
6170  * The fields for MyOpenSpace.Video
6171  * @class
6172  * @name MyOpenSpace.Video.Field
6173  * @static
6174  */
6175 MyOpenSpace.Video.Field = {
6176     /**
6177      * A number representing a Video's unique identifier.
6178      * @memberOf MyOpenSpace.Video.Field
6179      */
6180     VIDEO_ID:"VIDEO_ID",
6181     
6182     /**
6183      * The RESTFUL URI with which to access the video on the API.
6184      * @memberOf MyOpenSpace.Video.Field
6185      */
6186     VIDEO_URI:"VIDEO_URI",
6187     
6188     /**
6189      * The video's title.
6190      * @memberOf MyOpenSpace.Video.Field
6191      */
6192     TITLE:"TITLE",
6193     
6194     /**
6195      * The date the video was created.
6196      * @memberOf MyOpenSpace.Video.Field
6197      */
6198     DATE_CREATED:"DATE_CREATED",
6199     
6200     /**
6201      * The date the video was last updated.
6202      * @memberOf MyOpenSpace.Video.Field
6203      */
6204     LAST_UPDATE:"LAST_UPDATE",
6205     
6206     /**
6207      * An integer representing the media type for this video.
6208      * @memberOf MyOpenSpace.Video.Field
6209      */
6210     MEDIA_TYPE:"MEDIA_TYPE",
6211     
6212     /**
6213      * A URL for the thumbnail image associated with this video.
6214      * @memberOf MyOpenSpace.Video.Field
6215      */
6216     THUMB_URI:"THUMB_URI",
6217     
6218     /**
6219      * A description of the video.
6220      * @memberOf MyOpenSpace.Video.Field
6221      */
6222     DESCRIPTION:"DESCRIPTION",
6223     
6224     /**
6225      * The current status of the video, such as "ProcessingFailed"
6226      * @memberOf MyOpenSpace.Video.Field
6227      */
6228     MEDIA_STATUS:"MEDIA_STATUS",
6229     
6230     /**
6231      * The length of the video.
6232      * @memberOf MyOpenSpace.Video.Field
6233      */
6234     RUN_TIME:"RUN_TIME",
6235     
6236     /**
6237      * An integer representing the number of views the video has currently received.
6238      * @memberOf MyOpenSpace.Video.Field
6239      */
6240     TOTAL_VIEWS:"TOTAL_VIEWS",
6241     
6242     /**
6243      * An integer representing the number of comments the video has currently received.
6244      * @memberOf MyOpenSpace.Video.Field
6245      */
6246     TOTAL_COMMENTS:"TOTAL_COMMENTS",
6247     
6248     /**
6249      * An integer representing the rating the video has currently received.
6250      * @memberOf MyOpenSpace.Video.Field
6251      */
6252     TOTAL_RATING:"TOTAL_RATING",
6253     
6254     /**
6255      * An integer representing the number of votes the video has currently received.
6256      * @memberOf MyOpenSpace.Video.Field
6257      */
6258     TOTAL_VOTES:"TOTAL_VOTES",
6259     
6260     /**
6261      * A string representing the video's country, in terms of identifying culture, not necessarily geographic location.
6262      * @memberOf MyOpenSpace.Video.Field
6263      */
6264     COUNTRY:"COUNTRY",
6265     
6266     /**
6267      * A string representing the video's language.
6268      * @memberOf MyOpenSpace.Video.Field
6269      */
6270     LANGUAGE:"LANGUAGE"
6271 };
6272 
6273 /**
6274  * Returns the field specified by key
6275  * @param {String} key The key to search by
6276  * @return {MyOpenSpace.Video || undefined} The video if found, nothing otherwise.
6277  */
6278 MyOpenSpace.Video.prototype.getField = function(key) { return this[key]; };
6279 
6280 /**
6281  * Writes a value to the field specified by the key
6282  * @param {String} key The key to search by.
6283  * @param {String} val The value to set.
6284  * @private
6285  * @private
6286  */
6287 MyOpenSpace.Video.prototype.setField_ = function(key,val) { this[key] = val; };