Webhook

 avatar
unknown
javascript
5 months ago
42 kB
3
Indexable
/**
 * @typedef {Object} WebhookData
 * @property {string} url - The URL of the webhook.
 * @property {number} threadId - The ID of the thread.
 */

/**
 * @typedef {Object} WebhookUser
 * @property {string} username - The username of the user.
 * @property {string} avatarUrl - The URL of the user's avatar.
 */

/**
 * @typedef {Object} EmbedTitle
 * @property {string} title - The title of the embed.
 * @property {string} url - The URL of the embed.
 */

/**
 * @typedef {Object} EmbedAuthor
 * @property {string} name - The name of the author.
 * @property {string} url - The URL of the author.
 * @property {string} iconUrl - The URL of the author's icon.
 */

/**
 * @typedef {Object} EmbedFooter
 * @property {string} text - The text of the footer.
 * @property {string} iconUrl - The URL of the footer's icon.
 */

/**
 * @typedef {Object} MessageMentions
 * @property {String[]} parse - The types of mentions to parse.
 * @property {String[]} roles - The roles mentioned.
 * @property {String[]} users - The users mentioned.
 */

/**
 * @typedef {Object} Callback
 * @property {Function} edit - Function to edit the callback.
 * @property {Function} getOriginalMessageJSON - Function to get the original message JSON.
 * @property {Function} getOriginalMessage - Function to get the original message.
 */
 /**
 * @property {Message} message - The message to send.
 * @property {WebhookUser} user - The user of the webhook.
 * @property {WebhookData} webhookData - The data for the webhook.
 */
class Webhook {
  
  /**
   * Creates the webhook object
   * @param {WebhookData} webhookData
   * @param {WebhookUser} [user=null]
   * @param {Message} [message=null] 
   */
  constructor(webhookData, user = null, message=null) {
    this.webhookData = webhookData;
    this.user = user;
    this.message = message;
  }
  /**
   * Exeute the webhook and send the message.
   * @param {Callback} callback
   * @param {Message} [tMessage=null]
   * @returns {Callback} The callback oject for further chaining.
   * @throws {TypeError} - If no webhook URL or message is provided.
   * @throws {RangeError} - If the number of embeds or the total length of the embeds exceeds the limits.
   * @throws {Error} - If there are permission issues or unknown errors while editing the message.
   */
  execute(callback, tMessage = null) {

    
    if (this.webhookData.url == undefined || this.webhookData.url == null) throw new TypeError(`No webhook url was provided.`);
 
    let messageToUse = tMessage || this.message;
    
    if (!messageToUse) throw new TypeError(`No message for the webhook to send was provided.`);
    let message = messageToUse;

    let payload = {
      username: this.user?.username || null,
      avatar_url: this.user?.avatarUrl || null,
      content: message.content || null,
      tts: message.tts || false, 
      allowed_mentions: message.allowedMentions,
      embeds: message.embeds ? message.embeds.map(embed => embed.toObject()) : []
    };

    if (payload.embeds.length > 10) throw new RangeError(`You can only have a maximum of 10 embeds in a message.`);

    let totalLength = payload.embeds.reduce((acc, embed) => {
      let embedLength = (embed.title ?.title.length || 0) +
                        (embed.description?.description.length || 0) +
                        (embed.footer ?.footer.text.length || 0) +
                        (embed.author ?.author.name.length || 0);
      if (embed.fields) {
        embed.fields.forEach(field => {
          embedLength += field.name.length + field.value.length;
        });
      }
      return acc + embedLength;
    }, 0);

    if (totalLength > 6000) throw new RangeError(`The total length of the embeds exceeds the maximum of 6000 characters.`);

    let url = this.webhookData.url + `?wait=true` + (this.webhookData.threadId ? `&thread_id=${this.webhookData.threadId}` : '');

    let params =
    {
      headers: { "Content-Type": "application/json" },
      method: "POST",
      payload: JSON.stringify(payload),
      muteHttpExceptions: true
    };
    let firstResp = UrlFetchApp.fetch(url, params);
    
    /**
     * The callback object that is returned to the user and previously executed in the method provided.
     * @type {Callback}
     * 
     */
    let responseHandler = {

      /**
       * Edit the orginal message that was sent by the webhook.
       * This is a followup, meaning you can only edit the ONE message that was just sent by the webhook.
       * @param {Message} message2 
       * @throws {TypeError} If no message is provided.
       * @throws {RangeError} If the number of embeds or the total length of the embeds exceeds the limits.
       * @throws {Error} If there are permission issues or unknown errors while editing the message.
       * @returns {Object} The JSON response from the Discord API.
       * 
       */
      edit: (message2) => {
        let cont = firstResp.getContentText();
        let json = JSON.parse(cont);
        if (json.code === 50013) throw new Error(`Missing permissions to edit the message.`);
        if (json.code === 10008) throw new Error(`Unknown message.`);
        if (json.code === 50006) throw new Error(`Cannot edit a message authored by another user.`);
        if (json.code === 50007) throw new Error(`Cannot send an empty message.`);



        let editUrl = this.webhookData.url + `/messages/${json.id}` + (this.webhookData.threadId ? `&thread_id=${this.webhookData.threadId}` : '');
        if (message2 === undefined || message2 === null) throw new TypeError(`No message for the webhook to send was provided, when attempting to edit the original webhook message.`);
        

        let payload = {
          username: message2.user ? this.user.username : undefined,
          avatar_url: this.user ? this.user.avatarUrl : undefined,
          content: message2.content,
          tts: message2.tts,
          allowed_mentions: message2.allowedMentions,
          embeds: message2.embeds ? message2.embeds.map(embed => embed.toObject()) : []
        };

        if (payload.embeds.length > 10) throw new RangeError(`You can only have a maximum of 10 embeds in a message.`);

        let totalLength = payload.embeds.reduce((acc, embed) => {
          let embedLength = (embed.title ? embed.title.length : 0) +
            (embed.description ? embed.description.length : 0) +
            (embed.footer ? embed.footer.text.length : 0) +
            (embed.author ? embed.author.name.length : 0);
          if (embed.fields) {
            embed.fields.forEach(field => {
              embedLength += field.name.length + field.value.length;
            });
          }
          return acc + embedLength;
        }, 0);

        if (totalLength > 6000) throw new RangeError(`The total length of the embeds exceeds the maximum of 6000 characters.`);
        let params =
        {
          headers: { "Content-Type": "application/json" },
          method: "PATCH",
          payload: JSON.stringify(payload),
          muteHttpExceptions: true
        };
        let response = UrlFetchApp.fetch(editUrl, params);
        return JSON.parse(response.getContentText());
      },
      /**
       * Get the original message that was sent by the webhook.
       * @returns {Object} The JSON response from the Discord API.
       */
      getOriginalMessageJSON: () => {
        return JSON.parse(firstResp.getContentText());
      },
      /**
       *  Get the original message that was sent by the webhook.
       * @returns {Message} The original message that was sent by the webhook.
       */
      getOriginalMessage() {
        return message;
      },
      /**
       * 
       * @param {Callback} callback 
       * @param {Message} newM 
       * 
       * @returns {Callback} The callback object for further chaining.
       */
      followUp: (callback, newM) => {
          return this.execute(callback, newM);
      }
    }
    
    if (callback && typeof callback === 'function') {
      callback(responseHandler);
    }

    return responseHandler;

  }
  
  /**
   * Set a message that should be sent with the webhook. This will al
   * @param {Message} message The message to provide to the webhook.
   * @throws {TypeError} If the message is not an instance of Message.
   * @returns {Boolean} True if there was no override of the message, false if there was.
   * @see Webhook#execute in order to send the message and post it to discord.
   */
  setMessage(message) {
    _WebUtlity.checkInstance(message, 'Message');
    if(this.message == undefined || this.message == null) {
      this.message = message;
      return true;
    } else {
      this.message = message;
      return false;
    }
  }
  /**
   * Clears the message of the webhook.
   */
  clearMessage() {
    delete this.message;
    this.message = null;
  }
  /**
   * Set the user of the webhook.
   * @param {WebhookUser} user The user of the webhook.
   * @throws {TypeError} If the user is not an instance of WebhookUser.
   */
  setUser(user) {
    _WebUtlity.checkInstance(user, 'WebhookUser');
    this.user = user;
  }
  /**
   * Clears the user of the webhook and falls back to the default one configured in the webhook integration setting within discord
   */
  clearUser() {
    delete this.user;
  }
}
/**
 * Message object that includes important message data such as content and embeds.
 * @property {String} _content The message text content. Maximum character length is 2000.
 * @property {Embed[]} embeds The embeds of the message. Maximum of 10 embeds.
 * @property {Boolean} tts Whether the message should be a TTS message.
 * @property {MessageMentions} allowedMentions The allowed mentions of the message.
 */
class Message {
  /**
   * @param {String} cont The message text content. Maximum character length is 2000.
   * @throws {TypeError} If the content length exceeds 2000.
   */
  set content(cont) {
    if (cont.length > 2000) throw new TypeError(`Message content is limited to a maximum of 2000 characters. ${cont.length} characters is too long.`);
    this._content = cont;
  }
  get content() {
    return this._content || null;
  }

  /**
   * @param {...Embed} embeds 
   * @throws {TypeError} If the embeds are not valid Eg. wrong class.
   * @throws {RangeError} If the amounts of embeds are more than 10.
   */
  addEmbeds(...embeds) {
    embeds.forEach(embed => { if (!_WebUtlity.isValidEmbed(embed)) throw new TypeError(`Invalid Embed instance provided. The object provided is not an instance of the embed class.`) });
    if(this.embeds == undefined || this.embeds == null) this.embeds = embeds;
    else {
      this.embeds = this.embeds.concat(embeds);
    }
    if (this.embeds.length > 10) throw new RangeError(`You can only have a maximum of 10 embeds in a message.`);
  }
  /**
   * Clears the embeds of the message.
   */
  clearEmbeds() {
    delete this.embeds;

  }
  /**
   * Set the TTS of the message.
   * @param {Boolean} tts Whether Text to speech should be enabled or not. Default is false (disabled)
   * @throws {TypeError} If the TTS is not a boolean.
   */
  setTTS(tts = false) {
    if (typeof tts !== 'boolean') throw new TypeError(`TTS must be a boolean.`);
    this.tts = tts;
  }
  /**
   *
   * 0 - Roles
   * 1 - Users
   * 2 - Everyone
   * You may use Mentions.ROLES, Mentions.USERS, Mentions.EVERYONE to specify the mention types.
   * Note that providing 
   * 
   * @param  {...Number} number
   */
  allowMentionTypes(...number) {
    let allowed = [0, 1, 2];
    number.forEach(num => {
      if (!allowed.includes(num)) throw new TypeError(`Invalid mention type provided. The mention type provided is not valid.`);
    });

    if (this.allowedMentions == undefined) this.allowedMentions = { parse: [], roles: [], users: [] };
    if (number.includes(0) && !this.allowedMentions.parse.includes('roles')) this.allowedMentions.parse.push('roles');
    if (number.includes(1) && !this.allowedMentions.parse.includes('users')) this.allowedMentions.parse.push('users');
    if (number.includes(2) && !this.allowedMentions.parse.includes('everyone')) this.allowedMentions.parse.push('everyone');
  }
  /**
   * Roles you wish to be allowed to mention in the message.
   * @param  {...Number} roles 
   */
  setMentionRoles(...roles) {
    if (roles)
      if (this.allowedMentions == undefined) this.allowedMentions = { parse: [], roles: [], users: [] };
    if (this.allowedMentions.parse.includes('roles')) {
      this.allowedMentions.parse = this.allowedMentions.parse.filter(mention => mention !== 'roles');
    }
    this.allowedMentions.roles.concat(roles);
  }
  /**
   * Roles you wish to be allowed to mention in the message.
   * @param  {...Number} users 
   */
  setMentionUsers(...users) {
    if (users)
      if (this?.allowedMentions) this.allowedMentions = { parse: [], roles: [], users: [] };
    if (this.allowedMentions.parse.includes('users')) {
      this.allowedMentions.parse = this.allowedMentions.parse.filter(mention => mention !== 'users');
    }
    this.allowedMentions.users.concat(users);

  }
  /**
   * Clears the allowed mentions of the message.
   */
  clearMentions() {
    delete this.allowedMentions;
    this.allowedMentions = null;
  }
}

class Mentions { }
Mentions.ROLES = 0;
Mentions.USERS = 1;
Mentions.EVERYONE = 2;

/**
 * Embed object that can create embeds, when later using the build() function
 * @typedef {class} Embed
 * @property {Number} color The color of the embed. 
 * @property {EmbedAuthor} author The author of the embed.
 * @property {EmbedTitle} title The title of the embed.
 * @property {String} description
 * @property {Embed.Field[]} fields The fields of the embed.
 * @property {String} thumbnail The thumbnail url of the embed.
 * @property {String} image The image ur of the embed.
 * @property {EmbedFooter} footer The footer of the embed.
 * @property {Date} timestamp The date at the bottom of the embed.
 */
class Embed {
  /**
   * @param {Embed} embed Optional embed (NOT THE ONE THAT WAS BUILT) as parameter in case the embed needs to be edited.
   */
  static from(embed) {
    if (embed == undefined) return new Embed();
    else return embed;
  }

  /**
   * Set the color by supplying an instance of new Color()
   * @param {Number} color instance of Color, will throw an error if its not an instance of Color.
   * 
   * @return {Embed} This instance for easier chaining. 
   * 
   * @throws {TypeError} If the color is undefined or null.
   */
  setColor(color) {
    if (color === undefined || color === null) throw new TypeError(`Color cannot be empty.`);
    this.color = color;
    return this;
  }


  /**
   * Allows you to set the author of the embed.
   * @param {EmbedAuthor} author The icon url of placed in the footer.  
   * 
   * @return {Embed} This instance for easier chaining. 
   */
  setAuthor(author) {
    if (author == null || author == undefined) throw TypeError("Author cannot be empty/Null");
    if (author.name == null || author.name == undefined) throw Error("Author name cannot be empty/Null");
    if (author.name.length > 256) throw RangeError("Author name is limited to a maximum of 256 characters.");
    this.author = author;
    return this;
  }
  /**
   * Set the title and the url of the url if needed.
   * @param {EmbedTitle} embedTitle The title of the embed.
   * @throws {TypeError} If the title is undefined or null.
   * @throws {RangeError} If the title exceeds the maximum character length of 256.
   * @return {Embed} This instance for easier chaining. 
   */
  setTitle(embedTitle) {
    if (embedTitle == undefined || embedTitle == null) throw new TypeError("Title cannot be empty.");
    if (embedTitle.title.length > 256) throw new RangeError(`Title is limited to a maximum of 256 characters. ${embedTitle.title.length} characters is too long.`);
    this.title = embedTitle;
    return this;
  }
  /**
   * Get the title and title url of the embed.
   * @return {EmbedTitle} The title of the embed. Or null if no title is set.
   */
  getTitle() {
    return this.title || null;
  }

  /**
   * Set the description of the embed.
   * @param {String} description The title of the embed.
   * 
   * @return {Embed} This instance for easier chaining. 
   * 
   * @throws {TypeError} If the description is undefined or null.
   * @throws {RangeError} If the description exceeds the maximum character length of 4096.
   */
  setDescription(description) {
    if (description == undefined || description == null || description == "") throw new TypeError("Description cannot be empty.");
    if (description.length > 4096) throw new RangeError(`Description is limited to a maximum of 4096 characters. ${description.length} characters is too long.`);
    return this;
  }

  /**
   * Get the description of the embed.
   * @return {String} The description of the embed. Or null if no description is set.
   */
  getDescription() {
    return this.description || null;
  }

  /**
   * Adds multiple fields to the embed with the help of Field instances.
   * @param {...Embed.Field} fields An array of field instances.
   * 
   * @return {Embed} This instance for easier chaining. 
   * 
   * @throws {TypeError} If the fields are not instances of Field.
   * @throws {RangeError} If the amount of fields exceeds 25.
   */
  addFields(...fields) {
    fields.forEach(field => {
      if (!(field instanceof Embed.Field)) throw TypeError(`Invalid Embed Field instance provided. The object provided is not an instance of the Embed.Field class.`);
    });
    if(this.fields == undefined) this.fields = fields;
    else {
      this.fields = this.fields.concat(fields);
    }
    if (this.fields.length > 25) throw RangeError(`You can only have a maximum of 25 fields in an embed.`);
    return this;
  }

  /**
   * Get the fields of the embed.
   * @return {Embed.Field[]} The fields of the embed. Or null if no fields are set.
   */
  getFields() {
    return this.fields || null;
  }

  /**
   * Set the timestamp of the embed.
   * @param {Date} date A date, will then be converted to an ISO string that counts as valid embed timestamp.
   * 
   * @return {Embed} This instance for easier chaining. 
   */
  setTimestamp(date) {
    if (!(date instanceof Date)) throw Error("Invalid Date instance.");
    this.timestamp = date;
    return this;
  }
  /**
   * Get the timestamp of the embed in form of a date.
   * @returns {Date} The timestamp of the embed.
   */
  getTimestamp() {
    return this.timestamp || null;
  }
  /**
   * Adds an image to the embed. You can add up to 4 images if you add more embeds with the same title and a different image.
   * @param {string} url The url of the image.
   * 
   * @return {Embed} This instance for easier chaining. 
   * 
   * @throws {TypeError} If the url is undefined or null.
   */
  setImage(url) {
    if (url == null || url == undefined) throw Error("Image url cannot be empty/Null");
    this.image = url;
    return this;
  }
  /**
   *  @returns {String} The url of the image.
   */
  getImage() {
    return this.image || null;
  }

  /**
 * Adds a thumbnail to the embed.
 * @param {string} url The url of the thumbnail.
 * 
 * @return {Embed} This instance for easier chaining. 
 */
  setThumbnail(url) {
    if (url == null || url == undefined) throw Error("Thumbnail url cannot be empty/Null");
    this.thumbnail = url;
    return this;
  }
  /**
   * Adds a thumbnail to the embed.
   * @return {String} The url of the thumbnail.
   */
  getThumbnail() {
    return this.thumbnail || null;
  }
  /**
 * Allows you to add a blank field. 
 * @param {inline} url The url of the thumbnail.
 * 
 * @return {Embed} This instance for easier chaining. 
 */
  addBlankField(inline) {
    if (this.hasOwnProperty('fields')) this.fields.push(new Embed.Field('\u200b', '\u200b', inline));
    else this.fields = [new Embed.Field(undefined, undefined, inline)];
  }
  /**
   * Allows you to set the footer of the embed.
   * @param {EmbedFooter} footer Set the footer of the embed.
   * 
   * @return {Embed} This instance for easier chaining.
   * 
   * @throws {TypeError} If the text is empty/null.
   * @throws {RangeError} If the text exceeds the maximum character length of 2048.
   */
  setFooter(footer) {
    if (footer == undefined || footer == null) throw Error("Footer cannot be empty/Null");
    if (footer.text == undefined || footer.text == null || footer.text == "") throw Error("Footer text cannot be empty/Null");
    if (footer.text.length > 2048) throw RangeError("Footer text is limited to a maximum of 2048 characters.");
    this.footer = footer;
    return this;
  }
  toObject() {

    let embed = {};
    if (this.color != undefined && this.color != null) embed.color = this.color;
    if (this.title != undefined && this.title != null) embed.title = this.title.title;
    if (this.author != undefined && this.author != null) {
      embed.author = {};
      if (this.author.name != undefined && this.author.name != null) embed.author.name = this.author.name;
      if (this.author.url != undefined && this.author.url != null) embed.author.url = this.author.url;
      if (this.author.iconUrl != undefined && this.author.iconUrl != null) embed.author.icon_url = this.author.iconUrl;
    }
    if (this.description != undefined && this.description != null) embed.description = this.description;
    if (this.title != undefined && this.title != null && this.title.url != undefined && this.title.url != null) embed.url = this.title.url;
    if (this.fields != undefined && this.fields != null) {
      if(embed.fields == undefined) embed.fields = [];
      this.fields.forEach(field => embed.fields.push({name: field.name, value: field.value, inline: field.inline}));
    }
    if (this.thumbnail != undefined && this.thumbnail != null) embed.thumbnail = { url: this.thumbnail};
    if (this.image != undefined && this.image != null) embed.image = { url: this.image };
    if (this.footer != undefined && this.footer != null) {
      embed.footer = {};
      if (this.footer.text != undefined && this.footer.text != null) embed.footer.text = this.footer.text;
      if (this.footer.iconUrl != undefined && this.footer.iconUrl != null) embed.footer.icon_url = this.footer.iconUrl;
    }
    if (this.timestamp != undefined && this.timestamp != null) embed.timestamp = this.timestamp.toISOString();
    return embed;
  }

  /**
   * Builds the embed. The object returned is the only valid argument to provide to the webhook.
   */
  toJSON() {
    let json = JSON.stringify(this.toObject());
    //let temp = JSON.parse(json);
    return json;
  }
}
/**
 * Embed field
 * @property {String} name The name/title of the field.
 * @property {String} value The value of the field.
 * @property {Boolean} inline Whether the field is inline or not.
 */
Embed.Field = class Field {
  /**
   * Providing undefined causes the name or value to be blank using a special Unicode character \u200b
   * @param {String} name The name/title of the field. Maximum of 256 characters.
   * @param {String} value The value of the field. Maximum of 1024 characters. 
   * @param {Boolean} inline Whether the field is inline or not. Invalid values such as null cause auto-default to false.
   * 
   * @throws {RangeError} If name or value exceeds their maximum character length. 
   */
  constructor(name, value, inline) {
    if (name == undefined || name == null) name = '\u200b';
    if (value == undefined || value == null) value = '\u200b';
    if (name.length > 256) throw new RangeError(`Field names are limited to a maximum of 256 characters. ${name.length} characters is too long.`);
    if (value.length > 1024) throw new RangeError(`Field values are limited to a maximum of 1024 characters. ${name.length} characters is too long.`);
    if (inline == null) inline = false;
    this._name = name;
    this._value = value;
    this.inline = Boolean(inline);
  }
  /**
   * Set the field name/title
   * @param {string} name The name/title of the field. Maximum of 256 characters.
   * @throws {RangeError} If name or value exceeds their maximum character length. 
   */
  set name(name) {
    if (name.length > 256) throw new RangeError(`Field names are limited to a maximum of 256 characters. ${name.length} characters is too long.`);
    this._name = name;
  }
  /**
   * Get the field name/title
   * @returns {string} The name/title of the field.
   */
  get name() {
    return this._name;
  }
  /**
   * Set the field value
   * @param {string} value The value of the field. Maximum of 1024 characters.
   * @throws {TypeError} If name or value exceeds their maximum character length.
   */
  set value(value) {
    if (value.length > 1024) throw new TypeError(`Field values are limited to a maximum of 1024 characters. ${value.length} characters is too long.`);
    this._value = value;
  }
  /**
   * Get the field value
   * @returns {string} The value of the field.
   */
  get value() {
    return this._value;
  }
}

class _WebUtlity {

  /**
  * Checks if the object is an instance of Embed and if it is not undefined or null
  * @param {Embed} object The object to check.
  */
  static isValidEmbed(object) {
    if (object != null && object != undefined && object instanceof Embed) return true;
    else return false;
  }
  /**
   * @param {Object} object 
   * @param {String} className 
   * @throws {TypeError} If the object is not an instance of the specified class.
   */
  static checkInstance(object, className) {
    if (object === null || object === undefined || object.constructor.name !== className) {
      throw new TypeError(`Expected an instance of ${className}, but got ${typeof object}`);
    }
  }

}

class Color {
  /**
   * @param {number} red - The red component (0-255) Default is 0.
   * @param {number} green - The green component (0-255) Default is 0.
   * @param {number} blue - The blue component (0-255) Default is 0.
   * @returns {number} The decimal representation of the color.
   */
  static fromRGB(red = 0, green = 0, blue = 0) {
    let value = ((red << 16) | (green << 8) | blue);
    return value;
  }
  
  /** 
   * @param {Number} raw The raw decimal number you want to provide. Hex is also allowed
   * @throws {TypeError} If no raw decimal number is provided.
   */
  static raw(raw = 0x000000) {
    if (raw === undefined) return raw;
  }

}

/** @type {number} The decimal representation of the color aliceblue. */
Color.ALICEBLUE = 15792383;

/** @type {number} The decimal representation of the color antiquewhite. */
Color.ANTIQUEWHITE = 16444375;

/** @type {number} The decimal representation of the color aqua. */
Color.AQUA = 65535;

/** @type {number} The decimal representation of the color aquamarine. */
Color.AQUAMARINE = 8388564;

/** @type {number} The decimal representation of the color azure. */
Color.AZURE = 15794175;

/** @type {number} The decimal representation of the color beige. */
Color.BEIGE = 16119260;

/** @type {number} The decimal representation of the color bisque. */
Color.BISQUE = 16770244;

/** @type {number} The decimal representation of the color black. */
Color.BLACK = 0;

/** @type {number} The decimal representation of the color blanchedalmond. */
Color.BLANCHEDALMOND = 16772045;

/** @type {number} The decimal representation of the color blue. */
Color.BLUE = 255;

/** @type {number} The decimal representation of the color blueviolet. */
Color.BLUEVIOLET = 9055202;

/** @type {number} The decimal representation of the color brown. */
Color.BROWN = 10824234;

/** @type {number} The decimal representation of the color burlywood. */
Color.BURLYWOOD = 14596231;

/** @type {number} The decimal representation of the color cadetblue. */
Color.CADETBLUE = 6266528;

/** @type {number} The decimal representation of the color chartreuse. */
Color.CHARTREUSE = 8388352;

/** @type {number} The decimal representation of the color chocolate. */
Color.CHOCOLATE = 13789470;

/** @type {number} The decimal representation of the color coral. */
Color.CORAL = 16744272;

/** @type {number} The decimal representation of the color cornflowerblue. */
Color.CORNFLOWERBLUE = 6591981;

/** @type {number} The decimal representation of the color cornsilk. */
Color.CORNSILK = 16775388;

/** @type {number} The decimal representation of the color crimson. */
Color.CRIMSON = 14423100;

/** @type {number} The decimal representation of the color cyan. */
Color.CYAN = 65535;

/** @type {number} The decimal representation of the color darkblue. */
Color.DARKBLUE = 139;

/** @type {number} The decimal representation of the color darkcyan. */
Color.DARKCYAN = 35723;

/** @type {number} The decimal representation of the color darkgoldenrod. */
Color.DARKGOLDENROD = 12092939;

/** @type {number} The decimal representation of the color darkgray. */
Color.DARKGRAY = 11119017;

/** @type {number} The decimal representation of the color darkgreen. */
Color.DARKGREEN = 25600;

/** @type {number} The decimal representation of the color darkgrey. */
Color.DARKGREY = 11119017;

/** @type {number} The decimal representation of the color darkkhaki. */
Color.DARKKHAKI = 12433259;

/** @type {number} The decimal representation of the color darkmagenta. */
Color.DARKMAGENTA = 9109643;

/** @type {number} The decimal representation of the color darkolivegreen. */
Color.DARKOLIVEGREEN = 5597999;

/** @type {number} The decimal representation of the color darkorange. */
Color.DARKORANGE = 16747520;

/** @type {number} The decimal representation of the color darkorchid. */
Color.DARKORCHID = 10040012;

/** @type {number} The decimal representation of the color darkred. */
Color.DARKRED = 9109504;

/** @type {number} The decimal representation of the color darksalmon. */
Color.DARKSALMON = 15308410;

/** @type {number} The decimal representation of the color darkseagreen. */
Color.DARKSEAGREEN = 9419919;

/** @type {number} The decimal representation of the color darkslateblue. */
Color.DARKSLATEBLUE = 4734347;

/** @type {number} The decimal representation of the color darkslategray. */
Color.DARKSLATEGRAY = 3100495;

/** @type {number} The decimal representation of the color darkslategrey. */
Color.DARKSLATEGREY = 3100495;

/** @type {number} The decimal representation of the color darkturquoise. */
Color.DARKTURQUOISE = 52945;

/** @type {number} The decimal representation of the color darkviolet. */
Color.DARKVIOLET = 9699539;

/** @type {number} The decimal representation of the color deeppink. */
Color.DEEPPINK = 16716947;

/** @type {number} The decimal representation of the color deepskyblue. */
Color.DEEPSKYBLUE = 49151;

/** @type {number} The decimal representation of the color dimgray. */
Color.DIMGRAY = 6908265;

/** @type {number} The decimal representation of the color dimgrey. */
Color.DIMGREY = 6908265;

/** @type {number} The decimal representation of the color dodgerblue. */
Color.DODGERBLUE = 2003199;

/** @type {number} The decimal representation of the color firebrick. */
Color.FIREBRICK = 11674146;

/** @type {number} The decimal representation of the color floralwhite. */
Color.FLORALWHITE = 16775920;

/** @type {number} The decimal representation of the color forestgreen. */
Color.FORESTGREEN = 2263842;

/** @type {number} The decimal representation of the color fuchsia. */
Color.FUCHSIA = 16711935;

/** @type {number} The decimal representation of the color gainsboro. */
Color.GAINSBORO = 14474460;

/** @type {number} The decimal representation of the color ghostwhite. */
Color.GHOSTWHITE = 16316671;

/** @type {number} The decimal representation of the color gold. */
Color.GOLD = 16766720;

/** @type {number} The decimal representation of the color goldenrod. */
Color.GOLDENROD = 14329120;

/** @type {number} The decimal representation of the color gray. */
Color.GRAY = 8421504;

/** @type {number} The decimal representation of the color green. */
Color.GREEN = 32768;

/** @type {number} The decimal representation of the color greenyellow. */
Color.GREENYELLOW = 11403055;

/** @type {number} The decimal representation of the color grey. */
Color.GREY = 8421504;

/** @type {number} The decimal representation of the color honeydew. */
Color.HONEYDEW = 15794160;

/** @type {number} The decimal representation of the color hotpink. */
Color.HOTPINK = 16738740;

/** @type {number} The decimal representation of the color indianred. */
Color.INDIANRED = 13458524;

/** @type {number} The decimal representation of the color indigo. */
Color.INDIGO = 4915330;

/** @type {number} The decimal representation of the color ivory. */
Color.IVORY = 16777200;

/** @type {number} The decimal representation of the color khaki. */
Color.KHAKI = 15787660;

/** @type {number} The decimal representation of the color lavender. */
Color.LAVENDER = 15132410;

/** @type {number} The decimal representation of the color lavenderblush. */
Color.LAVENDERBLUSH = 16773365;

/** @type {number} The decimal representation of the color lawngreen. */
Color.LAWNGREEN = 8190976;

/** @type {number} The decimal representation of the color lemonchiffon. */
Color.LEMONCHIFFON = 16775885;

/** @type {number} The decimal representation of the color lightblue. */
Color.LIGHTBLUE = 11393254;

/** @type {number} The decimal representation of the color lightcoral. */
Color.LIGHTCORAL = 15761536;

/** @type {number} The decimal representation of the color lightcyan. */
Color.LIGHTCYAN = 14745599;

/** @type {number} The decimal representation of the color lightgoldenrodyellow. */
Color.LIGHTGOLDENRODYELLOW = 16448210;

/** @type {number} The decimal representation of the color lightgray. */
Color.LIGHTGRAY = 13882323;

/** @type {number} The decimal representation of the color lightgreen. */
Color.LIGHTGREEN = 9498256;

/** @type {number} The decimal representation of the color lightgrey. */
Color.LIGHTGREY = 13882323;

/** @type {number} The decimal representation of the color lightpink. */
Color.LIGHTPINK = 16758465;

/** @type {number} The decimal representation of the color lightsalmon. */
Color.LIGHTSALMON = 16752762;

/** @type {number} The decimal representation of the color lightseagreen. */
Color.LIGHTSEAGREEN = 2142890;

/** @type {number} The decimal representation of the color lightskyblue. */
Color.LIGHTSKYBLUE = 8900346;

/** @type {number} The decimal representation of the color lightslategray. */
Color.LIGHTSLATEGRAY = 7833753;

/** @type {number} The decimal representation of the color lightslategrey. */
Color.LIGHTSLATEGREY = 7833753;

/** @type {number} The decimal representation of the color lightsteelblue. */
Color.LIGHTSTEELBLUE = 11584734;

/** @type {number} The decimal representation of the color lightyellow. */
Color.LIGHTYELLOW = 16777184;

/** @type {number} The decimal representation of the color lime. */
Color.LIME = 65280;

/** @type {number} The decimal representation of the color limegreen. */
Color.LIMEGREEN = 3329330;

/** @type {number} The decimal representation of the color linen. */
Color.LINEN = 16445670;

/** @type {number} The decimal representation of the color magenta. */
Color.MAGENTA = 16711935;

/** @type {number} The decimal representation of the color maroon. */
Color.MAROON = 8388608;

/** @type {number} The decimal representation of the color mediumaquamarine. */
Color.MEDIUMAQUAMARINE = 6737322;

/** @type {number} The decimal representation of the color mediumblue. */
Color.MEDIUMBLUE = 205;

/** @type {number} The decimal representation of the color mediumorchid. */
Color.MEDIUMORCHID = 12211667;

/** @type {number} The decimal representation of the color mediumpurple. */
Color.MEDIUMPURPLE = 9662683;

/** @type {number} The decimal representation of the color mediumseagreen. */
Color.MEDIUMSEAGREEN = 3978097;

/** @type {number} The decimal representation of the color mediumslateblue. */
Color.MEDIUMSLATEBLUE = 8087790;

/** @type {number} The decimal representation of the color mediumspringgreen. */
Color.MEDIUMSPRINGGREEN = 64154;

/** @type {number} The decimal representation of the color mediumturquoise. */
Color.MEDIUMTURQUOISE = 4772300;

/** @type {number} The decimal representation of the color mediumvioletred. */
Color.MEDIUMVIOLETRED = 13047173;

/** @type {number} The decimal representation of the color midnightblue. */
Color.MIDNIGHTBLUE = 1644912;

/** @type {number} The decimal representation of the color mintcream. */
Color.MINTCREAM = 16121850;

/** @type {number} The decimal representation of the color mistyrose. */
Color.MISTYROSE = 16770273;

/** @type {number} The decimal representation of the color moccasin. */
Color.MOCCASIN = 16770229;

/** @type {number} The decimal representation of the color navajowhite. */
Color.NAVAJOWHITE = 16768685;

/** @type {number} The decimal representation of the color navy. */
Color.NAVY = 128;

/** @type {number} The decimal representation of the color oldlace. */
Color.OLDLACE = 16643558;

/** @type {number} The decimal representation of the color olive. */
Color.OLIVE = 8421376;

/** @type {number} The decimal representation of the color olivedrab. */
Color.OLIVEDRAB = 7048739;

/** @type {number} The decimal representation of the color orange. */
Color.ORANGE = 16753920;

/** @type {number} The decimal representation of the color orangered. */
Color.ORANGERED = 16729344;

/** @type {number} The decimal representation of the color orchid. */
Color.ORCHID = 14315734;

/** @type {number} The decimal representation of the color palegoldenrod. */
Color.PALEGOLDENROD = 15657130;

/** @type {number} The decimal representation of the color palegreen. */
Color.PALEGREEN = 10025880;

/** @type {number} The decimal representation of the color paleturquoise. */
Color.PALETURQUOISE = 11529966;

/** @type {number} The decimal representation of the color palevioletred. */
Color.PALEVIOLETRED = 14381203;

/** @type {number} The decimal representation of the color papayawhip. */
Color.PAPAYAWHIP = 16773077;

/** @type {number} The decimal representation of the color peachpuff. */
Color.PEACHPUFF = 16767673;

/** @type {number} The decimal representation of the color peru. */
Color.PERU = 13468991;

/** @type {number} The decimal representation of the color pink. */
Color.PINK = 16761035;

/** @type {number} The decimal representation of the color plum. */
Color.PLUM = 14524637;

/** @type {number} The decimal representation of the color powderblue. */
Color.POWDERBLUE = 11591910;

/** @type {number} The decimal representation of the color purple. */
Color.PURPLE = 8388736;

/** @type {number} The decimal representation of the color rebeccapurple. */
Color.REBECCAPURPLE = 6697881;

/** @type {number} The decimal representation of the color red. */
Color.RED = 16711680;

/** @type {number} The decimal representation of the color rosybrown. */
Color.ROSYBROWN = 12357519;

/** @type {number} The decimal representation of the color royalblue. */
Color.ROYALBLUE = 4286945;

/** @type {number} The decimal representation of the color saddlebrown. */
Color.SADDLEBROWN = 9127187;

/** @type {number} The decimal representation of the color salmon. */
Color.SALMON = 16416882;

/** @type {number} The decimal representation of the color sandybrown. */
Color.SANDYBROWN = 16032864;

/** @type {number} The decimal representation of the color seagreen. */
Color.SEAGREEN = 3050327;

/** @type {number} The decimal representation of the color seashell. */
Color.SEASHELL = 16774638;

/** @type {number} The decimal representation of the color sienna. */
Color.SIENNA = 10506797;

/** @type {number} The decimal representation of the color silver. */
Color.SILVER = 12632256;

/** @type {number} The decimal representation of the color skyblue. */
Color.SKYBLUE = 8900331;

/** @type {number} The decimal representation of the color slateblue. */
Color.SLATEBLUE = 6970061;

/** @type {number} The decimal representation of the color slategray. */
Color.SLATEGRAY = 7372944;

/** @type {number} The decimal representation of the color slategrey. */
Color.SLATEGREY = 7372944;

/** @type {number} The decimal representation of the color snow. */
Color.SNOW = 16775930;

/** @type {number} The decimal representation of the color springgreen. */
Color.SPRINGGREEN = 65407;

/** @type {number} The decimal representation of the color steelblue. */
Color.STEELBLUE = 4620980;

/** @type {number} The decimal representation of the color tan. */
Color.TAN = 13808780;

/** @type {number} The decimal representation of the color teal. */
Color.TEAL = 32896;

/** @type {number} The decimal representation of the color thistle. */
Color.THISTLE = 14204888;

/** @type {number} The decimal representation of the color tomato. */
Color.TOMATO = 16737095;

/** @type {number} The decimal representation of the color turquoise. */
Color.TURQUOISE = 4251856;

/** @type {number} The decimal representation of the color violet. */
Color.VIOLET = 15631086;

/** @type {number} The decimal representation of the color wheat. */
Color.WHEAT = 16113331;

/** @type {number} The decimal representation of the color white. */
Color.WHITE = 16777215;

/** @type {number} The decimal representation of the color whitesmoke. */
Color.WHITESMOKE = 16119285;

/** @type {number} The decimal representation of the color yellow. */
Color.YELLOW = 16776960;

/** @type {number} The decimal representation of the color yellowgreen. */
Color.YELLOWGREEN = 10145074;
Editor is loading...
Leave a Comment