diff --git a/README.md b/README.md index 802405aba7..084367ee33 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,10 @@ VictoriaMetrics is available in [binary releases](https://github.com/VictoriaMet and [source code](https://github.com/VictoriaMetrics/VictoriaMetrics). Just download VictoriaMetrics and follow [these instructions](https://docs.victoriametrics.com/Quick-Start.html). -Cluster version of VictoriaMetrics is available [here](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html). +The cluster version of VictoriaMetrics is available [here](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html). -Learn more about [key concepts](https://docs.victoriametrics.com/keyConcepts.html) of VictoriaMetrics and follow -[QuickStart guide](https://docs.victoriametrics.com/Quick-Start.html) for better experience. +Learn more about [key concepts](https://docs.victoriametrics.com/keyConcepts.html) of VictoriaMetrics and follow the +[QuickStart guide](https://docs.victoriametrics.com/Quick-Start.html) for a better experience. [Contact us](mailto:info@victoriametrics.com) if you need enterprise support for VictoriaMetrics. See [features available in enterprise package](https://victoriametrics.com/products/enterprise/). @@ -32,8 +32,8 @@ from [the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/rele VictoriaMetrics has the following prominent features: * It can be used as long-term storage for Prometheus. See [these docs](#prometheus-setup) for details. -* It can be used as drop-in replacement for Prometheus in Grafana, because it supports [Prometheus querying API](#prometheus-querying-api-usage). -* It can be used as drop-in replacement for Graphite in Grafana, because it supports [Graphite API](#graphite-api-usage). +* It can be used as a drop-in replacement for Prometheus in Grafana, because it supports [Prometheus querying API](#prometheus-querying-api-usage). +* It can be used as a drop-in replacement for Graphite in Grafana, because it supports [Graphite API](#graphite-api-usage). * It features easy setup and operation: * VictoriaMetrics consists of a single [small executable](https://medium.com/@valyala/stripping-dependency-bloat-in-victoriametrics-docker-image-983fb5912b0d) without external dependencies. * All the configuration is done via explicit command-line flags with reasonable defaults. @@ -243,7 +243,9 @@ Prometheus doesn't drop data during VictoriaMetrics restart. See [this article]( ## vmui VictoriaMetrics provides UI for query troubleshooting and exploration. The UI is available at `http://victoriametrics:8428/vmui`. -The UI allows exploring query results via graphs and tables. Graphs support scrolling and zooming: +The UI allows exploring query results via graphs and tables. It also provides support for [cardinality explorer](#cardinality-explorer). + +Graphs in vmui support scrolling and zooming: * Drag the graph to the left / right in order to move the displayed time range into the past / future. * Hold `Ctrl` (or `Cmd` on MacOS) and scroll up / down in order to zoom in / out the graph. @@ -261,6 +263,23 @@ VMUI allows investigating correlations between two queries on the same graph. Ju See the [example VMUI at VictoriaMetrics playground](https://play.victoriametrics.com/select/accounting/1/6a716b0f-38bc-4856-90ce-448fd713e3fe/prometheus/graph/?g0.expr=100%20*%20sum(rate(process_cpu_seconds_total))%20by%20(job)&g0.range_input=1d). +## Cardinality explorer + +VictoriaMetrics provides an ability to explore time series cardinality at `cardinality` tab in [vmui](#vmui) in the following ways: + +- To identify metric names with the highest number of series. +- To identify label=name pairs with the highest number of series. +- To identify labels with the highest number of unique values. + +By default cardinality explorer analyzes time series for the current date. It provides the ability to select different day at the top right corner. +By default all the time series for the selected date are analyzed. It is possible to narrow down the analysis to series +matching the specified [series selector](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors). + +Cardinality explorer is built on top of [/api/v1/status/tsdb](#tsdb-stats). + +See [cardinality explorer playground](https://play.victoriametrics.com/select/accounting/1/6a716b0f-38bc-4856-90ce-448fd713e3fe/prometheus/graph/#/cardinality). + + ## How to apply new config to VictoriaMetrics VictoriaMetrics is configured via command-line flags, so it must be restarted when new command-line flags should be applied: @@ -824,6 +843,11 @@ Each JSON line contains samples for a single time series. An example output: Optional `start` and `end` args may be added to the request in order to limit the time frame for the exported data. These args may contain either unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) values. +For example: +```bash +curl http://:8428/api/v1/export -d 'match[]=' -d 'start=1654543486' -d 'end=1654543486' +curl http://:8428/api/v1/export -d 'match[]=' -d 'start=2022-06-06T19:25:48+00:00' -d 'end=2022-06-06T19:29:07+00:00' +``` Optional `max_rows_per_line` arg may be added to the request for limiting the maximum number of rows exported per each JSON line. Optional `reduce_mem_usage=1` arg may be added to the request for reducing memory usage when exporting big number of time series. @@ -863,6 +887,11 @@ for metrics to export. Optional `start` and `end` args may be added to the request in order to limit the time frame for the exported data. These args may contain either unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) values. +For example: +```bash +curl http://:8428/api/v1/export/csv -d 'format=' -d 'match[]=' -d 'start=1654543486' -d 'end=1654543486' +curl http://:8428/api/v1/export/csv -d 'format=' -d 'match[]=' -d 'start=2022-06-06T19:25:48+00:00' -d 'end=2022-06-06T19:29:07+00:00' +``` The exported CSV data can be imported to VictoriaMetrics via [/api/v1/import/csv](#how-to-import-csv-data). @@ -885,6 +914,11 @@ wget -O- -q 'http://your_victoriametrics_instance:8428/api/v1/series/count' | jq Optional `start` and `end` args may be added to the request in order to limit the time frame for the exported data. These args may contain either unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) values. +For example: +```bash +curl http://:8428/api/v1/export/native -d 'match[]=' -d 'start=1654543486' -d 'end=1654543486' +curl http://:8428/api/v1/export/native -d 'match[]=' -d 'start=2022-06-06T19:25:48+00:00' -d 'end=2022-06-06T19:29:07+00:00' +``` The exported data can be imported to VictoriaMetrics via [/api/v1/import/native](#how-to-import-data-in-native-format). The native export format may change in incompatible way between VictoriaMetrics releases, so the data exported from the release X @@ -1079,8 +1113,13 @@ VictoriaMetrics exports [Prometheus-compatible federation data](https://promethe at `http://:8428/federate?match[]=`. Optional `start` and `end` args may be added to the request in order to scrape the last point for each selected time series on the `[start ... end]` interval. -`start` and `end` may contain either unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) values. By default, the last point -on the interval `[now - max_lookback ... now]` is scraped for each time series. The default value for `max_lookback` is `5m` (5 minutes), but it can be overridden. +`start` and `end` may contain either unix timestamp in seconds or [RFC3339](https://www.ietf.org/rfc/rfc3339.txt) values. +For example: +```bash +curl http://:8428/federate -d 'match[]=' -d 'start=1654543486' -d 'end=1654543486' +curl http://:8428/federate -d 'match[]=' -d 'start=2022-06-06T19:25:48+00:00' -d 'end=2022-06-06T19:29:07+00:00' +``` +By default, the last point on the interval `[now - max_lookback ... now]` is scraped for each time series. The default value for `max_lookback` is `5m` (5 minutes), but it can be overridden with `max_lookback` query arg. For instance, `/federate?match[]=up&max_lookback=1h` would return last points on the `[now - 1h ... now]` interval. This may be useful for time series federation with scrape intervals exceeding `5m`. @@ -1187,9 +1226,18 @@ values and timestamps. These are sorted and compressed raw time series values. A index files for searching for specific series in the values and timestamps files. `Parts` are periodically merged into the bigger parts. The resulting `part` is constructed -under `<-storageDataPath>/data/{small,big}/YYYY_MM/tmp` subdirectory. When the resulting `part` is complete, it is atomically moved from the `tmp` +under `<-storageDataPath>/data/{small,big}/YYYY_MM/tmp` subdirectory. +When the resulting `part` is complete, it is atomically moved from the `tmp` to its own subdirectory, while the source parts are atomically removed. The end result is that the source parts are substituted by a single resulting bigger `part` in the `<-storageDataPath>/data/{small,big}/YYYY_MM/` directory. + +VictoriaMetrics doesn't merge parts if their summary size exceeds free disk space. +This prevents from potential out of disk space errors during merge. +The number of parts may significantly increase over time under free disk space shortage. +This increases overhead during data querying, since VictoriaMetrics needs to read data from +bigger number of parts per each request. That's why it is recommended to have at least 20% +of free disk space under directory pointed by `-storageDataPath` command-line flag. + Information about merging process is available in [single-node VictoriaMetrics](https://grafana.com/dashboards/10229) and [clustered VictoriaMetrics](https://grafana.com/grafana/dashboards/11176) Grafana dashboards. See more details in [monitoring docs](#monitoring). @@ -1259,7 +1307,7 @@ The downsampling can be evaluated for free by downloading and using enterprise b ## Multi-tenancy -Single-node VictoriaMetrics doesn't support multi-tenancy. Use [cluster version](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#multitenancy) instead. +Single-node VictoriaMetrics doesn't support multi-tenancy. Use the [cluster version](https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#multitenancy) instead. ## Scalability and cluster version @@ -1267,7 +1315,7 @@ Though single-node VictoriaMetrics cannot scale to multiple nodes, it is optimiz This means that a single-node VictoriaMetrics may scale vertically and substitute a moderately sized cluster built with competing solutions such as Thanos, Uber M3, InfluxDB or TimescaleDB. See [vertical scalability benchmarks](https://medium.com/@valyala/measuring-vertical-scalability-for-time-series-databases-in-google-cloud-92550d78d8ae). -So try single-node VictoriaMetrics at first and then [switch to cluster version](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/cluster) if you still need +So try single-node VictoriaMetrics at first and then [switch to the cluster version](https://github.com/VictoriaMetrics/VictoriaMetrics/tree/cluster) if you still need horizontally scalable long-term remote storage for really large Prometheus deployments. [Contact us](mailto:info@victoriametrics.com) for enterprise support. @@ -1342,7 +1390,7 @@ The most interesting metrics are: aka [active time series](https://docs.victoriametrics.com/FAQ.html#what-is-an-active-time-series). * `increase(vm_new_timeseries_created_total[1h])` - time series [churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate) during the previous hour. * `sum(vm_rows{type=~"storage/.*"})` - total number of `(timestamp, value)` data points in the database. -* `sum(rate(vm_rows_inserted_total[5m]))` - ingestion rate, i.e. how many samples are inserted int the database per second. +* `sum(rate(vm_rows_inserted_total[5m]))` - ingestion rate, i.e. how many samples are inserted in the database per second. * `vm_free_disk_space_bytes` - free space left at `-storageDataPath`. * `sum(vm_data_size_bytes)` - the total size of data on disk. * `increase(vm_slow_row_inserts_total[5m])` - the number of slow inserts during the last 5 minutes. @@ -1365,6 +1413,8 @@ VictoriaMetrics returns TSDB stats at `/api/v1/status/tsdb` page in the way simi * `match[]=SELECTOR` where `SELECTOR` is an arbitrary [time series selector](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors) for series to take into account during stats calculation. By default all the series are taken into account. * `extra_label=LABEL=VALUE`. See [these docs](#prometheus-querying-api-enhancements) for more details. +VictoriaMetrics provides an UI on top of `/api/v1/status/tsdb` - see [cardinality explorer docs](#cardinality-explorer). + ## Query tracing VictoriaMetrics supports query tracing, which can be used for determining bottlenecks during query processing. @@ -1375,7 +1425,7 @@ In this case VictoriaMetrics puts query trace into `trace` field in the output J For example, the following command: ```bash -curl http://localhost:8428/api/v1/query_range -d 'query=2*rand()' -d 'start=-1h' -d 'step=1m' -d 'trace=1' | jq -r '.trace' +curl http://localhost:8428/api/v1/query_range -d 'query=2*rand()' -d 'start=-1h' -d 'step=1m' -d 'trace=1' | jq '.trace' ``` would return the following trace: @@ -1502,7 +1552,7 @@ See also more advanced [cardinality limiter in vmagent](https://docs.victoriamet It may be needed in order to suppress default gap filling algorithm used by VictoriaMetrics - by default it assumes each time series is continuous instead of discrete, so it fills gaps between real samples with regular intervals. -* Metrics and labels leading to [high cardinality](https://docs.victoriametrics.com/FAQ.html#what-is-high-cardinality) or [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate) can be determined at `/api/v1/status/tsdb` page. See [these docs](#tsdb-stats) for details. +* Metrics and labels leading to [high cardinality](https://docs.victoriametrics.com/FAQ.html#what-is-high-cardinality) or [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate) can be determined via [cardinality explorer](#cardinality-explorer) and via [/api/v1/status/tsdb](#tsdb-stats) endpoint. * New time series can be logged if `-logNewSeries` command-line flag is passed to VictoriaMetrics. diff --git a/app/victoria-metrics/main.go b/app/victoria-metrics/main.go index d6df1469af..a6c56fbbdf 100644 --- a/app/victoria-metrics/main.go +++ b/app/victoria-metrics/main.go @@ -103,7 +103,8 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { fmt.Fprintf(w, "Useful endpoints:
") httpserver.WriteAPIHelp(w, [][2]string{ {"vmui", "Web UI"}, - {"targets", "discovered targets list"}, + {"targets", "status for discovered active targets"}, + {"service-discovery", "labels before and after relabeling for discovered targets"}, {"api/v1/targets", "advanced information about discovered targets in JSON format"}, {"config", "-promscrape.config contents"}, {"metrics", "available service metrics"}, diff --git a/app/vmagent/main.go b/app/vmagent/main.go index 311296cca5..5d019d8314 100644 --- a/app/vmagent/main.go +++ b/app/vmagent/main.go @@ -167,7 +167,8 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { fmt.Fprintf(w, "See docs at https://docs.victoriametrics.com/vmagent.html
") fmt.Fprintf(w, "Useful endpoints:
") httpserver.WriteAPIHelp(w, [][2]string{ - {"targets", "discovered targets list"}, + {"targets", "status for discovered active targets"}, + {"service-discovery", "labels before and after relabeling for discovered targets"}, {"api/v1/targets", "advanced information about discovered targets in JSON format"}, {"config", "-promscrape.config contents"}, {"metrics", "available service metrics"}, @@ -178,6 +179,11 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { } path := strings.Replace(r.URL.Path, "//", "/", -1) + if strings.HasPrefix(path, "datadog/") { + // Trim suffix from paths starting from /datadog/ in order to support legacy DataDog agent. + // See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2670 + path = strings.TrimSuffix(path, "/") + } switch path { case "/api/v1/write": prometheusWriteRequests.Inc() @@ -262,7 +268,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { w.WriteHeader(202) fmt.Fprintf(w, `{"status":"ok"}`) return true - case "/datadog/intake/": + case "/datadog/intake": datadogIntakeRequests.Inc() w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{}`) @@ -271,6 +277,10 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { promscrapeTargetsRequests.Inc() promscrape.WriteHumanReadableTargetsStatus(w, r) return true + case "/service-discovery": + promscrapeServiceDiscoveryRequests.Inc() + promscrape.WriteServiceDiscovery(w, r) + return true case "/target_response": promscrapeTargetResponseRequests.Inc() if err := promscrape.WriteTargetResponse(w, r); err != nil { @@ -356,6 +366,11 @@ func processMultitenantRequest(w http.ResponseWriter, r *http.Request, path stri httpserver.Errorf(w, r, "cannot obtain auth token: %s", err) return true } + if strings.HasPrefix(p.Suffix, "datadog/") { + // Trim suffix from paths starting from /datadog/ in order to support legacy DataDog agent. + // See https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2670 + p.Suffix = strings.TrimSuffix(p.Suffix, "/") + } switch p.Suffix { case "prometheus/", "prometheus", "prometheus/api/v1/write": prometheusWriteRequests.Inc() @@ -439,7 +454,7 @@ func processMultitenantRequest(w http.ResponseWriter, r *http.Request, path stri w.WriteHeader(202) fmt.Fprintf(w, `{"status":"ok"}`) return true - case "datadog/intake/": + case "datadog/intake": datadogIntakeRequests.Inc() w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{}`) @@ -476,10 +491,11 @@ var ( datadogValidateRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/datadog/api/v1/validate", protocol="datadog"}`) datadogCheckRunRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/datadog/api/v1/check_run", protocol="datadog"}`) - datadogIntakeRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/datadog/intake/", protocol="datadog"}`) + datadogIntakeRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/datadog/intake", protocol="datadog"}`) - promscrapeTargetsRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/targets"}`) - promscrapeAPIV1TargetsRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/api/v1/targets"}`) + promscrapeTargetsRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/targets"}`) + promscrapeServiceDiscoveryRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/service-discovery"}`) + promscrapeAPIV1TargetsRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/api/v1/targets"}`) promscrapeTargetResponseRequests = metrics.NewCounter(`vmagent_http_requests_total{path="/target_response"}`) promscrapeTargetResponseErrors = metrics.NewCounter(`vmagent_http_request_errors_total{path="/target_response"}`) diff --git a/app/vmagent/static/js/bootstrap.bundle.min.js b/app/vmagent/static/js/bootstrap.bundle.min.js deleted file mode 100644 index c19bf0afd3..0000000000 --- a/app/vmagent/static/js/bootstrap.bundle.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Bootstrap v5.0.2 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]}},e=t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t},i=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i="#"+i.split("#")[1]),e=i&&"#"!==i?i.trim():null}return e},n=t=>{const e=i(t);return e&&document.querySelector(e)?e:null},s=t=>{const e=i(t);return e?document.querySelector(e):null},o=t=>{t.dispatchEvent(new Event("transitionend"))},r=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),a=e=>r(e)?e.jquery?e[0]:e:"string"==typeof e&&e.length>0?t.findOne(e):null,l=(t,e,i)=>{Object.keys(i).forEach(n=>{const s=i[n],o=e[n],a=o&&r(o)?"element":null==(l=o)?""+l:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)})},c=t=>!(!r(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),h=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),d=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?d(t.parentNode):null},u=()=>{},f=t=>t.offsetHeight,p=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},m=[],g=()=>"rtl"===document.documentElement.dir,_=t=>{var e;e=()=>{const e=p();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",()=>{m.forEach(t=>t())}),m.push(e)):e()},b=t=>{"function"==typeof t&&t()},v=(t,e,i=!0)=>{if(!i)return void b(t);const n=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let s=!1;const r=({target:i})=>{i===e&&(s=!0,e.removeEventListener("transitionend",r),b(t))};e.addEventListener("transitionend",r),setTimeout(()=>{s||o(e)},n)},y=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},w=/[^.]*(?=\..*)\.|.*/,E=/\..*/,A=/::\d+$/,T={};let O=1;const C={mouseenter:"mouseover",mouseleave:"mouseout"},k=/^(mouseenter|mouseleave)/i,L=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function x(t,e){return e&&`${e}::${O++}`||t.uidEvent||O++}function D(t){const e=x(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function S(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=I(e,i,n),l=D(t),c=l[a]||(l[a]={}),h=S(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=x(r,e.replace(w,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function j(t,e,i,n,s){const o=S(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function M(t){return t=t.replace(E,""),C[t]||t}const P={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=I(e,i,n),a=r!==e,l=D(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void j(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach(i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach(o=>{if(o.includes(n)){const n=s[o];j(t,e,i,n.originalHandler,n.delegationSelector)}})}(t,l,i,e.slice(1))});const h=l[r]||{};Object.keys(h).forEach(i=>{const n=i.replace(A,"");if(!a||e.includes(n)){const e=h[i];j(t,l,r,e.originalHandler,e.delegationSelector)}})},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=p(),s=M(e),o=e!==s,r=L.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach(t=>{Object.defineProperty(d,t,{get:()=>i[t]})}),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},H=new Map;var R={set(t,e,i){H.has(t)||H.set(t,new Map);const n=H.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>H.has(t)&&H.get(t).get(e)||null,remove(t,e){if(!H.has(t))return;const i=H.get(t);i.delete(e),0===i.size&&H.delete(t)}};class B{constructor(t){(t=a(t))&&(this._element=t,R.set(this._element,this.constructor.DATA_KEY,this))}dispose(){R.remove(this._element,this.constructor.DATA_KEY),P.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach(t=>{this[t]=null})}_queueCallback(t,e,i=!0){v(t,e,i)}static getInstance(t){return R.get(t,this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.0.2"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return"bs."+this.NAME}static get EVENT_KEY(){return"."+this.DATA_KEY}}class W extends B{static get NAME(){return"alert"}close(t){const e=t?this._getRootElement(t):this._element,i=this._triggerCloseEvent(e);null===i||i.defaultPrevented||this._removeElement(e)}_getRootElement(t){return s(t)||t.closest(".alert")}_triggerCloseEvent(t){return P.trigger(t,"close.bs.alert")}_removeElement(t){t.classList.remove("show");const e=t.classList.contains("fade");this._queueCallback(()=>this._destroyElement(t),t,e)}_destroyElement(t){t.remove(),P.trigger(t,"closed.bs.alert")}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);"close"===t&&e[t](this)}))}static handleDismiss(t){return function(e){e&&e.preventDefault(),t.close(this)}}}P.on(document,"click.bs.alert.data-api",'[data-bs-dismiss="alert"]',W.handleDismiss(new W)),_(W);class q extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=q.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function z(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function $(t){return t.replace(/[A-Z]/g,t=>"-"+t.toLowerCase())}P.on(document,"click.bs.button.data-api",'[data-bs-toggle="button"]',t=>{t.preventDefault();const e=t.target.closest('[data-bs-toggle="button"]');q.getOrCreateInstance(e).toggle()}),_(q);const U={setDataAttribute(t,e,i){t.setAttribute("data-bs-"+$(e),i)},removeDataAttribute(t,e){t.removeAttribute("data-bs-"+$(e))},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter(t=>t.startsWith("bs")).forEach(i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=z(t.dataset[i])}),e},getDataAttribute:(t,e)=>z(t.getAttribute("data-bs-"+$(e))),offset(t){const e=t.getBoundingClientRect();return{top:e.top+document.body.scrollTop,left:e.left+document.body.scrollLeft}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},F={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},V={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},K="next",X="prev",Y="left",Q="right",G={ArrowLeft:Q,ArrowRight:Y};class Z extends B{constructor(e,i){super(e),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(i),this._indicatorsElement=t.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return F}static get NAME(){return"carousel"}next(){this._slide(K)}nextWhenVisible(){!document.hidden&&c(this._element)&&this.next()}prev(){this._slide(X)}pause(e){e||(this._isPaused=!0),t.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(o(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(e){this._activeElement=t.findOne(".active.carousel-item",this._element);const i=this._getItemIndex(this._activeElement);if(e>this._items.length-1||e<0)return;if(this._isSliding)return void P.one(this._element,"slid.bs.carousel",()=>this.to(e));if(i===e)return this.pause(),void this.cycle();const n=e>i?K:X;this._slide(n,this._items[e])}_getConfig(t){return t={...F,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},l("carousel",t,V),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?Q:Y)}_addEventListeners(){this._config.keyboard&&P.on(this._element,"keydown.bs.carousel",t=>this._keydown(t)),"hover"===this._config.pause&&(P.on(this._element,"mouseenter.bs.carousel",t=>this.pause(t)),P.on(this._element,"mouseleave.bs.carousel",t=>this.cycle(t))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const e=t=>{!this._pointerEvent||"pen"!==t.pointerType&&"touch"!==t.pointerType?this._pointerEvent||(this.touchStartX=t.touches[0].clientX):this.touchStartX=t.clientX},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=t=>{!this._pointerEvent||"pen"!==t.pointerType&&"touch"!==t.pointerType||(this.touchDeltaX=t.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(t=>this.cycle(t),500+this._config.interval))};t.find(".carousel-item img",this._element).forEach(t=>{P.on(t,"dragstart.bs.carousel",t=>t.preventDefault())}),this._pointerEvent?(P.on(this._element,"pointerdown.bs.carousel",t=>e(t)),P.on(this._element,"pointerup.bs.carousel",t=>n(t)),this._element.classList.add("pointer-event")):(P.on(this._element,"touchstart.bs.carousel",t=>e(t)),P.on(this._element,"touchmove.bs.carousel",t=>i(t)),P.on(this._element,"touchend.bs.carousel",t=>n(t)))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=G[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(e){return this._items=e&&e.parentNode?t.find(".carousel-item",e.parentNode):[],this._items.indexOf(e)}_getItemByOrder(t,e){const i=t===K;return y(this._items,e,i,this._config.wrap)}_triggerSlideEvent(e,i){const n=this._getItemIndex(e),s=this._getItemIndex(t.findOne(".active.carousel-item",this._element));return P.trigger(this._element,"slide.bs.carousel",{relatedTarget:e,direction:i,from:s,to:n})}_setActiveIndicatorElement(e){if(this._indicatorsElement){const i=t.findOne(".active",this._indicatorsElement);i.classList.remove("active"),i.removeAttribute("aria-current");const n=t.find("[data-bs-target]",this._indicatorsElement);for(let t=0;t{P.trigger(this._element,"slid.bs.carousel",{relatedTarget:r,direction:u,from:o,to:a})};if(this._element.classList.contains("slide")){r.classList.add(d),f(r),s.classList.add(h),r.classList.add(h);const t=()=>{r.classList.remove(h,d),r.classList.add("active"),s.classList.remove("active",d,h),this._isSliding=!1,setTimeout(p,0)};this._queueCallback(t,s,!0)}else s.classList.remove("active"),r.classList.add("active"),this._isSliding=!1,p();l&&this.cycle()}_directionToOrder(t){return[Q,Y].includes(t)?g()?t===Y?X:K:t===Y?K:X:t}_orderToDirection(t){return[K,X].includes(t)?g()?t===X?Y:Q:t===X?Q:Y:t}static carouselInterface(t,e){const i=Z.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){Z.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=s(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},n=this.getAttribute("data-bs-slide-to");n&&(i.interval=!1),Z.carouselInterface(e,i),n&&Z.getInstance(e).to(n),t.preventDefault()}}P.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",Z.dataApiClickHandler),P.on(window,"load.bs.carousel.data-api",()=>{const e=t.find('[data-bs-ride="carousel"]');for(let t=0,i=e.length;tt===this._element);null!==o&&r.length&&(this._selector=o,this._triggerArray.push(i))}this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}static get Default(){return J}static get NAME(){return"collapse"}toggle(){this._element.classList.contains("show")?this.hide():this.show()}show(){if(this._isTransitioning||this._element.classList.contains("show"))return;let e,i;this._parent&&(e=t.find(".show, .collapsing",this._parent).filter(t=>"string"==typeof this._config.parent?t.getAttribute("data-bs-parent")===this._config.parent:t.classList.contains("collapse")),0===e.length&&(e=null));const n=t.findOne(this._selector);if(e){const t=e.find(t=>n!==t);if(i=t?et.getInstance(t):null,i&&i._isTransitioning)return}if(P.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e&&e.forEach(t=>{n!==t&&et.collapseInterface(t,"hide"),i||R.set(t,"bs.collapse",null)});const s=this._getDimension();this._element.classList.remove("collapse"),this._element.classList.add("collapsing"),this._element.style[s]=0,this._triggerArray.length&&this._triggerArray.forEach(t=>{t.classList.remove("collapsed"),t.setAttribute("aria-expanded",!0)}),this.setTransitioning(!0);const o="scroll"+(s[0].toUpperCase()+s.slice(1));this._queueCallback(()=>{this._element.classList.remove("collapsing"),this._element.classList.add("collapse","show"),this._element.style[s]="",this.setTransitioning(!1),P.trigger(this._element,"shown.bs.collapse")},this._element,!0),this._element.style[s]=this._element[o]+"px"}hide(){if(this._isTransitioning||!this._element.classList.contains("show"))return;if(P.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=this._element.getBoundingClientRect()[t]+"px",f(this._element),this._element.classList.add("collapsing"),this._element.classList.remove("collapse","show");const e=this._triggerArray.length;if(e>0)for(let t=0;t{this.setTransitioning(!1),this._element.classList.remove("collapsing"),this._element.classList.add("collapse"),P.trigger(this._element,"hidden.bs.collapse")},this._element,!0)}setTransitioning(t){this._isTransitioning=t}_getConfig(t){return(t={...J,...t}).toggle=Boolean(t.toggle),l("collapse",t,tt),t}_getDimension(){return this._element.classList.contains("width")?"width":"height"}_getParent(){let{parent:e}=this._config;e=a(e);const i=`[data-bs-toggle="collapse"][data-bs-parent="${e}"]`;return t.find(i,e).forEach(t=>{const e=s(t);this._addAriaAndCollapsedClass(e,[t])}),e}_addAriaAndCollapsedClass(t,e){if(!t||!e.length)return;const i=t.classList.contains("show");e.forEach(t=>{i?t.classList.remove("collapsed"):t.classList.add("collapsed"),t.setAttribute("aria-expanded",i)})}static collapseInterface(t,e){let i=et.getInstance(t);const n={...J,...U.getDataAttributes(t),..."object"==typeof e&&e?e:{}};if(!i&&n.toggle&&"string"==typeof e&&/show|hide/.test(e)&&(n.toggle=!1),i||(i=new et(t,n)),"string"==typeof e){if(void 0===i[e])throw new TypeError(`No method named "${e}"`);i[e]()}}static jQueryInterface(t){return this.each((function(){et.collapseInterface(this,t)}))}}P.on(document,"click.bs.collapse.data-api",'[data-bs-toggle="collapse"]',(function(e){("A"===e.target.tagName||e.delegateTarget&&"A"===e.delegateTarget.tagName)&&e.preventDefault();const i=U.getDataAttributes(this),s=n(this);t.find(s).forEach(t=>{const e=et.getInstance(t);let n;e?(null===e._parent&&"string"==typeof i.parent&&(e._config.parent=i.parent,e._parent=e._getParent()),n="toggle"):n=i,et.collapseInterface(t,n)})})),_(et);var it="top",nt="bottom",st="right",ot="left",rt=[it,nt,st,ot],at=rt.reduce((function(t,e){return t.concat([e+"-start",e+"-end"])}),[]),lt=[].concat(rt,["auto"]).reduce((function(t,e){return t.concat([e,e+"-start",e+"-end"])}),[]),ct=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function ht(t){return t?(t.nodeName||"").toLowerCase():null}function dt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function ut(t){return t instanceof dt(t).Element||t instanceof Element}function ft(t){return t instanceof dt(t).HTMLElement||t instanceof HTMLElement}function pt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof dt(t).ShadowRoot||t instanceof ShadowRoot)}var mt={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];ft(s)&&ht(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});ft(n)&&ht(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function gt(t){return t.split("-")[0]}function _t(t){var e=t.getBoundingClientRect();return{width:e.width,height:e.height,top:e.top,right:e.right,bottom:e.bottom,left:e.left,x:e.left,y:e.top}}function bt(t){var e=_t(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function vt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&pt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function yt(t){return dt(t).getComputedStyle(t)}function wt(t){return["table","td","th"].indexOf(ht(t))>=0}function Et(t){return((ut(t)?t.ownerDocument:t.document)||window.document).documentElement}function At(t){return"html"===ht(t)?t:t.assignedSlot||t.parentNode||(pt(t)?t.host:null)||Et(t)}function Tt(t){return ft(t)&&"fixed"!==yt(t).position?t.offsetParent:null}function Ot(t){for(var e=dt(t),i=Tt(t);i&&wt(i)&&"static"===yt(i).position;)i=Tt(i);return i&&("html"===ht(i)||"body"===ht(i)&&"static"===yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&ft(t)&&"fixed"===yt(t).position)return null;for(var i=At(t);ft(i)&&["html","body"].indexOf(ht(i))<0;){var n=yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Ct(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var kt=Math.max,Lt=Math.min,xt=Math.round;function Dt(t,e,i){return kt(t,Lt(e,i))}function St(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function It(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}var Nt={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=gt(i.placement),l=Ct(a),c=[ot,st].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return St("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:It(t,rt))}(s.padding,i),d=bt(o),u="y"===l?it:ot,f="y"===l?nt:st,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=Ot(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=Dt(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&vt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]},jt={top:"auto",right:"auto",bottom:"auto",left:"auto"};function Mt(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.offsets,r=t.position,a=t.gpuAcceleration,l=t.adaptive,c=t.roundOffsets,h=!0===c?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:xt(xt(e*n)/n)||0,y:xt(xt(i*n)/n)||0}}(o):"function"==typeof c?c(o):o,d=h.x,u=void 0===d?0:d,f=h.y,p=void 0===f?0:f,m=o.hasOwnProperty("x"),g=o.hasOwnProperty("y"),_=ot,b=it,v=window;if(l){var y=Ot(i),w="clientHeight",E="clientWidth";y===dt(i)&&"static"!==yt(y=Et(i)).position&&(w="scrollHeight",E="scrollWidth"),y=y,s===it&&(b=nt,p-=y[w]-n.height,p*=a?1:-1),s===ot&&(_=st,u-=y[E]-n.width,u*=a?1:-1)}var A,T=Object.assign({position:r},l&&jt);return a?Object.assign({},T,((A={})[b]=g?"0":"",A[_]=m?"0":"",A.transform=(v.devicePixelRatio||1)<2?"translate("+u+"px, "+p+"px)":"translate3d("+u+"px, "+p+"px, 0)",A)):Object.assign({},T,((e={})[b]=g?p+"px":"",e[_]=m?u+"px":"",e.transform="",e))}var Pt={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:gt(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,Mt(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,Mt(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}},Ht={passive:!0},Rt={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=dt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,Ht)})),a&&l.addEventListener("resize",i.update,Ht),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,Ht)})),a&&l.removeEventListener("resize",i.update,Ht)}},data:{}},Bt={left:"right",right:"left",bottom:"top",top:"bottom"};function Wt(t){return t.replace(/left|right|bottom|top/g,(function(t){return Bt[t]}))}var qt={start:"end",end:"start"};function zt(t){return t.replace(/start|end/g,(function(t){return qt[t]}))}function $t(t){var e=dt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Ut(t){return _t(Et(t)).left+$t(t).scrollLeft}function Ft(t){var e=yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Vt(t,e){var i;void 0===e&&(e=[]);var n=function t(e){return["html","body","#document"].indexOf(ht(e))>=0?e.ownerDocument.body:ft(e)&&Ft(e)?e:t(At(e))}(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=dt(n),r=s?[o].concat(o.visualViewport||[],Ft(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Vt(At(r)))}function Kt(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Xt(t,e){return"viewport"===e?Kt(function(t){var e=dt(t),i=Et(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+Ut(t),y:a}}(t)):ft(e)?function(t){var e=_t(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Kt(function(t){var e,i=Et(t),n=$t(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=kt(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=kt(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Ut(t),l=-n.scrollTop;return"rtl"===yt(s||i).direction&&(a+=kt(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Et(t)))}function Yt(t){return t.split("-")[1]}function Qt(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?gt(s):null,r=s?Yt(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case it:e={x:a,y:i.y-n.height};break;case nt:e={x:a,y:i.y+i.height};break;case st:e={x:i.x+i.width,y:l};break;case ot:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Ct(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case"start":e[c]=e[c]-(i[h]/2-n[h]/2);break;case"end":e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function Gt(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?"clippingParents":o,a=i.rootBoundary,l=void 0===a?"viewport":a,c=i.elementContext,h=void 0===c?"popper":c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=St("number"!=typeof p?p:It(p,rt)),g="popper"===h?"reference":"popper",_=t.elements.reference,b=t.rects.popper,v=t.elements[u?g:h],y=function(t,e,i){var n="clippingParents"===e?function(t){var e=Vt(At(t)),i=["absolute","fixed"].indexOf(yt(t).position)>=0&&ft(t)?Ot(t):t;return ut(i)?e.filter((function(t){return ut(t)&&vt(t,i)&&"body"!==ht(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Xt(t,i);return e.top=kt(n.top,e.top),e.right=Lt(n.right,e.right),e.bottom=Lt(n.bottom,e.bottom),e.left=kt(n.left,e.left),e}),Xt(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}(ut(v)?v:v.contextElement||Et(t.elements.popper),r,l),w=_t(_),E=Qt({reference:w,element:b,strategy:"absolute",placement:s}),A=Kt(Object.assign({},b,E)),T="popper"===h?A:w,O={top:y.top-T.top+m.top,bottom:T.bottom-y.bottom+m.bottom,left:y.left-T.left+m.left,right:T.right-y.right+m.right},C=t.modifiersData.offset;if("popper"===h&&C){var k=C[s];Object.keys(O).forEach((function(t){var e=[st,nt].indexOf(t)>=0?1:-1,i=[it,nt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e}))}return O}function Zt(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?lt:l,h=Yt(n),d=h?a?at:at.filter((function(t){return Yt(t)===h})):rt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=Gt(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[gt(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}var Jt={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=gt(g),b=l||(_!==g&&p?function(t){if("auto"===gt(t))return[];var e=Wt(t);return[zt(t),e,zt(e)]}(g):[Wt(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat("auto"===gt(i)?Zt(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=Gt(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),I=x?L?st:ot:L?nt:it;y[D]>w[D]&&(I=Wt(I));var N=Wt(I),j=[];if(o&&j.push(S[k]<=0),a&&j.push(S[I]<=0,S[N]<=0),j.every((function(t){return t}))){T=C,A=!1;break}E.set(C,j)}if(A)for(var M=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},P=p?3:1;P>0&&"break"!==M(P);P--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function te(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ee(t){return[it,st,nt,ot].some((function(e){return t[e]>=0}))}var ie={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=Gt(e,{elementContext:"reference"}),a=Gt(e,{altBoundary:!0}),l=te(r,n),c=te(a,s,o),h=ee(l),d=ee(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},ne={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=gt(t),s=[ot,it].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[ot,st].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},se={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Qt({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},oe={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=Gt(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=gt(e.placement),b=Yt(e.placement),v=!b,y=Ct(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?it:ot,L="y"===y?nt:st,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],I=E[y]-g[L],N=f?-T[x]/2:0,j="start"===b?A[x]:T[x],M="start"===b?-T[x]:-A[x],P=e.elements.arrow,H=f&&P?bt(P):{width:0,height:0},R=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},B=R[k],W=R[L],q=Dt(0,A[x],H[x]),z=v?A[x]/2-N-q-B-O:j-q-B-O,$=v?-A[x]/2+N+q+W+O:M+q+W+O,U=e.elements.arrow&&Ot(e.elements.arrow),F=U?"y"===y?U.clientTop||0:U.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-F,X=E[y]+$-V;if(o){var Y=Dt(f?Lt(S,K):S,D,f?kt(I,X):I);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?it:ot,G="x"===y?nt:st,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=Dt(f?Lt(J,K):J,Z,f?kt(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function re(t,e,i){void 0===i&&(i=!1);var n,s,o=Et(e),r=_t(t),a=ft(e),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(a||!a&&!i)&&(("body"!==ht(e)||Ft(o))&&(l=(n=e)!==dt(n)&&ft(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:$t(n)),ft(e)?((c=_t(e)).x+=e.clientLeft,c.y+=e.clientTop):o&&(c.x=Ut(o))),{x:r.left+l.scrollLeft-c.x,y:r.top+l.scrollTop-c.y,width:r.width,height:r.height}}var ae={placement:"bottom",modifiers:[],strategy:"absolute"};function le(){for(var t=arguments.length,e=new Array(t),i=0;i"applyStyles"===t.name&&!1===t.enabled);this._popper=ue(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}"ontouchstart"in document.documentElement&&!t.closest(".navbar-nav")&&[].concat(...document.body.children).forEach(t=>P.on(t,"mouseover",u)),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.toggle("show"),this._element.classList.toggle("show"),P.trigger(this._element,"shown.bs.dropdown",e)}}hide(){if(h(this._element)||!this._menu.classList.contains("show"))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_addEventListeners(){P.on(this._element,"click.bs.dropdown",t=>{t.preventDefault(),this.toggle()})}_completeHide(t){P.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",u)),this._popper&&this._popper.destroy(),this._menu.classList.remove("show"),this._element.classList.remove("show"),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),P.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},l("dropdown",t,this.constructor.DefaultType),"object"==typeof t.reference&&!r(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError("dropdown".toUpperCase()+': Option "reference" provided type "object" without a required "getBoundingClientRect" method.');return t}_getMenuElement(){return t.next(this._element,".dropdown-menu")[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ve;if(t.classList.contains("dropstart"))return ye;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ge:me:e?be:_e}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:e,target:i}){const n=t.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(c);n.length&&y(n,i,"ArrowDown"===e,!n.includes(i)).focus()}static dropdownInterface(t,e){const i=Ae.getOrCreateInstance(t,e);if("string"==typeof e){if(void 0===i[e])throw new TypeError(`No method named "${e}"`);i[e]()}}static jQueryInterface(t){return this.each((function(){Ae.dropdownInterface(this,t)}))}static clearMenus(e){if(e&&(2===e.button||"keyup"===e.type&&"Tab"!==e.key))return;const i=t.find('[data-bs-toggle="dropdown"]');for(let t=0,n=i.length;tthis.matches('[data-bs-toggle="dropdown"]')?this:t.prev(this,'[data-bs-toggle="dropdown"]')[0];return"Escape"===e.key?(n().focus(),void Ae.clearMenus()):"ArrowUp"===e.key||"ArrowDown"===e.key?(i||n().click(),void Ae.getInstance(n())._selectMenuItem(e)):void(i&&"Space"!==e.key||Ae.clearMenus())}}P.on(document,"keydown.bs.dropdown.data-api",'[data-bs-toggle="dropdown"]',Ae.dataApiKeydownHandler),P.on(document,"keydown.bs.dropdown.data-api",".dropdown-menu",Ae.dataApiKeydownHandler),P.on(document,"click.bs.dropdown.data-api",Ae.clearMenus),P.on(document,"keyup.bs.dropdown.data-api",Ae.clearMenus),P.on(document,"click.bs.dropdown.data-api",'[data-bs-toggle="dropdown"]',(function(t){t.preventDefault(),Ae.dropdownInterface(this)})),_(Ae);class Te{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",e=>e+t),this._setElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight",e=>e+t),this._setElementAttributes(".sticky-top","marginRight",e=>e-t)}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=i(Number.parseFloat(s))+"px"})}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight"),this._resetElementAttributes(".sticky-top","marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)})}_applyManipulationCallback(e,i){r(e)?i(e):t.find(e,this._element).forEach(i)}isOverflowing(){return this.getWidth()>0}}const Oe={isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},Ce={isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"};class ke{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&f(this._getElement()),this._getElement().classList.add("show"),this._emulateAnimation(()=>{b(t)})):b(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove("show"),this._emulateAnimation(()=>{this.dispose(),b(t)})):b(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className="modal-backdrop",this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...Oe,..."object"==typeof t?t:{}}).rootElement=a(t.rootElement),l("backdrop",t,Ce),t}_append(){this._isAppended||(this._config.rootElement.appendChild(this._getElement()),P.on(this._getElement(),"mousedown.bs.backdrop",()=>{b(this._config.clickCallback)}),this._isAppended=!0)}dispose(){this._isAppended&&(P.off(this._element,"mousedown.bs.backdrop"),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){v(t,this._getElement(),this._config.isAnimated)}}const Le={backdrop:!0,keyboard:!0,focus:!0},xe={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"};class De extends B{constructor(e,i){super(e),this._config=this._getConfig(i),this._dialog=t.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new Te}static get Default(){return Le}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||P.trigger(this._element,"show.bs.modal",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add("modal-open"),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),P.on(this._element,"click.dismiss.bs.modal",'[data-bs-dismiss="modal"]',t=>this.hide(t)),P.on(this._dialog,"mousedown.dismiss.bs.modal",()=>{P.one(this._element,"mouseup.dismiss.bs.modal",t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)})}),this._showBackdrop(()=>this._showElement(t)))}hide(t){if(t&&["A","AREA"].includes(t.target.tagName)&&t.preventDefault(),!this._isShown||this._isTransitioning)return;if(P.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const e=this._isAnimated();e&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),P.off(document,"focusin.bs.modal"),this._element.classList.remove("show"),P.off(this._element,"click.dismiss.bs.modal"),P.off(this._dialog,"mousedown.dismiss.bs.modal"),this._queueCallback(()=>this._hideModal(),this._element,e)}dispose(){[window,this._dialog].forEach(t=>P.off(t,".bs.modal")),this._backdrop.dispose(),super.dispose(),P.off(document,"focusin.bs.modal")}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new ke({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_getConfig(t){return t={...Le,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},l("modal",t,xe),t}_showElement(e){const i=this._isAnimated(),n=t.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.appendChild(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,n&&(n.scrollTop=0),i&&f(this._element),this._element.classList.add("show"),this._config.focus&&this._enforceFocus(),this._queueCallback(()=>{this._config.focus&&this._element.focus(),this._isTransitioning=!1,P.trigger(this._element,"shown.bs.modal",{relatedTarget:e})},this._dialog,i)}_enforceFocus(){P.off(document,"focusin.bs.modal"),P.on(document,"focusin.bs.modal",t=>{document===t.target||this._element===t.target||this._element.contains(t.target)||this._element.focus()})}_setEscapeEvent(){this._isShown?P.on(this._element,"keydown.dismiss.bs.modal",t=>{this._config.keyboard&&"Escape"===t.key?(t.preventDefault(),this.hide()):this._config.keyboard||"Escape"!==t.key||this._triggerBackdropTransition()}):P.off(this._element,"keydown.dismiss.bs.modal")}_setResizeEvent(){this._isShown?P.on(window,"resize.bs.modal",()=>this._adjustDialog()):P.off(window,"resize.bs.modal")}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove("modal-open"),this._resetAdjustments(),this._scrollBar.reset(),P.trigger(this._element,"hidden.bs.modal")})}_showBackdrop(t){P.on(this._element,"click.dismiss.bs.modal",t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())}),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(P.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains("modal-static")||(n||(i.overflowY="hidden"),t.add("modal-static"),this._queueCallback(()=>{t.remove("modal-static"),n||this._queueCallback(()=>{i.overflowY=""},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!g()||i&&!t&&g())&&(this._element.style.paddingLeft=e+"px"),(i&&!t&&!g()||!i&&t&&g())&&(this._element.style.paddingRight=e+"px")}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=De.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}P.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=s(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),P.one(e,"show.bs.modal",t=>{t.defaultPrevented||P.one(e,"hidden.bs.modal",()=>{c(this)&&this.focus()})}),De.getOrCreateInstance(e).toggle(this)})),_(De);const Se={backdrop:!0,keyboard:!0,scroll:!1},Ie={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"};class Ne extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._addEventListeners()}static get NAME(){return"offcanvas"}static get Default(){return Se}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||P.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||((new Te).hide(),this._enforceFocusOnElement(this._element)),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add("show"),this._queueCallback(()=>{P.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(P.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(P.off(document,"focusin.bs.offcanvas"),this._element.blur(),this._isShown=!1,this._element.classList.remove("show"),this._backdrop.hide(),this._queueCallback(()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new Te).reset(),P.trigger(this._element,"hidden.bs.offcanvas")},this._element,!0)))}dispose(){this._backdrop.dispose(),super.dispose(),P.off(document,"focusin.bs.offcanvas")}_getConfig(t){return t={...Se,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},l("offcanvas",t,Ie),t}_initializeBackDrop(){return new ke({isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_enforceFocusOnElement(t){P.off(document,"focusin.bs.offcanvas"),P.on(document,"focusin.bs.offcanvas",e=>{document===e.target||t===e.target||t.contains(e.target)||t.focus()}),t.focus()}_addEventListeners(){P.on(this._element,"click.dismiss.bs.offcanvas",'[data-bs-dismiss="offcanvas"]',()=>this.hide()),P.on(this._element,"keydown.dismiss.bs.offcanvas",t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()})}static jQueryInterface(t){return this.each((function(){const e=Ne.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}P.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(e){const i=s(this);if(["A","AREA"].includes(this.tagName)&&e.preventDefault(),h(this))return;P.one(i,"hidden.bs.offcanvas",()=>{c(this)&&this.focus()});const n=t.findOne(".offcanvas.show");n&&n!==i&&Ne.getInstance(n).hide(),Ne.getOrCreateInstance(i).toggle(this)})),P.on(window,"load.bs.offcanvas.data-api",()=>t.find(".offcanvas.show").forEach(t=>Ne.getOrCreateInstance(t).show())),_(Ne);const je=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Me=/^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/i,Pe=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,He=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!je.has(i)||Boolean(Me.test(t.nodeValue)||Pe.test(t.nodeValue));const n=e.filter(t=>t instanceof RegExp);for(let t=0,e=n.length;t{He(t,a)||i.removeAttribute(t.nodeName)})}return n.body.innerHTML}const Be=new RegExp("(^|\\s)bs-tooltip\\S+","g"),We=new Set(["sanitize","allowList","sanitizeFn"]),qe={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},ze={AUTO:"auto",TOP:"top",RIGHT:g()?"left":"right",BOTTOM:"bottom",LEFT:g()?"right":"left"},$e={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Ue={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"};class Fe extends B{constructor(t,e){if(void 0===fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return $e}static get NAME(){return"tooltip"}static get Event(){return Ue}static get DefaultType(){return qe}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains("show"))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),P.off(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this.tip&&this.tip.remove(),this._popper&&this._popper.destroy(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=P.trigger(this._element,this.constructor.Event.SHOW),i=d(this._element),n=null===i?this._element.ownerDocument.documentElement.contains(this._element):i.contains(this._element);if(t.defaultPrevented||!n)return;const s=this.getTipElement(),o=e(this.constructor.NAME);s.setAttribute("id",o),this._element.setAttribute("aria-describedby",o),this.setContent(),this._config.animation&&s.classList.add("fade");const r="function"==typeof this._config.placement?this._config.placement.call(this,s,this._element):this._config.placement,a=this._getAttachment(r);this._addAttachmentClass(a);const{container:l}=this._config;R.set(s,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(l.appendChild(s),P.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=ue(this._element,s,this._getPopperConfig(a)),s.classList.add("show");const c="function"==typeof this._config.customClass?this._config.customClass():this._config.customClass;c&&s.classList.add(...c.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>{P.on(t,"mouseover",u)});const h=this.tip.classList.contains("fade");this._queueCallback(()=>{const t=this._hoverState;this._hoverState=null,P.trigger(this._element,this.constructor.Event.SHOWN),"out"===t&&this._leave(null,this)},this.tip,h)}hide(){if(!this._popper)return;const t=this.getTipElement();if(P.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove("show"),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",u)),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains("fade");this._queueCallback(()=>{this._isWithActiveTrigger()||("show"!==this._hoverState&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),P.trigger(this._element,this.constructor.Event.HIDDEN),this._popper&&(this._popper.destroy(),this._popper=null))},this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");return t.innerHTML=this._config.template,this.tip=t.children[0],this.tip}setContent(){const e=this.getTipElement();this.setElementContent(t.findOne(".tooltip-inner",e),this.getTitle()),e.classList.remove("fade","show")}setElementContent(t,e){if(null!==t)return r(e)?(e=a(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.appendChild(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Re(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){let t=this._element.getAttribute("data-bs-original-title");return t||(t="function"==typeof this._config.title?this._config.title.call(this._element):this._config.title),t}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){const i=this.constructor.DATA_KEY;return(e=e||R.get(t.delegateTarget,i))||(e=new this.constructor(t.delegateTarget,this._getDelegateConfig()),R.set(t.delegateTarget,i,e)),e}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add("bs-tooltip-"+this.updateAttachment(t))}_getAttachment(t){return ze[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach(t=>{if("click"===t)P.on(this._element,this.constructor.Event.CLICK,this._config.selector,t=>this.toggle(t));else if("manual"!==t){const e="hover"===t?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i="hover"===t?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;P.on(this._element,e,this._config.selector,t=>this._enter(t)),P.on(this._element,i,this._config.selector,t=>this._leave(t))}}),this._hideModalHandler=()=>{this._element&&this.hide()},P.on(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),e.getTipElement().classList.contains("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e._config.delay&&e._config.delay.show?e._timeout=setTimeout(()=>{"show"===e._hoverState&&e.show()},e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e._config.delay&&e._config.delay.hide?e._timeout=setTimeout(()=>{"out"===e._hoverState&&e.hide()},e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach(t=>{We.has(t)&&delete e[t]}),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:a(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),l("tooltip",t,this.constructor.DefaultType),t.sanitize&&(t.template=Re(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};if(this._config)for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=t.getAttribute("class").match(Be);null!==e&&e.length>0&&e.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}static jQueryInterface(t){return this.each((function(){const e=Fe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}_(Fe);const Ve=new RegExp("(^|\\s)bs-popover\\S+","g"),Ke={...Fe.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},Xe={...Fe.DefaultType,content:"(string|element|function)"},Ye={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class Qe extends Fe{static get Default(){return Ke}static get NAME(){return"popover"}static get Event(){return Ye}static get DefaultType(){return Xe}isWithContent(){return this.getTitle()||this._getContent()}getTipElement(){return this.tip||(this.tip=super.getTipElement(),this.getTitle()||t.findOne(".popover-header",this.tip).remove(),this._getContent()||t.findOne(".popover-body",this.tip).remove()),this.tip}setContent(){const e=this.getTipElement();this.setElementContent(t.findOne(".popover-header",e),this.getTitle());let i=this._getContent();"function"==typeof i&&(i=i.call(this._element)),this.setElementContent(t.findOne(".popover-body",e),i),e.classList.remove("fade","show")}_addAttachmentClass(t){this.getTipElement().classList.add("bs-popover-"+this.updateAttachment(t))}_getContent(){return this._element.getAttribute("data-bs-content")||this._config.content}_cleanTipClass(){const t=this.getTipElement(),e=t.getAttribute("class").match(Ve);null!==e&&e.length>0&&e.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}static jQueryInterface(t){return this.each((function(){const e=Qe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}_(Qe);const Ge={offset:10,method:"auto",target:""},Ze={offset:"number",method:"string",target:"(string|element)"};class Je extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._selector=`${this._config.target} .nav-link, ${this._config.target} .list-group-item, ${this._config.target} .dropdown-item`,this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,P.on(this._scrollElement,"scroll.bs.scrollspy",()=>this._process()),this.refresh(),this._process()}static get Default(){return Ge}static get NAME(){return"scrollspy"}refresh(){const e=this._scrollElement===this._scrollElement.window?"offset":"position",i="auto"===this._config.method?e:this._config.method,s="position"===i?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),t.find(this._selector).map(e=>{const o=n(e),r=o?t.findOne(o):null;if(r){const t=r.getBoundingClientRect();if(t.width||t.height)return[U[i](r).top+s,o]}return null}).filter(t=>t).sort((t,e)=>t[0]-e[0]).forEach(t=>{this._offsets.push(t[0]),this._targets.push(t[1])})}dispose(){P.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){if("string"!=typeof(t={...Ge,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target&&r(t.target)){let{id:i}=t.target;i||(i=e("scrollspy"),t.target.id=i),t.target="#"+i}return l("scrollspy",t,Ze),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${t}[data-bs-target="${e}"],${t}[href="${e}"]`),n=t.findOne(i.join(","));n.classList.contains("dropdown-item")?(t.findOne(".dropdown-toggle",n.closest(".dropdown")).classList.add("active"),n.classList.add("active")):(n.classList.add("active"),t.parents(n,".nav, .list-group").forEach(e=>{t.prev(e,".nav-link, .list-group-item").forEach(t=>t.classList.add("active")),t.prev(e,".nav-item").forEach(e=>{t.children(e,".nav-link").forEach(t=>t.classList.add("active"))})})),P.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:e})}_clear(){t.find(this._selector).filter(t=>t.classList.contains("active")).forEach(t=>t.classList.remove("active"))}static jQueryInterface(t){return this.each((function(){const e=Je.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(window,"load.bs.scrollspy.data-api",()=>{t.find('[data-bs-spy="scroll"]').forEach(t=>new Je(t))}),_(Je);class ti extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains("active"))return;let e;const i=s(this._element),n=this._element.closest(".nav, .list-group");if(n){const i="UL"===n.nodeName||"OL"===n.nodeName?":scope > li > .active":".active";e=t.find(i,n),e=e[e.length-1]}const o=e?P.trigger(e,"hide.bs.tab",{relatedTarget:this._element}):null;if(P.trigger(this._element,"show.bs.tab",{relatedTarget:e}).defaultPrevented||null!==o&&o.defaultPrevented)return;this._activate(this._element,n);const r=()=>{P.trigger(e,"hidden.bs.tab",{relatedTarget:this._element}),P.trigger(this._element,"shown.bs.tab",{relatedTarget:e})};i?this._activate(i,i.parentNode,r):r()}_activate(e,i,n){const s=(!i||"UL"!==i.nodeName&&"OL"!==i.nodeName?t.children(i,".active"):t.find(":scope > li > .active",i))[0],o=n&&s&&s.classList.contains("fade"),r=()=>this._transitionComplete(e,s,n);s&&o?(s.classList.remove("show"),this._queueCallback(r,e,!0)):r()}_transitionComplete(e,i,n){if(i){i.classList.remove("active");const e=t.findOne(":scope > .dropdown-menu .active",i.parentNode);e&&e.classList.remove("active"),"tab"===i.getAttribute("role")&&i.setAttribute("aria-selected",!1)}e.classList.add("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!0),f(e),e.classList.contains("fade")&&e.classList.add("show");let s=e.parentNode;if(s&&"LI"===s.nodeName&&(s=s.parentNode),s&&s.classList.contains("dropdown-menu")){const i=e.closest(".dropdown");i&&t.find(".dropdown-toggle",i).forEach(t=>t.classList.add("active")),e.setAttribute("aria-expanded",!0)}n&&n()}static jQueryInterface(t){return this.each((function(){const e=ti.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),h(this)||ti.getOrCreateInstance(this).show()})),_(ti);const ei={animation:"boolean",autohide:"boolean",delay:"number"},ii={animation:!0,autohide:!0,delay:5e3};class ni extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return ei}static get Default(){return ii}static get NAME(){return"toast"}show(){P.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove("hide"),f(this._element),this._element.classList.add("showing"),this._queueCallback(()=>{this._element.classList.remove("showing"),this._element.classList.add("show"),P.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this._element.classList.contains("show")&&(P.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.remove("show"),this._queueCallback(()=>{this._element.classList.add("hide"),P.trigger(this._element,"hidden.bs.toast")},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),super.dispose()}_getConfig(t){return t={...ii,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},l("toast",t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){P.on(this._element,"click.dismiss.bs.toast",'[data-bs-dismiss="toast"]',()=>this.hide()),P.on(this._element,"mouseover.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"mouseout.bs.toast",t=>this._onInteraction(t,!1)),P.on(this._element,"focusin.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"focusout.bs.toast",t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return _(ni),{Alert:W,Button:q,Carousel:Z,Collapse:et,Dropdown:Ae,Modal:De,Offcanvas:Ne,Popover:Qe,ScrollSpy:Je,Tab:ti,Toast:ni,Tooltip:Fe}})); diff --git a/app/vmagent/static/js/jquery-3.6.0.min.js b/app/vmagent/static/js/jquery-3.6.0.min.js deleted file mode 100644 index c4c6022f29..0000000000 --- a/app/vmagent/static/js/jquery-3.6.0.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 # How often rules in the group are evaluated. [ interval: | default = -evaluationInterval flag ] +# Limit the number of alerts an alerting rule and series a recording +# rule can produce. 0 is no limit. +[ limit: | default = 0 ] + # How many rules execute at once within a group. Increasing concurrency may speed # up round execution speed. [ concurrency: | default = 1 ] @@ -535,6 +539,7 @@ See full description for these flags in `./vmalert --help`. * Graphite engine isn't supported yet; * `query` template function is disabled for performance reasons (might be changed in future); +* `limit` group's param has no effect during replay (might be changed in future); ## Monitoring diff --git a/app/vmalert/alerting.go b/app/vmalert/alerting.go index 855843df52..3f629dab46 100644 --- a/app/vmalert/alerting.go +++ b/app/vmalert/alerting.go @@ -240,7 +240,7 @@ const resolvedRetention = 15 * time.Minute // Exec executes AlertingRule expression via the given Querier. // Based on the Querier results AlertingRule maintains notifier.Alerts -func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time) ([]prompbmarshal.TimeSeries, error) { +func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time, limit int) ([]prompbmarshal.TimeSeries, error) { start := time.Now() qMetrics, err := ar.q.Query(ctx, ar.Expr, ts) ar.mu.Lock() @@ -307,7 +307,7 @@ func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time) ([]prompbmarshal a.ActiveAt = ts ar.alerts[h] = a } - + var numActivePending int for h, a := range ar.alerts { // if alert wasn't updated in this iteration // means it is resolved already @@ -324,12 +324,17 @@ func (ar *AlertingRule) Exec(ctx context.Context, ts time.Time) ([]prompbmarshal } continue } + numActivePending++ if a.State == notifier.StatePending && ts.Sub(a.ActiveAt) >= ar.For { a.State = notifier.StateFiring a.Start = ts alertsFired.Inc() } } + if limit > 0 && numActivePending > limit { + ar.alerts = map[uint64]*notifier.Alert{} + return nil, fmt.Errorf("exec exceeded limit of %d with %d alerts", limit, numActivePending) + } return ar.toTimeSeries(ts.Unix()), nil } diff --git a/app/vmalert/alerting_test.go b/app/vmalert/alerting_test.go index 6bbd2dff6f..ab5be63923 100644 --- a/app/vmalert/alerting_test.go +++ b/app/vmalert/alerting_test.go @@ -304,7 +304,7 @@ func TestAlertingRule_Exec(t *testing.T) { for _, step := range tc.steps { fq.reset() fq.add(step...) - if _, err := tc.rule.Exec(context.TODO(), time.Now()); err != nil { + if _, err := tc.rule.Exec(context.TODO(), time.Now(), 0); err != nil { t.Fatalf("unexpected err: %s", err) } // artificial delay between applying steps @@ -624,14 +624,14 @@ func TestAlertingRule_Exec_Negative(t *testing.T) { // successful attempt fq.add(metricWithValueAndLabels(t, 1, "__name__", "foo", "job", "bar")) - _, err := ar.Exec(context.TODO(), time.Now()) + _, err := ar.Exec(context.TODO(), time.Now(), 0) if err != nil { t.Fatal(err) } // label `job` will collide with rule extra label and will make both time series equal fq.add(metricWithValueAndLabels(t, 1, "__name__", "foo", "job", "baz")) - _, err = ar.Exec(context.TODO(), time.Now()) + _, err = ar.Exec(context.TODO(), time.Now(), 0) if !errors.Is(err, errDuplicate) { t.Fatalf("expected to have %s error; got %s", errDuplicate, err) } @@ -640,7 +640,7 @@ func TestAlertingRule_Exec_Negative(t *testing.T) { expErr := "connection reset by peer" fq.setErr(errors.New(expErr)) - _, err = ar.Exec(context.TODO(), time.Now()) + _, err = ar.Exec(context.TODO(), time.Now(), 0) if err == nil { t.Fatalf("expected to get err; got nil") } @@ -649,6 +649,50 @@ func TestAlertingRule_Exec_Negative(t *testing.T) { } } +func TestAlertingRuleLimit(t *testing.T) { + fq := &fakeQuerier{} + ar := newTestAlertingRule("test", 0) + ar.Labels = map[string]string{"job": "test"} + ar.q = fq + ar.For = time.Minute + testCases := []struct { + limit int + err string + tssNum int + }{ + { + limit: 0, + tssNum: 4, + }, + { + limit: -1, + tssNum: 4, + }, + { + limit: 1, + err: "exec exceeded limit of 1 with 2 alerts", + tssNum: 0, + }, + { + limit: 4, + tssNum: 4, + }, + } + var ( + err error + timestamp = time.Now() + ) + fq.add(metricWithValueAndLabels(t, 1, "__name__", "foo", "job", "bar")) + fq.add(metricWithValueAndLabels(t, 1, "__name__", "foo", "bar", "job")) + for _, testCase := range testCases { + _, err = ar.Exec(context.TODO(), timestamp, testCase.limit) + if err != nil && !strings.EqualFold(err.Error(), testCase.err) { + t.Fatal(err) + } + } + fq.reset() +} + func TestAlertingRule_Template(t *testing.T) { testCases := []struct { rule *AlertingRule @@ -761,7 +805,7 @@ func TestAlertingRule_Template(t *testing.T) { tc.rule.GroupID = fakeGroup.ID() tc.rule.q = fq fq.add(tc.metrics...) - if _, err := tc.rule.Exec(context.TODO(), time.Now()); err != nil { + if _, err := tc.rule.Exec(context.TODO(), time.Now(), 0); err != nil { t.Fatalf("unexpected err: %s", err) } for hash, expAlert := range tc.expAlerts { diff --git a/app/vmalert/config/config.go b/app/vmalert/config/config.go index ec961b0929..f79801025e 100644 --- a/app/vmalert/config/config.go +++ b/app/vmalert/config/config.go @@ -27,6 +27,7 @@ type Group struct { File string Name string `yaml:"name"` Interval *promutils.Duration `yaml:"interval,omitempty"` + Limit int `yaml:"limit,omitempty"` Rules []Rule `yaml:"rules"` Concurrency int `yaml:"concurrency"` // ExtraFilterLabels is a list label filters applied to every rule diff --git a/app/vmalert/config/config_test.go b/app/vmalert/config/config_test.go index c81717ed01..f63950f172 100644 --- a/app/vmalert/config/config_test.go +++ b/app/vmalert/config/config_test.go @@ -489,6 +489,22 @@ rules: name: TestGroup params: nocache: ["0"] +rules: + - alert: foo + expr: sum by(job) (up == 1) +`) + }) + + t.Run("`limit` change", func(t *testing.T) { + f(t, ` +name: TestGroup +limit: 5 +rules: + - alert: foo + expr: sum by(job) (up == 1) +`, ` +name: TestGroup +limit: 10 rules: - alert: foo expr: sum by(job) (up == 1) diff --git a/app/vmalert/config/testdata/rules/rules-replay-good.rules b/app/vmalert/config/testdata/rules/rules-replay-good.rules index 134a238bcf..a8138e5fc9 100644 --- a/app/vmalert/config/testdata/rules/rules-replay-good.rules +++ b/app/vmalert/config/testdata/rules/rules-replay-good.rules @@ -2,6 +2,7 @@ groups: - name: ReplayGroup interval: 1m concurrency: 1 + limit: 1000 rules: - record: type:vm_cache_entries:rate5m expr: sum(rate(vm_cache_entries[5m])) by (type) diff --git a/app/vmalert/config/testdata/rules/rules2-good.rules b/app/vmalert/config/testdata/rules/rules2-good.rules index 0387a41cd9..658adacfb8 100644 --- a/app/vmalert/config/testdata/rules/rules2-good.rules +++ b/app/vmalert/config/testdata/rules/rules2-good.rules @@ -2,6 +2,7 @@ groups: - name: TestGroup interval: 2s concurrency: 2 + limit: 1000 params: denyPartialResponse: ["true"] extra_label: ["env=dev"] diff --git a/app/vmalert/group.go b/app/vmalert/group.go index c428537ba1..747a4ca540 100644 --- a/app/vmalert/group.go +++ b/app/vmalert/group.go @@ -10,6 +10,8 @@ import ( "sync" "time" + "github.com/VictoriaMetrics/metrics" + "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/config" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/datasource" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/notifier" @@ -18,7 +20,6 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/decimal" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" - "github.com/VictoriaMetrics/metrics" ) // Group is an entity for grouping rules @@ -29,6 +30,7 @@ type Group struct { Rules []Rule Type datasource.Type Interval time.Duration + Limit int Concurrency int Checksum string LastEvaluation time.Time @@ -90,6 +92,7 @@ func newGroup(cfg config.Group, qb datasource.QuerierBuilder, defaultInterval ti Name: cfg.Name, File: cfg.File, Interval: cfg.Interval.Duration(), + Limit: cfg.Limit, Concurrency: cfg.Concurrency, Checksum: cfg.Checksum, Params: cfg.Params, @@ -215,6 +218,7 @@ func (g *Group) updateWith(newGroup *Group) error { g.Concurrency = newGroup.Concurrency g.Params = newGroup.Params g.Labels = newGroup.Labels + g.Limit = newGroup.Limit g.Checksum = newGroup.Checksum g.Rules = newRules return nil @@ -282,7 +286,7 @@ func (g *Group) start(ctx context.Context, nts func() []notifier.Notifier, rw *r } resolveDuration := getResolveDuration(g.Interval, *resendDelay, *maxResolveDuration) - errs := e.execConcurrently(ctx, g.Rules, ts, g.Concurrency, resolveDuration) + errs := e.execConcurrently(ctx, g.Rules, ts, g.Concurrency, resolveDuration, g.Limit) for err := range errs { if err != nil { logger.Errorf("group %q: %s", g.Name, err) @@ -360,12 +364,12 @@ type executor struct { previouslySentSeriesToRW map[uint64]map[string][]prompbmarshal.Label } -func (e *executor) execConcurrently(ctx context.Context, rules []Rule, ts time.Time, concurrency int, resolveDuration time.Duration) chan error { +func (e *executor) execConcurrently(ctx context.Context, rules []Rule, ts time.Time, concurrency int, resolveDuration time.Duration, limit int) chan error { res := make(chan error, len(rules)) if concurrency == 1 { // fast path for _, rule := range rules { - res <- e.exec(ctx, rule, ts, resolveDuration) + res <- e.exec(ctx, rule, ts, resolveDuration, limit) } close(res) return res @@ -378,7 +382,7 @@ func (e *executor) execConcurrently(ctx context.Context, rules []Rule, ts time.T sem <- struct{}{} wg.Add(1) go func(r Rule) { - res <- e.exec(ctx, r, ts, resolveDuration) + res <- e.exec(ctx, r, ts, resolveDuration, limit) <-sem wg.Done() }(rule) @@ -399,10 +403,10 @@ var ( remoteWriteTotal = metrics.NewCounter(`vmalert_remotewrite_total`) ) -func (e *executor) exec(ctx context.Context, rule Rule, ts time.Time, resolveDuration time.Duration) error { +func (e *executor) exec(ctx context.Context, rule Rule, ts time.Time, resolveDuration time.Duration, limit int) error { execTotal.Inc() - tss, err := rule.Exec(ctx, ts) + tss, err := rule.Exec(ctx, ts, limit) if err != nil { execErrors.Inc() return fmt.Errorf("rule %q: failed to execute: %w", rule, err) diff --git a/app/vmalert/recording.go b/app/vmalert/recording.go index 9a16cd408e..a222859068 100644 --- a/app/vmalert/recording.go +++ b/app/vmalert/recording.go @@ -124,7 +124,7 @@ func (rr *RecordingRule) ExecRange(ctx context.Context, start, end time.Time) ([ } // Exec executes RecordingRule expression via the given Querier. -func (rr *RecordingRule) Exec(ctx context.Context, ts time.Time) ([]prompbmarshal.TimeSeries, error) { +func (rr *RecordingRule) Exec(ctx context.Context, ts time.Time, limit int) ([]prompbmarshal.TimeSeries, error) { qMetrics, err := rr.q.Query(ctx, rr.Expr, ts) rr.mu.Lock() defer rr.mu.Unlock() @@ -137,6 +137,11 @@ func (rr *RecordingRule) Exec(ctx context.Context, ts time.Time) ([]prompbmarsha return nil, fmt.Errorf("failed to execute query %q: %w", rr.Expr, err) } + numSeries := len(qMetrics) + if limit > 0 && numSeries > limit { + return nil, fmt.Errorf("exec exceeded limit of %d with %d series", limit, numSeries) + } + duplicates := make(map[string]struct{}, len(qMetrics)) var tss []prompbmarshal.TimeSeries for _, r := range qMetrics { diff --git a/app/vmalert/recording_test.go b/app/vmalert/recording_test.go index cbb2b75a7c..5594c11ecc 100644 --- a/app/vmalert/recording_test.go +++ b/app/vmalert/recording_test.go @@ -11,7 +11,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" ) -func TestRecoridngRule_Exec(t *testing.T) { +func TestRecordingRule_Exec(t *testing.T) { timestamp := time.Now() testCases := []struct { rule *RecordingRule @@ -77,7 +77,7 @@ func TestRecoridngRule_Exec(t *testing.T) { fq := &fakeQuerier{} fq.add(tc.metrics...) tc.rule.q = fq - tss, err := tc.rule.Exec(context.TODO(), time.Now()) + tss, err := tc.rule.Exec(context.TODO(), time.Now(), 0) if err != nil { t.Fatalf("unexpected Exec err: %s", err) } @@ -88,7 +88,7 @@ func TestRecoridngRule_Exec(t *testing.T) { } } -func TestRecoridngRule_ExecRange(t *testing.T) { +func TestRecordingRule_ExecRange(t *testing.T) { timestamp := time.Now() testCases := []struct { rule *RecordingRule @@ -169,7 +169,48 @@ func TestRecoridngRule_ExecRange(t *testing.T) { } } -func TestRecoridngRule_ExecNegative(t *testing.T) { +func TestRecordingRuleLimit(t *testing.T) { + timestamp := time.Now() + testCases := []struct { + limit int + err string + }{ + { + limit: 0, + }, + { + limit: -1, + }, + { + limit: 1, + err: "exec exceeded limit of 1 with 3 series", + }, + { + limit: 2, + err: "exec exceeded limit of 2 with 3 series", + }, + } + testMetrics := []datasource.Metric{ + metricWithValuesAndLabels(t, []float64{1}, "__name__", "foo", "job", "foo"), + metricWithValuesAndLabels(t, []float64{2, 3}, "__name__", "bar", "job", "bar"), + metricWithValuesAndLabels(t, []float64{4, 5, 6}, "__name__", "baz", "job", "baz"), + } + rule := &RecordingRule{Name: "job:foo", Labels: map[string]string{ + "source": "test_limit", + }} + var err error + for _, testCase := range testCases { + fq := &fakeQuerier{} + fq.add(testMetrics...) + rule.q = fq + _, err = rule.Exec(context.TODO(), timestamp, testCase.limit) + if err != nil && !strings.EqualFold(err.Error(), testCase.err) { + t.Fatal(err) + } + } +} + +func TestRecordingRule_ExecNegative(t *testing.T) { rr := &RecordingRule{Name: "job:foo", Labels: map[string]string{ "job": "test", }} @@ -178,7 +219,7 @@ func TestRecoridngRule_ExecNegative(t *testing.T) { expErr := "connection reset by peer" fq.setErr(errors.New(expErr)) rr.q = fq - _, err := rr.Exec(context.TODO(), time.Now()) + _, err := rr.Exec(context.TODO(), time.Now(), 0) if err == nil { t.Fatalf("expected to get err; got nil") } @@ -193,7 +234,7 @@ func TestRecoridngRule_ExecNegative(t *testing.T) { fq.add(metricWithValueAndLabels(t, 1, "__name__", "foo", "job", "foo")) fq.add(metricWithValueAndLabels(t, 2, "__name__", "foo", "job", "bar")) - _, err = rr.Exec(context.TODO(), time.Now()) + _, err = rr.Exec(context.TODO(), time.Now(), 0) if err == nil { t.Fatalf("expected to get err; got nil") } diff --git a/app/vmalert/remotewrite/remotewrite.go b/app/vmalert/remotewrite/remotewrite.go index 992cea22bf..6d94c9ba0d 100644 --- a/app/vmalert/remotewrite/remotewrite.go +++ b/app/vmalert/remotewrite/remotewrite.go @@ -236,6 +236,9 @@ func (c *Client) send(ctx context.Context, data []byte) error { if err != nil { return fmt.Errorf("failed to create new HTTP request: %w", err) } + + req.Header.Set("Content-Encoding", "snappy") + if c.authCfg != nil { if auth := c.authCfg.GetAuthHeader(); auth != "" { req.Header.Set("Authorization", auth) diff --git a/app/vmalert/remotewrite/remotewrite_test.go b/app/vmalert/remotewrite/remotewrite_test.go index 18a9cfff61..da7c6db84d 100644 --- a/app/vmalert/remotewrite/remotewrite_test.go +++ b/app/vmalert/remotewrite/remotewrite_test.go @@ -80,6 +80,12 @@ func (rw *rwServer) handler(w http.ResponseWriter, r *http.Request) { rw.err(w, fmt.Errorf("bad method %q", r.Method)) return } + + h := r.Header.Get("Content-Encoding") + if h != "snappy" { + rw.err(w, fmt.Errorf("header read error: Content-Encoding is not snappy (%q)", h)) + } + data, err := ioutil.ReadAll(r.Body) if err != nil { rw.err(w, fmt.Errorf("body read err: %w", err)) diff --git a/app/vmalert/replay.go b/app/vmalert/replay.go index 16f1829026..1adf253d9d 100644 --- a/app/vmalert/replay.go +++ b/app/vmalert/replay.go @@ -7,12 +7,13 @@ import ( "strings" "time" + "github.com/dmitryk-dk/pb/v3" + "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/config" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/datasource" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/remotewrite" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal" - "github.com/dmitryk-dk/pb/v3" ) var ( @@ -87,6 +88,10 @@ func (g *Group) replay(start, end time.Time, rw *remotewrite.Client) int { "\nrequests to make: \t%d"+ "\nmax range per request: \t%v\n", g.Name, g.Interval, iterations, step) + if g.Limit > 0 { + fmt.Printf("\nPlease note, `limit: %d` param has no effect during replay.\n", + g.Limit) + } for _, rule := range g.Rules { fmt.Printf("> Rule %q (ID: %d)\n", rule, rule.ID()) var bar *pb.ProgressBar diff --git a/app/vmalert/rule.go b/app/vmalert/rule.go index 04ce44933b..630947060a 100644 --- a/app/vmalert/rule.go +++ b/app/vmalert/rule.go @@ -15,9 +15,10 @@ type Rule interface { // ID returns unique ID that may be used for // identifying this Rule among others. ID() uint64 - // Exec executes the rule with given context at the given timestamp - Exec(ctx context.Context, ts time.Time) ([]prompbmarshal.TimeSeries, error) - // ExecRange executes the rule on the given time range + // Exec executes the rule with given context at the given timestamp and limit. + // returns an err if number of resulting time series exceeds the limit. + Exec(ctx context.Context, ts time.Time, limit int) ([]prompbmarshal.TimeSeries, error) + // ExecRange executes the rule on the given time range. ExecRange(ctx context.Context, start, end time.Time) ([]prompbmarshal.TimeSeries, error) // UpdateWith performs modification of current Rule // with fields of the given Rule. diff --git a/app/vmalert/tpl/header.qtpl b/app/vmalert/tpl/header.qtpl index 471b5499e9..486521268a 100644 --- a/app/vmalert/tpl/header.qtpl +++ b/app/vmalert/tpl/header.qtpl @@ -3,7 +3,7 @@ vmalert{% if title != "" %} - {%s title %}{% endif %} - + VictoriaMetrics
`) -//line lib/promscrape/targetstatus.qtpl:92 - if targetsStatuses.err != nil { -//line lib/promscrape/targetstatus.qtpl:93 - streamerrorNotification(qw422016, targetsStatuses.err) -//line lib/promscrape/targetstatus.qtpl:94 - } -//line lib/promscrape/targetstatus.qtpl:94 - qw422016.N().S(`

Scrape targets


`) -//line lib/promscrape/targetstatus.qtpl:131 - if filter.endpointSearch == "" && filter.labelSearch == "" { -//line lib/promscrape/targetstatus.qtpl:131 - qw422016.N().S(``) -//line lib/promscrape/targetstatus.qtpl:135 - } else { -//line lib/promscrape/targetstatus.qtpl:135 - qw422016.N().S(``) -//line lib/promscrape/targetstatus.qtpl:139 - } -//line lib/promscrape/targetstatus.qtpl:139 - qw422016.N().S(`

`) -//line lib/promscrape/targetstatus.qtpl:174 - StreamTargets(qw422016, targetsStatuses.jobTargetsStatuses, targetsStatuses.emptyJobs, filter.showOnlyUnhealthy) -//line lib/promscrape/targetstatus.qtpl:174 - qw422016.N().S(`
`) -//line lib/promscrape/targetstatus.qtpl:177 - StreamServiceDiscovery(qw422016, targetsStatuses.jobTargetsStatuses, targetsStatuses.emptyJobs, filter.showOnlyUnhealthy, targetsStatuses.droppedKeyStatuses) -//line lib/promscrape/targetstatus.qtpl:177 - qw422016.N().S(`
`) -//line lib/promscrape/targetstatus.qtpl:215 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:63 + streamtargetsTabs(qw422016, tsr, filter, "scrapeTargets") +//line lib/promscrape/targetstatus.qtpl:63 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:69 } -//line lib/promscrape/targetstatus.qtpl:215 -func WriteTargetsResponseHTML(qq422016 qtio422016.Writer, scrapeTargets scrapeTargets) { -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 +func WriteTargetsResponseHTML(qq422016 qtio422016.Writer, tsr *targetsStatusResult, filter *requestFilter) { +//line lib/promscrape/targetstatus.qtpl:69 qw422016 := qt422016.AcquireWriter(qq422016) -//line lib/promscrape/targetstatus.qtpl:215 - StreamTargetsResponseHTML(qw422016, scrapeTargets) -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 + StreamTargetsResponseHTML(qw422016, tsr, filter) +//line lib/promscrape/targetstatus.qtpl:69 qt422016.ReleaseWriter(qw422016) -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 } -//line lib/promscrape/targetstatus.qtpl:215 -func TargetsResponseHTML(scrapeTargets scrapeTargets) string { -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 +func TargetsResponseHTML(tsr *targetsStatusResult, filter *requestFilter) string { +//line lib/promscrape/targetstatus.qtpl:69 qb422016 := qt422016.AcquireByteBuffer() -//line lib/promscrape/targetstatus.qtpl:215 - WriteTargetsResponseHTML(qb422016, scrapeTargets) -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 + WriteTargetsResponseHTML(qb422016, tsr, filter) +//line lib/promscrape/targetstatus.qtpl:69 qs422016 := string(qb422016.B) -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 qt422016.ReleaseByteBuffer(qb422016) -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 return qs422016 -//line lib/promscrape/targetstatus.qtpl:215 +//line lib/promscrape/targetstatus.qtpl:69 } -//line lib/promscrape/targetstatus.qtpl:217 -func streamqueryArgs(qw422016 *qt422016.Writer, m map[string]string) { +//line lib/promscrape/targetstatus.qtpl:71 +func StreamServiceDiscoveryResponse(qw422016 *qt422016.Writer, tsr *targetsStatusResult, filter *requestFilter) { +//line lib/promscrape/targetstatus.qtpl:71 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:75 + streamcommonHeader(qw422016) +//line lib/promscrape/targetstatus.qtpl:75 + qw422016.N().S(`Discovered Targets`) +//line lib/promscrape/targetstatus.qtpl:79 + streamnavbar(qw422016) +//line lib/promscrape/targetstatus.qtpl:79 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:81 + if tsr.err != nil { +//line lib/promscrape/targetstatus.qtpl:82 + streamerrorNotification(qw422016, tsr.err) +//line lib/promscrape/targetstatus.qtpl:83 + } +//line lib/promscrape/targetstatus.qtpl:83 + qw422016.N().S(`

Discovered Targets


`) +//line lib/promscrape/targetstatus.qtpl:88 + streamfiltersForm(qw422016, filter) +//line lib/promscrape/targetstatus.qtpl:88 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:90 + streamtargetsTabs(qw422016, tsr, filter, "discoveredTargets") +//line lib/promscrape/targetstatus.qtpl:90 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:96 +} + +//line lib/promscrape/targetstatus.qtpl:96 +func WriteServiceDiscoveryResponse(qq422016 qtio422016.Writer, tsr *targetsStatusResult, filter *requestFilter) { +//line lib/promscrape/targetstatus.qtpl:96 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:96 + StreamServiceDiscoveryResponse(qw422016, tsr, filter) +//line lib/promscrape/targetstatus.qtpl:96 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:96 +} + +//line lib/promscrape/targetstatus.qtpl:96 +func ServiceDiscoveryResponse(tsr *targetsStatusResult, filter *requestFilter) string { +//line lib/promscrape/targetstatus.qtpl:96 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:96 + WriteServiceDiscoveryResponse(qb422016, tsr, filter) +//line lib/promscrape/targetstatus.qtpl:96 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:96 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:96 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:96 +} + +//line lib/promscrape/targetstatus.qtpl:98 +func streamcommonHeader(qw422016 *qt422016.Writer) { +//line lib/promscrape/targetstatus.qtpl:98 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:102 +} + +//line lib/promscrape/targetstatus.qtpl:102 +func writecommonHeader(qq422016 qtio422016.Writer) { +//line lib/promscrape/targetstatus.qtpl:102 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:102 + streamcommonHeader(qw422016) +//line lib/promscrape/targetstatus.qtpl:102 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:102 +} + +//line lib/promscrape/targetstatus.qtpl:102 +func commonHeader() string { +//line lib/promscrape/targetstatus.qtpl:102 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:102 + writecommonHeader(qb422016) +//line lib/promscrape/targetstatus.qtpl:102 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:102 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:102 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:102 +} + +//line lib/promscrape/targetstatus.qtpl:104 +func streamnavbar(qw422016 *qt422016.Writer) { +//line lib/promscrape/targetstatus.qtpl:104 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:113 +} + +//line lib/promscrape/targetstatus.qtpl:113 +func writenavbar(qq422016 qtio422016.Writer) { +//line lib/promscrape/targetstatus.qtpl:113 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:113 + streamnavbar(qw422016) +//line lib/promscrape/targetstatus.qtpl:113 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:113 +} + +//line lib/promscrape/targetstatus.qtpl:113 +func navbar() string { +//line lib/promscrape/targetstatus.qtpl:113 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:113 + writenavbar(qb422016) +//line lib/promscrape/targetstatus.qtpl:113 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:113 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:113 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:113 +} + +//line lib/promscrape/targetstatus.qtpl:115 +func streamfiltersForm(qw422016 *qt422016.Writer, filter *requestFilter) { +//line lib/promscrape/targetstatus.qtpl:115 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:167 +} + +//line lib/promscrape/targetstatus.qtpl:167 +func writefiltersForm(qq422016 qtio422016.Writer, filter *requestFilter) { +//line lib/promscrape/targetstatus.qtpl:167 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:167 + streamfiltersForm(qw422016, filter) +//line lib/promscrape/targetstatus.qtpl:167 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:167 +} + +//line lib/promscrape/targetstatus.qtpl:167 +func filtersForm(filter *requestFilter) string { +//line lib/promscrape/targetstatus.qtpl:167 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:167 + writefiltersForm(qb422016, filter) +//line lib/promscrape/targetstatus.qtpl:167 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:167 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:167 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:167 +} + +//line lib/promscrape/targetstatus.qtpl:169 +func streamtargetsTabs(qw422016 *qt422016.Writer, tsr *targetsStatusResult, filter *requestFilter, activeTab string) { +//line lib/promscrape/targetstatus.qtpl:169 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:186 + switch activeTab { +//line lib/promscrape/targetstatus.qtpl:187 + case "scrapeTargets": +//line lib/promscrape/targetstatus.qtpl:188 + streamscrapeTargets(qw422016, tsr) +//line lib/promscrape/targetstatus.qtpl:189 + case "discoveredTargets": +//line lib/promscrape/targetstatus.qtpl:190 + streamdiscoveredTargets(qw422016, tsr) +//line lib/promscrape/targetstatus.qtpl:191 + } +//line lib/promscrape/targetstatus.qtpl:191 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:194 +} + +//line lib/promscrape/targetstatus.qtpl:194 +func writetargetsTabs(qq422016 qtio422016.Writer, tsr *targetsStatusResult, filter *requestFilter, activeTab string) { +//line lib/promscrape/targetstatus.qtpl:194 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:194 + streamtargetsTabs(qw422016, tsr, filter, activeTab) +//line lib/promscrape/targetstatus.qtpl:194 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:194 +} + +//line lib/promscrape/targetstatus.qtpl:194 +func targetsTabs(tsr *targetsStatusResult, filter *requestFilter, activeTab string) string { +//line lib/promscrape/targetstatus.qtpl:194 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:194 + writetargetsTabs(qb422016, tsr, filter, activeTab) +//line lib/promscrape/targetstatus.qtpl:194 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:194 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:194 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:194 +} + +//line lib/promscrape/targetstatus.qtpl:196 +func streamscrapeTargets(qw422016 *qt422016.Writer, tsr *targetsStatusResult) { +//line lib/promscrape/targetstatus.qtpl:196 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:199 + for i, jts := range tsr.jobTargetsStatuses { +//line lib/promscrape/targetstatus.qtpl:200 + streamscrapeJobTargets(qw422016, i, jts) +//line lib/promscrape/targetstatus.qtpl:201 + } +//line lib/promscrape/targetstatus.qtpl:202 + for i, jobName := range tsr.emptyJobs { +//line lib/promscrape/targetstatus.qtpl:204 + num := i + len(tsr.jobTargetsStatuses) + jts := &jobTargetsStatuses{ + jobName: jobName, + } + +//line lib/promscrape/targetstatus.qtpl:209 + streamscrapeJobTargets(qw422016, num, jts) +//line lib/promscrape/targetstatus.qtpl:210 + } +//line lib/promscrape/targetstatus.qtpl:210 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:213 +} + +//line lib/promscrape/targetstatus.qtpl:213 +func writescrapeTargets(qq422016 qtio422016.Writer, tsr *targetsStatusResult) { +//line lib/promscrape/targetstatus.qtpl:213 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:213 + streamscrapeTargets(qw422016, tsr) +//line lib/promscrape/targetstatus.qtpl:213 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:213 +} + +//line lib/promscrape/targetstatus.qtpl:213 +func scrapeTargets(tsr *targetsStatusResult) string { +//line lib/promscrape/targetstatus.qtpl:213 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:213 + writescrapeTargets(qb422016, tsr) +//line lib/promscrape/targetstatus.qtpl:213 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:213 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:213 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:213 +} + +//line lib/promscrape/targetstatus.qtpl:215 +func streamscrapeJobTargets(qw422016 *qt422016.Writer, num int, jts *jobTargetsStatuses) { +//line lib/promscrape/targetstatus.qtpl:215 + qw422016.N().S(`

`) //line lib/promscrape/targetstatus.qtpl:219 + qw422016.E().S(jts.jobName) +//line lib/promscrape/targetstatus.qtpl:219 + qw422016.N().S(` `) +//line lib/promscrape/targetstatus.qtpl:219 + qw422016.N().S(`(`) +//line lib/promscrape/targetstatus.qtpl:219 + qw422016.N().D(jts.upCount) +//line lib/promscrape/targetstatus.qtpl:219 + qw422016.N().S(`/`) +//line lib/promscrape/targetstatus.qtpl:219 + qw422016.N().D(jts.targetsTotal) +//line lib/promscrape/targetstatus.qtpl:219 + qw422016.N().S(` `) +//line lib/promscrape/targetstatus.qtpl:219 + qw422016.N().S(`up)`) +//line lib/promscrape/targetstatus.qtpl:220 + streamshowHideScrapeJobButtons(qw422016, num) +//line lib/promscrape/targetstatus.qtpl:220 + qw422016.N().S(`

`) +//line lib/promscrape/targetstatus.qtpl:238 + for _, ts := range jts.targetsStatus { +//line lib/promscrape/targetstatus.qtpl:240 + endpoint := ts.sw.Config.ScrapeURL + targetID := getTargetID(ts.sw) + lastScrapeDuration := ts.getDurationFromLastScrape() + +//line lib/promscrape/targetstatus.qtpl:243 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:279 + } +//line lib/promscrape/targetstatus.qtpl:279 + qw422016.N().S(`
EndpointStateLabelsScrapesErrorsLast ScrapeDurationSamplesLast error
`) +//line lib/promscrape/targetstatus.qtpl:246 + qw422016.E().S(endpoint) +//line lib/promscrape/targetstatus.qtpl:246 + qw422016.N().S(` (response)`) +//line lib/promscrape/targetstatus.qtpl:252 + if ts.up { +//line lib/promscrape/targetstatus.qtpl:252 + qw422016.N().S(`UP`) +//line lib/promscrape/targetstatus.qtpl:254 + } else { +//line lib/promscrape/targetstatus.qtpl:254 + qw422016.N().S(`DOWN`) +//line lib/promscrape/targetstatus.qtpl:256 + } +//line lib/promscrape/targetstatus.qtpl:256 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:261 + streamformatLabel(qw422016, promrelabel.FinalizeLabels(nil, ts.sw.Config.Labels)) +//line lib/promscrape/targetstatus.qtpl:261 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:267 + qw422016.N().D(ts.scrapesTotal) +//line lib/promscrape/targetstatus.qtpl:267 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:268 + qw422016.N().D(ts.scrapesFailed) +//line lib/promscrape/targetstatus.qtpl:268 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:270 + if lastScrapeDuration < 365*24*time.Hour { +//line lib/promscrape/targetstatus.qtpl:271 + qw422016.N().D(int(lastScrapeDuration.Milliseconds())) +//line lib/promscrape/targetstatus.qtpl:271 + qw422016.N().S(`ms ago`) +//line lib/promscrape/targetstatus.qtpl:272 + } else { +//line lib/promscrape/targetstatus.qtpl:272 + qw422016.N().S(`none`) +//line lib/promscrape/targetstatus.qtpl:274 + } +//line lib/promscrape/targetstatus.qtpl:274 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:275 + qw422016.N().D(int(ts.scrapeDuration)) +//line lib/promscrape/targetstatus.qtpl:275 + qw422016.N().S(`ms`) +//line lib/promscrape/targetstatus.qtpl:276 + qw422016.N().D(ts.samplesScraped) +//line lib/promscrape/targetstatus.qtpl:276 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:277 + if ts.err != nil { +//line lib/promscrape/targetstatus.qtpl:277 + qw422016.E().S(ts.err.Error()) +//line lib/promscrape/targetstatus.qtpl:277 + } +//line lib/promscrape/targetstatus.qtpl:277 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:285 +} + +//line lib/promscrape/targetstatus.qtpl:285 +func writescrapeJobTargets(qq422016 qtio422016.Writer, num int, jts *jobTargetsStatuses) { +//line lib/promscrape/targetstatus.qtpl:285 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:285 + streamscrapeJobTargets(qw422016, num, jts) +//line lib/promscrape/targetstatus.qtpl:285 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:285 +} + +//line lib/promscrape/targetstatus.qtpl:285 +func scrapeJobTargets(num int, jts *jobTargetsStatuses) string { +//line lib/promscrape/targetstatus.qtpl:285 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:285 + writescrapeJobTargets(qb422016, num, jts) +//line lib/promscrape/targetstatus.qtpl:285 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:285 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:285 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:285 +} + +//line lib/promscrape/targetstatus.qtpl:287 +func streamdiscoveredTargets(qw422016 *qt422016.Writer, tsr *targetsStatusResult) { +//line lib/promscrape/targetstatus.qtpl:288 + tljs := tsr.getTargetLabelsByJob() + +//line lib/promscrape/targetstatus.qtpl:288 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:291 + for i, tlj := range tljs { +//line lib/promscrape/targetstatus.qtpl:292 + streamdiscoveredJobTargets(qw422016, i, tlj) +//line lib/promscrape/targetstatus.qtpl:293 + } +//line lib/promscrape/targetstatus.qtpl:293 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:296 +} + +//line lib/promscrape/targetstatus.qtpl:296 +func writediscoveredTargets(qq422016 qtio422016.Writer, tsr *targetsStatusResult) { +//line lib/promscrape/targetstatus.qtpl:296 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:296 + streamdiscoveredTargets(qw422016, tsr) +//line lib/promscrape/targetstatus.qtpl:296 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:296 +} + +//line lib/promscrape/targetstatus.qtpl:296 +func discoveredTargets(tsr *targetsStatusResult) string { +//line lib/promscrape/targetstatus.qtpl:296 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:296 + writediscoveredTargets(qb422016, tsr) +//line lib/promscrape/targetstatus.qtpl:296 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:296 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:296 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:296 +} + +//line lib/promscrape/targetstatus.qtpl:298 +func streamdiscoveredJobTargets(qw422016 *qt422016.Writer, num int, tlj *targetLabelsByJob) { +//line lib/promscrape/targetstatus.qtpl:298 + qw422016.N().S(`

`) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.E().S(tlj.jobName) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.N().S(` `) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.N().S(`(`) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.N().D(tlj.activeTargets) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.N().S(`/`) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.N().D(tlj.activeTargets + tlj.droppedTargets) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.N().S(` `) +//line lib/promscrape/targetstatus.qtpl:300 + qw422016.N().S(`active)`) +//line lib/promscrape/targetstatus.qtpl:301 + streamshowHideScrapeJobButtons(qw422016, num) +//line lib/promscrape/targetstatus.qtpl:301 + qw422016.N().S(`

`) +//line lib/promscrape/targetstatus.qtpl:313 + for _, t := range tlj.targets { +//line lib/promscrape/targetstatus.qtpl:313 + qw422016.N().S(` 0 { +//line lib/promscrape/targetstatus.qtpl:317 + qw422016.N().S(`class="alert alert-danger"`) +//line lib/promscrape/targetstatus.qtpl:319 + } else { +//line lib/promscrape/targetstatus.qtpl:319 + qw422016.N().S(`class="alert alert-warning"`) +//line lib/promscrape/targetstatus.qtpl:321 + } +//line lib/promscrape/targetstatus.qtpl:322 + } +//line lib/promscrape/targetstatus.qtpl:322 + qw422016.N().S(`>`) +//line lib/promscrape/targetstatus.qtpl:340 + } +//line lib/promscrape/targetstatus.qtpl:340 + qw422016.N().S(`
StatusDiscovered LabelsTarget Labels
`) +//line lib/promscrape/targetstatus.qtpl:325 + if t.up { +//line lib/promscrape/targetstatus.qtpl:325 + qw422016.N().S(`UP`) +//line lib/promscrape/targetstatus.qtpl:327 + } else if len(t.labels) > 0 { +//line lib/promscrape/targetstatus.qtpl:327 + qw422016.N().S(`DOWN`) +//line lib/promscrape/targetstatus.qtpl:329 + } else { +//line lib/promscrape/targetstatus.qtpl:329 + qw422016.N().S(`DROPPED`) +//line lib/promscrape/targetstatus.qtpl:331 + } +//line lib/promscrape/targetstatus.qtpl:331 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:334 + streamformatLabel(qw422016, t.discoveredLabels) +//line lib/promscrape/targetstatus.qtpl:334 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:337 + streamformatLabel(qw422016, promrelabel.FinalizeLabels(nil, t.labels)) +//line lib/promscrape/targetstatus.qtpl:337 + qw422016.N().S(`
`) +//line lib/promscrape/targetstatus.qtpl:344 +} + +//line lib/promscrape/targetstatus.qtpl:344 +func writediscoveredJobTargets(qq422016 qtio422016.Writer, num int, tlj *targetLabelsByJob) { +//line lib/promscrape/targetstatus.qtpl:344 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:344 + streamdiscoveredJobTargets(qw422016, num, tlj) +//line lib/promscrape/targetstatus.qtpl:344 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:344 +} + +//line lib/promscrape/targetstatus.qtpl:344 +func discoveredJobTargets(num int, tlj *targetLabelsByJob) string { +//line lib/promscrape/targetstatus.qtpl:344 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:344 + writediscoveredJobTargets(qb422016, num, tlj) +//line lib/promscrape/targetstatus.qtpl:344 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:344 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:344 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:344 +} + +//line lib/promscrape/targetstatus.qtpl:346 +func streamshowHideScrapeJobButtons(qw422016 *qt422016.Writer, num int) { +//line lib/promscrape/targetstatus.qtpl:346 + qw422016.N().S(``) +//line lib/promscrape/targetstatus.qtpl:355 +} + +//line lib/promscrape/targetstatus.qtpl:355 +func writeshowHideScrapeJobButtons(qq422016 qtio422016.Writer, num int) { +//line lib/promscrape/targetstatus.qtpl:355 + qw422016 := qt422016.AcquireWriter(qq422016) +//line lib/promscrape/targetstatus.qtpl:355 + streamshowHideScrapeJobButtons(qw422016, num) +//line lib/promscrape/targetstatus.qtpl:355 + qt422016.ReleaseWriter(qw422016) +//line lib/promscrape/targetstatus.qtpl:355 +} + +//line lib/promscrape/targetstatus.qtpl:355 +func showHideScrapeJobButtons(num int) string { +//line lib/promscrape/targetstatus.qtpl:355 + qb422016 := qt422016.AcquireByteBuffer() +//line lib/promscrape/targetstatus.qtpl:355 + writeshowHideScrapeJobButtons(qb422016, num) +//line lib/promscrape/targetstatus.qtpl:355 + qs422016 := string(qb422016.B) +//line lib/promscrape/targetstatus.qtpl:355 + qt422016.ReleaseByteBuffer(qb422016) +//line lib/promscrape/targetstatus.qtpl:355 + return qs422016 +//line lib/promscrape/targetstatus.qtpl:355 +} + +//line lib/promscrape/targetstatus.qtpl:357 +func streamqueryArgs(qw422016 *qt422016.Writer, filter *requestFilter, override map[string]string) { +//line lib/promscrape/targetstatus.qtpl:359 + showOnlyUnhealthy := "false" + if filter.showOnlyUnhealthy { + showOnlyUnhealthy = "true" + } + m := map[string]string{ + "show_only_unhealthy": showOnlyUnhealthy, + "endpoint_search": filter.endpointSearch, + "label_search": filter.labelSearch, + } + for k, v := range override { + m[k] = v + } qa := make(url.Values, len(m)) for k, v := range m { qa[k] = []string{v} } -//line lib/promscrape/targetstatus.qtpl:224 +//line lib/promscrape/targetstatus.qtpl:376 qw422016.E().S(qa.Encode()) -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 } -//line lib/promscrape/targetstatus.qtpl:225 -func writequeryArgs(qq422016 qtio422016.Writer, m map[string]string) { -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 +func writequeryArgs(qq422016 qtio422016.Writer, filter *requestFilter, override map[string]string) { +//line lib/promscrape/targetstatus.qtpl:377 qw422016 := qt422016.AcquireWriter(qq422016) -//line lib/promscrape/targetstatus.qtpl:225 - streamqueryArgs(qw422016, m) -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 + streamqueryArgs(qw422016, filter, override) +//line lib/promscrape/targetstatus.qtpl:377 qt422016.ReleaseWriter(qw422016) -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 } -//line lib/promscrape/targetstatus.qtpl:225 -func queryArgs(m map[string]string) string { -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 +func queryArgs(filter *requestFilter, override map[string]string) string { +//line lib/promscrape/targetstatus.qtpl:377 qb422016 := qt422016.AcquireByteBuffer() -//line lib/promscrape/targetstatus.qtpl:225 - writequeryArgs(qb422016, m) -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 + writequeryArgs(qb422016, filter, override) +//line lib/promscrape/targetstatus.qtpl:377 qs422016 := string(qb422016.B) -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 qt422016.ReleaseByteBuffer(qb422016) -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 return qs422016 -//line lib/promscrape/targetstatus.qtpl:225 +//line lib/promscrape/targetstatus.qtpl:377 } -//line lib/promscrape/targetstatus.qtpl:227 +//line lib/promscrape/targetstatus.qtpl:379 func streamformatLabel(qw422016 *qt422016.Writer, labels []prompbmarshal.Label) { -//line lib/promscrape/targetstatus.qtpl:227 +//line lib/promscrape/targetstatus.qtpl:379 qw422016.N().S(`{`) -//line lib/promscrape/targetstatus.qtpl:229 +//line lib/promscrape/targetstatus.qtpl:381 for i, label := range labels { -//line lib/promscrape/targetstatus.qtpl:230 +//line lib/promscrape/targetstatus.qtpl:382 qw422016.E().S(label.Name) -//line lib/promscrape/targetstatus.qtpl:230 +//line lib/promscrape/targetstatus.qtpl:382 qw422016.N().S(`=`) -//line lib/promscrape/targetstatus.qtpl:230 +//line lib/promscrape/targetstatus.qtpl:382 qw422016.E().Q(label.Value) -//line lib/promscrape/targetstatus.qtpl:231 +//line lib/promscrape/targetstatus.qtpl:383 if i+1 < len(labels) { -//line lib/promscrape/targetstatus.qtpl:231 +//line lib/promscrape/targetstatus.qtpl:383 qw422016.N().S(`,`) -//line lib/promscrape/targetstatus.qtpl:231 +//line lib/promscrape/targetstatus.qtpl:383 qw422016.N().S(` `) -//line lib/promscrape/targetstatus.qtpl:231 +//line lib/promscrape/targetstatus.qtpl:383 } -//line lib/promscrape/targetstatus.qtpl:232 +//line lib/promscrape/targetstatus.qtpl:384 } -//line lib/promscrape/targetstatus.qtpl:232 +//line lib/promscrape/targetstatus.qtpl:384 qw422016.N().S(`}`) -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 } -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 func writeformatLabel(qq422016 qtio422016.Writer, labels []prompbmarshal.Label) { -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 qw422016 := qt422016.AcquireWriter(qq422016) -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 streamformatLabel(qw422016, labels) -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 qt422016.ReleaseWriter(qw422016) -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 } -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 func formatLabel(labels []prompbmarshal.Label) string { -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 qb422016 := qt422016.AcquireByteBuffer() -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 writeformatLabel(qb422016, labels) -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 qs422016 := string(qb422016.B) -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 qt422016.ReleaseByteBuffer(qb422016) -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 return qs422016 -//line lib/promscrape/targetstatus.qtpl:234 +//line lib/promscrape/targetstatus.qtpl:386 } -//line lib/promscrape/targetstatus.qtpl:236 +//line lib/promscrape/targetstatus.qtpl:388 func streamerrorNotification(qw422016 *qt422016.Writer, err error) { -//line lib/promscrape/targetstatus.qtpl:236 +//line lib/promscrape/targetstatus.qtpl:388 qw422016.N().S(``) -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 } -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 func writeerrorNotification(qq422016 qtio422016.Writer, err error) { -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 qw422016 := qt422016.AcquireWriter(qq422016) -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 streamerrorNotification(qw422016, err) -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 qt422016.ReleaseWriter(qw422016) -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 } -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 func errorNotification(err error) string { -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 qb422016 := qt422016.AcquireByteBuffer() -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 writeerrorNotification(qb422016, err) -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 qs422016 := string(qb422016.B) -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 qt422016.ReleaseByteBuffer(qb422016) -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 return qs422016 -//line lib/promscrape/targetstatus.qtpl:244 +//line lib/promscrape/targetstatus.qtpl:396 } diff --git a/lib/querytracer/tracer.go b/lib/querytracer/tracer.go index 0e22234c3d..a6467973af 100644 --- a/lib/querytracer/tracer.go +++ b/lib/querytracer/tracer.go @@ -15,16 +15,16 @@ var denyQueryTracing = flag.Bool("denyQueryTracing", false, "Whether to disable // Tracer represents query tracer. // // It must be created via New call. -// Each created tracer must be finalized via Donef call. +// Each created tracer must be finalized via Done or Donef call. // // Tracer may contain sub-tracers (branches) in order to build tree-like execution order. // Call Tracer.NewChild func for adding sub-tracer. type Tracer struct { // startTime is the time when Tracer was created startTime time.Time - // doneTime is the time when Donef was called + // doneTime is the time when Done or Donef was called doneTime time.Time - // message is the message generated by Printf or Donef call. + // message is the message generated by NewChild, Printf or Donef call. message string // children is a list of children Tracer objects children []*Tracer @@ -33,16 +33,17 @@ type Tracer struct { span *span } -// New creates a new instance of the tracer. +// New creates a new instance of the tracer with the given fmt.Sprintf(format, args...) message. // // If enabled isn't set, then all function calls to the returned object will be no-op. // -// Donef must be called when the tracer should be finished. -func New(enabled bool) *Tracer { +// Done or Donef must be called when the tracer should be finished. +func New(enabled bool, format string, args ...interface{}) *Tracer { if *denyQueryTracing || !enabled { return nil } return &Tracer{ + message: fmt.Sprintf(format, args...), startTime: time.Now(), } } @@ -52,26 +53,43 @@ func (t *Tracer) Enabled() bool { return t != nil } -// NewChild adds a new child Tracer to t. +// NewChild adds a new child Tracer to t with the given fmt.Sprintf(format, args...) message. +// +// The returned child must be closed via Done or Donef calls. // // NewChild cannot be called from concurrent goroutines. // Create children tracers from a single goroutine and then pass them // to concurrent goroutines. -func (t *Tracer) NewChild() *Tracer { +func (t *Tracer) NewChild(format string, args ...interface{}) *Tracer { if t == nil { return nil } - if t.message != "" { + if !t.doneTime.IsZero() { panic(fmt.Errorf("BUG: NewChild() cannot be called after Donef(%q) call", t.message)) } child := &Tracer{ + message: fmt.Sprintf(format, args...), startTime: time.Now(), } t.children = append(t.children, child) return child } -// Donef finishes t. +// Done finishes t. +// +// Done cannot be called multiple times. +// Other Tracer functions cannot be called after Done call. +func (t *Tracer) Done() { + if t == nil { + return + } + if !t.doneTime.IsZero() { + panic(fmt.Errorf("BUG: Donef(%q) already called", t.message)) + } + t.doneTime = time.Now() +} + +// Donef appends the given fmt.Sprintf(format, args..) message to t and finished it. // // Donef cannot be called multiple times. // Other Tracer functions cannot be called after Donef call. @@ -79,21 +97,21 @@ func (t *Tracer) Donef(format string, args ...interface{}) { if t == nil { return } - if t.message != "" { - panic(fmt.Errorf("BUG: Donef() already called with message %q", t.message)) + if !t.doneTime.IsZero() { + panic(fmt.Errorf("BUG: Donef(%q) already called", t.message)) } - t.message = fmt.Sprintf(format, args...) + t.message += ": " + fmt.Sprintf(format, args...) t.doneTime = time.Now() } -// Printf adds new message to t. +// Printf adds new fmt.Sprintf(format, args...) message to t. // // Printf cannot be called from concurrent goroutines. func (t *Tracer) Printf(format string, args ...interface{}) { if t == nil { return } - if t.message != "" { + if !t.doneTime.IsZero() { panic(fmt.Errorf("BUG: Printf() cannot be called after Done(%q) call", t.message)) } now := time.Now() @@ -177,8 +195,8 @@ func (t *Tracer) toSpanInternal(prevTime time.Time) (*span, time.Time) { // tracer with children msg := t.message doneTime := t.doneTime - if msg == "" { - msg = "missing Tracer.Donef() call" + if doneTime.IsZero() { + msg += ": missing Tracer.Done() call" doneTime = t.getLastChildDoneTime(t.startTime) } d := doneTime.Sub(t.startTime) diff --git a/lib/querytracer/tracer_test.go b/lib/querytracer/tracer_test.go index 8e8660aa55..fa278d2b70 100644 --- a/lib/querytracer/tracer_test.go +++ b/lib/querytracer/tracer_test.go @@ -6,21 +6,21 @@ import ( ) func TestTracerDisabled(t *testing.T) { - qt := New(false) + qt := New(false, "test") if qt.Enabled() { t.Fatalf("query tracer must be disabled") } - qtChild := qt.NewChild() + qtChild := qt.NewChild("child done %d", 456) if qtChild.Enabled() { t.Fatalf("query tracer must be disabled") } qtChild.Printf("foo %d", 123) - qtChild.Donef("child done %d", 456) + qtChild.Done() qt.Printf("parent %d", 789) if err := qt.AddJSON([]byte("foobar")); err != nil { t.Fatalf("unexpected error in AddJSON: %s", err) } - qt.Donef("test") + qt.Done() s := qt.String() if s != "" { t.Fatalf("unexpected trace; got %s; want empty", s) @@ -32,20 +32,20 @@ func TestTracerDisabled(t *testing.T) { } func TestTracerEnabled(t *testing.T) { - qt := New(true) + qt := New(true, "test") if !qt.Enabled() { t.Fatalf("query tracer must be enabled") } - qtChild := qt.NewChild() + qtChild := qt.NewChild("child done %d", 456) if !qtChild.Enabled() { t.Fatalf("child query tracer must be enabled") } qtChild.Printf("foo %d", 123) - qtChild.Donef("child done %d", 456) + qtChild.Done() qt.Printf("parent %d", 789) - qt.Donef("test") + qt.Donef("foo %d", 33) s := qt.String() - sExpected := `- 0ms: test + sExpected := `- 0ms: test: foo 33 | - 0ms: child done 456 | | - 0ms: foo 123 | - 0ms: parent 789 @@ -56,9 +56,9 @@ func TestTracerEnabled(t *testing.T) { } func TestTracerMultiline(t *testing.T) { - qt := New(true) + qt := New(true, "line1\nline2") qt.Printf("line3\nline4\n") - qt.Donef("line1\nline2") + qt.Done() s := qt.String() sExpected := `- 0ms: line1 | line2 @@ -71,18 +71,18 @@ func TestTracerMultiline(t *testing.T) { } func TestTracerToJSON(t *testing.T) { - qt := New(true) + qt := New(true, "test") if !qt.Enabled() { t.Fatalf("query tracer must be enabled") } - qtChild := qt.NewChild() + qtChild := qt.NewChild("child done %d", 456) if !qtChild.Enabled() { t.Fatalf("child query tracer must be enabled") } qtChild.Printf("foo %d", 123) - qtChild.Donef("child done %d", 456) + qtChild.Done() qt.Printf("parent %d", 789) - qt.Donef("test") + qt.Done() s := qt.ToJSON() sExpected := `{"duration_msec":0,"message":"test","children":[` + `{"duration_msec":0,"message":"child done 456","children":[` + @@ -94,11 +94,11 @@ func TestTracerToJSON(t *testing.T) { } func TestTraceAddJSON(t *testing.T) { - qtChild := New(true) + qtChild := New(true, "child") qtChild.Printf("foo") - qtChild.Donef("child") + qtChild.Done() jsonTrace := qtChild.ToJSON() - qt := New(true) + qt := New(true, "parent") qt.Printf("first_line") if err := qt.AddJSON([]byte(jsonTrace)); err != nil { t.Fatalf("unexpected error in AddJSON: %s", err) @@ -107,7 +107,7 @@ func TestTraceAddJSON(t *testing.T) { if err := qt.AddJSON(nil); err != nil { t.Fatalf("unexpected error in AddJSON(nil): %s", err) } - qt.Donef("parent") + qt.Done() s := qt.String() sExpected := `- 0ms: parent | - 0ms: first_line @@ -131,15 +131,15 @@ func TestTraceAddJSON(t *testing.T) { } func TestTraceMissingDonef(t *testing.T) { - qt := New(true) + qt := New(true, "parent") qt.Printf("parent printf") - qtChild := qt.NewChild() + qtChild := qt.NewChild("child") qtChild.Printf("child printf") qt.Printf("another parent printf") s := qt.String() - sExpected := `- 0ms: missing Tracer.Donef() call + sExpected := `- 0ms: parent: missing Tracer.Done() call | - 0ms: parent printf -| - 0ms: missing Tracer.Donef() call +| - 0ms: child: missing Tracer.Done() call | | - 0ms: child printf | - 0ms: another parent printf ` diff --git a/lib/storage/index_db.go b/lib/storage/index_db.go index 2794767edc..c08f7e7823 100644 --- a/lib/storage/index_db.go +++ b/lib/storage/index_db.go @@ -25,7 +25,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/uint64set" "github.com/VictoriaMetrics/VictoriaMetrics/lib/workingsetcache" "github.com/VictoriaMetrics/fastcache" - xxhash "github.com/cespare/xxhash/v2" + "github.com/cespare/xxhash/v2" ) const ( @@ -1381,6 +1381,7 @@ func (is *indexSearch) getTSDBStatusWithFiltersForDate(tfss []*TagFilters, date thSeriesCountByMetricName := newTopHeap(topN) var tmp, labelName, labelNameValue []byte var labelValueCountByLabelName, seriesCountByLabelValuePair uint64 + var totalSeries, totalLabelValuePairs uint64 nameEqualBytes := []byte("__name__=") loopsPaceLimiter := 0 @@ -1421,50 +1422,57 @@ func (is *indexSearch) getTSDBStatusWithFiltersForDate(tfss []*TagFilters, date if err != nil { return nil, fmt.Errorf("cannot unmarshal tag key from line %q: %w", item, err) } - if isArtificialTagKey(tmp) { + tagKey := tmp + if isArtificialTagKey(tagKey) { // Skip artificially created tag keys. kb.B = append(kb.B[:0], prefix...) - if len(tmp) > 0 && tmp[0] == compositeTagKeyPrefix { + if len(tagKey) > 0 && tagKey[0] == compositeTagKeyPrefix { kb.B = append(kb.B, compositeTagKeyPrefix) } else { - kb.B = marshalTagValue(kb.B, tmp) + kb.B = marshalTagValue(kb.B, tagKey) } kb.B[len(kb.B)-1]++ ts.Seek(kb.B) continue } - if len(tmp) == 0 { - tmp = append(tmp, "__name__"...) - } - if !bytes.Equal(tmp, labelName) { - thLabelValueCountByLabelName.pushIfNonEmpty(labelName, labelValueCountByLabelName) - labelValueCountByLabelName = 0 - labelName = append(labelName[:0], tmp...) + if len(tagKey) == 0 { + tagKey = append(tagKey, "__name__"...) + tmp = tagKey } tmp = append(tmp, '=') tail, tmp, err = unmarshalTagValue(tmp, tail) if err != nil { return nil, fmt.Errorf("cannot unmarshal tag value from line %q: %w", item, err) } - if !bytes.Equal(tmp, labelNameValue) { - thSeriesCountByLabelValuePair.pushIfNonEmpty(labelNameValue, seriesCountByLabelValuePair) - if bytes.HasPrefix(labelNameValue, nameEqualBytes) { - thSeriesCountByMetricName.pushIfNonEmpty(labelNameValue[len(nameEqualBytes):], seriesCountByLabelValuePair) - } - seriesCountByLabelValuePair = 0 - labelValueCountByLabelName++ - labelNameValue = append(labelNameValue[:0], tmp...) - } + tagKeyValue := tmp if filter == nil { if err := mp.InitOnlyTail(item, tail); err != nil { return nil, err } matchingSeriesCount = mp.MetricIDsLen() } + if string(tagKey) == "__name__" { + totalSeries += uint64(matchingSeriesCount) + } + if !bytes.Equal(tagKey, labelName) { + thLabelValueCountByLabelName.pushIfNonEmpty(labelName, labelValueCountByLabelName) + labelValueCountByLabelName = 0 + labelName = append(labelName[:0], tagKey...) + } + if !bytes.Equal(tagKeyValue, labelNameValue) { + thSeriesCountByLabelValuePair.pushIfNonEmpty(labelNameValue, seriesCountByLabelValuePair) + if bytes.HasPrefix(labelNameValue, nameEqualBytes) { + thSeriesCountByMetricName.pushIfNonEmpty(labelNameValue[len(nameEqualBytes):], seriesCountByLabelValuePair) + } + seriesCountByLabelValuePair = 0 + labelValueCountByLabelName++ + labelNameValue = append(labelNameValue[:0], tagKeyValue...) + } // Take into account deleted timeseries too. // It is OK if series can be counted multiple times in rare cases - // the returned number is an estimation. seriesCountByLabelValuePair += uint64(matchingSeriesCount) + totalLabelValuePairs += uint64(matchingSeriesCount) } if err := ts.Error(); err != nil { return nil, fmt.Errorf("error when counting time series by metric names: %w", err) @@ -1478,6 +1486,8 @@ func (is *indexSearch) getTSDBStatusWithFiltersForDate(tfss []*TagFilters, date SeriesCountByMetricName: thSeriesCountByMetricName.getSortedResult(), LabelValueCountByLabelName: thLabelValueCountByLabelName.getSortedResult(), SeriesCountByLabelValuePair: thSeriesCountByLabelValuePair.getSortedResult(), + TotalSeries: totalSeries, + TotalLabelValuePairs: totalLabelValuePairs, } return status, nil } @@ -1486,6 +1496,8 @@ func (is *indexSearch) getTSDBStatusWithFiltersForDate(tfss []*TagFilters, date // // See https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-stats type TSDBStatus struct { + TotalSeries uint64 + TotalLabelValuePairs uint64 SeriesCountByMetricName []TopHeapEntry LabelValueCountByLabelName []TopHeapEntry SeriesCountByLabelValuePair []TopHeapEntry diff --git a/lib/storage/index_db_test.go b/lib/storage/index_db_test.go index a5664e043a..a943c174f0 100644 --- a/lib/storage/index_db_test.go +++ b/lib/storage/index_db_test.go @@ -1832,6 +1832,14 @@ func TestSearchTSIDWithTimeRange(t *testing.T) { if !reflect.DeepEqual(status.SeriesCountByLabelValuePair, expectedSeriesCountByLabelValuePair) { t.Fatalf("unexpected SeriesCountByLabelValuePair;\ngot\n%v\nwant\n%v", status.SeriesCountByLabelValuePair, expectedSeriesCountByLabelValuePair) } + expectedTotalSeries := uint64(1000) + if status.TotalSeries != expectedTotalSeries { + t.Fatalf("unexpected TotalSeries; got %d; want %d", status.TotalSeries, expectedTotalSeries) + } + expectedLabelValuePairs := uint64(4000) + if status.TotalLabelValuePairs != expectedLabelValuePairs { + t.Fatalf("unexpected TotalLabelValuePairs; got %d; want %d", status.TotalLabelValuePairs, expectedLabelValuePairs) + } // Check GetTSDBStatusWithFiltersForDate tfs = NewTagFilters() @@ -1854,6 +1862,43 @@ func TestSearchTSIDWithTimeRange(t *testing.T) { if !reflect.DeepEqual(status.SeriesCountByMetricName, expectedSeriesCountByMetricName) { t.Fatalf("unexpected SeriesCountByMetricName;\ngot\n%v\nwant\n%v", status.SeriesCountByMetricName, expectedSeriesCountByMetricName) } + expectedTotalSeries = 1000 + if status.TotalSeries != expectedTotalSeries { + t.Fatalf("unexpected TotalSeries; got %d; want %d", status.TotalSeries, expectedTotalSeries) + } + expectedLabelValuePairs = 4000 + if status.TotalLabelValuePairs != expectedLabelValuePairs { + t.Fatalf("unexpected TotalLabelValuePairs; got %d; want %d", status.TotalLabelValuePairs, expectedLabelValuePairs) + } + // Check GetTSDBStatusWithFiltersForDate + tfs = NewTagFilters() + if err := tfs.Add([]byte("uniqueid"), []byte("0|1|3"), false, true); err != nil { + t.Fatalf("cannot add filter: %s", err) + } + status, err = db.GetTSDBStatusWithFiltersForDate([]*TagFilters{tfs}, baseDate, 5, 1e6, noDeadline) + if err != nil { + t.Fatalf("error in GetTSDBStatusWithFiltersForDate: %s", err) + } + if !status.hasEntries() { + t.Fatalf("expecting non-empty TSDB status") + } + expectedSeriesCountByMetricName = []TopHeapEntry{ + { + Name: "testMetric", + Count: 3, + }, + } + if !reflect.DeepEqual(status.SeriesCountByMetricName, expectedSeriesCountByMetricName) { + t.Fatalf("unexpected SeriesCountByMetricName;\ngot\n%v\nwant\n%v", status.SeriesCountByMetricName, expectedSeriesCountByMetricName) + } + expectedTotalSeries = 3 + if status.TotalSeries != expectedTotalSeries { + t.Fatalf("unexpected TotalSeries; got %d; want %d", status.TotalSeries, expectedTotalSeries) + } + expectedLabelValuePairs = 12 + if status.TotalLabelValuePairs != expectedLabelValuePairs { + t.Fatalf("unexpected TotalLabelValuePairs; got %d; want %d", status.TotalLabelValuePairs, expectedLabelValuePairs) + } } func toTFPointers(tfs []tagFilter) []*tagFilter { diff --git a/lib/storage/partition.go b/lib/storage/partition.go index d6aa984708..c9852b227c 100644 --- a/lib/storage/partition.go +++ b/lib/storage/partition.go @@ -869,10 +869,18 @@ func hasActiveMerges(pws []*partWrapper) bool { } var ( - bigMergeWorkersCount = (cgroup.AvailableCPUs() + 1) / 2 - smallMergeWorkersCount = (cgroup.AvailableCPUs() + 1) / 2 + bigMergeWorkersCount = getDefaultMergeConcurrency(4) + smallMergeWorkersCount = getDefaultMergeConcurrency(8) ) +func getDefaultMergeConcurrency(max int) int { + v := (cgroup.AvailableCPUs() + 1) / 2 + if v > max { + v = max + } + return v +} + // SetBigMergeWorkersCount sets the maximum number of concurrent mergers for big blocks. // // The function must be called before opening or creating any storage. diff --git a/lib/storage/search.go b/lib/storage/search.go index d74788e218..761b198456 100644 --- a/lib/storage/search.go +++ b/lib/storage/search.go @@ -141,8 +141,8 @@ func (s *Search) reset() { // // Init returns the upper bound on the number of found time series. func (s *Search) Init(qt *querytracer.Tracer, storage *Storage, tfss []*TagFilters, tr TimeRange, maxMetrics int, deadline uint64) int { - qt = qt.NewChild() - defer qt.Donef("init series search: filters=%s, timeRange=%s", tfss, &tr) + qt = qt.NewChild("init series search: filters=%s, timeRange=%s", tfss, &tr) + defer qt.Done() if s.needClosing { logger.Panicf("BUG: missing MustClose call before the next call to Init") } diff --git a/lib/storage/storage.go b/lib/storage/storage.go index 6807efca2d..f968d0663e 100644 --- a/lib/storage/storage.go +++ b/lib/storage/storage.go @@ -1061,8 +1061,8 @@ func nextRetentionDuration(retentionMsecs int64) time.Duration { // SearchMetricNames returns metric names matching the given tfss on the given tr. func (s *Storage) SearchMetricNames(qt *querytracer.Tracer, tfss []*TagFilters, tr TimeRange, maxMetrics int, deadline uint64) ([]MetricName, error) { - qt = qt.NewChild() - defer qt.Donef("search for matching metric names") + qt = qt.NewChild("search for matching metric names") + defer qt.Done() tsids, err := s.searchTSIDs(qt, tfss, tr, maxMetrics, deadline) if err != nil { return nil, err @@ -1104,8 +1104,8 @@ func (s *Storage) SearchMetricNames(qt *querytracer.Tracer, tfss []*TagFilters, // searchTSIDs returns sorted TSIDs for the given tfss and the given tr. func (s *Storage) searchTSIDs(qt *querytracer.Tracer, tfss []*TagFilters, tr TimeRange, maxMetrics int, deadline uint64) ([]TSID, error) { - qt = qt.NewChild() - defer qt.Donef("search for matching series ids") + qt = qt.NewChild("search for matching series ids") + defer qt.Done() // Do not cache tfss -> tsids here, since the caching is performed // on idb level. @@ -1154,8 +1154,8 @@ var ( // // This should speed-up further searchMetricNameWithCache calls for metricIDs from tsids. func (s *Storage) prefetchMetricNames(qt *querytracer.Tracer, tsids []TSID, deadline uint64) error { - qt = qt.NewChild() - defer qt.Donef("prefetch metric names for %d series ids", len(tsids)) + qt = qt.NewChild("prefetch metric names for %d series ids", len(tsids)) + defer qt.Done() if len(tsids) == 0 { qt.Printf("nothing to prefetch") return nil 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 40db8fd32f..beccfc7f6f 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 @@ -1937,9 +1937,15 @@ var awsPartition = partition{ }, "app-integrations": service{ Endpoints: serviceEndpoints{ + endpointKey{ + Region: "af-south-1", + }: endpoint{}, endpointKey{ Region: "ap-northeast-1", }: endpoint{}, + endpointKey{ + Region: "ap-northeast-2", + }: endpoint{}, endpointKey{ Region: "ap-southeast-1", }: endpoint{}, 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 6ef78c5c6a..6fac339edc 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.24" +const SDKVersion = "1.44.27" diff --git a/vendor/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md index 615c34e139..5c3c2a2580 100644 --- a/vendor/github.com/klauspost/compress/README.md +++ b/vendor/github.com/klauspost/compress/README.md @@ -17,6 +17,18 @@ This package provides various compression algorithms. # changelog +* May 25, 2022 (v1.15.5) + * s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602 + * s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601 + * huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596 + * zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588 + * zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592 + * zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599 + * zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593 + * huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586 + * flate: Inplace hashing for level 7-9 by @klauspost in https://github.com/klauspost/compress/pull/590 + + * May 11, 2022 (v1.15.4) * huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577) * inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581) @@ -83,6 +95,9 @@ While the release has been extensively tested, it is recommended to testing when * zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464) * Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445) +
+ See changes to v1.13.x + * Aug 30, 2021 (v1.13.5) * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425) * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413) @@ -111,6 +126,8 @@ While the release has been extensively tested, it is recommended to testing when * Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors. * zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382) * zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380) +
+
See changes to v1.12.x diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go index 602c05ee0c..c769f6941d 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_better.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go @@ -156,8 +156,8 @@ encodeLoop: panic("offset0 was 0") } - nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) candidateL := e.longTable[nextHashL] candidateS := e.table[nextHashS] @@ -518,8 +518,8 @@ encodeLoop: } // Store this, since we have it. - nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) // We have at least 4 byte match. // No need to check backwards. We come straight from a match @@ -674,8 +674,8 @@ encodeLoop: panic("offset0 was 0") } - nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) candidateL := e.longTable[nextHashL] candidateS := e.table[nextHashS] @@ -1047,8 +1047,8 @@ encodeLoop: } // Store this, since we have it. - nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) // We have at least 4 byte match. // No need to check backwards. We come straight from a match diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go index d6b3104240..7ff0c64fa3 100644 --- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go +++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go @@ -127,8 +127,8 @@ encodeLoop: panic("offset0 was 0") } - nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) candidateL := e.longTable[nextHashL] candidateS := e.table[nextHashS] @@ -439,8 +439,8 @@ encodeLoop: var t int32 for { - nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) candidateL := e.longTable[nextHashL] candidateS := e.table[nextHashS] @@ -785,8 +785,8 @@ encodeLoop: panic("offset0 was 0") } - nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) candidateL := e.longTable[nextHashL] candidateS := e.table[nextHashS] @@ -969,7 +969,7 @@ encodeLoop: te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)} te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)} longHash1 := hashLen(cv0, dFastLongTableBits, dFastLongLen) - longHash2 := hashLen(cv0, dFastLongTableBits, dFastLongLen) + longHash2 := hashLen(cv1, dFastLongTableBits, dFastLongLen) e.longTable[longHash1] = te0 e.longTable[longHash2] = te1 e.markLongShardDirty(longHash1) @@ -1002,8 +1002,8 @@ encodeLoop: } // Store this, since we have it. - nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) // We have at least 4 byte match. // No need to check backwards. We come straight from a match diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go index dcc987a7cb..e6b1d01cf6 100644 --- a/vendor/github.com/klauspost/compress/zstd/encoder.go +++ b/vendor/github.com/klauspost/compress/zstd/encoder.go @@ -551,7 +551,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte { } // If we can do everything in one block, prefer that. - if len(src) <= maxCompressedBlockSize { + if len(src) <= e.o.blockSize { enc.Reset(e.o.dict, true) // Slightly faster with no history and everything in one block. if e.o.crc { diff --git a/vendor/github.com/klauspost/compress/zstd/zip.go b/vendor/github.com/klauspost/compress/zstd/zip.go index b53f606a18..29c15c8c4e 100644 --- a/vendor/github.com/klauspost/compress/zstd/zip.go +++ b/vendor/github.com/klauspost/compress/zstd/zip.go @@ -18,7 +18,14 @@ const ZipMethodWinZip = 93 // See https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT const ZipMethodPKWare = 20 -var zipReaderPool sync.Pool +// zipReaderPool is the default reader pool. +var zipReaderPool = sync.Pool{New: func() interface{} { + z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1)) + if err != nil { + panic(err) + } + return z +}} // newZipReader creates a pooled zip decompressor. func newZipReader(opts ...DOption) func(r io.Reader) io.ReadCloser { diff --git a/vendor/golang.org/x/net/http2/writesched_priority.go b/vendor/golang.org/x/net/http2/writesched_priority.go index 2618b2c11d..0a242c669e 100644 --- a/vendor/golang.org/x/net/http2/writesched_priority.go +++ b/vendor/golang.org/x/net/http2/writesched_priority.go @@ -383,16 +383,15 @@ func (ws *priorityWriteScheduler) AdjustStream(streamID uint32, priority Priorit func (ws *priorityWriteScheduler) Push(wr FrameWriteRequest) { var n *priorityNode - if id := wr.StreamID(); id == 0 { + if wr.isControl() { n = &ws.root } else { + id := wr.StreamID() n = ws.nodes[id] if n == nil { // id is an idle or closed stream. wr should not be a HEADERS or - // DATA frame. However, wr can be a RST_STREAM. In this case, we - // push wr onto the root, rather than creating a new priorityNode, - // since RST_STREAM is tiny and the stream's priority is unknown - // anyway. See issue #17919. + // DATA frame. In other case, we push wr onto the root, rather + // than creating a new priorityNode. if wr.DataSize() > 0 { panic("add DATA on non-open stream") } diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index 1eab2fdf93..4c0850a45a 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -17,7 +17,8 @@ type token struct{} // A Group is a collection of goroutines working on subtasks that are part of // the same overall task. // -// A zero Group is valid and does not cancel on error. +// A zero Group is valid, has no limit on the number of active goroutines, +// and does not cancel on error. type Group struct { cancel func() diff --git a/vendor/google.golang.org/api/internal/version.go b/vendor/google.golang.org/api/internal/version.go index 060319e1ba..a382d160a6 100644 --- a/vendor/google.golang.org/api/internal/version.go +++ b/vendor/google.golang.org/api/internal/version.go @@ -5,4 +5,4 @@ package internal // Version is the current tagged release of the library. -const Version = "0.81.0" +const Version = "0.82.0" diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index ea9836d28b..de6d41c238 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -801,16 +801,31 @@ func (ac *addrConn) connect() error { return nil } +func equalAddresses(a, b []resolver.Address) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if !v.Equal(b[i]) { + return false + } + } + return true +} + // tryUpdateAddrs tries to update ac.addrs with the new addresses list. // -// If ac is Connecting, it returns false. The caller should tear down the ac and -// create a new one. Note that the backoff will be reset when this happens. -// // If ac is TransientFailure, it updates ac.addrs and returns true. The updated // addresses will be picked up by retry in the next iteration after backoff. // // If ac is Shutdown or Idle, it updates ac.addrs and returns true. // +// If the addresses is the same as the old list, it does nothing and returns +// true. +// +// If ac is Connecting, it returns false. The caller should tear down the ac and +// create a new one. Note that the backoff will be reset when this happens. +// // If ac is Ready, it checks whether current connected address of ac is in the // new addrs list. // - If true, it updates ac.addrs and returns true. The ac will keep using @@ -827,6 +842,10 @@ func (ac *addrConn) tryUpdateAddrs(addrs []resolver.Address) bool { return true } + if equalAddresses(ac.addrs, addrs) { + return true + } + if ac.state == connectivity.Connecting { return false } @@ -1219,6 +1238,7 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne ac.mu.Lock() defer ac.mu.Unlock() defer connClosed.Fire() + defer hcancel() if !hcStarted || hctx.Err() != nil { // We didn't start the health check or set the state to READY, so // no need to do anything else here. @@ -1229,7 +1249,6 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne // state, since there may be a new transport in this addrConn. return } - hcancel() ac.transport = nil // Refresh the name resolver ac.cc.resolveNow(resolver.ResolveNowOptions{}) @@ -1252,6 +1271,7 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, func() { prefaceReceived.Fire() }, onGoAway, onClose) if err != nil { // newTr is either nil, or closed. + hcancel() channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %s. Err: %v", addr, err) return err } diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go index 6d84f74c7d..18e530fc90 100644 --- a/vendor/google.golang.org/grpc/encoding/encoding.go +++ b/vendor/google.golang.org/grpc/encoding/encoding.go @@ -108,7 +108,7 @@ var registeredCodecs = make(map[string]Codec) // more details. // // NOTE: this function must only be called during initialization time (i.e. in -// an init() function), and is not thread-safe. If multiple Compressors are +// an init() function), and is not thread-safe. If multiple Codecs are // registered with the same name, the one registered last will take effect. func RegisterCodec(codec Codec) { if codec == nil { diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go index 8394d252df..244f4b081d 100644 --- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go +++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go @@ -137,6 +137,7 @@ type earlyAbortStream struct { streamID uint32 contentSubtype string status *status.Status + rst bool } func (*earlyAbortStream) isTransportResponseFrame() bool { return false } @@ -786,6 +787,11 @@ func (l *loopyWriter) earlyAbortStreamHandler(eas *earlyAbortStream) error { if err := l.writeHeader(eas.streamID, true, headerFields, nil); err != nil { return err } + if eas.rst { + if err := l.framer.fr.WriteRSTStream(eas.streamID, http2.ErrCodeNo); err != nil { + return err + } + } return nil } diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index 0956b500c1..45d7bd145e 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -21,7 +21,6 @@ package transport import ( "bytes" "context" - "errors" "fmt" "io" "math" @@ -53,10 +52,10 @@ import ( var ( // ErrIllegalHeaderWrite indicates that setting header is illegal because of // the stream's state. - ErrIllegalHeaderWrite = errors.New("transport: the stream is done or WriteHeader was already called") + ErrIllegalHeaderWrite = status.Error(codes.Internal, "transport: SendHeader called multiple times") // ErrHeaderListSizeLimitViolation indicates that the header list size is larger // than the limit set by peer. - ErrHeaderListSizeLimitViolation = errors.New("transport: trying to send header list size larger than the limit set by peer") + ErrHeaderListSizeLimitViolation = status.Error(codes.Internal, "transport: trying to send header list size larger than the limit set by peer") ) // serverConnectionCounter counts the number of connections a server has seen @@ -449,6 +448,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( streamID: streamID, contentSubtype: s.contentSubtype, status: status.New(codes.Internal, errMsg), + rst: !frame.StreamEnded(), }) return false } @@ -522,14 +522,16 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( } if httpMethod != http.MethodPost { t.mu.Unlock() + errMsg := fmt.Sprintf("http2Server.operateHeaders parsed a :method field: %v which should be POST", httpMethod) if logger.V(logLevel) { - logger.Infof("transport: http2Server.operateHeaders parsed a :method field: %v which should be POST", httpMethod) + logger.Infof("transport: %v", errMsg) } - t.controlBuf.put(&cleanupStream{ - streamID: streamID, - rst: true, - rstCode: http2.ErrCodeProtocol, - onWrite: func() {}, + t.controlBuf.put(&earlyAbortStream{ + httpStatus: 405, + streamID: streamID, + contentSubtype: s.contentSubtype, + status: status.New(codes.Internal, errMsg), + rst: !frame.StreamEnded(), }) s.cancel() return false @@ -550,6 +552,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( streamID: s.id, contentSubtype: s.contentSubtype, status: stat, + rst: !frame.StreamEnded(), }) return false } @@ -931,11 +934,25 @@ func (t *http2Server) checkForHeaderListSize(it interface{}) bool { return true } +func (t *http2Server) streamContextErr(s *Stream) error { + select { + case <-t.done: + return ErrConnClosing + default: + } + return ContextErr(s.ctx.Err()) +} + // WriteHeader sends the header metadata md back to the client. func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { - if s.updateHeaderSent() || s.getState() == streamDone { + if s.updateHeaderSent() { return ErrIllegalHeaderWrite } + + if s.getState() == streamDone { + return t.streamContextErr(s) + } + s.hdrMu.Lock() if md.Len() > 0 { if s.header.Len() > 0 { @@ -946,7 +963,7 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { } if err := t.writeHeaderLocked(s); err != nil { s.hdrMu.Unlock() - return err + return status.Convert(err).Err() } s.hdrMu.Unlock() return nil @@ -1062,23 +1079,12 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { func (t *http2Server) Write(s *Stream, hdr []byte, data []byte, opts *Options) error { if !s.isHeaderSent() { // Headers haven't been written yet. if err := t.WriteHeader(s, nil); err != nil { - if _, ok := err.(ConnectionError); ok { - return err - } - // TODO(mmukhi, dfawley): Make sure this is the right code to return. - return status.Errorf(codes.Internal, "transport: %v", err) + return err } } else { // Writing headers checks for this condition. if s.getState() == streamDone { - // TODO(mmukhi, dfawley): Should the server write also return io.EOF? - s.cancel() - select { - case <-t.done: - return ErrConnClosing - default: - } - return ContextErr(s.ctx.Err()) + return t.streamContextErr(s) } } df := &dataFrame{ @@ -1088,12 +1094,7 @@ func (t *http2Server) Write(s *Stream, hdr []byte, data []byte, opts *Options) e onEachWrite: t.setResetPingStrikes, } if err := s.wq.get(int32(len(hdr) + len(data))); err != nil { - select { - case <-t.done: - return ErrConnClosing - default: - } - return ContextErr(s.ctx.Err()) + return t.streamContextErr(s) } return t.controlBuf.put(df) } @@ -1229,10 +1230,6 @@ func (t *http2Server) Close() { // deleteStream deletes the stream s from transport's active streams. func (t *http2Server) deleteStream(s *Stream, eosReceived bool) { - // In case stream sending and receiving are invoked in separate - // goroutines (e.g., bi-directional streaming), cancel needs to be - // called to interrupt the potential blocking on other goroutines. - s.cancel() t.mu.Lock() if _, ok := t.activeStreams[s.id]; ok { @@ -1254,6 +1251,11 @@ func (t *http2Server) deleteStream(s *Stream, eosReceived bool) { // finishStream closes the stream and puts the trailing headerFrame into controlbuf. func (t *http2Server) finishStream(s *Stream, rst bool, rstCode http2.ErrCode, hdr *headerFrame, eosReceived bool) { + // In case stream sending and receiving are invoked in separate + // goroutines (e.g., bi-directional streaming), cancel needs to be + // called to interrupt the potential blocking on other goroutines. + s.cancel() + oldState := s.swapState(streamDone) if oldState == streamDone { // If the stream was already done, return. @@ -1273,6 +1275,11 @@ func (t *http2Server) finishStream(s *Stream, rst bool, rstCode http2.ErrCode, h // closeStream clears the footprint of a stream when the stream is not needed any more. func (t *http2Server) closeStream(s *Stream, rst bool, rstCode http2.ErrCode, eosReceived bool) { + // In case stream sending and receiving are invoked in separate + // goroutines (e.g., bi-directional streaming), cancel needs to be + // called to interrupt the potential blocking on other goroutines. + s.cancel() + s.swapState(streamDone) t.deleteStream(s, eosReceived) diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 96431a058b..65de84b300 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -1801,12 +1801,26 @@ func (s *Server) getCodec(contentSubtype string) baseCodec { return codec } -// SetHeader sets the header metadata. -// When called multiple times, all the provided metadata will be merged. -// All the metadata will be sent out when one of the following happens: -// - grpc.SendHeader() is called; -// - The first response is sent out; -// - An RPC status is sent out (error or success). +// SetHeader sets the header metadata to be sent from the server to the client. +// The context provided must be the context passed to the server's handler. +// +// Streaming RPCs should prefer the SetHeader method of the ServerStream. +// +// When called multiple times, all the provided metadata will be merged. All +// the metadata will be sent out when one of the following happens: +// +// - grpc.SendHeader is called, or for streaming handlers, stream.SendHeader. +// - The first response message is sent. For unary handlers, this occurs when +// the handler returns; for streaming handlers, this can happen when stream's +// SendMsg method is called. +// - An RPC status is sent out (error or success). This occurs when the handler +// returns. +// +// SetHeader will fail if called after any of the events above. +// +// The error returned is compatible with the status package. However, the +// status code will often not match the RPC status as seen by the client +// application, and therefore, should not be relied upon for this purpose. func SetHeader(ctx context.Context, md metadata.MD) error { if md.Len() == 0 { return nil @@ -1818,8 +1832,14 @@ func SetHeader(ctx context.Context, md metadata.MD) error { return stream.SetHeader(md) } -// SendHeader sends header metadata. It may be called at most once. -// The provided md and headers set by SetHeader() will be sent. +// SendHeader sends header metadata. It may be called at most once, and may not +// be called after any event that causes headers to be sent (see SetHeader for +// a complete list). The provided md and headers set by SetHeader() will be +// sent. +// +// The error returned is compatible with the status package. However, the +// status code will often not match the RPC status as seen by the client +// application, and therefore, should not be relied upon for this purpose. func SendHeader(ctx context.Context, md metadata.MD) error { stream := ServerTransportStreamFromContext(ctx) if stream == nil { @@ -1833,6 +1853,10 @@ func SendHeader(ctx context.Context, md metadata.MD) error { // SetTrailer sets the trailer metadata that will be sent when an RPC returns. // When called more than once, all the provided metadata will be merged. +// +// The error returned is compatible with the status package. However, the +// status code will often not match the RPC status as seen by the client +// application, and therefore, should not be relied upon for this purpose. func SetTrailer(ctx context.Context, md metadata.MD) error { if md.Len() == 0 { return nil diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index be51405358..236fc17ec3 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -1381,8 +1381,10 @@ func (as *addrConnStream) finish(err error) { // ServerStream defines the server-side behavior of a streaming RPC. // -// All errors returned from ServerStream methods are compatible with the -// status package. +// Errors returned from ServerStream methods are compatible with the status +// package. However, the status code will often not match the RPC status as +// seen by the client application, and therefore, should not be relied upon for +// this purpose. type ServerStream interface { // SetHeader sets the header metadata. It may be called multiple times. // When call multiple times, all the provided metadata will be merged. diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index f17192e6a3..5bc03f9b36 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.46.2" +const Version = "1.47.0" diff --git a/vendor/modules.txt b/vendor/modules.txt index cb2c654c43..e19d8e5f92 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.24 +# github.com/aws/aws-sdk-go v1.44.27 ## explicit; go 1.11 github.com/aws/aws-sdk-go/aws github.com/aws/aws-sdk-go/aws/arn @@ -155,7 +155,7 @@ github.com/influxdata/influxdb/pkg/escape # github.com/jmespath/go-jmespath v0.4.0 ## explicit; go 1.14 github.com/jmespath/go-jmespath -# github.com/klauspost/compress v1.15.5 +# github.com/klauspost/compress v1.15.6 ## explicit; go 1.16 github.com/klauspost/compress github.com/klauspost/compress/flate @@ -277,7 +277,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-20220526153639-5463443f8c37 +# golang.org/x/net v0.0.0-20220531201128-c960675eff93 ## explicit; go 1.17 golang.org/x/net/context golang.org/x/net/context/ctxhttp @@ -299,7 +299,7 @@ golang.org/x/oauth2/google/internal/externalaccount golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt -# golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 +# golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f ## explicit golang.org/x/sync/errgroup # golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a @@ -317,7 +317,7 @@ golang.org/x/text/unicode/norm ## explicit; go 1.17 golang.org/x/xerrors golang.org/x/xerrors/internal -# google.golang.org/api v0.81.0 +# google.golang.org/api v0.82.0 ## explicit; go 1.15 google.golang.org/api/googleapi google.golang.org/api/googleapi/transport @@ -350,7 +350,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-20220527130721-00d5c0f3be58 +# google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8 ## explicit; go 1.15 google.golang.org/genproto/googleapis/api/annotations google.golang.org/genproto/googleapis/iam/v1 @@ -365,7 +365,7 @@ google.golang.org/genproto/googleapis/type/decimal google.golang.org/genproto/googleapis/type/expr google.golang.org/genproto/googleapis/type/fraction google.golang.org/genproto/googleapis/type/month -# google.golang.org/grpc v1.46.2 +# google.golang.org/grpc v1.47.0 ## explicit; go 1.14 google.golang.org/grpc google.golang.org/grpc/attributes