diff options
Diffstat (limited to 'vendor/github.com/mattermost/mattermost-server/v5/model')
94 files changed, 6795 insertions, 3297 deletions
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/access.go b/vendor/github.com/mattermost/mattermost-server/v5/model/access.go index bbac3601..6b60ea9e 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/access.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/access.go @@ -31,17 +31,18 @@ type AccessResponse struct { ExpiresIn int32 `json:"expires_in"` Scope string `json:"scope"` RefreshToken string `json:"refresh_token"` + IdToken string `json:"id_token"` } // IsValid validates the AccessData and returns an error if it isn't configured // correctly. func (ad *AccessData) IsValid() *AppError { - if len(ad.ClientId) == 0 || len(ad.ClientId) > 26 { + if ad.ClientId == "" || len(ad.ClientId) > 26 { return NewAppError("AccessData.IsValid", "model.access.is_valid.client_id.app_error", nil, "", http.StatusBadRequest) } - if len(ad.UserId) == 0 || len(ad.UserId) > 26 { + if ad.UserId == "" || len(ad.UserId) > 26 { return NewAppError("AccessData.IsValid", "model.access.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) } @@ -53,7 +54,7 @@ func (ad *AccessData) IsValid() *AppError { return NewAppError("AccessData.IsValid", "model.access.is_valid.refresh_token.app_error", nil, "", http.StatusBadRequest) } - if len(ad.RedirectUri) == 0 || len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) { + if ad.RedirectUri == "" || len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) { return NewAppError("AccessData.IsValid", "model.access.is_valid.redirect_uri.app_error", nil, "", http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go b/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go index 1180ad22..d1216664 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go @@ -15,27 +15,27 @@ type AnalyticsRow struct { type AnalyticsRows []*AnalyticsRow -func (me *AnalyticsRow) ToJson() string { - b, _ := json.Marshal(me) +func (ar *AnalyticsRow) ToJson() string { + b, _ := json.Marshal(ar) return string(b) } func AnalyticsRowFromJson(data io.Reader) *AnalyticsRow { - var me *AnalyticsRow - json.NewDecoder(data).Decode(&me) - return me + var ar *AnalyticsRow + json.NewDecoder(data).Decode(&ar) + return ar } -func (me AnalyticsRows) ToJson() string { - if b, err := json.Marshal(me); err != nil { +func (ar AnalyticsRows) ToJson() string { + b, err := json.Marshal(ar) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func AnalyticsRowsFromJson(data io.Reader) AnalyticsRows { - var me AnalyticsRows - json.NewDecoder(data).Decode(&me) - return me + var ar AnalyticsRows + json.NewDecoder(data).Decode(&ar) + return ar } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go b/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go index f41d182a..b5bfc0c7 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go @@ -8,7 +8,7 @@ import ( "strings" ) -var atMentionRegexp = regexp.MustCompile(`\B@[[:alnum:]][[:alnum:]\.\-_]*`) +var atMentionRegexp = regexp.MustCompile(`\B@[[:alnum:]][[:alnum:]\.\-_:]*`) const usernameSpecialChars = ".-_" @@ -24,7 +24,7 @@ func PossibleAtMentions(message string) []string { alreadyMentioned := make(map[string]bool) for _, match := range atMentionRegexp.FindAllString(message, -1) { name := NormalizeUsername(match[1:]) - if !alreadyMentioned[name] && IsValidUsername(name) { + if !alreadyMentioned[name] && IsValidUsernameAllowRemote(name) { names = append(names, name) alreadyMentioned[name] = true } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go b/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go index 50af2880..b3cf6062 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go @@ -3,7 +3,9 @@ package model -import "github.com/francoispqt/gojay" +import ( + "github.com/francoispqt/gojay" +) // AuditModelTypeConv converts key model types to something better suited for audit output. func AuditModelTypeConv(val interface{}) (newVal interface{}, converted bool) { @@ -49,6 +51,8 @@ func AuditModelTypeConv(val interface{}) (newVal interface{}, converted bool) { return newAuditIncomingWebhook(v), true case *OutgoingWebhook: return newAuditOutgoingWebhook(v), true + case *RemoteCluster: + return newRemoteCluster(v), true } return val, false } @@ -665,3 +669,45 @@ func (h auditOutgoingWebhook) MarshalJSONObject(enc *gojay.Encoder) { func (h auditOutgoingWebhook) IsNil() bool { return false } + +type auditRemoteCluster struct { + RemoteId string + RemoteTeamId string + Name string + DisplayName string + SiteURL string + CreateAt int64 + LastPingAt int64 + CreatorId string +} + +// newRemoteCluster creates a simplified representation of RemoteCluster for output to audit log. +func newRemoteCluster(r *RemoteCluster) auditRemoteCluster { + var rc auditRemoteCluster + if r != nil { + rc.RemoteId = r.RemoteId + rc.RemoteTeamId = r.RemoteTeamId + rc.Name = r.Name + rc.DisplayName = r.DisplayName + rc.SiteURL = r.SiteURL + rc.CreateAt = r.CreateAt + rc.LastPingAt = r.LastPingAt + rc.CreatorId = r.CreatorId + } + return rc +} + +func (r auditRemoteCluster) MarshalJSONObject(enc *gojay.Encoder) { + enc.StringKey("remote_id", r.RemoteId) + enc.StringKey("remote_team_id", r.RemoteTeamId) + enc.StringKey("name", r.Name) + enc.StringKey("display_name", r.DisplayName) + enc.StringKey("site_url", r.SiteURL) + enc.Int64Key("create_at", r.CreateAt) + enc.Int64Key("last_ping_at", r.LastPingAt) + enc.StringKey("creator_id", r.CreatorId) +} + +func (r auditRemoteCluster) IsNil() bool { + return false +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go b/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go index a8f01e1b..54e361f9 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go @@ -14,17 +14,16 @@ func (o Audits) Etag() string { if len(o) > 0 { // the first in the list is always the most current return Etag(o[0].CreateAt) - } else { - return "" } + return "" } func (o Audits) ToJson() string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func AuditsFromJson(data io.Reader) Audits { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go b/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go index 0191a670..f2a8e8dc 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go @@ -47,7 +47,7 @@ func (ad *AuthData) IsValid() *AppError { return NewAppError("AuthData.IsValid", "model.authorize.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) } - if len(ad.Code) == 0 || len(ad.Code) > 128 { + if ad.Code == "" || len(ad.Code) > 128 { return NewAppError("AuthData.IsValid", "model.authorize.is_valid.auth_code.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest) } @@ -82,11 +82,11 @@ func (ar *AuthorizeRequest) IsValid() *AppError { return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest) } - if len(ar.ResponseType) == 0 { + if ar.ResponseType == "" { return NewAppError("AuthData.IsValid", "model.authorize.is_valid.response_type.app_error", nil, "", http.StatusBadRequest) } - if len(ar.RedirectUri) == 0 || len(ar.RedirectUri) > 256 || !IsValidHttpUrl(ar.RedirectUri) { + if ar.RedirectUri == "" || len(ar.RedirectUri) > 256 || !IsValidHttpUrl(ar.RedirectUri) { return NewAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest) } @@ -110,7 +110,7 @@ func (ad *AuthData) PreSave() { ad.CreateAt = GetMillis() } - if len(ad.Scope) == 0 { + if ad.Scope == "" { ad.Scope = DEFAULT_SCOPE } } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go index fb46be49..e58fc0be 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go @@ -17,6 +17,7 @@ const ( BOT_DESCRIPTION_MAX_RUNES = 1024 BOT_CREATOR_ID_MAX_RUNES = KEY_VALUE_PLUGIN_ID_MAX_RUNES // UserId or PluginId BOT_WARN_METRIC_BOT_USERNAME = "mattermost-advisor" + BOT_SYSTEM_BOT_USERNAME = "system-bot" ) // Bot is a special type of User meant for programmatic interactions. @@ -82,7 +83,7 @@ func (b *Bot) IsValid() *AppError { return NewAppError("Bot.IsValid", "model.bot.is_valid.description.app_error", b.Trace(), "", http.StatusBadRequest) } - if len(b.OwnerId) == 0 || utf8.RuneCountInString(b.OwnerId) > BOT_CREATOR_ID_MAX_RUNES { + if b.OwnerId == "" || utf8.RuneCountInString(b.OwnerId) > BOT_CREATOR_ID_MAX_RUNES { return NewAppError("Bot.IsValid", "model.bot.is_valid.creator_id.app_error", b.Trace(), "", http.StatusBadRequest) } @@ -128,6 +129,8 @@ func BotFromJson(data io.Reader) *Bot { } // Patch modifies an existing bot with optional fields from the given patch. +// TODO 6.0: consider returning a boolean to indicate whether or not the patch +// applied any changes. func (b *Bot) Patch(patch *BotPatch) { if patch.Username != nil { b.Username = *patch.Username @@ -142,6 +145,23 @@ func (b *Bot) Patch(patch *BotPatch) { } } +// WouldPatch returns whether or not the given patch would be applied or not. +func (b *Bot) WouldPatch(patch *BotPatch) bool { + if patch == nil { + return false + } + if patch.Username != nil && *patch.Username != b.Username { + return true + } + if patch.DisplayName != nil && *patch.DisplayName != b.DisplayName { + return true + } + if patch.Description != nil && *patch.Description != b.Description { + return true + } + return false +} + // ToJson serializes the bot patch to json. func (b *BotPatch) ToJson() []byte { data, err := json.Marshal(b) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/bot_default_image.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bot_default_image.go deleted file mode 100644 index d9cdd2e2..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/bot_default_image.go +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -var BotDefaultImage = []byte{ - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7e, - 0x08, 0x06, 0x00, 0x00, 0x00, 0xec, 0xa6, 0x19, 0xa2, 0x00, 0x00, 0x00, - 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, - 0x05, 0x00, 0x00, 0x0c, 0xe3, 0x49, 0x44, 0x41, 0x54, 0x78, 0x01, 0xed, - 0x5d, 0x5b, 0x88, 0x15, 0xc9, 0x19, 0xae, 0xf1, 0xba, 0x5e, 0xc6, 0x4b, - 0xbc, 0xa0, 0x46, 0xd7, 0x2b, 0xce, 0x2a, 0xba, 0xca, 0x8a, 0xa3, 0x82, - 0x38, 0xa3, 0x46, 0x47, 0x5d, 0x59, 0xa3, 0x2f, 0x9b, 0x28, 0x6e, 0xc2, - 0xea, 0x83, 0x22, 0x04, 0x82, 0x78, 0x41, 0xf2, 0xb2, 0x04, 0xd4, 0x07, - 0x49, 0x22, 0xc4, 0x07, 0xcd, 0x53, 0x30, 0x26, 0x1a, 0xa2, 0x08, 0xee, - 0xaa, 0xa8, 0x71, 0xb2, 0x41, 0x11, 0xbc, 0xdf, 0xd0, 0x8d, 0x6e, 0x24, - 0x82, 0xe3, 0x65, 0x32, 0x9b, 0x19, 0x1d, 0x47, 0xd7, 0xeb, 0xc9, 0xf7, - 0xb5, 0xa7, 0x0f, 0xe7, 0x9c, 0xe9, 0x3e, 0xdd, 0xe7, 0x4c, 0x57, 0x77, - 0x75, 0x75, 0xfd, 0xf0, 0x9f, 0xee, 0xae, 0xaa, 0xae, 0xfa, 0xff, 0xef, - 0xfb, 0x4f, 0x9d, 0xee, 0xaa, 0xea, 0x3e, 0x65, 0x42, 0x4f, 0xe9, 0x0b, - 0xb7, 0x46, 0x43, 0x2b, 0xd2, 0xdb, 0x91, 0xd8, 0xf6, 0x84, 0x96, 0x67, - 0x69, 0xf7, 0xf4, 0x3e, 0x36, 0xa2, 0x19, 0xfa, 0x34, 0xbd, 0xe5, 0x3e, - 0xf5, 0x31, 0xf4, 0xdf, 0xd0, 0x5b, 0xd0, 0x7f, 0xa5, 0xb7, 0x0d, 0xd8, - 0x6a, 0x25, 0x65, 0x1a, 0x78, 0xd3, 0x1b, 0x3e, 0x54, 0x41, 0x67, 0x42, - 0x2b, 0xa1, 0x24, 0x9d, 0x69, 0x32, 0xa4, 0x11, 0x95, 0x32, 0x18, 0xce, - 0x42, 0x6b, 0xa1, 0x5f, 0x43, 0x99, 0x16, 0x5b, 0x89, 0x63, 0x00, 0x74, - 0x03, 0xda, 0xb3, 0xa0, 0x24, 0xbc, 0x1a, 0x3a, 0x01, 0xda, 0x0e, 0x1a, - 0x85, 0xbc, 0x45, 0xa3, 0x57, 0xa0, 0xff, 0x80, 0x32, 0x20, 0x4e, 0x42, - 0x5b, 0xa0, 0x46, 0x02, 0x46, 0xa0, 0x3d, 0xea, 0xab, 0x81, 0xee, 0x86, - 0xb2, 0xab, 0x4e, 0x29, 0xaa, 0xb4, 0x8d, 0x36, 0xd2, 0x56, 0xda, 0x6c, - 0xa4, 0x8d, 0x08, 0x7c, 0x84, 0xf3, 0x7f, 0x03, 0x7d, 0x00, 0x55, 0x95, - 0x74, 0x37, 0xbb, 0x68, 0x33, 0x6d, 0xa7, 0x0f, 0x46, 0x8a, 0x44, 0xe0, - 0x63, 0x94, 0x3f, 0x0d, 0x75, 0x03, 0x37, 0x6e, 0xe9, 0xf4, 0x85, 0x3e, - 0x19, 0x29, 0x80, 0x00, 0xbb, 0xcc, 0x9f, 0x40, 0xf9, 0x9b, 0x1a, 0x37, - 0x82, 0xfd, 0xda, 0x4b, 0xdf, 0xe8, 0xa3, 0xf9, 0x79, 0x00, 0x08, 0xb6, - 0xf0, 0x02, 0xee, 0x73, 0xe8, 0xb7, 0x50, 0xbf, 0x40, 0xc6, 0xbd, 0x1c, - 0x7d, 0xa5, 0xcf, 0x51, 0x5d, 0xbc, 0xa2, 0x69, 0x35, 0x84, 0xb7, 0x6d, - 0xe7, 0xa0, 0x71, 0x27, 0xb4, 0x54, 0xfb, 0xe9, 0x3b, 0x31, 0x48, 0x9c, - 0x70, 0xa0, 0x66, 0x17, 0x94, 0xb7, 0x51, 0xa5, 0x82, 0xa7, 0xcb, 0x79, - 0xc4, 0x80, 0x58, 0x10, 0x13, 0xed, 0x85, 0xe3, 0x0e, 0xab, 0xa0, 0xdf, - 0x41, 0x75, 0x21, 0x30, 0x28, 0x3f, 0x88, 0x09, 0xb1, 0x89, 0xe3, 0xd8, - 0x0c, 0xcc, 0xf6, 0x16, 0x46, 0xf8, 0x57, 0xd0, 0xa0, 0x00, 0xd3, 0xb5, - 0x1e, 0x62, 0xa4, 0x5d, 0x6f, 0x50, 0x0d, 0xa7, 0xea, 0x0c, 0xf9, 0xbe, - 0x83, 0x9f, 0x58, 0x11, 0xb3, 0xd8, 0x0b, 0x6f, 0x77, 0xbe, 0x80, 0xbe, - 0x81, 0xea, 0xfa, 0x8d, 0x95, 0xe5, 0x17, 0x31, 0x23, 0x76, 0xb1, 0xbd, - 0x65, 0xe4, 0x84, 0x4c, 0xad, 0x21, 0xbe, 0xcd, 0x81, 0x4f, 0x0c, 0x89, - 0x65, 0xac, 0xe4, 0x7d, 0x58, 0x7b, 0x03, 0x2a, 0xeb, 0xdb, 0x91, 0xb4, - 0x7a, 0x89, 0x25, 0x31, 0x8d, 0x85, 0x8c, 0x87, 0x95, 0xf7, 0xa0, 0x49, - 0x23, 0x49, 0xb6, 0xbf, 0xc4, 0x94, 0xd8, 0x2a, 0x2d, 0xd5, 0xb0, 0xae, - 0x09, 0x2a, 0x1b, 0x8c, 0xa4, 0xd6, 0x4f, 0x6c, 0x89, 0xb1, 0x92, 0xf2, - 0x09, 0xac, 0xfa, 0x1e, 0x9a, 0x54, 0x72, 0xc2, 0xf2, 0x9b, 0x18, 0x13, - 0x6b, 0xa5, 0xa4, 0x1a, 0xd6, 0x18, 0xf2, 0xc3, 0x0b, 0x7e, 0x62, 0x4d, - 0xcc, 0x95, 0x90, 0x49, 0xb0, 0xe2, 0x09, 0x34, 0xac, 0x6f, 0x80, 0x69, - 0xe7, 0x1d, 0xd6, 0xc4, 0x9c, 0xd8, 0x47, 0x2a, 0x5c, 0x78, 0x59, 0x0f, - 0x35, 0xa4, 0x44, 0x83, 0x01, 0xb1, 0x27, 0x07, 0x91, 0xc8, 0x60, 0xb4, - 0x7a, 0x17, 0x6a, 0xc8, 0x8f, 0x16, 0x03, 0x72, 0x40, 0x2e, 0x42, 0x95, - 0x4e, 0x68, 0x2d, 0xc9, 0xd3, 0xb8, 0xaa, 0x05, 0x3d, 0xb9, 0x20, 0x27, - 0x45, 0x4b, 0xa9, 0xc3, 0x8c, 0xdb, 0xd1, 0xd2, 0x8f, 0x8b, 0x6e, 0xcd, - 0x9c, 0x20, 0x0b, 0x81, 0x41, 0xa8, 0xf8, 0x07, 0xd0, 0xc3, 0xb2, 0x1a, - 0xc8, 0xae, 0xf7, 0x53, 0x1c, 0xa8, 0xf6, 0x0d, 0x30, 0xf6, 0xbc, 0xe3, - 0x84, 0xdc, 0x48, 0x15, 0x5e, 0x70, 0x98, 0x2b, 0x7e, 0x75, 0xbf, 0x00, - 0xe4, 0xa6, 0xa8, 0x8b, 0xc2, 0x62, 0xd6, 0xa4, 0xbd, 0x87, 0xca, 0xff, - 0x06, 0x2d, 0x87, 0x1a, 0x51, 0x13, 0x01, 0x72, 0x43, 0x8e, 0xc8, 0x95, - 0x2f, 0x29, 0x26, 0x00, 0x7e, 0x85, 0x1a, 0x95, 0x1f, 0x8b, 0xf6, 0xe3, - 0xf5, 0x80, 0x01, 0x03, 0xc4, 0xee, 0xdd, 0xbb, 0x45, 0x5d, 0x5d, 0x9d, - 0xa5, 0xdc, 0x67, 0x9a, 0x26, 0x42, 0x8e, 0xc8, 0x55, 0xa0, 0xf2, 0x01, - 0x6a, 0x7b, 0x01, 0x8d, 0xfd, 0x6f, 0x6d, 0xbf, 0x7e, 0xfd, 0x52, 0x0f, - 0x1f, 0x3e, 0x4c, 0xe5, 0x0b, 0xd3, 0x98, 0xa7, 0x83, 0x8f, 0x69, 0xae, - 0xc8, 0x59, 0x60, 0x52, 0x8b, 0x9a, 0xb4, 0x00, 0x67, 0xd7, 0xae, 0x5d, - 0xf9, 0xdc, 0x67, 0x8e, 0x99, 0xa7, 0x8b, 0x9f, 0xf0, 0x83, 0x9c, 0x05, - 0x22, 0x9f, 0xa1, 0x16, 0x6d, 0x80, 0xb9, 0x7d, 0xfb, 0x76, 0x86, 0xf0, - 0xfc, 0x1d, 0xe6, 0xe9, 0xe4, 0x2b, 0x7c, 0x21, 0x77, 0x05, 0xa5, 0xac, - 0x60, 0xee, 0xbb, 0x95, 0x28, 0x7c, 0x1c, 0xba, 0x9f, 0x47, 0xb9, 0xd8, - 0x64, 0xbf, 0x78, 0xf1, 0x42, 0x74, 0xea, 0xe4, 0x3c, 0x66, 0xf2, 0xf2, - 0xe5, 0x4b, 0xd1, 0xb9, 0x73, 0xe7, 0xd8, 0xf8, 0xe2, 0xc3, 0xd0, 0xff, - 0xa2, 0x4c, 0x05, 0xd4, 0xf5, 0x11, 0x76, 0xaf, 0x8b, 0xc0, 0x8d, 0x38, - 0x59, 0x1b, 0xf2, 0x7d, 0x00, 0xa6, 0x5b, 0x11, 0x72, 0x47, 0x0e, 0x5d, - 0xa5, 0x50, 0x0f, 0xc0, 0x91, 0x25, 0x8e, 0x33, 0xf3, 0x4d, 0x1a, 0xda, - 0x48, 0xc2, 0x7a, 0x00, 0xf2, 0xf6, 0x14, 0x3a, 0x14, 0xfa, 0x3f, 0x1e, - 0xe4, 0x4b, 0xa1, 0x1e, 0xe0, 0x97, 0x28, 0xac, 0x15, 0xf9, 0xf9, 0xce, - 0x27, 0xe4, 0x98, 0x1c, 0x92, 0x4b, 0x47, 0x71, 0xeb, 0x01, 0x7a, 0xa1, - 0xf4, 0x7f, 0xa0, 0x3d, 0x1d, 0xcf, 0x8a, 0x71, 0x62, 0x02, 0x7b, 0x00, - 0xb2, 0xf5, 0x18, 0x3a, 0x0c, 0xca, 0x25, 0x65, 0x39, 0xe2, 0xd6, 0x03, - 0xfc, 0x02, 0xa5, 0xb4, 0x23, 0x3f, 0xc7, 0xf3, 0x64, 0x1d, 0x90, 0x4b, - 0x72, 0xda, 0x4a, 0x9c, 0x7a, 0x80, 0x2e, 0x28, 0xc5, 0x15, 0xa8, 0xbc, - 0x06, 0xd0, 0x4e, 0x12, 0xda, 0x03, 0x90, 0x47, 0x5e, 0x03, 0x70, 0xdd, - 0xc0, 0x73, 0x1e, 0xd8, 0xe2, 0xd4, 0x03, 0x70, 0x9a, 0x57, 0x4b, 0xf2, - 0x6d, 0xa7, 0x13, 0xba, 0x25, 0xa7, 0xad, 0xa6, 0xf0, 0x3b, 0x38, 0x80, - 0xf1, 0x73, 0x87, 0xb4, 0xc8, 0x93, 0x78, 0x7f, 0x3e, 0x67, 0xce, 0x1c, - 0x31, 0x7d, 0xfa, 0x74, 0x31, 0x68, 0xd0, 0x20, 0xd1, 0xbb, 0x77, 0xef, - 0x92, 0x6c, 0xea, 0xd8, 0xb1, 0xa3, 0xeb, 0x79, 0xcc, 0x3b, 0x74, 0xe8, - 0x90, 0x6b, 0x7e, 0xa1, 0x8c, 0xc6, 0xc6, 0x46, 0x6b, 0x5e, 0xe1, 0xf4, - 0xe9, 0xd3, 0xe2, 0xf8, 0xf1, 0xe3, 0x82, 0x3d, 0x8d, 0x82, 0xf2, 0x33, - 0xd8, 0xf4, 0x97, 0x42, 0x76, 0xfd, 0x10, 0x99, 0x4a, 0x3d, 0xc7, 0xd7, - 0xa5, 0x4b, 0x97, 0xd4, 0xa6, 0x4d, 0x9b, 0x52, 0x4d, 0x4d, 0x4d, 0xf9, - 0x03, 0x77, 0xca, 0x1e, 0xd3, 0x56, 0xda, 0x4c, 0xdb, 0x81, 0xa7, 0x4a, - 0x4a, 0x6e, 0xc9, 0xb1, 0xab, 0x6c, 0x40, 0x8e, 0x32, 0x06, 0x8f, 0x18, - 0x31, 0x22, 0x75, 0xe3, 0xc6, 0x0d, 0x65, 0x89, 0xf6, 0x32, 0x8c, 0xb6, - 0xd3, 0x07, 0x95, 0x30, 0x85, 0x2d, 0xe4, 0xd8, 0x55, 0x94, 0x79, 0x9e, - 0x6f, 0xd4, 0xa8, 0x51, 0xa9, 0xfa, 0xfa, 0x7a, 0x2f, 0x8c, 0x95, 0xcf, - 0xa7, 0x0f, 0xf4, 0x05, 0x88, 0xab, 0xa2, 0xe4, 0xd8, 0x51, 0x3e, 0x44, - 0xaa, 0x12, 0x46, 0x76, 0xed, 0xda, 0x35, 0x75, 0xed, 0xda, 0x35, 0xe5, - 0xc9, 0xf5, 0x6b, 0x20, 0x7d, 0xa1, 0x4f, 0xaa, 0xe0, 0x0b, 0x3b, 0xc8, - 0xb5, 0x25, 0xd9, 0x77, 0x01, 0x3f, 0xb2, 0x13, 0xa3, 0xde, 0xae, 0x5d, - 0xbb, 0x56, 0x8c, 0x1b, 0x37, 0x2e, 0x6a, 0x33, 0x02, 0x6b, 0x9f, 0xbe, - 0xd0, 0x27, 0x85, 0xc4, 0x91, 0x6b, 0xbe, 0x9a, 0x24, 0xf2, 0x28, 0x2d, - 0x2f, 0x2f, 0x8f, 0xd5, 0x05, 0x9f, 0xdf, 0x5e, 0x80, 0x17, 0x86, 0xf4, - 0x4d, 0x05, 0x8c, 0x61, 0xc3, 0x97, 0x76, 0x30, 0xda, 0x3d, 0x00, 0x6f, - 0x07, 0x67, 0xd8, 0x89, 0x51, 0x6e, 0x6b, 0x6a, 0x6a, 0x44, 0xcf, 0x9e, - 0xfa, 0x0d, 0x42, 0xd2, 0x27, 0xfa, 0xa6, 0x88, 0x54, 0xc1, 0x0e, 0x6b, - 0x08, 0xc0, 0x0e, 0x80, 0x4a, 0x24, 0x28, 0x31, 0xf1, 0x33, 0x77, 0xee, - 0x5c, 0x45, 0x30, 0x0a, 0xde, 0x0c, 0x85, 0x7c, 0x23, 0xd7, 0xe4, 0x3c, - 0xf3, 0xa6, 0xca, 0xd9, 0xc1, 0xbb, 0x5b, 0x5a, 0x8d, 0x43, 0x87, 0x0e, - 0x2d, 0xed, 0xc4, 0x18, 0x9c, 0xa5, 0x98, 0x6f, 0x16, 0xe7, 0x76, 0x0f, - 0x30, 0x5d, 0x15, 0xfc, 0xfa, 0xf7, 0xef, 0xaf, 0x8a, 0x29, 0x81, 0xdb, - 0xa1, 0x98, 0x6f, 0x16, 0xe7, 0x76, 0x00, 0x8c, 0x09, 0xdc, 0xdb, 0x12, - 0x2b, 0xec, 0xd0, 0xc1, 0xfa, 0x69, 0x2a, 0xf1, 0x6c, 0xb5, 0x4f, 0x53, - 0xcc, 0x37, 0x8b, 0x73, 0x06, 0x40, 0x37, 0x28, 0x67, 0x89, 0x8c, 0x24, - 0x0b, 0x01, 0x72, 0xde, 0x8d, 0x01, 0xc0, 0x45, 0x83, 0x4e, 0xd3, 0xc2, - 0xc9, 0x82, 0x23, 0x79, 0xde, 0x92, 0xf3, 0x0a, 0x3b, 0x00, 0x92, 0xe7, - 0xbe, 0xf1, 0x98, 0x08, 0x58, 0x01, 0x10, 0xe8, 0x13, 0x24, 0x51, 0xe0, - 0x7a, 0xe2, 0xc4, 0x09, 0xb1, 0x62, 0xc5, 0x0a, 0x31, 0x71, 0xe2, 0x44, - 0x31, 0x73, 0xe6, 0x4c, 0xb1, 0x7e, 0xfd, 0x7a, 0x71, 0xff, 0xfe, 0xfd, - 0xc0, 0x4c, 0x39, 0x7b, 0xf6, 0xac, 0x58, 0xb9, 0x72, 0xa5, 0x98, 0x30, - 0x61, 0x82, 0x98, 0x3f, 0x7f, 0xbe, 0xd8, 0xb6, 0x6d, 0x9b, 0x78, 0xf5, - 0xea, 0x55, 0x60, 0xf5, 0x47, 0x58, 0x91, 0xc5, 0xfd, 0x9f, 0x61, 0x40, - 0x28, 0x23, 0x54, 0x3d, 0x7a, 0xf4, 0xb0, 0x66, 0xc7, 0x38, 0x43, 0x46, - 0x1d, 0x3c, 0x78, 0x70, 0xab, 0x76, 0x8b, 0x99, 0x03, 0x78, 0xfb, 0xf6, - 0x6d, 0x6a, 0xf5, 0xea, 0xd5, 0xad, 0xea, 0xa0, 0x3f, 0x58, 0x2f, 0x90, - 0x3a, 0x78, 0xf0, 0xa0, 0xdf, 0x81, 0x3a, 0xd7, 0x72, 0x3b, 0x76, 0xec, - 0x48, 0x61, 0x9d, 0x40, 0xab, 0x36, 0x2a, 0x2b, 0x2b, 0x8b, 0x9e, 0xac, - 0xa2, 0x6f, 0xf9, 0x58, 0x13, 0x03, 0x1b, 0x0f, 0x6e, 0x89, 0x51, 0x7e, - 0x19, 0x89, 0xc7, 0xe4, 0x5e, 0x1c, 0x91, 0xd8, 0x80, 0xe5, 0xcc, 0xe4, - 0xc9, 0x93, 0x53, 0x17, 0x2e, 0x5c, 0x48, 0x91, 0xb0, 0x6c, 0x71, 0x02, - 0xa4, 0x98, 0x00, 0xd8, 0xbe, 0x7d, 0x7b, 0x41, 0xb0, 0xba, 0x77, 0xef, - 0x9e, 0xba, 0x73, 0xe7, 0x4e, 0x76, 0x93, 0x45, 0xed, 0x5f, 0xb9, 0x72, - 0x25, 0x85, 0x2b, 0x77, 0xd7, 0x36, 0x96, 0x2d, 0x5b, 0x56, 0x54, 0x7d, - 0x7e, 0xfc, 0x25, 0x46, 0xc4, 0x8a, 0x98, 0xc9, 0xe6, 0x25, 0xcd, 0xbd, - 0x38, 0x25, 0xb3, 0xa1, 0xb1, 0x63, 0xc7, 0xa6, 0xb0, 0x3a, 0xc6, 0x11, - 0x28, 0x3f, 0x80, 0x38, 0x9e, 0x88, 0xc4, 0xe7, 0xcf, 0x9f, 0xfb, 0x9a, - 0x61, 0x5b, 0xba, 0x74, 0xa9, 0x5b, 0x15, 0x9e, 0xe9, 0x4b, 0x96, 0x2c, - 0xf1, 0x24, 0xe1, 0xe6, 0xcd, 0x9b, 0x9e, 0xf5, 0xd8, 0x05, 0x8a, 0xf1, - 0x97, 0x98, 0x11, 0x3b, 0x99, 0xdc, 0xa0, 0xee, 0x53, 0xbc, 0x08, 0xec, - 0x01, 0x95, 0x26, 0x5b, 0xb6, 0x6c, 0x71, 0x7d, 0x14, 0xab, 0x2d, 0x8d, - 0xe2, 0xdb, 0x29, 0x9e, 0x3d, 0x7b, 0xe6, 0x59, 0xc5, 0x99, 0x33, 0x67, - 0x3c, 0xcb, 0xb8, 0x15, 0x38, 0x77, 0x8e, 0xaf, 0xde, 0x29, 0x2c, 0xe7, - 0xcf, 0x9f, 0x2f, 0x5c, 0xa0, 0xc4, 0x5c, 0x3e, 0xbe, 0x46, 0xec, 0x24, - 0x4b, 0x0f, 0x06, 0x80, 0xd4, 0x17, 0x3e, 0x4c, 0x9d, 0x3a, 0x55, 0x8a, - 0x0f, 0x77, 0xef, 0xde, 0xf5, 0x55, 0xef, 0xbd, 0x7b, 0xf7, 0x04, 0xba, - 0x55, 0x5f, 0x65, 0xb3, 0x0b, 0xf1, 0x9c, 0x07, 0x0f, 0x1e, 0x64, 0x27, - 0x39, 0xee, 0xb3, 0x7e, 0x59, 0x22, 0x0b, 0xbb, 0x2c, 0x7b, 0xcb, 0xa5, - 0x07, 0x80, 0xac, 0xe1, 0xcf, 0xf1, 0xe3, 0xfd, 0xbd, 0xab, 0x02, 0xdd, - 0xa8, 0x68, 0xd7, 0x8e, 0x6e, 0x16, 0x27, 0x3c, 0x67, 0xf4, 0xe8, 0xd1, - 0x9e, 0x27, 0x8d, 0x19, 0x23, 0x6f, 0x10, 0x55, 0x16, 0x76, 0x59, 0x4e, - 0xc9, 0x0f, 0x80, 0xac, 0xc6, 0x02, 0xdd, 0xad, 0xa8, 0xa8, 0x10, 0xc3, - 0x87, 0x0f, 0xf7, 0xac, 0x73, 0xde, 0xbc, 0x79, 0x9e, 0x65, 0xdc, 0x0a, - 0xcc, 0x9a, 0x35, 0xcb, 0x2d, 0xcb, 0x4a, 0xc7, 0xa2, 0x4f, 0x11, 0xc2, - 0xb7, 0xb4, 0xa0, 0x0d, 0x6d, 0xcc, 0xb4, 0x7a, 0x7f, 0xa9, 0x6f, 0xfe, - 0xb0, 0x2f, 0x80, 0x9c, 0xb6, 0xc5, 0x5c, 0x14, 0x39, 0x9d, 0x7f, 0xf2, - 0xe4, 0xc9, 0x54, 0x59, 0x59, 0x99, 0xeb, 0x85, 0x12, 0xd7, 0xe2, 0xb5, - 0xb4, 0xb4, 0x38, 0x9d, 0xea, 0x2b, 0xad, 0xa1, 0xa1, 0x21, 0xd5, 0xb7, - 0x6f, 0x5f, 0xd7, 0xfa, 0x37, 0x6f, 0xde, 0xec, 0xab, 0x1e, 0xbb, 0x50, - 0x29, 0xfe, 0x82, 0x60, 0xd7, 0xf6, 0x03, 0xc8, 0x7b, 0xc1, 0xbe, 0xb1, - 0xb9, 0x8d, 0x51, 0x14, 0xd9, 0xe9, 0x1c, 0xf4, 0xd9, 0xbf, 0x7f, 0xbf, - 0xc0, 0xab, 0x5d, 0x5a, 0xd9, 0x30, 0x63, 0xc6, 0x0c, 0x71, 0xec, 0xd8, - 0x31, 0x81, 0xb5, 0x78, 0xad, 0xf2, 0xfc, 0x26, 0xf4, 0xe9, 0xd3, 0x47, - 0x1c, 0x3d, 0x7a, 0x54, 0x8c, 0x1c, 0x39, 0x32, 0xe7, 0x14, 0x04, 0x9d, - 0xd8, 0xb0, 0x61, 0x83, 0x58, 0xb7, 0x6e, 0x5d, 0x4e, 0x7a, 0x0c, 0x0f, - 0x9a, 0x39, 0xf5, 0xc6, 0x00, 0xe8, 0x13, 0x43, 0xe3, 0x2d, 0x93, 0x17, - 0x2f, 0x5e, 0x2c, 0xaa, 0xaa, 0xaa, 0xac, 0x87, 0x31, 0x2e, 0x5e, 0xbc, - 0x28, 0x7a, 0xf5, 0xea, 0x25, 0x70, 0x0f, 0x2d, 0x66, 0xcf, 0x9e, 0x2d, - 0x48, 0x54, 0x5b, 0x65, 0xd2, 0xa4, 0x49, 0xe2, 0xd2, 0xa5, 0x4b, 0xe2, - 0xc8, 0x91, 0x23, 0x82, 0x57, 0xfc, 0x03, 0x07, 0x0e, 0x14, 0xfc, 0x69, - 0xe0, 0xa8, 0xa0, 0x06, 0x62, 0x7d, 0xf9, 0xaf, 0xc2, 0x11, 0x69, 0xdd, - 0x8c, 0xdd, 0xfd, 0x39, 0x6d, 0x4b, 0xe9, 0x12, 0x9d, 0xea, 0x89, 0x4b, - 0x5a, 0x29, 0xfe, 0xca, 0xe4, 0x06, 0x75, 0x5f, 0xe5, 0x4f, 0xc0, 0x13, - 0xa8, 0x91, 0x64, 0x22, 0xf0, 0x24, 0xd6, 0xd7, 0x00, 0xc9, 0xe4, 0x2c, - 0x50, 0xaf, 0x9b, 0x19, 0x00, 0x8d, 0x81, 0x56, 0x69, 0x2a, 0x8b, 0x13, - 0x02, 0x8d, 0x0c, 0x80, 0xdb, 0x71, 0xb2, 0xd8, 0xd8, 0x1a, 0x28, 0x02, - 0xb7, 0x19, 0x00, 0xdf, 0x04, 0x5a, 0xa5, 0xa9, 0x2c, 0x4e, 0x08, 0x7c, - 0xc3, 0x00, 0xe0, 0x7b, 0x00, 0x8d, 0x24, 0x13, 0x81, 0x4c, 0x00, 0xf0, - 0x36, 0xd0, 0x48, 0xb2, 0x10, 0x20, 0xe7, 0xb7, 0xd8, 0x03, 0xb4, 0x40, - 0xe5, 0x4d, 0x69, 0x25, 0x0b, 0xd4, 0x38, 0x79, 0x4b, 0xce, 0x5b, 0x18, - 0x00, 0x94, 0x9b, 0xef, 0x36, 0xe6, 0x33, 0x41, 0x08, 0x58, 0x9c, 0x73, - 0x28, 0x98, 0x72, 0x0a, 0x3a, 0xd7, 0xda, 0x8b, 0xd9, 0xc7, 0x9b, 0x37, - 0x6f, 0x04, 0x46, 0x02, 0x5d, 0xad, 0xce, 0x7f, 0x18, 0x83, 0xf3, 0xfc, - 0x85, 0xd6, 0x07, 0xb4, 0x6f, 0xdf, 0x3e, 0x67, 0x08, 0xf9, 0xf5, 0xeb, - 0xd7, 0xae, 0x75, 0x73, 0xa8, 0x99, 0xe5, 0x63, 0x2a, 0xe4, 0x3c, 0xf3, - 0x6c, 0xe0, 0xdf, 0x65, 0x39, 0xd1, 0xdc, 0x2c, 0x77, 0xae, 0x69, 0xf9, - 0xf2, 0xe5, 0x82, 0x2f, 0x77, 0x72, 0xd3, 0xeb, 0xd7, 0xaf, 0xe7, 0xb8, - 0xb6, 0x75, 0xeb, 0x56, 0xd7, 0xb2, 0xac, 0x63, 0xdf, 0xbe, 0x7d, 0x99, - 0xf2, 0x3c, 0xd7, 0xad, 0x5e, 0xa6, 0xb3, 0x6d, 0x99, 0x22, 0x19, 0x3b, - 0x8b, 0x73, 0xfb, 0x27, 0xe0, 0x2c, 0x1c, 0x91, 0xc2, 0xd4, 0xe5, 0xcb, - 0x97, 0x65, 0x62, 0xa4, 0x75, 0xdd, 0x12, 0xb1, 0x23, 0xd7, 0xe4, 0x3c, - 0xd3, 0x03, 0xb0, 0x9f, 0xfb, 0x27, 0x13, 0x82, 0x16, 0xcc, 0x99, 0x07, - 0x5d, 0xa5, 0xd4, 0xfa, 0x0a, 0xfd, 0x9c, 0x48, 0x6d, 0xd8, 0xa1, 0x72, - 0x89, 0xd8, 0x91, 0x6b, 0xeb, 0xb7, 0xcd, 0xee, 0x01, 0xd8, 0xbc, 0x94, - 0x9f, 0x01, 0xce, 0xa7, 0xaf, 0x5a, 0xb5, 0xca, 0xd7, 0x02, 0x4e, 0x07, - 0x0c, 0x42, 0x4f, 0x0a, 0x62, 0x0a, 0xb9, 0xad, 0x46, 0x73, 0xb1, 0x2b, - 0x31, 0x23, 0x76, 0x92, 0x24, 0xc3, 0xb5, 0x7d, 0x11, 0xc8, 0x76, 0x32, - 0x89, 0x41, 0x37, 0xba, 0x73, 0xe7, 0x4e, 0xb1, 0x77, 0xef, 0x5e, 0x6b, - 0x9e, 0x3e, 0x7b, 0x9d, 0xdb, 0xe3, 0xc7, 0x7c, 0x87, 0x71, 0xdb, 0x64, - 0xcd, 0x9a, 0x35, 0x62, 0xe1, 0xc2, 0x85, 0xae, 0x95, 0x0c, 0x19, 0x32, - 0x24, 0x27, 0x6f, 0xd1, 0xa2, 0x45, 0x62, 0xd8, 0xb0, 0x61, 0x39, 0x69, - 0xd9, 0x07, 0xd3, 0xa6, 0x4d, 0xcb, 0x1c, 0xf2, 0xdc, 0x3d, 0x7b, 0xf6, - 0x64, 0x8e, 0xf3, 0x77, 0x82, 0x78, 0xde, 0x7f, 0xe3, 0xc6, 0x8d, 0x39, - 0x6f, 0x44, 0xc1, 0x5b, 0xc5, 0x04, 0x57, 0x23, 0x07, 0x81, 0x4d, 0xbe, - 0xbd, 0x59, 0xc7, 0xae, 0x5c, 0xdf, 0x40, 0x21, 0x69, 0x6b, 0x03, 0xfc, - 0xd4, 0xcd, 0x39, 0x73, 0x5d, 0xc5, 0x69, 0x3d, 0x80, 0x1f, 0x4c, 0x02, - 0x2e, 0x43, 0x8e, 0x33, 0x92, 0xfd, 0x13, 0xc0, 0xc4, 0x3f, 0x66, 0x72, - 0xcc, 0x8e, 0xae, 0x08, 0xe4, 0x70, 0x9c, 0x1f, 0x00, 0x7f, 0x82, 0xd7, - 0xc5, 0x2f, 0xa2, 0xd7, 0x15, 0x2a, 0xfd, 0xfc, 0x22, 0xb7, 0xe4, 0x38, - 0x23, 0xf9, 0x01, 0x50, 0x87, 0x9c, 0xe3, 0x99, 0xdc, 0x08, 0x76, 0x0a, - 0x0d, 0xbc, 0x44, 0x60, 0x4e, 0xa0, 0x4d, 0x2a, 0xf0, 0x44, 0x31, 0xb9, - 0x25, 0xc7, 0x19, 0xc9, 0x0f, 0x00, 0x66, 0xe4, 0x74, 0x11, 0x99, 0x92, - 0x21, 0xed, 0xe0, 0x0f, 0x1c, 0x43, 0x6a, 0x29, 0xfc, 0x66, 0x1e, 0x3d, - 0x7a, 0x14, 0x7e, 0xa3, 0xb9, 0x2d, 0xb6, 0xe2, 0xd6, 0x29, 0x00, 0x0e, - 0xe2, 0x1c, 0xfe, 0xb9, 0x40, 0x24, 0x22, 0x71, 0xf0, 0x23, 0x12, 0x7f, - 0xb2, 0x1b, 0x8d, 0xd8, 0x37, 0x72, 0x4a, 0x6e, 0x73, 0xc4, 0x29, 0x00, - 0x9e, 0xa3, 0xc4, 0xef, 0x72, 0x4a, 0x85, 0x78, 0x70, 0xe0, 0xc0, 0x81, - 0x10, 0x5b, 0x0b, 0xb7, 0xa9, 0x88, 0x7d, 0x23, 0xa7, 0xe4, 0xd6, 0x97, - 0xf4, 0x42, 0xa9, 0x26, 0x68, 0x24, 0xb7, 0x84, 0x18, 0x00, 0xd1, 0xee, - 0x4e, 0x90, 0x3e, 0x45, 0x85, 0x67, 0x9a, 0x4b, 0x72, 0x5a, 0x94, 0xfc, - 0x1a, 0xa5, 0x23, 0x31, 0x1a, 0x03, 0x35, 0x29, 0x3e, 0x96, 0xa5, 0x8b, - 0xd0, 0x17, 0xfa, 0x14, 0x15, 0x9e, 0x68, 0x97, 0x5c, 0x16, 0x2d, 0xfc, - 0x8f, 0x19, 0x4e, 0x1a, 0x44, 0x62, 0xf8, 0x94, 0x29, 0x53, 0x8a, 0x7e, - 0x05, 0x8b, 0x8a, 0x01, 0xc3, 0xff, 0x0b, 0xa0, 0x2f, 0x51, 0xe1, 0x98, - 0xe6, 0x90, 0x5c, 0x96, 0x24, 0x5b, 0x71, 0x56, 0x64, 0xc6, 0x63, 0x28, - 0x36, 0x85, 0x21, 0xe4, 0x56, 0xaf, 0x96, 0x51, 0x91, 0xe8, 0x7c, 0x9b, - 0xb0, 0xe6, 0xc0, 0xb2, 0x9d, 0x3e, 0x44, 0x89, 0x21, 0xda, 0x26, 0x87, - 0xae, 0x52, 0xe6, 0x9a, 0xf3, 0x2e, 0x83, 0xff, 0xcc, 0xc4, 0x45, 0xa3, - 0xad, 0x9f, 0xbe, 0xf4, 0x38, 0x31, 0xc8, 0x6c, 0xbc, 0x48, 0x49, 0x2c, - 0x58, 0xb0, 0x40, 0xe0, 0x25, 0x4a, 0x25, 0xff, 0x59, 0x54, 0x90, 0xf6, - 0x14, 0xaa, 0x8b, 0x7f, 0x1e, 0x85, 0xf7, 0x12, 0x89, 0xc3, 0x87, 0x0f, - 0x0b, 0x99, 0x2f, 0x8f, 0x28, 0x64, 0x43, 0x56, 0x9e, 0xe7, 0x9f, 0x47, - 0x67, 0x95, 0x75, 0xdd, 0xfd, 0x0c, 0x39, 0x51, 0x47, 0xb1, 0x69, 0xbf, - 0x34, 0x0e, 0x96, 0xbb, 0xb2, 0x5a, 0x64, 0x46, 0xad, 0x09, 0x82, 0xd8, - 0x7d, 0x09, 0xc8, 0x99, 0xa7, 0x78, 0xfd, 0x04, 0xd8, 0x15, 0x7c, 0x80, - 0x9d, 0x2b, 0xd0, 0x4e, 0x76, 0x82, 0xd9, 0x2a, 0x8d, 0xc0, 0x4b, 0x58, - 0xc7, 0xe7, 0xd7, 0x3d, 0x1f, 0xfa, 0xf1, 0xbb, 0xa2, 0xb1, 0x01, 0x95, - 0xbd, 0x07, 0x9d, 0x01, 0x35, 0xa2, 0x3e, 0x02, 0xbc, 0xf0, 0xfb, 0x6b, - 0xd0, 0x66, 0x32, 0x00, 0xa4, 0xbe, 0x4b, 0x00, 0xf5, 0x9b, 0xdf, 0xfa, - 0xb6, 0x63, 0x40, 0x8e, 0xc8, 0x95, 0x14, 0xe1, 0x6b, 0xb3, 0x9e, 0x40, - 0x0d, 0x51, 0x6a, 0x62, 0x40, 0x6e, 0xc8, 0x91, 0x54, 0xf9, 0x14, 0xb5, - 0x9b, 0x00, 0x50, 0x13, 0x03, 0x72, 0x13, 0x8a, 0xfc, 0x1e, 0xad, 0x98, - 0x20, 0x50, 0x0b, 0x03, 0x72, 0x12, 0x9a, 0xf0, 0x6e, 0x80, 0xef, 0x51, - 0x35, 0x41, 0xa0, 0x06, 0x06, 0xe4, 0x22, 0xf4, 0x3b, 0x34, 0xfe, 0xe5, - 0xc8, 0x5d, 0x13, 0x04, 0x91, 0x7f, 0x09, 0xc8, 0x01, 0xb9, 0x88, 0x44, - 0x78, 0xc1, 0x51, 0x0f, 0x35, 0x3d, 0x41, 0x34, 0x18, 0x10, 0x7b, 0xe9, - 0x17, 0x7d, 0x5e, 0x91, 0x35, 0x09, 0x05, 0xcc, 0x9d, 0x41, 0xf8, 0x01, - 0x40, 0xcc, 0x89, 0xbd, 0x12, 0x52, 0x0d, 0x2b, 0xbe, 0x87, 0x9a, 0x9e, - 0x20, 0x1c, 0x0c, 0x88, 0x35, 0x31, 0x57, 0x4a, 0x3e, 0x81, 0x35, 0x26, - 0x08, 0xe4, 0x07, 0x00, 0x31, 0x26, 0xd6, 0x4a, 0x4a, 0x35, 0xac, 0x8a, - 0x6c, 0x29, 0x19, 0xda, 0xd6, 0xbd, 0x07, 0x22, 0xb6, 0xc4, 0x58, 0x69, - 0xe1, 0x8b, 0xfc, 0xef, 0x41, 0x75, 0x27, 0x23, 0x6c, 0xff, 0x88, 0xa9, - 0xbf, 0x3f, 0x49, 0x50, 0x20, 0x3c, 0xde, 0x87, 0x0d, 0x91, 0x3f, 0x67, - 0xa8, 0x51, 0x10, 0x12, 0x4b, 0x62, 0x1a, 0x2b, 0xe1, 0x6a, 0xa2, 0x5a, - 0x68, 0xd8, 0xdf, 0x14, 0xdd, 0xda, 0x23, 0x86, 0xc4, 0x32, 0x96, 0xc2, - 0xe9, 0xe6, 0x2f, 0xa0, 0x6f, 0xa0, 0xba, 0x11, 0x23, 0xdb, 0x1f, 0x62, - 0x46, 0xec, 0xfc, 0x4e, 0xd9, 0xa3, 0xa8, 0xba, 0x52, 0x0d, 0xd3, 0xf8, - 0x4c, 0x9a, 0x6c, 0xd0, 0x74, 0xa9, 0x9f, 0x58, 0x11, 0x33, 0xad, 0xa4, - 0x2f, 0xbc, 0xf9, 0x0a, 0xaa, 0x0b, 0x49, 0xb2, 0xfc, 0x20, 0x46, 0xc4, - 0x4a, 0x4b, 0x29, 0x83, 0x57, 0xab, 0xa0, 0xdf, 0x41, 0x65, 0x01, 0x18, - 0xd7, 0x7a, 0x89, 0x09, 0xb1, 0x21, 0x46, 0xda, 0x0b, 0x23, 0xfc, 0x0f, - 0xd0, 0xb7, 0xd0, 0xb8, 0x12, 0x16, 0x94, 0xdd, 0xc4, 0x80, 0x58, 0x68, - 0xfb, 0xad, 0x87, 0x6f, 0xae, 0x52, 0x89, 0x9c, 0x24, 0x4f, 0x2b, 0xd3, - 0x77, 0x62, 0x90, 0x68, 0xe1, 0x13, 0xca, 0x9f, 0x43, 0xbf, 0x85, 0x06, - 0xf5, 0xad, 0x52, 0xbd, 0x1e, 0xfa, 0x4a, 0x9f, 0xe9, 0xbb, 0x91, 0x34, - 0x02, 0xbc, 0xdd, 0xf9, 0x29, 0x94, 0xcb, 0xcf, 0x55, 0x27, 0xb0, 0x54, - 0xfb, 0xe8, 0x1b, 0x7d, 0xd4, 0xe2, 0xd6, 0x0e, 0x7e, 0x48, 0x93, 0x8f, - 0x51, 0xf3, 0x69, 0x68, 0xa9, 0x40, 0xab, 0x76, 0x1e, 0x7d, 0xa1, 0x4f, - 0x46, 0x8a, 0x44, 0xe0, 0x23, 0x94, 0xff, 0x2d, 0x94, 0xff, 0xe2, 0xac, - 0x1a, 0xa9, 0x5e, 0xf6, 0xd0, 0x66, 0xda, 0x4e, 0x1f, 0x8c, 0xb4, 0x11, - 0x01, 0x76, 0x99, 0x35, 0xd0, 0xdd, 0xd0, 0xa7, 0x50, 0x2f, 0xf0, 0xa3, - 0xca, 0xa7, 0x6d, 0xb4, 0x91, 0xb6, 0xc6, 0xa2, 0x9b, 0x8f, 0xe3, 0x3d, - 0x67, 0x37, 0x80, 0x3b, 0x0b, 0x3a, 0x33, 0xad, 0x1f, 0x62, 0x1b, 0xd5, - 0xc5, 0x14, 0x6f, 0xe1, 0xae, 0x42, 0x6b, 0xd3, 0x7a, 0x12, 0x5b, 0xfe, - 0x01, 0x47, 0x6c, 0x24, 0x8e, 0x01, 0x90, 0x0f, 0x2e, 0x27, 0x4a, 0xaa, - 0xa0, 0x0c, 0x08, 0xde, 0x52, 0x55, 0x40, 0x65, 0x4d, 0x9e, 0xf0, 0x2f, - 0xf6, 0xf8, 0xb8, 0x3c, 0xdf, 0xb4, 0x4d, 0xd2, 0xbf, 0x86, 0x32, 0x2d, - 0xb6, 0xa2, 0x43, 0x00, 0x38, 0x81, 0xcf, 0x41, 0x15, 0x06, 0x02, 0x17, - 0x4c, 0x72, 0x3b, 0x02, 0xca, 0x77, 0xe4, 0x74, 0x87, 0x96, 0xa7, 0xd5, - 0xde, 0xc7, 0xa1, 0xf5, 0x26, 0x14, 0x76, 0xdf, 0x7c, 0x23, 0x0a, 0x95, - 0xfb, 0x5c, 0x7c, 0x71, 0x07, 0x4a, 0xc2, 0x6f, 0xa5, 0xb7, 0x7c, 0x46, - 0x52, 0x2b, 0xf9, 0x3f, 0x92, 0xc9, 0x00, 0xb6, 0x61, 0xee, 0xab, 0xc9, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go index 429e1c3d..e4cfe125 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go @@ -3,7 +3,9 @@ package model -import "github.com/mattermost/mattermost-server/v5/mlog" +import ( + "github.com/mattermost/mattermost-server/v5/shared/mlog" +) type BundleInfo struct { Path string diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go index 282271ad..8dc3fa8d 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go @@ -34,23 +34,26 @@ const ( ) type Channel struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - TeamId string `json:"team_id"` - Type string `json:"type"` - DisplayName string `json:"display_name"` - Name string `json:"name"` - Header string `json:"header"` - Purpose string `json:"purpose"` - LastPostAt int64 `json:"last_post_at"` - TotalMsgCount int64 `json:"total_msg_count"` - ExtraUpdateAt int64 `json:"extra_update_at"` - CreatorId string `json:"creator_id"` - SchemeId *string `json:"scheme_id"` - Props map[string]interface{} `json:"props" db:"-"` - GroupConstrained *bool `json:"group_constrained"` + Id string `json:"id"` + CreateAt int64 `json:"create_at"` + UpdateAt int64 `json:"update_at"` + DeleteAt int64 `json:"delete_at"` + TeamId string `json:"team_id"` + Type string `json:"type"` + DisplayName string `json:"display_name"` + Name string `json:"name"` + Header string `json:"header"` + Purpose string `json:"purpose"` + LastPostAt int64 `json:"last_post_at"` + TotalMsgCount int64 `json:"total_msg_count"` + ExtraUpdateAt int64 `json:"extra_update_at"` + CreatorId string `json:"creator_id"` + SchemeId *string `json:"scheme_id"` + Props map[string]interface{} `json:"props" db:"-"` + GroupConstrained *bool `json:"group_constrained"` + Shared *bool `json:"shared"` + TotalMsgCountRoot int64 `json:"total_msg_count_root"` + PolicyID *string `json:"policy_id" db:"-"` } type ChannelWithTeamData struct { @@ -120,18 +123,21 @@ type ChannelModeratedRolesPatch struct { // PerPage number of results per page, if paginated. // type ChannelSearchOpts struct { - NotAssociatedToGroup string - ExcludeDefaultChannels bool - IncludeDeleted bool - Deleted bool - ExcludeChannelNames []string - TeamIds []string - GroupConstrained bool - ExcludeGroupConstrained bool - Public bool - Private bool - Page *int - PerPage *int + NotAssociatedToGroup string + ExcludeDefaultChannels bool + IncludeDeleted bool + Deleted bool + ExcludeChannelNames []string + TeamIds []string + GroupConstrained bool + ExcludeGroupConstrained bool + PolicyID string + ExcludePolicyConstrained bool + IncludePolicyID bool + Public bool + Private bool + Page *int + PerPage *int } type ChannelMemberCountByGroup struct { @@ -140,6 +146,14 @@ type ChannelMemberCountByGroup struct { ChannelMemberTimezonesCount int64 `db:"-" json:"channel_member_timezones_count"` } +type ChannelOption func(channel *Channel) + +func WithID(ID string) ChannelOption { + return func(channel *Channel) { + channel.Id = ID + } +} + func (o *Channel) DeepCopy() *Channel { copy := *o if copy.SchemeId != nil { @@ -313,6 +327,10 @@ func (o *Channel) IsGroupConstrained() bool { return o.GroupConstrained != nil && *o.GroupConstrained } +func (o *Channel) IsShared() bool { + return o.Shared != nil && *o.Shared +} + func (o *Channel) GetOtherUserIdForDM(userId string) string { if o.Type != CHANNEL_DIRECT { return "" @@ -336,9 +354,8 @@ func (o *Channel) GetOtherUserIdForDM(userId string) string { func GetDMNameFromIds(userId1, userId2 string) string { if userId1 > userId2 { return userId2 + "__" + userId1 - } else { - return userId1 + "__" + userId2 } + return userId1 + "__" + userId2 } func GetGroupDisplayNameFromUsers(users []*User, truncate bool) string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go index 11ddeec4..6230ab3d 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go @@ -14,11 +14,12 @@ import ( type ChannelCounts struct { Counts map[string]int64 `json:"counts"` + CountsRoot map[string]int64 `json:"counts_root"` UpdateTimes map[string]int64 `json:"update_times"` } func (o *ChannelCounts) Etag() string { - + // we don't include CountsRoot in ETag calculation, since it's a deriviative ids := []string{} for id := range o.Counts { ids = append(ids, id) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go index b47077ae..4ba9e5c3 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go @@ -11,11 +11,11 @@ import ( type ChannelList []*Channel func (o *ChannelList) ToJson() string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func (o *ChannelList) Etag() string { @@ -55,11 +55,11 @@ func ChannelSliceFromJson(data io.Reader) []*Channel { type ChannelListWithTeamData []*ChannelWithTeamData func (o *ChannelListWithTeamData) ToJson() string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func (o *ChannelListWithTeamData) Etag() string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go index d7a76e2d..bc02881e 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go @@ -24,36 +24,42 @@ const ( ) type ChannelUnread struct { - TeamId string `json:"team_id"` - ChannelId string `json:"channel_id"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` - NotifyProps StringMap `json:"-"` + TeamId string `json:"team_id"` + ChannelId string `json:"channel_id"` + MsgCount int64 `json:"msg_count"` + MentionCount int64 `json:"mention_count"` + MentionCountRoot int64 `json:"mention_count_root"` + MsgCountRoot int64 `json:"msg_count_root"` + NotifyProps StringMap `json:"-"` } type ChannelUnreadAt struct { - TeamId string `json:"team_id"` - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` - LastViewedAt int64 `json:"last_viewed_at"` - NotifyProps StringMap `json:"-"` + TeamId string `json:"team_id"` + UserId string `json:"user_id"` + ChannelId string `json:"channel_id"` + MsgCount int64 `json:"msg_count"` + MentionCount int64 `json:"mention_count"` + MentionCountRoot int64 `json:"mention_count_root"` + MsgCountRoot int64 `json:"msg_count_root"` + LastViewedAt int64 `json:"last_viewed_at"` + NotifyProps StringMap `json:"-"` } type ChannelMember struct { - ChannelId string `json:"channel_id"` - UserId string `json:"user_id"` - Roles string `json:"roles"` - LastViewedAt int64 `json:"last_viewed_at"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` - NotifyProps StringMap `json:"notify_props"` - LastUpdateAt int64 `json:"last_update_at"` - SchemeGuest bool `json:"scheme_guest"` - SchemeUser bool `json:"scheme_user"` - SchemeAdmin bool `json:"scheme_admin"` - ExplicitRoles string `json:"explicit_roles"` + ChannelId string `json:"channel_id"` + UserId string `json:"user_id"` + Roles string `json:"roles"` + LastViewedAt int64 `json:"last_viewed_at"` + MsgCount int64 `json:"msg_count"` + MentionCount int64 `json:"mention_count"` + MentionCountRoot int64 `json:"mention_count_root"` + MsgCountRoot int64 `json:"msg_count_root"` + NotifyProps StringMap `json:"notify_props"` + LastUpdateAt int64 `json:"last_update_at"` + SchemeGuest bool `json:"scheme_guest"` + SchemeUser bool `json:"scheme_user"` + SchemeAdmin bool `json:"scheme_admin"` + ExplicitRoles string `json:"explicit_roles"` } type ChannelMembers []ChannelMember @@ -65,11 +71,11 @@ type ChannelMemberForExport struct { } func (o *ChannelMembers) ToJson() string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func (o *ChannelUnread) ToJson() string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go index 87fd3aef..51e11736 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go @@ -11,18 +11,19 @@ import ( const CHANNEL_SEARCH_DEFAULT_LIMIT = 50 type ChannelSearch struct { - Term string `json:"term"` - ExcludeDefaultChannels bool `json:"exclude_default_channels"` - NotAssociatedToGroup string `json:"not_associated_to_group"` - TeamIds []string `json:"team_ids"` - GroupConstrained bool `json:"group_constrained"` - ExcludeGroupConstrained bool `json:"exclude_group_constrained"` - Public bool `json:"public"` - Private bool `json:"private"` - IncludeDeleted bool `json:"include_deleted"` - Deleted bool `json:"deleted"` - Page *int `json:"page,omitempty"` - PerPage *int `json:"per_page,omitempty"` + Term string `json:"term"` + ExcludeDefaultChannels bool `json:"exclude_default_channels"` + NotAssociatedToGroup string `json:"not_associated_to_group"` + TeamIds []string `json:"team_ids"` + GroupConstrained bool `json:"group_constrained"` + ExcludeGroupConstrained bool `json:"exclude_group_constrained"` + ExcludePolicyConstrained bool `json:"exclude_policy_constrained"` + Public bool `json:"public"` + Private bool `json:"private"` + IncludeDeleted bool `json:"include_deleted"` + Deleted bool `json:"deleted"` + Page *int `json:"page,omitempty"` + PerPage *int `json:"per_page,omitempty"` } // ToJson convert a Channel to a json string diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_sidebar.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_sidebar.go index 033432c9..35301d1e 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_sidebar.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_sidebar.go @@ -47,6 +47,7 @@ type SidebarCategory struct { Type SidebarCategoryType `json:"type"` DisplayName string `json:"display_name"` Muted bool `json:"muted"` + Collapsed bool `json:"collapsed"` } // SidebarCategoryWithChannels combines data from SidebarCategory table with the Channel IDs that belong to that category @@ -97,19 +98,19 @@ func (o SidebarCategoryWithChannels) ToJson() []byte { } func SidebarCategoriesWithChannelsToJson(o []*SidebarCategoryWithChannels) []byte { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return []byte("[]") - } else { - return b } + return b } func (o OrderedSidebarCategories) ToJson() []byte { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return []byte("[]") - } else { - return b } + return b } var categoryIdPattern = regexp.MustCompile("(favorites|channels|direct_messages)_[a-z0-9]{26}_[a-z0-9]{26}") diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go index 42fcac3a..2ba74434 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go @@ -9,8 +9,9 @@ import ( ) type ChannelView struct { - ChannelId string `json:"channel_id"` - PrevChannelId string `json:"prev_channel_id"` + ChannelId string `json:"channel_id"` + PrevChannelId string `json:"prev_channel_id"` + CollapsedThreadsSupported bool `json:"collapsed_threads_supported"` } func (o *ChannelView) ToJson() string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go b/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go index 8ebf0da1..0b9e713a 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go @@ -19,25 +19,29 @@ import ( ) const ( - HEADER_REQUEST_ID = "X-Request-ID" - HEADER_VERSION_ID = "X-Version-ID" - HEADER_CLUSTER_ID = "X-Cluster-ID" - HEADER_ETAG_SERVER = "ETag" - HEADER_ETAG_CLIENT = "If-None-Match" - HEADER_FORWARDED = "X-Forwarded-For" - HEADER_REAL_IP = "X-Real-IP" - HEADER_FORWARDED_PROTO = "X-Forwarded-Proto" - HEADER_TOKEN = "token" - HEADER_CSRF_TOKEN = "X-CSRF-Token" - HEADER_BEARER = "BEARER" - HEADER_AUTH = "Authorization" - HEADER_REQUESTED_WITH = "X-Requested-With" - HEADER_REQUESTED_WITH_XML = "XMLHttpRequest" - STATUS = "status" - STATUS_OK = "OK" - STATUS_FAIL = "FAIL" - STATUS_UNHEALTHY = "UNHEALTHY" - STATUS_REMOVE = "REMOVE" + HEADER_REQUEST_ID = "X-Request-ID" + HEADER_VERSION_ID = "X-Version-ID" + HEADER_CLUSTER_ID = "X-Cluster-ID" + HEADER_ETAG_SERVER = "ETag" + HEADER_ETAG_CLIENT = "If-None-Match" + HEADER_FORWARDED = "X-Forwarded-For" + HEADER_REAL_IP = "X-Real-IP" + HEADER_FORWARDED_PROTO = "X-Forwarded-Proto" + HEADER_TOKEN = "token" + HEADER_CSRF_TOKEN = "X-CSRF-Token" + HEADER_BEARER = "BEARER" + HEADER_AUTH = "Authorization" + HEADER_CLOUD_TOKEN = "X-Cloud-Token" + HEADER_REMOTECLUSTER_TOKEN = "X-RemoteCluster-Token" + HEADER_REMOTECLUSTER_ID = "X-RemoteCluster-Id" + HEADER_REQUESTED_WITH = "X-Requested-With" + HEADER_REQUESTED_WITH_XML = "XMLHttpRequest" + HEADER_RANGE = "Range" + STATUS = "status" + STATUS_OK = "OK" + STATUS_FAIL = "FAIL" + STATUS_UNHEALTHY = "UNHEALTHY" + STATUS_REMOVE = "REMOVE" CLIENT_DIR = "client" @@ -93,9 +97,8 @@ func (c *Client4) boolString(value bool) string { if value { return "true" - } else { - return "false" } + return "false" } func closeBody(r *http.Response) { @@ -189,12 +192,12 @@ func (c *Client4) GetUserRoute(userId string) string { return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId) } -func (c *Client4) GetUserThreadsRoute(userId string) string { - return fmt.Sprintf(c.GetUsersRoute()+"/%v/threads", userId) +func (c *Client4) GetUserThreadsRoute(userID, teamID string) string { + return c.GetUserRoute(userID) + c.GetTeamRoute(teamID) + "/threads" } -func (c *Client4) GetUserThreadRoute(userId, threadId string) string { - return fmt.Sprintf(c.GetUserThreadsRoute(userId)+"/%v", threadId) +func (c *Client4) GetUserThreadRoute(userId, teamId, threadId string) string { + return c.GetUserThreadsRoute(userId, teamId) + "/" + threadId } func (c *Client4) GetUserCategoryRoute(userID, teamID string) string { @@ -383,7 +386,11 @@ func (c *Client4) GetComplianceReportsRoute() string { } func (c *Client4) GetComplianceReportRoute(reportId string) string { - return fmt.Sprintf("/compliance/reports/%v", reportId) + return fmt.Sprintf("%s/%s", c.GetComplianceReportsRoute(), reportId) +} + +func (c *Client4) GetComplianceReportDownloadRoute(reportId string) string { + return fmt.Sprintf("%s/%s/download", c.GetComplianceReportsRoute(), reportId) } func (c *Client4) GetOutgoingWebhooksRoute() string { @@ -422,6 +429,10 @@ func (c *Client4) GetDataRetentionRoute() string { return "/data_retention" } +func (c *Client4) GetDataRetentionPolicyRoute(policyID string) string { + return fmt.Sprintf(c.GetDataRetentionRoute()+"/policies/%v", policyID) +} + func (c *Client4) GetElasticsearchRoute() string { return "/elasticsearch" } @@ -542,6 +553,30 @@ func (c *Client4) GetGroupSyncablesRoute(groupID string, syncableType GroupSynca return fmt.Sprintf("%s/%ss", c.GetGroupRoute(groupID), strings.ToLower(syncableType.String())) } +func (c *Client4) GetImportsRoute() string { + return "/imports" +} + +func (c *Client4) GetExportsRoute() string { + return "/exports" +} + +func (c *Client4) GetExportRoute(name string) string { + return fmt.Sprintf(c.GetExportsRoute()+"/%v", name) +} + +func (c *Client4) GetRemoteClusterRoute() string { + return "/remotecluster" +} + +func (c *Client4) GetSharedChannelsRoute() string { + return "/sharedchannels" +} + +func (c *Client4) GetPermissionsRoute() string { + return "/permissions" +} + func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) { return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag) } @@ -550,6 +585,14 @@ func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "") } +func (c *Client4) doApiDeleteBytes(url string, data []byte) (*http.Response, *AppError) { + return c.doApiRequestBytes(http.MethodDelete, c.ApiUrl+url, data, "") +} + +func (c *Client4) doApiPatchBytes(url string, data []byte) (*http.Response, *AppError) { + return c.doApiRequestBytes(http.MethodPatch, c.ApiUrl+url, data, "") +} + func (c *Client4) doApiPostBytes(url string, data []byte) (*http.Response, *AppError) { return c.doApiRequestBytes(http.MethodPost, c.ApiUrl+url, data, "") } @@ -567,24 +610,28 @@ func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) { } func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) { - return c.doApiRequestReader(method, url, strings.NewReader(data), etag) + return c.doApiRequestReader(method, url, strings.NewReader(data), map[string]string{HEADER_ETAG_CLIENT: etag}) +} + +func (c *Client4) DoApiRequestWithHeaders(method, url, data string, headers map[string]string) (*http.Response, *AppError) { + return c.doApiRequestReader(method, url, strings.NewReader(data), headers) } func (c *Client4) doApiRequestBytes(method, url string, data []byte, etag string) (*http.Response, *AppError) { - return c.doApiRequestReader(method, url, bytes.NewReader(data), etag) + return c.doApiRequestReader(method, url, bytes.NewReader(data), map[string]string{HEADER_ETAG_CLIENT: etag}) } -func (c *Client4) doApiRequestReader(method, url string, data io.Reader, etag string) (*http.Response, *AppError) { +func (c *Client4) doApiRequestReader(method, url string, data io.Reader, headers map[string]string) (*http.Response, *AppError) { rq, err := http.NewRequest(method, url, data) if err != nil { return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest) } - if len(etag) > 0 { - rq.Header.Set(HEADER_ETAG_CLIENT, etag) + for k, v := range headers { + rq.Header.Set(k, v) } - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -625,7 +672,7 @@ func (c *Client4) doUploadFile(url string, body io.Reader, contentType string, c } rq.Header.Set("Content-Type", contentType) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -649,7 +696,7 @@ func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) } rq.Header.Set("Content-Type", contentType) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -673,7 +720,7 @@ func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string } rq.Header.Set("Content-Type", contentType) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -1393,14 +1440,20 @@ func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) { // GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount // of unread messages and mentions the current user has for the teams it belongs to. -// An optional team ID can be set to exclude that team from the results. Must be authenticated. -func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) { - var optional string +// An optional team ID can be set to exclude that team from the results. +// An optional boolean can be set to include collapsed thread unreads. Must be authenticated. +func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string, includeCollapsedThreads bool) ([]*TeamUnread, *Response) { + query := url.Values{} + if teamIdToExclude != "" { - optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude)) + query.Set("exclude_team", teamIdToExclude) + } + + if includeCollapsedThreads { + query.Set("include_collapsed_threads", "true") } - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, "") + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread?"+query.Encode(), "") if err != nil { return nil, BuildErrorResponse(r, err) } @@ -1486,7 +1539,7 @@ func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) } rq.Header.Set("Content-Type", writer.FormDataContentType()) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -1735,7 +1788,7 @@ func (c *Client4) SetBotIconImage(botUserId string, data []byte) (bool, *Respons } rq.Header.Set("Content-Type", writer.FormDataContentType()) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -1822,6 +1875,18 @@ func (c *Client4) GetAllTeamsWithTotalCount(etag string, page int, perPage int) return teamsListWithCount.Teams, teamsListWithCount.TotalCount, BuildResponse(r) } +// GetAllTeamsExcludePolicyConstrained returns all teams which are not part of a data retention policy. +// Must be a system administrator. +func (c *Client4) GetAllTeamsExcludePolicyConstrained(etag string, page int, perPage int) ([]*Team, *Response) { + query := fmt.Sprintf("?page=%v&per_page=%v&exclude_policy_constrained=%v", page, perPage, true) + r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag) + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) +} + // GetTeamByName returns a team based on the provided team name string. func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) { r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag) @@ -2269,7 +2334,7 @@ func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) { } rq.Header.Set("Content-Type", writer.FormDataContentType()) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -2316,16 +2381,23 @@ func (c *Client4) RemoveTeamIcon(teamId string) (bool, *Response) { // GetAllChannels get all the channels. Must be a system administrator. func (c *Client4) GetAllChannels(page int, perPage int, etag string) (*ChannelListWithTeamData, *Response) { - return c.getAllChannels(page, perPage, etag, false) + return c.getAllChannels(page, perPage, etag, ChannelSearchOpts{}) } // GetAllChannelsIncludeDeleted get all the channels. Must be a system administrator. func (c *Client4) GetAllChannelsIncludeDeleted(page int, perPage int, etag string) (*ChannelListWithTeamData, *Response) { - return c.getAllChannels(page, perPage, etag, true) + return c.getAllChannels(page, perPage, etag, ChannelSearchOpts{IncludeDeleted: true}) +} + +// GetAllChannelsExcludePolicyConstrained gets all channels which are not part of a data retention policy. +// Must be a system administrator. +func (c *Client4) GetAllChannelsExcludePolicyConstrained(page, perPage int, etag string) (*ChannelListWithTeamData, *Response) { + return c.getAllChannels(page, perPage, etag, ChannelSearchOpts{ExcludePolicyConstrained: true}) } -func (c *Client4) getAllChannels(page int, perPage int, etag string, includeDeleted bool) (*ChannelListWithTeamData, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&include_deleted=%v", page, perPage, includeDeleted) +func (c *Client4) getAllChannels(page int, perPage int, etag string, opts ChannelSearchOpts) (*ChannelListWithTeamData, *Response) { + query := fmt.Sprintf("?page=%v&per_page=%v&include_deleted=%v&exclude_policy_constrained=%v", + page, perPage, opts.IncludeDeleted, opts.ExcludePolicyConstrained) r, err := c.DoApiGet(c.GetChannelsRoute()+query, etag) if err != nil { return nil, BuildErrorResponse(r, err) @@ -2849,8 +2921,9 @@ func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) } // SetPostUnread marks channel where post belongs as unread on the time of the provided post. -func (c *Client4) SetPostUnread(userId string, postId string) *Response { - r, err := c.DoApiPost(c.GetUserRoute(userId)+c.GetPostRoute(postId)+"/set_unread", "") +func (c *Client4) SetPostUnread(userId string, postId string, collapsedThreadsSupported bool) *Response { + b, _ := json.Marshal(map[string]bool{"collapsed_threads_supported": collapsedThreadsSupported}) + r, err := c.DoApiPost(c.GetUserRoute(userId)+c.GetPostRoute(postId)+"/set_unread", string(b)) if err != nil { return BuildErrorResponse(r, err) } @@ -2899,8 +2972,12 @@ func (c *Client4) DeletePost(postId string) (bool, *Response) { } // GetPostThread gets a post with all the other posts in the same thread. -func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Response) { - r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag) +func (c *Client4) GetPostThread(postId string, etag string, collapsedThreads bool) (*PostList, *Response) { + url := c.GetPostRoute(postId) + "/thread" + if collapsedThreads { + url += "?collapsedThreads=true" + } + r, err := c.DoApiGet(url, etag) if err != nil { return nil, BuildErrorResponse(r, err) } @@ -2909,8 +2986,11 @@ func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Respons } // GetPostsForChannel gets a page of posts with an array for ordering for a channel. -func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string) (*PostList, *Response) { +func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) + if collapsedThreads { + query += "&collapsedThreads=true" + } r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) if err != nil { return nil, BuildErrorResponse(r, err) @@ -2961,8 +3041,11 @@ func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId strin } // GetPostsSince gets posts created after a specified time as Unix time in milliseconds. -func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Response) { +func (c *Client4) GetPostsSince(channelId string, time int64, collapsedThreads bool) (*PostList, *Response) { query := fmt.Sprintf("?since=%v", time) + if collapsedThreads { + query += "&collapsedThreads=true" + } r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, "") if err != nil { return nil, BuildErrorResponse(r, err) @@ -2972,8 +3055,11 @@ func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Respo } // GetPostsAfter gets a page of posts that were posted after the post provided. -func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) { +func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId) + if collapsedThreads { + query += "&collapsedThreads=true" + } r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) if err != nil { return nil, BuildErrorResponse(r, err) @@ -2983,8 +3069,11 @@ func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, eta } // GetPostsBefore gets a page of posts that were posted before the post provided. -func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) { +func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId) + if collapsedThreads { + query += "&collapsedThreads=true" + } r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) if err != nil { return nil, BuildErrorResponse(r, err) @@ -2994,14 +3083,36 @@ func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, et } // GetPostsAroundLastUnread gets a list of posts around last unread post by a user in a channel. -func (c *Client4) GetPostsAroundLastUnread(userId, channelId string, limitBefore, limitAfter int) (*PostList, *Response) { +func (c *Client4) GetPostsAroundLastUnread(userId, channelId string, limitBefore, limitAfter int, collapsedThreads bool) (*PostList, *Response) { query := fmt.Sprintf("?limit_before=%v&limit_after=%v", limitBefore, limitAfter) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/posts/unread"+query, ""); err != nil { + if collapsedThreads { + query += "&collapsedThreads=true" + } + r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/posts/unread"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) +} + +// SearchFiles returns any posts with matching terms string. +func (c *Client4) SearchFiles(teamId string, terms string, isOrSearch bool) (*FileInfoList, *Response) { + params := SearchParameter{ + Terms: &terms, + IsOrSearch: &isOrSearch, + } + return c.SearchFilesWithParams(teamId, ¶ms) +} + +// SearchFilesWithParams returns any posts with matching terms string. +func (c *Client4) SearchFilesWithParams(teamId string, params *SearchParameter) (*FileInfoList, *Response) { + r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/files/search", params.SearchParameterToJson()) + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + return FileInfoListFromJson(r.Body), BuildResponse(r) } // SearchPosts returns any posts with matching terms string. @@ -3251,6 +3362,21 @@ func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, // General/System Section +// GenerateSupportPacket downloads the generated support packet +func (c *Client4) GenerateSupportPacket() ([]byte, *Response) { + r, appErr := c.DoApiGet(c.GetSystemRoute()+"/support_packet", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_job_result_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) +} + // GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above. func (c *Client4) GetPing() (string, *Response) { r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", "") @@ -3448,7 +3574,7 @@ func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) { } rq.Header.Set("Content-Type", writer.FormDataContentType()) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -3815,6 +3941,28 @@ func (c *Client4) GetSamlMetadataFromIdp(samlMetadataURL string) (*SamlMetadataR return SamlMetadataResponseFromJson(r.Body), BuildResponse(r) } +// ResetSamlAuthDataToEmail resets the AuthData field of SAML users to their Email. +func (c *Client4) ResetSamlAuthDataToEmail(includeDeleted bool, dryRun bool, userIDs []string) (int64, *Response) { + params := map[string]interface{}{ + "include_deleted": includeDeleted, + "dry_run": dryRun, + "user_ids": userIDs, + } + b, _ := json.Marshal(params) + r, err := c.doApiPostBytes(c.GetSamlRoute()+"/reset_auth_data", b) + if err != nil { + return 0, BuildErrorResponse(r, err) + } + defer closeBody(r) + respBody := map[string]int64{} + jsonErr := json.NewDecoder(r.Body).Decode(&respBody) + if jsonErr != nil { + appErr := NewAppError("Api4.ResetSamlAuthDataToEmail", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError) + return 0, BuildErrorResponse(r, appErr) + } + return respBody["num_affected"], BuildResponse(r) +} + // Compliance Section // CreateComplianceReport creates an incoming webhook for a channel. @@ -3850,12 +3998,12 @@ func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) // DownloadComplianceReport returns a full compliance report as a file. func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) { - rq, err := http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil) + rq, err := http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportDownloadRoute(reportId), nil) if err != nil { return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} } - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken) } @@ -3892,8 +4040,13 @@ func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) { // LDAP Section // SyncLdap will force a sync with the configured LDAP server. -func (c *Client4) SyncLdap() (bool, *Response) { - r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", "") +// If includeRemovedMembers is true, then group members who left or were removed from a +// synced team/channel will be re-joined; otherwise, they will be excluded. +func (c *Client4) SyncLdap(includeRemovedMembers bool) (bool, *Response) { + reqBody, _ := json.Marshal(map[string]interface{}{ + "include_removed_members": includeRemovedMembers, + }) + r, err := c.doApiPostBytes(c.GetLdapRoute()+"/sync", reqBody) if err != nil { return false, BuildErrorResponse(r, err) } @@ -4225,7 +4378,7 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { } rq.Header.Set("Content-Type", writer.FormDataContentType()) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -4380,7 +4533,7 @@ func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Respon } rq.Header.Set("Content-Type", "application/x-www-form-urlencoded") - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -4434,14 +4587,236 @@ func (c *Client4) PurgeBleveIndexes() (bool, *Response) { // Data Retention Section -// GetDataRetentionPolicy will get the current server data retention policy details. -func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) { +// GetDataRetentionPolicy will get the current global data retention policy details. +func (c *Client4) GetDataRetentionPolicy() (*GlobalRetentionPolicy, *Response) { r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", "") if err != nil { return nil, BuildErrorResponse(r, err) } defer closeBody(r) - return DataRetentionPolicyFromJson(r.Body), BuildResponse(r) + return GlobalRetentionPolicyFromJson(r.Body), BuildResponse(r) +} + +// GetDataRetentionPolicyByID will get the details for the granular data retention policy with the specified ID. +func (c *Client4) GetDataRetentionPolicyByID(policyID string) (*RetentionPolicyWithTeamAndChannelCounts, *Response) { + r, appErr := c.DoApiGet(c.GetDataRetentionPolicyRoute(policyID), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + policy, err := RetentionPolicyWithTeamAndChannelCountsFromJson(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.GetDataRetentionPolicyByID", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) + } + return policy, BuildResponse(r) +} + +// GetDataRetentionPoliciesCount will get the total number of granular data retention policies. +func (c *Client4) GetDataRetentionPoliciesCount() (int64, *Response) { + type CountBody struct { + TotalCount int64 `json:"total_count"` + } + r, appErr := c.DoApiGet(c.GetDataRetentionRoute()+"/policies_count", "") + if appErr != nil { + return 0, BuildErrorResponse(r, appErr) + } + var countObj CountBody + jsonErr := json.NewDecoder(r.Body).Decode(&countObj) + if jsonErr != nil { + return 0, BuildErrorResponse(r, NewAppError("Client4.GetDataRetentionPoliciesCount", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) + } + return countObj.TotalCount, BuildResponse(r) +} + +// GetDataRetentionPolicies will get the current granular data retention policies' details. +func (c *Client4) GetDataRetentionPolicies(page, perPage int) (*RetentionPolicyWithTeamAndChannelCountsList, *Response) { + query := fmt.Sprintf("?page=%d&per_page=%d", page, perPage) + r, appErr := c.DoApiGet(c.GetDataRetentionRoute()+"/policies"+query, "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + policies, err := RetentionPolicyWithTeamAndChannelCountsListFromJson(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.GetDataRetentionPolicies", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) + } + return policies, BuildResponse(r) +} + +// CreateDataRetentionPolicy will create a new granular data retention policy which will be applied to +// the specified teams and channels. The Id field of `policy` must be empty. +func (c *Client4) CreateDataRetentionPolicy(policy *RetentionPolicyWithTeamAndChannelIDs) (*RetentionPolicyWithTeamAndChannelCounts, *Response) { + r, appErr := c.doApiPostBytes(c.GetDataRetentionRoute()+"/policies", policy.ToJson()) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + newPolicy, err := RetentionPolicyWithTeamAndChannelCountsFromJson(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.CreateDataRetentionPolicy", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) + } + return newPolicy, BuildResponse(r) +} + +// DeleteDataRetentionPolicy will delete the granular data retention policy with the specified ID. +func (c *Client4) DeleteDataRetentionPolicy(policyID string) *Response { + r, appErr := c.DoApiDelete(c.GetDataRetentionPolicyRoute(policyID)) + if appErr != nil { + return BuildErrorResponse(r, appErr) + } + defer closeBody(r) + return BuildResponse(r) +} + +// PatchDataRetentionPolicy will patch the granular data retention policy with the specified ID. +// The Id field of `patch` must be non-empty. +func (c *Client4) PatchDataRetentionPolicy(patch *RetentionPolicyWithTeamAndChannelIDs) (*RetentionPolicyWithTeamAndChannelCounts, *Response) { + r, appErr := c.doApiPatchBytes(c.GetDataRetentionPolicyRoute(patch.ID), patch.ToJson()) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + policy, err := RetentionPolicyWithTeamAndChannelCountsFromJson(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.PatchDataRetentionPolicy", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) + } + return policy, BuildResponse(r) +} + +// GetTeamsForRetentionPolicy will get the teams to which the specified policy is currently applied. +func (c *Client4) GetTeamsForRetentionPolicy(policyID string, page, perPage int) (*TeamsWithCount, *Response) { + query := fmt.Sprintf("?page=%d&per_page=%d", page, perPage) + r, appErr := c.DoApiGet(c.GetDataRetentionPolicyRoute(policyID)+"/teams"+query, "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + var teams *TeamsWithCount + jsonErr := json.NewDecoder(r.Body).Decode(&teams) + if jsonErr != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.GetTeamsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) + } + return teams, BuildResponse(r) +} + +// SearchTeamsForRetentionPolicy will search the teams to which the specified policy is currently applied. +func (c *Client4) SearchTeamsForRetentionPolicy(policyID string, term string) ([]*Team, *Response) { + body, _ := json.Marshal(map[string]interface{}{"term": term}) + r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/teams/search", body) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + var teams []*Team + jsonErr := json.NewDecoder(r.Body).Decode(&teams) + if jsonErr != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.SearchTeamsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) + } + return teams, BuildResponse(r) +} + +// AddTeamsToRetentionPolicy will add the specified teams to the granular data retention policy +// with the specified ID. +func (c *Client4) AddTeamsToRetentionPolicy(policyID string, teamIDs []string) *Response { + body, _ := json.Marshal(teamIDs) + r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/teams", body) + if appErr != nil { + return BuildErrorResponse(r, appErr) + } + defer closeBody(r) + return BuildResponse(r) +} + +// RemoveTeamsFromRetentionPolicy will remove the specified teams from the granular data retention policy +// with the specified ID. +func (c *Client4) RemoveTeamsFromRetentionPolicy(policyID string, teamIDs []string) *Response { + body, _ := json.Marshal(teamIDs) + r, appErr := c.doApiDeleteBytes(c.GetDataRetentionPolicyRoute(policyID)+"/teams", body) + if appErr != nil { + return BuildErrorResponse(r, appErr) + } + defer closeBody(r) + return BuildResponse(r) +} + +// GetChannelsForRetentionPolicy will get the channels to which the specified policy is currently applied. +func (c *Client4) GetChannelsForRetentionPolicy(policyID string, page, perPage int) (*ChannelsWithCount, *Response) { + query := fmt.Sprintf("?page=%d&per_page=%d", page, perPage) + r, appErr := c.DoApiGet(c.GetDataRetentionPolicyRoute(policyID)+"/channels"+query, "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + var channels *ChannelsWithCount + jsonErr := json.NewDecoder(r.Body).Decode(&channels) + if jsonErr != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.GetChannelsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) + } + return channels, BuildResponse(r) +} + +// SearchChannelsForRetentionPolicy will search the channels to which the specified policy is currently applied. +func (c *Client4) SearchChannelsForRetentionPolicy(policyID string, term string) (ChannelListWithTeamData, *Response) { + body, _ := json.Marshal(map[string]interface{}{"term": term}) + r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/channels/search", body) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + var channels ChannelListWithTeamData + jsonErr := json.NewDecoder(r.Body).Decode(&channels) + if jsonErr != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.SearchChannelsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) + } + return channels, BuildResponse(r) +} + +// AddChannelsToRetentionPolicy will add the specified channels to the granular data retention policy +// with the specified ID. +func (c *Client4) AddChannelsToRetentionPolicy(policyID string, channelIDs []string) *Response { + body, _ := json.Marshal(channelIDs) + r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/channels", body) + if appErr != nil { + return BuildErrorResponse(r, appErr) + } + defer closeBody(r) + return BuildResponse(r) +} + +// RemoveChannelsFromRetentionPolicy will remove the specified channels from the granular data retention policy +// with the specified ID. +func (c *Client4) RemoveChannelsFromRetentionPolicy(policyID string, channelIDs []string) *Response { + body, _ := json.Marshal(channelIDs) + r, appErr := c.doApiDeleteBytes(c.GetDataRetentionPolicyRoute(policyID)+"/channels", body) + if appErr != nil { + return BuildErrorResponse(r, appErr) + } + defer closeBody(r) + return BuildResponse(r) +} + +// GetTeamPoliciesForUser will get the data retention policies for the teams to which a user belongs. +func (c *Client4) GetTeamPoliciesForUser(userID string, offset, limit int) (*RetentionPolicyForTeamList, *Response) { + r, appErr := c.DoApiGet(c.GetUserRoute(userID)+"/data_retention/team_policies", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + var teams RetentionPolicyForTeamList + jsonErr := json.NewDecoder(r.Body).Decode(&teams) + if jsonErr != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.GetTeamPoliciesForUser", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) + } + return &teams, BuildResponse(r) +} + +// GetChannelPoliciesForUser will get the data retention policies for the channels to which a user belongs. +func (c *Client4) GetChannelPoliciesForUser(userID string, offset, limit int) (*RetentionPolicyForChannelList, *Response) { + r, appErr := c.DoApiGet(c.GetUserRoute(userID)+"/data_retention/channel_policies", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + var channels RetentionPolicyForChannelList + jsonErr := json.NewDecoder(r.Body).Decode(&channels) + if jsonErr != nil { + return nil, BuildErrorResponse(r, NewAppError("Client4.GetChannelPoliciesForUser", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) + } + return &channels, BuildResponse(r) } // Commands Section @@ -5019,7 +5394,7 @@ func (c *Client4) uploadPlugin(file io.Reader, force bool) (*Manifest, *Response } rq.Header.Set("Content-Type", writer.FormDataContentType()) - if len(c.AuthToken) > 0 { + if c.AuthToken != "" { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } @@ -5436,7 +5811,7 @@ func (c *Client4) GetChannelMemberCountsByGroup(channelID string, includeTimezon // RequestTrialLicense will request a trial license and install it in the server func (c *Client4) RequestTrialLicense(users int) (bool, *Response) { - b, _ := json.Marshal(map[string]int{"users": users}) + b, _ := json.Marshal(map[string]interface{}{"users": users, "terms_accepted": true}) r, err := c.DoApiPost("/trial-license", string(b)) if err != nil { return false, BuildErrorResponse(r, err) @@ -5626,7 +6001,7 @@ func (c *Client4) GetUploadsForUser(userId string) ([]*UploadSession, *Response) // a FileInfo object. func (c *Client4) UploadData(uploadId string, data io.Reader) (*FileInfo, *Response) { url := c.GetUploadRoute(uploadId) - r, err := c.doApiRequestReader("POST", c.ApiUrl+url, data, "") + r, err := c.doApiRequestReader("POST", c.ApiUrl+url, data, nil) if err != nil { return nil, BuildErrorResponse(r, err) } @@ -5710,6 +6085,18 @@ func (c *Client4) GetSubscription() (*Subscription, *Response) { return subscription, BuildResponse(r) } +func (c *Client4) GetSubscriptionStats() (*SubscriptionStats, *Response) { + r, appErr := c.DoApiGet(c.GetCloudRoute()+"/subscription/stats", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + var stats *SubscriptionStats + json.NewDecoder(r.Body).Decode(&stats) + return stats, BuildResponse(r) +} + func (c *Client4) GetInvoicesForSubscription() ([]*Invoice, *Response) { r, appErr := c.DoApiGet(c.GetCloudRoute()+"/subscription/invoices", "") if appErr != nil { @@ -5753,13 +6140,62 @@ func (c *Client4) UpdateCloudCustomerAddress(address *Address) (*CloudCustomer, return customer, BuildResponse(r) } -func (c *Client4) GetUserThreads(userId string, options GetUserThreadsOpts) (*Threads, *Response) { +func (c *Client4) ListImports() ([]string, *Response) { + r, err := c.DoApiGet(c.GetImportsRoute(), "") + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + return ArrayFromJson(r.Body), BuildResponse(r) +} + +func (c *Client4) ListExports() ([]string, *Response) { + r, err := c.DoApiGet(c.GetExportsRoute(), "") + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + return ArrayFromJson(r.Body), BuildResponse(r) +} + +func (c *Client4) DeleteExport(name string) (bool, *Response) { + r, err := c.DoApiDelete(c.GetExportRoute(name)) + if err != nil { + return false, BuildErrorResponse(r, err) + } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) +} + +func (c *Client4) DownloadExport(name string, wr io.Writer, offset int64) (int64, *Response) { + var headers map[string]string + if offset > 0 { + headers = map[string]string{ + HEADER_RANGE: fmt.Sprintf("bytes=%d-", offset), + } + } + r, appErr := c.DoApiRequestWithHeaders(http.MethodGet, c.ApiUrl+c.GetExportRoute(name), "", headers) + if appErr != nil { + return 0, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + n, err := io.Copy(wr, r.Body) + if err != nil { + return n, BuildErrorResponse(r, NewAppError("DownloadExport", "model.client.copy.app_error", nil, err.Error(), r.StatusCode)) + } + return n, BuildResponse(r) +} + +func (c *Client4) GetUserThreads(userId, teamId string, options GetUserThreadsOpts) (*Threads, *Response) { v := url.Values{} if options.Since != 0 { v.Set("since", fmt.Sprintf("%d", options.Since)) } - if options.Page != 0 { - v.Set("page", fmt.Sprintf("%d", options.Page)) + if options.Before != "" { + v.Set("before", options.Before) + } + if options.After != "" { + v.Set("after", options.After) } if options.PageSize != 0 { v.Set("pageSize", fmt.Sprintf("%d", options.PageSize)) @@ -5770,8 +6206,10 @@ func (c *Client4) GetUserThreads(userId string, options GetUserThreadsOpts) (*Th if options.Deleted { v.Set("deleted", "true") } - - url := c.GetUserThreadsRoute(userId) + if options.Unread { + v.Set("unread", "true") + } + url := c.GetUserThreadsRoute(userId, teamId) if len(v) > 0 { url += "?" + v.Encode() } @@ -5788,18 +6226,25 @@ func (c *Client4) GetUserThreads(userId string, options GetUserThreadsOpts) (*Th return &threads, BuildResponse(r) } -func (c *Client4) UpdateThreadsReadForUser(userId string, timestamp int64) *Response { - r, appErr := c.DoApiPut(fmt.Sprintf("%s/read/%d", c.GetUserThreadsRoute(userId), timestamp), "") +func (c *Client4) GetUserThread(userId, teamId, threadId string, extended bool) (*ThreadResponse, *Response) { + url := c.GetUserThreadRoute(userId, teamId, threadId) + if extended { + url += "?extended=true" + } + r, appErr := c.DoApiGet(url, "") if appErr != nil { - return BuildErrorResponse(r, appErr) + return nil, BuildErrorResponse(r, appErr) } defer closeBody(r) - return BuildResponse(r) + var thread ThreadResponse + json.NewDecoder(r.Body).Decode(&thread) + + return &thread, BuildResponse(r) } -func (c *Client4) UpdateThreadReadForUser(userId, threadId string, timestamp int64) *Response { - r, appErr := c.DoApiPut(fmt.Sprintf("%s/read/%d", c.GetUserThreadRoute(userId, threadId), timestamp), "") +func (c *Client4) UpdateThreadsReadForUser(userId, teamId string) *Response { + r, appErr := c.DoApiPut(fmt.Sprintf("%s/read", c.GetUserThreadsRoute(userId, teamId)), "") if appErr != nil { return BuildErrorResponse(r, appErr) } @@ -5808,14 +6253,46 @@ func (c *Client4) UpdateThreadReadForUser(userId, threadId string, timestamp int return BuildResponse(r) } -func (c *Client4) UpdateThreadFollowForUser(userId, threadId string, state bool) *Response { +func (c *Client4) UpdateThreadReadForUser(userId, teamId, threadId string, timestamp int64) (*ThreadResponse, *Response) { + r, appErr := c.DoApiPut(fmt.Sprintf("%s/read/%d", c.GetUserThreadRoute(userId, teamId, threadId), timestamp), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + var thread ThreadResponse + json.NewDecoder(r.Body).Decode(&thread) + + return &thread, BuildResponse(r) +} + +func (c *Client4) UpdateThreadFollowForUser(userId, teamId, threadId string, state bool) *Response { var appErr *AppError var r *http.Response if state { - r, appErr = c.DoApiPut(c.GetUserThreadRoute(userId, threadId)+"/following", "") + r, appErr = c.DoApiPut(c.GetUserThreadRoute(userId, teamId, threadId)+"/following", "") } else { - r, appErr = c.DoApiDelete(c.GetUserThreadRoute(userId, threadId) + "/following") + r, appErr = c.DoApiDelete(c.GetUserThreadRoute(userId, teamId, threadId) + "/following") + } + if appErr != nil { + return BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + return BuildResponse(r) +} + +func (c *Client4) SendAdminUpgradeRequestEmail() *Response { + r, appErr := c.DoApiPost(c.GetCloudRoute()+"/subscription/limitreached/invite", "") + if appErr != nil { + return BuildErrorResponse(r, appErr) } + defer closeBody(r) + + return BuildResponse(r) +} + +func (c *Client4) SendAdminUpgradeRequestEmailOnJoin() *Response { + r, appErr := c.DoApiPost(c.GetCloudRoute()+"/subscription/limitreached/join", "") if appErr != nil { return BuildErrorResponse(r, appErr) } @@ -5823,3 +6300,44 @@ func (c *Client4) UpdateThreadFollowForUser(userId, threadId string, state bool) return BuildResponse(r) } + +func (c *Client4) GetAllSharedChannels(teamID string, page, perPage int) ([]*SharedChannel, *Response) { + url := fmt.Sprintf("%s/%s?page=%d&per_page=%d", c.GetSharedChannelsRoute(), teamID, page, perPage) + r, appErr := c.DoApiGet(url, "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + var channels []*SharedChannel + json.NewDecoder(r.Body).Decode(&channels) + + return channels, BuildResponse(r) +} + +func (c *Client4) GetRemoteClusterInfo(remoteID string) (RemoteClusterInfo, *Response) { + url := fmt.Sprintf("%s/remote_info/%s", c.GetSharedChannelsRoute(), remoteID) + r, appErr := c.DoApiGet(url, "") + if appErr != nil { + return RemoteClusterInfo{}, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + var rci RemoteClusterInfo + json.NewDecoder(r.Body).Decode(&rci) + + return rci, BuildResponse(r) +} + +func (c *Client4) GetAncillaryPermissions(subsectionPermissions []string) ([]string, *Response) { + var returnedPermissions []string + url := fmt.Sprintf("%s/ancillary?subsection_permissions=%s", c.GetPermissionsRoute(), strings.Join(subsectionPermissions, ",")) + r, appErr := c.DoApiGet(url, "") + if appErr != nil { + return returnedPermissions, BuildErrorResponse(r, appErr) + } + defer closeBody(r) + + json.NewDecoder(r.Body).Decode(&returnedPermissions) + return returnedPermissions, BuildResponse(r) +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cloud.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cloud.go index e4fddbcd..ffd85a2a 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cloud.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cloud.go @@ -3,13 +3,53 @@ package model +import "strings" + +const ( + EventTypeFailedPayment = "failed-payment" + EventTypeFailedPaymentNoCard = "failed-payment-no-card" + EventTypeSendAdminWelcomeEmail = "send-admin-welcome-email" + EventTypeTrialWillEnd = "trial-will-end" + EventTypeTrialEnded = "trial-ended" + JoinLimitation = "join" + InviteLimitation = "invite" +) + +var MockCWS string + +type BillingScheme string + +const ( + BillingSchemePerSeat = BillingScheme("per_seat") + BillingSchemeFlatFee = BillingScheme("flat_fee") +) + +type RecurringInterval string + +const ( + RecurringIntervalYearly = RecurringInterval("year") + RecurringIntervalMonthly = RecurringInterval("month") +) + +type SubscriptionFamily string + +const ( + SubscriptionFamilyCloud = SubscriptionFamily("cloud") + SubscriptionFamilyOnPrem = SubscriptionFamily("on-prem") +) + // Product model represents a product on the cloud system. type Product struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - PricePerSeat float64 `json:"price_per_seat"` - AddOns []*AddOn `json:"add_ons"` + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + PricePerSeat float64 `json:"price_per_seat"` + AddOns []*AddOn `json:"add_ons"` + SKU string `json:"sku"` + PriceID string `json:"price_id"` + Family SubscriptionFamily `json:"product_family"` + RecurringInterval RecurringInterval `json:"recurring_interval"` + BillingScheme BillingScheme `json:"billing_scheme"` } // AddOn represents an addon to a product. @@ -85,6 +125,13 @@ type Subscription struct { DNS string `json:"dns"` IsPaidTier string `json:"is_paid_tier"` LastInvoice *Invoice `json:"last_invoice"` + IsFreeTrial string `json:"is_free_trial"` + TrialEndAt int64 `json:"trial_end_at"` +} + +// GetWorkSpaceNameFromDNS returns the work space name. For example from test.mattermost.cloud.com, it returns test +func (s *Subscription) GetWorkSpaceNameFromDNS() string { + return strings.Split(s.DNS, ".")[0] } // Invoice model represents a cloud invoice @@ -112,3 +159,30 @@ type InvoiceLineItem struct { Type string `json:"type"` Metadata map[string]interface{} `json:"metadata"` } + +type CWSWebhookPayload struct { + Event string `json:"event"` + FailedPayment *FailedPayment `json:"failed_payment"` + CloudWorkspaceOwner *CloudWorkspaceOwner `json:"cloud_workspace_owner"` + SubscriptionTrialEndUnixTimeStamp int64 `json:"trial_end_time_stamp"` +} + +type FailedPayment struct { + CardBrand string `json:"card_brand"` + LastFour int `json:"last_four"` + FailureMessage string `json:"failure_message"` +} + +// CloudWorkspaceOwner is part of the CWS Webhook payload that contains information about the user that created the workspace from the CWS +type CloudWorkspaceOwner struct { + UserName string `json:"username"` +} +type SubscriptionStats struct { + RemainingSeats int `json:"remaining_seats"` + IsPaidTier string `json:"is_paid_tier"` + IsFreeTrial string `json:"is_free_trial"` +} + +type SubscriptionChange struct { + ProductID string `json:"product_id"` +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go index f6c9275a..758e4980 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go @@ -39,7 +39,7 @@ func (o *ClusterDiscovery) PreSave() { func (o *ClusterDiscovery) AutoFillHostname() { // attempt to set the hostname from the OS - if len(o.Hostname) == 0 { + if o.Hostname == "" { if hn, err := os.Hostname(); err == nil { o.Hostname = hn } @@ -48,8 +48,8 @@ func (o *ClusterDiscovery) AutoFillHostname() { func (o *ClusterDiscovery) AutoFillIpAddress(iface string, ipAddress string) { // attempt to set the hostname to the first non-local IP address - if len(o.Hostname) == 0 { - if len(ipAddress) > 0 { + if o.Hostname == "" { + if ipAddress != "" { o.Hostname = ipAddress } else { o.Hostname = GetServerIpAddress(iface) @@ -93,15 +93,15 @@ func (o *ClusterDiscovery) IsValid() *AppError { return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.id.app_error", nil, "", http.StatusBadRequest) } - if len(o.ClusterName) == 0 { + if o.ClusterName == "" { return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.name.app_error", nil, "", http.StatusBadRequest) } - if len(o.Type) == 0 { + if o.Type == "" { return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.type.app_error", nil, "", http.StatusBadRequest) } - if len(o.Hostname) == 0 { + if o.Hostname == "" { return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.hostname.app_error", nil, "", http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go index 82437469..fc15d38c 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go @@ -16,15 +16,15 @@ type ClusterInfo struct { Hostname string `json:"hostname"` } -func (me *ClusterInfo) ToJson() string { - b, _ := json.Marshal(me) +func (ci *ClusterInfo) ToJson() string { + b, _ := json.Marshal(ci) return string(b) } func ClusterInfoFromJson(data io.Reader) *ClusterInfo { - var me *ClusterInfo - json.NewDecoder(data).Decode(&me) - return me + var ci *ClusterInfo + json.NewDecoder(data).Decode(&ci) + return ci } func ClusterInfosToJson(objmap []*ClusterInfo) string { @@ -38,7 +38,6 @@ func ClusterInfosFromJson(data io.Reader) []*ClusterInfo { var objmap []*ClusterInfo if err := decoder.Decode(&objmap); err != nil { return make([]*ClusterInfo, 0) - } else { - return objmap } + return objmap } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go index 529f4a93..bd73ba8d 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go @@ -40,6 +40,7 @@ const ( CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_ALL_USERS = "inv_all_user_sessions" CLUSTER_EVENT_INSTALL_PLUGIN = "install_plugin" CLUSTER_EVENT_REMOVE_PLUGIN = "remove_plugin" + CLUSTER_EVENT_PLUGIN_EVENT = "plugin_event" CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TERMS_OF_SERVICE = "inv_terms_of_service" CLUSTER_EVENT_BUSY_STATE_CHANGED = "busy_state_change" diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go index afc2ab44..9e8c630c 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go @@ -15,13 +15,13 @@ type ClusterStats struct { TotalMasterDbConnections int `json:"total_master_db_connections"` } -func (me *ClusterStats) ToJson() string { - b, _ := json.Marshal(me) +func (cs *ClusterStats) ToJson() string { + b, _ := json.Marshal(cs) return string(b) } func ClusterStatsFromJson(data io.Reader) *ClusterStats { - var me *ClusterStats - json.NewDecoder(data).Decode(&me) - return me + var cs *ClusterStats + json.NewDecoder(data).Decode(&cs) + return cs } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command.go index 0013046b..59a4eee4 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command.go @@ -105,7 +105,7 @@ func (o *Command) IsValid() *AppError { return NewAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "", http.StatusBadRequest) } - if len(o.URL) == 0 || len(o.URL) > 1024 { + if o.URL == "" || len(o.URL) > 1024 { return NewAppError("Command.IsValid", "model.command.is_valid.url.app_error", nil, "", http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go index 15a6372a..45239d2c 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go @@ -7,21 +7,21 @@ import ( "encoding/json" "io" - goi18n "github.com/mattermost/go-i18n/i18n" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) type CommandArgs struct { - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - TeamId string `json:"team_id"` - RootId string `json:"root_id"` - ParentId string `json:"parent_id"` - TriggerId string `json:"trigger_id,omitempty"` - Command string `json:"command"` - SiteURL string `json:"-"` - T goi18n.TranslateFunc `json:"-"` - UserMentions UserMentionMap `json:"-"` - ChannelMentions ChannelMentionMap `json:"-"` + UserId string `json:"user_id"` + ChannelId string `json:"channel_id"` + TeamId string `json:"team_id"` + RootId string `json:"root_id"` + ParentId string `json:"parent_id"` + TriggerId string `json:"trigger_id,omitempty"` + Command string `json:"command"` + SiteURL string `json:"-"` + T i18n.TranslateFunc `json:"-"` + UserMentions UserMentionMap `json:"-"` + ChannelMentions ChannelMentionMap `json:"-"` // DO NOT USE Session field is deprecated. MM-26398 Session Session `json:"-"` diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go index 68d91b23..f115ed24 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go @@ -52,7 +52,7 @@ type AutocompleteArg struct { HelpText string // Type of the argument Type AutocompleteArgType - // Required determins if argument is optional or not. + // Required determines if argument is optional or not. Required bool // Actual data of the argument (depends on the Type) Data interface{} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go index 26b6cceb..80cca5ab 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go @@ -62,7 +62,7 @@ func CommandResponseFromJson(data io.Reader) (*CommandResponse, error) { var o CommandResponse err = json.Unmarshal(b, &o) if err != nil { - return nil, jsonutils.HumanizeJsonError(err, b) + return nil, jsonutils.HumanizeJSONError(err, b) } o.Attachments = StringifySlackFieldValue(o.Attachments) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go index 42a16cc7..3757ecc7 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go @@ -53,11 +53,11 @@ func (o *CommandWebhook) IsValid() *AppError { return NewAppError("CommandWebhook.IsValid", "model.command_hook.channel_id.app_error", nil, "", http.StatusBadRequest) } - if len(o.RootId) != 0 && !IsValidId(o.RootId) { + if o.RootId != "" && !IsValidId(o.RootId) { return NewAppError("CommandWebhook.IsValid", "model.command_hook.root_id.app_error", nil, "", http.StatusBadRequest) } - if len(o.ParentId) != 0 && !IsValidId(o.ParentId) { + if o.ParentId != "" && !IsValidId(o.ParentId) { return NewAppError("CommandWebhook.IsValid", "model.command_hook.parent_id.app_error", nil, "", http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go index a86087c1..0211805e 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go @@ -37,6 +37,19 @@ type Compliance struct { type Compliances []Compliance +// ComplianceExportCursor is used for paginated iteration of posts +// for compliance export. +// We need to keep track of the last post ID in addition to the last post +// CreateAt to break ties when two posts have the same CreateAt. +type ComplianceExportCursor struct { + LastChannelsQueryPostCreateAt int64 + LastChannelsQueryPostID string + ChannelsQueryCompleted bool + LastDirectMessagesQueryPostCreateAt int64 + LastDirectMessagesQueryPostID string + DirectMessagesQueryCompleted bool +} + func (c *Compliance) ToJson() string { b, _ := json.Marshal(c) return string(b) @@ -58,6 +71,11 @@ func (c *Compliance) PreSave() { c.CreateAt = GetMillis() } +func (c *Compliance) DeepCopy() *Compliance { + copy := *c + return © +} + func (c *Compliance) JobName() string { jobName := c.Type if c.Type == COMPLIANCE_TYPE_DAILY { @@ -79,7 +97,7 @@ func (c *Compliance) IsValid() *AppError { return NewAppError("Compliance.IsValid", "model.compliance.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) } - if len(c.Desc) > 512 || len(c.Desc) == 0 { + if len(c.Desc) > 512 || c.Desc == "" { return NewAppError("Compliance.IsValid", "model.compliance.is_valid.desc.app_error", nil, "", http.StatusBadRequest) } @@ -105,11 +123,11 @@ func ComplianceFromJson(data io.Reader) *Compliance { } func (c Compliances) ToJson() string { - if b, err := json.Marshal(c); err != nil { + b, err := json.Marshal(c) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func CompliancesFromJson(data io.Reader) Compliances { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go index fcf65075..5e18812b 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go @@ -53,6 +53,7 @@ func CompliancePostHeader() []string { "UserUsername", "UserEmail", "UserNickname", + "UserType", "PostId", "PostCreateAt", @@ -66,61 +67,58 @@ func CompliancePostHeader() []string { "PostProps", "PostHashtags", "PostFileIds", - "UserType", } } func cleanComplianceStrings(in string) string { if matched, _ := regexp.MatchString("^\\s*(=|\\+|\\-)", in); matched { return "'" + in - - } else { - return in } + return in } -func (me *CompliancePost) Row() []string { +func (cp *CompliancePost) Row() []string { postDeleteAt := "" - if me.PostDeleteAt > 0 { - postDeleteAt = time.Unix(0, me.PostDeleteAt*int64(1000*1000)).Format(time.RFC3339) + if cp.PostDeleteAt > 0 { + postDeleteAt = time.Unix(0, cp.PostDeleteAt*int64(1000*1000)).Format(time.RFC3339) } postUpdateAt := "" - if me.PostUpdateAt != me.PostCreateAt { - postUpdateAt = time.Unix(0, me.PostUpdateAt*int64(1000*1000)).Format(time.RFC3339) + if cp.PostUpdateAt != cp.PostCreateAt { + postUpdateAt = time.Unix(0, cp.PostUpdateAt*int64(1000*1000)).Format(time.RFC3339) } userType := "user" - if me.IsBot { + if cp.IsBot { userType = "bot" } return []string{ - cleanComplianceStrings(me.TeamName), - cleanComplianceStrings(me.TeamDisplayName), + cleanComplianceStrings(cp.TeamName), + cleanComplianceStrings(cp.TeamDisplayName), - cleanComplianceStrings(me.ChannelName), - cleanComplianceStrings(me.ChannelDisplayName), - cleanComplianceStrings(me.ChannelType), + cleanComplianceStrings(cp.ChannelName), + cleanComplianceStrings(cp.ChannelDisplayName), + cleanComplianceStrings(cp.ChannelType), - cleanComplianceStrings(me.UserUsername), - cleanComplianceStrings(me.UserEmail), - cleanComplianceStrings(me.UserNickname), + cleanComplianceStrings(cp.UserUsername), + cleanComplianceStrings(cp.UserEmail), + cleanComplianceStrings(cp.UserNickname), userType, - me.PostId, - time.Unix(0, me.PostCreateAt*int64(1000*1000)).Format(time.RFC3339), + cp.PostId, + time.Unix(0, cp.PostCreateAt*int64(1000*1000)).Format(time.RFC3339), postUpdateAt, postDeleteAt, - me.PostRootId, - me.PostParentId, - me.PostOriginalId, - cleanComplianceStrings(me.PostMessage), - me.PostType, - me.PostProps, - me.PostHashtags, - me.PostFileIds, + cp.PostRootId, + cp.PostParentId, + cp.PostOriginalId, + cleanComplianceStrings(cp.PostMessage), + cp.PostType, + cp.PostProps, + cp.PostHashtags, + cp.PostFileIds, } } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/config.go b/vendor/github.com/mattermost/mattermost-server/v5/model/config.go index cbdf0f55..548a266e 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/config.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/config.go @@ -19,7 +19,9 @@ import ( "time" "github.com/mattermost/ldap" - "github.com/mattermost/mattermost-server/v5/mlog" + + "github.com/mattermost/mattermost-server/v5/shared/filestore" + "github.com/mattermost/mattermost-server/v5/shared/mlog" ) const ( @@ -31,10 +33,11 @@ const ( IMAGE_DRIVER_LOCAL = "local" IMAGE_DRIVER_S3 = "amazons3" - DATABASE_DRIVER_SQLITE = "sqlite3" DATABASE_DRIVER_MYSQL = "mysql" DATABASE_DRIVER_POSTGRES = "postgres" + SEARCHENGINE_ELASTICSEARCH = "elasticsearch" + MINIO_ACCESS_KEY = "minioaccesskey" MINIO_SECRET_KEY = "miniosecretkey" MINIO_BUCKET = "mattermost-test" @@ -45,11 +48,12 @@ const ( SERVICE_GITLAB = "gitlab" SERVICE_GOOGLE = "google" SERVICE_OFFICE365 = "office365" + SERVICE_OPENID = "openid" GENERIC_NO_CHANNEL_NOTIFICATION = "generic_no_channel" GENERIC_NOTIFICATION = "generic" GENERIC_NOTIFICATION_SERVER = "https://push-test.mattermost.com" - MM_SUPPORT_ADDRESS = "support@mattermost.com" + MM_SUPPORT_ADVISOR_ADDRESS = "support-advisor@mattermost.com" FULL_NOTIFICATION = "full" ID_LOADED_NOTIFICATION = "id_loaded" @@ -83,6 +87,10 @@ const ( GROUP_UNREAD_CHANNELS_DEFAULT_ON = "default_on" GROUP_UNREAD_CHANNELS_DEFAULT_OFF = "default_off" + COLLAPSED_THREADS_DISABLED = "disabled" + COLLAPSED_THREADS_DEFAULT_ON = "default_on" + COLLAPSED_THREADS_DEFAULT_OFF = "default_off" + EMAIL_BATCHING_BUFFER_SIZE = 256 EMAIL_BATCHING_INTERVAL = 30 @@ -113,14 +121,20 @@ const ( FILE_SETTINGS_DEFAULT_DIRECTORY = "./data/" + IMPORT_SETTINGS_DEFAULT_DIRECTORY = "./import" + IMPORT_SETTINGS_DEFAULT_RETENTION_DAYS = 30 + + EXPORT_SETTINGS_DEFAULT_DIRECTORY = "./export" + EXPORT_SETTINGS_DEFAULT_RETENTION_DAYS = 30 + EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION = "" - SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://about.mattermost.com/default-terms/" - SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK = "https://about.mattermost.com/default-privacy-policy/" + SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://mattermost.com/terms-of-service/" + SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK = "https://mattermost.com/privacy-policy/" SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK = "https://about.mattermost.com/default-about/" SUPPORT_SETTINGS_DEFAULT_HELP_LINK = "https://about.mattermost.com/default-help/" SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "https://about.mattermost.com/default-report-a-problem/" - SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "feedback@mattermost.com" + SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "" SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD = 365 LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = "" @@ -192,6 +206,7 @@ const ( DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS = 365 DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS = 365 DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME = "02:00" + DATA_RETENTION_SETTINGS_DEFAULT_BATCH_SIZE = 3000 PLUGIN_SETTINGS_DEFAULT_DIRECTORY = "./plugins" PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY = "./client/plugins" @@ -222,11 +237,17 @@ const ( OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT = "https://login.microsoftonline.com/common/oauth2/v2.0/token" OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT = "https://graph.microsoft.com/v1.0/me" - CLOUD_SETTINGS_DEFAULT_CWS_URL = "https://customers.mattermost.com" + CLOUD_SETTINGS_DEFAULT_CWS_URL = "https://customers.mattermost.com" + CLOUD_SETTINGS_DEFAULT_CWS_API_URL = "https://portal.internal.prod.cloud.mattermost.com" + OPENID_SETTINGS_DEFAULT_SCOPE = "profile openid email" LOCAL_MODE_SOCKET_PATH = "/var/tmp/mattermost_local.socket" ) +func GetDefaultAppCustomURLSchemes() []string { + return []string{"mmauth://", "mmauthbeta://"} +} + var ServerTLSSupportedCiphers = map[string]uint16{ "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, @@ -253,105 +274,108 @@ var ServerTLSSupportedCiphers = map[string]uint16{ } type ServiceSettings struct { - SiteURL *string `access:"environment,authentication,write_restrictable"` + SiteURL *string `access:"environment_web_server,authentication_saml,write_restrictable"` WebsocketURL *string `access:"write_restrictable,cloud_restrictable"` - LicenseFileLocation *string `access:"write_restrictable,cloud_restrictable"` - ListenAddress *string `access:"environment,write_restrictable,cloud_restrictable"` - ConnectionSecurity *string `access:"environment,write_restrictable,cloud_restrictable"` - TLSCertFile *string `access:"environment,write_restrictable,cloud_restrictable"` - TLSKeyFile *string `access:"environment,write_restrictable,cloud_restrictable"` - TLSMinVer *string `access:"write_restrictable,cloud_restrictable"` + LicenseFileLocation *string `access:"write_restrictable,cloud_restrictable"` // telemetry: none + ListenAddress *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` // telemetry: none + ConnectionSecurity *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + TLSCertFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + TLSKeyFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + TLSMinVer *string `access:"write_restrictable,cloud_restrictable"` // telemetry: none TLSStrictTransport *bool `access:"write_restrictable,cloud_restrictable"` - TLSStrictTransportMaxAge *int64 `access:"write_restrictable,cloud_restrictable"` - TLSOverwriteCiphers []string `access:"write_restrictable,cloud_restrictable"` - UseLetsEncrypt *bool `access:"environment,write_restrictable,cloud_restrictable"` - LetsEncryptCertificateCacheFile *string `access:"environment,write_restrictable,cloud_restrictable"` - Forward80To443 *bool `access:"environment,write_restrictable,cloud_restrictable"` - TrustedProxyIPHeader []string `access:"write_restrictable,cloud_restrictable"` - ReadTimeout *int `access:"environment,write_restrictable,cloud_restrictable"` - WriteTimeout *int `access:"environment,write_restrictable,cloud_restrictable"` + TLSStrictTransportMaxAge *int64 `access:"write_restrictable,cloud_restrictable"` // telemetry: none + TLSOverwriteCiphers []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none + UseLetsEncrypt *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` + LetsEncryptCertificateCacheFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` // telemetry: none + Forward80To443 *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` + TrustedProxyIPHeader []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none + ReadTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` + WriteTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` IdleTimeout *int `access:"write_restrictable,cloud_restrictable"` - MaximumLoginAttempts *int `access:"authentication,write_restrictable,cloud_restrictable"` - GoroutineHealthThreshold *int `access:"write_restrictable,cloud_restrictable"` - GoogleDeveloperKey *string `access:"site,write_restrictable,cloud_restrictable"` - EnableOAuthServiceProvider *bool `access:"integrations"` - EnableIncomingWebhooks *bool `access:"integrations"` - EnableOutgoingWebhooks *bool `access:"integrations"` - EnableCommands *bool `access:"integrations"` - DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations" mapstructure:"EnableOnlyAdminIntegrations"` // This field is deprecated and must not be used. - EnablePostUsernameOverride *bool `access:"integrations"` - EnablePostIconOverride *bool `access:"integrations"` - EnableLinkPreviews *bool `access:"site"` - EnableTesting *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableDeveloper *bool `access:"environment,write_restrictable,cloud_restrictable"` + MaximumLoginAttempts *int `access:"authentication_password,write_restrictable,cloud_restrictable"` + GoroutineHealthThreshold *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none + EnableOAuthServiceProvider *bool `access:"integrations_integration_management"` + EnableIncomingWebhooks *bool `access:"integrations_integration_management"` + EnableOutgoingWebhooks *bool `access:"integrations_integration_management"` + EnableCommands *bool `access:"integrations_integration_management"` + EnablePostUsernameOverride *bool `access:"integrations_integration_management"` + EnablePostIconOverride *bool `access:"integrations_integration_management"` + GoogleDeveloperKey *string `access:"site_posts,write_restrictable,cloud_restrictable"` + DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations" mapstructure:"EnableOnlyAdminIntegrations"` // Deprecated: do not use + EnableLinkPreviews *bool `access:"site_posts"` + RestrictLinkPreviews *string `access:"site_posts"` + EnableTesting *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` + EnableDeveloper *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` EnableOpenTracing *bool `access:"write_restrictable,cloud_restrictable"` - EnableSecurityFixAlert *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableInsecureOutgoingConnections *bool `access:"environment,write_restrictable,cloud_restrictable"` - AllowedUntrustedInternalConnections *string `access:"environment,write_restrictable,cloud_restrictable"` - EnableMultifactorAuthentication *bool `access:"authentication"` - EnforceMultifactorAuthentication *bool `access:"authentication"` - EnableUserAccessTokens *bool `access:"integrations"` - AllowCorsFrom *string `access:"integrations,write_restrictable,cloud_restrictable"` - CorsExposedHeaders *string `access:"integrations,write_restrictable,cloud_restrictable"` - CorsAllowCredentials *bool `access:"integrations,write_restrictable,cloud_restrictable"` - CorsDebug *bool `access:"integrations,write_restrictable,cloud_restrictable"` + EnableSecurityFixAlert *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` + EnableInsecureOutgoingConnections *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` + AllowedUntrustedInternalConnections *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + EnableMultifactorAuthentication *bool `access:"authentication_mfa"` + EnforceMultifactorAuthentication *bool `access:"authentication_mfa"` + EnableUserAccessTokens *bool `access:"integrations_integration_management"` + AllowCorsFrom *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` + CorsExposedHeaders *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` + CorsAllowCredentials *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` + CorsDebug *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` AllowCookiesForSubdomains *bool `access:"write_restrictable,cloud_restrictable"` - ExtendSessionLengthWithActivity *bool `access:"environment,write_restrictable,cloud_restrictable"` - SessionLengthWebInDays *int `access:"environment,write_restrictable,cloud_restrictable"` - SessionLengthMobileInDays *int `access:"environment,write_restrictable,cloud_restrictable"` - SessionLengthSSOInDays *int `access:"environment,write_restrictable,cloud_restrictable"` - SessionCacheInMinutes *int `access:"environment,write_restrictable,cloud_restrictable"` - SessionIdleTimeoutInMinutes *int `access:"environment,write_restrictable,cloud_restrictable"` - WebsocketSecurePort *int `access:"write_restrictable,cloud_restrictable"` - WebsocketPort *int `access:"write_restrictable,cloud_restrictable"` - WebserverMode *string `access:"environment,write_restrictable,cloud_restrictable"` - EnableCustomEmoji *bool `access:"site"` - EnableEmojiPicker *bool `access:"site"` - EnableGifPicker *bool `access:"integrations"` - GfycatApiKey *string `access:"integrations"` - GfycatApiSecret *string `access:"integrations"` - DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation *string `json:"RestrictCustomEmojiCreation" mapstructure:"RestrictCustomEmojiCreation"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPostDelete *string `json:"RestrictPostDelete" mapstructure:"RestrictPostDelete"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_AllowEditPost *string `json:"AllowEditPost" mapstructure:"AllowEditPost"` // This field is deprecated and must not be used. + ExtendSessionLengthWithActivity *bool `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + SessionLengthWebInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + SessionLengthMobileInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + SessionLengthSSOInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + SessionCacheInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + SessionIdleTimeoutInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + WebsocketSecurePort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none + WebsocketPort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none + WebserverMode *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + EnableGifPicker *bool `access:"integrations_gif"` + GfycatApiKey *string `access:"integrations_gif"` + GfycatApiSecret *string `access:"integrations_gif"` + EnableCustomEmoji *bool `access:"site_emoji"` + EnableEmojiPicker *bool `access:"site_emoji"` + DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation *string `json:"RestrictCustomEmojiCreation" mapstructure:"RestrictCustomEmojiCreation"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPostDelete *string `json:"RestrictPostDelete" mapstructure:"RestrictPostDelete"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_AllowEditPost *string `json:"AllowEditPost" mapstructure:"AllowEditPost"` // Deprecated: do not use PostEditTimeLimit *int `access:"user_management_permissions"` - TimeBetweenUserTypingUpdatesMilliseconds *int64 `access:"experimental,write_restrictable,cloud_restrictable"` + TimeBetweenUserTypingUpdatesMilliseconds *int64 `access:"experimental_features,write_restrictable,cloud_restrictable"` EnablePostSearch *bool `access:"write_restrictable,cloud_restrictable"` - MinimumHashtagLength *int `access:"environment,write_restrictable,cloud_restrictable"` - EnableUserTypingMessages *bool `access:"experimental,write_restrictable,cloud_restrictable"` - EnableChannelViewedMessages *bool `access:"experimental,write_restrictable,cloud_restrictable"` + EnableFileSearch *bool `access:"write_restrictable"` + MinimumHashtagLength *int `access:"environment_database,write_restrictable,cloud_restrictable"` + EnableUserTypingMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + EnableChannelViewedMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` EnableUserStatuses *bool `access:"write_restrictable,cloud_restrictable"` - ExperimentalEnableAuthenticationTransfer *bool `access:"experimental,write_restrictable,cloud_restrictable"` + ExperimentalEnableAuthenticationTransfer *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` ClusterLogTimeoutMilliseconds *int `access:"write_restrictable,cloud_restrictable"` - CloseUnusedDirectMessages *bool `access:"experimental"` - EnablePreviewFeatures *bool `access:"experimental"` - EnableTutorial *bool `access:"experimental"` - ExperimentalEnableDefaultChannelLeaveJoinMessages *bool `access:"experimental"` - ExperimentalGroupUnreadChannels *string `access:"experimental"` - ExperimentalChannelOrganization *bool `access:"experimental"` - ExperimentalChannelSidebarOrganization *string `access:"experimental"` - ExperimentalDataPrefetch *bool `access:"experimental"` - DEPRECATED_DO_NOT_USE_ImageProxyType *string `json:"ImageProxyType" mapstructure:"ImageProxyType"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_ImageProxyURL *string `json:"ImageProxyURL" mapstructure:"ImageProxyURL"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_ImageProxyOptions *string `json:"ImageProxyOptions" mapstructure:"ImageProxyOptions"` // This field is deprecated and must not be used. + CloseUnusedDirectMessages *bool `access:"experimental_features"` + EnablePreviewFeatures *bool `access:"experimental_features"` + EnableTutorial *bool `access:"experimental_features"` + ExperimentalEnableDefaultChannelLeaveJoinMessages *bool `access:"experimental_features"` + ExperimentalGroupUnreadChannels *string `access:"experimental_features"` + ExperimentalChannelOrganization *bool `access:"experimental_features"` + DEPRECATED_DO_NOT_USE_ImageProxyType *string `json:"ImageProxyType" mapstructure:"ImageProxyType"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_ImageProxyURL *string `json:"ImageProxyURL" mapstructure:"ImageProxyURL"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_ImageProxyOptions *string `json:"ImageProxyOptions" mapstructure:"ImageProxyOptions"` // Deprecated: do not use EnableAPITeamDeletion *bool EnableAPIUserDeletion *bool - ExperimentalEnableHardenedMode *bool `access:"experimental"` + ExperimentalEnableHardenedMode *bool `access:"experimental_features"` DisableLegacyMFA *bool `access:"write_restrictable,cloud_restrictable"` - ExperimentalStrictCSRFEnforcement *bool `access:"experimental,write_restrictable,cloud_restrictable"` - EnableEmailInvitations *bool `access:"authentication"` - DisableBotsWhenOwnerIsDeactivated *bool `access:"integrations,write_restrictable,cloud_restrictable"` - EnableBotAccountCreation *bool `access:"integrations"` - EnableSVGs *bool `access:"site"` - EnableLatex *bool `access:"site"` + ExperimentalStrictCSRFEnforcement *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + EnableEmailInvitations *bool `access:"authentication_signup"` + DisableBotsWhenOwnerIsDeactivated *bool `access:"integrations_bot_accounts,write_restrictable,cloud_restrictable"` + EnableBotAccountCreation *bool `access:"integrations_bot_accounts"` + EnableSVGs *bool `access:"site_posts"` + EnableLatex *bool `access:"site_posts"` EnableAPIChannelDeletion *bool EnableLocalMode *bool - LocalModeSocketLocation *string - EnableAWSMetering *bool - SplitKey *string `access:"environment,write_restrictable"` - FeatureFlagSyncIntervalSeconds *int `access:"environment,write_restrictable"` - DebugSplit *bool `access:"environment,write_restrictable"` - ThreadAutoFollow *bool `access:"experimental"` - ManagedResourcePaths *string `access:"environment,write_restrictable,cloud_restrictable"` + LocalModeSocketLocation *string // telemetry: none + EnableAWSMetering *bool // telemetry: none + SplitKey *string `access:"experimental_feature_flags,write_restrictable"` // telemetry: none + FeatureFlagSyncIntervalSeconds *int `access:"experimental_feature_flags,write_restrictable"` // telemetry: none + DebugSplit *bool `access:"experimental_feature_flags,write_restrictable"` // telemetry: none + ThreadAutoFollow *bool `access:"experimental_features"` + CollapsedThreads *string `access:"experimental_features"` + ManagedResourcePaths *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + EnableLegacySidebar *bool `access:"experimental_features"` + EnableReliableWebSockets *bool `access:"experimental_features"` // telemetry: none } func (s *ServiceSettings) SetDefaults(isUpdate bool) { @@ -388,6 +412,10 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) { s.EnableLinkPreviews = NewBool(true) } + if s.RestrictLinkPreviews == nil { + s.RestrictLinkPreviews = NewString("") + } + if s.EnableTesting == nil { s.EnableTesting = NewBool(false) } @@ -518,6 +546,10 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) { s.EnablePostSearch = NewBool(true) } + if s.EnableFileSearch == nil { + s.EnableFileSearch = NewBool(true) + } + if s.MinimumHashtagLength == nil { s.MinimumHashtagLength = NewInt(3) } @@ -690,14 +722,6 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) { s.ExperimentalChannelOrganization = NewBool(experimentalUnreadEnabled) } - if s.ExperimentalChannelSidebarOrganization == nil { - s.ExperimentalChannelSidebarOrganization = NewString("disabled") - } - - if s.ExperimentalDataPrefetch == nil { - s.ExperimentalDataPrefetch = NewBool(true) - } - if s.DEPRECATED_DO_NOT_USE_ImageProxyType == nil { s.DEPRECATED_DO_NOT_USE_ImageProxyType = NewString("") } @@ -786,27 +810,40 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) { s.ThreadAutoFollow = NewBool(true) } + if s.CollapsedThreads == nil { + s.CollapsedThreads = NewString(COLLAPSED_THREADS_DISABLED) + } + if s.ManagedResourcePaths == nil { s.ManagedResourcePaths = NewString("") } + + if s.EnableLegacySidebar == nil { + s.EnableLegacySidebar = NewBool(false) + } + + if s.EnableReliableWebSockets == nil { + s.EnableReliableWebSockets = NewBool(true) + } } type ClusterSettings struct { - Enable *bool `access:"environment,write_restrictable"` - ClusterName *string `access:"environment,write_restrictable,cloud_restrictable"` - OverrideHostname *string `access:"environment,write_restrictable,cloud_restrictable"` - NetworkInterface *string `access:"environment,write_restrictable,cloud_restrictable"` - BindAddress *string `access:"environment,write_restrictable,cloud_restrictable"` - AdvertiseAddress *string `access:"environment,write_restrictable,cloud_restrictable"` - UseIpAddress *bool `access:"environment,write_restrictable,cloud_restrictable"` - UseExperimentalGossip *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableExperimentalGossipEncryption *bool `access:"environment,write_restrictable,cloud_restrictable"` - ReadOnlyConfig *bool `access:"environment,write_restrictable,cloud_restrictable"` - GossipPort *int `access:"environment,write_restrictable,cloud_restrictable"` - StreamingPort *int `access:"environment,write_restrictable,cloud_restrictable"` - MaxIdleConns *int `access:"environment,write_restrictable,cloud_restrictable"` - MaxIdleConnsPerHost *int `access:"environment,write_restrictable,cloud_restrictable"` - IdleConnTimeoutMilliseconds *int `access:"environment,write_restrictable,cloud_restrictable"` + Enable *bool `access:"environment_high_availability,write_restrictable"` + ClusterName *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none + OverrideHostname *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none + NetworkInterface *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` + BindAddress *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` + AdvertiseAddress *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` + UseIpAddress *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` + DEPRECATED_DO_NOT_USE_UseExperimentalGossip *bool `json:"UseExperimentalGossip" access:"environment_high_availability,write_restrictable,cloud_restrictable"` // Deprecated: do not use + EnableGossipCompression *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` + EnableExperimentalGossipEncryption *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` + ReadOnlyConfig *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` + GossipPort *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none + StreamingPort *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none + MaxIdleConns *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none + MaxIdleConnsPerHost *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none + IdleConnTimeoutMilliseconds *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none } func (s *ClusterSettings) SetDefaults() { @@ -838,14 +875,18 @@ func (s *ClusterSettings) SetDefaults() { s.UseIpAddress = NewBool(true) } - if s.UseExperimentalGossip == nil { - s.UseExperimentalGossip = NewBool(false) + if s.DEPRECATED_DO_NOT_USE_UseExperimentalGossip == nil { + s.DEPRECATED_DO_NOT_USE_UseExperimentalGossip = NewBool(true) } if s.EnableExperimentalGossipEncryption == nil { s.EnableExperimentalGossipEncryption = NewBool(false) } + if s.EnableGossipCompression == nil { + s.EnableGossipCompression = NewBool(true) + } + if s.ReadOnlyConfig == nil { s.ReadOnlyConfig = NewBool(true) } @@ -872,9 +913,9 @@ func (s *ClusterSettings) SetDefaults() { } type MetricsSettings struct { - Enable *bool `access:"environment,write_restrictable,cloud_restrictable"` - BlockProfileRate *int `access:"environment,write_restrictable,cloud_restrictable"` - ListenAddress *string `access:"environment,write_restrictable,cloud_restrictable"` + Enable *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` + BlockProfileRate *int `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` + ListenAddress *string `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` // telemetry: none } func (s *MetricsSettings) SetDefaults() { @@ -892,15 +933,16 @@ func (s *MetricsSettings) SetDefaults() { } type ExperimentalSettings struct { - ClientSideCertEnable *bool `access:"experimental,cloud_restrictable"` - ClientSideCertCheck *string `access:"experimental,cloud_restrictable"` - EnableClickToReply *bool `access:"experimental,write_restrictable,cloud_restrictable"` - LinkMetadataTimeoutMilliseconds *int64 `access:"experimental,write_restrictable,cloud_restrictable"` - RestrictSystemAdmin *bool `access:"experimental,write_restrictable"` - UseNewSAMLLibrary *bool `access:"experimental,cloud_restrictable"` - CloudUserLimit *int64 `access:"experimental,write_restrictable"` - CloudBilling *bool `access:"experimental,write_restrictable"` - EnableSharedChannels *bool `access:"experimental"` + ClientSideCertEnable *bool `access:"experimental_features,cloud_restrictable"` + ClientSideCertCheck *string `access:"experimental_features,cloud_restrictable"` + EnableClickToReply *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + LinkMetadataTimeoutMilliseconds *int64 `access:"experimental_features,write_restrictable,cloud_restrictable"` + RestrictSystemAdmin *bool `access:"experimental_features,write_restrictable"` + UseNewSAMLLibrary *bool `access:"experimental_features,cloud_restrictable"` + CloudUserLimit *int64 `access:"experimental_features,write_restrictable"` + CloudBilling *bool `access:"experimental_features,write_restrictable"` + EnableSharedChannels *bool `access:"experimental_features"` + EnableRemoteClusterService *bool `access:"experimental_features"` } func (s *ExperimentalSettings) SetDefaults() { @@ -940,6 +982,10 @@ func (s *ExperimentalSettings) SetDefaults() { if s.EnableSharedChannels == nil { s.EnableSharedChannels = NewBool(false) } + + if s.EnableRemoteClusterService == nil { + s.EnableRemoteClusterService = NewBool(false) + } } type AnalyticsSettings struct { @@ -953,16 +999,19 @@ func (s *AnalyticsSettings) SetDefaults() { } type SSOSettings struct { - Enable *bool `access:"authentication"` - Secret *string `access:"authentication"` - Id *string `access:"authentication"` - Scope *string `access:"authentication"` - AuthEndpoint *string `access:"authentication"` - TokenEndpoint *string `access:"authentication"` - UserApiEndpoint *string `access:"authentication"` -} - -func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEndpoint string) { + Enable *bool `access:"authentication_openid"` + Secret *string `access:"authentication_openid"` // telemetry: none + Id *string `access:"authentication_openid"` // telemetry: none + Scope *string `access:"authentication_openid"` // telemetry: none + AuthEndpoint *string `access:"authentication_openid"` // telemetry: none + TokenEndpoint *string `access:"authentication_openid"` // telemetry: none + UserApiEndpoint *string `access:"authentication_openid"` // telemetry: none + DiscoveryEndpoint *string `access:"authentication_openid"` // telemetry: none + ButtonText *string `access:"authentication_openid"` // telemetry: none + ButtonColor *string `access:"authentication_openid"` // telemetry: none +} + +func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEndpoint, buttonColor string) { if s.Enable == nil { s.Enable = NewBool(false) } @@ -979,6 +1028,10 @@ func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEnd s.Scope = NewString(scope) } + if s.DiscoveryEndpoint == nil { + s.DiscoveryEndpoint = NewString("") + } + if s.AuthEndpoint == nil { s.AuthEndpoint = NewString(authEndpoint) } @@ -990,17 +1043,26 @@ func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEnd if s.UserApiEndpoint == nil { s.UserApiEndpoint = NewString(userApiEndpoint) } + + if s.ButtonText == nil { + s.ButtonText = NewString("") + } + + if s.ButtonColor == nil { + s.ButtonColor = NewString(buttonColor) + } } type Office365Settings struct { - Enable *bool `access:"authentication"` - Secret *string `access:"authentication"` - Id *string `access:"authentication"` - Scope *string `access:"authentication"` - AuthEndpoint *string `access:"authentication"` - TokenEndpoint *string `access:"authentication"` - UserApiEndpoint *string `access:"authentication"` - DirectoryId *string `access:"authentication"` + Enable *bool `access:"authentication_openid"` + Secret *string `access:"authentication_openid"` // telemetry: none + Id *string `access:"authentication_openid"` // telemetry: none + Scope *string `access:"authentication_openid"` + AuthEndpoint *string `access:"authentication_openid"` // telemetry: none + TokenEndpoint *string `access:"authentication_openid"` // telemetry: none + UserApiEndpoint *string `access:"authentication_openid"` // telemetry: none + DiscoveryEndpoint *string `access:"authentication_openid"` // telemetry: none + DirectoryId *string `access:"authentication_openid"` // telemetry: none } func (s *Office365Settings) setDefaults() { @@ -1020,6 +1082,10 @@ func (s *Office365Settings) setDefaults() { s.Scope = NewString(OFFICE365_SETTINGS_DEFAULT_SCOPE) } + if s.DiscoveryEndpoint == nil { + s.DiscoveryEndpoint = NewString("") + } + if s.AuthEndpoint == nil { s.AuthEndpoint = NewString(OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT) } @@ -1043,24 +1109,33 @@ func (s *Office365Settings) SSOSettings() *SSOSettings { ssoSettings.Secret = s.Secret ssoSettings.Id = s.Id ssoSettings.Scope = s.Scope + ssoSettings.DiscoveryEndpoint = s.DiscoveryEndpoint ssoSettings.AuthEndpoint = s.AuthEndpoint ssoSettings.TokenEndpoint = s.TokenEndpoint ssoSettings.UserApiEndpoint = s.UserApiEndpoint return &ssoSettings } +type ReplicaLagSettings struct { + DataSource *string `access:"environment,write_restrictable,cloud_restrictable"` // telemetry: none + QueryAbsoluteLag *string `access:"environment,write_restrictable,cloud_restrictable"` // telemetry: none + QueryTimeLag *string `access:"environment,write_restrictable,cloud_restrictable"` // telemetry: none +} + type SqlSettings struct { - DriverName *string `access:"environment,write_restrictable,cloud_restrictable"` - DataSource *string `access:"environment,write_restrictable,cloud_restrictable"` - DataSourceReplicas []string `access:"environment,write_restrictable,cloud_restrictable"` - DataSourceSearchReplicas []string `access:"environment,write_restrictable,cloud_restrictable"` - MaxIdleConns *int `access:"environment,write_restrictable,cloud_restrictable"` - ConnMaxLifetimeMilliseconds *int `access:"environment,write_restrictable,cloud_restrictable"` - MaxOpenConns *int `access:"environment,write_restrictable,cloud_restrictable"` - Trace *bool `access:"environment,write_restrictable,cloud_restrictable"` - AtRestEncryptKey *string `access:"environment,write_restrictable,cloud_restrictable"` - QueryTimeout *int `access:"environment,write_restrictable,cloud_restrictable"` - DisableDatabaseSearch *bool `access:"environment,write_restrictable,cloud_restrictable"` + DriverName *string `access:"environment_database,write_restrictable,cloud_restrictable"` + DataSource *string `access:"environment_database,write_restrictable,cloud_restrictable"` // telemetry: none + DataSourceReplicas []string `access:"environment_database,write_restrictable,cloud_restrictable"` + DataSourceSearchReplicas []string `access:"environment_database,write_restrictable,cloud_restrictable"` + MaxIdleConns *int `access:"environment_database,write_restrictable,cloud_restrictable"` + ConnMaxLifetimeMilliseconds *int `access:"environment_database,write_restrictable,cloud_restrictable"` + ConnMaxIdleTimeMilliseconds *int `access:"environment_database,write_restrictable,cloud_restrictable"` + MaxOpenConns *int `access:"environment_database,write_restrictable,cloud_restrictable"` + Trace *bool `access:"environment_database,write_restrictable,cloud_restrictable"` + AtRestEncryptKey *string `access:"environment_database,write_restrictable,cloud_restrictable"` // telemetry: none + QueryTimeout *int `access:"environment_database,write_restrictable,cloud_restrictable"` + DisableDatabaseSearch *bool `access:"environment_database,write_restrictable,cloud_restrictable"` + ReplicaLagSettings []*ReplicaLagSettings `access:"environment_database,write_restrictable,cloud_restrictable"` // telemetry: none } func (s *SqlSettings) SetDefaults(isUpdate bool) { @@ -1082,7 +1157,7 @@ func (s *SqlSettings) SetDefaults(isUpdate bool) { if isUpdate { // When updating an existing configuration, ensure an encryption key has been specified. - if s.AtRestEncryptKey == nil || len(*s.AtRestEncryptKey) == 0 { + if s.AtRestEncryptKey == nil || *s.AtRestEncryptKey == "" { s.AtRestEncryptKey = NewString(NewRandomString(32)) } } else { @@ -1102,6 +1177,10 @@ func (s *SqlSettings) SetDefaults(isUpdate bool) { s.ConnMaxLifetimeMilliseconds = NewInt(3600000) } + if s.ConnMaxIdleTimeMilliseconds == nil { + s.ConnMaxIdleTimeMilliseconds = NewInt(300000) + } + if s.Trace == nil { s.Trace = NewBool(false) } @@ -1113,20 +1192,25 @@ func (s *SqlSettings) SetDefaults(isUpdate bool) { if s.DisableDatabaseSearch == nil { s.DisableDatabaseSearch = NewBool(false) } + + if s.ReplicaLagSettings == nil { + s.ReplicaLagSettings = []*ReplicaLagSettings{} + } } type LogSettings struct { - EnableConsole *bool `access:"environment,write_restrictable,cloud_restrictable"` - ConsoleLevel *string `access:"environment,write_restrictable,cloud_restrictable"` - ConsoleJson *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableFile *bool `access:"environment,write_restrictable,cloud_restrictable"` - FileLevel *string `access:"environment,write_restrictable,cloud_restrictable"` - FileJson *bool `access:"environment,write_restrictable,cloud_restrictable"` - FileLocation *string `access:"environment,write_restrictable,cloud_restrictable"` - EnableWebhookDebugging *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableDiagnostics *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableSentry *bool `access:"environment,write_restrictable,cloud_restrictable"` - AdvancedLoggingConfig *string `access:"environment,write_restrictable,cloud_restrictable"` + EnableConsole *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` + ConsoleLevel *string `access:"environment_logging,write_restrictable,cloud_restrictable"` + ConsoleJson *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` + EnableColor *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` // telemetry: none + EnableFile *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` + FileLevel *string `access:"environment_logging,write_restrictable,cloud_restrictable"` + FileJson *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` + FileLocation *string `access:"environment_logging,write_restrictable,cloud_restrictable"` + EnableWebhookDebugging *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` + EnableDiagnostics *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` // telemetry: none + EnableSentry *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` // telemetry: none + AdvancedLoggingConfig *string `access:"environment_logging,write_restrictable,cloud_restrictable"` } func (s *LogSettings) SetDefaults() { @@ -1138,6 +1222,10 @@ func (s *LogSettings) SetDefaults() { s.ConsoleLevel = NewString("DEBUG") } + if s.EnableColor == nil { + s.EnableColor = NewBool(false) + } + if s.EnableFile == nil { s.EnableFile = NewBool(true) } @@ -1176,14 +1264,14 @@ func (s *LogSettings) SetDefaults() { } type ExperimentalAuditSettings struct { - FileEnabled *bool `access:"experimental,write_restrictable,cloud_restrictable"` - FileName *string `access:"experimental,write_restrictable,cloud_restrictable"` - FileMaxSizeMB *int `access:"experimental,write_restrictable,cloud_restrictable"` - FileMaxAgeDays *int `access:"experimental,write_restrictable,cloud_restrictable"` - FileMaxBackups *int `access:"experimental,write_restrictable,cloud_restrictable"` - FileCompress *bool `access:"experimental,write_restrictable,cloud_restrictable"` - FileMaxQueueSize *int `access:"experimental,write_restrictable,cloud_restrictable"` - AdvancedLoggingConfig *string `access:"experimental,write_restrictable,cloud_restrictable"` + FileEnabled *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + FileName *string `access:"experimental_features,write_restrictable,cloud_restrictable"` // telemetry: none + FileMaxSizeMB *int `access:"experimental_features,write_restrictable,cloud_restrictable"` + FileMaxAgeDays *int `access:"experimental_features,write_restrictable,cloud_restrictable"` + FileMaxBackups *int `access:"experimental_features,write_restrictable,cloud_restrictable"` + FileCompress *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + FileMaxQueueSize *int `access:"experimental_features,write_restrictable,cloud_restrictable"` + AdvancedLoggingConfig *string `access:"experimental_features,write_restrictable,cloud_restrictable"` } func (s *ExperimentalAuditSettings) SetDefaults() { @@ -1224,6 +1312,7 @@ type NotificationLogSettings struct { EnableConsole *bool `access:"write_restrictable,cloud_restrictable"` ConsoleLevel *string `access:"write_restrictable,cloud_restrictable"` ConsoleJson *bool `access:"write_restrictable,cloud_restrictable"` + EnableColor *bool `access:"write_restrictable,cloud_restrictable"` // telemetry: none EnableFile *bool `access:"write_restrictable,cloud_restrictable"` FileLevel *string `access:"write_restrictable,cloud_restrictable"` FileJson *bool `access:"write_restrictable,cloud_restrictable"` @@ -1256,6 +1345,10 @@ func (s *NotificationLogSettings) SetDefaults() { s.ConsoleJson = NewBool(true) } + if s.EnableColor == nil { + s.EnableColor = NewBool(false) + } + if s.FileJson == nil { s.FileJson = NewBool(true) } @@ -1266,11 +1359,11 @@ func (s *NotificationLogSettings) SetDefaults() { } type PasswordSettings struct { - MinimumLength *int `access:"authentication"` - Lowercase *bool `access:"authentication"` - Number *bool `access:"authentication"` - Uppercase *bool `access:"authentication"` - Symbol *bool `access:"authentication"` + MinimumLength *int `access:"authentication_password"` + Lowercase *bool `access:"authentication_password"` + Number *bool `access:"authentication_password"` + Uppercase *bool `access:"authentication_password"` + Symbol *bool `access:"authentication_password"` } func (s *PasswordSettings) SetDefaults() { @@ -1296,25 +1389,27 @@ func (s *PasswordSettings) SetDefaults() { } type FileSettings struct { - EnableFileAttachments *bool `access:"site,cloud_restrictable"` - EnableMobileUpload *bool `access:"site,cloud_restrictable"` - EnableMobileDownload *bool `access:"site,cloud_restrictable"` - MaxFileSize *int64 `access:"environment,cloud_restrictable"` - DriverName *string `access:"environment,write_restrictable,cloud_restrictable"` - Directory *string `access:"environment,write_restrictable,cloud_restrictable"` - EnablePublicLink *bool `access:"site,cloud_restrictable"` - PublicLinkSalt *string `access:"site,cloud_restrictable"` - InitialFont *string `access:"environment,cloud_restrictable"` - AmazonS3AccessKeyId *string `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3SecretAccessKey *string `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3Bucket *string `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3PathPrefix *string `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3Region *string `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3Endpoint *string `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3SSL *bool `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3SignV2 *bool `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3SSE *bool `access:"environment,write_restrictable,cloud_restrictable"` - AmazonS3Trace *bool `access:"environment,write_restrictable,cloud_restrictable"` + EnableFileAttachments *bool `access:"site_file_sharing_and_downloads,cloud_restrictable"` + EnableMobileUpload *bool `access:"site_file_sharing_and_downloads,cloud_restrictable"` + EnableMobileDownload *bool `access:"site_file_sharing_and_downloads,cloud_restrictable"` + MaxFileSize *int64 `access:"environment_file_storage,cloud_restrictable"` + DriverName *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` + Directory *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` + EnablePublicLink *bool `access:"site_public_links,cloud_restrictable"` + ExtractContent *bool `access:"environment_file_storage,write_restrictable"` + ArchiveRecursion *bool `access:"environment_file_storage,write_restrictable"` + PublicLinkSalt *string `access:"site_public_links,cloud_restrictable"` // telemetry: none + InitialFont *string `access:"environment_file_storage,cloud_restrictable"` // telemetry: none + AmazonS3AccessKeyId *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none + AmazonS3SecretAccessKey *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none + AmazonS3Bucket *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none + AmazonS3PathPrefix *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none + AmazonS3Region *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none + AmazonS3Endpoint *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none + AmazonS3SSL *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` + AmazonS3SignV2 *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` + AmazonS3SSE *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` + AmazonS3Trace *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` } func (s *FileSettings) SetDefaults(isUpdate bool) { @@ -1331,7 +1426,7 @@ func (s *FileSettings) SetDefaults(isUpdate bool) { } if s.MaxFileSize == nil { - s.MaxFileSize = NewInt64(52428800) // 50 MB + s.MaxFileSize = NewInt64(MB * 100) } if s.DriverName == nil { @@ -1346,9 +1441,17 @@ func (s *FileSettings) SetDefaults(isUpdate bool) { s.EnablePublicLink = NewBool(false) } + if s.ExtractContent == nil { + s.ExtractContent = NewBool(true) + } + + if s.ArchiveRecursion == nil { + s.ArchiveRecursion = NewBool(false) + } + if isUpdate { // When updating an existing configuration, ensure link salt has been specified. - if s.PublicLinkSalt == nil || len(*s.PublicLinkSalt) == 0 { + if s.PublicLinkSalt == nil || *s.PublicLinkSalt == "" { s.PublicLinkSalt = NewString(NewRandomString(32)) } } else { @@ -1381,7 +1484,7 @@ func (s *FileSettings) SetDefaults(isUpdate bool) { s.AmazonS3Region = NewString("") } - if s.AmazonS3Endpoint == nil || len(*s.AmazonS3Endpoint) == 0 { + if s.AmazonS3Endpoint == nil || *s.AmazonS3Endpoint == "" { // Defaults to "s3.amazonaws.com" s.AmazonS3Endpoint = NewString("s3.amazonaws.com") } @@ -1404,37 +1507,59 @@ func (s *FileSettings) SetDefaults(isUpdate bool) { } } +func (s *FileSettings) ToFileBackendSettings(enableComplianceFeature bool) filestore.FileBackendSettings { + if *s.DriverName == IMAGE_DRIVER_LOCAL { + return filestore.FileBackendSettings{ + DriverName: *s.DriverName, + Directory: *s.Directory, + } + } + return filestore.FileBackendSettings{ + DriverName: *s.DriverName, + AmazonS3AccessKeyId: *s.AmazonS3AccessKeyId, + AmazonS3SecretAccessKey: *s.AmazonS3SecretAccessKey, + AmazonS3Bucket: *s.AmazonS3Bucket, + AmazonS3PathPrefix: *s.AmazonS3PathPrefix, + AmazonS3Region: *s.AmazonS3Region, + AmazonS3Endpoint: *s.AmazonS3Endpoint, + AmazonS3SSL: s.AmazonS3SSL == nil || *s.AmazonS3SSL, + AmazonS3SignV2: s.AmazonS3SignV2 != nil && *s.AmazonS3SignV2, + AmazonS3SSE: s.AmazonS3SSE != nil && *s.AmazonS3SSE && enableComplianceFeature, + AmazonS3Trace: s.AmazonS3Trace != nil && *s.AmazonS3Trace, + } +} + type EmailSettings struct { - EnableSignUpWithEmail *bool `access:"authentication"` - EnableSignInWithEmail *bool `access:"authentication"` - EnableSignInWithUsername *bool `access:"authentication"` - SendEmailNotifications *bool `access:"site"` - UseChannelInEmailNotifications *bool `access:"experimental"` - RequireEmailVerification *bool `access:"authentication"` - FeedbackName *string `access:"site"` - FeedbackEmail *string `access:"site,cloud_restrictable"` - ReplyToAddress *string `access:"site,cloud_restrictable"` - FeedbackOrganization *string `access:"site"` - EnableSMTPAuth *bool `access:"environment,write_restrictable,cloud_restrictable"` - SMTPUsername *string `access:"environment,write_restrictable,cloud_restrictable"` - SMTPPassword *string `access:"environment,write_restrictable,cloud_restrictable"` - SMTPServer *string `access:"environment,write_restrictable,cloud_restrictable"` - SMTPPort *string `access:"environment,write_restrictable,cloud_restrictable"` + EnableSignUpWithEmail *bool `access:"authentication_email"` + EnableSignInWithEmail *bool `access:"authentication_email"` + EnableSignInWithUsername *bool `access:"authentication_email"` + SendEmailNotifications *bool `access:"site_notifications"` + UseChannelInEmailNotifications *bool `access:"experimental_features"` + RequireEmailVerification *bool `access:"authentication_email"` + FeedbackName *string `access:"site_notifications"` + FeedbackEmail *string `access:"site_notifications,cloud_restrictable"` + ReplyToAddress *string `access:"site_notifications,cloud_restrictable"` + FeedbackOrganization *string `access:"site_notifications"` + EnableSMTPAuth *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` + SMTPUsername *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none + SMTPPassword *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none + SMTPServer *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none + SMTPPort *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none SMTPServerTimeout *int `access:"cloud_restrictable"` - ConnectionSecurity *string `access:"environment,write_restrictable,cloud_restrictable"` - SendPushNotifications *bool `access:"environment"` - PushNotificationServer *string `access:"environment"` - PushNotificationContents *string `access:"site"` - PushNotificationBuffer *int - EnableEmailBatching *bool `access:"site"` - EmailBatchingBufferSize *int `access:"experimental"` - EmailBatchingInterval *int `access:"experimental"` - EnablePreviewModeBanner *bool `access:"site"` - SkipServerCertificateVerification *bool `access:"environment,write_restrictable,cloud_restrictable"` - EmailNotificationContentsType *string `access:"site"` - LoginButtonColor *string `access:"experimental"` - LoginButtonBorderColor *string `access:"experimental"` - LoginButtonTextColor *string `access:"experimental"` + ConnectionSecurity *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` + SendPushNotifications *bool `access:"environment_push_notification_server"` + PushNotificationServer *string `access:"environment_push_notification_server"` // telemetry: none + PushNotificationContents *string `access:"site_notifications"` + PushNotificationBuffer *int // telemetry: none + EnableEmailBatching *bool `access:"site_notifications"` + EmailBatchingBufferSize *int `access:"experimental_features"` + EmailBatchingInterval *int `access:"experimental_features"` + EnablePreviewModeBanner *bool `access:"site_notifications"` + SkipServerCertificateVerification *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` + EmailNotificationContentsType *string `access:"site_notifications"` + LoginButtonColor *string `access:"experimental_features"` + LoginButtonBorderColor *string `access:"experimental_features"` + LoginButtonTextColor *string `access:"experimental_features"` } func (s *EmailSettings) SetDefaults(isUpdate bool) { @@ -1494,11 +1619,11 @@ func (s *EmailSettings) SetDefaults(isUpdate bool) { s.SMTPPassword = NewString("") } - if s.SMTPServer == nil || len(*s.SMTPServer) == 0 { + if s.SMTPServer == nil || *s.SMTPServer == "" { s.SMTPServer = NewString("localhost") } - if s.SMTPPort == nil || len(*s.SMTPPort) == 0 { + if s.SMTPPort == nil || *s.SMTPPort == "" { s.SMTPPort = NewString("10025") } @@ -1580,13 +1705,13 @@ func (s *EmailSettings) SetDefaults(isUpdate bool) { } type RateLimitSettings struct { - Enable *bool `access:"environment,write_restrictable,cloud_restrictable"` - PerSec *int `access:"environment,write_restrictable,cloud_restrictable"` - MaxBurst *int `access:"environment,write_restrictable,cloud_restrictable"` - MemoryStoreSize *int `access:"environment,write_restrictable,cloud_restrictable"` - VaryByRemoteAddr *bool `access:"environment,write_restrictable,cloud_restrictable"` - VaryByUser *bool `access:"environment,write_restrictable,cloud_restrictable"` - VaryByHeader string `access:"environment,write_restrictable,cloud_restrictable"` + Enable *bool `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` + PerSec *int `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` + MaxBurst *int `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` + MemoryStoreSize *int `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` + VaryByRemoteAddr *bool `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` + VaryByUser *bool `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` + VaryByHeader string `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` } func (s *RateLimitSettings) SetDefaults() { @@ -1616,8 +1741,8 @@ func (s *RateLimitSettings) SetDefaults() { } type PrivacySettings struct { - ShowEmailAddress *bool `access:"site"` - ShowFullName *bool `access:"site"` + ShowEmailAddress *bool `access:"site_users_and_teams"` + ShowFullName *bool `access:"site_users_and_teams"` } func (s *PrivacySettings) setDefaults() { @@ -1631,15 +1756,15 @@ func (s *PrivacySettings) setDefaults() { } type SupportSettings struct { - TermsOfServiceLink *string `access:"site,write_restrictable,cloud_restrictable"` - PrivacyPolicyLink *string `access:"site,write_restrictable,cloud_restrictable"` - AboutLink *string `access:"site,write_restrictable,cloud_restrictable"` - HelpLink *string `access:"site,write_restrictable,cloud_restrictable"` - ReportAProblemLink *string `access:"site,write_restrictable,cloud_restrictable"` - SupportEmail *string `access:"site"` - CustomTermsOfServiceEnabled *bool `access:"compliance"` - CustomTermsOfServiceReAcceptancePeriod *int `access:"compliance"` - EnableAskCommunityLink *bool `access:"site"` + TermsOfServiceLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` + PrivacyPolicyLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` + AboutLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` + HelpLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` + ReportAProblemLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` + SupportEmail *string `access:"site_customization"` + CustomTermsOfServiceEnabled *bool `access:"compliance_custom_terms_of_service"` + CustomTermsOfServiceReAcceptancePeriod *int `access:"compliance_custom_terms_of_service"` + EnableAskCommunityLink *bool `access:"site_customization"` } func (s *SupportSettings) SetDefaults() { @@ -1701,16 +1826,16 @@ func (s *SupportSettings) SetDefaults() { } type AnnouncementSettings struct { - EnableBanner *bool `access:"site"` - BannerText *string `access:"site"` - BannerColor *string `access:"site"` - BannerTextColor *string `access:"site"` - AllowBannerDismissal *bool `access:"site"` - AdminNoticesEnabled *bool `access:"site"` - UserNoticesEnabled *bool `access:"site"` - NoticesURL *string `access:"site,write_restrictable"` - NoticesFetchFrequency *int `access:"site,write_restrictable"` - NoticesSkipCache *bool `access:"site,write_restrictable"` + EnableBanner *bool `access:"site_announcement_banner"` + BannerText *string `access:"site_announcement_banner"` // telemetry: none + BannerColor *string `access:"site_announcement_banner"` + BannerTextColor *string `access:"site_announcement_banner"` + AllowBannerDismissal *bool `access:"site_announcement_banner"` + AdminNoticesEnabled *bool `access:"site_notices"` + UserNoticesEnabled *bool `access:"site_notices"` + NoticesURL *string `access:"site_notices,write_restrictable"` // telemetry: none + NoticesFetchFrequency *int `access:"site_notices,write_restrictable"` // telemetry: none + NoticesSkipCache *bool `access:"site_notices,write_restrictable"` // telemetry: none } func (s *AnnouncementSettings) SetDefaults() { @@ -1754,9 +1879,9 @@ func (s *AnnouncementSettings) SetDefaults() { } type ThemeSettings struct { - EnableThemeSelection *bool `access:"experimental"` - DefaultTheme *string `access:"experimental"` - AllowCustomThemes *bool `access:"experimental"` + EnableThemeSelection *bool `access:"experimental_features"` + DefaultTheme *string `access:"experimental_features"` + AllowCustomThemes *bool `access:"experimental_features"` AllowedThemes []string } @@ -1779,38 +1904,39 @@ func (s *ThemeSettings) SetDefaults() { } type TeamSettings struct { - SiteName *string `access:"site"` - MaxUsersPerTeam *int `access:"site"` - DEPRECATED_DO_NOT_USE_EnableTeamCreation *bool `json:"EnableTeamCreation" mapstructure:"EnableTeamCreation"` // This field is deprecated and must not be used. - EnableUserCreation *bool `access:"authentication"` - EnableOpenServer *bool `access:"authentication"` - EnableUserDeactivation *bool `access:"experimental"` - RestrictCreationToDomains *string `access:"authentication"` - EnableCustomBrand *bool `access:"site"` - CustomBrandText *string `access:"site"` - CustomDescriptionText *string `access:"site"` - RestrictDirectMessage *string `access:"site"` - DEPRECATED_DO_NOT_USE_RestrictTeamInvite *string `json:"RestrictTeamInvite" mapstructure:"RestrictTeamInvite"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement *string `json:"RestrictPublicChannelManagement" mapstructure:"RestrictPublicChannelManagement"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement *string `json:"RestrictPrivateChannelManagement" mapstructure:"RestrictPrivateChannelManagement"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation *string `json:"RestrictPublicChannelCreation" mapstructure:"RestrictPublicChannelCreation"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation *string `json:"RestrictPrivateChannelCreation" mapstructure:"RestrictPrivateChannelCreation"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion *string `json:"RestrictPublicChannelDeletion" mapstructure:"RestrictPublicChannelDeletion"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion *string `json:"RestrictPrivateChannelDeletion" mapstructure:"RestrictPrivateChannelDeletion"` // This field is deprecated and must not be used. - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers *string `json:"RestrictPrivateChannelManageMembers" mapstructure:"RestrictPrivateChannelManageMembers"` // This field is deprecated and must not be used. - EnableXToLeaveChannelsFromLHS *bool `access:"experimental"` - UserStatusAwayTimeout *int64 `access:"experimental"` - MaxChannelsPerTeam *int64 `access:"site"` - MaxNotificationsPerChannel *int64 `access:"environment"` - EnableConfirmNotificationsToChannel *bool `access:"site"` - TeammateNameDisplay *string `access:"site"` - ExperimentalViewArchivedChannels *bool `access:"experimental,site"` - ExperimentalEnableAutomaticReplies *bool `access:"experimental"` - ExperimentalHideTownSquareinLHS *bool `access:"experimental"` - ExperimentalTownSquareIsReadOnly *bool `access:"experimental"` - LockTeammateNameDisplay *bool `access:"site"` - ExperimentalPrimaryTeam *string `access:"experimental"` - ExperimentalDefaultChannels []string `access:"experimental"` + SiteName *string `access:"site_customization"` + MaxUsersPerTeam *int `access:"site_users_and_teams"` + DEPRECATED_DO_NOT_USE_EnableTeamCreation *bool `json:"EnableTeamCreation" mapstructure:"EnableTeamCreation"` // Deprecated: do not use + EnableUserCreation *bool `access:"authentication_signup"` + EnableOpenServer *bool `access:"authentication_signup"` + EnableUserDeactivation *bool `access:"experimental_features"` + RestrictCreationToDomains *string `access:"authentication_signup"` // telemetry: none + EnableCustomUserStatuses *bool `access:"site_users_and_teams"` + EnableCustomBrand *bool `access:"site_customization"` + CustomBrandText *string `access:"site_customization"` + CustomDescriptionText *string `access:"site_customization"` + RestrictDirectMessage *string `access:"site_users_and_teams"` + DEPRECATED_DO_NOT_USE_RestrictTeamInvite *string `json:"RestrictTeamInvite" mapstructure:"RestrictTeamInvite"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement *string `json:"RestrictPublicChannelManagement" mapstructure:"RestrictPublicChannelManagement"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement *string `json:"RestrictPrivateChannelManagement" mapstructure:"RestrictPrivateChannelManagement"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation *string `json:"RestrictPublicChannelCreation" mapstructure:"RestrictPublicChannelCreation"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation *string `json:"RestrictPrivateChannelCreation" mapstructure:"RestrictPrivateChannelCreation"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion *string `json:"RestrictPublicChannelDeletion" mapstructure:"RestrictPublicChannelDeletion"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion *string `json:"RestrictPrivateChannelDeletion" mapstructure:"RestrictPrivateChannelDeletion"` // Deprecated: do not use + DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers *string `json:"RestrictPrivateChannelManageMembers" mapstructure:"RestrictPrivateChannelManageMembers"` // Deprecated: do not use + EnableXToLeaveChannelsFromLHS *bool `access:"experimental_features"` + UserStatusAwayTimeout *int64 `access:"experimental_features"` + MaxChannelsPerTeam *int64 `access:"site_users_and_teams"` + MaxNotificationsPerChannel *int64 `access:"environment_push_notification_server"` + EnableConfirmNotificationsToChannel *bool `access:"site_notifications"` + TeammateNameDisplay *string `access:"site_users_and_teams"` + ExperimentalViewArchivedChannels *bool `access:"experimental_features,site_users_and_teams"` + ExperimentalEnableAutomaticReplies *bool `access:"experimental_features"` + ExperimentalHideTownSquareinLHS *bool `access:"experimental_features"` + ExperimentalTownSquareIsReadOnly *bool `access:"experimental_features"` + LockTeammateNameDisplay *bool `access:"site_users_and_teams"` + ExperimentalPrimaryTeam *string `access:"experimental_features"` + ExperimentalDefaultChannels []string `access:"experimental_features"` } func (s *TeamSettings) SetDefaults() { @@ -1839,6 +1965,10 @@ func (s *TeamSettings) SetDefaults() { s.RestrictCreationToDomains = NewString("") } + if s.EnableCustomUserStatuses == nil { + s.EnableCustomUserStatuses = NewBool(true) + } + if s.EnableCustomBrand == nil { s.EnableCustomBrand = NewBool(false) } @@ -1972,55 +2102,55 @@ type ClientRequirements struct { type LdapSettings struct { // Basic - Enable *bool `access:"authentication"` - EnableSync *bool `access:"authentication"` - LdapServer *string `access:"authentication"` - LdapPort *int `access:"authentication"` - ConnectionSecurity *string `access:"authentication"` - BaseDN *string `access:"authentication"` - BindUsername *string `access:"authentication"` - BindPassword *string `access:"authentication"` + Enable *bool `access:"authentication_ldap"` + EnableSync *bool `access:"authentication_ldap"` + LdapServer *string `access:"authentication_ldap"` // telemetry: none + LdapPort *int `access:"authentication_ldap"` // telemetry: none + ConnectionSecurity *string `access:"authentication_ldap"` + BaseDN *string `access:"authentication_ldap"` // telemetry: none + BindUsername *string `access:"authentication_ldap"` // telemetry: none + BindPassword *string `access:"authentication_ldap"` // telemetry: none // Filtering - UserFilter *string `access:"authentication"` - GroupFilter *string `access:"authentication"` - GuestFilter *string `access:"authentication"` + UserFilter *string `access:"authentication_ldap"` // telemetry: none + GroupFilter *string `access:"authentication_ldap"` + GuestFilter *string `access:"authentication_ldap"` EnableAdminFilter *bool AdminFilter *string // Group Mapping - GroupDisplayNameAttribute *string `access:"authentication"` - GroupIdAttribute *string `access:"authentication"` + GroupDisplayNameAttribute *string `access:"authentication_ldap"` + GroupIdAttribute *string `access:"authentication_ldap"` // User Mapping - FirstNameAttribute *string `access:"authentication"` - LastNameAttribute *string `access:"authentication"` - EmailAttribute *string `access:"authentication"` - UsernameAttribute *string `access:"authentication"` - NicknameAttribute *string `access:"authentication"` - IdAttribute *string `access:"authentication"` - PositionAttribute *string `access:"authentication"` - LoginIdAttribute *string `access:"authentication"` - PictureAttribute *string `access:"authentication"` + FirstNameAttribute *string `access:"authentication_ldap"` + LastNameAttribute *string `access:"authentication_ldap"` + EmailAttribute *string `access:"authentication_ldap"` + UsernameAttribute *string `access:"authentication_ldap"` + NicknameAttribute *string `access:"authentication_ldap"` + IdAttribute *string `access:"authentication_ldap"` + PositionAttribute *string `access:"authentication_ldap"` + LoginIdAttribute *string `access:"authentication_ldap"` + PictureAttribute *string `access:"authentication_ldap"` // Synchronization - SyncIntervalMinutes *int `access:"authentication"` + SyncIntervalMinutes *int `access:"authentication_ldap"` // Advanced - SkipCertificateVerification *bool `access:"authentication"` - PublicCertificateFile *string `access:"authentication"` - PrivateKeyFile *string `access:"authentication"` - QueryTimeout *int `access:"authentication"` - MaxPageSize *int `access:"authentication"` + SkipCertificateVerification *bool `access:"authentication_ldap"` + PublicCertificateFile *string `access:"authentication_ldap"` + PrivateKeyFile *string `access:"authentication_ldap"` + QueryTimeout *int `access:"authentication_ldap"` + MaxPageSize *int `access:"authentication_ldap"` // Customization - LoginFieldName *string `access:"authentication"` + LoginFieldName *string `access:"authentication_ldap"` - LoginButtonColor *string `access:"authentication"` - LoginButtonBorderColor *string `access:"authentication"` - LoginButtonTextColor *string `access:"authentication"` + LoginButtonColor *string `access:"experimental_features"` + LoginButtonBorderColor *string `access:"experimental_features"` + LoginButtonTextColor *string `access:"experimental_features"` - Trace *bool `access:"authentication"` + Trace *bool `access:"authentication_ldap"` // telemetry: none } func (s *LdapSettings) SetDefaults() { @@ -2169,9 +2299,10 @@ func (s *LdapSettings) SetDefaults() { } type ComplianceSettings struct { - Enable *bool `access:"compliance"` - Directory *string `access:"compliance"` - EnableDaily *bool `access:"compliance"` + Enable *bool `access:"compliance_compliance_monitoring"` + Directory *string `access:"compliance_compliance_monitoring"` // telemetry: none + EnableDaily *bool `access:"compliance_compliance_monitoring"` + BatchSize *int `access:"compliance_compliance_monitoring"` // telemetry: none } func (s *ComplianceSettings) SetDefaults() { @@ -2186,12 +2317,16 @@ func (s *ComplianceSettings) SetDefaults() { if s.EnableDaily == nil { s.EnableDaily = NewBool(false) } + + if s.BatchSize == nil { + s.BatchSize = NewInt(30000) + } } type LocalizationSettings struct { - DefaultServerLocale *string `access:"site"` - DefaultClientLocale *string `access:"site"` - AvailableLocales *string `access:"site"` + DefaultServerLocale *string `access:"site_localization"` + DefaultClientLocale *string `access:"site_localization"` + AvailableLocales *string `access:"site_localization"` } func (s *LocalizationSettings) SetDefaults() { @@ -2210,49 +2345,49 @@ func (s *LocalizationSettings) SetDefaults() { type SamlSettings struct { // Basic - Enable *bool `access:"authentication"` - EnableSyncWithLdap *bool `access:"authentication"` - EnableSyncWithLdapIncludeAuth *bool `access:"authentication"` - IgnoreGuestsLdapSync *bool `access:"authentication"` + Enable *bool `access:"authentication_saml"` + EnableSyncWithLdap *bool `access:"authentication_saml"` + EnableSyncWithLdapIncludeAuth *bool `access:"authentication_saml"` + IgnoreGuestsLdapSync *bool `access:"authentication_saml"` - Verify *bool `access:"authentication"` - Encrypt *bool `access:"authentication"` - SignRequest *bool `access:"authentication"` + Verify *bool `access:"authentication_saml"` + Encrypt *bool `access:"authentication_saml"` + SignRequest *bool `access:"authentication_saml"` - IdpUrl *string `access:"authentication"` - IdpDescriptorUrl *string `access:"authentication"` - IdpMetadataUrl *string `access:"authentication"` - ServiceProviderIdentifier *string `access:"authentication"` - AssertionConsumerServiceURL *string `access:"authentication"` + IdpUrl *string `access:"authentication_saml"` // telemetry: none + IdpDescriptorUrl *string `access:"authentication_saml"` // telemetry: none + IdpMetadataUrl *string `access:"authentication_saml"` // telemetry: none + ServiceProviderIdentifier *string `access:"authentication_saml"` // telemetry: none + AssertionConsumerServiceURL *string `access:"authentication_saml"` // telemetry: none - SignatureAlgorithm *string `access:"authentication"` - CanonicalAlgorithm *string `access:"authentication"` + SignatureAlgorithm *string `access:"authentication_saml"` + CanonicalAlgorithm *string `access:"authentication_saml"` - ScopingIDPProviderId *string `access:"authentication"` - ScopingIDPName *string `access:"authentication"` + ScopingIDPProviderId *string `access:"authentication_saml"` + ScopingIDPName *string `access:"authentication_saml"` - IdpCertificateFile *string `access:"authentication"` - PublicCertificateFile *string `access:"authentication"` - PrivateKeyFile *string `access:"authentication"` + IdpCertificateFile *string `access:"authentication_saml"` // telemetry: none + PublicCertificateFile *string `access:"authentication_saml"` // telemetry: none + PrivateKeyFile *string `access:"authentication_saml"` // telemetry: none // User Mapping - IdAttribute *string `access:"authentication"` - GuestAttribute *string `access:"authentication"` + IdAttribute *string `access:"authentication_saml"` + GuestAttribute *string `access:"authentication_saml"` EnableAdminAttribute *bool AdminAttribute *string - FirstNameAttribute *string `access:"authentication"` - LastNameAttribute *string `access:"authentication"` - EmailAttribute *string `access:"authentication"` - UsernameAttribute *string `access:"authentication"` - NicknameAttribute *string `access:"authentication"` - LocaleAttribute *string `access:"authentication"` - PositionAttribute *string `access:"authentication"` + FirstNameAttribute *string `access:"authentication_saml"` + LastNameAttribute *string `access:"authentication_saml"` + EmailAttribute *string `access:"authentication_saml"` + UsernameAttribute *string `access:"authentication_saml"` + NicknameAttribute *string `access:"authentication_saml"` + LocaleAttribute *string `access:"authentication_saml"` + PositionAttribute *string `access:"authentication_saml"` - LoginButtonText *string `access:"authentication"` + LoginButtonText *string `access:"authentication_saml"` - LoginButtonColor *string `access:"authentication"` - LoginButtonBorderColor *string `access:"authentication"` - LoginButtonTextColor *string `access:"authentication"` + LoginButtonColor *string `access:"experimental_features"` + LoginButtonBorderColor *string `access:"experimental_features"` + LoginButtonTextColor *string `access:"experimental_features"` } func (s *SamlSettings) SetDefaults() { @@ -2396,9 +2531,10 @@ func (s *SamlSettings) SetDefaults() { } type NativeAppSettings struct { - AppDownloadLink *string `access:"site,write_restrictable,cloud_restrictable"` - AndroidAppDownloadLink *string `access:"site,write_restrictable,cloud_restrictable"` - IosAppDownloadLink *string `access:"site,write_restrictable,cloud_restrictable"` + AppCustomURLSchemes []string `access:"site_customization,write_restrictable,cloud_restrictable"` // telemetry: none + AppDownloadLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` + AndroidAppDownloadLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` + IosAppDownloadLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` } func (s *NativeAppSettings) SetDefaults() { @@ -2413,30 +2549,34 @@ func (s *NativeAppSettings) SetDefaults() { if s.IosAppDownloadLink == nil { s.IosAppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK) } + + if s.AppCustomURLSchemes == nil { + s.AppCustomURLSchemes = GetDefaultAppCustomURLSchemes() + } } type ElasticsearchSettings struct { - ConnectionUrl *string `access:"environment,write_restrictable,cloud_restrictable"` - Username *string `access:"environment,write_restrictable,cloud_restrictable"` - Password *string `access:"environment,write_restrictable,cloud_restrictable"` - EnableIndexing *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableSearching *bool `access:"environment,write_restrictable,cloud_restrictable"` - EnableAutocomplete *bool `access:"environment,write_restrictable,cloud_restrictable"` - Sniff *bool `access:"environment,write_restrictable,cloud_restrictable"` - PostIndexReplicas *int `access:"environment,write_restrictable,cloud_restrictable"` - PostIndexShards *int `access:"environment,write_restrictable,cloud_restrictable"` - ChannelIndexReplicas *int `access:"environment,write_restrictable,cloud_restrictable"` - ChannelIndexShards *int `access:"environment,write_restrictable,cloud_restrictable"` - UserIndexReplicas *int `access:"environment,write_restrictable,cloud_restrictable"` - UserIndexShards *int `access:"environment,write_restrictable,cloud_restrictable"` - AggregatePostsAfterDays *int `access:"environment,write_restrictable,cloud_restrictable"` - PostsAggregatorJobStartTime *string `access:"environment,write_restrictable,cloud_restrictable"` - IndexPrefix *string `access:"environment,write_restrictable,cloud_restrictable"` - LiveIndexingBatchSize *int `access:"environment,write_restrictable,cloud_restrictable"` - BulkIndexingTimeWindowSeconds *int `access:"environment,write_restrictable,cloud_restrictable"` - RequestTimeoutSeconds *int `access:"environment,write_restrictable,cloud_restrictable"` - SkipTLSVerification *bool `access:"environment,write_restrictable,cloud_restrictable"` - Trace *string `access:"environment,write_restrictable,cloud_restrictable"` + ConnectionUrl *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + Username *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + Password *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + EnableIndexing *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + EnableSearching *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + EnableAutocomplete *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + Sniff *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + PostIndexReplicas *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + PostIndexShards *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + ChannelIndexReplicas *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + ChannelIndexShards *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + UserIndexReplicas *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + UserIndexShards *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + AggregatePostsAfterDays *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` // telemetry: none + PostsAggregatorJobStartTime *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` // telemetry: none + IndexPrefix *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + LiveIndexingBatchSize *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + BulkIndexingTimeWindowSeconds *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + RequestTimeoutSeconds *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + SkipTLSVerification *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` + Trace *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` } func (s *ElasticsearchSettings) SetDefaults() { @@ -2526,11 +2666,11 @@ func (s *ElasticsearchSettings) SetDefaults() { } type BleveSettings struct { - IndexDir *string `access:"experimental"` - EnableIndexing *bool `access:"experimental"` - EnableSearching *bool `access:"experimental"` - EnableAutocomplete *bool `access:"experimental"` - BulkIndexingTimeWindowSeconds *int `access:"experimental"` + IndexDir *string `access:"experimental_bleve"` // telemetry: none + EnableIndexing *bool `access:"experimental_bleve"` + EnableSearching *bool `access:"experimental_bleve"` + EnableAutocomplete *bool `access:"experimental_bleve"` + BulkIndexingTimeWindowSeconds *int `access:"experimental_bleve"` } func (bs *BleveSettings) SetDefaults() { @@ -2556,11 +2696,12 @@ func (bs *BleveSettings) SetDefaults() { } type DataRetentionSettings struct { - EnableMessageDeletion *bool `access:"compliance"` - EnableFileDeletion *bool `access:"compliance"` - MessageRetentionDays *int `access:"compliance"` - FileRetentionDays *int `access:"compliance"` - DeletionJobStartTime *string `access:"compliance"` + EnableMessageDeletion *bool `access:"compliance_data_retention_policy"` + EnableFileDeletion *bool `access:"compliance_data_retention_policy"` + MessageRetentionDays *int `access:"compliance_data_retention_policy"` + FileRetentionDays *int `access:"compliance_data_retention_policy"` + DeletionJobStartTime *string `access:"compliance_data_retention_policy"` + BatchSize *int `access:"compliance_data_retention_policy"` } func (s *DataRetentionSettings) SetDefaults() { @@ -2583,6 +2724,10 @@ func (s *DataRetentionSettings) SetDefaults() { if s.DeletionJobStartTime == nil { s.DeletionJobStartTime = NewString(DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME) } + + if s.BatchSize == nil { + s.BatchSize = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_BATCH_SIZE) + } } type JobSettings struct { @@ -2601,13 +2746,17 @@ func (s *JobSettings) SetDefaults() { } type CloudSettings struct { - CWSUrl *string `access:"environment,write_restrictable"` + CWSUrl *string `access:"write_restrictable"` + CWSAPIUrl *string `access:"write_restrictable"` } func (s *CloudSettings) SetDefaults() { if s.CWSUrl == nil { s.CWSUrl = NewString(CLOUD_SETTINGS_DEFAULT_CWS_URL) } + if s.CWSAPIUrl == nil { + s.CWSAPIUrl = NewString(CLOUD_SETTINGS_DEFAULT_CWS_API_URL) + } } type PluginState struct { @@ -2619,16 +2768,17 @@ type PluginSettings struct { EnableUploads *bool `access:"plugins,write_restrictable,cloud_restrictable"` AllowInsecureDownloadUrl *bool `access:"plugins,write_restrictable,cloud_restrictable"` EnableHealthCheck *bool `access:"plugins,write_restrictable,cloud_restrictable"` - Directory *string `access:"plugins,write_restrictable,cloud_restrictable"` - ClientDirectory *string `access:"plugins,write_restrictable,cloud_restrictable"` - Plugins map[string]map[string]interface{} `access:"plugins"` - PluginStates map[string]*PluginState `access:"plugins"` + Directory *string `access:"plugins,write_restrictable,cloud_restrictable"` // telemetry: none + ClientDirectory *string `access:"plugins,write_restrictable,cloud_restrictable"` // telemetry: none + Plugins map[string]map[string]interface{} `access:"plugins"` // telemetry: none + PluginStates map[string]*PluginState `access:"plugins"` // telemetry: none EnableMarketplace *bool `access:"plugins,write_restrictable,cloud_restrictable"` EnableRemoteMarketplace *bool `access:"plugins,write_restrictable,cloud_restrictable"` AutomaticPrepackagedPlugins *bool `access:"plugins,write_restrictable,cloud_restrictable"` RequirePluginSignature *bool `access:"plugins,write_restrictable,cloud_restrictable"` MarketplaceUrl *string `access:"plugins,write_restrictable,cloud_restrictable"` SignaturePublicKeyFiles []string `access:"plugins,write_restrictable,cloud_restrictable"` + ChimeraOAuthProxyUrl *string `access:"plugins,write_restrictable,cloud_restrictable"` } func (s *PluginSettings) SetDefaults(ls LogSettings) { @@ -2702,14 +2852,18 @@ func (s *PluginSettings) SetDefaults(ls LogSettings) { if s.SignaturePublicKeyFiles == nil { s.SignaturePublicKeyFiles = []string{} } + + if s.ChimeraOAuthProxyUrl == nil { + s.ChimeraOAuthProxyUrl = NewString("") + } } type GlobalRelayMessageExportSettings struct { - CustomerType *string `access:"compliance"` // must be either A9 or A10, dictates SMTP server url - SmtpUsername *string `access:"compliance"` - SmtpPassword *string `access:"compliance"` - EmailAddress *string `access:"compliance"` // the address to send messages to - SMTPServerTimeout *int `access:"compliance"` + CustomerType *string `access:"compliance_compliance_export"` // must be either A9 or A10, dictates SMTP server url + SmtpUsername *string `access:"compliance_compliance_export"` + SmtpPassword *string `access:"compliance_compliance_export"` + EmailAddress *string `access:"compliance_compliance_export"` // the address to send messages to + SMTPServerTimeout *int `access:"compliance_compliance_export"` } func (s *GlobalRelayMessageExportSettings) SetDefaults() { @@ -2731,15 +2885,15 @@ func (s *GlobalRelayMessageExportSettings) SetDefaults() { } type MessageExportSettings struct { - EnableExport *bool `access:"compliance"` - ExportFormat *string `access:"compliance"` - DailyRunTime *string `access:"compliance"` - ExportFromTimestamp *int64 `access:"compliance"` - BatchSize *int `access:"compliance"` - DownloadExportResults *bool `access:"compliance"` + EnableExport *bool `access:"compliance_compliance_export"` + ExportFormat *string `access:"compliance_compliance_export"` + DailyRunTime *string `access:"compliance_compliance_export"` + ExportFromTimestamp *int64 `access:"compliance_compliance_export"` + BatchSize *int `access:"compliance_compliance_export"` + DownloadExportResults *bool `access:"compliance_compliance_export"` // formatter-specific settings - these are only expected to be non-nil if ExportFormat is set to the associated format - GlobalRelaySettings *GlobalRelayMessageExportSettings + GlobalRelaySettings *GlobalRelayMessageExportSettings `access:"compliance_compliance_export"` } func (s *MessageExportSettings) SetDefaults() { @@ -2774,8 +2928,8 @@ func (s *MessageExportSettings) SetDefaults() { } type DisplaySettings struct { - CustomUrlSchemes []string `access:"site"` - ExperimentalTimezone *bool `access:"experimental"` + CustomUrlSchemes []string `access:"site_customization"` + ExperimentalTimezone *bool `access:"experimental_features"` } func (s *DisplaySettings) SetDefaults() { @@ -2790,10 +2944,10 @@ func (s *DisplaySettings) SetDefaults() { } type GuestAccountsSettings struct { - Enable *bool `access:"authentication"` - AllowEmailAccounts *bool `access:"authentication"` - EnforceMultifactorAuthentication *bool `access:"authentication"` - RestrictCreationToDomains *string `access:"authentication"` + Enable *bool `access:"authentication_guest_access"` + AllowEmailAccounts *bool `access:"authentication_guest_access"` + EnforceMultifactorAuthentication *bool `access:"authentication_guest_access"` + RestrictCreationToDomains *string `access:"authentication_guest_access"` } func (s *GuestAccountsSettings) SetDefaults() { @@ -2815,10 +2969,10 @@ func (s *GuestAccountsSettings) SetDefaults() { } type ImageProxySettings struct { - Enable *bool `access:"environment"` - ImageProxyType *string `access:"environment"` - RemoteImageProxyURL *string `access:"environment"` - RemoteImageProxyOptions *string `access:"environment"` + Enable *bool `access:"environment_image_proxy"` + ImageProxyType *string `access:"environment_image_proxy"` + RemoteImageProxyURL *string `access:"environment_image_proxy"` + RemoteImageProxyOptions *string `access:"environment_image_proxy"` } func (s *ImageProxySettings) SetDefaults(ss ServiceSettings) { @@ -2855,19 +3009,89 @@ func (s *ImageProxySettings) SetDefaults(ss ServiceSettings) { } } +// ImportSettings defines configuration settings for file imports. +type ImportSettings struct { + // The directory where to store the imported files. + Directory *string + // The number of days to retain the imported files before deleting them. + RetentionDays *int +} + +func (s *ImportSettings) isValid() *AppError { + if *s.Directory == "" { + return NewAppError("Config.IsValid", "model.config.is_valid.import.directory.app_error", nil, "", http.StatusBadRequest) + } + + if *s.RetentionDays <= 0 { + return NewAppError("Config.IsValid", "model.config.is_valid.import.retention_days_too_low.app_error", nil, "", http.StatusBadRequest) + } + + return nil +} + +// SetDefaults applies the default settings to the struct. +func (s *ImportSettings) SetDefaults() { + if s.Directory == nil || *s.Directory == "" { + s.Directory = NewString(IMPORT_SETTINGS_DEFAULT_DIRECTORY) + } + + if s.RetentionDays == nil { + s.RetentionDays = NewInt(IMPORT_SETTINGS_DEFAULT_RETENTION_DAYS) + } +} + +// ExportSettings defines configuration settings for file exports. +type ExportSettings struct { + // The directory where to store the exported files. + Directory *string // telemetry: none + // The number of days to retain the exported files before deleting them. + RetentionDays *int +} + +func (s *ExportSettings) isValid() *AppError { + if *s.Directory == "" { + return NewAppError("Config.IsValid", "model.config.is_valid.export.directory.app_error", nil, "", http.StatusBadRequest) + } + + if *s.RetentionDays <= 0 { + return NewAppError("Config.IsValid", "model.config.is_valid.export.retention_days_too_low.app_error", nil, "", http.StatusBadRequest) + } + + return nil +} + +// SetDefaults applies the default settings to the struct. +func (s *ExportSettings) SetDefaults() { + if s.Directory == nil || *s.Directory == "" { + s.Directory = NewString(EXPORT_SETTINGS_DEFAULT_DIRECTORY) + } + + if s.RetentionDays == nil { + s.RetentionDays = NewInt(EXPORT_SETTINGS_DEFAULT_RETENTION_DAYS) + } +} + type ConfigFunc func() *Config const ConfigAccessTagType = "access" const ConfigAccessTagWriteRestrictable = "write_restrictable" const ConfigAccessTagCloudRestrictable = "cloud_restrictable" +// Allows read access if any PERMISSION_SYSCONSOLE_READ_* is allowed +const ConfigAccessTagAnySysConsoleRead = "*_read" + // Config fields support the 'access' tag with the following values corresponding to the suffix of the associated // PERMISSION_SYSCONSOLE_*_* permission Id: 'about', 'reporting', 'user_management_users', // 'user_management_groups', 'user_management_teams', 'user_management_channels', -// 'user_management_permissions', 'environment', 'site', 'authentication', 'plugins', +// 'user_management_permissions', 'environment_web_server', 'environment_database', 'environment_elasticsearch', +// 'environment_file_storage', 'environment_image_proxy', 'environment_smtp', 'environment_push_notification_server', +// 'environment_high_availability', 'environment_rate_limiting', 'environment_logging', 'environment_session_lengths', +// 'environment_performance_monitoring', 'environment_developer', 'site', 'authentication', 'plugins', // 'integrations', 'compliance', 'plugins', and 'experimental'. They grant read and/or write access to the config field // to roles without PERMISSION_MANAGE_SYSTEM. // +// The 'access' tag '*_read' checks for any SYSCONSOLE read permission and grants access if any read permission is allowed. +// // By default config values can be written with PERMISSION_MANAGE_SYSTEM, but if ExperimentalSettings.RestrictSystemAdmin is true // and the access tag contains the value 'write_restrictable', then even PERMISSION_MANAGE_SYSTEM does not grant write access. // @@ -2910,6 +3134,7 @@ type Config struct { GitLabSettings SSOSettings GoogleSettings SSOSettings Office365Settings Office365Settings + OpenIdSettings SSOSettings LdapSettings LdapSettings ComplianceSettings ComplianceSettings LocalizationSettings LocalizationSettings @@ -2923,13 +3148,15 @@ type Config struct { BleveSettings BleveSettings DataRetentionSettings DataRetentionSettings MessageExportSettings MessageExportSettings - JobSettings JobSettings + JobSettings JobSettings // telemetry: none PluginSettings PluginSettings DisplaySettings DisplaySettings GuestAccountsSettings GuestAccountsSettings ImageProxySettings ImageProxySettings - CloudSettings CloudSettings - FeatureFlags *FeatureFlags `json:",omitempty"` + CloudSettings CloudSettings // telemetry: none + FeatureFlags *FeatureFlags `access:"*_read" json:",omitempty"` + ImportSettings ImportSettings // telemetry: none + ExportSettings ExportSettings } func (o *Config) Clone() *Config { @@ -2965,6 +3192,8 @@ func (o *Config) GetSSOService(service string) *SSOSettings { return &o.GoogleSettings case SERVICE_OFFICE365: return o.Office365Settings.SSOSettings() + case SERVICE_OPENID: + return &o.OpenIdSettings } return nil @@ -3000,8 +3229,10 @@ func (o *Config) SetDefaults() { o.EmailSettings.SetDefaults(isUpdate) o.PrivacySettings.setDefaults() o.Office365Settings.setDefaults() - o.GitLabSettings.setDefaults("", "", "", "") - o.GoogleSettings.setDefaults(GOOGLE_SETTINGS_DEFAULT_SCOPE, GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT) + o.Office365Settings.setDefaults() + o.GitLabSettings.setDefaults("", "", "", "", "") + o.GoogleSettings.setDefaults(GOOGLE_SETTINGS_DEFAULT_SCOPE, GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT, "") + o.OpenIdSettings.setDefaults(OPENID_SETTINGS_DEFAULT_SCOPE, "", "", "", "#145DBF") o.ServiceSettings.SetDefaults(isUpdate) o.PasswordSettings.SetDefaults() o.TeamSettings.SetDefaults() @@ -3033,10 +3264,12 @@ func (o *Config) SetDefaults() { o.FeatureFlags = &FeatureFlags{} o.FeatureFlags.SetDefaults() } + o.ImportSettings.SetDefaults() + o.ExportSettings.SetDefaults() } func (o *Config) IsValid() *AppError { - if len(*o.ServiceSettings.SiteURL) == 0 && *o.EmailSettings.EnableEmailBatching { + if *o.ServiceSettings.SiteURL == "" && *o.EmailSettings.EnableEmailBatching { return NewAppError("Config.IsValid", "model.config.is_valid.site_url_email_batching.app_error", nil, "", http.StatusBadRequest) } @@ -3044,7 +3277,7 @@ func (o *Config) IsValid() *AppError { return NewAppError("Config.IsValid", "model.config.is_valid.cluster_email_batching.app_error", nil, "", http.StatusBadRequest) } - if len(*o.ServiceSettings.SiteURL) == 0 && *o.ServiceSettings.AllowCookiesForSubdomains { + if *o.ServiceSettings.SiteURL == "" && *o.ServiceSettings.AllowCookiesForSubdomains { return NewAppError("Config.IsValid", "model.config.is_valid.allow_cookies_for_subdomains.app_error", nil, "", http.StatusBadRequest) } @@ -3100,7 +3333,7 @@ func (o *Config) IsValid() *AppError { return err } - if err := o.MessageExportSettings.isValid(o.FileSettings); err != nil { + if err := o.MessageExportSettings.isValid(); err != nil { return err } @@ -3111,6 +3344,10 @@ func (o *Config) IsValid() *AppError { if err := o.ImageProxySettings.isValid(); err != nil { return err } + + if err := o.ImportSettings.isValid(); err != nil { + return err + } return nil } @@ -3159,11 +3396,15 @@ func (s *SqlSettings) isValid() *AppError { return NewAppError("Config.IsValid", "model.config.is_valid.sql_conn_max_lifetime_milliseconds.app_error", nil, "", http.StatusBadRequest) } + if *s.ConnMaxIdleTimeMilliseconds < 0 { + return NewAppError("Config.IsValid", "model.config.is_valid.sql_conn_max_idle_time_milliseconds.app_error", nil, "", http.StatusBadRequest) + } + if *s.QueryTimeout <= 0 { return NewAppError("Config.IsValid", "model.config.is_valid.sql_query_timeout.app_error", nil, "", http.StatusBadRequest) } - if len(*s.DataSource) == 0 { + if *s.DataSource == "" { return NewAppError("Config.IsValid", "model.config.is_valid.sql_data_src.app_error", nil, "", http.StatusBadRequest) } @@ -3292,47 +3533,47 @@ func (s *LdapSettings) isValid() *AppError { func (s *SamlSettings) isValid() *AppError { if *s.Enable { - if len(*s.IdpUrl) == 0 || !IsValidHttpUrl(*s.IdpUrl) { + if *s.IdpUrl == "" || !IsValidHttpUrl(*s.IdpUrl) { return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_url.app_error", nil, "", http.StatusBadRequest) } - if len(*s.IdpDescriptorUrl) == 0 || !IsValidHttpUrl(*s.IdpDescriptorUrl) { + if *s.IdpDescriptorUrl == "" || !IsValidHttpUrl(*s.IdpDescriptorUrl) { return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_descriptor_url.app_error", nil, "", http.StatusBadRequest) } - if len(*s.IdpCertificateFile) == 0 { + if *s.IdpCertificateFile == "" { return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_cert.app_error", nil, "", http.StatusBadRequest) } - if len(*s.EmailAttribute) == 0 { + if *s.EmailAttribute == "" { return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest) } - if len(*s.UsernameAttribute) == 0 { + if *s.UsernameAttribute == "" { return NewAppError("Config.IsValid", "model.config.is_valid.saml_username_attribute.app_error", nil, "", http.StatusBadRequest) } - if len(*s.ServiceProviderIdentifier) == 0 { + if *s.ServiceProviderIdentifier == "" { return NewAppError("Config.IsValid", "model.config.is_valid.saml_spidentifier_attribute.app_error", nil, "", http.StatusBadRequest) } if *s.Verify { - if len(*s.AssertionConsumerServiceURL) == 0 || !IsValidHttpUrl(*s.AssertionConsumerServiceURL) { + if *s.AssertionConsumerServiceURL == "" || !IsValidHttpUrl(*s.AssertionConsumerServiceURL) { return NewAppError("Config.IsValid", "model.config.is_valid.saml_assertion_consumer_service_url.app_error", nil, "", http.StatusBadRequest) } } if *s.Encrypt { - if len(*s.PrivateKeyFile) == 0 { + if *s.PrivateKeyFile == "" { return NewAppError("Config.IsValid", "model.config.is_valid.saml_private_key.app_error", nil, "", http.StatusBadRequest) } - if len(*s.PublicCertificateFile) == 0 { + if *s.PublicCertificateFile == "" { return NewAppError("Config.IsValid", "model.config.is_valid.saml_public_cert.app_error", nil, "", http.StatusBadRequest) } } - if len(*s.EmailAttribute) == 0 { + if *s.EmailAttribute == "" { return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest) } @@ -3343,7 +3584,7 @@ func (s *SamlSettings) isValid() *AppError { return NewAppError("Config.IsValid", "model.config.is_valid.saml_canonical_algorithm.app_error", nil, "", http.StatusBadRequest) } - if len(*s.GuestAttribute) > 0 { + if *s.GuestAttribute != "" { if !(strings.Contains(*s.GuestAttribute, "=")) { return NewAppError("Config.IsValid", "model.config.is_valid.saml_guest_attribute.app_error", nil, "", http.StatusBadRequest) } @@ -3352,7 +3593,7 @@ func (s *SamlSettings) isValid() *AppError { } } - if len(*s.AdminAttribute) > 0 { + if *s.AdminAttribute != "" { if !(strings.Contains(*s.AdminAttribute, "=")) { return NewAppError("Config.IsValid", "model.config.is_valid.saml_admin_attribute.app_error", nil, "", http.StatusBadRequest) } @@ -3371,7 +3612,7 @@ func (s *ServiceSettings) isValid() *AppError { } if *s.ConnectionSecurity == CONN_SECURITY_TLS && !*s.UseLetsEncrypt { - appErr := NewAppError("Config.IsValid", "model.config.is_valid.tls_cert_file.app_error", nil, "", http.StatusBadRequest) + appErr := NewAppError("Config.IsValid", "model.config.is_valid.tls_cert_file_missing.app_error", nil, "", http.StatusBadRequest) if *s.TLSCertFile == "" { return appErr @@ -3379,7 +3620,7 @@ func (s *ServiceSettings) isValid() *AppError { return appErr } - appErr = NewAppError("Config.IsValid", "model.config.is_valid.tls_key_file.app_error", nil, "", http.StatusBadRequest) + appErr = NewAppError("Config.IsValid", "model.config.is_valid.tls_key_file_missing.app_error", nil, "", http.StatusBadRequest) if *s.TLSKeyFile == "" { return appErr @@ -3412,13 +3653,13 @@ func (s *ServiceSettings) isValid() *AppError { return NewAppError("Config.IsValid", "model.config.is_valid.login_attempts.app_error", nil, "", http.StatusBadRequest) } - if len(*s.SiteURL) != 0 { + if *s.SiteURL != "" { if _, err := url.ParseRequestURI(*s.SiteURL); err != nil { return NewAppError("Config.IsValid", "model.config.is_valid.site_url.app_error", nil, "", http.StatusBadRequest) } } - if len(*s.WebsocketURL) != 0 { + if *s.WebsocketURL != "" { if _, err := url.ParseRequestURI(*s.WebsocketURL); err != nil { return NewAppError("Config.IsValid", "model.config.is_valid.websocket_url.app_error", nil, "", http.StatusBadRequest) } @@ -3442,12 +3683,22 @@ func (s *ServiceSettings) isValid() *AppError { return NewAppError("Config.IsValid", "model.config.is_valid.group_unread_channels.app_error", nil, "", http.StatusBadRequest) } + if *s.CollapsedThreads != COLLAPSED_THREADS_DISABLED && !*s.ThreadAutoFollow { + return NewAppError("Config.IsValid", "model.config.is_valid.collapsed_threads.autofollow.app_error", nil, "", http.StatusBadRequest) + } + + if *s.CollapsedThreads != COLLAPSED_THREADS_DISABLED && + *s.CollapsedThreads != COLLAPSED_THREADS_DEFAULT_ON && + *s.CollapsedThreads != COLLAPSED_THREADS_DEFAULT_OFF { + return NewAppError("Config.IsValid", "model.config.is_valid.collapsed_threads.app_error", nil, "", http.StatusBadRequest) + } + return nil } func (s *ElasticsearchSettings) isValid() *AppError { if *s.EnableIndexing { - if len(*s.ConnectionUrl) == 0 { + if *s.ConnectionUrl == "" { return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.connection_url.app_error", nil, "", http.StatusBadRequest) } } @@ -3485,7 +3736,7 @@ func (s *ElasticsearchSettings) isValid() *AppError { func (bs *BleveSettings) isValid() *AppError { if *bs.EnableIndexing { - if len(*bs.IndexDir) == 0 { + if *bs.IndexDir == "" { return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.filename.app_error", nil, "", http.StatusBadRequest) } } else { @@ -3520,7 +3771,7 @@ func (s *DataRetentionSettings) isValid() *AppError { } func (s *LocalizationSettings) isValid() *AppError { - if len(*s.AvailableLocales) > 0 { + if *s.AvailableLocales != "" { if !strings.Contains(*s.AvailableLocales, *s.DefaultClientLocale) { return NewAppError("Config.IsValid", "model.config.is_valid.localization.available_locales.app_error", nil, "", http.StatusBadRequest) } @@ -3529,7 +3780,7 @@ func (s *LocalizationSettings) isValid() *AppError { return nil } -func (s *MessageExportSettings) isValid(fs FileSettings) *AppError { +func (s *MessageExportSettings) isValid() *AppError { if s.EnableExport == nil { return NewAppError("Config.IsValid", "model.config.is_valid.message_export.enable.app_error", nil, "", http.StatusBadRequest) } @@ -3615,32 +3866,36 @@ func (o *Config) GetSanitizeOptions() map[string]bool { } func (o *Config) Sanitize() { - if o.LdapSettings.BindPassword != nil && len(*o.LdapSettings.BindPassword) > 0 { + if o.LdapSettings.BindPassword != nil && *o.LdapSettings.BindPassword != "" { *o.LdapSettings.BindPassword = FAKE_SETTING } *o.FileSettings.PublicLinkSalt = FAKE_SETTING - if len(*o.FileSettings.AmazonS3SecretAccessKey) > 0 { + if *o.FileSettings.AmazonS3SecretAccessKey != "" { *o.FileSettings.AmazonS3SecretAccessKey = FAKE_SETTING } - if o.EmailSettings.SMTPPassword != nil && len(*o.EmailSettings.SMTPPassword) > 0 { + if o.EmailSettings.SMTPPassword != nil && *o.EmailSettings.SMTPPassword != "" { *o.EmailSettings.SMTPPassword = FAKE_SETTING } - if len(*o.GitLabSettings.Secret) > 0 { + if *o.GitLabSettings.Secret != "" { *o.GitLabSettings.Secret = FAKE_SETTING } - if o.GoogleSettings.Secret != nil && len(*o.GoogleSettings.Secret) > 0 { + if o.GoogleSettings.Secret != nil && *o.GoogleSettings.Secret != "" { *o.GoogleSettings.Secret = FAKE_SETTING } - if o.Office365Settings.Secret != nil && len(*o.Office365Settings.Secret) > 0 { + if o.Office365Settings.Secret != nil && *o.Office365Settings.Secret != "" { *o.Office365Settings.Secret = FAKE_SETTING } + if o.OpenIdSettings.Secret != nil && *o.OpenIdSettings.Secret != "" { + *o.OpenIdSettings.Secret = FAKE_SETTING + } + *o.SqlSettings.DataSource = FAKE_SETTING *o.SqlSettings.AtRestEncryptKey = FAKE_SETTING @@ -3654,11 +3909,11 @@ func (o *Config) Sanitize() { o.SqlSettings.DataSourceSearchReplicas[i] = FAKE_SETTING } - if o.MessageExportSettings.GlobalRelaySettings.SmtpPassword != nil && len(*o.MessageExportSettings.GlobalRelaySettings.SmtpPassword) > 0 { + if o.MessageExportSettings.GlobalRelaySettings.SmtpPassword != nil && *o.MessageExportSettings.GlobalRelaySettings.SmtpPassword != "" { *o.MessageExportSettings.GlobalRelaySettings.SmtpPassword = FAKE_SETTING } - if o.ServiceSettings.GfycatApiSecret != nil && len(*o.ServiceSettings.GfycatApiSecret) > 0 { + if o.ServiceSettings.GfycatApiSecret != nil && *o.ServiceSettings.GfycatApiSecret != "" { *o.ServiceSettings.GfycatApiSecret = FAKE_SETTING } @@ -3670,7 +3925,7 @@ func (o *Config) Sanitize() { func structToMapFilteredByTag(t interface{}, typeOfTag, filterTag string) map[string]interface{} { defer func() { if r := recover(); r != nil { - mlog.Error("Panicked in structToMapFilteredByTag. This should never happen.", mlog.Any("recover", r)) + mlog.Warn("Panicked in structToMapFilteredByTag. This should never happen.", mlog.Any("recover", r)) } }() diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/custom_status.go b/vendor/github.com/mattermost/mattermost-server/v5/model/custom_status.go new file mode 100644 index 00000000..9898ce6c --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/custom_status.go @@ -0,0 +1,141 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +import ( + "encoding/json" + "fmt" + "io" + "time" +) + +const ( + UserPropsKeyCustomStatus = "customStatus" + + CustomStatusTextMaxRunes = 100 + MaxRecentCustomStatuses = 5 + DefaultCustomStatusEmoji = "speech_balloon" +) + +var validCustomStatusDuration = map[string]bool{ + "thirty_minutes": true, + "one_hour": true, + "four_hours": true, + "today": true, + "this_week": true, + "date_and_time": true, +} + +type CustomStatus struct { + Emoji string `json:"emoji"` + Text string `json:"text"` + Duration string `json:"duration"` + ExpiresAt time.Time `json:"expires_at"` +} + +func (cs *CustomStatus) PreSave() { + if cs.Emoji == "" { + cs.Emoji = DefaultCustomStatusEmoji + } + + if cs.Duration == "" && !cs.ExpiresAt.Before(time.Now()) { + cs.Duration = "date_and_time" + } + + runes := []rune(cs.Text) + if len(runes) > CustomStatusTextMaxRunes { + cs.Text = string(runes[:CustomStatusTextMaxRunes]) + } +} + +func (cs *CustomStatus) ToJson() string { + csCopy := *cs + b, _ := json.Marshal(csCopy) + return string(b) +} + +func (cs *CustomStatus) AreDurationAndExpirationTimeValid() bool { + if cs.Duration == "" && (cs.ExpiresAt.IsZero() || !cs.ExpiresAt.Before(time.Now())) { + return true + } + + if validCustomStatusDuration[cs.Duration] && !cs.ExpiresAt.Before(time.Now()) { + return true + } + + return false +} + +func CustomStatusFromJson(data io.Reader) *CustomStatus { + var cs *CustomStatus + _ = json.NewDecoder(data).Decode(&cs) + return cs +} + +func RuneToHexadecimalString(r rune) string { + return fmt.Sprintf("%04x", r) +} + +type RecentCustomStatuses []CustomStatus + +func (rcs *RecentCustomStatuses) Contains(cs *CustomStatus) bool { + var csJSON = cs.ToJson() + + // status is empty + if cs == nil || csJSON == "" || (cs.Emoji == "" && cs.Text == "") { + return false + } + + for _, status := range *rcs { + if status.ToJson() == csJSON { + return true + } + } + + return false +} + +func (rcs *RecentCustomStatuses) Add(cs *CustomStatus) *RecentCustomStatuses { + newRCS := (*rcs)[:0] + + // if same `text` exists in existing recent custom statuses, modify existing status + for _, status := range *rcs { + if status.Text != cs.Text { + newRCS = append(newRCS, status) + } + } + newRCS = append(RecentCustomStatuses{*cs}, newRCS...) + if len(newRCS) > MaxRecentCustomStatuses { + newRCS = newRCS[:MaxRecentCustomStatuses] + } + return &newRCS +} + +func (rcs *RecentCustomStatuses) Remove(cs *CustomStatus) *RecentCustomStatuses { + var csJSON = cs.ToJson() + if csJSON == "" || (cs.Emoji == "" && cs.Text == "") { + return rcs + } + + newRCS := (*rcs)[:0] + for _, status := range *rcs { + if status.ToJson() != csJSON { + newRCS = append(newRCS, status) + } + } + + return &newRCS +} + +func (rcs *RecentCustomStatuses) ToJson() string { + rcsCopy := *rcs + b, _ := json.Marshal(rcsCopy) + return string(b) +} + +func RecentCustomStatusesFromJson(data io.Reader) *RecentCustomStatuses { + var rcs *RecentCustomStatuses + _ = json.NewDecoder(data).Decode(&rcs) + return rcs +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go b/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go index a39ff911..3f984d1b 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go @@ -8,20 +8,125 @@ import ( "io" ) -type DataRetentionPolicy struct { +type GlobalRetentionPolicy struct { MessageDeletionEnabled bool `json:"message_deletion_enabled"` FileDeletionEnabled bool `json:"file_deletion_enabled"` MessageRetentionCutoff int64 `json:"message_retention_cutoff"` FileRetentionCutoff int64 `json:"file_retention_cutoff"` } -func (me *DataRetentionPolicy) ToJson() string { - b, _ := json.Marshal(me) - return string(b) +type RetentionPolicy struct { + ID string `db:"Id" json:"id"` + DisplayName string `json:"display_name"` + PostDuration *int64 `json:"post_duration"` } -func DataRetentionPolicyFromJson(data io.Reader) *DataRetentionPolicy { - var me *DataRetentionPolicy - json.NewDecoder(data).Decode(&me) - return me +type RetentionPolicyWithTeamAndChannelIDs struct { + RetentionPolicy + TeamIDs []string `json:"team_ids"` + ChannelIDs []string `json:"channel_ids"` +} + +type RetentionPolicyWithTeamAndChannelCounts struct { + RetentionPolicy + ChannelCount int64 `json:"channel_count"` + TeamCount int64 `json:"team_count"` +} + +type RetentionPolicyChannel struct { + PolicyID string `db:"PolicyId"` + ChannelID string `db:"ChannelId"` +} + +type RetentionPolicyTeam struct { + PolicyID string `db:"PolicyId"` + TeamID string `db:"TeamId"` +} + +type RetentionPolicyWithTeamAndChannelCountsList struct { + Policies []*RetentionPolicyWithTeamAndChannelCounts `json:"policies"` + TotalCount int64 `json:"total_count"` +} + +type RetentionPolicyForTeam struct { + TeamID string `db:"Id" json:"team_id"` + PostDuration int64 `json:"post_duration"` +} + +type RetentionPolicyForTeamList struct { + Policies []*RetentionPolicyForTeam `json:"policies"` + TotalCount int64 `json:"total_count"` +} + +type RetentionPolicyForChannel struct { + ChannelID string `db:"Id" json:"channel_id"` + PostDuration int64 `json:"post_duration"` +} + +type RetentionPolicyForChannelList struct { + Policies []*RetentionPolicyForChannel `json:"policies"` + TotalCount int64 `json:"total_count"` +} + +type RetentionPolicyCursor struct { + ChannelPoliciesDone bool + TeamPoliciesDone bool + GlobalPoliciesDone bool +} + +func (rp *GlobalRetentionPolicy) ToJson() []byte { + b, _ := json.Marshal(rp) + return b +} + +func GlobalRetentionPolicyFromJson(data io.Reader) *GlobalRetentionPolicy { + var grp *GlobalRetentionPolicy + json.NewDecoder(data).Decode(&grp) + return grp +} + +func RetentionPolicyWithTeamAndChannelCountsFromJson(data io.Reader) (*RetentionPolicyWithTeamAndChannelCounts, error) { + var rp RetentionPolicyWithTeamAndChannelCounts + err := json.NewDecoder(data).Decode(&rp) + return &rp, err +} + +func (rp *RetentionPolicyWithTeamAndChannelCounts) ToJson() []byte { + b, _ := json.Marshal(rp) + return b +} + +func RetentionPolicyWithTeamAndChannelCountsListFromJson(data io.Reader) (*RetentionPolicyWithTeamAndChannelCountsList, error) { + var rpList *RetentionPolicyWithTeamAndChannelCountsList + err := json.NewDecoder(data).Decode(&rpList) + if err != nil { + return nil, err + } + return rpList, nil +} + +func (rpList *RetentionPolicyWithTeamAndChannelCountsList) ToJson() []byte { + b, _ := json.Marshal(rpList) + return b +} + +func RetentionPolicyWithTeamAndChannelIdsFromJson(data io.Reader) (*RetentionPolicyWithTeamAndChannelIDs, error) { + var rp *RetentionPolicyWithTeamAndChannelIDs + err := json.NewDecoder(data).Decode(&rp) + return rp, err +} + +func (rp *RetentionPolicyWithTeamAndChannelIDs) ToJson() []byte { + b, _ := json.Marshal(rp) + return b +} + +func (lst *RetentionPolicyForTeamList) ToJson() []byte { + b, _ := json.Marshal(lst) + return b +} + +func (lst *RetentionPolicyForChannelList) ToJson() []byte { + b, _ := json.Marshal(lst) + return b } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go index aeee9b38..f990c670 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go @@ -8,6 +8,7 @@ import ( "io" "net/http" "regexp" + "sort" ) const ( @@ -15,7 +16,9 @@ const ( EMOJI_SORT_BY_NAME = "name" ) -var EMOJI_PATTERN = regexp.MustCompile(`:[a-zA-Z0-9_-]+:`) +var EMOJI_PATTERN = regexp.MustCompile(`:[a-zA-Z0-9_+-]+:`) + +var ReverseSystemEmojisMap = makeReverseEmojiMap() type Emoji struct { Id string `json:"id"` @@ -36,6 +39,26 @@ func GetSystemEmojiId(emojiName string) (string, bool) { return id, found } +func makeReverseEmojiMap() map[string][]string { + reverseEmojiMap := make(map[string][]string) + for key, value := range SystemEmojis { + emojiNames := reverseEmojiMap[value] + emojiNames = append(emojiNames, key) + sort.Strings(emojiNames) + reverseEmojiMap[value] = emojiNames + } + + return reverseEmojiMap +} + +func GetEmojiNameFromUnicode(unicode string) (emojiName string, count int) { + if emojiNames, found := ReverseSystemEmojisMap[unicode]; found { + return emojiNames[0], len(emojiNames) + } + + return "", 0 +} + func (emoji *Emoji) IsValid() *AppError { if !IsValidId(emoji.Id) { return NewAppError("Emoji.IsValid", "model.emoji.id.app_error", nil, "", http.StatusBadRequest) @@ -57,7 +80,7 @@ func (emoji *Emoji) IsValid() *AppError { } func IsValidEmojiName(name string) *AppError { - if len(name) == 0 || len(name) > EMOJI_NAME_MAX_LENGTH || !IsValidAlphaNumHyphenUnderscore(name, false) || inSystemEmoji(name) { + if name == "" || len(name) > EMOJI_NAME_MAX_LENGTH || !IsValidAlphaNumHyphenUnderscorePlus(name) || inSystemEmoji(name) { return NewAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "", http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go index 807f6abb..849c2046 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +// This file is automatically generated via `make emojis`. Do not modify it manually. package model -var SystemEmojis = map[string]string{"policewoman": "1f46e-200d-2640-fe0f", "family_man_girl_medium_skin_tone": "1f468-1f3fd", "man_technologist": "1f468-200d-1f4bb", "family_woman_girl_medium_light_skin_tone": "1f469-1f3fc", "massage_woman_medium_light_skin_tone": "1f486-1f3fc-200d-2640-fe0f", "family_woman_woman_boy": "1f469-200d-1f469-200d-1f466", "rice_scene": "1f391", "notes": "1f3b6", "burundi": "1f1e7-1f1ee", "woman_medium_skin_tone": "1f469-1f3fd", "tipping_hand_man_medium_dark_skin_tone": "1f481-1f3fe-200d-2642-fe0f", "new_moon": "1f311", "belize": "1f1e7-1f1ff", "bhutan": "1f1e7-1f1f9", "eu": "1f1ea-1f1fa", "point_up_dark_skin_tone": "261d-1f3ff", "older_man_medium_light_skin_tone": "1f474-1f3fc", "prince": "1f934", "walking_man": "1f6b6", "telephone_receiver": "1f4de", "arrow_upper_right": "2197-fe0f", "taiwan": "1f1f9-1f1fc", "-1_light_skin_tone": "1f44e-1f3fb", "bear": "1f43b", "derelict_house": "1f3da", "blue_book": "1f4d8", "ok": "1f197", "woman_farmer_medium_light_skin_tone": "1f469-1f3fc", "man_shrugging_light_skin_tone": "1f937-1f3fb-200d-2642-fe0f", "dancing_women": "1f46f", "cd": "1f4bf", "tada": "1f389", "virgo": "264d-fe0f", "white_flower": "1f4ae", "guardswoman_medium_dark_skin_tone": "1f482-1f3fe-200d-2640-fe0f", "performing_arts": "1f3ad", "prayer_beads": "1f4ff", "congo_brazzaville": "1f1e8-1f1ec", "point_down_medium_skin_tone": "1f447-1f3fd", "raised_hand_with_fingers_splayed_light_skin_tone": "1f590-1f3fb", "man_playing_water_polo_medium_skin_tone": "1f93d-1f3fd-200d-2642-fe0f", "four_leaf_clover": "1f340", "microphone": "1f3a4", "heartpulse": "1f497", "north_korea": "1f1f0-1f1f5", "neutral_face": "1f610", "volleyball": "1f3d0", "man_playing_water_polo": "1f93d-200d-2642-fe0f", "uk": "1f1ec-1f1e7", "wallis_futuna": "1f1fc-1f1eb", "earth_africa": "1f30d", "droplet": "1f4a7", "construction_worker_man_medium_dark_skin_tone": "1f477-1f3fe-200d-2640-fe0f", "family_woman_woman_girl_boy_medium_light_skin_tone": "1f469-1f3fc", "mountain_biking_man_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2640-fe0f", "vulcan_salute_light_skin_tone": "1f596-1f3fb", "woman_shrugging_dark_skin_tone": "1f937-1f3ff-200d-2640-fe0f", "walking_man_medium_light_skin_tone": "1f6b6-1f3fc-200d-2640-fe0f", "wave": "1f44b", "framed_picture": "1f5bc", "mag": "1f50d", "fist_left": "1f91b", "building_construction": "1f3d7", "clock9": "1f558", "cayman_islands": "1f1f0-1f1fe", "laos": "1f1f1-1f1e6", "woman_playing_handball_dark_skin_tone": "1f93e-1f3ff-200d-2640-fe0f", "man_office_worker": "1f468-200d-1f4bc", "family_man_woman_girl": "1f468-200d-1f469-200d-1f467", "wilted_flower": "1f940", "books": "1f4da", "rage": "1f621", "rice_ball": "1f359", "desert": "1f3dc", "malta": "1f1f2-1f1f9", "haircut_woman_dark_skin_tone": "1f487-1f3ff-200d-2640-fe0f", "symbols": "1f523", "marshall_islands": "1f1f2-1f1ed", "sierra_leone": "1f1f8-1f1f1", "crossed_fingers_medium_dark_skin_tone": "1f91e-1f3fe", "man_judge_medium_skin_tone": "1f468-1f3fd", "bamboo": "1f38d", "keyboard": "2328-fe0f", "clock10": "1f559", "massage_man_medium_skin_tone": "1f486-1f3fd-200d-2642-fe0f", "tipping_hand_man_dark_skin_tone": "1f481-1f3ff-200d-2642-fe0f", "man_facepalming_light_skin_tone": "1f926-1f3fb-200d-2642-fe0f", "train": "1f68b", "traffic_light": "1f6a5", "vietnam": "1f1fb-1f1f3", "boy_medium_light_skin_tone": "1f466-1f3fc", "man_farmer_light_skin_tone": "1f468-1f3fb", "man_singer_medium_dark_skin_tone": "1f468-1f3fe", "woman_cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2640-fe0f", "top": "1f51d", "gb": "1f1ec-1f1e7", "mouse2": "1f401", "do_not_litter": "1f6af", "south_sudan": "1f1f8-1f1f8", "bowing_woman_light_skin_tone": "1f647-1f3fb-200d-2640-fe0f", "family_man_man_girl_girl_medium_light_skin_tone": "1f468-1f3fc", "japanese_goblin": "1f47a", "camel": "1f42b", "taurus": "2649-fe0f", "mute": "1f507", "woman_mechanic_medium_dark_skin_tone": "1f469-1f3fe", "surfer": "1f3c4", "tipping_hand_man": "1f481-200d-2642-fe0f", "family_woman_woman_boy_boy": "1f469-200d-1f469-200d-1f466-200d-1f466", "floppy_disk": "1f4be", "atm": "1f3e7", "clock230": "1f55d", "prince_light_skin_tone": "1f934-1f3fb", "name_badge": "1f4db", "octocat": "octocat", "family_woman_woman_girl_girl_dark_skin_tone": "1f469-1f3ff", "christmas_tree": "1f384", "waxing_gibbous_moon": "1f314", "mountain_cableway": "1f6a0", "woman_scientist_medium_dark_skin_tone": "1f469-1f3fe", "haircut_man_medium_dark_skin_tone": "1f487-1f3fe-200d-2642-fe0f", "basketball_woman_medium_dark_skin_tone": "26f9-1f3fe-200d-2640-fe0f", "family_man_man_boy_medium_light_skin_tone": "1f468-1f3fc", "rowing_woman_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2640-fe0f", "bowling": "1f3b3", "shinto_shrine": "26e9", "round_pushpin": "1f4cd", "cyprus": "1f1e8-1f1fe", "open_hands_dark_skin_tone": "1f450-1f3ff", "clap_medium_skin_tone": "1f44f-1f3fd", "bath_medium_dark_skin_tone": "1f6c0-1f3fe", "briefcase": "1f4bc", "tiger": "1f42f", "morocco": "1f1f2-1f1e6", "open_hands_light_skin_tone": "1f450-1f3fb", "hand_light_skin_tone": "270b-1f3fb", "weight_lifting_man_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2640-fe0f", "mans_shoe": "1f45e", "poland": "1f1f5-1f1f1", "raised_hands_medium_skin_tone": "1f64c-1f3fd", "family_man_woman_girl_boy_light_skin_tone": "1f468-1f3fb", "woman_playing_handball_medium_skin_tone": "1f93e-1f3fd-200d-2640-fe0f", "office": "1f3e2", "woman_singer_medium_dark_skin_tone": "1f469-1f3fe", "family_woman_woman_boy_boy_medium_light_skin_tone": "1f469-1f3fc", "scorpion": "1f982", "tomato": "1f345", "goal_net": "1f945", "chad": "1f1f9-1f1e9", "family_man_woman_girl_boy_medium_skin_tone": "1f468-1f3fd", "mountain_biking_man_light_skin_tone": "1f6b5-1f3fb-200d-2640-fe0f", "weight_lifting_man_dark_skin_tone": "1f3cb-1f3ff-200d-2640-fe0f", "eyeglasses": "1f453", "golfing_woman": "1f3cc-fe0f-200d-2640-fe0f", "dvd": "1f4c0", "clipboard": "1f4cb", "ireland": "1f1ee-1f1ea", "woman_student_dark_skin_tone": "1f469-1f3ff", "angry": "1f620", "baby": "1f476", "women_wrestling": "1f93c-200d-2640-fe0f", "black_square_button": "1f532", "male_detective_medium_light_skin_tone": "1f575-1f3fc-200d-2640-fe0f", "dancer_dark_skin_tone": "1f483-1f3ff", "id": "1f194", "vibration_mode": "1f4f3", "handshake": "1f91d", "tiger2": "1f405", "leaves": "1f343", "baseball": "26be-fe0f", "golf": "26f3-fe0f", "toilet": "1f6bd", "male_detective_dark_skin_tone": "1f575-1f3ff-200d-2640-fe0f", "family_woman_boy": "1f469-200d-1f466", "duck": "1f986", "writing_hand_medium_dark_skin_tone": "270d-1f3fe", "woman_singer_medium_light_skin_tone": "1f469-1f3fc", "man_teacher_medium_skin_tone": "1f468-1f3fd", "lips": "1f444", "octopus": "1f419", "policeman_medium_dark_skin_tone": "1f46e-1f3fe-200d-2640-fe0f", "man_factory_worker_dark_skin_tone": "1f468-1f3ff", "man_astronaut_light_skin_tone": "1f468-1f3fb", "ok_man_dark_skin_tone": "1f646-1f3ff-200d-2642-fe0f", "couple_with_heart": "1f491", "pray_medium_skin_tone": "1f64f-1f3fd", "woman_health_worker_light_skin_tone": "1f469-1f3fb", "tipping_hand_woman_medium_light_skin_tone": "1f481-1f3fc-200d-2640-fe0f", "no_good_woman_dark_skin_tone": "1f645-1f3ff-200d-2640-fe0f", "no_good_woman_medium_dark_skin_tone": "1f645-1f3fe-200d-2640-fe0f", "thumbsdown": "1f44e", "fist": "270a", "camera_flash": "1f4f8", "azerbaijan": "1f1e6-1f1ff", "woman_with_turban_medium_light_skin_tone": "1f473-1f3fc-200d-2640-fe0f", "man_singer_medium_skin_tone": "1f468-1f3fd", "mali": "1f1f2-1f1f1", "blonde_woman_medium_dark_skin_tone": "1f471-1f3fe-200d-2640-fe0f", "family_man_man_girl_light_skin_tone": "1f468-1f3fb", "biking_woman_medium_skin_tone": "1f6b4-1f3fd-200d-2640-fe0f", "crab": "1f980", "green_salad": "1f957", "men_wrestling": "1f93c-200d-2642-fe0f", "-1_medium_dark_skin_tone": "1f44e-1f3fe", "baby_dark_skin_tone": "1f476-1f3ff", "surfing_woman_light_skin_tone": "1f3c4-1f3fb-200d-2640-fe0f", "stuck_out_tongue_winking_eye": "1f61c", "plate_with_cutlery": "1f37d", "swimmer": "1f3ca", "blonde_woman_medium_light_skin_tone": "1f471-1f3fc-200d-2640-fe0f", "curly_loop": "27b0", "india": "1f1ee-1f1f3", "norfolk_island": "1f1f3-1f1eb", "mountain_biking_woman_dark_skin_tone": "1f6b5-1f3ff-200d-2640-fe0f", "ghost": "1f47b", "boar": "1f417", "railway_track": "1f6e4", "100": "1f4af", "metal_medium_dark_skin_tone": "1f918-1f3fe", "woman_playing_handball_light_skin_tone": "1f93e-1f3fb-200d-2640-fe0f", "barber": "1f488", "clock730": "1f562", "equatorial_guinea": "1f1ec-1f1f6", "maldives": "1f1f2-1f1fb", "weight_lifting_woman_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2640-fe0f", "eagle": "1f985", "tea": "1f375", "tanabata_tree": "1f38b", "night_with_stars": "1f303", "balloon": "1f388", "on": "1f51b", "lizard": "1f98e", "beer": "1f37a", "part_alternation_mark": "303d-fe0f", "white_square_button": "1f533", "clock430": "1f55f", "gibraltar": "1f1ec-1f1ee", "massage_woman_medium_skin_tone": "1f486-1f3fd-200d-2640-fe0f", "sweat": "1f613", "athletic_shoe": "1f45f", "joystick": "1f579", "biohazard": "2623-fe0f", "muscle_medium_light_skin_tone": "1f4aa-1f3fc", "bride_with_veil_medium_light_skin_tone": "1f470-1f3fc", "parasol_on_ground": "26f1", "costa_rica": "1f1e8-1f1f7", "woman_student_light_skin_tone": "1f469-1f3fb", "massage_woman_medium_dark_skin_tone": "1f486-1f3fe-200d-2640-fe0f", "surfing_woman_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2640-fe0f", "rowing_woman": "1f6a3-200d-2640-fe0f", "guardsman_light_skin_tone": "1f482-1f3fb-200d-2640-fe0f", "construction_worker_man_light_skin_tone": "1f477-1f3fb-200d-2640-fe0f", "family_woman_boy_boy": "1f469-200d-1f466-200d-1f466", "small_airplane": "1f6e9", "baggage_claim": "1f6c4", "bosnia_herzegovina": "1f1e7-1f1e6", "falkland_islands": "1f1eb-1f1f0", "crossed_fingers_medium_light_skin_tone": "1f91e-1f3fc", "man_scientist_medium_light_skin_tone": "1f468-1f3fc", "family_woman_girl_boy_medium_skin_tone": "1f469-1f3fd", "satisfied": "1f606", "u5408": "1f234", "cn": "1f1e8-1f1f3", "isle_of_man": "1f1ee-1f1f2", "fist_raised_medium_light_skin_tone": "270a-1f3fc", "family_man_woman_girl_dark_skin_tone": "1f468-1f3ff", "family_woman_girl_dark_skin_tone": "1f469-1f3ff", "family_man_boy_medium_skin_tone": "1f468-1f3fd", "money_mouth_face": "1f911", "syringe": "1f489", "hand_medium_light_skin_tone": "270b-1f3fc", "writing_hand_medium_skin_tone": "270d-1f3fd", "man_farmer_medium_light_skin_tone": "1f468-1f3fc", "woman_artist_dark_skin_tone": "1f469-1f3ff", "tickets": "1f39f", "man_cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2642-fe0f", "squid": "1f991", "fish": "1f41f", "memo": "1f4dd", "eye_speech_bubble": "1f441-200d-1f5e8", "+1_light_skin_tone": "1f44d-1f3fb", "tulip": "1f337", "blossom": "1f33c", "family_woman_woman_girl_medium_dark_skin_tone": "1f469-1f3fe", "triumph": "1f624", "rooster": "1f413", "ng": "1f196", "blonde_man_medium_light_skin_tone": "1f471-1f3fc-200d-2640-fe0f", "policeman_light_skin_tone": "1f46e-1f3fb-200d-2640-fe0f", "woman_cook_dark_skin_tone": "1f469-1f3ff", "pray_dark_skin_tone": "1f64f-1f3ff", "point_up_2_medium_skin_tone": "1f446-1f3fd", "busts_in_silhouette": "1f465", "tornado": "1f32a", "woman_juggling": "1f939-200d-2640-fe0f", "cupid": "1f498", "white_check_mark": "2705", "aruba": "1f1e6-1f1fc", "family_man_boy_boy_medium_dark_skin_tone": "1f468-1f3fe", "woman_cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2640-fe0f", "woman_playing_water_polo_dark_skin_tone": "1f93d-1f3ff-200d-2640-fe0f", "relaxed": "263a-fe0f", "birthday": "1f382", "high_brightness": "1f506", "couple_with_heart_woman_woman_medium_light_skin_tone": "1f469-1f3fc", "biking_man_dark_skin_tone": "1f6b4-1f3ff-200d-2640-fe0f", "disappointed_relieved": "1f625", "canary_islands": "1f1ee-1f1e8", "st_pierre_miquelon": "1f1f5-1f1f2", "trinidad_tobago": "1f1f9-1f1f9", "turkmenistan": "1f1f9-1f1f2", "pouting_woman_medium_skin_tone": "1f64e-1f3fd-200d-2640-fe0f", "man_student_dark_skin_tone": "1f468-1f3ff", "princess_dark_skin_tone": "1f478-1f3ff", "family_woman_boy_boy_medium_skin_tone": "1f469-1f3fd", "old_key": "1f5dd", "muscle_medium_skin_tone": "1f4aa-1f3fd", "ear_medium_dark_skin_tone": "1f442-1f3fe", "girl_medium_dark_skin_tone": "1f467-1f3fe", "man_pilot_dark_skin_tone": "1f468-1f3ff", "wolf": "1f43a", "gem": "1f48e", "arrow_double_up": "23eb", "woman_factory_worker_light_skin_tone": "1f469-1f3fb", "woman_mechanic_medium_skin_tone": "1f469-1f3fd", "woman_firefighter_light_skin_tone": "1f469-1f3fb", "sunglasses": "1f60e", "snake": "1f40d", "pen": "1f58a", "nose_medium_skin_tone": "1f443-1f3fd", "weight_lifting_man": "1f3cb-fe0f", "alarm_clock": "23f0", "golfing_woman_medium_light_skin_tone": "1f3cc-1f3fc-200d-2640-fe0f", "vulcan_salute": "1f596", "earth_asia": "1f30f", "+1_dark_skin_tone": "1f44d-1f3ff", "family_woman_boy_medium_dark_skin_tone": "1f469-1f3fe", "family_woman_girl_girl_light_skin_tone": "1f469-1f3fb", "weight_lifting_man_medium_light_skin_tone": "1f3cb-1f3fc-200d-2640-fe0f", "angel": "1f47c", "peach": "1f351", "truck": "1f69a", "tajikistan": "1f1f9-1f1ef", "tr": "1f1f9-1f1f7", "running_woman_medium_skin_tone": "1f3c3-1f3fd-200d-2640-fe0f", "wrench": "1f527", "black_flag": "1f3f4", "cape_verde": "1f1e8-1f1fb", "man_technologist_medium_light_skin_tone": "1f468-1f3fc", "mountain_biking_woman_medium_light_skin_tone": "1f6b5-1f3fc-200d-2640-fe0f", "man_astronaut_medium_skin_tone": "1f468-1f3fd", "man_in_tuxedo_medium_light_skin_tone": "1f935-1f3fc", "see_no_evil": "1f648", "egg": "1f95a", "1234": "1f522", "lesotho": "1f1f1-1f1f8", "middle_finger_medium_skin_tone": "1f595-1f3fd", "woman_health_worker_medium_light_skin_tone": "1f469-1f3fc", "sneezing_face": "1f927", "man_cook": "1f468-200d-1f373", "mortar_board": "1f393", "candle": "1f56f", "basketball_man_medium_skin_tone": "26f9-1f3fd-200d-2640-fe0f", "ferris_wheel": "1f3a1", "martinique": "1f1f2-1f1f6", "st_vincent_grenadines": "1f1fb-1f1e8", "yemen": "1f1fe-1f1ea", "pray_light_skin_tone": "1f64f-1f3fb", "man_in_tuxedo_medium_skin_tone": "1f935-1f3fd", "woman_pilot_medium_dark_skin_tone": "1f469-1f3fe", "pregnant_woman_dark_skin_tone": "1f930-1f3ff", "fu": "1f595", "haircut": "1f487", "boxing_glove": "1f94a", "page_with_curl": "1f4c3", "muscle_light_skin_tone": "1f4aa-1f3fb", "woman_firefighter_dark_skin_tone": "1f469-1f3ff", "ok_woman_light_skin_tone": "1f646-1f3fb-200d-2640-fe0f", "family_man_woman_boy_boy_medium_light_skin_tone": "1f468-1f3fc", "family_woman_boy_dark_skin_tone": "1f469-1f3ff", "weight_lifting_man_light_skin_tone": "1f3cb-1f3fb-200d-2640-fe0f", "blonde_man": "1f471", "woman_technologist": "1f469-200d-1f4bb", "boom": "1f4a5", "1st_place_medal": "1f947", "nine": "0039-fe0f-20e3", "czech_republic": "1f1e8-1f1ff", "meat_on_bone": "1f356", "hamburger": "1f354", "video_game": "1f3ae", "clock2": "1f551", "woman_facepalming_dark_skin_tone": "1f926-1f3ff-200d-2640-fe0f", "couplekiss_man_man_medium_dark_skin_tone": "1f468-1f3fe", "arrow_lower_right": "2198-fe0f", "haircut_woman_light_skin_tone": "1f487-1f3fb-200d-2640-fe0f", "woman_dark_skin_tone": "1f469-1f3ff", "older_man_light_skin_tone": "1f474-1f3fb", "first_quarter_moon_with_face": "1f31b", "fries": "1f35f", "restroom": "1f6bb", "zero": "0030-fe0f-20e3", "fr": "1f1eb-1f1f7", "kuwait": "1f1f0-1f1fc", "man_health_worker_medium_skin_tone": "1f468-1f3fd", "woman_judge_light_skin_tone": "1f469-1f3fb", "man_judge_dark_skin_tone": "1f468-1f3ff", "ok_woman_medium_skin_tone": "1f646-1f3fd-200d-2640-fe0f", "bike": "1f6b2", "registered": "00ae-fe0f", "blonde_woman_medium_skin_tone": "1f471-1f3fd-200d-2640-fe0f", "stuck_out_tongue_closed_eyes": "1f61d", "collision": "1f4a5", "wheelchair": "267f-fe0f", "black_circle": "26ab-fe0f", "point_up_2_light_skin_tone": "1f446-1f3fb", "older_man": "1f474", "suspension_railway": "1f69f", "libra": "264e-fe0f", "crossed_flags": "1f38c", "man_cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2642-fe0f", "man_playing_water_polo_dark_skin_tone": "1f93d-1f3ff-200d-2642-fe0f", "scream": "1f631", "no_good_man": "1f645-200d-2642-fe0f", "timer_clock": "23f2", "venezuela": "1f1fb-1f1ea", "raised_back_of_hand_light_skin_tone": "1f91a-1f3fb", "woman_technologist_medium_skin_tone": "1f469-1f3fd", "popcorn": "1f37f", "romania": "1f1f7-1f1f4", "togo": "1f1f9-1f1ec", "writing_hand_dark_skin_tone": "270d-1f3ff", "woman_singer_dark_skin_tone": "1f469-1f3ff", "pouting_woman_medium_dark_skin_tone": "1f64e-1f3fe-200d-2640-fe0f", "man_health_worker_light_skin_tone": "1f468-1f3fb", "dancer_medium_light_skin_tone": "1f483-1f3fc", "phone": "260e-fe0f", "chart": "1f4b9", "repeat": "1f501", "mahjong": "1f004-fe0f", "liberia": "1f1f1-1f1f7", "rage3": "rage3", "person_frowning": "1f64d", "open_hands_medium_skin_tone": "1f450-1f3fd", "man_dark_skin_tone": "1f468-1f3ff", "man_factory_worker_medium_light_skin_tone": "1f468-1f3fc", "man_astronaut_medium_light_skin_tone": "1f468-1f3fc", "ring": "1f48d", "ok_hand_medium_skin_tone": "1f44c-1f3fd", "santa": "1f385", "beach_umbrella": "1f3d6", "finland": "1f1eb-1f1ee", "woman_facepalming_medium_skin_tone": "1f926-1f3fd-200d-2640-fe0f", "woman_shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2640-fe0f", "sunflower": "1f33b", "ok_hand_dark_skin_tone": "1f44c-1f3ff", "santa_medium_skin_tone": "1f385-1f3fd", "call_me_hand_medium_skin_tone": "1f919-1f3fd", "man_firefighter_light_skin_tone": "1f468-1f3fb", "kiss": "1f48b", "mandarin": "1f34a", "dollar": "1f4b5", "clock3": "1f552", "argentina": "1f1e6-1f1f7", "fist_left_light_skin_tone": "1f91b-1f3fb", "santa_light_skin_tone": "1f385-1f3fb", "family_man_girl_boy_medium_light_skin_tone": "1f468-1f3fc", "sushi": "1f363", "rice": "1f35a", "mailbox_with_mail": "1f4ec", "woman_cook_medium_dark_skin_tone": "1f469-1f3fe", "family_man_woman_girl_girl_medium_dark_skin_tone": "1f468-1f3fe", "straight_ruler": "1f4cf", "blue_heart": "1f499", "slightly_frowning_face": "1f641", "crossed_fingers": "1f91e", "seedling": "1f331", "herb": "1f33f", "medal_military": "1f396", "camping": "1f3d5", "arrow_backward": "25c0-fe0f", "heavy_multiplication_x": "2716-fe0f", "icecream": "1f366", "heavy_dollar_sign": "1f4b2", "frowning_woman_dark_skin_tone": "1f64d-1f3ff-200d-2640-fe0f", "family_man_woman_boy_boy_medium_dark_skin_tone": "1f468-1f3fe", "brazil": "1f1e7-1f1f7", "fist_right_medium_light_skin_tone": "1f91c-1f3fc", "man_scientist_medium_dark_skin_tone": "1f468-1f3fe", "family_woman_girl_light_skin_tone": "1f469-1f3fb", "swimming_man_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2640-fe0f", "man": "1f468", "lemon": "1f34b", "japanese_castle": "1f3ef", "cinema": "1f3a6", "wave_light_skin_tone": "1f44b-1f3fb", "middle_finger_medium_light_skin_tone": "1f595-1f3fc", "five": "0035-fe0f-20e3", "boy_medium_dark_skin_tone": "1f466-1f3fe", "woman_technologist_dark_skin_tone": "1f469-1f3ff", "man_playing_handball_light_skin_tone": "1f93e-1f3fb-200d-2642-fe0f", "construction_worker_man": "1f477", "stadium": "1f3df", "biking_woman_dark_skin_tone": "1f6b4-1f3ff-200d-2640-fe0f", "trophy": "1f3c6", "arrow_left": "2b05-fe0f", "boy_dark_skin_tone": "1f466-1f3ff", "no_good_woman_light_skin_tone": "1f645-1f3fb-200d-2640-fe0f", "skull_and_crossbones": "2620-fe0f", "couple_with_heart_woman_woman": "1f469-200d-2764-fe0f-200d-1f469", "no_bicycles": "1f6b3", "bell": "1f514", "feelsgood": "feelsgood", "bowing_man_dark_skin_tone": "1f647-1f3ff-200d-2640-fe0f", "mouse": "1f42d", "anchor": "2693-fe0f", "cyclone": "1f300", "solomon_islands": "1f1f8-1f1e7", "basketball": "1f3c0", "notebook_with_decorative_cover": "1f4d4", "family_man_girl_girl_dark_skin_tone": "1f468-1f3ff", "singapore": "1f1f8-1f1ec", "golfing_man_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2640-fe0f", "woman": "1f469", "fried_shrimp": "1f364", "construction": "1f6a7", "eight_pointed_black_star": "2734-fe0f", "black_joker": "1f0cf", "cambodia": "1f1f0-1f1ed", "mount_fuji": "1f5fb", "link": "1f517", "womens": "1f6ba", "family_man_man_boy_boy_medium_skin_tone": "1f468-1f3fd", "joy": "1f602", "crying_cat_face": "1f63f", "parking": "1f17f-fe0f", "barbados": "1f1e7-1f1e7", "bowing_woman_dark_skin_tone": "1f647-1f3ff-200d-2640-fe0f", "angel_medium_light_skin_tone": "1f47c-1f3fc", "waning_gibbous_moon": "1f316", "synagogue": "1f54d", "american_samoa": "1f1e6-1f1f8", "basketball_woman_medium_light_skin_tone": "26f9-1f3fc-200d-2640-fe0f", "bug": "1f41b", "woman_farmer_light_skin_tone": "1f469-1f3fb", "door": "1f6aa", "place_of_worship": "1f6d0", "eight_spoked_asterisk": "2733-fe0f", "mrs_claus_dark_skin_tone": "1f936-1f3ff", "u7a7a": "1f233", "man_astronaut_medium_dark_skin_tone": "1f468-1f3fe", "jack_o_lantern": "1f383", "lock_with_ink_pen": "1f50f", "male_detective_medium_skin_tone": "1f575-1f3fd-200d-2640-fe0f", "woman_firefighter_medium_dark_skin_tone": "1f469-1f3fe", "smiling_imp": "1f608", "tv": "1f4fa", "pouting_man": "1f64e-200d-2642-fe0f", "e-mail": "1f4e7", "package": "1f4e6", "clock130": "1f55c", "family_man_boy_light_skin_tone": "1f468-1f3fb", "cat2": "1f408", "mountain_biking_woman_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2640-fe0f", "nauseated_face": "1f922", "fountain": "26f2-fe0f", "middle_finger": "1f595", "dancers": "1f46f", "cactus": "1f335", "man_student_light_skin_tone": "1f468-1f3fb", "family_man_man_girl_dark_skin_tone": "1f468-1f3ff", "family_man_girl_girl_medium_skin_tone": "1f468-1f3fd", "us_virgin_islands": "1f1fb-1f1ee", "woman_astronaut_medium_dark_skin_tone": "1f469-1f3fe", "honeybee": "1f41d", "bouquet": "1f490", "golfing_man": "1f3cc-fe0f", "u7981": "1f232", "french_guiana": "1f1ec-1f1eb", "kenya": "1f1f0-1f1ea", "melon": "1f348", "nicaragua": "1f1f3-1f1ee", "raised_hand_with_fingers_splayed_medium_light_skin_tone": "1f590-1f3fc", "bath_light_skin_tone": "1f6c0-1f3fb", "man_pilot_medium_light_skin_tone": "1f468-1f3fc", "european_post_office": "1f3e4", "mobile_phone_off": "1f4f4", "no_smoking": "1f6ad", "family_woman_girl_girl_medium_light_skin_tone": "1f469-1f3fc", "family_woman_girl_medium_dark_skin_tone": "1f469-1f3fe", "man_juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2642-fe0f", "expressionless": "1f611", "school_satchel": "1f392", "film_strip": "1f39e", "running_man_light_skin_tone": "1f3c3-1f3fb-200d-2640-fe0f", "family_man_woman_girl_medium_dark_skin_tone": "1f468-1f3fe", "family_woman_woman_boy_boy_light_skin_tone": "1f469-1f3fb", "smiley_cat": "1f63a", "chestnut": "1f330", "girl_dark_skin_tone": "1f467-1f3ff", "bride_with_veil_medium_dark_skin_tone": "1f470-1f3fe", "family_man_man_boy_boy_light_skin_tone": "1f468-1f3fb", "family_man_boy_boy_medium_light_skin_tone": "1f468-1f3fc", "wink": "1f609", "carrot": "1f955", "credit_card": "1f4b3", "triangular_ruler": "1f4d0", "question": "2753", "+1_medium_dark_skin_tone": "1f44d-1f3fe", "man_teacher_medium_dark_skin_tone": "1f468-1f3fe", "family_man_girl_girl_medium_light_skin_tone": "1f468-1f3fc", "kimono": "1f458", "bellhop_bell": "1f6ce", "red_circle": "1f534", "call_me_hand_light_skin_tone": "1f919-1f3fb", "nail_care_medium_skin_tone": "1f485-1f3fd", "woman_teacher_medium_skin_tone": "1f469-1f3fd", "woman_juggling_dark_skin_tone": "1f939-1f3ff-200d-2640-fe0f", "runner": "1f3c3", "heavy_check_mark": "2714-fe0f", "family_man_girl_girl_medium_dark_skin_tone": "1f468-1f3fe", "tent": "26fa-fe0f", "card_index_dividers": "1f5c2", "man_singer_dark_skin_tone": "1f468-1f3ff", "man_firefighter_medium_dark_skin_tone": "1f468-1f3fe", "man_playing_handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2642-fe0f", "female_detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2640-fe0f", "metal": "1f918", "dark_sunglasses": "1f576", "vertical_traffic_light": "1f6a6", "four": "0034-fe0f-20e3", "wavy_dash": "3030-fe0f", "ear_medium_light_skin_tone": "1f442-1f3fc", "man_juggling_dark_skin_tone": "1f939-1f3ff-200d-2642-fe0f", "kissing_heart": "1f618", "sweet_potato": "1f360", "gift_heart": "1f49d", "man_technologist_light_skin_tone": "1f468-1f3fb", "prince_medium_dark_skin_tone": "1f934-1f3fe", "ok_man_medium_skin_tone": "1f646-1f3fd-200d-2642-fe0f", "womans_clothes": "1f45a", "roller_coaster": "1f3a2", "woman_student_medium_light_skin_tone": "1f469-1f3fc", "zipper_mouth_face": "1f910", "person_with_blond_hair": "1f471", "leftwards_arrow_with_hook": "21a9-fe0f", "white_circle": "26aa-fe0f", "afghanistan": "1f1e6-1f1eb", "face_with_thermometer": "1f912", "bow": "1f647", "kr": "1f1f0-1f1f7", "finnadie": "finnadie", "girl_light_skin_tone": "1f467-1f3fb", "woman_farmer_medium_skin_tone": "1f469-1f3fd", "umbrella": "2614-fe0f", "ice_cream": "1f368", "point_down_medium_light_skin_tone": "1f447-1f3fc", "woman_health_worker_dark_skin_tone": "1f469-1f3ff", "rowing_woman_medium_light_skin_tone": "1f6a3-1f3fc-200d-2640-fe0f", "money_with_wings": "1f4b8", "dolls": "1f38e", "surfing_man_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2640-fe0f", "mrs_claus_medium_skin_tone": "1f936-1f3fd", "basketball_man_dark_skin_tone": "26f9-1f3ff-200d-2640-fe0f", "dragon_face": "1f432", "woman_cartwheeling": "1f938-200d-2640-fe0f", "aquarius": "2652-fe0f", "sos": "1f198", "clock1230": "1f567", "haiti": "1f1ed-1f1f9", "woman_facepalming": "1f926-200d-2640-fe0f", "clinking_glasses": "1f942", "trollface": "trollface", "mrs_claus_light_skin_tone": "1f936-1f3fb", "clap": "1f44f", "couplekiss_man_man": "1f468-200d-2764-fe0f-200d-1f48b-200d-1f468", "page_facing_up": "1f4c4", "belgium": "1f1e7-1f1ea", "curacao": "1f1e8-1f1fc", "family_woman_woman_boy_dark_skin_tone": "1f469-1f3ff", "two_men_holding_hands": "1f46c", "mountain_snow": "1f3d4", "wind_chime": "1f390", "person_with_pouting_face": "1f64e", "cityscape": "1f3d9", "bride_with_veil_dark_skin_tone": "1f470-1f3ff", "frowning_woman_light_skin_tone": "1f64d-1f3fb-200d-2640-fe0f", "bath_medium_light_skin_tone": "1f6c0-1f3fc", "sheep": "1f411", "sparkler": "1f387", "frowning_woman": "1f64d", "rat": "1f400", "custard": "1f36e", "video_camera": "1f4f9", "open_umbrella": "2602-fe0f", "man_with_turban_medium_light_skin_tone": "1f473-1f3fc-200d-2640-fe0f", "woman_student_medium_dark_skin_tone": "1f469-1f3fe", "ok_woman_medium_light_skin_tone": "1f646-1f3fc-200d-2640-fe0f", "swimming_man_dark_skin_tone": "1f3ca-1f3ff-200d-2640-fe0f", "man_cook_light_skin_tone": "1f468-1f3fb", "running_woman_light_skin_tone": "1f3c3-1f3fb-200d-2640-fe0f", "rabbit": "1f430", "ox": "1f402", "corn": "1f33d", "mozambique": "1f1f2-1f1ff", "point_right_light_skin_tone": "1f449-1f3fb", "nail_care_light_skin_tone": "1f485-1f3fb", "smiley": "1f603", "new_moon_with_face": "1f31a", "croatia": "1f1ed-1f1f7", "man_judge_medium_dark_skin_tone": "1f468-1f3fe", "fist_raised": "270a", "man_astronaut": "1f468-200d-1f680", "clock1130": "1f566", "st_lucia": "1f1f1-1f1e8", "princess": "1f478", "fist_left_medium_light_skin_tone": "1f91b-1f3fc", "point_left_medium_dark_skin_tone": "1f448-1f3fe", "woman_factory_worker_medium_skin_tone": "1f469-1f3fd", "angel_dark_skin_tone": "1f47c-1f3ff", "woman_cook": "1f469-200d-1f373", "koala": "1f428", "satellite": "1f4e1", "book": "1f4d6", "large_orange_diamond": "1f536", "monaco": "1f1f2-1f1e8", "spiral_notepad": "1f5d2", "capricorn": "2651-fe0f", "bacon": "1f953", "blonde_man_medium_dark_skin_tone": "1f471-1f3fe-200d-2640-fe0f", "business_suit_levitating_dark_skin_tone": "1f574-1f3ff", "call_me_hand_medium_light_skin_tone": "1f919-1f3fc", "female_detective_medium_light_skin_tone": "1f575-1f3fc-200d-2640-fe0f", "haircut_woman_medium_light_skin_tone": "1f487-1f3fc-200d-2640-fe0f", "alien": "1f47d", "baguette_bread": "1f956", "northern_mariana_islands": "1f1f2-1f1f5", "ukraine": "1f1fa-1f1e6", "flushed": "1f633", "man_scientist": "1f468-200d-1f52c", "trident": "1f531", "family_woman_woman_girl_boy_medium_skin_tone": "1f469-1f3fd", "family_man_boy_boy": "1f468-200d-1f466-200d-1f466", "tennis": "1f3be", "fire_engine": "1f692", "pushpin": "1f4cc", "man_health_worker_medium_dark_skin_tone": "1f468-1f3fe", "boy": "1f466", "headphones": "1f3a7", "fuelpump": "26fd-fe0f", "u6709": "1f236", "man_cook_medium_skin_tone": "1f468-1f3fd", "bride_with_veil_medium_skin_tone": "1f470-1f3fd", "point_up": "261d-fe0f", "necktie": "1f454", "control_knobs": "1f39b", "austria": "1f1e6-1f1f9", "papua_new_guinea": "1f1f5-1f1ec", "alembic": "2697-fe0f", "cook_islands": "1f1e8-1f1f0", "iceland": "1f1ee-1f1f8", "car": "1f697", "potable_water": "1f6b0", "haircut_man_medium_light_skin_tone": "1f487-1f3fc-200d-2642-fe0f", "couplekiss_woman_woman_medium_light_skin_tone": "1f469-1f3fc", "couplekiss_man_man_medium_skin_tone": "1f468-1f3fd", "cookie": "1f36a", "flight_departure": "1f6eb", "muscle_dark_skin_tone": "1f4aa-1f3ff", "construction_worker_man_medium_skin_tone": "1f477-1f3fd-200d-2640-fe0f", "black_medium_small_square": "25fe-fe0f", "guyana": "1f1ec-1f1fe", "file_folder": "1f4c1", "fountain_pen": "1f58b", "construction_worker_woman_medium_skin_tone": "1f477-1f3fd-200d-2640-fe0f", "family_man_woman_girl_boy_medium_light_skin_tone": "1f468-1f3fc", "poultry_leg": "1f357", "ski": "1f3bf", "guardswoman_medium_skin_tone": "1f482-1f3fd-200d-2640-fe0f", "family_man_man_girl_medium_dark_skin_tone": "1f468-1f3fe", "family_woman_boy_light_skin_tone": "1f469-1f3fb", "trumpet": "1f3ba", "no_pedestrians": "1f6b7", "heavy_minus_sign": "2796", "fist_oncoming": "1f44a", "ambulance": "1f691", "man_artist_dark_skin_tone": "1f468-1f3ff", "drum": "1f941", "train2": "1f686", "u7121": "1f21a-fe0f", "burkina_faso": "1f1e7-1f1eb", "nose_light_skin_tone": "1f443-1f3fb", "policewoman_medium_dark_skin_tone": "1f46e-1f3fe-200d-2640-fe0f", "lantern": "1f3ee", "metal_light_skin_tone": "1f918-1f3fb", "male_detective_light_skin_tone": "1f575-1f3fb-200d-2640-fe0f", "woman_juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2640-fe0f", "rowing_man_light_skin_tone": "1f6a3-1f3fb-200d-2640-fe0f", "lying_face": "1f925", "point_left": "1f448", "rosette": "1f3f5", "houses": "1f3d8", "repeat_one": "1f502", "liechtenstein": "1f1f1-1f1ee", "cloud_with_lightning": "1f329", "man_cartwheeling": "1f938-200d-2642-fe0f", "pause_button": "23f8", "arrows_clockwise": "1f503", "raised_hand_with_fingers_splayed_dark_skin_tone": "1f590-1f3ff", "clap_dark_skin_tone": "1f44f-1f3ff", "raising_hand_man_medium_skin_tone": "1f64b-1f3fd-200d-2642-fe0f", "family_woman_woman_girl_girl_medium_dark_skin_tone": "1f469-1f3fe", "dog": "1f436", "pouting_man_medium_dark_skin_tone": "1f64e-1f3fe-200d-2642-fe0f", "surfing_woman_medium_skin_tone": "1f3c4-1f3fd-200d-2640-fe0f", "confused": "1f615", "detective": "1f575-fe0f", "studio_microphone": "1f399", "fist_oncoming_medium_light_skin_tone": "1f44a-1f3fc", "man_firefighter_medium_skin_tone": "1f468-1f3fd", "tshirt": "1f455", "trolleybus": "1f68e", "norway": "1f1f3-1f1f4", "neckbeard": "neckbeard", "three": "0033-fe0f-20e3", "point_right_medium_skin_tone": "1f449-1f3fd", "man_medium_dark_skin_tone": "1f468-1f3fe", "pouting_man_medium_light_skin_tone": "1f64e-1f3fc-200d-2642-fe0f", "clock630": "1f561", "fist_raised_medium_skin_tone": "270a-1f3fd", "anguished": "1f627", "eye": "1f441", "bride_with_veil": "1f470", "hear_no_evil": "1f649", "wine_glass": "1f377", "soon": "1f51c", "family_man_boy_boy_light_skin_tone": "1f468-1f3fb", "family_woman_boy_boy_medium_light_skin_tone": "1f469-1f3fc", "dromedary_camel": "1f42a", "chipmunk": "1f43f", "soccer": "26bd-fe0f", "man_with_gua_pi_mao_medium_light_skin_tone": "1f472-1f3fc", "business_suit_levitating_medium_light_skin_tone": "1f574-1f3fc", "running_woman_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2640-fe0f", "speaking_head": "1f5e3", "menorah": "1f54e", "non-potable_water": "1f6b1", "woman_with_turban_dark_skin_tone": "1f473-1f3ff-200d-2640-fe0f", "woman_shrugging_medium_skin_tone": "1f937-1f3fd-200d-2640-fe0f", "frowning_woman_medium_light_skin_tone": "1f64d-1f3fc-200d-2640-fe0f", "biking_man_medium_light_skin_tone": "1f6b4-1f3fc-200d-2640-fe0f", "woman_shrugging": "1f937-200d-2640-fe0f", "arrow_upper_left": "2196-fe0f", "metal_medium_skin_tone": "1f918-1f3fd", "woman_factory_worker_dark_skin_tone": "1f469-1f3ff", "hotsprings": "2668-fe0f", "ear_dark_skin_tone": "1f442-1f3ff", "girl_medium_skin_tone": "1f467-1f3fd", "woman_farmer_dark_skin_tone": "1f469-1f3ff", "man_student_medium_skin_tone": "1f468-1f3fd", "biking_man_medium_skin_tone": "1f6b4-1f3fd-200d-2640-fe0f", "woman_scientist": "1f469-200d-1f52c", "vs": "1f19a", "weight_lifting_man_medium_skin_tone": "1f3cb-1f3fd-200d-2640-fe0f", "arrow_right": "27a1-fe0f", "woman_juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2640-fe0f", "racehorse": "1f40e", "sun_behind_large_cloud": "1f325", "convenience_store": "1f3ea", "namibia": "1f1f3-1f1e6", "raised_hands_medium_dark_skin_tone": "1f64c-1f3fe", "man_judge_medium_light_skin_tone": "1f468-1f3fc", "dancer_medium_skin_tone": "1f483-1f3fd", "fearful": "1f628", "frog": "1f438", "shopping_cart": "1f6d2", "family_man_boy_medium_light_skin_tone": "1f468-1f3fc", "basketball_man_medium_dark_skin_tone": "26f9-1f3fe-200d-2640-fe0f", "oman": "1f1f4-1f1f2", "paraguay": "1f1f5-1f1fe", "horse": "1f434", "tram": "1f68a", "wastebasket": "1f5d1", "yen": "1f4b4", "heavy_exclamation_mark": "2757-fe0f", "arrow_double_down": "23ec", "walking_woman_dark_skin_tone": "1f6b6-1f3ff-200d-2640-fe0f", "shoe": "1f45e", "ear_of_rice": "1f33e", "mountain": "26f0", "uzbekistan": "1f1fa-1f1ff", "baby_light_skin_tone": "1f476-1f3fb", "haircut_woman_medium_dark_skin_tone": "1f487-1f3fe-200d-2640-fe0f", "golfing_woman_medium_skin_tone": "1f3cc-1f3fd-200d-2640-fe0f", "earth_americas": "1f30e", "woman_playing_water_polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2640-fe0f", "walking_woman": "1f6b6-200d-2640-fe0f", "fried_egg": "1f373", "rocket": "1f680", "artificial_satellite": "1f6f0", "man_shrugging_medium_skin_tone": "1f937-1f3fd-200d-2642-fe0f", "golfing_man_dark_skin_tone": "1f3cc-1f3ff-200d-2640-fe0f", "older_woman_medium_skin_tone": "1f475-1f3fd", "man_with_gua_pi_mao_medium_dark_skin_tone": "1f472-1f3fe", "persevere": "1f623", "raising_hand_woman": "1f64b", "pig": "1f437", "european_castle": "1f3f0", "department_store": "1f3ec", "fist_right_light_skin_tone": "1f91c-1f3fb", "raising_hand_woman_dark_skin_tone": "1f64b-1f3ff-200d-2640-fe0f", "paw_prints": "1f43e", "moon": "1f314", "man_medium_skin_tone": "1f468-1f3fd", "rowing_man_dark_skin_tone": "1f6a3-1f3ff-200d-2640-fe0f", "sleepy": "1f62a", "light_rail": "1f688", "peace_symbol": "262e-fe0f", "m": "24c2-fe0f", "woman_pilot_medium_skin_tone": "1f469-1f3fd", "dango": "1f361", "minibus": "1f690", "family_man_man_girl_girl_medium_dark_skin_tone": "1f468-1f3fe", "dizzy_face": "1f635", "bowing_woman": "1f647-200d-2640-fe0f", "pig2": "1f416", "factory": "1f3ed", "small_red_triangle": "1f53a", "ok_man_light_skin_tone": "1f646-1f3fb-200d-2642-fe0f", "two_women_holding_hands": "1f46d", "funeral_urn": "26b1-fe0f", "cocos_islands": "1f1e8-1f1e8", "lipstick": "1f484", "fleur_de_lis": "269c-fe0f", "man_with_gua_pi_mao_dark_skin_tone": "1f472-1f3ff", "woman_factory_worker_medium_dark_skin_tone": "1f469-1f3fe", "no_good_man_medium_light_skin_tone": "1f645-1f3fc-200d-2642-fe0f", "horse_racing_medium_dark_skin_tone": "1f3c7-1f3fe", "clock1030": "1f565", "couplekiss_man_man_dark_skin_tone": "1f468-1f3ff", "frowning_man": "1f64d-200d-2642-fe0f", "family_woman_boy_boy_dark_skin_tone": "1f469-1f3ff", "family_man_girl_boy_light_skin_tone": "1f468-1f3fb", "smile": "1f604", "clock7": "1f556", "massage_man": "1f486-200d-2642-fe0f", "guardswoman_dark_skin_tone": "1f482-1f3ff-200d-2640-fe0f", "raising_hand_man_dark_skin_tone": "1f64b-1f3ff-200d-2642-fe0f", "woman_with_turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2640-fe0f", "worried": "1f61f", "no_good": "1f645", "card_index": "1f4c7", "aland_islands": "1f1e6-1f1fd", "lion": "1f981", "hammer": "1f528", "bomb": "1f4a3", "reunion": "1f1f7-1f1ea", "walking_man_light_skin_tone": "1f6b6-1f3fb-200d-2640-fe0f", "family_woman_boy_medium_light_skin_tone": "1f469-1f3fc", "pouting_cat": "1f63e", "cow": "1f42e", "motor_scooter": "1f6f5", "hong_kong": "1f1ed-1f1f0", "family_man_girl_medium_dark_skin_tone": "1f468-1f3fe", "sailboat": "26f5-fe0f", "fiji": "1f1eb-1f1ef", "raised_hands_medium_light_skin_tone": "1f64c-1f3fc", "woman_office_worker_dark_skin_tone": "1f469-1f3ff", "family_man_woman_girl_girl_medium_light_skin_tone": "1f468-1f3fc", "arrow_up": "2b06-fe0f", "walking_woman_medium_light_skin_tone": "1f6b6-1f3fc-200d-2640-fe0f", "nose_medium_light_skin_tone": "1f443-1f3fc", "basketball_woman": "26f9-fe0f-200d-2640-fe0f", "+1_medium_light_skin_tone": "1f44d-1f3fc", "crossed_fingers_medium_skin_tone": "1f91e-1f3fd", "raised_back_of_hand_dark_skin_tone": "1f91a-1f3ff", "swimming_woman_medium_light_skin_tone": "1f3ca-1f3fc-200d-2640-fe0f", "construction_worker_woman": "1f477-200d-2640-fe0f", "rugby_football": "1f3c9", "micronesia": "1f1eb-1f1f2", "point_up_2_medium_light_skin_tone": "1f446-1f3fc", "running_man_dark_skin_tone": "1f3c3-1f3ff-200d-2640-fe0f", "woman_playing_handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2640-fe0f", "speaker": "1f508", "jersey": "1f1ef-1f1ea", "laughing": "1f606", "pregnant_woman": "1f930", "haircut_woman": "1f487", "blue_car": "1f699", "microscope": "1f52c", "postbox": "1f4ee", "man_firefighter_dark_skin_tone": "1f468-1f3ff", "sunny": "2600-fe0f", "beginner": "1f530", "clap_medium_light_skin_tone": "1f44f-1f3fc", "man_with_turban_dark_skin_tone": "1f473-1f3ff-200d-2640-fe0f", "rotating_light": "1f6a8", "saudi_arabia": "1f1f8-1f1e6", "family_woman_woman_girl_girl_medium_skin_tone": "1f469-1f3fd", "family_woman_girl_boy_light_skin_tone": "1f469-1f3fb", "man_with_gua_pi_mao": "1f472", "electric_plug": "1f50c", "panama": "1f1f5-1f1e6", "family_woman_woman_girl_light_skin_tone": "1f469-1f3fb", "thinking": "1f914", "point_down": "1f447", "spider": "1f577", "cloud_with_lightning_and_rain": "26c8", "ice_skate": "26f8", "ok_man_medium_dark_skin_tone": "1f646-1f3fe-200d-2642-fe0f", "netherlands": "1f1f3-1f1f1", "family_man_woman_boy": "1f46a", "orange": "1f34a", "snowboarder": "1f3c2", "passenger_ship": "1f6f3", "arrows_counterclockwise": "1f504", "tractor": "1f69c", "gambia": "1f1ec-1f1f2", "middle_finger_dark_skin_tone": "1f595-1f3ff", "tipping_hand_woman_medium_dark_skin_tone": "1f481-1f3fe-200d-2640-fe0f", "family_man_man_girl_boy_medium_light_skin_tone": "1f468-1f3fc", "thumbsup": "1f44d", "couple": "1f46b", "pouch": "1f45d", "asterisk": "002a-fe0f-20e3", "anguilla": "1f1e6-1f1ee", "woman_cook_light_skin_tone": "1f469-1f3fb", "kissing_cat": "1f63d", "nose": "1f443", "point_left_medium_skin_tone": "1f448-1f3fd", "baby_chick": "1f424", "deciduous_tree": "1f333", "u7533": "1f238", "surfing_woman_dark_skin_tone": "1f3c4-1f3ff-200d-2640-fe0f", "woman_shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2640-fe0f", "family_woman_woman_boy_boy_dark_skin_tone": "1f469-1f3ff", "cloud_with_rain": "1f327", "oden": "1f362", "botswana": "1f1e7-1f1fc", "greenland": "1f1ec-1f1f1", "man_office_worker_light_skin_tone": "1f468-1f3fb", "raising_hand_woman_medium_dark_skin_tone": "1f64b-1f3fe-200d-2640-fe0f", "family_man_man_girl_boy_medium_dark_skin_tone": "1f468-1f3fe", "school": "1f3eb", "woman_astronaut_light_skin_tone": "1f469-1f3fb", "woman_judge_medium_skin_tone": "1f469-1f3fd", "dancing_men": "1f46f-200d-2642-fe0f", "paperclips": "1f587", "underage": "1f51e", "ok_woman_dark_skin_tone": "1f646-1f3ff-200d-2640-fe0f", "man_playing_handball_dark_skin_tone": "1f93e-1f3ff-200d-2642-fe0f", "family_man_girl_girl": "1f468-200d-1f467-200d-1f467", "wind_face": "1f32c", "banana": "1f34c", "eight": "0038-fe0f-20e3", "man_technologist_medium_dark_skin_tone": "1f468-1f3fe", "man_office_worker_medium_skin_tone": "1f468-1f3fd", "walking_man_dark_skin_tone": "1f6b6-1f3ff-200d-2640-fe0f", "family_man_man_girl_girl_medium_skin_tone": "1f468-1f3fd", "snowman": "26c4-fe0f", "basketball_man": "26f9-fe0f", "information_source": "2139-fe0f", "cote_divoire": "1f1e8-1f1ee", "man_in_tuxedo_light_skin_tone": "1f935-1f3fb", "walking_woman_light_skin_tone": "1f6b6-1f3fb-200d-2640-fe0f", "woman_playing_water_polo_light_skin_tone": "1f93d-1f3fb-200d-2640-fe0f", "bird": "1f426", "o": "2b55-fe0f", "family_woman_girl_medium_skin_tone": "1f469-1f3fd", "rowing_woman_dark_skin_tone": "1f6a3-1f3ff-200d-2640-fe0f", "facepunch": "1f44a", "railway_car": "1f683", "wave_dark_skin_tone": "1f44b-1f3ff", "man_cook_medium_dark_skin_tone": "1f468-1f3fe", "prince_medium_light_skin_tone": "1f934-1f3fc", "cowboy_hat_face": "1f920", "handbag": "1f45c", "hourglass": "231b-fe0f", "albania": "1f1e6-1f1f1", "chile": "1f1e8-1f1f1", "woman_singer_medium_skin_tone": "1f469-1f3fd", "ear_medium_skin_tone": "1f442-1f3fd", "pouting_man_medium_skin_tone": "1f64e-1f3fd-200d-2642-fe0f", "surfing_man_medium_light_skin_tone": "1f3c4-1f3fc-200d-2640-fe0f", "eggplant": "1f346", "next_track_button": "23ed", "gabon": "1f1ec-1f1e6", "western_sahara": "1f1ea-1f1ed", "raised_hands_light_skin_tone": "1f64c-1f3fb", "older_woman_medium_light_skin_tone": "1f475-1f3fc", "joy_cat": "1f639", "feet": "1f43e", "partly_sunny": "26c5-fe0f", "pig_nose": "1f43d", "wc": "1f6be", "malaysia": "1f1f2-1f1fe", "girl_medium_light_skin_tone": "1f467-1f3fc", "man_office_worker_medium_dark_skin_tone": "1f468-1f3fe", "man_mechanic_medium_light_skin_tone": "1f468-1f3fc", "shamrock": "2618-fe0f", "tumbler_glass": "1f943", "palestinian_territories": "1f1f5-1f1f8", "kissing": "1f617", "city_sunset": "1f306", "pencil2": "270f-fe0f", "cool": "1f192", "australia": "1f1e6-1f1fa", "green_heart": "1f49a", "sparkle": "2747-fe0f", "ng_woman": "1f645", "high_heel": "1f460", "hamster": "1f439", "last_quarter_moon": "1f317", "stopwatch": "23f1", "date": "1f4c5", "nail_care_dark_skin_tone": "1f485-1f3ff", "santa_dark_skin_tone": "1f385-1f3ff", "astonished": "1f632", "mushroom": "1f344", "radio": "1f4fb", "hammer_and_wrench": "1f6e0", "arrow_down": "2b07-fe0f", "speech_balloon": "1f4ac", "couple_with_heart_man_man_medium_skin_tone": "1f468-1f3fd", "euro": "1f4b6", "es": "1f1ea-1f1f8", "woman_factory_worker_medium_light_skin_tone": "1f469-1f3fc", "pouting_woman_dark_skin_tone": "1f64e-1f3ff-200d-2640-fe0f", "massage_woman": "1f486", "spades": "2660-fe0f", "blonde_woman_dark_skin_tone": "1f471-1f3ff-200d-2640-fe0f", "man_farmer_medium_skin_tone": "1f468-1f3fd", "man_mechanic_medium_skin_tone": "1f468-1f3fd", "family_man_boy_dark_skin_tone": "1f468-1f3ff", "man_juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2642-fe0f", "hearts": "2665-fe0f", "clock930": "1f564", "central_african_republic": "1f1e8-1f1eb", "boy_medium_skin_tone": "1f466-1f3fd", "pregnant_woman_medium_skin_tone": "1f930-1f3fd", "woman_facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2640-fe0f", "palm_tree": "1f334", "rose": "1f339", "beers": "1f37b", "red_car": "1f697", "no_entry": "26d4-fe0f", "candy": "1f36c", "fist_oncoming_medium_skin_tone": "1f44a-1f3fd", "rowing_woman_medium_skin_tone": "1f6a3-1f3fd-200d-2640-fe0f", "sake": "1f376", "oncoming_police_car": "1f694", "woman_teacher_medium_dark_skin_tone": "1f469-1f3fe", "family_man_woman_girl_girl_medium_skin_tone": "1f468-1f3fd", "kissing_closed_eyes": "1f61a", "pager": "1f4df", "pencil": "1f4dd", "copyright": "00a9-fe0f", "wave_medium_skin_tone": "1f44b-1f3fd", "loud_sound": "1f50a", "luxembourg": "1f1f1-1f1fa", "policewoman_dark_skin_tone": "1f46e-1f3ff-200d-2640-fe0f", "woman_cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2640-fe0f", "swimming_woman_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2640-fe0f", "family_man_man_girl_boy": "1f468-200d-1f468-200d-1f467-200d-1f466", "police_car": "1f693", "mailbox_with_no_mail": "1f4ed", "middle_finger_light_skin_tone": "1f595-1f3fb", "pregnant_woman_medium_light_skin_tone": "1f930-1f3fc", "raising_hand_woman_medium_skin_tone": "1f64b-1f3fd-200d-2640-fe0f", "running": "1f3c3", "sun_with_face": "1f31e", "man_teacher_dark_skin_tone": "1f468-1f3ff", "family_man_woman_girl_girl_dark_skin_tone": "1f468-1f3ff", "izakaya_lantern": "1f3ee", "comoros": "1f1f0-1f1f2", "fist_oncoming_medium_dark_skin_tone": "1f44a-1f3fe", "man_singer": "1f468-200d-1f3a4", "mountain_bicyclist": "1f6b5", "point_down_light_skin_tone": "1f447-1f3fb", "family_man_woman_girl_boy_medium_dark_skin_tone": "1f468-1f3fe", "sob": "1f62d", "ophiuchus": "26ce", "greece": "1f1ec-1f1f7", "raised_back_of_hand_medium_skin_tone": "1f91a-1f3fd", "family_man_man_boy_light_skin_tone": "1f468-1f3fb", "woman_cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2640-fe0f", "massage_woman_light_skin_tone": "1f486-1f3fb-200d-2640-fe0f", "fishing_pole_and_fish": "1f3a3", "two_hearts": "1f495", "armenia": "1f1e6-1f1f2", "south_africa": "1f1ff-1f1e6", "boy_light_skin_tone": "1f466-1f3fb", "man_in_tuxedo_medium_dark_skin_tone": "1f935-1f3fe", "kiribati": "1f1f0-1f1ee", "v_dark_skin_tone": "270c-1f3ff", "frowning_man_medium_light_skin_tone": "1f64d-1f3fc-200d-2642-fe0f", "family_woman_woman_girl_boy": "1f469-200d-1f469-200d-1f467-200d-1f466", "family_woman_girl_boy_medium_dark_skin_tone": "1f469-1f3fe", "leopard": "1f406", "fireworks": "1f386", "clock6": "1f555", "bowing_man_medium_light_skin_tone": "1f647-1f3fc-200d-2640-fe0f", "raising_hand": "1f64b", "family_man_woman_girl_girl_light_skin_tone": "1f468-1f3fb", "vulcan_salute_medium_light_skin_tone": "1f596-1f3fc", "guardswoman_medium_light_skin_tone": "1f482-1f3fc-200d-2640-fe0f", "muscle": "1f4aa", "full_moon": "1f315", "pisces": "2653-fe0f", "kosovo": "1f1fd-1f1f0", "fist_left_dark_skin_tone": "1f91b-1f3ff", "point_up_2_dark_skin_tone": "1f446-1f3ff", "man_technologist_dark_skin_tone": "1f468-1f3ff", "spoon": "1f944", "nigeria": "1f1f3-1f1ec", "raised_back_of_hand_medium_light_skin_tone": "1f91a-1f3fc", "blonde_woman_light_skin_tone": "1f471-1f3fb-200d-2640-fe0f", "man_dancing_light_skin_tone": "1f57a-1f3fb", "shrimp": "1f990", "mountain_biking_man": "1f6b5", "boat": "26f5-fe0f", "egypt": "1f1ea-1f1ec", "family_woman_woman_boy_light_skin_tone": "1f469-1f3fb", "man_playing_water_polo_light_skin_tone": "1f93d-1f3fb-200d-2642-fe0f", "family_man_man_boy_boy": "1f468-200d-1f468-200d-1f466-200d-1f466", "foggy": "1f301", "construction_worker_woman_medium_light_skin_tone": "1f477-1f3fc-200d-2640-fe0f", "princess_medium_skin_tone": "1f478-1f3fd", "man_dancing_medium_dark_skin_tone": "1f57a-1f3fe", "couple_with_heart_man_man_dark_skin_tone": "1f468-1f3ff", "carousel_horse": "1f3a0", "crayon": "1f58d", "niue": "1f1f3-1f1fa", "woman_office_worker_medium_skin_tone": "1f469-1f3fd", "swimming_man_medium_skin_tone": "1f3ca-1f3fd-200d-2640-fe0f", "pensive": "1f614", "fire": "1f525", "monorail": "1f69d", "guam": "1f1ec-1f1fa", "older_woman_light_skin_tone": "1f475-1f3fb", "man_facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2642-fe0f", "family_man_man_girl": "1f468-200d-1f468-200d-1f467", "hammer_and_pick": "2692", "space_invader": "1f47e", "waning_crescent_moon": "1f318", "love_letter": "1f48c", "star_and_crescent": "262a-fe0f", "man_with_turban_light_skin_tone": "1f473-1f3fb-200d-2640-fe0f", "tipping_hand_woman_light_skin_tone": "1f481-1f3fb-200d-2640-fe0f", "dress": "1f457", "rainbow": "1f308", "cheese": "1f9c0", "bento": "1f371", "gear": "2699-fe0f", "-1_medium_skin_tone": "1f44e-1f3fd", "family_man_girl_boy_dark_skin_tone": "1f468-1f3ff", "fish_cake": "1f365", "desert_island": "1f3dd", "crystal_ball": "1f52e", "lock": "1f512", "no_good_man_medium_skin_tone": "1f645-1f3fd-200d-2642-fe0f", "small_blue_diamond": "1f539", "fist_raised_medium_dark_skin_tone": "270a-1f3fe", "man_health_worker_medium_light_skin_tone": "1f468-1f3fc", "ok_man_medium_light_skin_tone": "1f646-1f3fc-200d-2642-fe0f", "man_cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2642-fe0f", "policeman": "1f46e", "closed_lock_with_key": "1f510", "koko": "1f201", "guardswoman": "1f482-200d-2640-fe0f", "mailbox": "1f4eb", "weight_lifting_woman_light_skin_tone": "1f3cb-1f3fb-200d-2640-fe0f", "drooling_face": "1f924", "motorway": "1f6e3", "orthodox_cross": "2626-fe0f", "peru": "1f1f5-1f1ea", "woman_firefighter_medium_light_skin_tone": "1f469-1f3fc", "atom_symbol": "269b-fe0f", "benin": "1f1e7-1f1ef", "montenegro": "1f1f2-1f1ea", "tonga": "1f1f9-1f1f4", "family_man_boy_boy_medium_skin_tone": "1f468-1f3fd", "man_mechanic_light_skin_tone": "1f468-1f3fb", "female_detective": "1f575-fe0f-200d-2640-fe0f", "closed_umbrella": "1f302", "cow2": "1f404", "ballot_box": "1f5f3", "construction_worker_man_dark_skin_tone": "1f477-1f3ff-200d-2640-fe0f", "woman_technologist_medium_dark_skin_tone": "1f469-1f3fe", "indonesia": "1f1ee-1f1e9", "woman_pilot_medium_light_skin_tone": "1f469-1f3fc", "family_man_man_boy_boy_medium_light_skin_tone": "1f468-1f3fc", "call_me_hand": "1f919", "sun_behind_small_cloud": "1f324", "national_park": "1f3de", "radio_button": "1f518", "selfie_medium_light_skin_tone": "1f933-1f3fc", "woman_firefighter": "1f469-200d-1f692", "metal_dark_skin_tone": "1f918-1f3ff", "older_woman": "1f475", "man_factory_worker_medium_skin_tone": "1f468-1f3fd", "pick": "26cf", "woman_student_medium_skin_tone": "1f469-1f3fd", "mountain_biking_woman_light_skin_tone": "1f6b5-1f3fb-200d-2640-fe0f", "flags": "1f38f", "black_nib": "2712-fe0f", "rwanda": "1f1f7-1f1fc", "surfing_man_light_skin_tone": "1f3c4-1f3fb-200d-2640-fe0f", "first_quarter_moon": "1f313", "oil_drum": "1f6e2", "heart_decoration": "1f49f", "jp": "1f1ef-1f1f5", "woman_pilot": "1f469-200d-2708-fe0f", "city_sunrise": "1f307", "leo": "264c-fe0f", "arrow_up_down": "2195-fe0f", "selfie_medium_skin_tone": "1f933-1f3fd", "surfing_man_medium_skin_tone": "1f3c4-1f3fd-200d-2640-fe0f", "ramen": "1f35c", "up": "1f199", "woman_medium_light_skin_tone": "1f469-1f3fc", "woman_artist": "1f469-200d-1f3a8", "football": "1f3c8", "shopping": "1f6cd", "small_red_triangle_down": "1f53b", "crossed_fingers_light_skin_tone": "1f91e-1f3fb", "woman_artist_medium_dark_skin_tone": "1f469-1f3fe", "milk_glass": "1f95b", "clapper": "1f3ac", "star_of_david": "2721-fe0f", "dominican_republic": "1f1e9-1f1f4", "woman_teacher_light_skin_tone": "1f469-1f3fb", "man_juggling_medium_skin_tone": "1f939-1f3fd-200d-2642-fe0f", "-1": "1f44e", "wedding": "1f492", "faroe_islands": "1f1eb-1f1f4", "raising_hand_man_medium_dark_skin_tone": "1f64b-1f3fe-200d-2642-fe0f", "gemini": "264a-fe0f", "st_helena": "1f1f8-1f1ed", "running_woman_medium_light_skin_tone": "1f3c3-1f3fc-200d-2640-fe0f", "biking_woman_light_skin_tone": "1f6b4-1f3fb-200d-2640-fe0f", "paperclip": "1f4ce", "wave_medium_light_skin_tone": "1f44b-1f3fc", "man_factory_worker_medium_dark_skin_tone": "1f468-1f3fe", "woman_cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2640-fe0f", "clock12": "1f55b", "ru": "1f1f7-1f1fa", "clown_face": "1f921", "pizza": "1f355", "hole": "1f573", "incoming_envelope": "1f4e8", "yin_yang": "262f-fe0f", "warning": "26a0-fe0f", "family_man_man_girl_boy_dark_skin_tone": "1f468-1f3ff", "man_cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2642-fe0f", "ram": "1f40f", "cucumber": "1f952", "heartbeat": "1f493", "swaziland": "1f1f8-1f1ff", "nail_care_medium_dark_skin_tone": "1f485-1f3fe", "bath_medium_skin_tone": "1f6c0-1f3fd", "strawberry": "1f353", "peanuts": "1f95c", "field_hockey": "1f3d1", "cricket": "1f3cf", "woman_farmer_medium_dark_skin_tone": "1f469-1f3fe", "family_man_man_girl_girl_light_skin_tone": "1f468-1f3fb", "penguin": "1f427", "star": "2b50-fe0f", "woman_shrugging_light_skin_tone": "1f937-1f3fb-200d-2640-fe0f", "golfing_man_light_skin_tone": "1f3cc-1f3fb-200d-2640-fe0f", "innocent": "1f607", "mosque": "1f54c", "calendar": "1f4c6", "canada": "1f1e8-1f1e6", "rage4": "rage4", "woman_office_worker_medium_dark_skin_tone": "1f469-1f3fe", "poodle": "1f429", "grapes": "1f347", "love_hotel": "1f3e9", "vulcan_salute_medium_skin_tone": "1f596-1f3fd", "guardsman_medium_dark_skin_tone": "1f482-1f3fe-200d-2640-fe0f", "raising_hand_man_light_skin_tone": "1f64b-1f3fb-200d-2642-fe0f", "sleeping": "1f634", "nail_care": "1f485", "monkey": "1f412", "sao_tome_principe": "1f1f8-1f1f9", "dancer_medium_dark_skin_tone": "1f483-1f3fe", "classical_building": "1f3db", "swimming_woman_medium_skin_tone": "1f3ca-1f3fd-200d-2640-fe0f", "ok_hand": "1f44c", "rice_cracker": "1f358", "moyai": "1f5ff", "rage2": "rage2", "angel_light_skin_tone": "1f47c-1f3fb", "family_man_man_boy_boy_dark_skin_tone": "1f468-1f3ff", "smile_cat": "1f638", "angola": "1f1e6-1f1f4", "cameroon": "1f1e8-1f1f2", "man_student_medium_dark_skin_tone": "1f468-1f3fe", "weight_lifting_woman_medium_light_skin_tone": "1f3cb-1f3fc-200d-2640-fe0f", "waxing_crescent_moon": "1f312", "articulated_lorry": "1f69b", "pouting_woman_light_skin_tone": "1f64e-1f3fb-200d-2640-fe0f", "running_man_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2640-fe0f", "couple_with_heart_woman_woman_light_skin_tone": "1f469-1f3fb", "horse_racing_light_skin_tone": "1f3c7-1f3fb", "raised_back_of_hand": "1f91a", "saxophone": "1f3b7", "right_anger_bubble": "1f5ef", "tokelau": "1f1f9-1f1f0", "no_good_woman_medium_light_skin_tone": "1f645-1f3fc-200d-2640-fe0f", "walking_woman_medium_skin_tone": "1f6b6-1f3fd-200d-2640-fe0f", "family_woman_girl_girl": "1f469-200d-1f467-200d-1f467", "cake": "1f370", "abcd": "1f521", "tuvalu": "1f1f9-1f1fb", "suspect": "suspect", "mattermost": "mattermost", "swimming_woman_light_skin_tone": "1f3ca-1f3fb-200d-2640-fe0f", "white_medium_square": "25fb-fe0f", "haircut_woman_medium_skin_tone": "1f487-1f3fd-200d-2640-fe0f", "massage_woman_dark_skin_tone": "1f486-1f3ff-200d-2640-fe0f", "family_man_woman_girl_light_skin_tone": "1f468-1f3fb", "turks_caicos_islands": "1f1f9-1f1e8", "point_left_dark_skin_tone": "1f448-1f3ff", "family_man_man_boy_medium_dark_skin_tone": "1f468-1f3fe", "hand": "270b", "coffee": "2615-fe0f", "somalia": "1f1f8-1f1f4", "mountain_biking_man_dark_skin_tone": "1f6b5-1f3ff-200d-2640-fe0f", "hatching_chick": "1f423", "pear": "1f350", "baby_bottle": "1f37c", "ribbon": "1f380", "st_kitts_nevis": "1f1f0-1f1f3", "radioactive": "2622-fe0f", "end": "1f51a", "hand_medium_skin_tone": "270b-1f3fd", "family_woman_woman_girl_medium_light_skin_tone": "1f469-1f3fc", "3rd_place_medal": "1f949", "fist_left_medium_dark_skin_tone": "1f91b-1f3fe", "bolivia": "1f1e7-1f1f4", "point_up_light_skin_tone": "261d-1f3fb", "cherries": "1f352", "inbox_tray": "1f4e5", "pitcairn_islands": "1f1f5-1f1f3", "rage1": "rage1", "man_farmer_medium_dark_skin_tone": "1f468-1f3fe", "woman_with_turban": "1f473-200d-2640-fe0f", "unicorn": "1f984", "butterfly": "1f98b", "watch": "231a-fe0f", "arrow_up_small": "1f53c", "triangular_flag_on_post": "1f6a9", "heart_eyes": "1f60d", "shallow_pan_of_food": "1f958", "broken_heart": "1f494", "family_man_boy_boy_dark_skin_tone": "1f468-1f3ff", "golfing_woman_dark_skin_tone": "1f3cc-1f3ff-200d-2640-fe0f", "bath_dark_skin_tone": "1f6c0-1f3ff", "selfie": "1f933", "congratulations": "3297-fe0f", "baby_medium_light_skin_tone": "1f476-1f3fc", "woman_health_worker_medium_skin_tone": "1f469-1f3fd", "man_juggling": "1f939-200d-2642-fe0f", "arrow_down_small": "1f53d", "writing_hand_medium_light_skin_tone": "270d-1f3fc", "blonde_woman": "1f471-200d-2640-fe0f", "massage": "1f486", "metro": "1f687", "bath": "1f6c0", "female_detective_light_skin_tone": "1f575-1f3fb-200d-2640-fe0f", "haircut_man_light_skin_tone": "1f487-1f3fb-200d-2642-fe0f", "bowing_woman_medium_dark_skin_tone": "1f647-1f3fe-200d-2640-fe0f", "family_woman_woman_boy_medium_dark_skin_tone": "1f469-1f3fe", "shell": "1f41a", "seychelles": "1f1f8-1f1e8", "tipping_hand_man_medium_skin_tone": "1f481-1f3fd-200d-2642-fe0f", "panda_face": "1f43c", "sint_maarten": "1f1f8-1f1fd", "face_with_head_bandage": "1f915", "checkered_flag": "1f3c1", "samoa": "1f1fc-1f1f8", "v_medium_skin_tone": "270c-1f3fd", "couple_with_heart_man_man": "1f468-200d-2764-fe0f-200d-1f468", "shaved_ice": "1f367", "badminton": "1f3f8", "clock530": "1f560", "man_playing_water_polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2642-fe0f", "bulgaria": "1f1e7-1f1ec", "hurtrealbad": "hurtrealbad", "fist_oncoming_dark_skin_tone": "1f44a-1f3ff", "bat": "1f987", "signal_strength": "1f4f6", "iran": "1f1ee-1f1f7", "construction_worker_woman_medium_dark_skin_tone": "1f477-1f3fe-200d-2640-fe0f", "kiwi_fruit": "1f95d", "2nd_place_medal": "1f948", "kaaba": "1f54b", "knife": "1f52a", "ok_hand_light_skin_tone": "1f44c-1f3fb", "angel_medium_dark_skin_tone": "1f47c-1f3fe", "spider_web": "1f578", "oncoming_taxi": "1f696", "bookmark": "1f516", "u6307": "1f22f-fe0f", "za": "1f1ff-1f1e6", "fist_raised_light_skin_tone": "270a-1f3fb", "mag_right": "1f50e", "guinea": "1f1ec-1f1f3", "family_woman_woman_girl_dark_skin_tone": "1f469-1f3ff", "man_playing_handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2642-fe0f", "game_die": "1f3b2", "bullettrain_front": "1f685", "speedboat": "1f6a4", "hand_dark_skin_tone": "270b-1f3ff", "selfie_light_skin_tone": "1f933-1f3fb", "family_man_woman_boy_boy_dark_skin_tone": "1f468-1f3ff", "running_man": "1f3c3", "couplekiss_woman_woman": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f469", "woman_teacher": "1f469-200d-1f3eb", "running_shirt_with_sash": "1f3bd", "bowing_man_medium_skin_tone": "1f647-1f3fd-200d-2640-fe0f", "point_right_medium_dark_skin_tone": "1f449-1f3fe", "man_cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2642-fe0f", "pouting_man_light_skin_tone": "1f64e-1f3fb-200d-2642-fe0f", "biking_man_light_skin_tone": "1f6b4-1f3fb-200d-2640-fe0f", "oncoming_automobile": "1f698", "steam_locomotive": "1f682", "newspaper": "1f4f0", "antigua_barbuda": "1f1e6-1f1ec", "macau": "1f1f2-1f1f4", "niger": "1f1f3-1f1ea", "chicken": "1f414", "flashlight": "1f526", "family_man_woman_boy_boy_medium_skin_tone": "1f468-1f3fd", "mens": "1f6b9", "it": "1f1ee-1f1f9", "new_caledonia": "1f1f3-1f1e8", "pray_medium_light_skin_tone": "1f64f-1f3fc", "nose_medium_dark_skin_tone": "1f443-1f3fe", "man_facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2642-fe0f", "poop": "1f4a9", "clap_light_skin_tone": "1f44f-1f3fb", "guardsman_medium_skin_tone": "1f482-1f3fd-200d-2640-fe0f", "woman_teacher_dark_skin_tone": "1f469-1f3ff", "grinning": "1f600", "aries": "2648-fe0f", "mrs_claus": "1f936", "green_book": "1f4d7", "middle_finger_medium_dark_skin_tone": "1f595-1f3fe", "rowing_woman_light_skin_tone": "1f6a3-1f3fb-200d-2640-fe0f", "tokyo_tower": "1f5fc", "printer": "1f5a8", "put_litter_in_its_place": "1f6ae", "suriname": "1f1f8-1f1f7", "woman_light_skin_tone": "1f469-1f3fb", "man_playing_water_polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2642-fe0f", "dove": "1f54a", "latin_cross": "271d-fe0f", "exclamation": "2757-fe0f", "man_health_worker_dark_skin_tone": "1f468-1f3ff", "bride_with_veil_light_skin_tone": "1f470-1f3fb", "rowboat": "1f6a3", "world_map": "1f5fa", "sleeping_bed": "1f6cc", "haircut_man_dark_skin_tone": "1f487-1f3ff-200d-2642-fe0f", "surfing_man_dark_skin_tone": "1f3c4-1f3ff-200d-2640-fe0f", "couple_with_heart_woman_man": "1f491", "chart_with_upwards_trend": "1f4c8", "fist_right_dark_skin_tone": "1f91c-1f3ff", "raised_hand_with_fingers_splayed_medium_skin_tone": "1f590-1f3fd", "older_woman_medium_dark_skin_tone": "1f475-1f3fe", "couplekiss_woman_woman_medium_dark_skin_tone": "1f469-1f3fe", "hatched_chick": "1f425", "running_man_medium_skin_tone": "1f3c3-1f3fd-200d-2640-fe0f", "chocolate_bar": "1f36b", "grenada": "1f1ec-1f1e9", "man_farmer_dark_skin_tone": "1f468-1f3ff", "milky_way": "1f30c", "slovakia": "1f1f8-1f1f0", "selfie_dark_skin_tone": "1f933-1f3ff", "prince_medium_skin_tone": "1f934-1f3fd", "family_man_boy": "1f468-200d-1f466", "chains": "26d3", "british_virgin_islands": "1f1fb-1f1ec", "bow_and_arrow": "1f3f9", "ferry": "26f4", "o2": "1f17e-fe0f", "st_barthelemy": "1f1e7-1f1f1", "policewoman_medium_skin_tone": "1f46e-1f3fd-200d-2640-fe0f", "imp": "1f47f", "bathtub": "1f6c1", "anger": "1f4a2", "previous_track_button": "23ee", "pouting_woman_medium_light_skin_tone": "1f64e-1f3fc-200d-2640-fe0f", "rabbit2": "1f407", "newspaper_roll": "1f5de", "one": "0031-fe0f-20e3", "family_man_man_girl_medium_skin_tone": "1f468-1f3fd", "pouting_woman": "1f64e", "moneybag": "1f4b0", "guardsman_dark_skin_tone": "1f482-1f3ff-200d-2640-fe0f", "man_shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2642-fe0f", "smirk": "1f60f", "woman_farmer": "1f469-200d-1f33e", "ocean": "1f30a", "sweat_drops": "1f4a6", "x": "274c", "woman_judge_medium_dark_skin_tone": "1f469-1f3fe", "tropical_drink": "1f379", "brunei": "1f1e7-1f1f3", "woman_artist_medium_light_skin_tone": "1f469-1f3fc", "pregnant_woman_medium_dark_skin_tone": "1f930-1f3fe", "basketball_woman_light_skin_tone": "26f9-1f3fb-200d-2640-fe0f", "evergreen_tree": "1f332", "fax": "1f4e0", "woman_medium_dark_skin_tone": "1f469-1f3fe", "walking_woman_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2640-fe0f", "lollipop": "1f36d", "bicyclist": "1f6b4", "bulb": "1f4a1", "computer": "1f4bb", "frowning_man_dark_skin_tone": "1f64d-1f3ff-200d-2642-fe0f", "guardsman_medium_light_skin_tone": "1f482-1f3fc-200d-2640-fe0f", "dancer_light_skin_tone": "1f483-1f3fb", "no_good_woman": "1f645", "cherry_blossom": "1f338", "woman_playing_water_polo": "1f93d-200d-2640-fe0f", "heavy_division_sign": "2797", "sri_lanka": "1f1f1-1f1f0", "-1_medium_light_skin_tone": "1f44e-1f3fc", "family_woman_girl_girl_dark_skin_tone": "1f469-1f3ff", "raised_hands": "1f64c", "sandal": "1f461", "rhinoceros": "1f98f", "swimming_man": "1f3ca", "scissors": "2702-fe0f", "horse_racing_dark_skin_tone": "1f3c7-1f3ff", "coffin": "26b0-fe0f", "clock1": "1f550", "eritrea": "1f1ea-1f1f7", "qatar": "1f1f6-1f1e6", "tanzania": "1f1f9-1f1ff", "pregnant_woman_light_skin_tone": "1f930-1f3fb", "cop": "1f46e", "tipping_hand_woman": "1f481", "estonia": "1f1ea-1f1ea", "man_singer_light_skin_tone": "1f468-1f3fb", "woman_judge_dark_skin_tone": "1f469-1f3ff", "business_suit_levitating_medium_skin_tone": "1f574-1f3fd", "blowfish": "1f421", "mountain_railway": "1f69e", "fast_forward": "23e9", "+1_medium_skin_tone": "1f44d-1f3fd", "goat": "1f410", "congo_kinshasa": "1f1e8-1f1e9", "point_down_dark_skin_tone": "1f447-1f3ff", "basketball_man_light_skin_tone": "26f9-1f3fb-200d-2640-fe0f", "woman_playing_handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2640-fe0f", "doughnut": "1f369", "musical_keyboard": "1f3b9", "couplekiss_woman_woman_medium_skin_tone": "1f469-1f3fd", "heavy_heart_exclamation": "2763-fe0f", "u6e80": "1f235", "woman_with_turban_medium_skin_tone": "1f473-1f3fd-200d-2640-fe0f", "horse_racing_medium_skin_tone": "1f3c7-1f3fd", "ear": "1f442", "canoe": "1f6f6", "andorra": "1f1e6-1f1e9", "ca": "1f1e8-1f1e6", "family_man_man_boy": "1f468-200d-1f468-200d-1f466", "ticket": "1f3ab", "station": "1f689", "large_blue_circle": "1f535", "palau": "1f1f5-1f1fc", "blush": "1f60a", "man_student": "1f468-200d-1f393", "woman_singer": "1f469-200d-1f3a4", "house_with_garden": "1f3e1", "smoking": "1f6ac", "b": "1f171-fe0f", "golfing_woman_light_skin_tone": "1f3cc-1f3fb-200d-2640-fe0f", "man_artist_light_skin_tone": "1f468-1f3fb", "unamused": "1f612", "japanese_ogre": "1f479", "film_projector": "1f4fd", "ballot_box_with_check": "2611-fe0f", "goberserk": "goberserk", "metal_medium_light_skin_tone": "1f918-1f3fc", "latvia": "1f1f1-1f1fb", "moldova": "1f1f2-1f1e9", "mask": "1f637", "bowing_man": "1f647", "man_shrugging": "1f937-200d-2642-fe0f", "ping_pong": "1f3d3", "trackball": "1f5b2", "six": "0036-fe0f-20e3", "point_up_medium_skin_tone": "261d-1f3fd", "hotel": "1f3e8", "bookmark_tabs": "1f4d1", "chart_with_downwards_trend": "1f4c9", "v_light_skin_tone": "270c-1f3fb", "tipping_hand_woman_medium_skin_tone": "1f481-1f3fd-200d-2640-fe0f", "heart_eyes_cat": "1f63b", "dancer": "1f483", "movie_camera": "1f3a5", "two": "0032-fe0f-20e3", "clap_medium_dark_skin_tone": "1f44f-1f3fe", "woman_astronaut_medium_skin_tone": "1f469-1f3fd", "frowning": "1f626", "cry": "1f622", "no_bell": "1f515", "hand_medium_dark_skin_tone": "270b-1f3fe", "ear_light_skin_tone": "1f442-1f3fb", "family_man_girl_boy": "1f468-200d-1f467-200d-1f466", "swimming_woman": "1f3ca-200d-2640-fe0f", "mountain_biking_woman": "1f6b5-200d-2640-fe0f", "mantelpiece_clock": "1f570", "bermuda": "1f1e7-1f1f2", "new_zealand": "1f1f3-1f1ff", "massage_man_medium_dark_skin_tone": "1f486-1f3fe-200d-2642-fe0f", "crown": "1f451", "biking_man": "1f6b4", "woman_playing_water_polo_medium_skin_tone": "1f93d-1f3fd-200d-2640-fe0f", "man_in_tuxedo_dark_skin_tone": "1f935-1f3ff", "no_entry_sign": "1f6ab", "hash": "0023-fe0f-20e3", "white_small_square": "25ab-fe0f", "iraq": "1f1ee-1f1f6", "switzerland": "1f1e8-1f1ed", "woman_mechanic_light_skin_tone": "1f469-1f3fb", "squirrel": "shipit", "woman_cook_medium_light_skin_tone": "1f469-1f3fc", "confounded": "1f616", "+1": "1f44d", "rowing_man": "1f6a3", "mailbox_closed": "1f4ea", "customs": "1f6c3", "mayotte": "1f1fe-1f1f9", "man_mechanic_medium_dark_skin_tone": "1f468-1f3fe", "man_artist_medium_skin_tone": "1f468-1f3fd", "man_playing_handball_medium_skin_tone": "1f93e-1f3fd-200d-2642-fe0f", "grimacing": "1f62c", "dart": "1f3af", "wave_medium_dark_skin_tone": "1f44b-1f3fe", "slightly_smiling_face": "1f642", "medal_sports": "1f3c5", "bank": "1f3e6", "man_student_medium_light_skin_tone": "1f468-1f3fc", "man_pilot_light_skin_tone": "1f468-1f3fb", "weight_lifting_woman_medium_skin_tone": "1f3cb-1f3fd-200d-2640-fe0f", "dash": "1f4a8", "volcano": "1f30b", "antarctica": "1f1e6-1f1f6", "woman_facepalming_light_skin_tone": "1f926-1f3fb-200d-2640-fe0f", "man_dancing_medium_light_skin_tone": "1f57a-1f3fc", "scream_cat": "1f640", "fog": "1f32b", "fist_oncoming_light_skin_tone": "1f44a-1f3fb", "man_dancing_medium_skin_tone": "1f57a-1f3fd", "burrito": "1f32f", "thought_balloon": "1f4ad", "massage_man_medium_light_skin_tone": "1f486-1f3fc-200d-2642-fe0f", "couple_with_heart_woman_woman_dark_skin_tone": "1f469-1f3ff", "writing_hand": "270d-fe0f", "zap": "26a1-fe0f", "recycle": "267b-fe0f", "policewoman_medium_light_skin_tone": "1f46e-1f3fc-200d-2640-fe0f", "frowning_woman_medium_skin_tone": "1f64d-1f3fd-200d-2640-fe0f", "massage_man_light_skin_tone": "1f486-1f3fb-200d-2642-fe0f", "woman_student": "1f469-200d-1f393", "surfing_woman": "1f3c4-200d-2640-fe0f", "sunrise": "1f305", "open_file_folder": "1f4c2", "diamonds": "2666-fe0f", "family_man_woman_girl_girl": "1f468-200d-1f469-200d-1f467-200d-1f467", "airplane": "2708-fe0f", "arrow_heading_down": "2935-fe0f", "uruguay": "1f1fa-1f1fe", "point_down_medium_dark_skin_tone": "1f447-1f3fe", "family_man_man_boy_dark_skin_tone": "1f468-1f3ff", "family_man_woman_girl_boy": "1f468-200d-1f469-200d-1f467-200d-1f466", "confetti_ball": "1f38a", "flower_playing_cards": "1f3b4", "algeria": "1f1e9-1f1ff", "man_teacher_medium_light_skin_tone": "1f468-1f3fc", "woman_artist_light_skin_tone": "1f469-1f3fb", "family_man_woman_girl_medium_skin_tone": "1f468-1f3fd", "nerd_face": "1f913", "eyes": "1f440", "boot": "1f462", "unlock": "1f513", "zzz": "1f4a4", "vatican_city": "1f1fb-1f1e6", "hot_pepper": "1f336", "slot_machine": "1f3b0", "sunrise_over_mountains": "1f304", "haircut_man_medium_skin_tone": "1f487-1f3fd-200d-2642-fe0f", "stuck_out_tongue": "1f61b", "point_up_medium_dark_skin_tone": "261d-1f3fe", "vulcan_salute_medium_dark_skin_tone": "1f596-1f3fe", "family": "1f46a", "key": "1f511", "myanmar": "1f1f2-1f1f2", "policeman_medium_light_skin_tone": "1f46e-1f3fc-200d-2640-fe0f", "man_shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2642-fe0f", "woman_health_worker": "1f469-200d-2695-fe0f", "woman_judge": "1f469-200d-2696-fe0f", "japan": "1f5fe", "dominica": "1f1e9-1f1f2", "dragon": "1f409", "open_book": "1f4d6", "raising_hand_man": "1f64b-200d-2642-fe0f", "bikini": "1f459", "loudspeaker": "1f4e2", "woman_astronaut_medium_light_skin_tone": "1f469-1f3fc", "envelope_with_arrow": "1f4e9", "thailand": "1f1f9-1f1ed", "point_up_medium_light_skin_tone": "261d-1f3fc", "baby_medium_dark_skin_tone": "1f476-1f3fe", "man_scientist_medium_skin_tone": "1f468-1f3fd", "bowing_woman_medium_light_skin_tone": "1f647-1f3fc-200d-2640-fe0f", "construction_worker": "1f477", "nut_and_bolt": "1f529", "sparkling_heart": "1f496", "couplekiss_woman_woman_dark_skin_tone": "1f469-1f3ff", "elephant": "1f418", "bar_chart": "1f4ca", "nose_dark_skin_tone": "1f443-1f3ff", "stop_button": "23f9", "family_man_woman_boy_boy_light_skin_tone": "1f468-1f3fb", "family_man_girl_medium_light_skin_tone": "1f468-1f3fc", "relieved": "1f60c", "man_in_tuxedo": "1f935", "kick_scooter": "1f6f4", "statue_of_liberty": "1f5fd", "information_desk_person": "1f481", "sa": "1f202-fe0f", "abc": "1f524", "robot": "1f916", "cat": "1f431", "accept": "1f251", "upside_down_face": "1f643", "cloud": "2601-fe0f", "frowning_man_light_skin_tone": "1f64d-1f3fb-200d-2642-fe0f", "walking_man_medium_skin_tone": "1f6b6-1f3fd-200d-2640-fe0f", "sparkles": "2728", "u5272": "1f239", "globe_with_meridians": "1f310", "frowning_woman_medium_dark_skin_tone": "1f64d-1f3fe-200d-2640-fe0f", "grey_exclamation": "2755", "tm": "2122-fe0f", "massage_man_dark_skin_tone": "1f486-1f3ff-200d-2642-fe0f", "family_woman_woman_girl_boy_dark_skin_tone": "1f469-1f3ff", "paintbrush": "1f58c", "arrow_right_hook": "21aa-fe0f", "mauritania": "1f1f2-1f1f7", "man_scientist_light_skin_tone": "1f468-1f3fb", "woman_juggling_light_skin_tone": "1f939-1f3fb-200d-2640-fe0f", "ok_woman": "1f646", "snail": "1f40c", "hocho": "1f52a", "arrow_forward": "25b6-fe0f", "french_southern_territories": "1f1f9-1f1eb", "iphone": "1f4f1", "princess_medium_light_skin_tone": "1f478-1f3fc", "maple_leaf": "1f341", "open_hands": "1f450", "racing_car": "1f3ce", "pill": "1f48a", "cuba": "1f1e8-1f1fa", "fist_raised_dark_skin_tone": "270a-1f3ff", "blonde_man_dark_skin_tone": "1f471-1f3ff-200d-2640-fe0f", "family_woman_girl_boy_dark_skin_tone": "1f469-1f3ff", "fox_face": "1f98a", "man_playing_handball": "1f93e-200d-2642-fe0f", "bullettrain_side": "1f684", "black_small_square": "25aa-fe0f", "kazakhstan": "1f1f0-1f1ff", "vanuatu": "1f1fb-1f1fa", "older_man_medium_skin_tone": "1f474-1f3fd", "man_teacher": "1f468-200d-1f3eb", "family_man_man_boy_boy_medium_dark_skin_tone": "1f468-1f3fe", "back": "1f519", "point_up_2_medium_dark_skin_tone": "1f446-1f3fe", "woman_teacher_medium_light_skin_tone": "1f469-1f3fc", "family_woman_boy_boy_medium_dark_skin_tone": "1f469-1f3fe", "surfing_woman_medium_light_skin_tone": "1f3c4-1f3fc-200d-2640-fe0f", "portugal": "1f1f5-1f1f9", "construction_worker_woman_dark_skin_tone": "1f477-1f3ff-200d-2640-fe0f", "family_man_man_boy_medium_skin_tone": "1f468-1f3fd", "family_man_girl_dark_skin_tone": "1f468-1f3ff", "woman_mechanic": "1f469-200d-1f527", "arrow_heading_up": "2934-fe0f", "clock330": "1f55e", "malawi": "1f1f2-1f1fc", "ok_hand_medium_dark_skin_tone": "1f44c-1f3fe", "prince_dark_skin_tone": "1f934-1f3ff", "ice_hockey": "1f3d2", "pk": "1f1f5-1f1f0", "san_marino": "1f1f8-1f1f2", "point_left_light_skin_tone": "1f448-1f3fb", "woman_office_worker_medium_light_skin_tone": "1f469-1f3fc", "swimming_man_medium_light_skin_tone": "1f3ca-1f3fc-200d-2640-fe0f", "stuffed_flatbread": "1f959", "aerial_tramway": "1f6a1", "family_man_man_girl_girl_dark_skin_tone": "1f468-1f3ff", "family_woman_girl_girl_medium_dark_skin_tone": "1f469-1f3fe", "closed_book": "1f4d5", "family_woman_girl_boy_medium_light_skin_tone": "1f469-1f3fc", "family_man_man_girl_boy_medium_skin_tone": "1f468-1f3fd", "v": "270c-fe0f", "play_or_pause_button": "23ef", "el_salvador": "1f1f8-1f1fb", "woman_judge_medium_light_skin_tone": "1f469-1f3fc", "santa_medium_light_skin_tone": "1f385-1f3fc", "couplekiss_man_man_light_skin_tone": "1f468-1f3fb", "blonde_man_light_skin_tone": "1f471-1f3fb-200d-2640-fe0f", "fist_right": "1f91c", "man_with_turban": "1f473", "cancer": "264b-fe0f", "tunisia": "1f1f9-1f1f3", "open_hands_medium_light_skin_tone": "1f450-1f3fc", "call_me_hand_medium_dark_skin_tone": "1f919-1f3fe", "tired_face": "1f62b", "tongue": "1f445", "shower": "1f6bf", "british_indian_ocean_territory": "1f1ee-1f1f4", "man_firefighter_medium_light_skin_tone": "1f468-1f3fc", "couple_with_heart_woman_woman_medium_dark_skin_tone": "1f469-1f3fe", "crescent_moon": "1f319", "ecuador": "1f1ea-1f1e8", "french_polynesia": "1f1f5-1f1eb", "man_light_skin_tone": "1f468-1f3fb", "mountain_biking_woman_medium_skin_tone": "1f6b5-1f3fd-200d-2640-fe0f", "pakistan": "1f1f5-1f1f0", "open_hands_medium_dark_skin_tone": "1f450-1f3fe", "telephone": "260e-fe0f", "envelope": "2709-fe0f", "revolving_hearts": "1f49e", "mega": "1f4e3", "montserrat": "1f1f2-1f1f8", "uganda": "1f1fa-1f1ec", "tropical_fish": "1f420", "hibiscus": "1f33a", "rainbow_flag": "1f3f3-fe0f-200d-1f308", "bangladesh": "1f1e7-1f1e9", "shipit": "shipit", "no_good_man_dark_skin_tone": "1f645-1f3ff-200d-2642-fe0f", "no_mouth": "1f636", "man_farmer": "1f468-200d-1f33e", "speak_no_evil": "1f64a", "level_slider": "1f39a", "guatemala": "1f1ec-1f1f9", "woman_factory_worker": "1f469-200d-1f3ed", "fork_and_knife": "1f374", "belarus": "1f1e7-1f1fe", "family_woman_woman_girl_boy_medium_dark_skin_tone": "1f469-1f3fe", "yum": "1f60b", "helicopter": "1f681", "busstop": "1f68f", "policewoman_light_skin_tone": "1f46e-1f3fb-200d-2640-fe0f", "man_technologist_medium_skin_tone": "1f468-1f3fd", "man_with_gua_pi_mao_light_skin_tone": "1f472-1f3fb", "man_astronaut_dark_skin_tone": "1f468-1f3ff", "skull": "1f480", "smirk_cat": "1f63c", "jeans": "1f456", "flipper": "1f42c", "dizzy": "1f4ab", "cocktail": "1f378", "basketball_woman_medium_skin_tone": "26f9-1f3fd-200d-2640-fe0f", "v_medium_light_skin_tone": "270c-1f3fc", "secret": "3299-fe0f", "seven": "0037-fe0f-20e3", "ghana": "1f1ec-1f1ed", "guernsey": "1f1ec-1f1ec", "kyrgyzstan": "1f1f0-1f1ec", "godmode": "godmode", "female_detective_dark_skin_tone": "1f575-1f3ff-200d-2640-fe0f", "fallen_leaf": "1f342", "snowflake": "2744-fe0f", "raised_hand_with_fingers_splayed_medium_dark_skin_tone": "1f590-1f3fe", "woman_health_worker_medium_dark_skin_tone": "1f469-1f3fe", "man_shrugging_dark_skin_tone": "1f937-1f3ff-200d-2642-fe0f", "pout": "1f621", "stars": "1f320", "family_woman_girl_boy": "1f469-200d-1f467-200d-1f466", "gun": "1f52b", "woman_scientist_dark_skin_tone": "1f469-1f3ff", "basketball_woman_dark_skin_tone": "26f9-1f3ff-200d-2640-fe0f", "biking_woman_medium_light_skin_tone": "1f6b4-1f3fc-200d-2640-fe0f", "family_man_girl_boy_medium_dark_skin_tone": "1f468-1f3fe", "oncoming_bus": "1f68d", "seat": "1f4ba", "vhs": "1f4fc", "lithuania": "1f1f1-1f1f9", "v_medium_dark_skin_tone": "270c-1f3fe", "man_with_gua_pi_mao_medium_skin_tone": "1f472-1f3fd", "frowning_face": "2639-fe0f", "shit": "1f4a9", "ab": "1f18e", "couple_with_heart_woman_woman_medium_skin_tone": "1f469-1f3fd", "family_woman_woman_girl_girl": "1f469-200d-1f469-200d-1f467-200d-1f467", "potato": "1f954", "minidisc": "1f4bd", "libya": "1f1f1-1f1fe", "point_right_dark_skin_tone": "1f449-1f3ff", "man_artist": "1f468-200d-1f3a8", "pineapple": "1f34d", "spaghetti": "1f35d", "couch_and_lamp": "1f6cb", "free": "1f193", "jamaica": "1f1ef-1f1f2", "woman_astronaut_dark_skin_tone": "1f469-1f3ff", "man_mechanic": "1f468-200d-1f527", "curry": "1f35b", "small_orange_diamond": "1f538", "pray": "1f64f", "hotdog": "1f32d", "currency_exchange": "1f4b1", "-1_dark_skin_tone": "1f44e-1f3ff", "man_office_worker_dark_skin_tone": "1f468-1f3ff", "clock830": "1f563", "policeman_medium_skin_tone": "1f46e-1f3fd-200d-2640-fe0f", "grin": "1f601", "water_buffalo": "1f403", "older_man_dark_skin_tone": "1f474-1f3ff", "business_suit_levitating_medium_dark_skin_tone": "1f574-1f3fe", "couple_with_heart_man_man_medium_light_skin_tone": "1f468-1f3fc", "rowing_man_medium_light_skin_tone": "1f6a3-1f3fc-200d-2640-fe0f", "purse": "1f45b", "slovenia": "1f1f8-1f1ee", "tipping_hand_man_medium_light_skin_tone": "1f481-1f3fc-200d-2642-fe0f", "madagascar": "1f1f2-1f1ec", "south_georgia_south_sandwich_islands": "1f1ec-1f1f8", "punch": "1f44a", "man_pilot": "1f468-200d-2708-fe0f", "owl": "1f989", "croissant": "1f950", "email": "2709-fe0f", "outbox_tray": "1f4e4", "construction_worker_man_medium_light_skin_tone": "1f477-1f3fc-200d-2640-fe0f", "mrs_claus_medium_dark_skin_tone": "1f936-1f3fe", "family_man_woman_girl_boy_dark_skin_tone": "1f468-1f3ff", "file_cabinet": "1f5c4", "hungary": "1f1ed-1f1fa", "pray_medium_dark_skin_tone": "1f64f-1f3fe", "woman_mechanic_dark_skin_tone": "1f469-1f3ff", "angel_medium_skin_tone": "1f47c-1f3fd", "man_dancing": "1f57a", "pound": "1f4b7", "macedonia": "1f1f2-1f1f0", "man_facepalming_medium_skin_tone": "1f926-1f3fd-200d-2642-fe0f", "scroll": "1f4dc", "rescue_worker_helmet": "26d1", "desktop_computer": "1f5a5", "heavy_plus_sign": "2795", "man_with_turban_medium_skin_tone": "1f473-1f3fd-200d-2640-fe0f", "horse_racing": "1f3c7", "low_brightness": "1f505", "loop": "27bf", "man_with_turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2640-fe0f", "champagne": "1f37e", "construction_worker_woman_light_skin_tone": "1f477-1f3fb-200d-2640-fe0f", "man_teacher_light_skin_tone": "1f468-1f3fb", "family_woman_woman_girl_girl_medium_light_skin_tone": "1f469-1f3fc", "footprints": "1f463", "cloud_with_snow": "1f328", "man_cook_medium_light_skin_tone": "1f468-1f3fc", "woman_mechanic_medium_light_skin_tone": "1f469-1f3fc", "point_up_2": "1f446", "circus_tent": "1f3aa", "serbia": "1f1f7-1f1f8", "fist_right_medium_dark_skin_tone": "1f91c-1f3fe", "weight_lifting_woman_dark_skin_tone": "1f3cb-1f3ff-200d-2640-fe0f", "musical_score": "1f3bc", "violin": "1f3bb", "card_file_box": "1f5c3", "tipping_hand_woman_dark_skin_tone": "1f481-1f3ff-200d-2640-fe0f", "man_facepalming_dark_skin_tone": "1f926-1f3ff-200d-2642-fe0f", "open_mouth": "1f62e", "left_right_arrow": "2194-fe0f", "no_good_man_light_skin_tone": "1f645-1f3fb-200d-2642-fe0f", "man_factory_worker": "1f468-200d-1f3ed", "man_judge": "1f468-200d-2696-fe0f", "negative_squared_cross_mark": "274e", "bowing_woman_medium_skin_tone": "1f647-1f3fd-200d-2640-fe0f", "family_woman_boy_boy_light_skin_tone": "1f469-1f3fb", "battery": "1f50b", "couplekiss_man_man_medium_light_skin_tone": "1f468-1f3fc", "clock5": "1f554", "white_flag": "1f3f3-fe0f", "guadeloupe": "1f1ec-1f1f5", "muscle_medium_dark_skin_tone": "1f4aa-1f3fe", "man_scientist_dark_skin_tone": "1f468-1f3ff", "business_suit_levitating_light_skin_tone": "1f574-1f3fb", "woman_office_worker": "1f469-200d-1f4bc", "gift": "1f381", "sound": "1f509", "clubs": "2663-fe0f", "woman_scientist_medium_light_skin_tone": "1f469-1f3fc", "female_detective_medium_skin_tone": "1f575-1f3fd-200d-2640-fe0f", "man_singer_medium_light_skin_tone": "1f468-1f3fc", "family_man_girl": "1f468-200d-1f467", "bee": "1f41d", "full_moon_with_face": "1f31d", "black_medium_square": "25fc-fe0f", "zambia": "1f1ff-1f1f2", "raised_hands_dark_skin_tone": "1f64c-1f3ff", "family_woman_woman_boy_boy_medium_skin_tone": "1f469-1f3fd", "bread": "1f35e", "clock11": "1f55a", "man_office_worker_medium_light_skin_tone": "1f468-1f3fc", "woman_firefighter_medium_skin_tone": "1f469-1f3fd", "man_dancing_dark_skin_tone": "1f57a-1f3ff", "family_man_boy_medium_dark_skin_tone": "1f468-1f3fe", "hugs": "1f917", "roll_eyes": "1f644", "raised_hand": "270b", "tangerine": "1f34a", "grey_question": "2754", "princess_light_skin_tone": "1f478-1f3fb", "motor_boat": "1f6e5", "passport_control": "1f6c2", "man_artist_medium_dark_skin_tone": "1f468-1f3fe", "golfing_man_medium_skin_tone": "1f3cc-1f3fd-200d-2640-fe0f", "shirt": "1f455", "whale": "1f433", "apple": "1f34e", "ethiopia": "1f1ea-1f1f9", "jordan": "1f1ef-1f1f4", "biking_woman_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2640-fe0f", "family_woman_girl_girl_medium_skin_tone": "1f469-1f3fd", "turkey": "1f983", "snowman_with_snow": "2603-fe0f", "fist_left_medium_skin_tone": "1f91b-1f3fd", "woman_with_turban_light_skin_tone": "1f473-1f3fb-200d-2640-fe0f", "woman_pilot_dark_skin_tone": "1f469-1f3ff", "family_woman_woman_boy_medium_skin_tone": "1f469-1f3fd", "purple_heart": "1f49c", "black_heart": "1f5a4", "haircut_man": "1f487-200d-2642-fe0f", "arrow_lower_left": "2199-fe0f", "guinea_bissau": "1f1ec-1f1fc", "sudan": "1f1f8-1f1e9", "woman_scientist_light_skin_tone": "1f469-1f3fb", "bust_in_silhouette": "1f464", "walking": "1f6b6", "european_union": "1f1ea-1f1fa", "running_woman_dark_skin_tone": "1f3c3-1f3ff-200d-2640-fe0f", "om": "1f549", "rowing_man_medium_skin_tone": "1f6a3-1f3fd-200d-2640-fe0f", "ideograph_advantage": "1f250", "nepal": "1f1f3-1f1f5", "syria": "1f1f8-1f1fe", "man_pilot_medium_dark_skin_tone": "1f468-1f3fe", "princess_medium_dark_skin_tone": "1f478-1f3fe", "watermelon": "1f349", "left_luggage": "1f6c5", "us": "1f1fa-1f1f8", "point_left_medium_light_skin_tone": "1f448-1f3fc", "family_man_girl_boy_medium_skin_tone": "1f468-1f3fd", "biking_man_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2640-fe0f", "keycap_ten": "1f51f", "man_medium_light_skin_tone": "1f468-1f3fc", "couple_with_heart_man_man_light_skin_tone": "1f468-1f3fb", "family_man_man_girl_boy_light_skin_tone": "1f468-1f3fb", "dog2": "1f415", "art": "1f3a8", "taxi": "1f695", "motorcycle": "1f3cd", "diamond_shape_with_a_dot_inside": "1f4a0", "writing_hand_light_skin_tone": "270d-1f3fb", "woman_playing_water_polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2640-fe0f", "martial_arts_uniform": "1f94b", "spiral_calendar": "1f5d3", "older_man_medium_dark_skin_tone": "1f474-1f3fe", "woman_artist_medium_skin_tone": "1f469-1f3fd", "no_good_man_medium_dark_skin_tone": "1f645-1f3fe-200d-2642-fe0f", "family_woman_woman_boy_medium_light_skin_tone": "1f469-1f3fc", "ship": "1f6a2", "bangbang": "203c-fe0f", "israel": "1f1ee-1f1f1", "rowing_man_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2640-fe0f", "calling": "1f4f2", "scorpius": "264f-fe0f", "vulcan_salute_dark_skin_tone": "1f596-1f3ff", "woman_office_worker_light_skin_tone": "1f469-1f3fb", "man_judge_light_skin_tone": "1f468-1f3fb", "family_woman_woman_boy_boy_medium_dark_skin_tone": "1f469-1f3fe", "woman_playing_handball": "1f93e-200d-2640-fe0f", "bridge_at_night": "1f309", "stop_sign": "1f6d1", "8ball": "1f3b1", "orange_book": "1f4d9", "couplekiss_man_woman": "1f48f", "no_mobile_phones": "1f4f5", "pouting_man_dark_skin_tone": "1f64e-1f3ff-200d-2642-fe0f", "man_juggling_light_skin_tone": "1f939-1f3fb-200d-2642-fe0f", "cold_sweat": "1f630", "star2": "1f31f", "taco": "1f32e", "point_right_medium_light_skin_tone": "1f449-1f3fc", "selfie_medium_dark_skin_tone": "1f933-1f3fe", "family_woman_woman_girl_boy_light_skin_tone": "1f469-1f3fb", "hankey": "1f4a9", "monkey_face": "1f435", "sweden": "1f1f8-1f1ea", "crocodile": "1f40a", "last_quarter_moon_with_face": "1f31c", "comet": "2604-fe0f", "caribbean_netherlands": "1f1e7-1f1f6", "walking_man_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2640-fe0f", "basketball_man_medium_light_skin_tone": "26f9-1f3fc-200d-2640-fe0f", "deer": "1f98c", "clock4": "1f553", "christmas_island": "1f1e8-1f1fd", "fist_right_medium_skin_tone": "1f91c-1f3fd", "man_cook_dark_skin_tone": "1f468-1f3ff", "family_man_man_girl_medium_light_skin_tone": "1f468-1f3fc", "whale2": "1f40b", "sagittarius": "2650-fe0f", "children_crossing": "1f6b8", "call_me_hand_dark_skin_tone": "1f919-1f3ff", "ok_woman_medium_dark_skin_tone": "1f646-1f3fe-200d-2640-fe0f", "man_firefighter": "1f468-200d-1f692", "rewind": "23ea", "guardswoman_light_skin_tone": "1f482-1f3fb-200d-2640-fe0f", "woman_technologist_light_skin_tone": "1f469-1f3fb", "woman_pilot_light_skin_tone": "1f469-1f3fb", "raising_hand_woman_light_skin_tone": "1f64b-1f3fb-200d-2640-fe0f", "bowing_man_light_skin_tone": "1f647-1f3fb-200d-2640-fe0f", "frowning_man_medium_skin_tone": "1f64d-1f3fd-200d-2642-fe0f", "shark": "1f988", "sun_behind_rain_cloud": "1f326", "dagger": "1f5e1", "musical_note": "1f3b5", "crossed_fingers_dark_skin_tone": "1f91e-1f3ff", "man_pilot_medium_skin_tone": "1f468-1f3fd", "family_woman_boy_medium_skin_tone": "1f469-1f3fd", "golfing_man_medium_light_skin_tone": "1f3cc-1f3fc-200d-2640-fe0f", "girl": "1f467", "family_man_woman_boy_boy": "1f468-200d-1f469-200d-1f466-200d-1f466", "biking_woman": "1f6b4-200d-2640-fe0f", "cl": "1f191", "raised_back_of_hand_medium_dark_skin_tone": "1f91a-1f3fe", "raising_hand_woman_medium_light_skin_tone": "1f64b-1f3fc-200d-2640-fe0f", "baby_medium_skin_tone": "1f476-1f3fd", "guardsman": "1f482", "woman_astronaut": "1f469-200d-1f680", "tophat": "1f3a9", "honduras": "1f1ed-1f1f3", "mexico": "1f1f2-1f1fd", "nauru": "1f1f3-1f1f7", "mrs_claus_medium_light_skin_tone": "1f936-1f3fc", "weary": "1f629", "womans_hat": "1f452", "person_fencing": "1f93a", "u6708": "1f237-fe0f", "a": "1f170-fe0f", "de": "1f1e9-1f1ea", "lebanon": "1f1f1-1f1e7", "puerto_rico": "1f1f5-1f1f7", "man_mechanic_dark_skin_tone": "1f468-1f3ff", "policeman_dark_skin_tone": "1f46e-1f3ff-200d-2640-fe0f", "kissing_smiling_eyes": "1f619", "avocado": "1f951", "six_pointed_star": "1f52f", "record_button": "23fa", "family_woman_woman_girl_girl_light_skin_tone": "1f469-1f3fb", "mountain_biking_man_medium_light_skin_tone": "1f6b5-1f3fc-200d-2640-fe0f", "couple_with_heart_man_man_medium_dark_skin_tone": "1f468-1f3fe", "family_man_girl_girl_light_skin_tone": "1f468-1f3fb", "post_office": "1f3e3", "telescope": "1f52d", "baby_symbol": "1f6bc", "capital_abcd": "1f520", "woman_singer_light_skin_tone": "1f469-1f3fb", "woman_facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2640-fe0f", "ant": "1f41c", "house": "1f3e0", "shield": "1f6e1", "yellow_heart": "1f49b", "u55b6": "1f23a", "senegal": "1f1f8-1f1f3", "united_arab_emirates": "1f1e6-1f1ea", "no_good_woman_medium_skin_tone": "1f645-1f3fd-200d-2640-fe0f", "running_man_medium_light_skin_tone": "1f3c3-1f3fc-200d-2640-fe0f", "beetle": "1f41e", "bus": "1f68c", "flight_arrival": "1f6ec", "black_large_square": "2b1b-fe0f", "white_large_square": "2b1c-fe0f", "woman_technologist_medium_light_skin_tone": "1f469-1f3fc", "skier": "26f7", "ok_hand_medium_light_skin_tone": "1f44c-1f3fc", "rofl": "1f923", "hushed": "1f62f", "ng_man": "1f645-200d-2642-fe0f", "running_woman": "1f3c3-200d-2640-fe0f", "family_man_man_girl_girl": "1f468-200d-1f468-200d-1f467-200d-1f467", "gorilla": "1f98d", "horse_racing_medium_light_skin_tone": "1f3c7-1f3fc", "mountain_biking_man_medium_skin_tone": "1f6b5-1f3fd-200d-2640-fe0f", "disappointed": "1f61e", "dolphin": "1f42c", "green_apple": "1f34f", "honey_pot": "1f36f", "georgia": "1f1ec-1f1ea", "business_suit_levitating": "1f574", "camera": "1f4f7", "ledger": "1f4d2", "woman_cook_medium_skin_tone": "1f469-1f3fd", "bahamas": "1f1e7-1f1f8", "family_woman_woman_girl": "1f469-200d-1f469-200d-1f467", "man_factory_worker_light_skin_tone": "1f468-1f3fb", "golfing_woman_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2640-fe0f", "family_woman_girl": "1f469-200d-1f467", "turtle": "1f422", "mauritius": "1f1f2-1f1fa", "family_man_girl_light_skin_tone": "1f468-1f3fb", "hospital": "1f3e5", "church": "26ea-fe0f", "wheel_of_dharma": "2638-fe0f", "mongolia": "1f1f2-1f1f3", "man_facepalming": "1f926-200d-2642-fe0f", "bed": "1f6cf", "man_artist_medium_light_skin_tone": "1f468-1f3fc", "santa_medium_dark_skin_tone": "1f385-1f3fe", "family_man_woman_girl_medium_light_skin_tone": "1f468-1f3fc", "large_blue_diamond": "1f537", "colombia": "1f1e8-1f1f4", "philippines": "1f1f5-1f1ed", "older_woman_dark_skin_tone": "1f475-1f3ff", "woman_scientist_medium_skin_tone": "1f469-1f3fd", "couplekiss_woman_woman_light_skin_tone": "1f469-1f3fb", "male_detective": "1f575-fe0f", "crossed_swords": "2694-fe0f", "notebook": "1f4d3", "nail_care_medium_light_skin_tone": "1f485-1f3fc", "blonde_man_medium_skin_tone": "1f471-1f3fd-200d-2640-fe0f", "tipping_hand_man_light_skin_tone": "1f481-1f3fb-200d-2642-fe0f", "sweat_smile": "1f605", "white_medium_small_square": "25fd-fe0f", "bowtie": "bowtie", "reminder_ribbon": "1f397", "clamp": "1f5dc", "balance_scale": "2696-fe0f", "postal_horn": "1f4ef", "swimming_woman_dark_skin_tone": "1f3ca-1f3ff-200d-2640-fe0f", "raised_hand_with_fingers_splayed": "1f590", "ok_man": "1f646-200d-2642-fe0f", "new": "1f195", "male_detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2640-fe0f", "computer_mouse": "1f5b1", "hourglass_flowing_sand": "23f3", "bahrain": "1f1e7-1f1ed", "djibouti": "1f1e9-1f1ef", "zimbabwe": "1f1ff-1f1fc", "swimming_man_light_skin_tone": "1f3ca-1f3fb-200d-2640-fe0f", "interrobang": "2049-fe0f", "clock8": "1f557", "pancakes": "1f95e", "thermometer": "1f321", "label": "1f3f7", "denmark": "1f1e9-1f1f0", "raising_hand_man_medium_light_skin_tone": "1f64b-1f3fc-200d-2642-fe0f", "frowning_man_medium_dark_skin_tone": "1f64d-1f3fe-200d-2642-fe0f", "point_right": "1f449", "guitar": "1f3b8", "family_woman_woman_girl_medium_skin_tone": "1f469-1f3fd", "woman_juggling_medium_skin_tone": "1f939-1f3fd-200d-2640-fe0f", "man_health_worker": "1f468-200d-2695-fe0f", "stew": "1f372", "surfing_man": "1f3c4", "twisted_rightwards_arrows": "1f500", "timor_leste": "1f1f9-1f1f1", "weight_lifting_woman": "1f3cb-fe0f-200d-2640-fe0f", "amphora": "1f3fa", "heart": "2764-fe0f", "bowing_man_medium_dark_skin_tone": "1f647-1f3fe-200d-2640-fe0f"} +var SystemEmojis = map[string]string{"grinning": "1f600", "smiley": "1f603", "smile": "1f604", "grin": "1f601", "laughing": "1f606", "satisfied": "1f606", "sweat_smile": "1f605", "rolling_on_the_floor_laughing": "1f923", "rofl": "1f923", "joy": "1f602", "slightly_smiling_face": "1f642", "upside_down_face": "1f643", "wink": "1f609", "blush": "1f60a", "innocent": "1f607", "smiling_face_with_3_hearts": "1f970", "heart_eyes": "1f60d", "star-struck": "1f929", "grinning_face_with_star_eyes": "1f929", "kissing_heart": "1f618", "kissing": "1f617", "relaxed": "263a-fe0f", "kissing_closed_eyes": "1f61a", "kissing_smiling_eyes": "1f619", "smiling_face_with_tear": "1f972", "yum": "1f60b", "stuck_out_tongue": "1f61b", "stuck_out_tongue_winking_eye": "1f61c", "zany_face": "1f92a", "grinning_face_with_one_large_and_one_small_eye": "1f92a", "stuck_out_tongue_closed_eyes": "1f61d", "money_mouth_face": "1f911", "hugging_face": "1f917", "hugs": "1f917", "face_with_hand_over_mouth": "1f92d", "smiling_face_with_smiling_eyes_and_hand_covering_mouth": "1f92d", "shushing_face": "1f92b", "face_with_finger_covering_closed_lips": "1f92b", "thinking_face": "1f914", "thinking": "1f914", "zipper_mouth_face": "1f910", "face_with_raised_eyebrow": "1f928", "face_with_one_eyebrow_raised": "1f928", "neutral_face": "1f610", "expressionless": "1f611", "no_mouth": "1f636", "smirk": "1f60f", "unamused": "1f612", "face_with_rolling_eyes": "1f644", "roll_eyes": "1f644", "grimacing": "1f62c", "lying_face": "1f925", "relieved": "1f60c", "pensive": "1f614", "sleepy": "1f62a", "drooling_face": "1f924", "sleeping": "1f634", "mask": "1f637", "face_with_thermometer": "1f912", "face_with_head_bandage": "1f915", "nauseated_face": "1f922", "face_vomiting": "1f92e", "face_with_open_mouth_vomiting": "1f92e", "sneezing_face": "1f927", "hot_face": "1f975", "cold_face": "1f976", "woozy_face": "1f974", "dizzy_face": "1f635", "exploding_head": "1f92f", "shocked_face_with_exploding_head": "1f92f", "face_with_cowboy_hat": "1f920", "cowboy_hat_face": "1f920", "partying_face": "1f973", "disguised_face": "1f978", "sunglasses": "1f60e", "nerd_face": "1f913", "face_with_monocle": "1f9d0", "confused": "1f615", "worried": "1f61f", "slightly_frowning_face": "1f641", "white_frowning_face": "2639-fe0f", "frowning_face": "2639-fe0f", "open_mouth": "1f62e", "hushed": "1f62f", "astonished": "1f632", "flushed": "1f633", "pleading_face": "1f97a", "frowning": "1f626", "anguished": "1f627", "fearful": "1f628", "cold_sweat": "1f630", "disappointed_relieved": "1f625", "cry": "1f622", "sob": "1f62d", "scream": "1f631", "confounded": "1f616", "persevere": "1f623", "disappointed": "1f61e", "sweat": "1f613", "weary": "1f629", "tired_face": "1f62b", "yawning_face": "1f971", "triumph": "1f624", "rage": "1f621", "pout": "1f621", "angry": "1f620", "face_with_symbols_on_mouth": "1f92c", "serious_face_with_symbols_covering_mouth": "1f92c", "smiling_imp": "1f608", "imp": "1f47f", "skull": "1f480", "skull_and_crossbones": "2620-fe0f", "hankey": "1f4a9", "poop": "1f4a9", "shit": "1f4a9", "clown_face": "1f921", "japanese_ogre": "1f479", "japanese_goblin": "1f47a", "ghost": "1f47b", "alien": "1f47d", "space_invader": "1f47e", "robot_face": "1f916", "robot": "1f916", "smiley_cat": "1f63a", "smile_cat": "1f638", "joy_cat": "1f639", "heart_eyes_cat": "1f63b", "smirk_cat": "1f63c", "kissing_cat": "1f63d", "scream_cat": "1f640", "crying_cat_face": "1f63f", "pouting_cat": "1f63e", "see_no_evil": "1f648", "hear_no_evil": "1f649", "speak_no_evil": "1f64a", "kiss": "1f48b", "love_letter": "1f48c", "cupid": "1f498", "gift_heart": "1f49d", "sparkling_heart": "1f496", "heartpulse": "1f497", "heartbeat": "1f493", "revolving_hearts": "1f49e", "two_hearts": "1f495", "heart_decoration": "1f49f", "heavy_heart_exclamation_mark_ornament": "2763-fe0f", "heavy_heart_exclamation": "2763-fe0f", "broken_heart": "1f494", "heart": "2764-fe0f", "orange_heart": "1f9e1", "yellow_heart": "1f49b", "green_heart": "1f49a", "blue_heart": "1f499", "purple_heart": "1f49c", "brown_heart": "1f90e", "black_heart": "1f5a4", "white_heart": "1f90d", "100": "1f4af", "anger": "1f4a2", "boom": "1f4a5", "collision": "1f4a5", "dizzy": "1f4ab", "sweat_drops": "1f4a6", "dash": "1f4a8", "hole": "1f573-fe0f", "bomb": "1f4a3", "speech_balloon": "1f4ac", "eye-in-speech-bubble": "1f441-fe0f-200d-1f5e8-fe0f", "left_speech_bubble": "1f5e8-fe0f", "right_anger_bubble": "1f5ef-fe0f", "thought_balloon": "1f4ad", "zzz": "1f4a4", "wave": "1f44b", "raised_back_of_hand": "1f91a", "raised_hand_with_fingers_splayed": "1f590-fe0f", "hand": "270b", "raised_hand": "270b", "spock-hand": "1f596", "vulcan_salute": "1f596", "ok_hand": "1f44c", "pinched_fingers": "1f90c", "pinching_hand": "1f90f", "v": "270c-fe0f", "crossed_fingers": "1f91e", "hand_with_index_and_middle_fingers_crossed": "1f91e", "i_love_you_hand_sign": "1f91f", "the_horns": "1f918", "sign_of_the_horns": "1f918", "metal": "1f918", "call_me_hand": "1f919", "point_left": "1f448", "point_right": "1f449", "point_up_2": "1f446", "middle_finger": "1f595", "reversed_hand_with_middle_finger_extended": "1f595", "fu": "1f595", "point_down": "1f447", "point_up": "261d-fe0f", "+1": "1f44d", "thumbsup": "1f44d", "-1": "1f44e", "thumbsdown": "1f44e", "fist": "270a", "fist_raised": "270a", "facepunch": "1f44a", "punch": "1f44a", "fist_oncoming": "1f44a", "left-facing_fist": "1f91b", "fist_left": "1f91b", "right-facing_fist": "1f91c", "fist_right": "1f91c", "clap": "1f44f", "raised_hands": "1f64c", "open_hands": "1f450", "palms_up_together": "1f932", "handshake": "1f91d", "pray": "1f64f", "writing_hand": "270d-fe0f", "nail_care": "1f485", "selfie": "1f933", "muscle": "1f4aa", "mechanical_arm": "1f9be", "mechanical_leg": "1f9bf", "leg": "1f9b5", "foot": "1f9b6", "ear": "1f442", "ear_with_hearing_aid": "1f9bb", "nose": "1f443", "brain": "1f9e0", "anatomical_heart": "1fac0", "lungs": "1fac1", "tooth": "1f9b7", "bone": "1f9b4", "eyes": "1f440", "eye": "1f441-fe0f", "tongue": "1f445", "lips": "1f444", "baby": "1f476", "child": "1f9d2", "boy": "1f466", "girl": "1f467", "adult": "1f9d1", "person_with_blond_hair": "1f471", "man": "1f468", "bearded_person": "1f9d4", "red_haired_man": "1f468-200d-1f9b0", "curly_haired_man": "1f468-200d-1f9b1", "white_haired_man": "1f468-200d-1f9b3", "bald_man": "1f468-200d-1f9b2", "woman": "1f469", "red_haired_woman": "1f469-200d-1f9b0", "red_haired_person": "1f9d1-200d-1f9b0", "curly_haired_woman": "1f469-200d-1f9b1", "curly_haired_person": "1f9d1-200d-1f9b1", "white_haired_woman": "1f469-200d-1f9b3", "white_haired_person": "1f9d1-200d-1f9b3", "bald_woman": "1f469-200d-1f9b2", "bald_person": "1f9d1-200d-1f9b2", "blond-haired-woman": "1f471-200d-2640-fe0f", "blonde_woman": "1f471-200d-2640-fe0f", "blond-haired-man": "1f471-200d-2642-fe0f", "blonde_man": "1f471-200d-2642-fe0f", "older_adult": "1f9d3", "older_man": "1f474", "older_woman": "1f475", "person_frowning": "1f64d", "man-frowning": "1f64d-200d-2642-fe0f", "frowning_man": "1f64d-200d-2642-fe0f", "woman-frowning": "1f64d-200d-2640-fe0f", "frowning_woman": "1f64d-200d-2640-fe0f", "person_with_pouting_face": "1f64e", "man-pouting": "1f64e-200d-2642-fe0f", "pouting_man": "1f64e-200d-2642-fe0f", "woman-pouting": "1f64e-200d-2640-fe0f", "pouting_woman": "1f64e-200d-2640-fe0f", "no_good": "1f645", "man-gesturing-no": "1f645-200d-2642-fe0f", "ng_man": "1f645-200d-2642-fe0f", "no_good_man": "1f645-200d-2642-fe0f", "woman-gesturing-no": "1f645-200d-2640-fe0f", "no_good_woman": "1f645-200d-2640-fe0f", "ng_woman": "1f645-200d-2640-fe0f", "ok_woman": "1f646", "man-gesturing-ok": "1f646-200d-2642-fe0f", "ok_man": "1f646-200d-2642-fe0f", "woman-gesturing-ok": "1f646-200d-2640-fe0f", "information_desk_person": "1f481", "man-tipping-hand": "1f481-200d-2642-fe0f", "tipping_hand_man": "1f481-200d-2642-fe0f", "woman-tipping-hand": "1f481-200d-2640-fe0f", "tipping_hand_woman": "1f481-200d-2640-fe0f", "raising_hand": "1f64b", "man-raising-hand": "1f64b-200d-2642-fe0f", "raising_hand_man": "1f64b-200d-2642-fe0f", "woman-raising-hand": "1f64b-200d-2640-fe0f", "raising_hand_woman": "1f64b-200d-2640-fe0f", "deaf_person": "1f9cf", "deaf_man": "1f9cf-200d-2642-fe0f", "deaf_woman": "1f9cf-200d-2640-fe0f", "bow": "1f647", "man-bowing": "1f647-200d-2642-fe0f", "bowing_man": "1f647-200d-2642-fe0f", "woman-bowing": "1f647-200d-2640-fe0f", "bowing_woman": "1f647-200d-2640-fe0f", "face_palm": "1f926", "man-facepalming": "1f926-200d-2642-fe0f", "man_facepalming": "1f926-200d-2642-fe0f", "woman-facepalming": "1f926-200d-2640-fe0f", "woman_facepalming": "1f926-200d-2640-fe0f", "shrug": "1f937", "man-shrugging": "1f937-200d-2642-fe0f", "man_shrugging": "1f937-200d-2642-fe0f", "woman-shrugging": "1f937-200d-2640-fe0f", "woman_shrugging": "1f937-200d-2640-fe0f", "health_worker": "1f9d1-200d-2695-fe0f", "male-doctor": "1f468-200d-2695-fe0f", "man_health_worker": "1f468-200d-2695-fe0f", "female-doctor": "1f469-200d-2695-fe0f", "woman_health_worker": "1f469-200d-2695-fe0f", "student": "1f9d1-200d-1f393", "male-student": "1f468-200d-1f393", "man_student": "1f468-200d-1f393", "female-student": "1f469-200d-1f393", "woman_student": "1f469-200d-1f393", "teacher": "1f9d1-200d-1f3eb", "male-teacher": "1f468-200d-1f3eb", "man_teacher": "1f468-200d-1f3eb", "female-teacher": "1f469-200d-1f3eb", "woman_teacher": "1f469-200d-1f3eb", "judge": "1f9d1-200d-2696-fe0f", "male-judge": "1f468-200d-2696-fe0f", "man_judge": "1f468-200d-2696-fe0f", "female-judge": "1f469-200d-2696-fe0f", "woman_judge": "1f469-200d-2696-fe0f", "farmer": "1f9d1-200d-1f33e", "male-farmer": "1f468-200d-1f33e", "man_farmer": "1f468-200d-1f33e", "female-farmer": "1f469-200d-1f33e", "woman_farmer": "1f469-200d-1f33e", "cook": "1f9d1-200d-1f373", "male-cook": "1f468-200d-1f373", "man_cook": "1f468-200d-1f373", "female-cook": "1f469-200d-1f373", "woman_cook": "1f469-200d-1f373", "mechanic": "1f9d1-200d-1f527", "male-mechanic": "1f468-200d-1f527", "man_mechanic": "1f468-200d-1f527", "female-mechanic": "1f469-200d-1f527", "woman_mechanic": "1f469-200d-1f527", "factory_worker": "1f9d1-200d-1f3ed", "male-factory-worker": "1f468-200d-1f3ed", "man_factory_worker": "1f468-200d-1f3ed", "female-factory-worker": "1f469-200d-1f3ed", "woman_factory_worker": "1f469-200d-1f3ed", "office_worker": "1f9d1-200d-1f4bc", "male-office-worker": "1f468-200d-1f4bc", "man_office_worker": "1f468-200d-1f4bc", "female-office-worker": "1f469-200d-1f4bc", "woman_office_worker": "1f469-200d-1f4bc", "scientist": "1f9d1-200d-1f52c", "male-scientist": "1f468-200d-1f52c", "man_scientist": "1f468-200d-1f52c", "female-scientist": "1f469-200d-1f52c", "woman_scientist": "1f469-200d-1f52c", "technologist": "1f9d1-200d-1f4bb", "male-technologist": "1f468-200d-1f4bb", "man_technologist": "1f468-200d-1f4bb", "female-technologist": "1f469-200d-1f4bb", "woman_technologist": "1f469-200d-1f4bb", "singer": "1f9d1-200d-1f3a4", "male-singer": "1f468-200d-1f3a4", "man_singer": "1f468-200d-1f3a4", "female-singer": "1f469-200d-1f3a4", "woman_singer": "1f469-200d-1f3a4", "artist": "1f9d1-200d-1f3a8", "male-artist": "1f468-200d-1f3a8", "man_artist": "1f468-200d-1f3a8", "female-artist": "1f469-200d-1f3a8", "woman_artist": "1f469-200d-1f3a8", "pilot": "1f9d1-200d-2708-fe0f", "male-pilot": "1f468-200d-2708-fe0f", "man_pilot": "1f468-200d-2708-fe0f", "female-pilot": "1f469-200d-2708-fe0f", "woman_pilot": "1f469-200d-2708-fe0f", "astronaut": "1f9d1-200d-1f680", "male-astronaut": "1f468-200d-1f680", "man_astronaut": "1f468-200d-1f680", "female-astronaut": "1f469-200d-1f680", "woman_astronaut": "1f469-200d-1f680", "firefighter": "1f9d1-200d-1f692", "male-firefighter": "1f468-200d-1f692", "man_firefighter": "1f468-200d-1f692", "female-firefighter": "1f469-200d-1f692", "woman_firefighter": "1f469-200d-1f692", "cop": "1f46e", "male-police-officer": "1f46e-200d-2642-fe0f", "policeman": "1f46e-200d-2642-fe0f", "female-police-officer": "1f46e-200d-2640-fe0f", "policewoman": "1f46e-200d-2640-fe0f", "sleuth_or_spy": "1f575-fe0f", "detective": "1f575-fe0f", "male-detective": "1f575-fe0f-200d-2642-fe0f", "male_detective": "1f575-fe0f-200d-2642-fe0f", "female-detective": "1f575-fe0f-200d-2640-fe0f", "female_detective": "1f575-fe0f-200d-2640-fe0f", "guardsman": "1f482", "male-guard": "1f482-200d-2642-fe0f", "female-guard": "1f482-200d-2640-fe0f", "guardswoman": "1f482-200d-2640-fe0f", "ninja": "1f977", "construction_worker": "1f477", "male-construction-worker": "1f477-200d-2642-fe0f", "construction_worker_man": "1f477-200d-2642-fe0f", "female-construction-worker": "1f477-200d-2640-fe0f", "construction_worker_woman": "1f477-200d-2640-fe0f", "prince": "1f934", "princess": "1f478", "man_with_turban": "1f473", "man-wearing-turban": "1f473-200d-2642-fe0f", "woman-wearing-turban": "1f473-200d-2640-fe0f", "woman_with_turban": "1f473-200d-2640-fe0f", "man_with_gua_pi_mao": "1f472", "person_with_headscarf": "1f9d5", "person_in_tuxedo": "1f935", "man_in_tuxedo": "1f935-200d-2642-fe0f", "woman_in_tuxedo": "1f935-200d-2640-fe0f", "bride_with_veil": "1f470", "man_with_veil": "1f470-200d-2642-fe0f", "woman_with_veil": "1f470-200d-2640-fe0f", "pregnant_woman": "1f930", "breast-feeding": "1f931", "woman_feeding_baby": "1f469-200d-1f37c", "man_feeding_baby": "1f468-200d-1f37c", "person_feeding_baby": "1f9d1-200d-1f37c", "angel": "1f47c", "santa": "1f385", "mrs_claus": "1f936", "mother_christmas": "1f936", "mx_claus": "1f9d1-200d-1f384", "superhero": "1f9b8", "male_superhero": "1f9b8-200d-2642-fe0f", "female_superhero": "1f9b8-200d-2640-fe0f", "supervillain": "1f9b9", "male_supervillain": "1f9b9-200d-2642-fe0f", "female_supervillain": "1f9b9-200d-2640-fe0f", "mage": "1f9d9", "male_mage": "1f9d9-200d-2642-fe0f", "female_mage": "1f9d9-200d-2640-fe0f", "fairy": "1f9da", "male_fairy": "1f9da-200d-2642-fe0f", "female_fairy": "1f9da-200d-2640-fe0f", "vampire": "1f9db", "male_vampire": "1f9db-200d-2642-fe0f", "female_vampire": "1f9db-200d-2640-fe0f", "merperson": "1f9dc", "merman": "1f9dc-200d-2642-fe0f", "mermaid": "1f9dc-200d-2640-fe0f", "elf": "1f9dd", "male_elf": "1f9dd-200d-2642-fe0f", "female_elf": "1f9dd-200d-2640-fe0f", "genie": "1f9de", "male_genie": "1f9de-200d-2642-fe0f", "female_genie": "1f9de-200d-2640-fe0f", "zombie": "1f9df", "male_zombie": "1f9df-200d-2642-fe0f", "female_zombie": "1f9df-200d-2640-fe0f", "massage": "1f486", "man-getting-massage": "1f486-200d-2642-fe0f", "massage_man": "1f486-200d-2642-fe0f", "woman-getting-massage": "1f486-200d-2640-fe0f", "massage_woman": "1f486-200d-2640-fe0f", "haircut": "1f487", "man-getting-haircut": "1f487-200d-2642-fe0f", "haircut_man": "1f487-200d-2642-fe0f", "woman-getting-haircut": "1f487-200d-2640-fe0f", "haircut_woman": "1f487-200d-2640-fe0f", "walking": "1f6b6", "man-walking": "1f6b6-200d-2642-fe0f", "walking_man": "1f6b6-200d-2642-fe0f", "woman-walking": "1f6b6-200d-2640-fe0f", "walking_woman": "1f6b6-200d-2640-fe0f", "standing_person": "1f9cd", "man_standing": "1f9cd-200d-2642-fe0f", "woman_standing": "1f9cd-200d-2640-fe0f", "kneeling_person": "1f9ce", "man_kneeling": "1f9ce-200d-2642-fe0f", "woman_kneeling": "1f9ce-200d-2640-fe0f", "person_with_probing_cane": "1f9d1-200d-1f9af", "man_with_probing_cane": "1f468-200d-1f9af", "woman_with_probing_cane": "1f469-200d-1f9af", "person_in_motorized_wheelchair": "1f9d1-200d-1f9bc", "man_in_motorized_wheelchair": "1f468-200d-1f9bc", "woman_in_motorized_wheelchair": "1f469-200d-1f9bc", "person_in_manual_wheelchair": "1f9d1-200d-1f9bd", "man_in_manual_wheelchair": "1f468-200d-1f9bd", "woman_in_manual_wheelchair": "1f469-200d-1f9bd", "runner": "1f3c3", "running": "1f3c3", "man-running": "1f3c3-200d-2642-fe0f", "running_man": "1f3c3-200d-2642-fe0f", "woman-running": "1f3c3-200d-2640-fe0f", "running_woman": "1f3c3-200d-2640-fe0f", "dancer": "1f483", "man_dancing": "1f57a", "man_in_business_suit_levitating": "1f574-fe0f", "business_suit_levitating": "1f574-fe0f", "dancers": "1f46f", "man-with-bunny-ears-partying": "1f46f-200d-2642-fe0f", "dancing_men": "1f46f-200d-2642-fe0f", "woman-with-bunny-ears-partying": "1f46f-200d-2640-fe0f", "dancing_women": "1f46f-200d-2640-fe0f", "person_in_steamy_room": "1f9d6", "man_in_steamy_room": "1f9d6-200d-2642-fe0f", "woman_in_steamy_room": "1f9d6-200d-2640-fe0f", "person_climbing": "1f9d7", "man_climbing": "1f9d7-200d-2642-fe0f", "woman_climbing": "1f9d7-200d-2640-fe0f", "fencer": "1f93a", "person_fencing": "1f93a", "horse_racing": "1f3c7", "skier": "26f7-fe0f", "snowboarder": "1f3c2", "golfer": "1f3cc-fe0f", "man-golfing": "1f3cc-fe0f-200d-2642-fe0f", "golfing_man": "1f3cc-fe0f-200d-2642-fe0f", "woman-golfing": "1f3cc-fe0f-200d-2640-fe0f", "golfing_woman": "1f3cc-fe0f-200d-2640-fe0f", "surfer": "1f3c4", "man-surfing": "1f3c4-200d-2642-fe0f", "surfing_man": "1f3c4-200d-2642-fe0f", "woman-surfing": "1f3c4-200d-2640-fe0f", "surfing_woman": "1f3c4-200d-2640-fe0f", "rowboat": "1f6a3", "man-rowing-boat": "1f6a3-200d-2642-fe0f", "rowing_man": "1f6a3-200d-2642-fe0f", "woman-rowing-boat": "1f6a3-200d-2640-fe0f", "rowing_woman": "1f6a3-200d-2640-fe0f", "swimmer": "1f3ca", "man-swimming": "1f3ca-200d-2642-fe0f", "swimming_man": "1f3ca-200d-2642-fe0f", "woman-swimming": "1f3ca-200d-2640-fe0f", "swimming_woman": "1f3ca-200d-2640-fe0f", "person_with_ball": "26f9-fe0f", "man-bouncing-ball": "26f9-fe0f-200d-2642-fe0f", "basketball_man": "26f9-fe0f-200d-2642-fe0f", "woman-bouncing-ball": "26f9-fe0f-200d-2640-fe0f", "basketball_woman": "26f9-fe0f-200d-2640-fe0f", "weight_lifter": "1f3cb-fe0f", "man-lifting-weights": "1f3cb-fe0f-200d-2642-fe0f", "weight_lifting_man": "1f3cb-fe0f-200d-2642-fe0f", "woman-lifting-weights": "1f3cb-fe0f-200d-2640-fe0f", "weight_lifting_woman": "1f3cb-fe0f-200d-2640-fe0f", "bicyclist": "1f6b4", "man-biking": "1f6b4-200d-2642-fe0f", "biking_man": "1f6b4-200d-2642-fe0f", "woman-biking": "1f6b4-200d-2640-fe0f", "biking_woman": "1f6b4-200d-2640-fe0f", "mountain_bicyclist": "1f6b5", "man-mountain-biking": "1f6b5-200d-2642-fe0f", "mountain_biking_man": "1f6b5-200d-2642-fe0f", "woman-mountain-biking": "1f6b5-200d-2640-fe0f", "mountain_biking_woman": "1f6b5-200d-2640-fe0f", "person_doing_cartwheel": "1f938", "man-cartwheeling": "1f938-200d-2642-fe0f", "man_cartwheeling": "1f938-200d-2642-fe0f", "woman-cartwheeling": "1f938-200d-2640-fe0f", "woman_cartwheeling": "1f938-200d-2640-fe0f", "wrestlers": "1f93c", "man-wrestling": "1f93c-200d-2642-fe0f", "men_wrestling": "1f93c-200d-2642-fe0f", "woman-wrestling": "1f93c-200d-2640-fe0f", "women_wrestling": "1f93c-200d-2640-fe0f", "water_polo": "1f93d", "man-playing-water-polo": "1f93d-200d-2642-fe0f", "man_playing_water_polo": "1f93d-200d-2642-fe0f", "woman-playing-water-polo": "1f93d-200d-2640-fe0f", "woman_playing_water_polo": "1f93d-200d-2640-fe0f", "handball": "1f93e", "man-playing-handball": "1f93e-200d-2642-fe0f", "man_playing_handball": "1f93e-200d-2642-fe0f", "woman-playing-handball": "1f93e-200d-2640-fe0f", "woman_playing_handball": "1f93e-200d-2640-fe0f", "juggling": "1f939", "man-juggling": "1f939-200d-2642-fe0f", "man_juggling": "1f939-200d-2642-fe0f", "woman-juggling": "1f939-200d-2640-fe0f", "woman_juggling": "1f939-200d-2640-fe0f", "person_in_lotus_position": "1f9d8", "man_in_lotus_position": "1f9d8-200d-2642-fe0f", "woman_in_lotus_position": "1f9d8-200d-2640-fe0f", "bath": "1f6c0", "sleeping_accommodation": "1f6cc", "sleeping_bed": "1f6cc", "people_holding_hands": "1f9d1-200d-1f91d-200d-1f9d1", "two_women_holding_hands": "1f46d", "women_holding_hands": "1f46d", "man_and_woman_holding_hands": "1f46b", "woman_and_man_holding_hands": "1f46b", "couple": "1f46b", "two_men_holding_hands": "1f46c", "men_holding_hands": "1f46c", "couplekiss": "1f48f", "woman-kiss-man": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f468", "couplekiss_man_woman": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f468", "man-kiss-man": "1f468-200d-2764-fe0f-200d-1f48b-200d-1f468", "couplekiss_man_man": "1f468-200d-2764-fe0f-200d-1f48b-200d-1f468", "woman-kiss-woman": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f469", "couplekiss_woman_woman": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f469", "couple_with_heart": "1f491", "woman-heart-man": "1f469-200d-2764-fe0f-200d-1f468", "couple_with_heart_woman_man": "1f469-200d-2764-fe0f-200d-1f468", "man-heart-man": "1f468-200d-2764-fe0f-200d-1f468", "couple_with_heart_man_man": "1f468-200d-2764-fe0f-200d-1f468", "woman-heart-woman": "1f469-200d-2764-fe0f-200d-1f469", "couple_with_heart_woman_woman": "1f469-200d-2764-fe0f-200d-1f469", "family": "1f46a", "man-woman-boy": "1f468-200d-1f469-200d-1f466", "family_man_woman_boy": "1f468-200d-1f469-200d-1f466", "man-woman-girl": "1f468-200d-1f469-200d-1f467", "family_man_woman_girl": "1f468-200d-1f469-200d-1f467", "man-woman-girl-boy": "1f468-200d-1f469-200d-1f467-200d-1f466", "family_man_woman_girl_boy": "1f468-200d-1f469-200d-1f467-200d-1f466", "man-woman-boy-boy": "1f468-200d-1f469-200d-1f466-200d-1f466", "family_man_woman_boy_boy": "1f468-200d-1f469-200d-1f466-200d-1f466", "man-woman-girl-girl": "1f468-200d-1f469-200d-1f467-200d-1f467", "family_man_woman_girl_girl": "1f468-200d-1f469-200d-1f467-200d-1f467", "man-man-boy": "1f468-200d-1f468-200d-1f466", "family_man_man_boy": "1f468-200d-1f468-200d-1f466", "man-man-girl": "1f468-200d-1f468-200d-1f467", "family_man_man_girl": "1f468-200d-1f468-200d-1f467", "man-man-girl-boy": "1f468-200d-1f468-200d-1f467-200d-1f466", "family_man_man_girl_boy": "1f468-200d-1f468-200d-1f467-200d-1f466", "man-man-boy-boy": "1f468-200d-1f468-200d-1f466-200d-1f466", "family_man_man_boy_boy": "1f468-200d-1f468-200d-1f466-200d-1f466", "man-man-girl-girl": "1f468-200d-1f468-200d-1f467-200d-1f467", "family_man_man_girl_girl": "1f468-200d-1f468-200d-1f467-200d-1f467", "woman-woman-boy": "1f469-200d-1f469-200d-1f466", "family_woman_woman_boy": "1f469-200d-1f469-200d-1f466", "woman-woman-girl": "1f469-200d-1f469-200d-1f467", "family_woman_woman_girl": "1f469-200d-1f469-200d-1f467", "woman-woman-girl-boy": "1f469-200d-1f469-200d-1f467-200d-1f466", "family_woman_woman_girl_boy": "1f469-200d-1f469-200d-1f467-200d-1f466", "woman-woman-boy-boy": "1f469-200d-1f469-200d-1f466-200d-1f466", "family_woman_woman_boy_boy": "1f469-200d-1f469-200d-1f466-200d-1f466", "woman-woman-girl-girl": "1f469-200d-1f469-200d-1f467-200d-1f467", "family_woman_woman_girl_girl": "1f469-200d-1f469-200d-1f467-200d-1f467", "man-boy": "1f468-200d-1f466", "family_man_boy": "1f468-200d-1f466", "man-boy-boy": "1f468-200d-1f466-200d-1f466", "family_man_boy_boy": "1f468-200d-1f466-200d-1f466", "man-girl": "1f468-200d-1f467", "family_man_girl": "1f468-200d-1f467", "man-girl-boy": "1f468-200d-1f467-200d-1f466", "family_man_girl_boy": "1f468-200d-1f467-200d-1f466", "man-girl-girl": "1f468-200d-1f467-200d-1f467", "family_man_girl_girl": "1f468-200d-1f467-200d-1f467", "woman-boy": "1f469-200d-1f466", "family_woman_boy": "1f469-200d-1f466", "woman-boy-boy": "1f469-200d-1f466-200d-1f466", "family_woman_boy_boy": "1f469-200d-1f466-200d-1f466", "woman-girl": "1f469-200d-1f467", "family_woman_girl": "1f469-200d-1f467", "woman-girl-boy": "1f469-200d-1f467-200d-1f466", "family_woman_girl_boy": "1f469-200d-1f467-200d-1f466", "woman-girl-girl": "1f469-200d-1f467-200d-1f467", "family_woman_girl_girl": "1f469-200d-1f467-200d-1f467", "speaking_head_in_silhouette": "1f5e3-fe0f", "speaking_head": "1f5e3-fe0f", "bust_in_silhouette": "1f464", "busts_in_silhouette": "1f465", "people_hugging": "1fac2", "footprints": "1f463", "skin-tone-2": "1f3fb", "skin-tone-3": "1f3fc", "skin-tone-4": "1f3fd", "skin-tone-5": "1f3fe", "skin-tone-6": "1f3ff", "monkey_face": "1f435", "monkey": "1f412", "gorilla": "1f98d", "orangutan": "1f9a7", "dog": "1f436", "dog2": "1f415", "guide_dog": "1f9ae", "service_dog": "1f415-200d-1f9ba", "poodle": "1f429", "wolf": "1f43a", "fox_face": "1f98a", "raccoon": "1f99d", "cat": "1f431", "cat2": "1f408", "black_cat": "1f408-200d-2b1b", "lion_face": "1f981", "lion": "1f981", "tiger": "1f42f", "tiger2": "1f405", "leopard": "1f406", "horse": "1f434", "racehorse": "1f40e", "unicorn_face": "1f984", "unicorn": "1f984", "zebra_face": "1f993", "deer": "1f98c", "bison": "1f9ac", "cow": "1f42e", "ox": "1f402", "water_buffalo": "1f403", "cow2": "1f404", "pig": "1f437", "pig2": "1f416", "boar": "1f417", "pig_nose": "1f43d", "ram": "1f40f", "sheep": "1f411", "goat": "1f410", "dromedary_camel": "1f42a", "camel": "1f42b", "llama": "1f999", "giraffe_face": "1f992", "elephant": "1f418", "mammoth": "1f9a3", "rhinoceros": "1f98f", "hippopotamus": "1f99b", "mouse": "1f42d", "mouse2": "1f401", "rat": "1f400", "hamster": "1f439", "rabbit": "1f430", "rabbit2": "1f407", "chipmunk": "1f43f-fe0f", "beaver": "1f9ab", "hedgehog": "1f994", "bat": "1f987", "bear": "1f43b", "polar_bear": "1f43b-200d-2744-fe0f", "koala": "1f428", "panda_face": "1f43c", "sloth": "1f9a5", "otter": "1f9a6", "skunk": "1f9a8", "kangaroo": "1f998", "badger": "1f9a1", "feet": "1f43e", "paw_prints": "1f43e", "turkey": "1f983", "chicken": "1f414", "rooster": "1f413", "hatching_chick": "1f423", "baby_chick": "1f424", "hatched_chick": "1f425", "bird": "1f426", "penguin": "1f427", "dove_of_peace": "1f54a-fe0f", "dove": "1f54a-fe0f", "eagle": "1f985", "duck": "1f986", "swan": "1f9a2", "owl": "1f989", "dodo": "1f9a4", "feather": "1fab6", "flamingo": "1f9a9", "peacock": "1f99a", "parrot": "1f99c", "frog": "1f438", "crocodile": "1f40a", "turtle": "1f422", "lizard": "1f98e", "snake": "1f40d", "dragon_face": "1f432", "dragon": "1f409", "sauropod": "1f995", "t-rex": "1f996", "whale": "1f433", "whale2": "1f40b", "dolphin": "1f42c", "flipper": "1f42c", "seal": "1f9ad", "fish": "1f41f", "tropical_fish": "1f420", "blowfish": "1f421", "shark": "1f988", "octopus": "1f419", "shell": "1f41a", "snail": "1f40c", "butterfly": "1f98b", "bug": "1f41b", "ant": "1f41c", "bee": "1f41d", "honeybee": "1f41d", "beetle": "1fab2", "ladybug": "1f41e", "lady_beetle": "1f41e", "cricket": "1f997", "cockroach": "1fab3", "spider": "1f577-fe0f", "spider_web": "1f578-fe0f", "scorpion": "1f982", "mosquito": "1f99f", "fly": "1fab0", "worm": "1fab1", "microbe": "1f9a0", "bouquet": "1f490", "cherry_blossom": "1f338", "white_flower": "1f4ae", "rosette": "1f3f5-fe0f", "rose": "1f339", "wilted_flower": "1f940", "hibiscus": "1f33a", "sunflower": "1f33b", "blossom": "1f33c", "tulip": "1f337", "seedling": "1f331", "potted_plant": "1fab4", "evergreen_tree": "1f332", "deciduous_tree": "1f333", "palm_tree": "1f334", "cactus": "1f335", "ear_of_rice": "1f33e", "herb": "1f33f", "shamrock": "2618-fe0f", "four_leaf_clover": "1f340", "maple_leaf": "1f341", "fallen_leaf": "1f342", "leaves": "1f343", "grapes": "1f347", "melon": "1f348", "watermelon": "1f349", "tangerine": "1f34a", "mandarin": "1f34a", "orange": "1f34a", "lemon": "1f34b", "banana": "1f34c", "pineapple": "1f34d", "mango": "1f96d", "apple": "1f34e", "green_apple": "1f34f", "pear": "1f350", "peach": "1f351", "cherries": "1f352", "strawberry": "1f353", "blueberries": "1fad0", "kiwifruit": "1f95d", "kiwi_fruit": "1f95d", "tomato": "1f345", "olive": "1fad2", "coconut": "1f965", "avocado": "1f951", "eggplant": "1f346", "potato": "1f954", "carrot": "1f955", "corn": "1f33d", "hot_pepper": "1f336-fe0f", "bell_pepper": "1fad1", "cucumber": "1f952", "leafy_green": "1f96c", "broccoli": "1f966", "garlic": "1f9c4", "onion": "1f9c5", "mushroom": "1f344", "peanuts": "1f95c", "chestnut": "1f330", "bread": "1f35e", "croissant": "1f950", "baguette_bread": "1f956", "flatbread": "1fad3", "pretzel": "1f968", "bagel": "1f96f", "pancakes": "1f95e", "waffle": "1f9c7", "cheese_wedge": "1f9c0", "cheese": "1f9c0", "meat_on_bone": "1f356", "poultry_leg": "1f357", "cut_of_meat": "1f969", "bacon": "1f953", "hamburger": "1f354", "fries": "1f35f", "pizza": "1f355", "hotdog": "1f32d", "sandwich": "1f96a", "taco": "1f32e", "burrito": "1f32f", "tamale": "1fad4", "stuffed_flatbread": "1f959", "falafel": "1f9c6", "egg": "1f95a", "fried_egg": "1f373", "cooking": "1f373", "shallow_pan_of_food": "1f958", "stew": "1f372", "fondue": "1fad5", "bowl_with_spoon": "1f963", "green_salad": "1f957", "popcorn": "1f37f", "butter": "1f9c8", "salt": "1f9c2", "canned_food": "1f96b", "bento": "1f371", "rice_cracker": "1f358", "rice_ball": "1f359", "rice": "1f35a", "curry": "1f35b", "ramen": "1f35c", "spaghetti": "1f35d", "sweet_potato": "1f360", "oden": "1f362", "sushi": "1f363", "fried_shrimp": "1f364", "fish_cake": "1f365", "moon_cake": "1f96e", "dango": "1f361", "dumpling": "1f95f", "fortune_cookie": "1f960", "takeout_box": "1f961", "crab": "1f980", "lobster": "1f99e", "shrimp": "1f990", "squid": "1f991", "oyster": "1f9aa", "icecream": "1f366", "shaved_ice": "1f367", "ice_cream": "1f368", "doughnut": "1f369", "cookie": "1f36a", "birthday": "1f382", "cake": "1f370", "cupcake": "1f9c1", "pie": "1f967", "chocolate_bar": "1f36b", "candy": "1f36c", "lollipop": "1f36d", "custard": "1f36e", "honey_pot": "1f36f", "baby_bottle": "1f37c", "glass_of_milk": "1f95b", "milk_glass": "1f95b", "coffee": "2615", "teapot": "1fad6", "tea": "1f375", "sake": "1f376", "champagne": "1f37e", "wine_glass": "1f377", "cocktail": "1f378", "tropical_drink": "1f379", "beer": "1f37a", "beers": "1f37b", "clinking_glasses": "1f942", "tumbler_glass": "1f943", "cup_with_straw": "1f964", "bubble_tea": "1f9cb", "beverage_box": "1f9c3", "mate_drink": "1f9c9", "ice_cube": "1f9ca", "chopsticks": "1f962", "knife_fork_plate": "1f37d-fe0f", "plate_with_cutlery": "1f37d-fe0f", "fork_and_knife": "1f374", "spoon": "1f944", "hocho": "1f52a", "knife": "1f52a", "amphora": "1f3fa", "earth_africa": "1f30d", "earth_americas": "1f30e", "earth_asia": "1f30f", "globe_with_meridians": "1f310", "world_map": "1f5fa-fe0f", "japan": "1f5fe", "compass": "1f9ed", "snow_capped_mountain": "1f3d4-fe0f", "mountain_snow": "1f3d4-fe0f", "mountain": "26f0-fe0f", "volcano": "1f30b", "mount_fuji": "1f5fb", "camping": "1f3d5-fe0f", "beach_with_umbrella": "1f3d6-fe0f", "beach_umbrella": "1f3d6-fe0f", "desert": "1f3dc-fe0f", "desert_island": "1f3dd-fe0f", "national_park": "1f3de-fe0f", "stadium": "1f3df-fe0f", "classical_building": "1f3db-fe0f", "building_construction": "1f3d7-fe0f", "bricks": "1f9f1", "rock": "1faa8", "wood": "1fab5", "hut": "1f6d6", "house_buildings": "1f3d8-fe0f", "houses": "1f3d8-fe0f", "derelict_house_building": "1f3da-fe0f", "derelict_house": "1f3da-fe0f", "house": "1f3e0", "house_with_garden": "1f3e1", "office": "1f3e2", "post_office": "1f3e3", "european_post_office": "1f3e4", "hospital": "1f3e5", "bank": "1f3e6", "hotel": "1f3e8", "love_hotel": "1f3e9", "convenience_store": "1f3ea", "school": "1f3eb", "department_store": "1f3ec", "factory": "1f3ed", "japanese_castle": "1f3ef", "european_castle": "1f3f0", "wedding": "1f492", "tokyo_tower": "1f5fc", "statue_of_liberty": "1f5fd", "church": "26ea", "mosque": "1f54c", "hindu_temple": "1f6d5", "synagogue": "1f54d", "shinto_shrine": "26e9-fe0f", "kaaba": "1f54b", "fountain": "26f2", "tent": "26fa", "foggy": "1f301", "night_with_stars": "1f303", "cityscape": "1f3d9-fe0f", "sunrise_over_mountains": "1f304", "sunrise": "1f305", "city_sunset": "1f306", "city_sunrise": "1f307", "bridge_at_night": "1f309", "hotsprings": "2668-fe0f", "carousel_horse": "1f3a0", "ferris_wheel": "1f3a1", "roller_coaster": "1f3a2", "barber": "1f488", "circus_tent": "1f3aa", "steam_locomotive": "1f682", "railway_car": "1f683", "bullettrain_side": "1f684", "bullettrain_front": "1f685", "train2": "1f686", "metro": "1f687", "light_rail": "1f688", "station": "1f689", "tram": "1f68a", "monorail": "1f69d", "mountain_railway": "1f69e", "train": "1f68b", "bus": "1f68c", "oncoming_bus": "1f68d", "trolleybus": "1f68e", "minibus": "1f690", "ambulance": "1f691", "fire_engine": "1f692", "police_car": "1f693", "oncoming_police_car": "1f694", "taxi": "1f695", "oncoming_taxi": "1f696", "car": "1f697", "red_car": "1f697", "oncoming_automobile": "1f698", "blue_car": "1f699", "pickup_truck": "1f6fb", "truck": "1f69a", "articulated_lorry": "1f69b", "tractor": "1f69c", "racing_car": "1f3ce-fe0f", "racing_motorcycle": "1f3cd-fe0f", "motorcycle": "1f3cd-fe0f", "motor_scooter": "1f6f5", "manual_wheelchair": "1f9bd", "motorized_wheelchair": "1f9bc", "auto_rickshaw": "1f6fa", "bike": "1f6b2", "scooter": "1f6f4", "kick_scooter": "1f6f4", "skateboard": "1f6f9", "roller_skate": "1f6fc", "busstop": "1f68f", "motorway": "1f6e3-fe0f", "railway_track": "1f6e4-fe0f", "oil_drum": "1f6e2-fe0f", "fuelpump": "26fd", "rotating_light": "1f6a8", "traffic_light": "1f6a5", "vertical_traffic_light": "1f6a6", "octagonal_sign": "1f6d1", "stop_sign": "1f6d1", "construction": "1f6a7", "anchor": "2693", "boat": "26f5", "sailboat": "26f5", "canoe": "1f6f6", "speedboat": "1f6a4", "passenger_ship": "1f6f3-fe0f", "ferry": "26f4-fe0f", "motor_boat": "1f6e5-fe0f", "ship": "1f6a2", "airplane": "2708-fe0f", "small_airplane": "1f6e9-fe0f", "airplane_departure": "1f6eb", "flight_departure": "1f6eb", "airplane_arriving": "1f6ec", "flight_arrival": "1f6ec", "parachute": "1fa82", "seat": "1f4ba", "helicopter": "1f681", "suspension_railway": "1f69f", "mountain_cableway": "1f6a0", "aerial_tramway": "1f6a1", "satellite": "1f6f0-fe0f", "artificial_satellite": "1f6f0-fe0f", "rocket": "1f680", "flying_saucer": "1f6f8", "bellhop_bell": "1f6ce-fe0f", "luggage": "1f9f3", "hourglass": "231b", "hourglass_flowing_sand": "23f3", "watch": "231a", "alarm_clock": "23f0", "stopwatch": "23f1-fe0f", "timer_clock": "23f2-fe0f", "mantelpiece_clock": "1f570-fe0f", "clock12": "1f55b", "clock1230": "1f567", "clock1": "1f550", "clock130": "1f55c", "clock2": "1f551", "clock230": "1f55d", "clock3": "1f552", "clock330": "1f55e", "clock4": "1f553", "clock430": "1f55f", "clock5": "1f554", "clock530": "1f560", "clock6": "1f555", "clock630": "1f561", "clock7": "1f556", "clock730": "1f562", "clock8": "1f557", "clock830": "1f563", "clock9": "1f558", "clock930": "1f564", "clock10": "1f559", "clock1030": "1f565", "clock11": "1f55a", "clock1130": "1f566", "new_moon": "1f311", "waxing_crescent_moon": "1f312", "first_quarter_moon": "1f313", "moon": "1f314", "waxing_gibbous_moon": "1f314", "full_moon": "1f315", "waning_gibbous_moon": "1f316", "last_quarter_moon": "1f317", "waning_crescent_moon": "1f318", "crescent_moon": "1f319", "new_moon_with_face": "1f31a", "first_quarter_moon_with_face": "1f31b", "last_quarter_moon_with_face": "1f31c", "thermometer": "1f321-fe0f", "sunny": "2600-fe0f", "full_moon_with_face": "1f31d", "sun_with_face": "1f31e", "ringed_planet": "1fa90", "star": "2b50", "star2": "1f31f", "stars": "1f320", "milky_way": "1f30c", "cloud": "2601-fe0f", "partly_sunny": "26c5", "thunder_cloud_and_rain": "26c8-fe0f", "cloud_with_lightning_and_rain": "26c8-fe0f", "mostly_sunny": "1f324-fe0f", "sun_small_cloud": "1f324-fe0f", "sun_behind_small_cloud": "1f324-fe0f", "barely_sunny": "1f325-fe0f", "sun_behind_cloud": "1f325-fe0f", "sun_behind_large_cloud": "1f325-fe0f", "partly_sunny_rain": "1f326-fe0f", "sun_behind_rain_cloud": "1f326-fe0f", "rain_cloud": "1f327-fe0f", "cloud_with_rain": "1f327-fe0f", "snow_cloud": "1f328-fe0f", "cloud_with_snow": "1f328-fe0f", "lightning": "1f329-fe0f", "lightning_cloud": "1f329-fe0f", "cloud_with_lightning": "1f329-fe0f", "tornado": "1f32a-fe0f", "tornado_cloud": "1f32a-fe0f", "fog": "1f32b-fe0f", "wind_blowing_face": "1f32c-fe0f", "wind_face": "1f32c-fe0f", "cyclone": "1f300", "rainbow": "1f308", "closed_umbrella": "1f302", "umbrella": "2602-fe0f", "open_umbrella": "2602-fe0f", "umbrella_with_rain_drops": "2614", "umbrella_on_ground": "26f1-fe0f", "parasol_on_ground": "26f1-fe0f", "zap": "26a1", "snowflake": "2744-fe0f", "snowman": "2603-fe0f", "snowman_with_snow": "2603-fe0f", "snowman_without_snow": "26c4", "comet": "2604-fe0f", "fire": "1f525", "droplet": "1f4a7", "ocean": "1f30a", "jack_o_lantern": "1f383", "christmas_tree": "1f384", "fireworks": "1f386", "sparkler": "1f387", "firecracker": "1f9e8", "sparkles": "2728", "balloon": "1f388", "tada": "1f389", "confetti_ball": "1f38a", "tanabata_tree": "1f38b", "bamboo": "1f38d", "dolls": "1f38e", "flags": "1f38f", "wind_chime": "1f390", "rice_scene": "1f391", "red_envelope": "1f9e7", "ribbon": "1f380", "gift": "1f381", "reminder_ribbon": "1f397-fe0f", "admission_tickets": "1f39f-fe0f", "tickets": "1f39f-fe0f", "ticket": "1f3ab", "medal": "1f396-fe0f", "medal_military": "1f396-fe0f", "trophy": "1f3c6", "sports_medal": "1f3c5", "medal_sports": "1f3c5", "first_place_medal": "1f947", "1st_place_medal": "1f947", "second_place_medal": "1f948", "2nd_place_medal": "1f948", "third_place_medal": "1f949", "3rd_place_medal": "1f949", "soccer": "26bd", "baseball": "26be", "softball": "1f94e", "basketball": "1f3c0", "volleyball": "1f3d0", "football": "1f3c8", "rugby_football": "1f3c9", "tennis": "1f3be", "flying_disc": "1f94f", "bowling": "1f3b3", "cricket_bat_and_ball": "1f3cf", "field_hockey_stick_and_ball": "1f3d1", "field_hockey": "1f3d1", "ice_hockey_stick_and_puck": "1f3d2", "ice_hockey": "1f3d2", "lacrosse": "1f94d", "table_tennis_paddle_and_ball": "1f3d3", "ping_pong": "1f3d3", "badminton_racquet_and_shuttlecock": "1f3f8", "badminton": "1f3f8", "boxing_glove": "1f94a", "martial_arts_uniform": "1f94b", "goal_net": "1f945", "golf": "26f3", "ice_skate": "26f8-fe0f", "fishing_pole_and_fish": "1f3a3", "diving_mask": "1f93f", "running_shirt_with_sash": "1f3bd", "ski": "1f3bf", "sled": "1f6f7", "curling_stone": "1f94c", "dart": "1f3af", "yo-yo": "1fa80", "kite": "1fa81", "8ball": "1f3b1", "crystal_ball": "1f52e", "magic_wand": "1fa84", "nazar_amulet": "1f9ff", "video_game": "1f3ae", "joystick": "1f579-fe0f", "slot_machine": "1f3b0", "game_die": "1f3b2", "jigsaw": "1f9e9", "teddy_bear": "1f9f8", "pinata": "1fa85", "nesting_dolls": "1fa86", "spades": "2660-fe0f", "hearts": "2665-fe0f", "diamonds": "2666-fe0f", "clubs": "2663-fe0f", "chess_pawn": "265f-fe0f", "black_joker": "1f0cf", "mahjong": "1f004", "flower_playing_cards": "1f3b4", "performing_arts": "1f3ad", "frame_with_picture": "1f5bc-fe0f", "framed_picture": "1f5bc-fe0f", "art": "1f3a8", "thread": "1f9f5", "sewing_needle": "1faa1", "yarn": "1f9f6", "knot": "1faa2", "eyeglasses": "1f453", "dark_sunglasses": "1f576-fe0f", "goggles": "1f97d", "lab_coat": "1f97c", "safety_vest": "1f9ba", "necktie": "1f454", "shirt": "1f455", "tshirt": "1f455", "jeans": "1f456", "scarf": "1f9e3", "gloves": "1f9e4", "coat": "1f9e5", "socks": "1f9e6", "dress": "1f457", "kimono": "1f458", "sari": "1f97b", "one-piece_swimsuit": "1fa71", "briefs": "1fa72", "shorts": "1fa73", "bikini": "1f459", "womans_clothes": "1f45a", "purse": "1f45b", "handbag": "1f45c", "pouch": "1f45d", "shopping_bags": "1f6cd-fe0f", "shopping": "1f6cd-fe0f", "school_satchel": "1f392", "thong_sandal": "1fa74", "mans_shoe": "1f45e", "shoe": "1f45e", "athletic_shoe": "1f45f", "hiking_boot": "1f97e", "womans_flat_shoe": "1f97f", "high_heel": "1f460", "sandal": "1f461", "ballet_shoes": "1fa70", "boot": "1f462", "crown": "1f451", "womans_hat": "1f452", "tophat": "1f3a9", "mortar_board": "1f393", "billed_cap": "1f9e2", "military_helmet": "1fa96", "helmet_with_white_cross": "26d1-fe0f", "rescue_worker_helmet": "26d1-fe0f", "prayer_beads": "1f4ff", "lipstick": "1f484", "ring": "1f48d", "gem": "1f48e", "mute": "1f507", "speaker": "1f508", "sound": "1f509", "loud_sound": "1f50a", "loudspeaker": "1f4e2", "mega": "1f4e3", "postal_horn": "1f4ef", "bell": "1f514", "no_bell": "1f515", "musical_score": "1f3bc", "musical_note": "1f3b5", "notes": "1f3b6", "studio_microphone": "1f399-fe0f", "level_slider": "1f39a-fe0f", "control_knobs": "1f39b-fe0f", "microphone": "1f3a4", "headphones": "1f3a7", "radio": "1f4fb", "saxophone": "1f3b7", "accordion": "1fa97", "guitar": "1f3b8", "musical_keyboard": "1f3b9", "trumpet": "1f3ba", "violin": "1f3bb", "banjo": "1fa95", "drum_with_drumsticks": "1f941", "drum": "1f941", "long_drum": "1fa98", "iphone": "1f4f1", "calling": "1f4f2", "phone": "260e-fe0f", "telephone": "260e-fe0f", "telephone_receiver": "1f4de", "pager": "1f4df", "fax": "1f4e0", "battery": "1f50b", "electric_plug": "1f50c", "computer": "1f4bb", "desktop_computer": "1f5a5-fe0f", "printer": "1f5a8-fe0f", "keyboard": "2328-fe0f", "three_button_mouse": "1f5b1-fe0f", "computer_mouse": "1f5b1-fe0f", "trackball": "1f5b2-fe0f", "minidisc": "1f4bd", "floppy_disk": "1f4be", "cd": "1f4bf", "dvd": "1f4c0", "abacus": "1f9ee", "movie_camera": "1f3a5", "film_frames": "1f39e-fe0f", "film_strip": "1f39e-fe0f", "film_projector": "1f4fd-fe0f", "clapper": "1f3ac", "tv": "1f4fa", "camera": "1f4f7", "camera_with_flash": "1f4f8", "camera_flash": "1f4f8", "video_camera": "1f4f9", "vhs": "1f4fc", "mag": "1f50d", "mag_right": "1f50e", "candle": "1f56f-fe0f", "bulb": "1f4a1", "flashlight": "1f526", "izakaya_lantern": "1f3ee", "lantern": "1f3ee", "diya_lamp": "1fa94", "notebook_with_decorative_cover": "1f4d4", "closed_book": "1f4d5", "book": "1f4d6", "open_book": "1f4d6", "green_book": "1f4d7", "blue_book": "1f4d8", "orange_book": "1f4d9", "books": "1f4da", "notebook": "1f4d3", "ledger": "1f4d2", "page_with_curl": "1f4c3", "scroll": "1f4dc", "page_facing_up": "1f4c4", "newspaper": "1f4f0", "rolled_up_newspaper": "1f5de-fe0f", "newspaper_roll": "1f5de-fe0f", "bookmark_tabs": "1f4d1", "bookmark": "1f516", "label": "1f3f7-fe0f", "moneybag": "1f4b0", "coin": "1fa99", "yen": "1f4b4", "dollar": "1f4b5", "euro": "1f4b6", "pound": "1f4b7", "money_with_wings": "1f4b8", "credit_card": "1f4b3", "receipt": "1f9fe", "chart": "1f4b9", "email": "2709-fe0f", "envelope": "2709-fe0f", "e-mail": "1f4e7", "incoming_envelope": "1f4e8", "envelope_with_arrow": "1f4e9", "outbox_tray": "1f4e4", "inbox_tray": "1f4e5", "package": "1f4e6", "mailbox": "1f4eb", "mailbox_closed": "1f4ea", "mailbox_with_mail": "1f4ec", "mailbox_with_no_mail": "1f4ed", "postbox": "1f4ee", "ballot_box_with_ballot": "1f5f3-fe0f", "ballot_box": "1f5f3-fe0f", "pencil2": "270f-fe0f", "black_nib": "2712-fe0f", "lower_left_fountain_pen": "1f58b-fe0f", "fountain_pen": "1f58b-fe0f", "lower_left_ballpoint_pen": "1f58a-fe0f", "pen": "1f58a-fe0f", "lower_left_paintbrush": "1f58c-fe0f", "paintbrush": "1f58c-fe0f", "lower_left_crayon": "1f58d-fe0f", "crayon": "1f58d-fe0f", "memo": "1f4dd", "pencil": "1f4dd", "briefcase": "1f4bc", "file_folder": "1f4c1", "open_file_folder": "1f4c2", "card_index_dividers": "1f5c2-fe0f", "date": "1f4c5", "calendar": "1f4c6", "spiral_note_pad": "1f5d2-fe0f", "spiral_notepad": "1f5d2-fe0f", "spiral_calendar_pad": "1f5d3-fe0f", "spiral_calendar": "1f5d3-fe0f", "card_index": "1f4c7", "chart_with_upwards_trend": "1f4c8", "chart_with_downwards_trend": "1f4c9", "bar_chart": "1f4ca", "clipboard": "1f4cb", "pushpin": "1f4cc", "round_pushpin": "1f4cd", "paperclip": "1f4ce", "linked_paperclips": "1f587-fe0f", "paperclips": "1f587-fe0f", "straight_ruler": "1f4cf", "triangular_ruler": "1f4d0", "scissors": "2702-fe0f", "card_file_box": "1f5c3-fe0f", "file_cabinet": "1f5c4-fe0f", "wastebasket": "1f5d1-fe0f", "lock": "1f512", "unlock": "1f513", "lock_with_ink_pen": "1f50f", "closed_lock_with_key": "1f510", "key": "1f511", "old_key": "1f5dd-fe0f", "hammer": "1f528", "axe": "1fa93", "pick": "26cf-fe0f", "hammer_and_pick": "2692-fe0f", "hammer_and_wrench": "1f6e0-fe0f", "dagger_knife": "1f5e1-fe0f", "dagger": "1f5e1-fe0f", "crossed_swords": "2694-fe0f", "gun": "1f52b", "boomerang": "1fa83", "bow_and_arrow": "1f3f9", "shield": "1f6e1-fe0f", "carpentry_saw": "1fa9a", "wrench": "1f527", "screwdriver": "1fa9b", "nut_and_bolt": "1f529", "gear": "2699-fe0f", "compression": "1f5dc-fe0f", "clamp": "1f5dc-fe0f", "scales": "2696-fe0f", "balance_scale": "2696-fe0f", "probing_cane": "1f9af", "link": "1f517", "chains": "26d3-fe0f", "hook": "1fa9d", "toolbox": "1f9f0", "magnet": "1f9f2", "ladder": "1fa9c", "alembic": "2697-fe0f", "test_tube": "1f9ea", "petri_dish": "1f9eb", "dna": "1f9ec", "microscope": "1f52c", "telescope": "1f52d", "satellite_antenna": "1f4e1", "syringe": "1f489", "drop_of_blood": "1fa78", "pill": "1f48a", "adhesive_bandage": "1fa79", "stethoscope": "1fa7a", "door": "1f6aa", "elevator": "1f6d7", "mirror": "1fa9e", "window": "1fa9f", "bed": "1f6cf-fe0f", "couch_and_lamp": "1f6cb-fe0f", "chair": "1fa91", "toilet": "1f6bd", "plunger": "1faa0", "shower": "1f6bf", "bathtub": "1f6c1", "mouse_trap": "1faa4", "razor": "1fa92", "lotion_bottle": "1f9f4", "safety_pin": "1f9f7", "broom": "1f9f9", "basket": "1f9fa", "roll_of_paper": "1f9fb", "bucket": "1faa3", "soap": "1f9fc", "toothbrush": "1faa5", "sponge": "1f9fd", "fire_extinguisher": "1f9ef", "shopping_trolley": "1f6d2", "shopping_cart": "1f6d2", "smoking": "1f6ac", "coffin": "26b0-fe0f", "headstone": "1faa6", "funeral_urn": "26b1-fe0f", "moyai": "1f5ff", "placard": "1faa7", "atm": "1f3e7", "put_litter_in_its_place": "1f6ae", "potable_water": "1f6b0", "wheelchair": "267f", "mens": "1f6b9", "womens": "1f6ba", "restroom": "1f6bb", "baby_symbol": "1f6bc", "wc": "1f6be", "passport_control": "1f6c2", "customs": "1f6c3", "baggage_claim": "1f6c4", "left_luggage": "1f6c5", "warning": "26a0-fe0f", "children_crossing": "1f6b8", "no_entry": "26d4", "no_entry_sign": "1f6ab", "no_bicycles": "1f6b3", "no_smoking": "1f6ad", "do_not_litter": "1f6af", "non-potable_water": "1f6b1", "no_pedestrians": "1f6b7", "no_mobile_phones": "1f4f5", "underage": "1f51e", "radioactive_sign": "2622-fe0f", "radioactive": "2622-fe0f", "biohazard_sign": "2623-fe0f", "biohazard": "2623-fe0f", "arrow_up": "2b06-fe0f", "arrow_upper_right": "2197-fe0f", "arrow_right": "27a1-fe0f", "arrow_lower_right": "2198-fe0f", "arrow_down": "2b07-fe0f", "arrow_lower_left": "2199-fe0f", "arrow_left": "2b05-fe0f", "arrow_upper_left": "2196-fe0f", "arrow_up_down": "2195-fe0f", "left_right_arrow": "2194-fe0f", "leftwards_arrow_with_hook": "21a9-fe0f", "arrow_right_hook": "21aa-fe0f", "arrow_heading_up": "2934-fe0f", "arrow_heading_down": "2935-fe0f", "arrows_clockwise": "1f503", "arrows_counterclockwise": "1f504", "back": "1f519", "end": "1f51a", "on": "1f51b", "soon": "1f51c", "top": "1f51d", "place_of_worship": "1f6d0", "atom_symbol": "269b-fe0f", "om_symbol": "1f549-fe0f", "om": "1f549-fe0f", "star_of_david": "2721-fe0f", "wheel_of_dharma": "2638-fe0f", "yin_yang": "262f-fe0f", "latin_cross": "271d-fe0f", "orthodox_cross": "2626-fe0f", "star_and_crescent": "262a-fe0f", "peace_symbol": "262e-fe0f", "menorah_with_nine_branches": "1f54e", "menorah": "1f54e", "six_pointed_star": "1f52f", "aries": "2648", "taurus": "2649", "gemini": "264a", "cancer": "264b", "leo": "264c", "virgo": "264d", "libra": "264e", "scorpius": "264f", "sagittarius": "2650", "capricorn": "2651", "aquarius": "2652", "pisces": "2653", "ophiuchus": "26ce", "twisted_rightwards_arrows": "1f500", "repeat": "1f501", "repeat_one": "1f502", "arrow_forward": "25b6-fe0f", "fast_forward": "23e9", "black_right_pointing_double_triangle_with_vertical_bar": "23ed-fe0f", "next_track_button": "23ed-fe0f", "black_right_pointing_triangle_with_double_vertical_bar": "23ef-fe0f", "play_or_pause_button": "23ef-fe0f", "arrow_backward": "25c0-fe0f", "rewind": "23ea", "black_left_pointing_double_triangle_with_vertical_bar": "23ee-fe0f", "previous_track_button": "23ee-fe0f", "arrow_up_small": "1f53c", "arrow_double_up": "23eb", "arrow_down_small": "1f53d", "arrow_double_down": "23ec", "double_vertical_bar": "23f8-fe0f", "pause_button": "23f8-fe0f", "black_square_for_stop": "23f9-fe0f", "stop_button": "23f9-fe0f", "black_circle_for_record": "23fa-fe0f", "record_button": "23fa-fe0f", "eject": "23cf-fe0f", "cinema": "1f3a6", "low_brightness": "1f505", "high_brightness": "1f506", "signal_strength": "1f4f6", "vibration_mode": "1f4f3", "mobile_phone_off": "1f4f4", "female_sign": "2640-fe0f", "male_sign": "2642-fe0f", "transgender_symbol": "26a7-fe0f", "heavy_multiplication_x": "2716-fe0f", "heavy_plus_sign": "2795", "heavy_minus_sign": "2796", "heavy_division_sign": "2797", "infinity": "267e-fe0f", "bangbang": "203c-fe0f", "interrobang": "2049-fe0f", "question": "2753", "grey_question": "2754", "grey_exclamation": "2755", "exclamation": "2757", "heavy_exclamation_mark": "2757", "wavy_dash": "3030-fe0f", "currency_exchange": "1f4b1", "heavy_dollar_sign": "1f4b2", "medical_symbol": "2695-fe0f", "staff_of_aesculapius": "2695-fe0f", "recycle": "267b-fe0f", "fleur_de_lis": "269c-fe0f", "trident": "1f531", "name_badge": "1f4db", "beginner": "1f530", "o": "2b55", "white_check_mark": "2705", "ballot_box_with_check": "2611-fe0f", "heavy_check_mark": "2714-fe0f", "x": "274c", "negative_squared_cross_mark": "274e", "curly_loop": "27b0", "loop": "27bf", "part_alternation_mark": "303d-fe0f", "eight_spoked_asterisk": "2733-fe0f", "eight_pointed_black_star": "2734-fe0f", "sparkle": "2747-fe0f", "copyright": "00a9-fe0f", "registered": "00ae-fe0f", "tm": "2122-fe0f", "hash": "0023-fe0f-20e3", "keycap_star": "002a-fe0f-20e3", "asterisk": "002a-fe0f-20e3", "zero": "0030-fe0f-20e3", "one": "0031-fe0f-20e3", "two": "0032-fe0f-20e3", "three": "0033-fe0f-20e3", "four": "0034-fe0f-20e3", "five": "0035-fe0f-20e3", "six": "0036-fe0f-20e3", "seven": "0037-fe0f-20e3", "eight": "0038-fe0f-20e3", "nine": "0039-fe0f-20e3", "keycap_ten": "1f51f", "capital_abcd": "1f520", "abcd": "1f521", "1234": "1f522", "symbols": "1f523", "abc": "1f524", "a": "1f170-fe0f", "ab": "1f18e", "b": "1f171-fe0f", "cl": "1f191", "cool": "1f192", "free": "1f193", "information_source": "2139-fe0f", "id": "1f194", "m": "24c2-fe0f", "new": "1f195", "ng": "1f196", "o2": "1f17e-fe0f", "ok": "1f197", "parking": "1f17f-fe0f", "sos": "1f198", "up": "1f199", "vs": "1f19a", "koko": "1f201", "sa": "1f202-fe0f", "u6708": "1f237-fe0f", "u6709": "1f236", "u6307": "1f22f", "ideograph_advantage": "1f250", "u5272": "1f239", "u7121": "1f21a", "u7981": "1f232", "accept": "1f251", "u7533": "1f238", "u5408": "1f234", "u7a7a": "1f233", "congratulations": "3297-fe0f", "secret": "3299-fe0f", "u55b6": "1f23a", "u6e80": "1f235", "red_circle": "1f534", "large_orange_circle": "1f7e0", "large_yellow_circle": "1f7e1", "large_green_circle": "1f7e2", "large_blue_circle": "1f535", "large_purple_circle": "1f7e3", "large_brown_circle": "1f7e4", "black_circle": "26ab", "white_circle": "26aa", "large_red_square": "1f7e5", "large_orange_square": "1f7e7", "large_yellow_square": "1f7e8", "large_green_square": "1f7e9", "large_blue_square": "1f7e6", "large_purple_square": "1f7ea", "large_brown_square": "1f7eb", "black_large_square": "2b1b", "white_large_square": "2b1c", "black_medium_square": "25fc-fe0f", "white_medium_square": "25fb-fe0f", "black_medium_small_square": "25fe", "white_medium_small_square": "25fd", "black_small_square": "25aa-fe0f", "white_small_square": "25ab-fe0f", "large_orange_diamond": "1f536", "large_blue_diamond": "1f537", "small_orange_diamond": "1f538", "small_blue_diamond": "1f539", "small_red_triangle": "1f53a", "small_red_triangle_down": "1f53b", "diamond_shape_with_a_dot_inside": "1f4a0", "radio_button": "1f518", "white_square_button": "1f533", "black_square_button": "1f532", "checkered_flag": "1f3c1", "triangular_flag_on_post": "1f6a9", "crossed_flags": "1f38c", "waving_black_flag": "1f3f4", "black_flag": "1f3f4", "waving_white_flag": "1f3f3-fe0f", "white_flag": "1f3f3-fe0f", "rainbow-flag": "1f3f3-fe0f-200d-1f308", "rainbow_flag": "1f3f3-fe0f-200d-1f308", "transgender_flag": "1f3f3-fe0f-200d-26a7-fe0f", "pirate_flag": "1f3f4-200d-2620-fe0f", "flag-ac": "1f1e6-1f1e8", "flag-ad": "1f1e6-1f1e9", "andorra": "1f1e6-1f1e9", "flag-ae": "1f1e6-1f1ea", "united_arab_emirates": "1f1e6-1f1ea", "flag-af": "1f1e6-1f1eb", "afghanistan": "1f1e6-1f1eb", "flag-ag": "1f1e6-1f1ec", "antigua_barbuda": "1f1e6-1f1ec", "flag-ai": "1f1e6-1f1ee", "anguilla": "1f1e6-1f1ee", "flag-al": "1f1e6-1f1f1", "albania": "1f1e6-1f1f1", "flag-am": "1f1e6-1f1f2", "armenia": "1f1e6-1f1f2", "flag-ao": "1f1e6-1f1f4", "angola": "1f1e6-1f1f4", "flag-aq": "1f1e6-1f1f6", "antarctica": "1f1e6-1f1f6", "flag-ar": "1f1e6-1f1f7", "argentina": "1f1e6-1f1f7", "flag-as": "1f1e6-1f1f8", "american_samoa": "1f1e6-1f1f8", "flag-at": "1f1e6-1f1f9", "austria": "1f1e6-1f1f9", "flag-au": "1f1e6-1f1fa", "australia": "1f1e6-1f1fa", "flag-aw": "1f1e6-1f1fc", "aruba": "1f1e6-1f1fc", "flag-ax": "1f1e6-1f1fd", "aland_islands": "1f1e6-1f1fd", "flag-az": "1f1e6-1f1ff", "azerbaijan": "1f1e6-1f1ff", "flag-ba": "1f1e7-1f1e6", "bosnia_herzegovina": "1f1e7-1f1e6", "flag-bb": "1f1e7-1f1e7", "barbados": "1f1e7-1f1e7", "flag-bd": "1f1e7-1f1e9", "bangladesh": "1f1e7-1f1e9", "flag-be": "1f1e7-1f1ea", "belgium": "1f1e7-1f1ea", "flag-bf": "1f1e7-1f1eb", "burkina_faso": "1f1e7-1f1eb", "flag-bg": "1f1e7-1f1ec", "bulgaria": "1f1e7-1f1ec", "flag-bh": "1f1e7-1f1ed", "bahrain": "1f1e7-1f1ed", "flag-bi": "1f1e7-1f1ee", "burundi": "1f1e7-1f1ee", "flag-bj": "1f1e7-1f1ef", "benin": "1f1e7-1f1ef", "flag-bl": "1f1e7-1f1f1", "st_barthelemy": "1f1e7-1f1f1", "flag-bm": "1f1e7-1f1f2", "bermuda": "1f1e7-1f1f2", "flag-bn": "1f1e7-1f1f3", "brunei": "1f1e7-1f1f3", "flag-bo": "1f1e7-1f1f4", "bolivia": "1f1e7-1f1f4", "flag-bq": "1f1e7-1f1f6", "caribbean_netherlands": "1f1e7-1f1f6", "flag-br": "1f1e7-1f1f7", "brazil": "1f1e7-1f1f7", "flag-bs": "1f1e7-1f1f8", "bahamas": "1f1e7-1f1f8", "flag-bt": "1f1e7-1f1f9", "bhutan": "1f1e7-1f1f9", "flag-bv": "1f1e7-1f1fb", "flag-bw": "1f1e7-1f1fc", "botswana": "1f1e7-1f1fc", "flag-by": "1f1e7-1f1fe", "belarus": "1f1e7-1f1fe", "flag-bz": "1f1e7-1f1ff", "belize": "1f1e7-1f1ff", "flag-ca": "1f1e8-1f1e6", "ca": "1f1e8-1f1e6", "canada": "1f1e8-1f1e6", "flag-cc": "1f1e8-1f1e8", "cocos_islands": "1f1e8-1f1e8", "flag-cd": "1f1e8-1f1e9", "congo_kinshasa": "1f1e8-1f1e9", "flag-cf": "1f1e8-1f1eb", "central_african_republic": "1f1e8-1f1eb", "flag-cg": "1f1e8-1f1ec", "congo_brazzaville": "1f1e8-1f1ec", "flag-ch": "1f1e8-1f1ed", "switzerland": "1f1e8-1f1ed", "flag-ci": "1f1e8-1f1ee", "cote_divoire": "1f1e8-1f1ee", "flag-ck": "1f1e8-1f1f0", "cook_islands": "1f1e8-1f1f0", "flag-cl": "1f1e8-1f1f1", "chile": "1f1e8-1f1f1", "flag-cm": "1f1e8-1f1f2", "cameroon": "1f1e8-1f1f2", "cn": "1f1e8-1f1f3", "flag-cn": "1f1e8-1f1f3", "flag-co": "1f1e8-1f1f4", "colombia": "1f1e8-1f1f4", "flag-cp": "1f1e8-1f1f5", "flag-cr": "1f1e8-1f1f7", "costa_rica": "1f1e8-1f1f7", "flag-cu": "1f1e8-1f1fa", "cuba": "1f1e8-1f1fa", "flag-cv": "1f1e8-1f1fb", "cape_verde": "1f1e8-1f1fb", "flag-cw": "1f1e8-1f1fc", "curacao": "1f1e8-1f1fc", "flag-cx": "1f1e8-1f1fd", "christmas_island": "1f1e8-1f1fd", "flag-cy": "1f1e8-1f1fe", "cyprus": "1f1e8-1f1fe", "flag-cz": "1f1e8-1f1ff", "czech_republic": "1f1e8-1f1ff", "de": "1f1e9-1f1ea", "flag-de": "1f1e9-1f1ea", "flag-dg": "1f1e9-1f1ec", "flag-dj": "1f1e9-1f1ef", "djibouti": "1f1e9-1f1ef", "flag-dk": "1f1e9-1f1f0", "denmark": "1f1e9-1f1f0", "flag-dm": "1f1e9-1f1f2", "dominica": "1f1e9-1f1f2", "flag-do": "1f1e9-1f1f4", "dominican_republic": "1f1e9-1f1f4", "flag-dz": "1f1e9-1f1ff", "algeria": "1f1e9-1f1ff", "flag-ea": "1f1ea-1f1e6", "flag-ec": "1f1ea-1f1e8", "ecuador": "1f1ea-1f1e8", "flag-ee": "1f1ea-1f1ea", "estonia": "1f1ea-1f1ea", "flag-eg": "1f1ea-1f1ec", "egypt": "1f1ea-1f1ec", "flag-eh": "1f1ea-1f1ed", "western_sahara": "1f1ea-1f1ed", "flag-er": "1f1ea-1f1f7", "eritrea": "1f1ea-1f1f7", "es": "1f1ea-1f1f8", "flag-es": "1f1ea-1f1f8", "flag-et": "1f1ea-1f1f9", "ethiopia": "1f1ea-1f1f9", "flag-eu": "1f1ea-1f1fa", "eu": "1f1ea-1f1fa", "european_union": "1f1ea-1f1fa", "flag-fi": "1f1eb-1f1ee", "finland": "1f1eb-1f1ee", "flag-fj": "1f1eb-1f1ef", "fiji": "1f1eb-1f1ef", "flag-fk": "1f1eb-1f1f0", "falkland_islands": "1f1eb-1f1f0", "flag-fm": "1f1eb-1f1f2", "micronesia": "1f1eb-1f1f2", "flag-fo": "1f1eb-1f1f4", "faroe_islands": "1f1eb-1f1f4", "fr": "1f1eb-1f1f7", "flag-fr": "1f1eb-1f1f7", "flag-ga": "1f1ec-1f1e6", "gabon": "1f1ec-1f1e6", "gb": "1f1ec-1f1e7", "uk": "1f1ec-1f1e7", "flag-gb": "1f1ec-1f1e7", "flag-gd": "1f1ec-1f1e9", "grenada": "1f1ec-1f1e9", "flag-ge": "1f1ec-1f1ea", "georgia": "1f1ec-1f1ea", "flag-gf": "1f1ec-1f1eb", "french_guiana": "1f1ec-1f1eb", "flag-gg": "1f1ec-1f1ec", "guernsey": "1f1ec-1f1ec", "flag-gh": "1f1ec-1f1ed", "ghana": "1f1ec-1f1ed", "flag-gi": "1f1ec-1f1ee", "gibraltar": "1f1ec-1f1ee", "flag-gl": "1f1ec-1f1f1", "greenland": "1f1ec-1f1f1", "flag-gm": "1f1ec-1f1f2", "gambia": "1f1ec-1f1f2", "flag-gn": "1f1ec-1f1f3", "guinea": "1f1ec-1f1f3", "flag-gp": "1f1ec-1f1f5", "guadeloupe": "1f1ec-1f1f5", "flag-gq": "1f1ec-1f1f6", "equatorial_guinea": "1f1ec-1f1f6", "flag-gr": "1f1ec-1f1f7", "greece": "1f1ec-1f1f7", "flag-gs": "1f1ec-1f1f8", "south_georgia_south_sandwich_islands": "1f1ec-1f1f8", "flag-gt": "1f1ec-1f1f9", "guatemala": "1f1ec-1f1f9", "flag-gu": "1f1ec-1f1fa", "guam": "1f1ec-1f1fa", "flag-gw": "1f1ec-1f1fc", "guinea_bissau": "1f1ec-1f1fc", "flag-gy": "1f1ec-1f1fe", "guyana": "1f1ec-1f1fe", "flag-hk": "1f1ed-1f1f0", "hong_kong": "1f1ed-1f1f0", "flag-hm": "1f1ed-1f1f2", "flag-hn": "1f1ed-1f1f3", "honduras": "1f1ed-1f1f3", "flag-hr": "1f1ed-1f1f7", "croatia": "1f1ed-1f1f7", "flag-ht": "1f1ed-1f1f9", "haiti": "1f1ed-1f1f9", "flag-hu": "1f1ed-1f1fa", "hungary": "1f1ed-1f1fa", "flag-ic": "1f1ee-1f1e8", "canary_islands": "1f1ee-1f1e8", "flag-id": "1f1ee-1f1e9", "indonesia": "1f1ee-1f1e9", "flag-ie": "1f1ee-1f1ea", "ireland": "1f1ee-1f1ea", "flag-il": "1f1ee-1f1f1", "israel": "1f1ee-1f1f1", "flag-im": "1f1ee-1f1f2", "isle_of_man": "1f1ee-1f1f2", "flag-in": "1f1ee-1f1f3", "india": "1f1ee-1f1f3", "flag-io": "1f1ee-1f1f4", "british_indian_ocean_territory": "1f1ee-1f1f4", "flag-iq": "1f1ee-1f1f6", "iraq": "1f1ee-1f1f6", "flag-ir": "1f1ee-1f1f7", "iran": "1f1ee-1f1f7", "flag-is": "1f1ee-1f1f8", "iceland": "1f1ee-1f1f8", "it": "1f1ee-1f1f9", "flag-it": "1f1ee-1f1f9", "flag-je": "1f1ef-1f1ea", "jersey": "1f1ef-1f1ea", "flag-jm": "1f1ef-1f1f2", "jamaica": "1f1ef-1f1f2", "flag-jo": "1f1ef-1f1f4", "jordan": "1f1ef-1f1f4", "jp": "1f1ef-1f1f5", "flag-jp": "1f1ef-1f1f5", "flag-ke": "1f1f0-1f1ea", "kenya": "1f1f0-1f1ea", "flag-kg": "1f1f0-1f1ec", "kyrgyzstan": "1f1f0-1f1ec", "flag-kh": "1f1f0-1f1ed", "cambodia": "1f1f0-1f1ed", "flag-ki": "1f1f0-1f1ee", "kiribati": "1f1f0-1f1ee", "flag-km": "1f1f0-1f1f2", "comoros": "1f1f0-1f1f2", "flag-kn": "1f1f0-1f1f3", "st_kitts_nevis": "1f1f0-1f1f3", "flag-kp": "1f1f0-1f1f5", "north_korea": "1f1f0-1f1f5", "kr": "1f1f0-1f1f7", "flag-kr": "1f1f0-1f1f7", "flag-kw": "1f1f0-1f1fc", "kuwait": "1f1f0-1f1fc", "flag-ky": "1f1f0-1f1fe", "cayman_islands": "1f1f0-1f1fe", "flag-kz": "1f1f0-1f1ff", "kazakhstan": "1f1f0-1f1ff", "flag-la": "1f1f1-1f1e6", "laos": "1f1f1-1f1e6", "flag-lb": "1f1f1-1f1e7", "lebanon": "1f1f1-1f1e7", "flag-lc": "1f1f1-1f1e8", "st_lucia": "1f1f1-1f1e8", "flag-li": "1f1f1-1f1ee", "liechtenstein": "1f1f1-1f1ee", "flag-lk": "1f1f1-1f1f0", "sri_lanka": "1f1f1-1f1f0", "flag-lr": "1f1f1-1f1f7", "liberia": "1f1f1-1f1f7", "flag-ls": "1f1f1-1f1f8", "lesotho": "1f1f1-1f1f8", "flag-lt": "1f1f1-1f1f9", "lithuania": "1f1f1-1f1f9", "flag-lu": "1f1f1-1f1fa", "luxembourg": "1f1f1-1f1fa", "flag-lv": "1f1f1-1f1fb", "latvia": "1f1f1-1f1fb", "flag-ly": "1f1f1-1f1fe", "libya": "1f1f1-1f1fe", "flag-ma": "1f1f2-1f1e6", "morocco": "1f1f2-1f1e6", "flag-mc": "1f1f2-1f1e8", "monaco": "1f1f2-1f1e8", "flag-md": "1f1f2-1f1e9", "moldova": "1f1f2-1f1e9", "flag-me": "1f1f2-1f1ea", "montenegro": "1f1f2-1f1ea", "flag-mf": "1f1f2-1f1eb", "flag-mg": "1f1f2-1f1ec", "madagascar": "1f1f2-1f1ec", "flag-mh": "1f1f2-1f1ed", "marshall_islands": "1f1f2-1f1ed", "flag-mk": "1f1f2-1f1f0", "macedonia": "1f1f2-1f1f0", "flag-ml": "1f1f2-1f1f1", "mali": "1f1f2-1f1f1", "flag-mm": "1f1f2-1f1f2", "myanmar": "1f1f2-1f1f2", "flag-mn": "1f1f2-1f1f3", "mongolia": "1f1f2-1f1f3", "flag-mo": "1f1f2-1f1f4", "macau": "1f1f2-1f1f4", "flag-mp": "1f1f2-1f1f5", "northern_mariana_islands": "1f1f2-1f1f5", "flag-mq": "1f1f2-1f1f6", "martinique": "1f1f2-1f1f6", "flag-mr": "1f1f2-1f1f7", "mauritania": "1f1f2-1f1f7", "flag-ms": "1f1f2-1f1f8", "montserrat": "1f1f2-1f1f8", "flag-mt": "1f1f2-1f1f9", "malta": "1f1f2-1f1f9", "flag-mu": "1f1f2-1f1fa", "mauritius": "1f1f2-1f1fa", "flag-mv": "1f1f2-1f1fb", "maldives": "1f1f2-1f1fb", "flag-mw": "1f1f2-1f1fc", "malawi": "1f1f2-1f1fc", "flag-mx": "1f1f2-1f1fd", "mexico": "1f1f2-1f1fd", "flag-my": "1f1f2-1f1fe", "malaysia": "1f1f2-1f1fe", "flag-mz": "1f1f2-1f1ff", "mozambique": "1f1f2-1f1ff", "flag-na": "1f1f3-1f1e6", "namibia": "1f1f3-1f1e6", "flag-nc": "1f1f3-1f1e8", "new_caledonia": "1f1f3-1f1e8", "flag-ne": "1f1f3-1f1ea", "niger": "1f1f3-1f1ea", "flag-nf": "1f1f3-1f1eb", "norfolk_island": "1f1f3-1f1eb", "flag-ng": "1f1f3-1f1ec", "nigeria": "1f1f3-1f1ec", "flag-ni": "1f1f3-1f1ee", "nicaragua": "1f1f3-1f1ee", "flag-nl": "1f1f3-1f1f1", "netherlands": "1f1f3-1f1f1", "flag-no": "1f1f3-1f1f4", "norway": "1f1f3-1f1f4", "flag-np": "1f1f3-1f1f5", "nepal": "1f1f3-1f1f5", "flag-nr": "1f1f3-1f1f7", "nauru": "1f1f3-1f1f7", "flag-nu": "1f1f3-1f1fa", "niue": "1f1f3-1f1fa", "flag-nz": "1f1f3-1f1ff", "new_zealand": "1f1f3-1f1ff", "flag-om": "1f1f4-1f1f2", "oman": "1f1f4-1f1f2", "flag-pa": "1f1f5-1f1e6", "panama": "1f1f5-1f1e6", "flag-pe": "1f1f5-1f1ea", "peru": "1f1f5-1f1ea", "flag-pf": "1f1f5-1f1eb", "french_polynesia": "1f1f5-1f1eb", "flag-pg": "1f1f5-1f1ec", "papua_new_guinea": "1f1f5-1f1ec", "flag-ph": "1f1f5-1f1ed", "philippines": "1f1f5-1f1ed", "flag-pk": "1f1f5-1f1f0", "pakistan": "1f1f5-1f1f0", "pk": "1f1f5-1f1f0", "flag-pl": "1f1f5-1f1f1", "poland": "1f1f5-1f1f1", "flag-pm": "1f1f5-1f1f2", "st_pierre_miquelon": "1f1f5-1f1f2", "flag-pn": "1f1f5-1f1f3", "pitcairn_islands": "1f1f5-1f1f3", "flag-pr": "1f1f5-1f1f7", "puerto_rico": "1f1f5-1f1f7", "flag-ps": "1f1f5-1f1f8", "palestinian_territories": "1f1f5-1f1f8", "flag-pt": "1f1f5-1f1f9", "portugal": "1f1f5-1f1f9", "flag-pw": "1f1f5-1f1fc", "palau": "1f1f5-1f1fc", "flag-py": "1f1f5-1f1fe", "paraguay": "1f1f5-1f1fe", "flag-qa": "1f1f6-1f1e6", "qatar": "1f1f6-1f1e6", "flag-re": "1f1f7-1f1ea", "reunion": "1f1f7-1f1ea", "flag-ro": "1f1f7-1f1f4", "romania": "1f1f7-1f1f4", "flag-rs": "1f1f7-1f1f8", "serbia": "1f1f7-1f1f8", "ru": "1f1f7-1f1fa", "flag-ru": "1f1f7-1f1fa", "flag-rw": "1f1f7-1f1fc", "rwanda": "1f1f7-1f1fc", "flag-sa": "1f1f8-1f1e6", "saudi_arabia": "1f1f8-1f1e6", "flag-sb": "1f1f8-1f1e7", "solomon_islands": "1f1f8-1f1e7", "flag-sc": "1f1f8-1f1e8", "seychelles": "1f1f8-1f1e8", "flag-sd": "1f1f8-1f1e9", "sudan": "1f1f8-1f1e9", "flag-se": "1f1f8-1f1ea", "sweden": "1f1f8-1f1ea", "flag-sg": "1f1f8-1f1ec", "singapore": "1f1f8-1f1ec", "flag-sh": "1f1f8-1f1ed", "st_helena": "1f1f8-1f1ed", "flag-si": "1f1f8-1f1ee", "slovenia": "1f1f8-1f1ee", "flag-sj": "1f1f8-1f1ef", "flag-sk": "1f1f8-1f1f0", "slovakia": "1f1f8-1f1f0", "flag-sl": "1f1f8-1f1f1", "sierra_leone": "1f1f8-1f1f1", "flag-sm": "1f1f8-1f1f2", "san_marino": "1f1f8-1f1f2", "flag-sn": "1f1f8-1f1f3", "senegal": "1f1f8-1f1f3", "flag-so": "1f1f8-1f1f4", "somalia": "1f1f8-1f1f4", "flag-sr": "1f1f8-1f1f7", "suriname": "1f1f8-1f1f7", "flag-ss": "1f1f8-1f1f8", "south_sudan": "1f1f8-1f1f8", "flag-st": "1f1f8-1f1f9", "sao_tome_principe": "1f1f8-1f1f9", "flag-sv": "1f1f8-1f1fb", "el_salvador": "1f1f8-1f1fb", "flag-sx": "1f1f8-1f1fd", "sint_maarten": "1f1f8-1f1fd", "flag-sy": "1f1f8-1f1fe", "syria": "1f1f8-1f1fe", "flag-sz": "1f1f8-1f1ff", "swaziland": "1f1f8-1f1ff", "flag-ta": "1f1f9-1f1e6", "flag-tc": "1f1f9-1f1e8", "turks_caicos_islands": "1f1f9-1f1e8", "flag-td": "1f1f9-1f1e9", "chad": "1f1f9-1f1e9", "flag-tf": "1f1f9-1f1eb", "french_southern_territories": "1f1f9-1f1eb", "flag-tg": "1f1f9-1f1ec", "togo": "1f1f9-1f1ec", "flag-th": "1f1f9-1f1ed", "thailand": "1f1f9-1f1ed", "flag-tj": "1f1f9-1f1ef", "tajikistan": "1f1f9-1f1ef", "flag-tk": "1f1f9-1f1f0", "tokelau": "1f1f9-1f1f0", "flag-tl": "1f1f9-1f1f1", "timor_leste": "1f1f9-1f1f1", "flag-tm": "1f1f9-1f1f2", "turkmenistan": "1f1f9-1f1f2", "flag-tn": "1f1f9-1f1f3", "tunisia": "1f1f9-1f1f3", "flag-to": "1f1f9-1f1f4", "tonga": "1f1f9-1f1f4", "flag-tr": "1f1f9-1f1f7", "tr": "1f1f9-1f1f7", "flag-tt": "1f1f9-1f1f9", "trinidad_tobago": "1f1f9-1f1f9", "flag-tv": "1f1f9-1f1fb", "tuvalu": "1f1f9-1f1fb", "flag-tw": "1f1f9-1f1fc", "taiwan": "1f1f9-1f1fc", "flag-tz": "1f1f9-1f1ff", "tanzania": "1f1f9-1f1ff", "flag-ua": "1f1fa-1f1e6", "ukraine": "1f1fa-1f1e6", "flag-ug": "1f1fa-1f1ec", "uganda": "1f1fa-1f1ec", "flag-um": "1f1fa-1f1f2", "flag-un": "1f1fa-1f1f3", "us": "1f1fa-1f1f8", "flag-us": "1f1fa-1f1f8", "flag-uy": "1f1fa-1f1fe", "uruguay": "1f1fa-1f1fe", "flag-uz": "1f1fa-1f1ff", "uzbekistan": "1f1fa-1f1ff", "flag-va": "1f1fb-1f1e6", "vatican_city": "1f1fb-1f1e6", "flag-vc": "1f1fb-1f1e8", "st_vincent_grenadines": "1f1fb-1f1e8", "flag-ve": "1f1fb-1f1ea", "venezuela": "1f1fb-1f1ea", "flag-vg": "1f1fb-1f1ec", "british_virgin_islands": "1f1fb-1f1ec", "flag-vi": "1f1fb-1f1ee", "us_virgin_islands": "1f1fb-1f1ee", "flag-vn": "1f1fb-1f1f3", "vietnam": "1f1fb-1f1f3", "flag-vu": "1f1fb-1f1fa", "vanuatu": "1f1fb-1f1fa", "flag-wf": "1f1fc-1f1eb", "wallis_futuna": "1f1fc-1f1eb", "flag-ws": "1f1fc-1f1f8", "samoa": "1f1fc-1f1f8", "flag-xk": "1f1fd-1f1f0", "kosovo": "1f1fd-1f1f0", "flag-ye": "1f1fe-1f1ea", "yemen": "1f1fe-1f1ea", "flag-yt": "1f1fe-1f1f9", "mayotte": "1f1fe-1f1f9", "flag-za": "1f1ff-1f1e6", "south_africa": "1f1ff-1f1e6", "za": "1f1ff-1f1e6", "flag-zm": "1f1ff-1f1f2", "zambia": "1f1ff-1f1f2", "flag-zw": "1f1ff-1f1fc", "zimbabwe": "1f1ff-1f1fc", "flag-england": "1f3f4-e0067-e0062-e0065-e006e-e0067-e007f", "flag-scotland": "1f3f4-e0067-e0062-e0073-e0063-e0074-e007f", "flag-wales": "1f3f4-e0067-e0062-e0077-e006c-e0073-e007f", "santa_light_skin_tone": "1f385-1f3fb", "santa_medium_light_skin_tone": "1f385-1f3fc", "santa_medium_skin_tone": "1f385-1f3fd", "santa_medium_dark_skin_tone": "1f385-1f3fe", "santa_dark_skin_tone": "1f385-1f3ff", "snowboarder_light_skin_tone": "1f3c2-1f3fb", "snowboarder_medium_light_skin_tone": "1f3c2-1f3fc", "snowboarder_medium_skin_tone": "1f3c2-1f3fd", "snowboarder_medium_dark_skin_tone": "1f3c2-1f3fe", "snowboarder_dark_skin_tone": "1f3c2-1f3ff", "woman-running_light_skin_tone": "1f3c3-1f3fb-200d-2640-fe0f", "running_woman_light_skin_tone": "1f3c3-1f3fb-200d-2640-fe0f", "woman-running_medium_light_skin_tone": "1f3c3-1f3fc-200d-2640-fe0f", "running_woman_medium_light_skin_tone": "1f3c3-1f3fc-200d-2640-fe0f", "woman-running_medium_skin_tone": "1f3c3-1f3fd-200d-2640-fe0f", "running_woman_medium_skin_tone": "1f3c3-1f3fd-200d-2640-fe0f", "woman-running_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2640-fe0f", "running_woman_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2640-fe0f", "woman-running_dark_skin_tone": "1f3c3-1f3ff-200d-2640-fe0f", "running_woman_dark_skin_tone": "1f3c3-1f3ff-200d-2640-fe0f", "man-running_light_skin_tone": "1f3c3-1f3fb-200d-2642-fe0f", "running_man_light_skin_tone": "1f3c3-1f3fb-200d-2642-fe0f", "man-running_medium_light_skin_tone": "1f3c3-1f3fc-200d-2642-fe0f", "running_man_medium_light_skin_tone": "1f3c3-1f3fc-200d-2642-fe0f", "man-running_medium_skin_tone": "1f3c3-1f3fd-200d-2642-fe0f", "running_man_medium_skin_tone": "1f3c3-1f3fd-200d-2642-fe0f", "man-running_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2642-fe0f", "running_man_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2642-fe0f", "man-running_dark_skin_tone": "1f3c3-1f3ff-200d-2642-fe0f", "running_man_dark_skin_tone": "1f3c3-1f3ff-200d-2642-fe0f", "runner_light_skin_tone": "1f3c3-1f3fb", "running_light_skin_tone": "1f3c3-1f3fb", "runner_medium_light_skin_tone": "1f3c3-1f3fc", "running_medium_light_skin_tone": "1f3c3-1f3fc", "runner_medium_skin_tone": "1f3c3-1f3fd", "running_medium_skin_tone": "1f3c3-1f3fd", "runner_medium_dark_skin_tone": "1f3c3-1f3fe", "running_medium_dark_skin_tone": "1f3c3-1f3fe", "runner_dark_skin_tone": "1f3c3-1f3ff", "running_dark_skin_tone": "1f3c3-1f3ff", "woman-surfing_light_skin_tone": "1f3c4-1f3fb-200d-2640-fe0f", "surfing_woman_light_skin_tone": "1f3c4-1f3fb-200d-2640-fe0f", "woman-surfing_medium_light_skin_tone": "1f3c4-1f3fc-200d-2640-fe0f", "surfing_woman_medium_light_skin_tone": "1f3c4-1f3fc-200d-2640-fe0f", "woman-surfing_medium_skin_tone": "1f3c4-1f3fd-200d-2640-fe0f", "surfing_woman_medium_skin_tone": "1f3c4-1f3fd-200d-2640-fe0f", "woman-surfing_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2640-fe0f", "surfing_woman_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2640-fe0f", "woman-surfing_dark_skin_tone": "1f3c4-1f3ff-200d-2640-fe0f", "surfing_woman_dark_skin_tone": "1f3c4-1f3ff-200d-2640-fe0f", "man-surfing_light_skin_tone": "1f3c4-1f3fb-200d-2642-fe0f", "surfing_man_light_skin_tone": "1f3c4-1f3fb-200d-2642-fe0f", "man-surfing_medium_light_skin_tone": "1f3c4-1f3fc-200d-2642-fe0f", "surfing_man_medium_light_skin_tone": "1f3c4-1f3fc-200d-2642-fe0f", "man-surfing_medium_skin_tone": "1f3c4-1f3fd-200d-2642-fe0f", "surfing_man_medium_skin_tone": "1f3c4-1f3fd-200d-2642-fe0f", "man-surfing_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2642-fe0f", "surfing_man_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2642-fe0f", "man-surfing_dark_skin_tone": "1f3c4-1f3ff-200d-2642-fe0f", "surfing_man_dark_skin_tone": "1f3c4-1f3ff-200d-2642-fe0f", "surfer_light_skin_tone": "1f3c4-1f3fb", "surfer_medium_light_skin_tone": "1f3c4-1f3fc", "surfer_medium_skin_tone": "1f3c4-1f3fd", "surfer_medium_dark_skin_tone": "1f3c4-1f3fe", "surfer_dark_skin_tone": "1f3c4-1f3ff", "horse_racing_light_skin_tone": "1f3c7-1f3fb", "horse_racing_medium_light_skin_tone": "1f3c7-1f3fc", "horse_racing_medium_skin_tone": "1f3c7-1f3fd", "horse_racing_medium_dark_skin_tone": "1f3c7-1f3fe", "horse_racing_dark_skin_tone": "1f3c7-1f3ff", "woman-swimming_light_skin_tone": "1f3ca-1f3fb-200d-2640-fe0f", "swimming_woman_light_skin_tone": "1f3ca-1f3fb-200d-2640-fe0f", "woman-swimming_medium_light_skin_tone": "1f3ca-1f3fc-200d-2640-fe0f", "swimming_woman_medium_light_skin_tone": "1f3ca-1f3fc-200d-2640-fe0f", "woman-swimming_medium_skin_tone": "1f3ca-1f3fd-200d-2640-fe0f", "swimming_woman_medium_skin_tone": "1f3ca-1f3fd-200d-2640-fe0f", "woman-swimming_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2640-fe0f", "swimming_woman_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2640-fe0f", "woman-swimming_dark_skin_tone": "1f3ca-1f3ff-200d-2640-fe0f", "swimming_woman_dark_skin_tone": "1f3ca-1f3ff-200d-2640-fe0f", "man-swimming_light_skin_tone": "1f3ca-1f3fb-200d-2642-fe0f", "swimming_man_light_skin_tone": "1f3ca-1f3fb-200d-2642-fe0f", "man-swimming_medium_light_skin_tone": "1f3ca-1f3fc-200d-2642-fe0f", "swimming_man_medium_light_skin_tone": "1f3ca-1f3fc-200d-2642-fe0f", "man-swimming_medium_skin_tone": "1f3ca-1f3fd-200d-2642-fe0f", "swimming_man_medium_skin_tone": "1f3ca-1f3fd-200d-2642-fe0f", "man-swimming_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2642-fe0f", "swimming_man_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2642-fe0f", "man-swimming_dark_skin_tone": "1f3ca-1f3ff-200d-2642-fe0f", "swimming_man_dark_skin_tone": "1f3ca-1f3ff-200d-2642-fe0f", "swimmer_light_skin_tone": "1f3ca-1f3fb", "swimmer_medium_light_skin_tone": "1f3ca-1f3fc", "swimmer_medium_skin_tone": "1f3ca-1f3fd", "swimmer_medium_dark_skin_tone": "1f3ca-1f3fe", "swimmer_dark_skin_tone": "1f3ca-1f3ff", "woman-lifting-weights_light_skin_tone": "1f3cb-1f3fb-200d-2640-fe0f", "weight_lifting_woman_light_skin_tone": "1f3cb-1f3fb-200d-2640-fe0f", "woman-lifting-weights_medium_light_skin_tone": "1f3cb-1f3fc-200d-2640-fe0f", "weight_lifting_woman_medium_light_skin_tone": "1f3cb-1f3fc-200d-2640-fe0f", "woman-lifting-weights_medium_skin_tone": "1f3cb-1f3fd-200d-2640-fe0f", "weight_lifting_woman_medium_skin_tone": "1f3cb-1f3fd-200d-2640-fe0f", "woman-lifting-weights_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2640-fe0f", "weight_lifting_woman_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2640-fe0f", "woman-lifting-weights_dark_skin_tone": "1f3cb-1f3ff-200d-2640-fe0f", "weight_lifting_woman_dark_skin_tone": "1f3cb-1f3ff-200d-2640-fe0f", "man-lifting-weights_light_skin_tone": "1f3cb-1f3fb-200d-2642-fe0f", "weight_lifting_man_light_skin_tone": "1f3cb-1f3fb-200d-2642-fe0f", "man-lifting-weights_medium_light_skin_tone": "1f3cb-1f3fc-200d-2642-fe0f", "weight_lifting_man_medium_light_skin_tone": "1f3cb-1f3fc-200d-2642-fe0f", "man-lifting-weights_medium_skin_tone": "1f3cb-1f3fd-200d-2642-fe0f", "weight_lifting_man_medium_skin_tone": "1f3cb-1f3fd-200d-2642-fe0f", "man-lifting-weights_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2642-fe0f", "weight_lifting_man_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2642-fe0f", "man-lifting-weights_dark_skin_tone": "1f3cb-1f3ff-200d-2642-fe0f", "weight_lifting_man_dark_skin_tone": "1f3cb-1f3ff-200d-2642-fe0f", "weight_lifter_light_skin_tone": "1f3cb-1f3fb", "weight_lifter_medium_light_skin_tone": "1f3cb-1f3fc", "weight_lifter_medium_skin_tone": "1f3cb-1f3fd", "weight_lifter_medium_dark_skin_tone": "1f3cb-1f3fe", "weight_lifter_dark_skin_tone": "1f3cb-1f3ff", "woman-golfing_light_skin_tone": "1f3cc-1f3fb-200d-2640-fe0f", "golfing_woman_light_skin_tone": "1f3cc-1f3fb-200d-2640-fe0f", "woman-golfing_medium_light_skin_tone": "1f3cc-1f3fc-200d-2640-fe0f", "golfing_woman_medium_light_skin_tone": "1f3cc-1f3fc-200d-2640-fe0f", "woman-golfing_medium_skin_tone": "1f3cc-1f3fd-200d-2640-fe0f", "golfing_woman_medium_skin_tone": "1f3cc-1f3fd-200d-2640-fe0f", "woman-golfing_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2640-fe0f", "golfing_woman_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2640-fe0f", "woman-golfing_dark_skin_tone": "1f3cc-1f3ff-200d-2640-fe0f", "golfing_woman_dark_skin_tone": "1f3cc-1f3ff-200d-2640-fe0f", "man-golfing_light_skin_tone": "1f3cc-1f3fb-200d-2642-fe0f", "golfing_man_light_skin_tone": "1f3cc-1f3fb-200d-2642-fe0f", "man-golfing_medium_light_skin_tone": "1f3cc-1f3fc-200d-2642-fe0f", "golfing_man_medium_light_skin_tone": "1f3cc-1f3fc-200d-2642-fe0f", "man-golfing_medium_skin_tone": "1f3cc-1f3fd-200d-2642-fe0f", "golfing_man_medium_skin_tone": "1f3cc-1f3fd-200d-2642-fe0f", "man-golfing_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2642-fe0f", "golfing_man_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2642-fe0f", "man-golfing_dark_skin_tone": "1f3cc-1f3ff-200d-2642-fe0f", "golfing_man_dark_skin_tone": "1f3cc-1f3ff-200d-2642-fe0f", "golfer_light_skin_tone": "1f3cc-1f3fb", "golfer_medium_light_skin_tone": "1f3cc-1f3fc", "golfer_medium_skin_tone": "1f3cc-1f3fd", "golfer_medium_dark_skin_tone": "1f3cc-1f3fe", "golfer_dark_skin_tone": "1f3cc-1f3ff", "ear_light_skin_tone": "1f442-1f3fb", "ear_medium_light_skin_tone": "1f442-1f3fc", "ear_medium_skin_tone": "1f442-1f3fd", "ear_medium_dark_skin_tone": "1f442-1f3fe", "ear_dark_skin_tone": "1f442-1f3ff", "nose_light_skin_tone": "1f443-1f3fb", "nose_medium_light_skin_tone": "1f443-1f3fc", "nose_medium_skin_tone": "1f443-1f3fd", "nose_medium_dark_skin_tone": "1f443-1f3fe", "nose_dark_skin_tone": "1f443-1f3ff", "point_up_2_light_skin_tone": "1f446-1f3fb", "point_up_2_medium_light_skin_tone": "1f446-1f3fc", "point_up_2_medium_skin_tone": "1f446-1f3fd", "point_up_2_medium_dark_skin_tone": "1f446-1f3fe", "point_up_2_dark_skin_tone": "1f446-1f3ff", "point_down_light_skin_tone": "1f447-1f3fb", "point_down_medium_light_skin_tone": "1f447-1f3fc", "point_down_medium_skin_tone": "1f447-1f3fd", "point_down_medium_dark_skin_tone": "1f447-1f3fe", "point_down_dark_skin_tone": "1f447-1f3ff", "point_left_light_skin_tone": "1f448-1f3fb", "point_left_medium_light_skin_tone": "1f448-1f3fc", "point_left_medium_skin_tone": "1f448-1f3fd", "point_left_medium_dark_skin_tone": "1f448-1f3fe", "point_left_dark_skin_tone": "1f448-1f3ff", "point_right_light_skin_tone": "1f449-1f3fb", "point_right_medium_light_skin_tone": "1f449-1f3fc", "point_right_medium_skin_tone": "1f449-1f3fd", "point_right_medium_dark_skin_tone": "1f449-1f3fe", "point_right_dark_skin_tone": "1f449-1f3ff", "facepunch_light_skin_tone": "1f44a-1f3fb", "punch_light_skin_tone": "1f44a-1f3fb", "fist_oncoming_light_skin_tone": "1f44a-1f3fb", "facepunch_medium_light_skin_tone": "1f44a-1f3fc", "punch_medium_light_skin_tone": "1f44a-1f3fc", "fist_oncoming_medium_light_skin_tone": "1f44a-1f3fc", "facepunch_medium_skin_tone": "1f44a-1f3fd", "punch_medium_skin_tone": "1f44a-1f3fd", "fist_oncoming_medium_skin_tone": "1f44a-1f3fd", "facepunch_medium_dark_skin_tone": "1f44a-1f3fe", "punch_medium_dark_skin_tone": "1f44a-1f3fe", "fist_oncoming_medium_dark_skin_tone": "1f44a-1f3fe", "facepunch_dark_skin_tone": "1f44a-1f3ff", "punch_dark_skin_tone": "1f44a-1f3ff", "fist_oncoming_dark_skin_tone": "1f44a-1f3ff", "wave_light_skin_tone": "1f44b-1f3fb", "wave_medium_light_skin_tone": "1f44b-1f3fc", "wave_medium_skin_tone": "1f44b-1f3fd", "wave_medium_dark_skin_tone": "1f44b-1f3fe", "wave_dark_skin_tone": "1f44b-1f3ff", "ok_hand_light_skin_tone": "1f44c-1f3fb", "ok_hand_medium_light_skin_tone": "1f44c-1f3fc", "ok_hand_medium_skin_tone": "1f44c-1f3fd", "ok_hand_medium_dark_skin_tone": "1f44c-1f3fe", "ok_hand_dark_skin_tone": "1f44c-1f3ff", "+1_light_skin_tone": "1f44d-1f3fb", "thumbsup_light_skin_tone": "1f44d-1f3fb", "+1_medium_light_skin_tone": "1f44d-1f3fc", "thumbsup_medium_light_skin_tone": "1f44d-1f3fc", "+1_medium_skin_tone": "1f44d-1f3fd", "thumbsup_medium_skin_tone": "1f44d-1f3fd", "+1_medium_dark_skin_tone": "1f44d-1f3fe", "thumbsup_medium_dark_skin_tone": "1f44d-1f3fe", "+1_dark_skin_tone": "1f44d-1f3ff", "thumbsup_dark_skin_tone": "1f44d-1f3ff", "-1_light_skin_tone": "1f44e-1f3fb", "thumbsdown_light_skin_tone": "1f44e-1f3fb", "-1_medium_light_skin_tone": "1f44e-1f3fc", "thumbsdown_medium_light_skin_tone": "1f44e-1f3fc", "-1_medium_skin_tone": "1f44e-1f3fd", "thumbsdown_medium_skin_tone": "1f44e-1f3fd", "-1_medium_dark_skin_tone": "1f44e-1f3fe", "thumbsdown_medium_dark_skin_tone": "1f44e-1f3fe", "-1_dark_skin_tone": "1f44e-1f3ff", "thumbsdown_dark_skin_tone": "1f44e-1f3ff", "clap_light_skin_tone": "1f44f-1f3fb", "clap_medium_light_skin_tone": "1f44f-1f3fc", "clap_medium_skin_tone": "1f44f-1f3fd", "clap_medium_dark_skin_tone": "1f44f-1f3fe", "clap_dark_skin_tone": "1f44f-1f3ff", "open_hands_light_skin_tone": "1f450-1f3fb", "open_hands_medium_light_skin_tone": "1f450-1f3fc", "open_hands_medium_skin_tone": "1f450-1f3fd", "open_hands_medium_dark_skin_tone": "1f450-1f3fe", "open_hands_dark_skin_tone": "1f450-1f3ff", "boy_light_skin_tone": "1f466-1f3fb", "boy_medium_light_skin_tone": "1f466-1f3fc", "boy_medium_skin_tone": "1f466-1f3fd", "boy_medium_dark_skin_tone": "1f466-1f3fe", "boy_dark_skin_tone": "1f466-1f3ff", "girl_light_skin_tone": "1f467-1f3fb", "girl_medium_light_skin_tone": "1f467-1f3fc", "girl_medium_skin_tone": "1f467-1f3fd", "girl_medium_dark_skin_tone": "1f467-1f3fe", "girl_dark_skin_tone": "1f467-1f3ff", "male-farmer_light_skin_tone": "1f468-1f3fb-200d-1f33e", "man_farmer_light_skin_tone": "1f468-1f3fb-200d-1f33e", "male-farmer_medium_light_skin_tone": "1f468-1f3fc-200d-1f33e", "man_farmer_medium_light_skin_tone": "1f468-1f3fc-200d-1f33e", "male-farmer_medium_skin_tone": "1f468-1f3fd-200d-1f33e", "man_farmer_medium_skin_tone": "1f468-1f3fd-200d-1f33e", "male-farmer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f33e", "man_farmer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f33e", "male-farmer_dark_skin_tone": "1f468-1f3ff-200d-1f33e", "man_farmer_dark_skin_tone": "1f468-1f3ff-200d-1f33e", "male-cook_light_skin_tone": "1f468-1f3fb-200d-1f373", "man_cook_light_skin_tone": "1f468-1f3fb-200d-1f373", "male-cook_medium_light_skin_tone": "1f468-1f3fc-200d-1f373", "man_cook_medium_light_skin_tone": "1f468-1f3fc-200d-1f373", "male-cook_medium_skin_tone": "1f468-1f3fd-200d-1f373", "man_cook_medium_skin_tone": "1f468-1f3fd-200d-1f373", "male-cook_medium_dark_skin_tone": "1f468-1f3fe-200d-1f373", "man_cook_medium_dark_skin_tone": "1f468-1f3fe-200d-1f373", "male-cook_dark_skin_tone": "1f468-1f3ff-200d-1f373", "man_cook_dark_skin_tone": "1f468-1f3ff-200d-1f373", "man_feeding_baby_light_skin_tone": "1f468-1f3fb-200d-1f37c", "man_feeding_baby_medium_light_skin_tone": "1f468-1f3fc-200d-1f37c", "man_feeding_baby_medium_skin_tone": "1f468-1f3fd-200d-1f37c", "man_feeding_baby_medium_dark_skin_tone": "1f468-1f3fe-200d-1f37c", "man_feeding_baby_dark_skin_tone": "1f468-1f3ff-200d-1f37c", "male-student_light_skin_tone": "1f468-1f3fb-200d-1f393", "man_student_light_skin_tone": "1f468-1f3fb-200d-1f393", "male-student_medium_light_skin_tone": "1f468-1f3fc-200d-1f393", "man_student_medium_light_skin_tone": "1f468-1f3fc-200d-1f393", "male-student_medium_skin_tone": "1f468-1f3fd-200d-1f393", "man_student_medium_skin_tone": "1f468-1f3fd-200d-1f393", "male-student_medium_dark_skin_tone": "1f468-1f3fe-200d-1f393", "man_student_medium_dark_skin_tone": "1f468-1f3fe-200d-1f393", "male-student_dark_skin_tone": "1f468-1f3ff-200d-1f393", "man_student_dark_skin_tone": "1f468-1f3ff-200d-1f393", "male-singer_light_skin_tone": "1f468-1f3fb-200d-1f3a4", "man_singer_light_skin_tone": "1f468-1f3fb-200d-1f3a4", "male-singer_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a4", "man_singer_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a4", "male-singer_medium_skin_tone": "1f468-1f3fd-200d-1f3a4", "man_singer_medium_skin_tone": "1f468-1f3fd-200d-1f3a4", "male-singer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a4", "man_singer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a4", "male-singer_dark_skin_tone": "1f468-1f3ff-200d-1f3a4", "man_singer_dark_skin_tone": "1f468-1f3ff-200d-1f3a4", "male-artist_light_skin_tone": "1f468-1f3fb-200d-1f3a8", "man_artist_light_skin_tone": "1f468-1f3fb-200d-1f3a8", "male-artist_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a8", "man_artist_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a8", "male-artist_medium_skin_tone": "1f468-1f3fd-200d-1f3a8", "man_artist_medium_skin_tone": "1f468-1f3fd-200d-1f3a8", "male-artist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a8", "man_artist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a8", "male-artist_dark_skin_tone": "1f468-1f3ff-200d-1f3a8", "man_artist_dark_skin_tone": "1f468-1f3ff-200d-1f3a8", "male-teacher_light_skin_tone": "1f468-1f3fb-200d-1f3eb", "man_teacher_light_skin_tone": "1f468-1f3fb-200d-1f3eb", "male-teacher_medium_light_skin_tone": "1f468-1f3fc-200d-1f3eb", "man_teacher_medium_light_skin_tone": "1f468-1f3fc-200d-1f3eb", "male-teacher_medium_skin_tone": "1f468-1f3fd-200d-1f3eb", "man_teacher_medium_skin_tone": "1f468-1f3fd-200d-1f3eb", "male-teacher_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3eb", "man_teacher_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3eb", "male-teacher_dark_skin_tone": "1f468-1f3ff-200d-1f3eb", "man_teacher_dark_skin_tone": "1f468-1f3ff-200d-1f3eb", "male-factory-worker_light_skin_tone": "1f468-1f3fb-200d-1f3ed", "man_factory_worker_light_skin_tone": "1f468-1f3fb-200d-1f3ed", "male-factory-worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f3ed", "man_factory_worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f3ed", "male-factory-worker_medium_skin_tone": "1f468-1f3fd-200d-1f3ed", "man_factory_worker_medium_skin_tone": "1f468-1f3fd-200d-1f3ed", "male-factory-worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3ed", "man_factory_worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3ed", "male-factory-worker_dark_skin_tone": "1f468-1f3ff-200d-1f3ed", "man_factory_worker_dark_skin_tone": "1f468-1f3ff-200d-1f3ed", "male-technologist_light_skin_tone": "1f468-1f3fb-200d-1f4bb", "man_technologist_light_skin_tone": "1f468-1f3fb-200d-1f4bb", "male-technologist_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bb", "man_technologist_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bb", "male-technologist_medium_skin_tone": "1f468-1f3fd-200d-1f4bb", "man_technologist_medium_skin_tone": "1f468-1f3fd-200d-1f4bb", "male-technologist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bb", "man_technologist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bb", "male-technologist_dark_skin_tone": "1f468-1f3ff-200d-1f4bb", "man_technologist_dark_skin_tone": "1f468-1f3ff-200d-1f4bb", "male-office-worker_light_skin_tone": "1f468-1f3fb-200d-1f4bc", "man_office_worker_light_skin_tone": "1f468-1f3fb-200d-1f4bc", "male-office-worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bc", "man_office_worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bc", "male-office-worker_medium_skin_tone": "1f468-1f3fd-200d-1f4bc", "man_office_worker_medium_skin_tone": "1f468-1f3fd-200d-1f4bc", "male-office-worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bc", "man_office_worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bc", "male-office-worker_dark_skin_tone": "1f468-1f3ff-200d-1f4bc", "man_office_worker_dark_skin_tone": "1f468-1f3ff-200d-1f4bc", "male-mechanic_light_skin_tone": "1f468-1f3fb-200d-1f527", "man_mechanic_light_skin_tone": "1f468-1f3fb-200d-1f527", "male-mechanic_medium_light_skin_tone": "1f468-1f3fc-200d-1f527", "man_mechanic_medium_light_skin_tone": "1f468-1f3fc-200d-1f527", "male-mechanic_medium_skin_tone": "1f468-1f3fd-200d-1f527", "man_mechanic_medium_skin_tone": "1f468-1f3fd-200d-1f527", "male-mechanic_medium_dark_skin_tone": "1f468-1f3fe-200d-1f527", "man_mechanic_medium_dark_skin_tone": "1f468-1f3fe-200d-1f527", "male-mechanic_dark_skin_tone": "1f468-1f3ff-200d-1f527", "man_mechanic_dark_skin_tone": "1f468-1f3ff-200d-1f527", "male-scientist_light_skin_tone": "1f468-1f3fb-200d-1f52c", "man_scientist_light_skin_tone": "1f468-1f3fb-200d-1f52c", "male-scientist_medium_light_skin_tone": "1f468-1f3fc-200d-1f52c", "man_scientist_medium_light_skin_tone": "1f468-1f3fc-200d-1f52c", "male-scientist_medium_skin_tone": "1f468-1f3fd-200d-1f52c", "man_scientist_medium_skin_tone": "1f468-1f3fd-200d-1f52c", "male-scientist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f52c", "man_scientist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f52c", "male-scientist_dark_skin_tone": "1f468-1f3ff-200d-1f52c", "man_scientist_dark_skin_tone": "1f468-1f3ff-200d-1f52c", "male-astronaut_light_skin_tone": "1f468-1f3fb-200d-1f680", "man_astronaut_light_skin_tone": "1f468-1f3fb-200d-1f680", "male-astronaut_medium_light_skin_tone": "1f468-1f3fc-200d-1f680", "man_astronaut_medium_light_skin_tone": "1f468-1f3fc-200d-1f680", "male-astronaut_medium_skin_tone": "1f468-1f3fd-200d-1f680", "man_astronaut_medium_skin_tone": "1f468-1f3fd-200d-1f680", "male-astronaut_medium_dark_skin_tone": "1f468-1f3fe-200d-1f680", "man_astronaut_medium_dark_skin_tone": "1f468-1f3fe-200d-1f680", "male-astronaut_dark_skin_tone": "1f468-1f3ff-200d-1f680", "man_astronaut_dark_skin_tone": "1f468-1f3ff-200d-1f680", "male-firefighter_light_skin_tone": "1f468-1f3fb-200d-1f692", "man_firefighter_light_skin_tone": "1f468-1f3fb-200d-1f692", "male-firefighter_medium_light_skin_tone": "1f468-1f3fc-200d-1f692", "man_firefighter_medium_light_skin_tone": "1f468-1f3fc-200d-1f692", "male-firefighter_medium_skin_tone": "1f468-1f3fd-200d-1f692", "man_firefighter_medium_skin_tone": "1f468-1f3fd-200d-1f692", "male-firefighter_medium_dark_skin_tone": "1f468-1f3fe-200d-1f692", "man_firefighter_medium_dark_skin_tone": "1f468-1f3fe-200d-1f692", "male-firefighter_dark_skin_tone": "1f468-1f3ff-200d-1f692", "man_firefighter_dark_skin_tone": "1f468-1f3ff-200d-1f692", "man_with_probing_cane_light_skin_tone": "1f468-1f3fb-200d-1f9af", "man_with_probing_cane_medium_light_skin_tone": "1f468-1f3fc-200d-1f9af", "man_with_probing_cane_medium_skin_tone": "1f468-1f3fd-200d-1f9af", "man_with_probing_cane_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9af", "man_with_probing_cane_dark_skin_tone": "1f468-1f3ff-200d-1f9af", "red_haired_man_light_skin_tone": "1f468-1f3fb-200d-1f9b0", "red_haired_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b0", "red_haired_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b0", "red_haired_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b0", "red_haired_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b0", "curly_haired_man_light_skin_tone": "1f468-1f3fb-200d-1f9b1", "curly_haired_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b1", "curly_haired_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b1", "curly_haired_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b1", "curly_haired_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b1", "bald_man_light_skin_tone": "1f468-1f3fb-200d-1f9b2", "bald_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b2", "bald_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b2", "bald_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b2", "bald_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b2", "white_haired_man_light_skin_tone": "1f468-1f3fb-200d-1f9b3", "white_haired_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b3", "white_haired_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b3", "white_haired_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b3", "white_haired_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b3", "man_in_motorized_wheelchair_light_skin_tone": "1f468-1f3fb-200d-1f9bc", "man_in_motorized_wheelchair_medium_light_skin_tone": "1f468-1f3fc-200d-1f9bc", "man_in_motorized_wheelchair_medium_skin_tone": "1f468-1f3fd-200d-1f9bc", "man_in_motorized_wheelchair_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9bc", "man_in_motorized_wheelchair_dark_skin_tone": "1f468-1f3ff-200d-1f9bc", "man_in_manual_wheelchair_light_skin_tone": "1f468-1f3fb-200d-1f9bd", "man_in_manual_wheelchair_medium_light_skin_tone": "1f468-1f3fc-200d-1f9bd", "man_in_manual_wheelchair_medium_skin_tone": "1f468-1f3fd-200d-1f9bd", "man_in_manual_wheelchair_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9bd", "man_in_manual_wheelchair_dark_skin_tone": "1f468-1f3ff-200d-1f9bd", "male-doctor_light_skin_tone": "1f468-1f3fb-200d-2695-fe0f", "man_health_worker_light_skin_tone": "1f468-1f3fb-200d-2695-fe0f", "male-doctor_medium_light_skin_tone": "1f468-1f3fc-200d-2695-fe0f", "man_health_worker_medium_light_skin_tone": "1f468-1f3fc-200d-2695-fe0f", "male-doctor_medium_skin_tone": "1f468-1f3fd-200d-2695-fe0f", "man_health_worker_medium_skin_tone": "1f468-1f3fd-200d-2695-fe0f", "male-doctor_medium_dark_skin_tone": "1f468-1f3fe-200d-2695-fe0f", "man_health_worker_medium_dark_skin_tone": "1f468-1f3fe-200d-2695-fe0f", "male-doctor_dark_skin_tone": "1f468-1f3ff-200d-2695-fe0f", "man_health_worker_dark_skin_tone": "1f468-1f3ff-200d-2695-fe0f", "male-judge_light_skin_tone": "1f468-1f3fb-200d-2696-fe0f", "man_judge_light_skin_tone": "1f468-1f3fb-200d-2696-fe0f", "male-judge_medium_light_skin_tone": "1f468-1f3fc-200d-2696-fe0f", "man_judge_medium_light_skin_tone": "1f468-1f3fc-200d-2696-fe0f", "male-judge_medium_skin_tone": "1f468-1f3fd-200d-2696-fe0f", "man_judge_medium_skin_tone": "1f468-1f3fd-200d-2696-fe0f", "male-judge_medium_dark_skin_tone": "1f468-1f3fe-200d-2696-fe0f", "man_judge_medium_dark_skin_tone": "1f468-1f3fe-200d-2696-fe0f", "male-judge_dark_skin_tone": "1f468-1f3ff-200d-2696-fe0f", "man_judge_dark_skin_tone": "1f468-1f3ff-200d-2696-fe0f", "male-pilot_light_skin_tone": "1f468-1f3fb-200d-2708-fe0f", "man_pilot_light_skin_tone": "1f468-1f3fb-200d-2708-fe0f", "male-pilot_medium_light_skin_tone": "1f468-1f3fc-200d-2708-fe0f", "man_pilot_medium_light_skin_tone": "1f468-1f3fc-200d-2708-fe0f", "male-pilot_medium_skin_tone": "1f468-1f3fd-200d-2708-fe0f", "man_pilot_medium_skin_tone": "1f468-1f3fd-200d-2708-fe0f", "male-pilot_medium_dark_skin_tone": "1f468-1f3fe-200d-2708-fe0f", "man_pilot_medium_dark_skin_tone": "1f468-1f3fe-200d-2708-fe0f", "male-pilot_dark_skin_tone": "1f468-1f3ff-200d-2708-fe0f", "man_pilot_dark_skin_tone": "1f468-1f3ff-200d-2708-fe0f", "man_light_skin_tone": "1f468-1f3fb", "man_medium_light_skin_tone": "1f468-1f3fc", "man_medium_skin_tone": "1f468-1f3fd", "man_medium_dark_skin_tone": "1f468-1f3fe", "man_dark_skin_tone": "1f468-1f3ff", "female-farmer_light_skin_tone": "1f469-1f3fb-200d-1f33e", "woman_farmer_light_skin_tone": "1f469-1f3fb-200d-1f33e", "female-farmer_medium_light_skin_tone": "1f469-1f3fc-200d-1f33e", "woman_farmer_medium_light_skin_tone": "1f469-1f3fc-200d-1f33e", "female-farmer_medium_skin_tone": "1f469-1f3fd-200d-1f33e", "woman_farmer_medium_skin_tone": "1f469-1f3fd-200d-1f33e", "female-farmer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f33e", "woman_farmer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f33e", "female-farmer_dark_skin_tone": "1f469-1f3ff-200d-1f33e", "woman_farmer_dark_skin_tone": "1f469-1f3ff-200d-1f33e", "female-cook_light_skin_tone": "1f469-1f3fb-200d-1f373", "woman_cook_light_skin_tone": "1f469-1f3fb-200d-1f373", "female-cook_medium_light_skin_tone": "1f469-1f3fc-200d-1f373", "woman_cook_medium_light_skin_tone": "1f469-1f3fc-200d-1f373", "female-cook_medium_skin_tone": "1f469-1f3fd-200d-1f373", "woman_cook_medium_skin_tone": "1f469-1f3fd-200d-1f373", "female-cook_medium_dark_skin_tone": "1f469-1f3fe-200d-1f373", "woman_cook_medium_dark_skin_tone": "1f469-1f3fe-200d-1f373", "female-cook_dark_skin_tone": "1f469-1f3ff-200d-1f373", "woman_cook_dark_skin_tone": "1f469-1f3ff-200d-1f373", "woman_feeding_baby_light_skin_tone": "1f469-1f3fb-200d-1f37c", "woman_feeding_baby_medium_light_skin_tone": "1f469-1f3fc-200d-1f37c", "woman_feeding_baby_medium_skin_tone": "1f469-1f3fd-200d-1f37c", "woman_feeding_baby_medium_dark_skin_tone": "1f469-1f3fe-200d-1f37c", "woman_feeding_baby_dark_skin_tone": "1f469-1f3ff-200d-1f37c", "female-student_light_skin_tone": "1f469-1f3fb-200d-1f393", "woman_student_light_skin_tone": "1f469-1f3fb-200d-1f393", "female-student_medium_light_skin_tone": "1f469-1f3fc-200d-1f393", "woman_student_medium_light_skin_tone": "1f469-1f3fc-200d-1f393", "female-student_medium_skin_tone": "1f469-1f3fd-200d-1f393", "woman_student_medium_skin_tone": "1f469-1f3fd-200d-1f393", "female-student_medium_dark_skin_tone": "1f469-1f3fe-200d-1f393", "woman_student_medium_dark_skin_tone": "1f469-1f3fe-200d-1f393", "female-student_dark_skin_tone": "1f469-1f3ff-200d-1f393", "woman_student_dark_skin_tone": "1f469-1f3ff-200d-1f393", "female-singer_light_skin_tone": "1f469-1f3fb-200d-1f3a4", "woman_singer_light_skin_tone": "1f469-1f3fb-200d-1f3a4", "female-singer_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a4", "woman_singer_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a4", "female-singer_medium_skin_tone": "1f469-1f3fd-200d-1f3a4", "woman_singer_medium_skin_tone": "1f469-1f3fd-200d-1f3a4", "female-singer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a4", "woman_singer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a4", "female-singer_dark_skin_tone": "1f469-1f3ff-200d-1f3a4", "woman_singer_dark_skin_tone": "1f469-1f3ff-200d-1f3a4", "female-artist_light_skin_tone": "1f469-1f3fb-200d-1f3a8", "woman_artist_light_skin_tone": "1f469-1f3fb-200d-1f3a8", "female-artist_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a8", "woman_artist_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a8", "female-artist_medium_skin_tone": "1f469-1f3fd-200d-1f3a8", "woman_artist_medium_skin_tone": "1f469-1f3fd-200d-1f3a8", "female-artist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a8", "woman_artist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a8", "female-artist_dark_skin_tone": "1f469-1f3ff-200d-1f3a8", "woman_artist_dark_skin_tone": "1f469-1f3ff-200d-1f3a8", "female-teacher_light_skin_tone": "1f469-1f3fb-200d-1f3eb", "woman_teacher_light_skin_tone": "1f469-1f3fb-200d-1f3eb", "female-teacher_medium_light_skin_tone": "1f469-1f3fc-200d-1f3eb", "woman_teacher_medium_light_skin_tone": "1f469-1f3fc-200d-1f3eb", "female-teacher_medium_skin_tone": "1f469-1f3fd-200d-1f3eb", "woman_teacher_medium_skin_tone": "1f469-1f3fd-200d-1f3eb", "female-teacher_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3eb", "woman_teacher_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3eb", "female-teacher_dark_skin_tone": "1f469-1f3ff-200d-1f3eb", "woman_teacher_dark_skin_tone": "1f469-1f3ff-200d-1f3eb", "female-factory-worker_light_skin_tone": "1f469-1f3fb-200d-1f3ed", "woman_factory_worker_light_skin_tone": "1f469-1f3fb-200d-1f3ed", "female-factory-worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f3ed", "woman_factory_worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f3ed", "female-factory-worker_medium_skin_tone": "1f469-1f3fd-200d-1f3ed", "woman_factory_worker_medium_skin_tone": "1f469-1f3fd-200d-1f3ed", "female-factory-worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3ed", "woman_factory_worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3ed", "female-factory-worker_dark_skin_tone": "1f469-1f3ff-200d-1f3ed", "woman_factory_worker_dark_skin_tone": "1f469-1f3ff-200d-1f3ed", "female-technologist_light_skin_tone": "1f469-1f3fb-200d-1f4bb", "woman_technologist_light_skin_tone": "1f469-1f3fb-200d-1f4bb", "female-technologist_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bb", "woman_technologist_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bb", "female-technologist_medium_skin_tone": "1f469-1f3fd-200d-1f4bb", "woman_technologist_medium_skin_tone": "1f469-1f3fd-200d-1f4bb", "female-technologist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bb", "woman_technologist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bb", "female-technologist_dark_skin_tone": "1f469-1f3ff-200d-1f4bb", "woman_technologist_dark_skin_tone": "1f469-1f3ff-200d-1f4bb", "female-office-worker_light_skin_tone": "1f469-1f3fb-200d-1f4bc", "woman_office_worker_light_skin_tone": "1f469-1f3fb-200d-1f4bc", "female-office-worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bc", "woman_office_worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bc", "female-office-worker_medium_skin_tone": "1f469-1f3fd-200d-1f4bc", "woman_office_worker_medium_skin_tone": "1f469-1f3fd-200d-1f4bc", "female-office-worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bc", "woman_office_worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bc", "female-office-worker_dark_skin_tone": "1f469-1f3ff-200d-1f4bc", "woman_office_worker_dark_skin_tone": "1f469-1f3ff-200d-1f4bc", "female-mechanic_light_skin_tone": "1f469-1f3fb-200d-1f527", "woman_mechanic_light_skin_tone": "1f469-1f3fb-200d-1f527", "female-mechanic_medium_light_skin_tone": "1f469-1f3fc-200d-1f527", "woman_mechanic_medium_light_skin_tone": "1f469-1f3fc-200d-1f527", "female-mechanic_medium_skin_tone": "1f469-1f3fd-200d-1f527", "woman_mechanic_medium_skin_tone": "1f469-1f3fd-200d-1f527", "female-mechanic_medium_dark_skin_tone": "1f469-1f3fe-200d-1f527", "woman_mechanic_medium_dark_skin_tone": "1f469-1f3fe-200d-1f527", "female-mechanic_dark_skin_tone": "1f469-1f3ff-200d-1f527", "woman_mechanic_dark_skin_tone": "1f469-1f3ff-200d-1f527", "female-scientist_light_skin_tone": "1f469-1f3fb-200d-1f52c", "woman_scientist_light_skin_tone": "1f469-1f3fb-200d-1f52c", "female-scientist_medium_light_skin_tone": "1f469-1f3fc-200d-1f52c", "woman_scientist_medium_light_skin_tone": "1f469-1f3fc-200d-1f52c", "female-scientist_medium_skin_tone": "1f469-1f3fd-200d-1f52c", "woman_scientist_medium_skin_tone": "1f469-1f3fd-200d-1f52c", "female-scientist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f52c", "woman_scientist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f52c", "female-scientist_dark_skin_tone": "1f469-1f3ff-200d-1f52c", "woman_scientist_dark_skin_tone": "1f469-1f3ff-200d-1f52c", "female-astronaut_light_skin_tone": "1f469-1f3fb-200d-1f680", "woman_astronaut_light_skin_tone": "1f469-1f3fb-200d-1f680", "female-astronaut_medium_light_skin_tone": "1f469-1f3fc-200d-1f680", "woman_astronaut_medium_light_skin_tone": "1f469-1f3fc-200d-1f680", "female-astronaut_medium_skin_tone": "1f469-1f3fd-200d-1f680", "woman_astronaut_medium_skin_tone": "1f469-1f3fd-200d-1f680", "female-astronaut_medium_dark_skin_tone": "1f469-1f3fe-200d-1f680", "woman_astronaut_medium_dark_skin_tone": "1f469-1f3fe-200d-1f680", "female-astronaut_dark_skin_tone": "1f469-1f3ff-200d-1f680", "woman_astronaut_dark_skin_tone": "1f469-1f3ff-200d-1f680", "female-firefighter_light_skin_tone": "1f469-1f3fb-200d-1f692", "woman_firefighter_light_skin_tone": "1f469-1f3fb-200d-1f692", "female-firefighter_medium_light_skin_tone": "1f469-1f3fc-200d-1f692", "woman_firefighter_medium_light_skin_tone": "1f469-1f3fc-200d-1f692", "female-firefighter_medium_skin_tone": "1f469-1f3fd-200d-1f692", "woman_firefighter_medium_skin_tone": "1f469-1f3fd-200d-1f692", "female-firefighter_medium_dark_skin_tone": "1f469-1f3fe-200d-1f692", "woman_firefighter_medium_dark_skin_tone": "1f469-1f3fe-200d-1f692", "female-firefighter_dark_skin_tone": "1f469-1f3ff-200d-1f692", "woman_firefighter_dark_skin_tone": "1f469-1f3ff-200d-1f692", "woman_with_probing_cane_light_skin_tone": "1f469-1f3fb-200d-1f9af", "woman_with_probing_cane_medium_light_skin_tone": "1f469-1f3fc-200d-1f9af", "woman_with_probing_cane_medium_skin_tone": "1f469-1f3fd-200d-1f9af", "woman_with_probing_cane_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9af", "woman_with_probing_cane_dark_skin_tone": "1f469-1f3ff-200d-1f9af", "red_haired_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b0", "red_haired_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b0", "red_haired_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b0", "red_haired_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b0", "red_haired_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b0", "curly_haired_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b1", "curly_haired_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b1", "curly_haired_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b1", "curly_haired_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b1", "curly_haired_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b1", "bald_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b2", "bald_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b2", "bald_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b2", "bald_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b2", "bald_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b2", "white_haired_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b3", "white_haired_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b3", "white_haired_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b3", "white_haired_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b3", "white_haired_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b3", "woman_in_motorized_wheelchair_light_skin_tone": "1f469-1f3fb-200d-1f9bc", "woman_in_motorized_wheelchair_medium_light_skin_tone": "1f469-1f3fc-200d-1f9bc", "woman_in_motorized_wheelchair_medium_skin_tone": "1f469-1f3fd-200d-1f9bc", "woman_in_motorized_wheelchair_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9bc", "woman_in_motorized_wheelchair_dark_skin_tone": "1f469-1f3ff-200d-1f9bc", "woman_in_manual_wheelchair_light_skin_tone": "1f469-1f3fb-200d-1f9bd", "woman_in_manual_wheelchair_medium_light_skin_tone": "1f469-1f3fc-200d-1f9bd", "woman_in_manual_wheelchair_medium_skin_tone": "1f469-1f3fd-200d-1f9bd", "woman_in_manual_wheelchair_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9bd", "woman_in_manual_wheelchair_dark_skin_tone": "1f469-1f3ff-200d-1f9bd", "female-doctor_light_skin_tone": "1f469-1f3fb-200d-2695-fe0f", "woman_health_worker_light_skin_tone": "1f469-1f3fb-200d-2695-fe0f", "female-doctor_medium_light_skin_tone": "1f469-1f3fc-200d-2695-fe0f", "woman_health_worker_medium_light_skin_tone": "1f469-1f3fc-200d-2695-fe0f", "female-doctor_medium_skin_tone": "1f469-1f3fd-200d-2695-fe0f", "woman_health_worker_medium_skin_tone": "1f469-1f3fd-200d-2695-fe0f", "female-doctor_medium_dark_skin_tone": "1f469-1f3fe-200d-2695-fe0f", "woman_health_worker_medium_dark_skin_tone": "1f469-1f3fe-200d-2695-fe0f", "female-doctor_dark_skin_tone": "1f469-1f3ff-200d-2695-fe0f", "woman_health_worker_dark_skin_tone": "1f469-1f3ff-200d-2695-fe0f", "female-judge_light_skin_tone": "1f469-1f3fb-200d-2696-fe0f", "woman_judge_light_skin_tone": "1f469-1f3fb-200d-2696-fe0f", "female-judge_medium_light_skin_tone": "1f469-1f3fc-200d-2696-fe0f", "woman_judge_medium_light_skin_tone": "1f469-1f3fc-200d-2696-fe0f", "female-judge_medium_skin_tone": "1f469-1f3fd-200d-2696-fe0f", "woman_judge_medium_skin_tone": "1f469-1f3fd-200d-2696-fe0f", "female-judge_medium_dark_skin_tone": "1f469-1f3fe-200d-2696-fe0f", "woman_judge_medium_dark_skin_tone": "1f469-1f3fe-200d-2696-fe0f", "female-judge_dark_skin_tone": "1f469-1f3ff-200d-2696-fe0f", "woman_judge_dark_skin_tone": "1f469-1f3ff-200d-2696-fe0f", "female-pilot_light_skin_tone": "1f469-1f3fb-200d-2708-fe0f", "woman_pilot_light_skin_tone": "1f469-1f3fb-200d-2708-fe0f", "female-pilot_medium_light_skin_tone": "1f469-1f3fc-200d-2708-fe0f", "woman_pilot_medium_light_skin_tone": "1f469-1f3fc-200d-2708-fe0f", "female-pilot_medium_skin_tone": "1f469-1f3fd-200d-2708-fe0f", "woman_pilot_medium_skin_tone": "1f469-1f3fd-200d-2708-fe0f", "female-pilot_medium_dark_skin_tone": "1f469-1f3fe-200d-2708-fe0f", "woman_pilot_medium_dark_skin_tone": "1f469-1f3fe-200d-2708-fe0f", "female-pilot_dark_skin_tone": "1f469-1f3ff-200d-2708-fe0f", "woman_pilot_dark_skin_tone": "1f469-1f3ff-200d-2708-fe0f", "woman_light_skin_tone": "1f469-1f3fb", "woman_medium_light_skin_tone": "1f469-1f3fc", "woman_medium_skin_tone": "1f469-1f3fd", "woman_medium_dark_skin_tone": "1f469-1f3fe", "woman_dark_skin_tone": "1f469-1f3ff", "man_and_woman_holding_hands_light_skin_tone": "1f46b-1f3fb", "woman_and_man_holding_hands_light_skin_tone": "1f46b-1f3fb", "couple_light_skin_tone": "1f46b-1f3fb", "man_and_woman_holding_hands_medium_light_skin_tone": "1f46b-1f3fc", "woman_and_man_holding_hands_medium_light_skin_tone": "1f46b-1f3fc", "couple_medium_light_skin_tone": "1f46b-1f3fc", "man_and_woman_holding_hands_medium_skin_tone": "1f46b-1f3fd", "woman_and_man_holding_hands_medium_skin_tone": "1f46b-1f3fd", "couple_medium_skin_tone": "1f46b-1f3fd", "man_and_woman_holding_hands_medium_dark_skin_tone": "1f46b-1f3fe", "woman_and_man_holding_hands_medium_dark_skin_tone": "1f46b-1f3fe", "couple_medium_dark_skin_tone": "1f46b-1f3fe", "man_and_woman_holding_hands_dark_skin_tone": "1f46b-1f3ff", "woman_and_man_holding_hands_dark_skin_tone": "1f46b-1f3ff", "couple_dark_skin_tone": "1f46b-1f3ff", "man_and_woman_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fc", "couple_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fd", "couple_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fe", "couple_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fe", "man_and_woman_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3ff", "couple_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fb", "couple_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fd", "couple_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fe", "couple_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fe", "man_and_woman_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3ff", "couple_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fb", "couple_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fc", "couple_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fe", "couple_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fe", "man_and_woman_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3ff", "couple_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fb", "couple_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fc", "couple_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fd", "couple_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3ff", "couple_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fb", "couple_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fc", "couple_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fd", "couple_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fe", "couple_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_light_skin_tone": "1f46c-1f3fb", "men_holding_hands_light_skin_tone": "1f46c-1f3fb", "two_men_holding_hands_medium_light_skin_tone": "1f46c-1f3fc", "men_holding_hands_medium_light_skin_tone": "1f46c-1f3fc", "two_men_holding_hands_medium_skin_tone": "1f46c-1f3fd", "men_holding_hands_medium_skin_tone": "1f46c-1f3fd", "two_men_holding_hands_medium_dark_skin_tone": "1f46c-1f3fe", "men_holding_hands_medium_dark_skin_tone": "1f46c-1f3fe", "two_men_holding_hands_dark_skin_tone": "1f46c-1f3ff", "men_holding_hands_dark_skin_tone": "1f46c-1f3ff", "two_men_holding_hands_light_skin_tone_medium_light_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_light_skin_tone_medium_light_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_light_skin_tone_medium_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_light_skin_tone_medium_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_light_skin_tone_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_light_skin_tone_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_medium_light_skin_tone_light_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_medium_light_skin_tone_light_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_medium_skin_tone_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_medium_skin_tone_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_medium_skin_tone_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_medium_skin_tone_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_dark_skin_tone_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_dark_skin_tone_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_dark_skin_tone_medium_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_dark_skin_tone_medium_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fe", "two_women_holding_hands_light_skin_tone": "1f46d-1f3fb", "women_holding_hands_light_skin_tone": "1f46d-1f3fb", "two_women_holding_hands_medium_light_skin_tone": "1f46d-1f3fc", "women_holding_hands_medium_light_skin_tone": "1f46d-1f3fc", "two_women_holding_hands_medium_skin_tone": "1f46d-1f3fd", "women_holding_hands_medium_skin_tone": "1f46d-1f3fd", "two_women_holding_hands_medium_dark_skin_tone": "1f46d-1f3fe", "women_holding_hands_medium_dark_skin_tone": "1f46d-1f3fe", "two_women_holding_hands_dark_skin_tone": "1f46d-1f3ff", "women_holding_hands_dark_skin_tone": "1f46d-1f3ff", "two_women_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fe", "two_women_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fe", "two_women_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fe", "two_women_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fe", "female-police-officer_light_skin_tone": "1f46e-1f3fb-200d-2640-fe0f", "policewoman_light_skin_tone": "1f46e-1f3fb-200d-2640-fe0f", "female-police-officer_medium_light_skin_tone": "1f46e-1f3fc-200d-2640-fe0f", "policewoman_medium_light_skin_tone": "1f46e-1f3fc-200d-2640-fe0f", "female-police-officer_medium_skin_tone": "1f46e-1f3fd-200d-2640-fe0f", "policewoman_medium_skin_tone": "1f46e-1f3fd-200d-2640-fe0f", "female-police-officer_medium_dark_skin_tone": "1f46e-1f3fe-200d-2640-fe0f", "policewoman_medium_dark_skin_tone": "1f46e-1f3fe-200d-2640-fe0f", "female-police-officer_dark_skin_tone": "1f46e-1f3ff-200d-2640-fe0f", "policewoman_dark_skin_tone": "1f46e-1f3ff-200d-2640-fe0f", "male-police-officer_light_skin_tone": "1f46e-1f3fb-200d-2642-fe0f", "policeman_light_skin_tone": "1f46e-1f3fb-200d-2642-fe0f", "male-police-officer_medium_light_skin_tone": "1f46e-1f3fc-200d-2642-fe0f", "policeman_medium_light_skin_tone": "1f46e-1f3fc-200d-2642-fe0f", "male-police-officer_medium_skin_tone": "1f46e-1f3fd-200d-2642-fe0f", "policeman_medium_skin_tone": "1f46e-1f3fd-200d-2642-fe0f", "male-police-officer_medium_dark_skin_tone": "1f46e-1f3fe-200d-2642-fe0f", "policeman_medium_dark_skin_tone": "1f46e-1f3fe-200d-2642-fe0f", "male-police-officer_dark_skin_tone": "1f46e-1f3ff-200d-2642-fe0f", "policeman_dark_skin_tone": "1f46e-1f3ff-200d-2642-fe0f", "cop_light_skin_tone": "1f46e-1f3fb", "cop_medium_light_skin_tone": "1f46e-1f3fc", "cop_medium_skin_tone": "1f46e-1f3fd", "cop_medium_dark_skin_tone": "1f46e-1f3fe", "cop_dark_skin_tone": "1f46e-1f3ff", "woman_with_veil_light_skin_tone": "1f470-1f3fb-200d-2640-fe0f", "woman_with_veil_medium_light_skin_tone": "1f470-1f3fc-200d-2640-fe0f", "woman_with_veil_medium_skin_tone": "1f470-1f3fd-200d-2640-fe0f", "woman_with_veil_medium_dark_skin_tone": "1f470-1f3fe-200d-2640-fe0f", "woman_with_veil_dark_skin_tone": "1f470-1f3ff-200d-2640-fe0f", "man_with_veil_light_skin_tone": "1f470-1f3fb-200d-2642-fe0f", "man_with_veil_medium_light_skin_tone": "1f470-1f3fc-200d-2642-fe0f", "man_with_veil_medium_skin_tone": "1f470-1f3fd-200d-2642-fe0f", "man_with_veil_medium_dark_skin_tone": "1f470-1f3fe-200d-2642-fe0f", "man_with_veil_dark_skin_tone": "1f470-1f3ff-200d-2642-fe0f", "bride_with_veil_light_skin_tone": "1f470-1f3fb", "bride_with_veil_medium_light_skin_tone": "1f470-1f3fc", "bride_with_veil_medium_skin_tone": "1f470-1f3fd", "bride_with_veil_medium_dark_skin_tone": "1f470-1f3fe", "bride_with_veil_dark_skin_tone": "1f470-1f3ff", "blond-haired-woman_light_skin_tone": "1f471-1f3fb-200d-2640-fe0f", "blonde_woman_light_skin_tone": "1f471-1f3fb-200d-2640-fe0f", "blond-haired-woman_medium_light_skin_tone": "1f471-1f3fc-200d-2640-fe0f", "blonde_woman_medium_light_skin_tone": "1f471-1f3fc-200d-2640-fe0f", "blond-haired-woman_medium_skin_tone": "1f471-1f3fd-200d-2640-fe0f", "blonde_woman_medium_skin_tone": "1f471-1f3fd-200d-2640-fe0f", "blond-haired-woman_medium_dark_skin_tone": "1f471-1f3fe-200d-2640-fe0f", "blonde_woman_medium_dark_skin_tone": "1f471-1f3fe-200d-2640-fe0f", "blond-haired-woman_dark_skin_tone": "1f471-1f3ff-200d-2640-fe0f", "blonde_woman_dark_skin_tone": "1f471-1f3ff-200d-2640-fe0f", "blond-haired-man_light_skin_tone": "1f471-1f3fb-200d-2642-fe0f", "blonde_man_light_skin_tone": "1f471-1f3fb-200d-2642-fe0f", "blond-haired-man_medium_light_skin_tone": "1f471-1f3fc-200d-2642-fe0f", "blonde_man_medium_light_skin_tone": "1f471-1f3fc-200d-2642-fe0f", "blond-haired-man_medium_skin_tone": "1f471-1f3fd-200d-2642-fe0f", "blonde_man_medium_skin_tone": "1f471-1f3fd-200d-2642-fe0f", "blond-haired-man_medium_dark_skin_tone": "1f471-1f3fe-200d-2642-fe0f", "blonde_man_medium_dark_skin_tone": "1f471-1f3fe-200d-2642-fe0f", "blond-haired-man_dark_skin_tone": "1f471-1f3ff-200d-2642-fe0f", "blonde_man_dark_skin_tone": "1f471-1f3ff-200d-2642-fe0f", "person_with_blond_hair_light_skin_tone": "1f471-1f3fb", "person_with_blond_hair_medium_light_skin_tone": "1f471-1f3fc", "person_with_blond_hair_medium_skin_tone": "1f471-1f3fd", "person_with_blond_hair_medium_dark_skin_tone": "1f471-1f3fe", "person_with_blond_hair_dark_skin_tone": "1f471-1f3ff", "man_with_gua_pi_mao_light_skin_tone": "1f472-1f3fb", "man_with_gua_pi_mao_medium_light_skin_tone": "1f472-1f3fc", "man_with_gua_pi_mao_medium_skin_tone": "1f472-1f3fd", "man_with_gua_pi_mao_medium_dark_skin_tone": "1f472-1f3fe", "man_with_gua_pi_mao_dark_skin_tone": "1f472-1f3ff", "woman-wearing-turban_light_skin_tone": "1f473-1f3fb-200d-2640-fe0f", "woman_with_turban_light_skin_tone": "1f473-1f3fb-200d-2640-fe0f", "woman-wearing-turban_medium_light_skin_tone": "1f473-1f3fc-200d-2640-fe0f", "woman_with_turban_medium_light_skin_tone": "1f473-1f3fc-200d-2640-fe0f", "woman-wearing-turban_medium_skin_tone": "1f473-1f3fd-200d-2640-fe0f", "woman_with_turban_medium_skin_tone": "1f473-1f3fd-200d-2640-fe0f", "woman-wearing-turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2640-fe0f", "woman_with_turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2640-fe0f", "woman-wearing-turban_dark_skin_tone": "1f473-1f3ff-200d-2640-fe0f", "woman_with_turban_dark_skin_tone": "1f473-1f3ff-200d-2640-fe0f", "man-wearing-turban_light_skin_tone": "1f473-1f3fb-200d-2642-fe0f", "man-wearing-turban_medium_light_skin_tone": "1f473-1f3fc-200d-2642-fe0f", "man-wearing-turban_medium_skin_tone": "1f473-1f3fd-200d-2642-fe0f", "man-wearing-turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2642-fe0f", "man-wearing-turban_dark_skin_tone": "1f473-1f3ff-200d-2642-fe0f", "man_with_turban_light_skin_tone": "1f473-1f3fb", "man_with_turban_medium_light_skin_tone": "1f473-1f3fc", "man_with_turban_medium_skin_tone": "1f473-1f3fd", "man_with_turban_medium_dark_skin_tone": "1f473-1f3fe", "man_with_turban_dark_skin_tone": "1f473-1f3ff", "older_man_light_skin_tone": "1f474-1f3fb", "older_man_medium_light_skin_tone": "1f474-1f3fc", "older_man_medium_skin_tone": "1f474-1f3fd", "older_man_medium_dark_skin_tone": "1f474-1f3fe", "older_man_dark_skin_tone": "1f474-1f3ff", "older_woman_light_skin_tone": "1f475-1f3fb", "older_woman_medium_light_skin_tone": "1f475-1f3fc", "older_woman_medium_skin_tone": "1f475-1f3fd", "older_woman_medium_dark_skin_tone": "1f475-1f3fe", "older_woman_dark_skin_tone": "1f475-1f3ff", "baby_light_skin_tone": "1f476-1f3fb", "baby_medium_light_skin_tone": "1f476-1f3fc", "baby_medium_skin_tone": "1f476-1f3fd", "baby_medium_dark_skin_tone": "1f476-1f3fe", "baby_dark_skin_tone": "1f476-1f3ff", "female-construction-worker_light_skin_tone": "1f477-1f3fb-200d-2640-fe0f", "construction_worker_woman_light_skin_tone": "1f477-1f3fb-200d-2640-fe0f", "female-construction-worker_medium_light_skin_tone": "1f477-1f3fc-200d-2640-fe0f", "construction_worker_woman_medium_light_skin_tone": "1f477-1f3fc-200d-2640-fe0f", "female-construction-worker_medium_skin_tone": "1f477-1f3fd-200d-2640-fe0f", "construction_worker_woman_medium_skin_tone": "1f477-1f3fd-200d-2640-fe0f", "female-construction-worker_medium_dark_skin_tone": "1f477-1f3fe-200d-2640-fe0f", "construction_worker_woman_medium_dark_skin_tone": "1f477-1f3fe-200d-2640-fe0f", "female-construction-worker_dark_skin_tone": "1f477-1f3ff-200d-2640-fe0f", "construction_worker_woman_dark_skin_tone": "1f477-1f3ff-200d-2640-fe0f", "male-construction-worker_light_skin_tone": "1f477-1f3fb-200d-2642-fe0f", "construction_worker_man_light_skin_tone": "1f477-1f3fb-200d-2642-fe0f", "male-construction-worker_medium_light_skin_tone": "1f477-1f3fc-200d-2642-fe0f", "construction_worker_man_medium_light_skin_tone": "1f477-1f3fc-200d-2642-fe0f", "male-construction-worker_medium_skin_tone": "1f477-1f3fd-200d-2642-fe0f", "construction_worker_man_medium_skin_tone": "1f477-1f3fd-200d-2642-fe0f", "male-construction-worker_medium_dark_skin_tone": "1f477-1f3fe-200d-2642-fe0f", "construction_worker_man_medium_dark_skin_tone": "1f477-1f3fe-200d-2642-fe0f", "male-construction-worker_dark_skin_tone": "1f477-1f3ff-200d-2642-fe0f", "construction_worker_man_dark_skin_tone": "1f477-1f3ff-200d-2642-fe0f", "construction_worker_light_skin_tone": "1f477-1f3fb", "construction_worker_medium_light_skin_tone": "1f477-1f3fc", "construction_worker_medium_skin_tone": "1f477-1f3fd", "construction_worker_medium_dark_skin_tone": "1f477-1f3fe", "construction_worker_dark_skin_tone": "1f477-1f3ff", "princess_light_skin_tone": "1f478-1f3fb", "princess_medium_light_skin_tone": "1f478-1f3fc", "princess_medium_skin_tone": "1f478-1f3fd", "princess_medium_dark_skin_tone": "1f478-1f3fe", "princess_dark_skin_tone": "1f478-1f3ff", "angel_light_skin_tone": "1f47c-1f3fb", "angel_medium_light_skin_tone": "1f47c-1f3fc", "angel_medium_skin_tone": "1f47c-1f3fd", "angel_medium_dark_skin_tone": "1f47c-1f3fe", "angel_dark_skin_tone": "1f47c-1f3ff", "woman-tipping-hand_light_skin_tone": "1f481-1f3fb-200d-2640-fe0f", "tipping_hand_woman_light_skin_tone": "1f481-1f3fb-200d-2640-fe0f", "woman-tipping-hand_medium_light_skin_tone": "1f481-1f3fc-200d-2640-fe0f", "tipping_hand_woman_medium_light_skin_tone": "1f481-1f3fc-200d-2640-fe0f", "woman-tipping-hand_medium_skin_tone": "1f481-1f3fd-200d-2640-fe0f", "tipping_hand_woman_medium_skin_tone": "1f481-1f3fd-200d-2640-fe0f", "woman-tipping-hand_medium_dark_skin_tone": "1f481-1f3fe-200d-2640-fe0f", "tipping_hand_woman_medium_dark_skin_tone": "1f481-1f3fe-200d-2640-fe0f", "woman-tipping-hand_dark_skin_tone": "1f481-1f3ff-200d-2640-fe0f", "tipping_hand_woman_dark_skin_tone": "1f481-1f3ff-200d-2640-fe0f", "man-tipping-hand_light_skin_tone": "1f481-1f3fb-200d-2642-fe0f", "tipping_hand_man_light_skin_tone": "1f481-1f3fb-200d-2642-fe0f", "man-tipping-hand_medium_light_skin_tone": "1f481-1f3fc-200d-2642-fe0f", "tipping_hand_man_medium_light_skin_tone": "1f481-1f3fc-200d-2642-fe0f", "man-tipping-hand_medium_skin_tone": "1f481-1f3fd-200d-2642-fe0f", "tipping_hand_man_medium_skin_tone": "1f481-1f3fd-200d-2642-fe0f", "man-tipping-hand_medium_dark_skin_tone": "1f481-1f3fe-200d-2642-fe0f", "tipping_hand_man_medium_dark_skin_tone": "1f481-1f3fe-200d-2642-fe0f", "man-tipping-hand_dark_skin_tone": "1f481-1f3ff-200d-2642-fe0f", "tipping_hand_man_dark_skin_tone": "1f481-1f3ff-200d-2642-fe0f", "information_desk_person_light_skin_tone": "1f481-1f3fb", "information_desk_person_medium_light_skin_tone": "1f481-1f3fc", "information_desk_person_medium_skin_tone": "1f481-1f3fd", "information_desk_person_medium_dark_skin_tone": "1f481-1f3fe", "information_desk_person_dark_skin_tone": "1f481-1f3ff", "female-guard_light_skin_tone": "1f482-1f3fb-200d-2640-fe0f", "guardswoman_light_skin_tone": "1f482-1f3fb-200d-2640-fe0f", "female-guard_medium_light_skin_tone": "1f482-1f3fc-200d-2640-fe0f", "guardswoman_medium_light_skin_tone": "1f482-1f3fc-200d-2640-fe0f", "female-guard_medium_skin_tone": "1f482-1f3fd-200d-2640-fe0f", "guardswoman_medium_skin_tone": "1f482-1f3fd-200d-2640-fe0f", "female-guard_medium_dark_skin_tone": "1f482-1f3fe-200d-2640-fe0f", "guardswoman_medium_dark_skin_tone": "1f482-1f3fe-200d-2640-fe0f", "female-guard_dark_skin_tone": "1f482-1f3ff-200d-2640-fe0f", "guardswoman_dark_skin_tone": "1f482-1f3ff-200d-2640-fe0f", "male-guard_light_skin_tone": "1f482-1f3fb-200d-2642-fe0f", "male-guard_medium_light_skin_tone": "1f482-1f3fc-200d-2642-fe0f", "male-guard_medium_skin_tone": "1f482-1f3fd-200d-2642-fe0f", "male-guard_medium_dark_skin_tone": "1f482-1f3fe-200d-2642-fe0f", "male-guard_dark_skin_tone": "1f482-1f3ff-200d-2642-fe0f", "guardsman_light_skin_tone": "1f482-1f3fb", "guardsman_medium_light_skin_tone": "1f482-1f3fc", "guardsman_medium_skin_tone": "1f482-1f3fd", "guardsman_medium_dark_skin_tone": "1f482-1f3fe", "guardsman_dark_skin_tone": "1f482-1f3ff", "dancer_light_skin_tone": "1f483-1f3fb", "dancer_medium_light_skin_tone": "1f483-1f3fc", "dancer_medium_skin_tone": "1f483-1f3fd", "dancer_medium_dark_skin_tone": "1f483-1f3fe", "dancer_dark_skin_tone": "1f483-1f3ff", "nail_care_light_skin_tone": "1f485-1f3fb", "nail_care_medium_light_skin_tone": "1f485-1f3fc", "nail_care_medium_skin_tone": "1f485-1f3fd", "nail_care_medium_dark_skin_tone": "1f485-1f3fe", "nail_care_dark_skin_tone": "1f485-1f3ff", "woman-getting-massage_light_skin_tone": "1f486-1f3fb-200d-2640-fe0f", "massage_woman_light_skin_tone": "1f486-1f3fb-200d-2640-fe0f", "woman-getting-massage_medium_light_skin_tone": "1f486-1f3fc-200d-2640-fe0f", "massage_woman_medium_light_skin_tone": "1f486-1f3fc-200d-2640-fe0f", "woman-getting-massage_medium_skin_tone": "1f486-1f3fd-200d-2640-fe0f", "massage_woman_medium_skin_tone": "1f486-1f3fd-200d-2640-fe0f", "woman-getting-massage_medium_dark_skin_tone": "1f486-1f3fe-200d-2640-fe0f", "massage_woman_medium_dark_skin_tone": "1f486-1f3fe-200d-2640-fe0f", "woman-getting-massage_dark_skin_tone": "1f486-1f3ff-200d-2640-fe0f", "massage_woman_dark_skin_tone": "1f486-1f3ff-200d-2640-fe0f", "man-getting-massage_light_skin_tone": "1f486-1f3fb-200d-2642-fe0f", "massage_man_light_skin_tone": "1f486-1f3fb-200d-2642-fe0f", "man-getting-massage_medium_light_skin_tone": "1f486-1f3fc-200d-2642-fe0f", "massage_man_medium_light_skin_tone": "1f486-1f3fc-200d-2642-fe0f", "man-getting-massage_medium_skin_tone": "1f486-1f3fd-200d-2642-fe0f", "massage_man_medium_skin_tone": "1f486-1f3fd-200d-2642-fe0f", "man-getting-massage_medium_dark_skin_tone": "1f486-1f3fe-200d-2642-fe0f", "massage_man_medium_dark_skin_tone": "1f486-1f3fe-200d-2642-fe0f", "man-getting-massage_dark_skin_tone": "1f486-1f3ff-200d-2642-fe0f", "massage_man_dark_skin_tone": "1f486-1f3ff-200d-2642-fe0f", "massage_light_skin_tone": "1f486-1f3fb", "massage_medium_light_skin_tone": "1f486-1f3fc", "massage_medium_skin_tone": "1f486-1f3fd", "massage_medium_dark_skin_tone": "1f486-1f3fe", "massage_dark_skin_tone": "1f486-1f3ff", "woman-getting-haircut_light_skin_tone": "1f487-1f3fb-200d-2640-fe0f", "haircut_woman_light_skin_tone": "1f487-1f3fb-200d-2640-fe0f", "woman-getting-haircut_medium_light_skin_tone": "1f487-1f3fc-200d-2640-fe0f", "haircut_woman_medium_light_skin_tone": "1f487-1f3fc-200d-2640-fe0f", "woman-getting-haircut_medium_skin_tone": "1f487-1f3fd-200d-2640-fe0f", "haircut_woman_medium_skin_tone": "1f487-1f3fd-200d-2640-fe0f", "woman-getting-haircut_medium_dark_skin_tone": "1f487-1f3fe-200d-2640-fe0f", "haircut_woman_medium_dark_skin_tone": "1f487-1f3fe-200d-2640-fe0f", "woman-getting-haircut_dark_skin_tone": "1f487-1f3ff-200d-2640-fe0f", "haircut_woman_dark_skin_tone": "1f487-1f3ff-200d-2640-fe0f", "man-getting-haircut_light_skin_tone": "1f487-1f3fb-200d-2642-fe0f", "haircut_man_light_skin_tone": "1f487-1f3fb-200d-2642-fe0f", "man-getting-haircut_medium_light_skin_tone": "1f487-1f3fc-200d-2642-fe0f", "haircut_man_medium_light_skin_tone": "1f487-1f3fc-200d-2642-fe0f", "man-getting-haircut_medium_skin_tone": "1f487-1f3fd-200d-2642-fe0f", "haircut_man_medium_skin_tone": "1f487-1f3fd-200d-2642-fe0f", "man-getting-haircut_medium_dark_skin_tone": "1f487-1f3fe-200d-2642-fe0f", "haircut_man_medium_dark_skin_tone": "1f487-1f3fe-200d-2642-fe0f", "man-getting-haircut_dark_skin_tone": "1f487-1f3ff-200d-2642-fe0f", "haircut_man_dark_skin_tone": "1f487-1f3ff-200d-2642-fe0f", "haircut_light_skin_tone": "1f487-1f3fb", "haircut_medium_light_skin_tone": "1f487-1f3fc", "haircut_medium_skin_tone": "1f487-1f3fd", "haircut_medium_dark_skin_tone": "1f487-1f3fe", "haircut_dark_skin_tone": "1f487-1f3ff", "muscle_light_skin_tone": "1f4aa-1f3fb", "muscle_medium_light_skin_tone": "1f4aa-1f3fc", "muscle_medium_skin_tone": "1f4aa-1f3fd", "muscle_medium_dark_skin_tone": "1f4aa-1f3fe", "muscle_dark_skin_tone": "1f4aa-1f3ff", "man_in_business_suit_levitating_light_skin_tone": "1f574-1f3fb", "business_suit_levitating_light_skin_tone": "1f574-1f3fb", "man_in_business_suit_levitating_medium_light_skin_tone": "1f574-1f3fc", "business_suit_levitating_medium_light_skin_tone": "1f574-1f3fc", "man_in_business_suit_levitating_medium_skin_tone": "1f574-1f3fd", "business_suit_levitating_medium_skin_tone": "1f574-1f3fd", "man_in_business_suit_levitating_medium_dark_skin_tone": "1f574-1f3fe", "business_suit_levitating_medium_dark_skin_tone": "1f574-1f3fe", "man_in_business_suit_levitating_dark_skin_tone": "1f574-1f3ff", "business_suit_levitating_dark_skin_tone": "1f574-1f3ff", "female-detective_light_skin_tone": "1f575-1f3fb-200d-2640-fe0f", "female_detective_light_skin_tone": "1f575-1f3fb-200d-2640-fe0f", "female-detective_medium_light_skin_tone": "1f575-1f3fc-200d-2640-fe0f", "female_detective_medium_light_skin_tone": "1f575-1f3fc-200d-2640-fe0f", "female-detective_medium_skin_tone": "1f575-1f3fd-200d-2640-fe0f", "female_detective_medium_skin_tone": "1f575-1f3fd-200d-2640-fe0f", "female-detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2640-fe0f", "female_detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2640-fe0f", "female-detective_dark_skin_tone": "1f575-1f3ff-200d-2640-fe0f", "female_detective_dark_skin_tone": "1f575-1f3ff-200d-2640-fe0f", "male-detective_light_skin_tone": "1f575-1f3fb-200d-2642-fe0f", "male_detective_light_skin_tone": "1f575-1f3fb-200d-2642-fe0f", "male-detective_medium_light_skin_tone": "1f575-1f3fc-200d-2642-fe0f", "male_detective_medium_light_skin_tone": "1f575-1f3fc-200d-2642-fe0f", "male-detective_medium_skin_tone": "1f575-1f3fd-200d-2642-fe0f", "male_detective_medium_skin_tone": "1f575-1f3fd-200d-2642-fe0f", "male-detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2642-fe0f", "male_detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2642-fe0f", "male-detective_dark_skin_tone": "1f575-1f3ff-200d-2642-fe0f", "male_detective_dark_skin_tone": "1f575-1f3ff-200d-2642-fe0f", "sleuth_or_spy_light_skin_tone": "1f575-1f3fb", "sleuth_or_spy_medium_light_skin_tone": "1f575-1f3fc", "sleuth_or_spy_medium_skin_tone": "1f575-1f3fd", "sleuth_or_spy_medium_dark_skin_tone": "1f575-1f3fe", "sleuth_or_spy_dark_skin_tone": "1f575-1f3ff", "man_dancing_light_skin_tone": "1f57a-1f3fb", "man_dancing_medium_light_skin_tone": "1f57a-1f3fc", "man_dancing_medium_skin_tone": "1f57a-1f3fd", "man_dancing_medium_dark_skin_tone": "1f57a-1f3fe", "man_dancing_dark_skin_tone": "1f57a-1f3ff", "raised_hand_with_fingers_splayed_light_skin_tone": "1f590-1f3fb", "raised_hand_with_fingers_splayed_medium_light_skin_tone": "1f590-1f3fc", "raised_hand_with_fingers_splayed_medium_skin_tone": "1f590-1f3fd", "raised_hand_with_fingers_splayed_medium_dark_skin_tone": "1f590-1f3fe", "raised_hand_with_fingers_splayed_dark_skin_tone": "1f590-1f3ff", "middle_finger_light_skin_tone": "1f595-1f3fb", "reversed_hand_with_middle_finger_extended_light_skin_tone": "1f595-1f3fb", "middle_finger_medium_light_skin_tone": "1f595-1f3fc", "reversed_hand_with_middle_finger_extended_medium_light_skin_tone": "1f595-1f3fc", "middle_finger_medium_skin_tone": "1f595-1f3fd", "reversed_hand_with_middle_finger_extended_medium_skin_tone": "1f595-1f3fd", "middle_finger_medium_dark_skin_tone": "1f595-1f3fe", "reversed_hand_with_middle_finger_extended_medium_dark_skin_tone": "1f595-1f3fe", "middle_finger_dark_skin_tone": "1f595-1f3ff", "reversed_hand_with_middle_finger_extended_dark_skin_tone": "1f595-1f3ff", "spock-hand_light_skin_tone": "1f596-1f3fb", "vulcan_salute_light_skin_tone": "1f596-1f3fb", "spock-hand_medium_light_skin_tone": "1f596-1f3fc", "vulcan_salute_medium_light_skin_tone": "1f596-1f3fc", "spock-hand_medium_skin_tone": "1f596-1f3fd", "vulcan_salute_medium_skin_tone": "1f596-1f3fd", "spock-hand_medium_dark_skin_tone": "1f596-1f3fe", "vulcan_salute_medium_dark_skin_tone": "1f596-1f3fe", "spock-hand_dark_skin_tone": "1f596-1f3ff", "vulcan_salute_dark_skin_tone": "1f596-1f3ff", "woman-gesturing-no_light_skin_tone": "1f645-1f3fb-200d-2640-fe0f", "no_good_woman_light_skin_tone": "1f645-1f3fb-200d-2640-fe0f", "woman-gesturing-no_medium_light_skin_tone": "1f645-1f3fc-200d-2640-fe0f", "no_good_woman_medium_light_skin_tone": "1f645-1f3fc-200d-2640-fe0f", "woman-gesturing-no_medium_skin_tone": "1f645-1f3fd-200d-2640-fe0f", "no_good_woman_medium_skin_tone": "1f645-1f3fd-200d-2640-fe0f", "woman-gesturing-no_medium_dark_skin_tone": "1f645-1f3fe-200d-2640-fe0f", "no_good_woman_medium_dark_skin_tone": "1f645-1f3fe-200d-2640-fe0f", "woman-gesturing-no_dark_skin_tone": "1f645-1f3ff-200d-2640-fe0f", "no_good_woman_dark_skin_tone": "1f645-1f3ff-200d-2640-fe0f", "man-gesturing-no_light_skin_tone": "1f645-1f3fb-200d-2642-fe0f", "no_good_man_light_skin_tone": "1f645-1f3fb-200d-2642-fe0f", "man-gesturing-no_medium_light_skin_tone": "1f645-1f3fc-200d-2642-fe0f", "no_good_man_medium_light_skin_tone": "1f645-1f3fc-200d-2642-fe0f", "man-gesturing-no_medium_skin_tone": "1f645-1f3fd-200d-2642-fe0f", "no_good_man_medium_skin_tone": "1f645-1f3fd-200d-2642-fe0f", "man-gesturing-no_medium_dark_skin_tone": "1f645-1f3fe-200d-2642-fe0f", "no_good_man_medium_dark_skin_tone": "1f645-1f3fe-200d-2642-fe0f", "man-gesturing-no_dark_skin_tone": "1f645-1f3ff-200d-2642-fe0f", "no_good_man_dark_skin_tone": "1f645-1f3ff-200d-2642-fe0f", "no_good_light_skin_tone": "1f645-1f3fb", "no_good_medium_light_skin_tone": "1f645-1f3fc", "no_good_medium_skin_tone": "1f645-1f3fd", "no_good_medium_dark_skin_tone": "1f645-1f3fe", "no_good_dark_skin_tone": "1f645-1f3ff", "woman-gesturing-ok_light_skin_tone": "1f646-1f3fb-200d-2640-fe0f", "woman-gesturing-ok_medium_light_skin_tone": "1f646-1f3fc-200d-2640-fe0f", "woman-gesturing-ok_medium_skin_tone": "1f646-1f3fd-200d-2640-fe0f", "woman-gesturing-ok_medium_dark_skin_tone": "1f646-1f3fe-200d-2640-fe0f", "woman-gesturing-ok_dark_skin_tone": "1f646-1f3ff-200d-2640-fe0f", "man-gesturing-ok_light_skin_tone": "1f646-1f3fb-200d-2642-fe0f", "ok_man_light_skin_tone": "1f646-1f3fb-200d-2642-fe0f", "man-gesturing-ok_medium_light_skin_tone": "1f646-1f3fc-200d-2642-fe0f", "ok_man_medium_light_skin_tone": "1f646-1f3fc-200d-2642-fe0f", "man-gesturing-ok_medium_skin_tone": "1f646-1f3fd-200d-2642-fe0f", "ok_man_medium_skin_tone": "1f646-1f3fd-200d-2642-fe0f", "man-gesturing-ok_medium_dark_skin_tone": "1f646-1f3fe-200d-2642-fe0f", "ok_man_medium_dark_skin_tone": "1f646-1f3fe-200d-2642-fe0f", "man-gesturing-ok_dark_skin_tone": "1f646-1f3ff-200d-2642-fe0f", "ok_man_dark_skin_tone": "1f646-1f3ff-200d-2642-fe0f", "ok_woman_light_skin_tone": "1f646-1f3fb", "ok_woman_medium_light_skin_tone": "1f646-1f3fc", "ok_woman_medium_skin_tone": "1f646-1f3fd", "ok_woman_medium_dark_skin_tone": "1f646-1f3fe", "ok_woman_dark_skin_tone": "1f646-1f3ff", "woman-bowing_light_skin_tone": "1f647-1f3fb-200d-2640-fe0f", "bowing_woman_light_skin_tone": "1f647-1f3fb-200d-2640-fe0f", "woman-bowing_medium_light_skin_tone": "1f647-1f3fc-200d-2640-fe0f", "bowing_woman_medium_light_skin_tone": "1f647-1f3fc-200d-2640-fe0f", "woman-bowing_medium_skin_tone": "1f647-1f3fd-200d-2640-fe0f", "bowing_woman_medium_skin_tone": "1f647-1f3fd-200d-2640-fe0f", "woman-bowing_medium_dark_skin_tone": "1f647-1f3fe-200d-2640-fe0f", "bowing_woman_medium_dark_skin_tone": "1f647-1f3fe-200d-2640-fe0f", "woman-bowing_dark_skin_tone": "1f647-1f3ff-200d-2640-fe0f", "bowing_woman_dark_skin_tone": "1f647-1f3ff-200d-2640-fe0f", "man-bowing_light_skin_tone": "1f647-1f3fb-200d-2642-fe0f", "bowing_man_light_skin_tone": "1f647-1f3fb-200d-2642-fe0f", "man-bowing_medium_light_skin_tone": "1f647-1f3fc-200d-2642-fe0f", "bowing_man_medium_light_skin_tone": "1f647-1f3fc-200d-2642-fe0f", "man-bowing_medium_skin_tone": "1f647-1f3fd-200d-2642-fe0f", "bowing_man_medium_skin_tone": "1f647-1f3fd-200d-2642-fe0f", "man-bowing_medium_dark_skin_tone": "1f647-1f3fe-200d-2642-fe0f", "bowing_man_medium_dark_skin_tone": "1f647-1f3fe-200d-2642-fe0f", "man-bowing_dark_skin_tone": "1f647-1f3ff-200d-2642-fe0f", "bowing_man_dark_skin_tone": "1f647-1f3ff-200d-2642-fe0f", "bow_light_skin_tone": "1f647-1f3fb", "bow_medium_light_skin_tone": "1f647-1f3fc", "bow_medium_skin_tone": "1f647-1f3fd", "bow_medium_dark_skin_tone": "1f647-1f3fe", "bow_dark_skin_tone": "1f647-1f3ff", "woman-raising-hand_light_skin_tone": "1f64b-1f3fb-200d-2640-fe0f", "raising_hand_woman_light_skin_tone": "1f64b-1f3fb-200d-2640-fe0f", "woman-raising-hand_medium_light_skin_tone": "1f64b-1f3fc-200d-2640-fe0f", "raising_hand_woman_medium_light_skin_tone": "1f64b-1f3fc-200d-2640-fe0f", "woman-raising-hand_medium_skin_tone": "1f64b-1f3fd-200d-2640-fe0f", "raising_hand_woman_medium_skin_tone": "1f64b-1f3fd-200d-2640-fe0f", "woman-raising-hand_medium_dark_skin_tone": "1f64b-1f3fe-200d-2640-fe0f", "raising_hand_woman_medium_dark_skin_tone": "1f64b-1f3fe-200d-2640-fe0f", "woman-raising-hand_dark_skin_tone": "1f64b-1f3ff-200d-2640-fe0f", "raising_hand_woman_dark_skin_tone": "1f64b-1f3ff-200d-2640-fe0f", "man-raising-hand_light_skin_tone": "1f64b-1f3fb-200d-2642-fe0f", "raising_hand_man_light_skin_tone": "1f64b-1f3fb-200d-2642-fe0f", "man-raising-hand_medium_light_skin_tone": "1f64b-1f3fc-200d-2642-fe0f", "raising_hand_man_medium_light_skin_tone": "1f64b-1f3fc-200d-2642-fe0f", "man-raising-hand_medium_skin_tone": "1f64b-1f3fd-200d-2642-fe0f", "raising_hand_man_medium_skin_tone": "1f64b-1f3fd-200d-2642-fe0f", "man-raising-hand_medium_dark_skin_tone": "1f64b-1f3fe-200d-2642-fe0f", "raising_hand_man_medium_dark_skin_tone": "1f64b-1f3fe-200d-2642-fe0f", "man-raising-hand_dark_skin_tone": "1f64b-1f3ff-200d-2642-fe0f", "raising_hand_man_dark_skin_tone": "1f64b-1f3ff-200d-2642-fe0f", "raising_hand_light_skin_tone": "1f64b-1f3fb", "raising_hand_medium_light_skin_tone": "1f64b-1f3fc", "raising_hand_medium_skin_tone": "1f64b-1f3fd", "raising_hand_medium_dark_skin_tone": "1f64b-1f3fe", "raising_hand_dark_skin_tone": "1f64b-1f3ff", "raised_hands_light_skin_tone": "1f64c-1f3fb", "raised_hands_medium_light_skin_tone": "1f64c-1f3fc", "raised_hands_medium_skin_tone": "1f64c-1f3fd", "raised_hands_medium_dark_skin_tone": "1f64c-1f3fe", "raised_hands_dark_skin_tone": "1f64c-1f3ff", "woman-frowning_light_skin_tone": "1f64d-1f3fb-200d-2640-fe0f", "frowning_woman_light_skin_tone": "1f64d-1f3fb-200d-2640-fe0f", "woman-frowning_medium_light_skin_tone": "1f64d-1f3fc-200d-2640-fe0f", "frowning_woman_medium_light_skin_tone": "1f64d-1f3fc-200d-2640-fe0f", "woman-frowning_medium_skin_tone": "1f64d-1f3fd-200d-2640-fe0f", "frowning_woman_medium_skin_tone": "1f64d-1f3fd-200d-2640-fe0f", "woman-frowning_medium_dark_skin_tone": "1f64d-1f3fe-200d-2640-fe0f", "frowning_woman_medium_dark_skin_tone": "1f64d-1f3fe-200d-2640-fe0f", "woman-frowning_dark_skin_tone": "1f64d-1f3ff-200d-2640-fe0f", "frowning_woman_dark_skin_tone": "1f64d-1f3ff-200d-2640-fe0f", "man-frowning_light_skin_tone": "1f64d-1f3fb-200d-2642-fe0f", "frowning_man_light_skin_tone": "1f64d-1f3fb-200d-2642-fe0f", "man-frowning_medium_light_skin_tone": "1f64d-1f3fc-200d-2642-fe0f", "frowning_man_medium_light_skin_tone": "1f64d-1f3fc-200d-2642-fe0f", "man-frowning_medium_skin_tone": "1f64d-1f3fd-200d-2642-fe0f", "frowning_man_medium_skin_tone": "1f64d-1f3fd-200d-2642-fe0f", "man-frowning_medium_dark_skin_tone": "1f64d-1f3fe-200d-2642-fe0f", "frowning_man_medium_dark_skin_tone": "1f64d-1f3fe-200d-2642-fe0f", "man-frowning_dark_skin_tone": "1f64d-1f3ff-200d-2642-fe0f", "frowning_man_dark_skin_tone": "1f64d-1f3ff-200d-2642-fe0f", "person_frowning_light_skin_tone": "1f64d-1f3fb", "person_frowning_medium_light_skin_tone": "1f64d-1f3fc", "person_frowning_medium_skin_tone": "1f64d-1f3fd", "person_frowning_medium_dark_skin_tone": "1f64d-1f3fe", "person_frowning_dark_skin_tone": "1f64d-1f3ff", "woman-pouting_light_skin_tone": "1f64e-1f3fb-200d-2640-fe0f", "pouting_woman_light_skin_tone": "1f64e-1f3fb-200d-2640-fe0f", "woman-pouting_medium_light_skin_tone": "1f64e-1f3fc-200d-2640-fe0f", "pouting_woman_medium_light_skin_tone": "1f64e-1f3fc-200d-2640-fe0f", "woman-pouting_medium_skin_tone": "1f64e-1f3fd-200d-2640-fe0f", "pouting_woman_medium_skin_tone": "1f64e-1f3fd-200d-2640-fe0f", "woman-pouting_medium_dark_skin_tone": "1f64e-1f3fe-200d-2640-fe0f", "pouting_woman_medium_dark_skin_tone": "1f64e-1f3fe-200d-2640-fe0f", "woman-pouting_dark_skin_tone": "1f64e-1f3ff-200d-2640-fe0f", "pouting_woman_dark_skin_tone": "1f64e-1f3ff-200d-2640-fe0f", "man-pouting_light_skin_tone": "1f64e-1f3fb-200d-2642-fe0f", "pouting_man_light_skin_tone": "1f64e-1f3fb-200d-2642-fe0f", "man-pouting_medium_light_skin_tone": "1f64e-1f3fc-200d-2642-fe0f", "pouting_man_medium_light_skin_tone": "1f64e-1f3fc-200d-2642-fe0f", "man-pouting_medium_skin_tone": "1f64e-1f3fd-200d-2642-fe0f", "pouting_man_medium_skin_tone": "1f64e-1f3fd-200d-2642-fe0f", "man-pouting_medium_dark_skin_tone": "1f64e-1f3fe-200d-2642-fe0f", "pouting_man_medium_dark_skin_tone": "1f64e-1f3fe-200d-2642-fe0f", "man-pouting_dark_skin_tone": "1f64e-1f3ff-200d-2642-fe0f", "pouting_man_dark_skin_tone": "1f64e-1f3ff-200d-2642-fe0f", "person_with_pouting_face_light_skin_tone": "1f64e-1f3fb", "person_with_pouting_face_medium_light_skin_tone": "1f64e-1f3fc", "person_with_pouting_face_medium_skin_tone": "1f64e-1f3fd", "person_with_pouting_face_medium_dark_skin_tone": "1f64e-1f3fe", "person_with_pouting_face_dark_skin_tone": "1f64e-1f3ff", "pray_light_skin_tone": "1f64f-1f3fb", "pray_medium_light_skin_tone": "1f64f-1f3fc", "pray_medium_skin_tone": "1f64f-1f3fd", "pray_medium_dark_skin_tone": "1f64f-1f3fe", "pray_dark_skin_tone": "1f64f-1f3ff", "woman-rowing-boat_light_skin_tone": "1f6a3-1f3fb-200d-2640-fe0f", "rowing_woman_light_skin_tone": "1f6a3-1f3fb-200d-2640-fe0f", "woman-rowing-boat_medium_light_skin_tone": "1f6a3-1f3fc-200d-2640-fe0f", "rowing_woman_medium_light_skin_tone": "1f6a3-1f3fc-200d-2640-fe0f", "woman-rowing-boat_medium_skin_tone": "1f6a3-1f3fd-200d-2640-fe0f", "rowing_woman_medium_skin_tone": "1f6a3-1f3fd-200d-2640-fe0f", "woman-rowing-boat_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2640-fe0f", "rowing_woman_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2640-fe0f", "woman-rowing-boat_dark_skin_tone": "1f6a3-1f3ff-200d-2640-fe0f", "rowing_woman_dark_skin_tone": "1f6a3-1f3ff-200d-2640-fe0f", "man-rowing-boat_light_skin_tone": "1f6a3-1f3fb-200d-2642-fe0f", "rowing_man_light_skin_tone": "1f6a3-1f3fb-200d-2642-fe0f", "man-rowing-boat_medium_light_skin_tone": "1f6a3-1f3fc-200d-2642-fe0f", "rowing_man_medium_light_skin_tone": "1f6a3-1f3fc-200d-2642-fe0f", "man-rowing-boat_medium_skin_tone": "1f6a3-1f3fd-200d-2642-fe0f", "rowing_man_medium_skin_tone": "1f6a3-1f3fd-200d-2642-fe0f", "man-rowing-boat_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2642-fe0f", "rowing_man_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2642-fe0f", "man-rowing-boat_dark_skin_tone": "1f6a3-1f3ff-200d-2642-fe0f", "rowing_man_dark_skin_tone": "1f6a3-1f3ff-200d-2642-fe0f", "rowboat_light_skin_tone": "1f6a3-1f3fb", "rowboat_medium_light_skin_tone": "1f6a3-1f3fc", "rowboat_medium_skin_tone": "1f6a3-1f3fd", "rowboat_medium_dark_skin_tone": "1f6a3-1f3fe", "rowboat_dark_skin_tone": "1f6a3-1f3ff", "woman-biking_light_skin_tone": "1f6b4-1f3fb-200d-2640-fe0f", "biking_woman_light_skin_tone": "1f6b4-1f3fb-200d-2640-fe0f", "woman-biking_medium_light_skin_tone": "1f6b4-1f3fc-200d-2640-fe0f", "biking_woman_medium_light_skin_tone": "1f6b4-1f3fc-200d-2640-fe0f", "woman-biking_medium_skin_tone": "1f6b4-1f3fd-200d-2640-fe0f", "biking_woman_medium_skin_tone": "1f6b4-1f3fd-200d-2640-fe0f", "woman-biking_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2640-fe0f", "biking_woman_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2640-fe0f", "woman-biking_dark_skin_tone": "1f6b4-1f3ff-200d-2640-fe0f", "biking_woman_dark_skin_tone": "1f6b4-1f3ff-200d-2640-fe0f", "man-biking_light_skin_tone": "1f6b4-1f3fb-200d-2642-fe0f", "biking_man_light_skin_tone": "1f6b4-1f3fb-200d-2642-fe0f", "man-biking_medium_light_skin_tone": "1f6b4-1f3fc-200d-2642-fe0f", "biking_man_medium_light_skin_tone": "1f6b4-1f3fc-200d-2642-fe0f", "man-biking_medium_skin_tone": "1f6b4-1f3fd-200d-2642-fe0f", "biking_man_medium_skin_tone": "1f6b4-1f3fd-200d-2642-fe0f", "man-biking_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2642-fe0f", "biking_man_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2642-fe0f", "man-biking_dark_skin_tone": "1f6b4-1f3ff-200d-2642-fe0f", "biking_man_dark_skin_tone": "1f6b4-1f3ff-200d-2642-fe0f", "bicyclist_light_skin_tone": "1f6b4-1f3fb", "bicyclist_medium_light_skin_tone": "1f6b4-1f3fc", "bicyclist_medium_skin_tone": "1f6b4-1f3fd", "bicyclist_medium_dark_skin_tone": "1f6b4-1f3fe", "bicyclist_dark_skin_tone": "1f6b4-1f3ff", "woman-mountain-biking_light_skin_tone": "1f6b5-1f3fb-200d-2640-fe0f", "mountain_biking_woman_light_skin_tone": "1f6b5-1f3fb-200d-2640-fe0f", "woman-mountain-biking_medium_light_skin_tone": "1f6b5-1f3fc-200d-2640-fe0f", "mountain_biking_woman_medium_light_skin_tone": "1f6b5-1f3fc-200d-2640-fe0f", "woman-mountain-biking_medium_skin_tone": "1f6b5-1f3fd-200d-2640-fe0f", "mountain_biking_woman_medium_skin_tone": "1f6b5-1f3fd-200d-2640-fe0f", "woman-mountain-biking_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2640-fe0f", "mountain_biking_woman_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2640-fe0f", "woman-mountain-biking_dark_skin_tone": "1f6b5-1f3ff-200d-2640-fe0f", "mountain_biking_woman_dark_skin_tone": "1f6b5-1f3ff-200d-2640-fe0f", "man-mountain-biking_light_skin_tone": "1f6b5-1f3fb-200d-2642-fe0f", "mountain_biking_man_light_skin_tone": "1f6b5-1f3fb-200d-2642-fe0f", "man-mountain-biking_medium_light_skin_tone": "1f6b5-1f3fc-200d-2642-fe0f", "mountain_biking_man_medium_light_skin_tone": "1f6b5-1f3fc-200d-2642-fe0f", "man-mountain-biking_medium_skin_tone": "1f6b5-1f3fd-200d-2642-fe0f", "mountain_biking_man_medium_skin_tone": "1f6b5-1f3fd-200d-2642-fe0f", "man-mountain-biking_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2642-fe0f", "mountain_biking_man_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2642-fe0f", "man-mountain-biking_dark_skin_tone": "1f6b5-1f3ff-200d-2642-fe0f", "mountain_biking_man_dark_skin_tone": "1f6b5-1f3ff-200d-2642-fe0f", "mountain_bicyclist_light_skin_tone": "1f6b5-1f3fb", "mountain_bicyclist_medium_light_skin_tone": "1f6b5-1f3fc", "mountain_bicyclist_medium_skin_tone": "1f6b5-1f3fd", "mountain_bicyclist_medium_dark_skin_tone": "1f6b5-1f3fe", "mountain_bicyclist_dark_skin_tone": "1f6b5-1f3ff", "woman-walking_light_skin_tone": "1f6b6-1f3fb-200d-2640-fe0f", "walking_woman_light_skin_tone": "1f6b6-1f3fb-200d-2640-fe0f", "woman-walking_medium_light_skin_tone": "1f6b6-1f3fc-200d-2640-fe0f", "walking_woman_medium_light_skin_tone": "1f6b6-1f3fc-200d-2640-fe0f", "woman-walking_medium_skin_tone": "1f6b6-1f3fd-200d-2640-fe0f", "walking_woman_medium_skin_tone": "1f6b6-1f3fd-200d-2640-fe0f", "woman-walking_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2640-fe0f", "walking_woman_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2640-fe0f", "woman-walking_dark_skin_tone": "1f6b6-1f3ff-200d-2640-fe0f", "walking_woman_dark_skin_tone": "1f6b6-1f3ff-200d-2640-fe0f", "man-walking_light_skin_tone": "1f6b6-1f3fb-200d-2642-fe0f", "walking_man_light_skin_tone": "1f6b6-1f3fb-200d-2642-fe0f", "man-walking_medium_light_skin_tone": "1f6b6-1f3fc-200d-2642-fe0f", "walking_man_medium_light_skin_tone": "1f6b6-1f3fc-200d-2642-fe0f", "man-walking_medium_skin_tone": "1f6b6-1f3fd-200d-2642-fe0f", "walking_man_medium_skin_tone": "1f6b6-1f3fd-200d-2642-fe0f", "man-walking_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2642-fe0f", "walking_man_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2642-fe0f", "man-walking_dark_skin_tone": "1f6b6-1f3ff-200d-2642-fe0f", "walking_man_dark_skin_tone": "1f6b6-1f3ff-200d-2642-fe0f", "walking_light_skin_tone": "1f6b6-1f3fb", "walking_medium_light_skin_tone": "1f6b6-1f3fc", "walking_medium_skin_tone": "1f6b6-1f3fd", "walking_medium_dark_skin_tone": "1f6b6-1f3fe", "walking_dark_skin_tone": "1f6b6-1f3ff", "bath_light_skin_tone": "1f6c0-1f3fb", "bath_medium_light_skin_tone": "1f6c0-1f3fc", "bath_medium_skin_tone": "1f6c0-1f3fd", "bath_medium_dark_skin_tone": "1f6c0-1f3fe", "bath_dark_skin_tone": "1f6c0-1f3ff", "sleeping_accommodation_light_skin_tone": "1f6cc-1f3fb", "sleeping_accommodation_medium_light_skin_tone": "1f6cc-1f3fc", "sleeping_accommodation_medium_skin_tone": "1f6cc-1f3fd", "sleeping_accommodation_medium_dark_skin_tone": "1f6cc-1f3fe", "sleeping_accommodation_dark_skin_tone": "1f6cc-1f3ff", "pinched_fingers_light_skin_tone": "1f90c-1f3fb", "pinched_fingers_medium_light_skin_tone": "1f90c-1f3fc", "pinched_fingers_medium_skin_tone": "1f90c-1f3fd", "pinched_fingers_medium_dark_skin_tone": "1f90c-1f3fe", "pinched_fingers_dark_skin_tone": "1f90c-1f3ff", "pinching_hand_light_skin_tone": "1f90f-1f3fb", "pinching_hand_medium_light_skin_tone": "1f90f-1f3fc", "pinching_hand_medium_skin_tone": "1f90f-1f3fd", "pinching_hand_medium_dark_skin_tone": "1f90f-1f3fe", "pinching_hand_dark_skin_tone": "1f90f-1f3ff", "the_horns_light_skin_tone": "1f918-1f3fb", "sign_of_the_horns_light_skin_tone": "1f918-1f3fb", "metal_light_skin_tone": "1f918-1f3fb", "the_horns_medium_light_skin_tone": "1f918-1f3fc", "sign_of_the_horns_medium_light_skin_tone": "1f918-1f3fc", "metal_medium_light_skin_tone": "1f918-1f3fc", "the_horns_medium_skin_tone": "1f918-1f3fd", "sign_of_the_horns_medium_skin_tone": "1f918-1f3fd", "metal_medium_skin_tone": "1f918-1f3fd", "the_horns_medium_dark_skin_tone": "1f918-1f3fe", "sign_of_the_horns_medium_dark_skin_tone": "1f918-1f3fe", "metal_medium_dark_skin_tone": "1f918-1f3fe", "the_horns_dark_skin_tone": "1f918-1f3ff", "sign_of_the_horns_dark_skin_tone": "1f918-1f3ff", "metal_dark_skin_tone": "1f918-1f3ff", "call_me_hand_light_skin_tone": "1f919-1f3fb", "call_me_hand_medium_light_skin_tone": "1f919-1f3fc", "call_me_hand_medium_skin_tone": "1f919-1f3fd", "call_me_hand_medium_dark_skin_tone": "1f919-1f3fe", "call_me_hand_dark_skin_tone": "1f919-1f3ff", "raised_back_of_hand_light_skin_tone": "1f91a-1f3fb", "raised_back_of_hand_medium_light_skin_tone": "1f91a-1f3fc", "raised_back_of_hand_medium_skin_tone": "1f91a-1f3fd", "raised_back_of_hand_medium_dark_skin_tone": "1f91a-1f3fe", "raised_back_of_hand_dark_skin_tone": "1f91a-1f3ff", "left-facing_fist_light_skin_tone": "1f91b-1f3fb", "fist_left_light_skin_tone": "1f91b-1f3fb", "left-facing_fist_medium_light_skin_tone": "1f91b-1f3fc", "fist_left_medium_light_skin_tone": "1f91b-1f3fc", "left-facing_fist_medium_skin_tone": "1f91b-1f3fd", "fist_left_medium_skin_tone": "1f91b-1f3fd", "left-facing_fist_medium_dark_skin_tone": "1f91b-1f3fe", "fist_left_medium_dark_skin_tone": "1f91b-1f3fe", "left-facing_fist_dark_skin_tone": "1f91b-1f3ff", "fist_left_dark_skin_tone": "1f91b-1f3ff", "right-facing_fist_light_skin_tone": "1f91c-1f3fb", "fist_right_light_skin_tone": "1f91c-1f3fb", "right-facing_fist_medium_light_skin_tone": "1f91c-1f3fc", "fist_right_medium_light_skin_tone": "1f91c-1f3fc", "right-facing_fist_medium_skin_tone": "1f91c-1f3fd", "fist_right_medium_skin_tone": "1f91c-1f3fd", "right-facing_fist_medium_dark_skin_tone": "1f91c-1f3fe", "fist_right_medium_dark_skin_tone": "1f91c-1f3fe", "right-facing_fist_dark_skin_tone": "1f91c-1f3ff", "fist_right_dark_skin_tone": "1f91c-1f3ff", "crossed_fingers_light_skin_tone": "1f91e-1f3fb", "hand_with_index_and_middle_fingers_crossed_light_skin_tone": "1f91e-1f3fb", "crossed_fingers_medium_light_skin_tone": "1f91e-1f3fc", "hand_with_index_and_middle_fingers_crossed_medium_light_skin_tone": "1f91e-1f3fc", "crossed_fingers_medium_skin_tone": "1f91e-1f3fd", "hand_with_index_and_middle_fingers_crossed_medium_skin_tone": "1f91e-1f3fd", "crossed_fingers_medium_dark_skin_tone": "1f91e-1f3fe", "hand_with_index_and_middle_fingers_crossed_medium_dark_skin_tone": "1f91e-1f3fe", "crossed_fingers_dark_skin_tone": "1f91e-1f3ff", "hand_with_index_and_middle_fingers_crossed_dark_skin_tone": "1f91e-1f3ff", "i_love_you_hand_sign_light_skin_tone": "1f91f-1f3fb", "i_love_you_hand_sign_medium_light_skin_tone": "1f91f-1f3fc", "i_love_you_hand_sign_medium_skin_tone": "1f91f-1f3fd", "i_love_you_hand_sign_medium_dark_skin_tone": "1f91f-1f3fe", "i_love_you_hand_sign_dark_skin_tone": "1f91f-1f3ff", "woman-facepalming_light_skin_tone": "1f926-1f3fb-200d-2640-fe0f", "woman_facepalming_light_skin_tone": "1f926-1f3fb-200d-2640-fe0f", "woman-facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2640-fe0f", "woman_facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2640-fe0f", "woman-facepalming_medium_skin_tone": "1f926-1f3fd-200d-2640-fe0f", "woman_facepalming_medium_skin_tone": "1f926-1f3fd-200d-2640-fe0f", "woman-facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2640-fe0f", "woman_facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2640-fe0f", "woman-facepalming_dark_skin_tone": "1f926-1f3ff-200d-2640-fe0f", "woman_facepalming_dark_skin_tone": "1f926-1f3ff-200d-2640-fe0f", "man-facepalming_light_skin_tone": "1f926-1f3fb-200d-2642-fe0f", "man_facepalming_light_skin_tone": "1f926-1f3fb-200d-2642-fe0f", "man-facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2642-fe0f", "man_facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2642-fe0f", "man-facepalming_medium_skin_tone": "1f926-1f3fd-200d-2642-fe0f", "man_facepalming_medium_skin_tone": "1f926-1f3fd-200d-2642-fe0f", "man-facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2642-fe0f", "man_facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2642-fe0f", "man-facepalming_dark_skin_tone": "1f926-1f3ff-200d-2642-fe0f", "man_facepalming_dark_skin_tone": "1f926-1f3ff-200d-2642-fe0f", "face_palm_light_skin_tone": "1f926-1f3fb", "face_palm_medium_light_skin_tone": "1f926-1f3fc", "face_palm_medium_skin_tone": "1f926-1f3fd", "face_palm_medium_dark_skin_tone": "1f926-1f3fe", "face_palm_dark_skin_tone": "1f926-1f3ff", "pregnant_woman_light_skin_tone": "1f930-1f3fb", "pregnant_woman_medium_light_skin_tone": "1f930-1f3fc", "pregnant_woman_medium_skin_tone": "1f930-1f3fd", "pregnant_woman_medium_dark_skin_tone": "1f930-1f3fe", "pregnant_woman_dark_skin_tone": "1f930-1f3ff", "breast-feeding_light_skin_tone": "1f931-1f3fb", "breast-feeding_medium_light_skin_tone": "1f931-1f3fc", "breast-feeding_medium_skin_tone": "1f931-1f3fd", "breast-feeding_medium_dark_skin_tone": "1f931-1f3fe", "breast-feeding_dark_skin_tone": "1f931-1f3ff", "palms_up_together_light_skin_tone": "1f932-1f3fb", "palms_up_together_medium_light_skin_tone": "1f932-1f3fc", "palms_up_together_medium_skin_tone": "1f932-1f3fd", "palms_up_together_medium_dark_skin_tone": "1f932-1f3fe", "palms_up_together_dark_skin_tone": "1f932-1f3ff", "selfie_light_skin_tone": "1f933-1f3fb", "selfie_medium_light_skin_tone": "1f933-1f3fc", "selfie_medium_skin_tone": "1f933-1f3fd", "selfie_medium_dark_skin_tone": "1f933-1f3fe", "selfie_dark_skin_tone": "1f933-1f3ff", "prince_light_skin_tone": "1f934-1f3fb", "prince_medium_light_skin_tone": "1f934-1f3fc", "prince_medium_skin_tone": "1f934-1f3fd", "prince_medium_dark_skin_tone": "1f934-1f3fe", "prince_dark_skin_tone": "1f934-1f3ff", "woman_in_tuxedo_light_skin_tone": "1f935-1f3fb-200d-2640-fe0f", "woman_in_tuxedo_medium_light_skin_tone": "1f935-1f3fc-200d-2640-fe0f", "woman_in_tuxedo_medium_skin_tone": "1f935-1f3fd-200d-2640-fe0f", "woman_in_tuxedo_medium_dark_skin_tone": "1f935-1f3fe-200d-2640-fe0f", "woman_in_tuxedo_dark_skin_tone": "1f935-1f3ff-200d-2640-fe0f", "man_in_tuxedo_light_skin_tone": "1f935-1f3fb-200d-2642-fe0f", "man_in_tuxedo_medium_light_skin_tone": "1f935-1f3fc-200d-2642-fe0f", "man_in_tuxedo_medium_skin_tone": "1f935-1f3fd-200d-2642-fe0f", "man_in_tuxedo_medium_dark_skin_tone": "1f935-1f3fe-200d-2642-fe0f", "man_in_tuxedo_dark_skin_tone": "1f935-1f3ff-200d-2642-fe0f", "person_in_tuxedo_light_skin_tone": "1f935-1f3fb", "person_in_tuxedo_medium_light_skin_tone": "1f935-1f3fc", "person_in_tuxedo_medium_skin_tone": "1f935-1f3fd", "person_in_tuxedo_medium_dark_skin_tone": "1f935-1f3fe", "person_in_tuxedo_dark_skin_tone": "1f935-1f3ff", "mrs_claus_light_skin_tone": "1f936-1f3fb", "mother_christmas_light_skin_tone": "1f936-1f3fb", "mrs_claus_medium_light_skin_tone": "1f936-1f3fc", "mother_christmas_medium_light_skin_tone": "1f936-1f3fc", "mrs_claus_medium_skin_tone": "1f936-1f3fd", "mother_christmas_medium_skin_tone": "1f936-1f3fd", "mrs_claus_medium_dark_skin_tone": "1f936-1f3fe", "mother_christmas_medium_dark_skin_tone": "1f936-1f3fe", "mrs_claus_dark_skin_tone": "1f936-1f3ff", "mother_christmas_dark_skin_tone": "1f936-1f3ff", "woman-shrugging_light_skin_tone": "1f937-1f3fb-200d-2640-fe0f", "woman_shrugging_light_skin_tone": "1f937-1f3fb-200d-2640-fe0f", "woman-shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2640-fe0f", "woman_shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2640-fe0f", "woman-shrugging_medium_skin_tone": "1f937-1f3fd-200d-2640-fe0f", "woman_shrugging_medium_skin_tone": "1f937-1f3fd-200d-2640-fe0f", "woman-shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2640-fe0f", "woman_shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2640-fe0f", "woman-shrugging_dark_skin_tone": "1f937-1f3ff-200d-2640-fe0f", "woman_shrugging_dark_skin_tone": "1f937-1f3ff-200d-2640-fe0f", "man-shrugging_light_skin_tone": "1f937-1f3fb-200d-2642-fe0f", "man_shrugging_light_skin_tone": "1f937-1f3fb-200d-2642-fe0f", "man-shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2642-fe0f", "man_shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2642-fe0f", "man-shrugging_medium_skin_tone": "1f937-1f3fd-200d-2642-fe0f", "man_shrugging_medium_skin_tone": "1f937-1f3fd-200d-2642-fe0f", "man-shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2642-fe0f", "man_shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2642-fe0f", "man-shrugging_dark_skin_tone": "1f937-1f3ff-200d-2642-fe0f", "man_shrugging_dark_skin_tone": "1f937-1f3ff-200d-2642-fe0f", "shrug_light_skin_tone": "1f937-1f3fb", "shrug_medium_light_skin_tone": "1f937-1f3fc", "shrug_medium_skin_tone": "1f937-1f3fd", "shrug_medium_dark_skin_tone": "1f937-1f3fe", "shrug_dark_skin_tone": "1f937-1f3ff", "woman-cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2640-fe0f", "woman_cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2640-fe0f", "woman-cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2640-fe0f", "woman_cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2640-fe0f", "woman-cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2640-fe0f", "woman_cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2640-fe0f", "woman-cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2640-fe0f", "woman_cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2640-fe0f", "woman-cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2640-fe0f", "woman_cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2640-fe0f", "man-cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2642-fe0f", "man_cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2642-fe0f", "man-cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2642-fe0f", "man_cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2642-fe0f", "man-cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2642-fe0f", "man_cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2642-fe0f", "man-cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2642-fe0f", "man_cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2642-fe0f", "man-cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2642-fe0f", "man_cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2642-fe0f", "person_doing_cartwheel_light_skin_tone": "1f938-1f3fb", "person_doing_cartwheel_medium_light_skin_tone": "1f938-1f3fc", "person_doing_cartwheel_medium_skin_tone": "1f938-1f3fd", "person_doing_cartwheel_medium_dark_skin_tone": "1f938-1f3fe", "person_doing_cartwheel_dark_skin_tone": "1f938-1f3ff", "woman-juggling_light_skin_tone": "1f939-1f3fb-200d-2640-fe0f", "woman_juggling_light_skin_tone": "1f939-1f3fb-200d-2640-fe0f", "woman-juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2640-fe0f", "woman_juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2640-fe0f", "woman-juggling_medium_skin_tone": "1f939-1f3fd-200d-2640-fe0f", "woman_juggling_medium_skin_tone": "1f939-1f3fd-200d-2640-fe0f", "woman-juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2640-fe0f", "woman_juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2640-fe0f", "woman-juggling_dark_skin_tone": "1f939-1f3ff-200d-2640-fe0f", "woman_juggling_dark_skin_tone": "1f939-1f3ff-200d-2640-fe0f", "man-juggling_light_skin_tone": "1f939-1f3fb-200d-2642-fe0f", "man_juggling_light_skin_tone": "1f939-1f3fb-200d-2642-fe0f", "man-juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2642-fe0f", "man_juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2642-fe0f", "man-juggling_medium_skin_tone": "1f939-1f3fd-200d-2642-fe0f", "man_juggling_medium_skin_tone": "1f939-1f3fd-200d-2642-fe0f", "man-juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2642-fe0f", "man_juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2642-fe0f", "man-juggling_dark_skin_tone": "1f939-1f3ff-200d-2642-fe0f", "man_juggling_dark_skin_tone": "1f939-1f3ff-200d-2642-fe0f", "juggling_light_skin_tone": "1f939-1f3fb", "juggling_medium_light_skin_tone": "1f939-1f3fc", "juggling_medium_skin_tone": "1f939-1f3fd", "juggling_medium_dark_skin_tone": "1f939-1f3fe", "juggling_dark_skin_tone": "1f939-1f3ff", "woman-playing-water-polo_light_skin_tone": "1f93d-1f3fb-200d-2640-fe0f", "woman_playing_water_polo_light_skin_tone": "1f93d-1f3fb-200d-2640-fe0f", "woman-playing-water-polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2640-fe0f", "woman_playing_water_polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2640-fe0f", "woman-playing-water-polo_medium_skin_tone": "1f93d-1f3fd-200d-2640-fe0f", "woman_playing_water_polo_medium_skin_tone": "1f93d-1f3fd-200d-2640-fe0f", "woman-playing-water-polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2640-fe0f", "woman_playing_water_polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2640-fe0f", "woman-playing-water-polo_dark_skin_tone": "1f93d-1f3ff-200d-2640-fe0f", "woman_playing_water_polo_dark_skin_tone": "1f93d-1f3ff-200d-2640-fe0f", "man-playing-water-polo_light_skin_tone": "1f93d-1f3fb-200d-2642-fe0f", "man_playing_water_polo_light_skin_tone": "1f93d-1f3fb-200d-2642-fe0f", "man-playing-water-polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2642-fe0f", "man_playing_water_polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2642-fe0f", "man-playing-water-polo_medium_skin_tone": "1f93d-1f3fd-200d-2642-fe0f", "man_playing_water_polo_medium_skin_tone": "1f93d-1f3fd-200d-2642-fe0f", "man-playing-water-polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2642-fe0f", "man_playing_water_polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2642-fe0f", "man-playing-water-polo_dark_skin_tone": "1f93d-1f3ff-200d-2642-fe0f", "man_playing_water_polo_dark_skin_tone": "1f93d-1f3ff-200d-2642-fe0f", "water_polo_light_skin_tone": "1f93d-1f3fb", "water_polo_medium_light_skin_tone": "1f93d-1f3fc", "water_polo_medium_skin_tone": "1f93d-1f3fd", "water_polo_medium_dark_skin_tone": "1f93d-1f3fe", "water_polo_dark_skin_tone": "1f93d-1f3ff", "woman-playing-handball_light_skin_tone": "1f93e-1f3fb-200d-2640-fe0f", "woman_playing_handball_light_skin_tone": "1f93e-1f3fb-200d-2640-fe0f", "woman-playing-handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2640-fe0f", "woman_playing_handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2640-fe0f", "woman-playing-handball_medium_skin_tone": "1f93e-1f3fd-200d-2640-fe0f", "woman_playing_handball_medium_skin_tone": "1f93e-1f3fd-200d-2640-fe0f", "woman-playing-handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2640-fe0f", "woman_playing_handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2640-fe0f", "woman-playing-handball_dark_skin_tone": "1f93e-1f3ff-200d-2640-fe0f", "woman_playing_handball_dark_skin_tone": "1f93e-1f3ff-200d-2640-fe0f", "man-playing-handball_light_skin_tone": "1f93e-1f3fb-200d-2642-fe0f", "man_playing_handball_light_skin_tone": "1f93e-1f3fb-200d-2642-fe0f", "man-playing-handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2642-fe0f", "man_playing_handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2642-fe0f", "man-playing-handball_medium_skin_tone": "1f93e-1f3fd-200d-2642-fe0f", "man_playing_handball_medium_skin_tone": "1f93e-1f3fd-200d-2642-fe0f", "man-playing-handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2642-fe0f", "man_playing_handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2642-fe0f", "man-playing-handball_dark_skin_tone": "1f93e-1f3ff-200d-2642-fe0f", "man_playing_handball_dark_skin_tone": "1f93e-1f3ff-200d-2642-fe0f", "handball_light_skin_tone": "1f93e-1f3fb", "handball_medium_light_skin_tone": "1f93e-1f3fc", "handball_medium_skin_tone": "1f93e-1f3fd", "handball_medium_dark_skin_tone": "1f93e-1f3fe", "handball_dark_skin_tone": "1f93e-1f3ff", "ninja_light_skin_tone": "1f977-1f3fb", "ninja_medium_light_skin_tone": "1f977-1f3fc", "ninja_medium_skin_tone": "1f977-1f3fd", "ninja_medium_dark_skin_tone": "1f977-1f3fe", "ninja_dark_skin_tone": "1f977-1f3ff", "leg_light_skin_tone": "1f9b5-1f3fb", "leg_medium_light_skin_tone": "1f9b5-1f3fc", "leg_medium_skin_tone": "1f9b5-1f3fd", "leg_medium_dark_skin_tone": "1f9b5-1f3fe", "leg_dark_skin_tone": "1f9b5-1f3ff", "foot_light_skin_tone": "1f9b6-1f3fb", "foot_medium_light_skin_tone": "1f9b6-1f3fc", "foot_medium_skin_tone": "1f9b6-1f3fd", "foot_medium_dark_skin_tone": "1f9b6-1f3fe", "foot_dark_skin_tone": "1f9b6-1f3ff", "female_superhero_light_skin_tone": "1f9b8-1f3fb-200d-2640-fe0f", "female_superhero_medium_light_skin_tone": "1f9b8-1f3fc-200d-2640-fe0f", "female_superhero_medium_skin_tone": "1f9b8-1f3fd-200d-2640-fe0f", "female_superhero_medium_dark_skin_tone": "1f9b8-1f3fe-200d-2640-fe0f", "female_superhero_dark_skin_tone": "1f9b8-1f3ff-200d-2640-fe0f", "male_superhero_light_skin_tone": "1f9b8-1f3fb-200d-2642-fe0f", "male_superhero_medium_light_skin_tone": "1f9b8-1f3fc-200d-2642-fe0f", "male_superhero_medium_skin_tone": "1f9b8-1f3fd-200d-2642-fe0f", "male_superhero_medium_dark_skin_tone": "1f9b8-1f3fe-200d-2642-fe0f", "male_superhero_dark_skin_tone": "1f9b8-1f3ff-200d-2642-fe0f", "superhero_light_skin_tone": "1f9b8-1f3fb", "superhero_medium_light_skin_tone": "1f9b8-1f3fc", "superhero_medium_skin_tone": "1f9b8-1f3fd", "superhero_medium_dark_skin_tone": "1f9b8-1f3fe", "superhero_dark_skin_tone": "1f9b8-1f3ff", "female_supervillain_light_skin_tone": "1f9b9-1f3fb-200d-2640-fe0f", "female_supervillain_medium_light_skin_tone": "1f9b9-1f3fc-200d-2640-fe0f", "female_supervillain_medium_skin_tone": "1f9b9-1f3fd-200d-2640-fe0f", "female_supervillain_medium_dark_skin_tone": "1f9b9-1f3fe-200d-2640-fe0f", "female_supervillain_dark_skin_tone": "1f9b9-1f3ff-200d-2640-fe0f", "male_supervillain_light_skin_tone": "1f9b9-1f3fb-200d-2642-fe0f", "male_supervillain_medium_light_skin_tone": "1f9b9-1f3fc-200d-2642-fe0f", "male_supervillain_medium_skin_tone": "1f9b9-1f3fd-200d-2642-fe0f", "male_supervillain_medium_dark_skin_tone": "1f9b9-1f3fe-200d-2642-fe0f", "male_supervillain_dark_skin_tone": "1f9b9-1f3ff-200d-2642-fe0f", "supervillain_light_skin_tone": "1f9b9-1f3fb", "supervillain_medium_light_skin_tone": "1f9b9-1f3fc", "supervillain_medium_skin_tone": "1f9b9-1f3fd", "supervillain_medium_dark_skin_tone": "1f9b9-1f3fe", "supervillain_dark_skin_tone": "1f9b9-1f3ff", "ear_with_hearing_aid_light_skin_tone": "1f9bb-1f3fb", "ear_with_hearing_aid_medium_light_skin_tone": "1f9bb-1f3fc", "ear_with_hearing_aid_medium_skin_tone": "1f9bb-1f3fd", "ear_with_hearing_aid_medium_dark_skin_tone": "1f9bb-1f3fe", "ear_with_hearing_aid_dark_skin_tone": "1f9bb-1f3ff", "woman_standing_light_skin_tone": "1f9cd-1f3fb-200d-2640-fe0f", "woman_standing_medium_light_skin_tone": "1f9cd-1f3fc-200d-2640-fe0f", "woman_standing_medium_skin_tone": "1f9cd-1f3fd-200d-2640-fe0f", "woman_standing_medium_dark_skin_tone": "1f9cd-1f3fe-200d-2640-fe0f", "woman_standing_dark_skin_tone": "1f9cd-1f3ff-200d-2640-fe0f", "man_standing_light_skin_tone": "1f9cd-1f3fb-200d-2642-fe0f", "man_standing_medium_light_skin_tone": "1f9cd-1f3fc-200d-2642-fe0f", "man_standing_medium_skin_tone": "1f9cd-1f3fd-200d-2642-fe0f", "man_standing_medium_dark_skin_tone": "1f9cd-1f3fe-200d-2642-fe0f", "man_standing_dark_skin_tone": "1f9cd-1f3ff-200d-2642-fe0f", "standing_person_light_skin_tone": "1f9cd-1f3fb", "standing_person_medium_light_skin_tone": "1f9cd-1f3fc", "standing_person_medium_skin_tone": "1f9cd-1f3fd", "standing_person_medium_dark_skin_tone": "1f9cd-1f3fe", "standing_person_dark_skin_tone": "1f9cd-1f3ff", "woman_kneeling_light_skin_tone": "1f9ce-1f3fb-200d-2640-fe0f", "woman_kneeling_medium_light_skin_tone": "1f9ce-1f3fc-200d-2640-fe0f", "woman_kneeling_medium_skin_tone": "1f9ce-1f3fd-200d-2640-fe0f", "woman_kneeling_medium_dark_skin_tone": "1f9ce-1f3fe-200d-2640-fe0f", "woman_kneeling_dark_skin_tone": "1f9ce-1f3ff-200d-2640-fe0f", "man_kneeling_light_skin_tone": "1f9ce-1f3fb-200d-2642-fe0f", "man_kneeling_medium_light_skin_tone": "1f9ce-1f3fc-200d-2642-fe0f", "man_kneeling_medium_skin_tone": "1f9ce-1f3fd-200d-2642-fe0f", "man_kneeling_medium_dark_skin_tone": "1f9ce-1f3fe-200d-2642-fe0f", "man_kneeling_dark_skin_tone": "1f9ce-1f3ff-200d-2642-fe0f", "kneeling_person_light_skin_tone": "1f9ce-1f3fb", "kneeling_person_medium_light_skin_tone": "1f9ce-1f3fc", "kneeling_person_medium_skin_tone": "1f9ce-1f3fd", "kneeling_person_medium_dark_skin_tone": "1f9ce-1f3fe", "kneeling_person_dark_skin_tone": "1f9ce-1f3ff", "deaf_woman_light_skin_tone": "1f9cf-1f3fb-200d-2640-fe0f", "deaf_woman_medium_light_skin_tone": "1f9cf-1f3fc-200d-2640-fe0f", "deaf_woman_medium_skin_tone": "1f9cf-1f3fd-200d-2640-fe0f", "deaf_woman_medium_dark_skin_tone": "1f9cf-1f3fe-200d-2640-fe0f", "deaf_woman_dark_skin_tone": "1f9cf-1f3ff-200d-2640-fe0f", "deaf_man_light_skin_tone": "1f9cf-1f3fb-200d-2642-fe0f", "deaf_man_medium_light_skin_tone": "1f9cf-1f3fc-200d-2642-fe0f", "deaf_man_medium_skin_tone": "1f9cf-1f3fd-200d-2642-fe0f", "deaf_man_medium_dark_skin_tone": "1f9cf-1f3fe-200d-2642-fe0f", "deaf_man_dark_skin_tone": "1f9cf-1f3ff-200d-2642-fe0f", "deaf_person_light_skin_tone": "1f9cf-1f3fb", "deaf_person_medium_light_skin_tone": "1f9cf-1f3fc", "deaf_person_medium_skin_tone": "1f9cf-1f3fd", "deaf_person_medium_dark_skin_tone": "1f9cf-1f3fe", "deaf_person_dark_skin_tone": "1f9cf-1f3ff", "farmer_light_skin_tone": "1f9d1-1f3fb-200d-1f33e", "farmer_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f33e", "farmer_medium_skin_tone": "1f9d1-1f3fd-200d-1f33e", "farmer_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f33e", "farmer_dark_skin_tone": "1f9d1-1f3ff-200d-1f33e", "cook_light_skin_tone": "1f9d1-1f3fb-200d-1f373", "cook_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f373", "cook_medium_skin_tone": "1f9d1-1f3fd-200d-1f373", "cook_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f373", "cook_dark_skin_tone": "1f9d1-1f3ff-200d-1f373", "person_feeding_baby_light_skin_tone": "1f9d1-1f3fb-200d-1f37c", "person_feeding_baby_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f37c", "person_feeding_baby_medium_skin_tone": "1f9d1-1f3fd-200d-1f37c", "person_feeding_baby_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f37c", "person_feeding_baby_dark_skin_tone": "1f9d1-1f3ff-200d-1f37c", "mx_claus_light_skin_tone": "1f9d1-1f3fb-200d-1f384", "mx_claus_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f384", "mx_claus_medium_skin_tone": "1f9d1-1f3fd-200d-1f384", "mx_claus_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f384", "mx_claus_dark_skin_tone": "1f9d1-1f3ff-200d-1f384", "student_light_skin_tone": "1f9d1-1f3fb-200d-1f393", "student_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f393", "student_medium_skin_tone": "1f9d1-1f3fd-200d-1f393", "student_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f393", "student_dark_skin_tone": "1f9d1-1f3ff-200d-1f393", "singer_light_skin_tone": "1f9d1-1f3fb-200d-1f3a4", "singer_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3a4", "singer_medium_skin_tone": "1f9d1-1f3fd-200d-1f3a4", "singer_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3a4", "singer_dark_skin_tone": "1f9d1-1f3ff-200d-1f3a4", "artist_light_skin_tone": "1f9d1-1f3fb-200d-1f3a8", "artist_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3a8", "artist_medium_skin_tone": "1f9d1-1f3fd-200d-1f3a8", "artist_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3a8", "artist_dark_skin_tone": "1f9d1-1f3ff-200d-1f3a8", "teacher_light_skin_tone": "1f9d1-1f3fb-200d-1f3eb", "teacher_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3eb", "teacher_medium_skin_tone": "1f9d1-1f3fd-200d-1f3eb", "teacher_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3eb", "teacher_dark_skin_tone": "1f9d1-1f3ff-200d-1f3eb", "factory_worker_light_skin_tone": "1f9d1-1f3fb-200d-1f3ed", "factory_worker_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3ed", "factory_worker_medium_skin_tone": "1f9d1-1f3fd-200d-1f3ed", "factory_worker_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3ed", "factory_worker_dark_skin_tone": "1f9d1-1f3ff-200d-1f3ed", "technologist_light_skin_tone": "1f9d1-1f3fb-200d-1f4bb", "technologist_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f4bb", "technologist_medium_skin_tone": "1f9d1-1f3fd-200d-1f4bb", "technologist_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f4bb", "technologist_dark_skin_tone": "1f9d1-1f3ff-200d-1f4bb", "office_worker_light_skin_tone": "1f9d1-1f3fb-200d-1f4bc", "office_worker_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f4bc", "office_worker_medium_skin_tone": "1f9d1-1f3fd-200d-1f4bc", "office_worker_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f4bc", "office_worker_dark_skin_tone": "1f9d1-1f3ff-200d-1f4bc", "mechanic_light_skin_tone": "1f9d1-1f3fb-200d-1f527", "mechanic_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f527", "mechanic_medium_skin_tone": "1f9d1-1f3fd-200d-1f527", "mechanic_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f527", "mechanic_dark_skin_tone": "1f9d1-1f3ff-200d-1f527", "scientist_light_skin_tone": "1f9d1-1f3fb-200d-1f52c", "scientist_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f52c", "scientist_medium_skin_tone": "1f9d1-1f3fd-200d-1f52c", "scientist_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f52c", "scientist_dark_skin_tone": "1f9d1-1f3ff-200d-1f52c", "astronaut_light_skin_tone": "1f9d1-1f3fb-200d-1f680", "astronaut_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f680", "astronaut_medium_skin_tone": "1f9d1-1f3fd-200d-1f680", "astronaut_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f680", "astronaut_dark_skin_tone": "1f9d1-1f3ff-200d-1f680", "firefighter_light_skin_tone": "1f9d1-1f3fb-200d-1f692", "firefighter_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f692", "firefighter_medium_skin_tone": "1f9d1-1f3fd-200d-1f692", "firefighter_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f692", "firefighter_dark_skin_tone": "1f9d1-1f3ff-200d-1f692", "people_holding_hands_light_skin_tone_light_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_light_skin_tone_medium_light_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_light_skin_tone_medium_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_light_skin_tone_dark_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_medium_light_skin_tone_light_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_medium_light_skin_tone_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_medium_skin_tone_light_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_medium_skin_tone_medium_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_medium_skin_tone_dark_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_medium_dark_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_dark_skin_tone_light_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_dark_skin_tone_medium_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_dark_skin_tone_dark_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3ff", "person_with_probing_cane_light_skin_tone": "1f9d1-1f3fb-200d-1f9af", "person_with_probing_cane_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9af", "person_with_probing_cane_medium_skin_tone": "1f9d1-1f3fd-200d-1f9af", "person_with_probing_cane_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9af", "person_with_probing_cane_dark_skin_tone": "1f9d1-1f3ff-200d-1f9af", "red_haired_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b0", "red_haired_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b0", "red_haired_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b0", "red_haired_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b0", "red_haired_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b0", "curly_haired_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b1", "curly_haired_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b1", "curly_haired_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b1", "curly_haired_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b1", "curly_haired_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b1", "bald_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b2", "bald_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b2", "bald_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b2", "bald_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b2", "bald_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b2", "white_haired_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b3", "white_haired_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b3", "white_haired_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b3", "white_haired_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b3", "white_haired_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b3", "person_in_motorized_wheelchair_light_skin_tone": "1f9d1-1f3fb-200d-1f9bc", "person_in_motorized_wheelchair_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9bc", "person_in_motorized_wheelchair_medium_skin_tone": "1f9d1-1f3fd-200d-1f9bc", "person_in_motorized_wheelchair_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9bc", "person_in_motorized_wheelchair_dark_skin_tone": "1f9d1-1f3ff-200d-1f9bc", "person_in_manual_wheelchair_light_skin_tone": "1f9d1-1f3fb-200d-1f9bd", "person_in_manual_wheelchair_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9bd", "person_in_manual_wheelchair_medium_skin_tone": "1f9d1-1f3fd-200d-1f9bd", "person_in_manual_wheelchair_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9bd", "person_in_manual_wheelchair_dark_skin_tone": "1f9d1-1f3ff-200d-1f9bd", "health_worker_light_skin_tone": "1f9d1-1f3fb-200d-2695-fe0f", "health_worker_medium_light_skin_tone": "1f9d1-1f3fc-200d-2695-fe0f", "health_worker_medium_skin_tone": "1f9d1-1f3fd-200d-2695-fe0f", "health_worker_medium_dark_skin_tone": "1f9d1-1f3fe-200d-2695-fe0f", "health_worker_dark_skin_tone": "1f9d1-1f3ff-200d-2695-fe0f", "judge_light_skin_tone": "1f9d1-1f3fb-200d-2696-fe0f", "judge_medium_light_skin_tone": "1f9d1-1f3fc-200d-2696-fe0f", "judge_medium_skin_tone": "1f9d1-1f3fd-200d-2696-fe0f", "judge_medium_dark_skin_tone": "1f9d1-1f3fe-200d-2696-fe0f", "judge_dark_skin_tone": "1f9d1-1f3ff-200d-2696-fe0f", "pilot_light_skin_tone": "1f9d1-1f3fb-200d-2708-fe0f", "pilot_medium_light_skin_tone": "1f9d1-1f3fc-200d-2708-fe0f", "pilot_medium_skin_tone": "1f9d1-1f3fd-200d-2708-fe0f", "pilot_medium_dark_skin_tone": "1f9d1-1f3fe-200d-2708-fe0f", "pilot_dark_skin_tone": "1f9d1-1f3ff-200d-2708-fe0f", "adult_light_skin_tone": "1f9d1-1f3fb", "adult_medium_light_skin_tone": "1f9d1-1f3fc", "adult_medium_skin_tone": "1f9d1-1f3fd", "adult_medium_dark_skin_tone": "1f9d1-1f3fe", "adult_dark_skin_tone": "1f9d1-1f3ff", "child_light_skin_tone": "1f9d2-1f3fb", "child_medium_light_skin_tone": "1f9d2-1f3fc", "child_medium_skin_tone": "1f9d2-1f3fd", "child_medium_dark_skin_tone": "1f9d2-1f3fe", "child_dark_skin_tone": "1f9d2-1f3ff", "older_adult_light_skin_tone": "1f9d3-1f3fb", "older_adult_medium_light_skin_tone": "1f9d3-1f3fc", "older_adult_medium_skin_tone": "1f9d3-1f3fd", "older_adult_medium_dark_skin_tone": "1f9d3-1f3fe", "older_adult_dark_skin_tone": "1f9d3-1f3ff", "bearded_person_light_skin_tone": "1f9d4-1f3fb", "bearded_person_medium_light_skin_tone": "1f9d4-1f3fc", "bearded_person_medium_skin_tone": "1f9d4-1f3fd", "bearded_person_medium_dark_skin_tone": "1f9d4-1f3fe", "bearded_person_dark_skin_tone": "1f9d4-1f3ff", "person_with_headscarf_light_skin_tone": "1f9d5-1f3fb", "person_with_headscarf_medium_light_skin_tone": "1f9d5-1f3fc", "person_with_headscarf_medium_skin_tone": "1f9d5-1f3fd", "person_with_headscarf_medium_dark_skin_tone": "1f9d5-1f3fe", "person_with_headscarf_dark_skin_tone": "1f9d5-1f3ff", "woman_in_steamy_room_light_skin_tone": "1f9d6-1f3fb-200d-2640-fe0f", "woman_in_steamy_room_medium_light_skin_tone": "1f9d6-1f3fc-200d-2640-fe0f", "woman_in_steamy_room_medium_skin_tone": "1f9d6-1f3fd-200d-2640-fe0f", "woman_in_steamy_room_medium_dark_skin_tone": "1f9d6-1f3fe-200d-2640-fe0f", "woman_in_steamy_room_dark_skin_tone": "1f9d6-1f3ff-200d-2640-fe0f", "man_in_steamy_room_light_skin_tone": "1f9d6-1f3fb-200d-2642-fe0f", "man_in_steamy_room_medium_light_skin_tone": "1f9d6-1f3fc-200d-2642-fe0f", "man_in_steamy_room_medium_skin_tone": "1f9d6-1f3fd-200d-2642-fe0f", "man_in_steamy_room_medium_dark_skin_tone": "1f9d6-1f3fe-200d-2642-fe0f", "man_in_steamy_room_dark_skin_tone": "1f9d6-1f3ff-200d-2642-fe0f", "person_in_steamy_room_light_skin_tone": "1f9d6-1f3fb", "person_in_steamy_room_medium_light_skin_tone": "1f9d6-1f3fc", "person_in_steamy_room_medium_skin_tone": "1f9d6-1f3fd", "person_in_steamy_room_medium_dark_skin_tone": "1f9d6-1f3fe", "person_in_steamy_room_dark_skin_tone": "1f9d6-1f3ff", "woman_climbing_light_skin_tone": "1f9d7-1f3fb-200d-2640-fe0f", "woman_climbing_medium_light_skin_tone": "1f9d7-1f3fc-200d-2640-fe0f", "woman_climbing_medium_skin_tone": "1f9d7-1f3fd-200d-2640-fe0f", "woman_climbing_medium_dark_skin_tone": "1f9d7-1f3fe-200d-2640-fe0f", "woman_climbing_dark_skin_tone": "1f9d7-1f3ff-200d-2640-fe0f", "man_climbing_light_skin_tone": "1f9d7-1f3fb-200d-2642-fe0f", "man_climbing_medium_light_skin_tone": "1f9d7-1f3fc-200d-2642-fe0f", "man_climbing_medium_skin_tone": "1f9d7-1f3fd-200d-2642-fe0f", "man_climbing_medium_dark_skin_tone": "1f9d7-1f3fe-200d-2642-fe0f", "man_climbing_dark_skin_tone": "1f9d7-1f3ff-200d-2642-fe0f", "person_climbing_light_skin_tone": "1f9d7-1f3fb", "person_climbing_medium_light_skin_tone": "1f9d7-1f3fc", "person_climbing_medium_skin_tone": "1f9d7-1f3fd", "person_climbing_medium_dark_skin_tone": "1f9d7-1f3fe", "person_climbing_dark_skin_tone": "1f9d7-1f3ff", "woman_in_lotus_position_light_skin_tone": "1f9d8-1f3fb-200d-2640-fe0f", "woman_in_lotus_position_medium_light_skin_tone": "1f9d8-1f3fc-200d-2640-fe0f", "woman_in_lotus_position_medium_skin_tone": "1f9d8-1f3fd-200d-2640-fe0f", "woman_in_lotus_position_medium_dark_skin_tone": "1f9d8-1f3fe-200d-2640-fe0f", "woman_in_lotus_position_dark_skin_tone": "1f9d8-1f3ff-200d-2640-fe0f", "man_in_lotus_position_light_skin_tone": "1f9d8-1f3fb-200d-2642-fe0f", "man_in_lotus_position_medium_light_skin_tone": "1f9d8-1f3fc-200d-2642-fe0f", "man_in_lotus_position_medium_skin_tone": "1f9d8-1f3fd-200d-2642-fe0f", "man_in_lotus_position_medium_dark_skin_tone": "1f9d8-1f3fe-200d-2642-fe0f", "man_in_lotus_position_dark_skin_tone": "1f9d8-1f3ff-200d-2642-fe0f", "person_in_lotus_position_light_skin_tone": "1f9d8-1f3fb", "person_in_lotus_position_medium_light_skin_tone": "1f9d8-1f3fc", "person_in_lotus_position_medium_skin_tone": "1f9d8-1f3fd", "person_in_lotus_position_medium_dark_skin_tone": "1f9d8-1f3fe", "person_in_lotus_position_dark_skin_tone": "1f9d8-1f3ff", "female_mage_light_skin_tone": "1f9d9-1f3fb-200d-2640-fe0f", "female_mage_medium_light_skin_tone": "1f9d9-1f3fc-200d-2640-fe0f", "female_mage_medium_skin_tone": "1f9d9-1f3fd-200d-2640-fe0f", "female_mage_medium_dark_skin_tone": "1f9d9-1f3fe-200d-2640-fe0f", "female_mage_dark_skin_tone": "1f9d9-1f3ff-200d-2640-fe0f", "male_mage_light_skin_tone": "1f9d9-1f3fb-200d-2642-fe0f", "male_mage_medium_light_skin_tone": "1f9d9-1f3fc-200d-2642-fe0f", "male_mage_medium_skin_tone": "1f9d9-1f3fd-200d-2642-fe0f", "male_mage_medium_dark_skin_tone": "1f9d9-1f3fe-200d-2642-fe0f", "male_mage_dark_skin_tone": "1f9d9-1f3ff-200d-2642-fe0f", "mage_light_skin_tone": "1f9d9-1f3fb", "mage_medium_light_skin_tone": "1f9d9-1f3fc", "mage_medium_skin_tone": "1f9d9-1f3fd", "mage_medium_dark_skin_tone": "1f9d9-1f3fe", "mage_dark_skin_tone": "1f9d9-1f3ff", "female_fairy_light_skin_tone": "1f9da-1f3fb-200d-2640-fe0f", "female_fairy_medium_light_skin_tone": "1f9da-1f3fc-200d-2640-fe0f", "female_fairy_medium_skin_tone": "1f9da-1f3fd-200d-2640-fe0f", "female_fairy_medium_dark_skin_tone": "1f9da-1f3fe-200d-2640-fe0f", "female_fairy_dark_skin_tone": "1f9da-1f3ff-200d-2640-fe0f", "male_fairy_light_skin_tone": "1f9da-1f3fb-200d-2642-fe0f", "male_fairy_medium_light_skin_tone": "1f9da-1f3fc-200d-2642-fe0f", "male_fairy_medium_skin_tone": "1f9da-1f3fd-200d-2642-fe0f", "male_fairy_medium_dark_skin_tone": "1f9da-1f3fe-200d-2642-fe0f", "male_fairy_dark_skin_tone": "1f9da-1f3ff-200d-2642-fe0f", "fairy_light_skin_tone": "1f9da-1f3fb", "fairy_medium_light_skin_tone": "1f9da-1f3fc", "fairy_medium_skin_tone": "1f9da-1f3fd", "fairy_medium_dark_skin_tone": "1f9da-1f3fe", "fairy_dark_skin_tone": "1f9da-1f3ff", "female_vampire_light_skin_tone": "1f9db-1f3fb-200d-2640-fe0f", "female_vampire_medium_light_skin_tone": "1f9db-1f3fc-200d-2640-fe0f", "female_vampire_medium_skin_tone": "1f9db-1f3fd-200d-2640-fe0f", "female_vampire_medium_dark_skin_tone": "1f9db-1f3fe-200d-2640-fe0f", "female_vampire_dark_skin_tone": "1f9db-1f3ff-200d-2640-fe0f", "male_vampire_light_skin_tone": "1f9db-1f3fb-200d-2642-fe0f", "male_vampire_medium_light_skin_tone": "1f9db-1f3fc-200d-2642-fe0f", "male_vampire_medium_skin_tone": "1f9db-1f3fd-200d-2642-fe0f", "male_vampire_medium_dark_skin_tone": "1f9db-1f3fe-200d-2642-fe0f", "male_vampire_dark_skin_tone": "1f9db-1f3ff-200d-2642-fe0f", "vampire_light_skin_tone": "1f9db-1f3fb", "vampire_medium_light_skin_tone": "1f9db-1f3fc", "vampire_medium_skin_tone": "1f9db-1f3fd", "vampire_medium_dark_skin_tone": "1f9db-1f3fe", "vampire_dark_skin_tone": "1f9db-1f3ff", "mermaid_light_skin_tone": "1f9dc-1f3fb-200d-2640-fe0f", "mermaid_medium_light_skin_tone": "1f9dc-1f3fc-200d-2640-fe0f", "mermaid_medium_skin_tone": "1f9dc-1f3fd-200d-2640-fe0f", "mermaid_medium_dark_skin_tone": "1f9dc-1f3fe-200d-2640-fe0f", "mermaid_dark_skin_tone": "1f9dc-1f3ff-200d-2640-fe0f", "merman_light_skin_tone": "1f9dc-1f3fb-200d-2642-fe0f", "merman_medium_light_skin_tone": "1f9dc-1f3fc-200d-2642-fe0f", "merman_medium_skin_tone": "1f9dc-1f3fd-200d-2642-fe0f", "merman_medium_dark_skin_tone": "1f9dc-1f3fe-200d-2642-fe0f", "merman_dark_skin_tone": "1f9dc-1f3ff-200d-2642-fe0f", "merperson_light_skin_tone": "1f9dc-1f3fb", "merperson_medium_light_skin_tone": "1f9dc-1f3fc", "merperson_medium_skin_tone": "1f9dc-1f3fd", "merperson_medium_dark_skin_tone": "1f9dc-1f3fe", "merperson_dark_skin_tone": "1f9dc-1f3ff", "female_elf_light_skin_tone": "1f9dd-1f3fb-200d-2640-fe0f", "female_elf_medium_light_skin_tone": "1f9dd-1f3fc-200d-2640-fe0f", "female_elf_medium_skin_tone": "1f9dd-1f3fd-200d-2640-fe0f", "female_elf_medium_dark_skin_tone": "1f9dd-1f3fe-200d-2640-fe0f", "female_elf_dark_skin_tone": "1f9dd-1f3ff-200d-2640-fe0f", "male_elf_light_skin_tone": "1f9dd-1f3fb-200d-2642-fe0f", "male_elf_medium_light_skin_tone": "1f9dd-1f3fc-200d-2642-fe0f", "male_elf_medium_skin_tone": "1f9dd-1f3fd-200d-2642-fe0f", "male_elf_medium_dark_skin_tone": "1f9dd-1f3fe-200d-2642-fe0f", "male_elf_dark_skin_tone": "1f9dd-1f3ff-200d-2642-fe0f", "elf_light_skin_tone": "1f9dd-1f3fb", "elf_medium_light_skin_tone": "1f9dd-1f3fc", "elf_medium_skin_tone": "1f9dd-1f3fd", "elf_medium_dark_skin_tone": "1f9dd-1f3fe", "elf_dark_skin_tone": "1f9dd-1f3ff", "point_up_light_skin_tone": "261d-1f3fb", "point_up_medium_light_skin_tone": "261d-1f3fc", "point_up_medium_skin_tone": "261d-1f3fd", "point_up_medium_dark_skin_tone": "261d-1f3fe", "point_up_dark_skin_tone": "261d-1f3ff", "woman-bouncing-ball_light_skin_tone": "26f9-1f3fb-200d-2640-fe0f", "basketball_woman_light_skin_tone": "26f9-1f3fb-200d-2640-fe0f", "woman-bouncing-ball_medium_light_skin_tone": "26f9-1f3fc-200d-2640-fe0f", "basketball_woman_medium_light_skin_tone": "26f9-1f3fc-200d-2640-fe0f", "woman-bouncing-ball_medium_skin_tone": "26f9-1f3fd-200d-2640-fe0f", "basketball_woman_medium_skin_tone": "26f9-1f3fd-200d-2640-fe0f", "woman-bouncing-ball_medium_dark_skin_tone": "26f9-1f3fe-200d-2640-fe0f", "basketball_woman_medium_dark_skin_tone": "26f9-1f3fe-200d-2640-fe0f", "woman-bouncing-ball_dark_skin_tone": "26f9-1f3ff-200d-2640-fe0f", "basketball_woman_dark_skin_tone": "26f9-1f3ff-200d-2640-fe0f", "man-bouncing-ball_light_skin_tone": "26f9-1f3fb-200d-2642-fe0f", "basketball_man_light_skin_tone": "26f9-1f3fb-200d-2642-fe0f", "man-bouncing-ball_medium_light_skin_tone": "26f9-1f3fc-200d-2642-fe0f", "basketball_man_medium_light_skin_tone": "26f9-1f3fc-200d-2642-fe0f", "man-bouncing-ball_medium_skin_tone": "26f9-1f3fd-200d-2642-fe0f", "basketball_man_medium_skin_tone": "26f9-1f3fd-200d-2642-fe0f", "man-bouncing-ball_medium_dark_skin_tone": "26f9-1f3fe-200d-2642-fe0f", "basketball_man_medium_dark_skin_tone": "26f9-1f3fe-200d-2642-fe0f", "man-bouncing-ball_dark_skin_tone": "26f9-1f3ff-200d-2642-fe0f", "basketball_man_dark_skin_tone": "26f9-1f3ff-200d-2642-fe0f", "person_with_ball_light_skin_tone": "26f9-1f3fb", "person_with_ball_medium_light_skin_tone": "26f9-1f3fc", "person_with_ball_medium_skin_tone": "26f9-1f3fd", "person_with_ball_medium_dark_skin_tone": "26f9-1f3fe", "person_with_ball_dark_skin_tone": "26f9-1f3ff", "fist_light_skin_tone": "270a-1f3fb", "fist_raised_light_skin_tone": "270a-1f3fb", "fist_medium_light_skin_tone": "270a-1f3fc", "fist_raised_medium_light_skin_tone": "270a-1f3fc", "fist_medium_skin_tone": "270a-1f3fd", "fist_raised_medium_skin_tone": "270a-1f3fd", "fist_medium_dark_skin_tone": "270a-1f3fe", "fist_raised_medium_dark_skin_tone": "270a-1f3fe", "fist_dark_skin_tone": "270a-1f3ff", "fist_raised_dark_skin_tone": "270a-1f3ff", "hand_light_skin_tone": "270b-1f3fb", "raised_hand_light_skin_tone": "270b-1f3fb", "hand_medium_light_skin_tone": "270b-1f3fc", "raised_hand_medium_light_skin_tone": "270b-1f3fc", "hand_medium_skin_tone": "270b-1f3fd", "raised_hand_medium_skin_tone": "270b-1f3fd", "hand_medium_dark_skin_tone": "270b-1f3fe", "raised_hand_medium_dark_skin_tone": "270b-1f3fe", "hand_dark_skin_tone": "270b-1f3ff", "raised_hand_dark_skin_tone": "270b-1f3ff", "v_light_skin_tone": "270c-1f3fb", "v_medium_light_skin_tone": "270c-1f3fc", "v_medium_skin_tone": "270c-1f3fd", "v_medium_dark_skin_tone": "270c-1f3fe", "v_dark_skin_tone": "270c-1f3ff", "writing_hand_light_skin_tone": "270d-1f3fb", "writing_hand_medium_light_skin_tone": "270d-1f3fc", "writing_hand_medium_skin_tone": "270d-1f3fd", "writing_hand_medium_dark_skin_tone": "270d-1f3fe", "writing_hand_dark_skin_tone": "270d-1f3ff", "mattermost": "mattermost"} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/feature_flags.go b/vendor/github.com/mattermost/mattermost-server/v5/model/feature_flags.go index 316c7ffb..7d3d6680 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/feature_flags.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/feature_flags.go @@ -3,16 +3,92 @@ package model +import ( + "reflect" + "strconv" +) + type FeatureFlags struct { // Exists only for unit and manual testing. // When set to a value, will be returned by the ping endpoint. TestFeature string + // Exists only for testing bool functionality. Boolean feature flags interpret "on" or "true" as true and + // all other values as false. + TestBoolFeature bool // Toggle on and off scheduled jobs for cloud user limit emails see MM-29999 CloudDelinquentEmailJobsEnabled bool + + // Toggle on and off support for Collapsed Threads + CollapsedThreads bool + + // Enable the remote cluster service for shared channels. + EnableRemoteClusterService bool + + // AppsEnabled toggle the Apps framework functionalities both in server and client side + AppsEnabled bool + + // Feature flags to control plugin versions + PluginIncidentManagement string `plugin_id:"com.mattermost.plugin-incident-management"` + PluginApps string `plugin_id:"com.mattermost.apps"` + PluginFocalboard string `plugin_id:"focalboard"` + + // Enable timed dnd support for user status + TimedDND bool } func (f *FeatureFlags) SetDefaults() { f.TestFeature = "off" + f.TestBoolFeature = false f.CloudDelinquentEmailJobsEnabled = false + f.CollapsedThreads = true + f.EnableRemoteClusterService = false + f.AppsEnabled = false + f.PluginIncidentManagement = "1.16.1" + f.PluginApps = "" + f.PluginFocalboard = "" + f.TimedDND = false +} + +func (f *FeatureFlags) Plugins() map[string]string { + rFFVal := reflect.ValueOf(f).Elem() + rFFType := reflect.TypeOf(f).Elem() + + pluginVersions := make(map[string]string) + for i := 0; i < rFFVal.NumField(); i++ { + rFieldVal := rFFVal.Field(i) + rFieldType := rFFType.Field(i) + + pluginId, hasPluginId := rFieldType.Tag.Lookup("plugin_id") + if !hasPluginId { + continue + } + + pluginVersions[pluginId] = rFieldVal.String() + } + + return pluginVersions +} + +// ToMap returns the feature flags as a map[string]string +// Supports boolean and string feature flags. +func (f *FeatureFlags) ToMap() map[string]string { + refStructVal := reflect.ValueOf(*f) + refStructType := reflect.TypeOf(*f) + ret := make(map[string]string) + for i := 0; i < refStructVal.NumField(); i++ { + refFieldVal := refStructVal.Field(i) + if !refFieldVal.IsValid() { + continue + } + refFieldType := refStructType.Field(i) + switch refFieldType.Type.Kind() { + case reflect.Bool: + ret[refFieldType.Name] = strconv.FormatBool(refFieldVal.Bool()) + default: + ret[refFieldType.Name] = refFieldVal.String() + } + } + + return ret } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file.go index 9f76bac1..d2cb8f34 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/file.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/file.go @@ -12,11 +12,6 @@ const ( MaxImageSize = int64(6048 * 4032) // 24 megapixels, roughly 36MB as a raw image ) -var ( - IMAGE_EXTENSIONS = [7]string{".jpg", ".jpeg", ".gif", ".bmp", ".png", ".tiff", "tif"} - IMAGE_MIME_TYPES = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff", ".tif": "image/tif"} -) - type FileUploadResponse struct { FileInfos []*FileInfo `json:"file_infos"` ClientIds []string `json:"client_ids"` diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go index c622b8f2..2bad9023 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go @@ -4,19 +4,14 @@ package model import ( - "bytes" "encoding/json" "image" "image/gif" - "image/jpeg" "io" "mime" "net/http" "path/filepath" "strings" - - "github.com/disintegration/imaging" - "github.com/mattermost/mattermost-server/v5/mlog" ) const ( @@ -44,6 +39,7 @@ type FileInfo struct { Id string `json:"id"` CreatorId string `json:"user_id"` PostId string `json:"post_id,omitempty"` + ChannelId string `db:"-" json:"channel_id"` CreateAt int64 `json:"create_at"` UpdateAt int64 `json:"update_at"` DeleteAt int64 `json:"delete_at"` @@ -59,6 +55,7 @@ type FileInfo struct { HasPreviewImage bool `json:"has_preview_image,omitempty"` MiniPreview *[]byte `json:"mini_preview"` // declared as *[]byte to avoid postgres/mysql differences in deserialization Content string `json:"-"` + RemoteId *string `json:"remote_id"` } func (fi *FileInfo) ToJson() string { @@ -72,9 +69,8 @@ func FileInfoFromJson(data io.Reader) *FileInfo { var fi FileInfo if err := decoder.Decode(&fi); err != nil { return nil - } else { - return &fi } + return &fi } func FileInfosToJson(infos []*FileInfo) string { @@ -88,9 +84,8 @@ func FileInfosFromJson(data io.Reader) []*FileInfo { var infos []*FileInfo if err := decoder.Decode(&infos); err != nil { return nil - } else { - return infos } + return infos } func (fi *FileInfo) PreSave() { @@ -105,6 +100,10 @@ func (fi *FileInfo) PreSave() { if fi.UpdateAt < fi.CreateAt { fi.UpdateAt = fi.CreateAt } + + if fi.RemoteId == nil { + fi.RemoteId = NewString("") + } } func (fi *FileInfo) IsValid() *AppError { @@ -116,7 +115,7 @@ func (fi *FileInfo) IsValid() *AppError { return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest) } - if len(fi.PostId) != 0 && !IsValidId(fi.PostId) { + if fi.PostId != "" && !IsValidId(fi.PostId) { return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest) } @@ -157,19 +156,6 @@ func NewInfo(name string) *FileInfo { return info } -func GenerateMiniPreviewImage(img image.Image) *[]byte { - preview := imaging.Resize(img, 16, 16, imaging.Lanczos) - - buf := new(bytes.Buffer) - - if err := jpeg.Encode(buf, preview, &jpeg.Options{Quality: 90}); err != nil { - mlog.Error("Unable to encode image as mini preview jpg", mlog.Err(err)) - return nil - } - data := buf.Bytes() - return &data -} - func GetInfoForBytes(name string, data io.ReadSeeker, size int) (*FileInfo, *AppError) { info := &FileInfo{ Name: name, @@ -196,13 +182,13 @@ func GetInfoForBytes(name string, data io.ReadSeeker, size int) (*FileInfo, *App if info.MimeType == "image/gif" { // Just show the gif itself instead of a preview image for animated gifs data.Seek(0, io.SeekStart) - if gifConfig, err := gif.DecodeAll(data); err != nil { + gifConfig, err := gif.DecodeAll(data) + if err != nil { // Still return the rest of the info even though it doesn't appear to be an actual gif info.HasPreviewImage = true return info, NewAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, err.Error(), http.StatusBadRequest) - } else { - info.HasPreviewImage = len(gifConfig.Image) == 1 } + info.HasPreviewImage = len(gifConfig.Image) == 1 } else { info.HasPreviewImage = true } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_list.go new file mode 100644 index 00000000..cd9694f5 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_list.go @@ -0,0 +1,128 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +import ( + "encoding/json" + "io" + "sort" +) + +type FileInfoList struct { + Order []string `json:"order"` + FileInfos map[string]*FileInfo `json:"file_infos"` + NextFileInfoId string `json:"next_file_info_id"` + PrevFileInfoId string `json:"prev_file_info_id"` +} + +func NewFileInfoList() *FileInfoList { + return &FileInfoList{ + Order: make([]string, 0), + FileInfos: make(map[string]*FileInfo), + NextFileInfoId: "", + PrevFileInfoId: "", + } +} + +func (o *FileInfoList) ToSlice() []*FileInfo { + var fileInfos []*FileInfo + for _, id := range o.Order { + fileInfos = append(fileInfos, o.FileInfos[id]) + } + return fileInfos +} + +func (o *FileInfoList) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } else { + return string(b) + } +} + +func (o *FileInfoList) MakeNonNil() { + if o.Order == nil { + o.Order = make([]string, 0) + } + + if o.FileInfos == nil { + o.FileInfos = make(map[string]*FileInfo) + } +} + +func (o *FileInfoList) AddOrder(id string) { + if o.Order == nil { + o.Order = make([]string, 0, 128) + } + + o.Order = append(o.Order, id) +} + +func (o *FileInfoList) AddFileInfo(fileInfo *FileInfo) { + if o.FileInfos == nil { + o.FileInfos = make(map[string]*FileInfo) + } + + o.FileInfos[fileInfo.Id] = fileInfo +} + +func (o *FileInfoList) UniqueOrder() { + keys := make(map[string]bool) + order := []string{} + for _, fileInfoId := range o.Order { + if _, value := keys[fileInfoId]; !value { + keys[fileInfoId] = true + order = append(order, fileInfoId) + } + } + + o.Order = order +} + +func (o *FileInfoList) Extend(other *FileInfoList) { + for fileInfoId := range other.FileInfos { + o.AddFileInfo(other.FileInfos[fileInfoId]) + } + + for _, fileInfoId := range other.Order { + o.AddOrder(fileInfoId) + } + + o.UniqueOrder() +} + +func (o *FileInfoList) SortByCreateAt() { + sort.Slice(o.Order, func(i, j int) bool { + return o.FileInfos[o.Order[i]].CreateAt > o.FileInfos[o.Order[j]].CreateAt + }) +} + +func (o *FileInfoList) Etag() string { + id := "0" + var t int64 = 0 + + for _, v := range o.FileInfos { + if v.UpdateAt > t { + t = v.UpdateAt + id = v.Id + } else if v.UpdateAt == t && v.Id > id { + t = v.UpdateAt + id = v.Id + } + } + + orderId := "" + if len(o.Order) > 0 { + orderId = o.Order[0] + } + + return Etag(orderId, id, t) +} + +func FileInfoListFromJson(data io.Reader) *FileInfoList { + var o *FileInfoList + json.NewDecoder(data).Decode(&o) + return o +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_search_results.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_search_results.go new file mode 100644 index 00000000..90f2922b --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_search_results.go @@ -0,0 +1,37 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +type FileInfoSearchMatches map[string][]string + +type FileInfoSearchResults struct { + *FileInfoList + Matches FileInfoSearchMatches `json:"matches"` +} + +func MakeFileInfoSearchResults(fileInfos *FileInfoList, matches FileInfoSearchMatches) *FileInfoSearchResults { + return &FileInfoSearchResults{ + fileInfos, + matches, + } +} + +func (o *FileInfoSearchResults) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } + return string(b) +} + +func FileInfoSearchResultsFromJson(data io.Reader) *FileInfoSearchResults { + var o *FileInfoSearchResults + json.NewDecoder(data).Decode(&o) + return o +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group.go index 49783c83..c70b7aa1 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/group.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/group.go @@ -139,7 +139,7 @@ func (group *Group) IsValidForCreate() *AppError { return NewAppError("Group.IsValidForCreate", "model.group.source.app_error", nil, "", http.StatusBadRequest) } - if len(group.RemoteId) > GroupRemoteIDMaxLength || (len(group.RemoteId) == 0 && group.requiresRemoteId()) { + if len(group.RemoteId) > GroupRemoteIDMaxLength || (group.RemoteId == "" && group.requiresRemoteId()) { return NewAppError("Group.IsValidForCreate", "model.group.remote_id.app_error", nil, "", http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go index 6a4d4023..eb3bdf09 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go @@ -60,14 +60,14 @@ func (syncable *GroupSyncable) UnmarshalJSON(b []byte) error { if err != nil { return err } + var channelId string + var teamId string for key, value := range kvp { switch key { case "team_id": - syncable.SyncableId = value.(string) - syncable.Type = GroupSyncableTypeTeam + teamId = value.(string) case "channel_id": - syncable.SyncableId = value.(string) - syncable.Type = GroupSyncableTypeChannel + channelId = value.(string) case "group_id": syncable.GroupId = value.(string) case "auto_add": @@ -75,30 +75,40 @@ func (syncable *GroupSyncable) UnmarshalJSON(b []byte) error { default: } } + if channelId != "" { + syncable.TeamID = teamId + syncable.SyncableId = channelId + syncable.Type = GroupSyncableTypeChannel + } else { + syncable.SyncableId = teamId + syncable.Type = GroupSyncableTypeTeam + } return nil } func (syncable *GroupSyncable) MarshalJSON() ([]byte, error) { type Alias GroupSyncable - switch syncable.Type { case GroupSyncableTypeTeam: return json.Marshal(&struct { - TeamID string `json:"team_id"` - TeamDisplayName string `json:"team_display_name,omitempty"` - TeamType string `json:"team_type,omitempty"` + TeamID string `json:"team_id"` + TeamDisplayName string `json:"team_display_name,omitempty"` + TeamType string `json:"team_type,omitempty"` + Type GroupSyncableType `json:"type,omitempty"` *Alias }{ TeamDisplayName: syncable.TeamDisplayName, TeamType: syncable.TeamType, TeamID: syncable.SyncableId, + Type: syncable.Type, Alias: (*Alias)(syncable), }) case GroupSyncableTypeChannel: return json.Marshal(&struct { - ChannelID string `json:"channel_id"` - ChannelDisplayName string `json:"channel_display_name,omitempty"` - ChannelType string `json:"channel_type,omitempty"` + ChannelID string `json:"channel_id"` + ChannelDisplayName string `json:"channel_display_name,omitempty"` + ChannelType string `json:"channel_type,omitempty"` + Type GroupSyncableType `json:"type,omitempty"` TeamID string `json:"team_id,omitempty"` TeamDisplayName string `json:"team_display_name,omitempty"` @@ -109,6 +119,7 @@ func (syncable *GroupSyncable) MarshalJSON() ([]byte, error) { ChannelID: syncable.SyncableId, ChannelDisplayName: syncable.ChannelDisplayName, ChannelType: syncable.ChannelType, + Type: syncable.Type, TeamID: syncable.TeamID, TeamDisplayName: syncable.TeamDisplayName, diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go b/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go index 3cdd4893..ac803a5d 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go @@ -23,7 +23,7 @@ func (i *GuestsInvite) IsValid() *AppError { } for _, email := range i.Emails { - if len(email) > USER_EMAIL_MAX_LENGTH || len(email) == 0 || !IsValidEmail(email) { + if len(email) > USER_EMAIL_MAX_LENGTH || email == "" || !IsValidEmail(email) { return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.email.app_error", nil, "email="+email, http.StatusBadRequest) } } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go index 78f1e4e8..f8fffe20 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go @@ -182,9 +182,8 @@ func decodeIncomingWebhookRequest(by []byte) (*IncomingWebhookRequest, error) { err := decoder.Decode(&o) if err == nil { return &o, nil - } else { - return nil, err } + return nil, err } func IncomingWebhookRequestFromJson(data io.Reader) (*IncomingWebhookRequest, *AppError) { @@ -211,7 +210,6 @@ func (o *IncomingWebhookRequest) ToJson() string { b, err := json.Marshal(o) if err != nil { return "" - } else { - return string(b) } + return string(b) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go b/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go index 9368f371..c533faa5 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go @@ -18,13 +18,13 @@ type InitialLoad struct { NoAccounts bool `json:"no_accounts"` } -func (me *InitialLoad) ToJson() string { - b, _ := json.Marshal(me) +func (il *InitialLoad) ToJson() string { + b, _ := json.Marshal(il) return string(b) } func InitialLoadFromJson(data io.Reader) *InitialLoad { - var o *InitialLoad - json.NewDecoder(data).Decode(&o) - return o + var il *InitialLoad + json.NewDecoder(data).Decode(&il) + return il } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go b/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go index a572c9de..7124a7e3 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go @@ -394,7 +394,7 @@ func (o *Post) StripActionIntegrations() { func (o *Post) GetAction(id string) *PostAction { for _, attachment := range o.Attachments() { for _, action := range attachment.Actions { - if action.Id == id { + if action != nil && action.Id == id { return action } } @@ -409,7 +409,7 @@ func (o *Post) GenerateActionIds() { if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok { for _, attachment := range attachments { for _, action := range attachment.Actions { - if action.Id == "" { + if action != nil && action.Id == "" { action.Id = NewId() } } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/job.go b/vendor/github.com/mattermost/mattermost-server/v5/model/job.go index 072bfb2b..78d5a4ff 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/job.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/job.go @@ -22,7 +22,12 @@ const ( JOB_TYPE_EXPIRY_NOTIFY = "expiry_notify" JOB_TYPE_PRODUCT_NOTICES = "product_notices" JOB_TYPE_ACTIVE_USERS = "active_users" + JOB_TYPE_IMPORT_PROCESS = "import_process" + JOB_TYPE_IMPORT_DELETE = "import_delete" + JOB_TYPE_EXPORT_PROCESS = "export_process" + JOB_TYPE_EXPORT_DELETE = "export_delete" JOB_TYPE_CLOUD = "cloud" + JOB_TYPE_RESEND_INVITATION_EMAIL = "resend_invitation_email" JOB_STATUS_PENDING = "pending" JOB_STATUS_IN_PROGRESS = "in_progress" @@ -33,6 +38,25 @@ const ( JOB_STATUS_WARNING = "warning" ) +var ALL_JOB_TYPES = [...]string{ + JOB_TYPE_DATA_RETENTION, + JOB_TYPE_MESSAGE_EXPORT, + JOB_TYPE_ELASTICSEARCH_POST_INDEXING, + JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION, + JOB_TYPE_BLEVE_POST_INDEXING, + JOB_TYPE_LDAP_SYNC, + JOB_TYPE_MIGRATIONS, + JOB_TYPE_PLUGINS, + JOB_TYPE_EXPIRY_NOTIFY, + JOB_TYPE_PRODUCT_NOTICES, + JOB_TYPE_ACTIVE_USERS, + JOB_TYPE_IMPORT_PROCESS, + JOB_TYPE_IMPORT_DELETE, + JOB_TYPE_EXPORT_PROCESS, + JOB_TYPE_EXPORT_DELETE, + JOB_TYPE_CLOUD, +} + type Job struct { Id string `json:"id"` Type string `json:"type"` @@ -66,7 +90,12 @@ func (j *Job) IsValid() *AppError { case JOB_TYPE_PRODUCT_NOTICES: case JOB_TYPE_EXPIRY_NOTIFY: case JOB_TYPE_ACTIVE_USERS: + case JOB_TYPE_IMPORT_PROCESS: + case JOB_TYPE_IMPORT_DELETE: + case JOB_TYPE_EXPORT_PROCESS: + case JOB_TYPE_EXPORT_DELETE: case JOB_TYPE_CLOUD: + case JOB_TYPE_RESEND_INVITATION_EMAIL: default: return NewAppError("Job.IsValid", "model.job.is_valid.type.app_error", nil, "id="+j.Id, http.StatusBadRequest) } @@ -94,9 +123,8 @@ func JobFromJson(data io.Reader) *Job { var job Job if err := json.NewDecoder(data).Decode(&job); err == nil { return &job - } else { - return nil } + return nil } func JobsToJson(jobs []*Job) string { @@ -108,9 +136,8 @@ func JobsFromJson(data io.Reader) []*Job { var jobs []*Job if err := json.NewDecoder(data).Decode(&jobs); err == nil { return jobs - } else { - return nil } + return nil } func (j *Job) DataToJson() string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/license.go b/vendor/github.com/mattermost/mattermost-server/v5/model/license.go index 3de4aba8..ab9e481a 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/license.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/license.go @@ -5,8 +5,10 @@ package model import ( "encoding/json" + "fmt" "io" "net/http" + "time" ) const ( @@ -16,6 +18,22 @@ const ( LICENSE_RENEWAL_LINK = "https://mattermost.com/renew/" ) +const ( + SIXTY_DAYS = 60 + FIFTY_EIGHT = 58 + LICENSE_UP_FOR_RENEWAL_EMAIL_SENT = "LicenseUpForRenewalEmailSent" +) + +var ( + trialDuration = 30*(time.Hour*24) + (time.Hour * 8) // 720 hours (30 days) + 8 hours is trial license duration + adminTrialDuration = 30*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 720 hours (30 days) + 23 hours, 59 mins and 59 seconds + + // a sanctioned trial's duration is either more than the upper bound, + // or less than the lower bound + sanctionedTrialDurationLowerBound = 31*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 744 hours (31 days) + 23 hours, 59 mins and 59 seconds + sanctionedTrialDurationUpperBound = 29*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 696 hours (29 days) + 23 hours, 59 mins and 59 seconds +) + type LicenseRecord struct { Id string `json:"id"` CreateAt int64 `json:"create_at"` @@ -31,6 +49,7 @@ type License struct { Features *Features `json:"features"` SkuName string `json:"sku_name"` SkuShortName string `json:"sku_short_name"` + IsTrial bool `json:"is_trial"` } type Customer struct { @@ -63,6 +82,7 @@ type Features struct { MFA *bool `json:"mfa"` GoogleOAuth *bool `json:"google_oauth"` Office365OAuth *bool `json:"office365_oauth"` + OpenId *bool `json:"openid"` Compliance *bool `json:"compliance"` Cluster *bool `json:"cluster"` Metrics *bool `json:"metrics"` @@ -83,6 +103,8 @@ type Features struct { EnterprisePlugins *bool `json:"enterprise_plugins"` AdvancedLogging *bool `json:"advanced_logging"` Cloud *bool `json:"cloud"` + SharedChannels *bool `json:"shared_channels"` + RemoteClusterService *bool `json:"remote_cluster_service"` // after we enabled more features we'll need to control them with this FutureFeatures *bool `json:"future_features"` @@ -95,6 +117,7 @@ func (f *Features) ToMap() map[string]interface{} { "mfa": *f.MFA, "google": *f.GoogleOAuth, "office365": *f.Office365OAuth, + "openid": *f.OpenId, "compliance": *f.Compliance, "cluster": *f.Cluster, "metrics": *f.Metrics, @@ -112,6 +135,8 @@ func (f *Features) ToMap() map[string]interface{} { "enterprise_plugins": *f.EnterprisePlugins, "advanced_logging": *f.AdvancedLogging, "cloud": *f.Cloud, + "shared_channels": *f.SharedChannels, + "remote_cluster_service": *f.RemoteClusterService, "future": *f.FutureFeatures, } } @@ -145,6 +170,10 @@ func (f *Features) SetDefaults() { f.Office365OAuth = NewBool(*f.FutureFeatures) } + if f.OpenId == nil { + f.OpenId = NewBool(*f.FutureFeatures) + } + if f.Compliance == nil { f.Compliance = NewBool(*f.FutureFeatures) } @@ -224,6 +253,14 @@ func (f *Features) SetDefaults() { if f.Cloud == nil { f.Cloud = NewBool(false) } + + if f.SharedChannels == nil { + f.SharedChannels = NewBool(*f.FutureFeatures) + } + + if f.RemoteClusterService == nil { + f.RemoteClusterService = NewBool(*f.FutureFeatures) + } } func (l *License) IsExpired() bool { @@ -235,6 +272,18 @@ func (l *License) IsPastGracePeriod() bool { return timeDiff > LICENSE_GRACE_PERIOD } +func (l *License) IsWithinExpirationPeriod() bool { + days := l.DaysToExpiration() + return days <= SIXTY_DAYS && days >= FIFTY_EIGHT +} + +func (l *License) DaysToExpiration() int { + dif := l.ExpiresAt - GetMillis() + d, _ := time.ParseDuration(fmt.Sprint(dif) + "ms") + days := d.Hours() / 24 + return int(days) +} + func (l *License) IsStarted() bool { return l.StartsAt < GetMillis() } @@ -244,6 +293,17 @@ func (l *License) ToJson() string { return string(b) } +func (l *License) IsTrialLicense() bool { + return l.IsTrial || (l.ExpiresAt-l.StartsAt) == trialDuration.Milliseconds() || (l.ExpiresAt-l.StartsAt) == adminTrialDuration.Milliseconds() +} + +func (l *License) IsSanctionedTrial() bool { + duration := l.ExpiresAt - l.StartsAt + + return l.IsTrialLicense() && + (duration >= sanctionedTrialDurationLowerBound.Milliseconds() || duration <= sanctionedTrialDurationUpperBound.Milliseconds()) +} + // NewTestLicense returns a license that expires in the future and has the given features. func NewTestLicense(features ...string) *License { ret := &License{ @@ -278,7 +338,7 @@ func (lr *LicenseRecord) IsValid() *AppError { return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) } - if len(lr.Bytes) == 0 || len(lr.Bytes) > 10000 { + if lr.Bytes == "" || len(lr.Bytes) > 10000 { return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go b/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go index 7c09830a..3fba0890 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go @@ -147,7 +147,7 @@ type Manifest struct { Id string `json:"id" yaml:"id"` // The name to be displayed for the plugin. - Name string `json:"name,omitempty" yaml:"name,omitempty"` + Name string `json:"name" yaml:"name"` // A description of what your plugin is and does. Description string `json:"description,omitempty" yaml:"description,omitempty"` @@ -196,9 +196,21 @@ type Manifest struct { } type ManifestServer struct { - // Executables are the paths to your executable binaries, specifying multiple entry points - // for different platforms when bundled together in a single plugin. - Executables *ManifestExecutables `json:"executables,omitempty" yaml:"executables,omitempty"` + // AllExecutables are the paths to your executable binaries, specifying multiple entry + // points for different platforms when bundled together in a single plugin. + AllExecutables map[string]string `json:"executables,omitempty" yaml:"executables,omitempty"` + + // Executables is a legacy field populated with a subset of supported platform executables. + // When unmarshalling, Executables is authoritative for the platform executable paths it + // contains, overriding any values in AllExecutables. When marshalling, AllExecutables + // is authoritative. + // + // Code duplication is avoided when (un)marshalling by leveraging type aliases in the + // various (Un)Marshal(JSON|YAML) methods, since aliases don't inherit the aliased type's + // methods. + // + // In v6.0, we should remove this field and rename AllExecutables back to Executables. + Executables *ManifestExecutables `json:"-" yaml:"-"` // Executable is the path to your executable binary. This should be relative to the root // of your bundle and the location of the manifest file. @@ -210,6 +222,79 @@ type ManifestServer struct { Executable string `json:"executable" yaml:"executable"` } +func (ms *ManifestServer) MarshalJSON() ([]byte, error) { + type auxManifestServer ManifestServer + + // Populate AllExecutables from Executables, if it exists. + if ms.Executables != nil { + if ms.AllExecutables == nil { + ms.AllExecutables = make(map[string]string) + } + + ms.AllExecutables["linux-amd64"] = ms.Executables.LinuxAmd64 + ms.AllExecutables["darwin-amd64"] = ms.Executables.DarwinAmd64 + ms.AllExecutables["windows-amd64"] = ms.Executables.WindowsAmd64 + } + + return json.Marshal((*auxManifestServer)(ms)) +} + +func (ms *ManifestServer) UnmarshalJSON(data []byte) error { + type auxManifestServer ManifestServer + + aux := (*auxManifestServer)(ms) + if err := json.Unmarshal(data, aux); err != nil { + return err + } + + if len(aux.AllExecutables) > 0 { + ms.Executables = &ManifestExecutables{ + LinuxAmd64: aux.AllExecutables["linux-amd64"], + DarwinAmd64: aux.AllExecutables["darwin-amd64"], + WindowsAmd64: aux.AllExecutables["windows-amd64"], + } + } + + return nil +} + +func (ms *ManifestServer) MarshalYAML() ([]byte, error) { + type auxManifestServer ManifestServer + + // Populate AllExecutables from Executables, if it exists. + if ms.Executables != nil { + if ms.AllExecutables == nil { + ms.AllExecutables = make(map[string]string) + } + + ms.AllExecutables["linux-amd64"] = ms.Executables.LinuxAmd64 + ms.AllExecutables["darwin-amd64"] = ms.Executables.DarwinAmd64 + ms.AllExecutables["windows-amd64"] = ms.Executables.WindowsAmd64 + } + + return yaml.Marshal((*auxManifestServer)(ms)) +} + +func (ms *ManifestServer) UnmarshalYAML(unmarshal func(interface{}) error) error { + type auxManifestServer ManifestServer + + aux := (*auxManifestServer)(ms) + if err := unmarshal(&aux); err != nil { + return err + } + + if len(aux.AllExecutables) > 0 { + ms.Executables = &ManifestExecutables{ + LinuxAmd64: aux.AllExecutables["linux-amd64"], + DarwinAmd64: aux.AllExecutables["darwin-amd64"], + WindowsAmd64: aux.AllExecutables["windows-amd64"], + } + } + + return nil +} + +// ManifestExecutables is a legacy structure capturing a subet of the known platform executables. type ManifestExecutables struct { // LinuxAmd64 is the path to your executable binary for the corresponding platform LinuxAmd64 string `json:"linux-amd64,omitempty" yaml:"linux-amd64,omitempty"` @@ -287,14 +372,9 @@ func (m *Manifest) GetExecutableForRuntime(goOs, goArch string) string { } var executable string - if server.Executables != nil { - if goOs == "linux" && goArch == "amd64" { - executable = server.Executables.LinuxAmd64 - } else if goOs == "darwin" && goArch == "amd64" { - executable = server.Executables.DarwinAmd64 - } else if goOs == "windows" && goArch == "amd64" { - executable = server.Executables.WindowsAmd64 - } + if len(server.AllExecutables) > 0 { + osArch := fmt.Sprintf("%s-%s", goOs, goArch) + executable = server.AllExecutables[osArch] } if executable == "" { @@ -329,6 +409,10 @@ func (m *Manifest) IsValid() error { return errors.New("invalid plugin ID") } + if strings.TrimSpace(m.Name) == "" { + return errors.New("a plugin name is needed") + } + if m.HomepageURL != "" && !IsValidHttpUrl(m.HomepageURL) { return errors.New("invalid HomepageURL") } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go index cccfb7f6..cad93dfb 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go @@ -20,8 +20,12 @@ type BaseMarketplacePlugin struct { IconData string `json:"icon_data"` DownloadURL string `json:"download_url"` ReleaseNotesURL string `json:"release_notes_url"` - Labels []MarketplaceLabel `json:"labels"` - Signature string `json:"signature"` // Signature represents a signature of a plugin saved in base64 encoding. + Labels []MarketplaceLabel `json:"labels,omitempty"` + Hosting string `json:"hosting"` // Indicated if the plugin is limited to a certain hosting type + AuthorType string `json:"author_type"` // The maintainer of the plugin + ReleaseStage string `json:"release_stage"` // The stage in the software release cycle that the plugin is in + Enterprise bool `json:"enterprise"` // Indicated if the plugin is an enterprise plugin + Signature string `json:"signature"` // Signature represents a signature of a plugin saved in base64 encoding. Manifest *Manifest `json:"manifest"` } @@ -83,6 +87,8 @@ type MarketplacePluginFilter struct { Cloud bool LocalOnly bool Platform string + PluginId string + ReturnAllVersions bool } // ApplyToURL modifies the given url to include query string parameters for the request. @@ -99,6 +105,8 @@ func (filter *MarketplacePluginFilter) ApplyToURL(u *url.URL) { q.Add("cloud", strconv.FormatBool(filter.Cloud)) q.Add("local_only", strconv.FormatBool(filter.LocalOnly)) q.Add("platform", filter.Platform) + q.Add("plugin_id", filter.PluginId) + q.Add("return_all_versions", strconv.FormatBool(filter.ReturnAllVersions)) u.RawQuery = q.Encode() } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go b/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go index 88108e2e..f94d861f 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go @@ -29,3 +29,8 @@ type MessageExport struct { PostOriginalId *string PostFileIds StringArray } + +type MessageExportCursor struct { + LastPostUpdateAt int64 + LastPostId string +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go b/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go index 979ff342..b2293566 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go @@ -13,13 +13,13 @@ type MfaSecret struct { QRCode string `json:"qr_code"` } -func (me *MfaSecret) ToJson() string { - b, _ := json.Marshal(me) +func (mfa *MfaSecret) ToJson() string { + b, _ := json.Marshal(mfa) return string(b) } func MfaSecretFromJson(data io.Reader) *MfaSecret { - var me *MfaSecret - json.NewDecoder(data).Decode(&me) - return me + var mfa *MfaSecret + json.NewDecoder(data).Decode(&mfa) + return mfa } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go b/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go index f552d168..019ca7b5 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go @@ -22,5 +22,17 @@ const ( MIGRATION_KEY_SIDEBAR_CATEGORIES_PHASE_2 = "migration_sidebar_categories_phase_2" MIGRATION_KEY_ADD_CONVERT_CHANNEL_PERMISSIONS = "add_convert_channel_permissions" MIGRATION_KEY_ADD_SYSTEM_ROLES_PERMISSIONS = "add_system_roles_permissions" + MIGRATION_KEY_ADD_BILLING_PERMISSIONS = "add_billing_permissions" MIGRATION_KEY_ADD_MANAGE_SHARED_CHANNEL_PERMISSIONS = "manage_shared_channel_permissions" + MIGRATION_KEY_ADD_MANAGE_SECURE_CONNECTIONS_PERMISSIONS = "manage_secure_connections_permissions" + MIGRATION_KEY_ADD_DOWNLOAD_COMPLIANCE_EXPORT_RESULTS = "download_compliance_export_results" + MIGRATION_KEY_ADD_COMPLIANCE_SUBSECTION_PERMISSIONS = "compliance_subsection_permissions" + MIGRATION_KEY_ADD_EXPERIMENTAL_SUBSECTION_PERMISSIONS = "experimental_subsection_permissions" + MIGRATION_KEY_ADD_AUTHENTICATION_SUBSECTION_PERMISSIONS = "authentication_subsection_permissions" + MIGRATION_KEY_ADD_SITE_SUBSECTION_PERMISSIONS = "site_subsection_permissions" + MIGRATION_KEY_ADD_ENVIRONMENT_SUBSECTION_PERMISSIONS = "environment_subsection_permissions" + MIGRATION_KEY_ADD_REPORTING_SUBSECTION_PERMISSIONS = "reporting_subsection_permissions" + MIGRATION_KEY_ADD_TEST_EMAIL_ANCILLARY_PERMISSION = "test_email_ancillary_permission" + MIGRATION_KEY_ADD_ABOUT_SUBSECTION_PERMISSIONS = "about_subsection_permissions" + MIGRATION_KEY_ADD_INTEGRATIONS_SUBSECTION_PERMISSIONS = "integrations_subsection_permissions" ) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go b/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go index 4a345a6e..07198116 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go @@ -53,11 +53,11 @@ func (a *OAuthApp) IsValid() *AppError { return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.creator_id.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) } - if len(a.ClientSecret) == 0 || len(a.ClientSecret) > 128 { + if a.ClientSecret == "" || len(a.ClientSecret) > 128 { return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.client_secret.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) } - if len(a.Name) == 0 || len(a.Name) > 64 { + if a.Name == "" || len(a.Name) > 64 { return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.name.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) } @@ -71,7 +71,7 @@ func (a *OAuthApp) IsValid() *AppError { } } - if len(a.Homepage) == 0 || len(a.Homepage) > 256 || !IsValidHttpUrl(a.Homepage) { + if a.Homepage == "" || len(a.Homepage) > 256 || !IsValidHttpUrl(a.Homepage) { return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) } @@ -79,7 +79,7 @@ func (a *OAuthApp) IsValid() *AppError { return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) } - if len(a.IconURL) > 0 { + if a.IconURL != "" { if len(a.IconURL) > 512 || !IsValidHttpUrl(a.IconURL) { return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go index d6cb2138..0d7a88fb 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go @@ -140,7 +140,7 @@ func (o *OutgoingWebhook) IsValid() *AppError { return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) } - if len(o.ChannelId) != 0 && !IsValidId(o.ChannelId) { + if o.ChannelId != "" && !IsValidId(o.ChannelId) { return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest) } @@ -154,7 +154,7 @@ func (o *OutgoingWebhook) IsValid() *AppError { if len(o.TriggerWords) != 0 { for _, triggerWord := range o.TriggerWords { - if len(triggerWord) == 0 { + if triggerWord == "" { return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.trigger_words.app_error", nil, "", http.StatusBadRequest) } } @@ -215,7 +215,7 @@ func (o *OutgoingWebhook) PreUpdate() { } func (o *OutgoingWebhook) TriggerWordExactMatch(word string) bool { - if len(word) == 0 { + if word == "" { return false } @@ -229,7 +229,7 @@ func (o *OutgoingWebhook) TriggerWordExactMatch(word string) bool { } func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool { - if len(word) == 0 { + if word == "" { return false } @@ -243,7 +243,7 @@ func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool { } func (o *OutgoingWebhook) GetTriggerWord(word string, isExactMatch bool) (triggerWord string) { - if len(word) == 0 { + if word == "" { return } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go b/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go index d982962f..bc4de236 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go @@ -100,13 +100,69 @@ var PERMISSION_USE_GROUP_MENTIONS *Permission var PERMISSION_READ_OTHER_USERS_TEAMS *Permission var PERMISSION_EDIT_BRAND *Permission var PERMISSION_MANAGE_SHARED_CHANNELS *Permission +var PERMISSION_MANAGE_SECURE_CONNECTIONS *Permission +var PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT *Permission +var PERMISSION_CREATE_DATA_RETENTION_JOB *Permission +var PERMISSION_READ_DATA_RETENTION_JOB *Permission +var PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB *Permission +var PERMISSION_READ_COMPLIANCE_EXPORT_JOB *Permission +var PERMISSION_READ_AUDITS *Permission +var PERMISSION_TEST_ELASTICSEARCH *Permission +var PERMISSION_TEST_SITE_URL *Permission +var PERMISSION_TEST_S3 *Permission +var PERMISSION_RELOAD_CONFIG *Permission +var PERMISSION_INVALIDATE_CACHES *Permission +var PERMISSION_RECYCLE_DATABASE_CONNECTIONS *Permission +var PERMISSION_PURGE_ELASTICSEARCH_INDEXES *Permission +var PERMISSION_TEST_EMAIL *Permission +var PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB *Permission +var PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB *Permission +var PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB *Permission +var PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB *Permission +var PERMISSION_PURGE_BLEVE_INDEXES *Permission +var PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB *Permission +var PERMISSION_CREATE_LDAP_SYNC_JOB *Permission +var PERMISSION_READ_LDAP_SYNC_JOB *Permission +var PERMISSION_TEST_LDAP *Permission +var PERMISSION_INVALIDATE_EMAIL_INVITE *Permission +var PERMISSION_GET_SAML_METADATA_FROM_IDP *Permission +var PERMISSION_ADD_SAML_PUBLIC_CERT *Permission +var PERMISSION_ADD_SAML_PRIVATE_CERT *Permission +var PERMISSION_ADD_SAML_IDP_CERT *Permission +var PERMISSION_REMOVE_SAML_PUBLIC_CERT *Permission +var PERMISSION_REMOVE_SAML_PRIVATE_CERT *Permission +var PERMISSION_REMOVE_SAML_IDP_CERT *Permission +var PERMISSION_GET_SAML_CERT_STATUS *Permission +var PERMISSION_ADD_LDAP_PUBLIC_CERT *Permission +var PERMISSION_ADD_LDAP_PRIVATE_CERT *Permission +var PERMISSION_REMOVE_LDAP_PUBLIC_CERT *Permission +var PERMISSION_REMOVE_LDAP_PRIVATE_CERT *Permission +var PERMISSION_GET_LOGS *Permission +var PERMISSION_GET_ANALYTICS *Permission +var PERMISSION_READ_LICENSE_INFORMATION *Permission +var PERMISSION_MANAGE_LICENSE_INFORMATION *Permission var PERMISSION_SYSCONSOLE_READ_ABOUT *Permission var PERMISSION_SYSCONSOLE_WRITE_ABOUT *Permission +var PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE *Permission +var PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE *Permission + +var PERMISSION_SYSCONSOLE_READ_BILLING *Permission +var PERMISSION_SYSCONSOLE_WRITE_BILLING *Permission + var PERMISSION_SYSCONSOLE_READ_REPORTING *Permission var PERMISSION_SYSCONSOLE_WRITE_REPORTING *Permission +var PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS *Permission +var PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS *Permission + +var PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS *Permission +var PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS *Permission + +var PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS *Permission +var PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS *Permission + var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS *Permission var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS *Permission @@ -125,27 +181,156 @@ var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS *Permission var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_SYSTEM_ROLES *Permission var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_SYSTEM_ROLES *Permission +// DEPRECATED var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT *Permission + +// DEPRECATED var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT *Permission +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING *Permission + +var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER *Permission +var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER *Permission + var PERMISSION_SYSCONSOLE_READ_SITE *Permission var PERMISSION_SYSCONSOLE_WRITE_SITE *Permission +var PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_EMOJI *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_POSTS *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS *Permission + +var PERMISSION_SYSCONSOLE_READ_SITE_NOTICES *Permission +var PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES *Permission + var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION *Permission var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION *Permission +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_MFA *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_OPENID *Permission + +var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS *Permission +var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_GUEST_ACCESS *Permission + var PERMISSION_SYSCONSOLE_READ_PLUGINS *Permission var PERMISSION_SYSCONSOLE_WRITE_PLUGINS *Permission var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS *Permission var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS *Permission +var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT *Permission +var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT *Permission + +var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS *Permission +var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS *Permission + +var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF *Permission +var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF *Permission + +var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS *Permission +var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS *Permission + var PERMISSION_SYSCONSOLE_READ_COMPLIANCE *Permission var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE *Permission +var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY *Permission +var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY *Permission + +var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT *Permission +var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT *Permission + +var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING *Permission +var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_MONITORING *Permission + +var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE *Permission +var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE *Permission + var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL *Permission var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL *Permission +var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES *Permission +var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURES *Permission + +var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS *Permission +var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURE_FLAGS *Permission + +var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE *Permission +var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE *Permission + // General permission that encompasses all system admin functions // in the future this could be broken up to allow access to some // admin functions but not others @@ -526,6 +711,277 @@ func initializePermissions() { "authentication.permissions.manage_shared_channels.description", PermissionScopeSystem, } + PERMISSION_MANAGE_SECURE_CONNECTIONS = &Permission{ + "manage_secure_connections", + "authentication.permissions.manage_secure_connections.name", + "authentication.permissions.manage_secure_connections.description", + PermissionScopeSystem, + } + + PERMISSION_CREATE_DATA_RETENTION_JOB = &Permission{ + "create_data_retention_job", + "", + "", + PermissionScopeSystem, + } + PERMISSION_READ_DATA_RETENTION_JOB = &Permission{ + "read_data_retention_job", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB = &Permission{ + "create_compliance_export_job", + "", + "", + PermissionScopeSystem, + } + PERMISSION_READ_COMPLIANCE_EXPORT_JOB = &Permission{ + "read_compliance_export_job", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_READ_AUDITS = &Permission{ + "read_audits", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_PURGE_BLEVE_INDEXES = &Permission{ + "purge_bleve_indexes", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB = &Permission{ + "create_post_bleve_indexes_job", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_CREATE_LDAP_SYNC_JOB = &Permission{ + "create_ldap_sync_job", + "", + "", + PermissionScopeSystem, + } + PERMISSION_READ_LDAP_SYNC_JOB = &Permission{ + "read_ldap_sync_job", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_TEST_LDAP = &Permission{ + "test_ldap", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_INVALIDATE_EMAIL_INVITE = &Permission{ + "invalidate_email_invite", + "", + "", + PermissionScopeSystem, + } + PERMISSION_GET_SAML_METADATA_FROM_IDP = &Permission{ + "get_saml_metadata_from_idp", + "", + "", + PermissionScopeSystem, + } + PERMISSION_ADD_SAML_PUBLIC_CERT = &Permission{ + "add_saml_public_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_ADD_SAML_PRIVATE_CERT = &Permission{ + "add_saml_private_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_ADD_SAML_IDP_CERT = &Permission{ + "add_saml_idp_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_REMOVE_SAML_PUBLIC_CERT = &Permission{ + "remove_saml_public_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_REMOVE_SAML_PRIVATE_CERT = &Permission{ + "remove_saml_private_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_REMOVE_SAML_IDP_CERT = &Permission{ + "remove_saml_idp_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_GET_SAML_CERT_STATUS = &Permission{ + "get_saml_cert_status", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_ADD_LDAP_PUBLIC_CERT = &Permission{ + "add_ldap_public_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_ADD_LDAP_PRIVATE_CERT = &Permission{ + "add_ldap_private_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_REMOVE_LDAP_PUBLIC_CERT = &Permission{ + "remove_ldap_public_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_REMOVE_LDAP_PRIVATE_CERT = &Permission{ + "remove_ldap_private_cert", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_GET_LOGS = &Permission{ + "get_logs", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_READ_LICENSE_INFORMATION = &Permission{ + "read_license_information", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_GET_ANALYTICS = &Permission{ + "get_analytics", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_MANAGE_LICENSE_INFORMATION = &Permission{ + "manage_license_information", + "", + "", + PermissionScopeSystem, + } + + PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT = &Permission{ + "download_compliance_export_result", + "authentication.permissions.download_compliance_export_result.name", + "authentication.permissions.download_compliance_export_result.description", + PermissionScopeSystem, + } + + PERMISSION_TEST_SITE_URL = &Permission{ + "test_site_url", + "", + "", + PermissionScopeSystem, + } + PERMISSION_TEST_ELASTICSEARCH = &Permission{ + "test_elasticsearch", + "", + "", + PermissionScopeSystem, + } + PERMISSION_TEST_S3 = &Permission{ + "test_s3", + "", + "", + PermissionScopeSystem, + } + PERMISSION_RELOAD_CONFIG = &Permission{ + "reload_config", + "", + "", + PermissionScopeSystem, + } + PERMISSION_INVALIDATE_CACHES = &Permission{ + "invalidate_caches", + "", + "", + PermissionScopeSystem, + } + PERMISSION_RECYCLE_DATABASE_CONNECTIONS = &Permission{ + "recycle_database_connections", + "", + "", + PermissionScopeSystem, + } + PERMISSION_PURGE_ELASTICSEARCH_INDEXES = &Permission{ + "purge_elasticsearch_indexes", + "", + "", + PermissionScopeSystem, + } + PERMISSION_TEST_EMAIL = &Permission{ + "test_email", + "", + "", + PermissionScopeSystem, + } + PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB = &Permission{ + "create_elasticsearch_post_indexing_job", + "", + "", + PermissionScopeSystem, + } + PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB = &Permission{ + "create_elasticsearch_post_aggregation_job", + "", + "", + PermissionScopeSystem, + } + PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB = &Permission{ + "read_elasticsearch_post_indexing_job", + "", + "", + PermissionScopeSystem, + } + PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB = &Permission{ + "read_elasticsearch_post_aggregation_job", + "", + "", + PermissionScopeSystem, + } + PERMISSION_REMOVE_USER_FROM_TEAM = &Permission{ "remove_user_from_team", "authentication.permissions.remove_user_from_team.name", @@ -676,30 +1132,94 @@ func initializePermissions() { "authentication.permissions.edit_brand.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_READ_ABOUT = &Permission{ "sysconsole_read_about", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_WRITE_ABOUT = &Permission{ "sysconsole_write_about", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE = &Permission{ + "sysconsole_read_about_edition_and_license", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE = &Permission{ + "sysconsole_write_about_edition_and_license", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_BILLING = &Permission{ + "sysconsole_read_billing", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_BILLING = &Permission{ + "sysconsole_write_billing", + "", + "", + PermissionScopeSystem, + } + // DEPRECATED PERMISSION_SYSCONSOLE_READ_REPORTING = &Permission{ "sysconsole_read_reporting", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_WRITE_REPORTING = &Permission{ "sysconsole_write_reporting", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS = &Permission{ + "sysconsole_read_reporting_site_statistics", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS = &Permission{ + "sysconsole_write_reporting_site_statistics", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS = &Permission{ + "sysconsole_read_reporting_team_statistics", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS = &Permission{ + "sysconsole_write_reporting_team_statistics", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS = &Permission{ + "sysconsole_read_reporting_server_logs", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS = &Permission{ + "sysconsole_write_reporting_server_logs", + "", + "", + PermissionScopeSystem, + } PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS = &Permission{ "sysconsole_read_user_management_users", "authentication.permissions.use_group_mentions.name", @@ -772,42 +1292,422 @@ func initializePermissions() { "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_READ_ENVIRONMENT = &Permission{ "sysconsole_read_environment", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT = &Permission{ "sysconsole_write_environment", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER = &Permission{ + "sysconsole_read_environment_web_server", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER = &Permission{ + "sysconsole_write_environment_web_server", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE = &Permission{ + "sysconsole_read_environment_database", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE = &Permission{ + "sysconsole_write_environment_database", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH = &Permission{ + "sysconsole_read_environment_elasticsearch", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH = &Permission{ + "sysconsole_write_environment_elasticsearch", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE = &Permission{ + "sysconsole_read_environment_file_storage", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE = &Permission{ + "sysconsole_write_environment_file_storage", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY = &Permission{ + "sysconsole_read_environment_image_proxy", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY = &Permission{ + "sysconsole_write_environment_image_proxy", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP = &Permission{ + "sysconsole_read_environment_smtp", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP = &Permission{ + "sysconsole_write_environment_smtp", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER = &Permission{ + "sysconsole_read_environment_push_notification_server", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER = &Permission{ + "sysconsole_write_environment_push_notification_server", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY = &Permission{ + "sysconsole_read_environment_high_availability", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY = &Permission{ + "sysconsole_write_environment_high_availability", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING = &Permission{ + "sysconsole_read_environment_rate_limiting", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING = &Permission{ + "sysconsole_write_environment_rate_limiting", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING = &Permission{ + "sysconsole_read_environment_logging", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING = &Permission{ + "sysconsole_write_environment_logging", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS = &Permission{ + "sysconsole_read_environment_session_lengths", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS = &Permission{ + "sysconsole_write_environment_session_lengths", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING = &Permission{ + "sysconsole_read_environment_performance_monitoring", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING = &Permission{ + "sysconsole_write_environment_performance_monitoring", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER = &Permission{ + "sysconsole_read_environment_developer", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER = &Permission{ + "sysconsole_write_environment_developer", + "", + "", + PermissionScopeSystem, + } + // DEPRECATED PERMISSION_SYSCONSOLE_READ_SITE = &Permission{ "sysconsole_read_site", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_WRITE_SITE = &Permission{ "sysconsole_write_site", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + + PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION = &Permission{ + "sysconsole_read_site_customization", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION = &Permission{ + "sysconsole_write_site_customization", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION = &Permission{ + "sysconsole_read_site_localization", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION = &Permission{ + "sysconsole_write_site_localization", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS = &Permission{ + "sysconsole_read_site_users_and_teams", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS = &Permission{ + "sysconsole_write_site_users_and_teams", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS = &Permission{ + "sysconsole_read_site_notifications", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS = &Permission{ + "sysconsole_write_site_notifications", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER = &Permission{ + "sysconsole_read_site_announcement_banner", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER = &Permission{ + "sysconsole_write_site_announcement_banner", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_EMOJI = &Permission{ + "sysconsole_read_site_emoji", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI = &Permission{ + "sysconsole_write_site_emoji", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_POSTS = &Permission{ + "sysconsole_read_site_posts", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS = &Permission{ + "sysconsole_write_site_posts", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS = &Permission{ + "sysconsole_read_site_file_sharing_and_downloads", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS = &Permission{ + "sysconsole_write_site_file_sharing_and_downloads", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS = &Permission{ + "sysconsole_read_site_public_links", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS = &Permission{ + "sysconsole_write_site_public_links", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_SITE_NOTICES = &Permission{ + "sysconsole_read_site_notices", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES = &Permission{ + "sysconsole_write_site_notices", + "", + "", + PermissionScopeSystem, + } + + // Deprecated PERMISSION_SYSCONSOLE_READ_AUTHENTICATION = &Permission{ "sysconsole_read_authentication", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // Deprecated PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION = &Permission{ "sysconsole_write_authentication", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP = &Permission{ + "sysconsole_read_authentication_signup", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP = &Permission{ + "sysconsole_write_authentication_signup", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL = &Permission{ + "sysconsole_read_authentication_email", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL = &Permission{ + "sysconsole_write_authentication_email", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD = &Permission{ + "sysconsole_read_authentication_password", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD = &Permission{ + "sysconsole_write_authentication_password", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA = &Permission{ + "sysconsole_read_authentication_mfa", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_MFA = &Permission{ + "sysconsole_write_authentication_mfa", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP = &Permission{ + "sysconsole_read_authentication_ldap", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP = &Permission{ + "sysconsole_write_authentication_ldap", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML = &Permission{ + "sysconsole_read_authentication_saml", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML = &Permission{ + "sysconsole_write_authentication_saml", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID = &Permission{ + "sysconsole_read_authentication_openid", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_OPENID = &Permission{ + "sysconsole_write_authentication_openid", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS = &Permission{ + "sysconsole_read_authentication_guest_access", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_GUEST_ACCESS = &Permission{ + "sysconsole_write_authentication_guest_access", + "", + "", + PermissionScopeSystem, + } PERMISSION_SYSCONSOLE_READ_PLUGINS = &Permission{ "sysconsole_read_plugins", "authentication.permissions.use_group_mentions.name", @@ -820,89 +1720,293 @@ func initializePermissions() { "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_READ_INTEGRATIONS = &Permission{ "sysconsole_read_integrations", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS = &Permission{ "sysconsole_write_integrations", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT = &Permission{ + "sysconsole_read_integrations_integration_management", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT = &Permission{ + "sysconsole_write_integrations_integration_management", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS = &Permission{ + "sysconsole_read_integrations_bot_accounts", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS = &Permission{ + "sysconsole_write_integrations_bot_accounts", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF = &Permission{ + "sysconsole_read_integrations_gif", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF = &Permission{ + "sysconsole_write_integrations_gif", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS = &Permission{ + "sysconsole_read_integrations_cors", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS = &Permission{ + "sysconsole_write_integrations_cors", + "", + "", + PermissionScopeSystem, + } + // DEPRECATED PERMISSION_SYSCONSOLE_READ_COMPLIANCE = &Permission{ "sysconsole_read_compliance", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE = &Permission{ "sysconsole_write_compliance", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } - PERMISSION_SYSCONSOLE_READ_PLUGINS = &Permission{ - "sysconsole_read_plugins", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY = &Permission{ + "sysconsole_read_compliance_data_retention_policy", + "", + "", PermissionScopeSystem, } - PERMISSION_SYSCONSOLE_WRITE_PLUGINS = &Permission{ - "sysconsole_write_plugins", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY = &Permission{ + "sysconsole_write_compliance_data_retention_policy", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT = &Permission{ + "sysconsole_read_compliance_compliance_export", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT = &Permission{ + "sysconsole_write_compliance_compliance_export", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING = &Permission{ + "sysconsole_read_compliance_compliance_monitoring", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_MONITORING = &Permission{ + "sysconsole_write_compliance_compliance_monitoring", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE = &Permission{ + "sysconsole_read_compliance_custom_terms_of_service", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE = &Permission{ + "sysconsole_write_compliance_custom_terms_of_service", + "", + "", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL = &Permission{ "sysconsole_read_experimental", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + // DEPRECATED PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL = &Permission{ "sysconsole_write_experimental", "authentication.permissions.use_group_mentions.name", "authentication.permissions.use_group_mentions.description", PermissionScopeSystem, } + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES = &Permission{ + "sysconsole_read_experimental_features", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURES = &Permission{ + "sysconsole_write_experimental_features", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS = &Permission{ + "sysconsole_read_experimental_feature_flags", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURE_FLAGS = &Permission{ + "sysconsole_write_experimental_feature_flags", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE = &Permission{ + "sysconsole_read_experimental_bleve", + "", + "", + PermissionScopeSystem, + } + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE = &Permission{ + "sysconsole_write_experimental_bleve", + "", + "", + PermissionScopeSystem, + } SysconsoleReadPermissions = []*Permission{ - PERMISSION_SYSCONSOLE_READ_ABOUT, - PERMISSION_SYSCONSOLE_READ_REPORTING, + PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE, + PERMISSION_SYSCONSOLE_READ_BILLING, + PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS, + PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS, + PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_SYSTEM_ROLES, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT, - PERMISSION_SYSCONSOLE_READ_SITE, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER, + PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION, + PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION, + PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS, + PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS, + PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER, + PERMISSION_SYSCONSOLE_READ_SITE_EMOJI, + PERMISSION_SYSCONSOLE_READ_SITE_POSTS, + PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS, + PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS, + PERMISSION_SYSCONSOLE_READ_SITE_NOTICES, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS, PERMISSION_SYSCONSOLE_READ_PLUGINS, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE, } SysconsoleWritePermissions = []*Permission{ - PERMISSION_SYSCONSOLE_WRITE_ABOUT, - PERMISSION_SYSCONSOLE_WRITE_REPORTING, + PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE, + PERMISSION_SYSCONSOLE_WRITE_BILLING, + PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS, + PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS, + PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_SYSTEM_ROLES, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT, - PERMISSION_SYSCONSOLE_WRITE_SITE, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER, + PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION, + PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION, + PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS, + PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS, + PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER, + PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI, + PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS, + PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS, + PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS, + PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_MFA, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_OPENID, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_GUEST_ACCESS, PERMISSION_SYSCONSOLE_WRITE_PLUGINS, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE, - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_MONITORING, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE, + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURES, + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURE_FLAGS, + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE, } SystemScopedPermissionsMinusSysconsole := []*Permission{ @@ -937,6 +2041,47 @@ func initializePermissions() { PERMISSION_DEMOTE_TO_GUEST, PERMISSION_EDIT_BRAND, PERMISSION_MANAGE_SHARED_CHANNELS, + PERMISSION_MANAGE_SECURE_CONNECTIONS, + PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT, + PERMISSION_CREATE_DATA_RETENTION_JOB, + PERMISSION_READ_DATA_RETENTION_JOB, + PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB, + PERMISSION_READ_COMPLIANCE_EXPORT_JOB, + PERMISSION_READ_AUDITS, + PERMISSION_TEST_SITE_URL, + PERMISSION_TEST_ELASTICSEARCH, + PERMISSION_TEST_S3, + PERMISSION_RELOAD_CONFIG, + PERMISSION_INVALIDATE_CACHES, + PERMISSION_RECYCLE_DATABASE_CONNECTIONS, + PERMISSION_PURGE_ELASTICSEARCH_INDEXES, + PERMISSION_TEST_EMAIL, + PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB, + PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB, + PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB, + PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB, + PERMISSION_PURGE_BLEVE_INDEXES, + PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB, + PERMISSION_CREATE_LDAP_SYNC_JOB, + PERMISSION_READ_LDAP_SYNC_JOB, + PERMISSION_TEST_LDAP, + PERMISSION_INVALIDATE_EMAIL_INVITE, + PERMISSION_GET_SAML_METADATA_FROM_IDP, + PERMISSION_ADD_SAML_PUBLIC_CERT, + PERMISSION_ADD_SAML_PRIVATE_CERT, + PERMISSION_ADD_SAML_IDP_CERT, + PERMISSION_REMOVE_SAML_PUBLIC_CERT, + PERMISSION_REMOVE_SAML_PRIVATE_CERT, + PERMISSION_REMOVE_SAML_IDP_CERT, + PERMISSION_GET_SAML_CERT_STATUS, + PERMISSION_ADD_LDAP_PUBLIC_CERT, + PERMISSION_ADD_LDAP_PRIVATE_CERT, + PERMISSION_REMOVE_LDAP_PUBLIC_CERT, + PERMISSION_REMOVE_LDAP_PRIVATE_CERT, + PERMISSION_GET_ANALYTICS, + PERMISSION_GET_LOGS, + PERMISSION_READ_LICENSE_INFORMATION, + PERMISSION_MANAGE_LICENSE_INFORMATION, } TeamScopedPermissions := []*Permission{ @@ -1000,6 +2145,22 @@ func initializePermissions() { PERMISSION_MANAGE_OTHERS_WEBHOOKS, PERMISSION_MANAGE_EMOJIS, PERMISSION_MANAGE_OTHERS_EMOJIS, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION, + PERMISSION_SYSCONSOLE_READ_SITE, + PERMISSION_SYSCONSOLE_WRITE_SITE, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT, + PERMISSION_SYSCONSOLE_READ_REPORTING, + PERMISSION_SYSCONSOLE_WRITE_REPORTING, + PERMISSION_SYSCONSOLE_READ_ABOUT, + PERMISSION_SYSCONSOLE_WRITE_ABOUT, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL, + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE, } AllPermissions = []*Permission{} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_cluster_event.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_cluster_event.go new file mode 100644 index 00000000..ba5c8052 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_cluster_event.go @@ -0,0 +1,28 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +const ( + PluginClusterEventSendTypeReliable = CLUSTER_SEND_RELIABLE + PluginClusterEventSendTypeBestEffort = CLUSTER_SEND_BEST_EFFORT +) + +// PluginClusterEvent is used to allow intra-cluster plugin communication. +type PluginClusterEvent struct { + // Id is the unique identifier for the event. + Id string + // Data is the event payload. + Data []byte +} + +// PluginClusterEventSendOptions defines some properties that apply when sending +// plugin events across a cluster. +type PluginClusterEventSendOptions struct { + // SendType defines the type of communication channel used to send the event. + SendType string + // TargetId identifies the cluster node to which the event should be sent. + // It should match the cluster id of the receiving instance. + // If empty, the event gets broadcasted to all other nodes. + TargetId string +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go index cd5406ea..73ef2d23 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go @@ -21,11 +21,11 @@ type PluginKeyValue struct { } func (kv *PluginKeyValue) IsValid() *AppError { - if len(kv.PluginId) == 0 || utf8.RuneCountInString(kv.PluginId) > KEY_VALUE_PLUGIN_ID_MAX_RUNES { + if kv.PluginId == "" || utf8.RuneCountInString(kv.PluginId) > KEY_VALUE_PLUGIN_ID_MAX_RUNES { return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.plugin_id.app_error", map[string]interface{}{"Max": KEY_VALUE_KEY_MAX_RUNES, "Min": 0}, "key="+kv.Key, http.StatusBadRequest) } - if len(kv.Key) == 0 || utf8.RuneCountInString(kv.Key) > KEY_VALUE_KEY_MAX_RUNES { + if kv.Key == "" || utf8.RuneCountInString(kv.Key) > KEY_VALUE_KEY_MAX_RUNES { return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.key.app_error", map[string]interface{}{"Max": KEY_VALUE_KEY_MAX_RUNES, "Min": 0}, "key="+kv.Key, http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post.go index 6e29ba3e..b7dff5bc 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post.go @@ -14,7 +14,7 @@ import ( "sync" "unicode/utf8" - "github.com/mattermost/mattermost-server/v5/utils/markdown" + "github.com/mattermost/mattermost-server/v5/shared/markdown" ) const ( @@ -45,7 +45,7 @@ const ( POST_EPHEMERAL = "system_ephemeral" POST_CHANGE_CHANNEL_PRIVACY = "system_change_chan_privacy" POST_ADD_BOT_TEAMS_CHANNELS = "add_bot_teams_channels" - POST_FILEIDS_MAX_RUNES = 150 + POST_FILEIDS_MAX_RUNES = 300 POST_FILENAMES_MAX_RUNES = 4000 POST_HASHTAGS_MAX_RUNES = 1000 POST_MESSAGE_MAX_RUNES_V1 = 4000 @@ -96,10 +96,14 @@ type Post struct { FileIds StringArray `json:"file_ids,omitempty"` PendingPostId string `json:"pending_post_id" db:"-"` HasReactions bool `json:"has_reactions,omitempty"` + RemoteId *string `json:"remote_id,omitempty"` // Transient data populated before sending a post to the client - ReplyCount int64 `json:"reply_count" db:"-"` - Metadata *PostMetadata `json:"metadata,omitempty" db:"-"` + ReplyCount int64 `json:"reply_count" db:"-"` + LastReplyAt int64 `json:"last_reply_at" db:"-"` + Participants []*User `json:"participants" db:"-"` + IsFollowing *bool `json:"is_following,omitempty" db:"-"` // for root posts in collapsed thread mode indicates if the current user is following this thread + Metadata *PostMetadata `json:"metadata,omitempty" db:"-"` } type PostEphemeral struct { @@ -163,6 +167,12 @@ type PostForIndexing struct { ParentCreateAt *int64 `json:"parent_create_at"` } +type FileForIndexing struct { + FileInfo + ChannelId string `json:"channel_id"` + Content string `json:"content"` +} + // ShallowCopy is an utility function to shallow copy a Post to the given // destination without touching the internal RWMutex. func (o *Post) ShallowCopy(dst *Post) error { @@ -194,7 +204,13 @@ func (o *Post) ShallowCopy(dst *Post) error { dst.PendingPostId = o.PendingPostId dst.HasReactions = o.HasReactions dst.ReplyCount = o.ReplyCount + dst.Participants = o.Participants + dst.LastReplyAt = o.LastReplyAt dst.Metadata = o.Metadata + if o.IsFollowing != nil { + dst.IsFollowing = NewBool(*o.IsFollowing) + } + dst.RemoteId = o.RemoteId return nil } @@ -218,17 +234,35 @@ func (o *Post) ToUnsanitizedJson() string { } type GetPostsSinceOptions struct { - ChannelId string - Time int64 - SkipFetchThreads bool + UserId string + ChannelId string + Time int64 + SkipFetchThreads bool + CollapsedThreads bool + CollapsedThreadsExtended bool + SortAscending bool +} + +type GetPostsSinceForSyncCursor struct { + LastPostUpdateAt int64 + LastPostId string +} + +type GetPostsSinceForSyncOptions struct { + ChannelId string + ExcludeRemoteId string + IncludeDeleted bool } type GetPostsOptions struct { - ChannelId string - PostId string - Page int - PerPage int - SkipFetchThreads bool + UserId string + ChannelId string + PostId string + Page int + PerPage int + SkipFetchThreads bool + CollapsedThreads bool + CollapsedThreadsExtended bool } func PostFromJson(data io.Reader) *Post { @@ -262,19 +296,19 @@ func (o *Post) IsValid(maxPostSize int) *AppError { return NewAppError("Post.IsValid", "model.post.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest) } - if !(IsValidId(o.RootId) || len(o.RootId) == 0) { + if !(IsValidId(o.RootId) || o.RootId == "") { return NewAppError("Post.IsValid", "model.post.is_valid.root_id.app_error", nil, "", http.StatusBadRequest) } - if !(IsValidId(o.ParentId) || len(o.ParentId) == 0) { + if !(IsValidId(o.ParentId) || o.ParentId == "") { return NewAppError("Post.IsValid", "model.post.is_valid.parent_id.app_error", nil, "", http.StatusBadRequest) } - if len(o.ParentId) == 26 && len(o.RootId) == 0 { + if len(o.ParentId) == 26 && o.RootId == "" { return NewAppError("Post.IsValid", "model.post.is_valid.root_parent.app_error", nil, "", http.StatusBadRequest) } - if !(len(o.OriginalId) == 26 || len(o.OriginalId) == 0) { + if !(len(o.OriginalId) == 26 || o.OriginalId == "") { return NewAppError("Post.IsValid", "model.post.is_valid.original_id.app_error", nil, "", http.StatusBadRequest) } @@ -337,6 +371,9 @@ func (o *Post) IsValid(maxPostSize int) *AppError { } func (o *Post) SanitizeProps() { + if o == nil { + return + } membersToSanitize := []string{ PROPS_ADD_CHANNEL_MEMBER, } @@ -346,6 +383,9 @@ func (o *Post) SanitizeProps() { o.DelProp(member) } } + for _, p := range o.Participants { + p.Sanitize(map[string]bool{}) + } } func (o *Post) PreSave() { @@ -432,6 +472,19 @@ func (o *Post) IsSystemMessage() bool { return len(o.Type) >= len(POST_SYSTEM_MESSAGE_PREFIX) && o.Type[:len(POST_SYSTEM_MESSAGE_PREFIX)] == POST_SYSTEM_MESSAGE_PREFIX } +// IsRemote returns true if the post originated on a remote cluster. +func (o *Post) IsRemote() bool { + return o.RemoteId != nil && *o.RemoteId != "" +} + +// GetRemoteID safely returns the remoteID or empty string if not remote. +func (o *Post) GetRemoteID() string { + if o.RemoteId != nil { + return *o.RemoteId + } + return "" +} + func (o *Post) IsJoinLeaveMessage() bool { return o.Type == POST_JOIN_LEAVE || o.Type == POST_ADD_REMOVE || @@ -552,6 +605,25 @@ func (o *Post) Attachments() []*SlackAttachment { if enc, err := json.Marshal(attachment); err == nil { var decoded SlackAttachment if json.Unmarshal(enc, &decoded) == nil { + // Ignoring nil actions + i := 0 + for _, action := range decoded.Actions { + if action != nil { + decoded.Actions[i] = action + i++ + } + } + decoded.Actions = decoded.Actions[:i] + + // Ignoring nil fields + i = 0 + for _, field := range decoded.Fields { + if field != nil { + decoded.Fields[i] = field + i++ + } + } + decoded.Fields = decoded.Fields[:i] ret = append(ret, &decoded) } } @@ -665,3 +737,15 @@ func RewriteImageURLs(message string, f func(string) string) string { return string(result) } + +func (o *Post) IsFromOAuthBot() bool { + props := o.GetProps() + return props["from_webhook"] == "true" && props["override_username"] != "" +} + +func (o *Post) ToNilIfInvalid() *Post { + if o.Id == "" { + return nil + } + return o +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go index d00b68b5..ba84f749 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go @@ -27,6 +27,11 @@ func NewPostList() *PostList { func (o *PostList) ToSlice() []*Post { var posts []*Post + + if l := len(o.Posts); l > 0 { + posts = make([]*Post, 0, l) + } + for _, id := range o.Order { posts = append(posts, o.Posts[id]) } @@ -58,9 +63,8 @@ func (o *PostList) ToJson() string { b, err := json.Marshal(©) if err != nil { return "" - } else { - return string(b) } + return string(b) } func (o *PostList) MakeNonNil() { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go index 74ef4b52..fc9ba083 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go @@ -28,9 +28,8 @@ func (o *PostSearchResults) ToJson() string { b, err := json.Marshal(©) if err != nil { return "" - } else { - return string(b) } + return string(b) } func PostSearchResultsFromJson(data io.Reader) *PostSearchResults { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go b/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go index e752bb54..ee0d21aa 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go @@ -21,12 +21,14 @@ const ( PREFERENCE_CATEGORY_FAVORITE_CHANNEL = "favorite_channel" PREFERENCE_CATEGORY_SIDEBAR_SETTINGS = "sidebar_settings" - PREFERENCE_CATEGORY_DISPLAY_SETTINGS = "display_settings" - PREFERENCE_NAME_CHANNEL_DISPLAY_MODE = "channel_display_mode" - PREFERENCE_NAME_COLLAPSE_SETTING = "collapse_previews" - PREFERENCE_NAME_MESSAGE_DISPLAY = "message_display" - PREFERENCE_NAME_NAME_FORMAT = "name_format" - PREFERENCE_NAME_USE_MILITARY_TIME = "use_military_time" + PREFERENCE_CATEGORY_DISPLAY_SETTINGS = "display_settings" + PREFERENCE_NAME_COLLAPSED_THREADS_ENABLED = "collapsed_reply_threads" + PREFERENCE_NAME_CHANNEL_DISPLAY_MODE = "channel_display_mode" + PREFERENCE_NAME_COLLAPSE_SETTING = "collapse_previews" + PREFERENCE_NAME_MESSAGE_DISPLAY = "message_display" + PREFERENCE_NAME_NAME_FORMAT = "name_format" + PREFERENCE_NAME_USE_MILITARY_TIME = "use_military_time" + PREFERENCE_RECOMMENDED_NEXT_STEPS = "recommended_next_steps" PREFERENCE_CATEGORY_THEME = "theme" // the name for theme props is the team id @@ -38,6 +40,12 @@ const ( PREFERENCE_NAME_LAST_CHANNEL = "channel" PREFERENCE_NAME_LAST_TEAM = "team" + PREFERENCE_CATEGORY_CUSTOM_STATUS = "custom_status" + PREFERENCE_NAME_RECENT_CUSTOM_STATUSES = "recent_custom_statuses" + PREFERENCE_NAME_CUSTOM_STATUS_TUTORIAL_STATE = "custom_status_tutorial_state" + + PREFERENCE_CUSTOM_STATUS_MODAL_VIEWED = "custom_status_modal_viewed" + PREFERENCE_CATEGORY_NOTIFICATIONS = "notifications" PREFERENCE_NAME_EMAIL_INTERVAL = "email_interval" @@ -73,7 +81,7 @@ func (o *Preference) IsValid() *AppError { return NewAppError("Preference.IsValid", "model.preference.is_valid.id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest) } - if len(o.Category) == 0 || len(o.Category) > 32 { + if o.Category == "" || len(o.Category) > 32 { return NewAppError("Preference.IsValid", "model.preference.is_valid.category.app_error", nil, "category="+o.Category, http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go b/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go index 6ed845b6..c2d24865 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go @@ -19,9 +19,8 @@ func PreferencesFromJson(data io.Reader) (Preferences, error) { decoder := json.NewDecoder(data) var o Preferences err := decoder.Decode(&o) - if err == nil { - return o, nil - } else { + if err != nil { return nil, err } + return o, nil } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/product_notices.go b/vendor/github.com/mattermost/mattermost-server/v5/model/product_notices.go index 6aa88fc7..455ae475 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/product_notices.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/product_notices.go @@ -5,8 +5,9 @@ package model import ( "encoding/json" - "github.com/pkg/errors" "io" + + "github.com/pkg/errors" ) type ProductNotices []ProductNotice @@ -39,18 +40,19 @@ func (n *ProductNotice) TeamAdminOnly() bool { } type Conditions struct { - Audience *NoticeAudience `json:"audience,omitempty"` - ClientType *NoticeClientType `json:"clientType,omitempty"` // Only show the notice on specific clients. Defaults to 'all' - DesktopVersion []string `json:"desktopVersion,omitempty"` // What desktop client versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] - DisplayDate *string `json:"displayDate,omitempty"` // When to display the notice.; Examples:; "2020-03-01T00:00:00Z" - show on specified date; ">= 2020-03-01T00:00:00Z" - show after specified date; "< 2020-03-01T00:00:00Z" - show before the specified date; "> 2020-03-01T00:00:00Z <= 2020-04-01T00:00:00Z" - show only between the specified dates - InstanceType *NoticeInstanceType `json:"instanceType,omitempty"` - MobileVersion []string `json:"mobileVersion,omitempty"` // What mobile client versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] - NumberOfPosts *int64 `json:"numberOfPosts,omitempty"` // Only show the notice when server has more than specified number of posts - NumberOfUsers *int64 `json:"numberOfUsers,omitempty"` // Only show the notice when server has more than specified number of users - ServerConfig map[string]interface{} `json:"serverConfig,omitempty"` // Map of mattermost server config paths and their values. Notice will be displayed only if; the values match the target server config; Example: serverConfig: { "PluginSettings.Enable": true, "GuestAccountsSettings.Enable":; false } - ServerVersion []string `json:"serverVersion,omitempty"` // What server versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] - Sku *NoticeSKU `json:"sku,omitempty"` - UserConfig map[string]interface{} `json:"userConfig,omitempty"` // Map of user's settings and their values. Notice will be displayed only if the values; match the viewing users' config; Example: userConfig: { "new_sidebar.disabled": true } + Audience *NoticeAudience `json:"audience,omitempty"` + ClientType *NoticeClientType `json:"clientType,omitempty"` // Only show the notice on specific clients. Defaults to 'all' + DesktopVersion []string `json:"desktopVersion,omitempty"` // What desktop client versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] + DisplayDate *string `json:"displayDate,omitempty"` // When to display the notice.; Examples:; "2020-03-01T00:00:00Z" - show on specified date; ">= 2020-03-01T00:00:00Z" - show after specified date; "< 2020-03-01T00:00:00Z" - show before the specified date; "> 2020-03-01T00:00:00Z <= 2020-04-01T00:00:00Z" - show only between the specified dates + InstanceType *NoticeInstanceType `json:"instanceType,omitempty"` + MobileVersion []string `json:"mobileVersion,omitempty"` // What mobile client versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] + NumberOfPosts *int64 `json:"numberOfPosts,omitempty"` // Only show the notice when server has more than specified number of posts + NumberOfUsers *int64 `json:"numberOfUsers,omitempty"` // Only show the notice when server has more than specified number of users + ServerConfig map[string]interface{} `json:"serverConfig,omitempty"` // Map of mattermost server config paths and their values. Notice will be displayed only if; the values match the target server config; Example: serverConfig: { "PluginSettings.Enable": true, "GuestAccountsSettings.Enable":; false } + ServerVersion []string `json:"serverVersion,omitempty"` // What server versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] + Sku *NoticeSKU `json:"sku,omitempty"` + UserConfig map[string]interface{} `json:"userConfig,omitempty"` // Map of user's settings and their values. Notice will be displayed only if the values; match the viewing users' config; Example: userConfig: { "new_sidebar.disabled": true } + DeprecatingDependency *ExternalDependency `json:"deprecating_dependency,omitempty"` // External dependency which is going to be deprecated } type NoticeMessageInternal struct { @@ -211,3 +213,8 @@ type ProductNoticeViewState struct { Viewed int32 Timestamp int64 } + +type ExternalDependency struct { + Name string `json:"name"` + MinimumVersion string `json:"minimum_version"` +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go b/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go index 80945905..2a0dc658 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go @@ -70,23 +70,23 @@ type PushNotification struct { IsIdLoaded bool `json:"is_id_loaded"` } -func (me *PushNotification) ToJson() string { - b, _ := json.Marshal(me) +func (pn *PushNotification) ToJson() string { + b, _ := json.Marshal(pn) return string(b) } -func (me *PushNotification) DeepCopy() *PushNotification { - copy := *me +func (pn *PushNotification) DeepCopy() *PushNotification { + copy := *pn return © } -func (me *PushNotification) SetDeviceIdAndPlatform(deviceId string) { +func (pn *PushNotification) SetDeviceIdAndPlatform(deviceId string) { index := strings.Index(deviceId, ":") if index > -1 { - me.Platform = deviceId[:index] - me.DeviceId = deviceId[index+1:] + pn.Platform = deviceId[:index] + pn.DeviceId = deviceId[index+1:] } } @@ -94,11 +94,11 @@ func PushNotificationFromJson(data io.Reader) (*PushNotification, error) { if data == nil { return nil, errors.New("push notification data can't be nil") } - var me *PushNotification - if err := json.NewDecoder(data).Decode(&me); err != nil { + var pn *PushNotification + if err := json.NewDecoder(data).Decode(&pn); err != nil { return nil, err } - return me, nil + return pn, nil } func PushNotificationAckFromJson(data io.Reader) (*PushNotificationAck, error) { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go index e6e8059b..227a089b 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go @@ -37,8 +37,8 @@ func NewErrorPushResponse(message string) PushResponse { return m } -func (me *PushResponse) ToJson() string { - b, _ := json.Marshal(me) +func (pr *PushResponse) ToJson() string { + b, _ := json.Marshal(pr) return string(b) } @@ -48,7 +48,6 @@ func PushResponseFromJson(data io.Reader) PushResponse { var objmap PushResponse if err := decoder.Decode(&objmap); err != nil { return make(map[string]string) - } else { - return objmap } + return objmap } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go b/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go index 50879c67..6d0ea68d 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go @@ -11,10 +11,13 @@ import ( ) type Reaction struct { - UserId string `json:"user_id"` - PostId string `json:"post_id"` - EmojiName string `json:"emoji_name"` - CreateAt int64 `json:"create_at"` + UserId string `json:"user_id"` + PostId string `json:"post_id"` + EmojiName string `json:"emoji_name"` + CreateAt int64 `json:"create_at"` + UpdateAt int64 `json:"update_at"` + DeleteAt int64 `json:"delete_at"` + RemoteId *string `json:"remote_id"` } func (o *Reaction) ToJson() string { @@ -27,9 +30,8 @@ func ReactionFromJson(data io.Reader) *Reaction { if err := json.NewDecoder(data).Decode(&o); err != nil { return nil - } else { - return &o } + return &o } func ReactionsToJson(o []*Reaction) string { @@ -48,9 +50,8 @@ func MapPostIdToReactionsFromJson(data io.Reader) map[string][]*Reaction { var objmap map[string][]*Reaction if err := decoder.Decode(&objmap); err != nil { return make(map[string][]*Reaction) - } else { - return objmap } + return objmap } func ReactionsFromJson(data io.Reader) []*Reaction { @@ -58,9 +59,8 @@ func ReactionsFromJson(data io.Reader) []*Reaction { if err := json.NewDecoder(data).Decode(&o); err != nil { return nil - } else { - return o } + return o } func (o *Reaction) IsValid() *AppError { @@ -74,7 +74,7 @@ func (o *Reaction) IsValid() *AppError { validName := regexp.MustCompile(`^[a-zA-Z0-9\-\+_]+$`) - if len(o.EmojiName) == 0 || len(o.EmojiName) > EMOJI_NAME_MAX_LENGTH || !validName.MatchString(o.EmojiName) { + if o.EmojiName == "" || len(o.EmojiName) > EMOJI_NAME_MAX_LENGTH || !validName.MatchString(o.EmojiName) { return NewAppError("Reaction.IsValid", "model.reaction.is_valid.emoji_name.app_error", nil, "emoji_name="+o.EmojiName, http.StatusBadRequest) } @@ -82,6 +82,10 @@ func (o *Reaction) IsValid() *AppError { return NewAppError("Reaction.IsValid", "model.reaction.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) } + if o.UpdateAt == 0 { + return NewAppError("Reaction.IsValid", "model.reaction.is_valid.update_at.app_error", nil, "", http.StatusBadRequest) + } + return nil } @@ -89,4 +93,18 @@ func (o *Reaction) PreSave() { if o.CreateAt == 0 { o.CreateAt = GetMillis() } + o.UpdateAt = GetMillis() + o.DeleteAt = 0 + + if o.RemoteId == nil { + o.RemoteId = NewString("") + } +} + +func (o *Reaction) PreUpdate() { + o.UpdateAt = GetMillis() + + if o.RemoteId == nil { + o.RemoteId = NewString("") + } } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/remote_cluster.go b/vendor/github.com/mattermost/mattermost-server/v5/model/remote_cluster.go new file mode 100644 index 00000000..2ec0cc9b --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/remote_cluster.go @@ -0,0 +1,355 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/json" + "errors" + "io" + "net/http" + "regexp" + "strings" + + "golang.org/x/crypto/scrypt" +) + +const ( + RemoteOfflineAfterMillis = 1000 * 60 * 5 // 5 minutes + RemoteNameMinLength = 1 + RemoteNameMaxLength = 64 +) + +var ( + validRemoteNameChars = regexp.MustCompile(`^[a-zA-Z0-9\.\-\_]+$`) +) + +type RemoteCluster struct { + RemoteId string `json:"remote_id"` + RemoteTeamId string `json:"remote_team_id"` + Name string `json:"name"` + DisplayName string `json:"display_name"` + SiteURL string `json:"site_url"` + CreateAt int64 `json:"create_at"` + LastPingAt int64 `json:"last_ping_at"` + Token string `json:"token"` + RemoteToken string `json:"remote_token"` + Topics string `json:"topics"` + CreatorId string `json:"creator_id"` +} + +func (rc *RemoteCluster) PreSave() { + if rc.RemoteId == "" { + rc.RemoteId = NewId() + } + + if rc.DisplayName == "" { + rc.DisplayName = rc.Name + } + + rc.Name = SanitizeUnicode(rc.Name) + rc.DisplayName = SanitizeUnicode(rc.DisplayName) + rc.Name = NormalizeRemoteName(rc.Name) + + if rc.Token == "" { + rc.Token = NewId() + } + + if rc.CreateAt == 0 { + rc.CreateAt = GetMillis() + } + rc.fixTopics() +} + +func (rc *RemoteCluster) IsValid() *AppError { + if !IsValidId(rc.RemoteId) { + return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.id.app_error", nil, "id="+rc.RemoteId, http.StatusBadRequest) + } + + if !IsValidRemoteName(rc.Name) { + return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.name.app_error", nil, "name="+rc.Name, http.StatusBadRequest) + } + + if rc.CreateAt == 0 { + return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.create_at.app_error", nil, "create_at=0", http.StatusBadRequest) + } + + if !IsValidId(rc.CreatorId) { + return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.id.app_error", nil, "creator_id="+rc.CreatorId, http.StatusBadRequest) + } + return nil +} + +func IsValidRemoteName(s string) bool { + if len(s) < RemoteNameMinLength || len(s) > RemoteNameMaxLength { + return false + } + return validRemoteNameChars.MatchString(s) +} + +func (rc *RemoteCluster) PreUpdate() { + if rc.DisplayName == "" { + rc.DisplayName = rc.Name + } + + rc.Name = SanitizeUnicode(rc.Name) + rc.DisplayName = SanitizeUnicode(rc.DisplayName) + rc.Name = NormalizeRemoteName(rc.Name) + rc.fixTopics() +} + +func (rc *RemoteCluster) IsOnline() bool { + return rc.LastPingAt > GetMillis()-RemoteOfflineAfterMillis +} + +// fixTopics ensures all topics are separated by one, and only one, space. +func (rc *RemoteCluster) fixTopics() { + trimmed := strings.TrimSpace(rc.Topics) + if trimmed == "" || trimmed == "*" { + rc.Topics = trimmed + return + } + + var sb strings.Builder + sb.WriteString(" ") + + ss := strings.Split(rc.Topics, " ") + for _, c := range ss { + cc := strings.TrimSpace(c) + if cc != "" { + sb.WriteString(cc) + sb.WriteString(" ") + } + } + rc.Topics = sb.String() +} + +func (rc *RemoteCluster) ToJSON() (string, error) { + b, err := json.Marshal(rc) + if err != nil { + return "", err + } + return string(b), nil +} + +func (rc *RemoteCluster) ToRemoteClusterInfo() RemoteClusterInfo { + return RemoteClusterInfo{ + Name: rc.Name, + DisplayName: rc.DisplayName, + CreateAt: rc.CreateAt, + LastPingAt: rc.LastPingAt, + } +} + +func NormalizeRemoteName(name string) string { + return strings.ToLower(name) +} + +func RemoteClusterFromJSON(data io.Reader) (*RemoteCluster, *AppError) { + var rc RemoteCluster + err := json.NewDecoder(data).Decode(&rc) + if err != nil { + return nil, NewAppError("RemoteClusterFromJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) + } + return &rc, nil +} + +// RemoteClusterInfo provides a subset of RemoteCluster fields suitable for sending to clients. +type RemoteClusterInfo struct { + Name string `json:"name"` + DisplayName string `json:"display_name"` + CreateAt int64 `json:"create_at"` + LastPingAt int64 `json:"last_ping_at"` +} + +// RemoteClusterFrame wraps a `RemoteClusterMsg` with credentials specific to a remote cluster. +type RemoteClusterFrame struct { + RemoteId string `json:"remote_id"` + Msg RemoteClusterMsg `json:"msg"` +} + +func (f *RemoteClusterFrame) IsValid() *AppError { + if !IsValidId(f.RemoteId) { + return NewAppError("RemoteClusterFrame.IsValid", "api.remote_cluster.invalid_id.app_error", nil, "RemoteId="+f.RemoteId, http.StatusBadRequest) + } + + if err := f.Msg.IsValid(); err != nil { + return err + } + + return nil +} + +func RemoteClusterFrameFromJSON(data io.Reader) (*RemoteClusterFrame, *AppError) { + var frame RemoteClusterFrame + err := json.NewDecoder(data).Decode(&frame) + if err != nil { + return nil, NewAppError("RemoteClusterFrameFromJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) + } + return &frame, nil +} + +// RemoteClusterMsg represents a message that is sent and received between clusters. +// These are processed and routed via the RemoteClusters service. +type RemoteClusterMsg struct { + Id string `json:"id"` + Topic string `json:"topic"` + CreateAt int64 `json:"create_at"` + Payload json.RawMessage `json:"payload"` +} + +func NewRemoteClusterMsg(topic string, payload json.RawMessage) RemoteClusterMsg { + return RemoteClusterMsg{ + Id: NewId(), + Topic: topic, + CreateAt: GetMillis(), + Payload: payload, + } +} + +func (m RemoteClusterMsg) IsValid() *AppError { + if !IsValidId(m.Id) { + return NewAppError("RemoteClusterMsg.IsValid", "api.remote_cluster.invalid_id.app_error", nil, "Id="+m.Id, http.StatusBadRequest) + } + + if m.Topic == "" { + return NewAppError("RemoteClusterMsg.IsValid", "api.remote_cluster.invalid_topic.app_error", nil, "Topic empty", http.StatusBadRequest) + } + + if len(m.Payload) == 0 { + return NewAppError("RemoteClusterMsg.IsValid", "api.context.invalid_body_param.app_error", map[string]interface{}{"Name": "PayLoad"}, "", http.StatusBadRequest) + } + + return nil +} + +func RemoteClusterMsgFromJSON(data io.Reader) (RemoteClusterMsg, *AppError) { + var msg RemoteClusterMsg + err := json.NewDecoder(data).Decode(&msg) + if err != nil { + return RemoteClusterMsg{}, NewAppError("RemoteClusterMsgFromJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) + } + return msg, nil +} + +// RemoteClusterPing represents a ping that is sent and received between clusters +// to indicate a connection is alive. This is the payload for a `RemoteClusterMsg`. +type RemoteClusterPing struct { + SentAt int64 `json:"sent_at"` + RecvAt int64 `json:"recv_at"` +} + +func RemoteClusterPingFromRawJSON(raw json.RawMessage) (RemoteClusterPing, *AppError) { + var ping RemoteClusterPing + err := json.Unmarshal(raw, &ping) + if err != nil { + return RemoteClusterPing{}, NewAppError("RemoteClusterPingFromRawJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) + } + return ping, nil +} + +// RemoteClusterInvite represents an invitation to establish a simple trust with a remote cluster. +type RemoteClusterInvite struct { + RemoteId string `json:"remote_id"` + RemoteTeamId string `json:"remote_team_id"` + SiteURL string `json:"site_url"` + Token string `json:"token"` +} + +func RemoteClusterInviteFromRawJSON(raw json.RawMessage) (*RemoteClusterInvite, *AppError) { + var invite RemoteClusterInvite + err := json.Unmarshal(raw, &invite) + if err != nil { + return nil, NewAppError("RemoteClusterInviteFromRawJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) + } + return &invite, nil +} + +func (rci *RemoteClusterInvite) Encrypt(password string) ([]byte, error) { + raw, err := json.Marshal(&rci) + if err != nil { + return nil, err + } + + // create random salt to be prepended to the blob. + salt := make([]byte, 16) + if _, err = io.ReadFull(rand.Reader, salt); err != nil { + return nil, err + } + + key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(key[:]) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + // create random nonce + nonce := make([]byte, gcm.NonceSize()) + if _, err = io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + // prefix the nonce to the cyphertext so we don't need to keep track of it. + sealed := gcm.Seal(nonce, nonce, raw, nil) + + return append(salt, sealed...), nil +} + +func (rci *RemoteClusterInvite) Decrypt(encrypted []byte, password string) error { + if len(encrypted) <= 16 { + return errors.New("invalid length") + } + + // first 16 bytes is the salt that was used to derive a key + salt := encrypted[:16] + encrypted = encrypted[16:] + + key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32) + if err != nil { + return err + } + + block, err := aes.NewCipher(key[:]) + if err != nil { + return err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return err + } + + // nonce was prefixed to the cyphertext when encrypting so we need to extract it. + nonceSize := gcm.NonceSize() + nonce, cyphertext := encrypted[:nonceSize], encrypted[nonceSize:] + + plain, err := gcm.Open(nil, nonce, cyphertext, nil) + if err != nil { + return err + } + + // try to unmarshall the decrypted JSON to this invite struct. + return json.Unmarshal(plain, &rci) +} + +// RemoteClusterQueryFilter provides filter criteria for RemoteClusterStore.GetAll +type RemoteClusterQueryFilter struct { + ExcludeOffline bool + InChannel string + NotInChannel string + Topic string + CreatorId string + OnlyConfirmed bool +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/role.go b/vendor/github.com/mattermost/mattermost-server/v5/model/role.go index 271e295b..fc1606ce 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/role.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/role.go @@ -47,6 +47,12 @@ func init() { // When updating the values here, the values in mattermost-redux must also be updated. SysconsoleAncillaryPermissions = map[string][]*Permission{ + PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE.Id: { + PERMISSION_READ_LICENSE_INFORMATION, + }, + PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE.Id: { + PERMISSION_MANAGE_LICENSE_INFORMATION, + }, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id: { PERMISSION_READ_PUBLIC_CHANNEL, PERMISSION_READ_CHANNEL, @@ -55,19 +61,44 @@ func init() { }, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS.Id: { PERMISSION_READ_OTHER_USERS_TEAMS, + PERMISSION_GET_ANALYTICS, }, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id: { PERMISSION_LIST_PRIVATE_TEAMS, PERMISSION_LIST_PUBLIC_TEAMS, PERMISSION_VIEW_TEAM, }, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id: { - PERMISSION_READ_JOBS, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH.Id: { + PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB, + PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB, + }, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER.Id: { + PERMISSION_TEST_SITE_URL, + PERMISSION_RELOAD_CONFIG, + PERMISSION_INVALIDATE_CACHES, + }, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE.Id: { + PERMISSION_RECYCLE_DATABASE_CONNECTIONS, + }, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH.Id: { + PERMISSION_TEST_ELASTICSEARCH, + PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB, + PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB, + PERMISSION_PURGE_ELASTICSEARCH_INDEXES, }, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id: { - PERMISSION_READ_JOBS, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE.Id: { + PERMISSION_TEST_S3, }, - PERMISSION_SYSCONSOLE_READ_REPORTING.Id: { + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP.Id: { + PERMISSION_TEST_EMAIL, + }, + PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS.Id: { + PERMISSION_GET_LOGS, + }, + PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS.Id: { + PERMISSION_GET_ANALYTICS, + }, + PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS.Id: { PERMISSION_VIEW_TEAM, }, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS.Id: { @@ -102,12 +133,54 @@ func init() { PERMISSION_CONVERT_PUBLIC_CHANNEL_TO_PRIVATE, PERMISSION_CONVERT_PRIVATE_CHANNEL_TO_PUBLIC, }, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT.Id: { - PERMISSION_MANAGE_JOBS, - }, - PERMISSION_SYSCONSOLE_WRITE_SITE.Id: { + PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION.Id: { PERMISSION_EDIT_BRAND, }, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY.Id: { + PERMISSION_CREATE_DATA_RETENTION_JOB, + }, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY.Id: { + PERMISSION_READ_DATA_RETENTION_JOB, + }, + PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT.Id: { + PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB, + PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT, + }, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT.Id: { + PERMISSION_READ_COMPLIANCE_EXPORT_JOB, + PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT, + }, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE.Id: { + PERMISSION_READ_AUDITS, + }, + PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE.Id: { + PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB, + PERMISSION_PURGE_BLEVE_INDEXES, + }, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP.Id: { + PERMISSION_CREATE_LDAP_SYNC_JOB, + PERMISSION_ADD_LDAP_PUBLIC_CERT, + PERMISSION_REMOVE_LDAP_PUBLIC_CERT, + PERMISSION_ADD_LDAP_PRIVATE_CERT, + PERMISSION_REMOVE_LDAP_PRIVATE_CERT, + }, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id: { + PERMISSION_TEST_LDAP, + PERMISSION_READ_LDAP_SYNC_JOB, + }, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL.Id: { + PERMISSION_INVALIDATE_EMAIL_INVITE, + }, + PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML.Id: { + PERMISSION_GET_SAML_METADATA_FROM_IDP, + PERMISSION_ADD_SAML_PUBLIC_CERT, + PERMISSION_ADD_SAML_PRIVATE_CERT, + PERMISSION_ADD_SAML_IDP_CERT, + PERMISSION_REMOVE_SAML_PUBLIC_CERT, + PERMISSION_REMOVE_SAML_PRIVATE_CERT, + PERMISSION_REMOVE_SAML_IDP_CERT, + PERMISSION_GET_SAML_CERT_STATUS, + }, } SystemUserManagerDefaultPermissions = []string{ @@ -118,29 +191,76 @@ func init() { PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS.Id, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS.Id, } SystemReadOnlyAdminDefaultPermissions = []string{ - PERMISSION_SYSCONSOLE_READ_ABOUT.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING.Id, + PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, - PERMISSION_SYSCONSOLE_READ_SITE.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER.Id, + PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION.Id, + PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION.Id, + PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER.Id, + PERMISSION_SYSCONSOLE_READ_SITE_EMOJI.Id, + PERMISSION_SYSCONSOLE_READ_SITE_POSTS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_NOTICES.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS.Id, PERMISSION_SYSCONSOLE_READ_PLUGINS.Id, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS.Id, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY.Id, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT.Id, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING.Id, + PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE.Id, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES.Id, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS.Id, + PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE.Id, } SystemManagerDefaultPermissions = []string{ - PERMISSION_SYSCONSOLE_READ_ABOUT.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING.Id, + PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS.Id, + PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, @@ -149,20 +269,75 @@ func init() { PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id, PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT.Id, - PERMISSION_SYSCONSOLE_READ_SITE.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING.Id, + PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING.Id, + PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER.Id, + PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION.Id, + PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION.Id, + PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER.Id, + PERMISSION_SYSCONSOLE_READ_SITE_EMOJI.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI.Id, + PERMISSION_SYSCONSOLE_READ_SITE_POSTS.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS.Id, + PERMISSION_SYSCONSOLE_READ_SITE_NOTICES.Id, + PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID.Id, + PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS.Id, PERMISSION_SYSCONSOLE_READ_PLUGINS.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS.Id, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF.Id, + PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS.Id, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT.Id, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS.Id, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF.Id, + PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS.Id, } // Add the ancillary permissions to each system role - SystemUserManagerDefaultPermissions = addAncillaryPermissions(SystemUserManagerDefaultPermissions) - SystemReadOnlyAdminDefaultPermissions = addAncillaryPermissions(SystemReadOnlyAdminDefaultPermissions) - SystemManagerDefaultPermissions = addAncillaryPermissions(SystemManagerDefaultPermissions) + SystemUserManagerDefaultPermissions = AddAncillaryPermissions(SystemUserManagerDefaultPermissions) + SystemReadOnlyAdminDefaultPermissions = AddAncillaryPermissions(SystemReadOnlyAdminDefaultPermissions) + SystemManagerDefaultPermissions = AddAncillaryPermissions(SystemManagerDefaultPermissions) } type RoleType string @@ -278,7 +453,7 @@ func (r *Role) MergeChannelHigherScopedPermissions(higherScopedPermissions *Role _, presentOnHigherScope := higherScopedPermissionsMap[cp.Id] - // For the channel admin role always look to the higher scope to determine if the role has ther permission. + // For the channel admin role always look to the higher scope to determine if the role has their permission. // The channel admin is a special case because they're not part of the UI to be "channel moderated", only // channel members and channel guests are. if higherScopedPermissions.RoleID == CHANNEL_ADMIN_ROLE_ID && presentOnHigherScope { @@ -475,7 +650,7 @@ func (r *Role) IsValidWithoutId() bool { return false } - if len(r.DisplayName) == 0 || len(r.DisplayName) > ROLE_DISPLAY_NAME_MAX_LENGTH { + if r.DisplayName == "" || len(r.DisplayName) > ROLE_DISPLAY_NAME_MAX_LENGTH { return false } @@ -519,7 +694,7 @@ func CleanRoleNames(roleNames []string) ([]string, bool) { } func IsValidRoleName(roleName string) bool { - if len(roleName) <= 0 || len(roleName) > ROLE_NAME_MAX_LENGTH { + if roleName == "" || len(roleName) > ROLE_NAME_MAX_LENGTH { return false } @@ -765,7 +940,7 @@ func MakeDefaultRoles() map[string]*Role { return roles } -func addAncillaryPermissions(permissions []string) []string { +func AddAncillaryPermissions(permissions []string) []string { for _, permission := range permissions { if ancillaryPermissions, ok := SysconsoleAncillaryPermissions[permission]; ok { for _, ancillaryPermission := range ancillaryPermissions { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go b/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go index 657cc749..cf20db63 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go @@ -11,42 +11,65 @@ import ( type TaskFunc func() type ScheduledTask struct { - Name string `json:"name"` - Interval time.Duration `json:"interval"` - Recurring bool `json:"recurring"` - function func() - cancel chan struct{} - cancelled chan struct{} + Name string `json:"name"` + Interval time.Duration `json:"interval"` + Recurring bool `json:"recurring"` + function func() + cancel chan struct{} + cancelled chan struct{} + fromNextIntervalTime bool } func CreateTask(name string, function TaskFunc, timeToExecution time.Duration) *ScheduledTask { - return createTask(name, function, timeToExecution, false) + return createTask(name, function, timeToExecution, false, false) } func CreateRecurringTask(name string, function TaskFunc, interval time.Duration) *ScheduledTask { - return createTask(name, function, interval, true) + return createTask(name, function, interval, true, false) } -func createTask(name string, function TaskFunc, interval time.Duration, recurring bool) *ScheduledTask { +func CreateRecurringTaskFromNextIntervalTime(name string, function TaskFunc, interval time.Duration) *ScheduledTask { + return createTask(name, function, interval, true, true) +} + +func createTask(name string, function TaskFunc, interval time.Duration, recurring bool, fromNextIntervalTime bool) *ScheduledTask { task := &ScheduledTask{ - Name: name, - Interval: interval, - Recurring: recurring, - function: function, - cancel: make(chan struct{}), - cancelled: make(chan struct{}), + Name: name, + Interval: interval, + Recurring: recurring, + function: function, + cancel: make(chan struct{}), + cancelled: make(chan struct{}), + fromNextIntervalTime: fromNextIntervalTime, } go func() { defer close(task.cancelled) - ticker := time.NewTicker(interval) + var firstTick <-chan time.Time + var ticker *time.Ticker + + if task.fromNextIntervalTime { + currTime := time.Now() + first := currTime.Truncate(interval) + if first.Before(currTime) { + first = first.Add(interval) + } + firstTick = time.After(time.Until(first)) + ticker = &time.Ticker{C: nil} + } else { + firstTick = nil + ticker = time.NewTicker(interval) + } defer func() { ticker.Stop() }() for { select { + case <-firstTick: + ticker = time.NewTicker(interval) + function() case <-ticker.C: function() case <-task.cancel: diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go b/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go index 630f14a6..b5bbf34a 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go @@ -101,9 +101,8 @@ func SchemesFromJson(data io.Reader) []*Scheme { var schemes []*Scheme if err := json.NewDecoder(data).Decode(&schemes); err == nil { return schemes - } else { - return nil } + return nil } func (scheme *Scheme) IsValid() bool { @@ -115,7 +114,7 @@ func (scheme *Scheme) IsValid() bool { } func (scheme *Scheme) IsValidForCreate() bool { - if len(scheme.DisplayName) == 0 || len(scheme.DisplayName) > SCHEME_DISPLAY_NAME_MAX_LENGTH { + if scheme.DisplayName == "" || len(scheme.DisplayName) > SCHEME_DISPLAY_NAME_MAX_LENGTH { return false } @@ -160,15 +159,15 @@ func (scheme *Scheme) IsValidForCreate() bool { } if scheme.Scope == SCHEME_SCOPE_CHANNEL { - if len(scheme.DefaultTeamAdminRole) != 0 { + if scheme.DefaultTeamAdminRole != "" { return false } - if len(scheme.DefaultTeamUserRole) != 0 { + if scheme.DefaultTeamUserRole != "" { return false } - if len(scheme.DefaultTeamGuestRole) != 0 { + if scheme.DefaultTeamGuestRole != "" { return false } } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go b/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go index d34c8865..41a2db2a 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go @@ -25,6 +25,8 @@ type SearchParams struct { ExcludedAfterDate string BeforeDate string ExcludedBeforeDate string + Extensions []string + ExcludedExtensions []string OnDate string ExcludedDate string OrTerms bool @@ -106,7 +108,7 @@ func (p *SearchParams) GetExcludedDateMillis() (int64, int64) { return GetStartOfDayMillis(date, p.TimeZoneOffset), GetEndOfDayMillis(date, p.TimeZoneOffset) } -var searchFlags = [...]string{"from", "channel", "in", "before", "after", "on"} +var searchFlags = [...]string{"from", "channel", "in", "before", "after", "on", "ext"} type flag struct { name string @@ -214,7 +216,7 @@ func parseSearchFlags(input []string) ([]searchWord, []flag) { // and remove extra pound #s word = hashtagStart.ReplaceAllString(word, "#") - if len(word) != 0 { + if word != "" { words = append(words, searchWord{ word, exclude, @@ -265,6 +267,8 @@ func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams { excludedBeforeDate := "" onDate := "" excludedDate := "" + excludedExtensions := []string{} + extensions := []string{} for _, flag := range flags { if flag.name == "in" || flag.name == "channel" { @@ -297,12 +301,18 @@ func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams { } else { onDate = flag.value } + } else if flag.name == "ext" { + if flag.exclude { + excludedExtensions = append(excludedExtensions, flag.value) + } else { + extensions = append(extensions, flag.value) + } } } paramsList := []*SearchParams{} - if len(plainTerms) > 0 || len(excludedPlainTerms) > 0 { + if plainTerms != "" || excludedPlainTerms != "" { paramsList = append(paramsList, &SearchParams{ Terms: plainTerms, ExcludedTerms: excludedPlainTerms, @@ -315,13 +325,15 @@ func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams { ExcludedAfterDate: excludedAfterDate, BeforeDate: beforeDate, ExcludedBeforeDate: excludedBeforeDate, + Extensions: extensions, + ExcludedExtensions: excludedExtensions, OnDate: onDate, ExcludedDate: excludedDate, TimeZoneOffset: timeZoneOffset, }) } - if len(hashtagTerms) > 0 || len(excludedHashtagTerms) > 0 { + if hashtagTerms != "" || excludedHashtagTerms != "" { paramsList = append(paramsList, &SearchParams{ Terms: hashtagTerms, ExcludedTerms: excludedHashtagTerms, @@ -334,6 +346,8 @@ func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams { ExcludedAfterDate: excludedAfterDate, BeforeDate: beforeDate, ExcludedBeforeDate: excludedBeforeDate, + Extensions: extensions, + ExcludedExtensions: excludedExtensions, OnDate: onDate, ExcludedDate: excludedDate, TimeZoneOffset: timeZoneOffset, @@ -341,13 +355,14 @@ func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams { } // special case for when no terms are specified but we still have a filter - if len(plainTerms) == 0 && len(hashtagTerms) == 0 && - len(excludedPlainTerms) == 0 && len(excludedHashtagTerms) == 0 && + if plainTerms == "" && hashtagTerms == "" && + excludedPlainTerms == "" && excludedHashtagTerms == "" && (len(inChannels) != 0 || len(fromUsers) != 0 || len(excludedChannels) != 0 || len(excludedUsers) != 0 || - len(afterDate) != 0 || len(excludedAfterDate) != 0 || - len(beforeDate) != 0 || len(excludedBeforeDate) != 0 || - len(onDate) != 0 || len(excludedDate) != 0) { + len(extensions) != 0 || len(excludedExtensions) != 0 || + afterDate != "" || excludedAfterDate != "" || + beforeDate != "" || excludedBeforeDate != "" || + onDate != "" || excludedDate != "") { paramsList = append(paramsList, &SearchParams{ Terms: "", ExcludedTerms: "", @@ -360,6 +375,8 @@ func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams { ExcludedAfterDate: excludedAfterDate, BeforeDate: beforeDate, ExcludedBeforeDate: excludedBeforeDate, + Extensions: extensions, + ExcludedExtensions: excludedExtensions, OnDate: onDate, ExcludedDate: excludedDate, TimeZoneOffset: timeZoneOffset, diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go index ae66cf30..66a65812 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go @@ -15,8 +15,8 @@ type SecurityBulletin struct { type SecurityBulletins []SecurityBulletin -func (me *SecurityBulletin) ToJson() string { - b, _ := json.Marshal(me) +func (sb *SecurityBulletin) ToJson() string { + b, _ := json.Marshal(sb) return string(b) } @@ -26,12 +26,12 @@ func SecurityBulletinFromJson(data io.Reader) *SecurityBulletin { return o } -func (me SecurityBulletins) ToJson() string { - if b, err := json.Marshal(me); err != nil { +func (sb SecurityBulletins) ToJson() string { + b, err := json.Marshal(sb) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func SecurityBulletinsFromJson(data io.Reader) SecurityBulletins { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/serialized_gen.go b/vendor/github.com/mattermost/mattermost-server/v5/model/serialized_gen.go deleted file mode 100644 index 1f16f1cb..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/serialized_gen.go +++ /dev/null @@ -1,1779 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -// Code generated by github.com/tinylib/msgp DO NOT EDIT. - -import ( - "github.com/tinylib/msgp/msgp" -) - -// DecodeMsg implements msgp.Decodable -func (z *Session) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0001 uint32 - zb0001, err = dc.ReadArrayHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 13 { - err = msgp.ArrayError{Wanted: 13, Got: zb0001} - return - } - z.Id, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.Token, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Token") - return - } - z.CreateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.ExpiresAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "ExpiresAt") - return - } - z.LastActivityAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.UserId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - z.DeviceId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "DeviceId") - return - } - z.Roles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.IsOAuth, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "IsOAuth") - return - } - z.ExpiredNotify, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "ExpiredNotify") - return - } - var zb0002 uint32 - zb0002, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - if z.Props == nil { - z.Props = make(StringMap, zb0002) - } else if len(z.Props) > 0 { - for key := range z.Props { - delete(z.Props, key) - } - } - for zb0002 > 0 { - zb0002-- - var za0001 string - var za0002 string - za0001, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - za0002, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - z.Props[za0001] = za0002 - } - var zb0003 uint32 - zb0003, err = dc.ReadArrayHeader() - if err != nil { - err = msgp.WrapError(err, "TeamMembers") - return - } - if cap(z.TeamMembers) >= int(zb0003) { - z.TeamMembers = (z.TeamMembers)[:zb0003] - } else { - z.TeamMembers = make([]*TeamMember, zb0003) - } - for za0003 := range z.TeamMembers { - if dc.IsNil() { - err = dc.ReadNil() - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - z.TeamMembers[za0003] = nil - } else { - if z.TeamMembers[za0003] == nil { - z.TeamMembers[za0003] = new(TeamMember) - } - err = z.TeamMembers[za0003].DecodeMsg(dc) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - z.Local, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "Local") - return - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z *Session) EncodeMsg(en *msgp.Writer) (err error) { - // array header, size 13 - err = en.Append(0x9d) - if err != nil { - return - } - err = en.WriteString(z.Id) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - err = en.WriteString(z.Token) - if err != nil { - err = msgp.WrapError(err, "Token") - return - } - err = en.WriteInt64(z.CreateAt) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - err = en.WriteInt64(z.ExpiresAt) - if err != nil { - err = msgp.WrapError(err, "ExpiresAt") - return - } - err = en.WriteInt64(z.LastActivityAt) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - err = en.WriteString(z.UserId) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - err = en.WriteString(z.DeviceId) - if err != nil { - err = msgp.WrapError(err, "DeviceId") - return - } - err = en.WriteString(z.Roles) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - err = en.WriteBool(z.IsOAuth) - if err != nil { - err = msgp.WrapError(err, "IsOAuth") - return - } - err = en.WriteBool(z.ExpiredNotify) - if err != nil { - err = msgp.WrapError(err, "ExpiredNotify") - return - } - err = en.WriteMapHeader(uint32(len(z.Props))) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - for za0001, za0002 := range z.Props { - err = en.WriteString(za0001) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - err = en.WriteString(za0002) - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - } - err = en.WriteArrayHeader(uint32(len(z.TeamMembers))) - if err != nil { - err = msgp.WrapError(err, "TeamMembers") - return - } - for za0003 := range z.TeamMembers { - if z.TeamMembers[za0003] == nil { - err = en.WriteNil() - if err != nil { - return - } - } else { - err = z.TeamMembers[za0003].EncodeMsg(en) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - err = en.WriteBool(z.Local) - if err != nil { - err = msgp.WrapError(err, "Local") - return - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z *Session) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - // array header, size 13 - o = append(o, 0x9d) - o = msgp.AppendString(o, z.Id) - o = msgp.AppendString(o, z.Token) - o = msgp.AppendInt64(o, z.CreateAt) - o = msgp.AppendInt64(o, z.ExpiresAt) - o = msgp.AppendInt64(o, z.LastActivityAt) - o = msgp.AppendString(o, z.UserId) - o = msgp.AppendString(o, z.DeviceId) - o = msgp.AppendString(o, z.Roles) - o = msgp.AppendBool(o, z.IsOAuth) - o = msgp.AppendBool(o, z.ExpiredNotify) - o = msgp.AppendMapHeader(o, uint32(len(z.Props))) - for za0001, za0002 := range z.Props { - o = msgp.AppendString(o, za0001) - o = msgp.AppendString(o, za0002) - } - o = msgp.AppendArrayHeader(o, uint32(len(z.TeamMembers))) - for za0003 := range z.TeamMembers { - if z.TeamMembers[za0003] == nil { - o = msgp.AppendNil(o) - } else { - o, err = z.TeamMembers[za0003].MarshalMsg(o) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - o = msgp.AppendBool(o, z.Local) - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *Session) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0001 uint32 - zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 13 { - err = msgp.ArrayError{Wanted: 13, Got: zb0001} - return - } - z.Id, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.Token, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Token") - return - } - z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.ExpiresAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "ExpiresAt") - return - } - z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.UserId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - z.DeviceId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "DeviceId") - return - } - z.Roles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.IsOAuth, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "IsOAuth") - return - } - z.ExpiredNotify, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "ExpiredNotify") - return - } - var zb0002 uint32 - zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - if z.Props == nil { - z.Props = make(StringMap, zb0002) - } else if len(z.Props) > 0 { - for key := range z.Props { - delete(z.Props, key) - } - } - for zb0002 > 0 { - var za0001 string - var za0002 string - zb0002-- - za0001, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - za0002, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - z.Props[za0001] = za0002 - } - var zb0003 uint32 - zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err, "TeamMembers") - return - } - if cap(z.TeamMembers) >= int(zb0003) { - z.TeamMembers = (z.TeamMembers)[:zb0003] - } else { - z.TeamMembers = make([]*TeamMember, zb0003) - } - for za0003 := range z.TeamMembers { - if msgp.IsNil(bts) { - bts, err = msgp.ReadNilBytes(bts) - if err != nil { - return - } - z.TeamMembers[za0003] = nil - } else { - if z.TeamMembers[za0003] == nil { - z.TeamMembers[za0003] = new(TeamMember) - } - bts, err = z.TeamMembers[za0003].UnmarshalMsg(bts) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - z.Local, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Local") - return - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z *Session) Msgsize() (s int) { - s = 1 + msgp.StringPrefixSize + len(z.Id) + msgp.StringPrefixSize + len(z.Token) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.UserId) + msgp.StringPrefixSize + len(z.DeviceId) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + msgp.BoolSize + msgp.MapHeaderSize - if z.Props != nil { - for za0001, za0002 := range z.Props { - _ = za0002 - s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) - } - } - s += msgp.ArrayHeaderSize - for za0003 := range z.TeamMembers { - if z.TeamMembers[za0003] == nil { - s += msgp.NilSize - } else { - s += z.TeamMembers[za0003].Msgsize() - } - } - s += msgp.BoolSize - return -} - -// DecodeMsg implements msgp.Decodable -func (z *StringMap) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0003 uint32 - zb0003, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(StringMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - zb0003-- - var zb0001 string - var zb0002 string - zb0001, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err) - return - } - zb0002, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - (*z)[zb0001] = zb0002 - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z StringMap) EncodeMsg(en *msgp.Writer) (err error) { - err = en.WriteMapHeader(uint32(len(z))) - if err != nil { - err = msgp.WrapError(err) - return - } - for zb0004, zb0005 := range z { - err = en.WriteString(zb0004) - if err != nil { - err = msgp.WrapError(err) - return - } - err = en.WriteString(zb0005) - if err != nil { - err = msgp.WrapError(err, zb0004) - return - } - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z StringMap) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - o = msgp.AppendMapHeader(o, uint32(len(z))) - for zb0004, zb0005 := range z { - o = msgp.AppendString(o, zb0004) - o = msgp.AppendString(o, zb0005) - } - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *StringMap) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0003 uint32 - zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(StringMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - var zb0001 string - var zb0002 string - zb0003-- - zb0001, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - zb0002, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - (*z)[zb0001] = zb0002 - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z StringMap) Msgsize() (s int) { - s = msgp.MapHeaderSize - if z != nil { - for zb0004, zb0005 := range z { - _ = zb0005 - s += msgp.StringPrefixSize + len(zb0004) + msgp.StringPrefixSize + len(zb0005) - } - } - return -} - -// DecodeMsg implements msgp.Decodable -func (z *TeamMember) DecodeMsg(dc *msgp.Reader) (err error) { - var field []byte - _ = field - var zb0001 uint32 - zb0001, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - for zb0001 > 0 { - zb0001-- - field, err = dc.ReadMapKeyPtr() - if err != nil { - err = msgp.WrapError(err) - return - } - switch msgp.UnsafeString(field) { - case "TeamId": - z.TeamId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "TeamId") - return - } - case "UserId": - z.UserId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - case "Roles": - z.Roles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - case "DeleteAt": - z.DeleteAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - case "SchemeGuest": - z.SchemeGuest, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "SchemeGuest") - return - } - case "SchemeUser": - z.SchemeUser, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "SchemeUser") - return - } - case "SchemeAdmin": - z.SchemeAdmin, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "SchemeAdmin") - return - } - case "ExplicitRoles": - z.ExplicitRoles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "ExplicitRoles") - return - } - default: - err = dc.Skip() - if err != nil { - err = msgp.WrapError(err) - return - } - } - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z *TeamMember) EncodeMsg(en *msgp.Writer) (err error) { - // map header, size 8 - // write "TeamId" - err = en.Append(0x88, 0xa6, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64) - if err != nil { - return - } - err = en.WriteString(z.TeamId) - if err != nil { - err = msgp.WrapError(err, "TeamId") - return - } - // write "UserId" - err = en.Append(0xa6, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64) - if err != nil { - return - } - err = en.WriteString(z.UserId) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - // write "Roles" - err = en.Append(0xa5, 0x52, 0x6f, 0x6c, 0x65, 0x73) - if err != nil { - return - } - err = en.WriteString(z.Roles) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - // write "DeleteAt" - err = en.Append(0xa8, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x74) - if err != nil { - return - } - err = en.WriteInt64(z.DeleteAt) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - // write "SchemeGuest" - err = en.Append(0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x47, 0x75, 0x65, 0x73, 0x74) - if err != nil { - return - } - err = en.WriteBool(z.SchemeGuest) - if err != nil { - err = msgp.WrapError(err, "SchemeGuest") - return - } - // write "SchemeUser" - err = en.Append(0xaa, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72) - if err != nil { - return - } - err = en.WriteBool(z.SchemeUser) - if err != nil { - err = msgp.WrapError(err, "SchemeUser") - return - } - // write "SchemeAdmin" - err = en.Append(0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e) - if err != nil { - return - } - err = en.WriteBool(z.SchemeAdmin) - if err != nil { - err = msgp.WrapError(err, "SchemeAdmin") - return - } - // write "ExplicitRoles" - err = en.Append(0xad, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73) - if err != nil { - return - } - err = en.WriteString(z.ExplicitRoles) - if err != nil { - err = msgp.WrapError(err, "ExplicitRoles") - return - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z *TeamMember) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - // map header, size 8 - // string "TeamId" - o = append(o, 0x88, 0xa6, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64) - o = msgp.AppendString(o, z.TeamId) - // string "UserId" - o = append(o, 0xa6, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64) - o = msgp.AppendString(o, z.UserId) - // string "Roles" - o = append(o, 0xa5, 0x52, 0x6f, 0x6c, 0x65, 0x73) - o = msgp.AppendString(o, z.Roles) - // string "DeleteAt" - o = append(o, 0xa8, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x74) - o = msgp.AppendInt64(o, z.DeleteAt) - // string "SchemeGuest" - o = append(o, 0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x47, 0x75, 0x65, 0x73, 0x74) - o = msgp.AppendBool(o, z.SchemeGuest) - // string "SchemeUser" - o = append(o, 0xaa, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x72) - o = msgp.AppendBool(o, z.SchemeUser) - // string "SchemeAdmin" - o = append(o, 0xab, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x41, 0x64, 0x6d, 0x69, 0x6e) - o = msgp.AppendBool(o, z.SchemeAdmin) - // string "ExplicitRoles" - o = append(o, 0xad, 0x45, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73) - o = msgp.AppendString(o, z.ExplicitRoles) - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *TeamMember) UnmarshalMsg(bts []byte) (o []byte, err error) { - var field []byte - _ = field - var zb0001 uint32 - zb0001, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - for zb0001 > 0 { - zb0001-- - field, bts, err = msgp.ReadMapKeyZC(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - switch msgp.UnsafeString(field) { - case "TeamId": - z.TeamId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "TeamId") - return - } - case "UserId": - z.UserId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - case "Roles": - z.Roles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - case "DeleteAt": - z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - case "SchemeGuest": - z.SchemeGuest, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "SchemeGuest") - return - } - case "SchemeUser": - z.SchemeUser, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "SchemeUser") - return - } - case "SchemeAdmin": - z.SchemeAdmin, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "SchemeAdmin") - return - } - case "ExplicitRoles": - z.ExplicitRoles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "ExplicitRoles") - return - } - default: - bts, err = msgp.Skip(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - } - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z *TeamMember) Msgsize() (s int) { - s = 1 + 7 + msgp.StringPrefixSize + len(z.TeamId) + 7 + msgp.StringPrefixSize + len(z.UserId) + 6 + msgp.StringPrefixSize + len(z.Roles) + 9 + msgp.Int64Size + 12 + msgp.BoolSize + 11 + msgp.BoolSize + 12 + msgp.BoolSize + 14 + msgp.StringPrefixSize + len(z.ExplicitRoles) - return -} - -// DecodeMsg implements msgp.Decodable -func (z *User) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0001 uint32 - zb0001, err = dc.ReadArrayHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 31 { - err = msgp.ArrayError{Wanted: 31, Got: zb0001} - return - } - z.Id, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.CreateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.UpdateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "UpdateAt") - return - } - z.DeleteAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - z.Username, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Username") - return - } - z.Password, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Password") - return - } - if dc.IsNil() { - err = dc.ReadNil() - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - z.AuthData = nil - } else { - if z.AuthData == nil { - z.AuthData = new(string) - } - *z.AuthData, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - } - z.AuthService, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "AuthService") - return - } - z.Email, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Email") - return - } - z.EmailVerified, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "EmailVerified") - return - } - z.Nickname, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Nickname") - return - } - z.FirstName, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "FirstName") - return - } - z.LastName, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "LastName") - return - } - z.Position, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Position") - return - } - z.Roles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.AllowMarketing, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "AllowMarketing") - return - } - var zb0002 uint32 - zb0002, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - if z.Props == nil { - z.Props = make(StringMap, zb0002) - } else if len(z.Props) > 0 { - for key := range z.Props { - delete(z.Props, key) - } - } - for zb0002 > 0 { - zb0002-- - var za0001 string - var za0002 string - za0001, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - za0002, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - z.Props[za0001] = za0002 - } - var zb0003 uint32 - zb0003, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - if z.NotifyProps == nil { - z.NotifyProps = make(StringMap, zb0003) - } else if len(z.NotifyProps) > 0 { - for key := range z.NotifyProps { - delete(z.NotifyProps, key) - } - } - for zb0003 > 0 { - zb0003-- - var za0003 string - var za0004 string - za0003, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - za0004, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "NotifyProps", za0003) - return - } - z.NotifyProps[za0003] = za0004 - } - z.LastPasswordUpdate, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastPasswordUpdate") - return - } - z.LastPictureUpdate, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastPictureUpdate") - return - } - z.FailedAttempts, err = dc.ReadInt() - if err != nil { - err = msgp.WrapError(err, "FailedAttempts") - return - } - z.Locale, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Locale") - return - } - var zb0004 uint32 - zb0004, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - if z.Timezone == nil { - z.Timezone = make(StringMap, zb0004) - } else if len(z.Timezone) > 0 { - for key := range z.Timezone { - delete(z.Timezone, key) - } - } - for zb0004 > 0 { - zb0004-- - var za0005 string - var za0006 string - za0005, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - za0006, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Timezone", za0005) - return - } - z.Timezone[za0005] = za0006 - } - z.MfaActive, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "MfaActive") - return - } - z.MfaSecret, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "MfaSecret") - return - } - z.LastActivityAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.IsBot, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "IsBot") - return - } - z.BotDescription, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "BotDescription") - return - } - z.BotLastIconUpdate, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "BotLastIconUpdate") - return - } - z.TermsOfServiceId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceId") - return - } - z.TermsOfServiceCreateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceCreateAt") - return - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z *User) EncodeMsg(en *msgp.Writer) (err error) { - // array header, size 31 - err = en.Append(0xdc, 0x0, 0x1f) - if err != nil { - return - } - err = en.WriteString(z.Id) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - err = en.WriteInt64(z.CreateAt) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - err = en.WriteInt64(z.UpdateAt) - if err != nil { - err = msgp.WrapError(err, "UpdateAt") - return - } - err = en.WriteInt64(z.DeleteAt) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - err = en.WriteString(z.Username) - if err != nil { - err = msgp.WrapError(err, "Username") - return - } - err = en.WriteString(z.Password) - if err != nil { - err = msgp.WrapError(err, "Password") - return - } - if z.AuthData == nil { - err = en.WriteNil() - if err != nil { - return - } - } else { - err = en.WriteString(*z.AuthData) - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - } - err = en.WriteString(z.AuthService) - if err != nil { - err = msgp.WrapError(err, "AuthService") - return - } - err = en.WriteString(z.Email) - if err != nil { - err = msgp.WrapError(err, "Email") - return - } - err = en.WriteBool(z.EmailVerified) - if err != nil { - err = msgp.WrapError(err, "EmailVerified") - return - } - err = en.WriteString(z.Nickname) - if err != nil { - err = msgp.WrapError(err, "Nickname") - return - } - err = en.WriteString(z.FirstName) - if err != nil { - err = msgp.WrapError(err, "FirstName") - return - } - err = en.WriteString(z.LastName) - if err != nil { - err = msgp.WrapError(err, "LastName") - return - } - err = en.WriteString(z.Position) - if err != nil { - err = msgp.WrapError(err, "Position") - return - } - err = en.WriteString(z.Roles) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - err = en.WriteBool(z.AllowMarketing) - if err != nil { - err = msgp.WrapError(err, "AllowMarketing") - return - } - err = en.WriteMapHeader(uint32(len(z.Props))) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - for za0001, za0002 := range z.Props { - err = en.WriteString(za0001) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - err = en.WriteString(za0002) - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - } - err = en.WriteMapHeader(uint32(len(z.NotifyProps))) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - for za0003, za0004 := range z.NotifyProps { - err = en.WriteString(za0003) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - err = en.WriteString(za0004) - if err != nil { - err = msgp.WrapError(err, "NotifyProps", za0003) - return - } - } - err = en.WriteInt64(z.LastPasswordUpdate) - if err != nil { - err = msgp.WrapError(err, "LastPasswordUpdate") - return - } - err = en.WriteInt64(z.LastPictureUpdate) - if err != nil { - err = msgp.WrapError(err, "LastPictureUpdate") - return - } - err = en.WriteInt(z.FailedAttempts) - if err != nil { - err = msgp.WrapError(err, "FailedAttempts") - return - } - err = en.WriteString(z.Locale) - if err != nil { - err = msgp.WrapError(err, "Locale") - return - } - err = en.WriteMapHeader(uint32(len(z.Timezone))) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - for za0005, za0006 := range z.Timezone { - err = en.WriteString(za0005) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - err = en.WriteString(za0006) - if err != nil { - err = msgp.WrapError(err, "Timezone", za0005) - return - } - } - err = en.WriteBool(z.MfaActive) - if err != nil { - err = msgp.WrapError(err, "MfaActive") - return - } - err = en.WriteString(z.MfaSecret) - if err != nil { - err = msgp.WrapError(err, "MfaSecret") - return - } - err = en.WriteInt64(z.LastActivityAt) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - err = en.WriteBool(z.IsBot) - if err != nil { - err = msgp.WrapError(err, "IsBot") - return - } - err = en.WriteString(z.BotDescription) - if err != nil { - err = msgp.WrapError(err, "BotDescription") - return - } - err = en.WriteInt64(z.BotLastIconUpdate) - if err != nil { - err = msgp.WrapError(err, "BotLastIconUpdate") - return - } - err = en.WriteString(z.TermsOfServiceId) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceId") - return - } - err = en.WriteInt64(z.TermsOfServiceCreateAt) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceCreateAt") - return - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z *User) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - // array header, size 31 - o = append(o, 0xdc, 0x0, 0x1f) - o = msgp.AppendString(o, z.Id) - o = msgp.AppendInt64(o, z.CreateAt) - o = msgp.AppendInt64(o, z.UpdateAt) - o = msgp.AppendInt64(o, z.DeleteAt) - o = msgp.AppendString(o, z.Username) - o = msgp.AppendString(o, z.Password) - if z.AuthData == nil { - o = msgp.AppendNil(o) - } else { - o = msgp.AppendString(o, *z.AuthData) - } - o = msgp.AppendString(o, z.AuthService) - o = msgp.AppendString(o, z.Email) - o = msgp.AppendBool(o, z.EmailVerified) - o = msgp.AppendString(o, z.Nickname) - o = msgp.AppendString(o, z.FirstName) - o = msgp.AppendString(o, z.LastName) - o = msgp.AppendString(o, z.Position) - o = msgp.AppendString(o, z.Roles) - o = msgp.AppendBool(o, z.AllowMarketing) - o = msgp.AppendMapHeader(o, uint32(len(z.Props))) - for za0001, za0002 := range z.Props { - o = msgp.AppendString(o, za0001) - o = msgp.AppendString(o, za0002) - } - o = msgp.AppendMapHeader(o, uint32(len(z.NotifyProps))) - for za0003, za0004 := range z.NotifyProps { - o = msgp.AppendString(o, za0003) - o = msgp.AppendString(o, za0004) - } - o = msgp.AppendInt64(o, z.LastPasswordUpdate) - o = msgp.AppendInt64(o, z.LastPictureUpdate) - o = msgp.AppendInt(o, z.FailedAttempts) - o = msgp.AppendString(o, z.Locale) - o = msgp.AppendMapHeader(o, uint32(len(z.Timezone))) - for za0005, za0006 := range z.Timezone { - o = msgp.AppendString(o, za0005) - o = msgp.AppendString(o, za0006) - } - o = msgp.AppendBool(o, z.MfaActive) - o = msgp.AppendString(o, z.MfaSecret) - o = msgp.AppendInt64(o, z.LastActivityAt) - o = msgp.AppendBool(o, z.IsBot) - o = msgp.AppendString(o, z.BotDescription) - o = msgp.AppendInt64(o, z.BotLastIconUpdate) - o = msgp.AppendString(o, z.TermsOfServiceId) - o = msgp.AppendInt64(o, z.TermsOfServiceCreateAt) - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *User) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0001 uint32 - zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 31 { - err = msgp.ArrayError{Wanted: 31, Got: zb0001} - return - } - z.Id, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.UpdateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "UpdateAt") - return - } - z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - z.Username, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Username") - return - } - z.Password, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Password") - return - } - if msgp.IsNil(bts) { - bts, err = msgp.ReadNilBytes(bts) - if err != nil { - return - } - z.AuthData = nil - } else { - if z.AuthData == nil { - z.AuthData = new(string) - } - *z.AuthData, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - } - z.AuthService, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "AuthService") - return - } - z.Email, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Email") - return - } - z.EmailVerified, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "EmailVerified") - return - } - z.Nickname, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Nickname") - return - } - z.FirstName, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "FirstName") - return - } - z.LastName, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastName") - return - } - z.Position, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Position") - return - } - z.Roles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.AllowMarketing, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "AllowMarketing") - return - } - var zb0002 uint32 - zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - if z.Props == nil { - z.Props = make(StringMap, zb0002) - } else if len(z.Props) > 0 { - for key := range z.Props { - delete(z.Props, key) - } - } - for zb0002 > 0 { - var za0001 string - var za0002 string - zb0002-- - za0001, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - za0002, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - z.Props[za0001] = za0002 - } - var zb0003 uint32 - zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - if z.NotifyProps == nil { - z.NotifyProps = make(StringMap, zb0003) - } else if len(z.NotifyProps) > 0 { - for key := range z.NotifyProps { - delete(z.NotifyProps, key) - } - } - for zb0003 > 0 { - var za0003 string - var za0004 string - zb0003-- - za0003, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - za0004, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "NotifyProps", za0003) - return - } - z.NotifyProps[za0003] = za0004 - } - z.LastPasswordUpdate, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastPasswordUpdate") - return - } - z.LastPictureUpdate, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastPictureUpdate") - return - } - z.FailedAttempts, bts, err = msgp.ReadIntBytes(bts) - if err != nil { - err = msgp.WrapError(err, "FailedAttempts") - return - } - z.Locale, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Locale") - return - } - var zb0004 uint32 - zb0004, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - if z.Timezone == nil { - z.Timezone = make(StringMap, zb0004) - } else if len(z.Timezone) > 0 { - for key := range z.Timezone { - delete(z.Timezone, key) - } - } - for zb0004 > 0 { - var za0005 string - var za0006 string - zb0004-- - za0005, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - za0006, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Timezone", za0005) - return - } - z.Timezone[za0005] = za0006 - } - z.MfaActive, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "MfaActive") - return - } - z.MfaSecret, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "MfaSecret") - return - } - z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.IsBot, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "IsBot") - return - } - z.BotDescription, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "BotDescription") - return - } - z.BotLastIconUpdate, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "BotLastIconUpdate") - return - } - z.TermsOfServiceId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceId") - return - } - z.TermsOfServiceCreateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceCreateAt") - return - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z *User) Msgsize() (s int) { - s = 3 + msgp.StringPrefixSize + len(z.Id) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.Username) + msgp.StringPrefixSize + len(z.Password) - if z.AuthData == nil { - s += msgp.NilSize - } else { - s += msgp.StringPrefixSize + len(*z.AuthData) - } - s += msgp.StringPrefixSize + len(z.AuthService) + msgp.StringPrefixSize + len(z.Email) + msgp.BoolSize + msgp.StringPrefixSize + len(z.Nickname) + msgp.StringPrefixSize + len(z.FirstName) + msgp.StringPrefixSize + len(z.LastName) + msgp.StringPrefixSize + len(z.Position) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + msgp.MapHeaderSize - if z.Props != nil { - for za0001, za0002 := range z.Props { - _ = za0002 - s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) - } - } - s += msgp.MapHeaderSize - if z.NotifyProps != nil { - for za0003, za0004 := range z.NotifyProps { - _ = za0004 - s += msgp.StringPrefixSize + len(za0003) + msgp.StringPrefixSize + len(za0004) - } - } - s += msgp.Int64Size + msgp.Int64Size + msgp.IntSize + msgp.StringPrefixSize + len(z.Locale) + msgp.MapHeaderSize - if z.Timezone != nil { - for za0005, za0006 := range z.Timezone { - _ = za0006 - s += msgp.StringPrefixSize + len(za0005) + msgp.StringPrefixSize + len(za0006) - } - } - s += msgp.BoolSize + msgp.StringPrefixSize + len(z.MfaSecret) + msgp.Int64Size + msgp.BoolSize + msgp.StringPrefixSize + len(z.BotDescription) + msgp.Int64Size + msgp.StringPrefixSize + len(z.TermsOfServiceId) + msgp.Int64Size - return -} - -// DecodeMsg implements msgp.Decodable -func (z *UserMap) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0003 uint32 - zb0003, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(UserMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - zb0003-- - var zb0001 string - var zb0002 *User - zb0001, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err) - return - } - if dc.IsNil() { - err = dc.ReadNil() - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - zb0002 = nil - } else { - if zb0002 == nil { - zb0002 = new(User) - } - err = zb0002.DecodeMsg(dc) - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - } - (*z)[zb0001] = zb0002 - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z UserMap) EncodeMsg(en *msgp.Writer) (err error) { - err = en.WriteMapHeader(uint32(len(z))) - if err != nil { - err = msgp.WrapError(err) - return - } - for zb0004, zb0005 := range z { - err = en.WriteString(zb0004) - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0005 == nil { - err = en.WriteNil() - if err != nil { - return - } - } else { - err = zb0005.EncodeMsg(en) - if err != nil { - err = msgp.WrapError(err, zb0004) - return - } - } - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z UserMap) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - o = msgp.AppendMapHeader(o, uint32(len(z))) - for zb0004, zb0005 := range z { - o = msgp.AppendString(o, zb0004) - if zb0005 == nil { - o = msgp.AppendNil(o) - } else { - o, err = zb0005.MarshalMsg(o) - if err != nil { - err = msgp.WrapError(err, zb0004) - return - } - } - } - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *UserMap) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0003 uint32 - zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(UserMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - var zb0001 string - var zb0002 *User - zb0003-- - zb0001, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if msgp.IsNil(bts) { - bts, err = msgp.ReadNilBytes(bts) - if err != nil { - return - } - zb0002 = nil - } else { - if zb0002 == nil { - zb0002 = new(User) - } - bts, err = zb0002.UnmarshalMsg(bts) - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - } - (*z)[zb0001] = zb0002 - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z UserMap) Msgsize() (s int) { - s = msgp.MapHeaderSize - if z != nil { - for zb0004, zb0005 := range z { - _ = zb0005 - s += msgp.StringPrefixSize + len(zb0004) - if zb0005 == nil { - s += msgp.NilSize - } else { - s += zb0005.Msgsize() - } - } - } - return -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/session.go b/vendor/github.com/mattermost/mattermost-server/v5/model/session.go index 976e1229..334c7175 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/session.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/session.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - "github.com/mattermost/mattermost-server/v5/mlog" + "github.com/mattermost/mattermost-server/v5/shared/mlog" ) const ( @@ -25,11 +25,16 @@ const ( SESSION_PROP_IS_BOT = "is_bot" SESSION_PROP_IS_BOT_VALUE = "true" SESSION_TYPE_USER_ACCESS_TOKEN = "UserAccessToken" + SESSION_TYPE_CLOUD_KEY = "CloudKey" + SESSION_TYPE_REMOTECLUSTER_TOKEN = "RemoteClusterToken" SESSION_PROP_IS_GUEST = "is_guest" SESSION_ACTIVITY_TIMEOUT = 1000 * 60 * 5 // 5 minutes SESSION_USER_ACCESS_TOKEN_EXPIRY = 100 * 365 // 100 years ) +//msgp StringMap +type StringMap map[string]string + //msgp:tuple Session // Session contains the user session details. @@ -53,20 +58,20 @@ type Session struct { // Returns true if the session is unrestricted, which should grant it // with all permissions. This is used for local mode sessions -func (me *Session) IsUnrestricted() bool { - return me.Local +func (s *Session) IsUnrestricted() bool { + return s.Local } -func (me *Session) DeepCopy() *Session { - copySession := *me +func (s *Session) DeepCopy() *Session { + copySession := *s - if me.Props != nil { - copySession.Props = CopyStringMap(me.Props) + if s.Props != nil { + copySession.Props = CopyStringMap(s.Props) } - if me.TeamMembers != nil { - copySession.TeamMembers = make([]*TeamMember, len(me.TeamMembers)) - for index, tm := range me.TeamMembers { + if s.TeamMembers != nil { + copySession.TeamMembers = make([]*TeamMember, len(s.TeamMembers)) + for index, tm := range s.TeamMembers { copySession.TeamMembers[index] = new(TeamMember) *copySession.TeamMembers[index] = *tm } @@ -75,45 +80,45 @@ func (me *Session) DeepCopy() *Session { return ©Session } -func (me *Session) ToJson() string { - b, _ := json.Marshal(me) +func (s *Session) ToJson() string { + b, _ := json.Marshal(s) return string(b) } func SessionFromJson(data io.Reader) *Session { - var me *Session - json.NewDecoder(data).Decode(&me) - return me + var s *Session + json.NewDecoder(data).Decode(&s) + return s } -func (me *Session) PreSave() { - if me.Id == "" { - me.Id = NewId() +func (s *Session) PreSave() { + if s.Id == "" { + s.Id = NewId() } - if me.Token == "" { - me.Token = NewId() + if s.Token == "" { + s.Token = NewId() } - me.CreateAt = GetMillis() - me.LastActivityAt = me.CreateAt + s.CreateAt = GetMillis() + s.LastActivityAt = s.CreateAt - if me.Props == nil { - me.Props = make(map[string]string) + if s.Props == nil { + s.Props = make(map[string]string) } } -func (me *Session) Sanitize() { - me.Token = "" +func (s *Session) Sanitize() { + s.Token = "" } -func (me *Session) IsExpired() bool { +func (s *Session) IsExpired() bool { - if me.ExpiresAt <= 0 { + if s.ExpiresAt <= 0 { return false } - if GetMillis() > me.ExpiresAt { + if GetMillis() > s.ExpiresAt { return true } @@ -123,25 +128,25 @@ func (me *Session) IsExpired() bool { // Deprecated: SetExpireInDays is deprecated and should not be used. // Use (*App).SetSessionExpireInDays instead which handles the // cases where the new ExpiresAt is not relative to CreateAt. -func (me *Session) SetExpireInDays(days int) { - if me.CreateAt == 0 { - me.ExpiresAt = GetMillis() + (1000 * 60 * 60 * 24 * int64(days)) +func (s *Session) SetExpireInDays(days int) { + if s.CreateAt == 0 { + s.ExpiresAt = GetMillis() + (1000 * 60 * 60 * 24 * int64(days)) } else { - me.ExpiresAt = me.CreateAt + (1000 * 60 * 60 * 24 * int64(days)) + s.ExpiresAt = s.CreateAt + (1000 * 60 * 60 * 24 * int64(days)) } } -func (me *Session) AddProp(key string, value string) { +func (s *Session) AddProp(key string, value string) { - if me.Props == nil { - me.Props = make(map[string]string) + if s.Props == nil { + s.Props = make(map[string]string) } - me.Props[key] = value + s.Props[key] = value } -func (me *Session) GetTeamByTeamId(teamId string) *TeamMember { - for _, team := range me.TeamMembers { +func (s *Session) GetTeamByTeamId(teamId string) *TeamMember { + for _, team := range s.TeamMembers { if team.TeamId == teamId { return team } @@ -150,77 +155,77 @@ func (me *Session) GetTeamByTeamId(teamId string) *TeamMember { return nil } -func (me *Session) IsMobileApp() bool { - return len(me.DeviceId) > 0 || me.IsMobile() +func (s *Session) IsMobileApp() bool { + return s.DeviceId != "" || s.IsMobile() } -func (me *Session) IsMobile() bool { - val, ok := me.Props[USER_AUTH_SERVICE_IS_MOBILE] +func (s *Session) IsMobile() bool { + val, ok := s.Props[USER_AUTH_SERVICE_IS_MOBILE] if !ok { return false } isMobile, err := strconv.ParseBool(val) if err != nil { - mlog.Error("Error parsing boolean property from Session", mlog.Err(err)) + mlog.Debug("Error parsing boolean property from Session", mlog.Err(err)) return false } return isMobile } -func (me *Session) IsSaml() bool { - val, ok := me.Props[USER_AUTH_SERVICE_IS_SAML] +func (s *Session) IsSaml() bool { + val, ok := s.Props[USER_AUTH_SERVICE_IS_SAML] if !ok { return false } isSaml, err := strconv.ParseBool(val) if err != nil { - mlog.Error("Error parsing boolean property from Session", mlog.Err(err)) + mlog.Debug("Error parsing boolean property from Session", mlog.Err(err)) return false } return isSaml } -func (me *Session) IsOAuthUser() bool { - val, ok := me.Props[USER_AUTH_SERVICE_IS_OAUTH] +func (s *Session) IsOAuthUser() bool { + val, ok := s.Props[USER_AUTH_SERVICE_IS_OAUTH] if !ok { return false } isOAuthUser, err := strconv.ParseBool(val) if err != nil { - mlog.Error("Error parsing boolean property from Session", mlog.Err(err)) + mlog.Debug("Error parsing boolean property from Session", mlog.Err(err)) return false } return isOAuthUser } -func (me *Session) IsSSOLogin() bool { - return me.IsOAuthUser() || me.IsSaml() +func (s *Session) IsSSOLogin() bool { + return s.IsOAuthUser() || s.IsSaml() } -func (me *Session) GetUserRoles() []string { - return strings.Fields(me.Roles) +func (s *Session) GetUserRoles() []string { + return strings.Fields(s.Roles) } -func (me *Session) GenerateCSRF() string { +func (s *Session) GenerateCSRF() string { token := NewId() - me.AddProp("csrf", token) + s.AddProp("csrf", token) return token } -func (me *Session) GetCSRF() string { - if me.Props == nil { +func (s *Session) GetCSRF() string { + if s.Props == nil { return "" } - return me.Props["csrf"] + return s.Props["csrf"] } func SessionsToJson(o []*Session) string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func SessionsFromJson(data io.Reader) []*Session { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/session_serial_gen.go b/vendor/github.com/mattermost/mattermost-server/v5/model/session_serial_gen.go new file mode 100644 index 00000000..612bbb89 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/session_serial_gen.go @@ -0,0 +1,540 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "github.com/tinylib/msgp/msgp" +) + +// DecodeMsg implements msgp.Decodable +func (z *Session) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0001 uint32 + zb0001, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 13 { + err = msgp.ArrayError{Wanted: 13, Got: zb0001} + return + } + z.Id, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.Token, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Token") + return + } + z.CreateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.ExpiresAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "ExpiresAt") + return + } + z.LastActivityAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.UserId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + z.DeviceId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "DeviceId") + return + } + z.Roles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.IsOAuth, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "IsOAuth") + return + } + z.ExpiredNotify, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "ExpiredNotify") + return + } + var zb0002 uint32 + zb0002, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + if z.Props == nil { + z.Props = make(StringMap, zb0002) + } else if len(z.Props) > 0 { + for key := range z.Props { + delete(z.Props, key) + } + } + for zb0002 > 0 { + zb0002-- + var za0001 string + var za0002 string + za0001, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + za0002, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + z.Props[za0001] = za0002 + } + var zb0003 uint32 + zb0003, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err, "TeamMembers") + return + } + if cap(z.TeamMembers) >= int(zb0003) { + z.TeamMembers = (z.TeamMembers)[:zb0003] + } else { + z.TeamMembers = make([]*TeamMember, zb0003) + } + for za0003 := range z.TeamMembers { + if dc.IsNil() { + err = dc.ReadNil() + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + z.TeamMembers[za0003] = nil + } else { + if z.TeamMembers[za0003] == nil { + z.TeamMembers[za0003] = new(TeamMember) + } + err = z.TeamMembers[za0003].DecodeMsg(dc) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + z.Local, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "Local") + return + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *Session) EncodeMsg(en *msgp.Writer) (err error) { + // array header, size 13 + err = en.Append(0x9d) + if err != nil { + return + } + err = en.WriteString(z.Id) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + err = en.WriteString(z.Token) + if err != nil { + err = msgp.WrapError(err, "Token") + return + } + err = en.WriteInt64(z.CreateAt) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + err = en.WriteInt64(z.ExpiresAt) + if err != nil { + err = msgp.WrapError(err, "ExpiresAt") + return + } + err = en.WriteInt64(z.LastActivityAt) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + err = en.WriteString(z.UserId) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + err = en.WriteString(z.DeviceId) + if err != nil { + err = msgp.WrapError(err, "DeviceId") + return + } + err = en.WriteString(z.Roles) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + err = en.WriteBool(z.IsOAuth) + if err != nil { + err = msgp.WrapError(err, "IsOAuth") + return + } + err = en.WriteBool(z.ExpiredNotify) + if err != nil { + err = msgp.WrapError(err, "ExpiredNotify") + return + } + err = en.WriteMapHeader(uint32(len(z.Props))) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + for za0001, za0002 := range z.Props { + err = en.WriteString(za0001) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + err = en.WriteString(za0002) + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + } + err = en.WriteArrayHeader(uint32(len(z.TeamMembers))) + if err != nil { + err = msgp.WrapError(err, "TeamMembers") + return + } + for za0003 := range z.TeamMembers { + if z.TeamMembers[za0003] == nil { + err = en.WriteNil() + if err != nil { + return + } + } else { + err = z.TeamMembers[za0003].EncodeMsg(en) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + err = en.WriteBool(z.Local) + if err != nil { + err = msgp.WrapError(err, "Local") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *Session) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // array header, size 13 + o = append(o, 0x9d) + o = msgp.AppendString(o, z.Id) + o = msgp.AppendString(o, z.Token) + o = msgp.AppendInt64(o, z.CreateAt) + o = msgp.AppendInt64(o, z.ExpiresAt) + o = msgp.AppendInt64(o, z.LastActivityAt) + o = msgp.AppendString(o, z.UserId) + o = msgp.AppendString(o, z.DeviceId) + o = msgp.AppendString(o, z.Roles) + o = msgp.AppendBool(o, z.IsOAuth) + o = msgp.AppendBool(o, z.ExpiredNotify) + o = msgp.AppendMapHeader(o, uint32(len(z.Props))) + for za0001, za0002 := range z.Props { + o = msgp.AppendString(o, za0001) + o = msgp.AppendString(o, za0002) + } + o = msgp.AppendArrayHeader(o, uint32(len(z.TeamMembers))) + for za0003 := range z.TeamMembers { + if z.TeamMembers[za0003] == nil { + o = msgp.AppendNil(o) + } else { + o, err = z.TeamMembers[za0003].MarshalMsg(o) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + o = msgp.AppendBool(o, z.Local) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *Session) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0001 uint32 + zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 13 { + err = msgp.ArrayError{Wanted: 13, Got: zb0001} + return + } + z.Id, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.Token, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Token") + return + } + z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.ExpiresAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "ExpiresAt") + return + } + z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.UserId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + z.DeviceId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "DeviceId") + return + } + z.Roles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.IsOAuth, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "IsOAuth") + return + } + z.ExpiredNotify, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "ExpiredNotify") + return + } + var zb0002 uint32 + zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + if z.Props == nil { + z.Props = make(StringMap, zb0002) + } else if len(z.Props) > 0 { + for key := range z.Props { + delete(z.Props, key) + } + } + for zb0002 > 0 { + var za0001 string + var za0002 string + zb0002-- + za0001, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + za0002, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Props", za0001) + return + } + z.Props[za0001] = za0002 + } + var zb0003 uint32 + zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TeamMembers") + return + } + if cap(z.TeamMembers) >= int(zb0003) { + z.TeamMembers = (z.TeamMembers)[:zb0003] + } else { + z.TeamMembers = make([]*TeamMember, zb0003) + } + for za0003 := range z.TeamMembers { + if msgp.IsNil(bts) { + bts, err = msgp.ReadNilBytes(bts) + if err != nil { + return + } + z.TeamMembers[za0003] = nil + } else { + if z.TeamMembers[za0003] == nil { + z.TeamMembers[za0003] = new(TeamMember) + } + bts, err = z.TeamMembers[za0003].UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "TeamMembers", za0003) + return + } + } + } + z.Local, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Local") + return + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *Session) Msgsize() (s int) { + s = 1 + msgp.StringPrefixSize + len(z.Id) + msgp.StringPrefixSize + len(z.Token) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.UserId) + msgp.StringPrefixSize + len(z.DeviceId) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + msgp.BoolSize + msgp.MapHeaderSize + if z.Props != nil { + for za0001, za0002 := range z.Props { + _ = za0002 + s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) + } + } + s += msgp.ArrayHeaderSize + for za0003 := range z.TeamMembers { + if z.TeamMembers[za0003] == nil { + s += msgp.NilSize + } else { + s += z.TeamMembers[za0003].Msgsize() + } + } + s += msgp.BoolSize + return +} + +// DecodeMsg implements msgp.Decodable +func (z *StringMap) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0003 uint32 + zb0003, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if (*z) == nil { + (*z) = make(StringMap, zb0003) + } else if len((*z)) > 0 { + for key := range *z { + delete((*z), key) + } + } + for zb0003 > 0 { + zb0003-- + var zb0001 string + var zb0002 string + zb0001, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err) + return + } + zb0002, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, zb0001) + return + } + (*z)[zb0001] = zb0002 + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z StringMap) EncodeMsg(en *msgp.Writer) (err error) { + err = en.WriteMapHeader(uint32(len(z))) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0004, zb0005 := range z { + err = en.WriteString(zb0004) + if err != nil { + err = msgp.WrapError(err) + return + } + err = en.WriteString(zb0005) + if err != nil { + err = msgp.WrapError(err, zb0004) + return + } + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z StringMap) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + o = msgp.AppendMapHeader(o, uint32(len(z))) + for zb0004, zb0005 := range z { + o = msgp.AppendString(o, zb0004) + o = msgp.AppendString(o, zb0005) + } + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *StringMap) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0003 uint32 + zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if (*z) == nil { + (*z) = make(StringMap, zb0003) + } else if len((*z)) > 0 { + for key := range *z { + delete((*z), key) + } + } + for zb0003 > 0 { + var zb0001 string + var zb0002 string + zb0003-- + zb0001, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + zb0002, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, zb0001) + return + } + (*z)[zb0001] = zb0002 + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z StringMap) Msgsize() (s int) { + s = msgp.MapHeaderSize + if z != nil { + for zb0004, zb0005 := range z { + _ = zb0005 + s += msgp.StringPrefixSize + len(zb0004) + msgp.StringPrefixSize + len(zb0005) + } + } + return +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/shared_channel.go b/vendor/github.com/mattermost/mattermost-server/v5/model/shared_channel.go new file mode 100644 index 00000000..e3643812 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/shared_channel.go @@ -0,0 +1,273 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +import ( + "encoding/json" + "io" + "net/http" + "unicode/utf8" +) + +// SharedChannel represents a channel that can be synchronized with a remote cluster. +// If "home" is true, then the shared channel is homed locally and "SharedChannelRemote" +// table contains the remote clusters that have been invited. +// If "home" is false, then the shared channel is homed remotely, and "RemoteId" +// field points to the remote cluster connection in "RemoteClusters" table. +type SharedChannel struct { + ChannelId string `json:"id"` + TeamId string `json:"team_id"` + Home bool `json:"home"` + ReadOnly bool `json:"readonly"` + ShareName string `json:"name"` + ShareDisplayName string `json:"display_name"` + SharePurpose string `json:"purpose"` + ShareHeader string `json:"header"` + CreatorId string `json:"creator_id"` + CreateAt int64 `json:"create_at"` + UpdateAt int64 `json:"update_at"` + RemoteId string `json:"remote_id,omitempty"` // if not "home" + Type string `db:"-"` +} + +func (sc *SharedChannel) ToJson() string { + b, _ := json.Marshal(sc) + return string(b) +} + +func SharedChannelFromJson(data io.Reader) (*SharedChannel, error) { + var sc *SharedChannel + err := json.NewDecoder(data).Decode(&sc) + return sc, err +} + +func (sc *SharedChannel) IsValid() *AppError { + if !IsValidId(sc.ChannelId) { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+sc.ChannelId, http.StatusBadRequest) + } + + if sc.Type != CHANNEL_DIRECT && !IsValidId(sc.TeamId) { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.id.app_error", nil, "TeamId="+sc.TeamId, http.StatusBadRequest) + } + + if sc.CreateAt == 0 { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if sc.UpdateAt == 0 { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if utf8.RuneCountInString(sc.ShareDisplayName) > CHANNEL_DISPLAY_NAME_MAX_RUNES { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if !IsValidChannelIdentifier(sc.ShareName) { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if utf8.RuneCountInString(sc.ShareHeader) > CHANNEL_HEADER_MAX_RUNES { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if utf8.RuneCountInString(sc.SharePurpose) > CHANNEL_PURPOSE_MAX_RUNES { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if !IsValidId(sc.CreatorId) { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "CreatorId="+sc.CreatorId, http.StatusBadRequest) + } + + if !sc.Home { + if !IsValidId(sc.RemoteId) { + return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.id.app_error", nil, "RemoteId="+sc.RemoteId, http.StatusBadRequest) + } + } + return nil +} + +func (sc *SharedChannel) PreSave() { + sc.ShareName = SanitizeUnicode(sc.ShareName) + sc.ShareDisplayName = SanitizeUnicode(sc.ShareDisplayName) + + sc.CreateAt = GetMillis() + sc.UpdateAt = sc.CreateAt +} + +func (sc *SharedChannel) PreUpdate() { + sc.UpdateAt = GetMillis() + sc.ShareName = SanitizeUnicode(sc.ShareName) + sc.ShareDisplayName = SanitizeUnicode(sc.ShareDisplayName) +} + +// SharedChannelRemote represents a remote cluster that has been invited +// to a shared channel. +type SharedChannelRemote struct { + Id string `json:"id"` + ChannelId string `json:"channel_id"` + CreatorId string `json:"creator_id"` + CreateAt int64 `json:"create_at"` + UpdateAt int64 `json:"update_at"` + IsInviteAccepted bool `json:"is_invite_accepted"` + IsInviteConfirmed bool `json:"is_invite_confirmed"` + RemoteId string `json:"remote_id"` + LastPostUpdateAt int64 `json:"last_post_update_at"` + LastPostId string `json:"last_post_id"` +} + +func (sc *SharedChannelRemote) ToJson() string { + b, _ := json.Marshal(sc) + return string(b) +} + +func SharedChannelRemoteFromJson(data io.Reader) (*SharedChannelRemote, error) { + var sc *SharedChannelRemote + err := json.NewDecoder(data).Decode(&sc) + return sc, err +} + +func (sc *SharedChannelRemote) IsValid() *AppError { + if !IsValidId(sc.Id) { + return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.id.app_error", nil, "Id="+sc.Id, http.StatusBadRequest) + } + + if !IsValidId(sc.ChannelId) { + return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+sc.ChannelId, http.StatusBadRequest) + } + + if sc.CreateAt == 0 { + return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if sc.UpdateAt == 0 { + return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) + } + + if !IsValidId(sc.CreatorId) { + return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "id="+sc.CreatorId, http.StatusBadRequest) + } + return nil +} + +func (sc *SharedChannelRemote) PreSave() { + if sc.Id == "" { + sc.Id = NewId() + } + sc.CreateAt = GetMillis() + sc.UpdateAt = sc.CreateAt +} + +func (sc *SharedChannelRemote) PreUpdate() { + sc.UpdateAt = GetMillis() +} + +type SharedChannelRemoteStatus struct { + ChannelId string `json:"channel_id"` + DisplayName string `json:"display_name"` + SiteURL string `json:"site_url"` + LastPingAt int64 `json:"last_ping_at"` + NextSyncAt int64 `json:"next_sync_at"` + ReadOnly bool `json:"readonly"` + IsInviteAccepted bool `json:"is_invite_accepted"` + Token string `json:"token"` +} + +// SharedChannelUser stores a lastSyncAt timestamp on behalf of a remote cluster for +// each user that has been synchronized. +type SharedChannelUser struct { + Id string `json:"id"` + UserId string `json:"user_id"` + ChannelId string `json:"channel_id"` + RemoteId string `json:"remote_id"` + CreateAt int64 `json:"create_at"` + LastSyncAt int64 `json:"last_sync_at"` +} + +func (scu *SharedChannelUser) PreSave() { + scu.Id = NewId() + scu.CreateAt = GetMillis() +} + +func (scu *SharedChannelUser) IsValid() *AppError { + if !IsValidId(scu.Id) { + return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "Id="+scu.Id, http.StatusBadRequest) + } + + if !IsValidId(scu.UserId) { + return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "UserId="+scu.UserId, http.StatusBadRequest) + } + + if !IsValidId(scu.ChannelId) { + return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+scu.ChannelId, http.StatusBadRequest) + } + + if !IsValidId(scu.RemoteId) { + return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "RemoteId="+scu.RemoteId, http.StatusBadRequest) + } + + if scu.CreateAt == 0 { + return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) + } + return nil +} + +type GetUsersForSyncFilter struct { + CheckProfileImage bool + ChannelID string + Limit uint64 +} + +// SharedChannelAttachment stores a lastSyncAt timestamp on behalf of a remote cluster for +// each file attachment that has been synchronized. +type SharedChannelAttachment struct { + Id string `json:"id"` + FileId string `json:"file_id"` + RemoteId string `json:"remote_id"` + CreateAt int64 `json:"create_at"` + LastSyncAt int64 `json:"last_sync_at"` +} + +func (scf *SharedChannelAttachment) PreSave() { + if scf.Id == "" { + scf.Id = NewId() + } + if scf.CreateAt == 0 { + scf.CreateAt = GetMillis() + scf.LastSyncAt = scf.CreateAt + } else { + scf.LastSyncAt = GetMillis() + } +} + +func (scf *SharedChannelAttachment) IsValid() *AppError { + if !IsValidId(scf.Id) { + return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.id.app_error", nil, "Id="+scf.Id, http.StatusBadRequest) + } + + if !IsValidId(scf.FileId) { + return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.id.app_error", nil, "FileId="+scf.FileId, http.StatusBadRequest) + } + + if !IsValidId(scf.RemoteId) { + return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.id.app_error", nil, "RemoteId="+scf.RemoteId, http.StatusBadRequest) + } + + if scf.CreateAt == 0 { + return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) + } + return nil +} + +type SharedChannelFilterOpts struct { + TeamId string + CreatorId string + ExcludeHome bool + ExcludeRemote bool +} + +type SharedChannelRemoteFilterOpts struct { + ChannelId string + RemoteId string + InclUnconfirmed bool +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go index a85c6be2..371baaab 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go @@ -179,6 +179,9 @@ func ParseSlackAttachment(post *Post, attachments []*SlackAttachment) { attachment.Pretext = ParseSlackLinksToMarkdown(attachment.Pretext) for _, field := range attachment.Fields { + if field == nil { + continue + } if value, ok := field.Value.(string); ok { field.Value = ParseSlackLinksToMarkdown(value) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/status.go b/vendor/github.com/mattermost/mattermost-server/v5/model/status.go index 1f32422a..f6f3a67a 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/status.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/status.go @@ -25,6 +25,8 @@ type Status struct { Manual bool `json:"manual"` LastActivityAt int64 `json:"last_activity_at"` ActiveChannel string `json:"active_channel,omitempty" db:"-"` + DNDEndTime int64 `json:"dnd_end_time"` + PrevStatus string `json:"-"` } func (o *Status) ToJson() string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go index 0ec4db7d..bdb90045 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go @@ -34,14 +34,16 @@ func (o *SwitchRequest) EmailToOAuth() bool { (o.NewService == USER_AUTH_SERVICE_SAML || o.NewService == USER_AUTH_SERVICE_GITLAB || o.NewService == SERVICE_GOOGLE || - o.NewService == SERVICE_OFFICE365) + o.NewService == SERVICE_OFFICE365 || + o.NewService == SERVICE_OPENID) } func (o *SwitchRequest) OAuthToEmail() bool { return (o.CurrentService == USER_AUTH_SERVICE_SAML || o.CurrentService == USER_AUTH_SERVICE_GITLAB || o.CurrentService == SERVICE_GOOGLE || - o.CurrentService == SERVICE_OFFICE365) && o.NewService == USER_AUTH_SERVICE_EMAIL + o.CurrentService == SERVICE_OFFICE365 || + o.CurrentService == SERVICE_OPENID) && o.NewService == USER_AUTH_SERVICE_EMAIL } func (o *SwitchRequest) EmailToLdap() bool { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/system.go b/vendor/github.com/mattermost/mattermost-server/v5/model/system.go index 4e76c959..b7cda1ef 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/system.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/system.go @@ -14,6 +14,7 @@ const ( SYSTEM_RAN_UNIT_TESTS = "RanUnitTests" SYSTEM_LAST_SECURITY_TIME = "LastSecurityTime" SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId" + SYSTEM_LICENSE_RENEWAL_TOKEN = "LicenseRenewalToken" SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime" SYSTEM_ASYMMETRIC_SIGNING_KEY = "AsymmetricSigningKey" SYSTEM_POST_ACTION_COOKIE_SECRET = "PostActionCookieSecret" @@ -31,10 +32,13 @@ const ( SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500 = "warn_metric_number_of_active_users_500" SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M = "warn_metric_number_of_posts_2M" SYSTEM_WARN_METRIC_LAST_RUN_TIMESTAMP_KEY = "LastWarnMetricRunTimestamp" + SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED = "warn_metric_support_email_not_configured" + SYSTEM_FIRST_ADMIN_VISIT_MARKETPLACE = "FirstAdminVisitMarketplace" AWS_METERING_REPORT_INTERVAL = 1 AWS_METERING_DIMENSION_USAGE_HRS = "UsageHrs" USER_LIMIT_OVERAGE_CYCLE_END_DATE = "UserLimitOverageCycleEndDate" OVER_USER_LIMIT_FORGIVEN_COUNT = "OverUserLimitForgivenCount" + OVER_USER_LIMIT_LAST_EMAIL_SENT = "OverUserLimitLastEmailSent" ) const ( @@ -85,6 +89,22 @@ type ServerBusyState struct { Expires_ts string `json:"expires_ts,omitempty"` } +type SupportPacket struct { + ServerOS string `yaml:"server_os"` + ServerArchitecture string `yaml:"server_architecture"` + DatabaseType string `yaml:"database_type"` + DatabaseVersion string `yaml:"database_version"` + LdapVendorName string `yaml:"ldap_vendor_name,omitempty"` + LdapVendorVersion string `yaml:"ldap_vendor_version,omitempty"` + ElasticServerVersion string `yaml:"elastic_server_version,omitempty"` + ElasticServerPlugins []string `yaml:"elastic_server_plugins,omitempty"` +} + +type FileData struct { + Filename string + Body []byte +} + func (sbs *ServerBusyState) ToJson() string { b, _ := json.Marshal(sbs) return string(b) @@ -151,13 +171,21 @@ var WarnMetricsTable = map[string]WarnMetric{ IsBotOnly: false, IsRunOnce: true, }, + SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED: { + Id: SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED, + Limit: -1, + IsBotOnly: true, + IsRunOnce: false, + SkipAction: true, + }, } type WarnMetric struct { - Id string - Limit int64 - IsBotOnly bool - IsRunOnce bool + Id string + Limit int64 + IsBotOnly bool + IsRunOnce bool + SkipAction bool } type WarnMetricDisplayTexts struct { @@ -182,9 +210,8 @@ func WarnMetricStatusFromJson(data io.Reader) *WarnMetricStatus { var o WarnMetricStatus if err := json.NewDecoder(data).Decode(&o); err != nil { return nil - } else { - return &o } + return &o } func MapWarnMetricStatusToJson(o map[string]*WarnMetricStatus) string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team.go index 381eb8bb..fc752f30 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team.go @@ -42,6 +42,7 @@ type Team struct { LastTeamIconUpdate int64 `json:"last_team_icon_update,omitempty"` SchemeId *string `json:"scheme_id"` GroupConstrained *bool `json:"group_constrained"` + PolicyID *string `json:"policy_id" db:"-"` } type TeamPatch struct { @@ -152,7 +153,7 @@ func (o *Team) IsValid() *AppError { return NewAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id, http.StatusBadRequest) } - if len(o.Email) > 0 && !IsValidEmail(o.Email) { + if o.Email != "" && !IsValidEmail(o.Email) { return NewAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id, http.StatusBadRequest) } @@ -168,7 +169,7 @@ func (o *Team) IsValid() *AppError { return NewAppError("Team.IsValid", "model.team.is_valid.description.app_error", nil, "id="+o.Id, http.StatusBadRequest) } - if len(o.InviteId) == 0 { + if o.InviteId == "" { return NewAppError("Team.IsValid", "model.team.is_valid.invite_id.app_error", nil, "id="+o.Id, http.StatusBadRequest) } @@ -208,7 +209,7 @@ func (o *Team) PreSave() { o.Description = SanitizeUnicode(o.Description) o.CompanyName = SanitizeUnicode(o.CompanyName) - if len(o.InviteId) == 0 { + if o.InviteId == "" { o.InviteId = NewId() } } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go index b747f17c..f5f1cc61 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go @@ -15,6 +15,9 @@ const ( USERNAME = "Username" ) +//msgp:tuple TeamMember +// This struct's serializer methods are auto-generated. If a new field is added/removed, +// please run make gen-serialized. type TeamMember struct { TeamId string `json:"team_id"` UserId string `json:"user_id"` @@ -26,28 +29,37 @@ type TeamMember struct { ExplicitRoles string `json:"explicit_roles"` } +//msgp:ignore TeamUnread type TeamUnread struct { - TeamId string `json:"team_id"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` + TeamId string `json:"team_id"` + MsgCount int64 `json:"msg_count"` + MentionCount int64 `json:"mention_count"` + MentionCountRoot int64 `json:"mention_count_root"` + MsgCountRoot int64 `json:"msg_count_root"` + ThreadCount int64 `json:"thread_count"` + ThreadMentionCount int64 `json:"thread_mention_count"` } +//msgp:ignore TeamMemberForExport type TeamMemberForExport struct { TeamMember TeamName string } +//msgp:ignore TeamMemberWithError type TeamMemberWithError struct { UserId string `json:"user_id"` Member *TeamMember `json:"member"` Error *AppError `json:"error"` } +//msgp:ignore EmailInviteWithError type EmailInviteWithError struct { Email string `json:"email"` Error *AppError `json:"error"` } +//msgp:ignore TeamMembersGetOptions type TeamMembersGetOptions struct { // Sort the team members. Accepts "Username", but defaults to "Id". Sort string @@ -98,11 +110,11 @@ func EmailInviteWithErrorToEmails(o []*EmailInviteWithError) []string { } func EmailInviteWithErrorToJson(o []*EmailInviteWithError) string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func EmailInviteWithErrorToString(o *EmailInviteWithError) string { @@ -120,11 +132,11 @@ func TeamMembersWithErrorToTeamMembers(o []*TeamMemberWithError) []*TeamMember { } func TeamMembersWithErrorToJson(o []*TeamMemberWithError) string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func TeamMemberWithErrorToString(o *TeamMemberWithError) string { @@ -138,11 +150,11 @@ func TeamMembersWithErrorFromJson(data io.Reader) []*TeamMemberWithError { } func TeamMembersToJson(o []*TeamMember) string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func TeamMembersFromJson(data io.Reader) []*TeamMember { @@ -152,11 +164,11 @@ func TeamMembersFromJson(data io.Reader) []*TeamMember { } func TeamsUnreadToJson(o []*TeamUnread) string { - if b, err := json.Marshal(o); err != nil { + b, err := json.Marshal(o) + if err != nil { return "[]" - } else { - return string(b) } + return string(b) } func TeamsUnreadFromJson(data io.Reader) []*TeamUnread { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member_serial_gen.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member_serial_gen.go new file mode 100644 index 00000000..044a608a --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member_serial_gen.go @@ -0,0 +1,193 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "github.com/tinylib/msgp/msgp" +) + +// DecodeMsg implements msgp.Decodable +func (z *TeamMember) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0001 uint32 + zb0001, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 8 { + err = msgp.ArrayError{Wanted: 8, Got: zb0001} + return + } + z.TeamId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "TeamId") + return + } + z.UserId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + z.Roles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.DeleteAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + z.SchemeGuest, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "SchemeGuest") + return + } + z.SchemeUser, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "SchemeUser") + return + } + z.SchemeAdmin, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "SchemeAdmin") + return + } + z.ExplicitRoles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "ExplicitRoles") + return + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *TeamMember) EncodeMsg(en *msgp.Writer) (err error) { + // array header, size 8 + err = en.Append(0x98) + if err != nil { + return + } + err = en.WriteString(z.TeamId) + if err != nil { + err = msgp.WrapError(err, "TeamId") + return + } + err = en.WriteString(z.UserId) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + err = en.WriteString(z.Roles) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + err = en.WriteInt64(z.DeleteAt) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + err = en.WriteBool(z.SchemeGuest) + if err != nil { + err = msgp.WrapError(err, "SchemeGuest") + return + } + err = en.WriteBool(z.SchemeUser) + if err != nil { + err = msgp.WrapError(err, "SchemeUser") + return + } + err = en.WriteBool(z.SchemeAdmin) + if err != nil { + err = msgp.WrapError(err, "SchemeAdmin") + return + } + err = en.WriteString(z.ExplicitRoles) + if err != nil { + err = msgp.WrapError(err, "ExplicitRoles") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *TeamMember) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // array header, size 8 + o = append(o, 0x98) + o = msgp.AppendString(o, z.TeamId) + o = msgp.AppendString(o, z.UserId) + o = msgp.AppendString(o, z.Roles) + o = msgp.AppendInt64(o, z.DeleteAt) + o = msgp.AppendBool(o, z.SchemeGuest) + o = msgp.AppendBool(o, z.SchemeUser) + o = msgp.AppendBool(o, z.SchemeAdmin) + o = msgp.AppendString(o, z.ExplicitRoles) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *TeamMember) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0001 uint32 + zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 8 { + err = msgp.ArrayError{Wanted: 8, Got: zb0001} + return + } + z.TeamId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TeamId") + return + } + z.UserId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "UserId") + return + } + z.Roles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + z.SchemeGuest, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "SchemeGuest") + return + } + z.SchemeUser, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "SchemeUser") + return + } + z.SchemeAdmin, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "SchemeAdmin") + return + } + z.ExplicitRoles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "ExplicitRoles") + return + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *TeamMember) Msgsize() (s int) { + s = 1 + msgp.StringPrefixSize + len(z.TeamId) + msgp.StringPrefixSize + len(z.UserId) + msgp.StringPrefixSize + len(z.Roles) + msgp.Int64Size + msgp.BoolSize + msgp.BoolSize + msgp.BoolSize + msgp.StringPrefixSize + len(z.ExplicitRoles) + return +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go index f9de5801..e24b8438 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go @@ -9,12 +9,17 @@ import ( ) type TeamSearch struct { - Term string `json:"term"` - Page *int `json:"page,omitempty"` - PerPage *int `json:"per_page,omitempty"` - AllowOpenInvite *bool `json:"allow_open_invite,omitempty"` - GroupConstrained *bool `json:"group_constrained,omitempty"` - IncludeGroupConstrained *bool `json:"include_group_constrained,omitempty"` + Term string `json:"term"` + Page *int `json:"page,omitempty"` + PerPage *int `json:"per_page,omitempty"` + AllowOpenInvite *bool `json:"allow_open_invite,omitempty"` + GroupConstrained *bool `json:"group_constrained,omitempty"` + IncludeGroupConstrained *bool `json:"include_group_constrained,omitempty"` + PolicyID *string `json:"policy_id,omitempty"` + ExcludePolicyConstrained *bool `json:"exclude_policy_constrained,omitempty"` + IncludePolicyID *bool `json:"-"` + IncludeDeleted *bool `json:"-"` + TeamType *string `json:"-"` } func (t *TeamSearch) IsPaginated() bool { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/thread.go b/vendor/github.com/mattermost/mattermost-server/v5/model/thread.go index ec091c00..fe4a4014 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/thread.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/thread.go @@ -16,23 +16,24 @@ type Thread struct { } type ThreadResponse struct { - PostId string `json:"id"` - ReplyCount int64 `json:"reply_count"` - LastReplyAt int64 `json:"last_reply_at"` - LastViewedAt int64 `json:"last_viewed_at"` - Participants []*User `json:"participants"` - Post *Post `json:"post"` + PostId string `json:"id"` + ReplyCount int64 `json:"reply_count"` + LastReplyAt int64 `json:"last_reply_at"` + LastViewedAt int64 `json:"last_viewed_at"` + Participants []*User `json:"participants"` + Post *Post `json:"post"` + UnreadReplies int64 `json:"unread_replies"` + UnreadMentions int64 `json:"unread_mentions"` } type Threads struct { - Total int64 `json:"total"` - Threads []*ThreadResponse `json:"threads"` + Total int64 `json:"total"` + TotalUnreadThreads int64 `json:"total_unread_threads"` + TotalUnreadMentions int64 `json:"total_unread_mentions"` + Threads []*ThreadResponse `json:"threads"` } type GetUserThreadsOpts struct { - // Page specifies which part of the results to return, by PageSize. Default = 0 - Page uint64 - // PageSize specifies the size of the returned chunk of results. Default = 30 PageSize uint64 @@ -44,6 +45,32 @@ type GetUserThreadsOpts struct { // Since filters the threads based on their LastUpdateAt timestamp. Since uint64 + + // Before specifies thread id as a cursor for pagination and will return `PageSize` threads before the cursor + Before string + + // After specifies thread id as a cursor for pagination and will return `PageSize` threads after the cursor + After string + + // Unread will make sure that only threads with unread replies are returned + Unread bool + + // TotalsOnly will not fetch any threads and just fetch the total counts + TotalsOnly bool + + // TeamOnly will only fetch threads and unreads for the specified team and excludes DMs/GMs + TeamOnly bool +} + +func (o *ThreadResponse) ToJson() string { + b, _ := json.Marshal(o) + return string(b) +} + +func ThreadResponseFromJson(s string) (*ThreadResponse, error) { + var t ThreadResponse + err := json.Unmarshal([]byte(s), &t) + return &t, err } func (o *Threads) ToJson() string { @@ -56,6 +83,12 @@ func (o *Thread) ToJson() string { return string(b) } +func ThreadFromJson(s string) (*Thread, error) { + var t Thread + err := json.Unmarshal([]byte(s), &t) + return &t, err +} + func (o *Thread) Etag() string { return Etag(o.PostId, o.LastReplyAt) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/token.go b/vendor/github.com/mattermost/mattermost-server/v5/model/token.go index 0730778c..2dcf4143 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/token.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/token.go @@ -3,7 +3,9 @@ package model -import "net/http" +import ( + "net/http" +) const ( TOKEN_SIZE = 64 diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/upload_session.go b/vendor/github.com/mattermost/mattermost-server/v5/model/upload_session.go index 663ee0b1..c5f09083 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/upload_session.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/upload_session.go @@ -18,6 +18,9 @@ const ( UploadTypeImport UploadType = "import" ) +// UploadNoUserID is a "fake" user id used by the API layer when in local mode. +const UploadNoUserID = "nouser" + // UploadSession contains information used to keep track of a file upload. type UploadSession struct { // The unique identifier for the session. @@ -29,7 +32,7 @@ type UploadSession struct { // The id of the user performing the upload. UserId string `json:"user_id"` // The id of the channel to upload to. - ChannelId string `json:"channel_id"` + ChannelId string `json:"channel_id,omitempty"` // The name of the file to upload. Filename string `json:"filename"` // The path where the file is stored. @@ -39,6 +42,10 @@ type UploadSession struct { // The amount of received data in bytes. If equal to FileSize it means the // upload has finished. FileOffset int64 `json:"file_offset"` + // Id of remote cluster if uploading for shared channel + RemoteId string `json:"remote_id"` + // Requested file id if uploading for shared channel + ReqFileId string `json:"req_file_id"` } // ToJson serializes the UploadSession into JSON and returns it as string. @@ -109,7 +116,7 @@ func (us *UploadSession) IsValid() *AppError { return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.type.app_error", nil, err.Error(), http.StatusBadRequest) } - if !IsValidId(us.UserId) { + if !IsValidId(us.UserId) && us.UserId != UploadNoUserID { return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.user_id.app_error", nil, "id="+us.Id, http.StatusBadRequest) } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user.go index dd4e2ba8..1745d726 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user.go @@ -9,17 +9,17 @@ import ( "fmt" "io" "io/ioutil" - "math/rand" "net/http" "regexp" "sort" "strings" - "time" "unicode/utf8" - "github.com/mattermost/mattermost-server/v5/services/timezones" "golang.org/x/crypto/bcrypt" "golang.org/x/text/language" + + "github.com/mattermost/mattermost-server/v5/services/timezones" + "github.com/mattermost/mattermost-server/v5/shared/mlog" ) const ( @@ -57,6 +57,7 @@ const ( USER_NAME_MIN_LENGTH = 1 USER_PASSWORD_MAX_LENGTH = 72 USER_LOCALE_MAX_LENGTH = 5 + USER_TIMEZONE_MAX_RUNES = 256 ) //msgp:tuple User @@ -90,12 +91,14 @@ type User struct { Timezone StringMap `json:"timezone"` MfaActive bool `json:"mfa_active,omitempty"` MfaSecret string `json:"mfa_secret,omitempty"` + RemoteId *string `json:"remote_id,omitempty"` LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"` IsBot bool `db:"-" json:"is_bot,omitempty"` BotDescription string `db:"-" json:"bot_description,omitempty"` BotLastIconUpdate int64 `db:"-" json:"bot_last_icon_update,omitempty"` TermsOfServiceId string `db:"-" json:"terms_of_service_id,omitempty"` TermsOfServiceCreateAt int64 `db:"-" json:"terms_of_service_create_at,omitempty"` + DisableWelcomeEmail bool `db:"-" json:"disable_welcome_email"` } //msgp UserMap @@ -104,11 +107,13 @@ type User struct { // It is used to generate methods which can be used for fast serialization/de-serialization. type UserMap map[string]*User +//msgp:ignore UserUpdate type UserUpdate struct { Old *User New *User } +//msgp:ignore UserPatch type UserPatch struct { Username *string `json:"username"` Password *string `json:"password,omitempty"` @@ -121,14 +126,17 @@ type UserPatch struct { NotifyProps StringMap `json:"notify_props,omitempty"` Locale *string `json:"locale"` Timezone StringMap `json:"timezone"` + RemoteId *string `json:"remote_id"` } +//msgp:ignore UserAuth type UserAuth struct { - Password string `json:"password,omitempty"` + Password string `json:"password,omitempty"` // DEPRECATED: It is not used. AuthData *string `json:"auth_data,omitempty"` AuthService string `json:"auth_service,omitempty"` } +//msgp:ignore UserForIndexing type UserForIndexing struct { Id string `json:"id"` Username string `json:"username"` @@ -142,6 +150,7 @@ type UserForIndexing struct { ChannelsIds []string `json:"channel_id"` } +//msgp:ignore ViewUsersRestrictions type ViewUsersRestrictions struct { Teams []string Channels []string @@ -158,6 +167,7 @@ func (r *ViewUsersRestrictions) Hash() string { return fmt.Sprintf("%x", hash.Sum(nil)) } +//msgp:ignore UserSlice type UserSlice []*User func (u UserSlice) Usernames() []string { @@ -262,11 +272,17 @@ func (u *User) IsValid() *AppError { return InvalidUserError("update_at", u.Id) } - if !IsValidUsername(u.Username) { - return InvalidUserError("username", u.Id) + if u.IsRemote() { + if !IsValidUsernameAllowRemote(u.Username) { + return InvalidUserError("username", u.Id) + } + } else { + if !IsValidUsername(u.Username) { + return InvalidUserError("username", u.Id) + } } - if len(u.Email) > USER_EMAIL_MAX_LENGTH || len(u.Email) == 0 || !IsValidEmail(u.Email) { + if len(u.Email) > USER_EMAIL_MAX_LENGTH || u.Email == "" || !IsValidEmail(u.Email) { return InvalidUserError("email", u.Id) } @@ -290,11 +306,11 @@ func (u *User) IsValid() *AppError { return InvalidUserError("auth_data", u.Id) } - if u.AuthData != nil && len(*u.AuthData) > 0 && len(u.AuthService) == 0 { + if u.AuthData != nil && *u.AuthData != "" && u.AuthService == "" { return InvalidUserError("auth_data_type", u.Id) } - if len(u.Password) > 0 && u.AuthData != nil && len(*u.AuthData) > 0 { + if u.Password != "" && u.AuthData != nil && *u.AuthData != "" { return InvalidUserError("auth_data_pwd", u.Id) } @@ -306,6 +322,14 @@ func (u *User) IsValid() *AppError { return InvalidUserError("locale", u.Id) } + if len(u.Timezone) > 0 { + if tzJSON, err := json.Marshal(u.Timezone); err != nil { + return NewAppError("User.IsValid", "model.user.is_valid.marshal.app_error", nil, err.Error(), http.StatusInternalServerError) + } else if utf8.RuneCount(tzJSON) > USER_TIMEZONE_MAX_RUNES { + return InvalidUserError("timezone_limit", u.Id) + } + } + return nil } @@ -373,7 +397,7 @@ func (u *User) PreSave() { u.Timezone = timezones.DefaultUserTimezone() } - if len(u.Password) > 0 { + if u.Password != "" { u.Password = HashPassword(u.Password) } } @@ -406,7 +430,7 @@ func (u *User) PreUpdate() { splitKeys := strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",") goodKeys := []string{} for _, key := range splitKeys { - if len(key) > 0 { + if key != "" { goodKeys = append(goodKeys, strings.ToLower(key)) } } @@ -497,6 +521,10 @@ func (u *User) Patch(patch *UserPatch) { if patch.Timezone != nil { u.Timezone = patch.Timezone } + + if patch.RemoteId != nil { + u.RemoteId = patch.RemoteId + } } // ToJson convert a User to a json string @@ -553,6 +581,7 @@ func (u *User) SanitizeInput(isAdmin bool) { u.FailedAttempts = 0 u.MfaActive = false u.MfaSecret = "" + u.Email = strings.TrimSpace(u.Email) } func (u *User) ClearNonProfileFields() { @@ -588,12 +617,22 @@ func (u *User) AddNotifyProp(key string, value string) { u.NotifyProps[key] = value } +func (u *User) SetCustomStatus(cs *CustomStatus) { + u.MakeNonNil() + u.Props[UserPropsKeyCustomStatus] = cs.ToJson() +} + +func (u *User) ClearCustomStatus() { + u.MakeNonNil() + u.Props[UserPropsKeyCustomStatus] = "" +} + func (u *User) GetFullName() string { - if len(u.FirstName) > 0 && len(u.LastName) > 0 { + if u.FirstName != "" && u.LastName != "" { return u.FirstName + " " + u.LastName - } else if len(u.FirstName) > 0 { + } else if u.FirstName != "" { return u.FirstName - } else if len(u.LastName) > 0 { + } else if u.LastName != "" { return u.LastName } else { return "" @@ -604,13 +643,13 @@ func (u *User) getDisplayName(baseName, nameFormat string) string { displayName := baseName if nameFormat == SHOW_NICKNAME_FULLNAME { - if len(u.Nickname) > 0 { + if u.Nickname != "" { displayName = u.Nickname - } else if fullName := u.GetFullName(); len(fullName) > 0 { + } else if fullName := u.GetFullName(); fullName != "" { displayName = fullName } } else if nameFormat == SHOW_FULLNAME { - if fullName := u.GetFullName(); len(fullName) > 0 { + if fullName := u.GetFullName(); fullName != "" { displayName = fullName } } @@ -691,7 +730,10 @@ func (u *User) IsSSOUser() bool { } func (u *User) IsOAuthUser() bool { - return u.AuthService == USER_AUTH_SERVICE_GITLAB + return u.AuthService == SERVICE_GITLAB || + u.AuthService == SERVICE_GOOGLE || + u.AuthService == SERVICE_OFFICE365 || + u.AuthService == SERVICE_OPENID } func (u *User) IsLDAPUser() bool { @@ -706,6 +748,61 @@ func (u *User) GetPreferredTimezone() string { return GetPreferredTimezone(u.Timezone) } +// IsRemote returns true if the user belongs to a remote cluster (has RemoteId). +func (u *User) IsRemote() bool { + return u.RemoteId != nil && *u.RemoteId != "" +} + +// GetRemoteID returns the remote id for this user or "" if not a remote user. +func (u *User) GetRemoteID() string { + if u.RemoteId != nil { + return *u.RemoteId + } + return "" +} + +// GetProp fetches a prop value by name. +func (u *User) GetProp(name string) (string, bool) { + val, ok := u.Props[name] + return val, ok +} + +// SetProp sets a prop value by name, creating the map if nil. +// Not thread safe. +func (u *User) SetProp(name string, value string) { + if u.Props == nil { + u.Props = make(map[string]string) + } + u.Props[name] = value +} + +func (u *User) ToPatch() *UserPatch { + return &UserPatch{ + Username: &u.Username, Password: &u.Password, + Nickname: &u.Nickname, FirstName: &u.FirstName, LastName: &u.LastName, + Position: &u.Position, Email: &u.Email, + Props: u.Props, NotifyProps: u.NotifyProps, + Locale: &u.Locale, Timezone: u.Timezone, + } +} + +func (u *UserPatch) SetField(fieldName string, fieldValue string) { + switch fieldName { + case "FirstName": + u.FirstName = &fieldValue + case "LastName": + u.LastName = &fieldValue + case "Nickname": + u.Nickname = &fieldValue + case "Email": + u.Email = &fieldValue + case "Position": + u.Position = &fieldValue + case "Username": + u.Username = &fieldValue + } +} + // UserFromJson will decode the input and return a User func UserFromJson(data io.Reader) *User { var user *User @@ -758,9 +855,10 @@ func HashPassword(password string) string { } // ComparePassword compares the hash +// This function is deprecated and will be removed in a future release. func ComparePassword(hash string, password string) bool { - if len(password) == 0 || len(hash) == 0 { + if password == "" || hash == "" { return false } @@ -769,12 +867,13 @@ func ComparePassword(hash string, password string) bool { } var validUsernameChars = regexp.MustCompile(`^[a-z0-9\.\-_]+$`) +var validUsernameCharsForRemote = regexp.MustCompile(`^[a-z0-9\.\-_:]+$`) -var restrictedUsernames = []string{ - "all", - "channel", - "matterbot", - "system", +var restrictedUsernames = map[string]struct{}{ + "all": {}, + "channel": {}, + "matterbot": {}, + "system": {}, } func IsValidUsername(s string) bool { @@ -786,17 +885,25 @@ func IsValidUsername(s string) bool { return false } - for _, restrictedUsername := range restrictedUsernames { - if s == restrictedUsername { - return false - } + _, found := restrictedUsernames[s] + return !found +} + +func IsValidUsernameAllowRemote(s string) bool { + if len(s) < USER_NAME_MIN_LENGTH || len(s) > USER_NAME_MAX_LENGTH { + return false } - return true + if !validUsernameCharsForRemote.MatchString(s) { + return false + } + + _, found := restrictedUsernames[s] + return !found } -func CleanUsername(s string) string { - s = NormalizeUsername(strings.Replace(s, " ", "-", -1)) +func CleanUsername(username string) string { + s := NormalizeUsername(strings.Replace(username, " ", "-", -1)) for _, value := range reservedName { if s == value { @@ -817,6 +924,8 @@ func CleanUsername(s string) string { if !IsValidUsername(s) { s = "a" + NewId() + mlog.Warn("Generating new username since provided username was invalid", + mlog.String("provided_username", username), mlog.String("new_username", s)) } return s @@ -858,6 +967,7 @@ func IsValidLocale(locale string) bool { return true } +//msgp:ignore UserWithGroups type UserWithGroups struct { User GroupIDs *string `json:"-"` @@ -872,12 +982,13 @@ func (u *UserWithGroups) GetGroupIDs() []string { return nil } trimmed := strings.TrimSpace(*u.GroupIDs) - if len(trimmed) == 0 { + if trimmed == "" { return nil } return strings.Split(trimmed, ",") } +//msgp:ignore UsersWithGroupsAndCount type UsersWithGroupsAndCount struct { Users []*UserWithGroups `json:"users"` Count int64 `json:"total_count"` @@ -889,27 +1000,3 @@ func UsersWithGroupsAndCountFromJson(data io.Reader) *UsersWithGroupsAndCount { json.Unmarshal(bodyBytes, uwg) return uwg } - -var passwordRandomSource = rand.NewSource(time.Now().Unix()) -var passwordSpecialChars = "!$%^&*(),." -var passwordNumbers = "0123456789" -var passwordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -var passwordLowerCaseLetters = "abcdefghijklmnopqrstuvwxyz" -var passwordAllChars = passwordSpecialChars + passwordNumbers + passwordUpperCaseLetters + passwordLowerCaseLetters - -func GeneratePassword(minimumLength int) string { - r := rand.New(passwordRandomSource) - - // Make sure we are guaranteed at least one of each type to meet any possible password complexity requirements. - password := string([]rune(passwordUpperCaseLetters)[r.Intn(len(passwordUpperCaseLetters))]) + - string([]rune(passwordNumbers)[r.Intn(len(passwordNumbers))]) + - string([]rune(passwordLowerCaseLetters)[r.Intn(len(passwordLowerCaseLetters))]) + - string([]rune(passwordSpecialChars)[r.Intn(len(passwordSpecialChars))]) - - for len(password) < minimumLength { - i := r.Intn(len(passwordAllChars)) - password = password + string([]rune(passwordAllChars)[i]) - } - - return password -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go index 48a892e2..118e138d 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go @@ -31,11 +31,10 @@ func UserAutocompleteFromJson(data io.Reader) *UserAutocomplete { decoder := json.NewDecoder(data) autocomplete := new(UserAutocomplete) err := decoder.Decode(&autocomplete) - if err == nil { - return autocomplete - } else { + if err != nil { return nil } + return autocomplete } func (o *UserAutocompleteInChannel) ToJson() string { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_serial_gen.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_serial_gen.go new file mode 100644 index 00000000..fb40b577 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/user_serial_gen.go @@ -0,0 +1,826 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +// Code generated by github.com/tinylib/msgp DO NOT EDIT. + +import ( + "github.com/tinylib/msgp/msgp" +) + +// DecodeMsg implements msgp.Decodable +func (z *User) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0001 uint32 + zb0001, err = dc.ReadArrayHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 32 { + err = msgp.ArrayError{Wanted: 32, Got: zb0001} + return + } + z.Id, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.CreateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.UpdateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "UpdateAt") + return + } + z.DeleteAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + z.Username, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Username") + return + } + z.Password, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Password") + return + } + if dc.IsNil() { + err = dc.ReadNil() + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + z.AuthData = nil + } else { + if z.AuthData == nil { + z.AuthData = new(string) + } + *z.AuthData, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + } + z.AuthService, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "AuthService") + return + } + z.Email, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Email") + return + } + z.EmailVerified, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "EmailVerified") + return + } + z.Nickname, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Nickname") + return + } + z.FirstName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "FirstName") + return + } + z.LastName, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "LastName") + return + } + z.Position, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Position") + return + } + z.Roles, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.AllowMarketing, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "AllowMarketing") + return + } + err = z.Props.DecodeMsg(dc) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + err = z.NotifyProps.DecodeMsg(dc) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + z.LastPasswordUpdate, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastPasswordUpdate") + return + } + z.LastPictureUpdate, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastPictureUpdate") + return + } + z.FailedAttempts, err = dc.ReadInt() + if err != nil { + err = msgp.WrapError(err, "FailedAttempts") + return + } + z.Locale, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "Locale") + return + } + err = z.Timezone.DecodeMsg(dc) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + z.MfaActive, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "MfaActive") + return + } + z.MfaSecret, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "MfaSecret") + return + } + if dc.IsNil() { + err = dc.ReadNil() + if err != nil { + err = msgp.WrapError(err, "RemoteId") + return + } + z.RemoteId = nil + } else { + if z.RemoteId == nil { + z.RemoteId = new(string) + } + *z.RemoteId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "RemoteId") + return + } + } + z.LastActivityAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.IsBot, err = dc.ReadBool() + if err != nil { + err = msgp.WrapError(err, "IsBot") + return + } + z.BotDescription, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "BotDescription") + return + } + z.BotLastIconUpdate, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "BotLastIconUpdate") + return + } + z.TermsOfServiceId, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceId") + return + } + z.TermsOfServiceCreateAt, err = dc.ReadInt64() + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceCreateAt") + return + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z *User) EncodeMsg(en *msgp.Writer) (err error) { + // array header, size 32 + err = en.Append(0xdc, 0x0, 0x20) + if err != nil { + return + } + err = en.WriteString(z.Id) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + err = en.WriteInt64(z.CreateAt) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + err = en.WriteInt64(z.UpdateAt) + if err != nil { + err = msgp.WrapError(err, "UpdateAt") + return + } + err = en.WriteInt64(z.DeleteAt) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + err = en.WriteString(z.Username) + if err != nil { + err = msgp.WrapError(err, "Username") + return + } + err = en.WriteString(z.Password) + if err != nil { + err = msgp.WrapError(err, "Password") + return + } + if z.AuthData == nil { + err = en.WriteNil() + if err != nil { + return + } + } else { + err = en.WriteString(*z.AuthData) + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + } + err = en.WriteString(z.AuthService) + if err != nil { + err = msgp.WrapError(err, "AuthService") + return + } + err = en.WriteString(z.Email) + if err != nil { + err = msgp.WrapError(err, "Email") + return + } + err = en.WriteBool(z.EmailVerified) + if err != nil { + err = msgp.WrapError(err, "EmailVerified") + return + } + err = en.WriteString(z.Nickname) + if err != nil { + err = msgp.WrapError(err, "Nickname") + return + } + err = en.WriteString(z.FirstName) + if err != nil { + err = msgp.WrapError(err, "FirstName") + return + } + err = en.WriteString(z.LastName) + if err != nil { + err = msgp.WrapError(err, "LastName") + return + } + err = en.WriteString(z.Position) + if err != nil { + err = msgp.WrapError(err, "Position") + return + } + err = en.WriteString(z.Roles) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + err = en.WriteBool(z.AllowMarketing) + if err != nil { + err = msgp.WrapError(err, "AllowMarketing") + return + } + err = z.Props.EncodeMsg(en) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + err = z.NotifyProps.EncodeMsg(en) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + err = en.WriteInt64(z.LastPasswordUpdate) + if err != nil { + err = msgp.WrapError(err, "LastPasswordUpdate") + return + } + err = en.WriteInt64(z.LastPictureUpdate) + if err != nil { + err = msgp.WrapError(err, "LastPictureUpdate") + return + } + err = en.WriteInt(z.FailedAttempts) + if err != nil { + err = msgp.WrapError(err, "FailedAttempts") + return + } + err = en.WriteString(z.Locale) + if err != nil { + err = msgp.WrapError(err, "Locale") + return + } + err = z.Timezone.EncodeMsg(en) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + err = en.WriteBool(z.MfaActive) + if err != nil { + err = msgp.WrapError(err, "MfaActive") + return + } + err = en.WriteString(z.MfaSecret) + if err != nil { + err = msgp.WrapError(err, "MfaSecret") + return + } + if z.RemoteId == nil { + err = en.WriteNil() + if err != nil { + return + } + } else { + err = en.WriteString(*z.RemoteId) + if err != nil { + err = msgp.WrapError(err, "RemoteId") + return + } + } + err = en.WriteInt64(z.LastActivityAt) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + err = en.WriteBool(z.IsBot) + if err != nil { + err = msgp.WrapError(err, "IsBot") + return + } + err = en.WriteString(z.BotDescription) + if err != nil { + err = msgp.WrapError(err, "BotDescription") + return + } + err = en.WriteInt64(z.BotLastIconUpdate) + if err != nil { + err = msgp.WrapError(err, "BotLastIconUpdate") + return + } + err = en.WriteString(z.TermsOfServiceId) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceId") + return + } + err = en.WriteInt64(z.TermsOfServiceCreateAt) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceCreateAt") + return + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z *User) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + // array header, size 32 + o = append(o, 0xdc, 0x0, 0x20) + o = msgp.AppendString(o, z.Id) + o = msgp.AppendInt64(o, z.CreateAt) + o = msgp.AppendInt64(o, z.UpdateAt) + o = msgp.AppendInt64(o, z.DeleteAt) + o = msgp.AppendString(o, z.Username) + o = msgp.AppendString(o, z.Password) + if z.AuthData == nil { + o = msgp.AppendNil(o) + } else { + o = msgp.AppendString(o, *z.AuthData) + } + o = msgp.AppendString(o, z.AuthService) + o = msgp.AppendString(o, z.Email) + o = msgp.AppendBool(o, z.EmailVerified) + o = msgp.AppendString(o, z.Nickname) + o = msgp.AppendString(o, z.FirstName) + o = msgp.AppendString(o, z.LastName) + o = msgp.AppendString(o, z.Position) + o = msgp.AppendString(o, z.Roles) + o = msgp.AppendBool(o, z.AllowMarketing) + o, err = z.Props.MarshalMsg(o) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + o, err = z.NotifyProps.MarshalMsg(o) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + o = msgp.AppendInt64(o, z.LastPasswordUpdate) + o = msgp.AppendInt64(o, z.LastPictureUpdate) + o = msgp.AppendInt(o, z.FailedAttempts) + o = msgp.AppendString(o, z.Locale) + o, err = z.Timezone.MarshalMsg(o) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + o = msgp.AppendBool(o, z.MfaActive) + o = msgp.AppendString(o, z.MfaSecret) + if z.RemoteId == nil { + o = msgp.AppendNil(o) + } else { + o = msgp.AppendString(o, *z.RemoteId) + } + o = msgp.AppendInt64(o, z.LastActivityAt) + o = msgp.AppendBool(o, z.IsBot) + o = msgp.AppendString(o, z.BotDescription) + o = msgp.AppendInt64(o, z.BotLastIconUpdate) + o = msgp.AppendString(o, z.TermsOfServiceId) + o = msgp.AppendInt64(o, z.TermsOfServiceCreateAt) + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *User) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0001 uint32 + zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 != 32 { + err = msgp.ArrayError{Wanted: 32, Got: zb0001} + return + } + z.Id, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Id") + return + } + z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "CreateAt") + return + } + z.UpdateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "UpdateAt") + return + } + z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "DeleteAt") + return + } + z.Username, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Username") + return + } + z.Password, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Password") + return + } + if msgp.IsNil(bts) { + bts, err = msgp.ReadNilBytes(bts) + if err != nil { + return + } + z.AuthData = nil + } else { + if z.AuthData == nil { + z.AuthData = new(string) + } + *z.AuthData, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "AuthData") + return + } + } + z.AuthService, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "AuthService") + return + } + z.Email, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Email") + return + } + z.EmailVerified, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "EmailVerified") + return + } + z.Nickname, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Nickname") + return + } + z.FirstName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "FirstName") + return + } + z.LastName, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastName") + return + } + z.Position, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Position") + return + } + z.Roles, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Roles") + return + } + z.AllowMarketing, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "AllowMarketing") + return + } + bts, err = z.Props.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "Props") + return + } + bts, err = z.NotifyProps.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "NotifyProps") + return + } + z.LastPasswordUpdate, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastPasswordUpdate") + return + } + z.LastPictureUpdate, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastPictureUpdate") + return + } + z.FailedAttempts, bts, err = msgp.ReadIntBytes(bts) + if err != nil { + err = msgp.WrapError(err, "FailedAttempts") + return + } + z.Locale, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Locale") + return + } + bts, err = z.Timezone.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "Timezone") + return + } + z.MfaActive, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "MfaActive") + return + } + z.MfaSecret, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "MfaSecret") + return + } + if msgp.IsNil(bts) { + bts, err = msgp.ReadNilBytes(bts) + if err != nil { + return + } + z.RemoteId = nil + } else { + if z.RemoteId == nil { + z.RemoteId = new(string) + } + *z.RemoteId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "RemoteId") + return + } + } + z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "LastActivityAt") + return + } + z.IsBot, bts, err = msgp.ReadBoolBytes(bts) + if err != nil { + err = msgp.WrapError(err, "IsBot") + return + } + z.BotDescription, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "BotDescription") + return + } + z.BotLastIconUpdate, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "BotLastIconUpdate") + return + } + z.TermsOfServiceId, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceId") + return + } + z.TermsOfServiceCreateAt, bts, err = msgp.ReadInt64Bytes(bts) + if err != nil { + err = msgp.WrapError(err, "TermsOfServiceCreateAt") + return + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *User) Msgsize() (s int) { + s = 3 + msgp.StringPrefixSize + len(z.Id) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.Username) + msgp.StringPrefixSize + len(z.Password) + if z.AuthData == nil { + s += msgp.NilSize + } else { + s += msgp.StringPrefixSize + len(*z.AuthData) + } + s += msgp.StringPrefixSize + len(z.AuthService) + msgp.StringPrefixSize + len(z.Email) + msgp.BoolSize + msgp.StringPrefixSize + len(z.Nickname) + msgp.StringPrefixSize + len(z.FirstName) + msgp.StringPrefixSize + len(z.LastName) + msgp.StringPrefixSize + len(z.Position) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + z.Props.Msgsize() + z.NotifyProps.Msgsize() + msgp.Int64Size + msgp.Int64Size + msgp.IntSize + msgp.StringPrefixSize + len(z.Locale) + z.Timezone.Msgsize() + msgp.BoolSize + msgp.StringPrefixSize + len(z.MfaSecret) + if z.RemoteId == nil { + s += msgp.NilSize + } else { + s += msgp.StringPrefixSize + len(*z.RemoteId) + } + s += msgp.Int64Size + msgp.BoolSize + msgp.StringPrefixSize + len(z.BotDescription) + msgp.Int64Size + msgp.StringPrefixSize + len(z.TermsOfServiceId) + msgp.Int64Size + return +} + +// DecodeMsg implements msgp.Decodable +func (z *UserMap) DecodeMsg(dc *msgp.Reader) (err error) { + var zb0003 uint32 + zb0003, err = dc.ReadMapHeader() + if err != nil { + err = msgp.WrapError(err) + return + } + if (*z) == nil { + (*z) = make(UserMap, zb0003) + } else if len((*z)) > 0 { + for key := range *z { + delete((*z), key) + } + } + for zb0003 > 0 { + zb0003-- + var zb0001 string + var zb0002 *User + zb0001, err = dc.ReadString() + if err != nil { + err = msgp.WrapError(err) + return + } + if dc.IsNil() { + err = dc.ReadNil() + if err != nil { + err = msgp.WrapError(err, zb0001) + return + } + zb0002 = nil + } else { + if zb0002 == nil { + zb0002 = new(User) + } + err = zb0002.DecodeMsg(dc) + if err != nil { + err = msgp.WrapError(err, zb0001) + return + } + } + (*z)[zb0001] = zb0002 + } + return +} + +// EncodeMsg implements msgp.Encodable +func (z UserMap) EncodeMsg(en *msgp.Writer) (err error) { + err = en.WriteMapHeader(uint32(len(z))) + if err != nil { + err = msgp.WrapError(err) + return + } + for zb0004, zb0005 := range z { + err = en.WriteString(zb0004) + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0005 == nil { + err = en.WriteNil() + if err != nil { + return + } + } else { + err = zb0005.EncodeMsg(en) + if err != nil { + err = msgp.WrapError(err, zb0004) + return + } + } + } + return +} + +// MarshalMsg implements msgp.Marshaler +func (z UserMap) MarshalMsg(b []byte) (o []byte, err error) { + o = msgp.Require(b, z.Msgsize()) + o = msgp.AppendMapHeader(o, uint32(len(z))) + for zb0004, zb0005 := range z { + o = msgp.AppendString(o, zb0004) + if zb0005 == nil { + o = msgp.AppendNil(o) + } else { + o, err = zb0005.MarshalMsg(o) + if err != nil { + err = msgp.WrapError(err, zb0004) + return + } + } + } + return +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *UserMap) UnmarshalMsg(bts []byte) (o []byte, err error) { + var zb0003 uint32 + zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if (*z) == nil { + (*z) = make(UserMap, zb0003) + } else if len((*z)) > 0 { + for key := range *z { + delete((*z), key) + } + } + for zb0003 > 0 { + var zb0001 string + var zb0002 *User + zb0003-- + zb0001, bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if msgp.IsNil(bts) { + bts, err = msgp.ReadNilBytes(bts) + if err != nil { + return + } + zb0002 = nil + } else { + if zb0002 == nil { + zb0002 = new(User) + } + bts, err = zb0002.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, zb0001) + return + } + } + (*z)[zb0001] = zb0002 + } + o = bts + return +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z UserMap) Msgsize() (s int) { + s = msgp.MapHeaderSize + if z != nil { + for zb0004, zb0005 := range z { + _ = zb0005 + s += msgp.StringPrefixSize + len(zb0004) + if zb0005 == nil { + s += msgp.NilSize + } else { + s += zb0005.Msgsize() + } + } + } + return +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go b/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go index 3aed19da..0c5a272c 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go @@ -18,10 +18,11 @@ import ( "regexp" "strconv" "strings" + "sync" "time" "unicode" - goi18n "github.com/mattermost/go-i18n/i18n" + "github.com/mattermost/mattermost-server/v5/shared/i18n" "github.com/pborman/uuid" ) @@ -30,10 +31,10 @@ const ( UPPERCASE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" NUMBERS = "0123456789" SYMBOLS = " !\"\\#$%&'()*+,-./:;<=>?@[]^_`|~" + MB = 1 << 20 ) type StringInterface map[string]interface{} -type StringMap map[string]string type StringArray []string func (sa StringArray) Remove(input string) StringArray { @@ -72,10 +73,13 @@ func (sa StringArray) Equals(input StringArray) bool { return true } -var translateFunc goi18n.TranslateFunc = nil +var translateFunc i18n.TranslateFunc +var translateFuncOnce sync.Once -func AppErrorInit(t goi18n.TranslateFunc) { - translateFunc = t +func AppErrorInit(t i18n.TranslateFunc) { + translateFuncOnce.Do(func() { + translateFunc = t + }) } type AppError struct { @@ -93,7 +97,7 @@ func (er *AppError) Error() string { return er.Where + ": " + er.Message + ", " + er.DetailedError } -func (er *AppError) Translate(T goi18n.TranslateFunc) { +func (er *AppError) Translate(T i18n.TranslateFunc) { if T == nil { er.Message = er.Id return @@ -106,12 +110,11 @@ func (er *AppError) Translate(T goi18n.TranslateFunc) { } } -func (er *AppError) SystemMessage(T goi18n.TranslateFunc) string { +func (er *AppError) SystemMessage(T i18n.TranslateFunc) string { if er.params == nil { return T(er.Id) - } else { - return T(er.Id, er.params) } + return T(er.Id, er.params) } func (er *AppError) ToJson() string { @@ -132,11 +135,10 @@ func AppErrorFromJson(data io.Reader) *AppError { decoder := json.NewDecoder(strings.NewReader(str)) var er AppError err := decoder.Decode(&er) - if err == nil { - return &er - } else { + if err != nil { return NewAppError("AppErrorFromJson", "model.utils.decode_json.app_error", nil, "body: "+str, http.StatusInternalServerError) } + return &er } func NewAppError(where string, id string, params map[string]interface{}, details string, status int) *AppError { @@ -183,14 +185,6 @@ func NewRandomString(length int) string { return encoding.EncodeToString(data)[:length] } -// NewRandomBase32String returns a base32 encoded string of a random slice -// of bytes of the given size. The resulting entropy will be (8 * size) bits. -func NewRandomBase32String(size int) string { - data := make([]byte, size) - rand.Read(data) - return base32.StdEncoding.EncodeToString(data) -} - // GetMillis is a convenience method to get milliseconds since epoch. func GetMillis() int64 { return time.Now().UnixNano() / int64(time.Millisecond) @@ -201,6 +195,11 @@ func GetMillisForTime(thisTime time.Time) int64 { return thisTime.UnixNano() / int64(time.Millisecond) } +// GetTimeForMillis is a convenience method to get time.Time for milliseconds since epoch. +func GetTimeForMillis(millis int64) time.Time { + return time.Unix(0, millis*int64(time.Millisecond)) +} + // PadDateStringZeros is a convenience method to pad 2 digit date parts with zeros to meet ISO 8601 format func PadDateStringZeros(dateString string) string { parts := strings.Split(dateString, "-") @@ -254,9 +253,8 @@ func MapFromJson(data io.Reader) map[string]string { var objmap map[string]string if err := decoder.Decode(&objmap); err != nil { return make(map[string]string) - } else { - return objmap } + return objmap } // MapFromJson will decode the key/value pair map @@ -266,9 +264,8 @@ func MapBoolFromJson(data io.Reader) map[string]bool { var objmap map[string]bool if err := decoder.Decode(&objmap); err != nil { return make(map[string]bool) - } else { - return objmap } + return objmap } func ArrayToJson(objmap []string) string { @@ -282,9 +279,8 @@ func ArrayFromJson(data io.Reader) []string { var objmap []string if err := decoder.Decode(&objmap); err != nil { return make([]string, 0) - } else { - return objmap } + return objmap } func ArrayFromInterface(data interface{}) []string { @@ -315,9 +311,8 @@ func StringInterfaceFromJson(data io.Reader) map[string]interface{} { var objmap map[string]interface{} if err := decoder.Decode(&objmap); err != nil { return make(map[string]interface{}) - } else { - return objmap } + return objmap } func StringToJson(s string) string { @@ -331,14 +326,19 @@ func StringFromJson(data io.Reader) string { var s string if err := decoder.Decode(&s); err != nil { return "" - } else { - return s } + return s +} + +// ToJson serializes an arbitrary data type to JSON, discarding the error. +func ToJson(v interface{}) []byte { + b, _ := json.Marshal(v) + return b } func GetServerIpAddress(iface string) string { var addrs []net.Addr - if len(iface) == 0 { + if iface == "" { var err error addrs, err = net.InterfaceAddrs() if err != nil { @@ -397,6 +397,7 @@ var reservedName = []string{ "channel", "claim", "error", + "files", "help", "landing", "login", @@ -437,6 +438,12 @@ func IsValidAlphaNumHyphenUnderscore(s string, withFormat bool) bool { return validSimpleAlphaNumHyphenUnderscore.MatchString(s) } +func IsValidAlphaNumHyphenUnderscorePlus(s string) bool { + + validSimpleAlphaNumHyphenUnderscorePlus := regexp.MustCompile(`^[a-zA-Z0-9+_-]+$`) + return validSimpleAlphaNumHyphenUnderscorePlus.MatchString(s) +} + func Etag(parts ...interface{}) string { etag := CurrentVersion @@ -486,25 +493,6 @@ func ParseHashtags(text string) (string, string) { return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString) } -func IsFileExtImage(ext string) bool { - ext = strings.ToLower(ext) - for _, imgExt := range IMAGE_EXTENSIONS { - if ext == imgExt { - return true - } - } - return false -} - -func GetImageMimeType(ext string) string { - ext = strings.ToLower(ext) - if len(IMAGE_MIME_TYPES[ext]) == 0 { - return "image" - } else { - return IMAGE_MIME_TYPES[ext] - } -} - func ClearMentionTags(post string) string { post = strings.Replace(post, "<mention>", "", -1) post = strings.Replace(post, "</mention>", "", -1) @@ -721,3 +709,18 @@ func filterBlocklist(r rune) rune { return r } + +// UniqueStrings returns a unique subset of the string slice provided. +func UniqueStrings(input []string) []string { + u := make([]string, 0, len(input)) + m := make(map[string]bool) + + for _, val := range input { + if _, ok := m[val]; !ok { + m[val] = true + u = append(u, val) + } + } + + return u +} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/version.go b/vendor/github.com/mattermost/mattermost-server/v5/model/version.go index 63145660..36acddf2 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/version.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/version.go @@ -13,6 +13,17 @@ import ( // It should be maintained in chronological order with most current // release at the front of the list. var versions = []string{ + "5.39.0", + "5.38.2", + "5.38.1", + "5.38.0", + "5.37.0", + "5.36.0", + "5.35.0", + "5.34.0", + "5.33.0", + "5.32.0", + "5.31.0", "5.30.0", "5.29.0", "5.28.0", @@ -148,9 +159,8 @@ func IsCurrentVersion(versionToCheck string) bool { if toCheckMajor == currentMajor && toCheckMinor == currentMinor { return true - } else { - return false } + return false } func IsPreviousVersionsSupported(versionToCheck string) bool { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go index a4f92f80..9a845d36 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go @@ -70,6 +70,10 @@ const ( WEBSOCKET_WARN_METRIC_STATUS_RECEIVED = "warn_metric_status_received" WEBSOCKET_WARN_METRIC_STATUS_REMOVED = "warn_metric_status_removed" WEBSOCKET_EVENT_CLOUD_PAYMENT_STATUS_UPDATED = "cloud_payment_status_updated" + WEBSOCKET_EVENT_THREAD_UPDATED = "thread_updated" + WEBSOCKET_EVENT_THREAD_FOLLOW_CHANGED = "thread_follow_changed" + WEBSOCKET_EVENT_THREAD_READ_CHANGED = "thread_read_changed" + WEBSOCKET_FIRST_ADMIN_VISIT_MARKETPLACE_STATUS_RECEIVED = "first_admin_visit_marketplace_status_received" ) type WebSocketMessage interface { diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go index 6628a5c9..f18f1285 100644 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go +++ b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go @@ -7,7 +7,7 @@ import ( "encoding/json" "io" - goi18n "github.com/mattermost/go-i18n/i18n" + "github.com/mattermost/mattermost-server/v5/shared/i18n" ) // WebSocketRequest represents a request made to the server through a websocket. @@ -18,9 +18,9 @@ type WebSocketRequest struct { Data map[string]interface{} `json:"data"` // The metadata for an action. // Server-provided fields - Session Session `json:"-"` - T goi18n.TranslateFunc `json:"-"` - Locale string `json:"-"` + Session Session `json:"-"` + T i18n.TranslateFunc `json:"-"` + Locale string `json:"-"` } func (o *WebSocketRequest) ToJson() string { |