Repository: VictoriaMetrics/VictoriaMetrics
Pull request #3104 (2022-09-13 08:22:25)

vmui: fix save query params to URL


Patch:
diff --git a/app/vmalert/README.md b/app/vmalert/README.md
index c9cbb39bb..c96f56659 100644
--- a/app/vmalert/README.md
+++ b/app/vmalert/README.md
@@ -184,6 +184,13 @@ expr: <string>
 # as firing once they return.
 [ for: <duration> | default = 0s ]
 
+# Whether to print debug information into logs.
+# Information includes alerts state changes and requests sent to the datasource. 
+# Please note, that if rule's query params contain sensitive 
+# information - it will be printed to logs.
+# Is applicable to alerting rules only.
+[ debug: <bool> | default = false ]
+
 # Labels to add or overwrite for each alert.
 labels:
   [ <labelname>: <tmpl_string> ]
diff --git a/app/vmalert/alerting.go b/app/vmalert/alerting.go
index df433538f..6c4e5a5b6 100644
--- a/app/vmalert/alerting.go
+++ b/app/vmalert/alerting.go
@@ -6,6 +6,7 @@ import (
 	"hash/fnv"
 	"sort"
 	"strconv"
+	"strings"
 	"sync"
 	"time"
 
@@ -30,6 +31,7 @@ type AlertingRule struct {
 	GroupID      uint64
 	GroupName    string
 	EvalInterval time.Duration
+	Debug        bool
 
 	q datasource.Querier
 
@@ -71,11 +73,13 @@ func newAlertingRule(qb datasource.QuerierBuilder, group *Group, cfg config.Rule
 		GroupID:      group.ID(),
 		GroupName:    group.Name,
 		EvalInterval: group.Interval,
+		Debug:        cfg.Debug,
 		q: qb.BuildWithParams(datasource.QuerierParams{
 			DataSourceType:     group.Type.String(),
 			EvaluationInterval: group.Interval,
 			QueryParams:        group.Params,
 			Headers:            group.Headers,
+			Debug:              cfg.Debug,
 		}),
 		alerts:  make(map[uint64]*notifier.Alert),
 		metrics: &alertingRuleMetrics{},
@@ -143,6 +147,32 @@ func (ar *AlertingRule) ID() uint64 {
 	return ar.RuleID
 }
 
+func (ar *AlertingRule) logDebugf(at time.Time, a *notifier.Alert, format string, args ...interface{}) {
+	if !ar.Debug {
+		return
+	}
+	prefix := fmt.Sprintf("DEBUG rule %q:%q (%d) at %v: ",
+		ar.GroupName, ar.Name, ar.RuleID, at.Format(time.RFC3339))
+
+	if a != nil {
+		labelKeys := make([]string, len(a.Labels))
+		var i int
+		for k := range a.Labels {
+			labelKeys[i] = k
+			i++
+		}
+		sort.Strings(labelKeys)
+		labels := make([]string, len(labelKeys))
+		for i, l := range labelKeys {
+			labels[i] = fmt.Sprintf("%s=%q", l, a.Labels[l])
+		}
+		labelsStr := strings.Join(labels, ",")
+		prefix += fmt.Sprintf("alert %d {%s} ", a.ID, labelsStr)
+	}
+	msg := fmt.Sprintf(format, args...)
+	logger.Infof("%s", prefix+msg)
+}
+
 type labelSet struct {
 	// origin labels from series
 	// used for templating
@@ -255,9 +285,12 @@ func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time, limit int) ([]pr
 		return nil, fmt.Errorf("failed to execute query %q: %w", ar.Expr, err)
 	}
 
+	ar.logDebugf(ts, nil, "query returned %d samples (elapsed: %s)", ar.lastExecSamples, ar.lastExecDuration)
+
 	for h, a := range ar.alerts {
 		// cleanup inactive alerts from previous Exec
 		if a.State == notifier.StateInactive && ts.Sub(a.ResolvedAt) > resolvedRetention {
+			ar.logDebugf(ts, a, "deleted as inactive")
 			delete(ar.alerts, h)
 		}
 	}
@@ -285,9 +318,10 @@ func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time, limit int) ([]pr
 				// back to notifier.StatePending
 				a.State = notifier.StatePending
 				a.ActiveAt = ts
+				ar.logDebugf(ts, a, "INACTIVE => PENDING")
 			}
 			if a.Value != m.Values[0] {
-				// update Value field with latest value
+				// update Value field with the latest value
 				a.Value = m.Values[0]
 				// and re-exec template since Value can be used
 				// in annotations
@@ -307,6 +341,7 @@ func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time, limit int) ([]pr
 		a.State = notifier.StatePending
 		a.ActiveAt = ts
 		ar.alerts[h] = a
+		ar.logDebugf(ts, a, "created in state PENDING")
 	}
 	var numActivePending int
 	for h, a := range ar.alerts {
@@ -317,11 +352,13 @@ func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time, limit int) ([]pr
 				// alert was in Pending state - it is not
 				// active anymore
 				delete(ar.alerts, h)
+				ar.logDebugf(ts, a, "PENDING => DELETED: is absent in current evaluation round")
 				continue
 			}
 			if a.State == notifier.StateFiring {
 				a.State = notifier.StateInactive
 				a.ResolvedAt = ts
+				ar.logDebugf(ts, a, "FIRING => INACTIVE: is absent in current evaluation round")
 			}
 			continue
 		}
@@ -330,6 +367,7 @@ func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time, limit int) ([]pr
 			a.State = notifier.StateFiring
 			a.Start = ts
 			alertsFired.Inc()
+			ar.logDebugf(ts, a, "PENDING => FIRING: %s since becoming active at %v", ts.Sub(a.ActiveAt), a.ActiveAt)
 		}
 	}
 	if limit > 0 && numActivePending > limit {
diff --git a/app/vmalert/config/config.go b/app/vmalert/config/config.go
index b0847448a..41b3afcfb 100644
--- a/app/vmalert/config/config.go
+++ b/app/vmalert/config/config.go
@@ -113,6 +113,7 @@ type Rule struct {
 	For         *promutils.Duration `yaml:"for,omitempty"`
 	Labels      map[string]string   `yaml:"labels,omitempty"`
 	Annotations map[string]string   `yaml:"annotations,omitempty"`
+	Debug       bool                `yaml:"debug,omitempty"`
 
 	// Catches all undefined fields and must be empty after parsing.
 	XXX map[string]interface{} `yaml:",inline"`
diff --git a/app/vmalert/datasource/datasource.go b/app/vmalert/datasource/datasource.go
index 900007941..8f8662125 100644
--- a/app/vmalert/datasource/datasource.go
+++ b/app/vmalert/datasource/datasource.go
@@ -23,6 +23,7 @@ type QuerierParams struct {
 	EvaluationInterval time.Duration
 	QueryParams        url.Values
 	Headers            map[string]string
+	Debug              bool
 }
 
 // Metric is the basic entity which should be return by datasource
diff --git a/app/vmalert/datasource/vm.go b/app/vmalert/datasource/vm.go
index 36547481f..331a5827a 100644
--- a/app/vmalert/datasource/vm.go
+++ b/app/vmalert/datasource/vm.go
@@ -9,6 +9,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
 )
 
@@ -39,6 +40,10 @@ type VMStorage struct {
 	evaluationInterval time.Duration
 	extraParams        url.Values
 	extraHeaders       []keyValue
+
+	// whether to print additional log messages
+	// for each sent request
+	debug bool
 }
 
 type keyValue struct {
@@ -64,6 +69,7 @@ func (s *VMStorage) ApplyParams(params QuerierParams) *VMStorage {
 	s.dataSourceType = toDatasourceType(params.DataSourceType)
 	s.evaluationInterval = params.EvaluationInterval
 	s.extraParams = params.QueryParams
+	s.debug = params.Debug
 	if params.Headers != nil {
 		for key, value := range params.Headers {
 			kv := keyValue{key: key, value: value}
@@ -151,6 +157,9 @@ func (s *VMStorage) QueryRange(ctx context.Context, query string, start, end tim
 }
 
 func (s *VMStorage) do(ctx context.Context, req *http.Request) (*http.Response, error) {
+	if s.debug {
+		logger.Infof("DEBUG datasource request: executing %s request with params %q", req.Method, req.URL.RawQuery)
+	}
 	resp, err := s.c.Do(req.WithContext(ctx))
 	if err != nil {
 		return nil, fmt.Errorf("error getting response from %s: %w", req.URL.Redacted(), err)
diff --git a/app/vmui/packages/vmui/src/state/common/StateContext.tsx b/app/vmui/packages/vmui/src/state/common/StateContext.tsx
index a5a7e7f0d..14886365f 100644
--- a/app/vmui/packages/vmui/src/state/common/StateContext.tsx
+++ b/app/vmui/packages/vmui/src/state/common/StateContext.tsx
@@ -24,7 +24,7 @@ export const StateProvider: FC = ({children}) => {
   const [state, dispatch] = useReducer(reducer, initialPrepopulatedState);
 
   useEffect(() => {
-    if (pathname !== router.dashboards || pathname !== router.home) return;
+    if (pathname !== router.dashboards && pathname !== router.home) return;
     setQueryStringValue(state as unknown as Record<string, unknown>);
   }, [state, pathname]);
 
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 50f79a48e..7cf32d73d 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -18,9 +18,11 @@ The following tip changes can be tested by building VictoriaMetrics components f
 **Update note:** this release changes data format for [/api/v1/export/native](https://docs.victoriametrics.com/#how-to-export-data-in-native-format) in incompatible way, so it cannot be imported into older version of VictoriaMetrics via [/api/v1/import/native](https://docs.victoriametrics.com/#how-to-import-data-in-native-format).
 
 * FEATURE: check the correctess of raw sample timestamps stored on disk when reading them. This reduces the probability of possible silent corruption of the data stored on disk. This should help [this](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2998) and [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3011).
+* FEATURE: atomically delete directories with snapshots, parts and partitions at [storage level](https://docs.victoriametrics.com/#storage). Previously such directories can be left in partially deleted state when the deletion operation was interrupted by unclean shutdown. This may result in `cannot open file ...: no such file or directory` error on the next start. The probability of this error was quite high when NFS or EFS was used as persistent storage for VictoriaMetrics data. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3038).
 * FEATURE: set the `start` arg to `end - 5 minutes` if isn't passed explicitly to [/api/v1/labels](https://docs.victoriametrics.com/url-examples.html#apiv1labels) and [/api/v1/label/.../values](https://docs.victoriametrics.com/url-examples.html#apiv1labelvalues). See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/3052).
 * FEATURE: [vmctl](https://docs.victoriametrics.com/vmctl.html): add `vm-native-step-interval` command line flag for `vm-native` mode. New option allows splitting the import process into chunks by time interval. This helps migrating data sets with high churn rate and provides better control over the process. See [feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2733).
 * FEATURE: [vmui](https://docs.victoriametrics.com/#vmui): add `top queries` tab, which shows various stats for recently executed queries. See [these docs](https://docs.victoriametrics.com/#top-queries) and [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2707).
+* FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert.html): add `debug` mode to the alerting rule settings for printing additional information into logs during evaluation. See `debug` param in [alerting rule config](https://docs.victoriametrics.com/vmalert.html#alerting-rules).
 
 * BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): properly calculate `rate_over_sum(m[d])` as `sum_over_time(m[d])/d`. Previously the `sum_over_time(m[d])` could be improperly divided by smaller than `d` time range. See [rate_over_sum() docs](https://docs.victoriametrics.com/MetricsQL.html#rate_over_sum) and [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3045).
 * BUGFIX: [VictoriaMetrics cluster](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html): properly calculate query results at `vmselect`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3067). The issue has been introduced in [v1.81.0](https://docs.victoriametrics.com/CHANGELOG.html#v1810).
diff --git a/docs/ExtendedPromQL.md b/docs/ExtendedPromQL.md
new file mode 100644
index 000000000..cb0e106cb
--- /dev/null
+++ b/docs/ExtendedPromQL.md
@@ -0,0 +1,7 @@
+---
+sort: 100
+---
+
+# MetricsQL old page
+
+The page has been moved to [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html).
diff --git a/docs/operator/api.MD b/docs/operator/api.MD
index a971958f6..a0d1f72c1 100644
--- a/docs/operator/api.MD
+++ b/docs/operator/api.MD
@@ -744,7 +744,7 @@ VMAgentSpec defines the desired state of VMAgent
 | extraEnvs | ExtraEnvs that will be added to VMAgent pod                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | [][v1.EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#envvar-v1-core)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | false |
 | serviceSpec | ServiceSpec that will be added to vmagent service spec                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | *[ServiceSpec](#servicespec)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | false |
 | serviceScrapeSpec | ServiceScrapeSpec that will be added to vmselect VMServiceScrape spec                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | *[VMServiceScrapeSpec](#vmservicescrapespec)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | false |
-| shardCount | ShardCount - numbers of shards of VMAgent in this case operator will use 1 deployment/sts per shard with replicas count according to spec.replicas https://victoriametrics.github.io/vmagent.html#scraping-big-number-of-targets                                                                                                                                                                                                                                                                                                                                            | *int                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | false |
+| shardCount | ShardCount - numbers of shards of VMAgent in this case operator will use 1 deployment/sts per shard with replicas count according to spec.replicas https://docs.victoriametrics.com/vmagent.html#scraping-big-number-of-targets                                                                                                                                                                                                                                                                                                                                            | *int                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | false |
 | updateStrategy | UpdateStrategy - overrides default update strategy. works only for deployments, statefulset always use OnDelete.                                                                                                                                                                                                                                                                                                                                                                                                                                                            | *[appsv1.DeploymentStrategyType](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#deploymentstrategy-v1-apps)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | false |
 | rollingUpdate | RollingUpdate - overrides deployment update params.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | *[appsv1.RollingUpdateDeployment](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#rollingupdatedeployment-v1-apps)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | false |
 | podDisruptionBudget | PodDisruptionBudget created by operator                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     | *[EmbeddedPodDisruptionBudgetSpec](#embeddedpoddisruptionbudgetspec)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | false |
diff --git a/docs/vmalert.md b/docs/vmalert.md
index 48df5d9c1..e13d03915 100644
--- a/docs/vmalert.md
+++ b/docs/vmalert.md
@@ -188,6 +188,13 @@ expr: <string>
 # as firing once they return.
 [ for: <duration> | default = 0s ]
 
+# Whether to print debug information into logs.
+# Information includes alerts state changes and requests sent to the datasource. 
+# Please note, that if rule's query params contain sensitive 
+# information - it will be printed to logs.
+# Is applicable to alerting rules only.
+[ debug: <bool> | default = false ]
+
 # Labels to add or overwrite for each alert.
 labels:
   [ <labelname>: <tmpl_string> ]
diff --git a/go.mod b/go.mod
index 0f7664a07..b52530a4a 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,7 @@ require (
 	github.com/VictoriaMetrics/fasthttp v1.1.0
 	github.com/VictoriaMetrics/metrics v1.22.2
 	github.com/VictoriaMetrics/metricsql v0.44.1
-	github.com/aws/aws-sdk-go v1.44.93
+	github.com/aws/aws-sdk-go v1.44.96
 	github.com/cespare/xxhash/v2 v2.1.2
 
 	// TODO: switch back to https://github.com/cheggaaa/pb/v3 when v3-pooling branch
@@ -22,15 +22,15 @@ require (
 	github.com/influxdata/influxdb v1.10.0
 	github.com/klauspost/compress v1.15.9
 	github.com/prometheus/prometheus v1.8.2-0.20201119142752-3ad25a6dc3d9
-	github.com/urfave/cli/v2 v2.14.1
+	github.com/urfave/cli/v2 v2.16.3
 	github.com/valyala/fastjson v1.6.3
 	github.com/valyala/fastrand v1.1.0
 	github.com/valyala/fasttemplate v1.2.1
 	github.com/valyala/gozstd v1.17.0
 	github.com/valyala/quicktemplate v1.7.0
-	golang.org/x/net v0.0.0-20220907135653-1e95f45603a7
-	golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
-	golang.org/x/sys v0.0.0-20220908150016-7ac13a9a928d
+	golang.org/x/net v0.0.0-20220909164309-bea034e7d591
+	golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1
+	golang.org/x/sys v0.0.0-20220913120320-3275c407cedc
 	google.golang.org/api v0.95.0
 	gopkg.in/yaml.v2 v2.4.0
 )
@@ -63,7 +63,7 @@ require (
 	github.com/prometheus/client_model v0.2.0 // indirect
 	github.com/prometheus/common v0.37.0 // indirect
 	github.com/prometheus/procfs v0.8.0 // indirect
-	github.com/rivo/uniseg v0.3.4 // indirect
+	github.com/rivo/uniseg v0.4.2 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/valyala/histogram v1.2.0 // indirect
@@ -75,7 +75,7 @@ require (
 	golang.org/x/text v0.3.7 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20220908141613-51c1cc9bc6d0 // indirect
+	google.golang.org/genproto v0.0.0-20220909194730-69f6226f97e5 // indirect
 	google.golang.org/grpc v1.49.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 )
diff --git a/go.sum b/go.sum
index e46b8b38a..421e1c47a 100644
--- a/go.sum
+++ b/go.sum
@@ -148,8 +148,8 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ
 github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
 github.com/aws/aws-sdk-go v1.35.31/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go v1.44.93 h1:hAgd9fuaptBatSft27/5eBMdcA8+cIMqo96/tZ6rKl8=
-github.com/aws/aws-sdk-go v1.44.93/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.96 h1:S9paaqnJ0AJ95t5AB+iK8RM6YNZN0W0Lek1gOVJsEr8=
+github.com/aws/aws-sdk-go v1.44.96/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
 github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -765,8 +765,8 @@ github.com/prometheus/prometheus v1.8.2-0.20201119142752-3ad25a6dc3d9/go.mod h1:
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw=
-github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
+github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -828,8 +828,8 @@ github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMW
 github.com/uber/jaeger-lib v2.4.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli/v2 v2.14.1 h1:0Sx+C9404t2+DPuIJ3UpZFOEFhNG3wPxMj7uZHyZKFA=
-github.com/urfave/cli/v2 v2.14.1/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
+github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk=
+github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
@@ -1007,8 +1007,8 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220907135653-1e95f45603a7 h1:1WGATo9HAhkWMbfyuVU0tEFP88OIkUvwaHFveQPvzCQ=
-golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
+golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1029,8 +1029,9 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
-golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
 golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
+golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA=
+golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1141,8 +1142,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908150016-7ac13a9a928d h1:RoyzQTK76Rktm3p4xyZslc8T8I1tBz4UEjZCzeh57mM=
-golang.org/x/sys v0.0.0-20220908150016-7ac13a9a928d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220913120320-3275c407cedc h1:dpclq5m2YrqPGStKmtw7IcNbKLfbIqKXvNxDJKdIKYc=
+golang.org/x/sys v0.0.0-20220913120320-3275c407cedc/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1382,8 +1383,8 @@ google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP
 google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
 google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
-google.golang.org/genproto v0.0.0-20220908141613-51c1cc9bc6d0 h1:bMz0aY2wd9TwUp9M7QfjBWuQqaFD/ZaTtvDpPDCo2Ow=
-google.golang.org/genproto v0.0.0-20220908141613-51c1cc9bc6d0/go.mod h1:rQWNQYp1kbHR3+n5cARSTCF5rlJOttUn8yIhRklGAWQ=
+google.golang.org/genproto v0.0.0-20220909194730-69f6226f97e5 h1:ngtP8S8JkBWfJACT9cmj5eTkS9tIWPQI5leBz/7Bq/c=
+google.golang.org/genproto v0.0.0-20220909194730-69f6226f97e5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
diff --git a/lib/fs/dir_remover.go b/lib/fs/dir_remover.go
index ba3e8d52e..79b3e429d 100644
--- a/lib/fs/dir_remover.go
+++ b/lib/fs/dir_remover.go
@@ -10,9 +10,13 @@ import (
 	"github.com/VictoriaMetrics/metrics"
 )
 
-func mustRemoveAll(path string, done func()) {
+// MustRemoveAll removes path with all the contents.
+//
+// It properly fsyncs the parent directory after path removal.
+//
+// It properly handles NFS issue https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 .
+func MustRemoveAll(path string) {
 	if tryRemoveAll(path) {
-		done()
 		return
 	}
 	select {
@@ -29,7 +33,6 @@ func mustRemoveAll(path string, done func()) {
 		for {
 			time.Sleep(time.Second)
 			if tryRemoveAll(path) {
-				done()
 				return
 			}
 		}
diff --git a/lib/fs/fs.go b/lib/fs/fs.go
index 9dc976f12..10b9e0cc9 100644
--- a/lib/fs/fs.go
+++ b/lib/fs/fs.go
@@ -8,8 +8,10 @@ import (
 	"os"
 	"path/filepath"
 	"regexp"
+	"strings"
 	"sync"
 	"sync/atomic"
+	"time"
 
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime"
 	"github.com/VictoriaMetrics/VictoriaMetrics/lib/filestream"
@@ -193,25 +195,57 @@ func IsEmptyDir(path string) bool {
 	return false
 }
 
-// MustRemoveAll removes path with all the contents.
+// MustRemoveDirAtomic removes the given dir atomically.
 //
-// It properly fsyncs the parent directory after path removal.
+// It uses the following algorithm:
 //
-// It properly handles NFS issue https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 .
-func MustRemoveAll(path string) {
-	mustRemoveAll(path, func() {})
+//  1. Atomically rename the "<dir>" to "<dir>.must-remove.<XYZ>",
+//     where <XYZ> is an unique number.
+//  2. Remove the "<dir>.must-remove.XYZ" in background.
+//
+// If the process crashes after the step 1, then the directory must be removed
+// on the next process start by calling MustRemoveTemporaryDirs on the parent directory.
+func MustRemoveDirAtomic(dir string) {
+	if !IsPathExist(dir) {
+		return
+	}
+	n := atomic.AddUint64(&atomicDirRemoveCounter, 1)
+	tmpDir := fmt.Sprintf("%s.must-remove.%d", dir, n)
+	if err := os.Rename(dir, tmpDir); err != nil {
+		logger.Panicf("FATAL: cannot move %s to %s: %s", dir, tmpDir, err)
+	}
+	MustRemoveAll(tmpDir)
+	parentDir := filepath.Dir(dir)
+	MustSyncPath(parentDir)
 }
 
-// MustRemoveAllWithDoneCallback removes path with all the contents.
-//
-// It properly fsyncs the parent directory after path removal.
-//
-// done is called after the path is successfully removed.
+var atomicDirRemoveCounter = uint64(time.Now().UnixNano())
+
+// MustRemoveTemporaryDirs removes all the subdirectories with ".must-remove.<XYZ>" suffix.
 //
-// done may be called after the function returns for NFS path.
-// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61.
-func MustRemoveAllWithDoneCallback(path string, done func()) {
-	mustRemoveAll(path, done)
+// Such directories may be left on unclean shutdown during MustRemoveDirAtomic call.
+func MustRemoveTemporaryDirs(dir string) {
+	d, err := os.Open(dir)
+	if err != nil {
+		logger.Panicf("FATAL: cannot open dir %q: %s", dir, err)
+	}
+	defer MustClose(d)
+	fis, err := d.Readdir(-1)
+	if err != nil {
+		logger.Panicf("FATAL: cannot read dir %q: %s", dir, err)
+	}
+	for _, fi := range fis {
+		if !IsDirOrSymlink(fi) {
+			// Skip non-directories
+			continue
+		}
+		dirName := fi.Name()
+		if strings.Contains(dirName, ".must-remove.") {
+			fullPath := dir + "/" + dirName
+			MustRemoveAll(fullPath)
+		}
+	}
+	MustSyncPath(dir)
 }
 
 // HardLinkFiles makes hard links for all the files from srcDir in dstDir.
diff --git a/lib/mergeset/block_stream_writer.go b/lib/mergeset/block_stream_writer.go
index 46bac85a6..b25e47325 100644
--- a/lib/mergeset/block_stream_writer.go
+++ b/lib/mergeset/block_stream_writer.go
@@ -94,7 +94,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 	metaindexPath := path + "/metaindex.bin"
 	metaindexFile, err := filestream.Create(metaindexPath, false)
 	if err != nil {
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create metaindex file: %w", err)
 	}
 
@@ -102,7 +102,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 	indexFile, err := filestream.Create(indexPath, nocache)
 	if err != nil {
 		metaindexFile.MustClose()
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create index file: %w", err)
 	}
 
@@ -111,7 +111,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 	if err != nil {
 		metaindexFile.MustClose()
 		indexFile.MustClose()
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create items file: %w", err)
 	}
 
@@ -121,7 +121,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 		metaindexFile.MustClose()
 		indexFile.MustClose()
 		itemsFile.MustClose()
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create lens file: %w", err)
 	}
 
diff --git a/lib/mergeset/table.go b/lib/mergeset/table.go
index e614b7ad2..3b3ceb8f9 100644
--- a/lib/mergeset/table.go
+++ b/lib/mergeset/table.go
@@ -1059,6 +1059,7 @@ func openParts(path string) ([]*partWrapper, error) {
 	if err := fs.MkdirAllIfNotExist(path); err != nil {
 		return nil, err
 	}
+	fs.MustRemoveTemporaryDirs(path)
 	d, err := os.Open(path)
 	if err != nil {
 		return nil, fmt.Errorf("cannot open difrectory: %w", err)
@@ -1073,13 +1074,13 @@ func openParts(path string) ([]*partWrapper, error) {
 	}
 
 	txnDir := path + "/txn"
-	fs.MustRemoveAll(txnDir)
+	fs.MustRemoveDirAtomic(txnDir)
 	if err := fs.MkdirAllFailIfExist(txnDir); err != nil {
 		return nil, fmt.Errorf("cannot create %q: %w", txnDir, err)
 	}
 
 	tmpDir := path + "/tmp"
-	fs.MustRemoveAll(tmpDir)
+	fs.MustRemoveDirAtomic(tmpDir)
 	if err := fs.MkdirAllFailIfExist(tmpDir); err != nil {
 		return nil, fmt.Errorf("cannot create %q: %w", tmpDir, err)
 	}
@@ -1106,7 +1107,7 @@ func openParts(path string) ([]*partWrapper, error) {
 		if fs.IsEmptyDir(partPath) {
 			// Remove empty directory, which can be left after unclean shutdown on NFS.
 			// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1142
-			fs.MustRemoveAll(partPath)
+			fs.MustRemoveDirAtomic(partPath)
 			continue
 		}
 		p, err := openFilePart(partPath)
@@ -1277,14 +1278,12 @@ func runTransaction(txnLock *sync.RWMutex, pathPrefix, txnPath string) error {
 	}
 
 	// Remove old paths. It is OK if certain paths don't exist.
-	var removeWG sync.WaitGroup
 	for _, path := range rmPaths {
 		path, err := validatePath(pathPrefix, path)
 		if err != nil {
 			return fmt.Errorf("invalid path to remove: %w", err)
 		}
-		removeWG.Add(1)
-		fs.MustRemoveAllWithDoneCallback(path, removeWG.Done)
+		fs.MustRemoveDirAtomic(path)
 	}
 
 	// Move the new part to new directory.
@@ -1316,9 +1315,6 @@ func runTransaction(txnLock *sync.RWMutex, pathPrefix, txnPath string) error {
 	pendingTxnDeletionsWG.Add(1)
 	go func() {
 		defer pendingTxnDeletionsWG.Done()
-		// Remove the transaction file only after all the source paths are deleted.
-		// This is required for NFS mounts. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 .
-		removeWG.Wait()
 		if err := os.Remove(txnPath); err != nil {
 			logger.Errorf("cannot remove transaction file %q: %s", txnPath, err)
 		}
diff --git a/lib/storage/block_stream_writer.go b/lib/storage/block_stream_writer.go
index c46f12fe2..790c36366 100644
--- a/lib/storage/block_stream_writer.go
+++ b/lib/storage/block_stream_writer.go
@@ -110,7 +110,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 	timestampsPath := path + "/timestamps.bin"
 	timestampsFile, err := filestream.Create(timestampsPath, nocache)
 	if err != nil {
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create timestamps file: %w", err)
 	}
 
@@ -118,7 +118,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 	valuesFile, err := filestream.Create(valuesPath, nocache)
 	if err != nil {
 		timestampsFile.MustClose()
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create values file: %w", err)
 	}
 
@@ -127,7 +127,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 	if err != nil {
 		timestampsFile.MustClose()
 		valuesFile.MustClose()
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create index file: %w", err)
 	}
 
@@ -139,7 +139,7 @@ func (bsw *blockStreamWriter) InitFromFilePart(path string, nocache bool, compre
 		timestampsFile.MustClose()
 		valuesFile.MustClose()
 		indexFile.MustClose()
-		fs.MustRemoveAll(path)
+		fs.MustRemoveDirAtomic(path)
 		return fmt.Errorf("cannot create metaindex file: %w", err)
 	}
 
diff --git a/lib/storage/index_db.go b/lib/storage/index_db.go
index 8b72d3c37..0e9eae1e7 100644
--- a/lib/storage/index_db.go
+++ b/lib/storage/index_db.go
@@ -308,7 +308,7 @@ func (db *indexDB) decRef() {
 	}
 
 	logger.Infof("dropping indexDB %q", tbPath)
-	fs.MustRemoveAll(tbPath)
+	fs.MustRemoveDirAtomic(tbPath)
 	logger.Infof("indexDB %q has been dropped", tbPath)
 }
 
diff --git a/lib/storage/partition.go b/lib/storage/partition.go
index 082bc4f15..d7af8a17a 100644
--- a/lib/storage/partition.go
+++ b/lib/storage/partition.go
@@ -236,8 +236,8 @@ func (pt *partition) Drop() {
 	// Wait until all the pending transaction deletions are finished before removing partition directories.
 	pendingTxnDeletionsWG.Wait()
 
-	fs.MustRemoveAll(pt.smallPartsPath)
-	fs.MustRemoveAll(pt.bigPartsPath)
+	fs.MustRemoveDirAtomic(pt.smallPartsPath)
+	fs.MustRemoveDirAtomic(pt.bigPartsPath)
 	logger.Infof("partition %q has been dropped", pt.name)
 }
 
@@ -1394,17 +1394,14 @@ func (pt *partition) removeStaleParts() {
 	}
 
 	// Physically remove stale parts under snapshotLock in order to provide
-	// consistent snapshots with partition.CreateSnapshot().
+	// consistent snapshots with table.CreateSnapshot().
 	pt.snapshotLock.RLock()
-	var removeWG sync.WaitGroup
 	for pw := range m {
 		logger.Infof("removing part %q, since its data is out of the configured retention (%d secs)", pw.p.path, pt.retentionMsecs/1000)
-		removeWG.Add(1)
-		fs.MustRemoveAllWithDoneCallback(pw.p.path, removeWG.Done)
+		fs.MustRemoveDirAtomic(pw.p.path)
 	}
-	removeWG.Wait()
 	// There is no need in calling fs.MustSyncPath() on pt.smallPartsPath and pt.bigPartsPath,
-	// since they should be automatically called inside fs.MustRemoveAllWithDoneCallback.
+	// since they should be automatically called inside fs.MustRemoveDirAtomic().
 
 	pt.snapshotLock.RUnlock()
 
@@ -1554,6 +1551,7 @@ func openParts(pathPrefix1, pathPrefix2, path string) ([]*partWrapper, error) {
 	if err := fs.MkdirAllIfNotExist(path); err != nil {
 		return nil, err
 	}
+	fs.MustRemoveTemporaryDirs(path)
 	d, err := os.Open(path)
 	if err != nil {
 		return nil, fmt.Errorf("cannot open directory %q: %w", path, err)
@@ -1568,9 +1566,9 @@ func openParts(pathPrefix1, pathPrefix2, path string) ([]*partWrapper, error) {
 	}
 
 	txnDir := path + "/txn"
-	fs.MustRemoveAll(txnDir)
+	fs.MustRemoveDirAtomic(txnDir)
 	tmpDir := path + "/tmp"
-	fs.MustRemoveAll(tmpDir)
+	fs.MustRemoveDirAtomic(tmpDir)
 	if err := createPartitionDirs(path); err != nil {
 		return nil, fmt.Errorf("cannot create directories for partition %q: %w", path, err)
 	}
@@ -1596,7 +1594,7 @@ func openParts(pathPrefix1, pathPrefix2, path string) ([]*partWrapper, error) {
 		if fs.IsEmptyDir(partPath) {
 			// Remove empty directory, which can be left after unclean shutdown on NFS.
 			// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1142
-			fs.MustRemoveAll(partPath)
+			fs.MustRemoveDirAtomic(partPath)
 			continue
 		}
 		startTime := time.Now()
@@ -1761,14 +1759,12 @@ func runTransaction(txnLock *sync.RWMutex, pathPrefix1, pathPrefix2, txnPath str
 	}
 
 	// Remove old paths. It is OK if certain paths don't exist.
-	var removeWG sync.WaitGroup
 	for _, path := range rmPaths {
 		path, err := validatePath(pathPrefix1, pathPrefix2, path)
 		if err != nil {
 			return fmt.Errorf("invalid path to remove: %w", err)
 		}
-		removeWG.Add(1)
-		fs.MustRemoveAllWithDoneCallback(path, removeWG.Done)
+		fs.MustRemoveDirAtomic(path)
 	}
 
 	// Move the new part to new directory.
@@ -1797,8 +1793,7 @@ func runTransaction(txnLock *sync.RWMutex, pathPrefix1, pathPrefix2, txnPath str
 		}
 	} else {
 		// Just remove srcPath.
-		removeWG.Add(1)
-		fs.MustRemoveAllWithDoneCallback(srcPath, removeWG.Done)
+		fs.MustRemoveDirAtomic(srcPath)
 	}
 
 	// Flush pathPrefix* directory metadata to the underying storage,
@@ -1809,12 +1804,9 @@ func runTransaction(txnLock *sync.RWMutex, pathPrefix1, pathPrefix2, txnPath str
 	pendingTxnDeletionsWG.Add(1)
 	go func() {
 		defer pendingTxnDeletionsWG.Done()
-		// Remove the transaction file only after all the source paths are deleted.
-		// This is required for NFS mounts. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/61 .
-		removeWG.Wait()
 
 		// There is no need in calling fs.MustSyncPath for pathPrefix* after parts' removal,
-		// since it is already called by fs.MustRemoveAllWithDoneCallback.
+		// since it is already called by fs.MustRemoveDirAtomic.
 
 		if err := os.Remove(txnPath); err != nil {
 			logger.Errorf("cannot remove transaction file %q: %s", txnPath, err)
diff --git a/lib/storage/storage.go b/lib/storage/storage.go
index 0f6555deb..991bfc759 100644
--- a/lib/storage/storage.go
+++ b/lib/storage/storage.go
@@ -169,11 +169,10 @@ func OpenStorage(path string, retentionMsecs int64, maxHourlySeries, maxDailySer
 	// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1447 for details.
 	if fs.IsPathExist(s.cachePath + "/reset_cache_on_startup") {
 		logger.Infof("removing cache directory at %q, since it contains `reset_cache_on_startup` file...", s.cachePath)
-		wg := getWaitGroup()
-		wg.Add(1)
-		fs.MustRemoveAllWithDoneCallback(s.cachePath, wg.Done)
-		wg.Wait()
-		putWaitGroup(wg)
+		// Do not use fs.MustRemoveDirAtomic() here, since the cache directory may be mounted
+		// to a separate filesystem. In this case the fs.MustRemoveDirAtomic() will fail while
+		// trying to remove the mount root.
+		fs.RemoveDirContents(s.cachePath)
 		logger.Infof("cache directory at %q has been successfully removed", s.cachePath)
 	}
 
@@ -195,6 +194,7 @@ func OpenStorage(path string, retentionMsecs int64, maxHourlySeries, maxDailySer
 	if err := fs.MkdirAllIfNotExist(snapshotsPath); err != nil {
 		return nil, fmt.Errorf("cannot create %q: %w", snapshotsPath, err)
 	}
+	fs.MustRemoveTemporaryDirs(snapshotsPath)
 
 	// Initialize series cardinality limiter.
 	if maxHourlySeries > 0 {
@@ -239,6 +239,7 @@ func OpenStorage(path string, retentionMsecs int64, maxHourlySeries, maxDailySer
 	if err := fs.MkdirAllIfNotExist(idbSnapshotsPath); err != nil {
 		return nil, fmt.Errorf("cannot create %q: %w", idbSnapshotsPath, err)
 	}
+	fs.MustRemoveTemporaryDirs(idbSnapshotsPath)
 	idbCurr, idbPrev, err := s.openIndexDBTables(idbPath)
 	if err != nil {
 		return nil, fmt.Errorf("cannot open indexdb tables at %q: %w", idbPath, err)
@@ -411,8 +412,8 @@ func (s *Storage) DeleteSnapshot(snapshotName string) error {
 
 	s.tb.MustDeleteSnapshot(snapshotName)
 	idbPath := fmt.Sprintf("%s/indexdb/snapshots/%s", s.path, snapshotName)
-	fs.MustRemoveAll(idbPath)
-	fs.MustRemoveAll(snapshotPath)
+	fs.MustRemoveDirAtomic(idbPath)
+	fs.MustRemoveDirAtomic(snapshotPath)
 
 	logger.Infof("deleted snapshot %q in %.3f seconds", snapshotPath, time.Since(startTime).Seconds())
 
@@ -2449,6 +2450,7 @@ func (s *Storage) openIndexDBTables(path string) (curr, prev *indexDB, err error
 	if err := fs.MkdirAllIfNotExist(path); err != nil {
 		return nil, nil, fmt.Errorf("cannot create directory %q: %w", path, err)
 	}
+	fs.MustRemoveTemporaryDirs(path)
 
 	d, err := os.Open(path)
 	if err != nil {
@@ -2494,7 +2496,7 @@ func (s *Storage) openIndexDBTables(path string) (curr, prev *indexDB, err error
 	for _, tn := range tableNames[:len(tableNames)-2] {
 		pathToRemove := path + "/" + tn
 		logger.Infof("removing obsolete indexdb dir %q...", pathToRemove)
-		fs.MustRemoveAll(pathToRemove)
+		fs.MustRemoveDirAtomic(pathToRemove)
 		logger.Infof("removed obsolete indexdb dir %q", pathToRemove)
 	}
 
diff --git a/lib/storage/table.go b/lib/storage/table.go
index 2d691ce07..cf005814b 100644
--- a/lib/storage/table.go
+++ b/lib/storage/table.go
@@ -103,18 +103,23 @@ func openTable(path string, getDeletedMetricIDs func() *uint64set.Set, retention
 	if err := fs.MkdirAllIfNotExist(smallPartitionsPath); err != nil {
 		return nil, fmt.Errorf("cannot create directory for small partitions %q: %w", smallPartitionsPath, err)
 	}
+	fs.MustRemoveTemporaryDirs(smallPartitionsPath)
 	smallSnapshotsPath := smallPartitionsPath + "/snapshots"
 	if err := fs.MkdirAllIfNotExist(smallSnapshotsPath); err != nil {
 		return nil, fmt.Errorf("cannot create %q: %w", smallSnapshotsPath, err)
 	}
+	fs.MustRemoveTemporaryDirs(smallSnapshotsPath)
+
 	bigPartitionsPath := path + "/big"
 	if err := fs.MkdirAllIfNotExist(bigPartitionsPath); err != nil {
 		return nil, fmt.Errorf("cannot create directory for big partitions %q: %w", bigPartitionsPath, err)
 	}
+	fs.MustRemoveTemporaryDirs(bigPartitionsPath)
 	bigSnapshotsPath := bigPartitionsPath + "/snapshots"
 	if err := fs.MkdirAllIfNotExist(bigSnapshotsPath); err != nil {
 		return nil, fmt.Errorf("cannot create %q: %w", bigSnapshotsPath, err)
 	}
+	fs.MustRemoveTemporaryDirs(bigSnapshotsPath)
 
 	// Open partitions.
 	pts, err := openPartitions(smallPartitionsPath, bigPartitionsPath, getDeletedMetricIDs, retentionMsecs, isReadOnly)
@@ -179,9 +184,9 @@ func (tb *table) CreateSnapshot(snapshotName string) (string, string, error) {
 // MustDeleteSnapshot deletes snapshot with the given snapshotName.
 func (tb *table) MustDeleteSnapshot(snapshotName string) {
 	smallDir := fmt.Sprintf("%s/small/snapshots/%s", tb.path, snapshotName)
-	fs.MustRemoveAll(smallDir)
+	fs.MustRemoveDirAtomic(smallDir)
 	bigDir := fmt.Sprintf("%s/big/snapshots/%s", tb.path, snapshotName)
-	fs.MustRemoveAll(bigDir)
+	fs.MustRemoveDirAtomic(bigDir)
 }
 
 func (tb *table) addPartitionNolock(pt *partition) {
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
index 0d2ea8151..7ec5aa0aa 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
@@ -6661,12 +6661,21 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "ap-northeast-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "ap-northeast-2",
+				}: endpoint{},
+				endpointKey{
+					Region: "ap-south-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "ap-southeast-1",
 				}: endpoint{},
 				endpointKey{
 					Region: "ap-southeast-2",
 				}: endpoint{},
+				endpointKey{
+					Region: "ca-central-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "eu-central-1",
 				}: endpoint{},
@@ -6676,6 +6685,12 @@ var awsPartition = partition{
 				endpointKey{
 					Region: "eu-west-1",
 				}: endpoint{},
+				endpointKey{
+					Region: "eu-west-2",
+				}: endpoint{},
+				endpointKey{
+					Region: "eu-west-3",
+				}: endpoint{},
 				endpointKey{
 					Region: "fips-us-east-1",
 				}: endpoint{
@@ -6703,6 +6718,9 @@ var awsPartition = partition{
 					},
 					Deprecated: boxedTrue,
 				},
+				endpointKey{
+					Region: "sa-east-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "us-east-1",
 				}: endpoint{},
@@ -6721,6 +6739,9 @@ var awsPartition = partition{
 				}: endpoint{
 					Hostname: "devops-guru-fips.us-east-2.amazonaws.com",
 				},
+				endpointKey{
+					Region: "us-west-1",
+				}: endpoint{},
 				endpointKey{
 					Region: "us-west-2",
 				}: endpoint{},
@@ -30127,6 +30148,13 @@ var awsusgovPartition = partition{
 				},
 			},
 		},
+		"managedblockchain": service{
+			Endpoints: serviceEndpoints{
+				endpointKey{
+					Region: "us-gov-west-1",
+				}: endpoint{},
+			},
+		},
 		"mediaconvert": service{
 			Endpoints: serviceEndpoints{
 				endpointKey{
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/version.go b/vendor/github.com/aws/aws-sdk-go/aws/version.go
index 551c8882a..43c5f9307 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/version.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/version.go
@@ -5,4 +5,4 @@ package aws
 const SDKName = "aws-sdk-go"
 
 // SDKVersion is the version of this SDK
-const SDKVersion = "1.44.93"
+const SDKVersion = "1.44.96"
diff --git a/vendor/github.com/rivo/uniseg/README.md b/vendor/github.com/rivo/uniseg/README.md
index 89fc21a3d..7e3d12e79 100644
--- a/vendor/github.com/rivo/uniseg/README.md
+++ b/vendor/github.com/rivo/uniseg/README.md
@@ -3,13 +3,13 @@
 [![Go Reference](https://pkg.go.dev/badge/github.com/rivo/uniseg.svg)](https://pkg.go.dev/github.com/rivo/uniseg)
 [![Go Report](https://img.shields.io/badge/go%20report-A%2B-brightgreen.svg)](https://goreportcard.com/report/github.com/rivo/uniseg)
 
-This Go package implements Unicode Text Segmentation according to [Unicode Standard Annex #29](https://unicode.org/reports/tr29/) and Unicode Line Breaking according to [Unicode Standard Annex #14](https://unicode.org/reports/tr14/) (Unicode version 14.0.0).
+This Go package implements Unicode Text Segmentation according to [Unicode Standard Annex #29](https://unicode.org/reports/tr29/), Unicode Line Breaking according to [Unicode Standard Annex #14](https://unicode.org/reports/tr14/) (Unicode version 14.0.0), and monospace font string width calculation similar to [wcwidth](https://man7.org/linux/man-pages/man3/wcwidth.3.html).
 
 ## Background
 
 ### Grapheme Clusters
 
-In Go, [strings are read-only slices of bytes](https://blog.golang.org/strings). They can be turned into Unicode code points using the `for` loop or by casting: `[]rune(str)`. However, multiple code points may be combined into one user-perceived character or what the Unicode specification calls "grapheme cluster". Here are some examples:
+In Go, [strings are read-only slices of bytes](https://go.dev/blog/strings). They can be turned into Unicode code points using the `for` loop or by casting: `[]rune(str)`. However, multiple code points may be combined into one user-perceived character or what the Unicode specification calls "grapheme cluster". Here are some examples:
 
 |String|Bytes (UTF-8)|Code points (runes)|Grapheme clusters|
 |-|-|-|-|
@@ -31,6 +31,10 @@ Sentence boundaries are often used for triple-click or some other method of sele
 
 Line breaking, also known as word wrapping, is the process of breaking a section of text into lines such that it will fit in the available width of a page, window or other display area. This package provides tools to determine where a string may or may not be broken and where it must be broken (for example after newline characters).
 
+### Monospace Width
+
+Most terminals or text displays / text editors using a monospace font (for example source code editors) use a fixed width for each character. Some characters such as emojis or characters found in Asian and other languages may take up more than one character cell. This package provides tools to determine the number of cells a string will take up when displayed in a monospace font. See [here](https://pkg.go.dev/github.com/rivo/uniseg#hdr-Monospace_Width) for more information.
+
 ## Installation
 
 ```bash
@@ -47,6 +51,14 @@ fmt.Println(n)
 // 2
 ```
 
+### Calculating the Monospace String Width
+
+```go
+width := uniseg.StringWidth("🇩🇪🏳️‍🌈!")
+fmt.Println(width)
+// 5
+```
+
 ### Using the [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) Class
 
 This is the most convenient method of iterating over grapheme clusters:
diff --git a/vendor/github.com/rivo/uniseg/doc.go b/vendor/github.com/rivo/uniseg/doc.go
index 6c498ede1..0fc2d8b43 100644
--- a/vendor/github.com/rivo/uniseg/doc.go
+++ b/vendor/github.com/rivo/uniseg/doc.go
@@ -1,8 +1,9 @@
 /*
-Package uniseg implements Unicode Text Segmentation and Unicode Line Breaking.
-Unicode Text Segmentation conforms to Unicode Standard Annex #29
-(https://unicode.org/reports/tr29/) and Unicode Line Breaking conforms to
-Unicode Standard Annex #14 (https://unicode.org/reports/tr14/).
+Package uniseg implements Unicode Text Segmentation, Unicode Line Breaking, and
+string width calculation for monospace fonts. Unicode Text Segmentation conforms
+to Unicode Standard Annex #29 (https://unicode.org/reports/tr29/) and Unicode
+Line Breaking conforms to Unicode Standard Annex #14
+(https://unicode.org/reports/tr14/).
 
 In short, using this package, you can split a string into grapheme clusters
 (what people would usually refer to as a "character"), into words, and into
@@ -12,8 +13,23 @@ as emojis, combining characters, or characters from Asian, Arabic, Hebrew, or
 other languages. Additionally, you can use it to implement line breaking (or
 "word wrapping"), that is, to determine where text can be broken over to the
 next line when the width of the line is not big enough to fit the entire text.
+Finally, you can use it to calculate the display width of a string for monospace
+fonts.
 
-Grapheme Clusters
+# Getting Started
+
+If you just want to count the number of characters in a string, you can use
+[GraphemeClusterCount]. If you want to determine the display width of a string,
+you can use [StringWidth]. If you want to iterate over a string, you can use
+[Step], [StepString], or the [Graphemes] class (more convenient but less
+performant). This will provide you with all information: grapheme clusters,
+word boundaries, sentence boundaries, line breaks, and monospace character
+widths. The specialized functions [FirstGraphemeCluster],
+[FirstGraphemeClusterInString], [FirstWord], [FirstWordInString],
+[FirstSentence], and [FirstSentenceInString] can be used if only one type of
+information is needed.
+
+# Grapheme Clusters
 
 Consider the rainbow flag emoji: 🏳️‍🌈. On most modern systems, it appears as one
 character. But its string representation actually has 14 bytes, so counting
@@ -21,11 +37,11 @@ bytes (or using len("🏳️‍🌈")) will not work as expected. Counting runes
 either: The flag has 4 Unicode code points, thus 4 runes. The stdlib function
 utf8.RuneCountInString("🏳️‍🌈") and len([]rune("🏳️‍🌈")) will both return 4.
 
-The uniseg.GraphemeClusterCount(str) function will return 1 for the rainbow flag
-emoji. The Graphemes class and a variety of functions in this package will allow
-you to split strings into its grapheme clusters.
+The [GraphemeClusterCount] function will return 1 for the rainbow flag emoji.
+The Graphemes class and a variety of functions in this package will allow you to
+split strings into its grapheme clusters.
 
-Word Boundaries
+# Word Boundaries
 
 Word boundaries are used in a number of different contexts. The most familiar
 ones are selection (double-click mouse selection), cursor movement ("move to
@@ -33,7 +49,7 @@ next word" control-arrow keys), and the dialog option "Whole Word Search" for
 search and replace. This package provides methods for determining word
 boundaries.
 
-Sentence Boundaries
+# Sentence Boundaries
 
 Sentence boundaries are often used for triple-click or some other method of
 selecting or iterating through blocks of text that are larger than single words.
@@ -41,7 +57,7 @@ They are also used to determine whether words occur within the same sentence in
 database queries. This package provides methods for determining sentence
 boundaries.
 
-Line Breaking
+# Line Breaking
 
 Line breaking, also known as word wrapping, is the process of breaking a section
 of text into lines such that it will fit in the available width of a page,
@@ -49,5 +65,44 @@ window or other display area. This package provides methods to determine the
 positions in a string where a line must be broken, may be broken, or must not be
 broken.
 
+# Monospace Width
+
+Monospace width, as referred to in this package, is the width of a string in a
+monospace font. This is commonly used in terminal user interfaces or text
+displays or editors that don't support proportional fonts. A width of 1
+corresponds to a single character cell. The C function [wcwidth()] and its
+implementation in other programming languages is in widespread use for the same
+purpose. However, there is no standard for the calculation of such widths, and
+this package differs from wcwidth() in a number of ways, presumably to generate
+more visually pleasing results.
+
+To start, we assume that every code point has a width of 1, with the following
+exceptions:
+
+  - Code points with grapheme cluster break properties Control, CR, LF, Extend,
+    and ZWJ have a width of 0.
+  - U+2E3A, Two-Em Dash, has a width of 3.
+  - U+2E3B, Three-Em Dash, has a width of 4.
+  - Characters with the East-Asian Width properties "Fullwidth" (F) and "Wide"
+    (W) have a width of 2. (Properties "Ambiguous" (A) and "Neutral" (N) both
+    have a width of 1.)
+  - Code points with grapheme cluster break property Regional Indicator have a
+    width of 2.
+  - Code points with grapheme cluster break property Extended Pictographic have
+    a width of 2, unless their Emoji Presentation flag is "No", in which case
+    the width is 1.
+
+For Hangul grapheme clusters composed of conjoining Jamo and for Regional
+Indicators (flags), all code points except the first one have a width of 0. For
+grapheme clusters starting with an Extended Pictographic, any additional code
+point will force a total width of 2, except if the Variation Selector-15
+(U+FE0E) is included, in which case the total width is always 1. Grapheme
+clusters ending with Variation Selector-16 (U+FE0F) have a width of 2.
+
+Note that whether these widths appear correct depends on your application's
+render engine, to which extent it conforms to the Unicode Standard, and its
+choice of font.
+
+[wcwidth()]: https://man7.org/linux/man-pages/man3/wcwidth.3.html
 */
 package uniseg
diff --git a/vendor/github.com/rivo/uniseg/eastasianwidth.go b/vendor/github.com/rivo/uniseg/eastasianwidth.go
index 456c1cac5..661934ac2 100644
--- a/vendor/github.com/rivo/uniseg/eastasianwidth.go
+++ b/vendor/github.com/rivo/uniseg/eastasianwidth.go
@@ -4,7 +4,10 @@ package uniseg
 
 // eastAsianWidth are taken from
 // https://www.unicode.org/Public/14.0.0/ucd/EastAsianWidth.txt
-// on July 25, 2022. See https://www.unicode.org/license.html for the Unicode
+// and
+// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
 // license agreement.
 var eastAsianWidth = [][3]int{
 	{0x0000, 0x001F, prN},     // Cc    [32] <control-0000>..<control-001F>
diff --git a/vendor/github.com/rivo/uniseg/emojipresentation.go b/vendor/github.com/rivo/uniseg/emojipresentation.go
new file mode 100644
index 000000000..fd0f7451a
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/emojipresentation.go
@@ -0,0 +1,285 @@
+package uniseg
+
+// Code generated via go generate from gen_properties.go. DO NOT EDIT.
+
+// emojiPresentation are taken from
+//
+// and
+// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
+// license agreement.
+var emojiPresentation = [][3]int{
+	{0x231A, 0x231B, prEmojiPresentation},   // E0.6   [2] (⌚..⌛)    watch..hourglass done
+	{0x23E9, 0x23EC, prEmojiPresentation},   // E0.6   [4] (⏩..⏬)    fast-forward button..fast down button
+	{0x23F0, 0x23F0, prEmojiPresentation},   // E0.6   [1] (⏰)       alarm clock
+	{0x23F3, 0x23F3, prEmojiPresentation},   // E0.6   [1] (⏳)       hourglass not done
+	{0x25FD, 0x25FE, prEmojiPresentation},   // E0.6   [2] (◽..◾)    white medium-small square..black medium-small square
+	{0x2614, 0x2615, prEmojiPresentation},   // E0.6   [2] (☔..☕)    umbrella with rain drops..hot beverage
+	{0x2648, 0x2653, prEmojiPresentation},   // E0.6  [12] (♈..♓)    Aries..Pisces
+	{0x267F, 0x267F, prEmojiPresentation},   // E0.6   [1] (♿)       wheelchair symbol
+	{0x2693, 0x2693, prEmojiPresentation},   // E0.6   [1] (⚓)       anchor
+	{0x26A1, 0x26A1, prEmojiPresentation},   // E0.6   [1] (⚡)       high voltage
+	{0x26AA, 0x26AB, prEmojiPresentation},   // E0.6   [2] (⚪..⚫)    white circle..black circle
+	{0x26BD, 0x26BE, prEmojiPresentation},   // E0.6   [2] (⚽..⚾)    soccer ball..baseball
+	{0x26C4, 0x26C5, prEmojiPresentation},   // E0.6   [2] (⛄..⛅)    snowman without snow..sun behind cloud
+	{0x26CE, 0x26CE, prEmojiPresentation},   // E0.6   [1] (⛎)       Ophiuchus
+	{0x26D4, 0x26D4, prEmojiPresentation},   // E0.6   [1] (⛔)       no entry
+	{0x26EA, 0x26EA, prEmojiPresentation},   // E0.6   [1] (⛪)       church
+	{0x26F2, 0x26F3, prEmojiPresentation},   // E0.6   [2] (⛲..⛳)    fountain..flag in hole
+	{0x26F5, 0x26F5, prEmojiPresentation},   // E0.6   [1] (⛵)       sailboat
+	{0x26FA, 0x26FA, prEmojiPresentation},   // E0.6   [1] (⛺)       tent
+	{0x26FD, 0x26FD, prEmojiPresentation},   // E0.6   [1] (⛽)       fuel pump
+	{0x2705, 0x2705, prEmojiPresentation},   // E0.6   [1] (✅)       check mark button
+	{0x270A, 0x270B, prEmojiPresentation},   // E0.6   [2] (✊..✋)    raised fist..raised hand
+	{0x2728, 0x2728, prEmojiPresentation},   // E0.6   [1] (✨)       sparkles
+	{0x274C, 0x274C, prEmojiPresentation},   // E0.6   [1] (❌)       cross mark
+	{0x274E, 0x274E, prEmojiPresentation},   // E0.6   [1] (❎)       cross mark button
+	{0x2753, 0x2755, prEmojiPresentation},   // E0.6   [3] (❓..❕)    red question mark..white exclamation mark
+	{0x2757, 0x2757, prEmojiPresentation},   // E0.6   [1] (❗)       red exclamation mark
+	{0x2795, 0x2797, prEmojiPresentation},   // E0.6   [3] (➕..➗)    plus..divide
+	{0x27B0, 0x27B0, prEmojiPresentation},   // E0.6   [1] (➰)       curly loop
+	{0x27BF, 0x27BF, prEmojiPresentation},   // E1.0   [1] (➿)       double curly loop
+	{0x2B1B, 0x2B1C, prEmojiPresentation},   // E0.6   [2] (⬛..⬜)    black large square..white large square
+	{0x2B50, 0x2B50, prEmojiPresentation},   // E0.6   [1] (⭐)       star
+	{0x2B55, 0x2B55, prEmojiPresentation},   // E0.6   [1] (⭕)       hollow red circle
+	{0x1F004, 0x1F004, prEmojiPresentation}, // E0.6   [1] (🀄)       mahjong red dragon
+	{0x1F0CF, 0x1F0CF, prEmojiPresentation}, // E0.6   [1] (🃏)       joker
+	{0x1F18E, 0x1F18E, prEmojiPresentation}, // E0.6   [1] (🆎)       AB button (blood type)
+	{0x1F191, 0x1F19A, prEmojiPresentation}, // E0.6  [10] (🆑..🆚)    CL button..VS button
+	{0x1F1E6, 0x1F1FF, prEmojiPresentation}, // E0.0  [26] (🇦..🇿)    regional indicator symbol letter a..regional indicator symbol letter z
+	{0x1F201, 0x1F201, prEmojiPresentation}, // E0.6   [1] (🈁)       Japanese “here” button
+	{0x1F21A, 0x1F21A, prEmojiPresentation}, // E0.6   [1] (🈚)       Japanese “free of charge” button
+	{0x1F22F, 0x1F22F, prEmojiPresentation}, // E0.6   [1] (🈯)       Japanese “reserved” button
+	{0x1F232, 0x1F236, prEmojiPresentation}, // E0.6   [5] (🈲..🈶)    Japanese “prohibited” button..Japanese “not free of charge” button
+	{0x1F238, 0x1F23A, prEmojiPresentation}, // E0.6   [3] (🈸..🈺)    Japanese “application” button..Japanese “open for business” button
+	{0x1F250, 0x1F251, prEmojiPresentation}, // E0.6   [2] (🉐..🉑)    Japanese “bargain” button..Japanese “acceptable” button
+	{0x1F300, 0x1F30C, prEmojiPresentation}, // E0.6  [13] (🌀..🌌)    cyclone..milky way
+	{0x1F30D, 0x1F30E, prEmojiPresentation}, // E0.7   [2] (🌍..🌎)    globe showing Europe-Africa..globe showing Americas
+	{0x1F30F, 0x1F30F, prEmojiPresentation}, // E0.6   [1] (🌏)       globe showing Asia-Australia
+	{0x1F310, 0x1F310, prEmojiPresentation}, // E1.0   [1] (🌐)       globe with meridians
+	{0x1F311, 0x1F311, prEmojiPresentation}, // E0.6   [1] (🌑)       new moon
+	{0x1F312, 0x1F312, prEmojiPresentation}, // E1.0   [1] (🌒)       waxing crescent moon
+	{0x1F313, 0x1F315, prEmojiPresentation}, // E0.6   [3] (🌓..🌕)    first quarter moon..full moon
+	{0x1F316, 0x1F318, prEmojiPresentation}, // E1.0   [3] (🌖..🌘)    waning gibbous moon..waning crescent moon
+	{0x1F319, 0x1F319, prEmojiPresentation}, // E0.6   [1] (🌙)       crescent moon
+	{0x1F31A, 0x1F31A, prEmojiPresentation}, // E1.0   [1] (🌚)       new moon face
+	{0x1F31B, 0x1F31B, prEmojiPresentation}, // E0.6   [1] (🌛)       first quarter moon face
+	{0x1F31C, 0x1F31C, prEmojiPresentation}, // E0.7   [1] (🌜)       last quarter moon face
+	{0x1F31D, 0x1F31E, prEmojiPresentation}, // E1.0   [2] (🌝..🌞)    full moon face..sun with face
+	{0x1F31F, 0x1F320, prEmojiPresentation}, // E0.6   [2] (🌟..🌠)    glowing star..shooting star
+	{0x1F32D, 0x1F32F, prEmojiPresentation}, // E1.0   [3] (🌭..🌯)    hot dog..burrito
+	{0x1F330, 0x1F331, prEmojiPresentation}, // E0.6   [2] (🌰..🌱)    chestnut..seedling
+	{0x1F332, 0x1F333, prEmojiPresentation}, // E1.0   [2] (🌲..🌳)    evergreen tree..deciduous tree
+	{0x1F334, 0x1F335, prEmojiPresentation}, // E0.6   [2] (🌴..🌵)    palm tree..cactus
+	{0x1F337, 0x1F34A, prEmojiPresentation}, // E0.6  [20] (🌷..🍊)    tulip..tangerine
+	{0x1F34B, 0x1F34B, prEmojiPresentation}, // E1.0   [1] (🍋)       lemon
+	{0x1F34C, 0x1F34F, prEmojiPresentation}, // E0.6   [4] (🍌..🍏)    banana..green apple
+	{0x1F350, 0x1F350, prEmojiPresentation}, // E1.0   [1] (🍐)       pear
+	{0x1F351, 0x1F37B, prEmojiPresentation}, // E0.6  [43] (🍑..🍻)    peach..clinking beer mugs
+	{0x1F37C, 0x1F37C, prEmojiPresentation}, // E1.0   [1] (🍼)       baby bottle
+	{0x1F37E, 0x1F37F, prEmojiPresentation}, // E1.0   [2] (🍾..🍿)    bottle with popping cork..popcorn
+	{0x1F380, 0x1F393, prEmojiPresentation}, // E0.6  [20] (🎀..🎓)    ribbon..graduation cap
+	{0x1F3A0, 0x1F3C4, prEmojiPresentation}, // E0.6  [37] (🎠..🏄)    carousel horse..person surfing
+	{0x1F3C5, 0x1F3C5, prEmojiPresentation}, // E1.0   [1] (🏅)       sports medal
+	{0x1F3C6, 0x1F3C6, prEmojiPresentation}, // E0.6   [1] (🏆)       trophy
+	{0x1F3C7, 0x1F3C7, prEmojiPresentation}, // E1.0   [1] (🏇)       horse racing
+	{0x1F3C8, 0x1F3C8, prEmojiPresentation}, // E0.6   [1] (🏈)       american football
+	{0x1F3C9, 0x1F3C9, prEmojiPresentation}, // E1.0   [1] (🏉)       rugby football
+	{0x1F3CA, 0x1F3CA, prEmojiPresentation}, // E0.6   [1] (🏊)       person swimming
+	{0x1F3CF, 0x1F3D3, prEmojiPresentation}, // E1.0   [5] (🏏..🏓)    cricket game..ping pong
+	{0x1F3E0, 0x1F3E3, prEmojiPresentation}, // E0.6   [4] (🏠..🏣)    house..Japanese post office
+	{0x1F3E4, 0x1F3E4, prEmojiPresentation}, // E1.0   [1] (🏤)       post office
+	{0x1F3E5, 0x1F3F0, prEmojiPresentation}, // E0.6  [12] (🏥..🏰)    hospital..castle
+	{0x1F3F4, 0x1F3F4, prEmojiPresentation}, // E1.0   [1] (🏴)       black flag
+	{0x1F3F8, 0x1F407, prEmojiPresentation}, // E1.0  [16] (🏸..🐇)    badminton..rabbit
+	{0x1F408, 0x1F408, prEmojiPresentation}, // E0.7   [1] (🐈)       cat
+	{0x1F409, 0x1F40B, prEmojiPresentation}, // E1.0   [3] (🐉..🐋)    dragon..whale
+	{0x1F40C, 0x1F40E, prEmojiPresentation}, // E0.6   [3] (🐌..🐎)    snail..horse
+	{0x1F40F, 0x1F410, prEmojiPresentation}, // E1.0   [2] (🐏..🐐)    ram..goat
+	{0x1F411, 0x1F412, prEmojiPresentation}, // E0.6   [2] (🐑..🐒)    ewe..monkey
+	{0x1F413, 0x1F413, prEmojiPresentation}, // E1.0   [1] (🐓)       rooster
+	{0x1F414, 0x1F414, prEmojiPresentation}, // E0.6   [1] (🐔)       chicken
+	{0x1F415, 0x1F415, prEmojiPresentation}, // E0.7   [1] (🐕)       dog
+	{0x1F416, 0x1F416, prEmojiPresentation}, // E1.0   [1] (🐖)       pig
+	{0x1F417, 0x1F429, prEmojiPresentation}, // E0.6  [19] (🐗..🐩)    boar..poodle
+	{0x1F42A, 0x1F42A, prEmojiPresentation}, // E1.0   [1] (🐪)       camel
+	{0x1F42B, 0x1F43E, prEmojiPresentation}, // E0.6  [20] (🐫..🐾)    two-hump camel..paw prints
+	{0x1F440, 0x1F440, prEmojiPresentation}, // E0.6   [1] (👀)       eyes
+	{0x1F442, 0x1F464, prEmojiPresentation}, // E0.6  [35] (👂..👤)    ear..bust in silhouette
+	{0x1F465, 0x1F465, prEmojiPresentation}, // E1.0   [1] (👥)       busts in silhouette
+	{0x1F466, 0x1F46B, prEmojiPresentation}, // E0.6   [6] (👦..👫)    boy..woman and man holding hands
+	{0x1F46C, 0x1F46D, prEmojiPresentation}, // E1.0   [2] (👬..👭)    men holding hands..women holding hands
+	{0x1F46E, 0x1F4AC, prEmojiPresentation}, // E0.6  [63] (👮..💬)    police officer..speech balloon
+	{0x1F4AD, 0x1F4AD, prEmojiPresentation}, // E1.0   [1] (💭)       thought balloon
+	{0x1F4AE, 0x1F4B5, prEmojiPresentation}, // E0.6   [8] (💮..💵)    white flower..dollar banknote
+	{0x1F4B6, 0x1F4B7, prEmojiPresentation}, // E1.0   [2] (💶..💷)    euro banknote..pound banknote
+	{0x1F4B8, 0x1F4EB, prEmojiPresentation}, // E0.6  [52] (💸..📫)    money with wings..closed mailbox with raised flag
+	{0x1F4EC, 0x1F4ED, prEmojiPresentation}, // E0.7   [2] (📬..📭)    open mailbox with raised flag..open mailbox with lowered flag
+	{0x1F4EE, 0x1F4EE, prEmojiPresentation}, // E0.6   [1] (📮)       postbox
+	{0x1F4EF, 0x1F4EF, prEmojiPresentation}, // E1.0   [1] (📯)       postal horn
+	{0x1F4F0, 0x1F4F4, prEmojiPresentation}, // E0.6   [5] (📰..📴)    newspaper..mobile phone off
+	{0x1F4F5, 0x1F4F5, prEmojiPresentation}, // E1.0   [1] (📵)       no mobile phones
+	{0x1F4F6, 0x1F4F7, prEmojiPresentation}, // E0.6   [2] (📶..📷)    antenna bars..camera
+	{0x1F4F8, 0x1F4F8, prEmojiPresentation}, // E1.0   [1] (📸)       camera with flash
+	{0x1F4F9, 0x1F4FC, prEmojiPresentation}, // E0.6   [4] (📹..📼)    video camera..videocassette
+	{0x1F4FF, 0x1F502, prEmojiPresentation}, // E1.0   [4] (📿..🔂)    prayer beads..repeat single button
+	{0x1F503, 0x1F503, prEmojiPresentation}, // E0.6   [1] (🔃)       clockwise vertical arrows
+	{0x1F504, 0x1F507, prEmojiPresentation}, // E1.0   [4] (🔄..🔇)    counterclockwise arrows button..muted speaker
+	{0x1F508, 0x1F508, prEmojiPresentation}, // E0.7   [1] (🔈)       speaker low volume
+	{0x1F509, 0x1F509, prEmojiPresentation}, // E1.0   [1] (🔉)       speaker medium volume
+	{0x1F50A, 0x1F514, prEmojiPresentation}, // E0.6  [11] (🔊..🔔)    speaker high volume..bell
+	{0x1F515, 0x1F515, prEmojiPresentation}, // E1.0   [1] (🔕)       bell with slash
+	{0x1F516, 0x1F52B, prEmojiPresentation}, // E0.6  [22] (🔖..🔫)    bookmark..water pistol
+	{0x1F52C, 0x1F52D, prEmojiPresentation}, // E1.0   [2] (🔬..🔭)    microscope..telescope
+	{0x1F52E, 0x1F53D, prEmojiPresentation}, // E0.6  [16] (🔮..🔽)    crystal ball..downwards button
+	{0x1F54B, 0x1F54E, prEmojiPresentation}, // E1.0   [4] (🕋..🕎)    kaaba..menorah
+	{0x1F550, 0x1F55B, prEmojiPresentation}, // E0.6  [12] (🕐..🕛)    one o’clock..twelve o’clock
+	{0x1F55C, 0x1F567, prEmojiPresentation}, // E0.7  [12] (🕜..🕧)    one-thirty..twelve-thirty
+	{0x1F57A, 0x1F57A, prEmojiPresentation}, // E3.0   [1] (🕺)       man dancing
+	{0x1F595, 0x1F596, prEmojiPresentation}, // E1.0   [2] (🖕..🖖)    middle finger..vulcan salute
+	{0x1F5A4, 0x1F5A4, prEmojiPresentation}, // E3.0   [1] (🖤)       black heart
+	{0x1F5FB, 0x1F5FF, prEmojiPresentation}, // E0.6   [5] (🗻..🗿)    mount fuji..moai
+	{0x1F600, 0x1F600, prEmojiPresentation}, // E1.0   [1] (😀)       grinning face
+	{0x1F601, 0x1F606, prEmojiPresentation}, // E0.6   [6] (😁..😆)    beaming face with smiling eyes..grinning squinting face
+	{0x1F607, 0x1F608, prEmojiPresentation}, // E1.0   [2] (😇..😈)    smiling face with halo..smiling face with horns
+	{0x1F609, 0x1F60D, prEmojiPresentation}, // E0.6   [5] (😉..😍)    winking face..smiling face with heart-eyes
+	{0x1F60E, 0x1F60E, prEmojiPresentation}, // E1.0   [1] (😎)       smiling face with sunglasses
+	{0x1F60F, 0x1F60F, prEmojiPresentation}, // E0.6   [1] (😏)       smirking face
+	{0x1F610, 0x1F610, prEmojiPresentation}, // E0.7   [1] (😐)       neutral face
+	{0x1F611, 0x1F611, prEmojiPresentation}, // E1.0   [1] (😑)       expressionless face
+	{0x1F612, 0x1F614, prEmojiPresentation}, // E0.6   [3] (😒..😔)    unamused face..pensive face
+	{0x1F615, 0x1F615, prEmojiPresentation}, // E1.0   [1] (😕)       confused face
+	{0x1F616, 0x1F616, prEmojiPresentation}, // E0.6   [1] (😖)       confounded face
+	{0x1F617, 0x1F617, prEmojiPresentation}, // E1.0   [1] (😗)       kissing face
+	{0x1F618, 0x1F618, prEmojiPresentation}, // E0.6   [1] (😘)       face blowing a kiss
+	{0x1F619, 0x1F619, prEmojiPresentation}, // E1.0   [1] (😙)       kissing face with smiling eyes
+	{0x1F61A, 0x1F61A, prEmojiPresentation}, // E0.6   [1] (😚)       kissing face with closed eyes
+	{0x1F61B, 0x1F61B, prEmojiPresentation}, // E1.0   [1] (😛)       face with tongue
+	{0x1F61C, 0x1F61E, prEmojiPresentation}, // E0.6   [3] (😜..😞)    winking face with tongue..disappointed face
+	{0x1F61F, 0x1F61F, prEmojiPresentation}, // E1.0   [1] (😟)       worried face
+	{0x1F620, 0x1F625, prEmojiPresentation}, // E0.6   [6] (😠..😥)    angry face..sad but relieved face
+	{0x1F626, 0x1F627, prEmojiPresentation}, // E1.0   [2] (😦..😧)    frowning face with open mouth..anguished face
+	{0x1F628, 0x1F62B, prEmojiPresentation}, // E0.6   [4] (😨..😫)    fearful face..tired face
+	{0x1F62C, 0x1F62C, prEmojiPresentation}, // E1.0   [1] (😬)       grimacing face
+	{0x1F62D, 0x1F62D, prEmojiPresentation}, // E0.6   [1] (😭)       loudly crying face
+	{0x1F62E, 0x1F62F, prEmojiPresentation}, // E1.0   [2] (😮..😯)    face with open mouth..hushed face
+	{0x1F630, 0x1F633, prEmojiPresentation}, // E0.6   [4] (😰..😳)    anxious face with sweat..flushed face
+	{0x1F634, 0x1F634, prEmojiPresentation}, // E1.0   [1] (😴)       sleeping face
+	{0x1F635, 0x1F635, prEmojiPresentation}, // E0.6   [1] (😵)       face with crossed-out eyes
+	{0x1F636, 0x1F636, prEmojiPresentation}, // E1.0   [1] (😶)       face without mouth
+	{0x1F637, 0x1F640, prEmojiPresentation}, // E0.6  [10] (😷..🙀)    face with medical mask..weary cat
+	{0x1F641, 0x1F644, prEmojiPresentation}, // E1.0   [4] (🙁..🙄)    slightly frowning face..face with rolling eyes
+	{0x1F645, 0x1F64F, prEmojiPresentation}, // E0.6  [11] (🙅..🙏)    person gesturing NO..folded hands
+	{0x1F680, 0x1F680, prEmojiPresentation}, // E0.6   [1] (🚀)       rocket
+	{0x1F681, 0x1F682, prEmojiPresentation}, // E1.0   [2] (🚁..🚂)    helicopter..locomotive
+	{0x1F683, 0x1F685, prEmojiPresentation}, // E0.6   [3] (🚃..🚅)    railway car..bullet train
+	{0x1F686, 0x1F686, prEmojiPresentation}, // E1.0   [1] (🚆)       train
+	{0x1F687, 0x1F687, prEmojiPresentation}, // E0.6   [1] (🚇)       metro
+	{0x1F688, 0x1F688, prEmojiPresentation}, // E1.0   [1] (🚈)       light rail
+	{0x1F689, 0x1F689, prEmojiPresentation}, // E0.6   [1] (🚉)       station
+	{0x1F68A, 0x1F68B, prEmojiPresentation}, // E1.0   [2] (🚊..🚋)    tram..tram car
+	{0x1F68C, 0x1F68C, prEmojiPresentation}, // E0.6   [1] (🚌)       bus
+	{0x1F68D, 0x1F68D, prEmojiPresentation}, // E0.7   [1] (🚍)       oncoming bus
+	{0x1F68E, 0x1F68E, prEmojiPresentation}, // E1.0   [1] (🚎)       trolleybus
+	{0x1F68F, 0x1F68F, prEmojiPresentation}, // E0.6   [1] (🚏)       bus stop
+	{0x1F690, 0x1F690, prEmojiPresentation}, // E1.0   [1] (🚐)       minibus
+	{0x1F691, 0x1F693, prEmojiPresentation}, // E0.6   [3] (🚑..🚓)    ambulance..police car
+	{0x1F694, 0x1F694, prEmojiPresentation}, // E0.7   [1] (🚔)       oncoming police car
+	{0x1F695, 0x1F695, prEmojiPresentation}, // E0.6   [1] (🚕)       taxi
+	{0x1F696, 0x1F696, prEmojiPresentation}, // E1.0   [1] (🚖)       oncoming taxi
+	{0x1F697, 0x1F697, prEmojiPresentation}, // E0.6   [1] (🚗)       automobile
+	{0x1F698, 0x1F698, prEmojiPresentation}, // E0.7   [1] (🚘)       oncoming automobile
+	{0x1F699, 0x1F69A, prEmojiPresentation}, // E0.6   [2] (🚙..🚚)    sport utility vehicle..delivery truck
+	{0x1F69B, 0x1F6A1, prEmojiPresentation}, // E1.0   [7] (🚛..🚡)    articulated lorry..aerial tramway
+	{0x1F6A2, 0x1F6A2, prEmojiPresentation}, // E0.6   [1] (🚢)       ship
+	{0x1F6A3, 0x1F6A3, prEmojiPresentation}, // E1.0   [1] (🚣)       person rowing boat
+	{0x1F6A4, 0x1F6A5, prEmojiPresentation}, // E0.6   [2] (🚤..🚥)    speedboat..horizontal traffic light
+	{0x1F6A6, 0x1F6A6, prEmojiPresentation}, // E1.0   [1] (🚦)       vertical traffic light
+	{0x1F6A7, 0x1F6AD, prEmojiPresentation}, // E0.6   [7] (🚧..🚭)    construction..no smoking
+	{0x1F6AE, 0x1F6B1, prEmojiPresentation}, // E1.0   [4] (🚮..🚱)    litter in bin sign..non-potable water
+	{0x1F6B2, 0x1F6B2, prEmojiPresentation}, // E0.6   [1] (🚲)       bicycle
+	{0x1F6B3, 0x1F6B5, prEmojiPresentation}, // E1.0   [3] (🚳..🚵)    no bicycles..person mountain biking
+	{0x1F6B6, 0x1F6B6, prEmojiPresentation}, // E0.6   [1] (🚶)       person walking
+	{0x1F6B7, 0x1F6B8, prEmojiPresentation}, // E1.0   [2] (🚷..🚸)    no pedestrians..children crossing
+	{0x1F6B9, 0x1F6BE, prEmojiPresentation}, // E0.6   [6] (🚹..🚾)    men’s room..water closet
+	{0x1F6BF, 0x1F6BF, prEmojiPresentation}, // E1.0   [1] (🚿)       shower
+	{0x1F6C0, 0x1F6C0, prEmojiPresentation}, // E0.6   [1] (🛀)       person taking bath
+	{0x1F6C1, 0x1F6C5, prEmojiPresentation}, // E1.0   [5] (🛁..🛅)    bathtub..left luggage
+	{0x1F6CC, 0x1F6CC, prEmojiPresentation}, // E1.0   [1] (🛌)       person in bed
+	{0x1F6D0, 0x1F6D0, prEmojiPresentation}, // E1.0   [1] (🛐)       place of worship
+	{0x1F6D1, 0x1F6D2, prEmojiPresentation}, // E3.0   [2] (🛑..🛒)    stop sign..shopping cart
+	{0x1F6D5, 0x1F6D5, prEmojiPresentation}, // E12.0  [1] (🛕)       hindu temple
+	{0x1F6D6, 0x1F6D7, prEmojiPresentation}, // E13.0  [2] (🛖..🛗)    hut..elevator
+	{0x1F6DD, 0x1F6DF, prEmojiPresentation}, // E14.0  [3] (🛝..🛟)    playground slide..ring buoy
+	{0x1F6EB, 0x1F6EC, prEmojiPresentation}, // E1.0   [2] (🛫..🛬)    airplane departure..airplane arrival
+	{0x1F6F4, 0x1F6F6, prEmojiPresentation}, // E3.0   [3] (🛴..🛶)    kick scooter..canoe
+	{0x1F6F7, 0x1F6F8, prEmojiPresentation}, // E5.0   [2] (🛷..🛸)    sled..flying saucer
+	{0x1F6F9, 0x1F6F9, prEmojiPresentation}, // E11.0  [1] (🛹)       skateboard
+	{0x1F6FA, 0x1F6FA, prEmojiPresentation}, // E12.0  [1] (🛺)       auto rickshaw
+	{0x1F6FB, 0x1F6FC, prEmojiPresentation}, // E13.0  [2] (🛻..🛼)    pickup truck..roller skate
+	{0x1F7E0, 0x1F7EB, prEmojiPresentation}, // E12.0 [12] (🟠..🟫)    orange circle..brown square
+	{0x1F7F0, 0x1F7F0, prEmojiPresentation}, // E14.0  [1] (🟰)       heavy equals sign
+	{0x1F90C, 0x1F90C, prEmojiPresentation}, // E13.0  [1] (🤌)       pinched fingers
+	{0x1F90D, 0x1F90F, prEmojiPresentation}, // E12.0  [3] (🤍..🤏)    white heart..pinching hand
+	{0x1F910, 0x1F918, prEmojiPresentation}, // E1.0   [9] (🤐..🤘)    zipper-mouth face..sign of the horns
+	{0x1F919, 0x1F91E, prEmojiPresentation}, // E3.0   [6] (🤙..🤞)    call me hand..crossed fingers
+	{0x1F91F, 0x1F91F, prEmojiPresentation}, // E5.0   [1] (🤟)       love-you gesture
+	{0x1F920, 0x1F927, prEmojiPresentation}, // E3.0   [8] (🤠..🤧)    cowboy hat face..sneezing face
+	{0x1F928, 0x1F92F, prEmojiPresentation}, // E5.0   [8] (🤨..🤯)    face with raised eyebrow..exploding head
+	{0x1F930, 0x1F930, prEmojiPresentation}, // E3.0   [1] (🤰)       pregnant woman
+	{0x1F931, 0x1F932, prEmojiPresentation}, // E5.0   [2] (🤱..🤲)    breast-feeding..palms up together
+	{0x1F933, 0x1F93A, prEmojiPresentation}, // E3.0   [8] (🤳..🤺)    selfie..person fencing
+	{0x1F93C, 0x1F93E, prEmojiPresentation}, // E3.0   [3] (🤼..🤾)    people wrestling..person playing handball
+	{0x1F93F, 0x1F93F, prEmojiPresentation}, // E12.0  [1] (🤿)       diving mask
+	{0x1F940, 0x1F945, prEmojiPresentation}, // E3.0   [6] (🥀..🥅)    wilted flower..goal net
+	{0x1F947, 0x1F94B, prEmojiPresentation}, // E3.0   [5] (🥇..🥋)    1st place medal..martial arts uniform
+	{0x1F94C, 0x1F94C, prEmojiPresentation}, // E5.0   [1] (🥌)       curling stone
+	{0x1F94D, 0x1F94F, prEmojiPresentation}, // E11.0  [3] (🥍..🥏)    lacrosse..flying disc
+	{0x1F950, 0x1F95E, prEmojiPresentation}, // E3.0  [15] (🥐..🥞)    croissant..pancakes
+	{0x1F95F, 0x1F96B, prEmojiPresentation}, // E5.0  [13] (🥟..🥫)    dumpling..canned food
+	{0x1F96C, 0x1F970, prEmojiPresentation}, // E11.0  [5] (🥬..🥰)    leafy green..smiling face with hearts
+	{0x1F971, 0x1F971, prEmojiPresentation}, // E12.0  [1] (🥱)       yawning face
+	{0x1F972, 0x1F972, prEmojiPresentation}, // E13.0  [1] (🥲)       smiling face with tear
+	{0x1F973, 0x1F976, prEmojiPresentation}, // E11.0  [4] (🥳..🥶)    partying face..cold face
+	{0x1F977, 0x1F978, prEmojiPresentation}, // E13.0  [2] (🥷..🥸)    ninja..disguised face
+	{0x1F979, 0x1F979, prEmojiPresentation}, // E14.0  [1] (🥹)       face holding back tears
+	{0x1F97A, 0x1F97A, prEmojiPresentation}, // E11.0  [1] (🥺)       pleading face
+	{0x1F97B, 0x1F97B, prEmojiPresentation}, // E12.0  [1] (🥻)       sari
+	{0x1F97C, 0x1F97F, prEmojiPresentation}, // E11.0  [4] (🥼..🥿)    lab coat..flat shoe
+	{0x1F980, 0x1F984, prEmojiPresentation}, // E1.0   [5] (🦀..🦄)    crab..unicorn
+	{0x1F985, 0x1F991, prEmojiPresentation}, // E3.0  [13] (🦅..🦑)    eagle..squid
+	{0x1F992, 0x1F997, prEmojiPresentation}, // E5.0   [6] (🦒..🦗)    giraffe..cricket
+	{0x1F998, 0x1F9A2, prEmojiPresentation}, // E11.0 [11] (🦘..🦢)    kangaroo..swan
+	{0x1F9A3, 0x1F9A4, prEmojiPresentation}, // E13.0  [2] (🦣..🦤)    mammoth..dodo
+	{0x1F9A5, 0x1F9AA, prEmojiPresentation}, // E12.0  [6] (🦥..🦪)    sloth..oyster
+	{0x1F9AB, 0x1F9AD, prEmojiPresentation}, // E13.0  [3] (🦫..🦭)    beaver..seal
+	{0x1F9AE, 0x1F9AF, prEmojiPresentation}, // E12.0  [2] (🦮..🦯)    guide dog..white cane
+	{0x1F9B0, 0x1F9B9, prEmojiPresentation}, // E11.0 [10] (🦰..🦹)    red hair..supervillain
+	{0x1F9BA, 0x1F9BF, prEmojiPresentation}, // E12.0  [6] (🦺..🦿)    safety vest..mechanical leg
+	{0x1F9C0, 0x1F9C0, prEmojiPresentation}, // E1.0   [1] (🧀)       cheese wedge
+	{0x1F9C1, 0x1F9C2, prEmojiPresentation}, // E11.0  [2] (🧁..🧂)    cupcake..salt
+	{0x1F9C3, 0x1F9CA, prEmojiPresentation}, // E12.0  [8] (🧃..🧊)    beverage box..ice
+	{0x1F9CB, 0x1F9CB, prEmojiPresentation}, // E13.0  [1] (🧋)       bubble tea
+	{0x1F9CC, 0x1F9CC, prEmojiPresentation}, // E14.0  [1] (🧌)       troll
+	{0x1F9CD, 0x1F9CF, prEmojiPresentation}, // E12.0  [3] (🧍..🧏)    person standing..deaf person
+	{0x1F9D0, 0x1F9E6, prEmojiPresentation}, // E5.0  [23] (🧐..🧦)    face with monocle..socks
+	{0x1F9E7, 0x1F9FF, prEmojiPresentation}, // E11.0 [25] (🧧..🧿)    red envelope..nazar amulet
+	{0x1FA70, 0x1FA73, prEmojiPresentation}, // E12.0  [4] (🩰..🩳)    ballet shoes..shorts
+	{0x1FA74, 0x1FA74, prEmojiPresentation}, // E13.0  [1] (🩴)       thong sandal
+	{0x1FA78, 0x1FA7A, prEmojiPresentation}, // E12.0  [3] (🩸..🩺)    drop of blood..stethoscope
+	{0x1FA7B, 0x1FA7C, prEmojiPresentation}, // E14.0  [2] (🩻..🩼)    x-ray..crutch
+	{0x1FA80, 0x1FA82, prEmojiPresentation}, // E12.0  [3] (🪀..🪂)    yo-yo..parachute
+	{0x1FA83, 0x1FA86, prEmojiPresentation}, // E13.0  [4] (🪃..🪆)    boomerang..nesting dolls
+	{0x1FA90, 0x1FA95, prEmojiPresentation}, // E12.0  [6] (🪐..🪕)    ringed planet..banjo
+	{0x1FA96, 0x1FAA8, prEmojiPresentation}, // E13.0 [19] (🪖..🪨)    military helmet..rock
+	{0x1FAA9, 0x1FAAC, prEmojiPresentation}, // E14.0  [4] (🪩..🪬)    mirror ball..hamsa
+	{0x1FAB0, 0x1FAB6, prEmojiPresentation}, // E13.0  [7] (🪰..🪶)    fly..feather
+	{0x1FAB7, 0x1FABA, prEmojiPresentation}, // E14.0  [4] (🪷..🪺)    lotus..nest with eggs
+	{0x1FAC0, 0x1FAC2, prEmojiPresentation}, // E13.0  [3] (🫀..🫂)    anatomical heart..people hugging
+	{0x1FAC3, 0x1FAC5, prEmojiPresentation}, // E14.0  [3] (🫃..🫅)    pregnant man..person with crown
+	{0x1FAD0, 0x1FAD6, prEmojiPresentation}, // E13.0  [7] (🫐..🫖)    blueberries..teapot
+	{0x1FAD7, 0x1FAD9, prEmojiPresentation}, // E14.0  [3] (🫗..🫙)    pouring liquid..jar
+	{0x1FAE0, 0x1FAE7, prEmojiPresentation}, // E14.0  [8] (🫠..🫧)    melting face..bubbles
+	{0x1FAF0, 0x1FAF6, prEmojiPresentation}, // E14.0  [7] (🫰..🫶)    hand with index finger and thumb crossed..heart hands
+}
diff --git a/vendor/github.com/rivo/uniseg/gen_properties.go b/vendor/github.com/rivo/uniseg/gen_properties.go
index 64512709e..999d5efdd 100644
--- a/vendor/github.com/rivo/uniseg/gen_properties.go
+++ b/vendor/github.com/rivo/uniseg/gen_properties.go
@@ -3,19 +3,22 @@
 // This program generates a property file in Go file from Unicode Character
 // Database auxiliary data files. The command line arguments are as follows:
 //
-//   1. The name of the Unicode data file (just the filename, without extension).
-//   2. The name of the locally generated Go file.
-//   3. The name of the slice mapping code points to properties.
-//   4. The name of the generator, for logging purposes.
-//   5. (Optional) Flags, comma-separated. The following flags are available:
-//        - "emojis": include emoji properties (Extended Pictographic only).
-//        - "gencat": include general category properties.
+//  1. The name of the Unicode data file (just the filename, without extension).
+//     Can be "-" (to skip) if the emoji flag is included.
+//  2. The name of the locally generated Go file.
+//  3. The name of the slice mapping code points to properties.
+//  4. The name of the generator, for logging purposes.
+//  5. (Optional) Flags, comma-separated. The following flags are available:
+//     - "emojis=<property>": include the specified emoji properties (e.g.
+//     "Extended_Pictographic").
+//     - "gencat": include general category properties.
 //
-//go:generate go run gen_properties.go auxiliary/GraphemeBreakProperty graphemeproperties.go graphemeCodePoints graphemes emojis
-//go:generate go run gen_properties.go auxiliary/WordBreakProperty wordproperties.go workBreakCodePoints words emojis
+//go:generate go run gen_properties.go auxiliary/GraphemeBreakProperty graphemeproperties.go graphemeCodePoints graphemes emojis=Extended_Pictographic
+//go:generate go run gen_properties.go auxiliary/WordBreakProperty wordproperties.go workBreakCodePoints words emojis=Extended_Pictographic
 //go:generate go run gen_properties.go auxiliary/SentenceBreakProperty sentenceproperties.go sentenceBreakCodePoints sentences
 //go:generate go run gen_properties.go LineBreak lineproperties.go lineBreakCodePoints lines gencat
 //go:generate go run gen_properties.go EastAsianWidth eastasianwidth.go eastAsianWidth eastasianwidth
+//go:generate go run gen_properties.go - emojipresentation.go emojiPresentation emojipresentation emojis=Emoji_Presentation
 package main
 
 import (
@@ -38,8 +41,8 @@ import (
 // We want to test against a specific version rather than the latest. When the
 // package is upgraded to a new version, change these to generate new tests.
 const (
-	gbpURL   = `https://www.unicode.org/Public/14.0.0/ucd/%s.txt`
-	emojiURL = `https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt`
+	propertyURL = `https://www.unicode.org/Public/14.0.0/ucd/%s.txt`
+	emojiURL    = `https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt`
 )
 
 // The regular expression for a line containing a code point range property.
@@ -55,20 +58,25 @@ func main() {
 	log.SetFlags(0)
 
 	// Parse flags.
-	flags := make(map[string]struct{})
+	flags := make(map[string]string)
 	if len(os.Args) >= 6 {
 		for _, flag := range strings.Split(os.Args[5], ",") {
-			flags[flag] = struct{}{}
+			flagFields := strings.Split(flag, "=")
+			if len(flagFields) == 1 {
+				flags[flagFields[0]] = "yes"
+			} else {
+				flags[flagFields[0]] = flagFields[1]
+			}
 		}
 	}
 
 	// Parse the text file and generate Go source code from it.
-	var emojis string
-	if _, ok := flags["emojis"]; ok {
-		emojis = emojiURL
-	}
 	_, includeGeneralCategory := flags["gencat"]
-	src, err := parse(fmt.Sprintf(gbpURL, os.Args[1]), emojis, includeGeneralCategory)
+	var mainURL string
+	if os.Args[1] != "-" {
+		mainURL = fmt.Sprintf(propertyURL, os.Args[1])
+	}
+	src, err := parse(mainURL, flags["emojis"], includeGeneralCategory)
 	if err != nil {
 		log.Fatal(err)
 	}
@@ -88,49 +96,57 @@ func main() {
 
 // parse parses the Unicode Properties text files located at the given URLs and
 // returns their equivalent Go source code to be used in the uniseg package. If
-// "emojiURL" is an empty string, no emoji code points will be included. If
+// "emojiProperty" is not an empty string, emoji code points for that emoji
+// property (e.g. "Extended_Pictographic") will be included. In those cases, you
+// may pass an empty "propertyURL" to skip parsing the main properties file. If
 // "includeGeneralCategory" is true, the Unicode General Category property will
 // be extracted from the comments and included in the output.
-func parse(gbpURL, emojiURL string, includeGeneralCategory bool) (string, error) {
+func parse(propertyURL, emojiProperty string, includeGeneralCategory bool) (string, error) {
+	if propertyURL == "" && emojiProperty == "" {
+		return "", errors.New("no properties to parse")
+	}
+
 	// Temporary buffer to hold properties.
 	var properties [][4]string
 
 	// Open the first URL.
-	log.Printf("Parsing %s", gbpURL)
-	res, err := http.Get(gbpURL)
-	if err != nil {
-		return "", err
-	}
-	in1 := res.Body
-	defer in1.Close()
-
-	// Parse it.
-	scanner := bufio.NewScanner(in1)
-	num := 0
-	for scanner.Scan() {
-		num++
-		line := strings.TrimSpace(scanner.Text())
-
-		// Skip comments and empty lines.
-		if strings.HasPrefix(line, "#") || line == "" {
-			continue
+	if propertyURL != "" {
+		log.Printf("Parsing %s", propertyURL)
+		res, err := http.Get(propertyURL)
+		if err != nil {
+			return "", err
 		}
+		in1 := res.Body
+		defer in1.Close()
 
-		// Everything else must be a code point range, a property and a comment.
-		from, to, property, comment, err := parseProperty(line)
-		if err != nil {
-			return "", fmt.Errorf("%s line %d: %v", os.Args[4], num, err)
+		// Parse it.
+		scanner := bufio.NewScanner(in1)
+		num := 0
+		for scanner.Scan() {
+			num++
+			line := strings.TrimSpace(scanner.Text())
+
+			// Skip comments and empty lines.
+			if strings.HasPrefix(line, "#") || line == "" {
+				continue
+			}
+
+			// Everything else must be a code point range, a property and a comment.
+			from, to, property, comment, err := parseProperty(line)
+			if err != nil {
+				return "", fmt.Errorf("%s line %d: %v", os.Args[4], num, err)
+			}
+			properties = append(properties, [4]string{from, to, property, comment})
+		}
+		if err := scanner.Err(); err != nil {
+			return "", err
 		}
-		properties = append(properties, [4]string{from, to, property, comment})
-	}
-	if err := scanner.Err(); err != nil {
-		return "", err
 	}
 
 	// Open the second URL.
-	if emojiURL != "" {
+	if emojiProperty != "" {
 		log.Printf("Parsing %s", emojiURL)
-		res, err = http.Get(emojiURL)
+		res, err := http.Get(emojiURL)
 		if err != nil {
 			return "", err
 		}
@@ -138,15 +154,15 @@ func parse(gbpURL, emojiURL string, includeGeneralCategory bool) (string, error)
 		defer in2.Close()
 
 		// Parse it.
-		scanner = bufio.NewScanner(in2)
-		num = 0
+		scanner := bufio.NewScanner(in2)
+		num := 0
 		for scanner.Scan() {
 			num++
 			line := scanner.Text()
 
 			// Skip comments, empty lines, and everything not containing
 			// "Extended_Pictographic".
-			if strings.HasPrefix(line, "#") || line == "" || !strings.Contains(line, "Extended_Pictographic") {
+			if strings.HasPrefix(line, "#") || line == "" || !strings.Contains(line, emojiProperty) {
 				continue
 			}
 
@@ -189,7 +205,7 @@ func parse(gbpURL, emojiURL string, includeGeneralCategory bool) (string, error)
 // Code generated via go generate from gen_properties.go. DO NOT EDIT.
 
 // ` + os.Args[3] + ` are taken from
-// ` + gbpURL + emojiComment + `
+// ` + propertyURL + emojiComment + `
 // on ` + time.Now().Format("January 2, 2006") + `. See https://www.unicode.org/license.html for the Unicode
 // license agreement.
 var ` + os.Args[3] + ` = [][` + strconv.Itoa(columns) + `]int{
diff --git a/vendor/github.com/rivo/uniseg/grapheme.go b/vendor/github.com/rivo/uniseg/grapheme.go
index 9aec08685..997abbefd 100644
--- a/vendor/github.com/rivo/uniseg/grapheme.go
+++ b/vendor/github.com/rivo/uniseg/grapheme.go
@@ -4,12 +4,14 @@ import "unicode/utf8"
 
 // Graphemes implements an iterator over Unicode grapheme clusters, or
 // user-perceived characters. While iterating, it also provides information
-// about word boundaries, sentence boundaries, and line breaks.
+// about word boundaries, sentence boundaries, line breaks, and monospace
+// character widths.
 //
 // After constructing the class via [NewGraphemes] for a given string "str",
-// [Next] is called for every grapheme cluster in a loop until it returns false.
-// Inside the loop, information about the grapheme cluster as well as boundary
-// information is available via the various methods (see examples below).
+// [Graphemes.Next] is called for every grapheme cluster in a loop until it
+// returns false. Inside the loop, information about the grapheme cluster as
+// well as boundary information and character width is available via the various
+// methods (see examples below).
 //
 // Using this class to iterate over a string is convenient but it is much slower
 // than using this package's [Step] or [StepString] functions or any of the
@@ -28,18 +30,18 @@ type Graphemes struct {
 	// string.
 	offset int
 
-	// The current boundary information of the Step() parser.
+	// The current boundary information of the [Step] parser.
 	boundaries int
 
-	// The current state of the Step() parser.
+	// The current state of the [Step] parser.
 	state int
 }
 
 // NewGraphemes returns a new grapheme cluster iterator.
-func NewGraphemes(s string) *Graphemes {
+func NewGraphemes(str string) *Graphemes {
 	return &Graphemes{
-		original:  s,
-		remaining: s,
+		original:  str,
+		remaining: str,
 		state:     -1,
 	}
 }
@@ -60,8 +62,8 @@ func (g *Graphemes) Next() bool {
 }
 
 // Runes returns a slice of runes (code points) which corresponds to the current
-// grapheme cluster. If the iterator is already past the end or [Next] has not
-// yet been called, nil is returned.
+// grapheme cluster. If the iterator is already past the end or [Graphemes.Next]
+// has not yet been called, nil is returned.
 func (g *Graphemes) Runes() []rune {
 	if g.state < 0 {
 		return nil
@@ -70,15 +72,15 @@ func (g *Graphemes) Runes() []rune {
 }
 
 // Str returns a substring of the original string which corresponds to the
-// current grapheme cluster. If the iterator is already past the end or [Next]
-// has not yet been called, an empty string is returned.
+// current grapheme cluster. If the iterator is already past the end or
+// [Graphemes.Next] has not yet been called, an empty string is returned.
 func (g *Graphemes) Str() string {
 	return g.cluster
 }
 
 // Bytes returns a byte slice which corresponds to the current grapheme cluster.
-// If the iterator is already past the end or [Next] has not yet been called,
-// nil is returned.
+// If the iterator is already past the end or [Graphemes.Next] has not yet been
+// called, nil is returned.
 func (g *Graphemes) Bytes() []byte {
 	if g.state < 0 {
 		return nil
@@ -90,8 +92,8 @@ func (g *Graphemes) Bytes() []byte {
 // positions into the original string. The first returned value "from" indexes
 // the first byte and the second returned value "to" indexes the first byte that
 // is not included anymore, i.e. str[from:to] is the current grapheme cluster of
-// the original string "str". If [Next] has not yet been called, both values are
-// 0. If the iterator is already past the end, both values are 1.
+// the original string "str". If [Graphemes.Next] has not yet been called, both
+// values are 0. If the iterator is already past the end, both values are 1.
 func (g *Graphemes) Positions() (int, int) {
 	if g.state == -1 {
 		return 0, 0
@@ -133,8 +135,16 @@ func (g *Graphemes) LineBreak() int {
 	return g.boundaries & MaskLine
 }
 
+// Width returns the monospace width of the current grapheme cluster.
+func (g *Graphemes) Width() int {
+	if g.state < 0 {
+		return 0
+	}
+	return g.boundaries >> ShiftWidth
+}
+
 // Reset puts the iterator into its initial state such that the next call to
-// [Next] sets it to the first grapheme cluster again.
+// [Graphemes.Next] sets it to the first grapheme cluster again.
 func (g *Graphemes) Reset() {
 	g.state = -1
 	g.offset = 0
@@ -153,6 +163,10 @@ func GraphemeClusterCount(s string) (n int) {
 	return
 }
 
+// The number of bits the grapheme property must be shifted to make place for
+// grapheme states.
+const shiftGraphemePropState = 4
+
 // FirstGraphemeCluster returns the first grapheme cluster found in the given
 // byte slice according to the rules of Unicode Standard Annex #29, Grapheme
 // Cluster Boundaries. This function can be called continuously to extract all
@@ -168,15 +182,15 @@ func GraphemeClusterCount(s string) (n int) {
 // "cluster" byte slice is the sub-slice of the input slice containing the
 // identified grapheme cluster.
 //
+// The returned width is the width of the grapheme cluster for most monospace
+// fonts where a value of 1 represents one character cell.
+//
 // Given an empty byte slice "b", the function returns nil values.
 //
 // While slightly less convenient than using the Graphemes class, this function
 // has much better performance and makes no allocations. It lends itself well to
 // large byte slices.
-//
-// The "reserved" return value is a placeholder for future functionality and may
-// be ignored for the time being.
-func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, reserved, newState int) {
+func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, newState int) {
 	// An empty byte slice returns nothing.
 	if len(b) == 0 {
 		return
@@ -185,34 +199,60 @@ func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, reserved,
 	// Extract the first rune.
 	r, length := utf8.DecodeRune(b)
 	if len(b) <= length { // If we're already past the end, there is nothing else to parse.
-		return b, nil, 0, grAny
+		var prop int
+		if state < 0 {
+			prop = property(graphemeCodePoints, r)
+		} else {
+			prop = state >> shiftGraphemePropState
+		}
+		return b, nil, runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
 	}
 
 	// If we don't know the state, determine it now.
+	var firstProp int
 	if state < 0 {
-		state, _ = transitionGraphemeState(state, r)
+		state, firstProp, _ = transitionGraphemeState(state, r)
+	} else {
+		firstProp = state >> shiftGraphemePropState
 	}
+	width += runeWidth(r, firstProp)
 
 	// Transition until we find a boundary.
-	var boundary bool
 	for {
+		var (
+			prop     int
+			boundary bool
+		)
+
 		r, l := utf8.DecodeRune(b[length:])
-		state, boundary = transitionGraphemeState(state, r)
+		state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)
 
 		if boundary {
-			return b[:length], b[length:], 0, state
+			return b[:length], b[length:], width, state | (prop << shiftGraphemePropState)
+		}
+
+		if r == vs16 {
+			width = 2
+		} else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL {
+			width += runeWidth(r, prop)
+		} else if firstProp == prExtendedPictographic {
+			if r == vs15 {
+				width = 1
+			} else {
+				width = 2
+			}
 		}
 
 		length += l
 		if len(b) <= length {
-			return b, nil, 0, grAny
+			return b, nil, width, grAny | (prop << shiftGraphemePropState)
 		}
 	}
 }
 
 // FirstGraphemeClusterInString is like [FirstGraphemeCluster] but its input and
 // outputs are strings.
-func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, reserved, newState int) {
+func FirstGraphemeClusterInString(str string, state int) (cluster, rest string, width, newState int) {
 	// An empty string returns nothing.
 	if len(str) == 0 {
 		return
@@ -221,27 +261,53 @@ func FirstGraphemeClusterInString(str string, state int) (cluster, rest string,
 	// Extract the first rune.
 	r, length := utf8.DecodeRuneInString(str)
 	if len(str) <= length { // If we're already past the end, there is nothing else to parse.
-		return str, "", 0, grAny
+		var prop int
+		if state < 0 {
+			prop = property(graphemeCodePoints, r)
+		} else {
+			prop = state >> shiftGraphemePropState
+		}
+		return str, "", runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
 	}
 
 	// If we don't know the state, determine it now.
+	var firstProp int
 	if state < 0 {
-		state, _ = transitionGraphemeState(state, r)
+		state, firstProp, _ = transitionGraphemeState(state, r)
+	} else {
+		firstProp = state >> shiftGraphemePropState
 	}
+	width += runeWidth(r, firstProp)
 
 	// Transition until we find a boundary.
-	var boundary bool
 	for {
+		var (
+			prop     int
+			boundary bool
+		)
+
 		r, l := utf8.DecodeRuneInString(str[length:])
-		state, boundary = transitionGraphemeState(state, r)
+		state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)
 
 		if boundary {
-			return str[:length], str[length:], 0, state
+			return str[:length], str[length:], width, state | (prop << shiftGraphemePropState)
+		}
+
+		if r == vs16 {
+			width = 2
+		} else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL {
+			width += runeWidth(r, prop)
+		} else if firstProp == prExtendedPictographic {
+			if r == vs15 {
+				width = 1
+			} else {
+				width = 2
+			}
 		}
 
 		length += l
 		if len(str) <= length {
-			return str, "", 0, grAny
+			return str, "", width, grAny | (prop << shiftGraphemePropState)
 		}
 	}
 }
diff --git a/vendor/github.com/rivo/uniseg/graphemeproperties.go b/vendor/github.com/rivo/uniseg/graphemeproperties.go
index a0c001689..a87d140bf 100644
--- a/vendor/github.com/rivo/uniseg/graphemeproperties.go
+++ b/vendor/github.com/rivo/uniseg/graphemeproperties.go
@@ -7,7 +7,7 @@ package uniseg
 // and
 // https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
 // ("Extended_Pictographic" only)
-// on July 25, 2022. See https://www.unicode.org/license.html for the Unicode
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
 // license agreement.
 var graphemeCodePoints = [][3]int{
 	{0x0000, 0x0009, prControl},                // Cc  [10] <control-0000>..<control-0009>
diff --git a/vendor/github.com/rivo/uniseg/graphemerules.go b/vendor/github.com/rivo/uniseg/graphemerules.go
index c8e07111c..907b30bd0 100644
--- a/vendor/github.com/rivo/uniseg/graphemerules.go
+++ b/vendor/github.com/rivo/uniseg/graphemerules.go
@@ -27,14 +27,14 @@ const (
 //
 // This map is queried as follows:
 //
-//   1. Find specific state + specific property. Stop if found.
-//   2. Find specific state + any property.
-//   3. Find any state + specific property.
-//   4. If only (2) or (3) (but not both) was found, stop.
-//   5. If both (2) and (3) were found, use state from (3) and breaking instruction
-//      from the transition with the lower rule number, prefer (3) if rule numbers
-//      are equal. Stop.
-//   6. Assume grAny and grBoundary.
+//  1. Find specific state + specific property. Stop if found.
+//  2. Find specific state + any property.
+//  3. Find any state + specific property.
+//  4. If only (2) or (3) (but not both) was found, stop.
+//  5. If both (2) and (3) were found, use state from (3) and breaking instruction
+//     from the transition with the lower rule number, prefer (3) if rule numbers
+//     are equal. Stop.
+//  6. Assume grAny and grBoundary.
 //
 // Unicode version 14.0.0.
 var grTransitions = map[[2]int][3]int{
@@ -92,22 +92,23 @@ var grTransitions = map[[2]int][3]int{
 }
 
 // transitionGraphemeState determines the new state of the grapheme cluster
-// parser given the current state and the next code point. It also returns
-// whether a cluster boundary was detected.
-func transitionGraphemeState(state int, r rune) (newState int, boundary bool) {
+// parser given the current state and the next code point. It also returns the
+// code point's grapheme property (the value mapped by the [graphemeCodePoints]
+// table) and whether a cluster boundary was detected.
+func transitionGraphemeState(state int, r rune) (newState, prop int, boundary bool) {
 	// Determine the property of the next character.
-	nextProperty := property(graphemeCodePoints, r)
+	prop = property(graphemeCodePoints, r)
 
 	// Find the applicable transition.
-	transition, ok := grTransitions[[2]int{state, nextProperty}]
+	transition, ok := grTransitions[[2]int{state, prop}]
 	if ok {
 		// We have a specific transition. We'll use it.
-		return transition[0], transition[1] == grBoundary
+		return transition[0], prop, transition[1] == grBoundary
 	}
 
 	// No specific transition found. Try the less specific ones.
 	transAnyProp, okAnyProp := grTransitions[[2]int{state, prAny}]
-	transAnyState, okAnyState := grTransitions[[2]int{grAny, nextProperty}]
+	transAnyState, okAnyState := grTransitions[[2]int{grAny, prop}]
 	if okAnyProp && okAnyState {
 		// Both apply. We'll use a mix (see comments for grTransitions).
 		newState = transAnyState[0]
@@ -120,7 +121,7 @@ func transitionGraphemeState(state int, r rune) (newState int, boundary bool) {
 
 	if okAnyProp {
 		// We only have a specific state.
-		return transAnyProp[0], transAnyProp[1] == grBoundary
+		return transAnyProp[0], prop, transAnyProp[1] == grBoundary
 		// This branch will probably never be reached because okAnyState will
 		// always be true given the current transition map. But we keep it here
 		// for future modifications to the transition map where this may not be
@@ -129,9 +130,9 @@ func transitionGraphemeState(state int, r rune) (newState int, boundary bool) {
 
 	if okAnyState {
 		// We only have a specific property.
-		return transAnyState[0], transAnyState[1] == grBoundary
+		return transAnyState[0], prop, transAnyState[1] == grBoundary
 	}
 
 	// No known transition. GB999: Any ÷ Any.
-	return grAny, true
+	return grAny, prop, true
 }
diff --git a/vendor/github.com/rivo/uniseg/line.go b/vendor/github.com/rivo/uniseg/line.go
index 03d1928c0..c0398cacf 100644
--- a/vendor/github.com/rivo/uniseg/line.go
+++ b/vendor/github.com/rivo/uniseg/line.go
@@ -13,7 +13,7 @@ import "unicode/utf8"
 //
 // The returned "segment" may not be broken into smaller parts, unless no other
 // breaking opportunities present themselves, in which case you may break by
-// grapheme clusters (using the FirstGraphemeCluster() function to determine the
+// grapheme clusters (using the [FirstGraphemeCluster] function to determine the
 // grapheme clusters).
 //
 // The "mustBreak" flag indicates whether you MUST break the line after the
@@ -42,7 +42,7 @@ import "unicode/utf8"
 //
 // Note also that this algorithm may break within grapheme clusters. This is
 // addressed in Section 8.2 Example 6 of UAX #14. To avoid this, you can use
-// the Step() function instead.
+// the [Step] function instead.
 func FirstLineSegment(b []byte, state int) (segment, rest []byte, mustBreak bool, newState int) {
 	// An empty byte slice returns nothing.
 	if len(b) == 0 {
@@ -114,7 +114,9 @@ func FirstLineSegmentInString(str string, state int) (segment, rest string, must
 }
 
 // HasTrailingLineBreak returns true if the last rune in the given byte slice is
-// one of the hard line break code points as defined in LB4 and LB5 of UAX #14.
+// one of the hard line break code points defined in LB4 and LB5 of [UAX #14].
+//
+// [UAX #14]: https://www.unicode.org/reports/tr14/#Algorithm
 func HasTrailingLineBreak(b []byte) bool {
 	r, _ := utf8.DecodeLastRune(b)
 	property, _ := propertyWithGenCat(lineBreakCodePoints, r)
diff --git a/vendor/github.com/rivo/uniseg/lineproperties.go b/vendor/github.com/rivo/uniseg/lineproperties.go
index 98948adf8..32169306e 100644
--- a/vendor/github.com/rivo/uniseg/lineproperties.go
+++ b/vendor/github.com/rivo/uniseg/lineproperties.go
@@ -4,7 +4,10 @@ package uniseg
 
 // lineBreakCodePoints are taken from
 // https://www.unicode.org/Public/14.0.0/ucd/LineBreak.txt
-// on July 25, 2022. See https://www.unicode.org/license.html for the Unicode
+// and
+// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
 // license agreement.
 var lineBreakCodePoints = [][4]int{
 	{0x0000, 0x0008, prCM, gcCc},     //     [9] <control-0000>..<control-0008>
diff --git a/vendor/github.com/rivo/uniseg/properties.go b/vendor/github.com/rivo/uniseg/properties.go
index 0bb3db62e..bc3c7bcf3 100644
--- a/vendor/github.com/rivo/uniseg/properties.go
+++ b/vendor/github.com/rivo/uniseg/properties.go
@@ -3,9 +3,9 @@ package uniseg
 // The Unicode properties as used in the various parsers. Only the ones needed
 // in the context of this package are included.
 const (
-	prXX  = 0    // Same as prAny.
-	prAny = iota // prAny must be 0.
-	prPrepend
+	prXX      = 0    // Same as prAny.
+	prAny     = iota // prAny must be 0.
+	prPrepend        // Grapheme properties must come first, to reduce the number of bits stored in the state vector.
 	prCR
 	prLF
 	prControl
@@ -86,6 +86,7 @@ const (
 	prW
 	prH
 	prF
+	prEmojiPresentation
 )
 
 // Unicode General Categories. Only the ones needed in the context of this
@@ -124,6 +125,12 @@ const (
 	gcCo
 )
 
+// Special code points.
+const (
+	vs15 = 0xfe0e // Variation Selector-15 (text presentation)
+	vs16 = 0xfe0f // Variation Selector-16 (emoji presentation)
+)
+
 // propertySearch performs a binary search on a property slice and returns the
 // entry whose range (start = first array element, end = second array element)
 // includes r, or an array of 0's if no such entry was found.
diff --git a/vendor/github.com/rivo/uniseg/sentenceproperties.go b/vendor/github.com/rivo/uniseg/sentenceproperties.go
index e6fe7254c..ba0cf2de1 100644
--- a/vendor/github.com/rivo/uniseg/sentenceproperties.go
+++ b/vendor/github.com/rivo/uniseg/sentenceproperties.go
@@ -4,7 +4,10 @@ package uniseg
 
 // sentenceBreakCodePoints are taken from
 // https://www.unicode.org/Public/14.0.0/ucd/auxiliary/SentenceBreakProperty.txt
-// on July 25, 2022. See https://www.unicode.org/license.html for the Unicode
+// and
+// https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
+// ("Extended_Pictographic" only)
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
 // license agreement.
 var sentenceBreakCodePoints = [][3]int{
 	{0x0009, 0x0009, prSp},        // Cc       <control-0009>
diff --git a/vendor/github.com/rivo/uniseg/step.go b/vendor/github.com/rivo/uniseg/step.go
index 8c515a966..55e7f1219 100644
--- a/vendor/github.com/rivo/uniseg/step.go
+++ b/vendor/github.com/rivo/uniseg/step.go
@@ -2,31 +2,37 @@ package uniseg
 
 import "unicode/utf8"
 
-// The bit masks used to extract boundary information returned by the Step()
-// function.
+// The bit masks used to extract boundary information returned by [Step].
 const (
 	MaskLine     = 3
 	MaskWord     = 4
 	MaskSentence = 8
 )
 
-// The bit positions by which boundary flags are shifted by the Step() function.
-// This must correspond to the Mask constants.
+// The number of bits to shift the boundary information returned by [Step] to
+// obtain the monospace width of the grapheme cluster.
+const ShiftWidth = 4
+
+// The bit positions by which boundary flags are shifted by the [Step] function.
+// These must correspond to the Mask constants.
 const (
 	shiftWord     = 2
 	shiftSentence = 3
+	// shiftwWidth is ShiftWidth above. No mask as these are always the remaining bits.
 )
 
-// The bit positions by which states are shifted by the Step() function. These
+// The bit positions by which states are shifted by the [Step] function. These
 // values must ensure state values defined for each of the boundary algorithms
-// don't overlap (and that they all still fit in a single int).
+// don't overlap (and that they all still fit in a single int). These must
+// correspond to the Mask constants.
 const (
 	shiftWordState     = 4
 	shiftSentenceState = 9
 	shiftLineState     = 13
+	shiftPropState     = 21 // No mask as these are always the remaining bits.
 )
 
-// The bit mask used to extract the state returned by the Step() function, after
+// The bit mask used to extract the state returned by the [Step] function, after
 // shifting. These values must correspond to the shift constants.
 const (
 	maskGraphemeState = 0xf
@@ -37,10 +43,11 @@ const (
 
 // Step returns the first grapheme cluster (user-perceived character) found in
 // the given byte slice. It also returns information about the boundary between
-// that grapheme cluster and the one following it. There are three types of
-// boundary information: word boundaries, sentence boundaries, and line breaks.
-// This function is therefore a combination of FirstGraphemeCluster(),
-// FirstWord(), FirstSentence(), and FirstLineSegment().
+// that grapheme cluster and the one following it as well as the monospace width
+// of the grapheme cluster. There are three types of boundary information: word
+// boundaries, sentence boundaries, and line breaks. This function is therefore
+// a combination of [FirstGraphemeCluster], [FirstWord], [FirstSentence], and
+// [FirstLineSegment].
 //
 // The "boundaries" return value can be evaluated as follows:
 //
@@ -54,6 +61,8 @@ const (
 //     boundary.
 //   - boundaries&MaskLine == LineCanBreak: You may or may not break the line at
 //     the boundary.
+//   - boundaries >> ShiftWidth: The width of the grapheme cluster for most
+//     monospace fonts where a value of 1 represents one character cell.
 //
 // This function can be called continuously to extract all grapheme clusters
 // from a byte slice, as illustrated in the examples below.
@@ -87,14 +96,20 @@ func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState i
 	// Extract the first rune.
 	r, length := utf8.DecodeRune(b)
 	if len(b) <= length { // If we're already past the end, there is nothing else to parse.
-		return b, nil, LineMustBreak | (1 << shiftWord) | (1 << shiftSentence), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState)
+		var prop int
+		if state < 0 {
+			prop = property(graphemeCodePoints, r)
+		} else {
+			prop = state >> shiftPropState
+		}
+		return b, nil, LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (runeWidth(r, prop) << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState) | (prop << shiftPropState)
 	}
 
 	// If we don't know the state, determine it now.
-	var graphemeState, wordState, sentenceState, lineState int
+	var graphemeState, wordState, sentenceState, lineState, firstProp int
 	remainder := b[length:]
 	if state < 0 {
-		graphemeState, _ = transitionGraphemeState(state, r)
+		graphemeState, firstProp, _ = transitionGraphemeState(state, r)
 		wordState, _ = transitionWordBreakState(state, r, remainder, "")
 		sentenceState, _ = transitionSentenceBreakState(state, r, remainder, "")
 		lineState, _ = transitionLineBreakState(state, r, remainder, "")
@@ -103,36 +118,51 @@ func Step(b []byte, state int) (cluster, rest []byte, boundaries int, newState i
 		wordState = (state >> shiftWordState) & maskWordState
 		sentenceState = (state >> shiftSentenceState) & maskSentenceState
 		lineState = (state >> shiftLineState) & maskLineState
+		firstProp = state >> shiftPropState
 	}
 
 	// Transition until we find a grapheme cluster boundary.
-	var (
-		graphemeBoundary, wordBoundary, sentenceBoundary bool
-		lineBreak                                        int
-	)
+	width := runeWidth(r, firstProp)
 	for {
+		var (
+			graphemeBoundary, wordBoundary, sentenceBoundary bool
+			lineBreak, prop                                  int
+		)
+
 		r, l := utf8.DecodeRune(remainder)
 		remainder = b[length+l:]
 
-		graphemeState, graphemeBoundary = transitionGraphemeState(graphemeState, r)
+		graphemeState, prop, graphemeBoundary = transitionGraphemeState(graphemeState, r)
 		wordState, wordBoundary = transitionWordBreakState(wordState, r, remainder, "")
 		sentenceState, sentenceBoundary = transitionSentenceBreakState(sentenceState, r, remainder, "")
 		lineState, lineBreak = transitionLineBreakState(lineState, r, remainder, "")
 
 		if graphemeBoundary {
-			boundary := lineBreak
+			boundary := lineBreak | (width << ShiftWidth)
 			if wordBoundary {
 				boundary |= 1 << shiftWord
 			}
 			if sentenceBoundary {
 				boundary |= 1 << shiftSentence
 			}
-			return b[:length], b[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState)
+			return b[:length], b[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState) | (prop << shiftPropState)
+		}
+
+		if r == vs16 {
+			width = 2
+		} else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL {
+			width += runeWidth(r, prop)
+		} else if firstProp == prExtendedPictographic {
+			if r == vs15 {
+				width = 1
+			} else {
+				width = 2
+			}
 		}
 
 		length += l
 		if len(b) <= length {
-			return b, nil, LineMustBreak | (1 << shiftWord) | (1 << shiftSentence), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState)
+			return b, nil, LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (width << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState) | (prop << shiftPropState)
 		}
 	}
 }
@@ -147,14 +177,15 @@ func StepString(str string, state int) (cluster, rest string, boundaries int, ne
 	// Extract the first rune.
 	r, length := utf8.DecodeRuneInString(str)
 	if len(str) <= length { // If we're already past the end, there is nothing else to parse.
-		return str, "", LineMustBreak | (1 << shiftWord) | (1 << shiftSentence), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState)
+		prop := property(graphemeCodePoints, r)
+		return str, "", LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (runeWidth(r, prop) << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState)
 	}
 
 	// If we don't know the state, determine it now.
-	var graphemeState, wordState, sentenceState, lineState int
+	var graphemeState, wordState, sentenceState, lineState, firstProp int
 	remainder := str[length:]
 	if state < 0 {
-		graphemeState, _ = transitionGraphemeState(state, r)
+		graphemeState, firstProp, _ = transitionGraphemeState(state, r)
 		wordState, _ = transitionWordBreakState(state, r, nil, remainder)
 		sentenceState, _ = transitionSentenceBreakState(state, r, nil, remainder)
 		lineState, _ = transitionLineBreakState(state, r, nil, remainder)
@@ -163,36 +194,51 @@ func StepString(str string, state int) (cluster, rest string, boundaries int, ne
 		wordState = (state >> shiftWordState) & maskWordState
 		sentenceState = (state >> shiftSentenceState) & maskSentenceState
 		lineState = (state >> shiftLineState) & maskLineState
+		firstProp = state >> shiftPropState
 	}
 
 	// Transition until we find a grapheme cluster boundary.
-	var (
-		graphemeBoundary, wordBoundary, sentenceBoundary bool
-		lineBreak                                        int
-	)
+	width := runeWidth(r, firstProp)
 	for {
+		var (
+			graphemeBoundary, wordBoundary, sentenceBoundary bool
+			lineBreak, prop                                  int
+		)
+
 		r, l := utf8.DecodeRuneInString(remainder)
 		remainder = str[length+l:]
 
-		graphemeState, graphemeBoundary = transitionGraphemeState(graphemeState, r)
+		graphemeState, prop, graphemeBoundary = transitionGraphemeState(graphemeState, r)
 		wordState, wordBoundary = transitionWordBreakState(wordState, r, nil, remainder)
 		sentenceState, sentenceBoundary = transitionSentenceBreakState(sentenceState, r, nil, remainder)
 		lineState, lineBreak = transitionLineBreakState(lineState, r, nil, remainder)
 
 		if graphemeBoundary {
-			boundary := lineBreak
+			boundary := lineBreak | (width << ShiftWidth)
 			if wordBoundary {
 				boundary |= 1 << shiftWord
 			}
 			if sentenceBoundary {
 				boundary |= 1 << shiftSentence
 			}
-			return str[:length], str[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState)
+			return str[:length], str[length:], boundary, graphemeState | (wordState << shiftWordState) | (sentenceState << shiftSentenceState) | (lineState << shiftLineState) | (prop << shiftPropState)
+		}
+
+		if r == vs16 {
+			width = 2
+		} else if firstProp != prExtendedPictographic && firstProp != prRegionalIndicator && firstProp != prL {
+			width += runeWidth(r, prop)
+		} else if firstProp == prExtendedPictographic {
+			if r == vs15 {
+				width = 1
+			} else {
+				width = 2
+			}
 		}
 
 		length += l
 		if len(str) <= length {
-			return str, "", LineMustBreak | (1 << shiftWord) | (1 << shiftSentence), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState)
+			return str, "", LineMustBreak | (1 << shiftWord) | (1 << shiftSentence) | (width << ShiftWidth), grAny | (wbAny << shiftWordState) | (sbAny << shiftSentenceState) | (lbAny << shiftLineState) | (prop << shiftPropState)
 		}
 	}
 }
diff --git a/vendor/github.com/rivo/uniseg/width.go b/vendor/github.com/rivo/uniseg/width.go
new file mode 100644
index 000000000..12a57cc2e
--- /dev/null
+++ b/vendor/github.com/rivo/uniseg/width.go
@@ -0,0 +1,54 @@
+package uniseg
+
+// runeWidth returns the monospace width for the given rune. The provided
+// grapheme property is a value mapped by the [graphemeCodePoints] table.
+//
+// Every rune has a width of 1, except for runes with the following properties
+// (evaluated in this order):
+//
+//   - Control, CR, LF, Extend, ZWJ: Width of 0
+//   - \u2e3a, TWO-EM DASH: Width of 3
+//   - \u2e3b, THREE-EM DASH: Width of 4
+//   - East-Asian width Fullwidth and Wide: Width of 2 (Ambiguous and Neutral
+//     have a width of 1)
+//   - Regional Indicator: Width of 2
+//   - Extended Pictographic: Width of 2, unless Emoji Presentation is "No".
+func runeWidth(r rune, graphemeProperty int) int {
+	switch graphemeProperty {
+	case prControl, prCR, prLF, prExtend, prZWJ:
+		return 0
+	case prRegionalIndicator:
+		return 2
+	case prExtendedPictographic:
+		if property(emojiPresentation, r) == prEmojiPresentation {
+			return 2
+		}
+		return 1
+	}
+
+	switch r {
+	case 0x2e3a:
+		return 3
+	case 0x2e3b:
+		return 4
+	}
+
+	switch property(eastAsianWidth, r) {
+	case prW, prF:
+		return 2
+	}
+
+	return 1
+}
+
+// StringWidth returns the monospace width for the given string, that is, the
+// number of same-size cells to be occupied by the string.
+func StringWidth(s string) (width int) {
+	state := -1
+	for len(s) > 0 {
+		var w int
+		_, s, w, state = FirstGraphemeClusterInString(s, state)
+		width += w
+	}
+	return
+}
diff --git a/vendor/github.com/rivo/uniseg/wordproperties.go b/vendor/github.com/rivo/uniseg/wordproperties.go
index 48697a433..805cc536c 100644
--- a/vendor/github.com/rivo/uniseg/wordproperties.go
+++ b/vendor/github.com/rivo/uniseg/wordproperties.go
@@ -7,7 +7,7 @@ package uniseg
 // and
 // https://unicode.org/Public/14.0.0/ucd/emoji/emoji-data.txt
 // ("Extended_Pictographic" only)
-// on July 25, 2022. See https://www.unicode.org/license.html for the Unicode
+// on September 10, 2022. See https://www.unicode.org/license.html for the Unicode
 // license agreement.
 var workBreakCodePoints = [][3]int{
 	{0x000A, 0x000A, prLF},                     // Cc       <control-000A>
@@ -624,8 +624,8 @@ var workBreakCodePoints = [][3]int{
 	{0x212A, 0x212D, prALetter},                // L&   [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
 	{0x212F, 0x2134, prALetter},                // L&   [6] SCRIPT SMALL E..SCRIPT SMALL O
 	{0x2135, 0x2138, prALetter},                // Lo   [4] ALEF SYMBOL..DALET SYMBOL
-	{0x2139, 0x2139, prALetter},                // L&       INFORMATION SOURCE
 	{0x2139, 0x2139, prExtendedPictographic},   // E0.6   [1] (ℹ️)       information
+	{0x2139, 0x2139, prALetter},                // L&       INFORMATION SOURCE
 	{0x213C, 0x213F, prALetter},                // L&   [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
 	{0x2145, 0x2149, prALetter},                // L&   [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
 	{0x214E, 0x214E, prALetter},                // L&       TURNED SMALL F
diff --git a/vendor/github.com/urfave/cli/v2/Makefile b/vendor/github.com/urfave/cli/v2/Makefile
index 3b0e5e0bb..797d093e9 100644
--- a/vendor/github.com/urfave/cli/v2/Makefile
+++ b/vendor/github.com/urfave/cli/v2/Makefile
@@ -4,8 +4,10 @@
 # are very important so that maintainers and contributors can focus their
 # attention on files that are primarily Go.
 
+GO_RUN_BUILD := go run internal/build/build.go
+
 .PHONY: all
-all: generate vet tag-test test check-binary-size tag-check-binary-size gfmrun v2diff
+all: generate vet tag-test test check-binary-size tag-check-binary-size gfmrun yamlfmt v2diff
 
 # NOTE: this is a special catch-all rule to run any of the commands
 # defined in internal/build/build.go with optional arguments passed
@@ -13,28 +15,12 @@ all: generate vet tag-test test check-binary-size tag-check-binary-size gfmrun v
 #
 #   $ make test GFLAGS='--packages cli'
 %:
-	go run internal/build/build.go $(GFLAGS) $* $(FLAGS)
-
-.PHONY: tag-test
-tag-test:
-	go run internal/build/build.go -tags urfave_cli_no_docs test
-
-.PHONY: tag-check-binary-size
-tag-check-binary-size:
-	go run internal/build/build.go -tags urfave_cli_no_docs check-binary-size
-
-.PHONY: gfmrun
-gfmrun:
-	go run internal/build/build.go gfmrun docs/v2/manual.md
+	$(GO_RUN_BUILD) $(GFLAGS) $* $(FLAGS)
 
 .PHONY: docs
 docs:
 	mkdocs build
 
-.PHONY: docs-deps
-docs-deps:
-	pip install -r mkdocs-requirements.txt
-
 .PHONY: serve-docs
 serve-docs:
 	mkdocs serve
diff --git a/vendor/github.com/urfave/cli/v2/app.go b/vendor/github.com/urfave/cli/v2/app.go
index 1d2f6e89a..2ffacd512 100644
--- a/vendor/github.com/urfave/cli/v2/app.go
+++ b/vendor/github.com/urfave/cli/v2/app.go
@@ -133,7 +133,6 @@ func compileTime() time.Time {
 func NewApp() *App {
 	return &App{
 		Name:         filepath.Base(os.Args[0]),
-		HelpName:     filepath.Base(os.Args[0]),
 		Usage:        "A new cli application",
 		UsageText:    "",
 		BashComplete: DefaultAppComplete,
diff --git a/vendor/github.com/urfave/cli/v2/context.go b/vendor/github.com/urfave/cli/v2/context.go
index dc0d1ef0e..0335849a1 100644
--- a/vendor/github.com/urfave/cli/v2/context.go
+++ b/vendor/github.com/urfave/cli/v2/context.go
@@ -105,6 +105,16 @@ func (cCtx *Context) Lineage() []*Context {
 	return lineage
 }
 
+// Count returns the num of occurences of this flag
+func (cCtx *Context) Count(name string) int {
+	if fs := cCtx.lookupFlagSet(name); fs != nil {
+		if cf, ok := fs.Lookup(name).Value.(Countable); ok {
+			return cf.Count()
+		}
+	}
+	return 0
+}
+
 // Value returns the value of the flag corresponding to `name`
 func (cCtx *Context) Value(name string) interface{} {
 	if fs := cCtx.lookupFlagSet(name); fs != nil {
diff --git a/vendor/github.com/urfave/cli/v2/flag-spec.yaml b/vendor/github.com/urfave/cli/v2/flag-spec.yaml
index 1c594d723..5c480bb09 100644
--- a/vendor/github.com/urfave/cli/v2/flag-spec.yaml
+++ b/vendor/github.com/urfave/cli/v2/flag-spec.yaml
@@ -1,59 +1,74 @@
 # NOTE: this file is used by the tool defined in
 # ./cmd/urfave-cli-genflags/main.go which uses the
 # `Spec` type that maps to this file structure.
-
 flag_types:
-  bool: {}
-  float64: {}
-  int64:
+  bool:
     struct_fields:
-      - { name: Base, type: int }
+      - name: Count
+        type: int
+        pointer: true
+  float64:
+  Float64Slice:
+    value_pointer: true
+    skip_interfaces:
+      - fmt.Stringer
   int:
     struct_fields:
-      - { name: Base, type: int }
-  time.Duration: {}
-  uint64:
-    struct_fields:
-      - { name: Base, type: int }
-  uint:
-    struct_fields:
-      - { name: Base, type: int }
-
-  string:
-    struct_fields:
-      - { name: TakesFile, type: bool }
-  Generic:
-    struct_fields:
-      - { name: TakesFile, type: bool }
-  Path:
-    struct_fields:
-      - { name: TakesFile, type: bool }
-
-  Float64Slice:
+      - name: Base
+        type: int
+  IntSlice:
     value_pointer: true
     skip_interfaces:
       - fmt.Stringer
+  int64:
+    struct_fields:
+      - name: Base
+        type: int
   Int64Slice:
     value_pointer: true
     skip_interfaces:
       - fmt.Stringer
-  IntSlice:
+  uint:
+    struct_fields:
+      - name: Base
+        type: int
+  UintSlice:
+    value_pointer: true
+    skip_interfaces:
+      - fmt.Stringer
+  uint64:
+    struct_fields:
+      - name: Base
+        type: int
+  Uint64Slice:
     value_pointer: true
     skip_interfaces:
       - fmt.Stringer
+  string:
+    struct_fields:
+      - name: TakesFile
+        type: bool
   StringSlice:
     value_pointer: true
     skip_interfaces:
       - fmt.Stringer
     struct_fields:
-      - { name: TakesFile, type: bool }
+      - name: TakesFile
+        type: bool
+  time.Duration:
   Timestamp:
     value_pointer: true
     struct_fields:
-      - { name: Layout, type: string }
-      - { name: Timezone, type: "*time.Location" }
-
-  # TODO: enable UintSlice
-  # UintSlice: {}
-  # TODO: enable Uint64Slice once #1334 lands
-  # Uint64Slice: {}
+      - name: Layout
+        type: string
+      - name: Timezone
+        type: "*time.Location"
+  Generic:
+    no_destination_pointer: true
+    struct_fields:
+      - name: TakesFile
+        type: bool
+  Path:
+    struct_fields:
+      - name: TakesFile
+        type: bool
diff --git a/vendor/github.com/urfave/cli/v2/flag.go b/vendor/github.com/urfave/cli/v2/flag.go
index 37c9fdab2..050bb4b1d 100644
--- a/vendor/github.com/urfave/cli/v2/flag.go
+++ b/vendor/github.com/urfave/cli/v2/flag.go
@@ -139,6 +139,12 @@ type CategorizableFlag interface {
 	GetCategory() string
 }
 
+// Countable is an interface to enable detection of flag values which support
+// repetitive flags
+type Countable interface {
+	Count() int
+}
+
 func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
 	set := flag.NewFlagSet(name, flag.ContinueOnError)
 
diff --git a/vendor/github.com/urfave/cli/v2/flag_bool.go b/vendor/github.com/urfave/cli/v2/flag_bool.go
index 3e19bde5b..cb937ae65 100644
--- a/vendor/github.com/urfave/cli/v2/flag_bool.go
+++ b/vendor/github.com/urfave/cli/v2/flag_bool.go
@@ -1,11 +1,63 @@
 package cli
 
 import (
+	"errors"
 	"flag"
 	"fmt"
 	"strconv"
 )
 
+// boolValue needs to implement the boolFlag internal interface in flag
+// to be able to capture bool fields and values
+//
+//	type boolFlag interface {
+//		  Value
+//		  IsBoolFlag() bool
+//	}
+type boolValue struct {
+	destination *bool
+	count       *int
+}
+
+func newBoolValue(val bool, p *bool, count *int) *boolValue {
+	*p = val
+	return &boolValue{
+		destination: p,
+		count:       count,
+	}
+}
+
+func (b *boolValue) Set(s string) error {
+	v, err := strconv.ParseBool(s)
+	if err != nil {
+		err = errors.New("parse error")
+		return err
+	}
+	*b.destination = v
+	if b.count != nil {
+		*b.count = *b.count + 1
+	}
+	return err
+}
+
+func (b *boolValue) Get() interface{} { return *b.destination }
+
+func (b *boolValue) String() string {
+	if b.destination != nil {
+		return strconv.FormatBool(*b.destination)
+	}
+	return strconv.FormatBool(false)
+}
+
+func (b *boolValue) IsBoolFlag() bool { return true }
+
+func (b *boolValue) Count() int {
+	if b.count != nil {
+		return *b.count
+	}
+	return 0
+}
+
 // TakesValue returns true of the flag takes a value, otherwise false
 func (f *BoolFlag) TakesValue() bool {
 	return false
@@ -60,12 +112,19 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) error {
 		f.HasBeenSet = true
 	}
 
+	count := f.Count
+	dest := f.Destination
+
+	if count == nil {
+		count = new(int)
+	}
+	if dest == nil {
+		dest = new(bool)
+	}
+
 	for _, name := range f.Names() {
-		if f.Destination != nil {
-			set.BoolVar(f.Destination, name, f.Value, f.Usage)
-			continue
-		}
-		set.Bool(name, f.Value, f.Usage)
+		value := newBoolValue(f.Value, dest, count)
+		set.Var(value, name, f.Usage)
 	}
 
 	return nil
diff --git a/vendor/github.com/urfave/cli/v2/flag_uint64_slice.go b/vendor/github.com/urfave/cli/v2/flag_uint64_slice.go
new file mode 100644
index 000000000..e60c3ea8a
--- /dev/null
+++ b/vendor/github.com/urfave/cli/v2/flag_uint64_slice.go
@@ -0,0 +1,203 @@
+package cli
+
+import (
+	"encoding/json"
+	"flag"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// Uint64Slice wraps []int64 to satisfy flag.Value
+type Uint64Slice struct {
+	slice      []uint64
+	hasBeenSet bool
+}
+
+// NewUint64Slice makes an *Uint64Slice with default values
+func NewUint64Slice(defaults ...uint64) *Uint64Slice {
+	return &Uint64Slice{slice: append([]uint64{}, defaults...)}
+}
+
+// clone allocate a copy of self object
+func (i *Uint64Slice) clone() *Uint64Slice {
+	n := &Uint64Slice{
+		slice:      make([]uint64, len(i.slice)),
+		hasBeenSet: i.hasBeenSet,
+	}
+	copy(n.slice, i.slice)
+	return n
+}
+
+// Set parses the value into an integer and appends it to the list of values
+func (i *Uint64Slice) Set(value string) error {
+	if !i.hasBeenSet {
+		i.slice = []uint64{}
+		i.hasBeenSet = true
+	}
+
+	if strings.HasPrefix(value, slPfx) {
+		// Deserializing assumes overwrite
+		_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice)
+		i.hasBeenSet = true
+		return nil
+	}
+
+	for _, s := range flagSplitMultiValues(value) {
+		tmp, err := strconv.ParseUint(strings.TrimSpace(s), 0, 64)
+		if err != nil {
+			return err
+		}
+
+		i.slice = append(i.slice, tmp)
+	}
+
+	return nil
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (i *Uint64Slice) String() string {
+	v := i.slice
+	if v == nil {
+		// treat nil the same as zero length non-nil
+		v = make([]uint64, 0)
+	}
+	str := fmt.Sprintf("%d", v)
+	str = strings.Replace(str, " ", ", ", -1)
+	str = strings.Replace(str, "[", "{", -1)
+	str = strings.Replace(str, "]", "}", -1)
+	return fmt.Sprintf("[]uint64%s", str)
+}
+
+// Serialize allows Uint64Slice to fulfill Serializer
+func (i *Uint64Slice) Serialize() string {
+	jsonBytes, _ := json.Marshal(i.slice)
+	return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
+}
+
+// Value returns the slice of ints set by this flag
+func (i *Uint64Slice) Value() []uint64 {
+	return i.slice
+}
+
+// Get returns the slice of ints set by this flag
+func (i *Uint64Slice) Get() interface{} {
+	return *i
+}
+
+// String returns a readable representation of this value
+// (for usage defaults)
+func (f *Uint64SliceFlag) String() string {
+	return withEnvHint(f.GetEnvVars(), f.stringify())
+}
+
+// TakesValue returns true of the flag takes a value, otherwise false
+func (f *Uint64SliceFlag) TakesValue() bool {
+	return true
+}
+
+// GetUsage returns the usage string for the flag
+func (f *Uint64SliceFlag) GetUsage() string {
+	return f.Usage
+}
+
+// GetCategory returns the category for the flag
+func (f *Uint64SliceFlag) GetCategory() string {
+	return f.Category
+}
+
+// GetValue returns the flags value as string representation and an empty
+// string if the flag takes no value at all.
+func (f *Uint64SliceFlag) GetValue() string {
+	if f.Value != nil {
+		return f.Value.String()
+	}
+	return ""
+}
+
+// GetDefaultText returns the default text for this flag
+func (f *Uint64SliceFlag) GetDefaultText() string {
+	if f.DefaultText != "" {
+		return f.DefaultText
+	}
+	return f.GetValue()
+}
+
+// GetEnvVars returns the env vars for this flag
+func (f *Uint64SliceFlag) GetEnvVars() []string {
+	return f.EnvVars
+}
+
+// Apply populates the flag given the flag set and environment
+func (f *Uint64SliceFlag) Apply(set *flag.FlagSet) error {
+	// apply any default
+	if f.Destination != nil && f.Value != nil {
+		f.Destination.slice = make([]uint64, len(f.Value.slice))
+		copy(f.Destination.slice, f.Value.slice)
+	}
+
+	// resolve setValue (what we will assign to the set)
+	var setValue *Uint64Slice
+	switch {
+	case f.Destination != nil:
+		setValue = f.Destination
+	case f.Value != nil:
+		setValue = f.Value.clone()
+	default:
+		setValue = new(Uint64Slice)
+	}
+
+	if val, source, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok && val != "" {
+		for _, s := range flagSplitMultiValues(val) {
+			if err := setValue.Set(strings.TrimSpace(s)); err != nil {
+				return fmt.Errorf("could not parse %q as uint64 slice value from %s for flag %s: %s", val, source, f.Name, err)
+			}
+		}
+
+		// Set this to false so that we reset the slice if we then set values from
+		// flags that have already been set by the environment.
+		setValue.hasBeenSet = false
+		f.HasBeenSet = true
+	}
+
+	for _, name := range f.Names() {
+		set.Var(setValue, name, f.Usage)
+	}
+
+	return nil
+}
+
+// Get returns the flag’s value in the given Context.
+func (f *Uint64SliceFlag) Get(ctx *Context) []uint64 {
+	return ctx.Uint64Slice(f.Name)
+}
+
+func (f *Uint64SliceFlag) stringify() string {
+	var defaultVals []string
+	if f.Value != nil && len(f.Value.Value()) > 0 {
+		for _, i := range f.Value.Value() {
+			defaultVals = append(defaultVals, strconv.FormatUint(i, 10))
+		}
+	}
+
+	return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
+}
+
+// Uint64Slice looks up the value of a local Uint64SliceFlag, returns
+// nil if not found
+func (cCtx *Context) Uint64Slice(name string) []uint64 {
+	if fs := cCtx.lookupFlagSet(name); fs != nil {
+		return lookupUint64Slice(name, fs)
+	}
+	return nil
+}
+
+func lookupUint64Slice(name string, set *flag.FlagSet) []uint64 {
+	f := set.Lookup(name)
+	if f != nil {
+		if slice, ok := unwrapFlagValue(f.Value).(*Uint64Slice); ok {
+			return slice.Value()
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/urfave/cli/v2/flag_uint_slice.go b/vendor/github.com/urfave/cli/v2/flag_uint_slice.go
new file mode 100644
index 000000000..350b29ccf
--- /dev/null
+++ b/vendor/github.com/urfave/cli/v2/flag_uint_slice.go
@@ -0,0 +1,214 @@
+package cli
+
+import (
+	"encoding/json"
+	"flag"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// UintSlice wraps []int to satisfy flag.Value
+type UintSlice struct {
+	slice      []uint
+	hasBeenSet bool
+}
+
+// NewUintSlice makes an *UintSlice with default values
+func NewUintSlice(defaults ...uint) *UintSlice {
+	return &UintSlice{slice: append([]uint{}, defaults...)}
+}
+
+// clone allocate a copy of self object
+func (i *UintSlice) clone() *UintSlice {
+	n := &UintSlice{
+		slice:      make([]uint, len(i.slice)),
+		hasBeenSet: i.hasBeenSet,
+	}
+	copy(n.slice, i.slice)
+	return n
+}
+
+// TODO: Consistently have specific Set function for Int64 and Float64 ?
+// SetInt directly adds an integer to the list of values
+func (i *UintSlice) SetUint(value uint) {
+	if !i.hasBeenSet {
+		i.slice = []uint{}
+		i.hasBeenSet = true
+	}
+
+	i.slice = append(i.slice, value)
+}
+
+// Set parses the value into an integer and appends it to the list of values
+func (i *UintSlice) Set(value string) error {
+	if !i.hasBeenSet {
+		i.slice = []uint{}
+		i.hasBeenSet = true
+	}
+
+	if strings.HasPrefix(value, slPfx) {
+		// Deserializing assumes overwrite
+		_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice)
+		i.hasBeenSet = true
+		return nil
+	}
+
+	for _, s := range flagSplitMultiValues(value) {
+		tmp, err := strconv.ParseUint(strings.TrimSpace(s), 0, 32)
+		if err != nil {
+			return err
+		}
+
+		i.slice = append(i.slice, uint(tmp))
+	}
+
+	return nil
+}
+
+// String returns a readable representation of this value (for usage defaults)
+func (i *UintSlice) String() string {
+	v := i.slice
+	if v == nil {
+		// treat nil the same as zero length non-nil
+		v = make([]uint, 0)
+	}
+	str := fmt.Sprintf("%d", v)
+	str = strings.Replace(str, " ", ", ", -1)
+	str = strings.Replace(str, "[", "{", -1)
+	str = strings.Replace(str, "]", "}", -1)
+	return fmt.Sprintf("[]uint%s", str)
+}
+
+// Serialize allows UintSlice to fulfill Serializer
+func (i *UintSlice) Serialize() string {
+	jsonBytes, _ := json.Marshal(i.slice)
+	return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
+}
+
+// Value returns the slice of ints set by this flag
+func (i *UintSlice) Value() []uint {
+	return i.slice
+}
+
+// Get returns the slice of ints set by this flag
+func (i *UintSlice) Get() interface{} {
+	return *i
+}
+
+// String returns a readable representation of this value
+// (for usage defaults)
+func (f *UintSliceFlag) String() string {
+	return withEnvHint(f.GetEnvVars(), f.stringify())
+}
+
+// TakesValue returns true of the flag takes a value, otherwise false
+func (f *UintSliceFlag) TakesValue() bool {
+	return true
+}
+
+// GetUsage returns the usage string for the flag
+func (f *UintSliceFlag) GetUsage() string {
+	return f.Usage
+}
+
+// GetCategory returns the category for the flag
+func (f *UintSliceFlag) GetCategory() string {
+	return f.Category
+}
+
+// GetValue returns the flags value as string representation and an empty
+// string if the flag takes no value at all.
+func (f *UintSliceFlag) GetValue() string {
+	if f.Value != nil {
+		return f.Value.String()
+	}
+	return ""
+}
+
+// GetDefaultText returns the default text for this flag
+func (f *UintSliceFlag) GetDefaultText() string {
+	if f.DefaultText != "" {
+		return f.DefaultText
+	}
+	return f.GetValue()
+}
+
+// GetEnvVars returns the env vars for this flag
+func (f *UintSliceFlag) GetEnvVars() []string {
+	return f.EnvVars
+}
+
+// Apply populates the flag given the flag set and environment
+func (f *UintSliceFlag) Apply(set *flag.FlagSet) error {
+	// apply any default
+	if f.Destination != nil && f.Value != nil {
+		f.Destination.slice = make([]uint, len(f.Value.slice))
+		copy(f.Destination.slice, f.Value.slice)
+	}
+
+	// resolve setValue (what we will assign to the set)
+	var setValue *UintSlice
+	switch {
+	case f.Destination != nil:
+		setValue = f.Destination
+	case f.Value != nil:
+		setValue = f.Value.clone()
+	default:
+		setValue = new(UintSlice)
+	}
+
+	if val, source, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok && val != "" {
+		for _, s := range flagSplitMultiValues(val) {
+			if err := setValue.Set(strings.TrimSpace(s)); err != nil {
+				return fmt.Errorf("could not parse %q as uint slice value from %s for flag %s: %s", val, source, f.Name, err)
+			}
+		}
+
+		// Set this to false so that we reset the slice if we then set values from
+		// flags that have already been set by the environment.
+		setValue.hasBeenSet = false
+		f.HasBeenSet = true
+	}
+
+	for _, name := range f.Names() {
+		set.Var(setValue, name, f.Usage)
+	}
+
+	return nil
+}
+
+// Get returns the flag’s value in the given Context.
+func (f *UintSliceFlag) Get(ctx *Context) []uint {
+	return ctx.UintSlice(f.Name)
+}
+
+func (f *UintSliceFlag) stringify() string {
+	var defaultVals []string
+	if f.Value != nil && len(f.Value.Value()) > 0 {
+		for _, i := range f.Value.Value() {
+			defaultVals = append(defaultVals, strconv.FormatUint(uint64(i), 10))
+		}
+	}
+
+	return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
+}
+
+// UintSlice looks up the value of a local UintSliceFlag, returns
+// nil if not found
+func (cCtx *Context) UintSlice(name string) []uint {
+	if fs := cCtx.lookupFlagSet(name); fs != nil {
+		return lookupUintSlice(name, fs)
+	}
+	return nil
+}
+
+func lookupUintSlice(name string, set *flag.FlagSet) []uint {
+	f := set.Lookup(name)
+	if f != nil {
+		if slice, ok := unwrapFlagValue(f.Value).(*UintSlice); ok {
+			return slice.Value()
+		}
+	}
+	return nil
+}
diff --git a/vendor/github.com/urfave/cli/v2/godoc-current.txt b/vendor/github.com/urfave/cli/v2/godoc-current.txt
index f3be3c039..fbeeb5fb8 100644
--- a/vendor/github.com/urfave/cli/v2/godoc-current.txt
+++ b/vendor/github.com/urfave/cli/v2/godoc-current.txt
@@ -49,8 +49,8 @@ AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
 
 COMMANDS:{{range .VisibleCategories}}{{if .Name}}
    {{.Name}}:{{range .VisibleCommands}}
-     {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}}
-   {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlagCategories}}
+     {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
+   {{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlagCategories}}
 
 GLOBAL OPTIONS:{{range .VisibleFlagCategories}}
    {{if .Name}}{{.Name}}
@@ -157,8 +157,8 @@ DESCRIPTION:
 
 COMMANDS:{{range .VisibleCategories}}{{if .Name}}
    {{.Name}}:{{range .VisibleCommands}}
-     {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}}
-   {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
+     {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
+     {{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
 
 OPTIONS:
    {{range .VisibleFlags}}{{.}}
@@ -300,6 +300,8 @@ type App struct {
 	CommandNotFound CommandNotFoundFunc
 	// Execute this function if a usage error occurs
 	OnUsageError OnUsageErrorFunc
+	// Execute this function when an invalid flag is accessed from the context
+	InvalidFlagAccessHandler InvalidFlagAccessFunc
 	// Compilation date
 	Compiled time.Time
 	// List of all authors who contributed
@@ -450,6 +452,8 @@ type BoolFlag struct {
 
 	Aliases []string
 	EnvVars []string
+
+	Count *int
 }
     BoolFlag is a flag with type bool
 
@@ -629,6 +633,9 @@ func (cCtx *Context) Args() Args
 func (cCtx *Context) Bool(name string) bool
     Bool looks up the value of a local BoolFlag, returns false if not found
 
+func (cCtx *Context) Count(name string) int
+    Count returns the num of occurences of this flag
+
 func (cCtx *Context) Duration(name string) time.Duration
     Duration looks up the value of a local DurationFlag, returns 0 if not found
 
@@ -698,9 +705,23 @@ func (cCtx *Context) Uint(name string) uint
 func (cCtx *Context) Uint64(name string) uint64
     Uint64 looks up the value of a local Uint64Flag, returns 0 if not found
 
+func (cCtx *Context) Uint64Slice(name string) []uint64
+    Uint64Slice looks up the value of a local Uint64SliceFlag, returns nil if
+    not found
+
+func (cCtx *Context) UintSlice(name string) []uint
+    UintSlice looks up the value of a local UintSliceFlag, returns nil if not
+    found
+
 func (cCtx *Context) Value(name string) interface{}
     Value returns the value of the flag corresponding to `name`
 
+type Countable interface {
+	Count() int
+}
+    Countable is an interface to enable detection of flag values which support
+    repetitive flags
+
 type DocGenerationFlag interface {
 	Flag
 
@@ -1064,7 +1085,7 @@ type GenericFlag struct {
 	HasBeenSet bool
 
 	Value       Generic
-	Destination *Generic
+	Destination Generic
 
 	Aliases []string
 	EnvVars []string
@@ -1420,6 +1441,10 @@ func (f *IntSliceFlag) String() string
 func (f *IntSliceFlag) TakesValue() bool
     TakesValue returns true of the flag takes a value, otherwise false
 
+type InvalidFlagAccessFunc func(*Context, string)
+    InvalidFlagAccessFunc is executed when an invalid flag is accessed from the
+    context.
+
 type MultiError interface {
 	error
 	Errors() []error
@@ -1899,6 +1924,89 @@ func (f *Uint64Flag) String() string
 func (f *Uint64Flag) TakesValue() bool
     TakesValue returns true of the flag takes a value, otherwise false
 
+type Uint64Slice struct {
+	// Has unexported fields.
+}
+    Uint64Slice wraps []int64 to satisfy flag.Value
+
+func NewUint64Slice(defaults ...uint64) *Uint64Slice
+    NewUint64Slice makes an *Uint64Slice with default values
+
+func (i *Uint64Slice) Get() interface{}
+    Get returns the slice of ints set by this flag
+
+func (i *Uint64Slice) Serialize() string
+    Serialize allows Uint64Slice to fulfill Serializer
+
+func (i *Uint64Slice) Set(value string) error
+    Set parses the value into an integer and appends it to the list of values
+
+func (i *Uint64Slice) String() string
+    String returns a readable representation of this value (for usage defaults)
+
+func (i *Uint64Slice) Value() []uint64
+    Value returns the slice of ints set by this flag
+
+type Uint64SliceFlag struct {
+	Name string
+
+	Category    string
+	DefaultText string
+	FilePath    string
+	Usage       string
+
+	Required   bool
+	Hidden     bool
+	HasBeenSet bool
+
+	Value       *Uint64Slice
+	Destination *Uint64Slice
+
+	Aliases []string
+	EnvVars []string
+}
+    Uint64SliceFlag is a flag with type *Uint64Slice
+
+func (f *Uint64SliceFlag) Apply(set *flag.FlagSet) error
+    Apply populates the flag given the flag set and environment
+
+func (f *Uint64SliceFlag) Get(ctx *Context) []uint64
+    Get returns the flag’s value in the given Context.
+
+func (f *Uint64SliceFlag) GetCategory() string
+    GetCategory returns the category for the flag
+
+func (f *Uint64SliceFlag) GetDefaultText() string
+    GetDefaultText returns the default text for this flag
+
+func (f *Uint64SliceFlag) GetEnvVars() []string
+    GetEnvVars returns the env vars for this flag
+
+func (f *Uint64SliceFlag) GetUsage() string
+    GetUsage returns the usage string for the flag
+
+func (f *Uint64SliceFlag) GetValue() string
+    GetValue returns the flags value as string representation and an empty
+    string if the flag takes no value at all.
+
+func (f *Uint64SliceFlag) IsRequired() bool
+    IsRequired returns whether or not the flag is required
+
+func (f *Uint64SliceFlag) IsSet() bool
+    IsSet returns whether or not the flag has been set through env or file
+
+func (f *Uint64SliceFlag) IsVisible() bool
+    IsVisible returns true if the flag is not hidden, otherwise false
+
+func (f *Uint64SliceFlag) Names() []string
+    Names returns the names of the flag
+
+func (f *Uint64SliceFlag) String() string
+    String returns a readable representation of this value (for usage defaults)
+
+func (f *Uint64SliceFlag) TakesValue() bool
+    TakesValue returns true of the flag takes a value, otherwise false
+
 type UintFlag struct {
 	Name string
 
@@ -1961,6 +2069,93 @@ func (f *UintFlag) String() string
 func (f *UintFlag) TakesValue() bool
     TakesValue returns true of the flag takes a value, otherwise false
 
+type UintSlice struct {
+	// Has unexported fields.
+}
+    UintSlice wraps []int to satisfy flag.Value
+
+func NewUintSlice(defaults ...uint) *UintSlice
+    NewUintSlice makes an *UintSlice with default values
+
+func (i *UintSlice) Get() interface{}
+    Get returns the slice of ints set by this flag
+
+func (i *UintSlice) Serialize() string
+    Serialize allows UintSlice to fulfill Serializer
+
+func (i *UintSlice) Set(value string) error
+    Set parses the value into an integer and appends it to the list of values
+
+func (i *UintSlice) SetUint(value uint)
+    TODO: Consistently have specific Set function for Int64 and Float64 ? SetInt
+    directly adds an integer to the list of values
+
+func (i *UintSlice) String() string
+    String returns a readable representation of this value (for usage defaults)
+
+func (i *UintSlice) Value() []uint
+    Value returns the slice of ints set by this flag
+
+type UintSliceFlag struct {
+	Name string
+
+	Category    string
+	DefaultText string
+	FilePath    string
+	Usage       string
+
+	Required   bool
+	Hidden     bool
+	HasBeenSet bool
+
+	Value       *UintSlice
+	Destination *UintSlice
+
+	Aliases []string
+	EnvVars []string
+}
+    UintSliceFlag is a flag with type *UintSlice
+
+func (f *UintSliceFlag) Apply(set *flag.FlagSet) error
+    Apply populates the flag given the flag set and environment
+
+func (f *UintSliceFlag) Get(ctx *Context) []uint
+    Get returns the flag’s value in the given Context.
+
+func (f *UintSliceFlag) GetCategory() string
+    GetCategory returns the category for the flag
+
+func (f *UintSliceFlag) GetDefaultText() string
+    GetDefaultText returns the default text for this flag
+
+func (f *UintSliceFlag) GetEnvVars() []string
+    GetEnvVars returns the env vars for this flag
+
+func (f *UintSliceFlag) GetUsage() string
+    GetUsage returns the usage string for the flag
+
+func (f *UintSliceFlag) GetValue() string
+    GetValue returns the flags value as string representation and an empty
+    string if the flag takes no value at all.
+
+func (f *UintSliceFlag) IsRequired() bool
+    IsRequired returns whether or not the flag is required
+
+func (f *UintSliceFlag) IsSet() bool
+    IsSet returns whether or not the flag has been set through env or file
+
+func (f *UintSliceFlag) IsVisible() bool
+    IsVisible returns true if the flag is not hidden, otherwise false
+
+func (f *UintSliceFlag) Names() []string
+    Names returns the names of the flag
+
+func (f *UintSliceFlag) String() string
+    String returns a readable representation of this value (for usage defaults)
+
+func (f *UintSliceFlag) TakesValue() bool
+    TakesValue returns true of the flag takes a value, otherwise false
+
 type VisibleFlag interface {
 	Flag
 
diff --git a/vendor/github.com/urfave/cli/v2/zz_generated.flags.go b/vendor/github.com/urfave/cli/v2/zz_generated.flags.go
index f5b73ba24..034ef35da 100644
--- a/vendor/github.com/urfave/cli/v2/zz_generated.flags.go
+++ b/vendor/github.com/urfave/cli/v2/zz_generated.flags.go
@@ -58,7 +58,7 @@ type GenericFlag struct {
 	HasBeenSet bool
 
 	Value       Generic
-	Destination *Generic
+	Destination Generic
 
 	Aliases []string
 	EnvVars []string
@@ -309,6 +309,86 @@ func (f *TimestampFlag) IsVisible() bool {
 	return !f.Hidden
 }
 
+// Uint64SliceFlag is a flag with type *Uint64Slice
+type Uint64SliceFlag struct {
+	Name string
+
+	Category    string
+	DefaultText string
+	FilePath    string
+	Usage       string
+
+	Required   bool
+	Hidden     bool
+	HasBeenSet bool
+
+	Value       *Uint64Slice
+	Destination *Uint64Slice
+
+	Aliases []string
+	EnvVars []string
+}
+
+// IsSet returns whether or not the flag has been set through env or file
+func (f *Uint64SliceFlag) IsSet() bool {
+	return f.HasBeenSet
+}
+
+// Names returns the names of the flag
+func (f *Uint64SliceFlag) Names() []string {
+	return FlagNames(f.Name, f.Aliases)
+}
+
+// IsRequired returns whether or not the flag is required
+func (f *Uint64SliceFlag) IsRequired() bool {
+	return f.Required
+}
+
+// IsVisible returns true if the flag is not hidden, otherwise false
+func (f *Uint64SliceFlag) IsVisible() bool {
+	return !f.Hidden
+}
+
+// UintSliceFlag is a flag with type *UintSlice
+type UintSliceFlag struct {
+	Name string
+
+	Category    string
+	DefaultText string
+	FilePath    string
+	Usage       string
+
+	Required   bool
+	Hidden     bool
+	HasBeenSet bool
+
+	Value       *UintSlice
+	Destination *UintSlice
+
+	Aliases []string
+	EnvVars []string
+}
+
+// IsSet returns whether or not the flag has been set through env or file
+func (f *UintSliceFlag) IsSet() bool {
+	return f.HasBeenSet
+}
+
+// Names returns the names of the flag
+func (f *UintSliceFlag) Names() []string {
+	return FlagNames(f.Name, f.Aliases)
+}
+
+// IsRequired returns whether or not the flag is required
+func (f *UintSliceFlag) IsRequired() bool {
+	return f.Required
+}
+
+// IsVisible returns true if the flag is not hidden, otherwise false
+func (f *UintSliceFlag) IsVisible() bool {
+	return !f.Hidden
+}
+
 // BoolFlag is a flag with type bool
 type BoolFlag struct {
 	Name string
@@ -327,6 +407,8 @@ type BoolFlag struct {
 
 	Aliases []string
 	EnvVars []string
+
+	Count *int
 }
 
 // String returns a readable representation of this value (for usage defaults)
diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go
index 0a54bdbcc..2cb9c408f 100644
--- a/vendor/golang.org/x/net/context/go17.go
+++ b/vendor/golang.org/x/net/context/go17.go
@@ -32,7 +32,7 @@ var DeadlineExceeded = context.DeadlineExceeded
 // call cancel as soon as the operations running in this Context complete.
 func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
 	ctx, f := context.WithCancel(parent)
-	return ctx, CancelFunc(f)
+	return ctx, f
 }
 
 // WithDeadline returns a copy of the parent context with the deadline adjusted
@@ -46,7 +46,7 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
 // call cancel as soon as the operations running in this Context complete.
 func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
 	ctx, f := context.WithDeadline(parent, deadline)
-	return ctx, CancelFunc(f)
+	return ctx, f
 }
 
 // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
diff --git a/vendor/golang.org/x/oauth2/jws/jws.go b/vendor/golang.org/x/oauth2/jws/jws.go
index 683d2d271..95015648b 100644
--- a/vendor/golang.org/x/oauth2/jws/jws.go
+++ b/vendor/golang.org/x/oauth2/jws/jws.go
@@ -178,5 +178,5 @@ func Verify(token string, key *rsa.PublicKey) error {
 
 	h := sha256.New()
 	h.Write([]byte(signedContent))
-	return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
+	return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString)
 }
diff --git a/vendor/golang.org/x/sys/unix/syscall.go b/vendor/golang.org/x/sys/unix/syscall.go
index 649fa8740..9916e5e85 100644
--- a/vendor/golang.org/x/sys/unix/syscall.go
+++ b/vendor/golang.org/x/sys/unix/syscall.go
@@ -29,8 +29,6 @@ import (
 	"bytes"
 	"strings"
 	"unsafe"
-
-	"golang.org/x/sys/internal/unsafeheader"
 )
 
 // ByteSliceFromString returns a NUL-terminated slice of bytes
@@ -82,12 +80,7 @@ func BytePtrToString(p *byte) string {
 		ptr = unsafe.Pointer(uintptr(ptr) + 1)
 	}
 
-	var s []byte
-	h := (*unsafeheader.Slice)(unsafe.Pointer(&s))
-	h.Data = unsafe.Pointer(p)
-	h.Len = n
-	h.Cap = n
-
+	s := unsafe.Slice((*byte)(unsafe.Pointer(p)), n)
 	return string(s)
 }
 
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go b/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
index 1596426b1..1259f6df5 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
@@ -7,11 +7,7 @@
 
 package unix
 
-import (
-	"unsafe"
-
-	"golang.org/x/sys/internal/unsafeheader"
-)
+import "unsafe"
 
 //sys	closedir(dir uintptr) (err error)
 //sys	readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
@@ -86,11 +82,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 		}
 
 		// Copy entry into return buffer.
-		var s []byte
-		hdr := (*unsafeheader.Slice)(unsafe.Pointer(&s))
-		hdr.Data = unsafe.Pointer(&entry)
-		hdr.Cap = reclen
-		hdr.Len = reclen
+		s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen)
 		copy(buf, s)
 
 		buf = buf[reclen:]
diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go
index 03fa546ec..8c6f4092a 100644
--- a/vendor/golang.org/x/sys/unix/syscall_solaris.go
+++ b/vendor/golang.org/x/sys/unix/syscall_solaris.go
@@ -750,8 +750,8 @@ type EventPort struct {
 	// we should handle things gracefully. To do so, we need to keep an extra
 	// reference to the cookie around until the event is processed
 	// thus the otherwise seemingly extraneous "cookies" map
-	// The key of this map is a pointer to the corresponding &fCookie.cookie
-	cookies map[*interface{}]*fileObjCookie
+	// The key of this map is a pointer to the corresponding fCookie
+	cookies map[*fileObjCookie]struct{}
 }
 
 // PortEvent is an abstraction of the port_event C struct.
@@ -778,7 +778,7 @@ func NewEventPort() (*EventPort, error) {
 		port:    port,
 		fds:     make(map[uintptr]*fileObjCookie),
 		paths:   make(map[string]*fileObjCookie),
-		cookies: make(map[*interface{}]*fileObjCookie),
+		cookies: make(map[*fileObjCookie]struct{}),
 	}
 	return e, nil
 }
@@ -799,6 +799,7 @@ func (e *EventPort) Close() error {
 	}
 	e.fds = nil
 	e.paths = nil
+	e.cookies = nil
 	return nil
 }
 
@@ -826,17 +827,16 @@ func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, coo
 	if _, found := e.paths[path]; found {
 		return fmt.Errorf("%v is already associated with this Event Port", path)
 	}
-	fobj, err := createFileObj(path, stat)
+	fCookie, err := createFileObjCookie(path, stat, cookie)
 	if err != nil {
 		return err
 	}
-	fCookie := &fileObjCookie{fobj, cookie}
-	_, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fobj)), events, (*byte)(unsafe.Pointer(&fCookie.cookie)))
+	_, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fCookie.fobj)), events, (*byte)(unsafe.Pointer(fCookie)))
 	if err != nil {
 		return err
 	}
 	e.paths[path] = fCookie
-	e.cookies[&fCookie.cookie] = fCookie
+	e.cookies[fCookie] = struct{}{}
 	return nil
 }
 
@@ -858,7 +858,7 @@ func (e *EventPort) DissociatePath(path string) error {
 	if err == nil {
 		// dissociate was successful, safe to delete the cookie
 		fCookie := e.paths[path]
-		delete(e.cookies, &fCookie.cookie)
+		delete(e.cookies, fCookie)
 	}
 	delete(e.paths, path)
 	return err
@@ -871,13 +871,16 @@ func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) erro
 	if _, found := e.fds[fd]; found {
 		return fmt.Errorf("%v is already associated with this Event Port", fd)
 	}
-	fCookie := &fileObjCookie{nil, cookie}
-	_, err := port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(&fCookie.cookie)))
+	fCookie, err := createFileObjCookie("", nil, cookie)
+	if err != nil {
+		return err
+	}
+	_, err = port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(fCookie)))
 	if err != nil {
 		return err
 	}
 	e.fds[fd] = fCookie
-	e.cookies[&fCookie.cookie] = fCookie
+	e.cookies[fCookie] = struct{}{}
 	return nil
 }
 
@@ -896,27 +899,31 @@ func (e *EventPort) DissociateFd(fd uintptr) error {
 	if err == nil {
 		// dissociate was successful, safe to delete the cookie
 		fCookie := e.fds[fd]
-		delete(e.cookies, &fCookie.cookie)
+		delete(e.cookies, fCookie)
 	}
 	delete(e.fds, fd)
 	return err
 }
 
-func createFileObj(name string, stat os.FileInfo) (*fileObj, error) {
-	fobj := new(fileObj)
-	bs, err := ByteSliceFromString(name)
-	if err != nil {
-		return nil, err
-	}
-	fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
-	s := stat.Sys().(*syscall.Stat_t)
-	fobj.Atim.Sec = s.Atim.Sec
-	fobj.Atim.Nsec = s.Atim.Nsec
-	fobj.Mtim.Sec = s.Mtim.Sec
-	fobj.Mtim.Nsec = s.Mtim.Nsec
-	fobj.Ctim.Sec = s.Ctim.Sec
-	fobj.Ctim.Nsec = s.Ctim.Nsec
-	return fobj, nil
+func createFileObjCookie(name string, stat os.FileInfo, cookie interface{}) (*fileObjCookie, error) {
+	fCookie := new(fileObjCookie)
+	fCookie.cookie = cookie
+	if name != "" && stat != nil {
+		fCookie.fobj = new(fileObj)
+		bs, err := ByteSliceFromString(name)
+		if err != nil {
+			return nil, err
+		}
+		fCookie.fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
+		s := stat.Sys().(*syscall.Stat_t)
+		fCookie.fobj.Atim.Sec = s.Atim.Sec
+		fCookie.fobj.Atim.Nsec = s.Atim.Nsec
+		fCookie.fobj.Mtim.Sec = s.Mtim.Sec
+		fCookie.fobj.Mtim.Nsec = s.Mtim.Nsec
+		fCookie.fobj.Ctim.Sec = s.Ctim.Sec
+		fCookie.fobj.Ctim.Nsec = s.Ctim.Nsec
+	}
+	return fCookie, nil
 }
 
 // GetOne wraps port_get(3c) and returns a single PortEvent.
@@ -929,44 +936,50 @@ func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {
 	p := new(PortEvent)
 	e.mu.Lock()
 	defer e.mu.Unlock()
-	e.peIntToExt(pe, p)
+	err = e.peIntToExt(pe, p)
+	if err != nil {
+		return nil, err
+	}
 	return p, nil
 }
 
 // peIntToExt converts a cgo portEvent struct into the friendlier PortEvent
 // NOTE: Always call this function while holding the e.mu mutex
-func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) {
+func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) error {
+	if e.cookies == nil {
+		return fmt.Errorf("this EventPort is already closed")
+	}
 	peExt.Events = peInt.Events
 	peExt.Source = peInt.Source
-	cookie := (*interface{})(unsafe.Pointer(peInt.User))
-	peExt.Cookie = *cookie
+	fCookie := (*fileObjCookie)(unsafe.Pointer(peInt.User))
+	_, found := e.cookies[fCookie]
+
+	if !found {
+		panic("unexpected event port address; may be due to kernel bug; see https://go.dev/issue/54254")
+	}
+	peExt.Cookie = fCookie.cookie
+	delete(e.cookies, fCookie)
+
 	switch peInt.Source {
 	case PORT_SOURCE_FD:
-		delete(e.cookies, cookie)
 		peExt.Fd = uintptr(peInt.Object)
 		// Only remove the fds entry if it exists and this cookie matches
 		if fobj, ok := e.fds[peExt.Fd]; ok {
-			if &fobj.cookie == cookie {
+			if fobj == fCookie {
 				delete(e.fds, peExt.Fd)
 			}
 		}
 	case PORT_SOURCE_FILE:
-		if fCookie, ok := e.cookies[cookie]; ok && uintptr(unsafe.Pointer(fCookie.fobj)) == uintptr(peInt.Object) {
-			// Use our stashed reference rather than using unsafe on what we got back
-			// the unsafe version would be (*fileObj)(unsafe.Pointer(uintptr(peInt.Object)))
-			peExt.fobj = fCookie.fobj
-		} else {
-			panic("unexpected event port address; may be due to kernel bug; see https://go.dev/issue/54254")
-		}
-		delete(e.cookies, cookie)
+		peExt.fobj = fCookie.fobj
 		peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name)))
 		// Only remove the paths entry if it exists and this cookie matches
 		if fobj, ok := e.paths[peExt.Path]; ok {
-			if &fobj.cookie == cookie {
+			if fobj == fCookie {
 				delete(e.paths, peExt.Path)
 			}
 		}
 	}
+	return nil
 }
 
 // Pending wraps port_getn(3c) and returns how many events are pending.
@@ -990,7 +1003,7 @@ func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error)
 	got := uint32(min)
 	max := uint32(len(s))
 	var err error
-	ps := make([]portEvent, max, max)
+	ps := make([]portEvent, max)
 	_, err = port_getn(e.port, &ps[0], max, &got, timeout)
 	// got will be trustworthy with ETIME, but not any other error.
 	if err != nil && err != ETIME {
@@ -998,8 +1011,18 @@ func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error)
 	}
 	e.mu.Lock()
 	defer e.mu.Unlock()
+	valid := 0
 	for i := 0; i < int(got); i++ {
-		e.peIntToExt(&ps[i], &s[i])
+		err2 := e.peIntToExt(&ps[i], &s[i])
+		if err2 != nil {
+			if valid == 0 && err == nil {
+				// If err2 is the only error and there are no valid events
+				// to return, return it to the caller.
+				err = err2
+			}
+			break
+		}
+		valid = i + 1
 	}
-	return int(got), err
+	return valid, err
 }
diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go
index 1ff5060b5..9f7535607 100644
--- a/vendor/golang.org/x/sys/unix/syscall_unix.go
+++ b/vendor/golang.org/x/sys/unix/syscall_unix.go
@@ -13,8 +13,6 @@ import (
 	"sync"
 	"syscall"
 	"unsafe"
-
-	"golang.org/x/sys/internal/unsafeheader"
 )
 
 var (
@@ -117,11 +115,7 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
 	}
 
 	// Use unsafe to convert addr into a []byte.
-	var b []byte
-	hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
-	hdr.Data = unsafe.Pointer(addr)
-	hdr.Cap = length
-	hdr.Len = length
+	b := unsafe.Slice((*byte)(unsafe.Pointer(addr)), length)
 
 	// Register mapping in m and return it.
 	p := &b[cap(b)-1]
diff --git a/vendor/golang.org/x/sys/unix/sysvshm_unix.go b/vendor/golang.org/x/sys/unix/sysvshm_unix.go
index 0bb4c8de5..5bb41d17b 100644
--- a/vendor/golang.org/x/sys/unix/sysvshm_unix.go
+++ b/vendor/golang.org/x/sys/unix/sysvshm_unix.go
@@ -7,11 +7,7 @@
 
 package unix
 
-import (
-	"unsafe"
-
-	"golang.org/x/sys/internal/unsafeheader"
-)
+import "unsafe"
 
 // SysvShmAttach attaches the Sysv shared memory segment associated with the
 // shared memory identifier id.
@@ -34,12 +30,7 @@ func SysvShmAttach(id int, addr uintptr, flag int) ([]byte, error) {
 	}
 
 	// Use unsafe to convert addr into a []byte.
-	// TODO: convert to unsafe.Slice once we can assume Go 1.17
-	var b []byte
-	hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
-	hdr.Data = unsafe.Pointer(addr)
-	hdr.Cap = int(info.Segsz)
-	hdr.Len = int(info.Segsz)
+	b := unsafe.Slice((*byte)(unsafe.Pointer(addr)), int(info.Segsz))
 	return b, nil
 }
 
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index e27913817..996cc53c0 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -364,6 +364,15 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 //sys	SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error)
 //sys	GetActiveProcessorCount(groupNumber uint16) (ret uint32)
 //sys	GetMaximumProcessorCount(groupNumber uint16) (ret uint32)
+//sys	EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows
+//sys	EnumChildWindows(hwnd HWND, enumFunc uintptr, param unsafe.Pointer) = user32.EnumChildWindows
+//sys	GetClassName(hwnd HWND, className *uint16, maxCount int32) (copied int32, err error) = user32.GetClassNameW
+//sys	GetDesktopWindow() (hwnd HWND) = user32.GetDesktopWindow
+//sys	GetForegroundWindow() (hwnd HWND) = user32.GetForegroundWindow
+//sys	IsWindow(hwnd HWND) (isWindow bool) = user32.IsWindow
+//sys	IsWindowUnicode(hwnd HWND) (isUnicode bool) = user32.IsWindowUnicode
+//sys	IsWindowVisible(hwnd HWND) (isVisible bool) = user32.IsWindowVisible
+//sys	GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) = user32.GetGUIThreadInfo
 
 // Volume Management Functions
 //sys	DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW
diff --git a/vendor/golang.org/x/sys/windows/types_windows.go b/vendor/golang.org/x/sys/windows/types_windows.go
index f9eaca528..ef489f546 100644
--- a/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/vendor/golang.org/x/sys/windows/types_windows.go
@@ -3213,3 +3213,22 @@ type ModuleInfo struct {
 }
 
 const ALL_PROCESSOR_GROUPS = 0xFFFF
+
+type Rect struct {
+	Left   int32
+	Top    int32
+	Right  int32
+	Bottom int32
+}
+
+type GUIThreadInfo struct {
+	Size        uint32
+	Flags       uint32
+	Active      HWND
+	Focus       HWND
+	Capture     HWND
+	MenuOwner   HWND
+	MoveSize    HWND
+	CaretHandle HWND
+	CaretRect   Rect
+}
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 52d4742cb..6c6f27ba5 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -444,9 +444,18 @@ var (
 	procCommandLineToArgvW                                   = modshell32.NewProc("CommandLineToArgvW")
 	procSHGetKnownFolderPath                                 = modshell32.NewProc("SHGetKnownFolderPath")
 	procShellExecuteW                                        = modshell32.NewProc("ShellExecuteW")
+	procEnumChildWindows                                     = moduser32.NewProc("EnumChildWindows")
+	procEnumWindows                                          = moduser32.NewProc("EnumWindows")
 	procExitWindowsEx                                        = moduser32.NewProc("ExitWindowsEx")
+	procGetClassNameW                                        = moduser32.NewProc("GetClassNameW")
+	procGetDesktopWindow                                     = moduser32.NewProc("GetDesktopWindow")
+	procGetForegroundWindow                                  = moduser32.NewProc("GetForegroundWindow")
+	procGetGUIThreadInfo                                     = moduser32.NewProc("GetGUIThreadInfo")
 	procGetShellWindow                                       = moduser32.NewProc("GetShellWindow")
 	procGetWindowThreadProcessId                             = moduser32.NewProc("GetWindowThreadProcessId")
+	procIsWindow                                             = moduser32.NewProc("IsWindow")
+	procIsWindowUnicode                                      = moduser32.NewProc("IsWindowUnicode")
+	procIsWindowVisible                                      = moduser32.NewProc("IsWindowVisible")
 	procMessageBoxW                                          = moduser32.NewProc("MessageBoxW")
 	procCreateEnvironmentBlock                               = moduserenv.NewProc("CreateEnvironmentBlock")
 	procDestroyEnvironmentBlock                              = moduserenv.NewProc("DestroyEnvironmentBlock")
@@ -3802,6 +3811,19 @@ func ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *ui
 	return
 }
 
+func EnumChildWindows(hwnd HWND, enumFunc uintptr, param unsafe.Pointer) {
+	syscall.Syscall(procEnumChildWindows.Addr(), 3, uintptr(hwnd), uintptr(enumFunc), uintptr(param))
+	return
+}
+
+func EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) {
+	r1, _, e1 := syscall.Syscall(procEnumWindows.Addr(), 2, uintptr(enumFunc), uintptr(param), 0)
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
 func ExitWindowsEx(flags uint32, reason uint32) (err error) {
 	r1, _, e1 := syscall.Syscall(procExitWindowsEx.Addr(), 2, uintptr(flags), uintptr(reason), 0)
 	if r1 == 0 {
@@ -3810,6 +3832,35 @@ func ExitWindowsEx(flags uint32, reason uint32) (err error) {
 	return
 }
 
+func GetClassName(hwnd HWND, className *uint16, maxCount int32) (copied int32, err error) {
+	r0, _, e1 := syscall.Syscall(procGetClassNameW.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(className)), uintptr(maxCount))
+	copied = int32(r0)
+	if copied == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func GetDesktopWindow() (hwnd HWND) {
+	r0, _, _ := syscall.Syscall(procGetDesktopWindow.Addr(), 0, 0, 0, 0)
+	hwnd = HWND(r0)
+	return
+}
+
+func GetForegroundWindow() (hwnd HWND) {
+	r0, _, _ := syscall.Syscall(procGetForegroundWindow.Addr(), 0, 0, 0, 0)
+	hwnd = HWND(r0)
+	return
+}
+
+func GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) {
+	r1, _, e1 := syscall.Syscall(procGetGUIThreadInfo.Addr(), 2, uintptr(thread), uintptr(unsafe.Pointer(info)), 0)
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
 func GetShellWindow() (shellWindow HWND) {
 	r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0)
 	shellWindow = HWND(r0)
@@ -3825,6 +3876,24 @@ func GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) {
 	return
 }
 
+func IsWindow(hwnd HWND) (isWindow bool) {
+	r0, _, _ := syscall.Syscall(procIsWindow.Addr(), 1, uintptr(hwnd), 0, 0)
+	isWindow = r0 != 0
+	return
+}
+
+func IsWindowUnicode(hwnd HWND) (isUnicode bool) {
+	r0, _, _ := syscall.Syscall(procIsWindowUnicode.Addr(), 1, uintptr(hwnd), 0, 0)
+	isUnicode = r0 != 0
+	return
+}
+
+func IsWindowVisible(hwnd HWND) (isVisible bool) {
+	r0, _, _ := syscall.Syscall(procIsWindowVisible.Addr(), 1, uintptr(hwnd), 0, 0)
+	isVisible = r0 != 0
+	return
+}
+
 func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) {
 	r0, _, e1 := syscall.Syscall6(procMessageBoxW.Addr(), 4, uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype), 0, 0)
 	ret = int32(r0)
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a7b4c3b6d..25b0e3a57 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -34,7 +34,7 @@ github.com/VictoriaMetrics/metricsql/binaryop
 # github.com/VividCortex/ewma v1.2.0
 ## explicit; go 1.12
 github.com/VividCortex/ewma
-# github.com/aws/aws-sdk-go v1.44.93
+# github.com/aws/aws-sdk-go v1.44.96
 ## explicit; go 1.11
 github.com/aws/aws-sdk-go/aws
 github.com/aws/aws-sdk-go/aws/arn
@@ -221,13 +221,13 @@ github.com/prometheus/prometheus/tsdb/record
 github.com/prometheus/prometheus/tsdb/tombstones
 github.com/prometheus/prometheus/tsdb/tsdbutil
 github.com/prometheus/prometheus/tsdb/wal
-# github.com/rivo/uniseg v0.3.4
+# github.com/rivo/uniseg v0.4.2
 ## explicit; go 1.18
 github.com/rivo/uniseg
 # github.com/russross/blackfriday/v2 v2.1.0
 ## explicit
 github.com/russross/blackfriday/v2
-# github.com/urfave/cli/v2 v2.14.1
+# github.com/urfave/cli/v2 v2.16.3
 ## explicit; go 1.18
 github.com/urfave/cli/v2
 # github.com/valyala/bytebufferpool v1.0.0
@@ -279,7 +279,7 @@ go.opencensus.io/trace/tracestate
 go.uber.org/atomic
 # go.uber.org/goleak v1.1.11-0.20210813005559-691160354723
 ## explicit; go 1.13
-# golang.org/x/net v0.0.0-20220907135653-1e95f45603a7
+# golang.org/x/net v0.0.0-20220909164309-bea034e7d591
 ## explicit; go 1.17
 golang.org/x/net/context
 golang.org/x/net/context/ctxhttp
@@ -291,7 +291,7 @@ golang.org/x/net/internal/socks
 golang.org/x/net/internal/timeseries
 golang.org/x/net/proxy
 golang.org/x/net/trace
-# golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
+# golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1
 ## explicit; go 1.17
 golang.org/x/oauth2
 golang.org/x/oauth2/authhandler
@@ -304,7 +304,7 @@ golang.org/x/oauth2/jwt
 # golang.org/x/sync v0.0.0-20220907140024-f12130a52804
 ## explicit
 golang.org/x/sync/errgroup
-# golang.org/x/sys v0.0.0-20220908150016-7ac13a9a928d
+# golang.org/x/sys v0.0.0-20220913120320-3275c407cedc
 ## explicit; go 1.17
 golang.org/x/sys/internal/unsafeheader
 golang.org/x/sys/unix
@@ -352,7 +352,7 @@ google.golang.org/appengine/internal/socket
 google.golang.org/appengine/internal/urlfetch
 google.golang.org/appengine/socket
 google.golang.org/appengine/urlfetch
-# google.golang.org/genproto v0.0.0-20220908141613-51c1cc9bc6d0
+# google.golang.org/genproto v0.0.0-20220909194730-69f6226f97e5
 ## explicit; go 1.19
 google.golang.org/genproto/googleapis/api/annotations
 google.golang.org/genproto/googleapis/iam/v1


Test patch:
diff --git a/app/vmalert/config/config_test.go b/app/vmalert/config/config_test.go
index 949f5ed1b..28b7f9db4 100644
--- a/app/vmalert/config/config_test.go
+++ b/app/vmalert/config/config_test.go
@@ -535,6 +535,21 @@ headers:
 rules:
   - alert: foo
     expr: sum by(job) (up == 1)
+`)
+	})
+
+	t.Run("`debug` change", func(t *testing.T) {
+		f(t, `
+name: TestGroup
+rules:
+  - alert: foo
+    expr: sum by(job) (up == 1)
+`, `
+name: TestGroup
+rules:
+  - alert: foo
+    expr: sum by(job) (up == 1)
+    debug: true
 `)
 	})
 }
diff --git a/app/vmalert/config/testdata/rules/rules2-good.rules b/app/vmalert/config/testdata/rules/rules2-good.rules
index 94b15bea9..615a085af 100644
--- a/app/vmalert/config/testdata/rules/rules2-good.rules
+++ b/app/vmalert/config/testdata/rules/rules2-good.rules
@@ -1,6 +1,6 @@
 groups:
   - name: TestGroup
-    interval: 2s
+    interval: 5s
     concurrency: 2
     limit: 1000
     headers:
@@ -11,6 +11,7 @@ groups:
       - alert: Conns
         expr: sum(vm_tcplistener_conns) by(instance) > 1
         for: 3m
+        debug: true
         annotations:
           summary: Too high connection number for {{$labels.instance}}
             {{ with printf "sum(vm_tcplistener_conns{instance=%q})" .Labels.instance | query }}
diff --git a/lib/storage/index_db_test.go b/lib/storage/index_db_test.go
index 5af5605a4..cd97a7f3a 100644
--- a/lib/storage/index_db_test.go
+++ b/lib/storage/index_db_test.go
@@ -2080,5 +2080,5 @@ func stopTestStorage(s *Storage) {
 	s.metricIDCache.Stop()
 	s.metricNameCache.Stop()
 	s.tsidCache.Stop()
-	fs.MustRemoveAll(s.cachePath)
+	fs.MustRemoveDirAtomic(s.cachePath)
 }