diff options
Diffstat (limited to 'vendor/github.com/mattermost/mattermost-server/v5/shared')
33 files changed, 0 insertions, 6980 deletions
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/filesstore.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/filesstore.go deleted file mode 100644 index ef02895d..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/filesstore.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package filestore - -import ( - "io" - "time" - - "github.com/pkg/errors" -) - -const ( - driverS3 = "amazons3" - driverLocal = "local" -) - -type ReadCloseSeeker interface { - io.ReadCloser - io.Seeker -} - -type FileBackend interface { - TestConnection() error - - Reader(path string) (ReadCloseSeeker, error) - ReadFile(path string) ([]byte, error) - FileExists(path string) (bool, error) - FileSize(path string) (int64, error) - CopyFile(oldPath, newPath string) error - MoveFile(oldPath, newPath string) error - WriteFile(fr io.Reader, path string) (int64, error) - AppendFile(fr io.Reader, path string) (int64, error) - RemoveFile(path string) error - FileModTime(path string) (time.Time, error) - - ListDirectory(path string) ([]string, error) - RemoveDirectory(path string) error -} - -type FileBackendSettings struct { - DriverName string - Directory string - AmazonS3AccessKeyId string - AmazonS3SecretAccessKey string - AmazonS3Bucket string - AmazonS3PathPrefix string - AmazonS3Region string - AmazonS3Endpoint string - AmazonS3SSL bool - AmazonS3SignV2 bool - AmazonS3SSE bool - AmazonS3Trace bool -} - -func (settings *FileBackendSettings) CheckMandatoryS3Fields() error { - if settings.AmazonS3Bucket == "" { - return errors.New("missing s3 bucket settings") - } - - // if S3 endpoint is not set call the set defaults to set that - if settings.AmazonS3Endpoint == "" { - settings.AmazonS3Endpoint = "s3.amazonaws.com" - } - - return nil -} - -func NewFileBackend(settings FileBackendSettings) (FileBackend, error) { - switch settings.DriverName { - case driverS3: - backend, err := NewS3FileBackend(settings) - if err != nil { - return nil, errors.Wrap(err, "unable to connect to the s3 backend") - } - return backend, nil - case driverLocal: - return &LocalFileBackend{ - directory: settings.Directory, - }, nil - } - return nil, errors.New("no valid filestorage driver found") -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/localstore.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/localstore.go deleted file mode 100644 index 6cd8c4ca..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/localstore.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package filestore - -import ( - "bytes" - "io" - "io/ioutil" - "os" - "path/filepath" - "time" - - "github.com/pkg/errors" - - "github.com/mattermost/mattermost-server/v5/shared/mlog" -) - -const ( - TestFilePath = "/testfile" -) - -type LocalFileBackend struct { - directory string -} - -// copyFile will copy a file from src path to dst path. -// Overwrites any existing files at dst. -// Permissions are copied from file at src to the new file at dst. -func copyFile(src, dst string) (err error) { - in, err := os.Open(src) - if err != nil { - return - } - defer in.Close() - - if err = os.MkdirAll(filepath.Dir(dst), os.ModePerm); err != nil { - return - } - out, err := os.Create(dst) - if err != nil { - return - } - defer func() { - if e := out.Close(); e != nil { - err = e - } - }() - - _, err = io.Copy(out, in) - if err != nil { - return - } - - err = out.Sync() - if err != nil { - return - } - - stat, err := os.Stat(src) - if err != nil { - return - } - err = os.Chmod(dst, stat.Mode()) - if err != nil { - return - } - - return -} - -func (b *LocalFileBackend) TestConnection() error { - f := bytes.NewReader([]byte("testingwrite")) - if _, err := writeFileLocally(f, filepath.Join(b.directory, TestFilePath)); err != nil { - return errors.Wrap(err, "unable to write to the local filesystem storage") - } - os.Remove(filepath.Join(b.directory, TestFilePath)) - mlog.Debug("Able to write files to local storage.") - return nil -} - -func (b *LocalFileBackend) Reader(path string) (ReadCloseSeeker, error) { - f, err := os.Open(filepath.Join(b.directory, path)) - if err != nil { - return nil, errors.Wrapf(err, "unable to open file %s", path) - } - return f, nil -} - -func (b *LocalFileBackend) ReadFile(path string) ([]byte, error) { - f, err := ioutil.ReadFile(filepath.Join(b.directory, path)) - if err != nil { - return nil, errors.Wrapf(err, "unable to read file %s", path) - } - return f, nil -} - -func (b *LocalFileBackend) FileExists(path string) (bool, error) { - _, err := os.Stat(filepath.Join(b.directory, path)) - - if os.IsNotExist(err) { - return false, nil - } - - if err != nil { - return false, errors.Wrapf(err, "unable to know if file %s exists", path) - } - return true, nil -} - -func (b *LocalFileBackend) FileSize(path string) (int64, error) { - info, err := os.Stat(filepath.Join(b.directory, path)) - if err != nil { - return 0, errors.Wrapf(err, "unable to get file size for %s", path) - } - return info.Size(), nil -} - -func (b *LocalFileBackend) FileModTime(path string) (time.Time, error) { - info, err := os.Stat(filepath.Join(b.directory, path)) - if err != nil { - return time.Time{}, errors.Wrapf(err, "unable to get modification time for file %s", path) - } - return info.ModTime(), nil -} - -func (b *LocalFileBackend) CopyFile(oldPath, newPath string) error { - if err := copyFile(filepath.Join(b.directory, oldPath), filepath.Join(b.directory, newPath)); err != nil { - return errors.Wrapf(err, "unable to copy file from %s to %s", oldPath, newPath) - } - return nil -} - -func (b *LocalFileBackend) MoveFile(oldPath, newPath string) error { - if err := os.MkdirAll(filepath.Dir(filepath.Join(b.directory, newPath)), 0750); err != nil { - return errors.Wrapf(err, "unable to create the new destination directory %s", filepath.Dir(newPath)) - } - - if err := os.Rename(filepath.Join(b.directory, oldPath), filepath.Join(b.directory, newPath)); err != nil { - return errors.Wrapf(err, "unable to move the file to %s to the destination directory", newPath) - } - - return nil -} - -func (b *LocalFileBackend) WriteFile(fr io.Reader, path string) (int64, error) { - return writeFileLocally(fr, filepath.Join(b.directory, path)) -} - -func writeFileLocally(fr io.Reader, path string) (int64, error) { - if err := os.MkdirAll(filepath.Dir(path), 0750); err != nil { - directory, _ := filepath.Abs(filepath.Dir(path)) - return 0, errors.Wrapf(err, "unable to create the directory %s for the file %s", directory, path) - } - fw, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - return 0, errors.Wrapf(err, "unable to open the file %s to write the data", path) - } - defer fw.Close() - written, err := io.Copy(fw, fr) - if err != nil { - return written, errors.Wrapf(err, "unable write the data in the file %s", path) - } - return written, nil -} - -func (b *LocalFileBackend) AppendFile(fr io.Reader, path string) (int64, error) { - fp := filepath.Join(b.directory, path) - if _, err := os.Stat(fp); err != nil { - return 0, errors.Wrapf(err, "unable to find the file %s to append the data", path) - } - fw, err := os.OpenFile(fp, os.O_WRONLY|os.O_APPEND, 0600) - if err != nil { - return 0, errors.Wrapf(err, "unable to open the file %s to append the data", path) - } - defer fw.Close() - written, err := io.Copy(fw, fr) - if err != nil { - return written, errors.Wrapf(err, "unable append the data in the file %s", path) - } - return written, nil -} - -func (b *LocalFileBackend) RemoveFile(path string) error { - if err := os.Remove(filepath.Join(b.directory, path)); err != nil { - return errors.Wrapf(err, "unable to remove the file %s", path) - } - return nil -} - -func (b *LocalFileBackend) ListDirectory(path string) ([]string, error) { - var paths []string - fileInfos, err := ioutil.ReadDir(filepath.Join(b.directory, path)) - if err != nil { - if os.IsNotExist(err) { - return paths, nil - } - return nil, errors.Wrapf(err, "unable to list the directory %s", path) - } - for _, fileInfo := range fileInfos { - paths = append(paths, filepath.Join(path, fileInfo.Name())) - } - return paths, nil -} - -func (b *LocalFileBackend) RemoveDirectory(path string) error { - if err := os.RemoveAll(filepath.Join(b.directory, path)); err != nil { - return errors.Wrapf(err, "unable to remove the directory %s", path) - } - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/s3_overrides.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/s3_overrides.go deleted file mode 100644 index e7b29b98..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/s3_overrides.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package filestore - -import ( - "context" - "net/http" - - "github.com/minio/minio-go/v7/pkg/credentials" -) - -// customTransport is used to point the request to a different server. -// This is helpful in situations where a different service is handling AWS S3 requests -// from multiple Mattermost applications, and the Mattermost service itself does not -// have any S3 credentials. -type customTransport struct { - base http.RoundTripper - host string - scheme string - client http.Client -} - -// RoundTrip implements the http.Roundtripper interface. -func (t *customTransport) RoundTrip(req *http.Request) (*http.Response, error) { - // Rountrippers should not modify the original request. - newReq := req.Clone(context.Background()) - *newReq.URL = *req.URL - req.URL.Scheme = t.scheme - req.URL.Host = t.host - return t.client.Do(req) -} - -// customProvider is a dummy credentials provider for the minio client to work -// without actually providing credentials. This is needed with a custom transport -// in cases where the minio client does not actually have credentials with itself, -// rather needs responses from another entity. -// -// It satisfies the credentials.Provider interface. -type customProvider struct { - isSignV2 bool -} - -// Retrieve just returns empty credentials. -func (cp customProvider) Retrieve() (credentials.Value, error) { - sign := credentials.SignatureV4 - if cp.isSignV2 { - sign = credentials.SignatureV2 - } - return credentials.Value{ - SignerType: sign, - }, nil -} - -// IsExpired always returns false. -func (cp customProvider) IsExpired() bool { return false } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/s3store.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/s3store.go deleted file mode 100644 index 5d0bf38e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/filestore/s3store.go +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package filestore - -import ( - "context" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" - - s3 "github.com/minio/minio-go/v7" - "github.com/minio/minio-go/v7/pkg/credentials" - "github.com/minio/minio-go/v7/pkg/encrypt" - "github.com/pkg/errors" - - "github.com/mattermost/mattermost-server/v5/shared/mlog" -) - -// S3FileBackend contains all necessary information to communicate with -// an AWS S3 compatible API backend. -type S3FileBackend struct { - endpoint string - accessKey string - secretKey string - secure bool - signV2 bool - region string - bucket string - pathPrefix string - encrypt bool - trace bool - client *s3.Client -} - -type S3FileBackendAuthError struct { - DetailedError string -} - -// S3FileBackendNoBucketError is returned when testing a connection and no S3 bucket is found -type S3FileBackendNoBucketError struct{} - -const ( - // This is not exported by minio. See: https://github.com/minio/minio-go/issues/1339 - bucketNotFound = "NoSuchBucket" -) - -var ( - imageExtensions = map[string]bool{".jpg": true, ".jpeg": true, ".gif": true, ".bmp": true, ".png": true, ".tiff": true, "tif": true} - imageMimeTypes = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff", ".tif": "image/tif"} -) - -func isFileExtImage(ext string) bool { - ext = strings.ToLower(ext) - return imageExtensions[ext] -} - -func getImageMimeType(ext string) string { - ext = strings.ToLower(ext) - if imageMimeTypes[ext] == "" { - return "image" - } - return imageMimeTypes[ext] -} - -func (s *S3FileBackendAuthError) Error() string { - return s.DetailedError -} - -func (s *S3FileBackendNoBucketError) Error() string { - return "no such bucket" -} - -// NewS3FileBackend returns an instance of an S3FileBackend. -func NewS3FileBackend(settings FileBackendSettings) (*S3FileBackend, error) { - backend := &S3FileBackend{ - endpoint: settings.AmazonS3Endpoint, - accessKey: settings.AmazonS3AccessKeyId, - secretKey: settings.AmazonS3SecretAccessKey, - secure: settings.AmazonS3SSL, - signV2: settings.AmazonS3SignV2, - region: settings.AmazonS3Region, - bucket: settings.AmazonS3Bucket, - pathPrefix: settings.AmazonS3PathPrefix, - encrypt: settings.AmazonS3SSE, - trace: settings.AmazonS3Trace, - } - cli, err := backend.s3New() - if err != nil { - return nil, err - } - backend.client = cli - return backend, nil -} - -// Similar to s3.New() but allows initialization of signature v2 or signature v4 client. -// If signV2 input is false, function always returns signature v4. -// -// Additionally this function also takes a user defined region, if set -// disables automatic region lookup. -func (b *S3FileBackend) s3New() (*s3.Client, error) { - var creds *credentials.Credentials - - isCloud := os.Getenv("MM_CLOUD_FILESTORE_BIFROST") != "" - if isCloud { - creds = credentials.New(customProvider{isSignV2: b.signV2}) - } else if b.accessKey == "" && b.secretKey == "" { - creds = credentials.NewIAM("") - } else if b.signV2 { - creds = credentials.NewStatic(b.accessKey, b.secretKey, "", credentials.SignatureV2) - } else { - creds = credentials.NewStatic(b.accessKey, b.secretKey, "", credentials.SignatureV4) - } - - opts := s3.Options{ - Creds: creds, - Secure: b.secure, - Region: b.region, - } - - // If this is a cloud installation, we override the default transport. - if isCloud { - tr, err := s3.DefaultTransport(b.secure) - if err != nil { - return nil, err - } - scheme := "http" - if b.secure { - scheme = "https" - } - opts.Transport = &customTransport{ - base: tr, - host: b.endpoint, - scheme: scheme, - } - } - - s3Clnt, err := s3.New(b.endpoint, &opts) - if err != nil { - return nil, err - } - - if b.trace { - s3Clnt.TraceOn(os.Stdout) - } - - return s3Clnt, nil -} - -func (b *S3FileBackend) TestConnection() error { - exists := true - var err error - // If a path prefix is present, we attempt to test the bucket by listing objects under the path - // and just checking the first response. This is because the BucketExists call is only at a bucket level - // and sometimes the user might only be allowed access to the specified path prefix. - if b.pathPrefix != "" { - obj := <-b.client.ListObjects(context.Background(), b.bucket, s3.ListObjectsOptions{Prefix: b.pathPrefix}) - if obj.Err != nil { - typedErr := s3.ToErrorResponse(obj.Err) - if typedErr.Code != bucketNotFound { - return &S3FileBackendAuthError{DetailedError: "unable to list objects in the S3 bucket"} - } - exists = false - } - } else { - exists, err = b.client.BucketExists(context.Background(), b.bucket) - if err != nil { - return &S3FileBackendAuthError{DetailedError: "unable to check if the S3 bucket exists"} - } - } - - if !exists { - return &S3FileBackendNoBucketError{} - } - mlog.Debug("Connection to S3 or minio is good. Bucket exists.") - return nil -} - -func (b *S3FileBackend) MakeBucket() error { - err := b.client.MakeBucket(context.Background(), b.bucket, s3.MakeBucketOptions{Region: b.region}) - if err != nil { - return errors.Wrap(err, "unable to create the s3 bucket") - } - return nil -} - -// Caller must close the first return value -func (b *S3FileBackend) Reader(path string) (ReadCloseSeeker, error) { - path = filepath.Join(b.pathPrefix, path) - minioObject, err := b.client.GetObject(context.Background(), b.bucket, path, s3.GetObjectOptions{}) - if err != nil { - return nil, errors.Wrapf(err, "unable to open file %s", path) - } - - return minioObject, nil -} - -func (b *S3FileBackend) ReadFile(path string) ([]byte, error) { - path = filepath.Join(b.pathPrefix, path) - minioObject, err := b.client.GetObject(context.Background(), b.bucket, path, s3.GetObjectOptions{}) - if err != nil { - return nil, errors.Wrapf(err, "unable to open file %s", path) - } - - defer minioObject.Close() - f, err := ioutil.ReadAll(minioObject) - if err != nil { - return nil, errors.Wrapf(err, "unable to read file %s", path) - } - return f, nil -} - -func (b *S3FileBackend) FileExists(path string) (bool, error) { - path = filepath.Join(b.pathPrefix, path) - - _, err := b.client.StatObject(context.Background(), b.bucket, path, s3.StatObjectOptions{}) - if err == nil { - return true, nil - } - - var s3Err s3.ErrorResponse - if errors.As(err, &s3Err); s3Err.Code == "NoSuchKey" { - return false, nil - } - - return false, errors.Wrapf(err, "unable to know if file %s exists", path) -} - -func (b *S3FileBackend) FileSize(path string) (int64, error) { - path = filepath.Join(b.pathPrefix, path) - - info, err := b.client.StatObject(context.Background(), b.bucket, path, s3.StatObjectOptions{}) - if err != nil { - return 0, errors.Wrapf(err, "unable to get file size for %s", path) - } - - return info.Size, nil -} - -func (b *S3FileBackend) FileModTime(path string) (time.Time, error) { - path = filepath.Join(b.pathPrefix, path) - - info, err := b.client.StatObject(context.Background(), b.bucket, path, s3.StatObjectOptions{}) - if err != nil { - return time.Time{}, errors.Wrapf(err, "unable to get modification time for file %s", path) - } - - return info.LastModified, nil -} - -func (b *S3FileBackend) CopyFile(oldPath, newPath string) error { - oldPath = filepath.Join(b.pathPrefix, oldPath) - newPath = filepath.Join(b.pathPrefix, newPath) - srcOpts := s3.CopySrcOptions{ - Bucket: b.bucket, - Object: oldPath, - Encryption: encrypt.NewSSE(), - } - dstOpts := s3.CopyDestOptions{ - Bucket: b.bucket, - Object: newPath, - Encryption: encrypt.NewSSE(), - } - if _, err := b.client.CopyObject(context.Background(), dstOpts, srcOpts); err != nil { - return errors.Wrapf(err, "unable to copy file from %s to %s", oldPath, newPath) - } - return nil -} - -func (b *S3FileBackend) MoveFile(oldPath, newPath string) error { - oldPath = filepath.Join(b.pathPrefix, oldPath) - newPath = filepath.Join(b.pathPrefix, newPath) - srcOpts := s3.CopySrcOptions{ - Bucket: b.bucket, - Object: oldPath, - Encryption: encrypt.NewSSE(), - } - dstOpts := s3.CopyDestOptions{ - Bucket: b.bucket, - Object: newPath, - Encryption: encrypt.NewSSE(), - } - - if _, err := b.client.CopyObject(context.Background(), dstOpts, srcOpts); err != nil { - return errors.Wrapf(err, "unable to copy the file to %s to the new destionation", newPath) - } - - if err := b.client.RemoveObject(context.Background(), b.bucket, oldPath, s3.RemoveObjectOptions{}); err != nil { - return errors.Wrapf(err, "unable to remove the file old file %s", oldPath) - } - - return nil -} - -func (b *S3FileBackend) WriteFile(fr io.Reader, path string) (int64, error) { - var contentType string - path = filepath.Join(b.pathPrefix, path) - if ext := filepath.Ext(path); isFileExtImage(ext) { - contentType = getImageMimeType(ext) - } else { - contentType = "binary/octet-stream" - } - - options := s3PutOptions(b.encrypt, contentType) - info, err := b.client.PutObject(context.Background(), b.bucket, path, fr, -1, options) - if err != nil { - return info.Size, errors.Wrapf(err, "unable write the data in the file %s", path) - } - - return info.Size, nil -} - -func (b *S3FileBackend) AppendFile(fr io.Reader, path string) (int64, error) { - fp := filepath.Join(b.pathPrefix, path) - if _, err := b.client.StatObject(context.Background(), b.bucket, fp, s3.StatObjectOptions{}); err != nil { - return 0, errors.Wrapf(err, "unable to find the file %s to append the data", path) - } - - var contentType string - if ext := filepath.Ext(fp); isFileExtImage(ext) { - contentType = getImageMimeType(ext) - } else { - contentType = "binary/octet-stream" - } - - options := s3PutOptions(b.encrypt, contentType) - sse := options.ServerSideEncryption - partName := fp + ".part" - info, err := b.client.PutObject(context.Background(), b.bucket, partName, fr, -1, options) - defer b.client.RemoveObject(context.Background(), b.bucket, partName, s3.RemoveObjectOptions{}) - if info.Size > 0 { - src1Opts := s3.CopySrcOptions{ - Bucket: b.bucket, - Object: fp, - } - src2Opts := s3.CopySrcOptions{ - Bucket: b.bucket, - Object: partName, - } - dstOpts := s3.CopyDestOptions{ - Bucket: b.bucket, - Object: fp, - Encryption: sse, - } - _, err = b.client.ComposeObject(context.Background(), dstOpts, src1Opts, src2Opts) - if err != nil { - return 0, errors.Wrapf(err, "unable append the data in the file %s", path) - } - return info.Size, nil - } - - return 0, errors.Wrapf(err, "unable append the data in the file %s", path) -} - -func (b *S3FileBackend) RemoveFile(path string) error { - path = filepath.Join(b.pathPrefix, path) - if err := b.client.RemoveObject(context.Background(), b.bucket, path, s3.RemoveObjectOptions{}); err != nil { - return errors.Wrapf(err, "unable to remove the file %s", path) - } - - return nil -} - -func getPathsFromObjectInfos(in <-chan s3.ObjectInfo) <-chan s3.ObjectInfo { - out := make(chan s3.ObjectInfo, 1) - - go func() { - defer close(out) - - for { - info, done := <-in - - if !done { - break - } - - out <- info - } - }() - - return out -} - -func (b *S3FileBackend) ListDirectory(path string) ([]string, error) { - path = filepath.Join(b.pathPrefix, path) - if !strings.HasSuffix(path, "/") && path != "" { - // s3Clnt returns only the path itself when "/" is not present - // appending "/" to make it consistent across all filestores - path = path + "/" - } - - opts := s3.ListObjectsOptions{ - Prefix: path, - } - var paths []string - for object := range b.client.ListObjects(context.Background(), b.bucket, opts) { - if object.Err != nil { - return nil, errors.Wrapf(object.Err, "unable to list the directory %s", path) - } - // We strip the path prefix that gets applied, - // so that it remains transparent to the application. - object.Key = strings.TrimPrefix(object.Key, b.pathPrefix) - trimmed := strings.Trim(object.Key, "/") - if trimmed != "" { - paths = append(paths, trimmed) - } - } - - return paths, nil -} - -func (b *S3FileBackend) RemoveDirectory(path string) error { - opts := s3.ListObjectsOptions{ - Prefix: filepath.Join(b.pathPrefix, path), - Recursive: true, - } - list := b.client.ListObjects(context.Background(), b.bucket, opts) - objectsCh := b.client.RemoveObjects(context.Background(), b.bucket, getPathsFromObjectInfos(list), s3.RemoveObjectsOptions{}) - for err := range objectsCh { - if err.Err != nil { - return errors.Wrapf(err.Err, "unable to remove the directory %s", path) - } - } - - return nil -} - -func s3PutOptions(encrypted bool, contentType string) s3.PutObjectOptions { - options := s3.PutObjectOptions{} - if encrypted { - options.ServerSideEncryption = encrypt.NewSSE() - } - options.ContentType = contentType - // We set the part size to the minimum allowed value of 5MBs - // to avoid an excessive allocation in minio.PutObject implementation. - options.PartSize = 1024 * 1024 * 5 - - return options -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/i18n/i18n.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/i18n/i18n.go deleted file mode 100644 index a5de30bb..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/i18n/i18n.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package i18n - -import ( - "fmt" - "html/template" - "io/ioutil" - "net/http" - "path/filepath" - "reflect" - "strings" - - "github.com/mattermost/go-i18n/i18n" - - "github.com/mattermost/mattermost-server/v5/shared/mlog" -) - -const defaultLocale = "en" - -// TranslateFunc is the type of the translate functions -type TranslateFunc func(translationID string, args ...interface{}) string - -// T is the translate function using the default server language as fallback language -var T TranslateFunc - -// TDefault is the translate function using english as fallback language -var TDefault TranslateFunc - -var locales map[string]string = make(map[string]string) -var defaultServerLocale string -var defaultClientLocale string - -// TranslationsPreInit loads translations from filesystem if they are not -// loaded already and assigns english while loading server config -func TranslationsPreInit(translationsDir string) error { - if T != nil { - return nil - } - - // Set T even if we fail to load the translations. Lots of shutdown handling code will - // segfault trying to handle the error, and the untranslated IDs are strictly better. - T = tfuncWithFallback(defaultLocale) - TDefault = tfuncWithFallback(defaultLocale) - - return initTranslationsWithDir(translationsDir) -} - -// InitTranslations set the defaults configured in the server and initialize -// the T function using the server default as fallback language -func InitTranslations(serverLocale, clientLocale string) error { - defaultServerLocale = serverLocale - defaultClientLocale = clientLocale - - var err error - T, err = getTranslationsBySystemLocale() - return err -} - -func initTranslationsWithDir(dir string) error { - files, _ := ioutil.ReadDir(dir) - for _, f := range files { - if filepath.Ext(f.Name()) == ".json" { - filename := f.Name() - locales[strings.Split(filename, ".")[0]] = filepath.Join(dir, filename) - - if err := i18n.LoadTranslationFile(filepath.Join(dir, filename)); err != nil { - return err - } - } - } - - return nil -} - -func getTranslationsBySystemLocale() (TranslateFunc, error) { - locale := defaultServerLocale - if _, ok := locales[locale]; !ok { - mlog.Warn("Failed to load system translations for", mlog.String("locale", locale), mlog.String("attempting to fall back to default locale", defaultLocale)) - locale = defaultLocale - } - - if locales[locale] == "" { - return nil, fmt.Errorf("failed to load system translations for '%v'", defaultLocale) - } - - translations := tfuncWithFallback(locale) - if translations == nil { - return nil, fmt.Errorf("failed to load system translations") - } - - mlog.Info("Loaded system translations", mlog.String("for locale", locale), mlog.String("from locale", locales[locale])) - return translations, nil -} - -// GetUserTranslations get the translation function for an specific locale -func GetUserTranslations(locale string) TranslateFunc { - if _, ok := locales[locale]; !ok { - locale = defaultLocale - } - - translations := tfuncWithFallback(locale) - return translations -} - -// GetTranslationsAndLocaleFromRequest return the translation function and the -// locale based on a request headers -func GetTranslationsAndLocaleFromRequest(r *http.Request) (TranslateFunc, string) { - // This is for checking against locales like pt_BR or zn_CN - headerLocaleFull := strings.Split(r.Header.Get("Accept-Language"), ",")[0] - // This is for checking against locales like en, es - headerLocale := strings.Split(strings.Split(r.Header.Get("Accept-Language"), ",")[0], "-")[0] - defaultLocale := defaultClientLocale - if locales[headerLocaleFull] != "" { - translations := tfuncWithFallback(headerLocaleFull) - return translations, headerLocaleFull - } else if locales[headerLocale] != "" { - translations := tfuncWithFallback(headerLocale) - return translations, headerLocale - } else if locales[defaultLocale] != "" { - translations := tfuncWithFallback(defaultLocale) - return translations, headerLocale - } - - translations := tfuncWithFallback(defaultLocale) - return translations, defaultLocale -} - -// GetSupportedLocales return a map of locale code and the file path with the -// translations -func GetSupportedLocales() map[string]string { - return locales -} - -func tfuncWithFallback(pref string) TranslateFunc { - t, _ := i18n.Tfunc(pref) - return func(translationID string, args ...interface{}) string { - if translated := t(translationID, args...); translated != translationID { - return translated - } - - t, _ := i18n.Tfunc(defaultLocale) - return t(translationID, args...) - } -} - -// TranslateAsHTML translates the translationID provided and return a -// template.HTML object -func TranslateAsHTML(t TranslateFunc, translationID string, args map[string]interface{}) template.HTML { - message := t(translationID, escapeForHTML(args)) - message = strings.Replace(message, "[[", "<strong>", -1) - message = strings.Replace(message, "]]", "</strong>", -1) - return template.HTML(message) -} - -func escapeForHTML(arg interface{}) interface{} { - switch typedArg := arg.(type) { - case string: - return template.HTMLEscapeString(typedArg) - case *string: - return template.HTMLEscapeString(*typedArg) - case map[string]interface{}: - safeArg := make(map[string]interface{}, len(typedArg)) - for key, value := range typedArg { - safeArg[key] = escapeForHTML(value) - } - return safeArg - default: - mlog.Warn( - "Unable to escape value for HTML template", - mlog.Any("html_template", arg), - mlog.String("template_type", reflect.ValueOf(arg).Type().String()), - ) - return "" - } -} - -// IdentityTfunc returns a translation function that don't translate, only -// returns the same id -func IdentityTfunc() TranslateFunc { - return func(translationID string, args ...interface{}) string { - return translationID - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/autolink.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/autolink.go deleted file mode 100644 index 2eb05d90..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/autolink.go +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "regexp" - "strings" - "unicode" - "unicode/utf8" -) - -// Based off of extensions/autolink.c from https://github.com/github/cmark - -var ( - DefaultURLSchemes = []string{"http", "https", "ftp", "mailto", "tel"} - wwwAutoLinkRegex = regexp.MustCompile(`^www\d{0,3}\.`) -) - -// Given a string with a w at the given position, tries to parse and return a range containing a www link. -// if one exists. If the text at the given position isn't a link, returns an empty string. Equivalent to -// www_match from the reference code. -func parseWWWAutolink(data string, position int) (Range, bool) { - // Check that this isn't part of another word - if position > 1 { - prevChar := data[position-1] - - if !isWhitespaceByte(prevChar) && !isAllowedBeforeWWWLink(prevChar) { - return Range{}, false - } - } - - // Check that this starts with www - if len(data)-position < 4 || !wwwAutoLinkRegex.MatchString(data[position:]) { - return Range{}, false - } - - end := checkDomain(data[position:], false) - if end == 0 { - return Range{}, false - } - - end += position - - // Grab all text until the end of the string or the next whitespace character - for end < len(data) && !isWhitespaceByte(data[end]) { - end += 1 - } - - // Trim trailing punctuation - end = trimTrailingCharactersFromLink(data, position, end) - if position == end { - return Range{}, false - } - - return Range{position, end}, true -} - -func isAllowedBeforeWWWLink(c byte) bool { - switch c { - case '*', '_', '~', ')': - return true - } - return false -} - -// Given a string with a : at the given position, tried to parse and return a range containing a URL scheme -// if one exists. If the text around the given position isn't a link, returns an empty string. Equivalent to -// url_match from the reference code. -func parseURLAutolink(data string, position int) (Range, bool) { - // Check that a :// exists. This doesn't match the clients that treat the slashes as optional. - if len(data)-position < 4 || data[position+1] != '/' || data[position+2] != '/' { - return Range{}, false - } - - start := position - 1 - for start > 0 && isAlphanumericByte(data[start-1]) { - start -= 1 - } - - if start < 0 || position >= len(data) { - return Range{}, false - } - - // Ensure that the URL scheme is allowed and that at least one character after the scheme is valid. - scheme := data[start:position] - if !isSchemeAllowed(scheme) || !isValidHostCharacter(data[position+3:]) { - return Range{}, false - } - - end := checkDomain(data[position+3:], true) - if end == 0 { - return Range{}, false - } - - end += position - - // Grab all text until the end of the string or the next whitespace character - for end < len(data) && !isWhitespaceByte(data[end]) { - end += 1 - } - - // Trim trailing punctuation - end = trimTrailingCharactersFromLink(data, start, end) - if start == end { - return Range{}, false - } - - return Range{start, end}, true -} - -func isSchemeAllowed(scheme string) bool { - // Note that this doesn't support the custom URL schemes implemented by the client - for _, allowed := range DefaultURLSchemes { - if strings.EqualFold(allowed, scheme) { - return true - } - } - - return false -} - -// Given a string starting with a URL, returns the number of valid characters that make up the URL's domain. -// Returns 0 if the string doesn't start with a domain name. allowShort determines whether or not the domain -// needs to contain a period to be considered valid. Equivalent to check_domain from the reference code. -func checkDomain(data string, allowShort bool) int { - foundUnderscore := false - foundPeriod := false - - i := 1 - for ; i < len(data)-1; i++ { - if data[i] == '_' { - foundUnderscore = true - break - } else if data[i] == '.' { - foundPeriod = true - } else if !isValidHostCharacter(data[i:]) && data[i] != '-' { - break - } - } - - if foundUnderscore { - return 0 - } - - if allowShort { - // If allowShort is set, accept any string of valid domain characters - return i - } - - // If allowShort isn't set, a valid domain just requires at least a single period. Note that this - // logic isn't entirely necessary because we already know the string starts with "www." when - // this is called from parseWWWAutolink - if foundPeriod { - return i - } - return 0 -} - -// Returns true if the provided link starts with a valid character for a domain name. Equivalent to -// is_valid_hostchar from the reference code. -func isValidHostCharacter(link string) bool { - c, _ := utf8.DecodeRuneInString(link) - if c == utf8.RuneError { - return false - } - - return !unicode.IsSpace(c) && !unicode.IsPunct(c) -} - -// Removes any trailing characters such as punctuation or stray brackets that shouldn't be part of the link. -// Returns a new end position for the link. Equivalent to autolink_delim from the reference code. -func trimTrailingCharactersFromLink(markdown string, start int, end int) int { - runes := []rune(markdown[start:end]) - linkEnd := len(runes) - - // Cut off the link before an open angle bracket if it contains one - for i, c := range runes { - if c == '<' { - linkEnd = i - break - } - } - - for linkEnd > 0 { - c := runes[linkEnd-1] - - if !canEndAutolink(c) { - // Trim trailing quotes, periods, etc - linkEnd = linkEnd - 1 - } else if c == ';' { - // Trim a trailing HTML entity - newEnd := linkEnd - 2 - - for newEnd > 0 && ((runes[newEnd] >= 'a' && runes[newEnd] <= 'z') || (runes[newEnd] >= 'A' && runes[newEnd] <= 'Z')) { - newEnd -= 1 - } - - if newEnd < linkEnd-2 && runes[newEnd] == '&' { - linkEnd = newEnd - } else { - // This isn't actually an HTML entity, so just trim the semicolon - linkEnd = linkEnd - 1 - } - } else if c == ')' { - // Only allow an autolink ending with a bracket if that bracket is part of a matching pair of brackets. - // If there are more closing brackets than opening ones, remove the extra bracket - - numClosing := 0 - numOpening := 0 - - // Examples (input text => output linked portion): - // - // http://www.pokemon.com/Pikachu_(Electric) - // => http://www.pokemon.com/Pikachu_(Electric) - // - // http://www.pokemon.com/Pikachu_((Electric) - // => http://www.pokemon.com/Pikachu_((Electric) - // - // http://www.pokemon.com/Pikachu_(Electric)) - // => http://www.pokemon.com/Pikachu_(Electric) - // - // http://www.pokemon.com/Pikachu_((Electric)) - // => http://www.pokemon.com/Pikachu_((Electric)) - - for i := 0; i < linkEnd; i++ { - if runes[i] == '(' { - numOpening += 1 - } else if runes[i] == ')' { - numClosing += 1 - } - } - - if numClosing <= numOpening { - // There's fewer or equal closing brackets, so we've found the end of the link - break - } - - linkEnd -= 1 - } else { - // There's no special characters at the end of the link, so we're at the end - break - } - } - - return start + len(string(runes[:linkEnd])) -} - -func canEndAutolink(c rune) bool { - switch c { - case '?', '!', '.', ',', ':', '*', '_', '~', '\'', '"': - return false - } - return true -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/block_quote.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/block_quote.go deleted file mode 100644 index 5cf66d10..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/block_quote.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -type BlockQuote struct { - blockBase - markdown string - - Children []Block -} - -func (b *BlockQuote) Continuation(indentation int, r Range) *continuation { - if indentation > 3 { - return nil - } - s := b.markdown[r.Position:r.End] - if s == "" || s[0] != '>' { - return nil - } - remaining := Range{r.Position + 1, r.End} - indentation, indentationBytes := countIndentation(b.markdown, remaining) - if indentation > 0 { - indentation-- - } - return &continuation{ - Indentation: indentation, - Remaining: Range{remaining.Position + indentationBytes, remaining.End}, - } -} - -func (b *BlockQuote) AddChild(openBlocks []Block) []Block { - b.Children = append(b.Children, openBlocks[0]) - return openBlocks -} - -func blockQuoteStart(markdown string, indent int, r Range) []Block { - if indent > 3 { - return nil - } - s := markdown[r.Position:r.End] - if s == "" || s[0] != '>' { - return nil - } - - block := &BlockQuote{ - markdown: markdown, - } - r.Position++ - if len(s) > 1 && s[1] == ' ' { - r.Position++ - } - - indent, bytes := countIndentation(markdown, r) - - ret := []Block{block} - if descendants := blockStartOrParagraph(markdown, indent, Range{r.Position + bytes, r.End}, nil, nil); descendants != nil { - block.Children = append(block.Children, descendants[0]) - ret = append(ret, descendants...) - } - return ret -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/blocks.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/blocks.go deleted file mode 100644 index fe9e272f..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/blocks.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "strings" -) - -type continuation struct { - Indentation int - Remaining Range -} - -type Block interface { - Continuation(indentation int, r Range) *continuation - AddLine(indentation int, r Range) bool - Close() - AllowsBlockStarts() bool - HasTrailingBlankLine() bool -} - -type blockBase struct{} - -func (*blockBase) AddLine(indentation int, r Range) bool { return false } -func (*blockBase) Close() {} -func (*blockBase) AllowsBlockStarts() bool { return true } -func (*blockBase) HasTrailingBlankLine() bool { return false } - -type ContainerBlock interface { - Block - AddChild(openBlocks []Block) []Block -} - -type Range struct { - Position int - End int -} - -func closeBlocks(blocks []Block, referenceDefinitions []*ReferenceDefinition) []*ReferenceDefinition { - for _, block := range blocks { - block.Close() - if p, ok := block.(*Paragraph); ok && len(p.ReferenceDefinitions) > 0 { - referenceDefinitions = append(referenceDefinitions, p.ReferenceDefinitions...) - } - } - return referenceDefinitions -} - -func ParseBlocks(markdown string, lines []Line) (*Document, []*ReferenceDefinition) { - document := &Document{} - var referenceDefinitions []*ReferenceDefinition - - openBlocks := []Block{document} - - for _, line := range lines { - r := line.Range - lastMatchIndex := 0 - - indentation, indentationBytes := countIndentation(markdown, r) - r = Range{r.Position + indentationBytes, r.End} - - for i, block := range openBlocks { - if continuation := block.Continuation(indentation, r); continuation != nil { - indentation = continuation.Indentation - r = continuation.Remaining - additionalIndentation, additionalIndentationBytes := countIndentation(markdown, r) - r = Range{r.Position + additionalIndentationBytes, r.End} - indentation += additionalIndentation - lastMatchIndex = i - } else { - break - } - } - - if openBlocks[lastMatchIndex].AllowsBlockStarts() { - if newBlocks := blockStart(markdown, indentation, r, openBlocks[:lastMatchIndex+1], openBlocks[lastMatchIndex+1:]); newBlocks != nil { - didAdd := false - for i := lastMatchIndex; i >= 0; i-- { - if container, ok := openBlocks[i].(ContainerBlock); ok { - if addedBlocks := container.AddChild(newBlocks); addedBlocks != nil { - referenceDefinitions = closeBlocks(openBlocks[i+1:], referenceDefinitions) - openBlocks = openBlocks[:i+1] - openBlocks = append(openBlocks, addedBlocks...) - didAdd = true - break - } - } - } - if didAdd { - continue - } - } - } - - isBlank := strings.TrimSpace(markdown[r.Position:r.End]) == "" - if paragraph, ok := openBlocks[len(openBlocks)-1].(*Paragraph); ok && !isBlank { - paragraph.Text = append(paragraph.Text, r) - continue - } - - referenceDefinitions = closeBlocks(openBlocks[lastMatchIndex+1:], referenceDefinitions) - openBlocks = openBlocks[:lastMatchIndex+1] - - if openBlocks[lastMatchIndex].AddLine(indentation, r) { - continue - } - - if paragraph := newParagraph(markdown, r); paragraph != nil { - for i := lastMatchIndex; i >= 0; i-- { - if container, ok := openBlocks[i].(ContainerBlock); ok { - if newBlocks := container.AddChild([]Block{paragraph}); newBlocks != nil { - referenceDefinitions = closeBlocks(openBlocks[i+1:], referenceDefinitions) - openBlocks = openBlocks[:i+1] - openBlocks = append(openBlocks, newBlocks...) - break - } - } - } - } - } - - referenceDefinitions = closeBlocks(openBlocks, referenceDefinitions) - - return document, referenceDefinitions -} - -func blockStart(markdown string, indentation int, r Range, matchedBlocks, unmatchedBlocks []Block) []Block { - if r.Position >= r.End { - return nil - } - - if start := blockQuoteStart(markdown, indentation, r); start != nil { - return start - } else if start := listStart(markdown, indentation, r, matchedBlocks, unmatchedBlocks); start != nil { - return start - } else if start := indentedCodeStart(markdown, indentation, r, matchedBlocks, unmatchedBlocks); start != nil { - return start - } else if start := fencedCodeStart(markdown, indentation, r); start != nil { - return start - } - - return nil -} - -func blockStartOrParagraph(markdown string, indentation int, r Range, matchedBlocks, unmatchedBlocks []Block) []Block { - if start := blockStart(markdown, indentation, r, matchedBlocks, unmatchedBlocks); start != nil { - return start - } - if paragraph := newParagraph(markdown, r); paragraph != nil { - return []Block{paragraph} - } - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/document.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/document.go deleted file mode 100644 index 306b93da..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/document.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -type Document struct { - blockBase - - Children []Block -} - -func (b *Document) Continuation(indentation int, r Range) *continuation { - return &continuation{ - Indentation: indentation, - Remaining: r, - } -} - -func (b *Document) AddChild(openBlocks []Block) []Block { - b.Children = append(b.Children, openBlocks[0]) - return openBlocks -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/fenced_code.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/fenced_code.go deleted file mode 100644 index c8caad55..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/fenced_code.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "strings" -) - -type FencedCodeLine struct { - Indentation int - Range Range -} - -type FencedCode struct { - blockBase - markdown string - didSeeClosingFence bool - - Indentation int - OpeningFence Range - RawInfo Range - RawCode []FencedCodeLine -} - -func (b *FencedCode) Code() (result string) { - for _, code := range b.RawCode { - result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End] - } - return -} - -func (b *FencedCode) Info() string { - return Unescape(b.markdown[b.RawInfo.Position:b.RawInfo.End]) -} - -func (b *FencedCode) Continuation(indentation int, r Range) *continuation { - if b.didSeeClosingFence { - return nil - } - return &continuation{ - Indentation: indentation, - Remaining: r, - } -} - -func (b *FencedCode) AddLine(indentation int, r Range) bool { - s := b.markdown[r.Position:r.End] - if indentation <= 3 && strings.HasPrefix(s, b.markdown[b.OpeningFence.Position:b.OpeningFence.End]) { - suffix := strings.TrimSpace(s[b.OpeningFence.End-b.OpeningFence.Position:]) - isClosingFence := true - for _, c := range suffix { - if c != rune(s[0]) { - isClosingFence = false - break - } - } - if isClosingFence { - b.didSeeClosingFence = true - return true - } - } - - if indentation >= b.Indentation { - indentation -= b.Indentation - } else { - indentation = 0 - } - - b.RawCode = append(b.RawCode, FencedCodeLine{ - Indentation: indentation, - Range: r, - }) - return true -} - -func (b *FencedCode) AllowsBlockStarts() bool { - return false -} - -func fencedCodeStart(markdown string, indentation int, r Range) []Block { - s := markdown[r.Position:r.End] - - if !strings.HasPrefix(s, "```") && !strings.HasPrefix(s, "~~~") { - return nil - } - - fenceCharacter := rune(s[0]) - fenceLength := 3 - for _, c := range s[3:] { - if c == fenceCharacter { - fenceLength++ - } else { - break - } - } - - for i := r.Position + fenceLength; i < r.End; i++ { - if markdown[i] == '`' { - return nil - } - } - - return []Block{ - &FencedCode{ - markdown: markdown, - Indentation: indentation, - RawInfo: trimRightSpace(markdown, Range{r.Position + fenceLength, r.End}), - OpeningFence: Range{r.Position, r.Position + fenceLength}, - }, - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/html.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/html.go deleted file mode 100644 index 52583074..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/html.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "fmt" - "strings" -) - -var htmlEscaper = strings.NewReplacer( - `&`, "&", - `<`, "<", - `>`, ">", - `"`, """, -) - -// RenderHTML produces HTML with the same behavior as the example renderer used in the CommonMark -// reference materials except for one slight difference: for brevity, no unnecessary whitespace is -// inserted between elements. The output is not defined by the CommonMark spec, and it exists -// primarily as an aid in testing. -func RenderHTML(markdown string) string { - return RenderBlockHTML(Parse(markdown)) -} - -func RenderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition) (result string) { - return renderBlockHTML(block, referenceDefinitions, false) -} - -func renderBlockHTML(block Block, referenceDefinitions []*ReferenceDefinition, isTightList bool) (result string) { - switch v := block.(type) { - case *Document: - for _, block := range v.Children { - result += RenderBlockHTML(block, referenceDefinitions) - } - case *Paragraph: - if len(v.Text) == 0 { - return - } - if !isTightList { - result += "<p>" - } - for _, inline := range v.ParseInlines(referenceDefinitions) { - result += RenderInlineHTML(inline) - } - if !isTightList { - result += "</p>" - } - case *List: - if v.IsOrdered { - if v.OrderedStart != 1 { - result += fmt.Sprintf(`<ol start="%v">`, v.OrderedStart) - } else { - result += "<ol>" - } - } else { - result += "<ul>" - } - for _, block := range v.Children { - result += renderBlockHTML(block, referenceDefinitions, !v.IsLoose) - } - if v.IsOrdered { - result += "</ol>" - } else { - result += "</ul>" - } - case *ListItem: - result += "<li>" - for _, block := range v.Children { - result += renderBlockHTML(block, referenceDefinitions, isTightList) - } - result += "</li>" - case *BlockQuote: - result += "<blockquote>" - for _, block := range v.Children { - result += RenderBlockHTML(block, referenceDefinitions) - } - result += "</blockquote>" - case *FencedCode: - if info := v.Info(); info != "" { - language := strings.Fields(info)[0] - result += `<pre><code class="language-` + htmlEscaper.Replace(language) + `">` - } else { - result += "<pre><code>" - } - result += htmlEscaper.Replace(v.Code()) + "</code></pre>" - case *IndentedCode: - result += "<pre><code>" + htmlEscaper.Replace(v.Code()) + "</code></pre>" - default: - panic(fmt.Sprintf("missing case for type %T", v)) - } - return -} - -func escapeURL(url string) (result string) { - for i := 0; i < len(url); { - switch b := url[i]; b { - case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '-', '_', '.', '!', '~', '*', '\'', '(', ')', '#': - result += string(b) - i++ - default: - if b == '%' && i+2 < len(url) && isHexByte(url[i+1]) && isHexByte(url[i+2]) { - result += url[i : i+3] - i += 3 - } else if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') { - result += string(b) - i++ - } else { - result += fmt.Sprintf("%%%0X", b) - i++ - } - } - } - return -} - -func RenderInlineHTML(inline Inline) (result string) { - switch v := inline.(type) { - case *Text: - return htmlEscaper.Replace(v.Text) - case *HardLineBreak: - return "<br />" - case *SoftLineBreak: - return "\n" - case *CodeSpan: - return "<code>" + htmlEscaper.Replace(v.Code) + "</code>" - case *InlineImage: - result += `<img src="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `" alt="` + htmlEscaper.Replace(renderImageAltText(v.Children)) + `"` - if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` - } - result += ` />` - case *ReferenceImage: - result += `<img src="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `" alt="` + htmlEscaper.Replace(renderImageAltText(v.Children)) + `"` - if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` - } - result += ` />` - case *InlineLink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"` - if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` - } - result += `>` - for _, inline := range v.Children { - result += RenderInlineHTML(inline) - } - result += "</a>" - case *ReferenceLink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `"` - if title := v.Title(); title != "" { - result += ` title="` + htmlEscaper.Replace(title) + `"` - } - result += `>` - for _, inline := range v.Children { - result += RenderInlineHTML(inline) - } - result += "</a>" - case *Autolink: - result += `<a href="` + htmlEscaper.Replace(escapeURL(v.Destination())) + `">` - for _, inline := range v.Children { - result += RenderInlineHTML(inline) - } - result += "</a>" - default: - panic(fmt.Sprintf("missing case for type %T", v)) - } - return -} - -func renderImageAltText(children []Inline) (result string) { - for _, inline := range children { - result += renderImageChildAltText(inline) - } - return -} - -func renderImageChildAltText(inline Inline) (result string) { - switch v := inline.(type) { - case *Text: - return v.Text - case *InlineImage: - for _, inline := range v.Children { - result += renderImageChildAltText(inline) - } - case *InlineLink: - for _, inline := range v.Children { - result += renderImageChildAltText(inline) - } - } - return -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/html_entities.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/html_entities.go deleted file mode 100644 index e94cebb9..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/html_entities.go +++ /dev/null @@ -1,2132 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -var htmlEntities = map[string]string{ - "AElig": "\u00C6", - "AMP": "\u0026", - "Aacute": "\u00C1", - "Abreve": "\u0102", - "Acirc": "\u00C2", - "Acy": "\u0410", - "Afr": "\U0001D504", - "Agrave": "\u00C0", - "Alpha": "\u0391", - "Amacr": "\u0100", - "And": "\u2A53", - "Aogon": "\u0104", - "Aopf": "\U0001D538", - "ApplyFunction": "\u2061", - "Aring": "\u00C5", - "Ascr": "\U0001D49C", - "Assign": "\u2254", - "Atilde": "\u00C3", - "Auml": "\u00C4", - "Backslash": "\u2216", - "Barv": "\u2AE7", - "Barwed": "\u2306", - "Bcy": "\u0411", - "Because": "\u2235", - "Bernoullis": "\u212C", - "Beta": "\u0392", - "Bfr": "\U0001D505", - "Bopf": "\U0001D539", - "Breve": "\u02D8", - "Bscr": "\u212C", - "Bumpeq": "\u224E", - "CHcy": "\u0427", - "COPY": "\u00A9", - "Cacute": "\u0106", - "Cap": "\u22D2", - "CapitalDifferentialD": "\u2145", - "Cayleys": "\u212D", - "Ccaron": "\u010C", - "Ccedil": "\u00C7", - "Ccirc": "\u0108", - "Cconint": "\u2230", - "Cdot": "\u010A", - "Cedilla": "\u00B8", - "CenterDot": "\u00B7", - "Cfr": "\u212D", - "Chi": "\u03A7", - "CircleDot": "\u2299", - "CircleMinus": "\u2296", - "CirclePlus": "\u2295", - "CircleTimes": "\u2297", - "ClockwiseContourIntegral": "\u2232", - "CloseCurlyDoubleQuote": "\u201D", - "CloseCurlyQuote": "\u2019", - "Colon": "\u2237", - "Colone": "\u2A74", - "Congruent": "\u2261", - "Conint": "\u222F", - "ContourIntegral": "\u222E", - "Copf": "\u2102", - "Coproduct": "\u2210", - "CounterClockwiseContourIntegral": "\u2233", - "Cross": "\u2A2F", - "Cscr": "\U0001D49E", - "Cup": "\u22D3", - "CupCap": "\u224D", - "DD": "\u2145", - "DDotrahd": "\u2911", - "DJcy": "\u0402", - "DScy": "\u0405", - "DZcy": "\u040F", - "Dagger": "\u2021", - "Darr": "\u21A1", - "Dashv": "\u2AE4", - "Dcaron": "\u010E", - "Dcy": "\u0414", - "Del": "\u2207", - "Delta": "\u0394", - "Dfr": "\U0001D507", - "DiacriticalAcute": "\u00B4", - "DiacriticalDot": "\u02D9", - "DiacriticalDoubleAcute": "\u02DD", - "DiacriticalGrave": "\u0060", - "DiacriticalTilde": "\u02DC", - "Diamond": "\u22C4", - "DifferentialD": "\u2146", - "Dopf": "\U0001D53B", - "Dot": "\u00A8", - "DotDot": "\u20DC", - "DotEqual": "\u2250", - "DoubleContourIntegral": "\u222F", - "DoubleDot": "\u00A8", - "DoubleDownArrow": "\u21D3", - "DoubleLeftArrow": "\u21D0", - "DoubleLeftRightArrow": "\u21D4", - "DoubleLeftTee": "\u2AE4", - "DoubleLongLeftArrow": "\u27F8", - "DoubleLongLeftRightArrow": "\u27FA", - "DoubleLongRightArrow": "\u27F9", - "DoubleRightArrow": "\u21D2", - "DoubleRightTee": "\u22A8", - "DoubleUpArrow": "\u21D1", - "DoubleUpDownArrow": "\u21D5", - "DoubleVerticalBar": "\u2225", - "DownArrow": "\u2193", - "DownArrowBar": "\u2913", - "DownArrowUpArrow": "\u21F5", - "DownBreve": "\u0311", - "DownLeftRightVector": "\u2950", - "DownLeftTeeVector": "\u295E", - "DownLeftVector": "\u21BD", - "DownLeftVectorBar": "\u2956", - "DownRightTeeVector": "\u295F", - "DownRightVector": "\u21C1", - "DownRightVectorBar": "\u2957", - "DownTee": "\u22A4", - "DownTeeArrow": "\u21A7", - "Downarrow": "\u21D3", - "Dscr": "\U0001D49F", - "Dstrok": "\u0110", - "ENG": "\u014A", - "ETH": "\u00D0", - "Eacute": "\u00C9", - "Ecaron": "\u011A", - "Ecirc": "\u00CA", - "Ecy": "\u042D", - "Edot": "\u0116", - "Efr": "\U0001D508", - "Egrave": "\u00C8", - "Element": "\u2208", - "Emacr": "\u0112", - "EmptySmallSquare": "\u25FB", - "EmptyVerySmallSquare": "\u25AB", - "Eogon": "\u0118", - "Eopf": "\U0001D53C", - "Epsilon": "\u0395", - "Equal": "\u2A75", - "EqualTilde": "\u2242", - "Equilibrium": "\u21CC", - "Escr": "\u2130", - "Esim": "\u2A73", - "Eta": "\u0397", - "Euml": "\u00CB", - "Exists": "\u2203", - "ExponentialE": "\u2147", - "Fcy": "\u0424", - "Ffr": "\U0001D509", - "FilledSmallSquare": "\u25FC", - "FilledVerySmallSquare": "\u25AA", - "Fopf": "\U0001D53D", - "ForAll": "\u2200", - "Fouriertrf": "\u2131", - "Fscr": "\u2131", - "GJcy": "\u0403", - "GT": "\u003E", - "Gamma": "\u0393", - "Gammad": "\u03DC", - "Gbreve": "\u011E", - "Gcedil": "\u0122", - "Gcirc": "\u011C", - "Gcy": "\u0413", - "Gdot": "\u0120", - "Gfr": "\U0001D50A", - "Gg": "\u22D9", - "Gopf": "\U0001D53E", - "GreaterEqual": "\u2265", - "GreaterEqualLess": "\u22DB", - "GreaterFullEqual": "\u2267", - "GreaterGreater": "\u2AA2", - "GreaterLess": "\u2277", - "GreaterSlantEqual": "\u2A7E", - "GreaterTilde": "\u2273", - "Gscr": "\U0001D4A2", - "Gt": "\u226B", - "HARDcy": "\u042A", - "Hacek": "\u02C7", - "Hat": "\u005E", - "Hcirc": "\u0124", - "Hfr": "\u210C", - "HilbertSpace": "\u210B", - "Hopf": "\u210D", - "HorizontalLine": "\u2500", - "Hscr": "\u210B", - "Hstrok": "\u0126", - "HumpDownHump": "\u224E", - "HumpEqual": "\u224F", - "IEcy": "\u0415", - "IJlig": "\u0132", - "IOcy": "\u0401", - "Iacute": "\u00CD", - "Icirc": "\u00CE", - "Icy": "\u0418", - "Idot": "\u0130", - "Ifr": "\u2111", - "Igrave": "\u00CC", - "Im": "\u2111", - "Imacr": "\u012A", - "ImaginaryI": "\u2148", - "Implies": "\u21D2", - "Int": "\u222C", - "Integral": "\u222B", - "Intersection": "\u22C2", - "InvisibleComma": "\u2063", - "InvisibleTimes": "\u2062", - "Iogon": "\u012E", - "Iopf": "\U0001D540", - "Iota": "\u0399", - "Iscr": "\u2110", - "Itilde": "\u0128", - "Iukcy": "\u0406", - "Iuml": "\u00CF", - "Jcirc": "\u0134", - "Jcy": "\u0419", - "Jfr": "\U0001D50D", - "Jopf": "\U0001D541", - "Jscr": "\U0001D4A5", - "Jsercy": "\u0408", - "Jukcy": "\u0404", - "KHcy": "\u0425", - "KJcy": "\u040C", - "Kappa": "\u039A", - "Kcedil": "\u0136", - "Kcy": "\u041A", - "Kfr": "\U0001D50E", - "Kopf": "\U0001D542", - "Kscr": "\U0001D4A6", - "LJcy": "\u0409", - "LT": "\u003C", - "Lacute": "\u0139", - "Lambda": "\u039B", - "Lang": "\u27EA", - "Laplacetrf": "\u2112", - "Larr": "\u219E", - "Lcaron": "\u013D", - "Lcedil": "\u013B", - "Lcy": "\u041B", - "LeftAngleBracket": "\u27E8", - "LeftArrow": "\u2190", - "LeftArrowBar": "\u21E4", - "LeftArrowRightArrow": "\u21C6", - "LeftCeiling": "\u2308", - "LeftDoubleBracket": "\u27E6", - "LeftDownTeeVector": "\u2961", - "LeftDownVector": "\u21C3", - "LeftDownVectorBar": "\u2959", - "LeftFloor": "\u230A", - "LeftRightArrow": "\u2194", - "LeftRightVector": "\u294E", - "LeftTee": "\u22A3", - "LeftTeeArrow": "\u21A4", - "LeftTeeVector": "\u295A", - "LeftTriangle": "\u22B2", - "LeftTriangleBar": "\u29CF", - "LeftTriangleEqual": "\u22B4", - "LeftUpDownVector": "\u2951", - "LeftUpTeeVector": "\u2960", - "LeftUpVector": "\u21BF", - "LeftUpVectorBar": "\u2958", - "LeftVector": "\u21BC", - "LeftVectorBar": "\u2952", - "Leftarrow": "\u21D0", - "Leftrightarrow": "\u21D4", - "LessEqualGreater": "\u22DA", - "LessFullEqual": "\u2266", - "LessGreater": "\u2276", - "LessLess": "\u2AA1", - "LessSlantEqual": "\u2A7D", - "LessTilde": "\u2272", - "Lfr": "\U0001D50F", - "Ll": "\u22D8", - "Lleftarrow": "\u21DA", - "Lmidot": "\u013F", - "LongLeftArrow": "\u27F5", - "LongLeftRightArrow": "\u27F7", - "LongRightArrow": "\u27F6", - "Longleftarrow": "\u27F8", - "Longleftrightarrow": "\u27FA", - "Longrightarrow": "\u27F9", - "Lopf": "\U0001D543", - "LowerLeftArrow": "\u2199", - "LowerRightArrow": "\u2198", - "Lscr": "\u2112", - "Lsh": "\u21B0", - "Lstrok": "\u0141", - "Lt": "\u226A", - "Map": "\u2905", - "Mcy": "\u041C", - "MediumSpace": "\u205F", - "Mellintrf": "\u2133", - "Mfr": "\U0001D510", - "MinusPlus": "\u2213", - "Mopf": "\U0001D544", - "Mscr": "\u2133", - "Mu": "\u039C", - "NJcy": "\u040A", - "Nacute": "\u0143", - "Ncaron": "\u0147", - "Ncedil": "\u0145", - "Ncy": "\u041D", - "NegativeMediumSpace": "\u200B", - "NegativeThickSpace": "\u200B", - "NegativeThinSpace": "\u200B", - "NegativeVeryThinSpace": "\u200B", - "NestedGreaterGreater": "\u226B", - "NestedLessLess": "\u226A", - "NewLine": "\u000A", - "Nfr": "\U0001D511", - "NoBreak": "\u2060", - "NonBreakingSpace": "\u00A0", - "Nopf": "\u2115", - "Not": "\u2AEC", - "NotCongruent": "\u2262", - "NotCupCap": "\u226D", - "NotDoubleVerticalBar": "\u2226", - "NotElement": "\u2209", - "NotEqual": "\u2260", - "NotEqualTilde": "\u2242\u0338", - "NotExists": "\u2204", - "NotGreater": "\u226F", - "NotGreaterEqual": "\u2271", - "NotGreaterFullEqual": "\u2267\u0338", - "NotGreaterGreater": "\u226B\u0338", - "NotGreaterLess": "\u2279", - "NotGreaterSlantEqual": "\u2A7E\u0338", - "NotGreaterTilde": "\u2275", - "NotHumpDownHump": "\u224E\u0338", - "NotHumpEqual": "\u224F\u0338", - "NotLeftTriangle": "\u22EA", - "NotLeftTriangleBar": "\u29CF\u0338", - "NotLeftTriangleEqual": "\u22EC", - "NotLess": "\u226E", - "NotLessEqual": "\u2270", - "NotLessGreater": "\u2278", - "NotLessLess": "\u226A\u0338", - "NotLessSlantEqual": "\u2A7D\u0338", - "NotLessTilde": "\u2274", - "NotNestedGreaterGreater": "\u2AA2\u0338", - "NotNestedLessLess": "\u2AA1\u0338", - "NotPrecedes": "\u2280", - "NotPrecedesEqual": "\u2AAF\u0338", - "NotPrecedesSlantEqual": "\u22E0", - "NotReverseElement": "\u220C", - "NotRightTriangle": "\u22EB", - "NotRightTriangleBar": "\u29D0\u0338", - "NotRightTriangleEqual": "\u22ED", - "NotSquareSubset": "\u228F\u0338", - "NotSquareSubsetEqual": "\u22E2", - "NotSquareSuperset": "\u2290\u0338", - "NotSquareSupersetEqual": "\u22E3", - "NotSubset": "\u2282\u20D2", - "NotSubsetEqual": "\u2288", - "NotSucceeds": "\u2281", - "NotSucceedsEqual": "\u2AB0\u0338", - "NotSucceedsSlantEqual": "\u22E1", - "NotSucceedsTilde": "\u227F\u0338", - "NotSuperset": "\u2283\u20D2", - "NotSupersetEqual": "\u2289", - "NotTilde": "\u2241", - "NotTildeEqual": "\u2244", - "NotTildeFullEqual": "\u2247", - "NotTildeTilde": "\u2249", - "NotVerticalBar": "\u2224", - "Nscr": "\U0001D4A9", - "Ntilde": "\u00D1", - "Nu": "\u039D", - "OElig": "\u0152", - "Oacute": "\u00D3", - "Ocirc": "\u00D4", - "Ocy": "\u041E", - "Odblac": "\u0150", - "Ofr": "\U0001D512", - "Ograve": "\u00D2", - "Omacr": "\u014C", - "Omega": "\u03A9", - "Omicron": "\u039F", - "Oopf": "\U0001D546", - "OpenCurlyDoubleQuote": "\u201C", - "OpenCurlyQuote": "\u2018", - "Or": "\u2A54", - "Oscr": "\U0001D4AA", - "Oslash": "\u00D8", - "Otilde": "\u00D5", - "Otimes": "\u2A37", - "Ouml": "\u00D6", - "OverBar": "\u203E", - "OverBrace": "\u23DE", - "OverBracket": "\u23B4", - "OverParenthesis": "\u23DC", - "PartialD": "\u2202", - "Pcy": "\u041F", - "Pfr": "\U0001D513", - "Phi": "\u03A6", - "Pi": "\u03A0", - "PlusMinus": "\u00B1", - "Poincareplane": "\u210C", - "Popf": "\u2119", - "Pr": "\u2ABB", - "Precedes": "\u227A", - "PrecedesEqual": "\u2AAF", - "PrecedesSlantEqual": "\u227C", - "PrecedesTilde": "\u227E", - "Prime": "\u2033", - "Product": "\u220F", - "Proportion": "\u2237", - "Proportional": "\u221D", - "Pscr": "\U0001D4AB", - "Psi": "\u03A8", - "QUOT": "\u0022", - "Qfr": "\U0001D514", - "Qopf": "\u211A", - "Qscr": "\U0001D4AC", - "RBarr": "\u2910", - "REG": "\u00AE", - "Racute": "\u0154", - "Rang": "\u27EB", - "Rarr": "\u21A0", - "Rarrtl": "\u2916", - "Rcaron": "\u0158", - "Rcedil": "\u0156", - "Rcy": "\u0420", - "Re": "\u211C", - "ReverseElement": "\u220B", - "ReverseEquilibrium": "\u21CB", - "ReverseUpEquilibrium": "\u296F", - "Rfr": "\u211C", - "Rho": "\u03A1", - "RightAngleBracket": "\u27E9", - "RightArrow": "\u2192", - "RightArrowBar": "\u21E5", - "RightArrowLeftArrow": "\u21C4", - "RightCeiling": "\u2309", - "RightDoubleBracket": "\u27E7", - "RightDownTeeVector": "\u295D", - "RightDownVector": "\u21C2", - "RightDownVectorBar": "\u2955", - "RightFloor": "\u230B", - "RightTee": "\u22A2", - "RightTeeArrow": "\u21A6", - "RightTeeVector": "\u295B", - "RightTriangle": "\u22B3", - "RightTriangleBar": "\u29D0", - "RightTriangleEqual": "\u22B5", - "RightUpDownVector": "\u294F", - "RightUpTeeVector": "\u295C", - "RightUpVector": "\u21BE", - "RightUpVectorBar": "\u2954", - "RightVector": "\u21C0", - "RightVectorBar": "\u2953", - "Rightarrow": "\u21D2", - "Ropf": "\u211D", - "RoundImplies": "\u2970", - "Rrightarrow": "\u21DB", - "Rscr": "\u211B", - "Rsh": "\u21B1", - "RuleDelayed": "\u29F4", - "SHCHcy": "\u0429", - "SHcy": "\u0428", - "SOFTcy": "\u042C", - "Sacute": "\u015A", - "Sc": "\u2ABC", - "Scaron": "\u0160", - "Scedil": "\u015E", - "Scirc": "\u015C", - "Scy": "\u0421", - "Sfr": "\U0001D516", - "ShortDownArrow": "\u2193", - "ShortLeftArrow": "\u2190", - "ShortRightArrow": "\u2192", - "ShortUpArrow": "\u2191", - "Sigma": "\u03A3", - "SmallCircle": "\u2218", - "Sopf": "\U0001D54A", - "Sqrt": "\u221A", - "Square": "\u25A1", - "SquareIntersection": "\u2293", - "SquareSubset": "\u228F", - "SquareSubsetEqual": "\u2291", - "SquareSuperset": "\u2290", - "SquareSupersetEqual": "\u2292", - "SquareUnion": "\u2294", - "Sscr": "\U0001D4AE", - "Star": "\u22C6", - "Sub": "\u22D0", - "Subset": "\u22D0", - "SubsetEqual": "\u2286", - "Succeeds": "\u227B", - "SucceedsEqual": "\u2AB0", - "SucceedsSlantEqual": "\u227D", - "SucceedsTilde": "\u227F", - "SuchThat": "\u220B", - "Sum": "\u2211", - "Sup": "\u22D1", - "Superset": "\u2283", - "SupersetEqual": "\u2287", - "Supset": "\u22D1", - "THORN": "\u00DE", - "TRADE": "\u2122", - "TSHcy": "\u040B", - "TScy": "\u0426", - "Tab": "\u0009", - "Tau": "\u03A4", - "Tcaron": "\u0164", - "Tcedil": "\u0162", - "Tcy": "\u0422", - "Tfr": "\U0001D517", - "Therefore": "\u2234", - "Theta": "\u0398", - "ThickSpace": "\u205F\u200A", - "ThinSpace": "\u2009", - "Tilde": "\u223C", - "TildeEqual": "\u2243", - "TildeFullEqual": "\u2245", - "TildeTilde": "\u2248", - "Topf": "\U0001D54B", - "TripleDot": "\u20DB", - "Tscr": "\U0001D4AF", - "Tstrok": "\u0166", - "Uacute": "\u00DA", - "Uarr": "\u219F", - "Uarrocir": "\u2949", - "Ubrcy": "\u040E", - "Ubreve": "\u016C", - "Ucirc": "\u00DB", - "Ucy": "\u0423", - "Udblac": "\u0170", - "Ufr": "\U0001D518", - "Ugrave": "\u00D9", - "Umacr": "\u016A", - "UnderBar": "\u005F", - "UnderBrace": "\u23DF", - "UnderBracket": "\u23B5", - "UnderParenthesis": "\u23DD", - "Union": "\u22C3", - "UnionPlus": "\u228E", - "Uogon": "\u0172", - "Uopf": "\U0001D54C", - "UpArrow": "\u2191", - "UpArrowBar": "\u2912", - "UpArrowDownArrow": "\u21C5", - "UpDownArrow": "\u2195", - "UpEquilibrium": "\u296E", - "UpTee": "\u22A5", - "UpTeeArrow": "\u21A5", - "Uparrow": "\u21D1", - "Updownarrow": "\u21D5", - "UpperLeftArrow": "\u2196", - "UpperRightArrow": "\u2197", - "Upsi": "\u03D2", - "Upsilon": "\u03A5", - "Uring": "\u016E", - "Uscr": "\U0001D4B0", - "Utilde": "\u0168", - "Uuml": "\u00DC", - "VDash": "\u22AB", - "Vbar": "\u2AEB", - "Vcy": "\u0412", - "Vdash": "\u22A9", - "Vdashl": "\u2AE6", - "Vee": "\u22C1", - "Verbar": "\u2016", - "Vert": "\u2016", - "VerticalBar": "\u2223", - "VerticalLine": "\u007C", - "VerticalSeparator": "\u2758", - "VerticalTilde": "\u2240", - "VeryThinSpace": "\u200A", - "Vfr": "\U0001D519", - "Vopf": "\U0001D54D", - "Vscr": "\U0001D4B1", - "Vvdash": "\u22AA", - "Wcirc": "\u0174", - "Wedge": "\u22C0", - "Wfr": "\U0001D51A", - "Wopf": "\U0001D54E", - "Wscr": "\U0001D4B2", - "Xfr": "\U0001D51B", - "Xi": "\u039E", - "Xopf": "\U0001D54F", - "Xscr": "\U0001D4B3", - "YAcy": "\u042F", - "YIcy": "\u0407", - "YUcy": "\u042E", - "Yacute": "\u00DD", - "Ycirc": "\u0176", - "Ycy": "\u042B", - "Yfr": "\U0001D51C", - "Yopf": "\U0001D550", - "Yscr": "\U0001D4B4", - "Yuml": "\u0178", - "ZHcy": "\u0416", - "Zacute": "\u0179", - "Zcaron": "\u017D", - "Zcy": "\u0417", - "Zdot": "\u017B", - "ZeroWidthSpace": "\u200B", - "Zeta": "\u0396", - "Zfr": "\u2128", - "Zopf": "\u2124", - "Zscr": "\U0001D4B5", - "aacute": "\u00E1", - "abreve": "\u0103", - "ac": "\u223E", - "acE": "\u223E\u0333", - "acd": "\u223F", - "acirc": "\u00E2", - "acute": "\u00B4", - "acy": "\u0430", - "aelig": "\u00E6", - "af": "\u2061", - "afr": "\U0001D51E", - "agrave": "\u00E0", - "alefsym": "\u2135", - "aleph": "\u2135", - "alpha": "\u03B1", - "amacr": "\u0101", - "amalg": "\u2A3F", - "amp": "\u0026", - "and": "\u2227", - "andand": "\u2A55", - "andd": "\u2A5C", - "andslope": "\u2A58", - "andv": "\u2A5A", - "ang": "\u2220", - "ange": "\u29A4", - "angle": "\u2220", - "angmsd": "\u2221", - "angmsdaa": "\u29A8", - "angmsdab": "\u29A9", - "angmsdac": "\u29AA", - "angmsdad": "\u29AB", - "angmsdae": "\u29AC", - "angmsdaf": "\u29AD", - "angmsdag": "\u29AE", - "angmsdah": "\u29AF", - "angrt": "\u221F", - "angrtvb": "\u22BE", - "angrtvbd": "\u299D", - "angsph": "\u2222", - "angst": "\u00C5", - "angzarr": "\u237C", - "aogon": "\u0105", - "aopf": "\U0001D552", - "ap": "\u2248", - "apE": "\u2A70", - "apacir": "\u2A6F", - "ape": "\u224A", - "apid": "\u224B", - "apos": "\u0027", - "approx": "\u2248", - "approxeq": "\u224A", - "aring": "\u00E5", - "ascr": "\U0001D4B6", - "ast": "\u002A", - "asymp": "\u2248", - "asympeq": "\u224D", - "atilde": "\u00E3", - "auml": "\u00E4", - "awconint": "\u2233", - "awint": "\u2A11", - "bNot": "\u2AED", - "backcong": "\u224C", - "backepsilon": "\u03F6", - "backprime": "\u2035", - "backsim": "\u223D", - "backsimeq": "\u22CD", - "barvee": "\u22BD", - "barwed": "\u2305", - "barwedge": "\u2305", - "bbrk": "\u23B5", - "bbrktbrk": "\u23B6", - "bcong": "\u224C", - "bcy": "\u0431", - "bdquo": "\u201E", - "becaus": "\u2235", - "because": "\u2235", - "bemptyv": "\u29B0", - "bepsi": "\u03F6", - "bernou": "\u212C", - "beta": "\u03B2", - "beth": "\u2136", - "between": "\u226C", - "bfr": "\U0001D51F", - "bigcap": "\u22C2", - "bigcirc": "\u25EF", - "bigcup": "\u22C3", - "bigodot": "\u2A00", - "bigoplus": "\u2A01", - "bigotimes": "\u2A02", - "bigsqcup": "\u2A06", - "bigstar": "\u2605", - "bigtriangledown": "\u25BD", - "bigtriangleup": "\u25B3", - "biguplus": "\u2A04", - "bigvee": "\u22C1", - "bigwedge": "\u22C0", - "bkarow": "\u290D", - "blacklozenge": "\u29EB", - "blacksquare": "\u25AA", - "blacktriangle": "\u25B4", - "blacktriangledown": "\u25BE", - "blacktriangleleft": "\u25C2", - "blacktriangleright": "\u25B8", - "blank": "\u2423", - "blk12": "\u2592", - "blk14": "\u2591", - "blk34": "\u2593", - "block": "\u2588", - "bne": "\u003D\u20E5", - "bnequiv": "\u2261\u20E5", - "bnot": "\u2310", - "bopf": "\U0001D553", - "bot": "\u22A5", - "bottom": "\u22A5", - "bowtie": "\u22C8", - "boxDL": "\u2557", - "boxDR": "\u2554", - "boxDl": "\u2556", - "boxDr": "\u2553", - "boxH": "\u2550", - "boxHD": "\u2566", - "boxHU": "\u2569", - "boxHd": "\u2564", - "boxHu": "\u2567", - "boxUL": "\u255D", - "boxUR": "\u255A", - "boxUl": "\u255C", - "boxUr": "\u2559", - "boxV": "\u2551", - "boxVH": "\u256C", - "boxVL": "\u2563", - "boxVR": "\u2560", - "boxVh": "\u256B", - "boxVl": "\u2562", - "boxVr": "\u255F", - "boxbox": "\u29C9", - "boxdL": "\u2555", - "boxdR": "\u2552", - "boxdl": "\u2510", - "boxdr": "\u250C", - "boxh": "\u2500", - "boxhD": "\u2565", - "boxhU": "\u2568", - "boxhd": "\u252C", - "boxhu": "\u2534", - "boxminus": "\u229F", - "boxplus": "\u229E", - "boxtimes": "\u22A0", - "boxuL": "\u255B", - "boxuR": "\u2558", - "boxul": "\u2518", - "boxur": "\u2514", - "boxv": "\u2502", - "boxvH": "\u256A", - "boxvL": "\u2561", - "boxvR": "\u255E", - "boxvh": "\u253C", - "boxvl": "\u2524", - "boxvr": "\u251C", - "bprime": "\u2035", - "breve": "\u02D8", - "brvbar": "\u00A6", - "bscr": "\U0001D4B7", - "bsemi": "\u204F", - "bsim": "\u223D", - "bsime": "\u22CD", - "bsol": "\u005C", - "bsolb": "\u29C5", - "bsolhsub": "\u27C8", - "bull": "\u2022", - "bullet": "\u2022", - "bump": "\u224E", - "bumpE": "\u2AAE", - "bumpe": "\u224F", - "bumpeq": "\u224F", - "cacute": "\u0107", - "cap": "\u2229", - "capand": "\u2A44", - "capbrcup": "\u2A49", - "capcap": "\u2A4B", - "capcup": "\u2A47", - "capdot": "\u2A40", - "caps": "\u2229\uFE00", - "caret": "\u2041", - "caron": "\u02C7", - "ccaps": "\u2A4D", - "ccaron": "\u010D", - "ccedil": "\u00E7", - "ccirc": "\u0109", - "ccups": "\u2A4C", - "ccupssm": "\u2A50", - "cdot": "\u010B", - "cedil": "\u00B8", - "cemptyv": "\u29B2", - "cent": "\u00A2", - "centerdot": "\u00B7", - "cfr": "\U0001D520", - "chcy": "\u0447", - "check": "\u2713", - "checkmark": "\u2713", - "chi": "\u03C7", - "cir": "\u25CB", - "cirE": "\u29C3", - "circ": "\u02C6", - "circeq": "\u2257", - "circlearrowleft": "\u21BA", - "circlearrowright": "\u21BB", - "circledR": "\u00AE", - "circledS": "\u24C8", - "circledast": "\u229B", - "circledcirc": "\u229A", - "circleddash": "\u229D", - "cire": "\u2257", - "cirfnint": "\u2A10", - "cirmid": "\u2AEF", - "cirscir": "\u29C2", - "clubs": "\u2663", - "clubsuit": "\u2663", - "colon": "\u003A", - "colone": "\u2254", - "coloneq": "\u2254", - "comma": "\u002C", - "commat": "\u0040", - "comp": "\u2201", - "compfn": "\u2218", - "complement": "\u2201", - "complexes": "\u2102", - "cong": "\u2245", - "congdot": "\u2A6D", - "conint": "\u222E", - "copf": "\U0001D554", - "coprod": "\u2210", - "copy": "\u00A9", - "copysr": "\u2117", - "crarr": "\u21B5", - "cross": "\u2717", - "cscr": "\U0001D4B8", - "csub": "\u2ACF", - "csube": "\u2AD1", - "csup": "\u2AD0", - "csupe": "\u2AD2", - "ctdot": "\u22EF", - "cudarrl": "\u2938", - "cudarrr": "\u2935", - "cuepr": "\u22DE", - "cuesc": "\u22DF", - "cularr": "\u21B6", - "cularrp": "\u293D", - "cup": "\u222A", - "cupbrcap": "\u2A48", - "cupcap": "\u2A46", - "cupcup": "\u2A4A", - "cupdot": "\u228D", - "cupor": "\u2A45", - "cups": "\u222A\uFE00", - "curarr": "\u21B7", - "curarrm": "\u293C", - "curlyeqprec": "\u22DE", - "curlyeqsucc": "\u22DF", - "curlyvee": "\u22CE", - "curlywedge": "\u22CF", - "curren": "\u00A4", - "curvearrowleft": "\u21B6", - "curvearrowright": "\u21B7", - "cuvee": "\u22CE", - "cuwed": "\u22CF", - "cwconint": "\u2232", - "cwint": "\u2231", - "cylcty": "\u232D", - "dArr": "\u21D3", - "dHar": "\u2965", - "dagger": "\u2020", - "daleth": "\u2138", - "darr": "\u2193", - "dash": "\u2010", - "dashv": "\u22A3", - "dbkarow": "\u290F", - "dblac": "\u02DD", - "dcaron": "\u010F", - "dcy": "\u0434", - "dd": "\u2146", - "ddagger": "\u2021", - "ddarr": "\u21CA", - "ddotseq": "\u2A77", - "deg": "\u00B0", - "delta": "\u03B4", - "demptyv": "\u29B1", - "dfisht": "\u297F", - "dfr": "\U0001D521", - "dharl": "\u21C3", - "dharr": "\u21C2", - "diam": "\u22C4", - "diamond": "\u22C4", - "diamondsuit": "\u2666", - "diams": "\u2666", - "die": "\u00A8", - "digamma": "\u03DD", - "disin": "\u22F2", - "div": "\u00F7", - "divide": "\u00F7", - "divideontimes": "\u22C7", - "divonx": "\u22C7", - "djcy": "\u0452", - "dlcorn": "\u231E", - "dlcrop": "\u230D", - "dollar": "\u0024", - "dopf": "\U0001D555", - "dot": "\u02D9", - "doteq": "\u2250", - "doteqdot": "\u2251", - "dotminus": "\u2238", - "dotplus": "\u2214", - "dotsquare": "\u22A1", - "doublebarwedge": "\u2306", - "downarrow": "\u2193", - "downdownarrows": "\u21CA", - "downharpoonleft": "\u21C3", - "downharpoonright": "\u21C2", - "drbkarow": "\u2910", - "drcorn": "\u231F", - "drcrop": "\u230C", - "dscr": "\U0001D4B9", - "dscy": "\u0455", - "dsol": "\u29F6", - "dstrok": "\u0111", - "dtdot": "\u22F1", - "dtri": "\u25BF", - "dtrif": "\u25BE", - "duarr": "\u21F5", - "duhar": "\u296F", - "dwangle": "\u29A6", - "dzcy": "\u045F", - "dzigrarr": "\u27FF", - "eDDot": "\u2A77", - "eDot": "\u2251", - "eacute": "\u00E9", - "easter": "\u2A6E", - "ecaron": "\u011B", - "ecir": "\u2256", - "ecirc": "\u00EA", - "ecolon": "\u2255", - "ecy": "\u044D", - "edot": "\u0117", - "ee": "\u2147", - "efDot": "\u2252", - "efr": "\U0001D522", - "eg": "\u2A9A", - "egrave": "\u00E8", - "egs": "\u2A96", - "egsdot": "\u2A98", - "el": "\u2A99", - "elinters": "\u23E7", - "ell": "\u2113", - "els": "\u2A95", - "elsdot": "\u2A97", - "emacr": "\u0113", - "empty": "\u2205", - "emptyset": "\u2205", - "emptyv": "\u2205", - "emsp": "\u2003", - "emsp13": "\u2004", - "emsp14": "\u2005", - "eng": "\u014B", - "ensp": "\u2002", - "eogon": "\u0119", - "eopf": "\U0001D556", - "epar": "\u22D5", - "eparsl": "\u29E3", - "eplus": "\u2A71", - "epsi": "\u03B5", - "epsilon": "\u03B5", - "epsiv": "\u03F5", - "eqcirc": "\u2256", - "eqcolon": "\u2255", - "eqsim": "\u2242", - "eqslantgtr": "\u2A96", - "eqslantless": "\u2A95", - "equals": "\u003D", - "equest": "\u225F", - "equiv": "\u2261", - "equivDD": "\u2A78", - "eqvparsl": "\u29E5", - "erDot": "\u2253", - "erarr": "\u2971", - "escr": "\u212F", - "esdot": "\u2250", - "esim": "\u2242", - "eta": "\u03B7", - "eth": "\u00F0", - "euml": "\u00EB", - "euro": "\u20AC", - "excl": "\u0021", - "exist": "\u2203", - "expectation": "\u2130", - "exponentiale": "\u2147", - "fallingdotseq": "\u2252", - "fcy": "\u0444", - "female": "\u2640", - "ffilig": "\uFB03", - "fflig": "\uFB00", - "ffllig": "\uFB04", - "ffr": "\U0001D523", - "filig": "\uFB01", - "fjlig": "\u0066\u006A", - "flat": "\u266D", - "fllig": "\uFB02", - "fltns": "\u25B1", - "fnof": "\u0192", - "fopf": "\U0001D557", - "forall": "\u2200", - "fork": "\u22D4", - "forkv": "\u2AD9", - "fpartint": "\u2A0D", - "frac12": "\u00BD", - "frac13": "\u2153", - "frac14": "\u00BC", - "frac15": "\u2155", - "frac16": "\u2159", - "frac18": "\u215B", - "frac23": "\u2154", - "frac25": "\u2156", - "frac34": "\u00BE", - "frac35": "\u2157", - "frac38": "\u215C", - "frac45": "\u2158", - "frac56": "\u215A", - "frac58": "\u215D", - "frac78": "\u215E", - "frasl": "\u2044", - "frown": "\u2322", - "fscr": "\U0001D4BB", - "gE": "\u2267", - "gEl": "\u2A8C", - "gacute": "\u01F5", - "gamma": "\u03B3", - "gammad": "\u03DD", - "gap": "\u2A86", - "gbreve": "\u011F", - "gcirc": "\u011D", - "gcy": "\u0433", - "gdot": "\u0121", - "ge": "\u2265", - "gel": "\u22DB", - "geq": "\u2265", - "geqq": "\u2267", - "geqslant": "\u2A7E", - "ges": "\u2A7E", - "gescc": "\u2AA9", - "gesdot": "\u2A80", - "gesdoto": "\u2A82", - "gesdotol": "\u2A84", - "gesl": "\u22DB\uFE00", - "gesles": "\u2A94", - "gfr": "\U0001D524", - "gg": "\u226B", - "ggg": "\u22D9", - "gimel": "\u2137", - "gjcy": "\u0453", - "gl": "\u2277", - "glE": "\u2A92", - "gla": "\u2AA5", - "glj": "\u2AA4", - "gnE": "\u2269", - "gnap": "\u2A8A", - "gnapprox": "\u2A8A", - "gne": "\u2A88", - "gneq": "\u2A88", - "gneqq": "\u2269", - "gnsim": "\u22E7", - "gopf": "\U0001D558", - "grave": "\u0060", - "gscr": "\u210A", - "gsim": "\u2273", - "gsime": "\u2A8E", - "gsiml": "\u2A90", - "gt": "\u003E", - "gtcc": "\u2AA7", - "gtcir": "\u2A7A", - "gtdot": "\u22D7", - "gtlPar": "\u2995", - "gtquest": "\u2A7C", - "gtrapprox": "\u2A86", - "gtrarr": "\u2978", - "gtrdot": "\u22D7", - "gtreqless": "\u22DB", - "gtreqqless": "\u2A8C", - "gtrless": "\u2277", - "gtrsim": "\u2273", - "gvertneqq": "\u2269\uFE00", - "gvnE": "\u2269\uFE00", - "hArr": "\u21D4", - "hairsp": "\u200A", - "half": "\u00BD", - "hamilt": "\u210B", - "hardcy": "\u044A", - "harr": "\u2194", - "harrcir": "\u2948", - "harrw": "\u21AD", - "hbar": "\u210F", - "hcirc": "\u0125", - "hearts": "\u2665", - "heartsuit": "\u2665", - "hellip": "\u2026", - "hercon": "\u22B9", - "hfr": "\U0001D525", - "hksearow": "\u2925", - "hkswarow": "\u2926", - "hoarr": "\u21FF", - "homtht": "\u223B", - "hookleftarrow": "\u21A9", - "hookrightarrow": "\u21AA", - "hopf": "\U0001D559", - "horbar": "\u2015", - "hscr": "\U0001D4BD", - "hslash": "\u210F", - "hstrok": "\u0127", - "hybull": "\u2043", - "hyphen": "\u2010", - "iacute": "\u00ED", - "ic": "\u2063", - "icirc": "\u00EE", - "icy": "\u0438", - "iecy": "\u0435", - "iexcl": "\u00A1", - "iff": "\u21D4", - "ifr": "\U0001D526", - "igrave": "\u00EC", - "ii": "\u2148", - "iiiint": "\u2A0C", - "iiint": "\u222D", - "iinfin": "\u29DC", - "iiota": "\u2129", - "ijlig": "\u0133", - "imacr": "\u012B", - "image": "\u2111", - "imagline": "\u2110", - "imagpart": "\u2111", - "imath": "\u0131", - "imof": "\u22B7", - "imped": "\u01B5", - "in": "\u2208", - "incare": "\u2105", - "infin": "\u221E", - "infintie": "\u29DD", - "inodot": "\u0131", - "int": "\u222B", - "intcal": "\u22BA", - "integers": "\u2124", - "intercal": "\u22BA", - "intlarhk": "\u2A17", - "intprod": "\u2A3C", - "iocy": "\u0451", - "iogon": "\u012F", - "iopf": "\U0001D55A", - "iota": "\u03B9", - "iprod": "\u2A3C", - "iquest": "\u00BF", - "iscr": "\U0001D4BE", - "isin": "\u2208", - "isinE": "\u22F9", - "isindot": "\u22F5", - "isins": "\u22F4", - "isinsv": "\u22F3", - "isinv": "\u2208", - "it": "\u2062", - "itilde": "\u0129", - "iukcy": "\u0456", - "iuml": "\u00EF", - "jcirc": "\u0135", - "jcy": "\u0439", - "jfr": "\U0001D527", - "jmath": "\u0237", - "jopf": "\U0001D55B", - "jscr": "\U0001D4BF", - "jsercy": "\u0458", - "jukcy": "\u0454", - "kappa": "\u03BA", - "kappav": "\u03F0", - "kcedil": "\u0137", - "kcy": "\u043A", - "kfr": "\U0001D528", - "kgreen": "\u0138", - "khcy": "\u0445", - "kjcy": "\u045C", - "kopf": "\U0001D55C", - "kscr": "\U0001D4C0", - "lAarr": "\u21DA", - "lArr": "\u21D0", - "lAtail": "\u291B", - "lBarr": "\u290E", - "lE": "\u2266", - "lEg": "\u2A8B", - "lHar": "\u2962", - "lacute": "\u013A", - "laemptyv": "\u29B4", - "lagran": "\u2112", - "lambda": "\u03BB", - "lang": "\u27E8", - "langd": "\u2991", - "langle": "\u27E8", - "lap": "\u2A85", - "laquo": "\u00AB", - "larr": "\u2190", - "larrb": "\u21E4", - "larrbfs": "\u291F", - "larrfs": "\u291D", - "larrhk": "\u21A9", - "larrlp": "\u21AB", - "larrpl": "\u2939", - "larrsim": "\u2973", - "larrtl": "\u21A2", - "lat": "\u2AAB", - "latail": "\u2919", - "late": "\u2AAD", - "lates": "\u2AAD\uFE00", - "lbarr": "\u290C", - "lbbrk": "\u2772", - "lbrace": "\u007B", - "lbrack": "\u005B", - "lbrke": "\u298B", - "lbrksld": "\u298F", - "lbrkslu": "\u298D", - "lcaron": "\u013E", - "lcedil": "\u013C", - "lceil": "\u2308", - "lcub": "\u007B", - "lcy": "\u043B", - "ldca": "\u2936", - "ldquo": "\u201C", - "ldquor": "\u201E", - "ldrdhar": "\u2967", - "ldrushar": "\u294B", - "ldsh": "\u21B2", - "le": "\u2264", - "leftarrow": "\u2190", - "leftarrowtail": "\u21A2", - "leftharpoondown": "\u21BD", - "leftharpoonup": "\u21BC", - "leftleftarrows": "\u21C7", - "leftrightarrow": "\u2194", - "leftrightarrows": "\u21C6", - "leftrightharpoons": "\u21CB", - "leftrightsquigarrow": "\u21AD", - "leftthreetimes": "\u22CB", - "leg": "\u22DA", - "leq": "\u2264", - "leqq": "\u2266", - "leqslant": "\u2A7D", - "les": "\u2A7D", - "lescc": "\u2AA8", - "lesdot": "\u2A7F", - "lesdoto": "\u2A81", - "lesdotor": "\u2A83", - "lesg": "\u22DA\uFE00", - "lesges": "\u2A93", - "lessapprox": "\u2A85", - "lessdot": "\u22D6", - "lesseqgtr": "\u22DA", - "lesseqqgtr": "\u2A8B", - "lessgtr": "\u2276", - "lesssim": "\u2272", - "lfisht": "\u297C", - "lfloor": "\u230A", - "lfr": "\U0001D529", - "lg": "\u2276", - "lgE": "\u2A91", - "lhard": "\u21BD", - "lharu": "\u21BC", - "lharul": "\u296A", - "lhblk": "\u2584", - "ljcy": "\u0459", - "ll": "\u226A", - "llarr": "\u21C7", - "llcorner": "\u231E", - "llhard": "\u296B", - "lltri": "\u25FA", - "lmidot": "\u0140", - "lmoust": "\u23B0", - "lmoustache": "\u23B0", - "lnE": "\u2268", - "lnap": "\u2A89", - "lnapprox": "\u2A89", - "lne": "\u2A87", - "lneq": "\u2A87", - "lneqq": "\u2268", - "lnsim": "\u22E6", - "loang": "\u27EC", - "loarr": "\u21FD", - "lobrk": "\u27E6", - "longleftarrow": "\u27F5", - "longleftrightarrow": "\u27F7", - "longmapsto": "\u27FC", - "longrightarrow": "\u27F6", - "looparrowleft": "\u21AB", - "looparrowright": "\u21AC", - "lopar": "\u2985", - "lopf": "\U0001D55D", - "loplus": "\u2A2D", - "lotimes": "\u2A34", - "lowast": "\u2217", - "lowbar": "\u005F", - "loz": "\u25CA", - "lozenge": "\u25CA", - "lozf": "\u29EB", - "lpar": "\u0028", - "lparlt": "\u2993", - "lrarr": "\u21C6", - "lrcorner": "\u231F", - "lrhar": "\u21CB", - "lrhard": "\u296D", - "lrm": "\u200E", - "lrtri": "\u22BF", - "lsaquo": "\u2039", - "lscr": "\U0001D4C1", - "lsh": "\u21B0", - "lsim": "\u2272", - "lsime": "\u2A8D", - "lsimg": "\u2A8F", - "lsqb": "\u005B", - "lsquo": "\u2018", - "lsquor": "\u201A", - "lstrok": "\u0142", - "lt": "\u003C", - "ltcc": "\u2AA6", - "ltcir": "\u2A79", - "ltdot": "\u22D6", - "lthree": "\u22CB", - "ltimes": "\u22C9", - "ltlarr": "\u2976", - "ltquest": "\u2A7B", - "ltrPar": "\u2996", - "ltri": "\u25C3", - "ltrie": "\u22B4", - "ltrif": "\u25C2", - "lurdshar": "\u294A", - "luruhar": "\u2966", - "lvertneqq": "\u2268\uFE00", - "lvnE": "\u2268\uFE00", - "mDDot": "\u223A", - "macr": "\u00AF", - "male": "\u2642", - "malt": "\u2720", - "maltese": "\u2720", - "map": "\u21A6", - "mapsto": "\u21A6", - "mapstodown": "\u21A7", - "mapstoleft": "\u21A4", - "mapstoup": "\u21A5", - "marker": "\u25AE", - "mcomma": "\u2A29", - "mcy": "\u043C", - "mdash": "\u2014", - "measuredangle": "\u2221", - "mfr": "\U0001D52A", - "mho": "\u2127", - "micro": "\u00B5", - "mid": "\u2223", - "midast": "\u002A", - "midcir": "\u2AF0", - "middot": "\u00B7", - "minus": "\u2212", - "minusb": "\u229F", - "minusd": "\u2238", - "minusdu": "\u2A2A", - "mlcp": "\u2ADB", - "mldr": "\u2026", - "mnplus": "\u2213", - "models": "\u22A7", - "mopf": "\U0001D55E", - "mp": "\u2213", - "mscr": "\U0001D4C2", - "mstpos": "\u223E", - "mu": "\u03BC", - "multimap": "\u22B8", - "mumap": "\u22B8", - "nGg": "\u22D9\u0338", - "nGt": "\u226B\u20D2", - "nGtv": "\u226B\u0338", - "nLeftarrow": "\u21CD", - "nLeftrightarrow": "\u21CE", - "nLl": "\u22D8\u0338", - "nLt": "\u226A\u20D2", - "nLtv": "\u226A\u0338", - "nRightarrow": "\u21CF", - "nVDash": "\u22AF", - "nVdash": "\u22AE", - "nabla": "\u2207", - "nacute": "\u0144", - "nang": "\u2220\u20D2", - "nap": "\u2249", - "napE": "\u2A70\u0338", - "napid": "\u224B\u0338", - "napos": "\u0149", - "napprox": "\u2249", - "natur": "\u266E", - "natural": "\u266E", - "naturals": "\u2115", - "nbsp": "\u00A0", - "nbump": "\u224E\u0338", - "nbumpe": "\u224F\u0338", - "ncap": "\u2A43", - "ncaron": "\u0148", - "ncedil": "\u0146", - "ncong": "\u2247", - "ncongdot": "\u2A6D\u0338", - "ncup": "\u2A42", - "ncy": "\u043D", - "ndash": "\u2013", - "ne": "\u2260", - "neArr": "\u21D7", - "nearhk": "\u2924", - "nearr": "\u2197", - "nearrow": "\u2197", - "nedot": "\u2250\u0338", - "nequiv": "\u2262", - "nesear": "\u2928", - "nesim": "\u2242\u0338", - "nexist": "\u2204", - "nexists": "\u2204", - "nfr": "\U0001D52B", - "ngE": "\u2267\u0338", - "nge": "\u2271", - "ngeq": "\u2271", - "ngeqq": "\u2267\u0338", - "ngeqslant": "\u2A7E\u0338", - "nges": "\u2A7E\u0338", - "ngsim": "\u2275", - "ngt": "\u226F", - "ngtr": "\u226F", - "nhArr": "\u21CE", - "nharr": "\u21AE", - "nhpar": "\u2AF2", - "ni": "\u220B", - "nis": "\u22FC", - "nisd": "\u22FA", - "niv": "\u220B", - "njcy": "\u045A", - "nlArr": "\u21CD", - "nlE": "\u2266\u0338", - "nlarr": "\u219A", - "nldr": "\u2025", - "nle": "\u2270", - "nleftarrow": "\u219A", - "nleftrightarrow": "\u21AE", - "nleq": "\u2270", - "nleqq": "\u2266\u0338", - "nleqslant": "\u2A7D\u0338", - "nles": "\u2A7D\u0338", - "nless": "\u226E", - "nlsim": "\u2274", - "nlt": "\u226E", - "nltri": "\u22EA", - "nltrie": "\u22EC", - "nmid": "\u2224", - "nopf": "\U0001D55F", - "not": "\u00AC", - "notin": "\u2209", - "notinE": "\u22F9\u0338", - "notindot": "\u22F5\u0338", - "notinva": "\u2209", - "notinvb": "\u22F7", - "notinvc": "\u22F6", - "notni": "\u220C", - "notniva": "\u220C", - "notnivb": "\u22FE", - "notnivc": "\u22FD", - "npar": "\u2226", - "nparallel": "\u2226", - "nparsl": "\u2AFD\u20E5", - "npart": "\u2202\u0338", - "npolint": "\u2A14", - "npr": "\u2280", - "nprcue": "\u22E0", - "npre": "\u2AAF\u0338", - "nprec": "\u2280", - "npreceq": "\u2AAF\u0338", - "nrArr": "\u21CF", - "nrarr": "\u219B", - "nrarrc": "\u2933\u0338", - "nrarrw": "\u219D\u0338", - "nrightarrow": "\u219B", - "nrtri": "\u22EB", - "nrtrie": "\u22ED", - "nsc": "\u2281", - "nsccue": "\u22E1", - "nsce": "\u2AB0\u0338", - "nscr": "\U0001D4C3", - "nshortmid": "\u2224", - "nshortparallel": "\u2226", - "nsim": "\u2241", - "nsime": "\u2244", - "nsimeq": "\u2244", - "nsmid": "\u2224", - "nspar": "\u2226", - "nsqsube": "\u22E2", - "nsqsupe": "\u22E3", - "nsub": "\u2284", - "nsubE": "\u2AC5\u0338", - "nsube": "\u2288", - "nsubset": "\u2282\u20D2", - "nsubseteq": "\u2288", - "nsubseteqq": "\u2AC5\u0338", - "nsucc": "\u2281", - "nsucceq": "\u2AB0\u0338", - "nsup": "\u2285", - "nsupE": "\u2AC6\u0338", - "nsupe": "\u2289", - "nsupset": "\u2283\u20D2", - "nsupseteq": "\u2289", - "nsupseteqq": "\u2AC6\u0338", - "ntgl": "\u2279", - "ntilde": "\u00F1", - "ntlg": "\u2278", - "ntriangleleft": "\u22EA", - "ntrianglelefteq": "\u22EC", - "ntriangleright": "\u22EB", - "ntrianglerighteq": "\u22ED", - "nu": "\u03BD", - "num": "\u0023", - "numero": "\u2116", - "numsp": "\u2007", - "nvDash": "\u22AD", - "nvHarr": "\u2904", - "nvap": "\u224D\u20D2", - "nvdash": "\u22AC", - "nvge": "\u2265\u20D2", - "nvgt": "\u003E\u20D2", - "nvinfin": "\u29DE", - "nvlArr": "\u2902", - "nvle": "\u2264\u20D2", - "nvlt": "\u003C\u20D2", - "nvltrie": "\u22B4\u20D2", - "nvrArr": "\u2903", - "nvrtrie": "\u22B5\u20D2", - "nvsim": "\u223C\u20D2", - "nwArr": "\u21D6", - "nwarhk": "\u2923", - "nwarr": "\u2196", - "nwarrow": "\u2196", - "nwnear": "\u2927", - "oS": "\u24C8", - "oacute": "\u00F3", - "oast": "\u229B", - "ocir": "\u229A", - "ocirc": "\u00F4", - "ocy": "\u043E", - "odash": "\u229D", - "odblac": "\u0151", - "odiv": "\u2A38", - "odot": "\u2299", - "odsold": "\u29BC", - "oelig": "\u0153", - "ofcir": "\u29BF", - "ofr": "\U0001D52C", - "ogon": "\u02DB", - "ograve": "\u00F2", - "ogt": "\u29C1", - "ohbar": "\u29B5", - "ohm": "\u03A9", - "oint": "\u222E", - "olarr": "\u21BA", - "olcir": "\u29BE", - "olcross": "\u29BB", - "oline": "\u203E", - "olt": "\u29C0", - "omacr": "\u014D", - "omega": "\u03C9", - "omicron": "\u03BF", - "omid": "\u29B6", - "ominus": "\u2296", - "oopf": "\U0001D560", - "opar": "\u29B7", - "operp": "\u29B9", - "oplus": "\u2295", - "or": "\u2228", - "orarr": "\u21BB", - "ord": "\u2A5D", - "order": "\u2134", - "orderof": "\u2134", - "ordf": "\u00AA", - "ordm": "\u00BA", - "origof": "\u22B6", - "oror": "\u2A56", - "orslope": "\u2A57", - "orv": "\u2A5B", - "oscr": "\u2134", - "oslash": "\u00F8", - "osol": "\u2298", - "otilde": "\u00F5", - "otimes": "\u2297", - "otimesas": "\u2A36", - "ouml": "\u00F6", - "ovbar": "\u233D", - "par": "\u2225", - "para": "\u00B6", - "parallel": "\u2225", - "parsim": "\u2AF3", - "parsl": "\u2AFD", - "part": "\u2202", - "pcy": "\u043F", - "percnt": "\u0025", - "period": "\u002E", - "permil": "\u2030", - "perp": "\u22A5", - "pertenk": "\u2031", - "pfr": "\U0001D52D", - "phi": "\u03C6", - "phiv": "\u03D5", - "phmmat": "\u2133", - "phone": "\u260E", - "pi": "\u03C0", - "pitchfork": "\u22D4", - "piv": "\u03D6", - "planck": "\u210F", - "planckh": "\u210E", - "plankv": "\u210F", - "plus": "\u002B", - "plusacir": "\u2A23", - "plusb": "\u229E", - "pluscir": "\u2A22", - "plusdo": "\u2214", - "plusdu": "\u2A25", - "pluse": "\u2A72", - "plusmn": "\u00B1", - "plussim": "\u2A26", - "plustwo": "\u2A27", - "pm": "\u00B1", - "pointint": "\u2A15", - "popf": "\U0001D561", - "pound": "\u00A3", - "pr": "\u227A", - "prE": "\u2AB3", - "prap": "\u2AB7", - "prcue": "\u227C", - "pre": "\u2AAF", - "prec": "\u227A", - "precapprox": "\u2AB7", - "preccurlyeq": "\u227C", - "preceq": "\u2AAF", - "precnapprox": "\u2AB9", - "precneqq": "\u2AB5", - "precnsim": "\u22E8", - "precsim": "\u227E", - "prime": "\u2032", - "primes": "\u2119", - "prnE": "\u2AB5", - "prnap": "\u2AB9", - "prnsim": "\u22E8", - "prod": "\u220F", - "profalar": "\u232E", - "profline": "\u2312", - "profsurf": "\u2313", - "prop": "\u221D", - "propto": "\u221D", - "prsim": "\u227E", - "prurel": "\u22B0", - "pscr": "\U0001D4C5", - "psi": "\u03C8", - "puncsp": "\u2008", - "qfr": "\U0001D52E", - "qint": "\u2A0C", - "qopf": "\U0001D562", - "qprime": "\u2057", - "qscr": "\U0001D4C6", - "quaternions": "\u210D", - "quatint": "\u2A16", - "quest": "\u003F", - "questeq": "\u225F", - "quot": "\u0022", - "rAarr": "\u21DB", - "rArr": "\u21D2", - "rAtail": "\u291C", - "rBarr": "\u290F", - "rHar": "\u2964", - "race": "\u223D\u0331", - "racute": "\u0155", - "radic": "\u221A", - "raemptyv": "\u29B3", - "rang": "\u27E9", - "rangd": "\u2992", - "range": "\u29A5", - "rangle": "\u27E9", - "raquo": "\u00BB", - "rarr": "\u2192", - "rarrap": "\u2975", - "rarrb": "\u21E5", - "rarrbfs": "\u2920", - "rarrc": "\u2933", - "rarrfs": "\u291E", - "rarrhk": "\u21AA", - "rarrlp": "\u21AC", - "rarrpl": "\u2945", - "rarrsim": "\u2974", - "rarrtl": "\u21A3", - "rarrw": "\u219D", - "ratail": "\u291A", - "ratio": "\u2236", - "rationals": "\u211A", - "rbarr": "\u290D", - "rbbrk": "\u2773", - "rbrace": "\u007D", - "rbrack": "\u005D", - "rbrke": "\u298C", - "rbrksld": "\u298E", - "rbrkslu": "\u2990", - "rcaron": "\u0159", - "rcedil": "\u0157", - "rceil": "\u2309", - "rcub": "\u007D", - "rcy": "\u0440", - "rdca": "\u2937", - "rdldhar": "\u2969", - "rdquo": "\u201D", - "rdquor": "\u201D", - "rdsh": "\u21B3", - "real": "\u211C", - "realine": "\u211B", - "realpart": "\u211C", - "reals": "\u211D", - "rect": "\u25AD", - "reg": "\u00AE", - "rfisht": "\u297D", - "rfloor": "\u230B", - "rfr": "\U0001D52F", - "rhard": "\u21C1", - "rharu": "\u21C0", - "rharul": "\u296C", - "rho": "\u03C1", - "rhov": "\u03F1", - "rightarrow": "\u2192", - "rightarrowtail": "\u21A3", - "rightharpoondown": "\u21C1", - "rightharpoonup": "\u21C0", - "rightleftarrows": "\u21C4", - "rightleftharpoons": "\u21CC", - "rightrightarrows": "\u21C9", - "rightsquigarrow": "\u219D", - "rightthreetimes": "\u22CC", - "ring": "\u02DA", - "risingdotseq": "\u2253", - "rlarr": "\u21C4", - "rlhar": "\u21CC", - "rlm": "\u200F", - "rmoust": "\u23B1", - "rmoustache": "\u23B1", - "rnmid": "\u2AEE", - "roang": "\u27ED", - "roarr": "\u21FE", - "robrk": "\u27E7", - "ropar": "\u2986", - "ropf": "\U0001D563", - "roplus": "\u2A2E", - "rotimes": "\u2A35", - "rpar": "\u0029", - "rpargt": "\u2994", - "rppolint": "\u2A12", - "rrarr": "\u21C9", - "rsaquo": "\u203A", - "rscr": "\U0001D4C7", - "rsh": "\u21B1", - "rsqb": "\u005D", - "rsquo": "\u2019", - "rsquor": "\u2019", - "rthree": "\u22CC", - "rtimes": "\u22CA", - "rtri": "\u25B9", - "rtrie": "\u22B5", - "rtrif": "\u25B8", - "rtriltri": "\u29CE", - "ruluhar": "\u2968", - "rx": "\u211E", - "sacute": "\u015B", - "sbquo": "\u201A", - "sc": "\u227B", - "scE": "\u2AB4", - "scap": "\u2AB8", - "scaron": "\u0161", - "sccue": "\u227D", - "sce": "\u2AB0", - "scedil": "\u015F", - "scirc": "\u015D", - "scnE": "\u2AB6", - "scnap": "\u2ABA", - "scnsim": "\u22E9", - "scpolint": "\u2A13", - "scsim": "\u227F", - "scy": "\u0441", - "sdot": "\u22C5", - "sdotb": "\u22A1", - "sdote": "\u2A66", - "seArr": "\u21D8", - "searhk": "\u2925", - "searr": "\u2198", - "searrow": "\u2198", - "sect": "\u00A7", - "semi": "\u003B", - "seswar": "\u2929", - "setminus": "\u2216", - "setmn": "\u2216", - "sext": "\u2736", - "sfr": "\U0001D530", - "sfrown": "\u2322", - "sharp": "\u266F", - "shchcy": "\u0449", - "shcy": "\u0448", - "shortmid": "\u2223", - "shortparallel": "\u2225", - "shy": "\u00AD", - "sigma": "\u03C3", - "sigmaf": "\u03C2", - "sigmav": "\u03C2", - "sim": "\u223C", - "simdot": "\u2A6A", - "sime": "\u2243", - "simeq": "\u2243", - "simg": "\u2A9E", - "simgE": "\u2AA0", - "siml": "\u2A9D", - "simlE": "\u2A9F", - "simne": "\u2246", - "simplus": "\u2A24", - "simrarr": "\u2972", - "slarr": "\u2190", - "smallsetminus": "\u2216", - "smashp": "\u2A33", - "smeparsl": "\u29E4", - "smid": "\u2223", - "smile": "\u2323", - "smt": "\u2AAA", - "smte": "\u2AAC", - "smtes": "\u2AAC\uFE00", - "softcy": "\u044C", - "sol": "\u002F", - "solb": "\u29C4", - "solbar": "\u233F", - "sopf": "\U0001D564", - "spades": "\u2660", - "spadesuit": "\u2660", - "spar": "\u2225", - "sqcap": "\u2293", - "sqcaps": "\u2293\uFE00", - "sqcup": "\u2294", - "sqcups": "\u2294\uFE00", - "sqsub": "\u228F", - "sqsube": "\u2291", - "sqsubset": "\u228F", - "sqsubseteq": "\u2291", - "sqsup": "\u2290", - "sqsupe": "\u2292", - "sqsupset": "\u2290", - "sqsupseteq": "\u2292", - "squ": "\u25A1", - "square": "\u25A1", - "squarf": "\u25AA", - "squf": "\u25AA", - "srarr": "\u2192", - "sscr": "\U0001D4C8", - "ssetmn": "\u2216", - "ssmile": "\u2323", - "sstarf": "\u22C6", - "star": "\u2606", - "starf": "\u2605", - "straightepsilon": "\u03F5", - "straightphi": "\u03D5", - "strns": "\u00AF", - "sub": "\u2282", - "subE": "\u2AC5", - "subdot": "\u2ABD", - "sube": "\u2286", - "subedot": "\u2AC3", - "submult": "\u2AC1", - "subnE": "\u2ACB", - "subne": "\u228A", - "subplus": "\u2ABF", - "subrarr": "\u2979", - "subset": "\u2282", - "subseteq": "\u2286", - "subseteqq": "\u2AC5", - "subsetneq": "\u228A", - "subsetneqq": "\u2ACB", - "subsim": "\u2AC7", - "subsub": "\u2AD5", - "subsup": "\u2AD3", - "succ": "\u227B", - "succapprox": "\u2AB8", - "succcurlyeq": "\u227D", - "succeq": "\u2AB0", - "succnapprox": "\u2ABA", - "succneqq": "\u2AB6", - "succnsim": "\u22E9", - "succsim": "\u227F", - "sum": "\u2211", - "sung": "\u266A", - "sup": "\u2283", - "sup1": "\u00B9", - "sup2": "\u00B2", - "sup3": "\u00B3", - "supE": "\u2AC6", - "supdot": "\u2ABE", - "supdsub": "\u2AD8", - "supe": "\u2287", - "supedot": "\u2AC4", - "suphsol": "\u27C9", - "suphsub": "\u2AD7", - "suplarr": "\u297B", - "supmult": "\u2AC2", - "supnE": "\u2ACC", - "supne": "\u228B", - "supplus": "\u2AC0", - "supset": "\u2283", - "supseteq": "\u2287", - "supseteqq": "\u2AC6", - "supsetneq": "\u228B", - "supsetneqq": "\u2ACC", - "supsim": "\u2AC8", - "supsub": "\u2AD4", - "supsup": "\u2AD6", - "swArr": "\u21D9", - "swarhk": "\u2926", - "swarr": "\u2199", - "swarrow": "\u2199", - "swnwar": "\u292A", - "szlig": "\u00DF", - "target": "\u2316", - "tau": "\u03C4", - "tbrk": "\u23B4", - "tcaron": "\u0165", - "tcedil": "\u0163", - "tcy": "\u0442", - "tdot": "\u20DB", - "telrec": "\u2315", - "tfr": "\U0001D531", - "there4": "\u2234", - "therefore": "\u2234", - "theta": "\u03B8", - "thetasym": "\u03D1", - "thetav": "\u03D1", - "thickapprox": "\u2248", - "thicksim": "\u223C", - "thinsp": "\u2009", - "thkap": "\u2248", - "thksim": "\u223C", - "thorn": "\u00FE", - "tilde": "\u02DC", - "times": "\u00D7", - "timesb": "\u22A0", - "timesbar": "\u2A31", - "timesd": "\u2A30", - "tint": "\u222D", - "toea": "\u2928", - "top": "\u22A4", - "topbot": "\u2336", - "topcir": "\u2AF1", - "topf": "\U0001D565", - "topfork": "\u2ADA", - "tosa": "\u2929", - "tprime": "\u2034", - "trade": "\u2122", - "triangle": "\u25B5", - "triangledown": "\u25BF", - "triangleleft": "\u25C3", - "trianglelefteq": "\u22B4", - "triangleq": "\u225C", - "triangleright": "\u25B9", - "trianglerighteq": "\u22B5", - "tridot": "\u25EC", - "trie": "\u225C", - "triminus": "\u2A3A", - "triplus": "\u2A39", - "trisb": "\u29CD", - "tritime": "\u2A3B", - "trpezium": "\u23E2", - "tscr": "\U0001D4C9", - "tscy": "\u0446", - "tshcy": "\u045B", - "tstrok": "\u0167", - "twixt": "\u226C", - "twoheadleftarrow": "\u219E", - "twoheadrightarrow": "\u21A0", - "uArr": "\u21D1", - "uHar": "\u2963", - "uacute": "\u00FA", - "uarr": "\u2191", - "ubrcy": "\u045E", - "ubreve": "\u016D", - "ucirc": "\u00FB", - "ucy": "\u0443", - "udarr": "\u21C5", - "udblac": "\u0171", - "udhar": "\u296E", - "ufisht": "\u297E", - "ufr": "\U0001D532", - "ugrave": "\u00F9", - "uharl": "\u21BF", - "uharr": "\u21BE", - "uhblk": "\u2580", - "ulcorn": "\u231C", - "ulcorner": "\u231C", - "ulcrop": "\u230F", - "ultri": "\u25F8", - "umacr": "\u016B", - "uml": "\u00A8", - "uogon": "\u0173", - "uopf": "\U0001D566", - "uparrow": "\u2191", - "updownarrow": "\u2195", - "upharpoonleft": "\u21BF", - "upharpoonright": "\u21BE", - "uplus": "\u228E", - "upsi": "\u03C5", - "upsih": "\u03D2", - "upsilon": "\u03C5", - "upuparrows": "\u21C8", - "urcorn": "\u231D", - "urcorner": "\u231D", - "urcrop": "\u230E", - "uring": "\u016F", - "urtri": "\u25F9", - "uscr": "\U0001D4CA", - "utdot": "\u22F0", - "utilde": "\u0169", - "utri": "\u25B5", - "utrif": "\u25B4", - "uuarr": "\u21C8", - "uuml": "\u00FC", - "uwangle": "\u29A7", - "vArr": "\u21D5", - "vBar": "\u2AE8", - "vBarv": "\u2AE9", - "vDash": "\u22A8", - "vangrt": "\u299C", - "varepsilon": "\u03F5", - "varkappa": "\u03F0", - "varnothing": "\u2205", - "varphi": "\u03D5", - "varpi": "\u03D6", - "varpropto": "\u221D", - "varr": "\u2195", - "varrho": "\u03F1", - "varsigma": "\u03C2", - "varsubsetneq": "\u228A\uFE00", - "varsubsetneqq": "\u2ACB\uFE00", - "varsupsetneq": "\u228B\uFE00", - "varsupsetneqq": "\u2ACC\uFE00", - "vartheta": "\u03D1", - "vartriangleleft": "\u22B2", - "vartriangleright": "\u22B3", - "vcy": "\u0432", - "vdash": "\u22A2", - "vee": "\u2228", - "veebar": "\u22BB", - "veeeq": "\u225A", - "vellip": "\u22EE", - "verbar": "\u007C", - "vert": "\u007C", - "vfr": "\U0001D533", - "vltri": "\u22B2", - "vnsub": "\u2282\u20D2", - "vnsup": "\u2283\u20D2", - "vopf": "\U0001D567", - "vprop": "\u221D", - "vrtri": "\u22B3", - "vscr": "\U0001D4CB", - "vsubnE": "\u2ACB\uFE00", - "vsubne": "\u228A\uFE00", - "vsupnE": "\u2ACC\uFE00", - "vsupne": "\u228B\uFE00", - "vzigzag": "\u299A", - "wcirc": "\u0175", - "wedbar": "\u2A5F", - "wedge": "\u2227", - "wedgeq": "\u2259", - "weierp": "\u2118", - "wfr": "\U0001D534", - "wopf": "\U0001D568", - "wp": "\u2118", - "wr": "\u2240", - "wreath": "\u2240", - "wscr": "\U0001D4CC", - "xcap": "\u22C2", - "xcirc": "\u25EF", - "xcup": "\u22C3", - "xdtri": "\u25BD", - "xfr": "\U0001D535", - "xhArr": "\u27FA", - "xharr": "\u27F7", - "xi": "\u03BE", - "xlArr": "\u27F8", - "xlarr": "\u27F5", - "xmap": "\u27FC", - "xnis": "\u22FB", - "xodot": "\u2A00", - "xopf": "\U0001D569", - "xoplus": "\u2A01", - "xotime": "\u2A02", - "xrArr": "\u27F9", - "xrarr": "\u27F6", - "xscr": "\U0001D4CD", - "xsqcup": "\u2A06", - "xuplus": "\u2A04", - "xutri": "\u25B3", - "xvee": "\u22C1", - "xwedge": "\u22C0", - "yacute": "\u00FD", - "yacy": "\u044F", - "ycirc": "\u0177", - "ycy": "\u044B", - "yen": "\u00A5", - "yfr": "\U0001D536", - "yicy": "\u0457", - "yopf": "\U0001D56A", - "yscr": "\U0001D4CE", - "yucy": "\u044E", - "yuml": "\u00FF", - "zacute": "\u017A", - "zcaron": "\u017E", - "zcy": "\u0437", - "zdot": "\u017C", - "zeetrf": "\u2128", - "zeta": "\u03B6", - "zfr": "\U0001D537", - "zhcy": "\u0436", - "zigrarr": "\u21DD", - "zopf": "\U0001D56B", - "zscr": "\U0001D4CF", - "zwj": "\u200D", - "zwnj": "\u200C", -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/indented_code.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/indented_code.go deleted file mode 100644 index a89ee6c7..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/indented_code.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "strings" -) - -type IndentedCodeLine struct { - Indentation int - Range Range -} - -type IndentedCode struct { - blockBase - markdown string - - RawCode []IndentedCodeLine -} - -func (b *IndentedCode) Code() (result string) { - for _, code := range b.RawCode { - result += strings.Repeat(" ", code.Indentation) + b.markdown[code.Range.Position:code.Range.End] - } - return -} - -func (b *IndentedCode) Continuation(indentation int, r Range) *continuation { - if indentation >= 4 { - return &continuation{ - Indentation: indentation - 4, - Remaining: r, - } - } - s := b.markdown[r.Position:r.End] - if strings.TrimSpace(s) == "" { - return &continuation{ - Remaining: r, - } - } - return nil -} - -func (b *IndentedCode) AddLine(indentation int, r Range) bool { - b.RawCode = append(b.RawCode, IndentedCodeLine{ - Indentation: indentation, - Range: r, - }) - return true -} - -func (b *IndentedCode) Close() { - for { - last := b.RawCode[len(b.RawCode)-1] - s := b.markdown[last.Range.Position:last.Range.End] - if strings.TrimRight(s, "\r\n") == "" { - b.RawCode = b.RawCode[:len(b.RawCode)-1] - } else { - break - } - } -} - -func (b *IndentedCode) AllowsBlockStarts() bool { - return false -} - -func indentedCodeStart(markdown string, indentation int, r Range, matchedBlocks, unmatchedBlocks []Block) []Block { - if len(unmatchedBlocks) > 0 { - if _, ok := unmatchedBlocks[len(unmatchedBlocks)-1].(*Paragraph); ok { - return nil - } - } else if len(matchedBlocks) > 0 { - if _, ok := matchedBlocks[len(matchedBlocks)-1].(*Paragraph); ok { - return nil - } - } - - if indentation < 4 { - return nil - } - - s := markdown[r.Position:r.End] - if strings.TrimSpace(s) == "" { - return nil - } - - return []Block{ - &IndentedCode{ - markdown: markdown, - RawCode: []IndentedCodeLine{{ - Indentation: indentation - 4, - Range: r, - }}, - }, - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/inlines.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/inlines.go deleted file mode 100644 index 43dee3bd..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/inlines.go +++ /dev/null @@ -1,663 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "container/list" - "strings" - "unicode" - "unicode/utf8" -) - -type Inline interface { - IsInline() bool -} - -type inlineBase struct{} - -func (inlineBase) IsInline() bool { return true } - -type Text struct { - inlineBase - - Text string - Range Range -} - -type CodeSpan struct { - inlineBase - - Code string -} - -type HardLineBreak struct { - inlineBase -} - -type SoftLineBreak struct { - inlineBase -} - -type InlineLinkOrImage struct { - inlineBase - - Children []Inline - - RawDestination Range - - markdown string - rawTitle string -} - -func (i *InlineLinkOrImage) Destination() string { - return Unescape(i.markdown[i.RawDestination.Position:i.RawDestination.End]) -} - -func (i *InlineLinkOrImage) Title() string { - return Unescape(i.rawTitle) -} - -type InlineLink struct { - InlineLinkOrImage -} - -type InlineImage struct { - InlineLinkOrImage -} - -type ReferenceLinkOrImage struct { - inlineBase - *ReferenceDefinition - - Children []Inline -} - -type ReferenceLink struct { - ReferenceLinkOrImage -} - -type ReferenceImage struct { - ReferenceLinkOrImage -} - -type Autolink struct { - inlineBase - - Children []Inline - - RawDestination Range - - markdown string -} - -func (i *Autolink) Destination() string { - destination := Unescape(i.markdown[i.RawDestination.Position:i.RawDestination.End]) - - if strings.HasPrefix(destination, "www") { - destination = "http://" + destination - } - - return destination -} - -type delimiterType int - -const ( - linkOpeningDelimiter delimiterType = iota - imageOpeningDelimiter -) - -type delimiter struct { - Type delimiterType - IsInactive bool - TextNode int - Range Range -} - -type inlineParser struct { - markdown string - ranges []Range - referenceDefinitions []*ReferenceDefinition - - raw string - position int - inlines []Inline - delimiterStack *list.List -} - -func newInlineParser(markdown string, ranges []Range, referenceDefinitions []*ReferenceDefinition) *inlineParser { - return &inlineParser{ - markdown: markdown, - ranges: ranges, - referenceDefinitions: referenceDefinitions, - delimiterStack: list.New(), - } -} - -func (p *inlineParser) parseBackticks() { - count := 1 - for i := p.position + 1; i < len(p.raw) && p.raw[i] == '`'; i++ { - count++ - } - opening := p.raw[p.position : p.position+count] - search := p.position + count - for search < len(p.raw) { - end := strings.Index(p.raw[search:], opening) - if end == -1 { - break - } - if search+end+count < len(p.raw) && p.raw[search+end+count] == '`' { - search += end + count - for search < len(p.raw) && p.raw[search] == '`' { - search++ - } - continue - } - code := strings.Join(strings.Fields(p.raw[p.position+count:search+end]), " ") - p.position = search + end + count - p.inlines = append(p.inlines, &CodeSpan{ - Code: code, - }) - return - } - p.position += len(opening) - absPos := relativeToAbsolutePosition(p.ranges, p.position-len(opening)) - p.inlines = append(p.inlines, &Text{ - Text: opening, - Range: Range{absPos, absPos + len(opening)}, - }) -} - -func (p *inlineParser) parseLineEnding() { - if p.position >= 1 && p.raw[p.position-1] == '\t' { - p.inlines = append(p.inlines, &HardLineBreak{}) - } else if p.position >= 2 && p.raw[p.position-1] == ' ' && (p.raw[p.position-2] == '\t' || p.raw[p.position-1] == ' ') { - p.inlines = append(p.inlines, &HardLineBreak{}) - } else { - p.inlines = append(p.inlines, &SoftLineBreak{}) - } - p.position++ - if p.position < len(p.raw) && p.raw[p.position] == '\n' { - p.position++ - } -} - -func (p *inlineParser) parseEscapeCharacter() { - if p.position+1 < len(p.raw) && isEscapableByte(p.raw[p.position+1]) { - absPos := relativeToAbsolutePosition(p.ranges, p.position+1) - p.inlines = append(p.inlines, &Text{ - Text: string(p.raw[p.position+1]), - Range: Range{absPos, absPos + len(string(p.raw[p.position+1]))}, - }) - p.position += 2 - } else { - absPos := relativeToAbsolutePosition(p.ranges, p.position) - p.inlines = append(p.inlines, &Text{ - Text: `\`, - Range: Range{absPos, absPos + 1}, - }) - p.position++ - } -} - -func (p *inlineParser) parseText() { - if next := strings.IndexAny(p.raw[p.position:], "\r\n\\`&![]wW:"); next == -1 { - absPos := relativeToAbsolutePosition(p.ranges, p.position) - p.inlines = append(p.inlines, &Text{ - Text: strings.TrimRightFunc(p.raw[p.position:], isWhitespace), - Range: Range{absPos, absPos + len(p.raw[p.position:])}, - }) - p.position = len(p.raw) - } else { - absPos := relativeToAbsolutePosition(p.ranges, p.position) - if p.raw[p.position+next] == '\r' || p.raw[p.position+next] == '\n' { - s := strings.TrimRightFunc(p.raw[p.position:p.position+next], isWhitespace) - p.inlines = append(p.inlines, &Text{ - Text: s, - Range: Range{absPos, absPos + len(s)}, - }) - } else { - if next == 0 { - // Always read at least one character since 'w', 'W', and ':' may not actually match another - // type of node - next = 1 - } - - p.inlines = append(p.inlines, &Text{ - Text: p.raw[p.position : p.position+next], - Range: Range{absPos, absPos + next}, - }) - } - p.position += next - } -} - -func (p *inlineParser) parseLinkOrImageDelimiter() { - absPos := relativeToAbsolutePosition(p.ranges, p.position) - if p.raw[p.position] == '[' { - p.inlines = append(p.inlines, &Text{ - Text: "[", - Range: Range{absPos, absPos + 1}, - }) - p.delimiterStack.PushBack(&delimiter{ - Type: linkOpeningDelimiter, - TextNode: len(p.inlines) - 1, - Range: Range{p.position, p.position + 1}, - }) - p.position++ - } else if p.raw[p.position] == '!' && p.position+1 < len(p.raw) && p.raw[p.position+1] == '[' { - p.inlines = append(p.inlines, &Text{ - Text: "![", - Range: Range{absPos, absPos + 2}, - }) - p.delimiterStack.PushBack(&delimiter{ - Type: imageOpeningDelimiter, - TextNode: len(p.inlines) - 1, - Range: Range{p.position, p.position + 2}, - }) - p.position += 2 - } else { - p.inlines = append(p.inlines, &Text{ - Text: "!", - Range: Range{absPos, absPos + 1}, - }) - p.position++ - } -} - -func (p *inlineParser) peekAtInlineLinkDestinationAndTitle(position int, isImage bool) (destination, title Range, end int, ok bool) { - if position >= len(p.raw) || p.raw[position] != '(' { - return - } - position++ - - destinationStart := nextNonWhitespace(p.raw, position) - if destinationStart >= len(p.raw) { - return - } else if p.raw[destinationStart] == ')' { - return Range{destinationStart, destinationStart}, Range{destinationStart, destinationStart}, destinationStart + 1, true - } - - destination, end, ok = parseLinkDestination(p.raw, destinationStart) - if !ok { - return - } - position = end - - if isImage && position < len(p.raw) && isWhitespaceByte(p.raw[position]) { - dimensionsStart := nextNonWhitespace(p.raw, position) - if dimensionsStart >= len(p.raw) { - return - } - - if p.raw[dimensionsStart] == '=' { - // Read optional image dimensions even if we don't use them - _, end, ok = parseImageDimensions(p.raw, dimensionsStart) - if !ok { - return - } - - position = end - } - } - - if position < len(p.raw) && isWhitespaceByte(p.raw[position]) { - titleStart := nextNonWhitespace(p.raw, position) - if titleStart >= len(p.raw) { - return - } else if p.raw[titleStart] == ')' { - return destination, Range{titleStart, titleStart}, titleStart + 1, true - } - - if p.raw[titleStart] == '"' || p.raw[titleStart] == '\'' || p.raw[titleStart] == '(' { - title, end, ok = parseLinkTitle(p.raw, titleStart) - if !ok { - return - } - position = end - } - } - - closingPosition := nextNonWhitespace(p.raw, position) - if closingPosition >= len(p.raw) || p.raw[closingPosition] != ')' { - return Range{}, Range{}, 0, false - } - - return destination, title, closingPosition + 1, true -} - -func (p *inlineParser) referenceDefinition(label string) *ReferenceDefinition { - clean := strings.Join(strings.Fields(label), " ") - for _, d := range p.referenceDefinitions { - if strings.EqualFold(clean, strings.Join(strings.Fields(d.Label()), " ")) { - return d - } - } - return nil -} - -func (p *inlineParser) lookForLinkOrImage() { - for element := p.delimiterStack.Back(); element != nil; element = element.Prev() { - d := element.Value.(*delimiter) - if d.Type != imageOpeningDelimiter && d.Type != linkOpeningDelimiter { - continue - } - if d.IsInactive { - p.delimiterStack.Remove(element) - break - } - - isImage := d.Type == imageOpeningDelimiter - - var inline Inline - - if destination, title, next, ok := p.peekAtInlineLinkDestinationAndTitle(p.position+1, isImage); ok { - destinationMarkdownPosition := relativeToAbsolutePosition(p.ranges, destination.Position) - linkOrImage := InlineLinkOrImage{ - Children: append([]Inline(nil), p.inlines[d.TextNode+1:]...), - RawDestination: Range{destinationMarkdownPosition, destinationMarkdownPosition + destination.End - destination.Position}, - markdown: p.markdown, - rawTitle: p.raw[title.Position:title.End], - } - if d.Type == imageOpeningDelimiter { - inline = &InlineImage{linkOrImage} - } else { - inline = &InlineLink{linkOrImage} - } - p.position = next - } else { - referenceLabel := "" - label, next, hasLinkLabel := parseLinkLabel(p.raw, p.position+1) - if hasLinkLabel && label.End > label.Position { - referenceLabel = p.raw[label.Position:label.End] - } else { - referenceLabel = p.raw[d.Range.End:p.position] - if !hasLinkLabel { - next = p.position + 1 - } - } - if referenceLabel != "" { - if reference := p.referenceDefinition(referenceLabel); reference != nil { - linkOrImage := ReferenceLinkOrImage{ - ReferenceDefinition: reference, - Children: append([]Inline(nil), p.inlines[d.TextNode+1:]...), - } - if d.Type == imageOpeningDelimiter { - inline = &ReferenceImage{linkOrImage} - } else { - inline = &ReferenceLink{linkOrImage} - } - p.position = next - } - } - } - - if inline != nil { - if d.Type == imageOpeningDelimiter { - p.inlines = append(p.inlines[:d.TextNode], inline) - } else { - p.inlines = append(p.inlines[:d.TextNode], inline) - for inlineElement := element.Prev(); inlineElement != nil; inlineElement = inlineElement.Prev() { - if d := inlineElement.Value.(*delimiter); d.Type == linkOpeningDelimiter { - d.IsInactive = true - } - } - } - p.delimiterStack.Remove(element) - return - } - p.delimiterStack.Remove(element) - break - } - absPos := relativeToAbsolutePosition(p.ranges, p.position) - p.inlines = append(p.inlines, &Text{ - Text: "]", - Range: Range{absPos, absPos + 1}, - }) - p.position++ -} - -func CharacterReference(ref string) string { - if ref == "" { - return "" - } - if ref[0] == '#' { - if len(ref) < 2 { - return "" - } - n := 0 - if ref[1] == 'X' || ref[1] == 'x' { - if len(ref) < 3 { - return "" - } - for i := 2; i < len(ref); i++ { - if i > 9 { - return "" - } - d := ref[i] - switch { - case d >= '0' && d <= '9': - n = n*16 + int(d-'0') - case d >= 'a' && d <= 'f': - n = n*16 + 10 + int(d-'a') - case d >= 'A' && d <= 'F': - n = n*16 + 10 + int(d-'A') - default: - return "" - } - } - } else { - for i := 1; i < len(ref); i++ { - if i > 8 || ref[i] < '0' || ref[i] > '9' { - return "" - } - n = n*10 + int(ref[i]-'0') - } - } - c := rune(n) - if c == '\u0000' || !utf8.ValidRune(c) { - return string(unicode.ReplacementChar) - } - return string(c) - } - if entity, ok := htmlEntities[ref]; ok { - return entity - } - return "" -} - -func (p *inlineParser) parseCharacterReference() { - absPos := relativeToAbsolutePosition(p.ranges, p.position) - p.position++ - if semicolon := strings.IndexByte(p.raw[p.position:], ';'); semicolon == -1 { - p.inlines = append(p.inlines, &Text{ - Text: "&", - Range: Range{absPos, absPos + 1}, - }) - } else if s := CharacterReference(p.raw[p.position : p.position+semicolon]); s != "" { - p.position += semicolon + 1 - p.inlines = append(p.inlines, &Text{ - Text: s, - Range: Range{absPos, absPos + len(s)}, - }) - } else { - p.inlines = append(p.inlines, &Text{ - Text: "&", - Range: Range{absPos, absPos + 1}, - }) - } -} - -func (p *inlineParser) parseAutolink(c rune) bool { - for element := p.delimiterStack.Back(); element != nil; element = element.Prev() { - d := element.Value.(*delimiter) - if !d.IsInactive { - return false - } - } - - var link Range - if c == ':' { - var ok bool - link, ok = parseURLAutolink(p.raw, p.position) - - if !ok { - return false - } - - // Since the current position is at the colon, we have to rewind the parsing slightly so that - // we don't duplicate the URL scheme - rewind := strings.Index(p.raw[link.Position:link.End], ":") - if rewind != -1 { - lastInline := p.inlines[len(p.inlines)-1] - lastText, ok := lastInline.(*Text) - - if !ok { - // This should never occur since parseURLAutolink will only return a non-empty value - // when the previous text ends in a valid URL protocol which would mean that the previous - // node is a Text node - return false - } - - p.inlines = p.inlines[0 : len(p.inlines)-1] - p.inlines = append(p.inlines, &Text{ - Text: lastText.Text[:len(lastText.Text)-rewind], - Range: Range{lastText.Range.Position, lastText.Range.End - rewind}, - }) - p.position -= rewind - } - } else if c == 'w' || c == 'W' { - var ok bool - link, ok = parseWWWAutolink(p.raw, p.position) - - if !ok { - return false - } - } - - linkMarkdownPosition := relativeToAbsolutePosition(p.ranges, link.Position) - linkRange := Range{linkMarkdownPosition, linkMarkdownPosition + link.End - link.Position} - - p.inlines = append(p.inlines, &Autolink{ - Children: []Inline{ - &Text{ - Text: p.raw[link.Position:link.End], - Range: linkRange, - }, - }, - RawDestination: linkRange, - markdown: p.markdown, - }) - p.position += (link.End - link.Position) - - return true -} - -func (p *inlineParser) Parse() []Inline { - for _, r := range p.ranges { - p.raw += p.markdown[r.Position:r.End] - } - - for p.position < len(p.raw) { - c, _ := utf8.DecodeRuneInString(p.raw[p.position:]) - - switch c { - case '\r', '\n': - p.parseLineEnding() - case '\\': - p.parseEscapeCharacter() - case '`': - p.parseBackticks() - case '&': - p.parseCharacterReference() - case '!', '[': - p.parseLinkOrImageDelimiter() - case ']': - p.lookForLinkOrImage() - case 'w', 'W', ':': - matched := p.parseAutolink(c) - - if !matched { - p.parseText() - } - default: - p.parseText() - } - } - - return p.inlines -} - -func ParseInlines(markdown string, ranges []Range, referenceDefinitions []*ReferenceDefinition) (inlines []Inline) { - return newInlineParser(markdown, ranges, referenceDefinitions).Parse() -} - -func MergeInlineText(inlines []Inline) []Inline { - ret := inlines[:0] - for i, v := range inlines { - // always add first node - if i == 0 { - ret = append(ret, v) - continue - } - // not a text node? nothing to merge - text, ok := v.(*Text) - if !ok { - ret = append(ret, v) - continue - } - // previous node is not a text node? nothing to merge - prevText, ok := ret[len(ret)-1].(*Text) - if !ok { - ret = append(ret, v) - continue - } - // previous node is not right before this one - if prevText.Range.End != text.Range.Position { - ret = append(ret, v) - continue - } - // we have two consecutive text nodes - ret[len(ret)-1] = &Text{ - Text: prevText.Text + text.Text, - Range: Range{prevText.Range.Position, text.Range.End}, - } - } - return ret -} - -func Unescape(markdown string) string { - ret := "" - - position := 0 - for position < len(markdown) { - c, cSize := utf8.DecodeRuneInString(markdown[position:]) - - switch c { - case '\\': - if position+1 < len(markdown) && isEscapableByte(markdown[position+1]) { - ret += string(markdown[position+1]) - position += 2 - } else { - ret += `\` - position++ - } - case '&': - position++ - if semicolon := strings.IndexByte(markdown[position:], ';'); semicolon == -1 { - ret += "&" - } else if s := CharacterReference(markdown[position : position+semicolon]); s != "" { - position += semicolon + 1 - ret += s - } else { - ret += "&" - } - default: - ret += string(c) - position += cSize - } - } - - return ret -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/inspect.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/inspect.go deleted file mode 100644 index 3c7f2d1c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/inspect.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -// Inspect traverses the markdown tree in depth-first order. If f returns true, Inspect invokes f -// recursively for each child of the block or inline, followed by a call of f(nil). -func Inspect(markdown string, f func(interface{}) bool) { - document, referenceDefinitions := Parse(markdown) - InspectBlock(document, func(block Block) bool { - if !f(block) { - return false - } - switch v := block.(type) { - case *Paragraph: - for _, inline := range MergeInlineText(v.ParseInlines(referenceDefinitions)) { - InspectInline(inline, func(inline Inline) bool { - return f(inline) - }) - } - } - return true - }) -} - -// InspectBlock traverses the blocks in depth-first order, starting with block. If f returns true, -// InspectBlock invokes f recursively for each child of the block, followed by a call of f(nil). -func InspectBlock(block Block, f func(Block) bool) { - if !f(block) { - return - } - switch v := block.(type) { - case *Document: - for _, child := range v.Children { - InspectBlock(child, f) - } - case *List: - for _, child := range v.Children { - InspectBlock(child, f) - } - case *ListItem: - for _, child := range v.Children { - InspectBlock(child, f) - } - case *BlockQuote: - for _, child := range v.Children { - InspectBlock(child, f) - } - } - f(nil) -} - -// InspectInline traverses the blocks in depth-first order, starting with block. If f returns true, -// InspectInline invokes f recursively for each child of the block, followed by a call of f(nil). -func InspectInline(inline Inline, f func(Inline) bool) { - if !f(inline) { - return - } - switch v := inline.(type) { - case *InlineImage: - for _, child := range v.Children { - InspectInline(child, f) - } - case *InlineLink: - for _, child := range v.Children { - InspectInline(child, f) - } - case *ReferenceImage: - for _, child := range v.Children { - InspectInline(child, f) - } - case *ReferenceLink: - for _, child := range v.Children { - InspectInline(child, f) - } - } - f(nil) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/lines.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/lines.go deleted file mode 100644 index f59e5afe..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/lines.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "strings" -) - -type Line struct { - Range -} - -func ParseLines(markdown string) []Line { - lineStartPosition := 0 - isAfterCarriageReturn := false - lines := make([]Line, 0, strings.Count(markdown, "\n")) - for position, r := range markdown { - if r == '\n' { - lines = append(lines, Line{Range{lineStartPosition, position + 1}}) - lineStartPosition = position + 1 - } else if isAfterCarriageReturn { - lines = append(lines, Line{Range{lineStartPosition, position}}) - lineStartPosition = position - } - isAfterCarriageReturn = r == '\r' - } - if lineStartPosition < len(markdown) { - lines = append(lines, Line{Range{lineStartPosition, len(markdown)}}) - } - return lines -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/links.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/links.go deleted file mode 100644 index 6aa56f25..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/links.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "unicode/utf8" -) - -func parseLinkDestination(markdown string, position int) (raw Range, next int, ok bool) { - if position >= len(markdown) { - return - } - - if markdown[position] == '<' { - isEscaped := false - - for offset, c := range []byte(markdown[position+1:]) { - if isEscaped { - isEscaped = false - if isEscapableByte(c) { - continue - } - } - - if c == '\\' { - isEscaped = true - } else if c == '<' { - break - } else if c == '>' { - return Range{position + 1, position + 1 + offset}, position + 1 + offset + 1, true - } else if isWhitespaceByte(c) { - break - } - } - } - - openCount := 0 - isEscaped := false - for offset, c := range []byte(markdown[position:]) { - if isEscaped { - isEscaped = false - if isEscapableByte(c) { - continue - } - } - - switch c { - case '\\': - isEscaped = true - case '(': - openCount++ - case ')': - if openCount < 1 { - return Range{position, position + offset}, position + offset, true - } - openCount-- - default: - if isWhitespaceByte(c) { - return Range{position, position + offset}, position + offset, true - } - } - } - return Range{position, len(markdown)}, len(markdown), true -} - -func parseLinkTitle(markdown string, position int) (raw Range, next int, ok bool) { - if position >= len(markdown) { - return - } - - originalPosition := position - - var closer byte - switch markdown[position] { - case '"', '\'': - closer = markdown[position] - case '(': - closer = ')' - default: - return - } - position++ - - for position < len(markdown) { - switch markdown[position] { - case '\\': - position++ - if position < len(markdown) && isEscapableByte(markdown[position]) { - position++ - } - case closer: - return Range{originalPosition + 1, position}, position + 1, true - default: - position++ - } - } - - return -} - -func parseLinkLabel(markdown string, position int) (raw Range, next int, ok bool) { - if position >= len(markdown) || markdown[position] != '[' { - return - } - - originalPosition := position - position++ - - for position < len(markdown) { - switch markdown[position] { - case '\\': - position++ - if position < len(markdown) && isEscapableByte(markdown[position]) { - position++ - } - case '[': - return - case ']': - if position-originalPosition >= 1000 && utf8.RuneCountInString(markdown[originalPosition:position]) >= 1000 { - return - } - return Range{originalPosition + 1, position}, position + 1, true - default: - position++ - } - } - - return -} - -// As a non-standard feature, we allow image links to specify dimensions of the image by adding "=WIDTHxHEIGHT" -// after the image destination but before the image title like ![alt](http://example.com/image.png =100x200 "title"). -// Both width and height are optional, but at least one of them must be specified. -func parseImageDimensions(markdown string, position int) (raw Range, next int, ok bool) { - if position >= len(markdown) { - return - } - - originalPosition := position - - // Read = - position += 1 - if position >= len(markdown) { - return - } - - // Read width - hasWidth := false - for position < len(markdown)-1 && isNumericByte(markdown[position]) { - hasWidth = true - position += 1 - } - - // Look for early end of dimensions - if isWhitespaceByte(markdown[position]) || markdown[position] == ')' { - return Range{originalPosition, position - 1}, position, true - } - - // Read the x - if (markdown[position] != 'x' && markdown[position] != 'X') || position == len(markdown)-1 { - return - } - position += 1 - - // Read height - hasHeight := false - for position < len(markdown)-1 && isNumericByte(markdown[position]) { - hasHeight = true - position += 1 - } - - // Make sure the there's no trailing characters - if !isWhitespaceByte(markdown[position]) && markdown[position] != ')' { - return - } - - if !hasWidth && !hasHeight { - // At least one of width or height is required - return - } - - return Range{originalPosition, position - 1}, position, true -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/list.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/list.go deleted file mode 100644 index 39039295..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/list.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "strings" -) - -type ListItem struct { - blockBase - markdown string - hasTrailingBlankLine bool - hasBlankLineBetweenChildren bool - - Indentation int - Children []Block -} - -func (b *ListItem) Continuation(indentation int, r Range) *continuation { - s := b.markdown[r.Position:r.End] - if strings.TrimSpace(s) == "" { - if b.Children == nil { - return nil - } - return &continuation{ - Remaining: r, - } - } - if indentation < b.Indentation { - return nil - } - return &continuation{ - Indentation: indentation - b.Indentation, - Remaining: r, - } -} - -func (b *ListItem) AddChild(openBlocks []Block) []Block { - b.Children = append(b.Children, openBlocks[0]) - if b.hasTrailingBlankLine { - b.hasBlankLineBetweenChildren = true - } - b.hasTrailingBlankLine = false - return openBlocks -} - -func (b *ListItem) AddLine(indentation int, r Range) bool { - isBlank := strings.TrimSpace(b.markdown[r.Position:r.End]) == "" - if isBlank { - b.hasTrailingBlankLine = true - } - return false -} - -func (b *ListItem) HasTrailingBlankLine() bool { - return b.hasTrailingBlankLine || (len(b.Children) > 0 && b.Children[len(b.Children)-1].HasTrailingBlankLine()) -} - -func (b *ListItem) isLoose() bool { - if b.hasBlankLineBetweenChildren { - return true - } - for i, child := range b.Children { - if i < len(b.Children)-1 && child.HasTrailingBlankLine() { - return true - } - } - return false -} - -type List struct { - blockBase - markdown string - hasTrailingBlankLine bool - hasBlankLineBetweenChildren bool - - IsLoose bool - IsOrdered bool - OrderedStart int - BulletOrDelimiter byte - Children []*ListItem -} - -func (b *List) Continuation(indentation int, r Range) *continuation { - s := b.markdown[r.Position:r.End] - if strings.TrimSpace(s) == "" { - return &continuation{ - Remaining: r, - } - } - return &continuation{ - Indentation: indentation, - Remaining: r, - } -} - -func (b *List) AddChild(openBlocks []Block) []Block { - if item, ok := openBlocks[0].(*ListItem); ok { - b.Children = append(b.Children, item) - if b.hasTrailingBlankLine { - b.hasBlankLineBetweenChildren = true - } - b.hasTrailingBlankLine = false - return openBlocks - } else if list, ok := openBlocks[0].(*List); ok { - if len(list.Children) == 1 && list.IsOrdered == b.IsOrdered && list.BulletOrDelimiter == b.BulletOrDelimiter { - return b.AddChild(openBlocks[1:]) - } - } - return nil -} - -func (b *List) AddLine(indentation int, r Range) bool { - isBlank := strings.TrimSpace(b.markdown[r.Position:r.End]) == "" - if isBlank { - b.hasTrailingBlankLine = true - } - return false -} - -func (b *List) HasTrailingBlankLine() bool { - return b.hasTrailingBlankLine || (len(b.Children) > 0 && b.Children[len(b.Children)-1].HasTrailingBlankLine()) -} - -func (b *List) isLoose() bool { - if b.hasBlankLineBetweenChildren { - return true - } - for i, child := range b.Children { - if child.isLoose() || (i < len(b.Children)-1 && child.HasTrailingBlankLine()) { - return true - } - } - return false -} - -func (b *List) Close() { - b.IsLoose = b.isLoose() -} - -func parseListMarker(markdown string, r Range) (success, isOrdered bool, orderedStart int, bulletOrDelimiter byte, markerWidth int, remaining Range) { - digits := 0 - n := 0 - for i := r.Position; i < r.End && markdown[i] >= '0' && markdown[i] <= '9'; i++ { - digits++ - n = n*10 + int(markdown[i]-'0') - } - if digits > 0 { - if digits > 9 || r.Position+digits >= r.End { - return - } - next := markdown[r.Position+digits] - if next != '.' && next != ')' { - return - } - return true, true, n, next, digits + 1, Range{r.Position + digits + 1, r.End} - } - if r.Position >= r.End { - return - } - next := markdown[r.Position] - if next != '-' && next != '+' && next != '*' { - return - } - return true, false, 0, next, 1, Range{r.Position + 1, r.End} -} - -func listStart(markdown string, indent int, r Range, matchedBlocks, unmatchedBlocks []Block) []Block { - afterList := false - if len(matchedBlocks) > 0 { - _, afterList = matchedBlocks[len(matchedBlocks)-1].(*List) - } - if !afterList && indent > 3 { - return nil - } - - success, isOrdered, orderedStart, bulletOrDelimiter, markerWidth, remaining := parseListMarker(markdown, r) - if !success { - return nil - } - - isBlank := strings.TrimSpace(markdown[remaining.Position:remaining.End]) == "" - if len(matchedBlocks) > 0 && len(unmatchedBlocks) == 0 { - if _, ok := matchedBlocks[len(matchedBlocks)-1].(*Paragraph); ok { - if isBlank || (isOrdered && orderedStart != 1) { - return nil - } - } - } - - indentAfterMarker, indentBytesAfterMarker := countIndentation(markdown, remaining) - if !isBlank && indentAfterMarker < 1 { - return nil - } - - remaining = Range{remaining.Position + indentBytesAfterMarker, remaining.End} - consumedIndentAfterMarker := indentAfterMarker - if isBlank || indentAfterMarker >= 5 { - consumedIndentAfterMarker = 1 - } - - listItem := &ListItem{ - markdown: markdown, - Indentation: indent + markerWidth + consumedIndentAfterMarker, - } - list := &List{ - markdown: markdown, - IsOrdered: isOrdered, - OrderedStart: orderedStart, - BulletOrDelimiter: bulletOrDelimiter, - Children: []*ListItem{listItem}, - } - ret := []Block{list, listItem} - if descendants := blockStartOrParagraph(markdown, indentAfterMarker-consumedIndentAfterMarker, remaining, nil, nil); descendants != nil { - listItem.Children = append(listItem.Children, descendants[0]) - ret = append(ret, descendants...) - } - return ret -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/markdown.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/markdown.go deleted file mode 100644 index 5ccdad8c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/markdown.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -// This package implements a parser for the subset of the CommonMark spec necessary for us to do -// server-side processing. It is not a full implementation and lacks many features. But it is -// complete enough to efficiently and accurately allow us to do what we need to like rewrite image -// URLs for proxying. -package markdown - -import ( - "strings" -) - -func isEscapable(c rune) bool { - return c > ' ' && (c < '0' || (c > '9' && (c < 'A' || (c > 'Z' && (c < 'a' || (c > 'z' && c <= '~')))))) -} - -func isEscapableByte(c byte) bool { - return isEscapable(rune(c)) -} - -func isWhitespace(c rune) bool { - switch c { - case ' ', '\t', '\n', '\u000b', '\u000c', '\r': - return true - } - return false -} - -func isWhitespaceByte(c byte) bool { - return isWhitespace(rune(c)) -} - -func isNumeric(c rune) bool { - return c >= '0' && c <= '9' -} - -func isNumericByte(c byte) bool { - return isNumeric(rune(c)) -} - -func isHex(c rune) bool { - return isNumeric(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') -} - -func isHexByte(c byte) bool { - return isHex(rune(c)) -} - -func isAlphanumeric(c rune) bool { - return isNumeric(c) || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') -} - -func isAlphanumericByte(c byte) bool { - return isAlphanumeric(rune(c)) -} - -func nextNonWhitespace(markdown string, position int) int { - for offset, c := range []byte(markdown[position:]) { - if !isWhitespaceByte(c) { - return position + offset - } - } - return len(markdown) -} - -func nextLine(markdown string, position int) (linePosition int, skippedNonWhitespace bool) { - for i := position; i < len(markdown); i++ { - c := markdown[i] - if c == '\r' { - if i+1 < len(markdown) && markdown[i+1] == '\n' { - return i + 2, skippedNonWhitespace - } - return i + 1, skippedNonWhitespace - } else if c == '\n' { - return i + 1, skippedNonWhitespace - } else if !isWhitespaceByte(c) { - skippedNonWhitespace = true - } - } - return len(markdown), skippedNonWhitespace -} - -func countIndentation(markdown string, r Range) (spaces, bytes int) { - for i := r.Position; i < r.End; i++ { - if markdown[i] == ' ' { - spaces++ - bytes++ - } else if markdown[i] == '\t' { - spaces += 4 - bytes++ - } else { - break - } - } - return -} - -func trimLeftSpace(markdown string, r Range) Range { - s := markdown[r.Position:r.End] - trimmed := strings.TrimLeftFunc(s, isWhitespace) - return Range{r.Position, r.End - (len(s) - len(trimmed))} -} - -func trimRightSpace(markdown string, r Range) Range { - s := markdown[r.Position:r.End] - trimmed := strings.TrimRightFunc(s, isWhitespace) - return Range{r.Position, r.End - (len(s) - len(trimmed))} -} - -func relativeToAbsolutePosition(ranges []Range, position int) int { - rem := position - for _, r := range ranges { - l := r.End - r.Position - if rem < l { - return r.Position + rem - } - rem -= l - } - if len(ranges) == 0 { - return 0 - } - return ranges[len(ranges)-1].End -} - -func trimBytesFromRanges(ranges []Range, bytes int) (result []Range) { - rem := bytes - for _, r := range ranges { - if rem == 0 { - result = append(result, r) - continue - } - l := r.End - r.Position - if rem < l { - result = append(result, Range{r.Position + rem, r.End}) - rem = 0 - continue - } - rem -= l - } - return -} - -func Parse(markdown string) (*Document, []*ReferenceDefinition) { - lines := ParseLines(markdown) - return ParseBlocks(markdown, lines) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/paragraph.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/paragraph.go deleted file mode 100644 index aef01b5e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/paragraph.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -import ( - "strings" -) - -type Paragraph struct { - blockBase - markdown string - - Text []Range - ReferenceDefinitions []*ReferenceDefinition -} - -func (b *Paragraph) ParseInlines(referenceDefinitions []*ReferenceDefinition) []Inline { - return ParseInlines(b.markdown, b.Text, referenceDefinitions) -} - -func (b *Paragraph) Continuation(indentation int, r Range) *continuation { - s := b.markdown[r.Position:r.End] - if strings.TrimSpace(s) == "" { - return nil - } - return &continuation{ - Indentation: indentation, - Remaining: r, - } -} - -func (b *Paragraph) Close() { - for { - for i := 0; i < len(b.Text); i++ { - b.Text[i] = trimLeftSpace(b.markdown, b.Text[i]) - if b.Text[i].Position < b.Text[i].End { - break - } - } - - if len(b.Text) == 0 || b.Text[0].Position < b.Text[0].End && b.markdown[b.Text[0].Position] != '[' { - break - } - - definition, remaining := parseReferenceDefinition(b.markdown, b.Text) - if definition == nil { - break - } - b.ReferenceDefinitions = append(b.ReferenceDefinitions, definition) - b.Text = remaining - } - - for i := len(b.Text) - 1; i >= 0; i-- { - b.Text[i] = trimRightSpace(b.markdown, b.Text[i]) - if b.Text[i].Position < b.Text[i].End { - break - } - } -} - -func newParagraph(markdown string, r Range) *Paragraph { - s := markdown[r.Position:r.End] - if strings.TrimSpace(s) == "" { - return nil - } - return &Paragraph{ - markdown: markdown, - Text: []Range{r}, - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/reference_definition.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/reference_definition.go deleted file mode 100644 index 69e8ed94..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/markdown/reference_definition.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package markdown - -type ReferenceDefinition struct { - RawDestination Range - - markdown string - rawLabel string - rawTitle string -} - -func (d *ReferenceDefinition) Destination() string { - return Unescape(d.markdown[d.RawDestination.Position:d.RawDestination.End]) -} - -func (d *ReferenceDefinition) Label() string { - return d.rawLabel -} - -func (d *ReferenceDefinition) Title() string { - return Unescape(d.rawTitle) -} - -func parseReferenceDefinition(markdown string, ranges []Range) (*ReferenceDefinition, []Range) { - raw := "" - for _, r := range ranges { - raw += markdown[r.Position:r.End] - } - - label, next, ok := parseLinkLabel(raw, 0) - if !ok { - return nil, nil - } - position := next - - if position >= len(raw) || raw[position] != ':' { - return nil, nil - } - position++ - - destination, next, ok := parseLinkDestination(raw, nextNonWhitespace(raw, position)) - if !ok { - return nil, nil - } - position = next - - absoluteDestination := relativeToAbsolutePosition(ranges, destination.Position) - ret := &ReferenceDefinition{ - RawDestination: Range{absoluteDestination, absoluteDestination + destination.End - destination.Position}, - markdown: markdown, - rawLabel: raw[label.Position:label.End], - } - - if position < len(raw) && isWhitespaceByte(raw[position]) { - title, next, ok := parseLinkTitle(raw, nextNonWhitespace(raw, position)) - if !ok { - if nextLine, skippedNonWhitespace := nextLine(raw, position); !skippedNonWhitespace { - return ret, trimBytesFromRanges(ranges, nextLine) - } - return nil, nil - } - if nextLine, skippedNonWhitespace := nextLine(raw, next); !skippedNonWhitespace { - ret.rawTitle = raw[title.Position:title.End] - return ret, trimBytesFromRanges(ranges, nextLine) - } - } - - if nextLine, skippedNonWhitespace := nextLine(raw, position); !skippedNonWhitespace { - return ret, trimBytesFromRanges(ranges, nextLine) - } - - return nil, nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/default.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/default.go deleted file mode 100644 index e7faa8c4..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/default.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "os" - - "github.com/mattermost/logr" -) - -// defaultLog manually encodes the log to STDERR, providing a basic, default logging implementation -// before mlog is fully configured. -func defaultLog(level, msg string, fields ...Field) { - log := struct { - Level string `json:"level"` - Message string `json:"msg"` - Fields []Field `json:"fields,omitempty"` - }{ - level, - msg, - fields, - } - - if b, err := json.Marshal(log); err != nil { - fmt.Fprintf(os.Stderr, `{"level":"error","msg":"failed to encode log message"}%s`, "\n") - } else { - fmt.Fprintf(os.Stderr, "%s\n", b) - } -} - -func defaultIsLevelEnabled(level LogLevel) bool { - return true -} - -func defaultDebugLog(msg string, fields ...Field) { - defaultLog("debug", msg, fields...) -} - -func defaultInfoLog(msg string, fields ...Field) { - defaultLog("info", msg, fields...) -} - -func defaultWarnLog(msg string, fields ...Field) { - defaultLog("warn", msg, fields...) -} - -func defaultErrorLog(msg string, fields ...Field) { - defaultLog("error", msg, fields...) -} - -func defaultCriticalLog(msg string, fields ...Field) { - // We map critical to error in zap, so be consistent. - defaultLog("error", msg, fields...) -} - -func defaultCustomLog(lvl LogLevel, msg string, fields ...Field) { - // custom log levels are only output once log targets are configured. -} - -func defaultCustomMultiLog(lvl []LogLevel, msg string, fields ...Field) { - // custom log levels are only output once log targets are configured. -} - -func defaultFlush(ctx context.Context) error { - return nil -} - -func defaultAdvancedConfig(cfg LogTargetCfg) error { - // mlog.ConfigAdvancedConfig should not be called until default - // logger is replaced with mlog.Logger instance. - return errors.New("cannot config advanced logging on default logger") -} - -func defaultAdvancedShutdown(ctx context.Context) error { - return nil -} - -func defaultAddTarget(targets ...logr.Target) error { - // mlog.AddTarget should not be called until default - // logger is replaced with mlog.Logger instance. - return errors.New("cannot AddTarget on default logger") -} - -func defaultRemoveTargets(ctx context.Context, f func(TargetInfo) bool) error { - // mlog.RemoveTargets should not be called until default - // logger is replaced with mlog.Logger instance. - return errors.New("cannot RemoveTargets on default logger") -} - -func defaultEnableMetrics(collector logr.MetricsCollector) error { - // mlog.EnableMetrics should not be called until default - // logger is replaced with mlog.Logger instance. - return errors.New("cannot EnableMetrics on default logger") -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/errors.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/errors.go deleted file mode 100644 index 93762fda..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/errors.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "github.com/mattermost/logr" -) - -// onLoggerError is called when the logging system encounters an error, -// such as a target not able to write records. The targets will keep trying -// however the error will be logged with a dedicated level that can be output -// to a safe/always available target for monitoring or alerting. -func onLoggerError(err error) { - Log(LvlLogError, "advanced logging error", Err(err)) -} - -// onQueueFull is called when the main logger queue is full, indicating the -// volume and frequency of log record creation is too high for the queue size -// and/or the target latencies. -func onQueueFull(rec *logr.LogRec, maxQueueSize int) bool { - Log(LvlLogError, "main queue full, dropping record", Any("rec", rec)) - return true // drop record -} - -// onTargetQueueFull is called when the main logger queue is full, indicating the -// volume and frequency of log record creation is too high for the target's queue size -// and/or the target latency. -func onTargetQueueFull(target logr.Target, rec *logr.LogRec, maxQueueSize int) bool { - Log(LvlLogError, "target queue full, dropping record", String("target", ""), Any("rec", rec)) - return true // drop record -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/global.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/global.go deleted file mode 100644 index aba06646..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/global.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "context" - "log" - "sync/atomic" - - "github.com/mattermost/logr" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -var globalLogger *Logger - -func InitGlobalLogger(logger *Logger) { - // Clean up previous instance. - if globalLogger != nil && globalLogger.logrLogger != nil { - globalLogger.logrLogger.Logr().Shutdown() - } - glob := *logger - glob.zap = glob.zap.WithOptions(zap.AddCallerSkip(1)) - globalLogger = &glob - IsLevelEnabled = globalLogger.IsLevelEnabled - Debug = globalLogger.Debug - Info = globalLogger.Info - Warn = globalLogger.Warn - Error = globalLogger.Error - Critical = globalLogger.Critical - Log = globalLogger.Log - LogM = globalLogger.LogM - Flush = globalLogger.Flush - ConfigAdvancedLogging = globalLogger.ConfigAdvancedLogging - ShutdownAdvancedLogging = globalLogger.ShutdownAdvancedLogging - AddTarget = globalLogger.AddTarget - RemoveTargets = globalLogger.RemoveTargets - EnableMetrics = globalLogger.EnableMetrics -} - -// logWriterFunc provides access to mlog via io.Writer, so the standard logger -// can be redirected to use mlog and whatever targets are defined. -type logWriterFunc func([]byte) (int, error) - -func (lw logWriterFunc) Write(p []byte) (int, error) { - return lw(p) -} - -func RedirectStdLog(logger *Logger) { - if atomic.LoadInt32(&disableZap) == 0 { - zap.RedirectStdLogAt(logger.zap.With(zap.String("source", "stdlog")).WithOptions(zap.AddCallerSkip(-2)), zapcore.ErrorLevel) - return - } - - writer := func(p []byte) (int, error) { - Log(LvlStdLog, string(p)) - return len(p), nil - } - log.SetOutput(logWriterFunc(writer)) -} - -type IsLevelEnabledFunc func(LogLevel) bool -type LogFunc func(string, ...Field) -type LogFuncCustom func(LogLevel, string, ...Field) -type LogFuncCustomMulti func([]LogLevel, string, ...Field) -type FlushFunc func(context.Context) error -type ConfigFunc func(cfg LogTargetCfg) error -type ShutdownFunc func(context.Context) error -type AddTargetFunc func(...logr.Target) error -type RemoveTargetsFunc func(context.Context, func(TargetInfo) bool) error -type EnableMetricsFunc func(logr.MetricsCollector) error - -// DON'T USE THIS Modify the level on the app logger -func GloballyDisableDebugLogForTest() { - globalLogger.consoleLevel.SetLevel(zapcore.ErrorLevel) -} - -// DON'T USE THIS Modify the level on the app logger -func GloballyEnableDebugLogForTest() { - globalLogger.consoleLevel.SetLevel(zapcore.DebugLevel) -} - -var IsLevelEnabled IsLevelEnabledFunc = defaultIsLevelEnabled -var Debug LogFunc = defaultDebugLog -var Info LogFunc = defaultInfoLog -var Warn LogFunc = defaultWarnLog -var Error LogFunc = defaultErrorLog -var Critical LogFunc = defaultCriticalLog -var Log LogFuncCustom = defaultCustomLog -var LogM LogFuncCustomMulti = defaultCustomMultiLog -var Flush FlushFunc = defaultFlush - -var ConfigAdvancedLogging ConfigFunc = defaultAdvancedConfig -var ShutdownAdvancedLogging ShutdownFunc = defaultAdvancedShutdown -var AddTarget AddTargetFunc = defaultAddTarget -var RemoveTargets RemoveTargetsFunc = defaultRemoveTargets -var EnableMetrics EnableMetricsFunc = defaultEnableMetrics diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/levels.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/levels.go deleted file mode 100644 index 24d29e0b..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/levels.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -// Standard levels -var ( - LvlPanic = LogLevel{ID: 0, Name: "panic", Stacktrace: true} - LvlFatal = LogLevel{ID: 1, Name: "fatal", Stacktrace: true} - LvlError = LogLevel{ID: 2, Name: "error"} - LvlWarn = LogLevel{ID: 3, Name: "warn"} - LvlInfo = LogLevel{ID: 4, Name: "info"} - LvlDebug = LogLevel{ID: 5, Name: "debug"} - LvlTrace = LogLevel{ID: 6, Name: "trace"} - // used by redirected standard logger - LvlStdLog = LogLevel{ID: 10, Name: "stdlog"} - // used only by the logger - LvlLogError = LogLevel{ID: 11, Name: "logerror", Stacktrace: true} -) - -// Register custom (discrete) levels here. -// !!!!! ID's must not exceed 32,768 !!!!!! -var ( - // used by the audit system - LvlAuditAPI = LogLevel{ID: 100, Name: "audit-api"} - LvlAuditContent = LogLevel{ID: 101, Name: "audit-content"} - LvlAuditPerms = LogLevel{ID: 102, Name: "audit-permissions"} - LvlAuditCLI = LogLevel{ID: 103, Name: "audit-cli"} - - // used by the TCP log target - LvlTcpLogTarget = LogLevel{ID: 120, Name: "TcpLogTarget"} - - // used by Remote Cluster Service - LvlRemoteClusterServiceDebug = LogLevel{ID: 130, Name: "RemoteClusterServiceDebug"} - LvlRemoteClusterServiceError = LogLevel{ID: 131, Name: "RemoteClusterServiceError"} - LvlRemoteClusterServiceWarn = LogLevel{ID: 132, Name: "RemoteClusterServiceWarn"} - - // used by Shared Channel Sync Service - LvlSharedChannelServiceDebug = LogLevel{ID: 200, Name: "SharedChannelServiceDebug"} - LvlSharedChannelServiceError = LogLevel{ID: 201, Name: "SharedChannelServiceError"} - LvlSharedChannelServiceWarn = LogLevel{ID: 202, Name: "SharedChannelServiceWarn"} - LvlSharedChannelServiceMessagesInbound = LogLevel{ID: 203, Name: "SharedChannelServiceMsgInbound"} - LvlSharedChannelServiceMessagesOutbound = LogLevel{ID: 204, Name: "SharedChannelServiceMsgOutbound"} - - // add more here ... -) - -// Combinations for LogM (log multi) -var ( - MLvlAuditAll = []LogLevel{LvlAuditAPI, LvlAuditContent, LvlAuditPerms, LvlAuditCLI} -) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/log.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/log.go deleted file mode 100644 index d50fc123..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/log.go +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "context" - "fmt" - "io" - "log" - "os" - "sync" - "sync/atomic" - "time" - - "github.com/mattermost/logr" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" - "gopkg.in/natefinch/lumberjack.v2" -) - -const ( - // Very verbose messages for debugging specific issues - LevelDebug = "debug" - // Default log level, informational - LevelInfo = "info" - // Warnings are messages about possible issues - LevelWarn = "warn" - // Errors are messages about things we know are problems - LevelError = "error" - - // DefaultFlushTimeout is the default amount of time mlog.Flush will wait - // before timing out. - DefaultFlushTimeout = time.Second * 5 -) - -var ( - // disableZap is set when Zap should be disabled and Logr used instead. - // This is needed for unit testing as Zap has no shutdown capabilities - // and holds file handles until process exit. Currently unit test create - // many server instances, and thus many Zap log files. - // This flag will be removed when Zap is permanently replaced. - disableZap int32 -) - -// Type and function aliases from zap to limit the libraries scope into MM code -type Field = zapcore.Field - -var Int64 = zap.Int64 -var Int32 = zap.Int32 -var Int = zap.Int -var Uint32 = zap.Uint32 -var String = zap.String -var Any = zap.Any -var Err = zap.Error -var NamedErr = zap.NamedError -var Bool = zap.Bool -var Duration = zap.Duration - -type LoggerIFace interface { - IsLevelEnabled(LogLevel) bool - Debug(string, ...Field) - Info(string, ...Field) - Warn(string, ...Field) - Error(string, ...Field) - Critical(string, ...Field) - Log(LogLevel, string, ...Field) - LogM([]LogLevel, string, ...Field) -} - -type TargetInfo logr.TargetInfo - -type LoggerConfiguration struct { - EnableConsole bool - ConsoleJson bool - EnableColor bool - ConsoleLevel string - EnableFile bool - FileJson bool - FileLevel string - FileLocation string -} - -type Logger struct { - zap *zap.Logger - consoleLevel zap.AtomicLevel - fileLevel zap.AtomicLevel - logrLogger *logr.Logger - mutex *sync.RWMutex -} - -func getZapLevel(level string) zapcore.Level { - switch level { - case LevelInfo: - return zapcore.InfoLevel - case LevelWarn: - return zapcore.WarnLevel - case LevelDebug: - return zapcore.DebugLevel - case LevelError: - return zapcore.ErrorLevel - default: - return zapcore.InfoLevel - } -} - -func makeEncoder(json, color bool) zapcore.Encoder { - encoderConfig := zap.NewProductionEncoderConfig() - if json { - return zapcore.NewJSONEncoder(encoderConfig) - } - - if color { - encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder - } - encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder - return zapcore.NewConsoleEncoder(encoderConfig) -} - -func NewLogger(config *LoggerConfiguration) *Logger { - cores := []zapcore.Core{} - logger := &Logger{ - consoleLevel: zap.NewAtomicLevelAt(getZapLevel(config.ConsoleLevel)), - fileLevel: zap.NewAtomicLevelAt(getZapLevel(config.FileLevel)), - logrLogger: newLogr(), - mutex: &sync.RWMutex{}, - } - - if config.EnableConsole { - writer := zapcore.Lock(os.Stderr) - core := zapcore.NewCore(makeEncoder(config.ConsoleJson, config.EnableColor), writer, logger.consoleLevel) - cores = append(cores, core) - } - - if config.EnableFile { - if atomic.LoadInt32(&disableZap) != 0 { - t := &LogTarget{ - Type: "file", - Format: "json", - Levels: mlogLevelToLogrLevels(config.FileLevel), - MaxQueueSize: DefaultMaxTargetQueue, - Options: []byte(fmt.Sprintf(`{"Filename":"%s", "MaxSizeMB":%d, "Compress":%t}`, - config.FileLocation, 100, true)), - } - if !config.FileJson { - t.Format = "plain" - } - if tgt, err := NewLogrTarget("mlogFile", t); err == nil { - logger.logrLogger.Logr().AddTarget(tgt) - } else { - Error("error creating mlogFile", Err(err)) - } - } else { - writer := zapcore.AddSync(&lumberjack.Logger{ - Filename: config.FileLocation, - MaxSize: 100, - Compress: true, - }) - - core := zapcore.NewCore(makeEncoder(config.FileJson, false), writer, logger.fileLevel) - cores = append(cores, core) - } - } - - combinedCore := zapcore.NewTee(cores...) - - logger.zap = zap.New(combinedCore, - zap.AddCaller(), - ) - return logger -} - -func (l *Logger) ChangeLevels(config *LoggerConfiguration) { - l.consoleLevel.SetLevel(getZapLevel(config.ConsoleLevel)) - l.fileLevel.SetLevel(getZapLevel(config.FileLevel)) -} - -func (l *Logger) SetConsoleLevel(level string) { - l.consoleLevel.SetLevel(getZapLevel(level)) -} - -func (l *Logger) With(fields ...Field) *Logger { - newLogger := *l - newLogger.zap = newLogger.zap.With(fields...) - if newLogger.getLogger() != nil { - ll := newLogger.getLogger().WithFields(zapToLogr(fields)) - newLogger.logrLogger = &ll - } - return &newLogger -} - -func (l *Logger) StdLog(fields ...Field) *log.Logger { - return zap.NewStdLog(l.With(fields...).zap.WithOptions(getStdLogOption())) -} - -// StdLogAt returns *log.Logger which writes to supplied zap logger at required level. -func (l *Logger) StdLogAt(level string, fields ...Field) (*log.Logger, error) { - return zap.NewStdLogAt(l.With(fields...).zap.WithOptions(getStdLogOption()), getZapLevel(level)) -} - -// StdLogWriter returns a writer that can be hooked up to the output of a golang standard logger -// anything written will be interpreted as log entries accordingly -func (l *Logger) StdLogWriter() io.Writer { - newLogger := *l - newLogger.zap = newLogger.zap.WithOptions(zap.AddCallerSkip(4), getStdLogOption()) - f := newLogger.Info - return &loggerWriter{f} -} - -func (l *Logger) WithCallerSkip(skip int) *Logger { - newLogger := *l - newLogger.zap = newLogger.zap.WithOptions(zap.AddCallerSkip(skip)) - return &newLogger -} - -// Made for the plugin interface, wraps mlog in a simpler interface -// at the cost of performance -func (l *Logger) Sugar() *SugarLogger { - return &SugarLogger{ - wrappedLogger: l, - zapSugar: l.zap.Sugar(), - } -} - -func (l *Logger) IsLevelEnabled(level LogLevel) bool { - return isLevelEnabled(l.getLogger(), logr.Level(level)) -} - -func (l *Logger) Debug(message string, fields ...Field) { - l.zap.Debug(message, fields...) - if isLevelEnabled(l.getLogger(), logr.Debug) { - l.getLogger().WithFields(zapToLogr(fields)).Debug(message) - } -} - -func (l *Logger) Info(message string, fields ...Field) { - l.zap.Info(message, fields...) - if isLevelEnabled(l.getLogger(), logr.Info) { - l.getLogger().WithFields(zapToLogr(fields)).Info(message) - } -} - -func (l *Logger) Warn(message string, fields ...Field) { - l.zap.Warn(message, fields...) - if isLevelEnabled(l.getLogger(), logr.Warn) { - l.getLogger().WithFields(zapToLogr(fields)).Warn(message) - } -} - -func (l *Logger) Error(message string, fields ...Field) { - l.zap.Error(message, fields...) - if isLevelEnabled(l.getLogger(), logr.Error) { - l.getLogger().WithFields(zapToLogr(fields)).Error(message) - } -} - -func (l *Logger) Critical(message string, fields ...Field) { - l.zap.Error(message, fields...) - if isLevelEnabled(l.getLogger(), logr.Error) { - l.getLogger().WithFields(zapToLogr(fields)).Error(message) - } -} - -func (l *Logger) Log(level LogLevel, message string, fields ...Field) { - l.getLogger().WithFields(zapToLogr(fields)).Log(logr.Level(level), message) -} - -func (l *Logger) LogM(levels []LogLevel, message string, fields ...Field) { - var logger *logr.Logger - for _, lvl := range levels { - if isLevelEnabled(l.getLogger(), logr.Level(lvl)) { - // don't create logger with fields unless at least one level is active. - if logger == nil { - l := l.getLogger().WithFields(zapToLogr(fields)) - logger = &l - } - logger.Log(logr.Level(lvl), message) - } - } -} - -func (l *Logger) Flush(cxt context.Context) error { - return l.getLogger().Logr().FlushWithTimeout(cxt) -} - -// ShutdownAdvancedLogging stops the logger from accepting new log records and tries to -// flush queues within the context timeout. Once complete all targets are shutdown -// and any resources released. -func (l *Logger) ShutdownAdvancedLogging(cxt context.Context) error { - err := l.getLogger().Logr().ShutdownWithTimeout(cxt) - l.setLogger(newLogr()) - return err -} - -// ConfigAdvancedLoggingConfig (re)configures advanced logging based on the -// specified log targets. This is the easiest way to get the advanced logger -// configured via a config source such as file. -func (l *Logger) ConfigAdvancedLogging(targets LogTargetCfg) error { - if err := l.ShutdownAdvancedLogging(context.Background()); err != nil { - Error("error shutting down previous logger", Err(err)) - } - - err := logrAddTargets(l.getLogger(), targets) - return err -} - -// AddTarget adds one or more logr.Target to the advanced logger. This is the preferred method -// to add custom targets or provide configuration that cannot be expressed via a -// config source. -func (l *Logger) AddTarget(targets ...logr.Target) error { - return l.getLogger().Logr().AddTarget(targets...) -} - -// RemoveTargets selectively removes targets that were previously added to this logger instance -// using the passed in filter function. The filter function should return true to remove the target -// and false to keep it. -func (l *Logger) RemoveTargets(ctx context.Context, f func(ti TargetInfo) bool) error { - // Use locally defined TargetInfo type so we don't spread Logr dependencies. - fc := func(tic logr.TargetInfo) bool { - return f(TargetInfo(tic)) - } - return l.getLogger().Logr().RemoveTargets(ctx, fc) -} - -// EnableMetrics enables metrics collection by supplying a MetricsCollector. -// The MetricsCollector provides counters and gauges that are updated by log targets. -func (l *Logger) EnableMetrics(collector logr.MetricsCollector) error { - return l.getLogger().Logr().SetMetricsCollector(collector) -} - -// getLogger is a concurrent safe getter of the logr logger -func (l *Logger) getLogger() *logr.Logger { - defer l.mutex.RUnlock() - l.mutex.RLock() - return l.logrLogger -} - -// setLogger is a concurrent safe setter of the logr logger -func (l *Logger) setLogger(logger *logr.Logger) { - defer l.mutex.Unlock() - l.mutex.Lock() - l.logrLogger = logger -} - -// DisableZap is called to disable Zap, and Logr will be used instead. Any Logger -// instances created after this call will only use Logr. -// -// This is needed for unit testing as Zap has no shutdown capabilities -// and holds file handles until process exit. Currently unit tests create -// many server instances, and thus many Zap log file handles. -// -// This method will be removed when Zap is permanently replaced. -func DisableZap() { - atomic.StoreInt32(&disableZap, 1) -} - -// EnableZap re-enables Zap such that any Logger instances created after this -// call will allow Zap targets. -func EnableZap() { - atomic.StoreInt32(&disableZap, 0) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/logr.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/logr.go deleted file mode 100644 index c44fafa0..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/logr.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "encoding/json" - "fmt" - "io" - "os" - - "github.com/hashicorp/go-multierror" - "github.com/mattermost/logr" - logrFmt "github.com/mattermost/logr/format" - "github.com/mattermost/logr/target" - "go.uber.org/zap/zapcore" -) - -const ( - DefaultMaxTargetQueue = 1000 - DefaultSysLogPort = 514 -) - -type LogLevel struct { - ID logr.LevelID - Name string - Stacktrace bool -} - -type LogTarget struct { - Type string // one of "console", "file", "tcp", "syslog", "none". - Format string // one of "json", "plain" - Levels []LogLevel - Options json.RawMessage - MaxQueueSize int -} - -type LogTargetCfg map[string]*LogTarget -type LogrCleanup func() error - -func newLogr() *logr.Logger { - lgr := &logr.Logr{} - lgr.OnExit = func(int) {} - lgr.OnPanic = func(interface{}) {} - lgr.OnLoggerError = onLoggerError - lgr.OnQueueFull = onQueueFull - lgr.OnTargetQueueFull = onTargetQueueFull - - logger := lgr.NewLogger() - return &logger -} - -func logrAddTargets(logger *logr.Logger, targets LogTargetCfg) error { - lgr := logger.Logr() - var errs error - for name, t := range targets { - target, err := NewLogrTarget(name, t) - if err != nil { - errs = multierror.Append(err) - continue - } - if target != nil { - target.SetName(name) - lgr.AddTarget(target) - } - } - return errs -} - -// NewLogrTarget creates a `logr.Target` based on a target config. -// Can be used when parsing custom config files, or when programmatically adding -// built-in targets. Use `mlog.AddTarget` to add custom targets. -func NewLogrTarget(name string, t *LogTarget) (logr.Target, error) { - formatter, err := newFormatter(name, t.Format) - if err != nil { - return nil, err - } - filter := newFilter(t.Levels) - - if t.MaxQueueSize == 0 { - t.MaxQueueSize = DefaultMaxTargetQueue - } - - switch t.Type { - case "console": - return newConsoleTarget(name, t, filter, formatter) - case "file": - return newFileTarget(name, t, filter, formatter) - case "syslog": - return newSyslogTarget(name, t, filter, formatter) - case "tcp": - return newTCPTarget(name, t, filter, formatter) - case "none": - return nil, nil - } - return nil, fmt.Errorf("invalid type '%s' for target %s", t.Type, name) -} - -func newFilter(levels []LogLevel) logr.Filter { - filter := &logr.CustomFilter{} - for _, lvl := range levels { - filter.Add(logr.Level(lvl)) - } - return filter -} - -func newFormatter(name string, format string) (logr.Formatter, error) { - switch format { - case "json", "": - return &logrFmt.JSON{}, nil - case "plain": - return &logrFmt.Plain{Delim: " | "}, nil - default: - return nil, fmt.Errorf("invalid format '%s' for target %s", format, name) - } -} - -func newConsoleTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) { - type consoleOptions struct { - Out string `json:"Out"` - } - options := &consoleOptions{} - if err := json.Unmarshal(t.Options, options); err != nil { - return nil, err - } - - var w io.Writer - switch options.Out { - case "stdout", "": - w = os.Stdout - case "stderr": - w = os.Stderr - default: - return nil, fmt.Errorf("invalid out '%s' for target %s", options.Out, name) - } - - newTarget := target.NewWriterTarget(filter, formatter, w, t.MaxQueueSize) - return newTarget, nil -} - -func newFileTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) { - type fileOptions struct { - Filename string `json:"Filename"` - MaxSize int `json:"MaxSizeMB"` - MaxAge int `json:"MaxAgeDays"` - MaxBackups int `json:"MaxBackups"` - Compress bool `json:"Compress"` - } - options := &fileOptions{} - if err := json.Unmarshal(t.Options, options); err != nil { - return nil, err - } - return newFileTargetWithOpts(name, t, target.FileOptions(*options), filter, formatter) -} - -func newFileTargetWithOpts(name string, t *LogTarget, opts target.FileOptions, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) { - if opts.Filename == "" { - return nil, fmt.Errorf("missing 'Filename' option for target %s", name) - } - if err := checkFileWritable(opts.Filename); err != nil { - return nil, fmt.Errorf("error writing to 'Filename' for target %s: %w", name, err) - } - - newTarget := target.NewFileTarget(filter, formatter, opts, t.MaxQueueSize) - return newTarget, nil -} - -func newSyslogTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) { - options := &SyslogParams{} - if err := json.Unmarshal(t.Options, options); err != nil { - return nil, err - } - - if options.IP == "" { - return nil, fmt.Errorf("missing 'IP' option for target %s", name) - } - if options.Port == 0 { - options.Port = DefaultSysLogPort - } - return NewSyslogTarget(filter, formatter, options, t.MaxQueueSize) -} - -func newTCPTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) { - options := &TcpParams{} - if err := json.Unmarshal(t.Options, options); err != nil { - return nil, err - } - - if options.IP == "" { - return nil, fmt.Errorf("missing 'IP' option for target %s", name) - } - if options.Port == 0 { - return nil, fmt.Errorf("missing 'Port' option for target %s", name) - } - return NewTcpTarget(filter, formatter, options, t.MaxQueueSize) -} - -func checkFileWritable(filename string) error { - // try opening/creating the file for writing - file, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600) - if err != nil { - return err - } - file.Close() - return nil -} - -func isLevelEnabled(logger *logr.Logger, level logr.Level) bool { - if logger == nil || logger.Logr() == nil { - return false - } - - status := logger.Logr().IsLevelEnabled(level) - return status.Enabled -} - -// zapToLogr converts Zap fields to Logr fields. -// This will not be needed once Logr is used for all logging. -func zapToLogr(zapFields []Field) logr.Fields { - encoder := zapcore.NewMapObjectEncoder() - for _, zapField := range zapFields { - zapField.AddTo(encoder) - } - return logr.Fields(encoder.Fields) -} - -// mlogLevelToLogrLevel converts a mlog logger level to -// an array of discrete Logr levels. -func mlogLevelToLogrLevels(level string) []LogLevel { - levels := make([]LogLevel, 0) - levels = append(levels, LvlError, LvlPanic, LvlFatal, LvlStdLog) - - switch level { - case LevelDebug: - levels = append(levels, LvlDebug) - fallthrough - case LevelInfo: - levels = append(levels, LvlInfo) - fallthrough - case LevelWarn: - levels = append(levels, LvlWarn) - } - return levels -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/stdlog.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/stdlog.go deleted file mode 100644 index fd702abf..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/stdlog.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "bytes" - "strings" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// Implementation of zapcore.Core to interpret log messages from a standard logger -// and translate the levels to zapcore levels. -type stdLogLevelInterpreterCore struct { - wrappedCore zapcore.Core -} - -func stdLogInterpretZapEntry(entry zapcore.Entry) zapcore.Entry { - message := entry.Message - if strings.Index(message, "[DEBUG]") == 0 { - entry.Level = zapcore.DebugLevel - entry.Message = message[7:] - } else if strings.Index(message, "[DEBG]") == 0 { - entry.Level = zapcore.DebugLevel - entry.Message = message[6:] - } else if strings.Index(message, "[WARN]") == 0 { - entry.Level = zapcore.WarnLevel - entry.Message = message[6:] - } else if strings.Index(message, "[ERROR]") == 0 { - entry.Level = zapcore.ErrorLevel - entry.Message = message[7:] - } else if strings.Index(message, "[EROR]") == 0 { - entry.Level = zapcore.ErrorLevel - entry.Message = message[6:] - } else if strings.Index(message, "[ERR]") == 0 { - entry.Level = zapcore.ErrorLevel - entry.Message = message[5:] - } else if strings.Index(message, "[INFO]") == 0 { - entry.Level = zapcore.InfoLevel - entry.Message = message[6:] - } - return entry -} - -func (s *stdLogLevelInterpreterCore) Enabled(lvl zapcore.Level) bool { - return s.wrappedCore.Enabled(lvl) -} - -func (s *stdLogLevelInterpreterCore) With(fields []zapcore.Field) zapcore.Core { - return s.wrappedCore.With(fields) -} - -func (s *stdLogLevelInterpreterCore) Check(entry zapcore.Entry, checkedEntry *zapcore.CheckedEntry) *zapcore.CheckedEntry { - entry = stdLogInterpretZapEntry(entry) - return s.wrappedCore.Check(entry, checkedEntry) -} - -func (s *stdLogLevelInterpreterCore) Write(entry zapcore.Entry, fields []zapcore.Field) error { - entry = stdLogInterpretZapEntry(entry) - return s.wrappedCore.Write(entry, fields) -} - -func (s *stdLogLevelInterpreterCore) Sync() error { - return s.wrappedCore.Sync() -} - -func getStdLogOption() zap.Option { - return zap.WrapCore( - func(core zapcore.Core) zapcore.Core { - return &stdLogLevelInterpreterCore{core} - }, - ) -} - -type loggerWriter struct { - logFunc func(msg string, fields ...Field) -} - -func (l *loggerWriter) Write(p []byte) (int, error) { - trimmed := string(bytes.TrimSpace(p)) - for _, line := range strings.Split(trimmed, "\n") { - l.logFunc(line) - } - return len(p), nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/sugar.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/sugar.go deleted file mode 100644 index 2368b085..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/sugar.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "go.uber.org/zap" -) - -// Made for the plugin interface, use the regular logger for other uses -type SugarLogger struct { - wrappedLogger *Logger - zapSugar *zap.SugaredLogger -} - -func (l *SugarLogger) Debug(msg string, keyValuePairs ...interface{}) { - l.zapSugar.Debugw(msg, keyValuePairs...) -} - -func (l *SugarLogger) Info(msg string, keyValuePairs ...interface{}) { - l.zapSugar.Infow(msg, keyValuePairs...) -} - -func (l *SugarLogger) Error(msg string, keyValuePairs ...interface{}) { - l.zapSugar.Errorw(msg, keyValuePairs...) -} - -func (l *SugarLogger) Warn(msg string, keyValuePairs ...interface{}) { - l.zapSugar.Warnw(msg, keyValuePairs...) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/syslog.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/syslog.go deleted file mode 100644 index 8766a964..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/syslog.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "context" - "crypto/tls" - "crypto/x509" - "encoding/base64" - "errors" - "fmt" - "io/ioutil" - - "github.com/mattermost/logr" - "github.com/wiggin77/merror" - syslog "github.com/wiggin77/srslog" -) - -// Syslog outputs log records to local or remote syslog. -type Syslog struct { - logr.Basic - w *syslog.Writer -} - -// SyslogParams provides parameters for dialing a syslog daemon. -type SyslogParams struct { - IP string `json:"IP"` - Port int `json:"Port"` - Tag string `json:"Tag"` - TLS bool `json:"TLS"` - Cert string `json:"Cert"` - Insecure bool `json:"Insecure"` -} - -// NewSyslogTarget creates a target capable of outputting log records to remote or local syslog, with or without TLS. -func NewSyslogTarget(filter logr.Filter, formatter logr.Formatter, params *SyslogParams, maxQueue int) (*Syslog, error) { - network := "tcp" - var config *tls.Config - - if params.TLS { - network = "tcp+tls" - config = &tls.Config{InsecureSkipVerify: params.Insecure} - if params.Cert != "" { - pool, err := getCertPool(params.Cert) - if err != nil { - return nil, err - } - config.RootCAs = pool - } - } - raddr := fmt.Sprintf("%s:%d", params.IP, params.Port) - - writer, err := syslog.DialWithTLSConfig(network, raddr, syslog.LOG_INFO, params.Tag, config) - if err != nil { - return nil, err - } - - s := &Syslog{w: writer} - s.Basic.Start(s, s, filter, formatter, maxQueue) - - return s, nil -} - -// Shutdown stops processing log records after making best effort to flush queue. -func (s *Syslog) Shutdown(ctx context.Context) error { - errs := merror.New() - - err := s.Basic.Shutdown(ctx) - errs.Append(err) - - err = s.w.Close() - errs.Append(err) - - return errs.ErrorOrNil() -} - -// getCertPool returns a x509.CertPool containing the cert(s) -// from `cert`, which can be a path to a .pem or .crt file, -// or a base64 encoded cert. -func getCertPool(cert string) (*x509.CertPool, error) { - if cert == "" { - return nil, errors.New("no cert provided") - } - - // first treat as a file and try to read. - serverCert, err := ioutil.ReadFile(cert) - if err != nil { - // maybe it's a base64 encoded cert - serverCert, err = base64.StdEncoding.DecodeString(cert) - if err != nil { - return nil, errors.New("cert cannot be read") - } - } - - pool := x509.NewCertPool() - if ok := pool.AppendCertsFromPEM(serverCert); ok { - return pool, nil - } - return nil, errors.New("cannot parse cert") -} - -// Write converts the log record to bytes, via the Formatter, -// and outputs to syslog. -func (s *Syslog) Write(rec *logr.LogRec) error { - _, stacktrace := s.IsLevelEnabled(rec.Level()) - - buf := rec.Logger().Logr().BorrowBuffer() - defer rec.Logger().Logr().ReleaseBuffer(buf) - - buf, err := s.Formatter().Format(rec, stacktrace, buf) - if err != nil { - return err - } - txt := buf.String() - - switch rec.Level() { - case logr.Panic, logr.Fatal: - err = s.w.Crit(txt) - case logr.Error: - err = s.w.Err(txt) - case logr.Warn: - err = s.w.Warning(txt) - case logr.Debug, logr.Trace: - err = s.w.Debug(txt) - default: - // logr.Info plus all custom levels. - err = s.w.Info(txt) - } - - if err != nil { - reporter := rec.Logger().Logr().ReportError - reporter(fmt.Errorf("syslog write fail: %w", err)) - // syslog writer will try to reconnect. - } - return err -} - -// String returns a string representation of this target. -func (s *Syslog) String() string { - return "SyslogTarget" -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/tcp.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/tcp.go deleted file mode 100644 index d65b43ee..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/tcp.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "context" - "crypto/tls" - "errors" - "fmt" - "net" - _ "net/http/pprof" - "sync" - "time" - - "github.com/hashicorp/go-multierror" - "github.com/mattermost/logr" -) - -const ( - DialTimeoutSecs = 30 - WriteTimeoutSecs = 30 - RetryBackoffMillis int64 = 100 - MaxRetryBackoffMillis int64 = 30 * 1000 // 30 seconds -) - -// Tcp outputs log records to raw socket server. -type Tcp struct { - logr.Basic - - params *TcpParams - addy string - - mutex sync.Mutex - conn net.Conn - monitor chan struct{} - shutdown chan struct{} -} - -// TcpParams provides parameters for dialing a socket server. -type TcpParams struct { - IP string `json:"IP"` - Port int `json:"Port"` - TLS bool `json:"TLS"` - Cert string `json:"Cert"` - Insecure bool `json:"Insecure"` -} - -// NewTcpTarget creates a target capable of outputting log records to a raw socket, with or without TLS. -func NewTcpTarget(filter logr.Filter, formatter logr.Formatter, params *TcpParams, maxQueue int) (*Tcp, error) { - tcp := &Tcp{ - params: params, - addy: fmt.Sprintf("%s:%d", params.IP, params.Port), - monitor: make(chan struct{}), - shutdown: make(chan struct{}), - } - tcp.Basic.Start(tcp, tcp, filter, formatter, maxQueue) - - return tcp, nil -} - -// getConn provides a net.Conn. If a connection already exists, it is returned immediately, -// otherwise this method blocks until a new connection is created, timeout or shutdown. -func (tcp *Tcp) getConn() (net.Conn, error) { - tcp.mutex.Lock() - defer tcp.mutex.Unlock() - - Log(LvlTcpLogTarget, "getConn enter", String("addy", tcp.addy)) - defer Log(LvlTcpLogTarget, "getConn exit", String("addy", tcp.addy)) - - if tcp.conn != nil { - Log(LvlTcpLogTarget, "reusing existing conn", String("addy", tcp.addy)) // use "With" once Zap is removed - return tcp.conn, nil - } - - type result struct { - conn net.Conn - err error - } - - connChan := make(chan result) - ctx, cancel := context.WithTimeout(context.Background(), time.Second*DialTimeoutSecs) - defer cancel() - - go func(ctx context.Context, ch chan result) { - Log(LvlTcpLogTarget, "dailing", String("addy", tcp.addy)) - conn, err := tcp.dial(ctx) - if err == nil { - tcp.conn = conn - tcp.monitor = make(chan struct{}) - go monitor(tcp.conn, tcp.monitor, Log) - } - ch <- result{conn: conn, err: err} - }(ctx, connChan) - - select { - case <-tcp.shutdown: - return nil, errors.New("shutdown") - case res := <-connChan: - return res.conn, res.err - } -} - -// dial connects to a TCP socket, and optionally performs a TLS handshake. -// A non-nil context must be provided which can cancel the dial. -func (tcp *Tcp) dial(ctx context.Context) (net.Conn, error) { - var dialer net.Dialer - dialer.Timeout = time.Second * DialTimeoutSecs - conn, err := dialer.DialContext(ctx, "tcp", fmt.Sprintf("%s:%d", tcp.params.IP, tcp.params.Port)) - if err != nil { - return nil, err - } - - if !tcp.params.TLS { - return conn, nil - } - - Log(LvlTcpLogTarget, "TLS handshake", String("addy", tcp.addy)) - - tlsconfig := &tls.Config{ - ServerName: tcp.params.IP, - InsecureSkipVerify: tcp.params.Insecure, - } - if tcp.params.Cert != "" { - pool, err := getCertPool(tcp.params.Cert) - if err != nil { - return nil, err - } - tlsconfig.RootCAs = pool - } - - tlsConn := tls.Client(conn, tlsconfig) - if err := tlsConn.Handshake(); err != nil { - return nil, err - } - return tlsConn, nil -} - -func (tcp *Tcp) close() error { - tcp.mutex.Lock() - defer tcp.mutex.Unlock() - - var err error - if tcp.conn != nil { - Log(LvlTcpLogTarget, "closing connection", String("addy", tcp.addy)) - close(tcp.monitor) - err = tcp.conn.Close() - tcp.conn = nil - } - return err -} - -// Shutdown stops processing log records after making best effort to flush queue. -func (tcp *Tcp) Shutdown(ctx context.Context) error { - errs := &multierror.Error{} - - Log(LvlTcpLogTarget, "shutting down", String("addy", tcp.addy)) - - if err := tcp.Basic.Shutdown(ctx); err != nil { - errs = multierror.Append(errs, err) - } - - if err := tcp.close(); err != nil { - errs = multierror.Append(errs, err) - } - - close(tcp.shutdown) - return errs.ErrorOrNil() -} - -// Write converts the log record to bytes, via the Formatter, and outputs to the socket. -// Called by dedicated target goroutine and will block until success or shutdown. -func (tcp *Tcp) Write(rec *logr.LogRec) error { - _, stacktrace := tcp.IsLevelEnabled(rec.Level()) - - buf := rec.Logger().Logr().BorrowBuffer() - defer rec.Logger().Logr().ReleaseBuffer(buf) - - buf, err := tcp.Formatter().Format(rec, stacktrace, buf) - if err != nil { - return err - } - - try := 1 - backoff := RetryBackoffMillis - for { - select { - case <-tcp.shutdown: - return err - default: - } - - conn, err := tcp.getConn() - if err != nil { - Log(LvlTcpLogTarget, "failed getting connection", String("addy", tcp.addy), Err(err)) - reporter := rec.Logger().Logr().ReportError - reporter(fmt.Errorf("log target %s connection error: %w", tcp.String(), err)) - backoff = tcp.sleep(backoff) - continue - } - - conn.SetWriteDeadline(time.Now().Add(time.Second * WriteTimeoutSecs)) - _, err = buf.WriteTo(conn) - if err == nil { - return nil - } - - Log(LvlTcpLogTarget, "write error", String("addy", tcp.addy), Err(err)) - reporter := rec.Logger().Logr().ReportError - reporter(fmt.Errorf("log target %s write error: %w", tcp.String(), err)) - - _ = tcp.close() - - backoff = tcp.sleep(backoff) - try++ - Log(LvlTcpLogTarget, "retrying write", String("addy", tcp.addy), Int("try", try)) - } -} - -// monitor continuously tries to read from the connection to detect socket close. -// This is needed because TCP target uses a write only socket and Linux systems -// take a long time to detect a loss of connectivity on a socket when only writing; -// the writes simply fail without an error returned. -func monitor(conn net.Conn, done <-chan struct{}, logFunc LogFuncCustom) { - addy := conn.RemoteAddr().String() - defer logFunc(LvlTcpLogTarget, "monitor exiting", String("addy", addy)) - - buf := make([]byte, 1) - for { - logFunc(LvlTcpLogTarget, "monitor loop", String("addy", addy)) - - select { - case <-done: - return - case <-time.After(1 * time.Second): - } - - err := conn.SetReadDeadline(time.Now().Add(time.Second * 30)) - if err != nil { - continue - } - - _, err = conn.Read(buf) - - if errt, ok := err.(net.Error); ok && errt.Timeout() { - // read timeout is expected, keep looping. - continue - } - - // Any other error closes the connection, forcing a reconnect. - logFunc(LvlTcpLogTarget, "monitor closing connection", Err(err)) - conn.Close() - return - } -} - -// String returns a string representation of this target. -func (tcp *Tcp) String() string { - return fmt.Sprintf("TcpTarget[%s:%d]", tcp.params.IP, tcp.params.Port) -} - -func (tcp *Tcp) sleep(backoff int64) int64 { - select { - case <-tcp.shutdown: - case <-time.After(time.Millisecond * time.Duration(backoff)): - } - - nextBackoff := backoff + (backoff >> 1) - if nextBackoff > MaxRetryBackoffMillis { - nextBackoff = MaxRetryBackoffMillis - } - return nextBackoff -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/test-tls-client-cert.pem b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/test-tls-client-cert.pem deleted file mode 100644 index 6ce8d042..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/test-tls-client-cert.pem +++ /dev/null @@ -1,43 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDjzCCAnegAwIBAgIRAPYfRSwdzKopBKxYxKqslJUwDQYJKoZIhvcNAQELBQAw -JzElMCMGA1UEAwwcTWF0dGVybW9zdCwgSW5jLiBJbnRlcm5hbCBDQTAeFw0xOTAz -MjIwMDE0MTVaFw0yMjAzMDYwMDE0MTVaMDsxOTA3BgNVBAMTME1hdHRlcm1vc3Qs -IEluYy4gSW50ZXJuYWwgSW50ZXJtZWRpYXRlIEF1dGhvcml0eTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMjliRdmvnNL4u/Jr/M2dPwQmTJXEBY/Vq9Q -vAU52X3tRMCPxcaFz+x6ftuvdO2NdohXGAmtx9QU5LZcvFeTDpoVEBo9A+4jtLvD -DZYaTNLpJmoSoJHaDbdWX+OAOqyDiWS741LuiMKWHhew9QOisat2ZINPxjmAd9wE -xthTMgzsv7MUqnMer8U5OGQ0Qy7wAmNRc+2K3qPwkxe2RUvcte50DUFNgxEginsh -vrkOXR383vUCZfu72qu8oggjiQpyTllu5je2Ap6JLjYLkEMiMqrYADuWor/ZHwa6 -WrFqVETxWfAV5u9Eh0wZM/KKYwRQuw9y+Nans77FmUl1tVWWNN8CAwEAAaOBoTCB -njAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBQY4Uqswyr2hO/HetZt2RDxJdTIPjBi -BgNVHSMEWzBZgBRFZXVg2Z5tNIsWeWjBLEy2yzKbMKErpCkwJzElMCMGA1UEAwwc -TWF0dGVybW9zdCwgSW5jLiBJbnRlcm5hbCBDQYIUEifGUOM+bIFZo1tkjZB5YGBr -0xEwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQAEdexL30Q0zBHmPAH8 -LhdK7dbzW1CmILbxRZlKAwRN+hKRXiMW3MHIkhNuoV9Aev602Q+ja4lWsRi/ktOL -ni1FWx5gSScgdG8JGj47dOmoT3vXKX7+umiv4rQLPDl9/DKMuv204OYJq6VT+uNU -6C6kL157jGJEO76H4fMZ8oYsD7Sq0zjiNKtuCYii0ngH3j3gB1jACLqRgveU7MdT -pqOV2KfY31+h8VBtkUvljNztQ9xNY8Fjmt0SMf7E3FaUcaar3ZCr70G5aU3dKbe7 -47vGOBa5tCqw4YK0jgDKid3IJQul9a3J1mSsH8Wy3to9cAV4KGZBQLnzCX15a/+v -3yVh ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDfjCCAmagAwIBAgIUEifGUOM+bIFZo1tkjZB5YGBr0xEwDQYJKoZIhvcNAQEL -BQAwJzElMCMGA1UEAwwcTWF0dGVybW9zdCwgSW5jLiBJbnRlcm5hbCBDQTAeFw0x -OTAzMjEyMTI4NDNaFw0yOTAzMTgyMTI4NDNaMCcxJTAjBgNVBAMMHE1hdHRlcm1v -c3QsIEluYy4gSW50ZXJuYWwgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQDH0Xq5rMBGpKOVWTpb5MnaJIWFP/vOtvEk+7hVrfOfe1/5x0Kk3UgAHj85 -otaEZD1Lhn/JLkEqCiE/UXMJFwJDlNcO4CkdKBSpYX4bKAqy5q/X3QwioMSNpJG1 -+YYrNGBH0sgKcKjyCaLhmqYLD0xZDVOmWIYBU9jUPyXw5U0tnsVrTqGMxVkm1xCY -krCWN1ZoUrLvL0MCZc5qpxoPTopr9UO9cqSBSuy6BVWVuEWBZhpqHt+ul8VxhzzY -q1k4l7r2qw+/wm1iJBedTeBVeWNag8JaVfLgu+/W7oJVlPO32Po7pnvHp8iJ3b4K -zXyVHaTX4S6Em+6LV8855TYrShzlAgMBAAGjgaEwgZ4wHQYDVR0OBBYEFEVldWDZ -nm00ixZ5aMEsTLbLMpswMGIGA1UdIwRbMFmAFEVldWDZnm00ixZ5aMEsTLbLMpsw -oSukKTAnMSUwIwYDVQQDDBxNYXR0ZXJtb3N0LCBJbmMuIEludGVybmFsIENBghQS -J8ZQ4z5sgVmjW2SNkHlgYGvTETAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAN -BgkqhkiG9w0BAQsFAAOCAQEAPiCWFmopyAkY2T3Zyo4yaRPhX1+VOTMKJtY6EUhq -/GHz6kzEyvCUBf0N892cibGxekrEoItY9NqO6RQRfowg+Gn5kc13z4NyL2W8/eoT -Xy0ZvfaQbU++fQ6pVtWtMblDMU9xiYd7/MDvJpO328l1Vhcdp8kEi+lCvpy0sCRc -PxzPhbgCMAbZEGx+4TMQd4SZKzlRxW/2fflpReh6v1Dv0VDUSYQWwsUnaLpdKHfh -a5k0vuySYcszE4YKlY0zakeFlJfp7fBp1xTwcdW8aTfw15EicPMwTc6xxA4JJUJx -cddu817n1nayK5u6r9Qh1oIVkr0nC9YELMMy4dpPgJ88SA== ------END CERTIFICATE----- diff --git a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/testing.go b/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/testing.go deleted file mode 100644 index 6b41a7e4..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/shared/mlog/testing.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package mlog - -import ( - "io" - "strings" - "sync" - "testing" - - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - -// testingWriter is an io.Writer that writes through t.Log -type testingWriter struct { - tb testing.TB -} - -func (tw *testingWriter) Write(b []byte) (int, error) { - tw.tb.Log(strings.TrimSpace(string(b))) - return len(b), nil -} - -// NewTestingLogger creates a Logger that proxies logs through a testing interface. -// This allows tests that spin up App instances to avoid spewing logs unless the test fails or -verbose is specified. -func NewTestingLogger(tb testing.TB, writer io.Writer) *Logger { - logWriter := &testingWriter{tb} - multiWriter := io.MultiWriter(logWriter, writer) - logWriterSync := zapcore.AddSync(multiWriter) - - testingLogger := &Logger{ - consoleLevel: zap.NewAtomicLevelAt(getZapLevel("debug")), - fileLevel: zap.NewAtomicLevelAt(getZapLevel("info")), - logrLogger: newLogr(), - mutex: &sync.RWMutex{}, - } - - logWriterCore := zapcore.NewCore(makeEncoder(true, false), zapcore.Lock(logWriterSync), testingLogger.consoleLevel) - - testingLogger.zap = zap.New(logWriterCore, - zap.AddCaller(), - ) - return testingLogger -} |