	/** DELETE ME WHEN FINISHED?! **/
	var dump = function(node, maxDepth, depth, str) {

    if (maxDepth === undefined) {
      var maxDepth = 10;
    }
	  if (depth === undefined) {
	   var depth = 0;
	  } 
	  if (str === undefined) {
      var str = '<pre>';
    }

    var val, w;
    
    for (i in node) {
      val = node[i];
      w = depth * 20;
      
      str += '<div style="margin-left:'+w+'px;border-left:2px solid #999;padding:10px;">';
      str += '<b>'+i+': </b>';

      if (typeof val == 'object' && depth < maxDepth) {
        str += "[object]\n";
        str = dump(val, maxDepth, depth + 1, str);
      } else {
        str += val;
      }

      str += '</div>';

    }
    return(str);
	};



(function($) {

	/* jQuery extensions -- find homes for these! */
  $.editable.addInputType('defaults', {
    element : function(settings, original) {
      var input = $('<input type="hidden">');        
      $(this).append(input);
      return(input);
    },
    content : function(string, settings, original) {
      $(':input:first', this).val(string);
    },
    buttons : function(settings, original) {
      if (settings.submit) {
        var submit = $('<button type="submit" class="jeditable-input jeditable-button jeditable-submit">').text(settings.submit);
  			$(this).append(submit);
      }
      if (settings.cancel) {
        var cancel = $('<button type="reset" class="jeditable-input jeditable-button jeditable-reset">').text(settings.cancel);
        $(this).append(cancel);

        $(cancel).click(function() {
								 //alert(original.revert);
          
		  var original_content = null;
		  var original_content = original.revert;
		  $(original).html(original_content);
		  original.editing = false;
		  return false;
		  
		  
        });
      }
    }
  });
  
  $.editable.addInputType('text', {
    element : function(settings, original) {
      var input = $('<input class="jeditable-input jeditable-text">');
      if (settings.width  != 'none') { input.width(settings.width);  }
      if (settings.height != 'none') { input.height(settings.height); }
      /* https://bugzilla.mozilla.org/show_bug.cgi?id=236791 */
      //input[0].setAttribute('autocomplete','off');
      input.attr('autocomplete','off');
      $(this).append(input);
      return(input);
    }
  });
  
  $.editable.addInputType('textarea', {
    element : function(settings, original) {
      var textarea = $('<textarea class="jeditable-input jeditable-textarea">');
      if (settings.rows) {
        textarea.attr('rows', settings.rows);
      } else {
        textarea.height(settings.height);
      }
      if (settings.cols) {
        textarea.attr('cols', settings.cols);
      } else {
        textarea.width(settings.width);
      }
      $(this).append(textarea);
      return(textarea);
    }
  });

  $.editable.addInputType('textarea-markitup', {
    element : function(settings, original) {
      var textarea = $('<textarea class="jeditable-input jeditable-textarea">');
      if (settings.rows) {
        textarea.attr('rows', settings.rows);
      } else {
        textarea.height(settings.height);
      }
      if (settings.cols) {
        textarea.attr('cols', settings.cols);
      } else {
        textarea.width(settings.width);
      }
      $(this).append(textarea);
      textarea.markItUp(Ultra.app.Community.getMarkItUpSettings());
	  
      return(textarea);
    }
  });
  
  $.editable.addInputType('select', {
    element : function(settings, original) {
      var select = $('<select class="jeditable-input jeditable-select">');
      $(this).append(select);
      return(select);
    },
    content : function(string, settings, original) {
      if (String == string.constructor) { 	 
        eval ('var json = ' + string);
        for (var key in json) {
          if ('selected' == key) {
            continue;
          } 
          var option = $('<option>').val(key).append(json[key]);
          $('select', this).append(option); 	 
        }
      }
      /* Loop option again to set selected. IE needed this... */ 
      $('select', this).children().each(function() {
        if ($(this).val() == json['selected']) {
          $(this).attr('selected', 'selected');
        };
      });
    }
  });
  
  $.editable.addInputType('autoselect', {
    element: function(settings, original) {
			var form = $(this);
      var select = $('<select class="jeditable-input jeditable-select jeditable-autoselect">').change(function(){
				form.submit();
			});
			form.append(select);
      return (select);
    },
    content : function(string, settings, original) {
      var selected = original.revert;
      if (String == string.constructor) { 	 
        eval ('var json = ' + string);
        for (var key in json) {
          if ('selected' == key) {
            selected = json[key];
            continue;
          } 
          var option = $('<option>').val(key).append(json[key]);
          $('select', this).append(option); 	 
        }
      }
      /* Loop option again to set selected. IE needed this... */ 
      $('select', this).children().each(function() {
        if ($(this).val() == selected) {
          $(this).attr('selected', 'selected');
        };
      });
    }
  });
  
  

  $.fn.getValues = function() {
    var values = {};
    this.each(function() {
      $(this).find('input, textarea, select').each(function() {
        var field = this.name;
        if (field !== '') {
          values[field] = $(this).val();
        }
      });
    });
    return values;
  };


  $.fn.validate = function(validators) {

    var internals = {
      notEmpty: function(val) {
        return val !== '';
      }
    };
    
    var errors = [];    
    
    this.each(function() {
      
      $(this).find('input, textarea, select').each(function() {
        
        var field = this.name;
        
        if (field !== '' && validators[field] !== undefined) {
          
          var value     = $(this).val();
          var validator = validators[field][0];
          var error_msg = validators[field][1];

          if (!(validator instanceof Function)) {
            validator = internals[validator];
          }
          
          if (!validator(value)) {
            errors.push({
              field:   field,
              message: error_msg
            });
          }
        }
        
      });
    });
    
    return errors;
  };






    var isDefined = function(obj) {    
      return typeof(obj) !== 'undefined';
    };


    /**
     *  getSelectionRange
     *
     */
    $.fn.getSelectionRange = function() {

      var start, end;
      
      var el = this[0];
      el.focus();
      
      // Mozilla / Safari
      if (isDefined(el.selectionStart)) {                  

        start = el.selectionStart;
        end   = el.selectionEnd;

      // IE
      } else if (isDefined(document.selection) && isDefined(document.selection.createRange)) {

        var range = document.selection.createRange();
        var range_length = range.text.length;

        if(range.parentElement() != el) {
          throw('Unable to get selection range.');
        }

        // Textarea
        if (el.type === 'textarea') {

          var duplicate_range = range.duplicate();
          duplicate_range.moveToElementText(el);
          duplicate_range.setEndPoint('EndToEnd', range);
        
          start = duplicate_range.text.length - range_length;
                    
        // Text Input
        } else {

          var text_range = el.createTextRange();
          text_range.setEndPoint("EndToStart", range);

          start = text_range.text.length;
        }
        
        end = start + range_length;

      // Unsupported type
      } else {
        throw('Unable to get selection range.');
      }      

      return {
        start: start,
        end:   end
      };
    };

    $.fn.getSelectionStart = function() {
      return this.getSelectionRange().start;
    }

    $.fn.getSelectionEnd = function() {
      return this.getSelectionRange().end;
    }
    
    
    /**
     *  setSelectionRange
     *
     */
    $.fn.setSelectionRange = function(start, end) {

      var el = this[0];
      el.focus();

      if (!isDefined(end)) {
        end = start;
      }
      
      // Mozilla / Safari
      if (isDefined(el.selectionStart)) {
      
        el.setSelectionRange(start, end);
        
      // IE
      } else if (isDefined(document.selection) && isDefined(document.selection.createRange)) {

        var value = this.val();
        var range = el.createTextRange();
        end   -= start + value.slice(start + 1, end).split("\n").length - 1;
        start -= value.slice(0, start).split("\n").length - 1;
        range.move('character', start);
        range.moveEnd('character', end);
        range.select();

      // Unsupported
      } else {      
        throw('Unable to set selection range.');
      }      

      return this;
    };



    /**
     *  getSelectedText
     *
     */
    $.fn.getSelectedText = function() {
    
      var selection = this.getSelectionRange();
      return this.val().substring(selection.start, selection.end);
    };



    /**
     *  setSelectedText
     *
     */
    $.fn.setSelectedText = function(text, select_text) {
    
      var selection = this.getSelectionRange();
      var start = selection.start;
      var end   = selection.end;
      var value = this.get(0).value; // DO NOT USE this.val() -- BROKEN IN IE
      
      this.val(value.substring(0, start) + text + value.substring(end, value.length));
      if (select_text == true) {
        this.setSelectionRange(start, start + text.length);
      } else {
        this.setSelectionRange(start + text.length, start + text.length);
      }

      return this;
    };


})(jQuery);








(function($) {
  
  /**
   *  Community
   *
   */
  Ultra.app.Community = function() {


    /**
     *  Public properties/methods
     *
     */
    var _this = {
      
      API_URL: '/flashApps/site/community/API.php',
      

      parseXMLNodeAsHTML: function(xml, node) {
        return $($(node, xml).text());
      },
      
      
      /**
       * Initiate an Ajax request to the Community API
       * @method  makeAPIRequest
       * @param   {object}  options   Ajax configuration
       */
      makeAPIRequest: function(options) {
		  //alert(options);
		  var Community = Ultra.app.Community;
        var config = $.extend({
          url:      this.API_URL,
          dataType: 'xml',
          type:     'POST',
		error: function() {
    	Community.handleError('Community.makeAPIRequest');
					}
        }, options || {});
		
        return $.ajax(config);
      },
      
    
      /**
       * Execute an action from the API response (uses jQuery methods)
       * @method  executeAPIAction
       * @param   {XML Element}  node   An XML node containing information
       */
      executeAPIAction: function(node) {
		  
        var action  = $(node);
        var content = $(action.text());
        var method  = action.attr('method');
        var target  = action.attr('target') ? $(action.attr('target')) : null;

        return content[method](target);
      },
      
    
      /**
       * Execute multiple actions from the API response (uses jQuery methods)
       * @method executeAPIActions
       * @param  {XML Element}
       */
      executeAPIActions: function(xml) {
        return $('action', xml).each(function() {
          return Ultra.app.Community.executeAPIAction(this);
        });
      },


      /**
       * Returns a default configuration object for jEditable inline widgets
       * @method 
       * @param  
       */
			apiUpdateConfigObject: function(options) {
		    return $.extend({
		      indicator: 'Saving...',
					id: 'uid',
					cssclass: 'jeditable',
					onblur: 'ignore'
					//onblur: 'submit'
		    }, options);
		  },


      /**
      * Returns a default data object for jEditable inline widgets
       * @method 
       * @param  
       */
			apiDataObject: function(options) {
				//alert("apidataobject");
		    return $.extend({
		      accessLevelID: 3,
		      viewMode: 'formElement'
		    }, options || {});
		  },


      /**
       * 
       * @method 
       * @param  
       */
			apiUpdate: function(value, obj) {
				//alert("apiupdate");
				var Community = Ultra.app.Community;

				var request = Community.makeAPIRequest({
					async: false,
					data: Community.apiDataObject($.extend(obj.submitdata, {
			      value: value
			    }))
				});

				var response = request.responseXML;				
        var value = $('value', response).text();

				return value;
			},
			
			
      /**
       * 
       * @method 
       * @param  
       */
			handleError: function(msg) {
        if (window.confirm("We have encountered a minor error.\n\nWould you like to take a moment to report this error and help us improve your experience?")) {
          location.href = 'feedback.php?error=' + msg;
        };
      },

			


      /**
       * 
       * @method 
       * @param  
       */
			togglePanel: function() {
  			$(this.hash).toggle();
  			$(this).toggleClass('selected');
        return false;
      }
      
    };
    
    return _this;
  
  }();


	
		Ultra.app.Community.removeComment = function() {
      if (!window.confirm('Are you sure you want to delete this comment?')) {
        return false;
      };

  	  var form = $(this);
      var data = form.getValues();

      var Community = Ultra.app.Community;
  
      Community.makeAPIRequest({
        data: data,
  
        // Handle error    
        error: function() {
          Community.handleError('Ultra.app.Community.removeComment');
        },
  
        // Handle success
        success: function(xml) {
          var comment = $('#comment_' + data.commentID);
          var commentList = comment.parent('.commentList');
          comment.fadeOut(function() {
            comment.remove();
            var num_comments = commentList.find('.comment').size();
            if (num_comments === 0) {
              commentList.find('#no_comments').show();
            }
          });
          
        }
      });
      
      return false;
		};


	/**
	 *  addComment
	 *
	 */
	Ultra.app.Community.addComment = function() {

	  var Community = Ultra.app.Community;
	  var form = $(this);


	  // Display loading indicator
	  var indicator = $('.loading_indicator').fadeIn('fast');


	  // Reset errors
	  form.find('label').removeClass('error');


	  // Validate form
	  var errors = form.validate({
	    'commentText':  ['notEmpty', 'Body is required']
	  });


	  // Display error
	  if (errors.length > 0) {

	    var error_msg = "Your submission produced the following errors:\n";

	    $.each(errors, function() {
	      error_msg += '* ' + this.message + "\n";
	      form.find('label[for=' + this.field + ']').addClass('error');
	    });

	    alert(error_msg);
	    indicator.fadeOut('fast');

	    return false;
	  }


	  // Submit data
	  Community.makeAPIRequest({
	    data: form.getValues(),

	    // Handle error    
	    error: function() {
        Community.handleError('Ultra.app.Community.addComment');
	      indicator.fadeOut('fast');
	    },

	    // Handle success
	    success: function(xml) {
	      Community.executeAPIActions(xml);
	      form.find('input[type=reset], button[type=reset]').click();
	      indicator.fadeOut('fast');
	    }
	  });

	  return false;
	};



	/**
	 *  showAddFriendDialog
	 *
	 */
	Ultra.app.Community.showAddFriendDialog = function() {
    var username = this.rel;
    $('#addFriend span.username').text(username);
    $('#addFriendForm input#to_user').val(username);

    var vp = Ultra.util.Viewport;
    var css = {
      top:    vp.getScrollTop() + 'px',
      left:   vp.getScrollLeft() + 'px',
      width:  vp.getPageWidth() + 'px',
      height: vp.getWindowHeight() + 'px'
    };
    $('#mask').css(css).show();
    $('#dialogContainer').css(css).show();
    $('#addFriend').appendTo('#dialogContainer').fadeIn();
	};

	/**
	 *  hideAddFriendDialog
	 *
	 */
	Ultra.app.Community.hideAddFriendDialog = function() {	 
    $('#addFriend').fadeOut(function() {
      $('#mask').hide();
      $('#dialogContainer').hide();
    });
	};


	/**
	 *  showSendMessageDialog
	 *
	 */
	Ultra.app.Community.showSendMessageDialog = function(username, message, isReply) {

    $('#sendMessage span.username').text(username);
    $('#sendMessageForm #to_user').val(username);

    if (message !== undefined) {
      if (isReply === true) {
        // Quote message and prepend Re: to the subject
        message.subject = message.subject.replace(/^(Re: )?(.*)/gi, 'Re: $2');
        message.message = "\n\nOn " + message.date + ", " + message.replyTo + " wrote:\n" + message.message.replace(/\<br\>/gi, "\n").replace(/(.{0,37})(\W)/ig, "\n> $1$2");
      }
      // Prepopulate form
      $('#sendMessageForm #subject').val(message.subject);
      $('#sendMessageForm #message').val(message.message);
    }

    var vp = Ultra.util.Viewport;
    var css = {
      top:    vp.getScrollTop() + 'px',
      left:   vp.getScrollLeft() + 'px',
      width:  vp.getPageWidth() + 'px',
      height: vp.getWindowHeight() + 'px'
    };
    $('#mask').css(css).show();
    $('#dialogContainer').css(css).show();
    $('#sendMessage').appendTo('#dialogContainer').fadeIn();
	};


	/**
	 *  hideSendMessageDialog
	 *
	 */
	Ultra.app.Community.hideSendMessageDialog = function() {
    $('#sendMessage').fadeOut(function() {
      $('#mask').hide();
      $('#dialogContainer').hide();
    });
	};


  Ultra.app.Community.removeMessageOrDay = function(uid) {
    var msg = $('#message_' + uid);
    var div = msg.parent('div');

    if(div.find('.message').size() > 1) {

      // Fade/remove message
      msg.fadeOut(function() {
        msg.remove();
      });
    } else {

      // Fade/remove day
      div.fadeOut(function() {
        div.remove();
        if ($('.day').size() === 0) {
          $('#no_messages').show();
        }
      });
    }
  };







	/**
	 *  deleteMessageFromSent
	 *
	 */
	Ultra.app.Community.deleteMessageFromSent = function(uid, username, redirect) {

	  var Community = Ultra.app.Community;

	  Community.makeAPIRequest({
	    data: {
				action: 'UserFriendMessage.deleteMessage',
				uid: uid,
				to_user: username
			},

	    // Handle error    
	    error: function() {
        Community.handleError('Ultra.app.Community.deleteMessageFromSent');
	    },

	    // Handle success
	    success: function(xml) {
  	    if (redirect !== undefined) {
          location.href = redirect;
          return;
  	    }
        Community.removeMessageOrDay(uid);
	      Community.executeAPIActions(xml);
	    }
	  });
		
		return false;
	}


	Ultra.app.Community.getMarkItUpSettings = function() {
    return {
      nameSpace:          "bbcode", // Useful to prevent multi-instances CSS conflict
	  previewParserPath:  "/flashApps/site/bbcode/parser.php",
	  //previewParserPath:  "/my/markitup/markitup.bbcode-parser.php",
      markupSet: [
        {name:'Bold', key:'B', openWith:'[b]', closeWith:'[/b]'}, 
        {name:'Italic', key:'I', openWith:'[i]', closeWith:'[/i]'}, 
        {name:'Underline', key:'U', openWith:'[u]', closeWith:'[/u]'}, 
        {separator:'---------------' },
        {name:'Picture', key:'P', replaceWith:'[img][![Url]!][/img]'}, 
        {name:'Link', key:'L', openWith:'[url=[![Url]!]]', closeWith:'[/url]', placeHolder:'Your text to link here...'},
        {separator:'---------------' },
        {name:'Colors', openWith:'[color=[![Color]!]]', closeWith:'[/color]', dropMenu: [
            {name:'Yellow', openWith:'[color=yellow]', closeWith:'[/color]', className:"col1-1" },
            {name:'Orange', openWith:'[color=orange]', closeWith:'[/color]', className:"col1-2" },
            {name:'Red', openWith:'[color=red]', closeWith:'[/color]', className:"col1-3" },
            {name:'Blue', openWith:'[color=blue]', closeWith:'[/color]', className:"col2-1" },
            {name:'Purple', openWith:'[color=purple]', closeWith:'[/color]', className:"col2-2" },
            {name:'Green', openWith:'[color=green]', closeWith:'[/color]', className:"col2-3" },
            {name:'White', openWith:'[color=white]', closeWith:'[/color]', className:"col3-1" },
            {name:'Gray', openWith:'[color=gray]', closeWith:'[/color]', className:"col3-2" },
            {name:'Black', openWith:'[color=black]', closeWith:'[/color]', className:"col3-3" }
        ]},
        {name:'Size', key:'S', openWith:'[size=[![Text size]!]]', closeWith:'[/size]', dropMenu :[
            {name:'Big', openWith:'[size=200]', closeWith:'[/size]' },
            {name:'Normal', openWith:'[size=100]', closeWith:'[/size]' },
            {name:'Small', openWith:'[size=50]', closeWith:'[/size]' }
        ]},
        {separator:'---------------' },
        {name:'Bulleted list', openWith:'[list]\n', closeWith:'\n[/list]'}, 
        {name:'Numeric list', openWith:'[list=[![Starting number]!]]\n', closeWith:'\n[/list]'}, 
        {name:'List item', openWith:'[*] '}, 
        {separator:'---------------' },
        {name:'Quotes', openWith:'[quote]', closeWith:'[/quote]'}, 
        {name:'Code', openWith:'[code]', closeWith:'[/code]'}, 
        {separator:'---------------' },
        {name:'Clean', className:"clean", replaceWith:function(h) { return h.selection.replace(/\[(.*?)\]/g, "") } },
        {name:'Preview', className:"preview", call:'preview' }
      ]
    };
  };
	/**
	 *  deleteMessageFromReceived
	 *
	 */
	Ultra.app.Community.deleteMessageFromReceived = function(uid, username, redirect) {

	  var Community = Ultra.app.Community;

	  Community.makeAPIRequest({
	    data: {
				action: 'UserFriendMessage.deleteMessage',
				uid: uid,
				from_user: username
			},

	    // Handle error    
	    error: function() {
        Community.handleError('Ultra.app.Community.deleteMessageFromReceived');
	    },

	    // Handle success
	    success: function(xml) {
  	    if (redirect !== undefined) {
          location.href = redirect;
          return;
  	    }
        Community.removeMessageOrDay(uid);
	      Community.executeAPIActions(xml);
	    }
	  });
		
		return false;
	}





	/**
	 *  sendMessage
	 *
	 */
	Ultra.app.Community.sendMessage = function() {

	  var Community = Ultra.app.Community;
	  var form = $(this);


	  // Display loading indicator
	  var indicator = $('.loading_indicator').fadeIn('fast');


	  // Reset errors
	  form.find('label').removeClass('error');


	  // Validate form
	  var errors = form.validate({
	    'subject':  ['notEmpty', 'Subject is required'],
	    'message':  ['notEmpty', 'Message is required']
	  });


	  // Display error
	  if (errors.length > 0) {

	    var error_msg = "Your submission produced the following errors:\n";

	    $.each(errors, function() {
	      error_msg += '* ' + this.message + "\n";
	      form.find('label[for=' + this.field + ']').addClass('error');
	    });

	    alert(error_msg);
	    indicator.fadeOut('fast');

	    return false;
	  }

	  // Submit data
	  Community.makeAPIRequest({
	    data: form.getValues(),

	    // Handle error    
	    error: function() {
        Community.handleError('Ultra.app.Community.sendMessage');
	      form.find('input[type=reset], button[type=reset]').click();
	      indicator.fadeOut('fast');
	    },

	    // Handle success
	    success: function(xml) {
				var error = $('error', xml);

				if (error.size() > 0) {
					var errorDialog = $('#errorDialog');
					errorDialog.find('#errorMsg').text(error.text()).end().show();
				} else {
		      Community.executeAPIActions(xml);
				}

				form.find('input[type=reset], button[type=reset]').click();	      
	      indicator.fadeOut('fast');
	    }
	  });

	  return false;
	};

})(jQuery);