diff --git a/README.md b/README.md index 08a64d20..fbc2fc59 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engine, which doesn't spy on users. It can be embedded into blogs, articles or any other place where readers add comments. -* Social login via Google, Facebook, Github and Yandex +* Social login via Google, Facebook, GitHub and Yandex +* Login via email * Optional anonymous access * Multi-level nested comments with both tree and plain presentations * Import from Disqus and WordPress @@ -23,6 +24,16 @@ Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engi * Integration with automatic ssl (direct and via [nginx-le](https://github.com/umputun/nginx-le)) * [Privacy focused](#privacy) +[Demo site](https://remark42.com/demo/) available with all authentication methods, including email auth and anonymous access. + +
Screenshots + +Comments example: +![](https://github.com/umputun/remark/blob/master/screenshots/comments.png) + +For admin screenshots see [Admin UI wiki](https://github.com/umputun/remark/wiki/Admin-UI) +
+ # @@ -127,6 +138,16 @@ _this is the recommended way to run remark42_ | auth.yandex.csec | AUTH_YANDEX_CSEC | | Yandex OAuth client secret | | auth.dev | AUTH_DEV | `false` | local oauth2 server, development mode only | | auth.anon | AUTH_ANON | `false` | enable anonymous login | +| auth.email.enable | AUTH_EMAIL_ENABLE | `false` | enable auth via email | +| auth.email.host | AUTH_EMAIL_HOST | | smtp host | +| auth.email.port | AUTH_EMAIL_PORT | `25` | smtp port | +| auth.email.from | AUTH_EMAIL_FROM | | email from | +| auth.email.subj | AUTH_EMAIL_SUBJ | `remark42 confirmation` | email subject | +| auth.email.content-type | AUTH_EMAIL_CONTENT_TYPE | `text/html` | email content type | +| auth.email.tls | AUTH_EMAIL_TLS | `false` | enable TLS | +| auth.email.user | AUTH_EMAIL_USER | | smtp user name | +| auth.email.passwd | AUTH_EMAIL_PASSWD | | smtp password | +| auth.email.timeout | AUTH_EMAIL_TIMEOUT | `10s` | smtp timeout | | notify.type | NOTIFY_TYPE | none | type of notification (none or telegram) | | notify.queue | NOTIFY_QUEUE | `100` | size of notification queue | | notify.telegram.token | NOTIFY_TELEGRAM_TOKEN | | telegram token | @@ -148,6 +169,7 @@ _this is the recommended way to run remark42_ | edit-time | EDIT_TIME | `5m` | edit window | | read-age | READONLY_AGE | | read-only age of comments, days | | img-proxy | IMG_PROXY | `false` | enable http->https proxy for images | +| emoji | EMOJI | `false` | enable emoji support | | port | REMARK_PORT | `8080` | web server port | | web-root | REMARK_WEB_ROOT | `./web` | web server root directory | | update-limit | UPDATE_LIMIT | `0.5` | updates/sec limit | @@ -612,17 +634,18 @@ Sort can be `time`, `active` or `score`. Supported sort order with prefix -/+, i ```go type Config struct { - Version string `json:"version"` - EditDuration int `json:"edit_duration"` - MaxCommentSize int `json:"max_comment_size"` - Admins []string `json:"admins"` - AdminEmail string `json:"admin_email"` - Auth []string `json:"auth_providers"` - LowScore int `json:"low_score"` - CriticalScore int `json:"critical_score"` - PositiveScore bool `json:"positive_score"` - ReadOnlyAge int `json:"readonly_age"` - MaxImageSize int `json:"max_image_size"` + Version string `json:"version"` + EditDuration int `json:"edit_duration"` + MaxCommentSize int `json:"max_comment_size"` + Admins []string `json:"admins"` + AdminEmail string `json:"admin_email"` + Auth []string `json:"auth_providers"` + LowScore int `json:"low_score"` + CriticalScore int `json:"critical_score"` + PositiveScore bool `json:"positive_score"` + ReadOnlyAge int `json:"readonly_age"` + MaxImageSize int `json:"max_image_size"` + EmojiEnabled bool `json:"emoji_enabled"` } ``` @@ -632,8 +655,8 @@ Sort can be `time`, `active` or `score`. Supported sort order with prefix -/+, i Streaming API provide server-sent events for post updates as well as site update -* `GET /api/v1/stream/info?site=site-idd&url=post-url` - returns stream (`event: info`) with `PostInfo` records for the site and url` -* `GET /api/v1/stream/last?site=site-id` - returns updates stream (`event: last`) with comments for the site` +* `GET /api/v1/stream/info?site=site-idd&url=post-url&since=unix_ts_msec` - returns stream (`event: info`) with `PostInfo` records for the site and url. `since` is optional +* `GET /api/v1/stream/last?site=site-id&since=unix_ts_msec` - returns updates stream (`event: last`) with comments for the site, `since` is optional
response example diff --git a/backend/app/cmd/server.go b/backend/app/cmd/server.go index 2de778f4..5ff65abe 100644 --- a/backend/app/cmd/server.go +++ b/backend/app/cmd/server.go @@ -15,12 +15,14 @@ import ( bolt "github.com/coreos/bbolt" log "github.com/go-pkgz/lgr" + "github.com/kyokomi/emoji" authcache "github.com/patrickmn/go-cache" "github.com/pkg/errors" "github.com/go-pkgz/auth" "github.com/go-pkgz/auth/avatar" "github.com/go-pkgz/auth/provider" + "github.com/go-pkgz/auth/provider/sender" "github.com/go-pkgz/auth/token" "github.com/go-pkgz/rest/cache" @@ -63,6 +65,7 @@ type ServerCommand struct { WebRoot string `long:"web-root" env:"REMARK_WEB_ROOT" default:"./web" description:"web root directory"` UpdateLimit float64 `long:"update-limit" env:"UPDATE_LIMIT" default:"0.5" description:"updates/sec limit"` RestrictedWords []string `long:"restricted-words" env:"RESTRICTED_WORDS" description:"words prohibited to use in comments" env-delim:","` + EnableEmoji bool `long:"emoji" env:"EMOJI" description:"enable emoji"` Auth struct { TTL struct { @@ -75,6 +78,18 @@ type ServerCommand struct { Yandex AuthGroup `group:"yandex" namespace:"yandex" env-namespace:"YANDEX" description:"Yandex OAuth"` Dev bool `long:"dev" env:"DEV" description:"enable dev (local) oauth2"` Anonymous bool `long:"anon" env:"ANON" description:"enable anonymous login"` + Email struct { + Enable bool `long:"enable" env:"ENABLE" description:"enable auth via email"` + Host string `long:"host" env:"HOST" description:"smtp host"` + Port int `long:"port" env:"PORT" description:"smtp port"` + From string `long:"from" env:"FROM" description:"email's from"` + Subject string `long:"subj" env:"SUBJ" default:"remark42 confirmation" description:"email's subject"` + ContentType string `long:"content-type" env:"CONTENT_TYPE" default:"text/html" description:"content type"` + TLS bool `long:"tls" env:"TLS" description:"enable TLS"` + SMTPUserName string `long:"user" env:"USER" description:"smtp user name"` + SMTPPassword string `long:"passwd" env:"PASSWD" description:"smtp password"` + TimeOut time.Duration `long:"timeout" env:"TIMEOUT" default:"10s" description:"smtp timeout"` + } `group:"email" namespace:"email" env-namespace:"EMAIL"` } `group:"auth" namespace:"auth" env-namespace:"AUTH"` CommonOpts @@ -292,7 +307,11 @@ func (s *ServerCommand) newServerApp() (*serverApp, error) { } imgProxy := &proxy.Image{Enabled: s.ImageProxy, RoutePath: "/api/v1/img", RemarkURL: s.RemarkURL} - commentFormatter := store.NewCommentFormatter(imgProxy) + emojiFmt := store.CommentConverterFunc(func(text string) string { return text }) + if s.EnableEmoji { + emojiFmt = func(text string) string { return emoji.Sprint(text) } + } + commentFormatter := store.NewCommentFormatter(imgProxy, emojiFmt) sslConfig, err := s.makeSSLConfig() if err != nil { @@ -320,6 +339,7 @@ func (s *ServerCommand) newServerApp() (*serverApp, error) { Refresh: s.Stream.RefreshInterval, MaxActive: int32(s.Stream.MaxActive), }, + EmojiEnabled: s.EnableEmoji, } srv.ScoreThresholds.Low, srv.ScoreThresholds.Critical = s.LowScore, s.CriticalScore @@ -507,6 +527,28 @@ func (s *ServerCommand) makeCache() (cache.LoadingCache, error) { return nil, errors.Errorf("unsupported cache type %s", s.Cache.Type) } +var msgTemplate = ` + + + + + + + +
+

Remark42

+

Confirmation for {{.User}} on site {{.Site}}

+
+

TOKEN

+

Copy and paste this text into “token” field on comments page

+

{{.Token}}

+
+

Sent to {{.Address}}

+
+ + +` + func (s *ServerCommand) addAuthProviders(authenticator *auth.Service) { providers := 0 @@ -532,6 +574,22 @@ func (s *ServerCommand) addAuthProviders(authenticator *auth.Service) { providers++ } + if s.Auth.Email.Enable { + params := sender.EmailParams{ + Host: s.Auth.Email.Host, + Port: s.Auth.Email.Port, + From: s.Auth.Email.From, + Subject: s.Auth.Email.Subject, + ContentType: s.Auth.Email.ContentType, + TLS: s.Auth.Email.TLS, + SMTPUserName: s.Auth.Email.SMTPUserName, + SMTPPassword: s.Auth.Email.SMTPPassword, + TimeOut: s.Auth.Email.TimeOut, + } + sndr := sender.NewEmailClient(params, log.Default()) + authenticator.AddVerifProvider("email", msgTemplate, sndr) + } + if s.Auth.Anonymous { log.Print("[INFO] anonymous access enabled") var isValidAnonName = regexp.MustCompile(`^[a-zA-Z][\w ]+$`).MatchString @@ -632,6 +690,7 @@ func (s *ServerCommand) makeAuthenticator(ds *service.DataStore, avas avatar.Sto AvatarRoutePath: "/api/v1/avatar", Logger: log.Default(), RefreshCache: newAuthRefreshCache(), + UseGravatar: true, }) s.addAuthProviders(authenticator) return authenticator diff --git a/backend/app/cmd/server_test.go b/backend/app/cmd/server_test.go index c93f4afc..da72d6c5 100644 --- a/backend/app/cmd/server_test.go +++ b/backend/app/cmd/server_test.go @@ -45,8 +45,8 @@ func TestServerApp(t *testing.T) { client := http.Client{Timeout: 5 * time.Second} req, err := http.NewRequest("POST", fmt.Sprintf("http://localhost:%d/api/v1/comment", port), strings.NewReader(`{"text": "test 123", "locator":{"url": "https://radio-t.com/blah1", "site": "remark"}}`)) + require.NoError(t, err) req.SetBasicAuth("admin", "password") - require.Nil(t, err) resp, err = client.Do(req) require.Nil(t, err) assert.Equal(t, http.StatusCreated, resp.StatusCode) @@ -381,10 +381,10 @@ func TestServerAuthHooks(t *testing.T) { client := http.Client{Timeout: 1 * time.Second} req, err := http.NewRequest("POST", fmt.Sprintf("http://localhost:%d/api/v1/comment", port), strings.NewReader(`{"text": "test 123", "locator":{"url": "https://radio-t.com/p/2018/12/29/podcast-630/", "site": "remark"}}`)) + require.NoError(t, err) req.Header.Set("X-JWT", tk) - require.Nil(t, err) resp, err := client.Do(req) - require.Nil(t, err) + require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, http.StatusCreated, resp.StatusCode, "non-blocked user able to post") @@ -406,8 +406,8 @@ func TestServerAuthHooks(t *testing.T) { // try add a comment with blocked user req, err = http.NewRequest("POST", fmt.Sprintf("http://localhost:%d/api/v1/comment", port), strings.NewReader(`{"text": "test 123 blah", "locator":{"url": "https://radio-t.com/blah1", "site": "remark"}}`)) + require.NoError(t, err) req.Header.Set("X-JWT", tk) - require.Nil(t, err) resp, err = client.Do(req) require.Nil(t, err) defer resp.Body.Close() @@ -444,11 +444,10 @@ func prepServerApp(t *testing.T, duration time.Duration, fn func(o ServerCommand require.Nil(t, err) ctx, cancel := context.WithCancel(context.Background()) - go func() { - time.Sleep(duration) + time.AfterFunc(duration, func() { log.Print("[TEST] terminate app") cancel() - }() + }) rand.Seed(time.Now().UnixNano()) return app, ctx } diff --git a/backend/app/migrator/native_test.go b/backend/app/migrator/native_test.go index 85570563..63e3d591 100644 --- a/backend/app/migrator/native_test.go +++ b/backend/app/migrator/native_test.go @@ -40,25 +40,25 @@ func TestNative_Export(t *testing.T) { dec := json.NewDecoder(strings.NewReader(c1)) - meta := struct { + m := struct { Version int `json:"version"` Users []service.UserMetaData `json:"users"` Posts []service.PostMetaData `json:"posts"` }{} - require.NoError(t, dec.Decode(&meta), "decode meta") + require.NoError(t, dec.Decode(&m), "decode meta") - assert.Equal(t, 2, len(meta.Users)) - assert.Equal(t, "user1", meta.Users[0].ID) - assert.Equal(t, false, meta.Users[0].Blocked.Status) - assert.Equal(t, true, meta.Users[0].Verified) - assert.Equal(t, "user2", meta.Users[1].ID) - assert.Equal(t, true, meta.Users[1].Blocked.Status) - assert.Equal(t, false, meta.Users[1].Verified) + assert.Equal(t, 2, len(m.Users)) + assert.Equal(t, "user1", m.Users[0].ID) + assert.Equal(t, false, m.Users[0].Blocked.Status) + assert.Equal(t, true, m.Users[0].Verified) + assert.Equal(t, "user2", m.Users[1].ID) + assert.Equal(t, true, m.Users[1].Blocked.Status) + assert.Equal(t, false, m.Users[1].Verified) - assert.Equal(t, 1, len(meta.Posts)) - assert.Equal(t, "https://radio-t.com", meta.Posts[0].URL) - assert.Equal(t, true, meta.Posts[0].ReadOnly) + assert.Equal(t, 1, len(m.Posts)) + assert.Equal(t, "https://radio-t.com", m.Posts[0].URL) + assert.Equal(t, true, m.Posts[0].ReadOnly) comments := [3]store.Comment{} diff --git a/backend/app/rest/api/admin_test.go b/backend/app/rest/api/admin_test.go index 6398cc24..436d3a15 100644 --- a/backend/app/rest/api/admin_test.go +++ b/backend/app/rest/api/admin_test.go @@ -316,8 +316,8 @@ func TestAdmin_Block(t *testing.T) { err = json.Unmarshal([]byte(res), &comments) assert.Nil(t, err) assert.Equal(t, 2, len(comments.Comments), "should have 2 comments") - assert.Equal(t, "", comments.Comments[0].Text) - assert.True(t, comments.Comments[0].Deleted) + assert.Equal(t, "", comments.Comments[0].Text, "permanent block clear comment") + assert.True(t, comments.Comments[0].Deleted, "permanent block set deleted comment's status") // unblock code, body = block(-1, "") @@ -331,14 +331,15 @@ func TestAdmin_Block(t *testing.T) { code, _ = block(1, "50ms") require.Equal(t, 200, code) + // get as regular user res, code = get(t, ts.URL+"/api/v1/find?site=radio-t&url=https://radio-t.com/blah&sort=+time") assert.Equal(t, 200, code) comments = commentsWithInfo{} err = json.Unmarshal([]byte(res), &comments) assert.Nil(t, err) assert.Equal(t, 4, len(comments.Comments), "should have 4 comments") - assert.Equal(t, "", comments.Comments[2].Text) - assert.True(t, comments.Comments[2].Deleted) + assert.Equal(t, "test test #1", comments.Comments[2].Text, "comment not removed and not cleared") + assert.False(t, comments.Comments[2].Deleted, "not deleted") srv.pubRest.cache = &cache.Nop{} // TODO: with lru cache it won't be refreshed and invalidated for long time time.Sleep(50 * time.Millisecond) diff --git a/backend/app/rest/api/migrator_test.go b/backend/app/rest/api/migrator_test.go index a4041366..51ee0658 100644 --- a/backend/app/rest/api/migrator_test.go +++ b/backend/app/rest/api/migrator_test.go @@ -26,6 +26,7 @@ func TestMigrator_Import(t *testing.T) { client := &http.Client{Timeout: 1 * time.Second} req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=radio-t&provider=native", r) + require.NoError(t, err) req.SetBasicAuth("admin", "password") assert.Nil(t, err) resp, err := client.Do(req) @@ -116,6 +117,7 @@ func TestMigrator_ImportDouble(t *testing.T) { r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with 10k records client := &http.Client{Timeout: 1 * time.Second} req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=radio-t&provider=native", r) + require.NoError(t, err) req.SetBasicAuth("admin", "password") assert.Nil(t, err) resp, err := client.Do(req) @@ -124,6 +126,7 @@ func TestMigrator_ImportDouble(t *testing.T) { client = &http.Client{Timeout: 1 * time.Second} req, err = http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=radio-t&provider=native", r) + require.NoError(t, err) req.SetBasicAuth("admin", "password") assert.Nil(t, err) resp, err = client.Do(req) @@ -144,6 +147,7 @@ func TestMigrator_ImportWaitExpired(t *testing.T) { r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with 10k records client := &http.Client{Timeout: 1 * time.Second} req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=radio-t&provider=native", r) + require.NoError(t, err) req.SetBasicAuth("admin", "password") require.Nil(t, err) resp, err := client.Do(req) @@ -152,6 +156,7 @@ func TestMigrator_ImportWaitExpired(t *testing.T) { client = &http.Client{Timeout: 10 * time.Second} req, err = http.NewRequest("GET", ts.URL+"/api/v1/admin/import/wait?site=radio-t&timeout=100ms", nil) + require.NoError(t, err) req.SetBasicAuth("admin", "password") assert.NoError(t, err) resp, err = client.Do(req) @@ -220,6 +225,7 @@ func TestMigrator_Export(t *testing.T) { func waitForImportCompletion(t *testing.T, ts *httptest.Server) { client := &http.Client{Timeout: 10 * time.Second} req, err := http.NewRequest("GET", ts.URL+"/api/v1/admin/import/wait?site=radio-t", nil) + require.NoError(t, err) req.SetBasicAuth("admin", "password") assert.NoError(t, err) resp, err := client.Do(req) diff --git a/backend/app/rest/api/rest.go b/backend/app/rest/api/rest.go index 30d037d7..435efae3 100644 --- a/backend/app/rest/api/rest.go +++ b/backend/app/rest/api/rest.go @@ -55,6 +55,7 @@ type Rest struct { Critical int } UpdateLimiter float64 + EmojiEnabled bool SSLConfig SSLConfig httpsServer *http.Server @@ -392,6 +393,7 @@ func (s *Rest) configCtrl(w http.ResponseWriter, r *http.Request) { PositiveScore bool `json:"positive_score"` ReadOnlyAge int `json:"readonly_age"` MaxImageSize int `json:"max_image_size"` + EmojiEnabled bool `json:"emoji_enabled"` }{ Version: s.Version, EditDuration: int(s.DataService.EditDuration.Seconds()), @@ -403,6 +405,7 @@ func (s *Rest) configCtrl(w http.ResponseWriter, r *http.Request) { PositiveScore: s.DataService.PositiveScore, ReadOnlyAge: s.ReadOnlyAge, MaxImageSize: s.ImageService.Store.SizeLimit(), + EmojiEnabled: s.EmojiEnabled, } cnf.Auth = []string{} @@ -441,14 +444,14 @@ func addFileServer(r chi.Router, path string, root http.FileSystem) { path += "*" r.With(tollbooth_chi.LimitHandler(tollbooth.NewLimiter(20, nil)), middleware.Timeout(10*time.Second)). - Get(path, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Get(path, func(w http.ResponseWriter, r *http.Request) { // don't show dirs, just serve files if strings.HasSuffix(r.URL.Path, "/") && len(r.URL.Path) > 1 && r.URL.Path != (origPath+"/") { http.NotFound(w, r) return } webFS.ServeHTTP(w, r) - })) + }) } func encodeJSONWithHTML(v interface{}) ([]byte, error) { diff --git a/backend/app/rest/api/rest_public.go b/backend/app/rest/api/rest_public.go index 201b66de..e07464b5 100644 --- a/backend/app/rest/api/rest_public.go +++ b/backend/app/rest/api/rest_public.go @@ -16,6 +16,7 @@ import ( log "github.com/go-pkgz/lgr" R "github.com/go-pkgz/rest" "github.com/go-pkgz/rest/cache" + "github.com/pkg/errors" "github.com/umputun/remark/backend/app/rest" "github.com/umputun/remark/backend/app/store" @@ -36,7 +37,7 @@ type public struct { type pubStore interface { Create(comment store.Comment) (commentID string, err error) Get(locator store.Locator, commentID string, user store.User) (store.Comment, error) - Find(locator store.Locator, sort string, user store.User) ([]store.Comment, error) + FindSince(locator store.Locator, sort string, user store.User, since time.Time) ([]store.Comment, error) Last(siteID string, limit int, since time.Time, user store.User) ([]store.Comment, error) User(siteID, userID string, limit, skip int, user store.User) ([]store.Comment, error) UserCount(siteID, userID string) (int, error) @@ -49,7 +50,7 @@ type pubStore interface { Counts(siteID string, postIDs []string) ([]store.PostInfo, error) } -// GET /find?site=siteID&url=post-url&format=[tree|plain]&sort=[+/-time|+/-score|+/-controversy ]&view=[user|all] +// GET /find?site=siteID&url=post-url&format=[tree|plain]&sort=[+/-time|+/-score|+/-controversy]&view=[user|all]&since=unix_ts_msec // find comments for given post. Returns in tree or plain formats, sorted func (s *public) findCommentsCtrl(w http.ResponseWriter, r *http.Request) { locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")} @@ -59,17 +60,27 @@ func (s *public) findCommentsCtrl(w http.ResponseWriter, r *http.Request) { } view := r.URL.Query().Get("view") - log.Printf("[DEBUG] get comments for %+v, sort %s, format %s", locator, sort, r.URL.Query().Get("format")) + since, err := s.parseSince(r) + if err != nil { + rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't parse since", rest.ErrCommentNotFound) + return + } + format := r.URL.Query().Get("format") + if format == "tree" { + since = time.Time{} // since doesn't make sense for tree + } + + log.Printf("[DEBUG] get comments for %+v, sort %s, format %s, since %v", locator, sort, format, since) key := cache.NewKey(locator.SiteID).ID(URLKeyWithUser(r)).Scopes(locator.SiteID, locator.URL) data, err := s.cache.Get(key, func() ([]byte, error) { - comments, e := s.dataService.Find(locator, sort, rest.GetUserOrEmpty(r)) + comments, e := s.dataService.FindSince(locator, sort, rest.GetUserOrEmpty(r), since) if e != nil { comments = []store.Comment{} // error should clear comments and continue for post info } comments = s.applyView(comments, view) var b []byte - switch r.URL.Query().Get("format") { + switch format { case "tree": tree := service.MakeTree(comments, sort, s.readOnlyAge) if tree.Nodes == nil { // eliminate json nil serialization @@ -152,15 +163,10 @@ func (s *public) infoStreamCtrl(w http.ResponseWriter, r *http.Request) { locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")} log.Printf("[DEBUG] start stream for %+v, timeout=%v, refresh=%v", locator, s.streamer.TimeOut, s.streamer.Refresh) - sinceTs := time.Time{} - since := r.URL.Query().Get("since") - if since != "" { - unixTS, e := strconv.ParseInt(since, 10, 64) - if e != nil { - rest.SendErrorJSON(w, r, http.StatusBadRequest, e, "can't translate since parameter", rest.ErrDecode) - return - } - sinceTs = time.Unix(unixTS/1000, 1000000*(unixTS%1000)) // since param in msec timestamp + sinceTs, err := s.parseSince(r) + if err != nil { + rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't translate since parameter", rest.ErrDecode) + return } fn := func() steamEventFn { @@ -191,8 +197,8 @@ func (s *public) infoStreamCtrl(w http.ResponseWriter, r *http.Request) { } } - if err := s.streamer.Activate(r.Context(), fn, w); err != nil { - rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't stream", rest.ErrInternal) + if e := s.streamer.Activate(r.Context(), fn, w); e != nil { + rest.SendErrorJSON(w, r, http.StatusInternalServerError, e, "can't stream", rest.ErrInternal) } } @@ -207,14 +213,10 @@ func (s *public) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) { limit = 0 } - sinceTime := time.Time{} - if since := r.URL.Query().Get("since"); since != "" { - unixTS, e := strconv.ParseInt(since, 10, 64) - if e != nil { - rest.SendErrorJSON(w, r, http.StatusBadRequest, e, "can't translate since parameter", rest.ErrDecode) - return - } - sinceTime = time.Unix(unixTS/1000, 1000000*(unixTS%1000)) // since param in msec timestamp + sinceTime, err := s.parseSince(r) + if err != nil { + rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't translate since parameter", rest.ErrDecode) + return } key := cache.NewKey(siteID).ID(URLKey(r)).Scopes(lastCommentsScope) @@ -243,14 +245,13 @@ func (s *public) lastCommentsStreamCtrl(w http.ResponseWriter, r *http.Request) siteID := r.URL.Query().Get("site") log.Printf("[DEBUG] get last comments stream for %s", siteID) - sinceTs := time.Now() - if since := r.URL.Query().Get("since"); since != "" { - unixTS, e := strconv.ParseInt(since, 10, 64) - if e != nil { - rest.SendErrorJSON(w, r, http.StatusBadRequest, e, "can't translate since parameter", rest.ErrDecode) - return - } - sinceTs = time.Unix(unixTS/1000, 1000000*(unixTS%1000)) // since param in msec timestamp + sinceTs, err := s.parseSince(r) + if err != nil { + rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't translate since parameter", rest.ErrDecode) + return + } + if sinceTs.IsZero() { + sinceTs = time.Now() } fn := func() steamEventFn { @@ -273,8 +274,8 @@ func (s *public) lastCommentsStreamCtrl(w http.ResponseWriter, r *http.Request) } } - if err := s.streamer.Activate(r.Context(), fn, w); err != nil { - rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't stream", rest.ErrInternal) + if e := s.streamer.Activate(r.Context(), fn, w); e != nil { + rest.SendErrorJSON(w, r, http.StatusInternalServerError, e, "can't stream", rest.ErrInternal) } } @@ -499,3 +500,15 @@ func (s *public) applyView(comments []store.Comment, view string) []store.Commen } return comments } + +func (s *public) parseSince(r *http.Request) (time.Time, error) { + sinceTs := time.Time{} + if since := r.URL.Query().Get("since"); since != "" { + unixTS, e := strconv.ParseInt(since, 10, 64) + if e != nil { + return time.Time{}, errors.Wrap(e, "can't translate since parameter") + } + sinceTs = time.Unix(unixTS/1000, 1000000*(unixTS%1000)) // since param in msec timestamp + } + return sinceTs, nil +} diff --git a/backend/app/rest/api/rest_public_test.go b/backend/app/rest/api/rest_public_test.go index 3526b0d6..f7d5ec9f 100644 --- a/backend/app/rest/api/rest_public_test.go +++ b/backend/app/rest/api/rest_public_test.go @@ -505,6 +505,7 @@ func TestRest_Config(t *testing.T) { assert.False(t, j["positive_score"].(bool)) assert.Equal(t, 10., j["readonly_age"]) assert.Equal(t, 10000., j["max_image_size"]) + assert.Equal(t, true, j["emoji_enabled"].(bool)) t.Logf("%+v", j) } diff --git a/backend/app/rest/api/rest_test.go b/backend/app/rest/api/rest_test.go index 469ad4cd..84ab7d3d 100644 --- a/backend/app/rest/api/rest_test.go +++ b/backend/app/rest/api/rest_test.go @@ -297,14 +297,14 @@ func startupT(t *testing.T) (ts *httptest.Server, srv *Rest, teardown func()) { memCache, err := cache.NewMemoryCache() assert.NoError(t, err) - adminStore := adminstore.NewStaticStore("123456", []string{"a1", "a2"}, "admin@remark-42.com") + astore := adminstore.NewStaticStore("123456", []string{"a1", "a2"}, "admin@remark-42.com") restrictedWordsMatcher := service.NewRestrictedWordsMatcher(service.StaticRestrictedWordsLister{Words: []string{"duck"}}) dataStore := &service.DataStore{ Engine: b, EditDuration: 5 * time.Minute, MaxCommentSize: 4000, - AdminStore: adminStore, + AdminStore: astore, MaxVotes: service.UnlimitedVotes, RestrictedWordsMatcher: restrictedWordsMatcher, } @@ -337,13 +337,14 @@ func startupT(t *testing.T) (ts *httptest.Server, srv *Rest, teardown func()) { NativeImporter: &migrator.Native{DataStore: dataStore}, NativeExporter: &migrator.Native{DataStore: dataStore}, Cache: &cache.Nop{}, - KeyStore: adminStore, + KeyStore: astore, }, Streamer: &Streamer{ Refresh: 100 * time.Millisecond, TimeOut: 5 * time.Second, MaxActive: 100, }, + EmojiEnabled: true, } srv.ScoreThresholds.Low, srv.ScoreThresholds.Critical = -5, -10 @@ -387,7 +388,7 @@ func get(t *testing.T, url string) (string, int) { return string(body), r.StatusCode } -func sendReq(t *testing.T, r *http.Request, token string) (*http.Response, error) { +func sendReq(_ *testing.T, r *http.Request, token string) (*http.Response, error) { client := http.Client{Timeout: 5 * time.Second} if token != "" { r.Header.Set("X-JWT", token) diff --git a/backend/app/rest/api/rss.go b/backend/app/rest/api/rss.go index b2d1fe3c..8dafd5ab 100644 --- a/backend/app/rest/api/rss.go +++ b/backend/app/rest/api/rss.go @@ -159,6 +159,7 @@ func (s *rss) toRssFeed(url string, comments []store.Comment, description string parentComment, err := s.dataService.Get(c.Locator, c.ParentID, store.User{}) if err == nil { f.Title = fmt.Sprintf("%s > %s", c.User.Name, parentComment.User.Name) + f.Description = f.Description + "

" + parentComment.Snippet(300) + "

" } else { log.Printf("[WARN] failed to get info about parent comment, %s", err) } diff --git a/backend/app/rest/api/rss_test.go b/backend/app/rest/api/rss_test.go index 306de8b9..bab6c832 100644 --- a/backend/app/rest/api/rss_test.go +++ b/backend/app/rest/api/rss_test.go @@ -161,7 +161,7 @@ func TestServer_RssWithReply(t *testing.T) { developer one > developer one https://radio-t.com/blah10#remark42__comment-comment-id-2 - xyz test + xyz test<blockquote><p>test 123</p></blockquote> developer one comment-id-2 %s @@ -247,7 +247,7 @@ func TestServer_RssReplies(t *testing.T) { user3 > user1 https://radio-t.com/blah1#remark42__comment-comment-3 - reply to c1 from user3 + reply to c1 from user3<blockquote><p>c1</p></blockquote> user3 comment-3 %s @@ -255,7 +255,7 @@ func TestServer_RssReplies(t *testing.T) { user2 > user1 https://radio-t.com/blah1#remark42__comment-comment-2 - reply to c1 from user2 + reply to c1 from user2<blockquote><p>c1</p></blockquote> user2 comment-2 %s diff --git a/backend/app/rest/httperrors_test.go b/backend/app/rest/httperrors_test.go index f0fceec1..955293e4 100644 --- a/backend/app/rest/httperrors_test.go +++ b/backend/app/rest/httperrors_test.go @@ -50,11 +50,13 @@ func TestErrorDetailsMsg(t *testing.T) { func TestErrorDetailsMsgWithUser(t *testing.T) { callerFn := func() { req, err := http.NewRequest("GET", "https://example.com/test?k1=v1&k2=v2", nil) + require.NoError(t, err) req.RemoteAddr = "127.0.0.1:1234" req = SetUserInfo(req, store.User{Name: "test", ID: "id"}) require.Nil(t, err) msg := errDetailsMsg(req, 500, errors.New("error 500"), "error details 123456", 34567) - assert.Equal(t, "error details 123456 - error 500 - 500 (34567) - test/id - 127.0.0.1 - https://example.com/test?k1=v1&k2=v2 [caused by app/rest/httperrors_test.go:59 rest.TestErrorDetailsMsgWithUser]", msg) + assert.Equal(t, "error details 123456 - error 500 - 500 (34567) - test/id - 127.0.0.1 - https://example." + + "com/test?k1=v1&k2=v2 [caused by app/rest/httperrors_test.go:61 rest.TestErrorDetailsMsgWithUser]", msg) } callerFn() } diff --git a/backend/app/store/comment.go b/backend/app/store/comment.go index a6241184..c7ac03ca 100644 --- a/backend/app/store/comment.go +++ b/backend/app/store/comment.go @@ -3,6 +3,7 @@ package store import ( "html/template" "regexp" + "strings" "time" "github.com/microcosm-cc/bluemonday" @@ -66,6 +67,7 @@ const ( // Maximum length for URL text shortening. const shortURLLen = 48 +const snippetLen = 200 // PrepareUntrusted pre-processes a comment received from untrusted source by clearing all // autogen fields and reset everything users not supposed to provide @@ -107,3 +109,24 @@ func (c *Comment) Sanitize() { c.User.Name = template.HTMLEscapeString(c.User.Name) c.User.Picture = p.Sanitize(c.User.Picture) } + +// Snippet from comment's text +func (c *Comment) Snippet(limit int) string { + if limit <= 0 { + limit = snippetLen + } + cleanText := strings.Replace(c.Text, "\n", " ", -1) + size := len([]rune(cleanText)) + if size < limit { + return cleanText + } + snippet := []rune(cleanText)[:size] + // go back in snippet and found the first space + for i := len(snippet) - 1; i >= 0; i-- { + if snippet[i] == ' ' { + snippet = snippet[:i] + break + } + } + return string(snippet) + " ..." +} diff --git a/backend/app/store/comment_test.go b/backend/app/store/comment_test.go index 2829382b..1e619735 100644 --- a/backend/app/store/comment_test.go +++ b/backend/app/store/comment_test.go @@ -1,6 +1,7 @@ package store import ( + "strconv" "testing" "time" @@ -34,6 +35,14 @@ func TestComment_Sanitize(t *testing.T) { User: User{ID: "id", Name: "xyz"}, }, }, + { + inp: Comment{Text: "blah & & 123 — —"}, + out: Comment{Text: `blah & & 123 — —`}, + }, + { + inp: Comment{Text: "blah & & 123 — —"}, + out: Comment{Text: `blah & & 123 — —`}, + }, } for n, tt := range tbl { @@ -120,3 +129,25 @@ func TestComment_SetDeletedHard(t *testing.T) { assert.False(t, comment.Pin) assert.Equal(t, User{Name: "deleted", ID: "deleted", Picture: "", Admin: false, Blocked: false, IP: ""}, comment.User) } + +func TestComment_Snippet(t *testing.T) { + tbl := []struct { + limit int + inp string + out string + }{ + {0, "", ""}, + {-1, "test\nblah", "test blah"}, + {5, "test\nblah", "test ..."}, + {5, "xyz12345 xxx", "xyz12345 ..."}, + {10, "xyz12345 xxx\ntest 123456", "xyz12345 xxx test ..."}, + } + + for i, tt := range tbl { + t.Run(strconv.Itoa(i), func(t *testing.T) { + c := Comment{Text: tt.inp} + out := c.Snippet(tt.limit) + assert.Equal(t, tt.out, out) + }) + } +} diff --git a/backend/app/store/engine/bolt.go b/backend/app/store/engine/bolt.go index e1c9d4d1..14ad4755 100644 --- a/backend/app/store/engine/bolt.go +++ b/backend/app/store/engine/bolt.go @@ -164,7 +164,7 @@ func (b *BoltDB) Find(req FindRequest) (comments []store.Comment, err error) { } switch { - case req.Locator.SiteID != "" && req.Locator.URL != "": // find comments for site and url + case req.Locator.SiteID != "" && req.Locator.URL != "": // find post comments, i.e. for site and url err = bdb.View(func(tx *bolt.Tx) error { bucket, e := b.getPostBucket(tx, req.Locator.URL) @@ -177,7 +177,9 @@ func (b *BoltDB) Find(req FindRequest) (comments []store.Comment, err error) { if e = json.Unmarshal(v, &comment); e != nil { return errors.Wrap(e, "failed to unmarshal") } - comments = append(comments, comment) + if req.Since.IsZero() || comment.Timestamp.After(req.Since) { + comments = append(comments, comment) + } return nil }) }) diff --git a/backend/app/store/engine/bolt_test.go b/backend/app/store/engine/bolt_test.go index 5a284ef3..55e94df9 100644 --- a/backend/app/store/engine/bolt_test.go +++ b/backend/app/store/engine/bolt_test.go @@ -166,6 +166,29 @@ func TestBoltDB_FindLastSince(t *testing.T) { assert.Equal(t, 0, len(res)) } +func TestBoltDB_FindInPostSince(t *testing.T) { + var b, teardown = prep(t) + defer teardown() + + ts := time.Date(2017, 12, 20, 15, 18, 21, 0, time.Local) + req := FindRequest{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, Sort: "-time", Since: ts} + res, err := b.Find(req) + assert.NoError(t, err) + assert.Equal(t, 2, len(res)) + assert.Equal(t, "some text2", res[0].Text) + + req.Since = time.Date(2017, 12, 20, 15, 18, 22, 0, time.Local) + res, err = b.Find(req) + assert.NoError(t, err) + assert.Equal(t, 1, len(res)) + assert.Equal(t, "some text2", res[0].Text) + + req.Since = time.Date(2017, 12, 20, 16, 18, 22, 0, time.Local) + res, err = b.Find(req) + assert.NoError(t, err) + assert.Equal(t, 0, len(res)) +} + func TestBoltDB_FindForUser(t *testing.T) { var b, teardown = prep(t) defer teardown() diff --git a/backend/app/store/formatter.go b/backend/app/store/formatter.go index 61a386e6..b3b52c31 100644 --- a/backend/app/store/formatter.go +++ b/backend/app/store/formatter.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/PuerkitoBio/goquery" - blackfriday "gopkg.in/russross/blackfriday.v2" + bf "gopkg.in/russross/blackfriday.v2" ) // CommentFormatter implements all generic formatting ops on comment @@ -40,10 +40,16 @@ func (f *CommentFormatter) Format(c Comment) Comment { // FormatText converts text with markdown processor, applies external converters and shortens links func (f *CommentFormatter) FormatText(txt string) (res string) { - mdExt := blackfriday.NoIntraEmphasis | blackfriday.Tables | blackfriday.FencedCode | - blackfriday.Strikethrough | blackfriday.SpaceHeadings | blackfriday.HardLineBreak | - blackfriday.BackslashLineBreak | blackfriday.Autolink - res = string(blackfriday.Run([]byte(txt), blackfriday.WithExtensions(mdExt))) + mdExt := bf.NoIntraEmphasis | bf.Tables | bf.FencedCode | + bf.Strikethrough | bf.SpaceHeadings | bf.HardLineBreak | + bf.BackslashLineBreak | bf.Autolink + + rend := bf.NewHTMLRenderer(bf.HTMLRendererParameters{ + Flags: bf.Smartypants | bf.SmartypantsFractions | bf.SmartypantsDashes | bf.SmartypantsAngledQuotes, + }) + + res = string(bf.Run([]byte(txt), bf.WithExtensions(mdExt), bf.WithRenderer(rend))) + res = f.unEscape(res) for _, conv := range f.converters { res = conv.Convert(res) @@ -85,3 +91,16 @@ func (f *CommentFormatter) shortenAutoLinks(commentHTML string, max int) (resHTM } return resHTML } + +func (f *CommentFormatter) unEscape(txt string) (res string) { + elems := []struct { + from, to string + }{ + {`&mdash;`, "—"}, + } + res = txt + for _, e := range elems { + res = strings.Replace(res, e.from, e.to, -1) + } + return res +} diff --git a/backend/app/store/formatter_test.go b/backend/app/store/formatter_test.go index 95959ca3..52b34961 100644 --- a/backend/app/store/formatter_test.go +++ b/backend/app/store/formatter_test.go @@ -14,17 +14,23 @@ func (m mockConverter) Convert(text string) string { return text + "!converted" func TestFormatter_FormatText(t *testing.T) { tbl := []struct { in, out string + name string }{ - {"", "!converted"}, - {"12345 abc", "

12345 abc

\n!converted"}, - {"**xyz** _aaa_", "

xyz aaa

\n!converted"}, + {"", "!converted", "empty"}, + {"12345 abc", "

12345 abc

\n!converted", "simple"}, + {"**xyz** _aaa_ - \"sfs\"", "

xyz aaa – «sfs»

\n!converted", "format"}, { - "http://127.0.0.1/some-long-link/12345/678901234567890", "

http://127.0.0.1/some-long-link/12345/6789012...

\n!converted", + "http://127.0.0.1/some-long-link/12345/678901234567890", + "

http://127.0.0." + + "1/some-long-link/12345/6789012...

\n!converted", "links", }, + {"— not translated #354", "

— not translated #354

\n!converted", "mdash"}, } f := NewCommentFormatter(mockConverter{}) - for n, tt := range tbl { - assert.Equal(t, tt.out, f.FormatText(tt.in), "check #%d", n) + for _, tt := range tbl { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.out, f.FormatText(tt.in)) + }) } } diff --git a/backend/app/store/service/service.go b/backend/app/store/service/service.go index 5a537bc6..937cbd3c 100644 --- a/backend/app/store/service/service.go +++ b/backend/app/store/service/service.go @@ -101,10 +101,15 @@ func (s *DataStore) Create(comment store.Comment) (commentID string, err error) return s.Engine.Create(comment) } -// Find wraps engine's Find call and alter results if needed -// user used to filter results for self vs others +// Find wraps engine's Find call and alter results if needed. User used to alter comments +// in order to differentiate between user's comments vs others comments. func (s *DataStore) Find(locator store.Locator, sort string, user store.User) ([]store.Comment, error) { - req := engine.FindRequest{Locator: locator, Sort: sort} + return s.FindSince(locator, sort, user, time.Time{}) +} + +// FindSince wraps engine's Find call and alter results if needed. Returns comments after since tx +func (s *DataStore) FindSince(locator store.Locator, sort string, user store.User, since time.Time) ([]store.Comment, error) { + req := engine.FindRequest{Locator: locator, Sort: sort, Since: since} comments, err := s.Engine.Find(req) if err != nil { return comments, err @@ -729,19 +734,15 @@ func (s *DataStore) alterComments(cc []store.Comment, user store.User) (res []st func (s *DataStore) alterComment(c store.Comment, user store.User) (res store.Comment) { blocReq := engine.FlagRequest{Flag: engine.Blocked, Locator: store.Locator{SiteID: c.Locator.SiteID}, UserID: c.User.ID} - blocked, _ := s.Engine.Flag(blocReq) + blocked, bErr := s.Engine.Flag(blocReq) - // process blocked users - if blocked { - if !user.Admin { // reset comment to deleted for non-admins - c.SetDeleted(store.SoftDelete) - } - c.User.Blocked = true - c.Deleted = true + // mark user blocked + if bErr == nil && blocked { + c.User.Blocked = blocked } // set verified status retroactively - if !blocked { + if !c.User.Blocked { verifReq := engine.FlagRequest{Flag: engine.Verified, Locator: store.Locator{SiteID: c.Locator.SiteID}, UserID: c.User.ID} c.User.Verified, _ = s.Engine.Flag(verifReq) } diff --git a/backend/app/store/service/service_test.go b/backend/app/store/service/service_test.go index e19b659d..2573f791 100644 --- a/backend/app/store/service/service_test.go +++ b/backend/app/store/service/service_test.go @@ -802,6 +802,23 @@ func TestService_Find(t *testing.T) { assert.InDelta(t, 0, res[1].Controversy, 0.01) } +func TestService_FindSince(t *testing.T) { + // two comments for https://radio-t.com, no reply + b := DataStore{Engine: prepStoreEngine(t), EditDuration: 100 * time.Millisecond, + AdminStore: admin.NewStaticStore("secret 123", []string{"user2"}, "user@email.com")} + + res, err := b.FindSince(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "time", store.User{}, time.Time{}) + require.NoError(t, err) + assert.Equal(t, 2, len(res)) + assert.Equal(t, "id-1", res[0].ID) + + res, err = b.FindSince(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "time", store.User{}, + time.Date(2017, 12, 20, 15, 18, 22, 0, time.Local)) + require.NoError(t, err) + assert.Equal(t, 1, len(res)) + assert.Equal(t, "id-2", res[0].ID) +} + func TestService_Info(t *testing.T) { defer teardown(t) @@ -1044,7 +1061,7 @@ func TestService_alterComment(t *testing.T) { r = svc.alterComment(store.Comment{ID: "123", User: store.User{IP: "127.0.0.1", ID: "devid", Verified: true}}, store.User{Name: "dev", ID: "devid", Admin: false}) assert.Equal(t, store.Comment{ID: "123", User: store.User{IP: "", Verified: true, Blocked: true, ID: "devid"}, - Deleted: true}, r, "blocked") + Deleted: false}, r, "blocked") } // makes new boltdb, put two records diff --git a/backend/go.mod b/backend/go.mod index 8fccd3d5..f8fdac22 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,28 +5,26 @@ go 1.12 replace gopkg.in/russross/blackfriday.v2 => github.com/russross/blackfriday/v2 v2.0.1 require ( - cloud.google.com/go v0.39.0 // indirect + cloud.google.com/go v0.41.0 // indirect github.com/PuerkitoBio/goquery v1.5.0 - github.com/coreos/bbolt v1.3.2 + github.com/coreos/bbolt v1.3.3 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/didip/tollbooth v4.0.0+incompatible github.com/didip/tollbooth_chi v0.0.0-20170928041846-6ab5f3083f3d github.com/go-chi/chi v4.0.2+incompatible github.com/go-chi/cors v1.0.0 github.com/go-chi/render v1.0.1 - github.com/go-pkgz/auth v0.5.2 + github.com/go-pkgz/auth v0.7.2 github.com/go-pkgz/lcw v0.3.1 - github.com/go-pkgz/lgr v0.6.2 - github.com/go-pkgz/mongo v1.1.2 // indirect + github.com/go-pkgz/lgr v0.6.3 github.com/go-pkgz/repeater v1.1.2 github.com/go-pkgz/rest v1.4.1 github.com/go-pkgz/syncs v1.1.1 - github.com/golang/protobuf v1.3.1 // indirect github.com/google/uuid v1.1.1 github.com/gorilla/feeds v1.1.1 github.com/hashicorp/go-multierror v1.0.0 - github.com/hashicorp/golang-lru v0.5.1 // indirect github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc + github.com/kyokomi/emoji v2.1.0+incompatible github.com/microcosm-cc/bluemonday v1.0.2 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.8.1 @@ -35,14 +33,9 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.3.0 - go.etcd.io/bbolt v1.3.2 // indirect - golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 - golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff - golang.org/x/net v0.0.0-20190603091049-60506f45cf65 - golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect - golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed // indirect - golang.org/x/text v0.3.2 // indirect - golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect - google.golang.org/appengine v1.6.0 // indirect - gopkg.in/russross/blackfriday.v2 v2.0.0-00010101000000-000000000000 + golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 + golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9 + golang.org/x/net v0.0.0-20190628185345-da137c7871d7 + golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect + gopkg.in/russross/blackfriday.v2 v2.0.1 ) diff --git a/backend/go.sum b/backend/go.sum index bb82f445..56a7f941 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,20 +1,19 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.39.0 h1:UgQP9na6OTfp4dsAiz/eFpFA1C6tPdH5wiRdi19tuMw= -cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= +cloud.google.com/go v0.41.0 h1:NFvqUTDnSNYPX5oReekmB+D+90jrJIcVImxQ3qrBVgM= +cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= -github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -33,19 +32,19 @@ github.com/go-chi/cors v1.0.0 h1:e6x8k7uWbUwYs+aXDoiUzeQFT6l0cygBYyNhD7/1Tg0= github.com/go-chi/cors v1.0.0/go.mod h1:K2Yje0VW/SJzxiyMYu6iPQYa7hMjQX2i/F491VChg1I= github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8= github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns= -github.com/go-pkgz/auth v0.5.2 h1:Sdu2K6iZxMDt5nQSAomEbzJhmIoUqNwfFMiJwYV8Xn4= -github.com/go-pkgz/auth v0.5.2/go.mod h1:CWtB8dHmOv+TfF3MUzKwk/YwTLepC2TaDL05A+pFVBM= +github.com/go-pkgz/auth v0.7.2 h1:+LvAgqwQtYuWphpZE8qLtspVd65+VgreJkFLsKrtmmk= +github.com/go-pkgz/auth v0.7.2/go.mod h1:ibOpZYISiaOvAHe2bsKj2s3v4AkMam2WxxIFn+zhulo= github.com/go-pkgz/lcw v0.3.1 h1:PhfB0xNUawLMlx5rXvOTIc7d5LMrr1GM9vIzmG96aUI= github.com/go-pkgz/lcw v0.3.1/go.mod h1:k+PY1CkCMTLXILtFoJOyK65Qqi9rkoTYunFH1vE/C0I= github.com/go-pkgz/lgr v0.2.2/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= github.com/go-pkgz/lgr v0.6.2 h1:Twf2YIe2J5tg7mKs+IkDDxrDF7GWlTCl/LzqELWjT5o= github.com/go-pkgz/lgr v0.6.2/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= -github.com/go-pkgz/mongo v1.0.0/go.mod h1:R9si/F2aJsjz4MUxhzuppIHY8yLV3YCeuCpgcI50cu4= +github.com/go-pkgz/lgr v0.6.3 h1:n9pGk2paBV8w/Y/FVEq5MkwDmP33dnUPKbY4CyyygwM= +github.com/go-pkgz/lgr v0.6.3/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= github.com/go-pkgz/mongo v1.1.2 h1:2Vqn3CWQJkkx4gxxDiQUitAW2FN/CH26lKHkipmpKcc= github.com/go-pkgz/mongo v1.1.2/go.mod h1:0NkWnzpiUxoL5fYZuttCtJrpC67oNDidfYxcdPqHTf0= github.com/go-pkgz/repeater v1.1.2 h1:OxTyUMdEGiN4jRk5g3HHWQ6o4GDezjCLwpmDa/On+mU= github.com/go-pkgz/repeater v1.1.2/go.mod h1:QfNR/a+xqjs+f9wSxWqOQlw9aQhmKlUaSwXCiZ+Ko2w= -github.com/go-pkgz/rest v1.2.0/go.mod h1:COazNj35u3RXAgQNBr6neR599tYP3URiOpsu9p0rOtk= github.com/go-pkgz/rest v1.4.1 h1:DmaVLPH2O7yLehrWOW0uz01d2mVHz9fBR/iuTiPRzaw= github.com/go-pkgz/rest v1.4.1/go.mod h1:COazNj35u3RXAgQNBr6neR599tYP3URiOpsu9p0rOtk= github.com/go-pkgz/syncs v1.1.1 h1:jWN+y6FS/Xe+8z4l3QMbSnODGyaxDHGojIS+wyKIjxg= @@ -54,17 +53,22 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY= github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -83,6 +87,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kyokomi/emoji v2.1.0+incompatible h1:+DYU2RgpI6OHG4oQkM5KlqD3Wd3UPEsX8jamTo1Mp6o= +github.com/kyokomi/emoji v2.1.0+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA= github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 h1:Ys0rDzh8s4UMlGaDa1UTA0sfKgvF0hQZzTYX8ktjiDc= @@ -109,37 +115,45 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b h1:VHyIDlv3XkfCa5/a81uzaoDkHH4rr81Z62g+xlnO8uM= -golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff h1:+2zgJKVDVAz/BWSsuniCmU1kLCjL88Z8/kv39xCI9NQ= golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9 h1:uc17S921SPw5F2gJo7slQ3aqvr2RwpL7eb3+DZncu3s= +golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 h1:1DW40AJQ7AP4nY6ORUGUdkpXyEC9W2GAXcOPaMZK0K8= -golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -148,14 +162,19 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb h1:1w588/yEchbPNpa9sEvOcMZYbWHedwJjg4VOAdDHWHk= -golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed h1:uPxWBzB3+mlnjy9W58qY1j/cjyFjutgw/Vhan2zLy/A= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -167,18 +186,35 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw= -google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/backend/remark.rest b/backend/remark.rest index 0c96235f..5136091f 100644 --- a/backend/remark.rest +++ b/backend/remark.rest @@ -1,6 +1,6 @@ ### find request with tree -GET {{host}}/api/v1/find?site={{site}}&sort=-controversy&format=tree&url={{url}} +GET {{host}}/api/v1/find?site={{site}}&sort=-time&format=tree&url={{url}} ### find request with plain GET {{host}}/api/v1/find?site={{site}}&sort=-controversy&format=plain&url={{url}} @@ -104,7 +104,7 @@ GET {{host}}/api/v1/admin/blocked?site={{site}} DELETE {{host}}/api/v1/admin/comment/3665976683?site={{site}}&url={{url}} ### get post info -GET {{host}}/api/v1/info?site={{site}}&url=https://radio-t.com/p/2018/05/08/prep-597/ +GET {{host}}/api/v1/info?site={{site}}&url={{url} ### post rss GET {{host}}/api/v1/rss/post?site={{site}}&url={{url}} @@ -121,7 +121,7 @@ GET {{host}}/api/v1/avatar/blah ### get config GET {{host}}/api/v1/config?site={{site}} -### deleteme (use request). dev token for secret=secret, not admin +### deleteme (user's request). dev token for secret=secret, not admin POST {{host}}/api/v1/deleteme?site_id={{site}} X-JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyZW1hcms0MiIsImV4cCI6Mzc4OTE5MTgyMiwianRpIjoicmFuZG9tIGlkIiwiaXNzIjoicmVtYXJrNDIiLCJuYmYiOjE1MjE4ODQyMjIsInVzZXIiOnsibmFtZSI6ImRldmVsb3BlciBvbmUiLCJpZCI6ImRldiIsInBpY3R1cmUiOiJodHRwOi8vZXhhbXBsZS5jb20vcGljLnBuZyIsImlwIjoiMTI3LjAuMC4xIiwiZW1haWwiOiJtZUBleGFtcGxlLmNvbSJ9fQ.aKUAXiZxXypgV7m1wEOgUcyPOvUDXHDi3A06YWKbcLg diff --git a/backend/vendor/github.com/coreos/bbolt/bolt_riscv64.go b/backend/vendor/github.com/coreos/bbolt/bolt_riscv64.go new file mode 100644 index 00000000..07b4b47c --- /dev/null +++ b/backend/vendor/github.com/coreos/bbolt/bolt_riscv64.go @@ -0,0 +1,12 @@ +// +build riscv64 + +package bbolt + +// maxMapSize represents the largest mmap size supported by Bolt. +const maxMapSize = 0xFFFFFFFFFFFF // 256TB + +// maxAllocSize is the size used when creating array pointers. +const maxAllocSize = 0x7FFFFFFF + +// Are unaligned load/stores broken on this arch? +var brokenUnaligned = true diff --git a/backend/vendor/github.com/coreos/bbolt/db.go b/backend/vendor/github.com/coreos/bbolt/db.go index 962248c9..870c8b1c 100644 --- a/backend/vendor/github.com/coreos/bbolt/db.go +++ b/backend/vendor/github.com/coreos/bbolt/db.go @@ -121,6 +121,7 @@ type DB struct { AllocSize int path string + openFile func(string, int, os.FileMode) (*os.File, error) file *os.File dataref []byte // mmap'ed readonly, write throws SEGV data *[maxMapSize]byte @@ -199,10 +200,15 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) { db.readOnly = true } + db.openFile = options.OpenFile + if db.openFile == nil { + db.openFile = os.OpenFile + } + // Open data file and separate sync handler for metadata writes. db.path = path var err error - if db.file, err = os.OpenFile(db.path, flag|os.O_CREATE, mode); err != nil { + if db.file, err = db.openFile(db.path, flag|os.O_CREATE, mode); err != nil { _ = db.close() return nil, err } @@ -1054,6 +1060,10 @@ type Options struct { // set directly on the DB itself when returned from Open(), but this option // is useful in APIs which expose Options but not the underlying DB. NoSync bool + + // OpenFile is used to open files. It defaults to os.OpenFile. This option + // is useful for writing hermetic tests. + OpenFile func(string, int, os.FileMode) (*os.File, error) } // DefaultOptions represent the options used if nil options are passed into Open(). diff --git a/backend/vendor/github.com/coreos/bbolt/freelist.go b/backend/vendor/github.com/coreos/bbolt/freelist.go index 93fd85d5..587b8cc0 100644 --- a/backend/vendor/github.com/coreos/bbolt/freelist.go +++ b/backend/vendor/github.com/coreos/bbolt/freelist.go @@ -349,6 +349,28 @@ func (f *freelist) reload(p *page) { f.readIDs(a) } +// noSyncReload reads the freelist from pgids and filters out pending items. +func (f *freelist) noSyncReload(pgids []pgid) { + // Build a cache of only pending pages. + pcache := make(map[pgid]bool) + for _, txp := range f.pending { + for _, pendingID := range txp.ids { + pcache[pendingID] = true + } + } + + // Check each page in the freelist and build a new available freelist + // with any pages not in the pending lists. + var a []pgid + for _, id := range pgids { + if !pcache[id] { + a = append(a, id) + } + } + + f.readIDs(a) +} + // reindex rebuilds the free cache based on available and pending free lists. func (f *freelist) reindex() { ids := f.getFreePageIDs() diff --git a/backend/vendor/github.com/coreos/bbolt/tx.go b/backend/vendor/github.com/coreos/bbolt/tx.go index f5086414..2df7688c 100644 --- a/backend/vendor/github.com/coreos/bbolt/tx.go +++ b/backend/vendor/github.com/coreos/bbolt/tx.go @@ -254,17 +254,36 @@ func (tx *Tx) Rollback() error { if tx.db == nil { return ErrTxClosed } - tx.rollback() + tx.nonPhysicalRollback() return nil } +// nonPhysicalRollback is called when user calls Rollback directly, in this case we do not need to reload the free pages from disk. +func (tx *Tx) nonPhysicalRollback() { + if tx.db == nil { + return + } + if tx.writable { + tx.db.freelist.rollback(tx.meta.txid) + } + tx.close() +} + +// rollback needs to reload the free pages from disk in case some system error happens like fsync error. func (tx *Tx) rollback() { if tx.db == nil { return } if tx.writable { tx.db.freelist.rollback(tx.meta.txid) - tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist)) + if !tx.db.hasSyncedFreelist() { + // Reconstruct free page list by scanning the DB to get the whole free page list. + // Note: scaning the whole db is heavy if your db size is large in NoSyncFreeList mode. + tx.db.freelist.noSyncReload(tx.db.freepages()) + } else { + // Read free page list from freelist page. + tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist)) + } } tx.close() } @@ -315,7 +334,7 @@ func (tx *Tx) Copy(w io.Writer) error { // If err == nil then exactly tx.Size() bytes will be written into the writer. func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) { // Attempt to open reader with WriteFlag - f, err := os.OpenFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0) + f, err := tx.db.openFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0) if err != nil { return 0, err } @@ -369,7 +388,7 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) { // A reader transaction is maintained during the copy so it is safe to continue // using the database while a copy is in progress. func (tx *Tx) CopyFile(path string, mode os.FileMode) error { - f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) + f, err := tx.db.openFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) if err != nil { return err } diff --git a/backend/vendor/github.com/go-pkgz/auth/.travis.yml b/backend/vendor/github.com/go-pkgz/auth/.travis.yml index 9fa53154..dbce24ab 100644 --- a/backend/vendor/github.com/go-pkgz/auth/.travis.yml +++ b/backend/vendor/github.com/go-pkgz/auth/.travis.yml @@ -4,13 +4,14 @@ services: - mongodb go: - - "1.11.x" + - "1.12.x" install: true before_install: - export TZ=America/Chicago - - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.13.2 + - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.17.1 + - golangci-lint --version - go get github.com/mattn/goveralls - export MONGO_TEST=mongodb://127.0.0.1:27017 - export PATH=$(pwd)/bin:$PATH @@ -18,6 +19,6 @@ before_install: script: - GO111MODULE=on go get ./... - GO111MODULE=on go mod vendor - - GO111MODULE=on go test -v -mod=vendor -covermode=count -coverprofile=profile.cov ./... || travis_terminate 1; + - GO111MODULE=on go test -v -mod=vendor -covermode=count -coverprofile=profile.cov ./... || travis_terminate 1; - golangci-lint run --tests=false || travis_terminate 1; - $GOPATH/bin/goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/backend/vendor/github.com/go-pkgz/auth/README.md b/backend/vendor/github.com/go-pkgz/auth/README.md index 2109af13..97c14766 100644 --- a/backend/vendor/github.com/go-pkgz/auth/README.md +++ b/backend/vendor/github.com/go-pkgz/auth/README.md @@ -9,7 +9,8 @@ This library provides "social login" with Github, Google, Facebook and Yandex as - JWT stored in a secure cookie with XSRF protection. Cookies can be session-only - Minimal scopes with user name, id and picture (avatar) only - Direct authentication with user's provided credential checker -- Integrated avatar proxy with FS, boltdb and gridfs storages +- Verified authentication with user's provided sender (email, im, etc) +- Integrated avatar proxy with FS, boltdb and gridfs storage - Support of user-defined storage for avatars - Identicon for default avatars - Black list with user-defined validator @@ -146,6 +147,41 @@ Such provider acts like any other, i.e. will be registered as `/auth/local/login The API for this provider - `GET /auth//login?user=&passwd=&aud=&session=[1|0]` _note: password parameter doesn't have to be naked/real password and can be any kind of password hash prepared by caller._ + +### Verified authentication + +Another non-oauth2 provider allowing user-confirmed authentication, for example by email or slack or telegram. This is +done by adding confirmed provider with `auth.AddVerifProvider`. + +```go + msgTemplate := "Confirmation email, token: {{.Token}}" + service.AddVerifProvider("email", msgTemplate, sender) +``` + +Message template may use the follow elements: + +- `{{.Address}}` - user address, for example email +- `{{.User}}` - user name +- `{{.Token}}` - confirmation token +- `{{.Site}}` - site ID + +Sender should be provided by end-user and implements a single function interface + +```go +type Sender interface { + Send(address string, text string) error +} +``` + +For convenience a functional wrapper `SenderFunc` provided. Email sender provided in `provider/sender` package and can be +used as `Sender`. + +The API for this provider: + + - `GET /auth//login?user=&address=&aud=&from=` - send confirmation request to user + - `GET /auth//login?token=&sess=[1|0]` - authorize with confirmation token + +The provider acts like any other, i.e. will be registered as `/auth/email/login`. ### Customization @@ -267,6 +303,7 @@ _instructions for google oauth2 setup borrowed from [oauth2_proxy](https://githu For more details refer to [Yandex OAuth](https://tech.yandex.com/oauth/doc/dg/concepts/about-docpage/) and [Yandex.Passport](https://tech.yandex.com/passport/doc/dg/index-docpage/) API documentation. + ## Status The library extracted from [remark42](https://github.com/umputun/remark) project. The original code in production use on multiple sites and seems to work fine. diff --git a/backend/vendor/github.com/go-pkgz/auth/auth.go b/backend/vendor/github.com/go-pkgz/auth/auth.go index 6f9b3afb..546b6f9d 100644 --- a/backend/vendor/github.com/go-pkgz/auth/auth.go +++ b/backend/vendor/github.com/go-pkgz/auth/auth.go @@ -26,6 +26,7 @@ type Service struct { authMiddleware middleware.Authenticator avatarProxy *avatar.Proxy issuer string + useGravatar bool } // Opts is a full set of all parameters to initialize Service @@ -54,6 +55,7 @@ type Opts struct { AvatarStore avatar.Store // store to save/load avatars, required AvatarResizeLimit int // resize avatar's limit in pixels AvatarRoutePath string // avatar routing prefix, i.e. "/api/v1/avatar", default `/avatar` + UseGravatar bool // for email based auth (verified provider) use gravatar service AdminPasswd string // if presented, allows basic auth with user admin and given password AudienceReader token.Audience // list of allowed aud values, default (empty) allows any @@ -72,7 +74,8 @@ func NewService(opts Opts) (res *Service) { AdminPasswd: opts.AdminPasswd, RefreshCache: opts.RefreshCache, }, - issuer: opts.Issuer, + issuer: opts.Issuer, + useGravatar: opts.UseGravatar, } if opts.Issuer == "" { @@ -235,6 +238,22 @@ func (s *Service) AddDirectProvider(name string, credChecker provider.CredChecke s.authMiddleware.Providers = s.providers } +// AddVerifProvider adds provider user's verification sent by sender +func (s *Service) AddVerifProvider(name string, msgTmpl string, sender provider.Sender) { + dh := provider.VerifyHandler{ + L: s.logger, + ProviderName: name, + Issuer: s.issuer, + TokenService: s.jwtService, + AvatarSaver: s.avatarProxy, + Sender: sender, + Template: msgTmpl, + UseGravatar: s.useGravatar, + } + s.providers = append(s.providers, provider.NewService(dh)) + s.authMiddleware.Providers = s.providers +} + // DevAuth makes dev oauth2 server, for testing and development only! func (s *Service) DevAuth() (*provider.DevAuthServer, error) { p, err := s.Provider("dev") // peak dev provider diff --git a/backend/vendor/github.com/go-pkgz/auth/avatar/avatar.go b/backend/vendor/github.com/go-pkgz/auth/avatar/avatar.go index 8c816a8f..c71d7c70 100644 --- a/backend/vendor/github.com/go-pkgz/auth/avatar/avatar.go +++ b/backend/vendor/github.com/go-pkgz/auth/avatar/avatar.go @@ -4,6 +4,8 @@ package avatar import ( "bytes" + "crypto/md5" + "encoding/hex" "image" "image/png" "io" @@ -182,6 +184,25 @@ func GenerateAvatar(user string) ([]byte, error) { return buf.Bytes(), err } +// GetGravatarURL returns url to gravatar picture for given email +func GetGravatarURL(email string) (res string, err error) { + + hash := md5.Sum([]byte(email)) + hexHash := hex.EncodeToString(hash[:]) + + client := http.Client{Timeout: 1 * time.Second} + res = "https://www.gravatar.com/avatar/" + hexHash + ".jpg" + resp, err := client.Get(res + "?d=404&s=80") + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return "", errors.New(resp.Status) + } + return res, nil +} + func retry(retries int, delay time.Duration, fn func() error) (err error) { for i := 0; i < retries; i++ { if err = fn(); err == nil { diff --git a/backend/vendor/github.com/go-pkgz/auth/go.mod b/backend/vendor/github.com/go-pkgz/auth/go.mod index e6b5dd84..e30a71a0 100644 --- a/backend/vendor/github.com/go-pkgz/auth/go.mod +++ b/backend/vendor/github.com/go-pkgz/auth/go.mod @@ -1,22 +1,22 @@ module github.com/go-pkgz/auth require ( - cloud.google.com/go v0.34.0 // indirect - github.com/boltdb/bolt v1.3.1 // indirect - github.com/coreos/bbolt v1.3.0 + cloud.google.com/go v0.40.0 // indirect + github.com/coreos/bbolt v1.3.3 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 - github.com/go-pkgz/mongo v1.0.0 - github.com/go-pkgz/rest v1.2.0 + github.com/go-pkgz/lgr v0.6.2 // indirect + github.com/go-pkgz/mongo v1.1.2 + github.com/go-pkgz/rest v1.4.1 github.com/kr/pretty v0.1.0 // indirect github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.3.0 - golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b - golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 // indirect - golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 - golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect - golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb // indirect - google.golang.org/appengine v1.4.0 // indirect + go.etcd.io/bbolt v1.3.3 // indirect + golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff + golang.org/x/net v0.0.0-20190611141213-3f473d35a33a // indirect + golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 + golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae // indirect + google.golang.org/appengine v1.6.1 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) diff --git a/backend/vendor/github.com/go-pkgz/auth/go.sum b/backend/vendor/github.com/go-pkgz/auth/go.sum index d49f877a..920e5a20 100644 --- a/backend/vendor/github.com/go-pkgz/auth/go.sum +++ b/backend/vendor/github.com/go-pkgz/auth/go.sum @@ -1,24 +1,45 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= -github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.40.0 h1:FjSY7bOj+WzJe6TZRVtXI2b9kAYvtNg4lMbcH2+MUkk= +cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/globalsign/mgo v0.0.0-20180615134936-113d3961e731/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-pkgz/mongo v1.0.0 h1:9jijAK7prCRMetiyTu3c1rv/2lMypzuf2DWcVpTlwzw= -github.com/go-pkgz/mongo v1.0.0/go.mod h1:R9si/F2aJsjz4MUxhzuppIHY8yLV3YCeuCpgcI50cu4= -github.com/go-pkgz/rest v1.2.0 h1:75GVv25NmkV2l4dBr/io/ZApJ6zWQu5aZ4wFJA6QQCw= -github.com/go-pkgz/rest v1.2.0/go.mod h1:COazNj35u3RXAgQNBr6neR599tYP3URiOpsu9p0rOtk= +github.com/go-pkgz/lgr v0.2.2/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= +github.com/go-pkgz/lgr v0.6.2 h1:Twf2YIe2J5tg7mKs+IkDDxrDF7GWlTCl/LzqELWjT5o= +github.com/go-pkgz/lgr v0.6.2/go.mod h1:hBM1NM/SoYdlrykgdgJWGrZ/TM/XaZIjRbJfx7NkMm8= +github.com/go-pkgz/mongo v1.1.2 h1:2Vqn3CWQJkkx4gxxDiQUitAW2FN/CH26lKHkipmpKcc= +github.com/go-pkgz/mongo v1.1.2/go.mod h1:0NkWnzpiUxoL5fYZuttCtJrpC67oNDidfYxcdPqHTf0= +github.com/go-pkgz/rest v1.4.1 h1:DmaVLPH2O7yLehrWOW0uz01d2mVHz9fBR/iuTiPRzaw= +github.com/go-pkgz/rest v1.4.1/go.mod h1:COazNj35u3RXAgQNBr6neR599tYP3URiOpsu9p0rOtk= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -33,21 +54,78 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b h1:VHyIDlv3XkfCa5/a81uzaoDkHH4rr81Z62g+xlnO8uM= -golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff h1:+2zgJKVDVAz/BWSsuniCmU1kLCjL88Z8/kv39xCI9NQ= +golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0 h1:1DW40AJQ7AP4nY6ORUGUdkpXyEC9W2GAXcOPaMZK0K8= -golang.org/x/net v0.0.0-20190107210223-45ffb0cd1ba0/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a h1:+KkCgOMgnKSgenxTBoiwkMqTiouMIy/3o8RLdmSbGoY= +golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb h1:1w588/yEchbPNpa9sEvOcMZYbWHedwJjg4VOAdDHWHk= -golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae h1:xiXzMMEQdQcric9hXtr1QU98MHunKK7OTtsoU6bYWs4= +golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/backend/vendor/github.com/go-pkgz/auth/provider/direct.go b/backend/vendor/github.com/go-pkgz/auth/provider/direct.go index 65465187..03034890 100644 --- a/backend/vendor/github.com/go-pkgz/auth/provider/direct.go +++ b/backend/vendor/github.com/go-pkgz/auth/provider/direct.go @@ -69,9 +69,16 @@ func (p DirectHandler) LoginHandler(w http.ResponseWriter, r *http.Request) { return } + cid, err := randToken() + if err != nil { + rest.SendErrorJSON(w, r, p.L, http.StatusInternalServerError, err, "can't make token id") + return + } + claims := token.Claims{ User: &u, StandardClaims: jwt.StandardClaims{ + Id: cid, Issuer: p.Issuer, Audience: aud, }, diff --git a/backend/vendor/github.com/go-pkgz/auth/provider/sender/email.go b/backend/vendor/github.com/go-pkgz/auth/provider/sender/email.go new file mode 100644 index 00000000..2e685e76 --- /dev/null +++ b/backend/vendor/github.com/go-pkgz/auth/provider/sender/email.go @@ -0,0 +1,151 @@ +package sender + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "net" + "net/smtp" + "time" + + "github.com/pkg/errors" + + "github.com/go-pkgz/auth/logger" +) + +// Email implements sender interface for VerifyHandler +// Uses common subject line and "from" for all messages +type Email struct { + logger.L + SMTPClient + EmailParams +} + +// EmailParams with all needed to make new Email client with smtp +type EmailParams struct { + Host string // SMTP host + Port int // SMTP port + From string // From email field + Subject string // Email subject + ContentType string // Content type, optional. Will trigger MIME and Content-Type headers + + TLS bool // TLS auth + SMTPUserName string // user name + SMTPPassword string // password + TimeOut time.Duration +} + +// SMTPClient interface defines subset of net/smtp used by email client +type SMTPClient interface { + Mail(string) error + Auth(smtp.Auth) error + Rcpt(string) error + Data() (io.WriteCloser, error) + Quit() error + Close() error +} + +// NewEmailClient creates email client with prepared smtp +func NewEmailClient(p EmailParams, l logger.L) *Email { + return &Email{EmailParams: p, L: l, SMTPClient: nil} +} + +// Send email with given text +// If SMTPClient defined in Email struct it will be used, if not - new smtp.Client on each send. +// Always closes client on completion or failure. +func (em *Email) Send(to string, text string) error { + em.Logf("[DEBUG] send %q to %s", text, to) + client := em.SMTPClient + if client == nil { // if client not set make new net/smtp + c, err := em.client() + if err != nil { + return errors.Wrap(err, "failed to make smtp client") + } + client = c + } + + var quit bool + defer func() { + if quit { // quit set if Quit() call passed because it's closing connection as well. + return + } + if err := client.Close(); err != nil { + em.Logf("[WARN] can't close smtp connection, %v", err) + } + }() + + if em.SMTPUserName != "" && em.SMTPPassword != "" { + auth := smtp.PlainAuth("", em.SMTPUserName, em.SMTPPassword, em.Host) + if err := client.Auth(auth); err != nil { + return errors.Wrapf(err, "failed to auth to smtp %s:%d", em.Host, em.Port) + } + } + + if err := client.Mail(em.From); err != nil { + return errors.Wrapf(err, "bad from address %q", em.From) + } + if err := client.Rcpt(to); err != nil { + return errors.Wrapf(err, "bad to address %q", to) + } + + writer, err := client.Data() + if err != nil { + return errors.Wrap(err, "can't make email writer") + } + + buf := bytes.NewBufferString(em.buildMessage(text, to)) + if _, err = buf.WriteTo(writer); err != nil { + return errors.Wrapf(err, "failed to send email body to %q", to) + } + if err = writer.Close(); err != nil { + em.Logf("[WARN] can't close smtp body writer, %v", err) + } + + if err = client.Quit(); err != nil { + em.Logf("[WARN] failed to send quit command to %s:%d, %v", em.Host, em.Port, err) + } else { + quit = true + } + return nil +} + +func (em *Email) client() (c *smtp.Client, err error) { + srvAddress := fmt.Sprintf("%s:%d", em.Host, em.Port) + if em.TLS { + tlsConf := &tls.Config{ + InsecureSkipVerify: false, + ServerName: em.Host, + } + conn, err := tls.Dial("tcp", srvAddress, tlsConf) + if err != nil { + return nil, errors.Wrapf(err, "failed to dial smtp tls to %s", srvAddress) + } + if c, err = smtp.NewClient(conn, em.Host); err != nil { + return nil, errors.Wrapf(err, "failed to make smtp client for %s", srvAddress) + } + return c, nil + } + + conn, err := net.DialTimeout("tcp", srvAddress, em.TimeOut) + if err != nil { + return nil, errors.Wrapf(err, "timeout connecting to %s", srvAddress) + } + + c, err = smtp.NewClient(conn, srvAddress) + if err != nil { + return nil, errors.Wrap(err, "failed to dial") + } + return c, nil +} + +func (em *Email) buildMessage(msg string, to string) (message string) { + message += fmt.Sprintf("From: %s\n", em.From) + message += fmt.Sprintf("To: %s\n", to) + message += fmt.Sprintf("Subject: %s\n", em.Subject) + if em.ContentType != "" { + message += fmt.Sprintf("MIME-version: 1.0;\nContent-Type: %s; charset=\"UTF-8\";\n", em.ContentType) + } + message += "\n" + msg + return message +} diff --git a/backend/vendor/github.com/go-pkgz/auth/provider/verify.go b/backend/vendor/github.com/go-pkgz/auth/provider/verify.go new file mode 100644 index 00000000..fe9bb269 --- /dev/null +++ b/backend/vendor/github.com/go-pkgz/auth/provider/verify.go @@ -0,0 +1,208 @@ +package provider + +import ( + "bytes" + "crypto/sha1" + "net/http" + "strings" + "text/template" + "time" + + "github.com/dgrijalva/jwt-go" + "github.com/go-pkgz/rest" + "github.com/pkg/errors" + + "github.com/go-pkgz/auth/avatar" + "github.com/go-pkgz/auth/logger" + "github.com/go-pkgz/auth/token" +) + +// VerifyHandler implements non-oauth2 provider authorizing users with some confirmation. +// can be email, IM or anything else implementing Sender interface +type VerifyHandler struct { + logger.L + ProviderName string + TokenService VerifTokenService + Issuer string + AvatarSaver AvatarSaver + Sender Sender + Template string + UseGravatar bool +} + +// Sender defines interface to send emails +type Sender interface { + Send(address string, text string) error +} + +// SenderFunc type is an adapter to allow the use of ordinary functions as Sender. +type SenderFunc func(address string, text string) error + +// Send calls f(address,text) to implement Sender interface +func (f SenderFunc) Send(address string, text string) error { + return f(address, text) +} + +// TokenService defines interface accessing tokens +type VerifTokenService interface { + Token(claims token.Claims) (string, error) + Parse(tokenString string) (claims token.Claims, err error) + IsExpired(claims token.Claims) bool + Set(w http.ResponseWriter, claims token.Claims) (token.Claims, error) + Reset(w http.ResponseWriter) +} + +// Name of the handler +func (e VerifyHandler) Name() string { return e.ProviderName } + +// LoginHandler gets name and address from query, makes confirmation token and sends it to user. +// In case if confirmation token presented in the query uses it to create auth token +func (e VerifyHandler) LoginHandler(w http.ResponseWriter, r *http.Request) { + + // GET /login?site=site&&user=name&address=someone@example.com + tkn := r.URL.Query().Get("token") + if tkn == "" { // no token, ask confirmation via email + e.sendConfirmation(w, r) + return + } + + // confirmation token presented + // GET /login?token=confirmation-jwt&sess=1 + confClaims, err := e.TokenService.Parse(tkn) + if err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusForbidden, err, "failed to verify confirmation token") + return + } + + if e.TokenService.IsExpired(confClaims) { + rest.SendErrorJSON(w, r, e.L, http.StatusForbidden, errors.New("expired"), "failed to verify confirmation token") + return + } + + elems := strings.Split(confClaims.Handshake.ID, "::") + if len(elems) != 2 { + rest.SendErrorJSON(w, r, e.L, http.StatusBadRequest, errors.New(confClaims.Handshake.ID), "invalid handshake token") + return + } + user, address := elems[0], elems[1] + sessOnly := r.URL.Query().Get("sess") == "1" + + u := token.User{ + Name: user, + ID: e.ProviderName + "_" + token.HashID(sha1.New(), address), + } + // try to get gravatar for email + if e.UseGravatar && strings.Contains(address, "@") { // TODO: better email check to avoid silly hits to gravatar api + if picURL, err := avatar.GetGravatarURL(address); err == nil { + u.Picture = picURL + } + } + + if u, err = setAvatar(e.AvatarSaver, u); err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusInternalServerError, err, "failed to save avatar to proxy") + return + } + + cid, err := randToken() + if err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusInternalServerError, err, "can't make token id") + return + } + + claims := token.Claims{ + User: &u, + StandardClaims: jwt.StandardClaims{ + Id: cid, + Issuer: e.Issuer, + Audience: confClaims.Audience, + }, + SessionOnly: sessOnly, + } + + if _, err = e.TokenService.Set(w, claims); err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusInternalServerError, err, "failed to set token") + return + } + if confClaims.Handshake != nil && confClaims.Handshake.From != "" { + http.Redirect(w, r, confClaims.Handshake.From, http.StatusTemporaryRedirect) + return + } + rest.RenderJSON(w, r, claims.User) +} + +// GET /login?site=site&&user=name&address=someone@example.com +func (e VerifyHandler) sendConfirmation(w http.ResponseWriter, r *http.Request) { + user, address := r.URL.Query().Get("user"), r.URL.Query().Get("address") + if user == "" || address == "" { + rest.SendErrorJSON(w, r, e.L, http.StatusBadRequest, errors.New("wrong request"), "can't get user and address") + return + } + claims := token.Claims{ + Handshake: &token.Handshake{ + State: "", + From: r.URL.Query().Get("from"), + ID: user + "::" + address, + }, + SessionOnly: r.URL.Query().Get("session") != "" && r.URL.Query().Get("session") != "0", + StandardClaims: jwt.StandardClaims{ + Audience: r.URL.Query().Get("site"), + ExpiresAt: time.Now().Add(30 * time.Minute).Unix(), + NotBefore: time.Now().Add(-1 * time.Minute).Unix(), + Issuer: e.Issuer, + }, + } + + tkn, err := e.TokenService.Token(claims) + if err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusForbidden, err, "failed to make login token") + return + } + + tmpl := msgTemplate + if e.Template != "" { + tmpl = e.Template + } + emailTmpl, err := template.New("confirm").Parse(tmpl) + if err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusInternalServerError, err, "can't parse confirmation template") + return + } + + tmplData := struct { + User string + Address string + Token string + Site string + }{ + User: user, + Address: address, + Token: tkn, + Site: r.URL.Query().Get("site"), + } + buf := bytes.Buffer{} + if err = emailTmpl.Execute(&buf, tmplData); err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusInternalServerError, err, "can't execute confirmation template") + return + } + + if err := e.Sender.Send(address, buf.String()); err != nil { + rest.SendErrorJSON(w, r, e.L, http.StatusInternalServerError, err, "failed to send confirmation") + return + } + + rest.RenderJSON(w, r, rest.JSON{"user": user, "address": address}) +} + +// AuthHandler doesn't do anything for direct login as it has no callbacks +func (e VerifyHandler) AuthHandler(w http.ResponseWriter, r *http.Request) {} + +// LogoutHandler - GET /logout +func (e VerifyHandler) LogoutHandler(w http.ResponseWriter, r *http.Request) { + e.TokenService.Reset(w) +} + +var msgTemplate = ` +Confirmation for {{.User}} {{.Address}}, site {{.Site}} + +Token: {{.Token}} +` diff --git a/backend/vendor/github.com/go-pkgz/lgr/.travis.yml b/backend/vendor/github.com/go-pkgz/lgr/.travis.yml index 189a75c8..1f388fa0 100644 --- a/backend/vendor/github.com/go-pkgz/lgr/.travis.yml +++ b/backend/vendor/github.com/go-pkgz/lgr/.travis.yml @@ -13,6 +13,9 @@ before_install: script: - GO111MODULE=on go get ./... + - GO111MODULE=on go mod vendor + - GO111MODULE=on go test -v -mod=vendor -covermode=count -coverprofile=profile.cov ./... || travis_terminate 1; - GO111MODULE=on go test -v -covermode=count -coverprofile=profile.cov ./... || travis_terminate 1; - - golangci-lint run || travis_terminate 1; + - golangci-lint run || travis_terminate 1; - $GOPATH/bin/goveralls -coverprofile=profile.cov -service=travis-ci + diff --git a/backend/vendor/github.com/go-pkgz/lgr/logger.go b/backend/vendor/github.com/go-pkgz/lgr/logger.go index 2dd86885..30dc4dca 100644 --- a/backend/vendor/github.com/go-pkgz/lgr/logger.go +++ b/backend/vendor/github.com/go-pkgz/lgr/logger.go @@ -170,12 +170,18 @@ func (l *Logger) logf(format string, args ...interface{}) { // write to err as well for high levels, exit(1) on fatal and panic and dump stack on panic level switch lv { case "ERROR": - _, _ = l.stderr.Write(data) + if l.stderr != l.stdout { + _, _ = l.stderr.Write(data) + } case "FATAL": - _, _ = l.stderr.Write(data) + if l.stderr != l.stdout { + _, _ = l.stderr.Write(data) + } l.fatal() case "PANIC": - _, _ = l.stderr.Write(data) + if l.stderr != l.stdout { + _, _ = l.stderr.Write(data) + } _, _ = l.stderr.Write(getDump()) l.fatal() } @@ -224,7 +230,7 @@ func (l *Logger) reportCaller(calldepth int) (res callerInfo) { } _, pkgInfo := path.Split(path.Dir(filePath)) - res.Pkg = pkgInfo + res.Pkg = strings.Split(pkgInfo, "@")[0] // remove version from package name res.File = filePath if pathElems := strings.Split(filePath, "/"); len(pathElems) > 2 { @@ -294,10 +300,10 @@ func (l *Logger) formatLevel(lv string) string { func (l *Logger) extractLevel(line string) (level, msg string) { for _, lv := range levels { if strings.HasPrefix(line, lv) { - return lv, line[len(lv)+1:] + return lv, strings.TrimSpace(line[len(lv):]) } if strings.HasPrefix(line, "["+lv+"]") { - return lv, line[len(lv)+3:] + return lv, strings.TrimSpace(line[len("["+lv+"]"):]) } } return "INFO", line diff --git a/backend/vendor/github.com/kyokomi/emoji/.gitignore b/backend/vendor/github.com/kyokomi/emoji/.gitignore new file mode 100644 index 00000000..8cd9b916 --- /dev/null +++ b/backend/vendor/github.com/kyokomi/emoji/.gitignore @@ -0,0 +1,2 @@ +.idea +emoji.iml diff --git a/backend/vendor/github.com/kyokomi/emoji/LICENSE b/backend/vendor/github.com/kyokomi/emoji/LICENSE new file mode 100644 index 00000000..239874e0 --- /dev/null +++ b/backend/vendor/github.com/kyokomi/emoji/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 kyokomi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/backend/vendor/github.com/kyokomi/emoji/README.md b/backend/vendor/github.com/kyokomi/emoji/README.md new file mode 100644 index 00000000..483066a5 --- /dev/null +++ b/backend/vendor/github.com/kyokomi/emoji/README.md @@ -0,0 +1,53 @@ +# Emoji +Emoji is a simple golang package. + +[![wercker status](https://app.wercker.com/status/7bef60de2c6d3e0e6c13d56b2393c5d8/s/master "wercker status")](https://app.wercker.com/project/byKey/7bef60de2c6d3e0e6c13d56b2393c5d8) +[![Coverage Status](https://coveralls.io/repos/kyokomi/emoji/badge.png?branch=master)](https://coveralls.io/r/kyokomi/emoji?branch=master) +[![GoDoc](https://godoc.org/github.com/kyokomi/emoji?status.svg)](https://godoc.org/github.com/kyokomi/emoji) + +Get it: + +``` +go get github.com/kyokomi/emoji +``` + +Import it: + +``` +import ( + "github.com/kyokomi/emoji" +) +``` + +## Usage + +```go +package main + +import ( + "fmt" + + "github.com/kyokomi/emoji" +) + +func main() { + fmt.Println("Hello World Emoji!") + + emoji.Println(":beer: Beer!!!") + + pizzaMessage := emoji.Sprint("I like a :pizza: and :sushi:!!") + fmt.Println(pizzaMessage) +} +``` + +## Demo + +![demo](screen/image.png) + +## Reference + +- [GitHub EMOJI CHEAT SHEET](http://www.emoji-cheat-sheet.com/) + +## License + +[MIT](https://github.com/kyokomi/emoji/blob/master/LICENSE) diff --git a/backend/vendor/github.com/kyokomi/emoji/emoji.go b/backend/vendor/github.com/kyokomi/emoji/emoji.go new file mode 100644 index 00000000..1b336679 --- /dev/null +++ b/backend/vendor/github.com/kyokomi/emoji/emoji.go @@ -0,0 +1,153 @@ +// Package emoji terminal output. +package emoji + +import ( + "bytes" + "errors" + "fmt" + "io" + "regexp" + "unicode" +) + +//go:generate generateEmojiCodeMap -pkg emoji + +// Replace Padding character for emoji. +const ( + ReplacePadding = " " +) + +// CodeMap gets the underlying map of emoji. +func CodeMap() map[string]string { + return emojiCodeMap +} + +// regular expression that matches :flag-[countrycode]: +var flagRegexp = regexp.MustCompile(":flag-([a-z]{2}):") + +func emojize(x string) string { + str, ok := emojiCodeMap[x] + if ok { + return str + ReplacePadding + } + if match := flagRegexp.FindStringSubmatch(x); len(match) == 2 { + return regionalIndicator(match[1][0]) + regionalIndicator(match[1][1]) + } + return x +} + +// regionalIndicator maps a lowercase letter to a unicode regional indicator +func regionalIndicator(i byte) string { + return string('\U0001F1E6' + rune(i) - 'a') +} + +func replaseEmoji(input *bytes.Buffer) string { + emoji := bytes.NewBufferString(":") + for { + i, _, err := input.ReadRune() + if err != nil { + // not replase + return emoji.String() + } + + if i == ':' && emoji.Len() == 1 { + return emoji.String() + replaseEmoji(input) + } + + emoji.WriteRune(i) + switch { + case unicode.IsSpace(i): + return emoji.String() + case i == ':': + return emojize(emoji.String()) + } + } +} + +func compile(x string) string { + if x == "" { + return "" + } + + input := bytes.NewBufferString(x) + output := bytes.NewBufferString("") + + for { + i, _, err := input.ReadRune() + if err != nil { + break + } + switch i { + default: + output.WriteRune(i) + case ':': + output.WriteString(replaseEmoji(input)) + } + } + return output.String() +} + +func compileValues(a *[]interface{}) { + for i, x := range *a { + if str, ok := x.(string); ok { + (*a)[i] = compile(str) + } + } +} + +// Print is fmt.Print which supports emoji +func Print(a ...interface{}) (int, error) { + compileValues(&a) + return fmt.Print(a...) +} + +// Println is fmt.Println which supports emoji +func Println(a ...interface{}) (int, error) { + compileValues(&a) + return fmt.Println(a...) +} + +// Printf is fmt.Printf which supports emoji +func Printf(format string, a ...interface{}) (int, error) { + format = compile(format) + compileValues(&a) + return fmt.Printf(format, a...) +} + +// Fprint is fmt.Fprint which supports emoji +func Fprint(w io.Writer, a ...interface{}) (int, error) { + compileValues(&a) + return fmt.Fprint(w, a...) +} + +// Fprintln is fmt.Fprintln which supports emoji +func Fprintln(w io.Writer, a ...interface{}) (int, error) { + compileValues(&a) + return fmt.Fprintln(w, a...) +} + +// Fprintf is fmt.Fprintf which supports emoji +func Fprintf(w io.Writer, format string, a ...interface{}) (int, error) { + format = compile(format) + compileValues(&a) + return fmt.Fprintf(w, format, a...) +} + +// Sprint is fmt.Sprint which supports emoji +func Sprint(a ...interface{}) string { + compileValues(&a) + return fmt.Sprint(a...) +} + +// Sprintf is fmt.Sprintf which supports emoji +func Sprintf(format string, a ...interface{}) string { + format = compile(format) + compileValues(&a) + return fmt.Sprintf(format, a...) +} + +// Errorf is fmt.Errorf which supports emoji +func Errorf(format string, a ...interface{}) error { + compileValues(&a) + return errors.New(Sprintf(format, a...)) +} diff --git a/backend/vendor/github.com/kyokomi/emoji/emoji_codemap.go b/backend/vendor/github.com/kyokomi/emoji/emoji_codemap.go new file mode 100644 index 00000000..e61326eb --- /dev/null +++ b/backend/vendor/github.com/kyokomi/emoji/emoji_codemap.go @@ -0,0 +1,3939 @@ +package emoji + +// NOTE: THIS FILE WAS PRODUCED BY THE +// EMOJICODEMAP CODE GENERATION TOOL (github.com/kyokomi/emoji/cmd/generateEmojiCodeMap) +// DO NOT EDIT + +// Mapping from character to concrete escape code. +var emojiCodeMap = map[string]string{ + ":+1:": "\U0001f44d", + ":-1:": "\U0001f44e", + ":100:": "\U0001f4af", + ":1234:": "\U0001f522", + ":1st_place_medal:": "\U0001f947", + ":2nd_place_medal:": "\U0001f948", + ":3rd_place_medal:": "\U0001f949", + ":8ball:": "\U0001f3b1", + ":AB_button_(blood_type):": "\U0001f18e", + ":ATM_sign:": "\U0001f3e7", + ":A_button_(blood_type):": "\U0001f170", + ":Aquarius:": "\U00002652", + ":Aries:": "\U00002648", + ":BACK_arrow:": "\U0001f519", + ":B_button_(blood_type):": "\U0001f171", + ":CL_button:": "\U0001f191", + ":COOL_button:": "\U0001f192", + ":Cancer:": "\U0000264b", + ":Capricorn:": "\U00002651", + ":Christmas_tree:": "\U0001f384", + ":END_arrow:": "\U0001f51a", + ":FREE_button:": "\U0001f193", + ":Gemini:": "\U0000264a", + ":ID_button:": "\U0001f194", + ":Japanese_acceptable_button:": "\U0001f251", + ":Japanese_application_button:": "\U0001f238", + ":Japanese_bargain_button:": "\U0001f250", + ":Japanese_castle:": "\U0001f3ef", + ":Japanese_congratulations_button:": "\U00003297", + ":Japanese_discount_button:": "\U0001f239", + ":Japanese_dolls:": "\U0001f38e", + ":Japanese_free_of_charge_button:": "\U0001f21a", + ":Japanese_here_button:": "\U0001f201", + ":Japanese_monthly_amount_button:": "\U0001f237", + ":Japanese_no_vacancy_button:": "\U0001f235", + ":Japanese_not_free_of_charge_button:": "\U0001f236", + ":Japanese_open_for_business_button:": "\U0001f23a", + ":Japanese_passing_grade_button:": "\U0001f234", + ":Japanese_post_office:": "\U0001f3e3", + ":Japanese_prohibited_button:": "\U0001f232", + ":Japanese_reserved_button:": "\U0001f22f", + ":Japanese_secret_button:": "\U00003299", + ":Japanese_service_charge_button:": "\U0001f202", + ":Japanese_symbol_for_beginner:": "\U0001f530", + ":Japanese_vacancy_button:": "\U0001f233", + ":Leo:": "\U0000264c", + ":Libra:": "\U0000264e", + ":Mrs._Claus:": "\U0001f936", + ":NEW_button:": "\U0001f195", + ":NG_button:": "\U0001f196", + ":OK_button:": "\U0001f197", + ":OK_hand:": "\U0001f44c", + ":ON!_arrow:": "\U0001f51b", + ":O_button_(blood_type):": "\U0001f17e", + ":Ophiuchus:": "\U000026ce", + ":P_button:": "\U0001f17f", + ":Pisces:": "\U00002653", + ":SOON_arrow:": "\U0001f51c", + ":SOS_button:": "\U0001f198", + ":Sagittarius:": "\U00002650", + ":Santa_Claus:": "\U0001f385", + ":Scorpio:": "\U0000264f", + ":Statue_of_Liberty:": "\U0001f5fd", + ":T-Rex:": "\U0001f996", + ":TOP_arrow:": "\U0001f51d", + ":Taurus:": "\U00002649", + ":Tokyo_tower:": "\U0001f5fc", + ":UP!_button:": "\U0001f199", + ":VS_button:": "\U0001f19a", + ":Virgo:": "\U0000264d", + ":a:": "\U0001f170", + ":ab:": "\U0001f18e", + ":abacus:": "\U0001f9ee", + ":abc:": "\U0001f524", + ":abcd:": "\U0001f521", + ":accept:": "\U0001f251", + ":admission_tickets:": "\U0001f39f", + ":adult:": "\U0001f9d1", + ":adult_tone1:": "\U0001f9d1\U0001f3fb", + ":adult_tone2:": "\U0001f9d1\U0001f3fc", + ":adult_tone3:": "\U0001f9d1\U0001f3fd", + ":adult_tone4:": "\U0001f9d1\U0001f3fe", + ":adult_tone5:": "\U0001f9d1\U0001f3ff", + ":aerial_tramway:": "\U0001f6a1", + ":afghanistan:": "\U0001f1e6\U0001f1eb", + ":airplane:": "\U00002708", + ":airplane_arrival:": "\U0001f6ec", + ":airplane_arriving:": "\U0001f6ec", + ":airplane_departure:": "\U0001f6eb", + ":airplane_small:": "\U0001f6e9", + ":aland_islands:": "\U0001f1e6\U0001f1fd", + ":alarm_clock:": "\U000023f0", + ":albania:": "\U0001f1e6\U0001f1f1", + ":alembic:": "\U00002697", + ":algeria:": "\U0001f1e9\U0001f1ff", + ":alien:": "\U0001f47d", + ":alien_monster:": "\U0001f47e", + ":ambulance:": "\U0001f691", + ":american_football:": "\U0001f3c8", + ":american_samoa:": "\U0001f1e6\U0001f1f8", + ":amphora:": "\U0001f3fa", + ":anchor:": "\U00002693", + ":andorra:": "\U0001f1e6\U0001f1e9", + ":angel:": "\U0001f47c", + ":angel_tone1:": "\U0001f47c\U0001f3fb", + ":angel_tone2:": "\U0001f47c\U0001f3fc", + ":angel_tone3:": "\U0001f47c\U0001f3fd", + ":angel_tone4:": "\U0001f47c\U0001f3fe", + ":angel_tone5:": "\U0001f47c\U0001f3ff", + ":anger:": "\U0001f4a2", + ":anger_right:": "\U0001f5ef", + ":anger_symbol:": "\U0001f4a2", + ":angola:": "\U0001f1e6\U0001f1f4", + ":angry:": "\U0001f620", + ":angry_face:": "\U0001f620", + ":angry_face_with_horns:": "\U0001f47f", + ":anguilla:": "\U0001f1e6\U0001f1ee", + ":anguished:": "\U0001f627", + ":anguished_face:": "\U0001f627", + ":ant:": "\U0001f41c", + ":antarctica:": "\U0001f1e6\U0001f1f6", + ":antenna_bars:": "\U0001f4f6", + ":antigua_barbuda:": "\U0001f1e6\U0001f1ec", + ":anxious_face_with_sweat:": "\U0001f630", + ":apple:": "\U0001f34e", + ":aquarius:": "\u2652", + ":argentina:": "\U0001f1e6\U0001f1f7", + ":aries:": "\u2648", + ":armenia:": "\U0001f1e6\U0001f1f2", + ":arrow_backward:": "\u25c0", + ":arrow_double_down:": "\u23ec", + ":arrow_double_up:": "\u23eb", + ":arrow_down:": "\u2b07", + ":arrow_down_small:": "\U0001f53d", + ":arrow_forward:": "\u25b6", + ":arrow_heading_down:": "\u2935", + ":arrow_heading_up:": "\u2934", + ":arrow_left:": "\u2b05", + ":arrow_lower_left:": "\u2199", + ":arrow_lower_right:": "\u2198", + ":arrow_right:": "\u27a1", + ":arrow_right_hook:": "\u21aa", + ":arrow_up:": "\u2b06", + ":arrow_up_down:": "\u2195", + ":arrow_up_small:": "\U0001f53c", + ":arrow_upper_left:": "\u2196", + ":arrow_upper_right:": "\u2197", + ":arrows_clockwise:": "\U0001f503", + ":arrows_counterclockwise:": "\U0001f504", + ":art:": "\U0001f3a8", + ":articulated_lorry:": "\U0001f69b", + ":artificial_satellite:": "\U0001f6f0", + ":artist_palette:": "\U0001f3a8", + ":aruba:": "\U0001f1e6\U0001f1fc", + ":asterisk:": "*\ufe0f\u20e3", + ":astonished:": "\U0001f632", + ":astonished_face:": "\U0001f632", + ":athletic_shoe:": "\U0001f45f", + ":atm:": "\U0001f3e7", + ":atom:": "\u269b", + ":atom_symbol:": "\U0000269b", + ":australia:": "\U0001f1e6\U0001f1fa", + ":austria:": "\U0001f1e6\U0001f1f9", + ":automobile:": "\U0001f697", + ":avocado:": "\U0001f951", + ":azerbaijan:": "\U0001f1e6\U0001f1ff", + ":b:": "\U0001f171", + ":baby:": "\U0001f476", + ":baby_angel:": "\U0001f47c", + ":baby_bottle:": "\U0001f37c", + ":baby_chick:": "\U0001f424", + ":baby_symbol:": "\U0001f6bc", + ":baby_tone1:": "\U0001f476\U0001f3fb", + ":baby_tone2:": "\U0001f476\U0001f3fc", + ":baby_tone3:": "\U0001f476\U0001f3fd", + ":baby_tone4:": "\U0001f476\U0001f3fe", + ":baby_tone5:": "\U0001f476\U0001f3ff", + ":back:": "\U0001f519", + ":backhand_index_pointing_down:": "\U0001f447", + ":backhand_index_pointing_left:": "\U0001f448", + ":backhand_index_pointing_right:": "\U0001f449", + ":backhand_index_pointing_up:": "\U0001f446", + ":backpack:": "\U0001f392", + ":bacon:": "\U0001f953", + ":badger:": "\U0001f9a1", + ":badminton:": "\U0001f3f8", + ":bagel:": "\U0001f96f", + ":baggage_claim:": "\U0001f6c4", + ":baguette_bread:": "\U0001f956", + ":bahamas:": "\U0001f1e7\U0001f1f8", + ":bahrain:": "\U0001f1e7\U0001f1ed", + ":balance_scale:": "\U00002696", + ":bald:": "\U0001f9b2", + ":balloon:": "\U0001f388", + ":ballot_box:": "\U0001f5f3", + ":ballot_box_with_ballot:": "\U0001f5f3", + ":ballot_box_with_check:": "\u2611", + ":bamboo:": "\U0001f38d", + ":banana:": "\U0001f34c", + ":bangbang:": "\u203c", + ":bangladesh:": "\U0001f1e7\U0001f1e9", + ":bank:": "\U0001f3e6", + ":bar_chart:": "\U0001f4ca", + ":barbados:": "\U0001f1e7\U0001f1e7", + ":barber:": "\U0001f488", + ":barber_pole:": "\U0001f488", + ":baseball:": "\U000026be", + ":basket:": "\U0001f9fa", + ":basketball:": "\U0001f3c0", + ":basketball_man:": "\u26f9", + ":basketball_woman:": "\u26f9\ufe0f\u200d\u2640\ufe0f", + ":bat:": "\U0001f987", + ":bath:": "\U0001f6c0", + ":bath_tone1:": "\U0001f6c0\U0001f3fb", + ":bath_tone2:": "\U0001f6c0\U0001f3fc", + ":bath_tone3:": "\U0001f6c0\U0001f3fd", + ":bath_tone4:": "\U0001f6c0\U0001f3fe", + ":bath_tone5:": "\U0001f6c0\U0001f3ff", + ":bathtub:": "\U0001f6c1", + ":battery:": "\U0001f50b", + ":beach:": "\U0001f3d6", + ":beach_umbrella:": "\u26f1", + ":beach_with_umbrella:": "\U0001f3d6", + ":beaming_face_with_smiling_eyes:": "\U0001f601", + ":bear:": "\U0001f43b", + ":bearded_person:": "\U0001f9d4", + ":bearded_person_tone1:": "\U0001f9d4\U0001f3fb", + ":bearded_person_tone2:": "\U0001f9d4\U0001f3fc", + ":bearded_person_tone3:": "\U0001f9d4\U0001f3fd", + ":bearded_person_tone4:": "\U0001f9d4\U0001f3fe", + ":bearded_person_tone5:": "\U0001f9d4\U0001f3ff", + ":beating_heart:": "\U0001f493", + ":bed:": "\U0001f6cf", + ":bee:": "\U0001f41d", + ":beer:": "\U0001f37a", + ":beer_mug:": "\U0001f37a", + ":beers:": "\U0001f37b", + ":beetle:": "\U0001f41e", + ":beginner:": "\U0001f530", + ":belarus:": "\U0001f1e7\U0001f1fe", + ":belgium:": "\U0001f1e7\U0001f1ea", + ":belize:": "\U0001f1e7\U0001f1ff", + ":bell:": "\U0001f514", + ":bell_with_slash:": "\U0001f515", + ":bellhop:": "\U0001f6ce", + ":bellhop_bell:": "\U0001f6ce", + ":benin:": "\U0001f1e7\U0001f1ef", + ":bento:": "\U0001f371", + ":bento_box:": "\U0001f371", + ":bermuda:": "\U0001f1e7\U0001f1f2", + ":bhutan:": "\U0001f1e7\U0001f1f9", + ":bicycle:": "\U0001f6b2", + ":bicyclist:": "\U0001f6b4", + ":bike:": "\U0001f6b2", + ":biking_man:": "\U0001f6b4", + ":biking_woman:": "\U0001f6b4\u200d\u2640", + ":bikini:": "\U0001f459", + ":billed_cap:": "\U0001f9e2", + ":biohazard:": "\U00002623", + ":bird:": "\U0001f426", + ":birthday:": "\U0001f382", + ":birthday_cake:": "\U0001f382", + ":black_circle:": "\U000026ab", + ":black_flag:": "\U0001f3f4", + ":black_heart:": "\U0001f5a4", + ":black_joker:": "\U0001f0cf", + ":black_large_square:": "\U00002b1b", + ":black_medium-small_square:": "\U000025fe", + ":black_medium_small_square:": "\u25fe", + ":black_medium_square:": "\U000025fc", + ":black_nib:": "\U00002712", + ":black_small_square:": "\U000025aa", + ":black_square_button:": "\U0001f532", + ":blond-haired_man:": "\U0001f471\u200d\u2642\ufe0f", + ":blond-haired_man_tone1:": "\U0001f471\U0001f3fb\u200d\u2642\ufe0f", + ":blond-haired_man_tone2:": "\U0001f471\U0001f3fc\u200d\u2642\ufe0f", + ":blond-haired_man_tone3:": "\U0001f471\U0001f3fd\u200d\u2642\ufe0f", + ":blond-haired_man_tone4:": "\U0001f471\U0001f3fe\u200d\u2642\ufe0f", + ":blond-haired_man_tone5:": "\U0001f471\U0001f3ff\u200d\u2642\ufe0f", + ":blond-haired_woman:": "\U0001f471\u200d\u2640\ufe0f", + ":blond-haired_woman_tone1:": "\U0001f471\U0001f3fb\u200d\u2640\ufe0f", + ":blond-haired_woman_tone2:": "\U0001f471\U0001f3fc\u200d\u2640\ufe0f", + ":blond-haired_woman_tone3:": "\U0001f471\U0001f3fd\u200d\u2640\ufe0f", + ":blond-haired_woman_tone4:": "\U0001f471\U0001f3fe\u200d\u2640\ufe0f", + ":blond-haired_woman_tone5:": "\U0001f471\U0001f3ff\u200d\u2640\ufe0f", + ":blond_haired_person:": "\U0001f471", + ":blond_haired_person_tone1:": "\U0001f471\U0001f3fb", + ":blond_haired_person_tone2:": "\U0001f471\U0001f3fc", + ":blond_haired_person_tone3:": "\U0001f471\U0001f3fd", + ":blond_haired_person_tone4:": "\U0001f471\U0001f3fe", + ":blond_haired_person_tone5:": "\U0001f471\U0001f3ff", + ":blonde_man:": "\U0001f471", + ":blonde_woman:": "\U0001f471\u200d\u2640", + ":blossom:": "\U0001f33c", + ":blowfish:": "\U0001f421", + ":blue_book:": "\U0001f4d8", + ":blue_car:": "\U0001f699", + ":blue_circle:": "\U0001f535", + ":blue_heart:": "\U0001f499", + ":blush:": "\U0001f60a", + ":boar:": "\U0001f417", + ":boat:": "\u26f5\ufe0f", + ":bolivia:": "\U0001f1e7\U0001f1f4", + ":bomb:": "\U0001f4a3", + ":bone:": "\U0001f9b4", + ":book:": "\U0001f4d6", + ":bookmark:": "\U0001f516", + ":bookmark_tabs:": "\U0001f4d1", + ":books:": "\U0001f4da", + ":boom:": "\U0001f4a5", + ":boot:": "\U0001f462", + ":bosnia_herzegovina:": "\U0001f1e7\U0001f1e6", + ":botswana:": "\U0001f1e7\U0001f1fc", + ":bottle_with_popping_cork:": "\U0001f37e", + ":bouquet:": "\U0001f490", + ":bow:": "\U0001f647", + ":bow_and_arrow:": "\U0001f3f9", + ":bowing_man:": "\U0001f647", + ":bowing_woman:": "\U0001f647\u200d\u2640", + ":bowl_with_spoon:": "\U0001f963", + ":bowling:": "\U0001f3b3", + ":boxing_glove:": "\U0001f94a", + ":boy:": "\U0001f466", + ":boy_tone1:": "\U0001f466\U0001f3fb", + ":boy_tone2:": "\U0001f466\U0001f3fc", + ":boy_tone3:": "\U0001f466\U0001f3fd", + ":boy_tone4:": "\U0001f466\U0001f3fe", + ":boy_tone5:": "\U0001f466\U0001f3ff", + ":brain:": "\U0001f9e0", + ":brazil:": "\U0001f1e7\U0001f1f7", + ":bread:": "\U0001f35e", + ":breast-feeding:": "\U0001f931", + ":breast_feeding:": "\U0001f931", + ":breast_feeding_tone1:": "\U0001f931\U0001f3fb", + ":breast_feeding_tone2:": "\U0001f931\U0001f3fc", + ":breast_feeding_tone3:": "\U0001f931\U0001f3fd", + ":breast_feeding_tone4:": "\U0001f931\U0001f3fe", + ":breast_feeding_tone5:": "\U0001f931\U0001f3ff", + ":brick:": "\U0001f9f1", + ":bride_with_veil:": "\U0001f470", + ":bride_with_veil_tone1:": "\U0001f470\U0001f3fb", + ":bride_with_veil_tone2:": "\U0001f470\U0001f3fc", + ":bride_with_veil_tone3:": "\U0001f470\U0001f3fd", + ":bride_with_veil_tone4:": "\U0001f470\U0001f3fe", + ":bride_with_veil_tone5:": "\U0001f470\U0001f3ff", + ":bridge_at_night:": "\U0001f309", + ":briefcase:": "\U0001f4bc", + ":bright_button:": "\U0001f506", + ":british_indian_ocean_territory:": "\U0001f1ee\U0001f1f4", + ":british_virgin_islands:": "\U0001f1fb\U0001f1ec", + ":broccoli:": "\U0001f966", + ":broken_heart:": "\U0001f494", + ":broom:": "\U0001f9f9", + ":brunei:": "\U0001f1e7\U0001f1f3", + ":bug:": "\U0001f41b", + ":building_construction:": "\U0001f3d7", + ":bulb:": "\U0001f4a1", + ":bulgaria:": "\U0001f1e7\U0001f1ec", + ":bullet_train:": "\U0001f685", + ":bullettrain_front:": "\U0001f685", + ":bullettrain_side:": "\U0001f684", + ":burkina_faso:": "\U0001f1e7\U0001f1eb", + ":burrito:": "\U0001f32f", + ":burundi:": "\U0001f1e7\U0001f1ee", + ":bus:": "\U0001f68c", + ":bus_stop:": "\U0001f68f", + ":business_suit_levitating:": "\U0001f574", + ":busstop:": "\U0001f68f", + ":bust_in_silhouette:": "\U0001f464", + ":busts_in_silhouette:": "\U0001f465", + ":butterfly:": "\U0001f98b", + ":cactus:": "\U0001f335", + ":cake:": "\U0001f370", + ":calendar:": "\U0001f4c5", + ":calendar_spiral:": "\U0001f5d3", + ":call_me:": "\U0001f919", + ":call_me_hand:": "\U0001f919", + ":call_me_tone1:": "\U0001f919\U0001f3fb", + ":call_me_tone2:": "\U0001f919\U0001f3fc", + ":call_me_tone3:": "\U0001f919\U0001f3fd", + ":call_me_tone4:": "\U0001f919\U0001f3fe", + ":call_me_tone5:": "\U0001f919\U0001f3ff", + ":calling:": "\U0001f4f2", + ":cambodia:": "\U0001f1f0\U0001f1ed", + ":camel:": "\U0001f42a", + ":camera:": "\U0001f4f7", + ":camera_flash:": "\U0001f4f8", + ":camera_with_flash:": "\U0001f4f8", + ":cameroon:": "\U0001f1e8\U0001f1f2", + ":camping:": "\U0001f3d5", + ":canada:": "\U0001f1e8\U0001f1e6", + ":canary_islands:": "\U0001f1ee\U0001f1e8", + ":cancer:": "\u264b", + ":candle:": "\U0001f56f", + ":candy:": "\U0001f36c", + ":canned_food:": "\U0001f96b", + ":canoe:": "\U0001f6f6", + ":cape_verde:": "\U0001f1e8\U0001f1fb", + ":capital_abcd:": "\U0001f520", + ":capricorn:": "\u2651", + ":car:": "\U0001f697", + ":card_box:": "\U0001f5c3", + ":card_file_box:": "\U0001f5c3", + ":card_index:": "\U0001f4c7", + ":card_index_dividers:": "\U0001f5c2", + ":caribbean_netherlands:": "\U0001f1e7\U0001f1f6", + ":carousel_horse:": "\U0001f3a0", + ":carp_streamer:": "\U0001f38f", + ":carrot:": "\U0001f955", + ":castle:": "\U0001f3f0", + ":cat:": "\U0001f408", + ":cat2:": "\U0001f408", + ":cat_face:": "\U0001f431", + ":cat_with_tears_of_joy:": "\U0001f639", + ":cat_with_wry_smile:": "\U0001f63c", + ":cayman_islands:": "\U0001f1f0\U0001f1fe", + ":cd:": "\U0001f4bf", + ":central_african_republic:": "\U0001f1e8\U0001f1eb", + ":chad:": "\U0001f1f9\U0001f1e9", + ":chains:": "\U000026d3", + ":champagne:": "\U0001f37e", + ":champagne_glass:": "\U0001f942", + ":chart:": "\U0001f4b9", + ":chart_decreasing:": "\U0001f4c9", + ":chart_increasing:": "\U0001f4c8", + ":chart_increasing_with_yen:": "\U0001f4b9", + ":chart_with_downwards_trend:": "\U0001f4c9", + ":chart_with_upwards_trend:": "\U0001f4c8", + ":check_box_with_check:": "\U00002611", + ":check_mark:": "\U00002714", + ":check_mark_button:": "\U00002705", + ":checkered_flag:": "\U0001f3c1", + ":cheese:": "\U0001f9c0", + ":cheese_wedge:": "\U0001f9c0", + ":chequered_flag:": "\U0001f3c1", + ":cherries:": "\U0001f352", + ":cherry_blossom:": "\U0001f338", + ":chess_pawn:": "\U0000265f", + ":chestnut:": "\U0001f330", + ":chicken:": "\U0001f414", + ":child:": "\U0001f9d2", + ":child_tone1:": "\U0001f9d2\U0001f3fb", + ":child_tone2:": "\U0001f9d2\U0001f3fc", + ":child_tone3:": "\U0001f9d2\U0001f3fd", + ":child_tone4:": "\U0001f9d2\U0001f3fe", + ":child_tone5:": "\U0001f9d2\U0001f3ff", + ":children_crossing:": "\U0001f6b8", + ":chile:": "\U0001f1e8\U0001f1f1", + ":chipmunk:": "\U0001f43f", + ":chocolate_bar:": "\U0001f36b", + ":chopsticks:": "\U0001f962", + ":christmas_island:": "\U0001f1e8\U0001f1fd", + ":christmas_tree:": "\U0001f384", + ":church:": "\U000026ea", + ":cigarette:": "\U0001f6ac", + ":cinema:": "\U0001f3a6", + ":circled_M:": "\U000024c2", + ":circus_tent:": "\U0001f3aa", + ":city_dusk:": "\U0001f306", + ":city_sunrise:": "\U0001f307", + ":city_sunset:": "\U0001f307", + ":cityscape:": "\U0001f3d9", + ":cityscape_at_dusk:": "\U0001f306", + ":cl:": "\U0001f191", + ":clamp:": "\U0001f5dc", + ":clap:": "\U0001f44f", + ":clap_tone1:": "\U0001f44f\U0001f3fb", + ":clap_tone2:": "\U0001f44f\U0001f3fc", + ":clap_tone3:": "\U0001f44f\U0001f3fd", + ":clap_tone4:": "\U0001f44f\U0001f3fe", + ":clap_tone5:": "\U0001f44f\U0001f3ff", + ":clapper:": "\U0001f3ac", + ":clapper_board:": "\U0001f3ac", + ":clapping_hands:": "\U0001f44f", + ":classical_building:": "\U0001f3db", + ":clinking_beer_mugs:": "\U0001f37b", + ":clinking_glasses:": "\U0001f942", + ":clipboard:": "\U0001f4cb", + ":clock:": "\U0001f570", + ":clock1:": "\U0001f550", + ":clock10:": "\U0001f559", + ":clock1030:": "\U0001f565", + ":clock11:": "\U0001f55a", + ":clock1130:": "\U0001f566", + ":clock12:": "\U0001f55b", + ":clock1230:": "\U0001f567", + ":clock130:": "\U0001f55c", + ":clock2:": "\U0001f551", + ":clock230:": "\U0001f55d", + ":clock3:": "\U0001f552", + ":clock330:": "\U0001f55e", + ":clock4:": "\U0001f553", + ":clock430:": "\U0001f55f", + ":clock5:": "\U0001f554", + ":clock530:": "\U0001f560", + ":clock6:": "\U0001f555", + ":clock630:": "\U0001f561", + ":clock7:": "\U0001f556", + ":clock730:": "\U0001f562", + ":clock8:": "\U0001f557", + ":clock830:": "\U0001f563", + ":clock9:": "\U0001f558", + ":clock930:": "\U0001f564", + ":clockwise_vertical_arrows:": "\U0001f503", + ":closed_book:": "\U0001f4d5", + ":closed_lock_with_key:": "\U0001f510", + ":closed_mailbox_with_lowered_flag:": "\U0001f4ea", + ":closed_mailbox_with_raised_flag:": "\U0001f4eb", + ":closed_umbrella:": "\U0001f302", + ":cloud:": "\U00002601", + ":cloud_lightning:": "\U0001f329", + ":cloud_rain:": "\U0001f327", + ":cloud_snow:": "\U0001f328", + ":cloud_tornado:": "\U0001f32a", + ":cloud_with_lightning:": "\U0001f329", + ":cloud_with_lightning_and_rain:": "\U000026c8", + ":cloud_with_rain:": "\U0001f327", + ":cloud_with_snow:": "\U0001f328", + ":clown:": "\U0001f921", + ":clown_face:": "\U0001f921", + ":club_suit:": "\U00002663", + ":clubs:": "\u2663", + ":clutch_bag:": "\U0001f45d", + ":cn:": "\U0001f1e8\U0001f1f3", + ":coat:": "\U0001f9e5", + ":cocktail:": "\U0001f378", + ":cocktail_glass:": "\U0001f378", + ":coconut:": "\U0001f965", + ":cocos_islands:": "\U0001f1e8\U0001f1e8", + ":coffee:": "\u2615", + ":coffin:": "\U000026b0", + ":cold_face:": "\U0001f976", + ":cold_sweat:": "\U0001f630", + ":collision:": "\U0001f4a5", + ":colombia:": "\U0001f1e8\U0001f1f4", + ":comet:": "\U00002604", + ":comoros:": "\U0001f1f0\U0001f1f2", + ":compass:": "\U0001f9ed", + ":compression:": "\U0001f5dc", + ":computer:": "\U0001f4bb", + ":computer_disk:": "\U0001f4bd", + ":computer_mouse:": "\U0001f5b1", + ":confetti_ball:": "\U0001f38a", + ":confounded:": "\U0001f616", + ":confounded_face:": "\U0001f616", + ":confused:": "\U0001f615", + ":confused_face:": "\U0001f615", + ":congo_brazzaville:": "\U0001f1e8\U0001f1ec", + ":congo_kinshasa:": "\U0001f1e8\U0001f1e9", + ":congratulations:": "\u3297", + ":construction:": "\U0001f6a7", + ":construction_site:": "\U0001f3d7", + ":construction_worker:": "\U0001f477", + ":construction_worker_man:": "\U0001f477", + ":construction_worker_tone1:": "\U0001f477\U0001f3fb", + ":construction_worker_tone2:": "\U0001f477\U0001f3fc", + ":construction_worker_tone3:": "\U0001f477\U0001f3fd", + ":construction_worker_tone4:": "\U0001f477\U0001f3fe", + ":construction_worker_tone5:": "\U0001f477\U0001f3ff", + ":construction_worker_woman:": "\U0001f477\u200d\u2640", + ":control_knobs:": "\U0001f39b", + ":convenience_store:": "\U0001f3ea", + ":cook_islands:": "\U0001f1e8\U0001f1f0", + ":cooked_rice:": "\U0001f35a", + ":cookie:": "\U0001f36a", + ":cooking:": "\U0001f373", + ":cool:": "\U0001f192", + ":cop:": "\U0001f46e", + ":copyright:": "\U000000a9", + ":corn:": "\U0001f33d", + ":costa_rica:": "\U0001f1e8\U0001f1f7", + ":cote_divoire:": "\U0001f1e8\U0001f1ee", + ":couch:": "\U0001f6cb", + ":couch_and_lamp:": "\U0001f6cb", + ":counterclockwise_arrows_button:": "\U0001f504", + ":couple:": "\U0001f46b", + ":couple_mm:": "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468", + ":couple_with_heart:": "\U0001f491", + ":couple_with_heart_man_man:": "\U0001f468\U0000200d\U00002764\U0000fe0f\U0000200d\U0001f468", + ":couple_with_heart_woman_man:": "\U0001f469\U0000200d\U00002764\U0000fe0f\U0000200d\U0001f468", + ":couple_with_heart_woman_woman:": "\U0001f469\U0000200d\U00002764\U0000fe0f\U0000200d\U0001f469", + ":couple_ww:": "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469", + ":couplekiss:": "\U0001f48f", + ":couplekiss_man_man:": "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468", + ":couplekiss_man_woman:": "\U0001f48f", + ":couplekiss_woman_woman:": "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469", + ":cow:": "\U0001f404", + ":cow2:": "\U0001f404", + ":cow_face:": "\U0001f42e", + ":cowboy:": "\U0001f920", + ":cowboy_hat_face:": "\U0001f920", + ":crab:": "\U0001f980", + ":crayon:": "\U0001f58d", + ":crazy_face:": "\U0001f92a", + ":credit_card:": "\U0001f4b3", + ":crescent_moon:": "\U0001f319", + ":cricket:": "\U0001f997", + ":cricket_game:": "\U0001f3cf", + ":croatia:": "\U0001f1ed\U0001f1f7", + ":crocodile:": "\U0001f40a", + ":croissant:": "\U0001f950", + ":cross:": "\u271d", + ":cross_mark:": "\U0000274c", + ":cross_mark_button:": "\U0000274e", + ":crossed_fingers:": "\U0001f91e", + ":crossed_flags:": "\U0001f38c", + ":crossed_swords:": "\U00002694", + ":crown:": "\U0001f451", + ":cruise_ship:": "\U0001f6f3", + ":cry:": "\U0001f622", + ":crying_cat:": "\U0001f63f", + ":crying_cat_face:": "\U0001f63f", + ":crying_face:": "\U0001f622", + ":crystal_ball:": "\U0001f52e", + ":cuba:": "\U0001f1e8\U0001f1fa", + ":cucumber:": "\U0001f952", + ":cup_with_straw:": "\U0001f964", + ":cupcake:": "\U0001f9c1", + ":cupid:": "\U0001f498", + ":curacao:": "\U0001f1e8\U0001f1fc", + ":curling_stone:": "\U0001f94c", + ":curly_hair:": "\U0001f9b1", + ":curly_loop:": "\U000027b0", + ":currency_exchange:": "\U0001f4b1", + ":curry:": "\U0001f35b", + ":curry_rice:": "\U0001f35b", + ":custard:": "\U0001f36e", + ":customs:": "\U0001f6c3", + ":cut_of_meat:": "\U0001f969", + ":cyclone:": "\U0001f300", + ":cyprus:": "\U0001f1e8\U0001f1fe", + ":czech_republic:": "\U0001f1e8\U0001f1ff", + ":dagger:": "\U0001f5e1", + ":dancer:": "\U0001f483", + ":dancer_tone1:": "\U0001f483\U0001f3fb", + ":dancer_tone2:": "\U0001f483\U0001f3fc", + ":dancer_tone3:": "\U0001f483\U0001f3fd", + ":dancer_tone4:": "\U0001f483\U0001f3fe", + ":dancer_tone5:": "\U0001f483\U0001f3ff", + ":dancers:": "\U0001f46f", + ":dancing_men:": "\U0001f46f\u200d\u2642", + ":dancing_women:": "\U0001f46f", + ":dango:": "\U0001f361", + ":dark_sunglasses:": "\U0001f576", + ":dart:": "\U0001f3af", + ":dash:": "\U0001f4a8", + ":dashing_away:": "\U0001f4a8", + ":date:": "\U0001f4c5", + ":de:": "\U0001f1e9\U0001f1ea", + ":deciduous_tree:": "\U0001f333", + ":deer:": "\U0001f98c", + ":delivery_truck:": "\U0001f69a", + ":denmark:": "\U0001f1e9\U0001f1f0", + ":department_store:": "\U0001f3ec", + ":derelict_house:": "\U0001f3da", + ":desert:": "\U0001f3dc", + ":desert_island:": "\U0001f3dd", + ":desktop:": "\U0001f5a5", + ":desktop_computer:": "\U0001f5a5", + ":detective:": "\U0001f575", + ":detective_tone1:": "\U0001f575\U0001f3fb", + ":detective_tone2:": "\U0001f575\U0001f3fc", + ":detective_tone3:": "\U0001f575\U0001f3fd", + ":detective_tone4:": "\U0001f575\U0001f3fe", + ":detective_tone5:": "\U0001f575\U0001f3ff", + ":diamond_shape_with_a_dot_inside:": "\U0001f4a0", + ":diamond_suit:": "\U00002666", + ":diamond_with_a_dot:": "\U0001f4a0", + ":diamonds:": "\u2666", + ":dim_button:": "\U0001f505", + ":direct_hit:": "\U0001f3af", + ":disappointed:": "\U0001f61e", + ":disappointed_face:": "\U0001f61e", + ":disappointed_relieved:": "\U0001f625", + ":dividers:": "\U0001f5c2", + ":division_sign:": "\U00002797", + ":dizzy:": "\U0001f4ab", + ":dizzy_face:": "\U0001f635", + ":djibouti:": "\U0001f1e9\U0001f1ef", + ":dna:": "\U0001f9ec", + ":do_not_litter:": "\U0001f6af", + ":dog:": "\U0001f415", + ":dog2:": "\U0001f415", + ":dog_face:": "\U0001f436", + ":dollar:": "\U0001f4b5", + ":dollar_banknote:": "\U0001f4b5", + ":dolls:": "\U0001f38e", + ":dolphin:": "\U0001f42c", + ":dominica:": "\U0001f1e9\U0001f1f2", + ":dominican_republic:": "\U0001f1e9\U0001f1f4", + ":door:": "\U0001f6aa", + ":dotted_six-pointed_star:": "\U0001f52f", + ":double_curly_loop:": "\U000027bf", + ":double_exclamation_mark:": "\U0000203c", + ":doughnut:": "\U0001f369", + ":dove:": "\U0001f54a", + ":down-left_arrow:": "\U00002199", + ":down-right_arrow:": "\U00002198", + ":down_arrow:": "\U00002b07", + ":downcast_face_with_sweat:": "\U0001f613", + ":downwards_button:": "\U0001f53d", + ":dragon:": "\U0001f409", + ":dragon_face:": "\U0001f432", + ":dress:": "\U0001f457", + ":dromedary_camel:": "\U0001f42a", + ":drooling_face:": "\U0001f924", + ":droplet:": "\U0001f4a7", + ":drum:": "\U0001f941", + ":duck:": "\U0001f986", + ":dumpling:": "\U0001f95f", + ":dvd:": "\U0001f4c0", + ":e-mail:": "\U0001f4e7", + ":eagle:": "\U0001f985", + ":ear:": "\U0001f442", + ":ear_of_corn:": "\U0001f33d", + ":ear_of_rice:": "\U0001f33e", + ":ear_tone1:": "\U0001f442\U0001f3fb", + ":ear_tone2:": "\U0001f442\U0001f3fc", + ":ear_tone3:": "\U0001f442\U0001f3fd", + ":ear_tone4:": "\U0001f442\U0001f3fe", + ":ear_tone5:": "\U0001f442\U0001f3ff", + ":earth_africa:": "\U0001f30d", + ":earth_americas:": "\U0001f30e", + ":earth_asia:": "\U0001f30f", + ":ecuador:": "\U0001f1ea\U0001f1e8", + ":egg:": "\U0001f95a", + ":eggplant:": "\U0001f346", + ":egypt:": "\U0001f1ea\U0001f1ec", + ":eight:": "8\ufe0f\u20e3", + ":eight-pointed_star:": "\U00002734", + ":eight-spoked_asterisk:": "\U00002733", + ":eight-thirty:": "\U0001f563", + ":eight_o’clock:": "\U0001f557", + ":eight_pointed_black_star:": "\u2734", + ":eight_spoked_asterisk:": "\u2733", + ":eject:": "\u23cf", + ":eject_button:": "\U000023cf", + ":el_salvador:": "\U0001f1f8\U0001f1fb", + ":electric_plug:": "\U0001f50c", + ":elephant:": "\U0001f418", + ":eleven-thirty:": "\U0001f566", + ":eleven_o’clock:": "\U0001f55a", + ":elf:": "\U0001f9dd", + ":elf_tone1:": "\U0001f9dd\U0001f3fb", + ":elf_tone2:": "\U0001f9dd\U0001f3fc", + ":elf_tone3:": "\U0001f9dd\U0001f3fd", + ":elf_tone4:": "\U0001f9dd\U0001f3fe", + ":elf_tone5:": "\U0001f9dd\U0001f3ff", + ":email:": "\u2709\ufe0f", + ":end:": "\U0001f51a", + ":england:": "\U0001f3f4\U000e0067\U000e0062\U000e0065\U000e006e\U000e0067\U000e007f", + ":envelope:": "\U00002709", + ":envelope_with_arrow:": "\U0001f4e9", + ":equatorial_guinea:": "\U0001f1ec\U0001f1f6", + ":eritrea:": "\U0001f1ea\U0001f1f7", + ":es:": "\U0001f1ea\U0001f1f8", + ":estonia:": "\U0001f1ea\U0001f1ea", + ":ethiopia:": "\U0001f1ea\U0001f1f9", + ":eu:": "\U0001f1ea\U0001f1fa", + ":euro:": "\U0001f4b6", + ":euro_banknote:": "\U0001f4b6", + ":european_castle:": "\U0001f3f0", + ":european_post_office:": "\U0001f3e4", + ":european_union:": "\U0001f1ea\U0001f1fa", + ":evergreen_tree:": "\U0001f332", + ":ewe:": "\U0001f411", + ":exclamation:": "\u2757", + ":exclamation_mark:": "\U00002757", + ":exclamation_question_mark:": "\U00002049", + ":exploding_head:": "\U0001f92f", + ":expressionless:": "\U0001f611", + ":expressionless_face:": "\U0001f611", + ":eye:": "\U0001f441", + ":eye_in_speech_bubble:": "\U0001f441\U0000fe0f\U0000200d\U0001f5e8\U0000fe0f", + ":eye_speech_bubble:": "\U0001f441\u200d\U0001f5e8", + ":eyeglasses:": "\U0001f453", + ":eyes:": "\U0001f440", + ":face_blowing_a_kiss:": "\U0001f618", + ":face_savoring_food:": "\U0001f60b", + ":face_screaming_in_fear:": "\U0001f631", + ":face_vomiting:": "\U0001f92e", + ":face_with_hand_over_mouth:": "\U0001f92d", + ":face_with_head-bandage:": "\U0001f915", + ":face_with_head_bandage:": "\U0001f915", + ":face_with_medical_mask:": "\U0001f637", + ":face_with_monocle:": "\U0001f9d0", + ":face_with_open_mouth:": "\U0001f62e", + ":face_with_raised_eyebrow:": "\U0001f928", + ":face_with_rolling_eyes:": "\U0001f644", + ":face_with_steam_from_nose:": "\U0001f624", + ":face_with_symbols_on_mouth:": "\U0001f92c", + ":face_with_symbols_over_mouth:": "\U0001f92c", + ":face_with_tears_of_joy:": "\U0001f602", + ":face_with_thermometer:": "\U0001f912", + ":face_with_tongue:": "\U0001f61b", + ":face_without_mouth:": "\U0001f636", + ":facepunch:": "\U0001f44a", + ":factory:": "\U0001f3ed", + ":fairy:": "\U0001f9da", + ":fairy_tone1:": "\U0001f9da\U0001f3fb", + ":fairy_tone2:": "\U0001f9da\U0001f3fc", + ":fairy_tone3:": "\U0001f9da\U0001f3fd", + ":fairy_tone4:": "\U0001f9da\U0001f3fe", + ":fairy_tone5:": "\U0001f9da\U0001f3ff", + ":falkland_islands:": "\U0001f1eb\U0001f1f0", + ":fallen_leaf:": "\U0001f342", + ":family:": "\U0001f46a", + ":family_man_boy:": "\U0001f468\U0000200d\U0001f466", + ":family_man_boy_boy:": "\U0001f468\U0000200d\U0001f466\U0000200d\U0001f466", + ":family_man_girl:": "\U0001f468\U0000200d\U0001f467", + ":family_man_girl_boy:": "\U0001f468\U0000200d\U0001f467\U0000200d\U0001f466", + ":family_man_girl_girl:": "\U0001f468\U0000200d\U0001f467\U0000200d\U0001f467", + ":family_man_man_boy:": "\U0001f468\U0000200d\U0001f468\U0000200d\U0001f466", + ":family_man_man_boy_boy:": "\U0001f468\U0000200d\U0001f468\U0000200d\U0001f466\U0000200d\U0001f466", + ":family_man_man_girl:": "\U0001f468\U0000200d\U0001f468\U0000200d\U0001f467", + ":family_man_man_girl_boy:": "\U0001f468\U0000200d\U0001f468\U0000200d\U0001f467\U0000200d\U0001f466", + ":family_man_man_girl_girl:": "\U0001f468\U0000200d\U0001f468\U0000200d\U0001f467\U0000200d\U0001f467", + ":family_man_woman_boy:": "\U0001f468\U0000200d\U0001f469\U0000200d\U0001f466", + ":family_man_woman_boy_boy:": "\U0001f468\U0000200d\U0001f469\U0000200d\U0001f466\U0000200d\U0001f466", + ":family_man_woman_girl:": "\U0001f468\U0000200d\U0001f469\U0000200d\U0001f467", + ":family_man_woman_girl_boy:": "\U0001f468\U0000200d\U0001f469\U0000200d\U0001f467\U0000200d\U0001f466", + ":family_man_woman_girl_girl:": "\U0001f468\U0000200d\U0001f469\U0000200d\U0001f467\U0000200d\U0001f467", + ":family_mmb:": "\U0001f468\u200d\U0001f468\u200d\U0001f466", + ":family_mmbb:": "\U0001f468\u200d\U0001f468\u200d\U0001f466\u200d\U0001f466", + ":family_mmg:": "\U0001f468\u200d\U0001f468\u200d\U0001f467", + ":family_mmgb:": "\U0001f468\u200d\U0001f468\u200d\U0001f467\u200d\U0001f466", + ":family_mmgg:": "\U0001f468\u200d\U0001f468\u200d\U0001f467\u200d\U0001f467", + ":family_mwbb:": "\U0001f468\u200d\U0001f469\u200d\U0001f466\u200d\U0001f466", + ":family_mwg:": "\U0001f468\u200d\U0001f469\u200d\U0001f467", + ":family_mwgb:": "\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466", + ":family_mwgg:": "\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f467", + ":family_woman_boy:": "\U0001f469\U0000200d\U0001f466", + ":family_woman_boy_boy:": "\U0001f469\U0000200d\U0001f466\U0000200d\U0001f466", + ":family_woman_girl:": "\U0001f469\U0000200d\U0001f467", + ":family_woman_girl_boy:": "\U0001f469\U0000200d\U0001f467\U0000200d\U0001f466", + ":family_woman_girl_girl:": "\U0001f469\U0000200d\U0001f467\U0000200d\U0001f467", + ":family_woman_woman_boy:": "\U0001f469\U0000200d\U0001f469\U0000200d\U0001f466", + ":family_woman_woman_boy_boy:": "\U0001f469\U0000200d\U0001f469\U0000200d\U0001f466\U0000200d\U0001f466", + ":family_woman_woman_girl:": "\U0001f469\U0000200d\U0001f469\U0000200d\U0001f467", + ":family_woman_woman_girl_boy:": "\U0001f469\U0000200d\U0001f469\U0000200d\U0001f467\U0000200d\U0001f466", + ":family_woman_woman_girl_girl:": "\U0001f469\U0000200d\U0001f469\U0000200d\U0001f467\U0000200d\U0001f467", + ":family_wwb:": "\U0001f469\u200d\U0001f469\u200d\U0001f466", + ":family_wwbb:": "\U0001f469\u200d\U0001f469\u200d\U0001f466\u200d\U0001f466", + ":family_wwg:": "\U0001f469\u200d\U0001f469\u200d\U0001f467", + ":family_wwgb:": "\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466", + ":family_wwgg:": "\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f467", + ":faroe_islands:": "\U0001f1eb\U0001f1f4", + ":fast-forward_button:": "\U000023e9", + ":fast_down_button:": "\U000023ec", + ":fast_forward:": "\u23e9", + ":fast_reverse_button:": "\U000023ea", + ":fast_up_button:": "\U000023eb", + ":fax:": "\U0001f4e0", + ":fax_machine:": "\U0001f4e0", + ":fearful:": "\U0001f628", + ":fearful_face:": "\U0001f628", + ":feet:": "\U0001f43e", + ":female_detective:": "\U0001f575\ufe0f\u200d\u2640\ufe0f", + ":female_sign:": "\U00002640", + ":ferris_wheel:": "\U0001f3a1", + ":ferry:": "\U000026f4", + ":field_hockey:": "\U0001f3d1", + ":fiji:": "\U0001f1eb\U0001f1ef", + ":file_cabinet:": "\U0001f5c4", + ":file_folder:": "\U0001f4c1", + ":film_frames:": "\U0001f39e", + ":film_projector:": "\U0001f4fd", + ":film_strip:": "\U0001f39e", + ":fingers_crossed:": "\U0001f91e", + ":fingers_crossed_tone1:": "\U0001f91e\U0001f3fb", + ":fingers_crossed_tone2:": "\U0001f91e\U0001f3fc", + ":fingers_crossed_tone3:": "\U0001f91e\U0001f3fd", + ":fingers_crossed_tone4:": "\U0001f91e\U0001f3fe", + ":fingers_crossed_tone5:": "\U0001f91e\U0001f3ff", + ":finland:": "\U0001f1eb\U0001f1ee", + ":fire:": "\U0001f525", + ":fire_engine:": "\U0001f692", + ":fire_extinguisher:": "\U0001f9ef", + ":firecracker:": "\U0001f9e8", + ":fireworks:": "\U0001f386", + ":first_place:": "\U0001f947", + ":first_quarter_moon:": "\U0001f313", + ":first_quarter_moon_face:": "\U0001f31b", + ":first_quarter_moon_with_face:": "\U0001f31b", + ":fish:": "\U0001f41f", + ":fish_cake:": "\U0001f365", + ":fish_cake_with_swirl:": "\U0001f365", + ":fishing_pole:": "\U0001f3a3", + ":fishing_pole_and_fish:": "\U0001f3a3", + ":fist:": "\u270a", + ":fist_left:": "\U0001f91b", + ":fist_oncoming:": "\U0001f44a", + ":fist_raised:": "\u270a", + ":fist_right:": "\U0001f91c", + ":fist_tone1:": "\u270a\U0001f3fb", + ":fist_tone2:": "\u270a\U0001f3fc", + ":fist_tone3:": "\u270a\U0001f3fd", + ":fist_tone4:": "\u270a\U0001f3fe", + ":fist_tone5:": "\u270a\U0001f3ff", + ":five:": "5\ufe0f\u20e3", + ":five-thirty:": "\U0001f560", + ":five_o’clock:": "\U0001f554", + ":flag_Afghanistan:": "\U0001f1e6\U0001f1eb", + ":flag_Albania:": "\U0001f1e6\U0001f1f1", + ":flag_Algeria:": "\U0001f1e9\U0001f1ff", + ":flag_American_Samoa:": "\U0001f1e6\U0001f1f8", + ":flag_Andorra:": "\U0001f1e6\U0001f1e9", + ":flag_Angola:": "\U0001f1e6\U0001f1f4", + ":flag_Anguilla:": "\U0001f1e6\U0001f1ee", + ":flag_Antarctica:": "\U0001f1e6\U0001f1f6", + ":flag_Antigua_&_Barbuda:": "\U0001f1e6\U0001f1ec", + ":flag_Argentina:": "\U0001f1e6\U0001f1f7", + ":flag_Armenia:": "\U0001f1e6\U0001f1f2", + ":flag_Aruba:": "\U0001f1e6\U0001f1fc", + ":flag_Ascension_Island:": "\U0001f1e6\U0001f1e8", + ":flag_Australia:": "\U0001f1e6\U0001f1fa", + ":flag_Austria:": "\U0001f1e6\U0001f1f9", + ":flag_Azerbaijan:": "\U0001f1e6\U0001f1ff", + ":flag_Bahamas:": "\U0001f1e7\U0001f1f8", + ":flag_Bahrain:": "\U0001f1e7\U0001f1ed", + ":flag_Bangladesh:": "\U0001f1e7\U0001f1e9", + ":flag_Barbados:": "\U0001f1e7\U0001f1e7", + ":flag_Belarus:": "\U0001f1e7\U0001f1fe", + ":flag_Belgium:": "\U0001f1e7\U0001f1ea", + ":flag_Belize:": "\U0001f1e7\U0001f1ff", + ":flag_Benin:": "\U0001f1e7\U0001f1ef", + ":flag_Bermuda:": "\U0001f1e7\U0001f1f2", + ":flag_Bhutan:": "\U0001f1e7\U0001f1f9", + ":flag_Bolivia:": "\U0001f1e7\U0001f1f4", + ":flag_Bosnia_&_Herzegovina:": "\U0001f1e7\U0001f1e6", + ":flag_Botswana:": "\U0001f1e7\U0001f1fc", + ":flag_Bouvet_Island:": "\U0001f1e7\U0001f1fb", + ":flag_Brazil:": "\U0001f1e7\U0001f1f7", + ":flag_British_Indian_Ocean_Territory:": "\U0001f1ee\U0001f1f4", + ":flag_British_Virgin_Islands:": "\U0001f1fb\U0001f1ec", + ":flag_Brunei:": "\U0001f1e7\U0001f1f3", + ":flag_Bulgaria:": "\U0001f1e7\U0001f1ec", + ":flag_Burkina_Faso:": "\U0001f1e7\U0001f1eb", + ":flag_Burundi:": "\U0001f1e7\U0001f1ee", + ":flag_Cambodia:": "\U0001f1f0\U0001f1ed", + ":flag_Cameroon:": "\U0001f1e8\U0001f1f2", + ":flag_Canada:": "\U0001f1e8\U0001f1e6", + ":flag_Canary_Islands:": "\U0001f1ee\U0001f1e8", + ":flag_Cape_Verde:": "\U0001f1e8\U0001f1fb", + ":flag_Caribbean_Netherlands:": "\U0001f1e7\U0001f1f6", + ":flag_Cayman_Islands:": "\U0001f1f0\U0001f1fe", + ":flag_Central_African_Republic:": "\U0001f1e8\U0001f1eb", + ":flag_Ceuta_&_Melilla:": "\U0001f1ea\U0001f1e6", + ":flag_Chad:": "\U0001f1f9\U0001f1e9", + ":flag_Chile:": "\U0001f1e8\U0001f1f1", + ":flag_China:": "\U0001f1e8\U0001f1f3", + ":flag_Christmas_Island:": "\U0001f1e8\U0001f1fd", + ":flag_Clipperton_Island:": "\U0001f1e8\U0001f1f5", + ":flag_Cocos_(Keeling)_Islands:": "\U0001f1e8\U0001f1e8", + ":flag_Colombia:": "\U0001f1e8\U0001f1f4", + ":flag_Comoros:": "\U0001f1f0\U0001f1f2", + ":flag_Congo_-_Brazzaville:": "\U0001f1e8\U0001f1ec", + ":flag_Congo_-_Kinshasa:": "\U0001f1e8\U0001f1e9", + ":flag_Cook_Islands:": "\U0001f1e8\U0001f1f0", + ":flag_Costa_Rica:": "\U0001f1e8\U0001f1f7", + ":flag_Croatia:": "\U0001f1ed\U0001f1f7", + ":flag_Cuba:": "\U0001f1e8\U0001f1fa", + ":flag_Curaçao:": "\U0001f1e8\U0001f1fc", + ":flag_Cyprus:": "\U0001f1e8\U0001f1fe", + ":flag_Czechia:": "\U0001f1e8\U0001f1ff", + ":flag_Côte_d’Ivoire:": "\U0001f1e8\U0001f1ee", + ":flag_Denmark:": "\U0001f1e9\U0001f1f0", + ":flag_Diego_Garcia:": "\U0001f1e9\U0001f1ec", + ":flag_Djibouti:": "\U0001f1e9\U0001f1ef", + ":flag_Dominica:": "\U0001f1e9\U0001f1f2", + ":flag_Dominican_Republic:": "\U0001f1e9\U0001f1f4", + ":flag_Ecuador:": "\U0001f1ea\U0001f1e8", + ":flag_Egypt:": "\U0001f1ea\U0001f1ec", + ":flag_El_Salvador:": "\U0001f1f8\U0001f1fb", + ":flag_England:": "\U0001f3f4\U000e0067\U000e0062\U000e0065\U000e006e\U000e0067\U000e007f", + ":flag_Equatorial_Guinea:": "\U0001f1ec\U0001f1f6", + ":flag_Eritrea:": "\U0001f1ea\U0001f1f7", + ":flag_Estonia:": "\U0001f1ea\U0001f1ea", + ":flag_Eswatini:": "\U0001f1f8\U0001f1ff", + ":flag_Ethiopia:": "\U0001f1ea\U0001f1f9", + ":flag_European_Union:": "\U0001f1ea\U0001f1fa", + ":flag_Falkland_Islands:": "\U0001f1eb\U0001f1f0", + ":flag_Faroe_Islands:": "\U0001f1eb\U0001f1f4", + ":flag_Fiji:": "\U0001f1eb\U0001f1ef", + ":flag_Finland:": "\U0001f1eb\U0001f1ee", + ":flag_France:": "\U0001f1eb\U0001f1f7", + ":flag_French_Guiana:": "\U0001f1ec\U0001f1eb", + ":flag_French_Polynesia:": "\U0001f1f5\U0001f1eb", + ":flag_French_Southern_Territories:": "\U0001f1f9\U0001f1eb", + ":flag_Gabon:": "\U0001f1ec\U0001f1e6", + ":flag_Gambia:": "\U0001f1ec\U0001f1f2", + ":flag_Georgia:": "\U0001f1ec\U0001f1ea", + ":flag_Germany:": "\U0001f1e9\U0001f1ea", + ":flag_Ghana:": "\U0001f1ec\U0001f1ed", + ":flag_Gibraltar:": "\U0001f1ec\U0001f1ee", + ":flag_Greece:": "\U0001f1ec\U0001f1f7", + ":flag_Greenland:": "\U0001f1ec\U0001f1f1", + ":flag_Grenada:": "\U0001f1ec\U0001f1e9", + ":flag_Guadeloupe:": "\U0001f1ec\U0001f1f5", + ":flag_Guam:": "\U0001f1ec\U0001f1fa", + ":flag_Guatemala:": "\U0001f1ec\U0001f1f9", + ":flag_Guernsey:": "\U0001f1ec\U0001f1ec", + ":flag_Guinea:": "\U0001f1ec\U0001f1f3", + ":flag_Guinea-Bissau:": "\U0001f1ec\U0001f1fc", + ":flag_Guyana:": "\U0001f1ec\U0001f1fe", + ":flag_Haiti:": "\U0001f1ed\U0001f1f9", + ":flag_Heard_&_McDonald_Islands:": "\U0001f1ed\U0001f1f2", + ":flag_Honduras:": "\U0001f1ed\U0001f1f3", + ":flag_Hong_Kong_SAR_China:": "\U0001f1ed\U0001f1f0", + ":flag_Hungary:": "\U0001f1ed\U0001f1fa", + ":flag_Iceland:": "\U0001f1ee\U0001f1f8", + ":flag_India:": "\U0001f1ee\U0001f1f3", + ":flag_Indonesia:": "\U0001f1ee\U0001f1e9", + ":flag_Iran:": "\U0001f1ee\U0001f1f7", + ":flag_Iraq:": "\U0001f1ee\U0001f1f6", + ":flag_Ireland:": "\U0001f1ee\U0001f1ea", + ":flag_Isle_of_Man:": "\U0001f1ee\U0001f1f2", + ":flag_Israel:": "\U0001f1ee\U0001f1f1", + ":flag_Italy:": "\U0001f1ee\U0001f1f9", + ":flag_Jamaica:": "\U0001f1ef\U0001f1f2", + ":flag_Japan:": "\U0001f1ef\U0001f1f5", + ":flag_Jersey:": "\U0001f1ef\U0001f1ea", + ":flag_Jordan:": "\U0001f1ef\U0001f1f4", + ":flag_Kazakhstan:": "\U0001f1f0\U0001f1ff", + ":flag_Kenya:": "\U0001f1f0\U0001f1ea", + ":flag_Kiribati:": "\U0001f1f0\U0001f1ee", + ":flag_Kosovo:": "\U0001f1fd\U0001f1f0", + ":flag_Kuwait:": "\U0001f1f0\U0001f1fc", + ":flag_Kyrgyzstan:": "\U0001f1f0\U0001f1ec", + ":flag_Laos:": "\U0001f1f1\U0001f1e6", + ":flag_Latvia:": "\U0001f1f1\U0001f1fb", + ":flag_Lebanon:": "\U0001f1f1\U0001f1e7", + ":flag_Lesotho:": "\U0001f1f1\U0001f1f8", + ":flag_Liberia:": "\U0001f1f1\U0001f1f7", + ":flag_Libya:": "\U0001f1f1\U0001f1fe", + ":flag_Liechtenstein:": "\U0001f1f1\U0001f1ee", + ":flag_Lithuania:": "\U0001f1f1\U0001f1f9", + ":flag_Luxembourg:": "\U0001f1f1\U0001f1fa", + ":flag_Macao_SAR_China:": "\U0001f1f2\U0001f1f4", + ":flag_Macedonia:": "\U0001f1f2\U0001f1f0", + ":flag_Madagascar:": "\U0001f1f2\U0001f1ec", + ":flag_Malawi:": "\U0001f1f2\U0001f1fc", + ":flag_Malaysia:": "\U0001f1f2\U0001f1fe", + ":flag_Maldives:": "\U0001f1f2\U0001f1fb", + ":flag_Mali:": "\U0001f1f2\U0001f1f1", + ":flag_Malta:": "\U0001f1f2\U0001f1f9", + ":flag_Marshall_Islands:": "\U0001f1f2\U0001f1ed", + ":flag_Martinique:": "\U0001f1f2\U0001f1f6", + ":flag_Mauritania:": "\U0001f1f2\U0001f1f7", + ":flag_Mauritius:": "\U0001f1f2\U0001f1fa", + ":flag_Mayotte:": "\U0001f1fe\U0001f1f9", + ":flag_Mexico:": "\U0001f1f2\U0001f1fd", + ":flag_Micronesia:": "\U0001f1eb\U0001f1f2", + ":flag_Moldova:": "\U0001f1f2\U0001f1e9", + ":flag_Monaco:": "\U0001f1f2\U0001f1e8", + ":flag_Mongolia:": "\U0001f1f2\U0001f1f3", + ":flag_Montenegro:": "\U0001f1f2\U0001f1ea", + ":flag_Montserrat:": "\U0001f1f2\U0001f1f8", + ":flag_Morocco:": "\U0001f1f2\U0001f1e6", + ":flag_Mozambique:": "\U0001f1f2\U0001f1ff", + ":flag_Myanmar_(Burma):": "\U0001f1f2\U0001f1f2", + ":flag_Namibia:": "\U0001f1f3\U0001f1e6", + ":flag_Nauru:": "\U0001f1f3\U0001f1f7", + ":flag_Nepal:": "\U0001f1f3\U0001f1f5", + ":flag_Netherlands:": "\U0001f1f3\U0001f1f1", + ":flag_New_Caledonia:": "\U0001f1f3\U0001f1e8", + ":flag_New_Zealand:": "\U0001f1f3\U0001f1ff", + ":flag_Nicaragua:": "\U0001f1f3\U0001f1ee", + ":flag_Niger:": "\U0001f1f3\U0001f1ea", + ":flag_Nigeria:": "\U0001f1f3\U0001f1ec", + ":flag_Niue:": "\U0001f1f3\U0001f1fa", + ":flag_Norfolk_Island:": "\U0001f1f3\U0001f1eb", + ":flag_North_Korea:": "\U0001f1f0\U0001f1f5", + ":flag_Northern_Mariana_Islands:": "\U0001f1f2\U0001f1f5", + ":flag_Norway:": "\U0001f1f3\U0001f1f4", + ":flag_Oman:": "\U0001f1f4\U0001f1f2", + ":flag_Pakistan:": "\U0001f1f5\U0001f1f0", + ":flag_Palau:": "\U0001f1f5\U0001f1fc", + ":flag_Palestinian_Territories:": "\U0001f1f5\U0001f1f8", + ":flag_Panama:": "\U0001f1f5\U0001f1e6", + ":flag_Papua_New_Guinea:": "\U0001f1f5\U0001f1ec", + ":flag_Paraguay:": "\U0001f1f5\U0001f1fe", + ":flag_Peru:": "\U0001f1f5\U0001f1ea", + ":flag_Philippines:": "\U0001f1f5\U0001f1ed", + ":flag_Pitcairn_Islands:": "\U0001f1f5\U0001f1f3", + ":flag_Poland:": "\U0001f1f5\U0001f1f1", + ":flag_Portugal:": "\U0001f1f5\U0001f1f9", + ":flag_Puerto_Rico:": "\U0001f1f5\U0001f1f7", + ":flag_Qatar:": "\U0001f1f6\U0001f1e6", + ":flag_Romania:": "\U0001f1f7\U0001f1f4", + ":flag_Russia:": "\U0001f1f7\U0001f1fa", + ":flag_Rwanda:": "\U0001f1f7\U0001f1fc", + ":flag_Réunion:": "\U0001f1f7\U0001f1ea", + ":flag_Samoa:": "\U0001f1fc\U0001f1f8", + ":flag_San_Marino:": "\U0001f1f8\U0001f1f2", + ":flag_Saudi_Arabia:": "\U0001f1f8\U0001f1e6", + ":flag_Scotland:": "\U0001f3f4\U000e0067\U000e0062\U000e0073\U000e0063\U000e0074\U000e007f", + ":flag_Senegal:": "\U0001f1f8\U0001f1f3", + ":flag_Serbia:": "\U0001f1f7\U0001f1f8", + ":flag_Seychelles:": "\U0001f1f8\U0001f1e8", + ":flag_Sierra_Leone:": "\U0001f1f8\U0001f1f1", + ":flag_Singapore:": "\U0001f1f8\U0001f1ec", + ":flag_Sint_Maarten:": "\U0001f1f8\U0001f1fd", + ":flag_Slovakia:": "\U0001f1f8\U0001f1f0", + ":flag_Slovenia:": "\U0001f1f8\U0001f1ee", + ":flag_Solomon_Islands:": "\U0001f1f8\U0001f1e7", + ":flag_Somalia:": "\U0001f1f8\U0001f1f4", + ":flag_South_Africa:": "\U0001f1ff\U0001f1e6", + ":flag_South_Georgia_&_South_Sandwich_Islands:": "\U0001f1ec\U0001f1f8", + ":flag_South_Korea:": "\U0001f1f0\U0001f1f7", + ":flag_South_Sudan:": "\U0001f1f8\U0001f1f8", + ":flag_Spain:": "\U0001f1ea\U0001f1f8", + ":flag_Sri_Lanka:": "\U0001f1f1\U0001f1f0", + ":flag_St._Barthélemy:": "\U0001f1e7\U0001f1f1", + ":flag_St._Helena:": "\U0001f1f8\U0001f1ed", + ":flag_St._Kitts_&_Nevis:": "\U0001f1f0\U0001f1f3", + ":flag_St._Lucia:": "\U0001f1f1\U0001f1e8", + ":flag_St._Martin:": "\U0001f1f2\U0001f1eb", + ":flag_St._Pierre_&_Miquelon:": "\U0001f1f5\U0001f1f2", + ":flag_St._Vincent_&_Grenadines:": "\U0001f1fb\U0001f1e8", + ":flag_Sudan:": "\U0001f1f8\U0001f1e9", + ":flag_Suriname:": "\U0001f1f8\U0001f1f7", + ":flag_Svalbard_&_Jan_Mayen:": "\U0001f1f8\U0001f1ef", + ":flag_Sweden:": "\U0001f1f8\U0001f1ea", + ":flag_Switzerland:": "\U0001f1e8\U0001f1ed", + ":flag_Syria:": "\U0001f1f8\U0001f1fe", + ":flag_São_Tomé_&_Príncipe:": "\U0001f1f8\U0001f1f9", + ":flag_Taiwan:": "\U0001f1f9\U0001f1fc", + ":flag_Tajikistan:": "\U0001f1f9\U0001f1ef", + ":flag_Tanzania:": "\U0001f1f9\U0001f1ff", + ":flag_Thailand:": "\U0001f1f9\U0001f1ed", + ":flag_Timor-Leste:": "\U0001f1f9\U0001f1f1", + ":flag_Togo:": "\U0001f1f9\U0001f1ec", + ":flag_Tokelau:": "\U0001f1f9\U0001f1f0", + ":flag_Tonga:": "\U0001f1f9\U0001f1f4", + ":flag_Trinidad_&_Tobago:": "\U0001f1f9\U0001f1f9", + ":flag_Tristan_da_Cunha:": "\U0001f1f9\U0001f1e6", + ":flag_Tunisia:": "\U0001f1f9\U0001f1f3", + ":flag_Turkey:": "\U0001f1f9\U0001f1f7", + ":flag_Turkmenistan:": "\U0001f1f9\U0001f1f2", + ":flag_Turks_&_Caicos_Islands:": "\U0001f1f9\U0001f1e8", + ":flag_Tuvalu:": "\U0001f1f9\U0001f1fb", + ":flag_U.S._Outlying_Islands:": "\U0001f1fa\U0001f1f2", + ":flag_U.S._Virgin_Islands:": "\U0001f1fb\U0001f1ee", + ":flag_Uganda:": "\U0001f1fa\U0001f1ec", + ":flag_Ukraine:": "\U0001f1fa\U0001f1e6", + ":flag_United_Arab_Emirates:": "\U0001f1e6\U0001f1ea", + ":flag_United_Kingdom:": "\U0001f1ec\U0001f1e7", + ":flag_United_Nations:": "\U0001f1fa\U0001f1f3", + ":flag_United_States:": "\U0001f1fa\U0001f1f8", + ":flag_Uruguay:": "\U0001f1fa\U0001f1fe", + ":flag_Uzbekistan:": "\U0001f1fa\U0001f1ff", + ":flag_Vanuatu:": "\U0001f1fb\U0001f1fa", + ":flag_Vatican_City:": "\U0001f1fb\U0001f1e6", + ":flag_Venezuela:": "\U0001f1fb\U0001f1ea", + ":flag_Vietnam:": "\U0001f1fb\U0001f1f3", + ":flag_Wales:": "\U0001f3f4\U000e0067\U000e0062\U000e0077\U000e006c\U000e0073\U000e007f", + ":flag_Wallis_&_Futuna:": "\U0001f1fc\U0001f1eb", + ":flag_Western_Sahara:": "\U0001f1ea\U0001f1ed", + ":flag_Yemen:": "\U0001f1fe\U0001f1ea", + ":flag_Zambia:": "\U0001f1ff\U0001f1f2", + ":flag_Zimbabwe:": "\U0001f1ff\U0001f1fc", + ":flag_ac:": "\U0001f1e6\U0001f1e8", + ":flag_ad:": "\U0001f1e6\U0001f1e9", + ":flag_ae:": "\U0001f1e6\U0001f1ea", + ":flag_af:": "\U0001f1e6\U0001f1eb", + ":flag_ag:": "\U0001f1e6\U0001f1ec", + ":flag_ai:": "\U0001f1e6\U0001f1ee", + ":flag_al:": "\U0001f1e6\U0001f1f1", + ":flag_am:": "\U0001f1e6\U0001f1f2", + ":flag_ao:": "\U0001f1e6\U0001f1f4", + ":flag_aq:": "\U0001f1e6\U0001f1f6", + ":flag_ar:": "\U0001f1e6\U0001f1f7", + ":flag_as:": "\U0001f1e6\U0001f1f8", + ":flag_at:": "\U0001f1e6\U0001f1f9", + ":flag_au:": "\U0001f1e6\U0001f1fa", + ":flag_aw:": "\U0001f1e6\U0001f1fc", + ":flag_ax:": "\U0001f1e6\U0001f1fd", + ":flag_az:": "\U0001f1e6\U0001f1ff", + ":flag_ba:": "\U0001f1e7\U0001f1e6", + ":flag_bb:": "\U0001f1e7\U0001f1e7", + ":flag_bd:": "\U0001f1e7\U0001f1e9", + ":flag_be:": "\U0001f1e7\U0001f1ea", + ":flag_bf:": "\U0001f1e7\U0001f1eb", + ":flag_bg:": "\U0001f1e7\U0001f1ec", + ":flag_bh:": "\U0001f1e7\U0001f1ed", + ":flag_bi:": "\U0001f1e7\U0001f1ee", + ":flag_bj:": "\U0001f1e7\U0001f1ef", + ":flag_bl:": "\U0001f1e7\U0001f1f1", + ":flag_black:": "\U0001f3f4", + ":flag_bm:": "\U0001f1e7\U0001f1f2", + ":flag_bn:": "\U0001f1e7\U0001f1f3", + ":flag_bo:": "\U0001f1e7\U0001f1f4", + ":flag_bq:": "\U0001f1e7\U0001f1f6", + ":flag_br:": "\U0001f1e7\U0001f1f7", + ":flag_bs:": "\U0001f1e7\U0001f1f8", + ":flag_bt:": "\U0001f1e7\U0001f1f9", + ":flag_bv:": "\U0001f1e7\U0001f1fb", + ":flag_bw:": "\U0001f1e7\U0001f1fc", + ":flag_by:": "\U0001f1e7\U0001f1fe", + ":flag_bz:": "\U0001f1e7\U0001f1ff", + ":flag_ca:": "\U0001f1e8\U0001f1e6", + ":flag_cc:": "\U0001f1e8\U0001f1e8", + ":flag_cd:": "\U0001f1e8\U0001f1e9", + ":flag_cf:": "\U0001f1e8\U0001f1eb", + ":flag_cg:": "\U0001f1e8\U0001f1ec", + ":flag_ch:": "\U0001f1e8\U0001f1ed", + ":flag_ci:": "\U0001f1e8\U0001f1ee", + ":flag_ck:": "\U0001f1e8\U0001f1f0", + ":flag_cl:": "\U0001f1e8\U0001f1f1", + ":flag_cm:": "\U0001f1e8\U0001f1f2", + ":flag_cn:": "\U0001f1e8\U0001f1f3", + ":flag_co:": "\U0001f1e8\U0001f1f4", + ":flag_cp:": "\U0001f1e8\U0001f1f5", + ":flag_cr:": "\U0001f1e8\U0001f1f7", + ":flag_cu:": "\U0001f1e8\U0001f1fa", + ":flag_cv:": "\U0001f1e8\U0001f1fb", + ":flag_cw:": "\U0001f1e8\U0001f1fc", + ":flag_cx:": "\U0001f1e8\U0001f1fd", + ":flag_cy:": "\U0001f1e8\U0001f1fe", + ":flag_cz:": "\U0001f1e8\U0001f1ff", + ":flag_de:": "\U0001f1e9\U0001f1ea", + ":flag_dg:": "\U0001f1e9\U0001f1ec", + ":flag_dj:": "\U0001f1e9\U0001f1ef", + ":flag_dk:": "\U0001f1e9\U0001f1f0", + ":flag_dm:": "\U0001f1e9\U0001f1f2", + ":flag_do:": "\U0001f1e9\U0001f1f4", + ":flag_dz:": "\U0001f1e9\U0001f1ff", + ":flag_ea:": "\U0001f1ea\U0001f1e6", + ":flag_ec:": "\U0001f1ea\U0001f1e8", + ":flag_ee:": "\U0001f1ea\U0001f1ea", + ":flag_eg:": "\U0001f1ea\U0001f1ec", + ":flag_eh:": "\U0001f1ea\U0001f1ed", + ":flag_er:": "\U0001f1ea\U0001f1f7", + ":flag_es:": "\U0001f1ea\U0001f1f8", + ":flag_et:": "\U0001f1ea\U0001f1f9", + ":flag_eu:": "\U0001f1ea\U0001f1fa", + ":flag_fi:": "\U0001f1eb\U0001f1ee", + ":flag_fj:": "\U0001f1eb\U0001f1ef", + ":flag_fk:": "\U0001f1eb\U0001f1f0", + ":flag_fm:": "\U0001f1eb\U0001f1f2", + ":flag_fo:": "\U0001f1eb\U0001f1f4", + ":flag_fr:": "\U0001f1eb\U0001f1f7", + ":flag_ga:": "\U0001f1ec\U0001f1e6", + ":flag_gb:": "\U0001f1ec\U0001f1e7", + ":flag_gd:": "\U0001f1ec\U0001f1e9", + ":flag_ge:": "\U0001f1ec\U0001f1ea", + ":flag_gf:": "\U0001f1ec\U0001f1eb", + ":flag_gg:": "\U0001f1ec\U0001f1ec", + ":flag_gh:": "\U0001f1ec\U0001f1ed", + ":flag_gi:": "\U0001f1ec\U0001f1ee", + ":flag_gl:": "\U0001f1ec\U0001f1f1", + ":flag_gm:": "\U0001f1ec\U0001f1f2", + ":flag_gn:": "\U0001f1ec\U0001f1f3", + ":flag_gp:": "\U0001f1ec\U0001f1f5", + ":flag_gq:": "\U0001f1ec\U0001f1f6", + ":flag_gr:": "\U0001f1ec\U0001f1f7", + ":flag_gs:": "\U0001f1ec\U0001f1f8", + ":flag_gt:": "\U0001f1ec\U0001f1f9", + ":flag_gu:": "\U0001f1ec\U0001f1fa", + ":flag_gw:": "\U0001f1ec\U0001f1fc", + ":flag_gy:": "\U0001f1ec\U0001f1fe", + ":flag_hk:": "\U0001f1ed\U0001f1f0", + ":flag_hm:": "\U0001f1ed\U0001f1f2", + ":flag_hn:": "\U0001f1ed\U0001f1f3", + ":flag_hr:": "\U0001f1ed\U0001f1f7", + ":flag_ht:": "\U0001f1ed\U0001f1f9", + ":flag_hu:": "\U0001f1ed\U0001f1fa", + ":flag_ic:": "\U0001f1ee\U0001f1e8", + ":flag_id:": "\U0001f1ee\U0001f1e9", + ":flag_ie:": "\U0001f1ee\U0001f1ea", + ":flag_il:": "\U0001f1ee\U0001f1f1", + ":flag_im:": "\U0001f1ee\U0001f1f2", + ":flag_in:": "\U0001f1ee\U0001f1f3", + ":flag_in_hole:": "\U000026f3", + ":flag_io:": "\U0001f1ee\U0001f1f4", + ":flag_iq:": "\U0001f1ee\U0001f1f6", + ":flag_ir:": "\U0001f1ee\U0001f1f7", + ":flag_is:": "\U0001f1ee\U0001f1f8", + ":flag_it:": "\U0001f1ee\U0001f1f9", + ":flag_je:": "\U0001f1ef\U0001f1ea", + ":flag_jm:": "\U0001f1ef\U0001f1f2", + ":flag_jo:": "\U0001f1ef\U0001f1f4", + ":flag_jp:": "\U0001f1ef\U0001f1f5", + ":flag_ke:": "\U0001f1f0\U0001f1ea", + ":flag_kg:": "\U0001f1f0\U0001f1ec", + ":flag_kh:": "\U0001f1f0\U0001f1ed", + ":flag_ki:": "\U0001f1f0\U0001f1ee", + ":flag_km:": "\U0001f1f0\U0001f1f2", + ":flag_kn:": "\U0001f1f0\U0001f1f3", + ":flag_kp:": "\U0001f1f0\U0001f1f5", + ":flag_kr:": "\U0001f1f0\U0001f1f7", + ":flag_kw:": "\U0001f1f0\U0001f1fc", + ":flag_ky:": "\U0001f1f0\U0001f1fe", + ":flag_kz:": "\U0001f1f0\U0001f1ff", + ":flag_la:": "\U0001f1f1\U0001f1e6", + ":flag_lb:": "\U0001f1f1\U0001f1e7", + ":flag_lc:": "\U0001f1f1\U0001f1e8", + ":flag_li:": "\U0001f1f1\U0001f1ee", + ":flag_lk:": "\U0001f1f1\U0001f1f0", + ":flag_lr:": "\U0001f1f1\U0001f1f7", + ":flag_ls:": "\U0001f1f1\U0001f1f8", + ":flag_lt:": "\U0001f1f1\U0001f1f9", + ":flag_lu:": "\U0001f1f1\U0001f1fa", + ":flag_lv:": "\U0001f1f1\U0001f1fb", + ":flag_ly:": "\U0001f1f1\U0001f1fe", + ":flag_ma:": "\U0001f1f2\U0001f1e6", + ":flag_mc:": "\U0001f1f2\U0001f1e8", + ":flag_md:": "\U0001f1f2\U0001f1e9", + ":flag_me:": "\U0001f1f2\U0001f1ea", + ":flag_mf:": "\U0001f1f2\U0001f1eb", + ":flag_mg:": "\U0001f1f2\U0001f1ec", + ":flag_mh:": "\U0001f1f2\U0001f1ed", + ":flag_mk:": "\U0001f1f2\U0001f1f0", + ":flag_ml:": "\U0001f1f2\U0001f1f1", + ":flag_mm:": "\U0001f1f2\U0001f1f2", + ":flag_mn:": "\U0001f1f2\U0001f1f3", + ":flag_mo:": "\U0001f1f2\U0001f1f4", + ":flag_mp:": "\U0001f1f2\U0001f1f5", + ":flag_mq:": "\U0001f1f2\U0001f1f6", + ":flag_mr:": "\U0001f1f2\U0001f1f7", + ":flag_ms:": "\U0001f1f2\U0001f1f8", + ":flag_mt:": "\U0001f1f2\U0001f1f9", + ":flag_mu:": "\U0001f1f2\U0001f1fa", + ":flag_mv:": "\U0001f1f2\U0001f1fb", + ":flag_mw:": "\U0001f1f2\U0001f1fc", + ":flag_mx:": "\U0001f1f2\U0001f1fd", + ":flag_my:": "\U0001f1f2\U0001f1fe", + ":flag_mz:": "\U0001f1f2\U0001f1ff", + ":flag_na:": "\U0001f1f3\U0001f1e6", + ":flag_nc:": "\U0001f1f3\U0001f1e8", + ":flag_ne:": "\U0001f1f3\U0001f1ea", + ":flag_nf:": "\U0001f1f3\U0001f1eb", + ":flag_ng:": "\U0001f1f3\U0001f1ec", + ":flag_ni:": "\U0001f1f3\U0001f1ee", + ":flag_nl:": "\U0001f1f3\U0001f1f1", + ":flag_no:": "\U0001f1f3\U0001f1f4", + ":flag_np:": "\U0001f1f3\U0001f1f5", + ":flag_nr:": "\U0001f1f3\U0001f1f7", + ":flag_nu:": "\U0001f1f3\U0001f1fa", + ":flag_nz:": "\U0001f1f3\U0001f1ff", + ":flag_om:": "\U0001f1f4\U0001f1f2", + ":flag_pa:": "\U0001f1f5\U0001f1e6", + ":flag_pe:": "\U0001f1f5\U0001f1ea", + ":flag_pf:": "\U0001f1f5\U0001f1eb", + ":flag_pg:": "\U0001f1f5\U0001f1ec", + ":flag_ph:": "\U0001f1f5\U0001f1ed", + ":flag_pk:": "\U0001f1f5\U0001f1f0", + ":flag_pl:": "\U0001f1f5\U0001f1f1", + ":flag_pm:": "\U0001f1f5\U0001f1f2", + ":flag_pn:": "\U0001f1f5\U0001f1f3", + ":flag_pr:": "\U0001f1f5\U0001f1f7", + ":flag_ps:": "\U0001f1f5\U0001f1f8", + ":flag_pt:": "\U0001f1f5\U0001f1f9", + ":flag_pw:": "\U0001f1f5\U0001f1fc", + ":flag_py:": "\U0001f1f5\U0001f1fe", + ":flag_qa:": "\U0001f1f6\U0001f1e6", + ":flag_re:": "\U0001f1f7\U0001f1ea", + ":flag_ro:": "\U0001f1f7\U0001f1f4", + ":flag_rs:": "\U0001f1f7\U0001f1f8", + ":flag_ru:": "\U0001f1f7\U0001f1fa", + ":flag_rw:": "\U0001f1f7\U0001f1fc", + ":flag_sa:": "\U0001f1f8\U0001f1e6", + ":flag_sb:": "\U0001f1f8\U0001f1e7", + ":flag_sc:": "\U0001f1f8\U0001f1e8", + ":flag_sd:": "\U0001f1f8\U0001f1e9", + ":flag_se:": "\U0001f1f8\U0001f1ea", + ":flag_sg:": "\U0001f1f8\U0001f1ec", + ":flag_sh:": "\U0001f1f8\U0001f1ed", + ":flag_si:": "\U0001f1f8\U0001f1ee", + ":flag_sj:": "\U0001f1f8\U0001f1ef", + ":flag_sk:": "\U0001f1f8\U0001f1f0", + ":flag_sl:": "\U0001f1f8\U0001f1f1", + ":flag_sm:": "\U0001f1f8\U0001f1f2", + ":flag_sn:": "\U0001f1f8\U0001f1f3", + ":flag_so:": "\U0001f1f8\U0001f1f4", + ":flag_sr:": "\U0001f1f8\U0001f1f7", + ":flag_ss:": "\U0001f1f8\U0001f1f8", + ":flag_st:": "\U0001f1f8\U0001f1f9", + ":flag_sv:": "\U0001f1f8\U0001f1fb", + ":flag_sx:": "\U0001f1f8\U0001f1fd", + ":flag_sy:": "\U0001f1f8\U0001f1fe", + ":flag_sz:": "\U0001f1f8\U0001f1ff", + ":flag_ta:": "\U0001f1f9\U0001f1e6", + ":flag_tc:": "\U0001f1f9\U0001f1e8", + ":flag_td:": "\U0001f1f9\U0001f1e9", + ":flag_tf:": "\U0001f1f9\U0001f1eb", + ":flag_tg:": "\U0001f1f9\U0001f1ec", + ":flag_th:": "\U0001f1f9\U0001f1ed", + ":flag_tj:": "\U0001f1f9\U0001f1ef", + ":flag_tk:": "\U0001f1f9\U0001f1f0", + ":flag_tl:": "\U0001f1f9\U0001f1f1", + ":flag_tm:": "\U0001f1f9\U0001f1f2", + ":flag_tn:": "\U0001f1f9\U0001f1f3", + ":flag_to:": "\U0001f1f9\U0001f1f4", + ":flag_tr:": "\U0001f1f9\U0001f1f7", + ":flag_tt:": "\U0001f1f9\U0001f1f9", + ":flag_tv:": "\U0001f1f9\U0001f1fb", + ":flag_tw:": "\U0001f1f9\U0001f1fc", + ":flag_tz:": "\U0001f1f9\U0001f1ff", + ":flag_ua:": "\U0001f1fa\U0001f1e6", + ":flag_ug:": "\U0001f1fa\U0001f1ec", + ":flag_um:": "\U0001f1fa\U0001f1f2", + ":flag_us:": "\U0001f1fa\U0001f1f8", + ":flag_uy:": "\U0001f1fa\U0001f1fe", + ":flag_uz:": "\U0001f1fa\U0001f1ff", + ":flag_va:": "\U0001f1fb\U0001f1e6", + ":flag_vc:": "\U0001f1fb\U0001f1e8", + ":flag_ve:": "\U0001f1fb\U0001f1ea", + ":flag_vg:": "\U0001f1fb\U0001f1ec", + ":flag_vi:": "\U0001f1fb\U0001f1ee", + ":flag_vn:": "\U0001f1fb\U0001f1f3", + ":flag_vu:": "\U0001f1fb\U0001f1fa", + ":flag_wf:": "\U0001f1fc\U0001f1eb", + ":flag_white:": "\U0001f3f3", + ":flag_ws:": "\U0001f1fc\U0001f1f8", + ":flag_xk:": "\U0001f1fd\U0001f1f0", + ":flag_ye:": "\U0001f1fe\U0001f1ea", + ":flag_yt:": "\U0001f1fe\U0001f1f9", + ":flag_za:": "\U0001f1ff\U0001f1e6", + ":flag_zm:": "\U0001f1ff\U0001f1f2", + ":flag_zw:": "\U0001f1ff\U0001f1fc", + ":flag_Åland_Islands:": "\U0001f1e6\U0001f1fd", + ":flags:": "\U0001f38f", + ":flashlight:": "\U0001f526", + ":flat_shoe:": "\U0001f97f", + ":fleur-de-lis:": "\U0000269c", + ":fleur_de_lis:": "\u269c\ufe0f", + ":flexed_biceps:": "\U0001f4aa", + ":flight_arrival:": "\U0001f6ec", + ":flight_departure:": "\U0001f6eb", + ":flipper:": "\U0001f42c", + ":floppy_disk:": "\U0001f4be", + ":flower_playing_cards:": "\U0001f3b4", + ":flushed:": "\U0001f633", + ":flushed_face:": "\U0001f633", + ":flying_disc:": "\U0001f94f", + ":flying_saucer:": "\U0001f6f8", + ":fog:": "\U0001f32b", + ":foggy:": "\U0001f301", + ":folded_hands:": "\U0001f64f", + ":foot:": "\U0001f9b6", + ":football:": "\U0001f3c8", + ":footprints:": "\U0001f463", + ":fork_and_knife:": "\U0001f374", + ":fork_and_knife_with_plate:": "\U0001f37d", + ":fork_knife_plate:": "\U0001f37d", + ":fortune_cookie:": "\U0001f960", + ":fountain:": "\U000026f2", + ":fountain_pen:": "\U0001f58b", + ":four:": "4\ufe0f\u20e3", + ":four-thirty:": "\U0001f55f", + ":four_leaf_clover:": "\U0001f340", + ":four_o’clock:": "\U0001f553", + ":fox:": "\U0001f98a", + ":fox_face:": "\U0001f98a", + ":fr:": "\U0001f1eb\U0001f1f7", + ":frame_photo:": "\U0001f5bc", + ":framed_picture:": "\U0001f5bc", + ":free:": "\U0001f193", + ":french_bread:": "\U0001f956", + ":french_fries:": "\U0001f35f", + ":french_guiana:": "\U0001f1ec\U0001f1eb", + ":french_polynesia:": "\U0001f1f5\U0001f1eb", + ":french_southern_territories:": "\U0001f1f9\U0001f1eb", + ":fried_egg:": "\U0001f373", + ":fried_shrimp:": "\U0001f364", + ":fries:": "\U0001f35f", + ":frog:": "\U0001f438", + ":front-facing_baby_chick:": "\U0001f425", + ":frowning:": "\U0001f626", + ":frowning2:": "\u2639", + ":frowning_face:": "\U00002639", + ":frowning_face_with_open_mouth:": "\U0001f626", + ":frowning_man:": "\U0001f64d\u200d\u2642", + ":frowning_woman:": "\U0001f64d", + ":fu:": "\U0001f595", + ":fuel_pump:": "\U000026fd", + ":fuelpump:": "\u26fd", + ":full_moon:": "\U0001f315", + ":full_moon_face:": "\U0001f31d", + ":full_moon_with_face:": "\U0001f31d", + ":funeral_urn:": "\U000026b1", + ":gabon:": "\U0001f1ec\U0001f1e6", + ":gambia:": "\U0001f1ec\U0001f1f2", + ":game_die:": "\U0001f3b2", + ":gb:": "\U0001f1ec\U0001f1e7", + ":gear:": "\U00002699", + ":gem:": "\U0001f48e", + ":gem_stone:": "\U0001f48e", + ":gemini:": "\u264a", + ":genie:": "\U0001f9de", + ":georgia:": "\U0001f1ec\U0001f1ea", + ":ghana:": "\U0001f1ec\U0001f1ed", + ":ghost:": "\U0001f47b", + ":gibraltar:": "\U0001f1ec\U0001f1ee", + ":gift:": "\U0001f381", + ":gift_heart:": "\U0001f49d", + ":giraffe:": "\U0001f992", + ":girl:": "\U0001f467", + ":girl_tone1:": "\U0001f467\U0001f3fb", + ":girl_tone2:": "\U0001f467\U0001f3fc", + ":girl_tone3:": "\U0001f467\U0001f3fd", + ":girl_tone4:": "\U0001f467\U0001f3fe", + ":girl_tone5:": "\U0001f467\U0001f3ff", + ":glass_of_milk:": "\U0001f95b", + ":glasses:": "\U0001f453", + ":globe_showing_Americas:": "\U0001f30e", + ":globe_showing_Asia-Australia:": "\U0001f30f", + ":globe_showing_Europe-Africa:": "\U0001f30d", + ":globe_with_meridians:": "\U0001f310", + ":gloves:": "\U0001f9e4", + ":glowing_star:": "\U0001f31f", + ":goal:": "\U0001f945", + ":goal_net:": "\U0001f945", + ":goat:": "\U0001f410", + ":goblin:": "\U0001f47a", + ":goggles:": "\U0001f97d", + ":golf:": "\u26f3", + ":golfing_man:": "\U0001f3cc", + ":golfing_woman:": "\U0001f3cc\ufe0f\u200d\u2640\ufe0f", + ":gorilla:": "\U0001f98d", + ":graduation_cap:": "\U0001f393", + ":grapes:": "\U0001f347", + ":greece:": "\U0001f1ec\U0001f1f7", + ":green_apple:": "\U0001f34f", + ":green_book:": "\U0001f4d7", + ":green_heart:": "\U0001f49a", + ":green_salad:": "\U0001f957", + ":greenland:": "\U0001f1ec\U0001f1f1", + ":grenada:": "\U0001f1ec\U0001f1e9", + ":grey_exclamation:": "\u2755", + ":grey_question:": "\u2754", + ":grimacing:": "\U0001f62c", + ":grimacing_face:": "\U0001f62c", + ":grin:": "\U0001f604", + ":grinning:": "\U0001f600", + ":grinning_cat:": "\U0001f63a", + ":grinning_cat_with_smiling_eyes:": "\U0001f638", + ":grinning_face:": "\U0001f600", + ":grinning_face_with_big_eyes:": "\U0001f603", + ":grinning_face_with_smiling_eyes:": "\U0001f604", + ":grinning_face_with_sweat:": "\U0001f605", + ":grinning_squinting_face:": "\U0001f606", + ":growing_heart:": "\U0001f497", + ":guadeloupe:": "\U0001f1ec\U0001f1f5", + ":guam:": "\U0001f1ec\U0001f1fa", + ":guard:": "\U0001f482", + ":guard_tone1:": "\U0001f482\U0001f3fb", + ":guard_tone2:": "\U0001f482\U0001f3fc", + ":guard_tone3:": "\U0001f482\U0001f3fd", + ":guard_tone4:": "\U0001f482\U0001f3fe", + ":guard_tone5:": "\U0001f482\U0001f3ff", + ":guardsman:": "\U0001f482", + ":guardswoman:": "\U0001f482\u200d\u2640", + ":guatemala:": "\U0001f1ec\U0001f1f9", + ":guernsey:": "\U0001f1ec\U0001f1ec", + ":guinea:": "\U0001f1ec\U0001f1f3", + ":guinea_bissau:": "\U0001f1ec\U0001f1fc", + ":guitar:": "\U0001f3b8", + ":gun:": "\U0001f52b", + ":guyana:": "\U0001f1ec\U0001f1fe", + ":haircut:": "\U0001f487", + ":haircut_man:": "\U0001f487\u200d\u2642", + ":haircut_woman:": "\U0001f487", + ":haiti:": "\U0001f1ed\U0001f1f9", + ":hamburger:": "\U0001f354", + ":hammer:": "\U0001f528", + ":hammer_and_pick:": "\U00002692", + ":hammer_and_wrench:": "\U0001f6e0", + ":hammer_pick:": "\u2692", + ":hamster:": "\U0001f439", + ":hand:": "\u270b", + ":hand_splayed_tone1:": "\U0001f590\U0001f3fb", + ":hand_splayed_tone2:": "\U0001f590\U0001f3fc", + ":hand_splayed_tone3:": "\U0001f590\U0001f3fd", + ":hand_splayed_tone4:": "\U0001f590\U0001f3fe", + ":hand_splayed_tone5:": "\U0001f590\U0001f3ff", + ":hand_with_fingers_splayed:": "\U0001f590", + ":handbag:": "\U0001f45c", + ":handshake:": "\U0001f91d", + ":hankey:": "\U0001f4a9", + ":hash:": "#\ufe0f\u20e3", + ":hatched_chick:": "\U0001f425", + ":hatching_chick:": "\U0001f423", + ":head_bandage:": "\U0001f915", + ":headphone:": "\U0001f3a7", + ":headphones:": "\U0001f3a7", + ":hear-no-evil_monkey:": "\U0001f649", + ":hear_no_evil:": "\U0001f649", + ":heart:": "\u2764", + ":heart_decoration:": "\U0001f49f", + ":heart_exclamation:": "\U00002763", + ":heart_eyes:": "\U0001f60d", + ":heart_eyes_cat:": "\U0001f63b", + ":heart_suit:": "\U00002665", + ":heart_with_arrow:": "\U0001f498", + ":heart_with_ribbon:": "\U0001f49d", + ":heartbeat:": "\U0001f493", + ":heartpulse:": "\U0001f497", + ":hearts:": "\u2665", + ":heavy_check_mark:": "\u2714", + ":heavy_division_sign:": "\u2797", + ":heavy_dollar_sign:": "\U0001f4b2", + ":heavy_exclamation_mark:": "\u2757\ufe0f", + ":heavy_heart_exclamation:": "\u2763\ufe0f", + ":heavy_minus_sign:": "\u2796", + ":heavy_multiplication_x:": "\u2716", + ":heavy_plus_sign:": "\u2795", + ":hedgehog:": "\U0001f994", + ":helicopter:": "\U0001f681", + ":helmet_with_cross:": "\u26d1", + ":herb:": "\U0001f33f", + ":hibiscus:": "\U0001f33a", + ":high-heeled_shoe:": "\U0001f460", + ":high-speed_train:": "\U0001f684", + ":high_brightness:": "\U0001f506", + ":high_heel:": "\U0001f460", + ":high_voltage:": "\U000026a1", + ":hiking_boot:": "\U0001f97e", + ":hippopotamus:": "\U0001f99b", + ":hocho:": "\U0001f52a", + ":hockey:": "\U0001f3d2", + ":hole:": "\U0001f573", + ":hollow_red_circle:": "\U00002b55", + ":homes:": "\U0001f3d8", + ":honduras:": "\U0001f1ed\U0001f1f3", + ":honey_pot:": "\U0001f36f", + ":honeybee:": "\U0001f41d", + ":hong_kong:": "\U0001f1ed\U0001f1f0", + ":horizontal_traffic_light:": "\U0001f6a5", + ":horse:": "\U0001f40e", + ":horse_face:": "\U0001f434", + ":horse_racing:": "\U0001f3c7", + ":horse_racing_tone1:": "\U0001f3c7\U0001f3fb", + ":horse_racing_tone2:": "\U0001f3c7\U0001f3fc", + ":horse_racing_tone3:": "\U0001f3c7\U0001f3fd", + ":horse_racing_tone4:": "\U0001f3c7\U0001f3fe", + ":horse_racing_tone5:": "\U0001f3c7\U0001f3ff", + ":hospital:": "\U0001f3e5", + ":hot_beverage:": "\U00002615", + ":hot_dog:": "\U0001f32d", + ":hot_face:": "\U0001f975", + ":hot_pepper:": "\U0001f336", + ":hot_springs:": "\U00002668", + ":hotdog:": "\U0001f32d", + ":hotel:": "\U0001f3e8", + ":hotsprings:": "\u2668", + ":hourglass:": "\u231b", + ":hourglass_done:": "\U0000231b", + ":hourglass_flowing_sand:": "\u23f3", + ":hourglass_not_done:": "\U000023f3", + ":house:": "\U0001f3e0", + ":house_abandoned:": "\U0001f3da", + ":house_with_garden:": "\U0001f3e1", + ":houses:": "\U0001f3d8", + ":hugging:": "\U0001f917", + ":hugging_face:": "\U0001f917", + ":hugs:": "\U0001f917", + ":hundred_points:": "\U0001f4af", + ":hungary:": "\U0001f1ed\U0001f1fa", + ":hushed:": "\U0001f62f", + ":hushed_face:": "\U0001f62f", + ":ice_cream:": "\U0001f368", + ":ice_hockey:": "\U0001f3d2", + ":ice_skate:": "\U000026f8", + ":icecream:": "\U0001f366", + ":iceland:": "\U0001f1ee\U0001f1f8", + ":id:": "\U0001f194", + ":ideograph_advantage:": "\U0001f250", + ":imp:": "\U0001f47f", + ":inbox_tray:": "\U0001f4e5", + ":incoming_envelope:": "\U0001f4e8", + ":index_pointing_up:": "\U0000261d", + ":india:": "\U0001f1ee\U0001f1f3", + ":indonesia:": "\U0001f1ee\U0001f1e9", + ":infinity:": "\U0000267e", + ":information:": "\U00002139", + ":information_desk_person:": "\U0001f481", + ":information_source:": "\u2139", + ":innocent:": "\U0001f607", + ":input_latin_letters:": "\U0001f524", + ":input_latin_lowercase:": "\U0001f521", + ":input_latin_uppercase:": "\U0001f520", + ":input_numbers:": "\U0001f522", + ":input_symbols:": "\U0001f523", + ":interrobang:": "\u2049", + ":iphone:": "\U0001f4f1", + ":iran:": "\U0001f1ee\U0001f1f7", + ":iraq:": "\U0001f1ee\U0001f1f6", + ":ireland:": "\U0001f1ee\U0001f1ea", + ":island:": "\U0001f3dd", + ":isle_of_man:": "\U0001f1ee\U0001f1f2", + ":israel:": "\U0001f1ee\U0001f1f1", + ":it:": "\U0001f1ee\U0001f1f9", + ":izakaya_lantern:": "\U0001f3ee", + ":jack-o-lantern:": "\U0001f383", + ":jack_o_lantern:": "\U0001f383", + ":jamaica:": "\U0001f1ef\U0001f1f2", + ":japan:": "\U0001f5fe", + ":japanese_castle:": "\U0001f3ef", + ":japanese_goblin:": "\U0001f47a", + ":japanese_ogre:": "\U0001f479", + ":jeans:": "\U0001f456", + ":jersey:": "\U0001f1ef\U0001f1ea", + ":joker:": "\U0001f0cf", + ":jordan:": "\U0001f1ef\U0001f1f4", + ":joy:": "\U0001f602", + ":joy_cat:": "\U0001f639", + ":joystick:": "\U0001f579", + ":jp:": "\U0001f1ef\U0001f1f5", + ":kaaba:": "\U0001f54b", + ":kangaroo:": "\U0001f998", + ":kazakhstan:": "\U0001f1f0\U0001f1ff", + ":kenya:": "\U0001f1f0\U0001f1ea", + ":key:": "\U0001f511", + ":key2:": "\U0001f5dd", + ":keyboard:": "\U00002328", + ":keycap_#:": "\U00000023\U0000fe0f\U000020e3", + ":keycap_*:": "\U0000002a\U0000fe0f\U000020e3", + ":keycap_0:": "\U00000030\U0000fe0f\U000020e3", + ":keycap_1:": "\U00000031\U0000fe0f\U000020e3", + ":keycap_10:": "\U0001f51f", + ":keycap_2:": "\U00000032\U0000fe0f\U000020e3", + ":keycap_3:": "\U00000033\U0000fe0f\U000020e3", + ":keycap_4:": "\U00000034\U0000fe0f\U000020e3", + ":keycap_5:": "\U00000035\U0000fe0f\U000020e3", + ":keycap_6:": "\U00000036\U0000fe0f\U000020e3", + ":keycap_7:": "\U00000037\U0000fe0f\U000020e3", + ":keycap_8:": "\U00000038\U0000fe0f\U000020e3", + ":keycap_9:": "\U00000039\U0000fe0f\U000020e3", + ":keycap_ten:": "\U0001f51f", + ":kick_scooter:": "\U0001f6f4", + ":kimono:": "\U0001f458", + ":kiribati:": "\U0001f1f0\U0001f1ee", + ":kiss:": "\U0001f48f", + ":kiss_man_man:": "\U0001f468\U0000200d\U00002764\U0000fe0f\U0000200d\U0001f48b\U0000200d\U0001f468", + ":kiss_mark:": "\U0001f48b", + ":kiss_mm:": "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468", + ":kiss_woman_man:": "\U0001f469\U0000200d\U00002764\U0000fe0f\U0000200d\U0001f48b\U0000200d\U0001f468", + ":kiss_woman_woman:": "\U0001f469\U0000200d\U00002764\U0000fe0f\U0000200d\U0001f48b\U0000200d\U0001f469", + ":kiss_ww:": "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469", + ":kissing:": "\U0001f617", + ":kissing_cat:": "\U0001f63d", + ":kissing_closed_eyes:": "\U0001f61a", + ":kissing_face:": "\U0001f617", + ":kissing_face_with_closed_eyes:": "\U0001f61a", + ":kissing_face_with_smiling_eyes:": "\U0001f619", + ":kissing_heart:": "\U0001f618", + ":kissing_smiling_eyes:": "\U0001f619", + ":kitchen_knife:": "\U0001f52a", + ":kiwi:": "\U0001f95d", + ":kiwi_fruit:": "\U0001f95d", + ":knife:": "\U0001f52a", + ":koala:": "\U0001f428", + ":koko:": "\U0001f201", + ":kosovo:": "\U0001f1fd\U0001f1f0", + ":kr:": "\U0001f1f0\U0001f1f7", + ":kuwait:": "\U0001f1f0\U0001f1fc", + ":kyrgyzstan:": "\U0001f1f0\U0001f1ec", + ":lab_coat:": "\U0001f97c", + ":label:": "\U0001f3f7", + ":lacrosse:": "\U0001f94d", + ":lady_beetle:": "\U0001f41e", + ":lantern:": "\U0001f3ee", + ":laos:": "\U0001f1f1\U0001f1e6", + ":laptop_computer:": "\U0001f4bb", + ":large_blue_circle:": "\U0001f535", + ":large_blue_diamond:": "\U0001f537", + ":large_orange_diamond:": "\U0001f536", + ":last_quarter_moon:": "\U0001f317", + ":last_quarter_moon_face:": "\U0001f31c", + ":last_quarter_moon_with_face:": "\U0001f31c", + ":last_track_button:": "\U000023ee", + ":latin_cross:": "\U0000271d", + ":latvia:": "\U0001f1f1\U0001f1fb", + ":laughing:": "\U0001f606", + ":leaf_fluttering_in_wind:": "\U0001f343", + ":leafy_green:": "\U0001f96c", + ":leaves:": "\U0001f343", + ":lebanon:": "\U0001f1f1\U0001f1e7", + ":ledger:": "\U0001f4d2", + ":left-facing_fist:": "\U0001f91b", + ":left-right_arrow:": "\U00002194", + ":left_arrow:": "\U00002b05", + ":left_arrow_curving_right:": "\U000021aa", + ":left_facing_fist:": "\U0001f91b", + ":left_facing_fist_tone1:": "\U0001f91b\U0001f3fb", + ":left_facing_fist_tone2:": "\U0001f91b\U0001f3fc", + ":left_facing_fist_tone3:": "\U0001f91b\U0001f3fd", + ":left_facing_fist_tone4:": "\U0001f91b\U0001f3fe", + ":left_facing_fist_tone5:": "\U0001f91b\U0001f3ff", + ":left_luggage:": "\U0001f6c5", + ":left_right_arrow:": "\u2194", + ":left_speech_bubble:": "\U0001f5e8", + ":leftwards_arrow_with_hook:": "\u21a9", + ":leg:": "\U0001f9b5", + ":lemon:": "\U0001f34b", + ":leo:": "\u264c", + ":leopard:": "\U0001f406", + ":lesotho:": "\U0001f1f1\U0001f1f8", + ":level_slider:": "\U0001f39a", + ":liberia:": "\U0001f1f1\U0001f1f7", + ":libra:": "\u264e", + ":libya:": "\U0001f1f1\U0001f1fe", + ":liechtenstein:": "\U0001f1f1\U0001f1ee", + ":light_bulb:": "\U0001f4a1", + ":light_rail:": "\U0001f688", + ":link:": "\U0001f517", + ":linked_paperclips:": "\U0001f587", + ":lion:": "\U0001f981", + ":lion_face:": "\U0001f981", + ":lips:": "\U0001f444", + ":lipstick:": "\U0001f484", + ":lithuania:": "\U0001f1f1\U0001f1f9", + ":litter_in_bin_sign:": "\U0001f6ae", + ":lizard:": "\U0001f98e", + ":llama:": "\U0001f999", + ":lobster:": "\U0001f99e", + ":lock:": "\U0001f512", + ":lock_with_ink_pen:": "\U0001f50f", + ":locked:": "\U0001f512", + ":locked_with_key:": "\U0001f510", + ":locked_with_pen:": "\U0001f50f", + ":locomotive:": "\U0001f682", + ":lollipop:": "\U0001f36d", + ":loop:": "\u27bf", + ":lotion_bottle:": "\U0001f9f4", + ":loud_sound:": "\U0001f50a", + ":loudly_crying_face:": "\U0001f62d", + ":loudspeaker:": "\U0001f4e2", + ":love-you_gesture:": "\U0001f91f", + ":love_hotel:": "\U0001f3e9", + ":love_letter:": "\U0001f48c", + ":love_you_gesture:": "\U0001f91f", + ":love_you_gesture_tone1:": "\U0001f91f\U0001f3fb", + ":love_you_gesture_tone2:": "\U0001f91f\U0001f3fc", + ":love_you_gesture_tone3:": "\U0001f91f\U0001f3fd", + ":love_you_gesture_tone4:": "\U0001f91f\U0001f3fe", + ":love_you_gesture_tone5:": "\U0001f91f\U0001f3ff", + ":low_brightness:": "\U0001f505", + ":luggage:": "\U0001f9f3", + ":luxembourg:": "\U0001f1f1\U0001f1fa", + ":lying_face:": "\U0001f925", + ":m:": "\u24dc", + ":macau:": "\U0001f1f2\U0001f1f4", + ":macedonia:": "\U0001f1f2\U0001f1f0", + ":madagascar:": "\U0001f1f2\U0001f1ec", + ":mag:": "\U0001f50d", + ":mag_right:": "\U0001f50e", + ":mage:": "\U0001f9d9", + ":mage_tone1:": "\U0001f9d9\U0001f3fb", + ":mage_tone2:": "\U0001f9d9\U0001f3fc", + ":mage_tone3:": "\U0001f9d9\U0001f3fd", + ":mage_tone4:": "\U0001f9d9\U0001f3fe", + ":mage_tone5:": "\U0001f9d9\U0001f3ff", + ":magnet:": "\U0001f9f2", + ":magnifying_glass_tilted_left:": "\U0001f50d", + ":magnifying_glass_tilted_right:": "\U0001f50e", + ":mahjong:": "\U0001f004", + ":mahjong_red_dragon:": "\U0001f004", + ":mailbox:": "\U0001f4eb", + ":mailbox_closed:": "\U0001f4ea", + ":mailbox_with_mail:": "\U0001f4ec", + ":mailbox_with_no_mail:": "\U0001f4ed", + ":malawi:": "\U0001f1f2\U0001f1fc", + ":malaysia:": "\U0001f1f2\U0001f1fe", + ":maldives:": "\U0001f1f2\U0001f1fb", + ":male_detective:": "\U0001f575", + ":male_sign:": "\U00002642", + ":mali:": "\U0001f1f2\U0001f1f1", + ":malta:": "\U0001f1f2\U0001f1f9", + ":man:": "\U0001f468", + ":man_artist:": "\U0001f468\U0000200d\U0001f3a8", + ":man_artist_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f3a8", + ":man_artist_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f3a8", + ":man_artist_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f3a8", + ":man_artist_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f3a8", + ":man_artist_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f3a8", + ":man_astronaut:": "\U0001f468\U0000200d\U0001f680", + ":man_astronaut_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f680", + ":man_astronaut_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f680", + ":man_astronaut_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f680", + ":man_astronaut_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f680", + ":man_astronaut_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f680", + ":man_bald:": "\U0001f468\U0000200d\U0001f9b2", + ":man_beard:": "\U0001f9d4", + ":man_biking:": "\U0001f6b4\U0000200d\U00002642\U0000fe0f", + ":man_biking_tone1:": "\U0001f6b4\U0001f3fb\u200d\u2642\ufe0f", + ":man_biking_tone2:": "\U0001f6b4\U0001f3fc\u200d\u2642\ufe0f", + ":man_biking_tone3:": "\U0001f6b4\U0001f3fd\u200d\u2642\ufe0f", + ":man_biking_tone4:": "\U0001f6b4\U0001f3fe\u200d\u2642\ufe0f", + ":man_biking_tone5:": "\U0001f6b4\U0001f3ff\u200d\u2642\ufe0f", + ":man_blond_hair:": "\U0001f471\U0000200d\U00002642\U0000fe0f", + ":man_bouncing_ball:": "\U000026f9\U0000fe0f\U0000200d\U00002642\U0000fe0f", + ":man_bouncing_ball_tone1:": "\u26f9\U0001f3fb\u200d\u2642\ufe0f", + ":man_bouncing_ball_tone2:": "\u26f9\U0001f3fc\u200d\u2642\ufe0f", + ":man_bouncing_ball_tone3:": "\u26f9\U0001f3fd\u200d\u2642\ufe0f", + ":man_bouncing_ball_tone4:": "\u26f9\U0001f3fe\u200d\u2642\ufe0f", + ":man_bouncing_ball_tone5:": "\u26f9\U0001f3ff\u200d\u2642\ufe0f", + ":man_bowing:": "\U0001f647\U0000200d\U00002642\U0000fe0f", + ":man_bowing_tone1:": "\U0001f647\U0001f3fb\u200d\u2642\ufe0f", + ":man_bowing_tone2:": "\U0001f647\U0001f3fc\u200d\u2642\ufe0f", + ":man_bowing_tone3:": "\U0001f647\U0001f3fd\u200d\u2642\ufe0f", + ":man_bowing_tone4:": "\U0001f647\U0001f3fe\u200d\u2642\ufe0f", + ":man_bowing_tone5:": "\U0001f647\U0001f3ff\u200d\u2642\ufe0f", + ":man_cartwheeling:": "\U0001f938\U0000200d\U00002642\U0000fe0f", + ":man_cartwheeling_tone1:": "\U0001f938\U0001f3fb\u200d\u2642\ufe0f", + ":man_cartwheeling_tone2:": "\U0001f938\U0001f3fc\u200d\u2642\ufe0f", + ":man_cartwheeling_tone3:": "\U0001f938\U0001f3fd\u200d\u2642\ufe0f", + ":man_cartwheeling_tone4:": "\U0001f938\U0001f3fe\u200d\u2642\ufe0f", + ":man_cartwheeling_tone5:": "\U0001f938\U0001f3ff\u200d\u2642\ufe0f", + ":man_climbing:": "\U0001f9d7\U0000200d\U00002642\U0000fe0f", + ":man_climbing_tone1:": "\U0001f9d7\U0001f3fb\u200d\u2642\ufe0f", + ":man_climbing_tone2:": "\U0001f9d7\U0001f3fc\u200d\u2642\ufe0f", + ":man_climbing_tone3:": "\U0001f9d7\U0001f3fd\u200d\u2642\ufe0f", + ":man_climbing_tone4:": "\U0001f9d7\U0001f3fe\u200d\u2642\ufe0f", + ":man_climbing_tone5:": "\U0001f9d7\U0001f3ff\u200d\u2642\ufe0f", + ":man_construction_worker:": "\U0001f477\U0000200d\U00002642\U0000fe0f", + ":man_construction_worker_tone1:": "\U0001f477\U0001f3fb\u200d\u2642\ufe0f", + ":man_construction_worker_tone2:": "\U0001f477\U0001f3fc\u200d\u2642\ufe0f", + ":man_construction_worker_tone3:": "\U0001f477\U0001f3fd\u200d\u2642\ufe0f", + ":man_construction_worker_tone4:": "\U0001f477\U0001f3fe\u200d\u2642\ufe0f", + ":man_construction_worker_tone5:": "\U0001f477\U0001f3ff\u200d\u2642\ufe0f", + ":man_cook:": "\U0001f468\U0000200d\U0001f373", + ":man_cook_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f373", + ":man_cook_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f373", + ":man_cook_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f373", + ":man_cook_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f373", + ":man_cook_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f373", + ":man_curly_hair:": "\U0001f468\U0000200d\U0001f9b1", + ":man_dancing:": "\U0001f57a", + ":man_dancing_tone1:": "\U0001f57a\U0001f3fb", + ":man_dancing_tone2:": "\U0001f57a\U0001f3fc", + ":man_dancing_tone3:": "\U0001f57a\U0001f3fd", + ":man_dancing_tone4:": "\U0001f57a\U0001f3fe", + ":man_dancing_tone5:": "\U0001f57a\U0001f3ff", + ":man_detective:": "\U0001f575\U0000fe0f\U0000200d\U00002642\U0000fe0f", + ":man_detective_tone1:": "\U0001f575\U0001f3fb\u200d\u2642\ufe0f", + ":man_detective_tone2:": "\U0001f575\U0001f3fc\u200d\u2642\ufe0f", + ":man_detective_tone3:": "\U0001f575\U0001f3fd\u200d\u2642\ufe0f", + ":man_detective_tone4:": "\U0001f575\U0001f3fe\u200d\u2642\ufe0f", + ":man_detective_tone5:": "\U0001f575\U0001f3ff\u200d\u2642\ufe0f", + ":man_elf:": "\U0001f9dd\U0000200d\U00002642\U0000fe0f", + ":man_elf_tone1:": "\U0001f9dd\U0001f3fb\u200d\u2642\ufe0f", + ":man_elf_tone2:": "\U0001f9dd\U0001f3fc\u200d\u2642\ufe0f", + ":man_elf_tone3:": "\U0001f9dd\U0001f3fd\u200d\u2642\ufe0f", + ":man_elf_tone4:": "\U0001f9dd\U0001f3fe\u200d\u2642\ufe0f", + ":man_elf_tone5:": "\U0001f9dd\U0001f3ff\u200d\u2642\ufe0f", + ":man_facepalming:": "\U0001f926\U0000200d\U00002642\U0000fe0f", + ":man_facepalming_tone1:": "\U0001f926\U0001f3fb\u200d\u2642\ufe0f", + ":man_facepalming_tone2:": "\U0001f926\U0001f3fc\u200d\u2642\ufe0f", + ":man_facepalming_tone3:": "\U0001f926\U0001f3fd\u200d\u2642\ufe0f", + ":man_facepalming_tone4:": "\U0001f926\U0001f3fe\u200d\u2642\ufe0f", + ":man_facepalming_tone5:": "\U0001f926\U0001f3ff\u200d\u2642\ufe0f", + ":man_factory_worker:": "\U0001f468\U0000200d\U0001f3ed", + ":man_factory_worker_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f3ed", + ":man_factory_worker_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f3ed", + ":man_factory_worker_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f3ed", + ":man_factory_worker_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f3ed", + ":man_factory_worker_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f3ed", + ":man_fairy:": "\U0001f9da\U0000200d\U00002642\U0000fe0f", + ":man_fairy_tone1:": "\U0001f9da\U0001f3fb\u200d\u2642\ufe0f", + ":man_fairy_tone2:": "\U0001f9da\U0001f3fc\u200d\u2642\ufe0f", + ":man_fairy_tone3:": "\U0001f9da\U0001f3fd\u200d\u2642\ufe0f", + ":man_fairy_tone4:": "\U0001f9da\U0001f3fe\u200d\u2642\ufe0f", + ":man_fairy_tone5:": "\U0001f9da\U0001f3ff\u200d\u2642\ufe0f", + ":man_farmer:": "\U0001f468\U0000200d\U0001f33e", + ":man_farmer_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f33e", + ":man_farmer_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f33e", + ":man_farmer_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f33e", + ":man_farmer_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f33e", + ":man_farmer_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f33e", + ":man_firefighter:": "\U0001f468\U0000200d\U0001f692", + ":man_firefighter_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f692", + ":man_firefighter_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f692", + ":man_firefighter_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f692", + ":man_firefighter_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f692", + ":man_firefighter_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f692", + ":man_frowning:": "\U0001f64d\U0000200d\U00002642\U0000fe0f", + ":man_frowning_tone1:": "\U0001f64d\U0001f3fb\u200d\u2642\ufe0f", + ":man_frowning_tone2:": "\U0001f64d\U0001f3fc\u200d\u2642\ufe0f", + ":man_frowning_tone3:": "\U0001f64d\U0001f3fd\u200d\u2642\ufe0f", + ":man_frowning_tone4:": "\U0001f64d\U0001f3fe\u200d\u2642\ufe0f", + ":man_frowning_tone5:": "\U0001f64d\U0001f3ff\u200d\u2642\ufe0f", + ":man_genie:": "\U0001f9de\U0000200d\U00002642\U0000fe0f", + ":man_gesturing_NO:": "\U0001f645\U0000200d\U00002642\U0000fe0f", + ":man_gesturing_OK:": "\U0001f646\U0000200d\U00002642\U0000fe0f", + ":man_gesturing_no:": "\U0001f645\u200d\u2642\ufe0f", + ":man_gesturing_no_tone1:": "\U0001f645\U0001f3fb\u200d\u2642\ufe0f", + ":man_gesturing_no_tone2:": "\U0001f645\U0001f3fc\u200d\u2642\ufe0f", + ":man_gesturing_no_tone3:": "\U0001f645\U0001f3fd\u200d\u2642\ufe0f", + ":man_gesturing_no_tone4:": "\U0001f645\U0001f3fe\u200d\u2642\ufe0f", + ":man_gesturing_no_tone5:": "\U0001f645\U0001f3ff\u200d\u2642\ufe0f", + ":man_gesturing_ok:": "\U0001f646\u200d\u2642\ufe0f", + ":man_gesturing_ok_tone1:": "\U0001f646\U0001f3fb\u200d\u2642\ufe0f", + ":man_gesturing_ok_tone2:": "\U0001f646\U0001f3fc\u200d\u2642\ufe0f", + ":man_gesturing_ok_tone3:": "\U0001f646\U0001f3fd\u200d\u2642\ufe0f", + ":man_gesturing_ok_tone4:": "\U0001f646\U0001f3fe\u200d\u2642\ufe0f", + ":man_gesturing_ok_tone5:": "\U0001f646\U0001f3ff\u200d\u2642\ufe0f", + ":man_getting_face_massage:": "\U0001f486\u200d\u2642\ufe0f", + ":man_getting_face_massage_tone1:": "\U0001f486\U0001f3fb\u200d\u2642\ufe0f", + ":man_getting_face_massage_tone2:": "\U0001f486\U0001f3fc\u200d\u2642\ufe0f", + ":man_getting_face_massage_tone3:": "\U0001f486\U0001f3fd\u200d\u2642\ufe0f", + ":man_getting_face_massage_tone4:": "\U0001f486\U0001f3fe\u200d\u2642\ufe0f", + ":man_getting_face_massage_tone5:": "\U0001f486\U0001f3ff\u200d\u2642\ufe0f", + ":man_getting_haircut:": "\U0001f487\U0000200d\U00002642\U0000fe0f", + ":man_getting_haircut_tone1:": "\U0001f487\U0001f3fb\u200d\u2642\ufe0f", + ":man_getting_haircut_tone2:": "\U0001f487\U0001f3fc\u200d\u2642\ufe0f", + ":man_getting_haircut_tone3:": "\U0001f487\U0001f3fd\u200d\u2642\ufe0f", + ":man_getting_haircut_tone4:": "\U0001f487\U0001f3fe\u200d\u2642\ufe0f", + ":man_getting_haircut_tone5:": "\U0001f487\U0001f3ff\u200d\u2642\ufe0f", + ":man_getting_massage:": "\U0001f486\U0000200d\U00002642\U0000fe0f", + ":man_golfing:": "\U0001f3cc\U0000fe0f\U0000200d\U00002642\U0000fe0f", + ":man_golfing_tone1:": "\U0001f3cc\U0001f3fb\u200d\u2642\ufe0f", + ":man_golfing_tone2:": "\U0001f3cc\U0001f3fc\u200d\u2642\ufe0f", + ":man_golfing_tone3:": "\U0001f3cc\U0001f3fd\u200d\u2642\ufe0f", + ":man_golfing_tone4:": "\U0001f3cc\U0001f3fe\u200d\u2642\ufe0f", + ":man_golfing_tone5:": "\U0001f3cc\U0001f3ff\u200d\u2642\ufe0f", + ":man_guard:": "\U0001f482\U0000200d\U00002642\U0000fe0f", + ":man_guard_tone1:": "\U0001f482\U0001f3fb\u200d\u2642\ufe0f", + ":man_guard_tone2:": "\U0001f482\U0001f3fc\u200d\u2642\ufe0f", + ":man_guard_tone3:": "\U0001f482\U0001f3fd\u200d\u2642\ufe0f", + ":man_guard_tone4:": "\U0001f482\U0001f3fe\u200d\u2642\ufe0f", + ":man_guard_tone5:": "\U0001f482\U0001f3ff\u200d\u2642\ufe0f", + ":man_health_worker:": "\U0001f468\U0000200d\U00002695\U0000fe0f", + ":man_health_worker_tone1:": "\U0001f468\U0001f3fb\u200d\u2695\ufe0f", + ":man_health_worker_tone2:": "\U0001f468\U0001f3fc\u200d\u2695\ufe0f", + ":man_health_worker_tone3:": "\U0001f468\U0001f3fd\u200d\u2695\ufe0f", + ":man_health_worker_tone4:": "\U0001f468\U0001f3fe\u200d\u2695\ufe0f", + ":man_health_worker_tone5:": "\U0001f468\U0001f3ff\u200d\u2695\ufe0f", + ":man_in_business_suit_levitating_tone1:": "\U0001f574\U0001f3fb", + ":man_in_business_suit_levitating_tone2:": "\U0001f574\U0001f3fc", + ":man_in_business_suit_levitating_tone3:": "\U0001f574\U0001f3fd", + ":man_in_business_suit_levitating_tone4:": "\U0001f574\U0001f3fe", + ":man_in_business_suit_levitating_tone5:": "\U0001f574\U0001f3ff", + ":man_in_lotus_position:": "\U0001f9d8\U0000200d\U00002642\U0000fe0f", + ":man_in_lotus_position_tone1:": "\U0001f9d8\U0001f3fb\u200d\u2642\ufe0f", + ":man_in_lotus_position_tone2:": "\U0001f9d8\U0001f3fc\u200d\u2642\ufe0f", + ":man_in_lotus_position_tone3:": "\U0001f9d8\U0001f3fd\u200d\u2642\ufe0f", + ":man_in_lotus_position_tone4:": "\U0001f9d8\U0001f3fe\u200d\u2642\ufe0f", + ":man_in_lotus_position_tone5:": "\U0001f9d8\U0001f3ff\u200d\u2642\ufe0f", + ":man_in_steamy_room:": "\U0001f9d6\U0000200d\U00002642\U0000fe0f", + ":man_in_steamy_room_tone1:": "\U0001f9d6\U0001f3fb\u200d\u2642\ufe0f", + ":man_in_steamy_room_tone2:": "\U0001f9d6\U0001f3fc\u200d\u2642\ufe0f", + ":man_in_steamy_room_tone3:": "\U0001f9d6\U0001f3fd\u200d\u2642\ufe0f", + ":man_in_steamy_room_tone4:": "\U0001f9d6\U0001f3fe\u200d\u2642\ufe0f", + ":man_in_steamy_room_tone5:": "\U0001f9d6\U0001f3ff\u200d\u2642\ufe0f", + ":man_in_suit_levitating:": "\U0001f574", + ":man_in_tuxedo:": "\U0001f935", + ":man_in_tuxedo_tone1:": "\U0001f935\U0001f3fb", + ":man_in_tuxedo_tone2:": "\U0001f935\U0001f3fc", + ":man_in_tuxedo_tone3:": "\U0001f935\U0001f3fd", + ":man_in_tuxedo_tone4:": "\U0001f935\U0001f3fe", + ":man_in_tuxedo_tone5:": "\U0001f935\U0001f3ff", + ":man_judge:": "\U0001f468\U0000200d\U00002696\U0000fe0f", + ":man_judge_tone1:": "\U0001f468\U0001f3fb\u200d\u2696\ufe0f", + ":man_judge_tone2:": "\U0001f468\U0001f3fc\u200d\u2696\ufe0f", + ":man_judge_tone3:": "\U0001f468\U0001f3fd\u200d\u2696\ufe0f", + ":man_judge_tone4:": "\U0001f468\U0001f3fe\u200d\u2696\ufe0f", + ":man_judge_tone5:": "\U0001f468\U0001f3ff\u200d\u2696\ufe0f", + ":man_juggling:": "\U0001f939\U0000200d\U00002642\U0000fe0f", + ":man_juggling_tone1:": "\U0001f939\U0001f3fb\u200d\u2642\ufe0f", + ":man_juggling_tone2:": "\U0001f939\U0001f3fc\u200d\u2642\ufe0f", + ":man_juggling_tone3:": "\U0001f939\U0001f3fd\u200d\u2642\ufe0f", + ":man_juggling_tone4:": "\U0001f939\U0001f3fe\u200d\u2642\ufe0f", + ":man_juggling_tone5:": "\U0001f939\U0001f3ff\u200d\u2642\ufe0f", + ":man_lifting_weights:": "\U0001f3cb\U0000fe0f\U0000200d\U00002642\U0000fe0f", + ":man_lifting_weights_tone1:": "\U0001f3cb\U0001f3fb\u200d\u2642\ufe0f", + ":man_lifting_weights_tone2:": "\U0001f3cb\U0001f3fc\u200d\u2642\ufe0f", + ":man_lifting_weights_tone3:": "\U0001f3cb\U0001f3fd\u200d\u2642\ufe0f", + ":man_lifting_weights_tone4:": "\U0001f3cb\U0001f3fe\u200d\u2642\ufe0f", + ":man_lifting_weights_tone5:": "\U0001f3cb\U0001f3ff\u200d\u2642\ufe0f", + ":man_mage:": "\U0001f9d9\U0000200d\U00002642\U0000fe0f", + ":man_mage_tone1:": "\U0001f9d9\U0001f3fb\u200d\u2642\ufe0f", + ":man_mage_tone2:": "\U0001f9d9\U0001f3fc\u200d\u2642\ufe0f", + ":man_mage_tone3:": "\U0001f9d9\U0001f3fd\u200d\u2642\ufe0f", + ":man_mage_tone4:": "\U0001f9d9\U0001f3fe\u200d\u2642\ufe0f", + ":man_mage_tone5:": "\U0001f9d9\U0001f3ff\u200d\u2642\ufe0f", + ":man_mechanic:": "\U0001f468\U0000200d\U0001f527", + ":man_mechanic_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f527", + ":man_mechanic_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f527", + ":man_mechanic_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f527", + ":man_mechanic_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f527", + ":man_mechanic_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f527", + ":man_mountain_biking:": "\U0001f6b5\U0000200d\U00002642\U0000fe0f", + ":man_mountain_biking_tone1:": "\U0001f6b5\U0001f3fb\u200d\u2642\ufe0f", + ":man_mountain_biking_tone2:": "\U0001f6b5\U0001f3fc\u200d\u2642\ufe0f", + ":man_mountain_biking_tone3:": "\U0001f6b5\U0001f3fd\u200d\u2642\ufe0f", + ":man_mountain_biking_tone4:": "\U0001f6b5\U0001f3fe\u200d\u2642\ufe0f", + ":man_mountain_biking_tone5:": "\U0001f6b5\U0001f3ff\u200d\u2642\ufe0f", + ":man_office_worker:": "\U0001f468\U0000200d\U0001f4bc", + ":man_office_worker_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f4bc", + ":man_office_worker_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f4bc", + ":man_office_worker_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f4bc", + ":man_office_worker_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f4bc", + ":man_office_worker_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f4bc", + ":man_pilot:": "\U0001f468\U0000200d\U00002708\U0000fe0f", + ":man_pilot_tone1:": "\U0001f468\U0001f3fb\u200d\u2708\ufe0f", + ":man_pilot_tone2:": "\U0001f468\U0001f3fc\u200d\u2708\ufe0f", + ":man_pilot_tone3:": "\U0001f468\U0001f3fd\u200d\u2708\ufe0f", + ":man_pilot_tone4:": "\U0001f468\U0001f3fe\u200d\u2708\ufe0f", + ":man_pilot_tone5:": "\U0001f468\U0001f3ff\u200d\u2708\ufe0f", + ":man_playing_handball:": "\U0001f93e\U0000200d\U00002642\U0000fe0f", + ":man_playing_handball_tone1:": "\U0001f93e\U0001f3fb\u200d\u2642\ufe0f", + ":man_playing_handball_tone2:": "\U0001f93e\U0001f3fc\u200d\u2642\ufe0f", + ":man_playing_handball_tone3:": "\U0001f93e\U0001f3fd\u200d\u2642\ufe0f", + ":man_playing_handball_tone4:": "\U0001f93e\U0001f3fe\u200d\u2642\ufe0f", + ":man_playing_handball_tone5:": "\U0001f93e\U0001f3ff\u200d\u2642\ufe0f", + ":man_playing_water_polo:": "\U0001f93d\U0000200d\U00002642\U0000fe0f", + ":man_playing_water_polo_tone1:": "\U0001f93d\U0001f3fb\u200d\u2642\ufe0f", + ":man_playing_water_polo_tone2:": "\U0001f93d\U0001f3fc\u200d\u2642\ufe0f", + ":man_playing_water_polo_tone3:": "\U0001f93d\U0001f3fd\u200d\u2642\ufe0f", + ":man_playing_water_polo_tone4:": "\U0001f93d\U0001f3fe\u200d\u2642\ufe0f", + ":man_playing_water_polo_tone5:": "\U0001f93d\U0001f3ff\u200d\u2642\ufe0f", + ":man_police_officer:": "\U0001f46e\U0000200d\U00002642\U0000fe0f", + ":man_police_officer_tone1:": "\U0001f46e\U0001f3fb\u200d\u2642\ufe0f", + ":man_police_officer_tone2:": "\U0001f46e\U0001f3fc\u200d\u2642\ufe0f", + ":man_police_officer_tone3:": "\U0001f46e\U0001f3fd\u200d\u2642\ufe0f", + ":man_police_officer_tone4:": "\U0001f46e\U0001f3fe\u200d\u2642\ufe0f", + ":man_police_officer_tone5:": "\U0001f46e\U0001f3ff\u200d\u2642\ufe0f", + ":man_pouting:": "\U0001f64e\U0000200d\U00002642\U0000fe0f", + ":man_pouting_tone1:": "\U0001f64e\U0001f3fb\u200d\u2642\ufe0f", + ":man_pouting_tone2:": "\U0001f64e\U0001f3fc\u200d\u2642\ufe0f", + ":man_pouting_tone3:": "\U0001f64e\U0001f3fd\u200d\u2642\ufe0f", + ":man_pouting_tone4:": "\U0001f64e\U0001f3fe\u200d\u2642\ufe0f", + ":man_pouting_tone5:": "\U0001f64e\U0001f3ff\u200d\u2642\ufe0f", + ":man_raising_hand:": "\U0001f64b\U0000200d\U00002642\U0000fe0f", + ":man_raising_hand_tone1:": "\U0001f64b\U0001f3fb\u200d\u2642\ufe0f", + ":man_raising_hand_tone2:": "\U0001f64b\U0001f3fc\u200d\u2642\ufe0f", + ":man_raising_hand_tone3:": "\U0001f64b\U0001f3fd\u200d\u2642\ufe0f", + ":man_raising_hand_tone4:": "\U0001f64b\U0001f3fe\u200d\u2642\ufe0f", + ":man_raising_hand_tone5:": "\U0001f64b\U0001f3ff\u200d\u2642\ufe0f", + ":man_red_hair:": "\U0001f468\U0000200d\U0001f9b0", + ":man_rowing_boat:": "\U0001f6a3\U0000200d\U00002642\U0000fe0f", + ":man_rowing_boat_tone1:": "\U0001f6a3\U0001f3fb\u200d\u2642\ufe0f", + ":man_rowing_boat_tone2:": "\U0001f6a3\U0001f3fc\u200d\u2642\ufe0f", + ":man_rowing_boat_tone3:": "\U0001f6a3\U0001f3fd\u200d\u2642\ufe0f", + ":man_rowing_boat_tone4:": "\U0001f6a3\U0001f3fe\u200d\u2642\ufe0f", + ":man_rowing_boat_tone5:": "\U0001f6a3\U0001f3ff\u200d\u2642\ufe0f", + ":man_running:": "\U0001f3c3\U0000200d\U00002642\U0000fe0f", + ":man_running_tone1:": "\U0001f3c3\U0001f3fb\u200d\u2642\ufe0f", + ":man_running_tone2:": "\U0001f3c3\U0001f3fc\u200d\u2642\ufe0f", + ":man_running_tone3:": "\U0001f3c3\U0001f3fd\u200d\u2642\ufe0f", + ":man_running_tone4:": "\U0001f3c3\U0001f3fe\u200d\u2642\ufe0f", + ":man_running_tone5:": "\U0001f3c3\U0001f3ff\u200d\u2642\ufe0f", + ":man_scientist:": "\U0001f468\U0000200d\U0001f52c", + ":man_scientist_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f52c", + ":man_scientist_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f52c", + ":man_scientist_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f52c", + ":man_scientist_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f52c", + ":man_scientist_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f52c", + ":man_shrugging:": "\U0001f937\U0000200d\U00002642\U0000fe0f", + ":man_shrugging_tone1:": "\U0001f937\U0001f3fb\u200d\u2642\ufe0f", + ":man_shrugging_tone2:": "\U0001f937\U0001f3fc\u200d\u2642\ufe0f", + ":man_shrugging_tone3:": "\U0001f937\U0001f3fd\u200d\u2642\ufe0f", + ":man_shrugging_tone4:": "\U0001f937\U0001f3fe\u200d\u2642\ufe0f", + ":man_shrugging_tone5:": "\U0001f937\U0001f3ff\u200d\u2642\ufe0f", + ":man_singer:": "\U0001f468\U0000200d\U0001f3a4", + ":man_singer_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f3a4", + ":man_singer_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f3a4", + ":man_singer_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f3a4", + ":man_singer_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f3a4", + ":man_singer_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f3a4", + ":man_student:": "\U0001f468\U0000200d\U0001f393", + ":man_student_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f393", + ":man_student_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f393", + ":man_student_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f393", + ":man_student_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f393", + ":man_student_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f393", + ":man_superhero:": "\U0001f9b8\U0000200d\U00002642\U0000fe0f", + ":man_supervillain:": "\U0001f9b9\U0000200d\U00002642\U0000fe0f", + ":man_surfing:": "\U0001f3c4\U0000200d\U00002642\U0000fe0f", + ":man_surfing_tone1:": "\U0001f3c4\U0001f3fb\u200d\u2642\ufe0f", + ":man_surfing_tone2:": "\U0001f3c4\U0001f3fc\u200d\u2642\ufe0f", + ":man_surfing_tone3:": "\U0001f3c4\U0001f3fd\u200d\u2642\ufe0f", + ":man_surfing_tone4:": "\U0001f3c4\U0001f3fe\u200d\u2642\ufe0f", + ":man_surfing_tone5:": "\U0001f3c4\U0001f3ff\u200d\u2642\ufe0f", + ":man_swimming:": "\U0001f3ca\U0000200d\U00002642\U0000fe0f", + ":man_swimming_tone1:": "\U0001f3ca\U0001f3fb\u200d\u2642\ufe0f", + ":man_swimming_tone2:": "\U0001f3ca\U0001f3fc\u200d\u2642\ufe0f", + ":man_swimming_tone3:": "\U0001f3ca\U0001f3fd\u200d\u2642\ufe0f", + ":man_swimming_tone4:": "\U0001f3ca\U0001f3fe\u200d\u2642\ufe0f", + ":man_swimming_tone5:": "\U0001f3ca\U0001f3ff\u200d\u2642\ufe0f", + ":man_teacher:": "\U0001f468\U0000200d\U0001f3eb", + ":man_teacher_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f3eb", + ":man_teacher_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f3eb", + ":man_teacher_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f3eb", + ":man_teacher_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f3eb", + ":man_teacher_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f3eb", + ":man_technologist:": "\U0001f468\U0000200d\U0001f4bb", + ":man_technologist_tone1:": "\U0001f468\U0001f3fb\u200d\U0001f4bb", + ":man_technologist_tone2:": "\U0001f468\U0001f3fc\u200d\U0001f4bb", + ":man_technologist_tone3:": "\U0001f468\U0001f3fd\u200d\U0001f4bb", + ":man_technologist_tone4:": "\U0001f468\U0001f3fe\u200d\U0001f4bb", + ":man_technologist_tone5:": "\U0001f468\U0001f3ff\u200d\U0001f4bb", + ":man_tipping_hand:": "\U0001f481\U0000200d\U00002642\U0000fe0f", + ":man_tipping_hand_tone1:": "\U0001f481\U0001f3fb\u200d\u2642\ufe0f", + ":man_tipping_hand_tone2:": "\U0001f481\U0001f3fc\u200d\u2642\ufe0f", + ":man_tipping_hand_tone3:": "\U0001f481\U0001f3fd\u200d\u2642\ufe0f", + ":man_tipping_hand_tone4:": "\U0001f481\U0001f3fe\u200d\u2642\ufe0f", + ":man_tipping_hand_tone5:": "\U0001f481\U0001f3ff\u200d\u2642\ufe0f", + ":man_tone1:": "\U0001f468\U0001f3fb", + ":man_tone2:": "\U0001f468\U0001f3fc", + ":man_tone3:": "\U0001f468\U0001f3fd", + ":man_tone4:": "\U0001f468\U0001f3fe", + ":man_tone5:": "\U0001f468\U0001f3ff", + ":man_vampire:": "\U0001f9db\U0000200d\U00002642\U0000fe0f", + ":man_vampire_tone1:": "\U0001f9db\U0001f3fb\u200d\u2642\ufe0f", + ":man_vampire_tone2:": "\U0001f9db\U0001f3fc\u200d\u2642\ufe0f", + ":man_vampire_tone3:": "\U0001f9db\U0001f3fd\u200d\u2642\ufe0f", + ":man_vampire_tone4:": "\U0001f9db\U0001f3fe\u200d\u2642\ufe0f", + ":man_vampire_tone5:": "\U0001f9db\U0001f3ff\u200d\u2642\ufe0f", + ":man_walking:": "\U0001f6b6\U0000200d\U00002642\U0000fe0f", + ":man_walking_tone1:": "\U0001f6b6\U0001f3fb\u200d\u2642\ufe0f", + ":man_walking_tone2:": "\U0001f6b6\U0001f3fc\u200d\u2642\ufe0f", + ":man_walking_tone3:": "\U0001f6b6\U0001f3fd\u200d\u2642\ufe0f", + ":man_walking_tone4:": "\U0001f6b6\U0001f3fe\u200d\u2642\ufe0f", + ":man_walking_tone5:": "\U0001f6b6\U0001f3ff\u200d\u2642\ufe0f", + ":man_wearing_turban:": "\U0001f473\U0000200d\U00002642\U0000fe0f", + ":man_wearing_turban_tone1:": "\U0001f473\U0001f3fb\u200d\u2642\ufe0f", + ":man_wearing_turban_tone2:": "\U0001f473\U0001f3fc\u200d\u2642\ufe0f", + ":man_wearing_turban_tone3:": "\U0001f473\U0001f3fd\u200d\u2642\ufe0f", + ":man_wearing_turban_tone4:": "\U0001f473\U0001f3fe\u200d\u2642\ufe0f", + ":man_wearing_turban_tone5:": "\U0001f473\U0001f3ff\u200d\u2642\ufe0f", + ":man_white_hair:": "\U0001f468\U0000200d\U0001f9b3", + ":man_with_Chinese_cap:": "\U0001f472", + ":man_with_chinese_cap:": "\U0001f472", + ":man_with_chinese_cap_tone1:": "\U0001f472\U0001f3fb", + ":man_with_chinese_cap_tone2:": "\U0001f472\U0001f3fc", + ":man_with_chinese_cap_tone3:": "\U0001f472\U0001f3fd", + ":man_with_chinese_cap_tone4:": "\U0001f472\U0001f3fe", + ":man_with_chinese_cap_tone5:": "\U0001f472\U0001f3ff", + ":man_with_gua_pi_mao:": "\U0001f472", + ":man_with_turban:": "\U0001f473", + ":man_zombie:": "\U0001f9df\U0000200d\U00002642\U0000fe0f", + ":mandarin:": "\U0001f34a", + ":mango:": "\U0001f96d", + ":mans_shoe:": "\U0001f45e", + ":mantelpiece_clock:": "\U0001f570", + ":man’s_shoe:": "\U0001f45e", + ":map:": "\U0001f5fa", + ":map_of_Japan:": "\U0001f5fe", + ":maple_leaf:": "\U0001f341", + ":marshall_islands:": "\U0001f1f2\U0001f1ed", + ":martial_arts_uniform:": "\U0001f94b", + ":martinique:": "\U0001f1f2\U0001f1f6", + ":mask:": "\U0001f637", + ":massage:": "\U0001f486", + ":massage_man:": "\U0001f486\u200d\u2642", + ":massage_woman:": "\U0001f486", + ":mauritania:": "\U0001f1f2\U0001f1f7", + ":mauritius:": "\U0001f1f2\U0001f1fa", + ":mayotte:": "\U0001f1fe\U0001f1f9", + ":meat_on_bone:": "\U0001f356", + ":medal:": "\U0001f3c5", + ":medal_military:": "\U0001f396", + ":medal_sports:": "\U0001f3c5", + ":medical_symbol:": "\U00002695", + ":mega:": "\U0001f4e3", + ":megaphone:": "\U0001f4e3", + ":melon:": "\U0001f348", + ":memo:": "\U0001f4dd", + ":men_holding_hands:": "\U0001f46c", + ":men_with_bunny_ears:": "\U0001f46f\U0000200d\U00002642\U0000fe0f", + ":men_with_bunny_ears_partying:": "\U0001f46f\u200d\u2642\ufe0f", + ":men_wrestling:": "\U0001f93c\U0000200d\U00002642\U0000fe0f", + ":menorah:": "\U0001f54e", + ":mens:": "\U0001f6b9", + ":men’s_room:": "\U0001f6b9", + ":mermaid:": "\U0001f9dc\U0000200d\U00002640\U0000fe0f", + ":mermaid_tone1:": "\U0001f9dc\U0001f3fb\u200d\u2640\ufe0f", + ":mermaid_tone2:": "\U0001f9dc\U0001f3fc\u200d\u2640\ufe0f", + ":mermaid_tone3:": "\U0001f9dc\U0001f3fd\u200d\u2640\ufe0f", + ":mermaid_tone4:": "\U0001f9dc\U0001f3fe\u200d\u2640\ufe0f", + ":mermaid_tone5:": "\U0001f9dc\U0001f3ff\u200d\u2640\ufe0f", + ":merman:": "\U0001f9dc\U0000200d\U00002642\U0000fe0f", + ":merman_tone1:": "\U0001f9dc\U0001f3fb\u200d\u2642\ufe0f", + ":merman_tone2:": "\U0001f9dc\U0001f3fc\u200d\u2642\ufe0f", + ":merman_tone3:": "\U0001f9dc\U0001f3fd\u200d\u2642\ufe0f", + ":merman_tone4:": "\U0001f9dc\U0001f3fe\u200d\u2642\ufe0f", + ":merman_tone5:": "\U0001f9dc\U0001f3ff\u200d\u2642\ufe0f", + ":merperson:": "\U0001f9dc", + ":merperson_tone1:": "\U0001f9dc\U0001f3fb", + ":merperson_tone2:": "\U0001f9dc\U0001f3fc", + ":merperson_tone3:": "\U0001f9dc\U0001f3fd", + ":merperson_tone4:": "\U0001f9dc\U0001f3fe", + ":merperson_tone5:": "\U0001f9dc\U0001f3ff", + ":metal:": "\U0001f918", + ":metal_tone1:": "\U0001f918\U0001f3fb", + ":metal_tone2:": "\U0001f918\U0001f3fc", + ":metal_tone3:": "\U0001f918\U0001f3fd", + ":metal_tone4:": "\U0001f918\U0001f3fe", + ":metal_tone5:": "\U0001f918\U0001f3ff", + ":metro:": "\U0001f687", + ":mexico:": "\U0001f1f2\U0001f1fd", + ":microbe:": "\U0001f9a0", + ":micronesia:": "\U0001f1eb\U0001f1f2", + ":microphone:": "\U0001f3a4", + ":microphone2:": "\U0001f399", + ":microscope:": "\U0001f52c", + ":middle_finger:": "\U0001f595", + ":middle_finger_tone1:": "\U0001f595\U0001f3fb", + ":middle_finger_tone2:": "\U0001f595\U0001f3fc", + ":middle_finger_tone3:": "\U0001f595\U0001f3fd", + ":middle_finger_tone4:": "\U0001f595\U0001f3fe", + ":middle_finger_tone5:": "\U0001f595\U0001f3ff", + ":military_medal:": "\U0001f396", + ":milk:": "\U0001f95b", + ":milk_glass:": "\U0001f95b", + ":milky_way:": "\U0001f30c", + ":minibus:": "\U0001f690", + ":minidisc:": "\U0001f4bd", + ":minus_sign:": "\U00002796", + ":moai:": "\U0001f5ff", + ":mobile_phone:": "\U0001f4f1", + ":mobile_phone_off:": "\U0001f4f4", + ":mobile_phone_with_arrow:": "\U0001f4f2", + ":moldova:": "\U0001f1f2\U0001f1e9", + ":monaco:": "\U0001f1f2\U0001f1e8", + ":money-mouth_face:": "\U0001f911", + ":money_bag:": "\U0001f4b0", + ":money_mouth:": "\U0001f911", + ":money_mouth_face:": "\U0001f911", + ":money_with_wings:": "\U0001f4b8", + ":moneybag:": "\U0001f4b0", + ":mongolia:": "\U0001f1f2\U0001f1f3", + ":monkey:": "\U0001f412", + ":monkey_face:": "\U0001f435", + ":monorail:": "\U0001f69d", + ":montenegro:": "\U0001f1f2\U0001f1ea", + ":montserrat:": "\U0001f1f2\U0001f1f8", + ":moon:": "\U0001f314", + ":moon_cake:": "\U0001f96e", + ":moon_viewing_ceremony:": "\U0001f391", + ":morocco:": "\U0001f1f2\U0001f1e6", + ":mortar_board:": "\U0001f393", + ":mosque:": "\U0001f54c", + ":mosquito:": "\U0001f99f", + ":motor_boat:": "\U0001f6e5", + ":motor_scooter:": "\U0001f6f5", + ":motorboat:": "\U0001f6e5", + ":motorcycle:": "\U0001f3cd", + ":motorway:": "\U0001f6e3", + ":mount_fuji:": "\U0001f5fb", + ":mountain:": "\U000026f0", + ":mountain_bicyclist:": "\U0001f6b5", + ":mountain_biking_man:": "\U0001f6b5", + ":mountain_biking_woman:": "\U0001f6b5\u200d\u2640", + ":mountain_cableway:": "\U0001f6a0", + ":mountain_railway:": "\U0001f69e", + ":mountain_snow:": "\U0001f3d4", + ":mouse:": "\U0001f401", + ":mouse2:": "\U0001f401", + ":mouse_face:": "\U0001f42d", + ":mouse_three_button:": "\U0001f5b1", + ":mouth:": "\U0001f444", + ":movie_camera:": "\U0001f3a5", + ":moyai:": "\U0001f5ff", + ":mozambique:": "\U0001f1f2\U0001f1ff", + ":mrs_claus:": "\U0001f936", + ":mrs_claus_tone1:": "\U0001f936\U0001f3fb", + ":mrs_claus_tone2:": "\U0001f936\U0001f3fc", + ":mrs_claus_tone3:": "\U0001f936\U0001f3fd", + ":mrs_claus_tone4:": "\U0001f936\U0001f3fe", + ":mrs_claus_tone5:": "\U0001f936\U0001f3ff", + ":multiplication_sign:": "\U00002716", + ":muscle:": "\U0001f4aa", + ":muscle_tone1:": "\U0001f4aa\U0001f3fb", + ":muscle_tone2:": "\U0001f4aa\U0001f3fc", + ":muscle_tone3:": "\U0001f4aa\U0001f3fd", + ":muscle_tone4:": "\U0001f4aa\U0001f3fe", + ":muscle_tone5:": "\U0001f4aa\U0001f3ff", + ":mushroom:": "\U0001f344", + ":musical_keyboard:": "\U0001f3b9", + ":musical_note:": "\U0001f3b5", + ":musical_notes:": "\U0001f3b6", + ":musical_score:": "\U0001f3bc", + ":mute:": "\U0001f507", + ":muted_speaker:": "\U0001f507", + ":myanmar:": "\U0001f1f2\U0001f1f2", + ":nail_care:": "\U0001f485", + ":nail_care_tone1:": "\U0001f485\U0001f3fb", + ":nail_care_tone2:": "\U0001f485\U0001f3fc", + ":nail_care_tone3:": "\U0001f485\U0001f3fd", + ":nail_care_tone4:": "\U0001f485\U0001f3fe", + ":nail_care_tone5:": "\U0001f485\U0001f3ff", + ":nail_polish:": "\U0001f485", + ":name_badge:": "\U0001f4db", + ":namibia:": "\U0001f1f3\U0001f1e6", + ":national_park:": "\U0001f3de", + ":nauru:": "\U0001f1f3\U0001f1f7", + ":nauseated_face:": "\U0001f922", + ":nazar_amulet:": "\U0001f9ff", + ":necktie:": "\U0001f454", + ":negative_squared_cross_mark:": "\u274e", + ":nepal:": "\U0001f1f3\U0001f1f5", + ":nerd:": "\U0001f913", + ":nerd_face:": "\U0001f913", + ":netherlands:": "\U0001f1f3\U0001f1f1", + ":neutral_face:": "\U0001f610", + ":new:": "\U0001f195", + ":new_caledonia:": "\U0001f1f3\U0001f1e8", + ":new_moon:": "\U0001f311", + ":new_moon_face:": "\U0001f31a", + ":new_moon_with_face:": "\U0001f31a", + ":new_zealand:": "\U0001f1f3\U0001f1ff", + ":newspaper:": "\U0001f4f0", + ":newspaper2:": "\U0001f5de", + ":newspaper_roll:": "\U0001f5de", + ":next_track_button:": "\U000023ed", + ":ng:": "\U0001f196", + ":ng_man:": "\U0001f645\u200d\u2642", + ":ng_woman:": "\U0001f645", + ":nicaragua:": "\U0001f1f3\U0001f1ee", + ":niger:": "\U0001f1f3\U0001f1ea", + ":nigeria:": "\U0001f1f3\U0001f1ec", + ":night_with_stars:": "\U0001f303", + ":nine:": "9\ufe0f\u20e3", + ":nine-thirty:": "\U0001f564", + ":nine_o’clock:": "\U0001f558", + ":niue:": "\U0001f1f3\U0001f1fa", + ":no_bell:": "\U0001f515", + ":no_bicycles:": "\U0001f6b3", + ":no_entry:": "\U000026d4", + ":no_entry_sign:": "\U0001f6ab", + ":no_good:": "\U0001f645", + ":no_good_man:": "\U0001f645\u200d\u2642", + ":no_good_woman:": "\U0001f645", + ":no_littering:": "\U0001f6af", + ":no_mobile_phones:": "\U0001f4f5", + ":no_mouth:": "\U0001f636", + ":no_one_under_eighteen:": "\U0001f51e", + ":no_pedestrians:": "\U0001f6b7", + ":no_smoking:": "\U0001f6ad", + ":non-potable_water:": "\U0001f6b1", + ":norfolk_island:": "\U0001f1f3\U0001f1eb", + ":north_korea:": "\U0001f1f0\U0001f1f5", + ":northern_mariana_islands:": "\U0001f1f2\U0001f1f5", + ":norway:": "\U0001f1f3\U0001f1f4", + ":nose:": "\U0001f443", + ":nose_tone1:": "\U0001f443\U0001f3fb", + ":nose_tone2:": "\U0001f443\U0001f3fc", + ":nose_tone3:": "\U0001f443\U0001f3fd", + ":nose_tone4:": "\U0001f443\U0001f3fe", + ":nose_tone5:": "\U0001f443\U0001f3ff", + ":notebook:": "\U0001f4d3", + ":notebook_with_decorative_cover:": "\U0001f4d4", + ":notepad_spiral:": "\U0001f5d2", + ":notes:": "\U0001f3b6", + ":nut_and_bolt:": "\U0001f529", + ":o:": "\u2b55", + ":o2:": "\U0001f17e", + ":ocean:": "\U0001f30a", + ":octagonal_sign:": "\U0001f6d1", + ":octopus:": "\U0001f419", + ":oden:": "\U0001f362", + ":office:": "\U0001f3e2", + ":office_building:": "\U0001f3e2", + ":ogre:": "\U0001f479", + ":oil:": "\U0001f6e2", + ":oil_drum:": "\U0001f6e2", + ":ok:": "\U0001f197", + ":ok_hand:": "\U0001f44c", + ":ok_hand_tone1:": "\U0001f44c\U0001f3fb", + ":ok_hand_tone2:": "\U0001f44c\U0001f3fc", + ":ok_hand_tone3:": "\U0001f44c\U0001f3fd", + ":ok_hand_tone4:": "\U0001f44c\U0001f3fe", + ":ok_hand_tone5:": "\U0001f44c\U0001f3ff", + ":ok_man:": "\U0001f646\u200d\u2642", + ":ok_woman:": "\U0001f646", + ":old_key:": "\U0001f5dd", + ":old_man:": "\U0001f474", + ":old_woman:": "\U0001f475", + ":older_adult:": "\U0001f9d3", + ":older_adult_tone1:": "\U0001f9d3\U0001f3fb", + ":older_adult_tone2:": "\U0001f9d3\U0001f3fc", + ":older_adult_tone3:": "\U0001f9d3\U0001f3fd", + ":older_adult_tone4:": "\U0001f9d3\U0001f3fe", + ":older_adult_tone5:": "\U0001f9d3\U0001f3ff", + ":older_man:": "\U0001f474", + ":older_man_tone1:": "\U0001f474\U0001f3fb", + ":older_man_tone2:": "\U0001f474\U0001f3fc", + ":older_man_tone3:": "\U0001f474\U0001f3fd", + ":older_man_tone4:": "\U0001f474\U0001f3fe", + ":older_man_tone5:": "\U0001f474\U0001f3ff", + ":older_person:": "\U0001f9d3", + ":older_woman:": "\U0001f475", + ":older_woman_tone1:": "\U0001f475\U0001f3fb", + ":older_woman_tone2:": "\U0001f475\U0001f3fc", + ":older_woman_tone3:": "\U0001f475\U0001f3fd", + ":older_woman_tone4:": "\U0001f475\U0001f3fe", + ":older_woman_tone5:": "\U0001f475\U0001f3ff", + ":om:": "\U0001f549", + ":om_symbol:": "\U0001f549", + ":oman:": "\U0001f1f4\U0001f1f2", + ":on:": "\U0001f51b", + ":oncoming_automobile:": "\U0001f698", + ":oncoming_bus:": "\U0001f68d", + ":oncoming_fist:": "\U0001f44a", + ":oncoming_police_car:": "\U0001f694", + ":oncoming_taxi:": "\U0001f696", + ":one:": "1\ufe0f\u20e3", + ":one-thirty:": "\U0001f55c", + ":one_o’clock:": "\U0001f550", + ":open_book:": "\U0001f4d6", + ":open_file_folder:": "\U0001f4c2", + ":open_hands:": "\U0001f450", + ":open_hands_tone1:": "\U0001f450\U0001f3fb", + ":open_hands_tone2:": "\U0001f450\U0001f3fc", + ":open_hands_tone3:": "\U0001f450\U0001f3fd", + ":open_hands_tone4:": "\U0001f450\U0001f3fe", + ":open_hands_tone5:": "\U0001f450\U0001f3ff", + ":open_mailbox_with_lowered_flag:": "\U0001f4ed", + ":open_mailbox_with_raised_flag:": "\U0001f4ec", + ":open_mouth:": "\U0001f62e", + ":open_umbrella:": "\u2602\ufe0f", + ":ophiuchus:": "\u26ce", + ":optical_disk:": "\U0001f4bf", + ":orange:": "\U0001f34a", + ":orange_book:": "\U0001f4d9", + ":orange_heart:": "\U0001f9e1", + ":orthodox_cross:": "\U00002626", + ":outbox_tray:": "\U0001f4e4", + ":owl:": "\U0001f989", + ":ox:": "\U0001f402", + ":package:": "\U0001f4e6", + ":page_facing_up:": "\U0001f4c4", + ":page_with_curl:": "\U0001f4c3", + ":pager:": "\U0001f4df", + ":paintbrush:": "\U0001f58c", + ":pakistan:": "\U0001f1f5\U0001f1f0", + ":palau:": "\U0001f1f5\U0001f1fc", + ":palestinian_territories:": "\U0001f1f5\U0001f1f8", + ":palm_tree:": "\U0001f334", + ":palms_up_together:": "\U0001f932", + ":palms_up_together_tone1:": "\U0001f932\U0001f3fb", + ":palms_up_together_tone2:": "\U0001f932\U0001f3fc", + ":palms_up_together_tone3:": "\U0001f932\U0001f3fd", + ":palms_up_together_tone4:": "\U0001f932\U0001f3fe", + ":palms_up_together_tone5:": "\U0001f932\U0001f3ff", + ":panama:": "\U0001f1f5\U0001f1e6", + ":pancakes:": "\U0001f95e", + ":panda:": "\U0001f43c", + ":panda_face:": "\U0001f43c", + ":paperclip:": "\U0001f4ce", + ":paperclips:": "\U0001f587", + ":papua_new_guinea:": "\U0001f1f5\U0001f1ec", + ":paraguay:": "\U0001f1f5\U0001f1fe", + ":parasol_on_ground:": "\u26f1", + ":park:": "\U0001f3de", + ":parking:": "\U0001f17f", + ":parrot:": "\U0001f99c", + ":part_alternation_mark:": "\U0000303d", + ":partly_sunny:": "\u26c5", + ":party_popper:": "\U0001f389", + ":partying_face:": "\U0001f973", + ":passenger_ship:": "\U0001f6f3", + ":passport_control:": "\U0001f6c2", + ":pause_button:": "\U000023f8", + ":paw_prints:": "\U0001f43e", + ":peace:": "\u262e", + ":peace_symbol:": "\U0000262e", + ":peach:": "\U0001f351", + ":peacock:": "\U0001f99a", + ":peanuts:": "\U0001f95c", + ":pear:": "\U0001f350", + ":pen:": "\U0001f58a", + ":pen_ballpoint:": "\U0001f58a", + ":pen_fountain:": "\U0001f58b", + ":pencil:": "\U0000270f", + ":pencil2:": "\u270f", + ":penguin:": "\U0001f427", + ":pensive:": "\U0001f614", + ":pensive_face:": "\U0001f614", + ":people_with_bunny_ears:": "\U0001f46f", + ":people_with_bunny_ears_partying:": "\U0001f46f", + ":people_wrestling:": "\U0001f93c", + ":performing_arts:": "\U0001f3ad", + ":persevere:": "\U0001f623", + ":persevering_face:": "\U0001f623", + ":person:": "\U0001f9d1", + ":person_biking:": "\U0001f6b4", + ":person_biking_tone1:": "\U0001f6b4\U0001f3fb", + ":person_biking_tone2:": "\U0001f6b4\U0001f3fc", + ":person_biking_tone3:": "\U0001f6b4\U0001f3fd", + ":person_biking_tone4:": "\U0001f6b4\U0001f3fe", + ":person_biking_tone5:": "\U0001f6b4\U0001f3ff", + ":person_blond_hair:": "\U0001f471", + ":person_bouncing_ball:": "\U000026f9", + ":person_bouncing_ball_tone1:": "\u26f9\U0001f3fb", + ":person_bouncing_ball_tone2:": "\u26f9\U0001f3fc", + ":person_bouncing_ball_tone3:": "\u26f9\U0001f3fd", + ":person_bouncing_ball_tone4:": "\u26f9\U0001f3fe", + ":person_bouncing_ball_tone5:": "\u26f9\U0001f3ff", + ":person_bowing:": "\U0001f647", + ":person_bowing_tone1:": "\U0001f647\U0001f3fb", + ":person_bowing_tone2:": "\U0001f647\U0001f3fc", + ":person_bowing_tone3:": "\U0001f647\U0001f3fd", + ":person_bowing_tone4:": "\U0001f647\U0001f3fe", + ":person_bowing_tone5:": "\U0001f647\U0001f3ff", + ":person_cartwheeling:": "\U0001f938", + ":person_climbing:": "\U0001f9d7", + ":person_climbing_tone1:": "\U0001f9d7\U0001f3fb", + ":person_climbing_tone2:": "\U0001f9d7\U0001f3fc", + ":person_climbing_tone3:": "\U0001f9d7\U0001f3fd", + ":person_climbing_tone4:": "\U0001f9d7\U0001f3fe", + ":person_climbing_tone5:": "\U0001f9d7\U0001f3ff", + ":person_doing_cartwheel:": "\U0001f938", + ":person_doing_cartwheel_tone1:": "\U0001f938\U0001f3fb", + ":person_doing_cartwheel_tone2:": "\U0001f938\U0001f3fc", + ":person_doing_cartwheel_tone3:": "\U0001f938\U0001f3fd", + ":person_doing_cartwheel_tone4:": "\U0001f938\U0001f3fe", + ":person_doing_cartwheel_tone5:": "\U0001f938\U0001f3ff", + ":person_facepalming:": "\U0001f926", + ":person_facepalming_tone1:": "\U0001f926\U0001f3fb", + ":person_facepalming_tone2:": "\U0001f926\U0001f3fc", + ":person_facepalming_tone3:": "\U0001f926\U0001f3fd", + ":person_facepalming_tone4:": "\U0001f926\U0001f3fe", + ":person_facepalming_tone5:": "\U0001f926\U0001f3ff", + ":person_fencing:": "\U0001f93a", + ":person_frowning:": "\U0001f64d", + ":person_frowning_tone1:": "\U0001f64d\U0001f3fb", + ":person_frowning_tone2:": "\U0001f64d\U0001f3fc", + ":person_frowning_tone3:": "\U0001f64d\U0001f3fd", + ":person_frowning_tone4:": "\U0001f64d\U0001f3fe", + ":person_frowning_tone5:": "\U0001f64d\U0001f3ff", + ":person_gesturing_NO:": "\U0001f645", + ":person_gesturing_OK:": "\U0001f646", + ":person_gesturing_no:": "\U0001f645", + ":person_gesturing_no_tone1:": "\U0001f645\U0001f3fb", + ":person_gesturing_no_tone2:": "\U0001f645\U0001f3fc", + ":person_gesturing_no_tone3:": "\U0001f645\U0001f3fd", + ":person_gesturing_no_tone4:": "\U0001f645\U0001f3fe", + ":person_gesturing_no_tone5:": "\U0001f645\U0001f3ff", + ":person_gesturing_ok:": "\U0001f646", + ":person_gesturing_ok_tone1:": "\U0001f646\U0001f3fb", + ":person_gesturing_ok_tone2:": "\U0001f646\U0001f3fc", + ":person_gesturing_ok_tone3:": "\U0001f646\U0001f3fd", + ":person_gesturing_ok_tone4:": "\U0001f646\U0001f3fe", + ":person_gesturing_ok_tone5:": "\U0001f646\U0001f3ff", + ":person_getting_haircut:": "\U0001f487", + ":person_getting_haircut_tone1:": "\U0001f487\U0001f3fb", + ":person_getting_haircut_tone2:": "\U0001f487\U0001f3fc", + ":person_getting_haircut_tone3:": "\U0001f487\U0001f3fd", + ":person_getting_haircut_tone4:": "\U0001f487\U0001f3fe", + ":person_getting_haircut_tone5:": "\U0001f487\U0001f3ff", + ":person_getting_massage:": "\U0001f486", + ":person_getting_massage_tone1:": "\U0001f486\U0001f3fb", + ":person_getting_massage_tone2:": "\U0001f486\U0001f3fc", + ":person_getting_massage_tone3:": "\U0001f486\U0001f3fd", + ":person_getting_massage_tone4:": "\U0001f486\U0001f3fe", + ":person_getting_massage_tone5:": "\U0001f486\U0001f3ff", + ":person_golfing:": "\U0001f3cc", + ":person_golfing_tone1:": "\U0001f3cc\U0001f3fb", + ":person_golfing_tone2:": "\U0001f3cc\U0001f3fc", + ":person_golfing_tone3:": "\U0001f3cc\U0001f3fd", + ":person_golfing_tone4:": "\U0001f3cc\U0001f3fe", + ":person_golfing_tone5:": "\U0001f3cc\U0001f3ff", + ":person_in_bed:": "\U0001f6cc", + ":person_in_bed_tone1:": "\U0001f6cc\U0001f3fb", + ":person_in_bed_tone2:": "\U0001f6cc\U0001f3fc", + ":person_in_bed_tone3:": "\U0001f6cc\U0001f3fd", + ":person_in_bed_tone4:": "\U0001f6cc\U0001f3fe", + ":person_in_bed_tone5:": "\U0001f6cc\U0001f3ff", + ":person_in_lotus_position:": "\U0001f9d8", + ":person_in_lotus_position_tone1:": "\U0001f9d8\U0001f3fb", + ":person_in_lotus_position_tone2:": "\U0001f9d8\U0001f3fc", + ":person_in_lotus_position_tone3:": "\U0001f9d8\U0001f3fd", + ":person_in_lotus_position_tone4:": "\U0001f9d8\U0001f3fe", + ":person_in_lotus_position_tone5:": "\U0001f9d8\U0001f3ff", + ":person_in_steamy_room:": "\U0001f9d6", + ":person_in_steamy_room_tone1:": "\U0001f9d6\U0001f3fb", + ":person_in_steamy_room_tone2:": "\U0001f9d6\U0001f3fc", + ":person_in_steamy_room_tone3:": "\U0001f9d6\U0001f3fd", + ":person_in_steamy_room_tone4:": "\U0001f9d6\U0001f3fe", + ":person_in_steamy_room_tone5:": "\U0001f9d6\U0001f3ff", + ":person_juggling:": "\U0001f939", + ":person_juggling_tone1:": "\U0001f939\U0001f3fb", + ":person_juggling_tone2:": "\U0001f939\U0001f3fc", + ":person_juggling_tone3:": "\U0001f939\U0001f3fd", + ":person_juggling_tone4:": "\U0001f939\U0001f3fe", + ":person_juggling_tone5:": "\U0001f939\U0001f3ff", + ":person_lifting_weights:": "\U0001f3cb", + ":person_lifting_weights_tone1:": "\U0001f3cb\U0001f3fb", + ":person_lifting_weights_tone2:": "\U0001f3cb\U0001f3fc", + ":person_lifting_weights_tone3:": "\U0001f3cb\U0001f3fd", + ":person_lifting_weights_tone4:": "\U0001f3cb\U0001f3fe", + ":person_lifting_weights_tone5:": "\U0001f3cb\U0001f3ff", + ":person_mountain_biking:": "\U0001f6b5", + ":person_mountain_biking_tone1:": "\U0001f6b5\U0001f3fb", + ":person_mountain_biking_tone2:": "\U0001f6b5\U0001f3fc", + ":person_mountain_biking_tone3:": "\U0001f6b5\U0001f3fd", + ":person_mountain_biking_tone4:": "\U0001f6b5\U0001f3fe", + ":person_mountain_biking_tone5:": "\U0001f6b5\U0001f3ff", + ":person_playing_handball:": "\U0001f93e", + ":person_playing_handball_tone1:": "\U0001f93e\U0001f3fb", + ":person_playing_handball_tone2:": "\U0001f93e\U0001f3fc", + ":person_playing_handball_tone3:": "\U0001f93e\U0001f3fd", + ":person_playing_handball_tone4:": "\U0001f93e\U0001f3fe", + ":person_playing_handball_tone5:": "\U0001f93e\U0001f3ff", + ":person_playing_water_polo:": "\U0001f93d", + ":person_playing_water_polo_tone1:": "\U0001f93d\U0001f3fb", + ":person_playing_water_polo_tone2:": "\U0001f93d\U0001f3fc", + ":person_playing_water_polo_tone3:": "\U0001f93d\U0001f3fd", + ":person_playing_water_polo_tone4:": "\U0001f93d\U0001f3fe", + ":person_playing_water_polo_tone5:": "\U0001f93d\U0001f3ff", + ":person_pouting:": "\U0001f64e", + ":person_pouting_tone1:": "\U0001f64e\U0001f3fb", + ":person_pouting_tone2:": "\U0001f64e\U0001f3fc", + ":person_pouting_tone3:": "\U0001f64e\U0001f3fd", + ":person_pouting_tone4:": "\U0001f64e\U0001f3fe", + ":person_pouting_tone5:": "\U0001f64e\U0001f3ff", + ":person_raising_hand:": "\U0001f64b", + ":person_raising_hand_tone1:": "\U0001f64b\U0001f3fb", + ":person_raising_hand_tone2:": "\U0001f64b\U0001f3fc", + ":person_raising_hand_tone3:": "\U0001f64b\U0001f3fd", + ":person_raising_hand_tone4:": "\U0001f64b\U0001f3fe", + ":person_raising_hand_tone5:": "\U0001f64b\U0001f3ff", + ":person_rowing_boat:": "\U0001f6a3", + ":person_rowing_boat_tone1:": "\U0001f6a3\U0001f3fb", + ":person_rowing_boat_tone2:": "\U0001f6a3\U0001f3fc", + ":person_rowing_boat_tone3:": "\U0001f6a3\U0001f3fd", + ":person_rowing_boat_tone4:": "\U0001f6a3\U0001f3fe", + ":person_rowing_boat_tone5:": "\U0001f6a3\U0001f3ff", + ":person_running:": "\U0001f3c3", + ":person_running_tone1:": "\U0001f3c3\U0001f3fb", + ":person_running_tone2:": "\U0001f3c3\U0001f3fc", + ":person_running_tone3:": "\U0001f3c3\U0001f3fd", + ":person_running_tone4:": "\U0001f3c3\U0001f3fe", + ":person_running_tone5:": "\U0001f3c3\U0001f3ff", + ":person_shrugging:": "\U0001f937", + ":person_shrugging_tone1:": "\U0001f937\U0001f3fb", + ":person_shrugging_tone2:": "\U0001f937\U0001f3fc", + ":person_shrugging_tone3:": "\U0001f937\U0001f3fd", + ":person_shrugging_tone4:": "\U0001f937\U0001f3fe", + ":person_shrugging_tone5:": "\U0001f937\U0001f3ff", + ":person_surfing:": "\U0001f3c4", + ":person_surfing_tone1:": "\U0001f3c4\U0001f3fb", + ":person_surfing_tone2:": "\U0001f3c4\U0001f3fc", + ":person_surfing_tone3:": "\U0001f3c4\U0001f3fd", + ":person_surfing_tone4:": "\U0001f3c4\U0001f3fe", + ":person_surfing_tone5:": "\U0001f3c4\U0001f3ff", + ":person_swimming:": "\U0001f3ca", + ":person_swimming_tone1:": "\U0001f3ca\U0001f3fb", + ":person_swimming_tone2:": "\U0001f3ca\U0001f3fc", + ":person_swimming_tone3:": "\U0001f3ca\U0001f3fd", + ":person_swimming_tone4:": "\U0001f3ca\U0001f3fe", + ":person_swimming_tone5:": "\U0001f3ca\U0001f3ff", + ":person_taking_bath:": "\U0001f6c0", + ":person_tipping_hand:": "\U0001f481", + ":person_tipping_hand_tone1:": "\U0001f481\U0001f3fb", + ":person_tipping_hand_tone2:": "\U0001f481\U0001f3fc", + ":person_tipping_hand_tone3:": "\U0001f481\U0001f3fd", + ":person_tipping_hand_tone4:": "\U0001f481\U0001f3fe", + ":person_tipping_hand_tone5:": "\U0001f481\U0001f3ff", + ":person_walking:": "\U0001f6b6", + ":person_walking_tone1:": "\U0001f6b6\U0001f3fb", + ":person_walking_tone2:": "\U0001f6b6\U0001f3fc", + ":person_walking_tone3:": "\U0001f6b6\U0001f3fd", + ":person_walking_tone4:": "\U0001f6b6\U0001f3fe", + ":person_walking_tone5:": "\U0001f6b6\U0001f3ff", + ":person_wearing_turban:": "\U0001f473", + ":person_wearing_turban_tone1:": "\U0001f473\U0001f3fb", + ":person_wearing_turban_tone2:": "\U0001f473\U0001f3fc", + ":person_wearing_turban_tone3:": "\U0001f473\U0001f3fd", + ":person_wearing_turban_tone4:": "\U0001f473\U0001f3fe", + ":person_wearing_turban_tone5:": "\U0001f473\U0001f3ff", + ":person_with_blond_hair:": "\U0001f471", + ":person_with_pouting_face:": "\U0001f64e", + ":peru:": "\U0001f1f5\U0001f1ea", + ":petri_dish:": "\U0001f9eb", + ":philippines:": "\U0001f1f5\U0001f1ed", + ":phone:": "\u260e\ufe0f", + ":pick:": "\U000026cf", + ":pie:": "\U0001f967", + ":pig:": "\U0001f416", + ":pig2:": "\U0001f416", + ":pig_face:": "\U0001f437", + ":pig_nose:": "\U0001f43d", + ":pile_of_poo:": "\U0001f4a9", + ":pill:": "\U0001f48a", + ":pine_decoration:": "\U0001f38d", + ":pineapple:": "\U0001f34d", + ":ping_pong:": "\U0001f3d3", + ":pirate_flag:": "\U0001f3f4\U0000200d\U00002620\U0000fe0f", + ":pisces:": "\u2653", + ":pistol:": "\U0001f52b", + ":pitcairn_islands:": "\U0001f1f5\U0001f1f3", + ":pizza:": "\U0001f355", + ":place_of_worship:": "\U0001f6d0", + ":plate_with_cutlery:": "\U0001f37d", + ":play_button:": "\U000025b6", + ":play_or_pause_button:": "\U000023ef", + ":play_pause:": "\u23ef", + ":pleading_face:": "\U0001f97a", + ":plus_sign:": "\U00002795", + ":point_down:": "\U0001f447", + ":point_down_tone1:": "\U0001f447\U0001f3fb", + ":point_down_tone2:": "\U0001f447\U0001f3fc", + ":point_down_tone3:": "\U0001f447\U0001f3fd", + ":point_down_tone4:": "\U0001f447\U0001f3fe", + ":point_down_tone5:": "\U0001f447\U0001f3ff", + ":point_left:": "\U0001f448", + ":point_left_tone1:": "\U0001f448\U0001f3fb", + ":point_left_tone2:": "\U0001f448\U0001f3fc", + ":point_left_tone3:": "\U0001f448\U0001f3fd", + ":point_left_tone4:": "\U0001f448\U0001f3fe", + ":point_left_tone5:": "\U0001f448\U0001f3ff", + ":point_right:": "\U0001f449", + ":point_right_tone1:": "\U0001f449\U0001f3fb", + ":point_right_tone2:": "\U0001f449\U0001f3fc", + ":point_right_tone3:": "\U0001f449\U0001f3fd", + ":point_right_tone4:": "\U0001f449\U0001f3fe", + ":point_right_tone5:": "\U0001f449\U0001f3ff", + ":point_up:": "\u261d", + ":point_up_2:": "\U0001f446", + ":point_up_2_tone1:": "\U0001f446\U0001f3fb", + ":point_up_2_tone2:": "\U0001f446\U0001f3fc", + ":point_up_2_tone3:": "\U0001f446\U0001f3fd", + ":point_up_2_tone4:": "\U0001f446\U0001f3fe", + ":point_up_2_tone5:": "\U0001f446\U0001f3ff", + ":point_up_tone1:": "\u261d\U0001f3fb", + ":point_up_tone2:": "\u261d\U0001f3fc", + ":point_up_tone3:": "\u261d\U0001f3fd", + ":point_up_tone4:": "\u261d\U0001f3fe", + ":point_up_tone5:": "\u261d\U0001f3ff", + ":poland:": "\U0001f1f5\U0001f1f1", + ":police_car:": "\U0001f693", + ":police_car_light:": "\U0001f6a8", + ":police_officer:": "\U0001f46e", + ":police_officer_tone1:": "\U0001f46e\U0001f3fb", + ":police_officer_tone2:": "\U0001f46e\U0001f3fc", + ":police_officer_tone3:": "\U0001f46e\U0001f3fd", + ":police_officer_tone4:": "\U0001f46e\U0001f3fe", + ":police_officer_tone5:": "\U0001f46e\U0001f3ff", + ":policeman:": "\U0001f46e", + ":policewoman:": "\U0001f46e\u200d\u2640", + ":poodle:": "\U0001f429", + ":pool_8_ball:": "\U0001f3b1", + ":poop:": "\U0001f4a9", + ":popcorn:": "\U0001f37f", + ":portugal:": "\U0001f1f5\U0001f1f9", + ":post_office:": "\U0001f3e4", + ":postal_horn:": "\U0001f4ef", + ":postbox:": "\U0001f4ee", + ":pot_of_food:": "\U0001f372", + ":potable_water:": "\U0001f6b0", + ":potato:": "\U0001f954", + ":pouch:": "\U0001f45d", + ":poultry_leg:": "\U0001f357", + ":pound:": "\U0001f4b7", + ":pound_banknote:": "\U0001f4b7", + ":pout:": "\U0001f621", + ":pouting_cat:": "\U0001f63e", + ":pouting_face:": "\U0001f621", + ":pouting_man:": "\U0001f64e\u200d\u2642", + ":pouting_woman:": "\U0001f64e", + ":pray:": "\U0001f64f", + ":pray_tone1:": "\U0001f64f\U0001f3fb", + ":pray_tone2:": "\U0001f64f\U0001f3fc", + ":pray_tone3:": "\U0001f64f\U0001f3fd", + ":pray_tone4:": "\U0001f64f\U0001f3fe", + ":pray_tone5:": "\U0001f64f\U0001f3ff", + ":prayer_beads:": "\U0001f4ff", + ":pregnant_woman:": "\U0001f930", + ":pregnant_woman_tone1:": "\U0001f930\U0001f3fb", + ":pregnant_woman_tone2:": "\U0001f930\U0001f3fc", + ":pregnant_woman_tone3:": "\U0001f930\U0001f3fd", + ":pregnant_woman_tone4:": "\U0001f930\U0001f3fe", + ":pregnant_woman_tone5:": "\U0001f930\U0001f3ff", + ":pretzel:": "\U0001f968", + ":previous_track_button:": "\u23ee", + ":prince:": "\U0001f934", + ":prince_tone1:": "\U0001f934\U0001f3fb", + ":prince_tone2:": "\U0001f934\U0001f3fc", + ":prince_tone3:": "\U0001f934\U0001f3fd", + ":prince_tone4:": "\U0001f934\U0001f3fe", + ":prince_tone5:": "\U0001f934\U0001f3ff", + ":princess:": "\U0001f478", + ":princess_tone1:": "\U0001f478\U0001f3fb", + ":princess_tone2:": "\U0001f478\U0001f3fc", + ":princess_tone3:": "\U0001f478\U0001f3fd", + ":princess_tone4:": "\U0001f478\U0001f3fe", + ":princess_tone5:": "\U0001f478\U0001f3ff", + ":printer:": "\U0001f5a8", + ":prohibited:": "\U0001f6ab", + ":projector:": "\U0001f4fd", + ":puerto_rico:": "\U0001f1f5\U0001f1f7", + ":punch:": "\U0001f44a", + ":punch_tone1:": "\U0001f44a\U0001f3fb", + ":punch_tone2:": "\U0001f44a\U0001f3fc", + ":punch_tone3:": "\U0001f44a\U0001f3fd", + ":punch_tone4:": "\U0001f44a\U0001f3fe", + ":punch_tone5:": "\U0001f44a\U0001f3ff", + ":purple_heart:": "\U0001f49c", + ":purse:": "\U0001f45b", + ":pushpin:": "\U0001f4cc", + ":put_litter_in_its_place:": "\U0001f6ae", + ":puzzle_piece:": "\U0001f9e9", + ":qatar:": "\U0001f1f6\U0001f1e6", + ":question:": "\u2753", + ":question_mark:": "\U00002753", + ":rabbit:": "\U0001f407", + ":rabbit2:": "\U0001f407", + ":rabbit_face:": "\U0001f430", + ":raccoon:": "\U0001f99d", + ":race_car:": "\U0001f3ce", + ":racehorse:": "\U0001f40e", + ":racing_car:": "\U0001f3ce", + ":radio:": "\U0001f4fb", + ":radio_button:": "\U0001f518", + ":radioactive:": "\U00002622", + ":rage:": "\U0001f621", + ":railway_car:": "\U0001f683", + ":railway_track:": "\U0001f6e4", + ":rainbow:": "\U0001f308", + ":rainbow_flag:": "\U0001f3f3\U0000fe0f\U0000200d\U0001f308", + ":raised_back_of_hand:": "\U0001f91a", + ":raised_back_of_hand_tone1:": "\U0001f91a\U0001f3fb", + ":raised_back_of_hand_tone2:": "\U0001f91a\U0001f3fc", + ":raised_back_of_hand_tone3:": "\U0001f91a\U0001f3fd", + ":raised_back_of_hand_tone4:": "\U0001f91a\U0001f3fe", + ":raised_back_of_hand_tone5:": "\U0001f91a\U0001f3ff", + ":raised_fist:": "\U0000270a", + ":raised_hand:": "\U0000270b", + ":raised_hand_tone1:": "\u270b\U0001f3fb", + ":raised_hand_tone2:": "\u270b\U0001f3fc", + ":raised_hand_tone3:": "\u270b\U0001f3fd", + ":raised_hand_tone4:": "\u270b\U0001f3fe", + ":raised_hand_tone5:": "\u270b\U0001f3ff", + ":raised_hand_with_fingers_splayed:": "\U0001f590", + ":raised_hands:": "\U0001f64c", + ":raised_hands_tone1:": "\U0001f64c\U0001f3fb", + ":raised_hands_tone2:": "\U0001f64c\U0001f3fc", + ":raised_hands_tone3:": "\U0001f64c\U0001f3fd", + ":raised_hands_tone4:": "\U0001f64c\U0001f3fe", + ":raised_hands_tone5:": "\U0001f64c\U0001f3ff", + ":raising_hand:": "\U0001f64b", + ":raising_hand_man:": "\U0001f64b\u200d\u2642", + ":raising_hand_woman:": "\U0001f64b", + ":raising_hands:": "\U0001f64c", + ":ram:": "\U0001f40f", + ":ramen:": "\U0001f35c", + ":rat:": "\U0001f400", + ":receipt:": "\U0001f9fe", + ":record_button:": "\U000023fa", + ":recycle:": "\u267b", + ":recycling_symbol:": "\U0000267b", + ":red_apple:": "\U0001f34e", + ":red_car:": "\U0001f697", + ":red_circle:": "\U0001f534", + ":red_envelope:": "\U0001f9e7", + ":red_hair:": "\U0001f9b0", + ":red_heart:": "\U00002764", + ":red_paper_lantern:": "\U0001f3ee", + ":red_triangle_pointed_down:": "\U0001f53b", + ":red_triangle_pointed_up:": "\U0001f53a", + ":registered:": "\U000000ae", + ":relaxed:": "\u263a", + ":relieved:": "\U0001f60c", + ":relieved_face:": "\U0001f60c", + ":reminder_ribbon:": "\U0001f397", + ":repeat:": "\U0001f501", + ":repeat_button:": "\U0001f501", + ":repeat_one:": "\U0001f502", + ":repeat_single_button:": "\U0001f502", + ":rescue_worker_helmet:": "\u26d1", + ":rescue_worker’s_helmet:": "\U000026d1", + ":restroom:": "\U0001f6bb", + ":reunion:": "\U0001f1f7\U0001f1ea", + ":reverse_button:": "\U000025c0", + ":revolving_hearts:": "\U0001f49e", + ":rewind:": "\u23ea", + ":rhino:": "\U0001f98f", + ":rhinoceros:": "\U0001f98f", + ":ribbon:": "\U0001f380", + ":rice:": "\U0001f35a", + ":rice_ball:": "\U0001f359", + ":rice_cracker:": "\U0001f358", + ":rice_scene:": "\U0001f391", + ":right-facing_fist:": "\U0001f91c", + ":right_anger_bubble:": "\U0001f5ef", + ":right_arrow:": "\U000027a1", + ":right_arrow_curving_down:": "\U00002935", + ":right_arrow_curving_left:": "\U000021a9", + ":right_arrow_curving_up:": "\U00002934", + ":right_facing_fist:": "\U0001f91c", + ":right_facing_fist_tone1:": "\U0001f91c\U0001f3fb", + ":right_facing_fist_tone2:": "\U0001f91c\U0001f3fc", + ":right_facing_fist_tone3:": "\U0001f91c\U0001f3fd", + ":right_facing_fist_tone4:": "\U0001f91c\U0001f3fe", + ":right_facing_fist_tone5:": "\U0001f91c\U0001f3ff", + ":ring:": "\U0001f48d", + ":roasted_sweet_potato:": "\U0001f360", + ":robot:": "\U0001f916", + ":rocket:": "\U0001f680", + ":rofl:": "\U0001f923", + ":roll_eyes:": "\U0001f644", + ":roll_of_paper:": "\U0001f9fb", + ":rolled-up_newspaper:": "\U0001f5de", + ":roller_coaster:": "\U0001f3a2", + ":rolling_eyes:": "\U0001f644", + ":rolling_on_the_floor_laughing:": "\U0001f923", + ":romania:": "\U0001f1f7\U0001f1f4", + ":rooster:": "\U0001f413", + ":rose:": "\U0001f339", + ":rosette:": "\U0001f3f5", + ":rotating_light:": "\U0001f6a8", + ":round_pushpin:": "\U0001f4cd", + ":rowboat:": "\U0001f6a3", + ":rowing_man:": "\U0001f6a3", + ":rowing_woman:": "\U0001f6a3\u200d\u2640", + ":ru:": "\U0001f1f7\U0001f1fa", + ":rugby_football:": "\U0001f3c9", + ":runner:": "\U0001f3c3", + ":running:": "\U0001f3c3", + ":running_man:": "\U0001f3c3", + ":running_shirt:": "\U0001f3bd", + ":running_shirt_with_sash:": "\U0001f3bd", + ":running_shoe:": "\U0001f45f", + ":running_woman:": "\U0001f3c3\u200d\u2640", + ":rwanda:": "\U0001f1f7\U0001f1fc", + ":sa:": "\U0001f202", + ":sad_but_relieved_face:": "\U0001f625", + ":safety_pin:": "\U0001f9f7", + ":sagittarius:": "\u2650", + ":sailboat:": "\U000026f5", + ":sake:": "\U0001f376", + ":salad:": "\U0001f957", + ":salt:": "\U0001f9c2", + ":samoa:": "\U0001f1fc\U0001f1f8", + ":san_marino:": "\U0001f1f8\U0001f1f2", + ":sandal:": "\U0001f461", + ":sandwich:": "\U0001f96a", + ":santa:": "\U0001f385", + ":santa_tone1:": "\U0001f385\U0001f3fb", + ":santa_tone2:": "\U0001f385\U0001f3fc", + ":santa_tone3:": "\U0001f385\U0001f3fd", + ":santa_tone4:": "\U0001f385\U0001f3fe", + ":santa_tone5:": "\U0001f385\U0001f3ff", + ":sao_tome_principe:": "\U0001f1f8\U0001f1f9", + ":sassy_man:": "\U0001f481\u200d\u2642", + ":sassy_woman:": "\U0001f481", + ":satellite:": "\U0001f6f0", + ":satellite_antenna:": "\U0001f4e1", + ":satellite_orbital:": "\U0001f6f0", + ":satisfied:": "\U0001f606", + ":saudi_arabia:": "\U0001f1f8\U0001f1e6", + ":sauropod:": "\U0001f995", + ":saxophone:": "\U0001f3b7", + ":scales:": "\u2696", + ":scarf:": "\U0001f9e3", + ":school:": "\U0001f3eb", + ":school_satchel:": "\U0001f392", + ":scissors:": "\U00002702", + ":scooter:": "\U0001f6f4", + ":scorpion:": "\U0001f982", + ":scorpius:": "\u264f", + ":scotland:": "\U0001f3f4\U000e0067\U000e0062\U000e0073\U000e0063\U000e0074\U000e007f", + ":scream:": "\U0001f631", + ":scream_cat:": "\U0001f640", + ":scroll:": "\U0001f4dc", + ":seat:": "\U0001f4ba", + ":second_place:": "\U0001f948", + ":secret:": "\u3299", + ":see-no-evil_monkey:": "\U0001f648", + ":see_no_evil:": "\U0001f648", + ":seedling:": "\U0001f331", + ":selfie:": "\U0001f933", + ":selfie_tone1:": "\U0001f933\U0001f3fb", + ":selfie_tone2:": "\U0001f933\U0001f3fc", + ":selfie_tone3:": "\U0001f933\U0001f3fd", + ":selfie_tone4:": "\U0001f933\U0001f3fe", + ":selfie_tone5:": "\U0001f933\U0001f3ff", + ":senegal:": "\U0001f1f8\U0001f1f3", + ":serbia:": "\U0001f1f7\U0001f1f8", + ":seven:": "7\ufe0f\u20e3", + ":seven-thirty:": "\U0001f562", + ":seven_o’clock:": "\U0001f556", + ":seychelles:": "\U0001f1f8\U0001f1e8", + ":shallow_pan_of_food:": "\U0001f958", + ":shamrock:": "\U00002618", + ":shark:": "\U0001f988", + ":shaved_ice:": "\U0001f367", + ":sheaf_of_rice:": "\U0001f33e", + ":sheep:": "\U0001f411", + ":shell:": "\U0001f41a", + ":shield:": "\U0001f6e1", + ":shinto_shrine:": "\U000026e9", + ":ship:": "\U0001f6a2", + ":shirt:": "\U0001f455", + ":shit:": "\U0001f4a9", + ":shoe:": "\U0001f45e", + ":shooting_star:": "\U0001f320", + ":shopping:": "\U0001f6cd", + ":shopping_bags:": "\U0001f6cd", + ":shopping_cart:": "\U0001f6d2", + ":shortcake:": "\U0001f370", + ":shower:": "\U0001f6bf", + ":shrimp:": "\U0001f990", + ":shuffle_tracks_button:": "\U0001f500", + ":shushing_face:": "\U0001f92b", + ":sierra_leone:": "\U0001f1f8\U0001f1f1", + ":sign_of_the_horns:": "\U0001f918", + ":signal_strength:": "\U0001f4f6", + ":singapore:": "\U0001f1f8\U0001f1ec", + ":sint_maarten:": "\U0001f1f8\U0001f1fd", + ":six:": "6\ufe0f\u20e3", + ":six-thirty:": "\U0001f561", + ":six_o’clock:": "\U0001f555", + ":six_pointed_star:": "\U0001f52f", + ":skateboard:": "\U0001f6f9", + ":ski:": "\U0001f3bf", + ":skier:": "\U000026f7", + ":skis:": "\U0001f3bf", + ":skull:": "\U0001f480", + ":skull_and_crossbones:": "\U00002620", + ":skull_crossbones:": "\u2620", + ":sled:": "\U0001f6f7", + ":sleeping:": "\U0001f634", + ":sleeping_accommodation:": "\U0001f6cc", + ":sleeping_bed:": "\U0001f6cc", + ":sleeping_face:": "\U0001f634", + ":sleepy:": "\U0001f62a", + ":sleepy_face:": "\U0001f62a", + ":slight_frown:": "\U0001f641", + ":slight_smile:": "\U0001f642", + ":slightly_frowning_face:": "\U0001f641", + ":slightly_smiling_face:": "\U0001f642", + ":slot_machine:": "\U0001f3b0", + ":slovakia:": "\U0001f1f8\U0001f1f0", + ":slovenia:": "\U0001f1f8\U0001f1ee", + ":small_airplane:": "\U0001f6e9", + ":small_blue_diamond:": "\U0001f539", + ":small_orange_diamond:": "\U0001f538", + ":small_red_triangle:": "\U0001f53a", + ":small_red_triangle_down:": "\U0001f53b", + ":smile:": "\U0001f604", + ":smile_cat:": "\U0001f638", + ":smiley:": "\U0001f603", + ":smiley_cat:": "\U0001f63a", + ":smiling_cat_with_heart-eyes:": "\U0001f63b", + ":smiling_face:": "\U0000263a", + ":smiling_face_with_halo:": "\U0001f607", + ":smiling_face_with_heart-eyes:": "\U0001f60d", + ":smiling_face_with_hearts:": "\U0001f970", + ":smiling_face_with_horns:": "\U0001f608", + ":smiling_face_with_smiling_eyes:": "\U0001f60a", + ":smiling_face_with_sunglasses:": "\U0001f60e", + ":smiling_imp:": "\U0001f608", + ":smirk:": "\U0001f60f", + ":smirk_cat:": "\U0001f63c", + ":smirking_face:": "\U0001f60f", + ":smoking:": "\U0001f6ac", + ":snail:": "\U0001f40c", + ":snake:": "\U0001f40d", + ":sneezing_face:": "\U0001f927", + ":snow-capped_mountain:": "\U0001f3d4", + ":snowboarder:": "\U0001f3c2", + ":snowboarder_tone1:": "\U0001f3c2\U0001f3fb", + ":snowboarder_tone2:": "\U0001f3c2\U0001f3fc", + ":snowboarder_tone3:": "\U0001f3c2\U0001f3fd", + ":snowboarder_tone4:": "\U0001f3c2\U0001f3fe", + ":snowboarder_tone5:": "\U0001f3c2\U0001f3ff", + ":snowflake:": "\U00002744", + ":snowman:": "\U00002603", + ":snowman2:": "\u2603", + ":snowman_with_snow:": "\u2603\ufe0f", + ":snowman_without_snow:": "\U000026c4", + ":soap:": "\U0001f9fc", + ":sob:": "\U0001f62d", + ":soccer:": "\u26bd", + ":soccer_ball:": "\U000026bd", + ":socks:": "\U0001f9e6", + ":soft_ice_cream:": "\U0001f366", + ":softball:": "\U0001f94e", + ":solomon_islands:": "\U0001f1f8\U0001f1e7", + ":somalia:": "\U0001f1f8\U0001f1f4", + ":soon:": "\U0001f51c", + ":sos:": "\U0001f198", + ":sound:": "\U0001f509", + ":south_africa:": "\U0001f1ff\U0001f1e6", + ":south_georgia_south_sandwich_islands:": "\U0001f1ec\U0001f1f8", + ":south_sudan:": "\U0001f1f8\U0001f1f8", + ":space_invader:": "\U0001f47e", + ":spade_suit:": "\U00002660", + ":spades:": "\u2660", + ":spaghetti:": "\U0001f35d", + ":sparkle:": "\U00002747", + ":sparkler:": "\U0001f387", + ":sparkles:": "\U00002728", + ":sparkling_heart:": "\U0001f496", + ":speak-no-evil_monkey:": "\U0001f64a", + ":speak_no_evil:": "\U0001f64a", + ":speaker:": "\U0001f508", + ":speaker_high_volume:": "\U0001f50a", + ":speaker_low_volume:": "\U0001f508", + ":speaker_medium_volume:": "\U0001f509", + ":speaking_head:": "\U0001f5e3", + ":speech_balloon:": "\U0001f4ac", + ":speech_left:": "\U0001f5e8", + ":speedboat:": "\U0001f6a4", + ":spider:": "\U0001f577", + ":spider_web:": "\U0001f578", + ":spiral_calendar:": "\U0001f5d3", + ":spiral_notepad:": "\U0001f5d2", + ":spiral_shell:": "\U0001f41a", + ":sponge:": "\U0001f9fd", + ":spoon:": "\U0001f944", + ":sport_utility_vehicle:": "\U0001f699", + ":sports_medal:": "\U0001f3c5", + ":spouting_whale:": "\U0001f433", + ":squid:": "\U0001f991", + ":squinting_face_with_tongue:": "\U0001f61d", + ":sri_lanka:": "\U0001f1f1\U0001f1f0", + ":st_barthelemy:": "\U0001f1e7\U0001f1f1", + ":st_helena:": "\U0001f1f8\U0001f1ed", + ":st_kitts_nevis:": "\U0001f1f0\U0001f1f3", + ":st_lucia:": "\U0001f1f1\U0001f1e8", + ":st_pierre_miquelon:": "\U0001f1f5\U0001f1f2", + ":st_vincent_grenadines:": "\U0001f1fb\U0001f1e8", + ":stadium:": "\U0001f3df", + ":star:": "\U00002b50", + ":star-struck:": "\U0001f929", + ":star2:": "\U0001f31f", + ":star_and_crescent:": "\U0000262a", + ":star_of_David:": "\U00002721", + ":star_of_david:": "\u2721", + ":star_struck:": "\U0001f929", + ":stars:": "\U0001f320", + ":station:": "\U0001f689", + ":statue_of_liberty:": "\U0001f5fd", + ":steam_locomotive:": "\U0001f682", + ":steaming_bowl:": "\U0001f35c", + ":stew:": "\U0001f372", + ":stop_button:": "\U000023f9", + ":stop_sign:": "\U0001f6d1", + ":stopwatch:": "\U000023f1", + ":straight_ruler:": "\U0001f4cf", + ":strawberry:": "\U0001f353", + ":stuck_out_tongue:": "\U0001f61b", + ":stuck_out_tongue_closed_eyes:": "\U0001f61d", + ":stuck_out_tongue_winking_eye:": "\U0001f61c", + ":studio_microphone:": "\U0001f399", + ":stuffed_flatbread:": "\U0001f959", + ":sudan:": "\U0001f1f8\U0001f1e9", + ":sun:": "\U00002600", + ":sun_behind_cloud:": "\U000026c5", + ":sun_behind_large_cloud:": "\U0001f325", + ":sun_behind_rain_cloud:": "\U0001f326", + ":sun_behind_small_cloud:": "\U0001f324", + ":sun_with_face:": "\U0001f31e", + ":sunflower:": "\U0001f33b", + ":sunglasses:": "\U0001f576", + ":sunny:": "\u2600", + ":sunrise:": "\U0001f305", + ":sunrise_over_mountains:": "\U0001f304", + ":sunset:": "\U0001f307", + ":superhero:": "\U0001f9b8", + ":supervillain:": "\U0001f9b9", + ":surfer:": "\U0001f3c4", + ":surfing_man:": "\U0001f3c4", + ":surfing_woman:": "\U0001f3c4\u200d\u2640", + ":suriname:": "\U0001f1f8\U0001f1f7", + ":sushi:": "\U0001f363", + ":suspension_railway:": "\U0001f69f", + ":swan:": "\U0001f9a2", + ":swaziland:": "\U0001f1f8\U0001f1ff", + ":sweat:": "\U0001f613", + ":sweat_droplets:": "\U0001f4a6", + ":sweat_drops:": "\U0001f4a6", + ":sweat_smile:": "\U0001f605", + ":sweden:": "\U0001f1f8\U0001f1ea", + ":sweet_potato:": "\U0001f360", + ":swimmer:": "\U0001f3ca", + ":swimming_man:": "\U0001f3ca", + ":swimming_woman:": "\U0001f3ca\u200d\u2640", + ":switzerland:": "\U0001f1e8\U0001f1ed", + ":symbols:": "\U0001f523", + ":synagogue:": "\U0001f54d", + ":syria:": "\U0001f1f8\U0001f1fe", + ":syringe:": "\U0001f489", + ":t-shirt:": "\U0001f455", + ":t_rex:": "\U0001f996", + ":taco:": "\U0001f32e", + ":tada:": "\U0001f389", + ":taiwan:": "\U0001f1f9\U0001f1fc", + ":tajikistan:": "\U0001f1f9\U0001f1ef", + ":takeout_box:": "\U0001f961", + ":tanabata_tree:": "\U0001f38b", + ":tangerine:": "\U0001f34a", + ":tanzania:": "\U0001f1f9\U0001f1ff", + ":taurus:": "\u2649", + ":taxi:": "\U0001f695", + ":tea:": "\U0001f375", + ":teacup_without_handle:": "\U0001f375", + ":tear-off_calendar:": "\U0001f4c6", + ":teddy_bear:": "\U0001f9f8", + ":telephone:": "\U0000260e", + ":telephone_receiver:": "\U0001f4de", + ":telescope:": "\U0001f52d", + ":television:": "\U0001f4fa", + ":ten-thirty:": "\U0001f565", + ":ten_o’clock:": "\U0001f559", + ":tennis:": "\U0001f3be", + ":tent:": "\U000026fa", + ":test_tube:": "\U0001f9ea", + ":thailand:": "\U0001f1f9\U0001f1ed", + ":thermometer:": "\U0001f321", + ":thermometer_face:": "\U0001f912", + ":thinking:": "\U0001f914", + ":thinking_face:": "\U0001f914", + ":third_place:": "\U0001f949", + ":thought_balloon:": "\U0001f4ad", + ":thread:": "\U0001f9f5", + ":three:": "3\ufe0f\u20e3", + ":three-thirty:": "\U0001f55e", + ":three_o’clock:": "\U0001f552", + ":thumbs_down:": "\U0001f44e", + ":thumbs_up:": "\U0001f44d", + ":thumbsdown:": "\U0001f44e", + ":thumbsdown_tone1:": "\U0001f44e\U0001f3fb", + ":thumbsdown_tone2:": "\U0001f44e\U0001f3fc", + ":thumbsdown_tone3:": "\U0001f44e\U0001f3fd", + ":thumbsdown_tone4:": "\U0001f44e\U0001f3fe", + ":thumbsdown_tone5:": "\U0001f44e\U0001f3ff", + ":thumbsup:": "\U0001f44d", + ":thumbsup_tone1:": "\U0001f44d\U0001f3fb", + ":thumbsup_tone2:": "\U0001f44d\U0001f3fc", + ":thumbsup_tone3:": "\U0001f44d\U0001f3fd", + ":thumbsup_tone4:": "\U0001f44d\U0001f3fe", + ":thumbsup_tone5:": "\U0001f44d\U0001f3ff", + ":thunder_cloud_rain:": "\u26c8", + ":ticket:": "\U0001f3ab", + ":tickets:": "\U0001f39f", + ":tiger:": "\U0001f405", + ":tiger2:": "\U0001f405", + ":tiger_face:": "\U0001f42f", + ":timer:": "\u23f2", + ":timer_clock:": "\U000023f2", + ":timor_leste:": "\U0001f1f9\U0001f1f1", + ":tipping_hand_man:": "\U0001f481\u200d\u2642", + ":tipping_hand_woman:": "\U0001f481", + ":tired_face:": "\U0001f62b", + ":tm:": "\u2122", + ":togo:": "\U0001f1f9\U0001f1ec", + ":toilet:": "\U0001f6bd", + ":tokelau:": "\U0001f1f9\U0001f1f0", + ":tokyo_tower:": "\U0001f5fc", + ":tomato:": "\U0001f345", + ":tonga:": "\U0001f1f9\U0001f1f4", + ":tongue:": "\U0001f445", + ":toolbox:": "\U0001f9f0", + ":tools:": "\U0001f6e0", + ":tooth:": "\U0001f9b7", + ":top:": "\U0001f51d", + ":top_hat:": "\U0001f3a9", + ":tophat:": "\U0001f3a9", + ":tornado:": "\U0001f32a", + ":tr:": "\U0001f1f9\U0001f1f7", + ":track_next:": "\u23ed", + ":track_previous:": "\u23ee", + ":trackball:": "\U0001f5b2", + ":tractor:": "\U0001f69c", + ":trade_mark:": "\U00002122", + ":traffic_light:": "\U0001f6a5", + ":train:": "\U0001f686", + ":train2:": "\U0001f686", + ":tram:": "\U0001f68a", + ":tram_car:": "\U0001f68b", + ":triangular_flag:": "\U0001f6a9", + ":triangular_flag_on_post:": "\U0001f6a9", + ":triangular_ruler:": "\U0001f4d0", + ":trident:": "\U0001f531", + ":trident_emblem:": "\U0001f531", + ":trinidad_tobago:": "\U0001f1f9\U0001f1f9", + ":triumph:": "\U0001f624", + ":trolleybus:": "\U0001f68e", + ":trophy:": "\U0001f3c6", + ":tropical_drink:": "\U0001f379", + ":tropical_fish:": "\U0001f420", + ":truck:": "\U0001f69a", + ":trumpet:": "\U0001f3ba", + ":tshirt:": "\U0001f455", + ":tulip:": "\U0001f337", + ":tumbler_glass:": "\U0001f943", + ":tunisia:": "\U0001f1f9\U0001f1f3", + ":turkey:": "\U0001f983", + ":turkmenistan:": "\U0001f1f9\U0001f1f2", + ":turks_caicos_islands:": "\U0001f1f9\U0001f1e8", + ":turtle:": "\U0001f422", + ":tuvalu:": "\U0001f1f9\U0001f1fb", + ":tv:": "\U0001f4fa", + ":twelve-thirty:": "\U0001f567", + ":twelve_o’clock:": "\U0001f55b", + ":twisted_rightwards_arrows:": "\U0001f500", + ":two:": "2\ufe0f\u20e3", + ":two-hump_camel:": "\U0001f42b", + ":two-thirty:": "\U0001f55d", + ":two_hearts:": "\U0001f495", + ":two_men_holding_hands:": "\U0001f46c", + ":two_o’clock:": "\U0001f551", + ":two_women_holding_hands:": "\U0001f46d", + ":u5272:": "\U0001f239", + ":u5408:": "\U0001f234", + ":u55b6:": "\U0001f23a", + ":u6307:": "\U0001f22f", + ":u6708:": "\U0001f237", + ":u6709:": "\U0001f236", + ":u6e80:": "\U0001f235", + ":u7121:": "\U0001f21a", + ":u7533:": "\U0001f238", + ":u7981:": "\U0001f232", + ":u7a7a:": "\U0001f233", + ":uganda:": "\U0001f1fa\U0001f1ec", + ":uk:": "\U0001f1ec\U0001f1e7", + ":ukraine:": "\U0001f1fa\U0001f1e6", + ":umbrella:": "\U00002602", + ":umbrella2:": "\u2602", + ":umbrella_on_ground:": "\U000026f1", + ":umbrella_with_rain_drops:": "\U00002614", + ":unamused:": "\U0001f612", + ":unamused_face:": "\U0001f612", + ":underage:": "\U0001f51e", + ":unicorn:": "\U0001f984", + ":united_arab_emirates:": "\U0001f1e6\U0001f1ea", + ":united_nations:": "\U0001f1fa\U0001f1f3", + ":unlock:": "\U0001f513", + ":unlocked:": "\U0001f513", + ":up:": "\U0001f199", + ":up-down_arrow:": "\U00002195", + ":up-left_arrow:": "\U00002196", + ":up-right_arrow:": "\U00002197", + ":up_arrow:": "\U00002b06", + ":upside-down_face:": "\U0001f643", + ":upside_down:": "\U0001f643", + ":upside_down_face:": "\U0001f643", + ":upwards_button:": "\U0001f53c", + ":urn:": "\u26b1", + ":uruguay:": "\U0001f1fa\U0001f1fe", + ":us:": "\U0001f1fa\U0001f1f8", + ":us_virgin_islands:": "\U0001f1fb\U0001f1ee", + ":uzbekistan:": "\U0001f1fa\U0001f1ff", + ":v:": "\u270c", + ":v_tone1:": "\u270c\U0001f3fb", + ":v_tone2:": "\u270c\U0001f3fc", + ":v_tone3:": "\u270c\U0001f3fd", + ":v_tone4:": "\u270c\U0001f3fe", + ":v_tone5:": "\u270c\U0001f3ff", + ":vampire:": "\U0001f9db", + ":vampire_tone1:": "\U0001f9db\U0001f3fb", + ":vampire_tone2:": "\U0001f9db\U0001f3fc", + ":vampire_tone3:": "\U0001f9db\U0001f3fd", + ":vampire_tone4:": "\U0001f9db\U0001f3fe", + ":vampire_tone5:": "\U0001f9db\U0001f3ff", + ":vanuatu:": "\U0001f1fb\U0001f1fa", + ":vatican_city:": "\U0001f1fb\U0001f1e6", + ":venezuela:": "\U0001f1fb\U0001f1ea", + ":vertical_traffic_light:": "\U0001f6a6", + ":vhs:": "\U0001f4fc", + ":vibration_mode:": "\U0001f4f3", + ":victory_hand:": "\U0000270c", + ":video_camera:": "\U0001f4f9", + ":video_game:": "\U0001f3ae", + ":videocassette:": "\U0001f4fc", + ":vietnam:": "\U0001f1fb\U0001f1f3", + ":violin:": "\U0001f3bb", + ":virgo:": "\u264d", + ":volcano:": "\U0001f30b", + ":volleyball:": "\U0001f3d0", + ":vs:": "\U0001f19a", + ":vulcan:": "\U0001f596", + ":vulcan_salute:": "\U0001f596", + ":vulcan_tone1:": "\U0001f596\U0001f3fb", + ":vulcan_tone2:": "\U0001f596\U0001f3fc", + ":vulcan_tone3:": "\U0001f596\U0001f3fd", + ":vulcan_tone4:": "\U0001f596\U0001f3fe", + ":vulcan_tone5:": "\U0001f596\U0001f3ff", + ":wales:": "\U0001f3f4\U000e0067\U000e0062\U000e0077\U000e006c\U000e0073\U000e007f", + ":walking:": "\U0001f6b6", + ":walking_man:": "\U0001f6b6", + ":walking_woman:": "\U0001f6b6\u200d\u2640", + ":wallis_futuna:": "\U0001f1fc\U0001f1eb", + ":waning_crescent_moon:": "\U0001f318", + ":waning_gibbous_moon:": "\U0001f316", + ":warning:": "\U000026a0", + ":wastebasket:": "\U0001f5d1", + ":watch:": "\U0000231a", + ":water_buffalo:": "\U0001f403", + ":water_closet:": "\U0001f6be", + ":water_wave:": "\U0001f30a", + ":watermelon:": "\U0001f349", + ":wave:": "\U0001f44b", + ":wave_tone1:": "\U0001f44b\U0001f3fb", + ":wave_tone2:": "\U0001f44b\U0001f3fc", + ":wave_tone3:": "\U0001f44b\U0001f3fd", + ":wave_tone4:": "\U0001f44b\U0001f3fe", + ":wave_tone5:": "\U0001f44b\U0001f3ff", + ":waving_hand:": "\U0001f44b", + ":wavy_dash:": "\U00003030", + ":waxing_crescent_moon:": "\U0001f312", + ":waxing_gibbous_moon:": "\U0001f314", + ":wc:": "\U0001f6be", + ":weary:": "\U0001f629", + ":weary_cat:": "\U0001f640", + ":weary_face:": "\U0001f629", + ":wedding:": "\U0001f492", + ":weight_lifting_man:": "\U0001f3cb", + ":weight_lifting_woman:": "\U0001f3cb\ufe0f\u200d\u2640\ufe0f", + ":western_sahara:": "\U0001f1ea\U0001f1ed", + ":whale:": "\U0001f40b", + ":whale2:": "\U0001f40b", + ":wheel_of_dharma:": "\U00002638", + ":wheelchair:": "\u267f", + ":wheelchair_symbol:": "\U0000267f", + ":white_check_mark:": "\u2705", + ":white_circle:": "\U000026aa", + ":white_exclamation_mark:": "\U00002755", + ":white_flag:": "\U0001f3f3", + ":white_flower:": "\U0001f4ae", + ":white_hair:": "\U0001f9b3", + ":white_large_square:": "\U00002b1c", + ":white_medium-small_square:": "\U000025fd", + ":white_medium_small_square:": "\u25fd", + ":white_medium_square:": "\U000025fb", + ":white_question_mark:": "\U00002754", + ":white_small_square:": "\U000025ab", + ":white_square_button:": "\U0001f533", + ":white_sun_cloud:": "\U0001f325", + ":white_sun_rain_cloud:": "\U0001f326", + ":white_sun_small_cloud:": "\U0001f324", + ":wilted_flower:": "\U0001f940", + ":wilted_rose:": "\U0001f940", + ":wind_blowing_face:": "\U0001f32c", + ":wind_chime:": "\U0001f390", + ":wind_face:": "\U0001f32c", + ":wine_glass:": "\U0001f377", + ":wink:": "\U0001f609", + ":winking_face:": "\U0001f609", + ":winking_face_with_tongue:": "\U0001f61c", + ":wolf:": "\U0001f43a", + ":woman:": "\U0001f469", + ":woman_and_man_holding_hands:": "\U0001f46b", + ":woman_artist:": "\U0001f469\U0000200d\U0001f3a8", + ":woman_artist_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f3a8", + ":woman_artist_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f3a8", + ":woman_artist_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f3a8", + ":woman_artist_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f3a8", + ":woman_artist_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f3a8", + ":woman_astronaut:": "\U0001f469\U0000200d\U0001f680", + ":woman_astronaut_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f680", + ":woman_astronaut_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f680", + ":woman_astronaut_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f680", + ":woman_astronaut_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f680", + ":woman_astronaut_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f680", + ":woman_bald:": "\U0001f469\U0000200d\U0001f9b2", + ":woman_biking:": "\U0001f6b4\U0000200d\U00002640\U0000fe0f", + ":woman_biking_tone1:": "\U0001f6b4\U0001f3fb\u200d\u2640\ufe0f", + ":woman_biking_tone2:": "\U0001f6b4\U0001f3fc\u200d\u2640\ufe0f", + ":woman_biking_tone3:": "\U0001f6b4\U0001f3fd\u200d\u2640\ufe0f", + ":woman_biking_tone4:": "\U0001f6b4\U0001f3fe\u200d\u2640\ufe0f", + ":woman_biking_tone5:": "\U0001f6b4\U0001f3ff\u200d\u2640\ufe0f", + ":woman_blond_hair:": "\U0001f471\U0000200d\U00002640\U0000fe0f", + ":woman_bouncing_ball:": "\U000026f9\U0000fe0f\U0000200d\U00002640\U0000fe0f", + ":woman_bouncing_ball_tone1:": "\u26f9\U0001f3fb\u200d\u2640\ufe0f", + ":woman_bouncing_ball_tone2:": "\u26f9\U0001f3fc\u200d\u2640\ufe0f", + ":woman_bouncing_ball_tone3:": "\u26f9\U0001f3fd\u200d\u2640\ufe0f", + ":woman_bouncing_ball_tone4:": "\u26f9\U0001f3fe\u200d\u2640\ufe0f", + ":woman_bouncing_ball_tone5:": "\u26f9\U0001f3ff\u200d\u2640\ufe0f", + ":woman_bowing:": "\U0001f647\U0000200d\U00002640\U0000fe0f", + ":woman_bowing_tone1:": "\U0001f647\U0001f3fb\u200d\u2640\ufe0f", + ":woman_bowing_tone2:": "\U0001f647\U0001f3fc\u200d\u2640\ufe0f", + ":woman_bowing_tone3:": "\U0001f647\U0001f3fd\u200d\u2640\ufe0f", + ":woman_bowing_tone4:": "\U0001f647\U0001f3fe\u200d\u2640\ufe0f", + ":woman_bowing_tone5:": "\U0001f647\U0001f3ff\u200d\u2640\ufe0f", + ":woman_cartwheeling:": "\U0001f938\U0000200d\U00002640\U0000fe0f", + ":woman_cartwheeling_tone1:": "\U0001f938\U0001f3fb\u200d\u2640\ufe0f", + ":woman_cartwheeling_tone2:": "\U0001f938\U0001f3fc\u200d\u2640\ufe0f", + ":woman_cartwheeling_tone3:": "\U0001f938\U0001f3fd\u200d\u2640\ufe0f", + ":woman_cartwheeling_tone4:": "\U0001f938\U0001f3fe\u200d\u2640\ufe0f", + ":woman_cartwheeling_tone5:": "\U0001f938\U0001f3ff\u200d\u2640\ufe0f", + ":woman_climbing:": "\U0001f9d7\U0000200d\U00002640\U0000fe0f", + ":woman_climbing_tone1:": "\U0001f9d7\U0001f3fb\u200d\u2640\ufe0f", + ":woman_climbing_tone2:": "\U0001f9d7\U0001f3fc\u200d\u2640\ufe0f", + ":woman_climbing_tone3:": "\U0001f9d7\U0001f3fd\u200d\u2640\ufe0f", + ":woman_climbing_tone4:": "\U0001f9d7\U0001f3fe\u200d\u2640\ufe0f", + ":woman_climbing_tone5:": "\U0001f9d7\U0001f3ff\u200d\u2640\ufe0f", + ":woman_construction_worker:": "\U0001f477\U0000200d\U00002640\U0000fe0f", + ":woman_construction_worker_tone1:": "\U0001f477\U0001f3fb\u200d\u2640\ufe0f", + ":woman_construction_worker_tone2:": "\U0001f477\U0001f3fc\u200d\u2640\ufe0f", + ":woman_construction_worker_tone3:": "\U0001f477\U0001f3fd\u200d\u2640\ufe0f", + ":woman_construction_worker_tone4:": "\U0001f477\U0001f3fe\u200d\u2640\ufe0f", + ":woman_construction_worker_tone5:": "\U0001f477\U0001f3ff\u200d\u2640\ufe0f", + ":woman_cook:": "\U0001f469\U0000200d\U0001f373", + ":woman_cook_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f373", + ":woman_cook_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f373", + ":woman_cook_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f373", + ":woman_cook_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f373", + ":woman_cook_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f373", + ":woman_curly_hair:": "\U0001f469\U0000200d\U0001f9b1", + ":woman_dancing:": "\U0001f483", + ":woman_detective:": "\U0001f575\U0000fe0f\U0000200d\U00002640\U0000fe0f", + ":woman_detective_tone1:": "\U0001f575\U0001f3fb\u200d\u2640\ufe0f", + ":woman_detective_tone2:": "\U0001f575\U0001f3fc\u200d\u2640\ufe0f", + ":woman_detective_tone3:": "\U0001f575\U0001f3fd\u200d\u2640\ufe0f", + ":woman_detective_tone4:": "\U0001f575\U0001f3fe\u200d\u2640\ufe0f", + ":woman_detective_tone5:": "\U0001f575\U0001f3ff\u200d\u2640\ufe0f", + ":woman_elf:": "\U0001f9dd\U0000200d\U00002640\U0000fe0f", + ":woman_elf_tone1:": "\U0001f9dd\U0001f3fb\u200d\u2640\ufe0f", + ":woman_elf_tone2:": "\U0001f9dd\U0001f3fc\u200d\u2640\ufe0f", + ":woman_elf_tone3:": "\U0001f9dd\U0001f3fd\u200d\u2640\ufe0f", + ":woman_elf_tone4:": "\U0001f9dd\U0001f3fe\u200d\u2640\ufe0f", + ":woman_elf_tone5:": "\U0001f9dd\U0001f3ff\u200d\u2640\ufe0f", + ":woman_facepalming:": "\U0001f926\U0000200d\U00002640\U0000fe0f", + ":woman_facepalming_tone1:": "\U0001f926\U0001f3fb\u200d\u2640\ufe0f", + ":woman_facepalming_tone2:": "\U0001f926\U0001f3fc\u200d\u2640\ufe0f", + ":woman_facepalming_tone3:": "\U0001f926\U0001f3fd\u200d\u2640\ufe0f", + ":woman_facepalming_tone4:": "\U0001f926\U0001f3fe\u200d\u2640\ufe0f", + ":woman_facepalming_tone5:": "\U0001f926\U0001f3ff\u200d\u2640\ufe0f", + ":woman_factory_worker:": "\U0001f469\U0000200d\U0001f3ed", + ":woman_factory_worker_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f3ed", + ":woman_factory_worker_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f3ed", + ":woman_factory_worker_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f3ed", + ":woman_factory_worker_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f3ed", + ":woman_factory_worker_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f3ed", + ":woman_fairy:": "\U0001f9da\U0000200d\U00002640\U0000fe0f", + ":woman_fairy_tone1:": "\U0001f9da\U0001f3fb\u200d\u2640\ufe0f", + ":woman_fairy_tone2:": "\U0001f9da\U0001f3fc\u200d\u2640\ufe0f", + ":woman_fairy_tone3:": "\U0001f9da\U0001f3fd\u200d\u2640\ufe0f", + ":woman_fairy_tone4:": "\U0001f9da\U0001f3fe\u200d\u2640\ufe0f", + ":woman_fairy_tone5:": "\U0001f9da\U0001f3ff\u200d\u2640\ufe0f", + ":woman_farmer:": "\U0001f469\U0000200d\U0001f33e", + ":woman_farmer_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f33e", + ":woman_farmer_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f33e", + ":woman_farmer_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f33e", + ":woman_farmer_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f33e", + ":woman_farmer_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f33e", + ":woman_firefighter:": "\U0001f469\U0000200d\U0001f692", + ":woman_firefighter_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f692", + ":woman_firefighter_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f692", + ":woman_firefighter_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f692", + ":woman_firefighter_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f692", + ":woman_firefighter_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f692", + ":woman_frowning:": "\U0001f64d\U0000200d\U00002640\U0000fe0f", + ":woman_frowning_tone1:": "\U0001f64d\U0001f3fb\u200d\u2640\ufe0f", + ":woman_frowning_tone2:": "\U0001f64d\U0001f3fc\u200d\u2640\ufe0f", + ":woman_frowning_tone3:": "\U0001f64d\U0001f3fd\u200d\u2640\ufe0f", + ":woman_frowning_tone4:": "\U0001f64d\U0001f3fe\u200d\u2640\ufe0f", + ":woman_frowning_tone5:": "\U0001f64d\U0001f3ff\u200d\u2640\ufe0f", + ":woman_genie:": "\U0001f9de\U0000200d\U00002640\U0000fe0f", + ":woman_gesturing_NO:": "\U0001f645\U0000200d\U00002640\U0000fe0f", + ":woman_gesturing_OK:": "\U0001f646\U0000200d\U00002640\U0000fe0f", + ":woman_gesturing_no:": "\U0001f645\u200d\u2640\ufe0f", + ":woman_gesturing_no_tone1:": "\U0001f645\U0001f3fb\u200d\u2640\ufe0f", + ":woman_gesturing_no_tone2:": "\U0001f645\U0001f3fc\u200d\u2640\ufe0f", + ":woman_gesturing_no_tone3:": "\U0001f645\U0001f3fd\u200d\u2640\ufe0f", + ":woman_gesturing_no_tone4:": "\U0001f645\U0001f3fe\u200d\u2640\ufe0f", + ":woman_gesturing_no_tone5:": "\U0001f645\U0001f3ff\u200d\u2640\ufe0f", + ":woman_gesturing_ok:": "\U0001f646\u200d\u2640\ufe0f", + ":woman_gesturing_ok_tone1:": "\U0001f646\U0001f3fb\u200d\u2640\ufe0f", + ":woman_gesturing_ok_tone2:": "\U0001f646\U0001f3fc\u200d\u2640\ufe0f", + ":woman_gesturing_ok_tone3:": "\U0001f646\U0001f3fd\u200d\u2640\ufe0f", + ":woman_gesturing_ok_tone4:": "\U0001f646\U0001f3fe\u200d\u2640\ufe0f", + ":woman_gesturing_ok_tone5:": "\U0001f646\U0001f3ff\u200d\u2640\ufe0f", + ":woman_getting_face_massage:": "\U0001f486\u200d\u2640\ufe0f", + ":woman_getting_face_massage_tone1:": "\U0001f486\U0001f3fb\u200d\u2640\ufe0f", + ":woman_getting_face_massage_tone2:": "\U0001f486\U0001f3fc\u200d\u2640\ufe0f", + ":woman_getting_face_massage_tone3:": "\U0001f486\U0001f3fd\u200d\u2640\ufe0f", + ":woman_getting_face_massage_tone4:": "\U0001f486\U0001f3fe\u200d\u2640\ufe0f", + ":woman_getting_face_massage_tone5:": "\U0001f486\U0001f3ff\u200d\u2640\ufe0f", + ":woman_getting_haircut:": "\U0001f487\U0000200d\U00002640\U0000fe0f", + ":woman_getting_haircut_tone1:": "\U0001f487\U0001f3fb\u200d\u2640\ufe0f", + ":woman_getting_haircut_tone2:": "\U0001f487\U0001f3fc\u200d\u2640\ufe0f", + ":woman_getting_haircut_tone3:": "\U0001f487\U0001f3fd\u200d\u2640\ufe0f", + ":woman_getting_haircut_tone4:": "\U0001f487\U0001f3fe\u200d\u2640\ufe0f", + ":woman_getting_haircut_tone5:": "\U0001f487\U0001f3ff\u200d\u2640\ufe0f", + ":woman_getting_massage:": "\U0001f486\U0000200d\U00002640\U0000fe0f", + ":woman_golfing:": "\U0001f3cc\U0000fe0f\U0000200d\U00002640\U0000fe0f", + ":woman_golfing_tone1:": "\U0001f3cc\U0001f3fb\u200d\u2640\ufe0f", + ":woman_golfing_tone2:": "\U0001f3cc\U0001f3fc\u200d\u2640\ufe0f", + ":woman_golfing_tone3:": "\U0001f3cc\U0001f3fd\u200d\u2640\ufe0f", + ":woman_golfing_tone4:": "\U0001f3cc\U0001f3fe\u200d\u2640\ufe0f", + ":woman_golfing_tone5:": "\U0001f3cc\U0001f3ff\u200d\u2640\ufe0f", + ":woman_guard:": "\U0001f482\U0000200d\U00002640\U0000fe0f", + ":woman_guard_tone1:": "\U0001f482\U0001f3fb\u200d\u2640\ufe0f", + ":woman_guard_tone2:": "\U0001f482\U0001f3fc\u200d\u2640\ufe0f", + ":woman_guard_tone3:": "\U0001f482\U0001f3fd\u200d\u2640\ufe0f", + ":woman_guard_tone4:": "\U0001f482\U0001f3fe\u200d\u2640\ufe0f", + ":woman_guard_tone5:": "\U0001f482\U0001f3ff\u200d\u2640\ufe0f", + ":woman_health_worker:": "\U0001f469\U0000200d\U00002695\U0000fe0f", + ":woman_health_worker_tone1:": "\U0001f469\U0001f3fb\u200d\u2695\ufe0f", + ":woman_health_worker_tone2:": "\U0001f469\U0001f3fc\u200d\u2695\ufe0f", + ":woman_health_worker_tone3:": "\U0001f469\U0001f3fd\u200d\u2695\ufe0f", + ":woman_health_worker_tone4:": "\U0001f469\U0001f3fe\u200d\u2695\ufe0f", + ":woman_health_worker_tone5:": "\U0001f469\U0001f3ff\u200d\u2695\ufe0f", + ":woman_in_lotus_position:": "\U0001f9d8\U0000200d\U00002640\U0000fe0f", + ":woman_in_lotus_position_tone1:": "\U0001f9d8\U0001f3fb\u200d\u2640\ufe0f", + ":woman_in_lotus_position_tone2:": "\U0001f9d8\U0001f3fc\u200d\u2640\ufe0f", + ":woman_in_lotus_position_tone3:": "\U0001f9d8\U0001f3fd\u200d\u2640\ufe0f", + ":woman_in_lotus_position_tone4:": "\U0001f9d8\U0001f3fe\u200d\u2640\ufe0f", + ":woman_in_lotus_position_tone5:": "\U0001f9d8\U0001f3ff\u200d\u2640\ufe0f", + ":woman_in_steamy_room:": "\U0001f9d6\U0000200d\U00002640\U0000fe0f", + ":woman_in_steamy_room_tone1:": "\U0001f9d6\U0001f3fb\u200d\u2640\ufe0f", + ":woman_in_steamy_room_tone2:": "\U0001f9d6\U0001f3fc\u200d\u2640\ufe0f", + ":woman_in_steamy_room_tone3:": "\U0001f9d6\U0001f3fd\u200d\u2640\ufe0f", + ":woman_in_steamy_room_tone4:": "\U0001f9d6\U0001f3fe\u200d\u2640\ufe0f", + ":woman_in_steamy_room_tone5:": "\U0001f9d6\U0001f3ff\u200d\u2640\ufe0f", + ":woman_judge:": "\U0001f469\U0000200d\U00002696\U0000fe0f", + ":woman_judge_tone1:": "\U0001f469\U0001f3fb\u200d\u2696\ufe0f", + ":woman_judge_tone2:": "\U0001f469\U0001f3fc\u200d\u2696\ufe0f", + ":woman_judge_tone3:": "\U0001f469\U0001f3fd\u200d\u2696\ufe0f", + ":woman_judge_tone4:": "\U0001f469\U0001f3fe\u200d\u2696\ufe0f", + ":woman_judge_tone5:": "\U0001f469\U0001f3ff\u200d\u2696\ufe0f", + ":woman_juggling:": "\U0001f939\U0000200d\U00002640\U0000fe0f", + ":woman_juggling_tone1:": "\U0001f939\U0001f3fb\u200d\u2640\ufe0f", + ":woman_juggling_tone2:": "\U0001f939\U0001f3fc\u200d\u2640\ufe0f", + ":woman_juggling_tone3:": "\U0001f939\U0001f3fd\u200d\u2640\ufe0f", + ":woman_juggling_tone4:": "\U0001f939\U0001f3fe\u200d\u2640\ufe0f", + ":woman_juggling_tone5:": "\U0001f939\U0001f3ff\u200d\u2640\ufe0f", + ":woman_lifting_weights:": "\U0001f3cb\U0000fe0f\U0000200d\U00002640\U0000fe0f", + ":woman_lifting_weights_tone1:": "\U0001f3cb\U0001f3fb\u200d\u2640\ufe0f", + ":woman_lifting_weights_tone2:": "\U0001f3cb\U0001f3fc\u200d\u2640\ufe0f", + ":woman_lifting_weights_tone3:": "\U0001f3cb\U0001f3fd\u200d\u2640\ufe0f", + ":woman_lifting_weights_tone4:": "\U0001f3cb\U0001f3fe\u200d\u2640\ufe0f", + ":woman_lifting_weights_tone5:": "\U0001f3cb\U0001f3ff\u200d\u2640\ufe0f", + ":woman_mage:": "\U0001f9d9\U0000200d\U00002640\U0000fe0f", + ":woman_mage_tone1:": "\U0001f9d9\U0001f3fb\u200d\u2640\ufe0f", + ":woman_mage_tone2:": "\U0001f9d9\U0001f3fc\u200d\u2640\ufe0f", + ":woman_mage_tone3:": "\U0001f9d9\U0001f3fd\u200d\u2640\ufe0f", + ":woman_mage_tone4:": "\U0001f9d9\U0001f3fe\u200d\u2640\ufe0f", + ":woman_mage_tone5:": "\U0001f9d9\U0001f3ff\u200d\u2640\ufe0f", + ":woman_mechanic:": "\U0001f469\U0000200d\U0001f527", + ":woman_mechanic_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f527", + ":woman_mechanic_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f527", + ":woman_mechanic_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f527", + ":woman_mechanic_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f527", + ":woman_mechanic_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f527", + ":woman_mountain_biking:": "\U0001f6b5\U0000200d\U00002640\U0000fe0f", + ":woman_mountain_biking_tone1:": "\U0001f6b5\U0001f3fb\u200d\u2640\ufe0f", + ":woman_mountain_biking_tone2:": "\U0001f6b5\U0001f3fc\u200d\u2640\ufe0f", + ":woman_mountain_biking_tone3:": "\U0001f6b5\U0001f3fd\u200d\u2640\ufe0f", + ":woman_mountain_biking_tone4:": "\U0001f6b5\U0001f3fe\u200d\u2640\ufe0f", + ":woman_mountain_biking_tone5:": "\U0001f6b5\U0001f3ff\u200d\u2640\ufe0f", + ":woman_office_worker:": "\U0001f469\U0000200d\U0001f4bc", + ":woman_office_worker_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f4bc", + ":woman_office_worker_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f4bc", + ":woman_office_worker_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f4bc", + ":woman_office_worker_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f4bc", + ":woman_office_worker_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f4bc", + ":woman_pilot:": "\U0001f469\U0000200d\U00002708\U0000fe0f", + ":woman_pilot_tone1:": "\U0001f469\U0001f3fb\u200d\u2708\ufe0f", + ":woman_pilot_tone2:": "\U0001f469\U0001f3fc\u200d\u2708\ufe0f", + ":woman_pilot_tone3:": "\U0001f469\U0001f3fd\u200d\u2708\ufe0f", + ":woman_pilot_tone4:": "\U0001f469\U0001f3fe\u200d\u2708\ufe0f", + ":woman_pilot_tone5:": "\U0001f469\U0001f3ff\u200d\u2708\ufe0f", + ":woman_playing_handball:": "\U0001f93e\U0000200d\U00002640\U0000fe0f", + ":woman_playing_handball_tone1:": "\U0001f93e\U0001f3fb\u200d\u2640\ufe0f", + ":woman_playing_handball_tone2:": "\U0001f93e\U0001f3fc\u200d\u2640\ufe0f", + ":woman_playing_handball_tone3:": "\U0001f93e\U0001f3fd\u200d\u2640\ufe0f", + ":woman_playing_handball_tone4:": "\U0001f93e\U0001f3fe\u200d\u2640\ufe0f", + ":woman_playing_handball_tone5:": "\U0001f93e\U0001f3ff\u200d\u2640\ufe0f", + ":woman_playing_water_polo:": "\U0001f93d\U0000200d\U00002640\U0000fe0f", + ":woman_playing_water_polo_tone1:": "\U0001f93d\U0001f3fb\u200d\u2640\ufe0f", + ":woman_playing_water_polo_tone2:": "\U0001f93d\U0001f3fc\u200d\u2640\ufe0f", + ":woman_playing_water_polo_tone3:": "\U0001f93d\U0001f3fd\u200d\u2640\ufe0f", + ":woman_playing_water_polo_tone4:": "\U0001f93d\U0001f3fe\u200d\u2640\ufe0f", + ":woman_playing_water_polo_tone5:": "\U0001f93d\U0001f3ff\u200d\u2640\ufe0f", + ":woman_police_officer:": "\U0001f46e\U0000200d\U00002640\U0000fe0f", + ":woman_police_officer_tone1:": "\U0001f46e\U0001f3fb\u200d\u2640\ufe0f", + ":woman_police_officer_tone2:": "\U0001f46e\U0001f3fc\u200d\u2640\ufe0f", + ":woman_police_officer_tone3:": "\U0001f46e\U0001f3fd\u200d\u2640\ufe0f", + ":woman_police_officer_tone4:": "\U0001f46e\U0001f3fe\u200d\u2640\ufe0f", + ":woman_police_officer_tone5:": "\U0001f46e\U0001f3ff\u200d\u2640\ufe0f", + ":woman_pouting:": "\U0001f64e\U0000200d\U00002640\U0000fe0f", + ":woman_pouting_tone1:": "\U0001f64e\U0001f3fb\u200d\u2640\ufe0f", + ":woman_pouting_tone2:": "\U0001f64e\U0001f3fc\u200d\u2640\ufe0f", + ":woman_pouting_tone3:": "\U0001f64e\U0001f3fd\u200d\u2640\ufe0f", + ":woman_pouting_tone4:": "\U0001f64e\U0001f3fe\u200d\u2640\ufe0f", + ":woman_pouting_tone5:": "\U0001f64e\U0001f3ff\u200d\u2640\ufe0f", + ":woman_raising_hand:": "\U0001f64b\U0000200d\U00002640\U0000fe0f", + ":woman_raising_hand_tone1:": "\U0001f64b\U0001f3fb\u200d\u2640\ufe0f", + ":woman_raising_hand_tone2:": "\U0001f64b\U0001f3fc\u200d\u2640\ufe0f", + ":woman_raising_hand_tone3:": "\U0001f64b\U0001f3fd\u200d\u2640\ufe0f", + ":woman_raising_hand_tone4:": "\U0001f64b\U0001f3fe\u200d\u2640\ufe0f", + ":woman_raising_hand_tone5:": "\U0001f64b\U0001f3ff\u200d\u2640\ufe0f", + ":woman_red_hair:": "\U0001f469\U0000200d\U0001f9b0", + ":woman_rowing_boat:": "\U0001f6a3\U0000200d\U00002640\U0000fe0f", + ":woman_rowing_boat_tone1:": "\U0001f6a3\U0001f3fb\u200d\u2640\ufe0f", + ":woman_rowing_boat_tone2:": "\U0001f6a3\U0001f3fc\u200d\u2640\ufe0f", + ":woman_rowing_boat_tone3:": "\U0001f6a3\U0001f3fd\u200d\u2640\ufe0f", + ":woman_rowing_boat_tone4:": "\U0001f6a3\U0001f3fe\u200d\u2640\ufe0f", + ":woman_rowing_boat_tone5:": "\U0001f6a3\U0001f3ff\u200d\u2640\ufe0f", + ":woman_running:": "\U0001f3c3\U0000200d\U00002640\U0000fe0f", + ":woman_running_tone1:": "\U0001f3c3\U0001f3fb\u200d\u2640\ufe0f", + ":woman_running_tone2:": "\U0001f3c3\U0001f3fc\u200d\u2640\ufe0f", + ":woman_running_tone3:": "\U0001f3c3\U0001f3fd\u200d\u2640\ufe0f", + ":woman_running_tone4:": "\U0001f3c3\U0001f3fe\u200d\u2640\ufe0f", + ":woman_running_tone5:": "\U0001f3c3\U0001f3ff\u200d\u2640\ufe0f", + ":woman_scientist:": "\U0001f469\U0000200d\U0001f52c", + ":woman_scientist_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f52c", + ":woman_scientist_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f52c", + ":woman_scientist_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f52c", + ":woman_scientist_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f52c", + ":woman_scientist_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f52c", + ":woman_shrugging:": "\U0001f937\U0000200d\U00002640\U0000fe0f", + ":woman_shrugging_tone1:": "\U0001f937\U0001f3fb\u200d\u2640\ufe0f", + ":woman_shrugging_tone2:": "\U0001f937\U0001f3fc\u200d\u2640\ufe0f", + ":woman_shrugging_tone3:": "\U0001f937\U0001f3fd\u200d\u2640\ufe0f", + ":woman_shrugging_tone4:": "\U0001f937\U0001f3fe\u200d\u2640\ufe0f", + ":woman_shrugging_tone5:": "\U0001f937\U0001f3ff\u200d\u2640\ufe0f", + ":woman_singer:": "\U0001f469\U0000200d\U0001f3a4", + ":woman_singer_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f3a4", + ":woman_singer_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f3a4", + ":woman_singer_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f3a4", + ":woman_singer_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f3a4", + ":woman_singer_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f3a4", + ":woman_student:": "\U0001f469\U0000200d\U0001f393", + ":woman_student_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f393", + ":woman_student_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f393", + ":woman_student_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f393", + ":woman_student_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f393", + ":woman_student_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f393", + ":woman_superhero:": "\U0001f9b8\U0000200d\U00002640\U0000fe0f", + ":woman_supervillain:": "\U0001f9b9\U0000200d\U00002640\U0000fe0f", + ":woman_surfing:": "\U0001f3c4\U0000200d\U00002640\U0000fe0f", + ":woman_surfing_tone1:": "\U0001f3c4\U0001f3fb\u200d\u2640\ufe0f", + ":woman_surfing_tone2:": "\U0001f3c4\U0001f3fc\u200d\u2640\ufe0f", + ":woman_surfing_tone3:": "\U0001f3c4\U0001f3fd\u200d\u2640\ufe0f", + ":woman_surfing_tone4:": "\U0001f3c4\U0001f3fe\u200d\u2640\ufe0f", + ":woman_surfing_tone5:": "\U0001f3c4\U0001f3ff\u200d\u2640\ufe0f", + ":woman_swimming:": "\U0001f3ca\U0000200d\U00002640\U0000fe0f", + ":woman_swimming_tone1:": "\U0001f3ca\U0001f3fb\u200d\u2640\ufe0f", + ":woman_swimming_tone2:": "\U0001f3ca\U0001f3fc\u200d\u2640\ufe0f", + ":woman_swimming_tone3:": "\U0001f3ca\U0001f3fd\u200d\u2640\ufe0f", + ":woman_swimming_tone4:": "\U0001f3ca\U0001f3fe\u200d\u2640\ufe0f", + ":woman_swimming_tone5:": "\U0001f3ca\U0001f3ff\u200d\u2640\ufe0f", + ":woman_teacher:": "\U0001f469\U0000200d\U0001f3eb", + ":woman_teacher_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f3eb", + ":woman_teacher_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f3eb", + ":woman_teacher_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f3eb", + ":woman_teacher_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f3eb", + ":woman_teacher_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f3eb", + ":woman_technologist:": "\U0001f469\U0000200d\U0001f4bb", + ":woman_technologist_tone1:": "\U0001f469\U0001f3fb\u200d\U0001f4bb", + ":woman_technologist_tone2:": "\U0001f469\U0001f3fc\u200d\U0001f4bb", + ":woman_technologist_tone3:": "\U0001f469\U0001f3fd\u200d\U0001f4bb", + ":woman_technologist_tone4:": "\U0001f469\U0001f3fe\u200d\U0001f4bb", + ":woman_technologist_tone5:": "\U0001f469\U0001f3ff\u200d\U0001f4bb", + ":woman_tipping_hand:": "\U0001f481\U0000200d\U00002640\U0000fe0f", + ":woman_tipping_hand_tone1:": "\U0001f481\U0001f3fb\u200d\u2640\ufe0f", + ":woman_tipping_hand_tone2:": "\U0001f481\U0001f3fc\u200d\u2640\ufe0f", + ":woman_tipping_hand_tone3:": "\U0001f481\U0001f3fd\u200d\u2640\ufe0f", + ":woman_tipping_hand_tone4:": "\U0001f481\U0001f3fe\u200d\u2640\ufe0f", + ":woman_tipping_hand_tone5:": "\U0001f481\U0001f3ff\u200d\u2640\ufe0f", + ":woman_tone1:": "\U0001f469\U0001f3fb", + ":woman_tone2:": "\U0001f469\U0001f3fc", + ":woman_tone3:": "\U0001f469\U0001f3fd", + ":woman_tone4:": "\U0001f469\U0001f3fe", + ":woman_tone5:": "\U0001f469\U0001f3ff", + ":woman_vampire:": "\U0001f9db\U0000200d\U00002640\U0000fe0f", + ":woman_vampire_tone1:": "\U0001f9db\U0001f3fb\u200d\u2640\ufe0f", + ":woman_vampire_tone2:": "\U0001f9db\U0001f3fc\u200d\u2640\ufe0f", + ":woman_vampire_tone3:": "\U0001f9db\U0001f3fd\u200d\u2640\ufe0f", + ":woman_vampire_tone4:": "\U0001f9db\U0001f3fe\u200d\u2640\ufe0f", + ":woman_vampire_tone5:": "\U0001f9db\U0001f3ff\u200d\u2640\ufe0f", + ":woman_walking:": "\U0001f6b6\U0000200d\U00002640\U0000fe0f", + ":woman_walking_tone1:": "\U0001f6b6\U0001f3fb\u200d\u2640\ufe0f", + ":woman_walking_tone2:": "\U0001f6b6\U0001f3fc\u200d\u2640\ufe0f", + ":woman_walking_tone3:": "\U0001f6b6\U0001f3fd\u200d\u2640\ufe0f", + ":woman_walking_tone4:": "\U0001f6b6\U0001f3fe\u200d\u2640\ufe0f", + ":woman_walking_tone5:": "\U0001f6b6\U0001f3ff\u200d\u2640\ufe0f", + ":woman_wearing_turban:": "\U0001f473\U0000200d\U00002640\U0000fe0f", + ":woman_wearing_turban_tone1:": "\U0001f473\U0001f3fb\u200d\u2640\ufe0f", + ":woman_wearing_turban_tone2:": "\U0001f473\U0001f3fc\u200d\u2640\ufe0f", + ":woman_wearing_turban_tone3:": "\U0001f473\U0001f3fd\u200d\u2640\ufe0f", + ":woman_wearing_turban_tone4:": "\U0001f473\U0001f3fe\u200d\u2640\ufe0f", + ":woman_wearing_turban_tone5:": "\U0001f473\U0001f3ff\u200d\u2640\ufe0f", + ":woman_white_hair:": "\U0001f469\U0000200d\U0001f9b3", + ":woman_with_headscarf:": "\U0001f9d5", + ":woman_with_headscarf_tone1:": "\U0001f9d5\U0001f3fb", + ":woman_with_headscarf_tone2:": "\U0001f9d5\U0001f3fc", + ":woman_with_headscarf_tone3:": "\U0001f9d5\U0001f3fd", + ":woman_with_headscarf_tone4:": "\U0001f9d5\U0001f3fe", + ":woman_with_headscarf_tone5:": "\U0001f9d5\U0001f3ff", + ":woman_with_turban:": "\U0001f473\u200d\u2640", + ":woman_zombie:": "\U0001f9df\U0000200d\U00002640\U0000fe0f", + ":womans_clothes:": "\U0001f45a", + ":womans_hat:": "\U0001f452", + ":woman’s_boot:": "\U0001f462", + ":woman’s_clothes:": "\U0001f45a", + ":woman’s_hat:": "\U0001f452", + ":woman’s_sandal:": "\U0001f461", + ":women_holding_hands:": "\U0001f46d", + ":women_with_bunny_ears:": "\U0001f46f\U0000200d\U00002640\U0000fe0f", + ":women_with_bunny_ears_partying:": "\U0001f46f\u200d\u2640\ufe0f", + ":women_wrestling:": "\U0001f93c\U0000200d\U00002640\U0000fe0f", + ":womens:": "\U0001f6ba", + ":women’s_room:": "\U0001f6ba", + ":woozy_face:": "\U0001f974", + ":world_map:": "\U0001f5fa", + ":worried:": "\U0001f61f", + ":worried_face:": "\U0001f61f", + ":wrapped_gift:": "\U0001f381", + ":wrench:": "\U0001f527", + ":writing_hand:": "\U0000270d", + ":writing_hand_tone1:": "\u270d\U0001f3fb", + ":writing_hand_tone2:": "\u270d\U0001f3fc", + ":writing_hand_tone3:": "\u270d\U0001f3fd", + ":writing_hand_tone4:": "\u270d\U0001f3fe", + ":writing_hand_tone5:": "\u270d\U0001f3ff", + ":x:": "\u274c", + ":yarn:": "\U0001f9f6", + ":yellow_heart:": "\U0001f49b", + ":yemen:": "\U0001f1fe\U0001f1ea", + ":yen:": "\U0001f4b4", + ":yen_banknote:": "\U0001f4b4", + ":yin_yang:": "\U0000262f", + ":yum:": "\U0001f60b", + ":zambia:": "\U0001f1ff\U0001f1f2", + ":zany_face:": "\U0001f92a", + ":zap:": "\u26a1", + ":zebra:": "\U0001f993", + ":zero:": "0\ufe0f\u20e3", + ":zimbabwe:": "\U0001f1ff\U0001f1fc", + ":zipper-mouth_face:": "\U0001f910", + ":zipper_mouth:": "\U0001f910", + ":zipper_mouth_face:": "\U0001f910", + ":zombie:": "\U0001f9df", + ":zzz:": "\U0001f4a4", +} diff --git a/backend/vendor/github.com/kyokomi/emoji/wercker.yml b/backend/vendor/github.com/kyokomi/emoji/wercker.yml new file mode 100644 index 00000000..16021130 --- /dev/null +++ b/backend/vendor/github.com/kyokomi/emoji/wercker.yml @@ -0,0 +1,25 @@ +box: golang +build: + steps: + - setup-go-workspace + - script: + name: install goveralls + code: | + go get github.com/mattn/goveralls + - script: + name: go get + code: | + go get ./... + - script: + name: go build + code: | + go build ./... + - script: + name: go test + code: | + go test ./... + - script: + name: coveralls + code: | + goveralls -v -service wercker.com -repotoken $COVERALLS_TOKEN + diff --git a/backend/vendor/golang.org/x/crypto/acme/acme.go b/backend/vendor/golang.org/x/crypto/acme/acme.go index 00ee9555..fa365b7b 100644 --- a/backend/vendor/golang.org/x/crypto/acme/acme.go +++ b/backend/vendor/golang.org/x/crypto/acme/acme.go @@ -109,6 +109,13 @@ type Client struct { // The jitter is a random value up to 1 second. RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration + // UserAgent is prepended to the User-Agent header sent to the ACME server, + // which by default is this package's name and version. + // + // Reusable libraries and tools in particular should set this value to be + // identifiable by the server, in case they are causing issues. + UserAgent string + dirMu sync.Mutex // guards writes to dir dir *Directory // cached result of Client's Discover method diff --git a/backend/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/backend/vendor/golang.org/x/crypto/acme/autocert/autocert.go index e562609c..70ab355f 100644 --- a/backend/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ b/backend/vendor/golang.org/x/crypto/acme/autocert/autocert.go @@ -980,6 +980,9 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) { return nil, err } } + if client.UserAgent == "" { + client.UserAgent = "autocert" + } var contact []string if m.Email != "" { contact = []string{"mailto:" + m.Email} diff --git a/backend/vendor/golang.org/x/crypto/acme/http.go b/backend/vendor/golang.org/x/crypto/acme/http.go index a43ce6a5..600d5798 100644 --- a/backend/vendor/golang.org/x/crypto/acme/http.go +++ b/backend/vendor/golang.org/x/crypto/acme/http.go @@ -219,6 +219,7 @@ func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, // doNoRetry issues a request req, replacing its context (if any) with ctx. func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) { + req.Header.Set("User-Agent", c.userAgent()) res, err := c.httpClient().Do(req.WithContext(ctx)) if err != nil { select { @@ -243,6 +244,23 @@ func (c *Client) httpClient() *http.Client { return http.DefaultClient } +// packageVersion is the version of the module that contains this package, for +// sending as part of the User-Agent header. It's set in version_go112.go. +var packageVersion string + +// userAgent returns the User-Agent header value. It includes the package name, +// the module version (if available), and the c.UserAgent value (if set). +func (c *Client) userAgent() string { + ua := "golang.org/x/crypto/acme" + if packageVersion != "" { + ua += "@" + packageVersion + } + if c.UserAgent != "" { + ua = c.UserAgent + " " + ua + } + return ua +} + // isBadNonce reports whether err is an ACME "badnonce" error. func isBadNonce(err error) bool { // According to the spec badNonce is urn:ietf:params:acme:error:badNonce. diff --git a/backend/vendor/golang.org/x/crypto/acme/version_go112.go b/backend/vendor/golang.org/x/crypto/acme/version_go112.go new file mode 100644 index 00000000..b58f2456 --- /dev/null +++ b/backend/vendor/golang.org/x/crypto/acme/version_go112.go @@ -0,0 +1,27 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.12 + +package acme + +import "runtime/debug" + +func init() { + // Set packageVersion if the binary was built in modules mode and x/crypto + // was not replaced with a different module. + info, ok := debug.ReadBuildInfo() + if !ok { + return + } + for _, m := range info.Deps { + if m.Path != "golang.org/x/crypto" { + continue + } + if m.Replace == nil { + packageVersion = m.Version + } + break + } +} diff --git a/backend/vendor/golang.org/x/sys/unix/dirent.go b/backend/vendor/golang.org/x/sys/unix/dirent.go index 4407c505..6f3460e6 100644 --- a/backend/vendor/golang.org/x/sys/unix/dirent.go +++ b/backend/vendor/golang.org/x/sys/unix/dirent.go @@ -6,12 +6,97 @@ package unix -import "syscall" +import "unsafe" + +// readInt returns the size-bytes unsigned integer in native byte order at offset off. +func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { + if len(b) < int(off+size) { + return 0, false + } + if isBigEndian { + return readIntBE(b[off:], size), true + } + return readIntLE(b[off:], size), true +} + +func readIntBE(b []byte, size uintptr) uint64 { + switch size { + case 1: + return uint64(b[0]) + case 2: + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[1]) | uint64(b[0])<<8 + case 4: + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 + case 8: + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + default: + panic("syscall: readInt with unsupported size") + } +} + +func readIntLE(b []byte, size uintptr) uint64 { + switch size { + case 1: + return uint64(b[0]) + case 2: + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 + case 4: + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 + case 8: + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + default: + panic("syscall: readInt with unsupported size") + } +} // ParseDirent parses up to max directory entries in buf, // appending the names to names. It returns the number of // bytes consumed from buf, the number of entries added // to names, and the new names slice. func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { - return syscall.ParseDirent(buf, max, names) + origlen := len(buf) + count = 0 + for max != 0 && len(buf) > 0 { + reclen, ok := direntReclen(buf) + if !ok || reclen > uint64(len(buf)) { + return origlen, count, names + } + rec := buf[:reclen] + buf = buf[reclen:] + ino, ok := direntIno(rec) + if !ok { + break + } + if ino == 0 { // File absent in directory. + continue + } + const namoff = uint64(unsafe.Offsetof(Dirent{}.Name)) + namlen, ok := direntNamlen(rec) + if !ok || namoff+namlen > uint64(len(rec)) { + break + } + name := rec[namoff : namoff+namlen] + for i, c := range name { + if c == 0 { + name = name[:i] + break + } + } + // Check for useless names before allocating a string. + if string(name) == "." || string(name) == ".." { + continue + } + max-- + count++ + names = append(names, string(name)) + } + return origlen - len(buf), count, names } diff --git a/backend/vendor/golang.org/x/sys/unix/mkall.sh b/backend/vendor/golang.org/x/sys/unix/mkall.sh index 80d00707..5a22eca9 100644 --- a/backend/vendor/golang.org/x/sys/unix/mkall.sh +++ b/backend/vendor/golang.org/x/sys/unix/mkall.sh @@ -105,25 +105,25 @@ dragonfly_amd64) freebsd_386) mkerrors="$mkerrors -m32" mksyscall="go run mksyscall.go -l32" - mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; freebsd_amd64) mkerrors="$mkerrors -m64" - mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; freebsd_arm) mkerrors="$mkerrors" mksyscall="go run mksyscall.go -l32 -arm" - mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'" # Let the type of C char be signed for making the bare syscall # API consistent across platforms. mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" ;; freebsd_arm64) mkerrors="$mkerrors -m64" - mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master'" + mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'" mktypes="GOARCH=$GOARCH go tool cgo -godefs" ;; netbsd_386) diff --git a/backend/vendor/golang.org/x/sys/unix/mkerrors.sh b/backend/vendor/golang.org/x/sys/unix/mkerrors.sh index 4c91159c..3d85f279 100644 --- a/backend/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/backend/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -183,6 +183,7 @@ struct ltchars { #include #include #include +#include #include #include #include diff --git a/backend/vendor/golang.org/x/sys/unix/mkpost.go b/backend/vendor/golang.org/x/sys/unix/mkpost.go index 4d5b531b..eb433205 100644 --- a/backend/vendor/golang.org/x/sys/unix/mkpost.go +++ b/backend/vendor/golang.org/x/sys/unix/mkpost.go @@ -50,8 +50,8 @@ func main() { } // Intentionally export __val fields in Fsid and Sigset_t - valRegex := regexp.MustCompile(`type (Fsid|Sigset_t) struct {(\s+)X__val(\s+\S+\s+)}`) - b = valRegex.ReplaceAll(b, []byte("type $1 struct {${2}Val$3}")) + valRegex := regexp.MustCompile(`type (Fsid|Sigset_t) struct {(\s+)X__(bits|val)(\s+\S+\s+)}`) + b = valRegex.ReplaceAll(b, []byte("type $1 struct {${2}Val$4}")) // Intentionally export __fds_bits field in FdSet fdSetRegex := regexp.MustCompile(`type (FdSet) struct {(\s+)X__fds_bits(\s+\S+\s+)}`) diff --git a/backend/vendor/golang.org/x/sys/unix/mksysnum.go b/backend/vendor/golang.org/x/sys/unix/mksysnum.go index 07f8960f..baa6ecd8 100644 --- a/backend/vendor/golang.org/x/sys/unix/mksysnum.go +++ b/backend/vendor/golang.org/x/sys/unix/mksysnum.go @@ -139,7 +139,7 @@ func main() { text += format(name, num, proto) } case "freebsd": - if t.Match(`^([0-9]+)\s+\S+\s+(?:NO)?STD\s+({ \S+\s+(\w+).*)$`) { + if t.Match(`^([0-9]+)\s+\S+\s+(?:(?:NO)?STD|COMPAT10)\s+({ \S+\s+(\w+).*)$`) { num, proto := t.sub[1], t.sub[2] name := fmt.Sprintf("SYS_%s", t.sub[3]) text += format(name, num, proto) diff --git a/backend/vendor/golang.org/x/sys/unix/readdirent_getdents.go b/backend/vendor/golang.org/x/sys/unix/readdirent_getdents.go new file mode 100644 index 00000000..3a90aa6d --- /dev/null +++ b/backend/vendor/golang.org/x/sys/unix/readdirent_getdents.go @@ -0,0 +1,12 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix dragonfly freebsd linux netbsd openbsd + +package unix + +// ReadDirent reads directory entries from fd and writes them into buf. +func ReadDirent(fd int, buf []byte) (n int, err error) { + return Getdents(fd, buf) +} diff --git a/backend/vendor/golang.org/x/sys/unix/readdirent_getdirentries.go b/backend/vendor/golang.org/x/sys/unix/readdirent_getdirentries.go new file mode 100644 index 00000000..5fdae40b --- /dev/null +++ b/backend/vendor/golang.org/x/sys/unix/readdirent_getdirentries.go @@ -0,0 +1,19 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package unix + +import "unsafe" + +// ReadDirent reads directory entries from fd and writes them into buf. +func ReadDirent(fd int, buf []byte) (n int, err error) { + // Final argument is (basep *uintptr) and the syscall doesn't take nil. + // 64 bits should be enough. (32 bits isn't even on 386). Since the + // actual system call is getdirentries64, 64 is a good guess. + // TODO(rsc): Can we use a single global basep for all calls? + var base = (*uintptr)(unsafe.Pointer(new(uint64))) + return Getdirentries(fd, buf, base) +} diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_aix.go b/backend/vendor/golang.org/x/sys/unix/syscall_aix.go index 45e12fb8..1aa065f9 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_aix.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_aix.go @@ -280,8 +280,24 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e return -1, ENOSYS } +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + reclen, ok := direntReclen(buf) + if !ok { + return 0, false + } + return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true +} + //sys getdirent(fd int, buf []byte) (n int, err error) -func ReadDirent(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { return getdirent(fd, buf) } diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_bsd.go b/backend/vendor/golang.org/x/sys/unix/syscall_bsd.go index 33c8b5f0..97a8eef6 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_bsd.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_bsd.go @@ -63,15 +63,6 @@ func Setgroups(gids []int) (err error) { return setgroups(len(a), &a[0]) } -func ReadDirent(fd int, buf []byte) (n int, err error) { - // Final argument is (basep *uintptr) and the syscall doesn't take nil. - // 64 bits should be enough. (32 bits isn't even on 386). Since the - // actual system call is getdirentries64, 64 is a good guess. - // TODO(rsc): Can we use a single global basep for all calls? - var base = (*uintptr)(unsafe.Pointer(new(uint64))) - return Getdirentries(fd, buf, base) -} - // Wait status is 7 bits at bottom, either 0 (exited), // 0x7F (stopped), or a signal number that caused an exit. // The 0x80 bit is whether there was a core dump. @@ -86,6 +77,7 @@ const ( shift = 8 exited = 0 + killed = 9 stopped = 0x7F ) @@ -112,6 +104,8 @@ func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 } func (w WaitStatus) Stopped() bool { return w&mask == stopped && syscall.Signal(w>>shift) != SIGSTOP } +func (w WaitStatus) Killed() bool { return w&mask == killed && syscall.Signal(w>>shift) != SIGKILL } + func (w WaitStatus) Continued() bool { return w&mask == stopped && syscall.Signal(w>>shift) == SIGSTOP } func (w WaitStatus) StopSignal() syscall.Signal { diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_darwin.go b/backend/vendor/golang.org/x/sys/unix/syscall_darwin.go index 21200918..216b4ac9 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -77,6 +77,18 @@ func nametomib(name string) (mib []_C_int, err error) { return buf[0 : n/siz], nil } +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) +} + //sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) } func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) } diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/backend/vendor/golang.org/x/sys/unix/syscall_dragonfly.go index 962eee30..260a400f 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_dragonfly.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_dragonfly.go @@ -57,6 +57,22 @@ func nametomib(name string) (mib []_C_int, err error) { return buf[0 : n/siz], nil } +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) +} + +func direntReclen(buf []byte) (uint64, bool) { + namlen, ok := direntNamlen(buf) + if !ok { + return 0, false + } + return (16 + namlen + 1 + 7) &^ 7, true +} + +func direntNamlen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) +} + //sysnb pipe() (r int, w int, err error) func Pipe(p []int) (err error) { @@ -269,6 +285,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e //sys Fstatfs(fd int, stat *Statfs_t) (err error) //sys Fsync(fd int) (err error) //sys Ftruncate(fd int, length int64) (err error) +//sys Getdents(fd int, buf []byte) (n int, err error) //sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) //sys Getdtablesize() (size int) //sysnb Getegid() (egid int) diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_freebsd.go b/backend/vendor/golang.org/x/sys/unix/syscall_freebsd.go index f135812a..329d240b 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_freebsd.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_freebsd.go @@ -82,6 +82,18 @@ func nametomib(name string) (mib []_C_int, err error) { return buf[0 : n/siz], nil } +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) +} + func Pipe(p []int) (err error) { return Pipe2(p, 0) } @@ -362,7 +374,21 @@ func Getdents(fd int, buf []byte) (n int, err error) { func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { if supportsABI(_ino64First) { - return getdirentries_freebsd12(fd, buf, basep) + if basep == nil || unsafe.Sizeof(*basep) == 8 { + return getdirentries_freebsd12(fd, buf, (*uint64)(unsafe.Pointer(basep))) + } + // The freebsd12 syscall needs a 64-bit base. On 32-bit machines + // we can't just use the basep passed in. See #32498. + var base uint64 = uint64(*basep) + n, err = getdirentries_freebsd12(fd, buf, &base) + *basep = uintptr(base) + if base>>32 != 0 { + // We can't stuff the base back into a uintptr, so any + // future calls would be suspect. Generate an error. + // EIO is allowed by getdirentries. + err = EIO + } + return } // The old syscall entries are smaller than the new. Use 1/4 of the original @@ -507,6 +533,70 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e return sendfile(outfd, infd, offset, count) } +//sys ptrace(request int, pid int, addr uintptr, data int) (err error) + +func PtraceAttach(pid int) (err error) { + return ptrace(PTRACE_ATTACH, pid, 0, 0) +} + +func PtraceCont(pid int, signal int) (err error) { + return ptrace(PTRACE_CONT, pid, 1, signal) +} + +func PtraceDetach(pid int) (err error) { + return ptrace(PTRACE_DETACH, pid, 1, 0) +} + +func PtraceGetFpRegs(pid int, fpregsout *FpReg) (err error) { + return ptrace(PTRACE_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0) +} + +func PtraceGetFsBase(pid int, fsbase *int64) (err error) { + return ptrace(PTRACE_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0) +} + +func PtraceGetRegs(pid int, regsout *Reg) (err error) { + return ptrace(PTRACE_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0) +} + +func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { + ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint(countin)} + err = ptrace(PTRACE_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) + return int(ioDesc.Len), err +} + +func PtraceLwpEvents(pid int, enable int) (err error) { + return ptrace(PTRACE_LWPEVENTS, pid, 0, enable) +} + +func PtraceLwpInfo(pid int, info uintptr) (err error) { + return ptrace(PTRACE_LWPINFO, pid, info, int(unsafe.Sizeof(PtraceLwpInfoStruct{}))) +} + +func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) { + return PtraceIO(PIOD_READ_D, pid, addr, out, SizeofLong) +} + +func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) { + return PtraceIO(PIOD_READ_I, pid, addr, out, SizeofLong) +} + +func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) { + return PtraceIO(PIOD_WRITE_D, pid, addr, data, SizeofLong) +} + +func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) { + return PtraceIO(PIOD_WRITE_I, pid, addr, data, SizeofLong) +} + +func PtraceSetRegs(pid int, regs *Reg) (err error) { + return ptrace(PTRACE_SETREGS, pid, uintptr(unsafe.Pointer(regs)), 0) +} + +func PtraceSingleStep(pid int) (err error) { + return ptrace(PTRACE_SINGLESTEP, pid, 1, 0) +} + /* * Exposed directly */ @@ -555,7 +645,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e //sys Fsync(fd int) (err error) //sys Ftruncate(fd int, length int64) (err error) //sys getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) -//sys getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) +//sys getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) //sys Getdtablesize() (size int) //sysnb Getegid() (egid int) //sysnb Geteuid() (uid int) diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_linux.go b/backend/vendor/golang.org/x/sys/unix/syscall_linux.go index c92545ea..637b5017 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -13,7 +13,6 @@ package unix import ( "encoding/binary" - "net" "runtime" "syscall" "unsafe" @@ -765,7 +764,7 @@ const px_proto_oe = 0 type SockaddrPPPoE struct { SID uint16 - Remote net.HardwareAddr + Remote []byte Dev string raw RawSockaddrPPPoX } @@ -916,7 +915,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { } sa := &SockaddrPPPoE{ SID: binary.BigEndian.Uint16(pp[6:8]), - Remote: net.HardwareAddr(pp[8:14]), + Remote: pp[8:14], } for i := 14; i < 14+IFNAMSIZ; i++ { if pp[i] == 0 { @@ -1414,8 +1413,20 @@ func Reboot(cmd int) (err error) { return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "") } -func ReadDirent(fd int, buf []byte) (n int, err error) { - return Getdents(fd, buf) +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + reclen, ok := direntReclen(buf) + if !ok { + return 0, false + } + return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true } //sys mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) @@ -1450,6 +1461,8 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e //sys Acct(path string) (err error) //sys AddKey(keyType string, description string, payload []byte, ringid int) (id int, err error) //sys Adjtimex(buf *Timex) (state int, err error) +//sys Capget(hdr *CapUserHeader, data *CapUserData) (err error) +//sys Capset(hdr *CapUserHeader, data *CapUserData) (err error) //sys Chdir(path string) (err error) //sys Chroot(path string) (err error) //sys ClockGetres(clockid int32, res *Timespec) (err error) @@ -1755,8 +1768,6 @@ func OpenByHandleAt(mountFD int, handle FileHandle, flags int) (fd int, err erro // Alarm // ArchPrctl // Brk -// Capget -// Capset // ClockNanosleep // ClockSettime // Clone diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/backend/vendor/golang.org/x/sys/unix/syscall_netbsd.go index 5240e16e..5ef30904 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_netbsd.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_netbsd.go @@ -94,6 +94,18 @@ func nametomib(name string) (mib []_C_int, err error) { return mib, nil } +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) +} + func SysctlClockinfo(name string) (*Clockinfo, error) { mib, err := sysctlmib(name) if err != nil { @@ -120,9 +132,30 @@ func Pipe(p []int) (err error) { return } -//sys getdents(fd int, buf []byte) (n int, err error) +//sys Getdents(fd int, buf []byte) (n int, err error) func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - return getdents(fd, buf) + n, err = Getdents(fd, buf) + if err != nil || basep == nil { + return + } + + var off int64 + off, err = Seek(fd, 0, 1 /* SEEK_CUR */) + if err != nil { + *basep = ^uintptr(0) + return + } + *basep = uintptr(off) + if unsafe.Sizeof(*basep) == 8 { + return + } + if off>>32 != 0 { + // We can't stuff the offset back into a uintptr, so any + // future calls would be suspect. Generate an error. + // EIO is allowed by getdirentries. + err = EIO + } + return } const ImplementsGetwd = true diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/backend/vendor/golang.org/x/sys/unix/syscall_openbsd.go index c8648ec0..1a074b2f 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_openbsd.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_openbsd.go @@ -43,6 +43,18 @@ func nametomib(name string) (mib []_C_int, err error) { return nil, EINVAL } +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) +} + func SysctlClockinfo(name string) (*Clockinfo, error) { mib, err := sysctlmib(name) if err != nil { @@ -89,9 +101,30 @@ func Pipe(p []int) (err error) { return } -//sys getdents(fd int, buf []byte) (n int, err error) +//sys Getdents(fd int, buf []byte) (n int, err error) func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { - return getdents(fd, buf) + n, err = Getdents(fd, buf) + if err != nil || basep == nil { + return + } + + var off int64 + off, err = Seek(fd, 0, 1 /* SEEK_CUR */) + if err != nil { + *basep = ^uintptr(0) + return + } + *basep = uintptr(off) + if unsafe.Sizeof(*basep) == 8 { + return + } + if off>>32 != 0 { + // We can't stuff the offset back into a uintptr, so any + // future calls would be suspect. Generate an error. + // EIO was allowed by getdirentries. + err = EIO + } + return } const ImplementsGetwd = true diff --git a/backend/vendor/golang.org/x/sys/unix/syscall_solaris.go b/backend/vendor/golang.org/x/sys/unix/syscall_solaris.go index e4780127..0153a316 100644 --- a/backend/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/backend/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -35,6 +35,22 @@ type SockaddrDatalink struct { raw RawSockaddrDatalink } +func direntIno(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) +} + +func direntReclen(buf []byte) (uint64, bool) { + return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) +} + +func direntNamlen(buf []byte) (uint64, bool) { + reclen, ok := direntReclen(buf) + if !ok { + return 0, false + } + return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true +} + //sysnb pipe(p *[2]_C_int) (n int, err error) func Pipe(p []int) (err error) { @@ -189,6 +205,7 @@ func Setgroups(gids []int) (err error) { return setgroups(len(a), &a[0]) } +// ReadDirent reads directory entries from fd and writes them into buf. func ReadDirent(fd int, buf []byte) (n int, err error) { // Final argument is (basep *uintptr) and the syscall doesn't take nil. // TODO(rsc): Can we use a single global basep for all calls? diff --git a/backend/vendor/golang.org/x/sys/unix/types_freebsd.go b/backend/vendor/golang.org/x/sys/unix/types_freebsd.go index 74707989..a121dc33 100644 --- a/backend/vendor/golang.org/x/sys/unix/types_freebsd.go +++ b/backend/vendor/golang.org/x/sys/unix/types_freebsd.go @@ -243,11 +243,55 @@ const ( // Ptrace requests const ( - PTRACE_TRACEME = C.PT_TRACE_ME - PTRACE_CONT = C.PT_CONTINUE - PTRACE_KILL = C.PT_KILL + PTRACE_ATTACH = C.PT_ATTACH + PTRACE_CONT = C.PT_CONTINUE + PTRACE_DETACH = C.PT_DETACH + PTRACE_GETFPREGS = C.PT_GETFPREGS + PTRACE_GETFSBASE = C.PT_GETFSBASE + PTRACE_GETLWPLIST = C.PT_GETLWPLIST + PTRACE_GETNUMLWPS = C.PT_GETNUMLWPS + PTRACE_GETREGS = C.PT_GETREGS + PTRACE_GETXSTATE = C.PT_GETXSTATE + PTRACE_IO = C.PT_IO + PTRACE_KILL = C.PT_KILL + PTRACE_LWPEVENTS = C.PT_LWP_EVENTS + PTRACE_LWPINFO = C.PT_LWPINFO + PTRACE_SETFPREGS = C.PT_SETFPREGS + PTRACE_SETREGS = C.PT_SETREGS + PTRACE_SINGLESTEP = C.PT_STEP + PTRACE_TRACEME = C.PT_TRACE_ME ) +const ( + PIOD_READ_D = C.PIOD_READ_D + PIOD_WRITE_D = C.PIOD_WRITE_D + PIOD_READ_I = C.PIOD_READ_I + PIOD_WRITE_I = C.PIOD_WRITE_I +) + +const ( + PL_FLAG_BORN = C.PL_FLAG_BORN + PL_FLAG_EXITED = C.PL_FLAG_EXITED + PL_FLAG_SI = C.PL_FLAG_SI +) + +const ( + TRAP_BRKPT = C.TRAP_BRKPT + TRAP_TRACE = C.TRAP_TRACE +) + +type PtraceLwpInfoStruct C.struct_ptrace_lwpinfo + +type __Siginfo C.struct___siginfo + +type Sigset_t C.sigset_t + +type Reg C.struct_reg + +type FpReg C.struct_fpreg + +type PtraceIoDesc C.struct_ptrace_io_desc + // Events (kqueue, kevent) type Kevent_t C.struct_kevent_freebsd11 diff --git a/backend/vendor/golang.org/x/sys/unix/types_netbsd.go b/backend/vendor/golang.org/x/sys/unix/types_netbsd.go index 2dd4f954..4a96d72c 100644 --- a/backend/vendor/golang.org/x/sys/unix/types_netbsd.go +++ b/backend/vendor/golang.org/x/sys/unix/types_netbsd.go @@ -254,6 +254,7 @@ type Ptmget C.struct_ptmget const ( AT_FDCWD = C.AT_FDCWD + AT_SYMLINK_FOLLOW = C.AT_SYMLINK_FOLLOW AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW ) diff --git a/backend/vendor/golang.org/x/sys/unix/types_openbsd.go b/backend/vendor/golang.org/x/sys/unix/types_openbsd.go index 8aafbe44..775cb57d 100644 --- a/backend/vendor/golang.org/x/sys/unix/types_openbsd.go +++ b/backend/vendor/golang.org/x/sys/unix/types_openbsd.go @@ -241,6 +241,7 @@ type Winsize C.struct_winsize const ( AT_FDCWD = C.AT_FDCWD + AT_SYMLINK_FOLLOW = C.AT_SYMLINK_FOLLOW AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW ) diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 881e69f1..1db2f00d 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 039b007d..8a9d2ead 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index 97ed569a..2e745581 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index d47f3ba6..b1dc633a 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 0ae030ee..ad4d9afb 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 91b49ddd..fe296502 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 7f1ef04e..60887830 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 724a244f..4cf9ddfa 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 25044629..374e3007 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0xff CBAUDEX = 0x0 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index e7c49911..badf1410 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0xff CBAUDEX = 0x0 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 0373d65a..0ce8c7ef 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index b2ed7ee6..47675125 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -334,6 +334,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 58067c52..a46fc9b4 100644 --- a/backend/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/backend/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -337,6 +337,45 @@ const ( CAN_SFF_MASK = 0x7ff CAN_TP16 = 0x3 CAN_TP20 = 0x4 + CAP_AUDIT_CONTROL = 0x1e + CAP_AUDIT_READ = 0x25 + CAP_AUDIT_WRITE = 0x1d + CAP_BLOCK_SUSPEND = 0x24 + CAP_CHOWN = 0x0 + CAP_DAC_OVERRIDE = 0x1 + CAP_DAC_READ_SEARCH = 0x2 + CAP_FOWNER = 0x3 + CAP_FSETID = 0x4 + CAP_IPC_LOCK = 0xe + CAP_IPC_OWNER = 0xf + CAP_KILL = 0x5 + CAP_LAST_CAP = 0x25 + CAP_LEASE = 0x1c + CAP_LINUX_IMMUTABLE = 0x9 + CAP_MAC_ADMIN = 0x21 + CAP_MAC_OVERRIDE = 0x20 + CAP_MKNOD = 0x1b + CAP_NET_ADMIN = 0xc + CAP_NET_BIND_SERVICE = 0xa + CAP_NET_BROADCAST = 0xb + CAP_NET_RAW = 0xd + CAP_SETFCAP = 0x1f + CAP_SETGID = 0x6 + CAP_SETPCAP = 0x8 + CAP_SETUID = 0x7 + CAP_SYSLOG = 0x22 + CAP_SYS_ADMIN = 0x15 + CAP_SYS_BOOT = 0x16 + CAP_SYS_CHROOT = 0x12 + CAP_SYS_MODULE = 0x10 + CAP_SYS_NICE = 0x17 + CAP_SYS_PACCT = 0x14 + CAP_SYS_PTRACE = 0x13 + CAP_SYS_RAWIO = 0x11 + CAP_SYS_RESOURCE = 0x18 + CAP_SYS_TIME = 0x19 + CAP_SYS_TTY_CONFIG = 0x1a + CAP_WAKE_ALARM = 0x23 CBAUD = 0x100f CBAUDEX = 0x1000 CFLUSH = 0xf diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go index ae9f1a21..cdfe9318 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_amd64.go @@ -749,6 +749,23 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Getdents(fd int, buf []byte) (n int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go index 80903e47..a783306b 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_386.go @@ -387,6 +387,16 @@ func pipe2(p *[2]_C_int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ptrace(request int, pid int, addr uintptr, data int) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -1019,7 +1029,7 @@ func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { +func getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go index cd250ff0..f995520d 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_amd64.go @@ -387,6 +387,16 @@ func pipe2(p *[2]_C_int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ptrace(request int, pid int, addr uintptr, data int) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -1019,7 +1029,7 @@ func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { +func getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go index 290a9c2c..d681acd4 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm.go @@ -387,6 +387,16 @@ func pipe2(p *[2]_C_int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ptrace(request int, pid int, addr uintptr, data int) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -1019,7 +1029,7 @@ func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { +func getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go index c6df9d2e..5049b2ed 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_freebsd_arm64.go @@ -404,6 +404,16 @@ func Getcwd(buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func ptrace(request int, pid int, addr uintptr, data int) (err error) { + _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 { @@ -1019,7 +1029,7 @@ func getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) { +func getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go index 81d90a27..c5e46e4c 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go index 0c184586..da8819e4 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go index 18ef8a62..6ad9be6d 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go index 2fba25d0..f8833178 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go index c330f4ff..8eebc6c7 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go index 8e9e0098..ecf62a67 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go index c22d6260..1ba0f7b6 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go index 700a99e9..20012b2f 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go index cec4c106..2b520dea 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go index 677ef5a6..d9f044c9 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go index 565034c5..9feed65e 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go index 7feb2c6b..0a651508 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go index 07655c45..e27f6693 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go @@ -408,6 +408,26 @@ func Adjtimex(buf *Timex) (state int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Capget(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Capset(hdr *CapUserHeader, data *CapUserData) (err error) { + _, _, e1 := Syscall(SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Chdir(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go index 642db767..7e058266 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go @@ -389,7 +389,7 @@ func pipe() (fd1 int, fd2 int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go index 59585fee..d94d076a 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go @@ -389,7 +389,7 @@ func pipe() (fd1 int, fd2 int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go index 6ec31434..cf5bf3d0 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go @@ -389,7 +389,7 @@ func pipe() (fd1 int, fd2 int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go index 603d1443..243a9317 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go @@ -389,7 +389,7 @@ func pipe() (fd1 int, fd2 int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go index 6a489fac..a9532d07 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go @@ -387,7 +387,7 @@ func pipe(p *[2]_C_int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go index 30cba434..0cb9f017 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go @@ -387,7 +387,7 @@ func pipe(p *[2]_C_int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go index fa1beda3..6fc99b54 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -387,7 +387,7 @@ func pipe(p *[2]_C_int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go index eb589904..27878a72 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go @@ -387,7 +387,7 @@ func pipe(p *[2]_C_int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func getdents(fd int, buf []byte) (n int, err error) { +func Getdents(fd int, buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { _p0 = unsafe.Pointer(&buf[0]) diff --git a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go index 55c3a329..9474974b 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go +++ b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_386.go @@ -1,4 +1,4 @@ -// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master +// go run mksysnum.go https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build 386,freebsd @@ -118,8 +118,6 @@ const ( SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); } SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); } SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); } - SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } - SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } SYS_SETFIB = 175 // { int setfib(int fibnum); } SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } SYS_SETGID = 181 // { int setgid(gid_t gid); } @@ -133,10 +131,6 @@ const ( SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } - SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); } - SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence); } - SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, off_t length); } - SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, off_t length); } SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } @@ -164,6 +158,7 @@ const ( SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( struct ffclock_estimate *cest); } SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( struct ffclock_estimate *cest); } + SYS_CLOCK_NANOSLEEP = 244 // { int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp); } SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,int which, clockid_t *clock_id); } SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } @@ -197,13 +192,10 @@ const ( SYS_GETSID = 310 // { int getsid(pid_t pid); } SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } - SYS_AIO_RETURN = 314 // { int aio_return(struct aiocb *aiocbp); } + SYS_AIO_RETURN = 314 // { ssize_t aio_return(struct aiocb *aiocbp); } SYS_AIO_SUSPEND = 315 // { int aio_suspend( struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); } SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } - SYS_OAIO_READ = 318 // { int oaio_read(struct oaiocb *aiocbp); } - SYS_OAIO_WRITE = 319 // { int oaio_write(struct oaiocb *aiocbp); } - SYS_OLIO_LISTIO = 320 // { int olio_listio(int mode, struct oaiocb * const *acb_list, int nent, struct osigevent *sig); } SYS_YIELD = 321 // { int yield(void); } SYS_MLOCKALL = 324 // { int mlockall(int how); } SYS_MUNLOCKALL = 325 // { int munlockall(void); } @@ -236,7 +228,7 @@ const ( SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } - SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } + SYS_AIO_WAITCOMPLETE = 359 // { ssize_t aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } SYS_KQUEUE = 362 // { int kqueue(void); } @@ -258,7 +250,7 @@ const ( SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); } - SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int flags); } + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int mode); } SYS_STATFS = 396 // { int statfs(char *path, struct statfs *buf); } SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } @@ -293,8 +285,6 @@ const ( SYS_THR_EXIT = 431 // { void thr_exit(long *state); } SYS_THR_SELF = 432 // { int thr_self(long *id); } SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } - SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } - SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( const char *path, int attrnamespace, void *data, size_t nbytes); } @@ -400,4 +390,7 @@ const ( SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); } SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); } SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); } + SYS_NUMA_GETAFFINITY = 548 // { int numa_getaffinity(cpuwhich_t which, id_t id, struct vm_domain_policy_entry *policy); } + SYS_NUMA_SETAFFINITY = 549 // { int numa_setaffinity(cpuwhich_t which, id_t id, const struct vm_domain_policy_entry *policy); } + SYS_FDATASYNC = 550 // { int fdatasync(int fd); } ) diff --git a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go index b39be6cb..48a7beae 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_amd64.go @@ -1,4 +1,4 @@ -// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master +// go run mksysnum.go https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build amd64,freebsd @@ -118,8 +118,6 @@ const ( SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); } SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); } SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); } - SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } - SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } SYS_SETFIB = 175 // { int setfib(int fibnum); } SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } SYS_SETGID = 181 // { int setgid(gid_t gid); } @@ -133,10 +131,6 @@ const ( SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } - SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); } - SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence); } - SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, off_t length); } - SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, off_t length); } SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } @@ -164,6 +158,7 @@ const ( SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( struct ffclock_estimate *cest); } SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( struct ffclock_estimate *cest); } + SYS_CLOCK_NANOSLEEP = 244 // { int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp); } SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,int which, clockid_t *clock_id); } SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } @@ -197,13 +192,10 @@ const ( SYS_GETSID = 310 // { int getsid(pid_t pid); } SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } - SYS_AIO_RETURN = 314 // { int aio_return(struct aiocb *aiocbp); } + SYS_AIO_RETURN = 314 // { ssize_t aio_return(struct aiocb *aiocbp); } SYS_AIO_SUSPEND = 315 // { int aio_suspend( struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); } SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } - SYS_OAIO_READ = 318 // { int oaio_read(struct oaiocb *aiocbp); } - SYS_OAIO_WRITE = 319 // { int oaio_write(struct oaiocb *aiocbp); } - SYS_OLIO_LISTIO = 320 // { int olio_listio(int mode, struct oaiocb * const *acb_list, int nent, struct osigevent *sig); } SYS_YIELD = 321 // { int yield(void); } SYS_MLOCKALL = 324 // { int mlockall(int how); } SYS_MUNLOCKALL = 325 // { int munlockall(void); } @@ -236,7 +228,7 @@ const ( SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } - SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } + SYS_AIO_WAITCOMPLETE = 359 // { ssize_t aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } SYS_KQUEUE = 362 // { int kqueue(void); } @@ -258,7 +250,7 @@ const ( SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); } - SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int flags); } + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int mode); } SYS_STATFS = 396 // { int statfs(char *path, struct statfs *buf); } SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } @@ -293,8 +285,6 @@ const ( SYS_THR_EXIT = 431 // { void thr_exit(long *state); } SYS_THR_SELF = 432 // { int thr_self(long *id); } SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } - SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } - SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( const char *path, int attrnamespace, void *data, size_t nbytes); } @@ -400,4 +390,7 @@ const ( SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); } SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); } SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); } + SYS_NUMA_GETAFFINITY = 548 // { int numa_getaffinity(cpuwhich_t which, id_t id, struct vm_domain_policy_entry *policy); } + SYS_NUMA_SETAFFINITY = 549 // { int numa_setaffinity(cpuwhich_t which, id_t id, const struct vm_domain_policy_entry *policy); } + SYS_FDATASYNC = 550 // { int fdatasync(int fd); } ) diff --git a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go index 44ffd4ce..4a6dfd4a 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm.go @@ -1,4 +1,4 @@ -// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master +// go run mksysnum.go https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm,freebsd @@ -118,8 +118,6 @@ const ( SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); } SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); } SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); } - SYS_FREEBSD6_PREAD = 173 // { ssize_t freebsd6_pread(int fd, void *buf, size_t nbyte, int pad, off_t offset); } - SYS_FREEBSD6_PWRITE = 174 // { ssize_t freebsd6_pwrite(int fd, const void *buf, size_t nbyte, int pad, off_t offset); } SYS_SETFIB = 175 // { int setfib(int fibnum); } SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } SYS_SETGID = 181 // { int setgid(gid_t gid); } @@ -133,10 +131,6 @@ const ( SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } - SYS_FREEBSD6_MMAP = 197 // { caddr_t freebsd6_mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); } - SYS_FREEBSD6_LSEEK = 199 // { off_t freebsd6_lseek(int fd, int pad, off_t offset, int whence); } - SYS_FREEBSD6_TRUNCATE = 200 // { int freebsd6_truncate(char *path, int pad, off_t length); } - SYS_FREEBSD6_FTRUNCATE = 201 // { int freebsd6_ftruncate(int fd, int pad, off_t length); } SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } @@ -164,6 +158,7 @@ const ( SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( struct ffclock_estimate *cest); } SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( struct ffclock_estimate *cest); } + SYS_CLOCK_NANOSLEEP = 244 // { int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp); } SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,int which, clockid_t *clock_id); } SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } @@ -197,13 +192,10 @@ const ( SYS_GETSID = 310 // { int getsid(pid_t pid); } SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } - SYS_AIO_RETURN = 314 // { int aio_return(struct aiocb *aiocbp); } + SYS_AIO_RETURN = 314 // { ssize_t aio_return(struct aiocb *aiocbp); } SYS_AIO_SUSPEND = 315 // { int aio_suspend( struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); } SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } - SYS_OAIO_READ = 318 // { int oaio_read(struct oaiocb *aiocbp); } - SYS_OAIO_WRITE = 319 // { int oaio_write(struct oaiocb *aiocbp); } - SYS_OLIO_LISTIO = 320 // { int olio_listio(int mode, struct oaiocb * const *acb_list, int nent, struct osigevent *sig); } SYS_YIELD = 321 // { int yield(void); } SYS_MLOCKALL = 324 // { int mlockall(int how); } SYS_MUNLOCKALL = 325 // { int munlockall(void); } @@ -236,7 +228,7 @@ const ( SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } - SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } + SYS_AIO_WAITCOMPLETE = 359 // { ssize_t aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } SYS_KQUEUE = 362 // { int kqueue(void); } @@ -258,7 +250,7 @@ const ( SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); } - SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int flags); } + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int mode); } SYS_STATFS = 396 // { int statfs(char *path, struct statfs *buf); } SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } @@ -293,8 +285,6 @@ const ( SYS_THR_EXIT = 431 // { void thr_exit(long *state); } SYS_THR_SELF = 432 // { int thr_self(long *id); } SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } - SYS__UMTX_LOCK = 434 // { int _umtx_lock(struct umtx *umtx); } - SYS__UMTX_UNLOCK = 435 // { int _umtx_unlock(struct umtx *umtx); } SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( const char *path, int attrnamespace, void *data, size_t nbytes); } @@ -400,4 +390,7 @@ const ( SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); } SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); } SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); } + SYS_NUMA_GETAFFINITY = 548 // { int numa_getaffinity(cpuwhich_t which, id_t id, struct vm_domain_policy_entry *policy); } + SYS_NUMA_SETAFFINITY = 549 // { int numa_setaffinity(cpuwhich_t which, id_t id, const struct vm_domain_policy_entry *policy); } + SYS_FDATASYNC = 550 // { int fdatasync(int fd); } ) diff --git a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go index 9f21e955..3e51af8e 100644 --- a/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/zsysnum_freebsd_arm64.go @@ -1,4 +1,4 @@ -// go run mksysnum.go https://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master +// go run mksysnum.go https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master // Code generated by the command above; see README.md. DO NOT EDIT. // +build arm64,freebsd @@ -7,13 +7,13 @@ package unix const ( // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int - SYS_EXIT = 1 // { void sys_exit(int rval); } exit \ + SYS_EXIT = 1 // { void sys_exit(int rval); } exit sys_exit_args void SYS_FORK = 2 // { int fork(void); } - SYS_READ = 3 // { ssize_t read(int fd, void *buf, \ - SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, \ + SYS_READ = 3 // { ssize_t read(int fd, void *buf, size_t nbyte); } + SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, size_t nbyte); } SYS_OPEN = 5 // { int open(char *path, int flags, int mode); } SYS_CLOSE = 6 // { int close(int fd); } - SYS_WAIT4 = 7 // { int wait4(int pid, int *status, \ + SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, struct rusage *rusage); } SYS_LINK = 9 // { int link(char *path, char *link); } SYS_UNLINK = 10 // { int unlink(char *path); } SYS_CHDIR = 12 // { int chdir(char *path); } @@ -21,20 +21,20 @@ const ( SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); } SYS_CHMOD = 15 // { int chmod(char *path, int mode); } SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); } - SYS_OBREAK = 17 // { int obreak(char *nsize); } break \ + SYS_OBREAK = 17 // { int obreak(char *nsize); } break obreak_args int SYS_GETPID = 20 // { pid_t getpid(void); } - SYS_MOUNT = 21 // { int mount(char *type, char *path, \ + SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, caddr_t data); } SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); } SYS_SETUID = 23 // { int setuid(uid_t uid); } SYS_GETUID = 24 // { uid_t getuid(void); } SYS_GETEUID = 25 // { uid_t geteuid(void); } - SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, \ - SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, \ - SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, \ - SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, \ - SYS_ACCEPT = 30 // { int accept(int s, \ - SYS_GETPEERNAME = 31 // { int getpeername(int fdes, \ - SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, \ + SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, int flags); } + SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, int flags, struct sockaddr * __restrict from, __socklen_t * __restrict fromlenaddr); } + SYS_ACCEPT = 30 // { int accept(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen); } + SYS_GETPEERNAME = 31 // { int getpeername(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } + SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); } SYS_ACCESS = 33 // { int access(char *path, int amode); } SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); } SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); } @@ -42,56 +42,57 @@ const ( SYS_KILL = 37 // { int kill(int pid, int signum); } SYS_GETPPID = 39 // { pid_t getppid(void); } SYS_DUP = 41 // { int dup(u_int fd); } + SYS_PIPE = 42 // { int pipe(void); } SYS_GETEGID = 43 // { gid_t getegid(void); } - SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \ - SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, \ + SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, size_t offset, u_int scale); } + SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, int pid); } SYS_GETGID = 47 // { gid_t getgid(void); } - SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int \ + SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); } SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); } SYS_ACCT = 51 // { int acct(char *path); } - SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, \ - SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, \ + SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, stack_t *oss); } + SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); } SYS_REBOOT = 55 // { int reboot(int opt); } SYS_REVOKE = 56 // { int revoke(char *path); } SYS_SYMLINK = 57 // { int symlink(char *path, char *link); } - SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, \ - SYS_EXECVE = 59 // { int execve(char *fname, char **argv, \ - SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args \ + SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, size_t count); } + SYS_EXECVE = 59 // { int execve(char *fname, char **argv, char **envv); } + SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args int SYS_CHROOT = 61 // { int chroot(char *path); } - SYS_MSYNC = 65 // { int msync(void *addr, size_t len, \ + SYS_MSYNC = 65 // { int msync(void *addr, size_t len, int flags); } SYS_VFORK = 66 // { int vfork(void); } SYS_SBRK = 69 // { int sbrk(int incr); } SYS_SSTK = 70 // { int sstk(int incr); } - SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise \ + SYS_OVADVISE = 72 // { int ovadvise(int anom); } vadvise ovadvise_args int SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); } - SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, \ - SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, \ - SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \ - SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, \ - SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, \ + SYS_MPROTECT = 74 // { int mprotect(const void *addr, size_t len, int prot); } + SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, int behav); } + SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, char *vec); } + SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); } SYS_GETPGRP = 81 // { int getpgrp(void); } SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); } - SYS_SETITIMER = 83 // { int setitimer(u_int which, struct \ + SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } SYS_SWAPON = 85 // { int swapon(char *name); } - SYS_GETITIMER = 86 // { int getitimer(u_int which, \ + SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); } SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); } SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); } SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); } - SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \ + SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); } SYS_FSYNC = 95 // { int fsync(int fd); } - SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, \ - SYS_SOCKET = 97 // { int socket(int domain, int type, \ - SYS_CONNECT = 98 // { int connect(int s, caddr_t name, \ + SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, int prio); } + SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); } + SYS_CONNECT = 98 // { int connect(int s, caddr_t name, int namelen); } SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); } - SYS_BIND = 104 // { int bind(int s, caddr_t name, \ - SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \ + SYS_BIND = 104 // { int bind(int s, caddr_t name, int namelen); } + SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, int valsize); } SYS_LISTEN = 106 // { int listen(int s, int backlog); } - SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \ - SYS_GETRUSAGE = 117 // { int getrusage(int who, \ - SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \ - SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, \ - SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \ - SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \ + SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); } + SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, int *avalsize); } + SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); } SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); } SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); } SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); } @@ -99,24 +100,24 @@ const ( SYS_RENAME = 128 // { int rename(char *from, char *to); } SYS_FLOCK = 131 // { int flock(int fd, int how); } SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); } - SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \ + SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, int tolen); } SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); } - SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, \ + SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); } SYS_MKDIR = 136 // { int mkdir(char *path, int mode); } SYS_RMDIR = 137 // { int rmdir(char *path); } - SYS_UTIMES = 138 // { int utimes(char *path, \ - SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \ + SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); } + SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); } SYS_SETSID = 147 // { int setsid(void); } - SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \ + SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, caddr_t arg); } SYS_NLM_SYSCALL = 154 // { int nlm_syscall(int debug_level, int grace_period, int addr_count, char **addrs); } SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); } - SYS_LGETFH = 160 // { int lgetfh(char *fname, \ - SYS_GETFH = 161 // { int getfh(char *fname, \ + SYS_LGETFH = 160 // { int lgetfh(char *fname, struct fhandle *fhp); } + SYS_GETFH = 161 // { int getfh(char *fname, struct fhandle *fhp); } SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); } - SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \ - SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, \ - SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, \ - SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, \ + SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, struct rtprio *rtp); } + SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); } + SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); } + SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); } SYS_SETFIB = 175 // { int setfib(int fibnum); } SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); } SYS_SETGID = 181 // { int setgid(gid_t gid); } @@ -127,269 +128,269 @@ const ( SYS_LSTAT = 190 // { int lstat(char *path, struct stat *ub); } SYS_PATHCONF = 191 // { int pathconf(char *path, int name); } SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); } - SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \ - SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \ - SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, \ - SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, \ + SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int + SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int + SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); } + SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); } SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); } SYS_UNDELETE = 205 // { int undelete(char *path); } SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); } SYS_GETPGID = 207 // { int getpgid(pid_t pid); } - SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \ - SYS_SEMGET = 221 // { int semget(key_t key, int nsems, \ - SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, \ + SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_SEMGET = 221 // { int semget(key_t key, int nsems, int semflg); } + SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, size_t nsops); } SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); } - SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, \ - SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, \ - SYS_SHMAT = 228 // { int shmat(int shmid, const void *shmaddr, \ + SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + SYS_SHMAT = 228 // { int shmat(int shmid, const void *shmaddr, int shmflg); } SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); } - SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, \ - SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \ - SYS_CLOCK_SETTIME = 233 // { int clock_settime( \ - SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \ - SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, \ + SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, int shmflg); } + SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, struct timespec *tp); } + SYS_CLOCK_SETTIME = 233 // { int clock_settime( clockid_t clock_id, const struct timespec *tp); } + SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, struct timespec *tp); } + SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, struct sigevent *evp, int *timerid); } SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); } - SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, \ - SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct \ + SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); } + SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct itimerspec *value); } SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); } - SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \ + SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); } SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); } - SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \ - SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \ - SYS_CLOCK_NANOSLEEP = 244 // { int clock_nanosleep(clockid_t clock_id, \ - SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\ + SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( struct ffclock_estimate *cest); } + SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( struct ffclock_estimate *cest); } + SYS_CLOCK_NANOSLEEP = 244 // { int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp); } + SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,int which, clockid_t *clock_id); } SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); } - SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \ + SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); } SYS_RFORK = 251 // { int rfork(int flags); } - SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, \ + SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, int timeout); } SYS_ISSETUGID = 253 // { int issetugid(void); } SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); } SYS_AIO_READ = 255 // { int aio_read(struct aiocb *aiocbp); } SYS_AIO_WRITE = 256 // { int aio_write(struct aiocb *aiocbp); } - SYS_LIO_LISTIO = 257 // { int lio_listio(int mode, \ - SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, \ + SYS_LIO_LISTIO = 257 // { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); } + SYS_GETDENTS = 272 // { int getdents(int fd, char *buf, size_t count); } SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); } - SYS_LUTIMES = 276 // { int lutimes(char *path, \ + SYS_LUTIMES = 276 // { int lutimes(char *path, struct timeval *tptr); } SYS_NSTAT = 278 // { int nstat(char *path, struct nstat *ub); } SYS_NFSTAT = 279 // { int nfstat(int fd, struct nstat *sb); } SYS_NLSTAT = 280 // { int nlstat(char *path, struct nstat *ub); } - SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, \ - SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, \ - SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, \ - SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, \ + SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); } + SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); } + SYS_FHSTAT = 299 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); } SYS_MODNEXT = 300 // { int modnext(int modid); } - SYS_MODSTAT = 301 // { int modstat(int modid, \ + SYS_MODSTAT = 301 // { int modstat(int modid, struct module_stat *stat); } SYS_MODFNEXT = 302 // { int modfnext(int modid); } SYS_MODFIND = 303 // { int modfind(const char *name); } SYS_KLDLOAD = 304 // { int kldload(const char *file); } SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); } SYS_KLDFIND = 306 // { int kldfind(const char *file); } SYS_KLDNEXT = 307 // { int kldnext(int fileid); } - SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct \ + SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct kld_file_stat* stat); } SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); } SYS_GETSID = 310 // { int getsid(pid_t pid); } - SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, \ - SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, \ + SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); } + SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); } SYS_AIO_RETURN = 314 // { ssize_t aio_return(struct aiocb *aiocbp); } - SYS_AIO_SUSPEND = 315 // { int aio_suspend( \ - SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, \ + SYS_AIO_SUSPEND = 315 // { int aio_suspend( struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); } + SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); } SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); } SYS_YIELD = 321 // { int yield(void); } SYS_MLOCKALL = 324 // { int mlockall(int how); } SYS_MUNLOCKALL = 325 // { int munlockall(void); } SYS___GETCWD = 326 // { int __getcwd(char *buf, u_int buflen); } - SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, \ - SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct \ - SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int \ + SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); } + SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); } + SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); } SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); } SYS_SCHED_YIELD = 331 // { int sched_yield (void); } SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); } SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); } - SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, \ + SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); } SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); } - SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, \ + SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, void *data); } SYS_JAIL = 338 // { int jail(struct jail *jail); } - SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, \ + SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, sigset_t *oset); } SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); } SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); } - SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, \ - SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, \ - SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \ - SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \ - SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, \ - SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, \ - SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \ - SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, \ - SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \ - SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, \ - SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \ - SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( \ - SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( \ - SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \ - SYS_AIO_WAITCOMPLETE = 359 // { ssize_t aio_waitcomplete( \ - SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \ - SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \ + SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout); } + SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, siginfo_t *info); } + SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, acl_type_t type); } + SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); } + SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); } + SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); } + SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); } + SYS_AIO_WAITCOMPLETE = 359 // { ssize_t aio_waitcomplete( struct aiocb **aiocbp, struct timespec *timeout); } + SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); } + SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); } SYS_KQUEUE = 362 // { int kqueue(void); } - SYS_KEVENT = 363 // { int kevent(int fd, \ - SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, \ - SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, \ - SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, \ + SYS_KEVENT = 363 // { int kevent(int fd, struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } + SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, int attrnamespace, const char *attrname); } SYS___SETUGID = 374 // { int __setugid(int flag); } SYS_EACCESS = 376 // { int eaccess(char *path, int amode); } - SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, \ + SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, unsigned int iovcnt, int flags); } SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); } SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); } - SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, \ - SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, \ - SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, \ - SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, \ - SYS_KENV = 390 // { int kenv(int what, const char *name, \ - SYS_LCHFLAGS = 391 // { int lchflags(const char *path, \ - SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, \ - SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, \ - SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, \ - SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, \ - SYS_STATFS = 396 // { int statfs(char *path, \ + SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, struct mac *mac_p); } + SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, struct mac *mac_p); } + SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, struct mac *mac_p); } + SYS_KENV = 390 // { int kenv(int what, const char *name, char *value, int len); } + SYS_LCHFLAGS = 391 // { int lchflags(const char *path, u_long flags); } + SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); } + SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); } + SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); } + SYS_GETFSSTAT = 395 // { int getfsstat(struct statfs *buf, long bufsize, int mode); } + SYS_STATFS = 396 // { int statfs(char *path, struct statfs *buf); } SYS_FSTATFS = 397 // { int fstatfs(int fd, struct statfs *buf); } - SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, \ + SYS_FHSTATFS = 398 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); } SYS_KSEM_CLOSE = 400 // { int ksem_close(semid_t id); } SYS_KSEM_POST = 401 // { int ksem_post(semid_t id); } SYS_KSEM_WAIT = 402 // { int ksem_wait(semid_t id); } SYS_KSEM_TRYWAIT = 403 // { int ksem_trywait(semid_t id); } - SYS_KSEM_INIT = 404 // { int ksem_init(semid_t *idp, \ - SYS_KSEM_OPEN = 405 // { int ksem_open(semid_t *idp, \ + SYS_KSEM_INIT = 404 // { int ksem_init(semid_t *idp, unsigned int value); } + SYS_KSEM_OPEN = 405 // { int ksem_open(semid_t *idp, const char *name, int oflag, mode_t mode, unsigned int value); } SYS_KSEM_UNLINK = 406 // { int ksem_unlink(const char *name); } SYS_KSEM_GETVALUE = 407 // { int ksem_getvalue(semid_t id, int *val); } SYS_KSEM_DESTROY = 408 // { int ksem_destroy(semid_t id); } - SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, \ - SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, \ - SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, \ - SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( \ - SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( \ - SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( \ - SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, \ - SYS_SIGACTION = 416 // { int sigaction(int sig, \ - SYS_SIGRETURN = 417 // { int sigreturn( \ + SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } + SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, struct mac *mac_p); } + SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, struct mac *mac_p); } + SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link( const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); } + SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link( const char *path, int attrnamespace, const char *attrname); } + SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, char **envv, struct mac *mac_p); } + SYS_SIGACTION = 416 // { int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); } + SYS_SIGRETURN = 417 // { int sigreturn( const struct __ucontext *sigcntxp); } SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); } - SYS_SETCONTEXT = 422 // { int setcontext( \ - SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, \ + SYS_SETCONTEXT = 422 // { int setcontext( const struct __ucontext *ucp); } + SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, const struct __ucontext *ucp); } SYS_SWAPOFF = 424 // { int swapoff(const char *name); } - SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, \ - SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, \ - SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, \ - SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, \ - SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, \ - SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, \ + SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, acl_type_t type); } + SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); } + SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, int *sig); } + SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, int flags); } SYS_THR_EXIT = 431 // { void thr_exit(long *state); } SYS_THR_SELF = 432 // { int thr_self(long *id); } SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); } SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); } - SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, \ - SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( \ - SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( \ - SYS_KSEM_TIMEDWAIT = 441 // { int ksem_timedwait(semid_t id, \ - SYS_THR_SUSPEND = 442 // { int thr_suspend( \ + SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link( const char *path, int attrnamespace, void *data, size_t nbytes); } + SYS_KSEM_TIMEDWAIT = 441 // { int ksem_timedwait(semid_t id, const struct timespec *abstime); } + SYS_THR_SUSPEND = 442 // { int thr_suspend( const struct timespec *timeout); } SYS_THR_WAKE = 443 // { int thr_wake(long id); } SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); } - SYS_AUDIT = 445 // { int audit(const void *record, \ - SYS_AUDITON = 446 // { int auditon(int cmd, void *data, \ + SYS_AUDIT = 445 // { int audit(const void *record, u_int length); } + SYS_AUDITON = 446 // { int auditon(int cmd, void *data, u_int length); } SYS_GETAUID = 447 // { int getauid(uid_t *auid); } SYS_SETAUID = 448 // { int setauid(uid_t *auid); } SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); } SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); } - SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( \ - SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( \ + SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } + SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr( struct auditinfo_addr *auditinfo_addr, u_int length); } SYS_AUDITCTL = 453 // { int auditctl(char *path); } - SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, \ - SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, \ + SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, u_long val, void *uaddr1, void *uaddr2); } + SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, int param_size); } SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); } - SYS_KMQ_OPEN = 457 // { int kmq_open(const char *path, int flags, \ - SYS_KMQ_SETATTR = 458 // { int kmq_setattr(int mqd, \ - SYS_KMQ_TIMEDRECEIVE = 459 // { int kmq_timedreceive(int mqd, \ - SYS_KMQ_TIMEDSEND = 460 // { int kmq_timedsend(int mqd, \ - SYS_KMQ_NOTIFY = 461 // { int kmq_notify(int mqd, \ + SYS_KMQ_OPEN = 457 // { int kmq_open(const char *path, int flags, mode_t mode, const struct mq_attr *attr); } + SYS_KMQ_SETATTR = 458 // { int kmq_setattr(int mqd, const struct mq_attr *attr, struct mq_attr *oattr); } + SYS_KMQ_TIMEDRECEIVE = 459 // { int kmq_timedreceive(int mqd, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout); } + SYS_KMQ_TIMEDSEND = 460 // { int kmq_timedsend(int mqd, const char *msg_ptr, size_t msg_len,unsigned msg_prio, const struct timespec *abs_timeout);} + SYS_KMQ_NOTIFY = 461 // { int kmq_notify(int mqd, const struct sigevent *sigev); } SYS_KMQ_UNLINK = 462 // { int kmq_unlink(const char *path); } SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); } SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); } SYS_AIO_FSYNC = 465 // { int aio_fsync(int op, struct aiocb *aiocbp); } - SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, \ + SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, lwpid_t lwpid, struct rtprio *rtp); } SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); } - SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, \ - SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, \ - SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, \ - SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, \ - SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, \ - SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, \ - SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, \ + SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); } + SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, struct sockaddr * from, __socklen_t *fromlenaddr, struct sctp_sndrcvinfo *sinfo, int *msg_flags); } + SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, size_t nbyte, off_t offset); } + SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, size_t nbyte, off_t offset); } + SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } + SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, int whence); } SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); } SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); } SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); } - SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, \ + SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, mode_t mode); } SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); } SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); } - SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, \ - SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, \ - SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, \ - SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, \ - SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, \ - SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, \ - SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, \ - SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, \ - SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, \ - SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, \ - SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, \ + SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid); } + SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id, cpusetid_t *setid); } + SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, cpuset_t *mask); } + SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, const cpuset_t *mask); } + SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, int flag); } + SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, int flag); } + SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, gid_t gid, int flag); } + SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, char **envv); } + SYS_FSTATAT = 493 // { int fstatat(int fd, char *path, struct stat *buf, int flag); } + SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, struct timeval *times); } + SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, char *path2, int flag); } SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); } SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); } - SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, \ - SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, \ - SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, \ - SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, \ - SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, \ + SYS_MKNODAT = 498 // { int mknodat(int fd, char *path, mode_t mode, dev_t dev); } + SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, mode_t mode); } + SYS_READLINKAT = 500 // { int readlinkat(int fd, char *path, char *buf, size_t bufsize); } + SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, char *new); } + SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, char *path2); } SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); } SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); } SYS_GSSD_SYSCALL = 505 // { int gssd_syscall(char *path); } - SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, \ - SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, \ + SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, unsigned int iovcnt, int flags); } + SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, unsigned int iovcnt, int flags); } SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); } SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); } - SYS___SEMCTL = 510 // { int __semctl(int semid, int semnum, \ - SYS_MSGCTL = 511 // { int msgctl(int msqid, int cmd, \ - SYS_SHMCTL = 512 // { int shmctl(int shmid, int cmd, \ + SYS___SEMCTL = 510 // { int __semctl(int semid, int semnum, int cmd, union semun *arg); } + SYS_MSGCTL = 511 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } + SYS_SHMCTL = 512 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); } - SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, \ + SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, int fd, cap_rights_t *rightsp); } SYS_CAP_ENTER = 516 // { int cap_enter(void); } SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); } SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); } SYS_PDKILL = 519 // { int pdkill(int fd, int signum); } SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); } - SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, \ - SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, \ + SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *sm); } + SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, size_t namelen); } SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); } - SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, \ - SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, \ - SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, \ - SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, \ - SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \ - SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \ - SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \ - SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, \ - SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \ - SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \ - SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \ - SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \ - SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \ - SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, \ - SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, \ - SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, \ - SYS_ACCEPT4 = 541 // { int accept4(int s, \ + SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); } + SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, off_t offset, off_t len); } + SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, off_t len, int advice); } + SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *info); } + SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, cap_rights_t *rightsp); } + SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, const u_long *cmds, size_t ncmds); } + SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, u_long *cmds, size_t maxcmds); } + SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, uint32_t fcntlrights); } + SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); } + SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, int namelen); } + SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, int namelen); } + SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, u_long flags, int atflag); } + SYS_ACCEPT4 = 541 // { int accept4(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen, int flags); } SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); } SYS_AIO_MLOCK = 543 // { int aio_mlock(struct aiocb *aiocbp); } - SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, \ - SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, \ - SYS_FUTIMENS = 546 // { int futimens(int fd, \ - SYS_UTIMENSAT = 547 // { int utimensat(int fd, \ - SYS_NUMA_GETAFFINITY = 548 // { int numa_getaffinity(cpuwhich_t which, \ - SYS_NUMA_SETAFFINITY = 549 // { int numa_setaffinity(cpuwhich_t which, \ + SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, int com, void *data); } + SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); } + SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); } + SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); } + SYS_NUMA_GETAFFINITY = 548 // { int numa_getaffinity(cpuwhich_t which, id_t id, struct vm_domain_policy_entry *policy); } + SYS_NUMA_SETAFFINITY = 549 // { int numa_setaffinity(cpuwhich_t which, id_t id, const struct vm_domain_policy_entry *policy); } SYS_FDATASYNC = 550 // { int fdatasync(int fd); } ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go index 0edc5409..7312e95f 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go @@ -324,11 +324,108 @@ const ( ) const ( - PTRACE_TRACEME = 0x0 - PTRACE_CONT = 0x7 - PTRACE_KILL = 0x8 + PTRACE_ATTACH = 0xa + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0xb + PTRACE_GETFPREGS = 0x23 + PTRACE_GETFSBASE = 0x47 + PTRACE_GETLWPLIST = 0xf + PTRACE_GETNUMLWPS = 0xe + PTRACE_GETREGS = 0x21 + PTRACE_GETXSTATE = 0x45 + PTRACE_IO = 0xc + PTRACE_KILL = 0x8 + PTRACE_LWPEVENTS = 0x18 + PTRACE_LWPINFO = 0xd + PTRACE_SETFPREGS = 0x24 + PTRACE_SETREGS = 0x22 + PTRACE_SINGLESTEP = 0x9 + PTRACE_TRACEME = 0x0 ) +const ( + PIOD_READ_D = 0x1 + PIOD_WRITE_D = 0x2 + PIOD_READ_I = 0x3 + PIOD_WRITE_I = 0x4 +) + +const ( + PL_FLAG_BORN = 0x100 + PL_FLAG_EXITED = 0x200 + PL_FLAG_SI = 0x20 +) + +const ( + TRAP_BRKPT = 0x1 + TRAP_TRACE = 0x2 +) + +type PtraceLwpInfoStruct struct { + Lwpid int32 + Event int32 + Flags int32 + Sigmask Sigset_t + Siglist Sigset_t + Siginfo __Siginfo + Tdname [20]int8 + Child_pid int32 + Syscall_code uint32 + Syscall_narg uint32 +} + +type __Siginfo struct { + Signo int32 + Errno int32 + Code int32 + Pid int32 + Uid uint32 + Status int32 + Addr *byte + Value [4]byte + X_reason [32]byte +} + +type Sigset_t struct { + Val [4]uint32 +} + +type Reg struct { + Fs uint32 + Es uint32 + Ds uint32 + Edi uint32 + Esi uint32 + Ebp uint32 + Isp uint32 + Ebx uint32 + Edx uint32 + Ecx uint32 + Eax uint32 + Trapno uint32 + Err uint32 + Eip uint32 + Cs uint32 + Eflags uint32 + Esp uint32 + Ss uint32 + Gs uint32 +} + +type FpReg struct { + Env [7]uint32 + Acc [8][10]uint8 + Ex_sw uint32 + Pad [64]uint8 +} + +type PtraceIoDesc struct { + Op int32 + Offs *byte + Addr *byte + Len uint +} + type Kevent_t struct { Ident uint32 Filter int16 diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go index 8881ce84..29ba2f5b 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go @@ -322,11 +322,115 @@ const ( ) const ( - PTRACE_TRACEME = 0x0 - PTRACE_CONT = 0x7 - PTRACE_KILL = 0x8 + PTRACE_ATTACH = 0xa + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0xb + PTRACE_GETFPREGS = 0x23 + PTRACE_GETFSBASE = 0x47 + PTRACE_GETLWPLIST = 0xf + PTRACE_GETNUMLWPS = 0xe + PTRACE_GETREGS = 0x21 + PTRACE_GETXSTATE = 0x45 + PTRACE_IO = 0xc + PTRACE_KILL = 0x8 + PTRACE_LWPEVENTS = 0x18 + PTRACE_LWPINFO = 0xd + PTRACE_SETFPREGS = 0x24 + PTRACE_SETREGS = 0x22 + PTRACE_SINGLESTEP = 0x9 + PTRACE_TRACEME = 0x0 ) +const ( + PIOD_READ_D = 0x1 + PIOD_WRITE_D = 0x2 + PIOD_READ_I = 0x3 + PIOD_WRITE_I = 0x4 +) + +const ( + PL_FLAG_BORN = 0x100 + PL_FLAG_EXITED = 0x200 + PL_FLAG_SI = 0x20 +) + +const ( + TRAP_BRKPT = 0x1 + TRAP_TRACE = 0x2 +) + +type PtraceLwpInfoStruct struct { + Lwpid int32 + Event int32 + Flags int32 + Sigmask Sigset_t + Siglist Sigset_t + Siginfo __Siginfo + Tdname [20]int8 + Child_pid int32 + Syscall_code uint32 + Syscall_narg uint32 +} + +type __Siginfo struct { + Signo int32 + Errno int32 + Code int32 + Pid int32 + Uid uint32 + Status int32 + Addr *byte + Value [8]byte + _ [40]byte +} + +type Sigset_t struct { + Val [4]uint32 +} + +type Reg struct { + R15 int64 + R14 int64 + R13 int64 + R12 int64 + R11 int64 + R10 int64 + R9 int64 + R8 int64 + Rdi int64 + Rsi int64 + Rbp int64 + Rbx int64 + Rdx int64 + Rcx int64 + Rax int64 + Trapno uint32 + Fs uint16 + Gs uint16 + Err uint32 + Es uint16 + Ds uint16 + Rip int64 + Cs int64 + Rflags int64 + Rsp int64 + Ss int64 +} + +type FpReg struct { + Env [4]uint64 + Acc [8][16]uint8 + Xacc [16][16]uint8 + Spare [12]uint64 +} + +type PtraceIoDesc struct { + Op int32 + Offs *byte + Addr *byte + Len uint +} + type Kevent_t struct { Ident uint64 Filter int16 diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go index fc713999..b4090ef3 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go @@ -322,11 +322,92 @@ const ( ) const ( - PTRACE_TRACEME = 0x0 - PTRACE_CONT = 0x7 - PTRACE_KILL = 0x8 + PTRACE_ATTACH = 0xa + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0xb + PTRACE_GETFPREGS = 0x23 + PTRACE_GETFSBASE = 0x47 + PTRACE_GETLWPLIST = 0xf + PTRACE_GETNUMLWPS = 0xe + PTRACE_GETREGS = 0x21 + PTRACE_GETXSTATE = 0x45 + PTRACE_IO = 0xc + PTRACE_KILL = 0x8 + PTRACE_LWPEVENTS = 0x18 + PTRACE_LWPINFO = 0xd + PTRACE_SETFPREGS = 0x24 + PTRACE_SETREGS = 0x22 + PTRACE_SINGLESTEP = 0x9 + PTRACE_TRACEME = 0x0 ) +const ( + PIOD_READ_D = 0x1 + PIOD_WRITE_D = 0x2 + PIOD_READ_I = 0x3 + PIOD_WRITE_I = 0x4 +) + +const ( + PL_FLAG_BORN = 0x100 + PL_FLAG_EXITED = 0x200 + PL_FLAG_SI = 0x20 +) + +const ( + TRAP_BRKPT = 0x1 + TRAP_TRACE = 0x2 +) + +type PtraceLwpInfoStruct struct { + Lwpid int32 + Event int32 + Flags int32 + Sigmask Sigset_t + Siglist Sigset_t + Siginfo __Siginfo + Tdname [20]int8 + Child_pid int32 + Syscall_code uint32 + Syscall_narg uint32 +} + +type __Siginfo struct { + Signo int32 + Errno int32 + Code int32 + Pid int32 + Uid uint32 + Status int32 + Addr *byte + Value [4]byte + X_reason [32]byte +} + +type Sigset_t struct { + Val [4]uint32 +} + +type Reg struct { + R [13]uint32 + R_sp uint32 + R_lr uint32 + R_pc uint32 + R_cpsr uint32 +} + +type FpReg struct { + Fpr_fpsr uint32 + Fpr [8][3]uint32 +} + +type PtraceIoDesc struct { + Op int32 + Offs *byte + Addr *byte + Len uint +} + type Kevent_t struct { Ident uint32 Filter int16 diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go index 5a0753ee..1542a877 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go @@ -322,11 +322,93 @@ const ( ) const ( - PTRACE_TRACEME = 0x0 - PTRACE_CONT = 0x7 - PTRACE_KILL = 0x8 + PTRACE_ATTACH = 0xa + PTRACE_CONT = 0x7 + PTRACE_DETACH = 0xb + PTRACE_GETFPREGS = 0x23 + PTRACE_GETFSBASE = 0x47 + PTRACE_GETLWPLIST = 0xf + PTRACE_GETNUMLWPS = 0xe + PTRACE_GETREGS = 0x21 + PTRACE_GETXSTATE = 0x45 + PTRACE_IO = 0xc + PTRACE_KILL = 0x8 + PTRACE_LWPEVENTS = 0x18 + PTRACE_LWPINFO = 0xd + PTRACE_SETFPREGS = 0x24 + PTRACE_SETREGS = 0x22 + PTRACE_SINGLESTEP = 0x9 + PTRACE_TRACEME = 0x0 ) +const ( + PIOD_READ_D = 0x1 + PIOD_WRITE_D = 0x2 + PIOD_READ_I = 0x3 + PIOD_WRITE_I = 0x4 +) + +const ( + PL_FLAG_BORN = 0x100 + PL_FLAG_EXITED = 0x200 + PL_FLAG_SI = 0x20 +) + +const ( + TRAP_BRKPT = 0x1 + TRAP_TRACE = 0x2 +) + +type PtraceLwpInfoStruct struct { + Lwpid int32 + Event int32 + Flags int32 + Sigmask Sigset_t + Siglist Sigset_t + Siginfo __Siginfo + Tdname [20]int8 + Child_pid int32 + Syscall_code uint32 + Syscall_narg uint32 +} + +type __Siginfo struct { + Signo int32 + Errno int32 + Code int32 + Pid int32 + Uid uint32 + Status int32 + Addr *byte + Value [8]byte + X_reason [40]byte +} + +type Sigset_t struct { + Val [4]uint32 +} + +type Reg struct { + X [30]uint64 + Lr uint64 + Sp uint64 + Elr uint64 + Spsr uint32 +} + +type FpReg struct { + Fp_q [32]uint128 + Fp_sr uint32 + Fp_cr uint32 +} + +type PtraceIoDesc struct { + Op int32 + Offs *byte + Addr *byte + Len uint +} + type Kevent_t struct { Ident uint64 Filter int16 diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index 06e3a3f4..5492b966 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -2467,3 +2467,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index cef25e73..caf33b2c 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -2480,3 +2480,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index c4369361..93aec7e2 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -2458,3 +2458,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index 76c55e05..0a038436 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -2459,3 +2459,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index 4302d574..2de0e580 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -2464,3 +2464,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index 7ea742be..3735eb42 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -2461,3 +2461,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index 8f2b8ad4..073c2993 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -2461,3 +2461,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index 865bf57d..58d09f75 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -2464,3 +2464,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 2b68027d..3f1e62e0 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -2469,3 +2469,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 76cd7e64..e67be11e 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -2469,3 +2469,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index f99f0615..f44f2940 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -2486,3 +2486,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index d9d03ae4..90bf5dcc 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -2483,3 +2483,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index b247fe94..4f054dcb 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -2464,3 +2464,20 @@ const ( BPF_FD_TYPE_UPROBE = 0x4 BPF_FD_TYPE_URETPROBE = 0x5 ) + +type CapUserHeader struct { + Version uint32 + Pid int32 +} + +type CapUserData struct { + Effective uint32 + Permitted uint32 + Inheritable uint32 +} + +const ( + LINUX_CAPABILITY_VERSION_1 = 0x19980330 + LINUX_CAPABILITY_VERSION_2 = 0x20071026 + LINUX_CAPABILITY_VERSION_3 = 0x20080522 +) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go index a2268b4f..86736ab6 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go @@ -411,6 +411,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go index 59e1da0a..3427811f 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go @@ -418,6 +418,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go index 1f1f0f38..399f37a4 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go @@ -416,6 +416,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go index 8dca204a..32f0c15d 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go @@ -418,6 +418,7 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x200 ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go index 900fb446..61ea0019 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go @@ -436,6 +436,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go index 028fa78d..87a493f6 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go @@ -436,6 +436,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go index b45d5eed..d80836ef 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go @@ -437,6 +437,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go index fa369a32..4e158746 100644 --- a/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go +++ b/backend/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go @@ -430,6 +430,7 @@ type Winsize struct { const ( AT_FDCWD = -0x64 + AT_SYMLINK_FOLLOW = 0x4 AT_SYMLINK_NOFOLLOW = 0x2 ) diff --git a/backend/vendor/google.golang.org/appengine/README.md b/backend/vendor/google.golang.org/appengine/README.md index 4376a376..9fdbacd3 100644 --- a/backend/vendor/google.golang.org/appengine/README.md +++ b/backend/vendor/google.golang.org/appengine/README.md @@ -79,11 +79,11 @@ The `EnableKeyConversion` enables automatic conversion from a key encoded with c ### Enabling key conversion -Enable key conversion by calling `EnableKeyConversion(ctx)` in the `/_ah/startup` handler for basic and manual scaling or any handler in automatic scaling. +Enable key conversion by calling `EnableKeyConversion(ctx)` in the `/_ah/start` handler for basic and manual scaling or any handler in automatic scaling. #### 1. Basic or manual scaling -This startup handler will enable key conversion for all handlers in the service. +This start handler will enable key conversion for all handlers in the service. ``` http.HandleFunc("/_ah/start", func(w http.ResponseWriter, r *http.Request) { diff --git a/backend/vendor/google.golang.org/appengine/go.mod b/backend/vendor/google.golang.org/appengine/go.mod index f449359d..45159279 100644 --- a/backend/vendor/google.golang.org/appengine/go.mod +++ b/backend/vendor/google.golang.org/appengine/go.mod @@ -1,7 +1,10 @@ module google.golang.org/appengine require ( - github.com/golang/protobuf v1.2.0 - golang.org/x/net v0.0.0-20180724234803-3673e40ba225 - golang.org/x/text v0.3.0 + github.com/golang/protobuf v1.3.1 + golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 // indirect + golang.org/x/net v0.0.0-20190603091049-60506f45cf65 + golang.org/x/sys v0.0.0-20190606165138-5da285871e9c // indirect + golang.org/x/text v0.3.2 + golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b // indirect ) diff --git a/backend/vendor/google.golang.org/appengine/go.sum b/backend/vendor/google.golang.org/appengine/go.sum index 1a221c08..cb323255 100644 --- a/backend/vendor/google.golang.org/appengine/go.sum +++ b/backend/vendor/google.golang.org/appengine/go.sum @@ -1,6 +1,22 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225 h1:kNX+jCowfMYzvlSvJu5pQWEmyWFrBXJ3PBy10xKMXK8= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= diff --git a/backend/vendor/modules.txt b/backend/vendor/modules.txt index 03360d58..582f708d 100644 --- a/backend/vendor/modules.txt +++ b/backend/vendor/modules.txt @@ -1,10 +1,10 @@ -# cloud.google.com/go v0.39.0 +# cloud.google.com/go v0.41.0 cloud.google.com/go/compute/metadata # github.com/PuerkitoBio/goquery v1.5.0 github.com/PuerkitoBio/goquery # github.com/andybalholm/cascadia v1.0.0 github.com/andybalholm/cascadia -# github.com/coreos/bbolt v1.3.2 +# github.com/coreos/bbolt v1.3.3 github.com/coreos/bbolt # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew @@ -30,16 +30,17 @@ github.com/go-chi/chi/middleware github.com/go-chi/cors # github.com/go-chi/render v1.0.1 github.com/go-chi/render -# github.com/go-pkgz/auth v0.5.2 +# github.com/go-pkgz/auth v0.7.2 github.com/go-pkgz/auth github.com/go-pkgz/auth/avatar github.com/go-pkgz/auth/provider +github.com/go-pkgz/auth/provider/sender github.com/go-pkgz/auth/token github.com/go-pkgz/auth/logger github.com/go-pkgz/auth/middleware # github.com/go-pkgz/lcw v0.3.1 github.com/go-pkgz/lcw -# github.com/go-pkgz/lgr v0.6.2 +# github.com/go-pkgz/lgr v0.6.3 github.com/go-pkgz/lgr # github.com/go-pkgz/mongo v1.1.2 github.com/go-pkgz/mongo @@ -67,6 +68,8 @@ github.com/hashicorp/golang-lru github.com/hashicorp/golang-lru/simplelru # github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc github.com/jessevdk/go-flags +# github.com/kyokomi/emoji v2.1.0+incompatible +github.com/kyokomi/emoji # github.com/microcosm-cc/bluemonday v1.0.2 github.com/microcosm-cc/bluemonday # github.com/nullrocks/identicon v0.0.0-20180626043057-7875f45b0022 @@ -89,13 +92,13 @@ github.com/stretchr/objx github.com/stretchr/testify/mock github.com/stretchr/testify/assert github.com/stretchr/testify/require -# golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 +# golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 golang.org/x/crypto/acme/autocert golang.org/x/crypto/acme -# golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff +# golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9 golang.org/x/image/draw golang.org/x/image/math/f64 -# golang.org/x/net v0.0.0-20190603091049-60506f45cf65 +# golang.org/x/net v0.0.0-20190628185345-da137c7871d7 golang.org/x/net/html golang.org/x/net/idna golang.org/x/net/html/atom @@ -110,7 +113,7 @@ golang.org/x/oauth2/yandex golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt -# golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed +# golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb golang.org/x/sys/unix # golang.org/x/text v0.3.2 golang.org/x/text/secure/bidirule @@ -119,7 +122,7 @@ golang.org/x/text/unicode/norm golang.org/x/text/transform # golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 golang.org/x/time/rate -# google.golang.org/appengine v1.6.0 +# google.golang.org/appengine v1.6.1 google.golang.org/appengine google.golang.org/appengine/urlfetch google.golang.org/appengine/internal @@ -130,5 +133,5 @@ google.golang.org/appengine/internal/base google.golang.org/appengine/internal/datastore google.golang.org/appengine/internal/log google.golang.org/appengine/internal/remote_api -# gopkg.in/russross/blackfriday.v2 v2.0.0-00010101000000-000000000000 => github.com/russross/blackfriday/v2 v2.0.1 +# gopkg.in/russross/blackfriday.v2 v2.0.1 => github.com/russross/blackfriday/v2 v2.0.1 gopkg.in/russross/blackfriday.v2 diff --git a/compose-dev-backend.yml b/compose-dev-backend.yml index fed061f2..f03e7cfa 100644 --- a/compose-dev-backend.yml +++ b/compose-dev-backend.yml @@ -1,6 +1,6 @@ # compose file for local development # starts backend on 8080 with basic auth "dev:password" and Dev oauth2 provider on port 8084, UI on http://127.0.0.1:8080/web -# +# # mongo-related tests needs mongodb container running - docker run -d -name=mongo mongo:3.6 --smallfiles # start build with backend tests: # MONGO_REMARK_TEST=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mongo) \ @@ -9,31 +9,30 @@ # to skip mongo test set MONGO_REMARK_TEST=skip # # start remark42 service - docker-compose -f compose-dev-backend.yml up -version: '2' +version: "2" services: remark42: - build: + build: context: . dockerfile: Dockerfile args: - SKIP_BACKEND_TEST - SKIP_FRONTEND_TEST=true - - MONGO_TEST=skip # disable mongo tests on build by default. To allow remove =skip part and see above image: umputun/remark42:dev container_name: "remark42-dev" hostname: "remark42-dev" logging: - driver: json-file - options: - max-size: "10m" - max-file: "5" + driver: json-file + options: + max-size: "10m" + max-file: "5" ports: - - "8080:8080" # primary rest server - - "8084:8084" # local oauth2 server + - "8080:8080" # primary rest server + - "8084:8084" # local oauth2 server environment: - REMARK_URL=http://127.0.0.1:8080 @@ -42,10 +41,19 @@ services: - BACKUP_PATH=/srv/var/backup - DEBUG=true - ADMIN_PASSWD=password - - AUTH_DEV=true # activate local oauth "dev" - - ADMIN_SHARED_ID=dev_user # set admin flag for default user on local ouath2 + - AUTH_DEV=true # activate local oauth "dev" + - ADMIN_SHARED_ID=dev_user # set admin flag for default user on local ouath2 - NOTIFY_TYPE - NOTIFY_TELEGRAM_TOKEN - NOTIFY_TELEGRAM_CHAN + - EMOJI=true + - AUTH_EMAIL_ENABLE=true + - AUTH_ANON=true + - AUTH_GOOGLE_CID=1111 + - AUTH_GOOGLE_CSEC=1111 + - AUTH_GITHUB_CID=1111 + - AUTH_GITHUB_CSEC=1111 + - AUTH_FACEBOOK_CID=1111 + - AUTH_FACEBOOK_CSEC=1111 volumes: - - ./var:/srv/var + - ./var:/srv/var diff --git a/compose-dev-frontend.yml b/compose-dev-frontend.yml index 5898c101..22e1125b 100644 --- a/compose-dev-frontend.yml +++ b/compose-dev-frontend.yml @@ -39,5 +39,6 @@ services: - POSITIVE_SCORE=false # restricts comment's score to be only positive - EDIT_TIME=5m # edit window - AUTH_ANON=true + - AUTH_EMAIL_ENABLE=true volumes: - ./var:/srv/var diff --git a/frontend/.babelrc b/frontend/.babelrc deleted file mode 100644 index d99459f5..00000000 --- a/frontend/.babelrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "browsers": ["> 1%", "android >= 4.4.4", "ios >= 9", "IE >= 11"] - }, - "useBuiltIns": "usage", - "corejs": 3 - } - ], - [ - "@babel/preset-react", - { - "pragma": "h", - "pragmaFrag": "div" - } - ] - ], - "plugins": ["@babel/plugin-syntax-dynamic-import", ["@babel/plugin-transform-react-jsx", { "pragma": "h" }]] -} diff --git a/frontend/.babelrc.js b/frontend/.babelrc.js new file mode 100644 index 00000000..0147e92e --- /dev/null +++ b/frontend/.babelrc.js @@ -0,0 +1,22 @@ +module.exports = { + presets: [ + [ + '@babel/preset-env', + { + targets: { + browsers: ['> 1%', 'android >= 4.4.4', 'ios >= 9', 'IE >= 11'], + }, + useBuiltIns: 'usage', + corejs: 3, + }, + ], + [ + '@babel/preset-react', + { + pragma: 'h', + pragmaFrag: 'div', + }, + ], + ], + plugins: ['@babel/plugin-syntax-dynamic-import', ['@babel/plugin-transform-react-jsx', { pragma: 'h' }]], +}; diff --git a/frontend/.eslintignore b/frontend/.eslintignore new file mode 100644 index 00000000..507ce055 --- /dev/null +++ b/frontend/.eslintignore @@ -0,0 +1,5 @@ +node_modules +public +!.prettierrc.js +!.eslintrc.js +!.babelrc.js \ No newline at end of file diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index a837287f..aebda7de 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/camelcase */ + module.exports = { parser: 'babel-eslint', extends: [ diff --git a/frontend/app/@types/enzyme/enzyme.d.ts b/frontend/app/@types/enzyme/enzyme.d.ts new file mode 100644 index 00000000..97a4e355 --- /dev/null +++ b/frontend/app/@types/enzyme/enzyme.d.ts @@ -0,0 +1,723 @@ +/** + * THIS IS PATCHED VERSION OF @types/enzyme THAT ADJUSTED FOR PREACT + * ALL CREDIT GOES TO MAINTAINERS OF @types/enzyme + */ + +/* eslint-disable */ + +declare module 'enzyme' { + // Type definitions for Enzyme 3.10 + // Project: https://github.com/airbnb/enzyme + // Definitions by: Marian Palkus + // Cap3 + // Ivo Stratev + // jwbay + // huhuanming + // MartynasZilinskas + // Torgeir Hovden + // Martin Hochel + // Christian Rackerseder + // Mateusz Sokoła + // Braiden Cutforth + // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + // TypeScript Version: 3.1 + + /// + import { Component } from 'preact'; + + export type HTMLAttributes = any; + + class ReactElement {} + + export class ElementClass {} + + /* These are purposefully stripped down versions of React.ComponentClass and React.StatelessComponent. + * The optional static properties on them break overload ordering for wrapper methods if they're not + * all specified in the implementation. TS chooses the EnzymePropSelector overload and loses the generics + */ + export interface ComponentClass { + new (props: Props, context?: any): Component; + } + + export type StatelessComponent = (props: Props, context?: any) => JSX.Element | null; + + export type ComponentType = ComponentClass | StatelessComponent; + + /** + * Many methods in Enzyme's API accept a selector as an argument. Selectors in Enzyme can fall into one of the + * following three categories: + * + * 1. A Valid CSS Selector + * 2. A React Component Constructor + * 3. A React Component's displayName + * 4. A React Stateless component + * 5. A React component property map + */ + export interface EnzymePropSelector { + [key: string]: any; + } + export type EnzymeSelector = string | StatelessComponent | ComponentClass | EnzymePropSelector; + + export type Intercepter = (intercepter: T) => void; + + export interface CommonWrapper

> { + /** + * Returns a new wrapper with only the nodes of the current wrapper that, when passed into the provided predicate function, return true. + */ + filterWhere(predicate: (wrapper: this) => boolean): this; + + /** + * Returns whether or not the current wrapper has a node anywhere in it's render tree that looks like the one passed in. + */ + contains(node: ReactElement | ReactElement[] | string): boolean; + + /** + * Returns whether or not a given react element exists in the shallow render tree. + */ + containsMatchingElement(node: ReactElement | ReactElement[]): boolean; + + /** + * Returns whether or not all the given react elements exists in the shallow render tree + */ + containsAllMatchingElements(nodes: ReactElement[] | ReactElement[][]): boolean; + + /** + * Returns whether or not one of the given react elements exists in the shallow render tree. + */ + containsAnyMatchingElements(nodes: ReactElement[] | ReactElement[][]): boolean; + + /** + * Returns whether or not the current render tree is equal to the given node, based on the expected value. + */ + equals(node: ReactElement): boolean; + + /** + * Returns whether or not a given react element matches the shallow render tree. + */ + matchesElement(node: ReactElement): boolean; + + /** + * Returns whether or not the current node has a className prop including the passed in class name. + */ + hasClass(className: string | RegExp): boolean; + + /** + * Invokes a function prop. + * @param invokePropName The function prop to call. + * @param ...args The argments to the invokePropName function + * @returns The value of the function. + */ + invoke< + K extends NonNullable<{ [K in keyof P]: P[K] extends ((...arg: any[]) => void) | undefined ? K : never }[keyof P]> + >( + invokePropName: K + ): P[K]; + + /** + * Returns whether or not the current node matches a provided selector. + */ + is(selector: EnzymeSelector): boolean; + + /** + * Returns whether or not the current node is empty. + * @deprecated Use .exists() instead. + */ + isEmpty(): boolean; + + /** + * Returns whether or not the current node exists. + */ + exists(selector?: EnzymeSelector): boolean; + + /** + * Returns a new wrapper with only the nodes of the current wrapper that don't match the provided selector. + * This method is effectively the negation or inverse of filter. + */ + not(selector: EnzymeSelector): this; + + /** + * Returns a string of the rendered text of the current render tree. This function should be looked at with + * skepticism if being used to test what the actual HTML output of the component will be. If that is what you + * would like to test, use enzyme's render function instead. + * + * Note: can only be called on a wrapper of a single node. + */ + text(): string; + + /** + * Returns a string of the rendered HTML markup of the current render tree. + * + * Note: can only be called on a wrapper of a single node. + */ + html(): string; + + /** + * Returns the node at a given index of the current wrapper. + */ + get(index: number): ReactElement; + + /** + * Returns the wrapper's underlying node. + */ + getNode(): ReactElement; + + /** + * Returns the wrapper's underlying nodes. + */ + getNodes(): ReactElement[]; + + /** + * Returns the wrapper's underlying node. + */ + getElement(): ReactElement; + + /** + * Returns the wrapper's underlying node. + */ + getElements(): ReactElement[]; + + /** + * Returns the outer most DOMComponent of the current wrapper. + */ + getDOMNode(): T; + + /** + * Returns a wrapper around the node at a given index of the current wrapper. + */ + at(index: number): this; + + /** + * Reduce the set of matched nodes to the first in the set. + */ + first(): this; + + /** + * Reduce the set of matched nodes to the last in the set. + */ + last(): this; + + /** + * Returns a new wrapper with a subset of the nodes of the original wrapper, according to the rules of `Array#slice`. + */ + slice(begin?: number, end?: number): this; + + /** + * Taps into the wrapper method chain. Helpful for debugging. + */ + tap(intercepter: Intercepter): this; + + /** + * Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it will return just that value. + */ + state(): S; + state(key: K): S[K]; + state(key: string): T; + + /** + * Returns the context hash for the root node of the wrapper. Optionally pass in a prop name and it will return just that value. + */ + context(): any; + context(key: string): T; + + /** + * Returns the props hash for the current node of the wrapper. + * + * NOTE: can only be called on a wrapper of a single node. + */ + props(): P; + + /** + * Returns the prop value for the node of the current wrapper with the provided key. + * + * NOTE: can only be called on a wrapper of a single node. + */ + prop(key: K): P[K]; + prop(key: string): T; + + /** + * Returns the key value for the node of the current wrapper. + * NOTE: can only be called on a wrapper of a single node. + */ + key(): string; + + /** + * Simulate events. + * Returns itself. + * @param args? + */ + simulate(event: string, ...args: any[]): this; + + /** + * Used to simulate throwing a rendering error. Pass an error to throw. + * Returns itself. + * @param error + */ + simulateError(error: any): this; + + /** + * A method to invoke setState() on the root component instance similar to how you might in the definition of + * the component, and re-renders. This method is useful for testing your component in hard to achieve states, + * however should be used sparingly. If possible, you should utilize your component's external API in order to + * get it into whatever state you want to test, in order to be as accurate of a test as possible. This is not + * always practical, however. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + setState(state: Pick, callback?: () => void): this; + + /** + * A method that sets the props of the root component, and re-renders. Useful for when you are wanting to test + * how the component behaves over time with changing props. Calling this, for instance, will call the + * componentWillReceiveProps lifecycle method. + * + * Similar to setState, this method accepts a props object and will merge it in with the already existing props. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + setProps(props: Pick, callback?: () => void): this; + + /** + * A method that sets the context of the root component, and re-renders. Useful for when you are wanting to + * test how the component behaves over time with changing contexts. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + setContext(context: any): this; + + /** + * Gets the instance of the component being rendered as the root node passed into shallow(). + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + instance(): C; + + /** + * Forces a re-render. Useful to run before checking the render output if something external may be updating + * the state of the component somewhere. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + update(): this; + + /** + * Returns an html-like string of the wrapper for debugging purposes. Useful to print out to the console when + * tests are not passing when you expect them to. + */ + debug(): string; + + /** + * Returns the name of the current node of the wrapper. + */ + name(): string; + + /** + * Iterates through each node of the current wrapper and executes the provided function with a wrapper around + * the corresponding node passed in as the first argument. + * + * Returns itself. + * @param fn A callback to be run for every node in the collection. Should expect a ShallowWrapper as the first + * argument, and will be run with a context of the original instance. + */ + forEach(fn: (wrapper: this, index: number) => any): this; + + /** + * Maps the current array of nodes to another array. Each node is passed in as a ShallowWrapper to the map + * function. + * Returns an array of the returned values from the mapping function.. + * @param fn A mapping function to be run for every node in the collection, the results of which will be mapped + * to the returned array. Should expect a ShallowWrapper as the first argument, and will be run + * with a context of the original instance. + */ + map(fn: (wrapper: this, index: number) => V): V[]; + + /** + * Applies the provided reducing function to every node in the wrapper to reduce to a single value. Each node + * is passed in as a ShallowWrapper, and is processed from left to right. + */ + reduce(fn: (prevVal: R, wrapper: this, index: number) => R, initialValue?: R): R; + + /** + * Applies the provided reducing function to every node in the wrapper to reduce to a single value. + * Each node is passed in as a ShallowWrapper, and is processed from right to left. + */ + reduceRight(fn: (prevVal: R, wrapper: this, index: number) => R, initialValue?: R): R; + + /** + * Returns whether or not any of the nodes in the wrapper match the provided selector. + */ + some(selector: EnzymeSelector): boolean; + + /** + * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. + */ + someWhere(fn: (wrapper: this) => boolean): boolean; + + /** + * Returns whether or not all of the nodes in the wrapper match the provided selector. + */ + every(selector: EnzymeSelector): boolean; + + /** + * Returns whether or not all of the nodes in the wrapper pass the provided predicate function. + */ + everyWhere(fn: (wrapper: this) => boolean): boolean; + + /** + * Returns true if renderer returned null + */ + isEmptyRender(): boolean; + + /** + * Renders the component to static markup and returns a Cheerio wrapper around the result. + */ + render(): Cheerio; + + /** + * Returns the type of the current node of this wrapper. If it's a composite component, this will be the + * component constructor. If it's native DOM node, it will be a string of the tag name. + * + * Note: can only be called on a wrapper of a single node. + */ + type(): string | ComponentClass

| StatelessComponent

; + + length: number; + } + + export type Parameters = T extends (...args: infer A) => any ? A : never; + + // tslint:disable-next-line no-empty-interface + export interface ShallowWrapper

extends CommonWrapper {} + export class ShallowWrapper

{ + constructor(nodes: JSX.Element[] | JSX.Element, root?: ShallowWrapper, options?: ShallowRendererProps); + shallow(options?: ShallowRendererProps): ShallowWrapper; + unmount(): this; + + /** + * Find every node in the render tree that matches the provided selector. + * @param selector The selector to match. + */ + find(statelessComponent: StatelessComponent): ShallowWrapper; + find(component: ComponentType): ShallowWrapper; + find(props: EnzymePropSelector): ShallowWrapper; + find(selector: string): ShallowWrapper; + + /** + * Removes nodes in the current wrapper that do not match the provided selector. + * @param selector The selector to match. + */ + filter(statelessComponent: StatelessComponent): ShallowWrapper; + filter(component: ComponentType): ShallowWrapper; + filter(props: EnzymePropSelector | string): ShallowWrapper; + + /** + * Finds every node in the render tree that returns true for the provided predicate function. + */ + findWhere(predicate: (wrapper: ShallowWrapper) => boolean): ShallowWrapper; + + /** + * Returns a new wrapper with all of the children of the node(s) in the current wrapper. Optionally, a selector + * can be provided and it will filter the children by this selector. + */ + children(statelessComponent: StatelessComponent): ShallowWrapper; + children(component: ComponentType): ShallowWrapper; + children(selector: string): ShallowWrapper; + children(props?: EnzymePropSelector): ShallowWrapper; + + /** + * Returns a new wrapper with child at the specified index. + */ + childAt(index: number): ShallowWrapper; + childAt(index: number): ShallowWrapper; + + /** + * Shallow render the one non-DOM child of the current wrapper, and return a wrapper around the result. + * NOTE: can only be called on wrapper of a single non-DOM component element node. + */ + dive( + options?: ShallowRendererProps + ): ShallowWrapper; + dive(options?: ShallowRendererProps): ShallowWrapper; + dive(options?: ShallowRendererProps): ShallowWrapper; + + /** + * Strips out all the not host-nodes from the list of nodes + * + * This method is useful if you want to check for the presence of host nodes + * (actually rendered HTML elements) ignoring the React nodes. + */ + hostNodes(): ShallowWrapper; + + /** + * Returns a wrapper around all of the parents/ancestors of the wrapper. Does not include the node in the + * current wrapper. Optionally, a selector can be provided and it will filter the parents by this selector. + * + * Note: can only be called on a wrapper of a single node. + */ + parents(statelessComponent: StatelessComponent): ShallowWrapper; + parents(component: ComponentType): ShallowWrapper; + parents(selector: string): ShallowWrapper; + parents(props?: EnzymePropSelector): ShallowWrapper; + + /** + * Returns a wrapper of the first element that matches the selector by traversing up through the current node's + * ancestors in the tree, starting with itself. + * + * Note: can only be called on a wrapper of a single node. + */ + closest(statelessComponent: StatelessComponent): ShallowWrapper; + closest(component: ComponentType): ShallowWrapper; + closest(props: EnzymePropSelector): ShallowWrapper; + closest(selector: string): ShallowWrapper; + + /** + * Returns a wrapper with the direct parent of the node in the current wrapper. + */ + parent(): ShallowWrapper; + + /** + * Returns a wrapper of the node rendered by the provided render prop. + */ + renderProp( + prop: PropName + ): (...params: Parameters) => ShallowWrapper; + + /** + * If a wrappingComponent was passed in options, + * this methods returns a ShallowWrapper around the rendered wrappingComponent. + * This ShallowWrapper can be used to update the wrappingComponent's props and state + */ + getWrappingComponent: () => ShallowWrapper; + } + + // tslint:disable-next-line no-empty-interface + export interface ReactWrapper

extends CommonWrapper {} + export class ReactWrapper

{ + constructor(nodes: JSX.Element | JSX.Element[], root?: ReactWrapper, options?: MountRendererProps); + + unmount(): this; + mount(): this; + + /** + * Returns a wrapper of the node that matches the provided reference name. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + ref(refName: string): ReactWrapper; + ref(refName: string): ReactWrapper; + + /** + * Detaches the react tree from the DOM. Runs ReactDOM.unmountComponentAtNode() under the hood. + * + * This method will most commonly be used as a "cleanup" method if you decide to use the attachTo option in mount(node, options). + * + * The method is intentionally not "fluent" (in that it doesn't return this) because you should not be doing anything with this wrapper after this method is called. + * + * Using the attachTo is not generally recommended unless it is absolutely necessary to test something. + * It is your responsibility to clean up after yourself at the end of the test if you do decide to use it, though. + */ + detach(): void; + + /** + * Strips out all the not host-nodes from the list of nodes + * + * This method is useful if you want to check for the presence of host nodes + * (actually rendered HTML elements) ignoring the React nodes. + */ + hostNodes(): ReactWrapper; + + /** + * Find every node in the render tree that matches the provided selector. + * @param selector The selector to match. + */ + find(statelessComponent: StatelessComponent): ReactWrapper; + find(component: ComponentType): ReactWrapper; + find(props: EnzymePropSelector): ReactWrapper; + find(selector: string): ReactWrapper; + + /** + * Finds every node in the render tree that returns true for the provided predicate function. + */ + findWhere(predicate: (wrapper: ReactWrapper) => boolean): ReactWrapper; + + /** + * Removes nodes in the current wrapper that do not match the provided selector. + * @param selector The selector to match. + */ + filter(statelessComponent: StatelessComponent): ReactWrapper; + filter(component: ComponentType): ReactWrapper; + filter(props: EnzymePropSelector | string): ReactWrapper; + + /** + * Returns a new wrapper with all of the children of the node(s) in the current wrapper. Optionally, a selector + * can be provided and it will filter the children by this selector. + */ + children(statelessComponent: StatelessComponent): ReactWrapper; + children(component: ComponentType): ReactWrapper; + children(selector: string): ReactWrapper; + children(props?: EnzymePropSelector): ReactWrapper; + + /** + * Returns a new wrapper with child at the specified index. + */ + childAt(index: number): ReactWrapper; + childAt(index: number): ReactWrapper; + + /** + * Returns a wrapper around all of the parents/ancestors of the wrapper. Does not include the node in the + * current wrapper. Optionally, a selector can be provided and it will filter the parents by this selector. + * + * Note: can only be called on a wrapper of a single node. + */ + parents(statelessComponent: StatelessComponent): ReactWrapper; + parents(component: ComponentType): ReactWrapper; + parents(selector: string): ReactWrapper; + parents(props?: EnzymePropSelector): ReactWrapper; + + /** + * Returns a wrapper of the first element that matches the selector by traversing up through the current node's + * ancestors in the tree, starting with itself. + * + * Note: can only be called on a wrapper of a single node. + */ + closest(statelessComponent: StatelessComponent): ReactWrapper; + closest(component: ComponentType): ReactWrapper; + closest(props: EnzymePropSelector): ReactWrapper; + closest(selector: string): ReactWrapper; + + /** + * Returns a wrapper with the direct parent of the node in the current wrapper. + */ + parent(): ReactWrapper; + } + + export interface Lifecycles { + componentDidUpdate?: { + onSetState: boolean; + prevContext: boolean; + }; + getDerivedStateFromProps?: { hasShouldComponentUpdateBug: boolean } | boolean; + getChildContext?: { + calledByRenderer: boolean; + [key: string]: any; + }; + setState?: any; + // TODO Maybe some life cycle are missing + [lifecycleName: string]: any; + } + + export interface ShallowRendererProps { + // See https://github.com/airbnb/enzyme/blob/enzyme@3.10.0/docs/api/shallow.md#arguments + /** + * If set to true, componentDidMount is not called on the component, and componentDidUpdate is not called after + * setProps and setContext. Default to false. + */ + disableLifecycleMethods?: boolean; + /** + * Enable experimental support for full react lifecycle methods + */ + lifecycleExperimental?: boolean; + /** + * Context to be passed into the component + */ + context?: any; + /** + * The legacy enableComponentDidUpdateOnSetState option should be matched by + * `lifecycles: { componentDidUpdate: { onSetState: true } }`, for compatibility + */ + enableComponentDidUpdateOnSetState?: boolean; + /** + * the legacy supportPrevContextArgumentOfComponentDidUpdate option should be matched by + * `lifecycles: { componentDidUpdate: { prevContext: true } }`, for compatibility + */ + supportPrevContextArgumentOfComponentDidUpdate?: boolean; + lifecycles?: Lifecycles; + /** + * A component that will render as a parent of the node. + * It can be used to provide context to the node, among other things. + * See https://airbnb.io/enzyme/docs/api/ShallowWrapper/getWrappingComponent.html + * Note: wrappingComponent must render its children. + */ + wrappingComponent?: ComponentType; + /** + * Initial props to pass to the wrappingComponent if it is specified. + */ + wrappingComponentProps?: any; + /** + * If set to true, when rendering Suspense enzyme will replace all the lazy components in children + * with fallback element prop. Otherwise it won't handle fallback of lazy component. + * Default to true. Note: not supported in React < 16.6. + */ + suspenseFallback?: boolean; + adapter?: EnzymeAdapter; + /* TODO what are these doing??? */ + attachTo?: any; + hydrateIn?: any; + PROVIDER_VALUES?: any; + } + + export interface MountRendererProps { + /** + * Context to be passed into the component + */ + context?: {}; + /** + * DOM Element to attach the component to + */ + attachTo?: HTMLElement | null; + /** + * Merged contextTypes for all children of the wrapper + */ + childContextTypes?: {}; + } + + /** + * Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that + * your tests aren't indirectly asserting on behavior of child components. + */ + export function shallow( + node: ReactElement

, + options?: ShallowRendererProps + ): ShallowWrapper; + export function shallow

(node: ReactElement

, options?: ShallowRendererProps): ShallowWrapper; + export function shallow(node: ReactElement

, options?: ShallowRendererProps): ShallowWrapper; + + /** + * Mounts and renders a react component into the document and provides a testing wrapper around it. + */ + export function mount( + node: ReactElement

, + options?: MountRendererProps + ): ReactWrapper; + export function mount

(node: ReactElement

, options?: MountRendererProps): ReactWrapper; + export function mount(node: ReactElement

, options?: MountRendererProps): ReactWrapper; + + /** + * Render react components to static HTML and analyze the resulting HTML structure. + */ + export function render(node: ReactElement

, options?: any): Cheerio; + + // See https://github.com/airbnb/enzyme/blob/v3.10.0/packages/enzyme/src/EnzymeAdapter.js + export class EnzymeAdapter { + wrapWithWrappingComponent?: (node: ReactElement, options?: ShallowRendererProps) => any; + } + + /** + * Configure enzyme to use the correct adapter for the react version + * This is enabling the Enzyme configuration with adapters in TS + */ + export function configure(options: { + adapter: EnzymeAdapter; + // See https://github.com/airbnb/enzyme/blob/enzyme@3.10.0/docs/guides/migration-from-2-to-3.md#lifecycle-methods + // Actually, `{adapter:} & Pick` is more precise. However, + // in that case jsdoc won't be shown + /** + * If set to true, componentDidMount is not called on the component, and componentDidUpdate is not called after + * setProps and setContext. Default to false. + */ + disableLifecycleMethods?: boolean; + }): void; +} diff --git a/frontend/app/common/__mocks__/constants.ts b/frontend/app/common/__mocks__/constants.ts new file mode 100644 index 00000000..3fb7aef8 --- /dev/null +++ b/frontend/app/common/__mocks__/constants.ts @@ -0,0 +1,7 @@ +// @ts-ignore +const mock: typeof import('@app/common/constants') = { + ...jest.requireActual('@app/common/constants'), + BASE_URL: 'https://demo.remark42.com/', +}; + +module.exports = mock; diff --git a/frontend/app/common/__mocks__/settings.ts b/frontend/app/common/__mocks__/settings.ts new file mode 100644 index 00000000..adcb398c --- /dev/null +++ b/frontend/app/common/__mocks__/settings.ts @@ -0,0 +1,20 @@ +// @ts-ignore +const mock: typeof import('@app/common/settings') = { + ...jest.requireActual('@app/common/settings'), + siteId: 'remark', + pageTitle: 'remark test', + url: 'https://remark42.com/test', + maxShownComments: 20, + token: 'abcd', + theme: 'light', + querySettings: { + site_id: 'remark', + page_title: 'remark test', + url: 'https://remark42.com/test', + max_shown_comments: 20, + token: 'abcd', + theme: 'light', + }, +}; + +module.exports = mock; diff --git a/frontend/app/common/api.ts b/frontend/app/common/api.ts index 490bb2f6..a2e62a28 100644 --- a/frontend/app/common/api.ts +++ b/frontend/app/common/api.ts @@ -12,8 +12,27 @@ const __loginAnonymously = (username: string): Promise => { return fetcher.get({ url, withCredentials: true, overriddenApiBase: '' }); }; +const __loginViaEmail = (token: string): Promise => { + const url = `/auth/email/login?token=${token}`; + return fetcher.get({ url, withCredentials: true, overriddenApiBase: '' }); +}; + +/** + * First step of two of `email` authorization + * + * @param username userrname + * @param address email address + */ +export const sendEmailVerificationRequest = (username: string, address: string): Promise => { + const url = `/auth/email/login?id=${siteId}&user=${encodeURIComponent(username)}&address=${encodeURIComponent( + address + )}`; + return fetcher.get({ url, withCredentials: true, overriddenApiBase: '' }); +}; + export const logIn = (provider: AuthProvider): Promise => { if (provider.name === 'anonymous') return __loginAnonymously(provider.username); + if (provider.name === 'email') return __loginViaEmail(provider.token); return new Promise((resolve, reject) => { const url = `${BASE_URL}/auth/${provider.name}/login?from=${encodeURIComponent( diff --git a/frontend/app/common/constants.ts b/frontend/app/common/constants.ts index 217cbd27..6e22940f 100644 --- a/frontend/app/common/constants.ts +++ b/frontend/app/common/constants.ts @@ -22,6 +22,7 @@ export const PROVIDER_NAMES: { [P in AuthProvider['name']]: string } = { yandex: 'Yandex', dev: 'Dev', anonymous: 'Anonymous', + email: 'Email', }; /** locastorage key for collapsed comments */ diff --git a/frontend/app/common/fetcher.test.ts b/frontend/app/common/fetcher.test.ts index 8d1e54f2..d45be047 100644 --- a/frontend/app/common/fetcher.test.ts +++ b/frontend/app/common/fetcher.test.ts @@ -1,23 +1,13 @@ import fetcher from './fetcher'; +import { mockHeaders } from '@app/testUtils/mockHeaders'; describe('fetcher', () => { - let originalHeaders = (window as any).Headers; - beforeAll(() => { - originalHeaders = (window as any).Headers; - (window as any).Headers = class { - append() {} - has() { - return false; - } - get() { - return null; - } - }; + mockHeaders.mock(); }); afterAll(() => { - (window as any).Headers = originalHeaders; + mockHeaders.restore(); }); afterEach(() => { diff --git a/frontend/app/common/polyfills.ts b/frontend/app/common/polyfills.ts index 84e4c1c9..79f9a86c 100644 --- a/frontend/app/common/polyfills.ts +++ b/frontend/app/common/polyfills.ts @@ -1,3 +1,4 @@ +import 'intersection-observer'; import 'core-js/es/promise'; import 'focus-visible'; import '@webcomponents/custom-elements'; diff --git a/frontend/app/common/types.ts b/frontend/app/common/types.ts index 14095f29..debc98d5 100644 --- a/frontend/app/common/types.ts +++ b/frontend/app/common/types.ts @@ -65,6 +65,14 @@ export interface Comment { delete?: boolean; /** post title */ title?: string; + /** + * @ClientOnly defines whether comments was hidden (deleted) + * + * Situatuon may occure for example if user decided to hide someone, + * in this case we don't use `delete` field because comment with `delete` + * still renders, and comment with `hidden` flag completely removed from DOM + */ + hidden?: boolean; } export interface CommentsResponse { @@ -119,7 +127,8 @@ export type AuthProvider = | { name: 'github' } | { name: 'yandex' } | { name: 'dev' } - | { name: 'anonymous'; username: string }; + | { name: 'anonymous'; username: string } + | { name: 'email'; token: string }; export type BlockTTL = 'permanently' | '43200m' | '10080m' | '1440m'; diff --git a/frontend/app/components/auth-panel/__anonymous-login-form/index.ts b/frontend/app/components/auth-panel/__anonymous-login-form/index.ts index c3cc53f0..134b7c86 100644 --- a/frontend/app/components/auth-panel/__anonymous-login-form/index.ts +++ b/frontend/app/components/auth-panel/__anonymous-login-form/index.ts @@ -1,3 +1,3 @@ -export { AnonymousLoginForm } from './auth-panel__anonymous-login-form'; +import './auth-panel__anonymous-login-form.scss'; -require('./auth-panel__anonymous-login-form.scss'); +export { AnonymousLoginForm } from './auth-panel__anonymous-login-form'; diff --git a/frontend/app/components/auth-panel/__dropdown-provider/auth-panel__dropdown-provider.scss b/frontend/app/components/auth-panel/__dropdown-provider/auth-panel__dropdown-provider.scss new file mode 100644 index 00000000..599ec6af --- /dev/null +++ b/frontend/app/components/auth-panel/__dropdown-provider/auth-panel__dropdown-provider.scss @@ -0,0 +1,3 @@ +.auth-panel__dropdown-provider { + padding: 0.2rem 0.4rem; +} diff --git a/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.scss b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.scss new file mode 100644 index 00000000..6ff96ca5 --- /dev/null +++ b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.scss @@ -0,0 +1,52 @@ +.auth-panel-email-login-form { + padding: 0.35em 0.55em; + display: flex; + flex-direction: column; + flex-wrap: nowrap; +} + +.auth-panel-email-login-form__input, +.auth-panel-email-login-form__token-input { + width: 12rem; + margin: 0.15rem; +} + +.auth-panel-email-login-form__token-input { + resize: vertical; + font: inherit; + font-weight: normal; + font-size: 0.8em; +} + +.auth-panel-email-login-form__submit { + background: none; + border: none; + padding: 0; + padding: 0.1em; + margin-top: 0.2em; + color: currentColor; + font: inherit; + cursor: pointer; +} + +.auth-panel-email-login-form__submit:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.auth-panel-email-login-form__back-button { + color: #259c9a; + cursor: pointer; + margin-left: 0.1rem; + margin-bottom: 0.5rem; + + &:hover { + opacity: 0.8; + } +} + +.auth-panel-email-login-form__error { + color: #9a0000; + text-align: center; + margin-top: 1em; +} diff --git a/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.test.tsx b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.test.tsx new file mode 100644 index 00000000..55c9926a --- /dev/null +++ b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.test.tsx @@ -0,0 +1,50 @@ +/** @jsx h */ +import { h } from 'preact'; +import { mount } from 'enzyme'; +import { EmailLoginForm, Props, State } from './auth-panel__email-login-form'; +import { User } from '@app/common/types'; +import { sleep } from '@app/utils/sleep'; + +describe('EmailLoginForm', () => { + it('works', async () => { + const testUser = ({} as any) as User; + const sendEmailVerification = jest.fn(async () => {}); + const onSignIn = jest.fn(async () => testUser); + const onSuccess = jest.fn(async () => {}); + const el = mount( + + ); + await new Promise(resolve => + el.setState( + { + usernameValue: 'someone', + addressValue: 'someone@example.com', + } as State, + resolve + ) + ); + el.find('form').simulate('submit'); + await sleep(100); + expect(sendEmailVerification).toBeCalledWith('someone', 'someone@example.com'); + expect(el.state().verificationSent).toBe(true); + + await new Promise(resolve => + el.setState( + { + tokenValue: 'abcd', + } as State, + resolve + ) + ); + + el.find('form').simulate('submit'); + await sleep(100); + expect(onSignIn).toBeCalledWith('abcd'); + expect(onSuccess).toBeCalledWith(testUser); + }); +}); diff --git a/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.tsx b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.tsx new file mode 100644 index 00000000..544e4b3a --- /dev/null +++ b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.tsx @@ -0,0 +1,235 @@ +/** @jsx h */ +import { h, Component, RenderableProps } from 'preact'; +import b from 'bem-react-helper'; +import { Theme, User } from '@app/common/types'; +import { sendEmailVerificationRequest } from '@app/common/api'; +import { extractErrorMessageFromResponse } from '@app/utils/errorUtils'; +import { connect } from 'preact-redux'; +import { getHandleClickProps } from '@app/common/accessibility'; +import { sleep } from '@app/utils/sleep'; +import TextareaAutosize from '@app/components/input/textarea-autosize'; + +const mapStateToProps = () => ({ + sendEmailVerification: sendEmailVerificationRequest, +}); + +export type Props = { + onSignIn(token: string): Promise; + onSuccess?(user: User): Promise; + theme: Theme; + className?: string; +} & ReturnType; + +export interface State { + usernameValue: string; + addressValue: string; + tokenValue: string; + verificationSent: boolean; + loading: boolean; + error: string | null; +} + +export class EmailLoginForm extends Component { + static usernameRegex = /^[a-zA-Z][\w ]+$/; + static emailRegex = /[^@]+@[^.]+\..+/; + + inputRef?: HTMLInputElement; + tokenRef?: TextareaAutosize; + + constructor(props: Props) { + super(props); + + this.state = { + usernameValue: '', + addressValue: '', + tokenValue: '', + verificationSent: false, + loading: false, + error: null, + }; + + this.focus = this.focus.bind(this); + this.onVerificationSubmit = this.onVerificationSubmit.bind(this); + this.onSubmit = this.onSubmit.bind(this); + this.onUsernameChange = this.onUsernameChange.bind(this); + this.onAddressChange = this.onAddressChange.bind(this); + this.onTokenChange = this.onTokenChange.bind(this); + this.goBack = this.goBack.bind(this); + } + + async focus() { + await sleep(100); + if (this.inputRef) { + this.inputRef.focus(); + return; + } + this.tokenRef && this.tokenRef.textareaRef && this.tokenRef.textareaRef.select(); + } + + async onVerificationSubmit(e: Event) { + e.preventDefault(); + this.setState({ loading: true }); + try { + await this.props.sendEmailVerification(this.state.usernameValue, this.state.addressValue); + this.setState({ verificationSent: true }); + setTimeout(() => { + this.tokenRef && this.tokenRef.focus(); + }, 100); + } catch (e) { + this.setState({ error: extractErrorMessageFromResponse(e) }); + } finally { + this.setState({ loading: false }); + } + } + + async onSubmit(e: Event) { + e.preventDefault(); + try { + this.setState({ loading: true }); + const user = await this.props.onSignIn(this.state.tokenValue); + if (!user) { + this.setState({ error: 'No user was found' }); + return; + } + this.setState({ verificationSent: false, tokenValue: '' }); + this.props.onSuccess && this.props.onSuccess(user); + } catch (e) { + this.setState({ error: extractErrorMessageFromResponse(e) }); + } finally { + this.setState({ loading: false }); + } + } + + onUsernameChange(e: Event) { + this.setState({ error: null, usernameValue: (e.target as HTMLInputElement).value }); + } + + onAddressChange(e: Event) { + this.setState({ error: null, addressValue: (e.target as HTMLInputElement).value }); + } + + onTokenChange(e: Event) { + this.setState({ error: null, tokenValue: (e.target as HTMLInputElement).value }); + } + + goBack() { + this.setState({ + tokenValue: '', + error: null, + verificationSent: false, + }); + setTimeout(() => { + this.inputRef && this.inputRef.focus(); + }, 100); + } + + getForm1InvalidReason(): string | null { + if (this.state.loading) return 'Loading...'; + const username = this.state.usernameValue; + if (username.length < 3) return 'Username must be at least 3 characters long'; + if (!EmailLoginForm.usernameRegex.test(username)) + return 'Username must start from the letter and contain only latin letters, numbers, underscores, and spaces'; + if (!EmailLoginForm.emailRegex.test(this.state.addressValue)) return 'Address should be valid email address'; + return null; + } + + getForm2InvalidReason(): string | null { + if (this.state.loading) return 'Loading...'; + if (this.state.tokenValue.length === 0) return 'Token field must not be empty'; + return null; + } + + componentDidMount() { + setTimeout(() => { + this.inputRef && this.inputRef.focus(); + }, 100); + } + + render(props: RenderableProps) { + // TODO: will be great to `b` to accept `string | undefined | (string|undefined)[]` as classname + let className = b('auth-panel-email-login-form', {}, { theme: props.theme }); + if (props.className) { + className += ' ' + b('auth-panel-email-login-form', {}, { theme: props.theme }); + } + + const form1InvalidReason = this.getForm1InvalidReason(); + + if (!this.state.verificationSent) + return ( +

+ {/* + * We adding hidden span element to bear with DropDown's onOutSideClick handler. + * This function checks if element that was clicked is a children of it's root component. + * And the problem is that by the time handler gets executed our target element is not a + * part of a dom, so handler suggests that we clicked somewhere outside and hides dropdown + */} + + {'< Back'} + + (this.inputRef = ref)} + type="text" + placeholder="Username" + value={this.state.usernameValue} + onInput={this.onUsernameChange} + /> + + + {this.state.error && } +
+ ); + + const form2InvalidReason = this.getForm2InvalidReason(); + + return ( +
+ + {'< Back'} + + (this.tokenRef = ref)} + placeholder="Token" + value={this.state.tokenValue} + onInput={this.onTokenChange} + spellcheck={false} + autocomplete="off" + /> + + {this.state.error && } + + ); + } +} + +export const EmailLoginFormConnected = connect( + mapStateToProps, + null, + null, + { withRef: true } +)(EmailLoginForm); diff --git a/frontend/app/components/auth-panel/__email-login-form/index.ts b/frontend/app/components/auth-panel/__email-login-form/index.ts new file mode 100644 index 00000000..eade0573 --- /dev/null +++ b/frontend/app/components/auth-panel/__email-login-form/index.ts @@ -0,0 +1,3 @@ +import './auth-panel__email-login-form.scss'; + +export { EmailLoginForm, EmailLoginFormConnected } from './auth-panel__email-login-form'; diff --git a/frontend/app/components/auth-panel/__select-label-value/auth-panel__select-label-value.scss b/frontend/app/components/auth-panel/__select-label-value/auth-panel__select-label-value.scss new file mode 100644 index 00000000..1aa311c7 --- /dev/null +++ b/frontend/app/components/auth-panel/__select-label-value/auth-panel__select-label-value.scss @@ -0,0 +1,9 @@ +.auth-panel__select-label-value_focused { + outline: 1px dotted; + outline-color: inherit; + + @supports (outline-color: -webkit-focus-ring-color) { + outline-color: -webkit-focus-ring-color; + outline-style: auto; + } +} diff --git a/frontend/app/components/auth-panel/__user-id/index.ts b/frontend/app/components/auth-panel/__user-id/index.ts index e11d552b..0a741abd 100644 --- a/frontend/app/components/auth-panel/__user-id/index.ts +++ b/frontend/app/components/auth-panel/__user-id/index.ts @@ -1,3 +1,3 @@ -export { UserID } from './auth-panel__user-id'; +import './auth-panel__user-id.scss'; -require('./auth-panel__user-id.scss'); +export { UserID } from './auth-panel__user-id'; diff --git a/frontend/app/components/auth-panel/auth-panel.scss b/frontend/app/components/auth-panel/auth-panel.scss index 03c6138a..9988a8a7 100644 --- a/frontend/app/components/auth-panel/auth-panel.scss +++ b/frontend/app/components/auth-panel/auth-panel.scss @@ -3,4 +3,5 @@ justify-content: space-between; font-size: 14px; line-height: 16px; + align-items: baseline; } diff --git a/frontend/app/components/auth-panel/auth-panel.test.tsx b/frontend/app/components/auth-panel/auth-panel.test.tsx index 92e4f53d..07c0de00 100644 --- a/frontend/app/components/auth-panel/auth-panel.test.tsx +++ b/frontend/app/components/auth-panel/auth-panel.test.tsx @@ -1,12 +1,13 @@ /** @jsx h */ -import { h, render } from 'preact'; +import { h } from 'preact'; +import { mount } from 'enzyme'; import { Props, AuthPanel } from './auth-panel'; -import { createDomContainer } from '../../testUtils'; import { User, PostInfo } from '../../common/types'; const DefaultProps: Partial = { sort: '-score', providers: ['google', 'github'], + provider: { name: null }, postInfo: { read_only: false, url: 'https://example.com', @@ -17,125 +18,139 @@ const DefaultProps: Partial = { describe('', () => { describe('For not authorized user', () => { - let container: HTMLElement; - - createDomContainer(domContainer => { - container = domContainer; - }); - it('should render login form with google and github provider', () => { - const element = ; + const element = mount(); - render(element, container); - - const authPanelColumn = container.querySelectorAll('.auth-panel__column'); + const authPanelColumn = element.find('.auth-panel__column'); expect(authPanelColumn.length).toEqual(2); - const authForm = authPanelColumn[0]; + const authForm = authPanelColumn.first(); - expect(authForm.textContent).toEqual(expect.stringContaining('Sign in to comment using')); + expect(authForm.text()).toEqual(expect.stringContaining('Sign in to comment using')); - const providerLinks = authForm.querySelectorAll('.auth-panel__pseudo-link'); + const providerLinks = authForm.find('.auth-panel__pseudo-link'); - expect(providerLinks[0].textContent).toEqual('Google'); - expect(providerLinks[1].textContent).toEqual('GitHub'); + expect(providerLinks.at(0).text()).toEqual('Google'); + expect(providerLinks.at(1).text()).toEqual('GitHub'); + }); + + describe('sorting', () => { + it('should place selected provider first', () => { + const element = mount( + + ); + + const providerLinks = element + .find('.auth-panel__column') + .first() + .find('.auth-panel__pseudo-link'); + + expect(providerLinks.at(0).text()).toEqual('GitHub'); + expect(providerLinks.at(1).text()).toEqual('Google'); + expect(providerLinks.at(2).text()).toEqual('Yandex'); + }); + + it('should do nothing if provider not found', () => { + const element = mount( + + ); + + const providerLinks = element + .find('.auth-panel__column') + .first() + .find('.auth-panel__pseudo-link'); + + expect(providerLinks.at(0).text()).toEqual('Google'); + expect(providerLinks.at(1).text()).toEqual('GitHub'); + expect(providerLinks.at(2).text()).toEqual('Yandex'); + }); }); it('should render login form with google and github provider for read-only post', () => { - const element = ( + const element = mount( ); - render(element, container); - - const authPanelColumn = container.querySelectorAll('.auth-panel__column'); + const authPanelColumn = element.find('.auth-panel__column'); expect(authPanelColumn.length).toEqual(2); - const authForm = authPanelColumn[0]; + const authForm = authPanelColumn.first(); - expect(authForm.textContent).toEqual(expect.stringContaining('Sign in using Google or GitHub')); + expect(authForm.text()).toEqual(expect.stringContaining('Sign in using Google or GitHub')); - const providerLinks = authForm.querySelectorAll('.auth-panel__pseudo-link'); + const providerLinks = authForm.find('.auth-panel__pseudo-link'); - expect(providerLinks[0].textContent).toEqual('Google'); - expect(providerLinks[1].textContent).toEqual('GitHub'); + expect(providerLinks.at(0).text()).toEqual('Google'); + expect(providerLinks.at(1).text()).toEqual('GitHub'); }); it('should not render settings if there is no hidden users', () => { - const element = ( + const element = mount( ); - render(element, container); + const adminAction = element.find('.auth-panel__admin-action'); - const adminAction = container.querySelector('.auth-panel__admin-action')!; - - expect(adminAction).toBe(null); + expect(adminAction.exists()).toBe(false); }); it('should render settings if there is some hidden users', () => { - const element = ( + const element = mount( ); - render(element, container); + const adminAction = element.find('.auth-panel__admin-action'); - const adminAction = container.querySelector('.auth-panel__admin-action')!; - - expect(adminAction.textContent).toEqual('Show settings'); + expect(adminAction.text()).toEqual('Show settings'); }); }); describe('For authorized user', () => { - let container: HTMLElement; - - createDomContainer(domContainer => { - container = domContainer; - }); - it('should render info about current user', () => { - const element = ; + const element = mount(); - render(element, container); - - const authPanelColumn = container.querySelectorAll('.auth-panel__column'); + const authPanelColumn = element.find('.auth-panel__column'); expect(authPanelColumn.length).toEqual(2); - const userInfo = authPanelColumn[0]; + const userInfo = authPanelColumn.first(); - expect(userInfo.textContent).toEqual(expect.stringContaining('You signed in as John')); + expect(userInfo.text()).toEqual(expect.stringContaining('You signed in as John')); }); }); describe('For admin user', () => { - let container: HTMLElement; - - createDomContainer(domContainer => { - container = domContainer; - }); - it('should render admin action', () => { - const element = ; + const element = mount( + + ); - render(element, container); + const adminAction = element.find('.auth-panel__admin-action').first(); - const adminAction = container.querySelector('.auth-panel__admin-action')!; - - expect(adminAction.textContent).toEqual('Show settings'); + expect(adminAction.text()).toEqual('Show settings'); }); }); }); diff --git a/frontend/app/components/auth-panel/auth-panel.tsx b/frontend/app/components/auth-panel/auth-panel.tsx index 0e8b1e39..b77fd3c1 100644 --- a/frontend/app/components/auth-panel/auth-panel.tsx +++ b/frontend/app/components/auth-panel/auth-panel.tsx @@ -11,16 +11,20 @@ import Dropdown, { DropdownItem } from '@app/components/dropdown'; import { Button } from '@app/components/button'; import { UserID } from './__user-id'; import { AnonymousLoginForm } from './__anonymous-login-form'; +import { EmailLoginForm, EmailLoginFormConnected } from './__email-login-form'; import { StoreState } from '@app/store'; +import { ProviderState } from '@app/store/provider/reducers'; +import debounce from '@app/utils/debounce'; export interface Props { user: User | null; hiddenUsers: StoreState['hiddenUsers']; - providers: (AuthProvider['name'])[]; sort: Sorting; isCommentsDisabled: boolean; theme: Theme; postInfo: PostInfo; + providers: (AuthProvider['name'])[]; + provider: ProviderState; onSortChange(s: Sorting): Promise; onSignIn(p: AuthProvider): Promise; @@ -34,24 +38,53 @@ export interface Props { interface State { isBlockedVisible: boolean; anonymousUsernameInputValue: string; + threshold: number; + sortSelectFocused: boolean; } export class AuthPanel extends Component { + emailLoginRef?: EmailLoginForm; + constructor(props: Props) { super(props); this.state = { isBlockedVisible: false, anonymousUsernameInputValue: 'anon', + threshold: 3, + sortSelectFocused: false, }; this.toggleBlockedVisibility = this.toggleBlockedVisibility.bind(this); this.toggleCommentsAvailability = this.toggleCommentsAvailability.bind(this); this.onSortChange = this.onSortChange.bind(this); this.onSignIn = this.onSignIn.bind(this); + this.onEmailSignIn = this.onEmailSignIn.bind(this); this.handleAnonymousLoginFormSubmut = this.handleAnonymousLoginFormSubmut.bind(this); this.handleOAuthLogin = this.handleOAuthLogin.bind(this); this.toggleUserInfoVisibility = this.toggleUserInfoVisibility.bind(this); + this.onEmailTitleClick = this.onEmailTitleClick.bind(this); + } + + componentWillMount() { + this.resizeHandler(); + window.addEventListener('resize', this.resizeHandler); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.resizeHandler); + } + + singInMessageAndSortWidth = 255; + + resizeHandler = debounce(() => { + this.setState({ + threshold: Math.max(3, Math.round((window.innerWidth - this.singInMessageAndSortWidth) / 80)), + }); + }, 100); + + onEmailTitleClick() { + this.emailLoginRef && this.emailLoginRef.focus(); } onSortChange(e: Event) { @@ -60,6 +93,16 @@ export class AuthPanel extends Component { } } + onSortFocus = () => { + this.setState({ sortSelectFocused: true }); + }; + + onSortBlur = (e: Event) => { + this.setState({ sortSelectFocused: false }); + + this.onSortChange(e); + }; + toggleBlockedVisibility() { if (!this.state.isBlockedVisible) { if (this.props.onBlockedUsersShow) this.props.onBlockedUsersShow(); @@ -94,6 +137,10 @@ export class AuthPanel extends Component { this.props.onSignIn(provider); } + onEmailSignIn(token: string) { + return this.props.onSignIn({ name: 'email', token }); + } + async handleAnonymousLoginFormSubmut(username: string) { this.onSignIn({ name: 'anonymous', username }); } @@ -104,152 +151,256 @@ export class AuthPanel extends Component { this.onSignIn({ name: p } as AuthProvider); } - render(props: RenderableProps, { isBlockedVisible }: State) { - const { user, providers = [], sort, isCommentsDisabled } = props; - const sortArray = getSortArray(sort); - const loggedIn = !!user; - const signInMessage = props.postInfo.read_only ? 'Sign in using ' : 'Sign in to comment using '; + renderAuthorized = () => { + const { user, onSignOut } = this.props; + if (!user) return null; + const isUserAnonymous = user && user.id.substr(0, 10) === 'anonymous_'; - const isSettingsLabelVisible = - Object.keys(this.props.hiddenUsers).length > 0 || (user && user.admin) || this.state.isBlockedVisible; return ( -
- {user && ( -
- You signed in as{' '} - - - - +
+ You signed in as{' '} + + + + - {!isUserAnonymous && ( - - - - )} - {' '} - -
- )} - - {IS_STORAGE_AVAILABLE && !loggedIn && ( -
- {signInMessage} - {providers.map((provider, i) => { - const comma = i === 0 ? '' : i === providers.length - 1 ? ' or ' : ', '; - - if (provider === 'anonymous') { - return ( - - {comma}{' '} - - - - - - - ); - } - - return ( - - {comma} - - {PROVIDER_NAMES[provider]} - - - ); - })} -
- )} - - {!IS_STORAGE_AVAILABLE && IS_THIRD_PARTY && ( -
- Disable third-party cookies blocking to sign in or open comments in{' '} - - new page - -
- )} - - {!IS_STORAGE_AVAILABLE && !IS_THIRD_PARTY && ( -
Allow cookies to sign in and comment
- )} - -
- {isSettingsLabelVisible && ( - this.toggleBlockedVisibility())} - role="link" - > - {isBlockedVisible ? 'Hide' : 'Show'} settings - + {!isUserAnonymous && ( + + + )} + {' '} + +
+ ); + }; + + renderProvider = (provider: AuthProvider['name'], dropdown: boolean = false) => { + if (provider === 'anonymous') { + return ( + + + + + + ); + } + if (provider === 'email') { + return ( + + + (this.emailLoginRef = ref ? ref.getWrappedInstance() : null)} + onSignIn={this.onEmailSignIn} + theme={this.props.theme} + className="auth-panel__email-login-form" + /> + + + ); + } + + return ( + + {PROVIDER_NAMES[provider]} + + ); + }; + + renderOther = (providers: (AuthProvider['name'])[]) => { + return ( + + {providers.map(provider => ( + {this.renderProvider(provider, true)} + ))} + + ); + }; + + renderUnauthorized = () => { + const { user, providers = [], postInfo } = this.props; + const { threshold } = this.state; + if (user || !IS_STORAGE_AVAILABLE) return null; + + const signInMessage = postInfo.read_only ? 'Sign in using ' : 'Sign in to comment using '; + const sortedProviders = ((): typeof providers => { + if (!this.props.provider.name) return providers; + const lastProviderIndex = providers.indexOf(this.props.provider.name as typeof providers[0]); + if (lastProviderIndex < 1) return providers; + return [ + this.props.provider.name as typeof providers[0], + ...providers.slice(0, lastProviderIndex), + ...providers.slice(lastProviderIndex + 1), + ]; + })(); + + const isAboveThreshold = sortedProviders.length > threshold; + + return ( +
+ {signInMessage} + {!isAboveThreshold && + sortedProviders.map((provider, i) => { + const comma = i === 0 ? '' : i === sortedProviders.length - 1 ? ' or ' : ', '; + + return ( + + {comma} + {this.renderProvider(provider)} + + ); + })} + {isAboveThreshold && + sortedProviders.slice(0, threshold - 1).map((provider, i) => { + const comma = i === 0 ? '' : ', '; + + return ( + + {comma} + {this.renderProvider(provider)} + + ); + })} + {isAboveThreshold && ( + + {' or '} + {this.renderOther(sortedProviders.slice(threshold - 1))} + + )} +
+ ); + }; + + renderThirdPartyWarning = () => { + if (IS_STORAGE_AVAILABLE || !IS_THIRD_PARTY) return null; + return ( +
+ Disable third-party cookies blocking to sign in or open comments in{' '} + + new page + +
+ ); + }; + + renderCookiesWarning = () => { + if (IS_STORAGE_AVAILABLE || IS_THIRD_PARTY) return null; + return
Allow cookies to sign in and comment
; + }; + + renderSettingsLabel = () => { + return ( + this.toggleBlockedVisibility())} + role="link" + > + {this.state.isBlockedVisible ? 'Hide' : 'Show'} settings + + ); + }; + + renderReadOnlySwitch = () => { + const { isCommentsDisabled } = this.props; + return ( + this.toggleCommentsAvailability())} + role="link" + > + {isCommentsDisabled ? 'Enable' : 'Disable'} comments + + ); + }; + + renderSort = () => { + const { sort } = this.props; + const { sortSelectFocused } = this.state; + const sortArray = getSortArray(sort); + return ( + + Sort by{' '} + + + {sortArray.find(x => 'selected' in x && x.selected!)!.label} + + + + + ); + }; + + render(props: RenderableProps, { isBlockedVisible }: State) { + const { + user, + postInfo: { read_only }, + theme, + } = props; + const isAdmin = user && user.admin; + const isSettingsLabelVisible = Object.keys(this.props.hiddenUsers).length > 0 || isAdmin || isBlockedVisible; + + return ( +
+ {this.renderAuthorized()} + {this.renderUnauthorized()} + {this.renderThirdPartyWarning()} + {this.renderCookiesWarning()} +
+ {isSettingsLabelVisible && this.renderSettingsLabel()} {isSettingsLabelVisible && ' • '} - {user && user.admin && ( - this.toggleCommentsAvailability())} - role="link" - > - {isCommentsDisabled ? 'Enable' : 'Disable'} comments - - )} + {isAdmin && this.renderReadOnlySwitch()} - {user && user.admin && ' • '} + {isAdmin && ' • '} - {!(user && user.admin) && props.postInfo.read_only && ( - Read-only - )} + {!isAdmin && read_only && Read-only} - - Sort by{' '} - - {sortArray.find(x => 'selected' in x && x.selected!)!.label} - - - + {this.renderSort()}
); diff --git a/frontend/app/components/auth-panel/index.ts b/frontend/app/components/auth-panel/index.ts index e3fb738d..7e03ca7f 100644 --- a/frontend/app/components/auth-panel/index.ts +++ b/frontend/app/components/auth-panel/index.ts @@ -1,19 +1,22 @@ +import './auth-panel.scss'; + +import './__readonly-label/auth-panel__readonly-label.scss'; + +import './__column/auth-panel__column.scss'; +import './__pseudo-link/auth-panel__pseudo-link.scss'; +import './__select/auth-panel__select.scss'; +import './__select-label/auth-panel__select-label.scss'; +import './__select-label-value/auth-panel__select-label-value.scss'; +import './__sort/auth-panel__sort.scss'; + +import './__user-id/auth-panel__user-id.scss'; +import './__sign-out/auth-panel__sign-out.scss'; + +import './_theme/_dark/auth-panel_theme_dark.scss'; +import './_theme/_light/auth-panel_theme_light.scss'; + +import './_logged-in/auth-panel_logged-in.scss'; + +import './__dropdown-provider/auth-panel__dropdown-provider.scss'; + export { AuthPanel } from './auth-panel'; - -require('./auth-panel.scss'); - -require('./__readonly-label/auth-panel__readonly-label.scss'); - -require('./__column/auth-panel__column.scss'); -require('./__pseudo-link/auth-panel__pseudo-link.scss'); -require('./__select/auth-panel__select.scss'); -require('./__select-label/auth-panel__select-label.scss'); -require('./__sort/auth-panel__sort.scss'); - -require('./__user-id/auth-panel__user-id.scss'); -require('./__sign-out/auth-panel__sign-out.scss'); - -require('./_theme/_dark/auth-panel_theme_dark.scss'); -require('./_theme/_light/auth-panel_theme_light.scss'); - -require('./_logged-in/auth-panel_logged-in.scss'); diff --git a/frontend/app/components/avatar-icon/index.ts b/frontend/app/components/avatar-icon/index.ts index bf1046e9..dc67c600 100644 --- a/frontend/app/components/avatar-icon/index.ts +++ b/frontend/app/components/avatar-icon/index.ts @@ -1,4 +1,4 @@ -export { AvatarIcon } from './avatar-icon'; +import './avatar-icon.scss'; +import './_default/avatar-icon_default.scss'; -require('./avatar-icon.scss'); -require('./_default/avatar-icon_default.scss'); +export { AvatarIcon } from './avatar-icon'; diff --git a/frontend/app/components/button/index.ts b/frontend/app/components/button/index.ts index 056a4772..bbd5ea59 100644 --- a/frontend/app/components/button/index.ts +++ b/frontend/app/components/button/index.ts @@ -1,8 +1,8 @@ +import './button.scss'; + +import './_kind/_link/button_kind_link.scss'; +import './_kind/_text/button_kind_text.scss'; + +import './_focused/button_focused.scss'; + export { Button } from './button'; - -require('./button.scss'); - -require('./_kind/_link/button_kind_link.scss'); -require('./_kind/_text/button_kind_text.scss'); - -require('./_focused/button_focused.scss'); diff --git a/frontend/app/components/comment/__controls/comment__controls.scss b/frontend/app/components/comment/__controls/comment__controls.scss index 056a60ad..c01d01bd 100644 --- a/frontend/app/components/comment/__controls/comment__controls.scss +++ b/frontend/app/components/comment/__controls/comment__controls.scss @@ -4,10 +4,13 @@ user-select: none; font-size: 14px; font-weight: 700; - opacity: 0; - &:hover, - &:focus-within { - opacity: 1; + @media (hover: hover) { + opacity: 0; + + &:hover, + &:focus-within { + opacity: 1; + } } } diff --git a/frontend/app/components/comment/__vote/_type/_down/comment__vote_type_down.scss b/frontend/app/components/comment/__vote/_type/_down/comment__vote_type_down.scss index 5caf0646..4c8db682 100644 --- a/frontend/app/components/comment/__vote/_type/_down/comment__vote_type_down.scss +++ b/frontend/app/components/comment/__vote/_type/_down/comment__vote_type_down.scss @@ -2,7 +2,8 @@ transform: scale(1, -1); margin-left: 4px; - &.comment__vote_selected, &:hover { + &.comment__vote_selected, + &:hover { background-image: url('comment__vote_type_down.svg'); } } diff --git a/frontend/app/components/comment/__vote/_type/_up/comment__vote_type_up.scss b/frontend/app/components/comment/__vote/_type/_up/comment__vote_type_up.scss index c3a78603..5fb20825 100644 --- a/frontend/app/components/comment/__vote/_type/_up/comment__vote_type_up.scss +++ b/frontend/app/components/comment/__vote/_type/_up/comment__vote_type_up.scss @@ -1,7 +1,8 @@ .comment__vote_type_up { margin-right: 4px; - &.comment__vote_selected, &:hover { + &.comment__vote_selected, + &:hover { background-image: url('comment__vote_type_up.svg'); } } diff --git a/frontend/app/components/comment/comment.test.tsx b/frontend/app/components/comment/comment.test.tsx index 14a26ebd..7f86b714 100644 --- a/frontend/app/components/comment/comment.test.tsx +++ b/frontend/app/components/comment/comment.test.tsx @@ -1,9 +1,9 @@ /** @jsx h */ -import { h, render } from 'preact'; +import { h } from 'preact'; +import { mount } from 'enzyme'; import { Props, Comment } from './comment'; -import { createDomContainer } from '../../testUtils'; import { User, Comment as CommentType, PostInfo } from '@app/common/types'; -import { delay } from '@app/store/comments/utils'; +import { sleep } from '@app/utils/sleep'; const DefaultProps: Partial = { post_info: { @@ -30,193 +30,196 @@ const DefaultProps: Partial = { describe('', () => { describe('voting', () => { - let container: HTMLElement; - - createDomContainer(domContainer => { - container = domContainer; - }); - it('disabled on user info widget', () => { - const element = ; - render(element, container); + const element = mount(); - const voteButtons = container.querySelectorAll('.comment__vote'); + const voteButtons = element.find('.comment__vote'); expect(voteButtons.length).toStrictEqual(2); - for (const b of voteButtons as any) { - expect(b.getAttribute('aria-disabled')).toStrictEqual('true'); - expect(b.getAttribute('title')).toStrictEqual("Voting allowed only on post's page"); - } + voteButtons.forEach(b => { + expect(b.getDOMNode().getAttribute('aria-disabled')).toStrictEqual('true'); + expect(b.getDOMNode().getAttribute('title')).toStrictEqual("Voting allowed only on post's page"); + }); }); it('disabled on read only post', () => { - const element = ( - + const element = mount( + ); - render(element, container); - const voteButtons = container.querySelectorAll('.comment__vote'); + const voteButtons = element.find('.comment__vote'); expect(voteButtons.length).toStrictEqual(2); - for (const b of voteButtons as any) { - expect(b.getAttribute('aria-disabled')).toStrictEqual('true'); - expect(b.getAttribute('title')).toStrictEqual("Can't vote on read-only topics"); - } + voteButtons.forEach(b => { + expect(b.getDOMNode().getAttribute('aria-disabled')).toStrictEqual('true'); + expect(b.getDOMNode().getAttribute('title')).toStrictEqual("Can't vote on read-only topics"); + }); }); it('disabled for deleted comment', () => { - const element = ( + const element = mount( // ahem - + ); - render(element, container); - const voteButtons = container.querySelectorAll('.comment__vote'); + const voteButtons = element.find('.comment__vote'); expect(voteButtons.length).toStrictEqual(2); - for (const b of voteButtons as any) { - expect(b.getAttribute('aria-disabled')).toStrictEqual('true'); - expect(b.getAttribute('title')).toStrictEqual("Can't vote for deleted comment"); - } + voteButtons.forEach(b => { + expect(b.getDOMNode().getAttribute('aria-disabled')).toStrictEqual('true'); + expect(b.getDOMNode().getAttribute('title')).toStrictEqual("Can't vote for deleted comment"); + }); }); it('disabled for guest', () => { - const element = ( + const element = mount( ); - render(element, container); - const voteButtons = container.querySelectorAll('.comment__vote'); + const voteButtons = element.find('.comment__vote'); expect(voteButtons.length).toStrictEqual(2); - for (const b of voteButtons as any) { - expect(b.getAttribute('aria-disabled')).toStrictEqual('true'); - expect(b.getAttribute('title')).toStrictEqual("Can't vote for your own comment"); - } + voteButtons.forEach(b => { + expect(b.getDOMNode().getAttribute('aria-disabled')).toStrictEqual('true'); + expect(b.getDOMNode().getAttribute('title')).toStrictEqual("Can't vote for your own comment"); + }); }); it('disabled for own comment', () => { - const element = ; - render(element, container); + const element = mount(); - const voteButtons = container.querySelectorAll('.comment__vote'); + const voteButtons = element.find('.comment__vote'); expect(voteButtons.length).toStrictEqual(2); - for (const b of voteButtons as any) { - expect(b.getAttribute('aria-disabled')).toStrictEqual('true'); - expect(b.getAttribute('title')).toStrictEqual('Sign in to vote'); - } + voteButtons.forEach(b => { + expect(b.getDOMNode().getAttribute('aria-disabled')).toStrictEqual('true'); + expect(b.getDOMNode().getAttribute('title')).toStrictEqual('Sign in to vote'); + }); }); it('disabled for already upvoted comment', async () => { const voteSpy = jest.fn(async () => {}); - const element = ( + const element = mount( ); - render(element, container); - const voteButtons = container.querySelectorAll('.comment__vote'); + const voteButtons = element.find('.comment__vote'); expect(voteButtons.length).toStrictEqual(2); - expect(voteButtons[0].getAttribute('aria-disabled')).toStrictEqual('true'); - voteButtons[0].click(); - await delay(100); + expect( + voteButtons + .at(0) + .getDOMNode() + .getAttribute('aria-disabled') + ).toStrictEqual('true'); + voteButtons.at(0).simulate('click'); + await sleep(100); expect(voteSpy).not.toBeCalled(); - expect(voteButtons[1].getAttribute('aria-disabled')).toStrictEqual('false'); - voteButtons[1].click(); - await delay(100); + expect( + voteButtons + .at(1) + .getDOMNode() + .getAttribute('aria-disabled') + ).toStrictEqual('false'); + voteButtons.at(1).simulate('click'); + await sleep(100); expect(voteSpy).toBeCalled(); }, 30000); it('disabled for already downvoted comment', async () => { const voteSpy = jest.fn(async () => {}); - const element = ( + const element = mount( ); - render(element, container); - const voteButtons = container.querySelectorAll('.comment__vote'); + const voteButtons = element.find('.comment__vote'); expect(voteButtons.length).toStrictEqual(2); - expect(voteButtons[1].getAttribute('aria-disabled')).toStrictEqual('true'); - voteButtons[1].click(); - await delay(100); + expect( + voteButtons + .at(1) + .getDOMNode() + .getAttribute('aria-disabled') + ).toStrictEqual('true'); + voteButtons.at(1).simulate('click'); + await sleep(100); expect(voteSpy).not.toBeCalled(); - expect(voteButtons[0].getAttribute('aria-disabled')).toStrictEqual('false'); - voteButtons[0].click(); - await delay(100); + expect( + voteButtons + .at(0) + .getDOMNode() + .getAttribute('aria-disabled') + ).toStrictEqual('false'); + voteButtons.at(0).simulate('click'); + await sleep(100); expect(voteSpy).toBeCalled(); }, 30000); }); describe('admin controls', () => { - let container: HTMLElement; - - createDomContainer(domContainer => { - container = domContainer; - }); - it('for admin if shows admin controls', () => { - const element = ; - render(element, container); + const element = mount( + + ); - const controls = container.querySelectorAll('.comment__controls > span'); - expect(controls!.length).toBe(5); - expect(controls![0].textContent).toBe('Copy'); - expect(controls![1].textContent).toBe('Pin'); - expect(controls![2].textContent).toBe('Hide'); - expect(controls![3].childNodes[0].textContent).toBe('Block'); - expect(controls![4].textContent).toBe('Delete'); + const controls = element.find('.comment__controls > span'); + expect(controls.length).toBe(5); + expect(controls.at(0).text()).toEqual('Copy'); + expect(controls.at(1).text()).toEqual('Pin'); + expect(controls.at(2).text()).toEqual('Hide'); + expect(controls.at(3).getDOMNode().childNodes[0].textContent).toEqual('Block'); + expect(controls.at(4).text()).toEqual('Delete'); }); it('for regular user it shows only "hide"', () => { - const element = ; - render(element, container); + const element = mount( + + ); - const controls = container.querySelectorAll('.comment__controls > span'); - expect(controls!.length).toBe(1); - expect(controls![0].textContent).toBe('Hide'); + const controls = element.find('.comment__controls > span'); + expect(controls.length).toBe(1); + expect(controls.at(0).text()).toEqual('Hide'); }); it('verification badge clickable for admin', () => { - const element = ; - render(element, container); + const element = mount( + + ); - const controls = container.querySelector('.comment__verification')!; - expect(controls.classList.contains('comment__verification_clickable')).toBe(true); + const controls = element.find('.comment__verification').first(); + expect(controls.hasClass('comment__verification_clickable')).toEqual(true); }); it('verification badge not clickable for regular user', () => { - const element = ( + const element = mount( ); - render(element, container); - const controls = container.querySelector('.comment__verification')!; - expect(controls.classList.contains('comment__verification_clickable')).toBe(false); + const controls = element.find('.comment__verification').first(); + expect(controls.hasClass('comment__verification_clickable')).toEqual(false); }); }); }); diff --git a/frontend/app/components/comment/comment.tsx b/frontend/app/components/comment/comment.tsx index cac52d67..ed80a559 100644 --- a/frontend/app/components/comment/comment.tsx +++ b/frontend/app/components/comment/comment.tsx @@ -42,6 +42,7 @@ export type Props = { disabled?: boolean; collapsed?: boolean; theme: Theme; + inView?: boolean; level?: number; mix?: string; getPreview?: typeof getPreview; @@ -64,6 +65,7 @@ export interface State { * without server response */ cachedScore: number; + initial: boolean; } export class Comment extends Component { @@ -80,6 +82,7 @@ export class Comment extends Component { voteErrorMessage: null, scoreDelta: 0, cachedScore: props.data.score, + initial: true, }; this.votingPromise = Promise.resolve(); @@ -91,10 +94,20 @@ export class Comment extends Component { this.blockUser = debounce(this.blockUser, 100).bind(this); } + // getHandleClickProps = (handler?: (e: KeyboardEvent | MouseEvent) => void) => { + // if (this.state.initial) return null; + // if (this.props.inView === false) return null; + // return getHandleClickProps(handler); + // }; + componentWillReceiveProps(nextProps: Props) { this.updateState(nextProps); } + componentDidMount() { + this.setState({ initial: false }); + } + updateState = (props: Props) => { this.setState({ scoreDelta: props.data.vote, @@ -454,15 +467,12 @@ export class Comment extends Component { const o = { ...props.data, controversyText: `Controversy: ${(props.data.controversy || 0).toFixed(2)}`, - text: props.data.text.length - ? props.view === 'preview' + text: + props.view === 'preview' ? getTextSnippet(props.data.text) - : props.data.text - : this.props.isUserBanned - ? 'This user was blocked' - : props.data.delete - ? 'This comment was deleted' - : props.data.text, + : props.data.delete + ? 'This comment was deleted' + : props.data.text, time: formatTime(new Date(props.data.time)), orig: isEditing ? props.data.orig && @@ -532,6 +542,19 @@ export class Comment extends Component { ); } + if (this.props.inView === false) { + const [width, height] = this.base ? [this.base.scrollWidth, this.base.scrollHeight] : [100, 100]; + return ( +
+ ); + } + return (
{ )} - {isAdmin && props.isUserBanned && props.view !== 'user' && Blocked} + {props.isUserBanned && props.view !== 'user' && Blocked} {isAdmin && !props.isUserBanned && props.data.delete && Deleted} diff --git a/frontend/app/components/comment/connected-comment.ts b/frontend/app/components/comment/connected-comment.ts index 4e5dc89b..994288b3 100644 --- a/frontend/app/components/comment/connected-comment.ts +++ b/frontend/app/components/comment/connected-comment.ts @@ -3,6 +3,8 @@ * and should be importded explicitly */ +import './styles'; + import { Comment as CommentType } from '@app/common/types'; import { connect } from 'preact-redux'; @@ -40,7 +42,7 @@ const mapStateToProps = (state: StoreState, cprops: { data: CommentType }) => { > = { editMode: getCommentMode(state, cprops.data.id), user: state.user, - isUserBanned: state.bannedUsers.find(u => u.id === cprops.data.user.id) !== undefined, + isUserBanned: cprops.data.user.block || state.bannedUsers.find(u => u.id === cprops.data.user.id) !== undefined, post_info: state.info, isCommentsDisabled: state.info.read_only || false, theme: state.theme, diff --git a/frontend/app/components/comment/styles.ts b/frontend/app/components/comment/styles.ts index 4acbc281..2a9c9791 100644 --- a/frontend/app/components/comment/styles.ts +++ b/frontend/app/components/comment/styles.ts @@ -1,51 +1,51 @@ +import './comment.scss'; + +import './__action/comment__action.scss'; +import './__action/_type/_collapse/comment__action_type_collapse.scss'; +import './__action/_type/_edit/comment__action_type_edit.scss'; +import './__action/_type/_delete/comment__action_type_delete.scss'; + +import './__edit-timer/comment__edit-timer.scss'; + +import './__body/comment__body.scss'; + +import './__control/comment__control.scss'; +import './__control/_select/comment__control_select.scss'; +import './__control/_select-label/comment__control_select-label.scss'; +import './__control/_view/_inactive/comment__control_view_inactive.scss'; + +import './__controls/comment__controls.scss'; +import './__info/comment__info.scss'; +import './__input/comment__input.scss'; +import './__link-to-parent/comment__link-to-parent.scss'; +import './__score/comment__score.scss'; +import './__score-value/comment__score-value.scss'; +import './__status/comment__status.scss'; +import './__text/comment__text.scss'; +import './__time/comment__time.scss'; +import './__user-id/comment__user-id.scss'; +import './__username/comment__username.scss'; + +import './__verification/comment__verification.scss'; +import './__verification/_active/comment__verification_active.scss'; +import './__verification/_clickable/comment__verification_clickable.scss'; + +import './__vote/comment__vote.scss'; +import './__vote/_disabled/comment__vote_disabled.scss'; +import './__vote/_selected/comment__vote_selected.scss'; +import './__vote/_type/_down/comment__vote_type_down.scss'; +import './__vote/_type/_up/comment__vote_type_up.scss'; + +import './_collapsed/comment_collapsed.scss'; +import './_editing/comment_editing.scss'; +import './_replying/comment_replying.scss'; +import './_useless/comment_useless.scss'; + +import './_view/_admin/comment_view_admin.scss'; +import './_view/_preview/comment_view_preview.scss'; +import './_view/_user/comment_view_user.scss'; + +import './_theme/_dark/comment_theme_dark.scss'; +import './_theme/_light/comment_theme_light.scss'; + import '@app/components/raw-content'; - -require('./comment.scss'); - -require('./__action/comment__action.scss'); -require('./__action/_type/_collapse/comment__action_type_collapse.scss'); -require('./__action/_type/_edit/comment__action_type_edit.scss'); -require('./__action/_type/_delete/comment__action_type_delete.scss'); - -require('./__edit-timer/comment__edit-timer.scss'); - -require('./__body/comment__body.scss'); - -require('./__control/comment__control.scss'); -require('./__control/_select/comment__control_select.scss'); -require('./__control/_select-label/comment__control_select-label.scss'); -require('./__control/_view/_inactive/comment__control_view_inactive.scss'); - -require('./__controls/comment__controls.scss'); -require('./__info/comment__info.scss'); -require('./__input/comment__input.scss'); -require('./__link-to-parent/comment__link-to-parent.scss'); -require('./__score/comment__score.scss'); -require('./__score-value/comment__score-value.scss'); -require('./__status/comment__status.scss'); -require('./__text/comment__text.scss'); -require('./__time/comment__time.scss'); -require('./__user-id/comment__user-id.scss'); -require('./__username/comment__username.scss'); - -require('./__verification/comment__verification.scss'); -require('./__verification/_active/comment__verification_active.scss'); -require('./__verification/_clickable/comment__verification_clickable.scss'); - -require('./__vote/comment__vote.scss'); -require('./__vote/_disabled/comment__vote_disabled.scss'); -require('./__vote/_selected/comment__vote_selected.scss'); -require('./__vote/_type/_down/comment__vote_type_down.scss'); -require('./__vote/_type/_up/comment__vote_type_up.scss'); - -require('./_collapsed/comment_collapsed.scss'); -require('./_editing/comment_editing.scss'); -require('./_replying/comment_replying.scss'); -require('./_useless/comment_useless.scss'); - -require('./_view/_admin/comment_view_admin.scss'); -require('./_view/_preview/comment_view_preview.scss'); -require('./_view/_user/comment_view_user.scss'); - -require('./_theme/_dark/comment_theme_dark.scss'); -require('./_theme/_light/comment_theme_light.scss'); diff --git a/frontend/app/components/countdown/index.tsx b/frontend/app/components/countdown/index.tsx index be17bda9..518f385f 100644 --- a/frontend/app/components/countdown/index.tsx +++ b/frontend/app/components/countdown/index.tsx @@ -32,6 +32,9 @@ export default class Countdown extends Component { }); this.start(); } + componentWillUnmount() { + window.clearInterval(this.intervalID); + } shouldComponentUpdate() { return false; } diff --git a/frontend/app/components/dropdown/__item/dropdown__item.scss b/frontend/app/components/dropdown/__item/dropdown__item.scss index 7ad17863..1f1a37ba 100644 --- a/frontend/app/components/dropdown/__item/dropdown__item.scss +++ b/frontend/app/components/dropdown/__item/dropdown__item.scss @@ -1,6 +1,6 @@ .dropdown__item { - a, - button { + & > a, + & > button { display: block; width: 100%; text-align: left; diff --git a/frontend/app/components/dropdown/_active/dropdown_active.scss b/frontend/app/components/dropdown/_active/dropdown_active.scss index 5a3e604b..3316d0eb 100644 --- a/frontend/app/components/dropdown/_active/dropdown_active.scss +++ b/frontend/app/components/dropdown/_active/dropdown_active.scss @@ -1,5 +1,5 @@ .dropdown_active { - .dropdown__content { + & > .dropdown__content { display: block; } } diff --git a/frontend/app/components/dropdown/dropdown.tsx b/frontend/app/components/dropdown/dropdown.tsx index 82359008..b4ffdda0 100644 --- a/frontend/app/components/dropdown/dropdown.tsx +++ b/frontend/app/components/dropdown/dropdown.tsx @@ -4,6 +4,7 @@ import b from 'bem-react-helper'; import { Button } from '@app/components/button'; import { Theme } from '@app/common/types'; +import { sleep } from '@app/utils/sleep'; interface Props { title: string; @@ -13,10 +14,13 @@ interface Props { onTitleClick?: () => void; mix?: string; theme: Theme; + onOpen?: (root: HTMLDivElement) => unknown; + onClose?: (root: HTMLDivElement) => unknown; } interface State { isActive: boolean; + contentTranslateX: number; } export default class Dropdown extends Component { @@ -27,53 +31,149 @@ export default class Dropdown extends Component { this.state = { isActive: props.isActive || false, + contentTranslateX: 0, }; + + this.onOutsideClick = this.onOutsideClick.bind(this); + this.receiveMessage = this.receiveMessage.bind(this); + this.__onOpen = this.__onOpen.bind(this); + this.__onClose = this.__onClose.bind(this); } onTitleClick() { - this.setState({ - isActive: !this.state.isActive, - }); + const isActive = !this.state.isActive; + const contentTranslateX = isActive ? this.state.contentTranslateX : 0; + this.setState( + { + contentTranslateX, + isActive, + }, + async () => { + await this.__adjustDropDownContent(); + if (isActive) { + this.__onOpen(); + this.props.onOpen && this.props.onOpen(this.rootNode!); + } else { + this.__onClose(); + this.props.onClose && this.props.onClose(this.rootNode!); + } - if (this.props.onTitleClick) { - this.props.onTitleClick(); + if (this.props.onTitleClick) { + this.props.onTitleClick(); + } + } + ); + } + + storedDocumentHeight: string | null = null; + storedDocumentHeightSet: boolean = false; + checkInterval: number | undefined = undefined; + + __onOpen() { + const isChildOfDropDown = (() => { + if (!this.rootNode) return false; + let parent = this.rootNode.parentElement!; + while (parent !== document.body) { + if (parent.classList.contains('dropdown')) return true; + parent = parent.parentElement!; + } + return false; + })(); + if (isChildOfDropDown) return; + + this.storedDocumentHeight = document.body.style.minHeight; + this.storedDocumentHeightSet = true; + + let prevDcBottom: number | null = null; + + this.checkInterval = window.setInterval(() => { + if (!this.rootNode || !this.state.isActive) return; + const windowHeight = window.innerHeight; + const dcBottom = (() => { + const dc = Array.from(this.rootNode.children).find(c => c.classList.contains('dropdown__content')); + if (!dc) return 0; + const rect = dc.getBoundingClientRect(); + return window.scrollY + Math.abs(rect.top) + dc.scrollHeight + 10; + })(); + if (prevDcBottom === null && dcBottom <= windowHeight) return; + if (dcBottom !== prevDcBottom) { + prevDcBottom = dcBottom; + document.body.style.minHeight = dcBottom + 'px'; + } + }, 100); + } + + __onClose() { + window.clearInterval(this.checkInterval); + if (this.storedDocumentHeightSet) { + document.body.style.minHeight = this.storedDocumentHeight; } } + async __adjustDropDownContent() { + if (!this.rootNode) return; + const dc = this.rootNode.querySelector('.dropdown__content'); + if (!dc) return; + await sleep(10); + const rect = dc.getBoundingClientRect(); + if (rect.left > 0) { + const wWindow = window.innerWidth; + if (rect.right <= wWindow) return; + const delta = rect.right - wWindow; + const max = Math.min(rect.left, delta); + this.setState({ + contentTranslateX: -max, + }); + return; + } + this.setState({ + contentTranslateX: -rect.left, + }); + } + receiveMessage(e: { data: string | object }) { try { const data = typeof e.data === 'string' ? JSON.parse(e.data) : e.data; - if (data.clickOutside) { - if (this.state.isActive) { - this.setState({ - isActive: false, - }); + if (!data.clickOutside) return; + if (!this.state.isActive) return; + this.setState( + { + contentTranslateX: 0, + isActive: false, + }, + () => { + this.__onClose(); + this.props.onClose && this.props.onClose(this.rootNode!); } - } + ); } catch (e) {} } onOutsideClick(e: MouseEvent) { - if (this.rootNode && !this.rootNode.contains(e.target as Node)) { - if (this.state.isActive) { - this.setState({ - isActive: false, - }); + if (!this.rootNode || this.rootNode.contains(e.target as Node) || !this.state.isActive) return; + this.setState( + { + contentTranslateX: 0, + isActive: false, + }, + () => { + this.__onClose(); + this.props.onClose && this.props.onClose(this.rootNode!); } - } + ); } componentDidMount() { - document.addEventListener('click', e => this.onOutsideClick(e)); + document.addEventListener('click', this.onOutsideClick); - window.addEventListener('message', e => this.receiveMessage(e)); + window.addEventListener('message', this.receiveMessage); } componentWillUnmount() { - document.removeEventListener('click', e => this.onOutsideClick(e)); + document.removeEventListener('click', this.onOutsideClick); - window.removeEventListener('message', e => this.receiveMessage(e)); + window.removeEventListener('message', this.receiveMessage); } render(props: RenderableProps, { isActive }: State) { @@ -93,7 +193,12 @@ export default class Dropdown extends Component { {title} -
+
{heading &&
{heading}
}
{children}
diff --git a/frontend/app/components/dropdown/index.ts b/frontend/app/components/dropdown/index.ts index ff172454..c079805c 100644 --- a/frontend/app/components/dropdown/index.ts +++ b/frontend/app/components/dropdown/index.ts @@ -1,16 +1,16 @@ +import './dropdown.scss'; +import './_active/dropdown_active.scss'; + +import './__item/dropdown__item.scss'; +import './__items/dropdown__items.scss'; +import './__title/dropdown__title.scss'; +import './__content/dropdown__content.scss'; + +import './_theme/_dark/dropdown_theme_dark.scss'; +import './_theme/_light/dropdown_theme_light.scss'; + import Dropdown from './dropdown'; export default Dropdown; export { default as DropdownItem } from './__item'; - -require('./dropdown.scss'); -require('./_active/dropdown_active.scss'); - -require('./__item/dropdown__item.scss'); -require('./__items/dropdown__items.scss'); -require('./__title/dropdown__title.scss'); -require('./__content/dropdown__content.scss'); - -require('./_theme/_dark/dropdown_theme_dark.scss'); -require('./_theme/_light/dropdown_theme_light.scss'); diff --git a/frontend/app/components/input/__markdown-toolbar/input__markdown-toolbar.scss b/frontend/app/components/input/__markdown-toolbar/input__markdown-toolbar.scss index 1122ca4e..fd58dca5 100644 --- a/frontend/app/components/input/__markdown-toolbar/input__markdown-toolbar.scss +++ b/frontend/app/components/input/__markdown-toolbar/input__markdown-toolbar.scss @@ -3,6 +3,14 @@ float: right; } +.input__toolbar-file-input { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0 0 0 0); +} + .input__toolbar-item { background: none; border: 0; diff --git a/frontend/app/components/input/input.tsx b/frontend/app/components/input/input.tsx index 158982e8..8478e8a9 100644 --- a/frontend/app/components/input/input.tsx +++ b/frontend/app/components/input/input.tsx @@ -58,7 +58,7 @@ interface State { const Labels = { main: 'Send', - edit: 'Edit', + edit: 'Save', reply: 'Reply', }; @@ -92,6 +92,7 @@ export class Input extends Component { this.appendError = this.appendError.bind(this); this.uploadImage = this.uploadImage.bind(this); this.uploadImages = this.uploadImages.bind(this); + this.onPaste = this.onPaste.bind(this); } componentWillReceiveProps(nextProps: Props) { @@ -135,6 +136,15 @@ export class Input extends Component { }); } + async onPaste(e: ClipboardEvent) { + if (!(e.clipboardData && e.clipboardData.files.length > 0)) { + return; + } + e.preventDefault(); + const files = Array.from(e.clipboardData.files); + await this.uploadImages(files); + } + send(e: Event) { const text = this.state.text; const props = this.props; @@ -354,11 +364,16 @@ export class Input extends Component { onDrop={this.onDrop} >
- +
(this.textAreaRef = ref)} className="input__field" placeholder="Your comment here" @@ -368,6 +383,7 @@ export class Input extends Component { onKeyDown={this.onKeyDown} disabled={isDisabled} autofocus={!!props.autofocus} + spellcheck={true} /> {charactersLeft < 100 && {charactersLeft}} diff --git a/frontend/app/components/input/markdown-toolbar-icons/image-icon.tsx b/frontend/app/components/input/markdown-toolbar-icons/image-icon.tsx new file mode 100644 index 00000000..d1766ab1 --- /dev/null +++ b/frontend/app/components/input/markdown-toolbar-icons/image-icon.tsx @@ -0,0 +1,13 @@ +/** @jsx h */ +import { h } from 'preact'; + +export default function ImageIcon() { + return ( + + ); +} diff --git a/frontend/app/components/input/markdown-toolbar.tsx b/frontend/app/components/input/markdown-toolbar.tsx index a50c9ba5..9c29ebe7 100644 --- a/frontend/app/components/input/markdown-toolbar.tsx +++ b/frontend/app/components/input/markdown-toolbar.tsx @@ -7,11 +7,23 @@ import ItalicIcon from './markdown-toolbar-icons/italic-icon'; import QuoteIcon from './markdown-toolbar-icons/quote-icon'; import CodeIcon from './markdown-toolbar-icons/code-icon'; import LinkIcon from './markdown-toolbar-icons/link-icon'; +import ImageIcon from './markdown-toolbar-icons/image-icon'; import UnorderedListIcon from './markdown-toolbar-icons/unordered-list-icon'; import OrderedListIcon from './markdown-toolbar-icons/ordered-list-icon'; interface Props { textareaId: string; + uploadImages: (files: File[]) => Promise; + allowUpload: boolean; +} + +interface FileEventTarget extends EventTarget { + readonly files: FileList | null; + value: string | null; +} + +interface FileInputEvent extends Event { + readonly currentTarget: FileEventTarget | null; } const boldLabel = 'Add bold text '; @@ -22,8 +34,20 @@ const codeLabel = 'Insert a code'; const linkLabel = 'Add a link '; const unorderedListLabel = 'Add a bulleted list'; const orderedListLabel = 'Add a numbered list'; +const attachImageLabel = 'Attach the image, drag & drop or paste from clipboard'; export default class MarkdownToolbar extends Component { + constructor(props: Props) { + super(props); + this.uploadImages = this.uploadImages.bind(this); + } + async uploadImages(e: Event) { + const currentTarget = (e as FileInputEvent).currentTarget; + if (!(this.props.allowUpload && currentTarget && currentTarget.files && currentTarget.files.length !== 0)) return; + const files = Array.from(currentTarget.files); + await this.props.uploadImages(files); + currentTarget.value = null; + } render(props: RenderableProps) { return ( @@ -48,6 +72,12 @@ export default class MarkdownToolbar extends Component { + {this.props.allowUpload ? ( + + ) : null}
diff --git a/frontend/app/components/input/styles.ts b/frontend/app/components/input/styles.ts index 450bcf82..c75b61dc 100644 --- a/frontend/app/components/input/styles.ts +++ b/frontend/app/components/input/styles.ts @@ -1,25 +1,25 @@ +import './input.scss'; + +import './__actions/input__actions.scss'; + +import './__button/input__button.scss'; +import './__button/_type/_preview/input__button_type_preview.scss'; +import './__button/_type/_send/input__button_type_send.scss'; + +import './__control-panel/input__control-panel.scss'; +import './__counter/input__counter.scss'; +import './__error/input__error.scss'; +import './__field/input__field.scss'; +import './__field-wrapper/input__field-wrapper.scss'; +import './__preview/input__preview.scss'; +import './__preview-wrapper/input__preview-wrapper.scss'; +import './__rss/input__rss.scss'; +import './__rss-link/input__rss-link.scss'; +import './__markdown/input__markdown.scss'; +import './__markdown-link/input__markdown-link.scss'; +import './__markdown-toolbar/input__markdown-toolbar.scss'; + +import './_theme/_dark/input_theme_dark.scss'; +import './_theme/_light/input_theme_light.scss'; + import '@app/components/raw-content'; - -require('./input.scss'); - -require('./__actions/input__actions.scss'); - -require('./__button/input__button.scss'); -require('./__button/_type/_preview/input__button_type_preview.scss'); -require('./__button/_type/_send/input__button_type_send.scss'); - -require('./__control-panel/input__control-panel.scss'); -require('./__counter/input__counter.scss'); -require('./__error/input__error.scss'); -require('./__field/input__field.scss'); -require('./__field-wrapper/input__field-wrapper.scss'); -require('./__preview/input__preview.scss'); -require('./__preview-wrapper/input__preview-wrapper.scss'); -require('./__rss/input__rss.scss'); -require('./__rss-link/input__rss-link.scss'); -require('./__markdown/input__markdown.scss'); -require('./__markdown-link/input__markdown-link.scss'); -require('./__markdown-toolbar/input__markdown-toolbar.scss'); - -require('./_theme/_dark/input_theme_dark.scss'); -require('./_theme/_light/input_theme_light.scss'); diff --git a/frontend/app/components/list-comments/index.ts b/frontend/app/components/list-comments/index.ts index 7815fcc0..6a0df3e1 100644 --- a/frontend/app/components/list-comments/index.ts +++ b/frontend/app/components/list-comments/index.ts @@ -1,5 +1,5 @@ +import './list-comments.scss'; + +import './__item/list-comments__item.scss'; + export { ListComments } from './list-comments'; - -require('./list-comments.scss'); - -require('./__item/list-comments__item.scss'); diff --git a/frontend/app/components/preloader/preloader.test.tsx b/frontend/app/components/preloader/preloader.test.tsx index 68c2b7c0..9386067e 100644 --- a/frontend/app/components/preloader/preloader.test.tsx +++ b/frontend/app/components/preloader/preloader.test.tsx @@ -1,18 +1,12 @@ /** @jsx h */ -import { h, render } from 'preact'; +import { h } from 'preact'; +import { mount } from 'enzyme'; import Preloader from './preloader'; -import { createDomContainer } from '@app/testUtils'; describe(``, () => { - let container: HTMLElement; - - createDomContainer(domContainer => { - container = domContainer; - }); - it('should render Preloader', () => { - render(, container); + const element = mount(); - expect(container.children[0].className).toEqual('preloader root__preloader'); + expect(element.childAt(0).hasClass('preloader root__preloader')).toEqual(true); }); }); diff --git a/frontend/app/components/raw-content/index.ts b/frontend/app/components/raw-content/index.ts index b66e8692..c5a58809 100644 --- a/frontend/app/components/raw-content/index.ts +++ b/frontend/app/components/raw-content/index.ts @@ -1,4 +1,4 @@ -require('./raw-content.scss'); +import './raw-content.scss'; -require('./_theme/_dark/raw-content_theme_dark.scss'); -require('./_theme/_light/raw-content_theme_light.scss'); +import './_theme/_dark/raw-content_theme_dark.scss'; +import './_theme/_light/raw-content_theme_light.scss'; diff --git a/frontend/app/components/root/in-view/in-view.tsx b/frontend/app/components/root/in-view/in-view.tsx new file mode 100644 index 00000000..ff5d85ca --- /dev/null +++ b/frontend/app/components/root/in-view/in-view.tsx @@ -0,0 +1,72 @@ +import { Component } from 'preact'; +import { sleep } from '@app/utils/sleep'; + +interface Props { + children: (props: { inView: boolean; ref: (ref: Component) => Component }) => JSX.Element; +} + +interface State { + inView: boolean; + ref: Element | undefined; +} + +const instance_map: Map> = new Map(); + +const observer = new IntersectionObserver( + entries => { + entries.forEach(e => { + const instance = instance_map.get(e.target); + if (!instance) return; + instance.setState({ + inView: e.isIntersecting, + }); + }); + }, + { + rootMargin: '50px', + } +); + +export class InView extends Component { + state: State = { + inView: false, + ref: undefined, + }; + + componentWillUpdate(_nextProps: Props, nextState: State) { + if (this.state.ref === nextState.ref) return; + + if (this.state.ref instanceof Element) { + observer.unobserve(this.state.ref); + instance_map.delete(this.state.ref); + } + + if (nextState.ref instanceof Element) { + observer.observe(nextState.ref); + instance_map.set(nextState.ref, this); + } + } + + refSetter = async (ref: Component | null) => { + await sleep(1); + const el = ref ? ref.base : undefined; + if (el === this.state.ref) return; + this.setState({ + ref: ref ? ref.base : undefined, + }); + }; + + componentWillUnmount() { + if (!(this.state.ref instanceof Element)) return; + + observer.unobserve(this.state.ref); + instance_map.delete(this.state.ref); + } + + render() { + const props = { inView: this.state.inView, ref: this.refSetter }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const r = (this.props.children as any)[0](props); + return r; + } +} diff --git a/frontend/app/components/root/index.ts b/frontend/app/components/root/index.ts index 2db6192e..17b01efa 100644 --- a/frontend/app/components/root/index.ts +++ b/frontend/app/components/root/index.ts @@ -1,15 +1,15 @@ +import './root.scss'; + +import './__copyright/root__copyright.scss'; +import './__input/root__input.scss'; +import './__preloader/root__preloader.scss'; +import './__pinned-comment/root__pinned-comment.scss'; +import './__pinned-comments/root__pinned-comments.scss'; +import './__show-more/root__show-more.scss'; +import './__thread/root__thread.scss'; +import './__threads/root__threads.scss'; + +import './_theme/_dark/root_theme_dark.scss'; +import './_theme/_light/root_theme_light.scss'; + export { Root, ConnectedRoot } from './root'; - -require('./root.scss'); - -require('./__copyright/root__copyright.scss'); -require('./__input/root__input.scss'); -require('./__preloader/root__preloader.scss'); -require('./__pinned-comment/root__pinned-comment.scss'); -require('./__pinned-comments/root__pinned-comments.scss'); -require('./__show-more/root__show-more.scss'); -require('./__thread/root__thread.scss'); -require('./__threads/root__threads.scss'); - -require('./_theme/_dark/root_theme_dark.scss'); -require('./_theme/_light/root_theme_light.scss'); diff --git a/frontend/app/components/root/root.tsx b/frontend/app/components/root/root.tsx index ce5ba242..2b226aad 100644 --- a/frontend/app/components/root/root.tsx +++ b/frontend/app/components/root/root.tsx @@ -3,16 +3,7 @@ import { h, Component, RenderableProps } from 'preact'; import { connect } from 'preact-redux'; import b from 'bem-react-helper'; -import { - User, - Node, - PostInfo, - BlockedUser, - Comment as CommentType, - Sorting, - Theme, - AuthProvider, -} from '@app/common/types'; +import { User, Sorting, AuthProvider } from '@app/common/types'; import { NODE_ID, COMMENT_NODE_CLASSNAME_PREFIX, @@ -31,7 +22,7 @@ import { blockUser, unblockUser, fetchBlockedUsers, - setSettingsVisibleState, + setSettingsVisibility, hideUser, unhideUser, } from '@app/store/user/actions'; @@ -51,11 +42,26 @@ import { uploadImage, getPreview } from '@app/common/api'; import { isUserAnonymous } from '@app/utils/isUserAnonymous'; import { bindActions } from '@app/utils/actionBinder'; +const mapStateToProps = (state: StoreState) => ({ + user: state.user, + sort: state.sort, + isSettingsVisible: state.isSettingsVisible, + topComments: state.topComments, + pinnedComments: state.pinnedComments.map(id => state.comments[id]).filter(c => !c.hidden), + provider: state.provider, + theme: state.theme, + info: state.info, + hiddenUsers: state.hiddenUsers, + blockedUsers: state.bannedUsers, + getPreview, + uploadImage, +}); + const boundActions = bindActions({ fetchComments, fetchUser, fetchBlockedUsers, - setSettingsVisible: setSettingsVisibleState, + setSettingsVisibility, logIn, logOut: logout, setTheme, @@ -70,19 +76,7 @@ const boundActions = bindActions({ updateComment, }); -type Props = { - user: User | null; - sort: Sorting; - comments: Node[]; - pinnedComments: CommentType[]; - theme: Theme; - info: PostInfo; - hiddenUsers: StoreState['hiddenUsers']; - blockedUsers: BlockedUser[]; - isSettingsVisible: boolean; - getPreview: typeof getPreview; - uploadImage: typeof uploadImage; -} & typeof boundActions; +type Props = ReturnType & typeof boundActions; interface State { isLoaded: boolean; @@ -168,7 +162,7 @@ export class Root extends Component { if (this.props.user && this.props.user.admin) { await this.props.fetchBlockedUsers(); } - this.props.setSettingsVisible(true); + this.props.setSettingsVisibility(true); } async onBlockedUsersHide() { @@ -176,7 +170,7 @@ export class Root extends Component { if (this.state.wasSomeoneUnblocked) { this.props.fetchComments(this.props.sort); } - this.props.setSettingsVisible(false); + this.props.setSettingsVisibility(false); this.setState({ wasSomeoneUnblocked: false, }); @@ -229,9 +223,10 @@ export class Root extends Component { user={this.props.user} hiddenUsers={this.props.hiddenUsers} sort={this.props.sort} - providers={StaticStore.config.auth_providers} isCommentsDisabled={isCommentsDisabled} postInfo={this.props.info} + providers={StaticStore.config.auth_providers} + provider={this.props.provider} onSignIn={this.logIn} onSignOut={this.logOut} onBlockedUsersShow={this.onBlockedUsersShow} @@ -258,24 +253,34 @@ export class Root extends Component { {this.props.pinnedComments.length > 0 && (
{this.props.pinnedComments.map(comment => ( - + ))}
)} - {!!this.props.comments.length && !isCommentsListLoading && ( + {!!this.props.topComments.length && !isCommentsListLoading && (
- {(IS_MOBILE ? this.props.comments.slice(0, commentsShown) : this.props.comments).map(thread => ( + {(IS_MOBILE && commentsShown < this.props.topComments.length + ? this.props.topComments.slice(0, commentsShown) + : this.props.topComments + ).map(id => ( ))} - {commentsShown < this.props.comments.length && IS_MOBILE && ( + {commentsShown < this.props.topComments.length && IS_MOBILE && ( @@ -320,18 +325,6 @@ export class Root extends Component { /** Root component connected to redux */ export const ConnectedRoot = connect( - (state: StoreState) => ({ - user: state.user, - sort: state.sort, - isSettingsVisible: state.isSettingsVisible, - comments: state.comments, - pinnedComments: state.pinnedComments, - theme: state.theme, - info: state.info, - hiddenUsers: state.hiddenUsers, - blockedUsers: state.bannedUsers, - getPreview, - uploadImage, - }), + mapStateToProps, boundActions )(Root); diff --git a/frontend/app/components/settings/index.ts b/frontend/app/components/settings/index.ts index 085058aa..ba3d40d6 100644 --- a/frontend/app/components/settings/index.ts +++ b/frontend/app/components/settings/index.ts @@ -1,16 +1,16 @@ +import './settings.scss'; + +import './__action/settings__action.scss'; +import './__section/settings__section.scss'; +import './__list/settings__list.scss'; +import './__invisible/settings__invisible.scss'; +import './__dimmed/settings__dimmed.scss'; +import './__username/settings__username.scss'; +import './__user-id/settings__user-id.scss'; +import './_theme/_dark/settings_theme_dark.scss'; +import './_theme/_light/settings_theme_light.scss'; + import withTheme from '../../components/with-theme'; import Settings from './settings'; export default withTheme(Settings); - -require('./settings.scss'); - -require('./__action/settings__action.scss'); -require('./__section/settings__section.scss'); -require('./__list/settings__list.scss'); -require('./__invisible/settings__invisible.scss'); -require('./__dimmed/settings__dimmed.scss'); -require('./__username/settings__username.scss'); -require('./__user-id/settings__user-id.scss'); -require('./_theme/_dark/settings_theme_dark.scss'); -require('./_theme/_light/settings_theme_light.scss'); diff --git a/frontend/app/components/settings/settings.tsx b/frontend/app/components/settings/settings.tsx index 1ced460a..9666f176 100644 --- a/frontend/app/components/settings/settings.tsx +++ b/frontend/app/components/settings/settings.tsx @@ -135,7 +135,7 @@ export default class BlockedUsers extends Component { {formatTime(new Date(user.time))} {isUserUnblocked && ( - this.block(user))} className="blocked-users__action"> + this.block(user))} className="settings__action"> block )} diff --git a/frontend/app/components/thread/index.ts b/frontend/app/components/thread/index.ts index e4069c8f..6fd13765 100644 --- a/frontend/app/components/thread/index.ts +++ b/frontend/app/components/thread/index.ts @@ -1,4 +1,4 @@ -export { ConnectedThread as Thread } from './thread'; +import './thread.scss'; +import './_theme_dark/thread_theme_dark.scss'; -require('./thread.scss'); -require('./_theme_dark/thread_theme_dark.scss'); +export { ConnectedThread as Thread } from './thread'; diff --git a/frontend/app/components/thread/thread.tsx b/frontend/app/components/thread/thread.tsx index d51ebf25..d228c06f 100644 --- a/frontend/app/components/thread/thread.tsx +++ b/frontend/app/components/thread/thread.tsx @@ -4,55 +4,67 @@ import { connect } from 'preact-redux'; import b from 'bem-react-helper'; import { ConnectedComment as Comment } from '@app/components/comment/connected-comment'; -import { Node, Theme } from '@app/common/types'; +import { Comment as CommentInterface } from '@app/common/types'; import { getThreadIsCollapsed } from '@app/store/thread/getters'; import { StoreState } from '@app/store'; +import { InView } from '../root/in-view/in-view'; -interface Props { - collapsed: boolean; - data: Node; - isCommentsDisabled: boolean; +const mapStateToProps = (state: StoreState, props: { id: CommentInterface['id'] }) => { + const comment = state.comments[props.id]; + return { + comment, + childs: state.childComments[props.id], + collapsed: getThreadIsCollapsed(state, comment), + isCommentsDisabled: !!state.info.read_only, + theme: state.theme, + }; +}; + +type Props = { + id: CommentInterface['id']; + childs?: (CommentInterface['id'])[]; level: number; - theme: Theme; mix?: string; getPreview(text: string): Promise; -} +} & ReturnType; function Thread(props: RenderableProps) { - const { - collapsed, - data: { comment, replies = [] }, - level, - theme, - } = props; + const { collapsed, comment, childs, level, theme } = props; + + if (comment.hidden) return null; const indented = level > 0; + const repliesCount = childs ? childs.length : 0; return (
- + + {inviewProps => ( + inviewProps.ref(ref)} + key={`comment-${props.id}`} + view="main" + data={comment} + repliesCount={repliesCount} + level={level} + inView={inviewProps.inView} + /> + )} + {!collapsed && - !!replies.length && - replies.map(thread => ( - + childs && + !!childs.length && + childs.map(id => ( + ))}
); } -export const ConnectedThread = connect((state: StoreState, props: { data: Node }) => ({ - collapsed: getThreadIsCollapsed(state, props.data.comment), - isCommentsDisabled: !!state.info.read_only, - theme: state.theme, -}))(Thread); +export const ConnectedThread = connect(mapStateToProps)(Thread); diff --git a/frontend/app/components/user-info/index.ts b/frontend/app/components/user-info/index.ts index 067cda79..2fe6e07f 100644 --- a/frontend/app/components/user-info/index.ts +++ b/frontend/app/components/user-info/index.ts @@ -1,8 +1,8 @@ +import './user-info.scss'; + +import './__avatar/user-info__avatar.scss'; +import './__id/user-info__id.scss'; +import './__preloader/user-info__preloader.scss'; +import './__title/user-info__title.scss'; + export { ConnectedUserInfo as UserInfo } from './user-info'; - -require('./user-info.scss'); - -require('./__avatar/user-info__avatar.scss'); -require('./__id/user-info__id.scss'); -require('./__preloader/user-info__preloader.scss'); -require('./__title/user-info__title.scss'); diff --git a/frontend/app/remark.tsx b/frontend/app/remark.tsx index 9eaa17e9..65ba48ae 100644 --- a/frontend/app/remark.tsx +++ b/frontend/app/remark.tsx @@ -18,6 +18,8 @@ import { StaticStore } from '@app/common/static_store'; import api from '@app/common/api'; import { bindActionCreators } from 'redux'; import { fetchHiddenUsers } from './store/user/actions'; +import { restoreProvider } from './store/provider/actions'; +import { restoreCollapsedThreads } from './store/thread/actions'; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); @@ -37,8 +39,13 @@ async function init(): Promise { return; } - const boundFetchHiddenUsers = bindActionCreators(fetchHiddenUsers, reduxStore.dispatch); - boundFetchHiddenUsers(); + const boundActions = bindActionCreators( + { fetchHiddenUsers, restoreProvider, restoreCollapsedThreads }, + reduxStore.dispatch + ); + boundActions.fetchHiddenUsers(); + boundActions.restoreProvider(); + boundActions.restoreCollapsedThreads(); const params = window.location.search .replace(/^\?/, '') diff --git a/frontend/app/store/actions.ts b/frontend/app/store/actions.ts index f95b2821..dbfcfdd9 100644 --- a/frontend/app/store/actions.ts +++ b/frontend/app/store/actions.ts @@ -5,6 +5,7 @@ import { THEME_ACTIONS } from './theme/types'; import { THREAD_ACTIONS } from './thread/types'; import { USER_ACTIONS } from './user/types'; import { USER_INFO_ACTIONS } from './user-info/types'; +import { PROVIDER_ACTIONS } from './provider/types'; /** Merged store actions */ export type ACTIONS = @@ -14,4 +15,5 @@ export type ACTIONS = | THEME_ACTIONS | THREAD_ACTIONS | USER_ACTIONS - | USER_INFO_ACTIONS; + | USER_INFO_ACTIONS + | PROVIDER_ACTIONS; diff --git a/frontend/app/store/comments/actions.ts b/frontend/app/store/comments/actions.ts index 5fbeb4bd..09d853de 100644 --- a/frontend/app/store/comments/actions.ts +++ b/frontend/app/store/comments/actions.ts @@ -1,56 +1,40 @@ import api from '@app/common/api'; -import { Tree, Comment, Sorting, CommentMode } from '@app/common/types'; +import { Tree, Comment, Sorting, CommentMode, Node } from '@app/common/types'; import { StoreAction, StoreState } from '../index'; import { POST_INFO_SET } from '../post_info/types'; -import { - getPinnedComments, - addComment as uAddComment, - replaceComment as uReplaceComment, - removeComment as uRemoveComment, - setCommentPin as uSetCommentPin, - filterTree, -} from './utils'; -import { COMMENTS_SET, PINNED_COMMENTS_SET, COMMENT_MODE_SET } from './types'; +import { filterTree } from './utils'; +import { COMMENTS_SET, COMMENT_MODE_SET, COMMENTS_APPEND, COMMENTS_EDIT } from './types'; /** sets comments, and put pinned comments in cache */ -export const setComments = (comments: StoreState['comments']): StoreAction => dispatch => { +export const setComments = (comments: Node[]): StoreAction => dispatch => { dispatch({ type: COMMENTS_SET, comments, }); - dispatch({ - type: PINNED_COMMENTS_SET, - comments: getPinnedComments(comments), - }); }; /** appends comment to tree */ -export const addComment = (text: string, title: string, pid?: Comment['id']): StoreAction> => async ( - dispatch, - getState -) => { +export const addComment = ( + text: string, + title: string, + pid?: Comment['id'] +): StoreAction> => async dispatch => { const comment = await api.addComment({ text, title, pid }); - const comments = getState().comments; - dispatch(setComments(uAddComment(comments, comment))); + dispatch({ type: COMMENTS_APPEND, pid: pid || null, comment }); }; /** edits comment in tree */ -export const updateComment = (id: Comment['id'], text: string): StoreAction> => async ( - dispatch, - getState -) => { +export const updateComment = (id: Comment['id'], text: string): StoreAction> => async dispatch => { const comment = await api.updateComment({ id, text }); - const comments = getState().comments; - dispatch(setComments(uReplaceComment(comments, comment))); + dispatch({ type: COMMENTS_EDIT, comment }); }; /** edits comment in tree */ -export const putVote = (id: Comment['id'], value: number): StoreAction> => async (dispatch, getState) => { +export const putVote = (id: Comment['id'], value: number): StoreAction> => async dispatch => { await api.putCommentVote({ id, value }); - const updatedComment = await api.getComment(id); - const comments = getState().comments; - dispatch(setComments(uReplaceComment(comments, updatedComment))); + const comment = await api.getComment(id); + dispatch({ type: COMMENTS_EDIT, comment }); }; /** edits comment in tree */ @@ -63,8 +47,9 @@ export const setPinState = (id: Comment['id'], value: boolean): StoreAction> => } else { await api.removeMyComment(id); } - const comments = getState().comments; - dispatch(setComments(uRemoveComment(comments, id))); + let comment = getState().comments[id]; + comment = { ...comment, delete: true, edit: { summary: '', time: new Date().toISOString() } }; + dispatch({ type: COMMENTS_EDIT, comment }); }; /** fetches comments from server */ diff --git a/frontend/app/store/comments/reducers.ts b/frontend/app/store/comments/reducers.ts index 7f33d525..8ece8c96 100644 --- a/frontend/app/store/comments/reducers.ts +++ b/frontend/app/store/comments/reducers.ts @@ -1,29 +1,129 @@ -import { Node, Comment } from '@app/common/types'; +import { Node, Comment, CommentMode } from '@app/common/types'; -import { StoreState } from '../index'; import { COMMENTS_SET, COMMENTS_SET_ACTION, - PINNED_COMMENTS_SET_ACTION, - PINNED_COMMENTS_SET, COMMENT_MODE_SET, COMMENT_MODE_SET_ACTION, + COMMENTS_APPEND_ACTION, + COMMENTS_APPEND, + COMMENTS_EDIT_ACTION, + COMMENTS_EDIT, + COMMENTS_PATCH, + COMMENTS_PATCH_ACTION, } from './types'; +import { getPinnedComments } from './utils'; +import { cmpRef } from '@app/utils/cmpRef'; -export const comments = (state: StoreState['comments'] = [], action: COMMENTS_SET_ACTION): Node[] => { +export const topComments = ( + state: (Comment['id'])[] = [], + action: COMMENTS_SET_ACTION | COMMENTS_APPEND_ACTION +): (Comment['id'])[] => { switch (action.type) { case COMMENTS_SET: { - return action.comments; + return cmpRef(state, action.comments.map(x => x.comment.id)); + } + case COMMENTS_APPEND: { + if (action.comment.pid) return state; + return [action.comment.id, ...state]; } default: return state; } }; +const reduceChildIds = ( + c: Record, + x: Node +): Record => { + if (!x.replies) return c; + if (!c[x.comment.id]) { + c[x.comment.id] = []; + } + for (const reply of x.replies) { + c[x.comment.id].push(reply.comment.id); + if (reply.replies) { + reduceChildIds(c, reply); + } + } + + return c; +}; + +export const childComments = ( + state: Record = {}, + action: COMMENTS_SET_ACTION | COMMENTS_APPEND_ACTION +): Record => { + switch (action.type) { + case COMMENTS_SET: { + return action.comments.reduce>(reduceChildIds, {}); + } + case COMMENTS_APPEND: { + if (!action.comment.pid) return state; + return { ...state, [action.comment.pid]: [action.comment.id, ...(state[action.comment.pid] || [])] }; + } + default: + return state; + } +}; + +const cmpComment = (a: Comment | undefined, b: Comment): Comment => { + if (!a) return b; + if (a.id !== b.id) return b; + if (!a.edit) { + if (!b.edit) return a; + return b; + } + if (!b.edit) return b; + if (a.edit.time !== b.edit.time) return b; + return a; +}; + +const reduceComments = (c: Record, x: Node): Record => { + c[x.comment.id] = cmpComment(c[x.comment.id], x.comment); + if (x.replies) { + x.replies.reduce(reduceComments, c); + } + return c; +}; + +export const comments = ( + state: Record = {}, + action: COMMENTS_SET_ACTION | COMMENTS_APPEND_ACTION | COMMENTS_EDIT_ACTION | COMMENTS_PATCH_ACTION +): Record => { + switch (action.type) { + case COMMENTS_SET: { + return action.comments.reduce>(reduceComments, { ...state }); + } + case COMMENTS_APPEND: + case COMMENTS_EDIT: { + return { ...state, [action.comment.id]: action.comment }; + } + case COMMENTS_PATCH: { + let newState = state; + let changed = false; + const editObject = { summary: '', time: new Date().toISOString() }; + for (const id of action.ids) { + if (!state.hasOwnProperty(id)) continue; + if (!changed) { + changed = true; + newState = { ...newState }; + } + newState[id] = { ...newState[id], edit: editObject, ...action.patch }; + } + return newState; + } + default: + return state; + } +}; + +export type ActiveCommentState = null | { id: Comment['id']; state: CommentMode }; + export const activeComment = ( - state: StoreState['activeComment'] = null, + state: ActiveCommentState = null, action: COMMENT_MODE_SET_ACTION -): StoreState['activeComment'] => { +): ActiveCommentState => { switch (action.type) { case COMMENT_MODE_SET: { return action.mode; @@ -34,16 +134,40 @@ export const activeComment = ( }; export const pinnedComments = ( - state: StoreState['pinnedComments'] = [], - action: PINNED_COMMENTS_SET_ACTION -): Comment[] => { + state: (Comment['id'])[] = [], + action: COMMENTS_SET_ACTION | COMMENTS_EDIT_ACTION | COMMENTS_PATCH_ACTION +): (Comment['id'])[] => { switch (action.type) { - case PINNED_COMMENTS_SET: { - return action.comments; + case COMMENTS_SET: { + return getPinnedComments(action.comments).map(x => x.id); } + case COMMENTS_EDIT: { + const index = state.indexOf(action.comment.id); + if (!action.comment.pin) { + if (index === -1) return state; + const newState = [...state]; + newState.splice(index, 1); + return newState; + } + if (index !== -1) return state; + return [...state, action.comment.id]; + } + case COMMENTS_PATCH: { + if (!action.patch.hasOwnProperty('pin')) return state; + if (!action.patch.pin) { + return state.filter(x => action.ids.indexOf(x) === -1); + } + return [...state, ...action.ids].reduce<(Comment['id'])[]>((c, x) => { + if (c.indexOf(x) === -1) { + c.push(x); + } + return c; + }, []); + } + default: return state; } }; -export default { comments, activeComment, pinnedComments }; +export default { topComments, childComments, comments, activeComment, pinnedComments }; diff --git a/frontend/app/store/comments/types.ts b/frontend/app/store/comments/types.ts index b92a9c0f..c2bc79aa 100644 --- a/frontend/app/store/comments/types.ts +++ b/frontend/app/store/comments/types.ts @@ -1,32 +1,33 @@ -import { Node } from '@app/common/types'; +import { Node, Comment } from '@app/common/types'; import { StoreState } from '../index'; export const COMMENTS_SET = 'COMMENTS/SET'; export interface COMMENTS_SET_ACTION { type: typeof COMMENTS_SET; - comments: StoreState['comments']; + comments: Node[]; } export const COMMENTS_APPEND = 'COMMENTS/APPEND'; export interface COMMENTS_APPEND_ACTION { type: typeof COMMENTS_APPEND; - comments: Node; + comment: Comment; } -export const PINNED_COMMENTS_SET = 'PINNED_COMMENTS/SET'; +export const COMMENTS_EDIT = 'COMMENTS/EDIT'; -export interface PINNED_COMMENTS_SET_ACTION { - type: typeof PINNED_COMMENTS_SET; - comments: StoreState['pinnedComments']; +export interface COMMENTS_EDIT_ACTION { + type: typeof COMMENTS_EDIT; + comment: Comment; } -export const COMMENTS_FETCH_TREE = 'COMMENTS/FETCH_TREE'; +export const COMMENTS_PATCH = 'COMMENTS/PATCH'; -export interface COMMENTS_FETCH_TREE_ACTION { - type: typeof COMMENTS_FETCH_TREE; - comments: Node[]; +export interface COMMENTS_PATCH_ACTION { + type: typeof COMMENTS_PATCH; + ids: (Comment['id'])[]; + patch: Partial; } export const COMMENT_MODE_SET = 'COMMENT_MODE/SET'; @@ -39,6 +40,6 @@ export interface COMMENT_MODE_SET_ACTION { export type COMMENTS_ACTIONS = | COMMENTS_SET_ACTION | COMMENTS_APPEND_ACTION - | PINNED_COMMENTS_SET_ACTION - | COMMENTS_FETCH_TREE_ACTION + | COMMENTS_EDIT_ACTION + | COMMENTS_PATCH_ACTION | COMMENT_MODE_SET_ACTION; diff --git a/frontend/app/store/comments/utils.ts b/frontend/app/store/comments/utils.ts index 689add16..c7a17393 100644 --- a/frontend/app/store/comments/utils.ts +++ b/frontend/app/store/comments/utils.ts @@ -1,41 +1,4 @@ -import { Comment, Node, User } from '@app/common/types'; - -/** - * Traverses through tree and applies function to comment with given id. - * Note that function must not mutate comment, or rerender will not happen - */ -function mapTreeIfID(tree: Node[], id: Comment['id'], fn: (c: Node) => Node): Node[] { - // path of indexes to comment with given id - let path: number[] = []; - const subfn = (tree: Node[], level: number): boolean => { - for (let i = 0; i < tree.length; i++) { - path = path.slice(0, level); - path.push(i); - if (id === tree[i].comment.id) return true; - if (tree[i].replies) { - if (subfn(tree[i].replies!, level + 1)) return true; - } - } - return false; - }; - if (!subfn(tree, 0)) return tree; - - // dereferencing (cloning) node path to comment with id, - // so react will cause rerender - const treeClone = [...tree]; - let subtree = treeClone; - for (let i = 0; i < path.length; i++) { - const index = path[i]; - if (i === path.length - 1) { - subtree[index] = fn(subtree[index]); - break; - } - subtree[index] = { comment: subtree[index].comment, replies: [...subtree[index].replies!] }; - subtree = subtree[index].replies!; - } - - return treeClone; -} +import { Comment, Node } from '@app/common/types'; /** * Filters tree node @@ -58,22 +21,6 @@ export function filterTree(tree: Node[], fn: (node: Node) => boolean): Node[] { return newTree; } -/** - * Traverses through tree and applies function to comment on which function passed. - * Note that function must not mutate comment - */ -function mapTree(tree: Node[], fn: (c: Comment) => Comment): Node[] { - return tree.map(node => { - const clone: Node = { - comment: fn(node.comment), - }; - if (node.replies) { - clone.replies = mapTree(node.replies, fn); - } - return clone; - }); -} - export function findPinnedComments(thread: Node): Comment[] { let result: Comment[] = []; @@ -93,74 +40,3 @@ export function findPinnedComments(thread: Node): Comment[] { export function getPinnedComments(threads: Node[]): Comment[] { return threads.reduce((acc: Comment[], thread: Node) => acc.concat(findPinnedComments(thread)), []); } - -export function removeComment(comments: Node[], id: Comment['id']): Node[] { - return mapTreeIfID( - comments, - id, - (n): Node => ({ - comment: { - ...n.comment, - delete: true, - }, - replies: n.replies, - }) - ); -} - -export function setCommentPin(comments: Node[], id: Comment['id'], value: boolean): Node[] { - return mapTreeIfID( - comments, - id, - (n): Node => ({ - comment: { - ...n.comment, - pin: value, - }, - replies: n.replies, - }) - ); -} - -export function setUserVerified(comments: Node[], userId: User['id'], value: boolean): Node[] { - return mapTree(comments, comment => { - if (comment.user.id !== userId) return comment; - return { - ...comment, - user: { - ...comment.user, - verified: value, - }, - }; - }); -} - -function pasteReply(comments: Node[], reply: Comment): Node[] { - return mapTreeIfID( - comments, - reply.pid, - (n): Node => { - const nn = { ...n }; - if (!nn.replies) nn.replies = []; - nn.replies = [{ comment: reply }, ...nn.replies]; - return nn; - } - ); -} - -export function addComment(comments: Node[], comment: Comment): Node[] { - if (comment.pid !== '') { - return pasteReply(comments, comment); - } - return [{ comment }, ...comments]; -} - -export function replaceComment(comments: Node[], comment: Comment): Node[] { - return mapTreeIfID(comments, comment.id, n => ({ ...n, comment })); -} - -export function delay(ms: number = 100): Promise { - return new Promise(resolve => { - setTimeout(resolve, ms); - }); -} diff --git a/frontend/app/store/index.ts b/frontend/app/store/index.ts index 3800808a..706f1767 100644 --- a/frontend/app/store/index.ts +++ b/frontend/app/store/index.ts @@ -1,43 +1,13 @@ import { createStore, applyMiddleware, AnyAction, compose } from 'redux'; import { combineReducers } from 'redux'; import thunk, { ThunkAction, ThunkDispatch } from 'redux-thunk'; -import { Comment, User, PostInfo, Node, BlockedUser, Theme, Sorting, CommentMode } from '@app/common/types'; - import storeReducers from './reducers'; import { ACTIONS } from './actions'; -export interface StoreState { - /** Comments sort */ - sort: Sorting; - /** Comments list */ - comments: Node[]; - /** List of pinned comments */ - pinnedComments: Comment[]; - /** Defines comment that is in reply or edit mode */ - activeComment: null | { id: Comment['id']; state: CommentMode }; - /** Logged in user */ - user: User | null; - /** Remark's styling theme */ - theme: Theme; - /** Current post information */ - info: PostInfo; - /** List of banned users */ - bannedUsers: BlockedUser[]; - /** List of hidden users */ - hiddenUsers: { [id: string]: User }; - /** Whether list of blocked users should be visible */ - isSettingsVisible: boolean; - /** Map of collapsed threads */ - collapsedThreads: { - [key: string]: boolean; - }; - /** used in user comments widget */ - userComments?: { - [key: string]: Comment[]; - }; -} +const reducers = combineReducers(storeReducers); + +export type StoreState = ReturnType; -const reducers = combineReducers(storeReducers); const middleware = applyMiddleware(thunk); /** diff --git a/frontend/app/store/post_info/reducers.ts b/frontend/app/store/post_info/reducers.ts index 72f3befc..337782bf 100644 --- a/frontend/app/store/post_info/reducers.ts +++ b/frontend/app/store/post_info/reducers.ts @@ -1,5 +1,6 @@ import { PostInfo } from '@app/common/types'; import { POST_INFO_SET, POST_INFO_SET_ACTION } from './types'; +import { cmpRef } from '@app/utils/cmpRef'; /* eslint-disable @typescript-eslint/camelcase */ const DefaultPostInfo: PostInfo = { @@ -14,7 +15,7 @@ const DefaultPostInfo: PostInfo = { export const info = (state: PostInfo = DefaultPostInfo, action: POST_INFO_SET_ACTION): PostInfo => { switch (action.type) { case POST_INFO_SET: { - return action.info; + return cmpRef(state, action.info); } default: return state; diff --git a/frontend/app/store/provider/actions.ts b/frontend/app/store/provider/actions.ts new file mode 100644 index 00000000..efd2dc28 --- /dev/null +++ b/frontend/app/store/provider/actions.ts @@ -0,0 +1,31 @@ +import { PROVIDER_UPDATE_ACTION, PROVIDER_UPDATE } from './types'; +import { StoreAction } from '..'; +import { setItem, getItem } from '@app/common/local-storage'; + +const PROVIDER_LOCALSTORAGE_KEY = '__remarkProvider'; + +/** saves last login provider from localstorage and put to store */ +export function updateProvider(payload: PROVIDER_UPDATE_ACTION['payload']): StoreAction { + return dispatch => { + setItem(PROVIDER_LOCALSTORAGE_KEY, JSON.stringify(payload)); + dispatch({ + type: PROVIDER_UPDATE, + payload, + }); + }; +} + +/** restores last login provider from localstorage and put to store */ +export function restoreProvider(): StoreAction { + return dispatch => { + const payloadString = getItem(PROVIDER_LOCALSTORAGE_KEY); + if (!payloadString) return; + try { + const payload = JSON.parse(payloadString); + dispatch({ + type: PROVIDER_UPDATE, + payload, + }); + } catch {} + }; +} diff --git a/frontend/app/store/provider/reducers.test.ts b/frontend/app/store/provider/reducers.test.ts new file mode 100644 index 00000000..67238d04 --- /dev/null +++ b/frontend/app/store/provider/reducers.test.ts @@ -0,0 +1,19 @@ +import reducer from './reducers'; +import { PROVIDER_UPDATE } from './types'; + +describe('provider reducer', () => { + it('should set name of provider', () => { + const result = reducer.provider( + { name: null }, + { + type: PROVIDER_UPDATE, + payload: { + name: 'something', + }, + } + ); + expect(result).toStrictEqual({ + name: 'something', + }); + }); +}); diff --git a/frontend/app/store/provider/reducers.ts b/frontend/app/store/provider/reducers.ts new file mode 100644 index 00000000..997f1bd6 --- /dev/null +++ b/frontend/app/store/provider/reducers.ts @@ -0,0 +1,17 @@ +import { PROVIDER_ACTIONS, PROVIDER_UPDATE } from './types'; + +export interface ProviderState { + name: string | null; +} + +function provider(state: ProviderState = { name: null }, action: PROVIDER_ACTIONS): ProviderState { + switch (action.type) { + case PROVIDER_UPDATE: { + return { ...state, ...action.payload }; + } + default: + return state; + } +} + +export default { provider }; diff --git a/frontend/app/store/provider/types.ts b/frontend/app/store/provider/types.ts new file mode 100644 index 00000000..513cc09a --- /dev/null +++ b/frontend/app/store/provider/types.ts @@ -0,0 +1,9 @@ +export const PROVIDER_UPDATE = 'PROVIDER/UPDATE'; +export interface PROVIDER_UPDATE_ACTION { + type: typeof PROVIDER_UPDATE; + payload: { + name: string; + }; +} + +export type PROVIDER_ACTIONS = PROVIDER_UPDATE_ACTION; diff --git a/frontend/app/store/reducers.ts b/frontend/app/store/reducers.ts index 2c7a30db..a3e2f2a6 100644 --- a/frontend/app/store/reducers.ts +++ b/frontend/app/store/reducers.ts @@ -5,6 +5,7 @@ import theme from './theme/reducers'; import user from './user/reducers'; import userInfo from './user-info/reducers'; import thread from './thread/reducers'; +import provider from './provider/reducers'; /** Merged store reducers */ export default { @@ -15,4 +16,5 @@ export default { ...user, ...userInfo, ...thread, + ...provider, }; diff --git a/frontend/app/store/sort/actions.ts b/frontend/app/store/sort/actions.ts index 6ca70e5a..ec4c4d8e 100644 --- a/frontend/app/store/sort/actions.ts +++ b/frontend/app/store/sort/actions.ts @@ -8,7 +8,7 @@ import { SORT_SET, SORT_SET_ACTION } from './types'; function setSortCookie(sort: Sorting) { try { - setCookie(COOKIE_SORT_KEY, sort, { expires: 60 * 60 * 24 * 365 }); // save sorting for a year + setCookie(COOKIE_SORT_KEY, sort, { expires: 60 * 60 * 24 * 365, path: '/' }); // save sorting for a year } catch { // can't save; ignore it } diff --git a/frontend/app/store/thread/actions.ts b/frontend/app/store/thread/actions.ts index 6faa5165..e55e072f 100644 --- a/frontend/app/store/thread/actions.ts +++ b/frontend/app/store/thread/actions.ts @@ -2,8 +2,13 @@ import { Comment } from '@app/common/types'; import { siteId, url } from '@app/common/settings'; import { StoreAction } from '../index'; -import { THREAD_SET_COLLAPSE } from './types'; -import { saveCollapsedComments } from './utils'; +import { THREAD_SET_COLLAPSE, THREAD_RESTORE_COLLAPSE_ACTION, THREAD_RESTORE_COLLAPSE } from './types'; +import { saveCollapsedComments, getCollapsedComments } from './utils'; + +export const restoreCollapsedThreads = (): THREAD_RESTORE_COLLAPSE_ACTION => ({ + type: THREAD_RESTORE_COLLAPSE, + ids: getCollapsedComments(), +}); export const setCollapse = (id: Comment['id'], value: boolean): StoreAction => (dispatch, getState) => { dispatch({ diff --git a/frontend/app/store/thread/reducers.ts b/frontend/app/store/thread/reducers.ts index 7718275b..f21d39e1 100644 --- a/frontend/app/store/thread/reducers.ts +++ b/frontend/app/store/thread/reducers.ts @@ -1,27 +1,23 @@ -import { THREAD_GET_COLLAPSE_ACTION, THREAD_SET_COLLAPSE, THREAD_SET_COLLAPSE_ACTION } from './types'; -import { getCollapsedComments } from './utils'; -import { StoreState } from '../index'; +import { THREAD_SET_COLLAPSE, THREAD_ACTIONS, THREAD_RESTORE_COLLAPSE } from './types'; -const collapsedCommentIds = getCollapsedComments(); +export interface CollapsedThreadsState { + [key: string]: boolean; +} -const initialState: StoreState['collapsedThreads'] = collapsedCommentIds.reduce( - (acc: { [key: string]: boolean }, id) => { - acc[id] = true; - return acc; - }, - {} -); - -export const collapsedThreads = ( - state: StoreState['collapsedThreads'] = initialState, - action: THREAD_GET_COLLAPSE_ACTION | THREAD_SET_COLLAPSE_ACTION -): { [key: string]: boolean } => { +export const collapsedThreads = (state: CollapsedThreadsState = {}, action: THREAD_ACTIONS): CollapsedThreadsState => { switch (action.type) { - case THREAD_SET_COLLAPSE: + case THREAD_RESTORE_COLLAPSE: { + return action.ids.reduce((acc, id) => { + acc[id] = true; + return acc; + }, {}); + } + case THREAD_SET_COLLAPSE: { return { ...state, [action.id]: action.collapsed, }; + } default: return state; } diff --git a/frontend/app/store/thread/types.ts b/frontend/app/store/thread/types.ts index c5afd40e..d4ca8424 100644 --- a/frontend/app/store/thread/types.ts +++ b/frontend/app/store/thread/types.ts @@ -1,8 +1,9 @@ import { Comment } from '@app/common/types'; -export const THREAD_GET_COLLAPSE = 'THREAD/COLLAPSE_GET'; -export interface THREAD_GET_COLLAPSE_ACTION { - type: typeof THREAD_GET_COLLAPSE; +export const THREAD_RESTORE_COLLAPSE = 'THREAD/COLLAPSE_RESTORE'; +export interface THREAD_RESTORE_COLLAPSE_ACTION { + type: typeof THREAD_RESTORE_COLLAPSE; + ids: (Comment['id'])[]; } export const THREAD_SET_COLLAPSE = 'THREAD/COLLAPSE_SET'; @@ -12,4 +13,4 @@ export interface THREAD_SET_COLLAPSE_ACTION { collapsed: boolean; } -export type THREAD_ACTIONS = THREAD_GET_COLLAPSE_ACTION | THREAD_SET_COLLAPSE_ACTION; +export type THREAD_ACTIONS = THREAD_RESTORE_COLLAPSE_ACTION | THREAD_SET_COLLAPSE_ACTION; diff --git a/frontend/app/store/user-info/reducers.ts b/frontend/app/store/user-info/reducers.ts index fffd506d..8995592d 100644 --- a/frontend/app/store/user-info/reducers.ts +++ b/frontend/app/store/user-info/reducers.ts @@ -1,12 +1,12 @@ import { Comment } from '@app/common/types'; -import { StoreState } from '../index'; import { USER_INFO_SET, USER_INFO_ACTIONS } from './types'; -export const userComments = ( - state: StoreState['userComments'] = {}, - action: USER_INFO_ACTIONS -): { [key: string]: Comment[] } => { +export interface UserCommentsState { + [key: string]: Comment[]; +} + +export const userComments = (state: UserCommentsState = {}, action: USER_INFO_ACTIONS): UserCommentsState => { switch (action.type) { case USER_INFO_SET: { return { diff --git a/frontend/app/store/user/actions.ts b/frontend/app/store/user/actions.ts index f71921c9..41388d9b 100644 --- a/frontend/app/store/user/actions.ts +++ b/frontend/app/store/user/actions.ts @@ -8,19 +8,16 @@ import { USER_SET, USER_UNBAN, USER_BANLIST_SET, - USER_HIDELIST_SET_ACTION, USER_HIDELIST_SET, - USER_HIDE_ACTION, USER_HIDE, - USER_UNHIDE_ACTION, USER_UNHIDE, SETTINGS_VISIBLE_SET, } from './types'; -import { setComments, unsetCommentMode } from '../comments/actions'; -import { setUserVerified as uSetUserVerified, filterTree } from '../comments/utils'; +import { unsetCommentMode } from '../comments/actions'; import { IS_STORAGE_AVAILABLE, LS_HIDDEN_USERS_KEY } from '@app/common/constants'; import { getItem } from '@app/common/local-storage'; -import { Dispatch } from 'redux'; +import { updateProvider } from '../provider/actions'; +import { COMMENTS_PATCH } from '../comments/types'; export const fetchUser = (): StoreAction> => async dispatch => { const user = await api.getUser(); @@ -33,6 +30,7 @@ export const fetchUser = (): StoreAction> => async dispatch export const logIn = (provider: AuthProvider): StoreAction> => async dispatch => { const user = await api.logIn(provider); + dispatch(updateProvider({ name: provider.name })); dispatch({ type: USER_SET, user, @@ -74,19 +72,29 @@ export const blockUser = ( }); }; -export const unblockUser = (id: User['id']): StoreAction> => async dispatch => { +export const unblockUser = (id: User['id']): StoreAction> => async (dispatch, getState) => { await api.unblockUser(id); dispatch({ type: USER_UNBAN, id, }); + const comments = Object.values(getState().comments).filter(c => c.user.id === id); + + if (!comments.length) return; + const user = comments[0].user; + + dispatch({ + type: COMMENTS_PATCH, + ids: comments.map(c => c.id), + patch: { user: { ...user, block: false } }, + }); }; export const fetchHiddenUsers = (): StoreAction => dispatch => { if (!IS_STORAGE_AVAILABLE) return; const hiddenUsers = JSON.parse(getItem(LS_HIDDEN_USERS_KEY) || '{}'); - return (dispatch as Dispatch)({ type: USER_HIDELIST_SET, payload: hiddenUsers }); + dispatch({ type: USER_HIDELIST_SET, payload: hiddenUsers }); }; export const hideUser = (user: User): StoreAction => (dispatch, getState) => { @@ -95,13 +103,18 @@ export const hideUser = (user: User): StoreAction => (dispatch, getState) hiddenUsers[user.id] = user; localStorage.setItem(LS_HIDDEN_USERS_KEY, JSON.stringify(hiddenUsers)); } - (dispatch as Dispatch)({ type: USER_HIDE, user }); + dispatch({ type: USER_HIDE, user }); - const comments = getState().comments; - return dispatch(setComments(filterTree(comments, node => node.comment.user.id !== user.id))); + dispatch({ + type: COMMENTS_PATCH, + ids: Object.values(getState().comments) + .filter(c => c.user.id === user.id) + .map(c => c.id), + patch: { hidden: true }, + }); }; -export const unhideUser = (userId: string): StoreAction => dispatch => { +export const unhideUser = (userId: string): StoreAction => (dispatch, _getState) => { if (IS_STORAGE_AVAILABLE) { const hiddenUsers = JSON.parse(getItem(LS_HIDDEN_USERS_KEY) || '{}'); if (hiddenUsers.hasOwnProperty(userId)) { @@ -109,7 +122,10 @@ export const unhideUser = (userId: string): StoreAction => dispatch => { } localStorage.setItem(LS_HIDDEN_USERS_KEY, JSON.stringify(hiddenUsers)); } - return (dispatch as Dispatch)({ type: USER_UNHIDE, id: userId }); + + dispatch({ type: USER_UNHIDE, id: userId }); + + // no need for comments patch as comments will be refetched after action }; export const setVerifiedStatus = (id: User['id'], status: boolean): StoreAction> => async ( @@ -121,11 +137,18 @@ export const setVerifiedStatus = (id: User['id'], status: boolean): StoreAction< } else { await api.removeVerifyStatus(id); } - const comments = getState().comments; - dispatch(setComments(uSetUserVerified(comments, id, status))); + const comments = Object.values(getState().comments).filter(c => c.user.id === id); + if (!comments.length) return; + const user = comments[0].user; + + dispatch({ + type: COMMENTS_PATCH, + ids: comments.map(c => c.id), + patch: { user: { ...user, verified: status } }, + }); }; -export const setSettingsVisibleState = (state: boolean): StoreAction => dispatch => { +export const setSettingsVisibility = (state: boolean): StoreAction => dispatch => { dispatch({ type: SETTINGS_VISIBLE_SET, state, diff --git a/frontend/app/store/user/reducers.ts b/frontend/app/store/user/reducers.ts index fe3affff..7a133a09 100644 --- a/frontend/app/store/user/reducers.ts +++ b/frontend/app/store/user/reducers.ts @@ -1,6 +1,5 @@ import { User, BlockedUser } from '@app/common/types'; -import { StoreState } from '../index'; import { USER_SET, USER_BAN, @@ -14,7 +13,7 @@ import { USER_UNHIDE, } from './types'; -export const user = (state: StoreState['user'] = null, action: USER_ACTIONS): User | null => { +export const user = (state: User | null = null, action: USER_ACTIONS): User | null => { switch (action.type) { case USER_SET: { return action.user; @@ -24,7 +23,7 @@ export const user = (state: StoreState['user'] = null, action: USER_ACTIONS): Us } }; -export const bannedUsers = (state: StoreState['bannedUsers'] = [], action: USER_ACTIONS): BlockedUser[] => { +export const bannedUsers = (state: BlockedUser[] = [], action: USER_ACTIONS): BlockedUser[] => { switch (action.type) { case USER_BANLIST_SET: { return action.list; @@ -47,7 +46,7 @@ export const bannedUsers = (state: StoreState['bannedUsers'] = [], action: USER_ } }; -export const hiddenUsers = (state: StoreState['hiddenUsers'] = {}, action: USER_ACTIONS): StoreState['hiddenUsers'] => { +export const hiddenUsers = (state: { [id: string]: User } = {}, action: USER_ACTIONS): { [id: string]: User } => { switch (action.type) { case USER_HIDELIST_SET: { return action.payload; @@ -66,10 +65,7 @@ export const hiddenUsers = (state: StoreState['hiddenUsers'] = {}, action: USER_ } }; -export const isSettingsVisible = ( - state: StoreState['isSettingsVisible'] = false, - action: SETTINGS_VISIBLE_SET_ACTION -): boolean => { +export const isSettingsVisible = (state: boolean = false, action: SETTINGS_VISIBLE_SET_ACTION): boolean => { switch (action.type) { case SETTINGS_VISIBLE_SET: { return action.state; diff --git a/frontend/app/testUtils/index.ts b/frontend/app/testUtils/index.ts index 8f373dd0..7fc1f067 100644 --- a/frontend/app/testUtils/index.ts +++ b/frontend/app/testUtils/index.ts @@ -1,4 +1,10 @@ +import 'jest-extended'; +import 'jest-enzyme'; import { StaticStore } from '@app/common/static_store'; +import { configure } from 'enzyme'; +import PreactAdapter from 'enzyme-adapter-preact-pure'; + +configure({ adapter: new PreactAdapter() }); require('document-register-element/pony')(window); @@ -17,21 +23,3 @@ beforeEach(() => { version: 'jest-test', }; }); - -export function createDomContainer(setup: (domContainer: HTMLElement) => void): void { - let domContainer: HTMLElement | null = null; - beforeAll(() => { - domContainer = document.createElement('div'); - (document.body || document.documentElement).appendChild(domContainer); - setup(domContainer); - }); - - beforeEach(() => { - domContainer!.innerHTML = ''; - }); - - afterAll(() => { - domContainer!.parentNode!.removeChild(domContainer!); - domContainer = null; - }); -} diff --git a/frontend/app/testUtils/mockHeaders.ts b/frontend/app/testUtils/mockHeaders.ts new file mode 100644 index 00000000..6c335f1b --- /dev/null +++ b/frontend/app/testUtils/mockHeaders.ts @@ -0,0 +1,21 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const originalHeaders = (window as any).Headers; + +export const mockHeaders = { + mock: () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (window as any).Headers = class { + append() {} + has() { + return false; + } + get() { + return null; + } + }; + }, + restore: () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (window as any).Headers = originalHeaders; + }, +}; diff --git a/frontend/app/testUtils/mockPostInfo.ts b/frontend/app/testUtils/mockPostInfo.ts new file mode 100644 index 00000000..4d32cd9e --- /dev/null +++ b/frontend/app/testUtils/mockPostInfo.ts @@ -0,0 +1,2 @@ +jest.mock('@app/common/settings'); +jest.mock('@app/common/constants'); diff --git a/frontend/app/testUtils/mockStore.ts b/frontend/app/testUtils/mockStore.ts new file mode 100644 index 00000000..ccb6da27 --- /dev/null +++ b/frontend/app/testUtils/mockStore.ts @@ -0,0 +1,5 @@ +import createMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const mockStore = createMockStore([thunk]); diff --git a/frontend/app/utils/bench.ts b/frontend/app/utils/bench.ts new file mode 100644 index 00000000..41a74fe1 --- /dev/null +++ b/frontend/app/utils/bench.ts @@ -0,0 +1,8 @@ +export function bench(fn: () => T, label: string = 'bench'): T { + const d = performance.now(); + const r = fn(); + const dd = performance.now(); + // eslint-disable-next-line no-console + console.info(label, dd - d); + return r; +} diff --git a/frontend/app/utils/cmpRef.ts b/frontend/app/utils/cmpRef.ts new file mode 100644 index 00000000..d803b0ed --- /dev/null +++ b/frontend/app/utils/cmpRef.ts @@ -0,0 +1,13 @@ +import isEqual from 'lodash/isEqual'; + +/** + * Deeply compares two entities, + * and if they are equal, then first entity + * will be returned + * + * Useful when we deal with react objects + */ +export function cmpRef(a: T, b: T): T { + if (isEqual(a, b)) return a; + return b; +} diff --git a/frontend/app/utils/parseQuery.ts b/frontend/app/utils/parseQuery.ts index 26d47204..8f83ba53 100644 --- a/frontend/app/utils/parseQuery.ts +++ b/frontend/app/utils/parseQuery.ts @@ -4,17 +4,15 @@ export function parseQuery(search: string): { [key: string]: string } { return search .substr(1) .split('&') - .map( - (chunk): [string, string] => { - const parts = chunk.split('='); - if (parts.length < 2) { - parts[1] = ''; - } else { - parts[1] = decodeURIComponent(parts[1]); - } - return parts as [string, string]; + .map((chunk): [string, string] => { + const parts = chunk.split('='); + if (parts.length < 2) { + parts[1] = ''; + } else { + parts[1] = decodeURIComponent(parts[1]); } - ) + return parts as [string, string]; + }) .reduce<{ [key: string]: string }>((c, x) => { c[x[0]] = x[1]; return c; diff --git a/frontend/app/utils/shallowCompare.ts b/frontend/app/utils/shallowCompare.ts new file mode 100644 index 00000000..7c17ec05 --- /dev/null +++ b/frontend/app/utils/shallowCompare.ts @@ -0,0 +1,10 @@ +export function shallowCompare(a: T, b: T): boolean { + const entriesA = Object.entries(a); + const keysB = Object.keys(b); + if (entriesA.length !== keysB.length) return false; + for (const [key, value] of entriesA) { + // @ts-ignore + if (value !== b[key]) return false; + } + return true; +} diff --git a/frontend/escheck.js b/frontend/escheck.js new file mode 100644 index 00000000..4b27c465 --- /dev/null +++ b/frontend/escheck.js @@ -0,0 +1,28 @@ +const spawn = require('child_process').spawn; +const path = require('path'); + +module.exports = function({ mode = 'es5', glob } = {}) { + return new Promise((resolve, reject) => { + if (!glob) { + reject(new Error('no glob provided')); + } + const check = spawn('./node_modules/.bin/es-check', [mode, glob], { + cwd: path.resolve(__dirname, './'), + }); + + const buffer = []; + + check.stdout.on('data', data => { + buffer.push(data.toString('utf-8')); + }); + + check.stderr.on('data', data => { + buffer.push(data.toString('utf-8')); + }); + + check.on('close', code => { + if (code === 0) resolve(); + reject(new Error(`es-check exited with code ${code}\n\n${buffer.join('\n')}`)); + }); + }); +}; diff --git a/frontend/index.ejs b/frontend/index.ejs index ad30ee78..8fc69ac4 100644 --- a/frontend/index.ejs +++ b/frontend/index.ejs @@ -2,7 +2,7 @@ - + remark42 demo page