text: /*
   * The base model for a comment.
   *
   * This provides all the common properties, serialization, deserialization,
   * validation, and other functionality of comments. It's meant to be
   * subclassed by more specific implementations.
   */
  RB.BaseComment = RB.BaseResource.extend({
      defaults: _.defaults({
          /*
           * The text format type to request for text in all responses.
           */
          forceTextType: null,
  
          /*
           * A string containing a comma-separated list of text types to include
           * in the payload.
           */
          includeTextTypes: null,
  
          /* Whether or not an issue is opened. */
          issueOpened: null,
  
          /*
           * The current state of the issue.
           *
           * This must be one of STATE_DROPPED, STATE_OPEN, or STATE_RESOLVED.
           */
          issueStatus: null,
  
          /*
           * Markdown-formatted text fields, if the caller fetches or posts with
           * include-text-types=raw.
           */
          markdownTextFields: {},
  
          /*
           * Raw text fields, if the caller fetches or posts with
           * include-text-types=raw.
           */
          rawTextFields: {},
  
          /* Whether the comment is saved in rich-text (Markdown) format. */
          richText: null,
  
          /* The text entered for the comment. */
          text: ''
      }, RB.BaseResource.prototype.defaults),
  
      extraQueryArgs: {
          'force-text-type': 'html',
          'include-text-types': 'raw'
      },
  
      supportsExtraData: true,
  
      attrToJsonMap: {
          forceTextType: 'force_text_type',
          includeTextTypes: 'include_text_types',
          issueOpened: 'issue_opened',
          issueStatus: 'issue_status',
          richText: 'text_type'
      },
  
      serializedAttrs: [
          'forceTextType',
          'includeTextTypes',
          'issueOpened',
          'issueStatus',
          'richText',
          'text'
      ],
  
      deserializedAttrs: [
          'issueOpened',
          'issueStatus',
          'text',
          'html'
      ],
  
      serializers: {
          forceTextType: RB.JSONSerializers.onlyIfValue,
          includeTextTypes: RB.JSONSerializers.onlyIfValue,
          richText: RB.JSONSerializers.textType,
  
          issueStatus: function(value) {
              var parentObject;
  
              if (this.get('loaded')) {
                  parentObject = this.get('parentObject');
  
                  if (parentObject.get('public')) {
                      return value;
                  }
              }
  
              return undefined;
          }
      },
  
      /*
       * Destroys the comment if and only if the text is empty.
       *
       * This works just like destroy(), and will in fact call destroy()
       * with all provided arguments, but only if there's some actual
       * text in the comment.
       */
      destroyIfEmpty: function(options, context) {
          if (!this.get('text')) {
              this.destroy(options, context);
          }
      },
  
      /*
       * Deserializes comment data from an API payload.
       *
       * This must be overloaded by subclasses, and the parent version called.
       */
      parseResourceData: function(rsp) {
          var rawTextFields = rsp.raw_text_fields || rsp,
              data = RB.BaseResource.prototype.parseResourceData.call(this, rsp);
  
          data.richText = (rawTextFields.text_type === 'markdown');
  
          if (rsp.raw_text_fields) {
              data.rawTextFields = {
                  text: rsp.raw_text_fields.text
              };
          }
  
          if (rsp.markdown_text_fields) {
              data.markdownTextFields = {
                  text: rsp.markdown_text_fields.text
              };
          }
  
          if (rsp.html_text_fields) {
              data.html = rsp.html_text_fields.text;
          }
  
          return data;
      },
  
      /*
       * Performs validation on the attributes of the model.
       *
       * By default, this validates the issueStatus field. It can be
       * overridden to provide additional validation, but the parent
       * function must be called.
       */
      validate: function(attrs) {
          if (_.has(attrs, 'parentObject') && !attrs.parentObject) {
              return RB.BaseResource.strings.UNSET_PARENT_OBJECT;
          }
  
          if (attrs.issueStatus &&
              attrs.issueStatus !== RB.BaseComment.STATE_DROPPED &&
              attrs.issueStatus !== RB.BaseComment.STATE_OPEN &&
              attrs.issueStatus !== RB.BaseComment.STATE_RESOLVED) {
              return RB.BaseComment.strings.INVALID_ISSUE_STATUS;
          }
  
          return RB.BaseResource.prototype.validate.apply(this, arguments);
      }
  }, {
      STATE_DROPPED: 'dropped',
      STATE_OPEN: 'open',
      STATE_RESOLVED: 'resolved',
  
      strings: {
          INVALID_ISSUE_STATUS: 'issueStatus must be one of STATE_DROPPED, ' +
                                'STATE_OPEN, or STATE_RESOLVED'
      }
  });
  