Compare commits

...

4 Commits

Author SHA1 Message Date
wxiaoguang
0ab0bfc375 fix: don't log network error in console when loading issue popup (#40288)
* fix #40286

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
2026-11-09 05:59:03 +00:00
Giteabot
f3354aa902 chore(deps): update dependencies (#40292)
Updates JS, Go, Python and Actions dependencies, including the stylelint
18 and stylelint-config-recommended 19 majors.

- Update clippie to 4.3.1, which fixes copy buttons in browsers without
`ClipboardItem` such as Pale Moon
- Exempt the markup `tt` selectors from the new `selector-no-deprecated`
rule, the sanitizer allows `<tt>`
- Replace the `stylelint-value-no-unknown-custom-properties` plugin with
stylelint's `referenceFiles` and the core `no-unknown-*` rules
- Remove dead dropdown loading icon styles that referenced deleted
keyframes

Fixes: https://github.com/go-gitea/gitea/issues/40287

Assisted-by: Claude Code:claude-opus-5-5

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-09 05:32:54 +00:00
Shudhanshu Singh
7b1cde99d0 perf(charset): skip plain ASCII text when escaping control characters (#39937)
Every line of file, blame, diff and code preview views goes through
`EscapeControlHTML`, which streamed it through a 32 KiB read buffer and
copied every tag and text part. Views render the `EscapeStatus` before
the content, so every caller holds the complete HTML and streaming can't
help. It is now escaped in one pass over the string and returned
unchanged when nothing needs escaping.

- Skip text of printable ASCII, tabs and newlines, such lines return
immediately
- Render markup and wiki pages into a buffer instead of a pipe and
goroutine, and remove `EscapeControlReader`
- Analyze long text parts in windows overlapping by the detection
context, which bounds memory without changing results
- Escape invalid bytes before a tag, they were moved into the tag part
unescaped and could hide a `<math>` tag

| | before | after |
|---|---|---|
| ASCII line | 5.1 µs, 59 allocs | 0.08 µs, 1 alloc |
| line with one `é` | 3.9 µs, 30 allocs | 0.29 µs, 3 allocs |
| 150 KB document | 2.5 ms, 5.6 MB | 0.27 ms, 0.6 KB |

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-11-09 03:42:30 +00:00
GiteaBot
2bbac68f45 [skip ci] Updated translations via Crowdin 2026-11-09 00:36:42 +00:00
54 changed files with 855 additions and 1736 deletions

View File

@@ -9,7 +9,7 @@ inputs:
runs:
using: composite
steps:
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
- uses: pnpm/action-setup@73e46992e05b19abd31f2f3c20e0e7370d762115 # v6.1.1
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version: 26

View File

@@ -4,7 +4,7 @@ description: Set up uv and python and restore the uv cache
runs:
using: composite
steps:
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
with:
python-version: 3.15 # renovate: datasource=python-version depName=python versioning=python
save-cache: ${{ github.workflow == 'cache-seeder' }}

View File

@@ -9,7 +9,7 @@ concurrency:
group: cron-renovate
env:
RENOVATE_VERSION: 44.190.1 # renovate: datasource=npm depName=renovate
RENOVATE_VERSION: 44.210.0 # renovate: datasource=npm depName=renovate
permissions:
contents: read
@@ -21,7 +21,7 @@ jobs:
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: renovatebot/github-action@2804199d260ad00c1fae0e9e842888369391c776 # v46.3.10
- uses: renovatebot/github-action@1c0cf989c02653fba0efe7ca5772338860ca71dc # v46.3.12
with:
renovate-version: ${{ env.RENOVATE_VERSION }}
configurationFile: renovate.json5

View File

@@ -15,7 +15,7 @@ jobs:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: crowdin/github-action@959dc74ac104447731cba99a016f85d0ae719788 # v3.5.0
- uses: crowdin/github-action@5b9790df740c85af5412a3a3a91b24988d5d324f # v3.5.1
with:
upload_sources: true
upload_translations: false

View File

@@ -128,7 +128,7 @@ jobs:
ports:
- "9200:9200"
meilisearch:
image: getmeili/meilisearch:v1@sha256:1f578fa865f8251894b3bf38d6668d6209a3f451f8f65ab953e129d4c1db5ef4
image: getmeili/meilisearch:v1@sha256:88f2a08eb9532cc54a60d8fd014a23bf5cfda33d0c01ecbbaca9b4b463e17466
env:
MEILI_ENV: development # disable auth
ports:

View File

@@ -8,7 +8,7 @@ AIR_PACKAGE ?= github.com/air-verse/air@v1.67.4 # renovate: datasource=go
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v4/cmd/editorconfig-checker@v4.0.2 # renovate: datasource=go
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.15.0 # renovate: datasource=go
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.17 # renovate: datasource=go
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.36.6 # renovate: datasource=go
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.36.7 # renovate: datasource=go
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.9.0 # renovate: datasource=go
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 # renovate: datasource=go
SHELLCHECK_IMAGE ?= docker.io/koalaman/shellcheck:v0.11.0@sha256:61862eba1fcf09a484ebcc6feea46f1782532571a34ed51fedf90dd25f925a8d # renovate: datasource=docker

20
go.mod
View File

@@ -9,7 +9,7 @@ require (
gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
gitea.com/lunny/levelqueue v0.5.1
gitea.dev/actionslib v1.5.2
gitea.dev/sdk v1.5.0
gitea.dev/sdk v1.5.1
github.com/42wim/httpsig v1.3.0
github.com/42wim/sshsig v0.0.0-20260317195500-b9f38cf0d432
github.com/Azure/go-ntlmssp v0.1.1
@@ -19,14 +19,14 @@ require (
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.10.0
github.com/alecthomas/chroma/v2 v2.27.0
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.6.1
github.com/blevesearch/bleve/v2 v2.6.2
github.com/bohde/codel v0.2.0
github.com/bradfitz/gomemcache v0.0.0-20260422231931-4d751bb6e37c
github.com/buildkite/terminal-to-html/v3 v3.17.3
github.com/caddyserver/certmagic v0.25.6
github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20260812203852-971c0284dc33
github.com/coder/websocket v1.8.15
github.com/dlclark/regexp2/v2 v2.11.0
github.com/dlclark/regexp2/v2 v2.12.0
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707
github.com/dustin/go-humanize v1.1.0
github.com/editorconfig/editorconfig-core-go/v2 v2.6.5
@@ -79,11 +79,11 @@ require (
github.com/stretchr/testify v1.12.1
github.com/syndtr/goleveldb v1.0.0
github.com/ulikunitz/xz v0.5.17
github.com/urfave/cli-docs/v3 v3.1.0
github.com/urfave/cli-docs/v3 v3.2.0
github.com/urfave/cli/v3 v3.14.0
github.com/wneessen/go-mail v0.8.1
github.com/yuin/goldmark v1.8.6
gitlab.com/gitlab-org/api/client-go/v3 v3.39.1
github.com/yuin/goldmark v1.8.7
gitlab.com/gitlab-org/api/client-go/v3 v3.43.0
go.yaml.in/yaml/v4 v4.0.0
golang.org/x/crypto v0.58.0
golang.org/x/image v0.47.0
@@ -113,7 +113,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.24.5 // indirect
github.com/blevesearch/bleve_index_api v1.4.1 // indirect
github.com/blevesearch/geo v0.2.6 // indirect
github.com/blevesearch/geo v0.2.7-0.20260831141219-9c3e3a4d84bc // indirect
github.com/blevesearch/go-faiss v1.1.5 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect
@@ -122,14 +122,14 @@ require (
github.com/blevesearch/segment v0.9.1 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
github.com/blevesearch/vellum v1.2.0 // indirect
github.com/blevesearch/vellum v1.2.1 // indirect
github.com/blevesearch/zapx/v11 v11.4.3 // indirect
github.com/blevesearch/zapx/v12 v12.4.3 // indirect
github.com/blevesearch/zapx/v13 v13.4.3 // indirect
github.com/blevesearch/zapx/v14 v14.4.3 // indirect
github.com/blevesearch/zapx/v15 v15.4.3 // indirect
github.com/blevesearch/zapx/v16 v16.3.4 // indirect
github.com/blevesearch/zapx/v17 v17.2.3 // indirect
github.com/blevesearch/zapx/v17 v17.2.4 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.4 // indirect
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.4 // indirect
@@ -221,7 +221,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.28.0 // indirect
go.uber.org/zap/exp v0.3.0 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
go.yaml.in/yaml/v3 v3.0.6 // indirect
go4.org v0.0.0-20260112195520-a5071408f32f // indirect
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
golang.org/x/time v0.16.0 // indirect

40
go.sum
View File

@@ -14,8 +14,8 @@ gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGq
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitea.dev/actionslib v1.5.2 h1:PSSUd+4jIjI+ycqo62+BRgAWkBnzjgeGQAcI3ZqH7LY=
gitea.dev/actionslib v1.5.2/go.mod h1:i8wUQMnvGwT13f2re2ZTMCFL/TyauQLeOb1L4ngjtPk=
gitea.dev/sdk v1.5.0 h1:qxtIHpkid4pva3id7S+UlJIGJAAQ8/riQidqD3jzErc=
gitea.dev/sdk v1.5.0/go.mod h1:cM7S3Y9TY3LraJoRHHDLlY3YnVTu4bTc9TEBGuFa2Jw=
gitea.dev/sdk v1.5.1 h1:bMBU3rPoU87a8OOgtfu5w4sZn2x/ydwNAkqFLfIN8c8=
gitea.dev/sdk v1.5.1/go.mod h1:cM7S3Y9TY3LraJoRHHDLlY3YnVTu4bTc9TEBGuFa2Jw=
github.com/42wim/httpsig v1.3.0 h1:HK2bieeZ99X9IvOoc1ST6yrhLek0f4MqlEGES2JCP3g=
github.com/42wim/httpsig v1.3.0/go.mod h1:lgC3Yrvp4lxi1odEF1ge3kQBu/VM+SRcZQu5YwiR3dU=
github.com/42wim/sshsig v0.0.0-20260317195500-b9f38cf0d432 h1:3Fcz1QzlS7Jv4FT2KI3cHNSZL+KPN3dXxurn9f3YL/Y=
@@ -66,12 +66,12 @@ github.com/bits-and-blooms/bitset v1.24.5 h1:654xBVHc23gJMAgOTkPNoCVfiRxuIOAUnAZ
github.com/bits-and-blooms/bitset v1.24.5/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/blevesearch/bleve/v2 v2.6.1 h1:47vLskRTqxvQEtxVPYHjf5KpOgzD2msslXFjvUQCgWQ=
github.com/blevesearch/bleve/v2 v2.6.1/go.mod h1:Dvvx6ZoEBTOj6RSzfk0lEz0wce/qhe2yOUubXeuzd2c=
github.com/blevesearch/bleve/v2 v2.6.2 h1:CaPS1fjYgp+ejW5Nd7OTmVTCkuFzzqyjrADi/XCizdU=
github.com/blevesearch/bleve/v2 v2.6.2/go.mod h1:w86Ae7GPU0r5IW2S6OSrdUojZY3z7WmOb2pgAnfg8fQ=
github.com/blevesearch/bleve_index_api v1.4.1 h1:CYIyecFlI+/RYjzUm+NmDjYbSvk870Bb7f+Vl4b12q8=
github.com/blevesearch/bleve_index_api v1.4.1/go.mod h1:xvd48t5XMeeioWQ5/jZvgLrV98flT2rdvEJ3l/ki4Ko=
github.com/blevesearch/geo v0.2.6 h1:7K1oyQKYlauC+mJuo2AfNPyjN/4mihEoJMfyClVH1Mo=
github.com/blevesearch/geo v0.2.6/go.mod h1:6qzVUiB4BK47QkSZcRqiXEP2W3EeXuzM5XFTF8AdZ8A=
github.com/blevesearch/geo v0.2.7-0.20260831141219-9c3e3a4d84bc h1:2nCheDGYfGpD+w6d1czqyzuLXUgQpuk8tTi66si470c=
github.com/blevesearch/geo v0.2.7-0.20260831141219-9c3e3a4d84bc/go.mod h1:6qzVUiB4BK47QkSZcRqiXEP2W3EeXuzM5XFTF8AdZ8A=
github.com/blevesearch/go-faiss v1.1.5 h1:/IU5lkOahH9Ghfk9n3F6N0XD7PYVXZJWmNDc9TtXuco=
github.com/blevesearch/go-faiss v1.1.5/go.mod h1:w3W9AiWsFRGVaMG+/cmJi7iHEAuGyC6blsgO1EzCK/M=
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
@@ -88,8 +88,8 @@ github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A=
github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ=
github.com/blevesearch/vellum v1.2.0 h1:xkDiOEsHc2t3Cp0NsNZZ36pvc130sCzcGKOPMzXe+e0=
github.com/blevesearch/vellum v1.2.0/go.mod h1:uEcfBJz7mAOf0Kvq6qoEKQQkLODBF46SINYNkZNae4k=
github.com/blevesearch/vellum v1.2.1 h1:PYryJDqBHjLM6n3YindZSQcrseaMs8QpcsrrAOpwwj8=
github.com/blevesearch/vellum v1.2.1/go.mod h1:uEcfBJz7mAOf0Kvq6qoEKQQkLODBF46SINYNkZNae4k=
github.com/blevesearch/zapx/v11 v11.4.3 h1:PTZOO5loKpHC/x/GzmPZNa9cw7GZIQxd5qRjwij9tHY=
github.com/blevesearch/zapx/v11 v11.4.3/go.mod h1:4gdeyy9oGa/lLa6D34R9daXNUvfMPZqUYjPwiLmekwc=
github.com/blevesearch/zapx/v12 v12.4.3 h1:eElXvAaAX4m04t//CGBQAtHNPA+Q6A1hHZVrN3LSFYo=
@@ -102,8 +102,8 @@ github.com/blevesearch/zapx/v15 v15.4.3 h1:iJiMJOHrz216jyO6lS0m9RTCEkprUnzvqAI2l
github.com/blevesearch/zapx/v15 v15.4.3/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
github.com/blevesearch/zapx/v16 v16.3.4 h1:hDAqA8qusZTNbPEL7//w5P65UZ2de6yhSeUaTbp0Po0=
github.com/blevesearch/zapx/v16 v16.3.4/go.mod h1:zqkPPqs9GS9FzVWzCO3Wf1X044yWAV17+4zb+FTiEHg=
github.com/blevesearch/zapx/v17 v17.2.3 h1:UYYJPAt5b2tVxldx5h0jmv23RMsg8/UZKFVya7v92po=
github.com/blevesearch/zapx/v17 v17.2.3/go.mod h1:r7mb4QWbDQSkbAnOjCb9iCfkcrzajB4yBdJpuBIo/fE=
github.com/blevesearch/zapx/v17 v17.2.4 h1:6BekwKXVubfivq87E91dqJgRDhmguA0Hvm1JTyqNzWM=
github.com/blevesearch/zapx/v17 v17.2.4/go.mod h1:8gLqU0Hr+MuFCBbL/lDS3O9MiTFjyoTcLXkiVCjwqMs=
github.com/bmatcuk/doublestar/v4 v4.10.4 h1:oTKkRmRuOsKMqFe1AQazd9gGBFNEpOmgKp/xzB97dnA=
github.com/bmatcuk/doublestar/v4 v4.10.4/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q=
@@ -162,8 +162,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2/v2 v2.11.0 h1:z5uRPHav+eTVpoffDSuUP2KPS4f1ONZaPDK73S8HA0w=
github.com/dlclark/regexp2/v2 v2.11.0/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU=
github.com/dlclark/regexp2/v2 v2.12.0 h1:GsCgDZZeHluUDHASr2yqQonZk4Tma5LFmLH9CSsFFEE=
github.com/dlclark/regexp2/v2 v2.12.0/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
@@ -540,8 +540,8 @@ github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77ro
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.17 h1:flR0y/x1hgM8EGV1AW3Xll6T413G0glV8UfBwR617V4=
github.com/ulikunitz/xz v0.5.17/go.mod h1:H9Rt/W6/Qj27PGauhQc6nfCDy7vHpzsOThBSaYDoEhw=
github.com/urfave/cli-docs/v3 v3.1.0 h1:Sa5xm19IpE5gpm6tZzXdfjdFxn67PnEsE4dpXF7vsKw=
github.com/urfave/cli-docs/v3 v3.1.0/go.mod h1:59d+5Hz1h6GSGJ10cvcEkbIe3j233t4XDqI72UIx7to=
github.com/urfave/cli-docs/v3 v3.2.0 h1:1J2pmtDuMRConzYb/QHyPbeFB6HvMtYm3xre9uhs81c=
github.com/urfave/cli-docs/v3 v3.2.0/go.mod h1:cjSVza4yCaqQet06zO6QhYqXQYjGRqbUj8zok6mHDRU=
github.com/urfave/cli/v3 v3.14.0 h1:a8414NQlHJs0c/iBsulKLzlES0n/lEAskbL2LKpU4/s=
github.com/urfave/cli/v3 v3.14.0/go.mod h1:vXn6HxPNccJSzQr2QvwVncOKrgYGIHU0HY5h8B2nQj4=
github.com/wneessen/go-mail v0.8.1 h1:tVcncj02/QySVFw3zr/kXOzZcuFQqBNT6K+Rbgm/pcM=
@@ -551,8 +551,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.8.6 h1:d0VcaP1sx9GkFVkoW+KtggpGi2KZ965i14b0+bDQST4=
github.com/yuin/goldmark v1.8.6/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/yuin/goldmark v1.8.7 h1:XT/tNqCIbabh0ln675w4x3dv04kQBKi8NwYqi9IJaxI=
github.com/yuin/goldmark v1.8.7/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
@@ -561,8 +561,8 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
gitlab.com/gitlab-org/api/client-go/v3 v3.39.1 h1:yBmlSUi5P6L354Aq3PJCWvW24zz9Ru3WnAXgNMwA9g8=
gitlab.com/gitlab-org/api/client-go/v3 v3.39.1/go.mod h1:jBFhGkTHLKkgeHEdS/A8yA0tQ6UHq96QVsS5muu6flM=
gitlab.com/gitlab-org/api/client-go/v3 v3.43.0 h1:X7qHPPt6If/5f0bgBpeT8GYWx2zDnuUzRsfnzJa9/cc=
gitlab.com/gitlab-org/api/client-go/v3 v3.43.0/go.mod h1:8cuzgeUJzkVvaRvw57iZ8foGmL5q8GZXi4lHTiF5edY=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
go.uber.org/atomic v1.12.0 h1:BvcXdFKuviU4fTL/f+SxdQ5qJX/Jix8pAkgdUcb3XOE=
@@ -579,8 +579,8 @@ go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U=
go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ=
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
go.yaml.in/yaml/v3 v3.0.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM=
go.yaml.in/yaml/v3 v3.0.6/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
go.yaml.in/yaml/v4 v4.0.0 h1:/LG1pNO84Z4l603j/xMn69CcS5OYhMQ/f7l2LoQUGuw=
go.yaml.in/yaml/v4 v4.0.0/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
go4.org v0.0.0-20260112195520-a5071408f32f h1:ziUVAjmTPwQMBmYR1tbdRFJPtTcQUI12fH9QQjfb0Sw=

View File

@@ -29,6 +29,9 @@ func TestAmbiguousCharacters(t *testing.T) {
found := i < len(ambiguous.Confusable) && ambiguous.Confusable[i] == confusable
assert.True(t, found, "%c is not in %d", confusable, i)
}
for r := rune(0x20); r < 0x7f; r++ {
assert.False(t, unicode.Is(ambiguous.RangeTable, r), "%c must not be ambiguous, isStringAsciiSafe skips it", r)
}
}
var confusableTo rune

View File

@@ -22,15 +22,14 @@ import (
"golang.org/x/text/transform"
)
var globalVars = sync.OnceValue(func() (ret struct {
utf8Bom []byte
const utf8Bom = "\xef\xbb\xbf"
var globalVars = sync.OnceValue(func() (ret struct {
defaultWordRegexp *regexp.Regexp
ambiguousTableMap map[string]*AmbiguousTable
invisibleRangeTable *unicode.RangeTable
},
) {
ret.utf8Bom = []byte("\xef\xbb\xbf")
ret.ambiguousTableMap = newAmbiguousTableMap()
ret.invisibleRangeTable = newInvisibleRangeTable()
return ret
@@ -139,7 +138,7 @@ func maybeRemoveBOM(content []byte, opts ConvertOpts) []byte {
if opts.KeepBOM {
return content
}
return bytes.TrimPrefix(content, globalVars().utf8Bom)
return bytes.TrimPrefix(content, []byte(utf8Bom))
}
// DetectEncoding detect the encoding of content

View File

@@ -5,10 +5,8 @@ package charset
import (
"html/template"
"io"
"strings"
"sync"
"gitea.dev/modules/htmlutil"
"gitea.dev/modules/setting"
"gitea.dev/modules/translation"
)
@@ -28,21 +26,31 @@ func EscapeOptionsForView() EscapeOptions {
}
}
// EscapeControlHTML escapes the Unicode control sequences in a provided html document
func EscapeControlHTML(html template.HTML, locale translation.Locale, opts ...EscapeOptions) (escaped *EscapeStatus, output template.HTML) {
if !setting.UI.AmbiguousUnicodeDetection {
return &EscapeStatus{}, html
var asciiSafeBytes = sync.OnceValue(func() (ret [256]bool) {
for c := range ret {
ret[c] = (c >= 0x20 && c < 0x7f) || c == '\t' || c == '\n'
}
w := &htmlutil.HTMLBuilder{}
escaped, _ = EscapeControlReader(strings.NewReader(string(html)), w, locale, opts...)
return escaped, w.HTMLString()
return ret
})
func isStringAsciiSafe(str string) bool {
safeBytes := asciiSafeBytes()
for i := range len(str) {
if !safeBytes[str[i]] {
return false
}
}
return true
}
// EscapeControlReader escapes the Unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus
func EscapeControlReader(reader io.Reader, writer htmlutil.HTMLWriter, locale translation.Locale, opts ...EscapeOptions) (*EscapeStatus, error) {
if !setting.UI.AmbiguousUnicodeDetection {
_, err := io.Copy(writer.OriginWriter(), reader)
return &EscapeStatus{}, err
// EscapeControlHTML escapes the Unicode control sequences in a provided html document, in memory as views render the EscapeStatus first
func EscapeControlHTML(html template.HTML, locale translation.Locale, opts ...EscapeOptions) (escaped *EscapeStatus, output template.HTML) {
if !setting.UI.AmbiguousUnicodeDetection || isStringAsciiSafe(string(html)) {
return &EscapeStatus{}, html
}
return escapeStream(locale, reader, writer.OriginWriter(), opts...)
escaper := &htmlEscaper{escaped: &EscapeStatus{}, locale: locale, ambiguousTables: AmbiguousTablesForLocale(locale)}
if len(opts) > 0 {
escaper.allowed = opts[0].Allowed
}
return escaper.escaped, template.HTML(escaper.escape(string(html)))
}

View File

@@ -4,116 +4,96 @@
package charset
import (
"bytes"
"fmt"
"html"
"io"
"slices"
"strings"
"unicode"
"unicode/utf8"
"gitea.dev/modules/setting"
"gitea.dev/modules/translation"
"gitea.dev/modules/util"
)
type htmlChunkReader struct {
in io.Reader
readErr error
readBuf []byte
curInTag bool
}
type escapeStreamer struct {
htmlChunkReader
type htmlEscaper struct {
escaped *EscapeStatus
locale translation.Locale
ambiguousTables []*AmbiguousTable
allowed map[rune]bool
tagPartial []byte // partial tag content, used to detect if we are in some tags
inTagMath bool // MathML operators like U+2212 are intended and wrapping them breaks the math layout
out io.Writer
detectResults []detectResult
written int // content before this offset has been written to out
out strings.Builder
}
func escapeStream(locale translation.Locale, in io.Reader, out io.Writer, opts ...EscapeOptions) (*EscapeStatus, error) {
es := &escapeStreamer{
escaped: &EscapeStatus{},
locale: locale,
ambiguousTables: AmbiguousTablesForLocale(locale),
htmlChunkReader: htmlChunkReader{
in: in,
readBuf: make([]byte, 0, 32*1024),
},
out: out,
}
const detectWindowRunes = 4096 // bounds the detection results of long text parts
if len(opts) > 0 {
es.allowed = opts[0].Allowed
}
readCount := 0
lastIsTag := false
for {
parts, partInTag, err := es.readRunes()
readCount++
if err == io.EOF {
return es.escaped, nil
} else if err != nil {
return nil, err
func (e *htmlEscaper) escape(content string) string {
for pos := 0; pos < len(content); {
if content[pos] == '<' {
tagEnd := len(content)
if idx := strings.IndexByte(content[pos:], '>'); idx != -1 {
tagEnd = pos + idx + 1
}
e.trackHtmlTag(content[pos:tagEnd])
pos = tagEnd
continue
}
for i, part := range parts {
if partInTag[i] {
lastIsTag = true
es.trackHtmlTag(part)
if _, err := out.Write(part); err != nil {
return nil, err
}
} else {
// if last part is tag, then this part is content begin
// if the content is the first part of the first read, then it's also content begin
isContentBegin := lastIsTag || (readCount == 1 && i == 0)
lastIsTag = false
if isContentBegin {
if part, err = es.trimAndWriteBom(part); err != nil {
return nil, err
}
}
if es.inTagMath {
if _, err := out.Write(part); err != nil {
return nil, err
}
} else if err = es.detectAndWriteRunes(part); err != nil {
return nil, err
}
textEnd := len(content)
if idx := strings.IndexByte(content[pos:], '<'); idx != -1 {
textEnd = pos + idx
}
if strings.HasPrefix(content[pos:textEnd], utf8Bom) {
pos += len(utf8Bom) // a BOM at the start of a text part is kept as is
}
if !e.inTagMath && !isStringAsciiSafe(content[pos:textEnd]) {
e.escapeText(content, pos, textEnd)
}
pos = textEnd
}
if e.written == 0 {
return content
}
e.out.WriteString(content[e.written:])
return e.out.String()
}
// escapeText analyzes content[start:end] in windows overlapping by the context analyzeDetectResults looks at
func (e *htmlEscaper) escapeText(content string, start, end int) {
for skip := 0; ; skip = longSentenceDetectionLimit {
results := e.detectRunes(content[start:end])
e.analyzeDetectResults(results)
lastResult := results[len(results)-1]
isLastWindow := start+lastResult.position+lastResult.runeSize == end
emitEnd := len(results)
if !isLastWindow {
emitEnd -= longSentenceDetectionLimit
}
for _, res := range results[skip:emitEnd] {
if res.needEscape {
e.out.WriteString(content[e.written : start+res.position])
e.writeEscapedRune(res)
e.written = start + res.position + res.runeSize
}
}
if isLastWindow {
return
}
start += results[emitEnd-longSentenceDetectionLimit].position
}
}
// trackHtmlTag receives tag parts, a tag might be split into multiple parts
func (e *escapeStreamer) trackHtmlTag(part []byte) {
const maxHeadLen = 100 // only read the first N bytes of the tag for detection purpose
if part[0] == '<' {
// start a new tag
e.tagPartial = e.tagPartial[:0]
}
if len(e.tagPartial) >= maxHeadLen {
return
}
e.tagPartial = append(e.tagPartial, part[:min(len(part), maxHeadLen-len(e.tagPartial))]...)
func (e *htmlEscaper) trackHtmlTag(tag string) {
isTag := func(prefix string) bool {
if len(e.tagPartial) < len(prefix)+1 {
if len(tag) < len(prefix)+1 {
return false
}
if !util.AsciiEqualFold(e.tagPartial[:len(prefix)], []byte(prefix)) {
if !util.AsciiEqualFold(tag[:len(prefix)], prefix) {
return false
}
return strings.IndexByte(" \t\n\r\f>", e.tagPartial[len(prefix)]) != -1
return strings.IndexByte(" \t\n\r\f>", tag[len(prefix)]) != -1
}
if isTag("<math") {
e.inTagMath = true
@@ -122,20 +102,9 @@ func (e *escapeStreamer) trackHtmlTag(part []byte) {
}
}
func (e *escapeStreamer) trimAndWriteBom(part []byte) ([]byte, error) {
remaining, ok := bytes.CutPrefix(part, globalVars().utf8Bom)
if ok {
part = remaining
if _, err := e.out.Write(globalVars().utf8Bom); err != nil {
return part, err
}
}
return part, nil
}
const longSentenceDetectionLimit = 20
func (e *escapeStreamer) possibleLongSentence(results []detectResult, pos int) bool {
func (e *htmlEscaper) possibleLongSentence(results []detectResult, pos int) bool {
countBasic := 0
countNonASCII := 0
for i := max(pos-longSentenceDetectionLimit, 0); i < min(pos+longSentenceDetectionLimit, len(results)); i++ {
@@ -152,214 +121,56 @@ func (e *escapeStreamer) possibleLongSentence(results []detectResult, pos int) b
return countChar != 0 && countNonASCII*100/countChar >= 50
}
func (e *escapeStreamer) analyzeDetectResults(results []detectResult) {
func (e *htmlEscaper) analyzeDetectResults(results []detectResult) {
for i := range results {
res := &results[i]
if res.runeType == runeTypeInvisible || res.runeType == runeTypeAmbiguous {
leftIsNonASCII := i > 0 && (results[i-1].runeType == runeTypeNonASCII || results[i-1].runeType == runeTypeAmbiguous)
rightIsNonASCII := i < len(results)-1 && (results[i+1].runeType == runeTypeNonASCII || results[i+1].runeType == runeTypeAmbiguous)
surroundingNonASCII := leftIsNonASCII || rightIsNonASCII
if !surroundingNonASCII {
if len(results) < longSentenceDetectionLimit {
res.needEscape = setting.UI.AmbiguousUnicodeDetection
} else if !e.possibleLongSentence(results, i) {
res.needEscape = setting.UI.AmbiguousUnicodeDetection
}
}
res.needEscape = !surroundingNonASCII && (len(results) < longSentenceDetectionLimit || !e.possibleLongSentence(results, i))
}
}
}
func (e *escapeStreamer) detectAndWriteRunes(part []byte) error {
results := e.detectRunes(part)
e.analyzeDetectResults(results)
return e.writeDetectResults(part, results)
func (e *htmlEscaper) writeEscapedRune(res detectResult) {
switch res.runeType {
case runeTypeBroken:
e.writeBrokenRune()
case runeTypeAmbiguous:
e.writeAmbiguousRune(res.runeChar, res.confusable)
case runeTypeInvisible:
e.writeInvisibleRune(res.runeChar)
case runeTypeControlChar:
e.writeControlRune(res.runeChar)
default:
panic("unreachable")
}
}
func (e *htmlChunkReader) readRunes() (parts [][]byte, partInTag []bool, _ error) {
// we have read everything, eof
if e.readErr != nil && len(e.readBuf) == 0 {
return nil, nil, e.readErr
}
// not eof, and the there is space in the buffer, try to read more data
if e.readErr == nil && len(e.readBuf) <= cap(e.readBuf)*3/4 {
n, err := e.in.Read(e.readBuf[len(e.readBuf):cap(e.readBuf)])
e.readErr = err
e.readBuf = e.readBuf[:len(e.readBuf)+n]
}
if len(e.readBuf) == 0 {
return nil, nil, e.readErr
}
// try to exact tag parts and content parts
pos := 0
for pos < len(e.readBuf) {
var curPartEnd int
nextInTag := e.curInTag
if e.curInTag {
// if cur part is in tag, try to find the tag close char '>'
idx := bytes.IndexByte(e.readBuf[pos:], '>')
if idx == -1 {
// if no tag close char, then the whole buffer is in tag
curPartEnd = len(e.readBuf)
} else {
// tag part ends, switch to content part
curPartEnd = pos + idx + 1
nextInTag = !nextInTag
}
} else {
// if cur part is in content, try to find the tag open char '<'
idx := bytes.IndexByte(e.readBuf[pos:], '<')
if idx == -1 {
// if no tag open char, then the whole buffer is in content
curPartEnd = len(e.readBuf)
} else {
// content part ends, switch to tag part
curPartEnd = pos + idx
nextInTag = !nextInTag
}
}
curPartLen := curPartEnd - pos
if curPartLen == 0 {
// if cur part is empty, only need to switch the part type
if e.curInTag == nextInTag {
panic("impossible, curPartLen is 0 but the part in tag status is not switched")
}
e.curInTag = nextInTag
continue
}
// now, curPartLen can't be 0
curPart := make([]byte, curPartLen)
copy(curPart, e.readBuf[pos:curPartEnd])
// now we get the curPart bytes, but we can't directly use it, the last rune in it might have been cut
// try to decode the last rune, if it's invalid, then we cut the last byte and try again until we get a valid rune or no byte left
for i := curPartLen - 1; i >= 0; i-- {
last, lastSize := utf8.DecodeRune(curPart[i:])
if last == utf8.RuneError && lastSize == 1 {
curPartLen--
} else {
curPartLen += lastSize - 1
break
}
}
if curPartLen == 0 {
// actually it's impossible that the part doesn't contain any valid rune,
// the only case is that the cap(readBuf) is too small, or the origin contain indeed doesn't contain any valid rune
// * try to leave the last 4 bytes (possible longest utf-8 encoding) to next round
// * at least consume 1 byte to avoid infinite loop
curPartLen = max(len(curPart)-utf8.UTFMax, 1)
}
// if curPartLen is not the same as curPart, it means we have cut some bytes,
// need to wait for more data if not eof
trailingCorrupted := curPartLen != len(curPart)
// finally, we get the real part we need
curPart = curPart[:curPartLen]
parts = append(parts, curPart)
partInTag = append(partInTag, e.curInTag)
pos += curPartLen
e.curInTag = nextInTag
if trailingCorrupted && e.readErr == nil {
// if the last part is corrupted, and we haven't reach eof, then we need to wait for more data to get the complete part
break
}
}
copy(e.readBuf, e.readBuf[pos:])
e.readBuf = e.readBuf[:len(e.readBuf)-pos]
return parts, partInTag, nil
}
func (e *escapeStreamer) writeDetectResults(data []byte, results []detectResult) error {
lastWriteRawIdx := -1
for idx := range results {
res := &results[idx]
if !res.needEscape {
if lastWriteRawIdx == -1 {
lastWriteRawIdx = idx
}
continue
}
if lastWriteRawIdx != -1 {
if _, err := e.out.Write(data[results[lastWriteRawIdx].position:res.position]); err != nil {
return err
}
lastWriteRawIdx = -1
}
switch res.runeType {
case runeTypeBroken:
if err := e.writeBrokenRune(data[res.position : res.position+res.runeSize]); err != nil {
return err
}
case runeTypeAmbiguous:
if err := e.writeAmbiguousRune(res.runeChar, res.confusable); err != nil {
return err
}
case runeTypeInvisible:
if err := e.writeInvisibleRune(res.runeChar); err != nil {
return err
}
case runeTypeControlChar:
if err := e.writeControlRune(res.runeChar); err != nil {
return err
}
default:
panic("unreachable")
}
}
if lastWriteRawIdx != -1 {
lastResult := results[len(results)-1]
if _, err := e.out.Write(data[results[lastWriteRawIdx].position : lastResult.position+lastResult.runeSize]); err != nil {
return err
}
}
return nil
}
func (e *escapeStreamer) writeBrokenRune(_ []byte) (err error) {
func (e *htmlEscaper) writeBrokenRune() {
// Although we'd like to use the original bytes to display (show the real broken content to users),
// however, when this "escape stream" module is applied to the content, the content has already been processed by other modules.
// however, when this escaper is applied to the content, the content has already been processed by other modules.
// So the invalid bytes just can't be kept till this step, in most (all) cases, the only thing we see here is utf8.RuneError
_, err = io.WriteString(e.out, `<span class="broken-code-point"><3E></span>`)
return err
e.out.WriteString(`<span class="broken-code-point"><3E></span>`)
}
func (e *escapeStreamer) writeEscapedCharHTML(tag1, attr, tag2, content, tag3 string) (err error) {
_, err = io.WriteString(e.out, tag1)
if err != nil {
return err
}
_, err = io.WriteString(e.out, html.EscapeString(attr))
if err != nil {
return err
}
_, err = io.WriteString(e.out, tag2)
if err != nil {
return err
}
_, err = io.WriteString(e.out, html.EscapeString(content))
if err != nil {
return err
}
_, err = io.WriteString(e.out, tag3)
return err
func (e *htmlEscaper) writeEscapedCharHTML(tag1, attr, tag2, content, tag3 string) {
e.out.WriteString(tag1)
e.out.WriteString(html.EscapeString(attr))
e.out.WriteString(tag2)
e.out.WriteString(html.EscapeString(content))
e.out.WriteString(tag3)
}
func runeToHex(r rune) string {
return fmt.Sprintf("[U+%04X]", r)
}
func (e *escapeStreamer) writeAmbiguousRune(r, c rune) (err error) {
func (e *htmlEscaper) writeAmbiguousRune(r, c rune) {
e.escaped.Escaped = true
e.escaped.HasAmbiguous = true
return e.writeEscapedCharHTML(
e.writeEscapedCharHTML(
`<span class="ambiguous-code-point" data-tooltip-content="`,
e.locale.TrString("repo.ambiguous_character", string(r)+" "+runeToHex(r), string(c)+" "+runeToHex(c)),
`"><span class="char">`,
@@ -368,10 +179,10 @@ func (e *escapeStreamer) writeAmbiguousRune(r, c rune) (err error) {
)
}
func (e *escapeStreamer) writeInvisibleRune(r rune) error {
func (e *htmlEscaper) writeInvisibleRune(r rune) {
e.escaped.Escaped = true
e.escaped.HasInvisible = true
return e.writeEscapedCharHTML(
e.writeEscapedCharHTML(
`<span class="escaped-code-point" data-escaped="`,
runeToHex(r),
`"><span class="char">`,
@@ -380,7 +191,7 @@ func (e *escapeStreamer) writeInvisibleRune(r rune) error {
)
}
func (e *escapeStreamer) writeControlRune(r rune) error {
func (e *htmlEscaper) writeControlRune(r rune) {
var display string
if r >= 0 && r <= 0x1f {
display = string(0x2400 + r)
@@ -389,7 +200,7 @@ func (e *escapeStreamer) writeControlRune(r rune) error {
} else {
display = runeToHex(r)
}
return e.writeEscapedCharHTML(
e.writeEscapedCharHTML(
`<span class="broken-code-point" data-escaped="`,
display,
`"><span class="char">`,
@@ -416,42 +227,39 @@ const (
runeTypeControlChar
)
func (e *escapeStreamer) detectRunes(data []byte) []detectResult {
runeCount := utf8.RuneCount(data)
results := make([]detectResult, runeCount)
func (e *htmlEscaper) detectRunes(data string) []detectResult {
results := slices.Grow(e.detectResults[:0], min(len(data), detectWindowRunes))
invisibleRangeTable := globalVars().invisibleRangeTable
var i int
var confusable rune
for pos := 0; pos < len(data); i++ {
r, runeSize := utf8.DecodeRune(data[pos:])
results[i].runeChar = r
results[i].runeSize = runeSize
results[i].position = pos
safeBytes := asciiSafeBytes()
for pos := 0; pos < len(data) && len(results) < detectWindowRunes; {
r, runeSize := utf8.DecodeRuneInString(data[pos:])
res := detectResult{runeChar: r, runeSize: runeSize, position: pos}
pos += runeSize
switch {
case r < utf8.RuneSelf && safeBytes[r]: // basic rune, no table contains printable ASCII
case r == utf8.RuneError:
results[i].runeType = runeTypeBroken
results[i].needEscape = true
case r == ' ' || r == '\t' || r == '\n' || e.allowed[r]:
results[i].runeType = runeTypeBasic
res.runeType = runeTypeBroken
res.needEscape = true
case e.allowed[r]:
res.runeType = runeTypeBasic
if r >= 0x80 {
results[i].runeType = runeTypeNonASCII
res.runeType = runeTypeNonASCII
}
case r < 0x20 || r == 0x7f:
results[i].runeType = runeTypeControlChar
results[i].needEscape = true
res.runeType = runeTypeControlChar
res.needEscape = true
case unicode.Is(invisibleRangeTable, r):
results[i].runeType = runeTypeInvisible
// not sure about results[i].needEscape, will be detected separately
case isAmbiguous(r, &confusable, e.ambiguousTables...):
results[i].runeType = runeTypeAmbiguous
results[i].confusable = confusable
// not sure about results[i].needEscape, will be detected separately
case r >= 0x80:
results[i].runeType = runeTypeNonASCII
default: // details to basic runes
res.runeType = runeTypeInvisible
// not sure about res.needEscape, will be detected separately
case isAmbiguous(r, &res.confusable, e.ambiguousTables...):
res.runeType = runeTypeAmbiguous
// not sure about res.needEscape, will be detected separately
default:
res.runeType = runeTypeNonASCII
}
results = append(results, res)
}
e.detectResults = results
return results
}

View File

@@ -4,16 +4,15 @@
package charset
import (
"html/template"
"strings"
"testing"
"gitea.dev/modules/htmlutil"
"gitea.dev/modules/setting"
"gitea.dev/modules/test"
"gitea.dev/modules/translation"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type escapeControlTest struct {
@@ -131,9 +130,9 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`,
// UTF-8/16/32 all use the same codepoint for BOM
// Gitea could read UTF-16/32 content and convert into UTF-8 internally then render it, so we only process UTF-8 internally
name: "UTF BOM",
text: "\xef\xbb\xbftest",
result: "\xef\xbb\xbftest",
status: EscapeStatus{},
text: "\xef\xbb\xbftest<b>\xef\xbb\xbftest\xef\xbb\xbf",
result: "\xef\xbb\xbftest<b>\xef\xbb\xbftest" + `<span class="escaped-code-point" data-escaped="[U+FEFF]"><span class="char">` + "\xef\xbb\xbf" + `</span></span>`,
status: EscapeStatus{Escaped: true, HasInvisible: true},
},
{
name: "ambiguous",
@@ -141,45 +140,35 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`,
result: `O<span class="ambiguous-code-point" data-tooltip-content="repo.ambiguous_character:𝐾 [U+1D43E],K [U+004B]"><span class="char">𝐾</span></span>`,
status: EscapeStatus{Escaped: true, HasAmbiguous: true},
},
{
name: "long text analyzed in overlapping windows",
text: strings.Repeat("a", 4095) + "\u202e\u0436" + strings.Repeat("a", 5000) + "\u202e",
result: strings.Repeat("a", 4095) + "\u202e\u0436" + strings.Repeat("a", 5000) + `<span class="escaped-code-point" data-escaped="[U+202E]"><span class="char">` + "\u202e" + `</span></span>`,
status: EscapeStatus{Escaped: true, HasInvisible: true},
},
{
name: "broken byte before tag",
text: "00\xa9<b>",
result: `00<span class="broken-code-point"><3E></span><b>`,
},
{
name: "ambiguous in math",
text: "<math><mo>−</mo><mi>b</mi></math> −",
result: `<math><mo>−</mo><mi>b</mi></math> <span class="ambiguous-code-point" data-tooltip-content="repo.ambiguous_character:− [U+2212],- [U+002D]"><span class="char">−</span></span>`,
text: `<maTH display="block"><mo>−</mo></MAth><mathx>−`,
result: `<maTH display="block"><mo>−</mo></MAth><mathx><span class="ambiguous-code-point" data-tooltip-content="repo.ambiguous_character:− [U+2212],- [U+002D]"><span class="char">−</span></span>`,
status: EscapeStatus{Escaped: true, HasAmbiguous: true},
},
}
func TestEscapeControlReader(t *testing.T) {
func TestEscapeControlHTML(t *testing.T) {
for _, tt := range escapeControlTests {
t.Run(tt.name, func(t *testing.T) {
output := &htmlutil.HTMLBuilder{}
status, err := EscapeControlReader(strings.NewReader(tt.text), output, &translation.MockLocale{})
assert.NoError(t, err)
status, output := EscapeControlHTML(template.HTML(tt.text), &translation.MockLocale{})
assert.Equal(t, tt.status, *status)
outStr := output.String()
assert.Equal(t, tt.result, outStr)
assert.EqualValues(t, tt.result, output)
})
}
}
func TestTrackHtmlTag(t *testing.T) {
e := &escapeStreamer{}
for _, tt := range []struct {
parts []string
inMath bool
}{
{[]string{"<ma", `TH display="block">`}, true},
{[]string{"<mo>"}, true},
{[]string{"</MA", "th>"}, false},
{[]string{"<mathx>"}, false},
} {
for _, part := range tt.parts {
e.trackHtmlTag([]byte(part))
}
assert.Equal(t, tt.inMath, e.inTagMath, "%v", tt.parts)
}
}
func TestSettingAmbiguousUnicodeDetection(t *testing.T) {
defer test.MockVariableValue(&setting.UI.AmbiguousUnicodeDetection, true)()
_, out := EscapeControlHTML("a test", &translation.MockLocale{})
@@ -188,50 +177,3 @@ func TestSettingAmbiguousUnicodeDetection(t *testing.T) {
_, out = EscapeControlHTML("a test", &translation.MockLocale{})
assert.EqualValues(t, `a test`, out)
}
func TestHTMLChunkReader(t *testing.T) {
type textPart struct {
text string
isTag bool
}
testReadChunks := func(t *testing.T, chunkSize int, input string, expected []textPart) {
r := &htmlChunkReader{in: strings.NewReader(input), readBuf: make([]byte, 0, chunkSize)}
var results []textPart
for {
parts, partIsTag, err := r.readRunes()
if err != nil {
break
}
for i, part := range parts {
results = append(results, textPart{string(part), partIsTag[i]})
}
}
assert.Equal(t, expected, results, "chunk size: %d, input: %s", chunkSize, input)
}
testReadChunks(t, 10, "abc<def>ghi", []textPart{
{text: "abc", isTag: false},
{text: "<def>", isTag: true},
{text: "gh", isTag: false},
// -- chunk
{text: "i", isTag: false},
})
testReadChunks(t, 10, "<abc><def>ghi", []textPart{
{text: "<abc>", isTag: true},
{text: "<def>", isTag: true},
// -- chunk
{text: "ghi", isTag: false},
})
rune1, rune2, rune3, rune4 := "A", "é", "啊", "🌞"
require.Len(t, rune1, 1)
require.Len(t, rune2, 2)
require.Len(t, rune3, 3)
require.Len(t, rune4, 4)
input := "<" + rune1 + rune2 + rune3 + rune4 + ">" + rune1 + rune2 + rune3 + rune4
testReadChunks(t, 4, input, []textPart{{"<Aé", true}, {"啊", true}, {"🌞", true}, {">", true}, {"Aé", false}, {"啊", false}, {"🌞", false}})
testReadChunks(t, 5, input, []textPart{{"<Aé", true}, {"啊", true}, {"🌞>", true}, {"Aé", false}, {"啊", false}, {"🌞", false}})
testReadChunks(t, 6, input, []textPart{{"<Aé", true}, {"啊", true}, {"🌞>", true}, {"A", false}, {"é啊", false}, {"🌞", false}})
testReadChunks(t, 7, input, []textPart{{"<Aé啊", true}, {"🌞>", true}, {"A", false}, {"é啊", false}, {"🌞", false}})
}

View File

@@ -140,11 +140,6 @@ func NewHTMLWriter(w io.Writer) HTMLWriter {
return &htmlWriter{w: w}
}
func NewHTMLStringWriter() (*strings.Builder, HTMLWriter) {
sb := &strings.Builder{}
return sb, &htmlWriter{w: sb}
}
type HTMLBuilder struct {
sb strings.Builder
}
@@ -157,10 +152,6 @@ func (b *HTMLBuilder) OriginWriter() io.Writer {
return &b.sb
}
func (b *HTMLBuilder) Reset() {
b.sb.Reset()
}
func (b *HTMLBuilder) WriteString(s string) HTMLWriter {
b.sb.WriteString(template.HTMLEscapeString(s))
return b

View File

@@ -252,8 +252,7 @@ func postProcess(ctx *RenderContext, procs []processor, input io.Reader, output
if !ctx.usedByRender && ctx.RenderHelper != nil {
defer ctx.RenderHelper.CleanUp()
}
// FIXME: don't read all content to memory
rawHTML, err := io.ReadAll(input)
rawHTML, err := io.ReadAll(input) // no streaming by design, the TOC before the content needs all headings
if err != nil {
return err
}

View File

@@ -23,9 +23,7 @@ func (p *finalProcessor) Write(data []byte) (int, error) {
}
func (p *finalProcessor) Close() error {
// TODO: reading the whole markdown isn't a problem at the moment,
// because "postProcess" already does so. In the future we could optimize the code to process data on the fly.
buf := p.buf.Bytes()
buf := p.buf.Bytes() // no streaming by design, detecting HTML needs the whole content
buf = bytes.ReplaceAll(buf, []byte(` data-attr-class="`+p.renderInternal.secureIDPrefix), []byte(` class="`))
tmp := bytes.TrimSpace(buf)

View File

@@ -140,8 +140,7 @@ func render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
limit: setting.UI.MaxDisplayFileSize * 3,
}
// FIXME: Don't read all to memory, but goldmark doesn't support
buf, err := io.ReadAll(input)
buf, err := io.ReadAll(input) // no streaming by design, link reference definitions may follow their use
if err != nil {
log.Error("Unable to ReadAll: %v", err)
return err

View File

@@ -405,8 +405,6 @@
"form.repo_name_been_taken": "Název repozitáře je již použit.",
"form.repository_force_private": "Vynucené soukromí je povoleno: soukromé repozitáře nelze zveřejnit.",
"form.repository_files_already_exist": "Soubory pro tento repozitář již existují. Obraťte se na správce systému.",
"form.repository_files_already_exist.delete": "Soubory pro tento repozitář již existují. Musíte je odstranit.",
"form.repository_files_already_exist.adopt_or_delete": "Soubory pro tento repozitář již existují. Přijměte je, nebo je odstraňte.",
"form.org_name_been_taken": "Název organizace je již použit.",
"form.team_name_been_taken": "Název týmu je již použit.",
"form.team_no_units_error": "Povolit přístup alespoň do jedné sekce repozitáře.",
@@ -814,14 +812,6 @@
"repo.reactions_more": "a %d dalších",
"repo.unit_disabled": "Správce webu zakázal tuto sekci repozitáře.",
"repo.language_other": "Jiný",
"repo.adopt_preexisting_label": "Přijmout soubory",
"repo.adopt_preexisting": "Přijmout již existující soubory",
"repo.adopt_preexisting_content": "Vytvořit repozitář z %s",
"repo.adopt_preexisting_success": "Přijaty soubory a vytvořen repozitář z %s",
"repo.delete_preexisting_label": "Smazat",
"repo.delete_preexisting": "Odstranit již existující soubory",
"repo.delete_preexisting_content": "Odstranit soubory v %s",
"repo.delete_preexisting_success": "Smazány nepřijaté soubory v %s",
"repo.blame_prior": "Zobrazit blame před touto změnou",
"repo.blame.ignore_revs": "Ignorování revizí v <a href=\"%s\">.git-blame-ignorerevs</a>. Klikněte zde <a href=\"%s\">pro obejití</a> a zobrazení normálního pohledu blame.",
"repo.blame.ignore_revs.failed": "Nepodařilo se ignorovat revize v <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -2531,8 +2521,6 @@
"admin.orgs.members": "Členové",
"admin.orgs.new_orga": "Nová organizace",
"admin.repos.repo_manage_panel": "Správa repozitáře",
"admin.repos.unadopted": "Nepřijaté repozitáře",
"admin.repos.unadopted.no_more": "Nebyly nalezeny žádné další nepřijaté repositáře",
"admin.repos.owner": "Vlastník",
"admin.repos.name": "Název",
"admin.repos.private": "Soukromý",

View File

@@ -546,9 +546,6 @@
"form.repo_name_been_taken": "Der Repository-Name wird schon verwendet.",
"form.repository_force_private": "Privat erzwingen ist aktiviert: Private Repositories können nicht veröffentlicht werden.",
"form.repository_files_already_exist": "Dateien für dieses Repository sind bereits vorhanden. Kontaktiere den Systemadministrator.",
"form.repository_files_already_exist.adopt": "Dateien für dieses Repository existieren bereits und können nur übernommen werden.",
"form.repository_files_already_exist.delete": "Dateien für dieses Repository sind bereits vorhanden. Du must sie löschen.",
"form.repository_files_already_exist.adopt_or_delete": "Dateien für dieses Repository existieren bereits. Du musst sie entweder übernehmen oder löschen.",
"form.org_name_been_taken": "Der Organisationsname ist bereits vergeben.",
"form.team_name_been_taken": "Der Teamname ist bereits vergeben.",
"form.team_no_units_error": "Das Team muss auf mindestens einen Bereich Zugriff haben.",
@@ -1011,15 +1008,6 @@
"repo.reactions": "Reaktionen",
"repo.unit_disabled": "Der Administrator hat diesen Repository-Bereich deaktiviert.",
"repo.language_other": "Andere",
"repo.adopt_search": "Geben einen Benutzernamen ein, um nach nicht angenommenen Repositories zu suchen... (leer lassen um alle zu finden)",
"repo.adopt_preexisting_label": "Dateien übernehmen",
"repo.adopt_preexisting": "Vorhandene Dateien übernehmen",
"repo.adopt_preexisting_content": "Repository aus %s erstellen",
"repo.adopt_preexisting_success": "Dateien übernommen und Repository erstellt von %s",
"repo.delete_preexisting_label": "Löschen",
"repo.delete_preexisting": "Vorhandene Dateien löschen",
"repo.delete_preexisting_content": "Dateien in %s löschen",
"repo.delete_preexisting_success": "Nicht übernommene Dateien in %s gelöscht",
"repo.blame_prior": "Blame vor dieser Änderung anzeigen",
"repo.blame.ignore_revs": "Revisionen in <a href=\"%s\">.git-blame-ignore-revs</a> werden ignoriert. Klicke <a href=\"%s\">hier, um das zu umgehen</a> und die normale Blame-Ansicht zu sehen.",
"repo.blame.ignore_revs.failed": "Fehler beim Ignorieren der Revisionen in <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -3133,8 +3121,6 @@
"admin.orgs.members": "Mitglieder",
"admin.orgs.new_orga": "Neue Organisation",
"admin.repos.repo_manage_panel": "Repositoryverwaltung",
"admin.repos.unadopted": "Nicht übernommene Repositories",
"admin.repos.unadopted.no_more": "Keine weiteren nicht übernommenen Repositories gefunden",
"admin.repos.owner": "Besitzer",
"admin.repos.name": "Name",
"admin.repos.private": "Privat",

View File

@@ -363,8 +363,6 @@
"form.repo_name_been_taken": "Το όνομα του αποθετηρίου χρησιμοποιείται ήδη.",
"form.repository_force_private": "Η επιλογή Μόνο Ιδιωτικά είναι ενεργοποιημένη: τα ιδιωτικά αποθετήρια δεν μπορούν να δημοσιευθούν.",
"form.repository_files_already_exist": "Αρχεία υπάρχουν ήδη για αυτό το αποθετήριο. Επικοινωνήστε με το διαχειριστή του συστήματος.",
"form.repository_files_already_exist.delete": "Τα αρχεία υπάρχουν ήδη για αυτόν το αποθετήριο. Πρέπει να τα διαγράψετε.",
"form.repository_files_already_exist.adopt_or_delete": "Τα αρχεία υπάρχουν ήδη για αυτόν το αποθετήριο. Είτε υιοθετήστε τα είτε διαγράψτε τα.",
"form.org_name_been_taken": "Το όνομα του οργανισμού χρησιμοποιείται ήδη.",
"form.team_name_been_taken": "Το όνομα της ομάδας χρησιμοποιείται ήδη.",
"form.team_no_units_error": "Να επιτρέπεται η πρόσβαση σε τουλάχιστον μία ενότητα αποθετηρίου.",
@@ -734,14 +732,6 @@
"repo.reactions_more": "και %d περισσότερα",
"repo.unit_disabled": "Ο διαχειριστής του ιστότοπου έχει απενεργοποιήσει αυτήν την ενότητα αποθετηρίου.",
"repo.language_other": "Άλλο",
"repo.adopt_preexisting_label": "Υιοθέτηση Αρχείων",
"repo.adopt_preexisting": "Υιοθετήστε τα προϋπάρχοντα αρχεία",
"repo.adopt_preexisting_content": "Δημιουργία αποθετηρίου από %s",
"repo.adopt_preexisting_success": "Υιοθετήθηκαν αρχεία και δημιουργήθηκε το αποθετήριο από %s",
"repo.delete_preexisting_label": "Διαγραφή",
"repo.delete_preexisting": "Διαγραφή αρχείων που προϋπήρχαν",
"repo.delete_preexisting_content": "Διαγραφή αρχείων στο %s",
"repo.delete_preexisting_success": "Διαγράφηκαν τα μη υιοθετημένα αρχεία στο %s",
"repo.blame_prior": "Προβολή ευθύνης πριν από αυτή την αλλαγή",
"repo.blame.ignore_revs": "Αγνόηση των αναθεωρήσεων στο <a href=\"%s\">.git-blame-ignore-revs</a>. Πατήστε <a href=\"%s\">εδώ</a> για να το παρακάμψετε και να δείτε την κανονική προβολή ευθυνών.",
"repo.blame.ignore_revs.failed": "Αποτυχία αγνόησης των αναθεωρήσεων στο <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -2281,8 +2271,6 @@
"admin.orgs.members": "Μέλη",
"admin.orgs.new_orga": "Νέος Οργανισμός",
"admin.repos.repo_manage_panel": "Διαχείριση Αποθετηρίου",
"admin.repos.unadopted": "Μη Υιοθετημένα Αποθετήρια",
"admin.repos.unadopted.no_more": "Δεν βρέθηκαν μη υιοθετημένα αποθετήρια",
"admin.repos.owner": "Ιδιοκτήτης",
"admin.repos.name": "Όνομα",
"admin.repos.private": "Ιδιωτικό",

View File

@@ -358,8 +358,6 @@
"form.repo_name_been_taken": "El nombre del repositorio ya está usado.",
"form.repository_force_private": "Forzar Privado está habilitado: los repositorios privados no pueden hacerse públicos.",
"form.repository_files_already_exist": "Ya existen archivos para este repositorio. Póngase en contacto con el administrador del sistema.",
"form.repository_files_already_exist.delete": "Ya existen archivos para este repositorio. Debe eliminarlos.",
"form.repository_files_already_exist.adopt_or_delete": "Ya existen archivos para este repositorio. Adoptarlos o eliminarlos.",
"form.org_name_been_taken": "Ya existe una organización con este nombre.",
"form.team_name_been_taken": "Ya existe un equipo con este nombre.",
"form.team_no_units_error": "Permitir el acceso a por lo menos una sección del repositorio.",
@@ -721,14 +719,6 @@
"repo.reactions_more": "y %d más",
"repo.unit_disabled": "El administrador del sitio ha deshabilitado esta sección del repositorio.",
"repo.language_other": "Otros",
"repo.adopt_preexisting_label": "Adoptar archivos",
"repo.adopt_preexisting": "Adoptar archivos preexistentes",
"repo.adopt_preexisting_content": "Crear repositorio desde %s",
"repo.adopt_preexisting_success": "Archivos aprobados y creados del repositorio desde %s",
"repo.delete_preexisting_label": "Eliminar",
"repo.delete_preexisting": "Eliminar archivos preexistentes",
"repo.delete_preexisting_content": "Eliminar archivos en %s",
"repo.delete_preexisting_success": "Eliminó archivos no adoptados en %s",
"repo.blame_prior": "Ver la culpa antes de este cambio",
"repo.blame.ignore_revs": "Ignorando revisiones en <a href=\"%s\">.git-blame-ignore-revs</a>. Haga clic <a href=\"%s\">aquí para saltar</a> y para a la vista normal.",
"repo.blame.ignore_revs.failed": "No se pudieron ignorar las revisiones en <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -2245,8 +2235,6 @@
"admin.orgs.members": "Miembros",
"admin.orgs.new_orga": "Nueva organización",
"admin.repos.repo_manage_panel": "Gestión de repositorios",
"admin.repos.unadopted": "Repositorios no adoptados",
"admin.repos.unadopted.no_more": "No se encontraron más repositorios no adoptados",
"admin.repos.owner": "Propietario",
"admin.repos.name": "Nombre",
"admin.repos.private": "Privado",

View File

@@ -279,8 +279,6 @@
"form.username_change_not_local_user": "کاربران غیر بومی مجاز به تغییر نام‌کاربری نیستند.",
"form.repo_name_been_taken": "نام مخزن قبلا ثبت شده است.",
"form.repository_files_already_exist": "در حال حاضر این فایل در این مخزن موجود است. با مدیر سیستم خود تماس بگیرید.",
"form.repository_files_already_exist.delete": "فایل‌ها در این مخزن موجود است. ابتدا باید آن را پاک کنید.",
"form.repository_files_already_exist.adopt_or_delete": "این فایل در این مخزن موجود است. یا از آن استفاده کرده یا آن را پاک کنید.",
"form.org_name_been_taken": "نام سازمان قبلا ثبت شده است.",
"form.team_name_been_taken": "نام تیم قبلا ثبت شده است.",
"form.team_no_units_error": "اجازه دسترسی به حداقل یک بخش مخزن.",
@@ -562,14 +560,6 @@
"repo.reactions_more": "و %d بیشتر",
"repo.unit_disabled": "مدیر سایت این قسمت مخزن را غیرفعال کرده است.",
"repo.language_other": "دیگر",
"repo.adopt_preexisting_label": "فایلهای پذیرش یافته",
"repo.adopt_preexisting": "فایلهای موجود برای پذیرش",
"repo.adopt_preexisting_content": "ایجاد مخزن از %s",
"repo.adopt_preexisting_success": "فایل‌ها را پذیرفت و انبار را از %s ایجاد کرد",
"repo.delete_preexisting_label": "حذف",
"repo.delete_preexisting": "حذف فایلهایی که قبلا موجود بود",
"repo.delete_preexisting_content": "حذف فایلهای موجود در %s",
"repo.delete_preexisting_success": "فایل های تصویب نشده پاک شده در %s",
"repo.blame_prior": "قبل از این تغییر، سرزنش را مشاهده کنید",
"repo.transfer.accept": "تایید انتقال",
"repo.transfer.reject": "رد انتقال",
@@ -1777,8 +1767,6 @@
"admin.orgs.members": "اعضاء",
"admin.orgs.new_orga": "سازمان جدید",
"admin.repos.repo_manage_panel": "مدیریت مخزن",
"admin.repos.unadopted": "مخازن تصویب نشده",
"admin.repos.unadopted.no_more": "هیچ مخزن تایید نشده دیگری یافت نشد",
"admin.repos.owner": "مالک",
"admin.repos.name": "نام",
"admin.repos.private": "خصوصی",

View File

@@ -493,7 +493,6 @@
"repo.watchers": "Tarkkailijat",
"repo.stargazers": "Tähtiharrastajat",
"repo.forks": "Haarat",
"repo.delete_preexisting_label": "Poista",
"repo.desc.private": "Yksityinen",
"repo.desc.public": "Julkinen",
"repo.desc.template": "Malli",

View File

@@ -546,9 +546,6 @@
"form.repo_name_been_taken": "Ce nom de dépôt est déjà utilisé.",
"form.repository_force_private": "Force Private est activé : les dépôts privés ne peuvent pas être rendus publics.",
"form.repository_files_already_exist": "Les fichiers existent déjà pour ce dépôt. Contactez l'administrateur système.",
"form.repository_files_already_exist.adopt": "Des fichiers existent déjà dans ce dépôt et ne peuvent être qu’adoptés.",
"form.repository_files_already_exist.delete": "Des fichiers existent déjà pour ce dépôt. Vous devez les supprimer.",
"form.repository_files_already_exist.adopt_or_delete": "Des fichiers existent déjà dans ce dépôt. Veuillez les adopter ou les supprimer.",
"form.org_name_been_taken": "Ce nom d'organisation est déjà pris.",
"form.team_name_been_taken": "Le nom d'équipe est déjà pris.",
"form.team_no_units_error": "Autoriser l’accès à au moins une section du dépôt.",
@@ -1011,15 +1008,6 @@
"repo.reactions": "Réactions",
"repo.unit_disabled": "L’administrateur du site a désactivé cette section du dépôt.",
"repo.language_other": "Autre",
"repo.adopt_search": "Entrez un nom d’utilisateur pour rechercher les dépôts dépossédés… (laissez vide pour tous trouver)",
"repo.adopt_preexisting_label": "Adopter les fichiers",
"repo.adopt_preexisting": "Adopter les fichiers préexistants",
"repo.adopt_preexisting_content": "Créer un dépôt à partir de %s.",
"repo.adopt_preexisting_success": "Fichiers adoptés et dépôt créé depuis %s",
"repo.delete_preexisting_label": "Supprimer",
"repo.delete_preexisting": "Supprimer les fichiers préexistants",
"repo.delete_preexisting_content": "Supprimer les fichiers dans %s",
"repo.delete_preexisting_success": "Fichiers dépossédés supprimés dans %s.",
"repo.blame_prior": "Voir le blame avant cette modification",
"repo.blame.ignore_revs": "Les révisions dans <a href=\"%s\">.git-blame-ignore-revs</a> sont ignorées. Vous pouvez quand même <a href=\"%s\">voir ces blâmes</a>.",
"repo.blame.ignore_revs.failed": "Impossible d'ignorer les révisions dans <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -1708,6 +1696,7 @@
"repo.issues.review.content.empty": "Vous devez laisser un commentaire indiquant le(s) changement(s) demandé(s).",
"repo.issues.review.reject": "a requis les changements %s",
"repo.issues.review.wait": "a été sollicité pour évaluer cette demande d’ajout %s.",
"repo.codeowners": "Propriétaires du code",
"repo.issues.review.codeowners_rules": "Règles des CODEOWNERS",
"repo.issues.review.add_review_request": "a demandé à %s une évaluation %s.",
"repo.issues.review.remove_review_request": "a retiré la demande d’évaluation pour %s %s.",
@@ -2661,6 +2650,8 @@
"repo.release.message": "Décrire cette publication",
"repo.release.prerelease_desc": "Marquer comme pré-publication",
"repo.release.prerelease_helper": "Marquer cette publication comme impropre à la production.",
"repo.release.make_latest": "Définir comme dernière version",
"repo.release.make_latest_helper": "Libeller cette version comme la dernière de ce dépôt.",
"repo.release.cancel": "Annuler",
"repo.release.publish": "Publier",
"repo.release.save_draft": "Sauvegarder le Brouillon",
@@ -3138,8 +3129,6 @@
"admin.orgs.members": "Membres",
"admin.orgs.new_orga": "Nouvelle organisation",
"admin.repos.repo_manage_panel": "Gestion des dépôts",
"admin.repos.unadopted": "Dépôts dépossédés",
"admin.repos.unadopted.no_more": "Aucun dépôt dépossédé trouvé.",
"admin.repos.owner": "Propriétaire",
"admin.repos.name": "Nom",
"admin.repos.private": "Privé",
@@ -3677,10 +3666,15 @@
"packages.terraform.lock.error.already_locked": "L’état Terraform est déjà verrouillé.",
"packages.terraform.delete.locked": "L’état Terraform est verrouillé et ne peut pas être supprimé.",
"packages.terraform.delete.latest": "La dernière version d’un état Terraform ne peut pas être supprimée.",
"packages.terraform_module.install": "Ajoutez le module à votre configuration Terraform :",
"packages.terraform_module.install_terragrunt": "Ou ajoutez-le à votre configuration Terragrunt :",
"packages.terraform_module.credentials": "Configurer les identifiants pour ce registre dans ~/.terraformrc:",
"packages.terraform_module.submodules": "Sous-modules",
"packages.terraform_module.name": "Nom",
"packages.terraform_module.type": "Type",
"packages.terraform_module.default": "Par défaut",
"packages.terraform_module.description": "Description",
"packages.terraform_module.required": "requis",
"packages.vagrant.install": "Pour ajouter une machine Vagrant, exécutez la commande suivante :",
"packages.settings.link": "Lier ce paquet à un dépôt",
"packages.settings.link.description": "Si vous liez un paquet à dépôt, il sera visible dans sa liste des paquets.",

View File

@@ -546,9 +546,6 @@
"form.repo_name_been_taken": "Úsáidtear ainm an stór cheana féin.",
"form.repository_force_private": "Tá Force Private cumasaithe: ní féidir stórais phríobháideacha a dhéanamh poiblí.",
"form.repository_files_already_exist": "Tá comhaid ann cheana féin don stór seo. Déan teagmháil leis an riarthóir córais.",
"form.repository_files_already_exist.adopt": "Tá comhaid ann cheana féin don stórlann seo agus ní féidir iad a ghlacadh ach amháin.",
"form.repository_files_already_exist.delete": "Tá comhaid ann cheana féin don stór seo. Ní mór duit iad a scriosadh.",
"form.repository_files_already_exist.adopt_or_delete": "Tá comhaid ann cheana féin don stór seo. Glac iad nó scrios iad.",
"form.org_name_been_taken": "Tá ainm na heagraíochta glactha cheana féin.",
"form.team_name_been_taken": "Tá ainm na foirne glactha cheana féin.",
"form.team_no_units_error": "Ceadaigh rochtain ar chuid stórais amháin ar a laghad.",
@@ -1012,15 +1009,6 @@
"repo.reactions": "Imoibrithe",
"repo.unit_disabled": "Tá an chuid stórais seo díchumasaithe ag riarthóir an láithreáin.",
"repo.language_other": "Eile",
"repo.adopt_search": "Cuir isteach ainm úsáideora chun cuardach a dhéanamh ar stórtha neamhuchtaithe… (fág bán chun gach ceann a aimsiú)",
"repo.adopt_preexisting_label": "Glacadh le Comhaid",
"repo.adopt_preexisting": "Glac le comhaid atá ann cheana",
"repo.adopt_preexisting_content": "Cruthaigh stór ó %s",
"repo.adopt_preexisting_success": "Comhaid ghlacadh agus stór cruthaithe ó %s",
"repo.delete_preexisting_label": "Scrios",
"repo.delete_preexisting": "Scrios comhaid atá ann cheana",
"repo.delete_preexisting_content": "Scrios comhaid i %s",
"repo.delete_preexisting_success": "Scriosta comhaid neamhghlactha i %s",
"repo.blame_prior": "Féach ar an milleán roimh an athrú seo",
"repo.blame.ignore_revs": "Ag déanamh neamhairde de leasuithe i <a href=\"%s\">.git-blame-ignore-revs</a>. Cliceáil <a href=\"%s\">anseo chun seachaint</a> agus an gnáth-amharc milleán a fheiceáil.",
"repo.blame.ignore_revs.failed": "Theip ar neamhaird a dhéanamh ar leasuithe i <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -3146,8 +3134,6 @@
"admin.orgs.members": "Comhaltaí",
"admin.orgs.new_orga": "Eagraíocht Nua",
"admin.repos.repo_manage_panel": "Bainistíocht Stórais",
"admin.repos.unadopted": "Stórais Neamhghlactha",
"admin.repos.unadopted.no_more": "Níor aimsíodh níos mó stórais neamhghlactha",
"admin.repos.owner": "Úinéir",
"admin.repos.name": "Ainm",
"admin.repos.private": "Príobháideach",

View File

@@ -432,7 +432,6 @@
"repo.forks": "Másolások",
"repo.reactions_more": "és további %d",
"repo.language_other": "Egyéb",
"repo.delete_preexisting_label": "Törlés",
"repo.desc.private": "Privát",
"repo.desc.public": "Nyilvános",
"repo.desc.template": "Sablon",

View File

@@ -464,7 +464,6 @@
"repo.forks": "Garpu",
"repo.reactions_more": "dan %d lainnya",
"repo.unit_disabled": "Administrator web menonaktifkan bagian repositori ini.",
"repo.delete_preexisting_label": "Hapus",
"repo.desc.private": "Pribadi",
"repo.desc.public": "Publik",
"repo.desc.template": "Contoh",

View File

@@ -435,8 +435,6 @@
"repo.forks": "Skiptingar",
"repo.reactions_more": "og %d fleiri",
"repo.language_other": "Annað",
"repo.delete_preexisting_label": "Eyða",
"repo.delete_preexisting_content": "Eyða skrám í %s",
"repo.desc.private": "Einka",
"repo.desc.public": "Opinbert",
"repo.desc.template": "Sniðmát",

View File

@@ -281,8 +281,6 @@
"form.repo_name_been_taken": "Il nome del repository esiste già.",
"form.repository_force_private": "Force Private è abilitato: i repository privati non possono essere resi pubblici.",
"form.repository_files_already_exist": "File già esistenti per questo repository. Contatta l'amministratore di sistema.",
"form.repository_files_already_exist.delete": "I file esistono già per questo repository. È necessario eliminarli.",
"form.repository_files_already_exist.adopt_or_delete": "I file esistono già per questo repository. O li Adotti o li Elimini.",
"form.org_name_been_taken": "Il nome della organizzazione esiste già.",
"form.team_name_been_taken": "Il nome del team esiste già.",
"form.team_no_units_error": "Consenti l'accesso ad almeno una sezione del repository.",
@@ -584,14 +582,6 @@
"repo.reactions_more": "e %d più",
"repo.unit_disabled": "L'amministratore ha disabilitato questa sezione del repository.",
"repo.language_other": "Altro",
"repo.adopt_preexisting_label": "Adotta File",
"repo.adopt_preexisting": "Adottare file preesistenti",
"repo.adopt_preexisting_content": "Crea repository da %s",
"repo.adopt_preexisting_success": "File adottati e repository creati da %s",
"repo.delete_preexisting_label": "Elimina",
"repo.delete_preexisting": "Elimina file preesistenti",
"repo.delete_preexisting_content": "Elimina file in %s",
"repo.delete_preexisting_success": "Eliminato file non adottati in %s",
"repo.blame_prior": "Visualizza la colpa prima di questa modifica",
"repo.transfer.accept": "Accetta trasferimento",
"repo.transfer.reject": "Rifiuta trasferimento",
@@ -1862,8 +1852,6 @@
"admin.orgs.members": "Membri",
"admin.orgs.new_orga": "Nuova Organizzazione",
"admin.repos.repo_manage_panel": "Gestione Repository",
"admin.repos.unadopted": "Depositi Non Adottati",
"admin.repos.unadopted.no_more": "Nessun repository non adottato trovato",
"admin.repos.owner": "Proprietario",
"admin.repos.name": "Nome",
"admin.repos.private": "Privati",

View File

@@ -546,9 +546,6 @@
"form.repo_name_been_taken": "リポジトリ名が既に使用されています。",
"form.repository_force_private": "強制プライベートが有効です。プライベートリポジトリはパブリックにできません。",
"form.repository_files_already_exist": "このリポジトリには既にファイルが存在しています。システム管理者に問い合わせてください。",
"form.repository_files_already_exist.adopt": "このリポジトリには既にファイルが存在しており、それらを取り込むことはできます。",
"form.repository_files_already_exist.delete": "このリポジトリには既にファイルが存在しています。 それらを削除する必要があります。",
"form.repository_files_already_exist.adopt_or_delete": "このリポジトリには既にファイルが存在しています。 それらを取り込むか削除してください。",
"form.org_name_been_taken": "組織名が既に使用されています。",
"form.team_name_been_taken": "チーム名が既に使用されています。",
"form.team_no_units_error": "リポジトリセクションは、少なくともひとつはアクセスを許可してください。",
@@ -1010,15 +1007,6 @@
"repo.reactions": "リアクション",
"repo.unit_disabled": "サイト管理者がこのリポジトリセクションを無効にしています。",
"repo.language_other": "その他",
"repo.adopt_search": "未登録リポジトリを探すユーザー名を入力… (空ですべてを探索)",
"repo.adopt_preexisting_label": "ファイルを登録",
"repo.adopt_preexisting": "既存ファイルの登録",
"repo.adopt_preexisting_content": "%s からリポジトリを作成します",
"repo.adopt_preexisting_success": "%s のファイルを登録し、リポジトリを作成しました",
"repo.delete_preexisting_label": "削除",
"repo.delete_preexisting": "既存のファイルを削除",
"repo.delete_preexisting_content": "%s のファイルを削除します",
"repo.delete_preexisting_success": "%s の未登録ファイルを削除しました",
"repo.blame_prior": "この変更より前のBlameを表示",
"repo.blame.ignore_revs": "<a href=\"%s\">.git-blame-ignore-revs</a> で指定されたリビジョンは除外しています。 これを迂回して通常のBlame表示を見るには <a href=\"%s\">ここ</a>をクリック。",
"repo.blame.ignore_revs.failed": "<a href=\"%s\">.git-blame-ignore-revs</a> によるリビジョンの無視は失敗しました。",
@@ -3121,8 +3109,6 @@
"admin.orgs.members": "メンバー",
"admin.orgs.new_orga": "新しい組織",
"admin.repos.repo_manage_panel": "リポジトリの管理",
"admin.repos.unadopted": "未登録リポジトリ",
"admin.repos.unadopted.no_more": "未登録のリポジトリはありません",
"admin.repos.owner": "オーナー",
"admin.repos.name": "名称",
"admin.repos.private": "プライベート",

View File

@@ -546,9 +546,6 @@
"form.repo_name_been_taken": "이미 사용하고 있는 리포지토리 이름입니다.",
"form.repository_force_private": "강제 비공개 모드가 활성화됨: 비공개 리포지토리는 공개로 설정할 수 없습니다.",
"form.repository_files_already_exist": "리포지토리에 파일이 이미 존재합니다. 시스템 운영자에게 문의하세요.",
"form.repository_files_already_exist.adopt": "리포지토리에 파일이 이미 존재하며 편입만 가능합니다.",
"form.repository_files_already_exist.delete": "리포지토리에 파일이 이미 존재합니다. 이미 존재하는 파일을 삭제해야 합니다.",
"form.repository_files_already_exist.adopt_or_delete": "리포지토리에 파일이 이미 존재합니다. 편입하거나 삭제하세요.",
"form.org_name_been_taken": "이미 사용중인 조직 이름입니다.",
"form.team_name_been_taken": "이미 사용중인 팀 이름입니다.",
"form.team_no_units_error": "최소 하나 이상의 리포지토리 섹션에 대한 접근을 허용하십시오.",
@@ -1011,15 +1008,6 @@
"repo.reactions": "리액션",
"repo.unit_disabled": "사이트 운영자가 이 리포지토리 섹션을 비활성화했습니다.",
"repo.language_other": "기타",
"repo.adopt_search": "편입되지 않은 리포지토리를 찾을 사용자명을 입력하세요… (모두 찾으려면 비워두세요)",
"repo.adopt_preexisting_label": "파일 편입",
"repo.adopt_preexisting": "기존 파일 편입",
"repo.adopt_preexisting_content": "%s에서 리포지토리 생성",
"repo.adopt_preexisting_success": "%s에서 파일을 편입하여 리포지토리를 생성했습니다",
"repo.delete_preexisting_label": "삭제",
"repo.delete_preexisting": "기존 파일 삭제",
"repo.delete_preexisting_content": "%s 내의 파일 삭제",
"repo.delete_preexisting_success": "%s 내의 편입되지 않은 파일을 삭제함",
"repo.blame_prior": "이 변경 이전의 Blame 보기",
"repo.blame.ignore_revs": "<a href=\"%s\">.git-blame-ignore-revs</a>에 있는 리비전을 무시합니다. 일반 blame 보기를 보려면 <a href=\"%s\">여기를 클릭하여 우회</a>하세요.",
"repo.blame.ignore_revs.failed": "<a href=\"%s\">.git-blame-ignore-revs</a>내의 리비전을 무시하는 데 실패했습니다.",
@@ -3133,8 +3121,6 @@
"admin.orgs.members": "멤버",
"admin.orgs.new_orga": "새 조직",
"admin.repos.repo_manage_panel": "리포지토리 관리",
"admin.repos.unadopted": "편입되지 않은 저장소",
"admin.repos.unadopted.no_more": "더 이상 채택되지 않은 리포지토리를 찾을 수 없음",
"admin.repos.owner": "소유자",
"admin.repos.name": "이름",
"admin.repos.private": "비공개",

View File

@@ -370,8 +370,6 @@
"form.repo_name_been_taken": "Jau eksistē repozitorijs ar šādu nosaukumu.",
"form.repository_force_private": "Ir ieslēgts piespiedu privātais režīms: repozitorijus nav iespējams padarīt publiskus.",
"form.repository_files_already_exist": "Šī repozitorija faili jau eksistē, sazinieties ar sistēmas administratoru.",
"form.repository_files_already_exist.delete": "Šī repozitorija faili jau eksistē, nepieciešams tos dzēst.",
"form.repository_files_already_exist.adopt_or_delete": "Šī repozitorija faili jau eksistē, tie ir jāpārņem vai jādzēš.",
"form.org_name_been_taken": "Organizācijas nosaukums jau ir aizņemts.",
"form.team_name_been_taken": "Komandas nosaukums jau ir aizņemts.",
"form.team_no_units_error": "Komandai ir jābūt iespējotai vismaz vienai sadaļai.",
@@ -745,14 +743,6 @@
"repo.reactions_more": "un vēl %d",
"repo.unit_disabled": "Administrators ir atspējojies šo repozitorija sadaļu.",
"repo.language_other": "Citas",
"repo.adopt_preexisting_label": "Pārņemt failus",
"repo.adopt_preexisting": "Pārņemt jau eksistējošos failus",
"repo.adopt_preexisting_content": "Izveidot repozitoriju no direktorijas %s",
"repo.adopt_preexisting_success": "Pārņemti faili un izveidots repozitorijs no %s",
"repo.delete_preexisting_label": "Dzēst",
"repo.delete_preexisting": "Dzēst jau eksistējošos failus",
"repo.delete_preexisting_content": "Dzēst failus direktorijā %s",
"repo.delete_preexisting_success": "Dzēst nepārņemtos failus direktorijā %s",
"repo.blame_prior": "Aplūkot vainīgo par izmaiņām pirms šīs revīzijas",
"repo.blame.ignore_revs": "Neņem vērā izmaiņas no <a href=\"%s\">.git-blame-ignore-revs</a>. Nospiediet <a href=\"%s\">šeit, lai to apietu</a> un redzētu visu izmaiņu skatu.",
"repo.blame.ignore_revs.failed": "Neizdevās neņemt vērā izmaiņas no <a href=\"%s\">.git-blam-ignore-revs</a>.",
@@ -2318,8 +2308,6 @@
"admin.orgs.members": "Dalībnieki",
"admin.orgs.new_orga": "Jauna organizācija",
"admin.repos.repo_manage_panel": "Repozitoriju pārvaldība",
"admin.repos.unadopted": "Nepārņemtie repozitoriji",
"admin.repos.unadopted.no_more": "Netika atrasts neviens nepārņemtais repozitorijs",
"admin.repos.owner": "Īpašnieks",
"admin.repos.name": "Nosaukums",
"admin.repos.private": "Privāts",

View File

@@ -283,8 +283,6 @@
"form.repo_name_been_taken": "De repository-naam wordt al gebruikt.",
"form.repository_force_private": "Forceer privé is ingeschakeld: privé repositories kunnen niet openbaar worden gemaakt.",
"form.repository_files_already_exist": "Er bestaan al bestanden voor deze repository. Neem contact op met de systeembeheerder.",
"form.repository_files_already_exist.delete": "Er bestaan al bestanden voor deze repository. U moet deze verwijderen.",
"form.repository_files_already_exist.adopt_or_delete": "Er bestaan al bestanden voor deze repository. Adopteer of verwijder deze.",
"form.org_name_been_taken": "Naam van de organisatie wordt al gebruikt.",
"form.team_name_been_taken": "De teamnaam is al in gebruik.",
"form.team_no_units_error": "Toegang verlenen tot ten minste één repository sectie.",
@@ -578,14 +576,6 @@
"repo.reactions_more": "en %d meer",
"repo.unit_disabled": "De sitebeheerder heeft deze repositorie sectie uitgeschakeld.",
"repo.language_other": "Andere",
"repo.adopt_preexisting_label": "Bestanden adopteren",
"repo.adopt_preexisting": "Bestaamde bestanden adopteren",
"repo.adopt_preexisting_content": "Maak een repository van %s",
"repo.adopt_preexisting_success": "Bestanden geadopteerd en repository gemaakt van %s",
"repo.delete_preexisting_label": "Verwijderen",
"repo.delete_preexisting": "Verwijder reeds bestaande bestanden",
"repo.delete_preexisting_content": "Verwijder bestanden in %s",
"repo.delete_preexisting_success": "Niet-geadopteerde bestanden verwijderd in %s",
"repo.blame_prior": "Bekijk de schuld voorafgaand aan deze verandering",
"repo.transfer.accept": "Accepteer overdracht",
"repo.transfer.reject": "Overdracht afwijzen",
@@ -1710,8 +1700,6 @@
"admin.orgs.members": "Leden",
"admin.orgs.new_orga": "Nieuwe organisatie",
"admin.repos.repo_manage_panel": "Repositories beheren",
"admin.repos.unadopted": "Niet-geadopteerde repositories",
"admin.repos.unadopted.no_more": "Geen niet-geadopteerde repositories meer gevonden",
"admin.repos.owner": "Eigenaar",
"admin.repos.name": "Naam",
"admin.repos.private": "Prive",

View File

@@ -520,9 +520,6 @@
"form.repo_name_been_taken": "Nazwa repozytorium jest już zajęta.",
"form.repository_force_private": "Wymuszenie Prywatności jest włączone: prywatne repozytoria nie mogą zostać zmienione na publiczne.",
"form.repository_files_already_exist": "Pliki już istnieją dla tego repozytorium. Skontaktuj się z administratorem systemu.",
"form.repository_files_already_exist.adopt": "Pliki już istnieją dla tego repozytorium i mogą być jedynie dostosowane.",
"form.repository_files_already_exist.delete": "Pliki już istnieją dla tego repozytorium. Musisz je usunąć.",
"form.repository_files_already_exist.adopt_or_delete": "Pliki już istnieją dla tego repozytorium. Przyjmij, lub usuń je.",
"form.org_name_been_taken": "Nazwa organizacji jest już zajęta.",
"form.team_name_been_taken": "Nazwa zespołu jest już zajęta.",
"form.team_no_units_error": "Zezwól na dostęp do co najmniej jednej sekcji repozytorium.",
@@ -985,15 +982,6 @@
"repo.reactions": "Reakcje",
"repo.unit_disabled": "Administrator witryny wyłączył tę sekcję repozytorium.",
"repo.language_other": "Pozostałe",
"repo.adopt_search": "Wprowadź nazwę użytkownika, aby wyszukać nieprzyjęte repozytoria… (pozostaw puste, aby wyszukać wszystkie)",
"repo.adopt_preexisting_label": "Przyjmij pliki",
"repo.adopt_preexisting": "Przyjmij istniejące pliki",
"repo.adopt_preexisting_content": "Stwórz repozytorium z %s",
"repo.adopt_preexisting_success": "Przyjęto pliki i utworzono repozytorium z %s",
"repo.delete_preexisting_label": "Usuń",
"repo.delete_preexisting": "Usuń istniejące pliki",
"repo.delete_preexisting_content": "Usuń pliki w %s",
"repo.delete_preexisting_success": "Usunięto nieprzyjęte pliki w %s",
"repo.blame_prior": "Zobacz odpowiedzialność sprzed tej zmiany",
"repo.blame.ignore_revs": "Ignorowanie rewizji w <a href=\"%s\">.git-blame-ignore-revs</a>. Kliknij <a href=\"%s\">tutaj, aby ominąć ignorowanie</a> i zobaczyć normalny widok odpowiedzialności.",
"repo.blame.ignore_revs.failed": "Nie udało się zignorować rewizji w <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -3076,8 +3064,6 @@
"admin.orgs.members": "Członkowie",
"admin.orgs.new_orga": "Nowa organizacja",
"admin.repos.repo_manage_panel": "Zarządzanie repozytoriami",
"admin.repos.unadopted": "Nieprzyjęte repozytoria",
"admin.repos.unadopted.no_more": "Nie znaleziono więcej nieprzyjętych repozytoriów",
"admin.repos.owner": "Właściciel",
"admin.repos.name": "Nazwa",
"admin.repos.private": "Prywatne",

View File

@@ -471,9 +471,6 @@
"form.repo_name_been_taken": "O nome de repositório já está sendo usado.",
"form.repository_force_private": "Forçar Privado está ativado: repositórios privados não podem ser tornados públicos.",
"form.repository_files_already_exist": "Arquivos já existem neste repositório. Contate o administrador.",
"form.repository_files_already_exist.adopt": "Arquivos já existem neste repositório e só podem ser adotados.",
"form.repository_files_already_exist.delete": "Arquivos já existem neste repositório. Você deve deletá-los.",
"form.repository_files_already_exist.adopt_or_delete": "Arquivos já existem neste repositório. Você deve adotá-los ou deletá-los.",
"form.org_name_been_taken": "O nome da organização já está sendo usado.",
"form.team_name_been_taken": "O nome da equipe já está sendo usado.",
"form.team_no_units_error": "Permitir acesso a pelo menos uma seção de repositório.",
@@ -917,15 +914,6 @@
"repo.reactions": "Reações",
"repo.unit_disabled": "O administrador do site desabilitou esta seção do repositório.",
"repo.language_other": "Outra",
"repo.adopt_search": "Digite o nome de usuário para pesquisar por repositórios órfãos… (deixe em branco para encontrar todos)",
"repo.adopt_preexisting_label": "Adotar Arquivos",
"repo.adopt_preexisting": "Adotar arquivos pré-existentes",
"repo.adopt_preexisting_content": "Criar repositório a partir de %s",
"repo.adopt_preexisting_success": "Arquivos adotados e repositório criado a partir de %s",
"repo.delete_preexisting_label": "Excluir",
"repo.delete_preexisting": "Excluir arquivos pré-existentes",
"repo.delete_preexisting_content": "Excluir arquivos em %s",
"repo.delete_preexisting_success": "Arquivos órfãos excluídos em %s",
"repo.blame_prior": "Ver a responsabilização anterior a esta modificação",
"repo.blame.ignore_revs": "Ignorando revisões presentes em <a href=\"%s\">.git-blame-ignore-revs</a>. Clique <a href=\"%s\">aqui para ignorar</a> e ver o blame normalmente.",
"repo.blame.ignore_revs.failed": "Falha ao ignorar revisões em <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -2652,8 +2640,6 @@
"admin.orgs.members": "Membros",
"admin.orgs.new_orga": "Nova Organização",
"admin.repos.repo_manage_panel": "Gerenciamento do Repositório",
"admin.repos.unadopted": "Repositórios Não Adotados",
"admin.repos.unadopted.no_more": "Não foram encontrados mais repositórios não adotados",
"admin.repos.owner": "Proprietário",
"admin.repos.name": "Nome",
"admin.repos.private": "Privado",

View File

@@ -407,6 +407,7 @@
"auth.twofa_scratch_used": "Você usou o seu código de recuperação. Foi reencaminhado para a página de configurações da autenticação em dois passos para poder remover o registo do seu dispositivo ou gerar um novo código de recuperação.",
"auth.twofa_passcode_incorrect": "A senha está errada. Se perdeu o seu dispositivo, use o código de recuperação para iniciar a sessão.",
"auth.twofa_scratch_token_incorrect": "O código de recuperação está errado.",
"auth.twofa_too_many_attempts": "Demasiados códigos errados. Tente mais tarde ou use o seu código de recuperação.",
"auth.twofa_required": "Tem de configurar a autenticação em dois passos para obter acesso aos repositórios ou então tentar iniciar a sessão novamente.",
"auth.login_userpass": "Iniciar sessão",
"auth.oauth_signup_tab": "Fazer inscrição",
@@ -546,9 +547,6 @@
"form.repo_name_been_taken": "O nome do repositório já foi usado.",
"form.repository_force_private": "Forçar Privado está habilitado: repositórios privados não podem ser tornados públicos.",
"form.repository_files_already_exist": "Já existem ficheiros neste repositório. Contacte o administrador do sistema.",
"form.repository_files_already_exist.adopt": "Já existem ficheiros neste repositório e só podem ser adoptados.",
"form.repository_files_already_exist.delete": "Já existem ficheiros neste repositório. Tem que os eliminar.",
"form.repository_files_already_exist.adopt_or_delete": "Já existem ficheiros neste repositório. Adopte-os ou elimine-os.",
"form.org_name_been_taken": "O nome da organização já foi tomado.",
"form.team_name_been_taken": "O nome da equipa já foi tomado.",
"form.team_no_units_error": "Permitir acesso a pelo menos uma secção do repositório.",
@@ -834,6 +832,7 @@
"settings.permission_anonymous_read": "Leitura anónima",
"settings.permission_everyone_read": "Leitura pública",
"settings.permission_everyone_write": "Escrita pública",
"settings.access_token_desc": "As permissões dos códigos escolhidos limitam a autorização apenas às rotas da <a %s>API</a> correspondentes. Permissões do repositório incluem as permissões do estado do cometimento. Leia a <a %s>documentação</a> para obter mais informação.",
"settings.at_least_one_permission": "Tem que escolher pelo menos uma permissão para criar um código",
"settings.permissions_list": "Permissões:",
"settings.manage_oauth2_applications": "Gerir aplicações OAuth2",
@@ -1002,6 +1001,7 @@
"repo.mirror_last_synced": "Última sincronização",
"repo.mirror_password_placeholder": "(inalterada)",
"repo.mirror_password_blank_placeholder": "(não definida)",
"repo.mirror_password_help": "Altere o nome de utilizador ou o endereço para eliminar uma senha armazenada.",
"repo.watchers": "Vigilantes",
"repo.stargazers": "Fãs",
"repo.stars_remove_warning": "Isto irá remover todas as marcas de favoritos deste repositório.",
@@ -1011,15 +1011,6 @@
"repo.reactions": "Respostas",
"repo.unit_disabled": "O administrador desabilitou esta secção do repositório.",
"repo.language_other": "Outros",
"repo.adopt_search": "Insira o nome de utilizador para procurar repositórios adoptados… (deixe em branco para encontrar todos)",
"repo.adopt_preexisting_label": "Adoptar ficheiros",
"repo.adopt_preexisting": "Adoptar ficheiros pré-existentes",
"repo.adopt_preexisting_content": "Criar repositório a partir de %s",
"repo.adopt_preexisting_success": "Ficheiros adoptados e repositório criado a partir de %s",
"repo.delete_preexisting_label": "Eliminar",
"repo.delete_preexisting": "Eliminar ficheiros pré-existentes",
"repo.delete_preexisting_content": "Eliminar ficheiros em %s",
"repo.delete_preexisting_success": "Eliminados os ficheiros não adoptados em %s",
"repo.blame_prior": "Ver a responsabilização anterior a esta modificação",
"repo.blame.ignore_revs": "Ignorando as revisões em <a href=\"%s\">.git-blame-ignore-revs</a>. Clique <a href=\"%s\">aqui para contornar</a> e ver a vista normal de responsabilização.",
"repo.blame.ignore_revs.failed": "Falhou ao ignorar as revisões em <a href=\"%s\">.git-blame-ignore-revs</a>.",
@@ -1710,6 +1701,7 @@
"repo.issues.review.content.empty": "Tem que deixar um comentário indicando a(s) modificação(ões) solicitada(s).",
"repo.issues.review.reject": "modificações solicitadas %s",
"repo.issues.review.wait": "foi solicitada para revisão %s",
"repo.codeowners": "Proprietários do código",
"repo.issues.review.codeowners_rules": "Regras do CODEOWNERS",
"repo.issues.review.add_review_request": "solicitou revisão de %s %s",
"repo.issues.review.remove_review_request": "removeu a solicitação de revisão para %s %s",
@@ -2297,6 +2289,7 @@
"repo.settings.event_branch_delete": "Exclusão do ramo",
"repo.settings.event_push_desc": "Envio do Git para um repositório.",
"repo.settings.event_repository": "Repositório",
"repo.settings.event_repository_desc": "Repositório criado, eliminado, renomeado ou transferido.",
"repo.settings.event_header_issue": "Eventos da questão",
"repo.settings.event_issues": "Questões",
"repo.settings.event_issues_desc": "Questão aberta, fechada, reaberta, editada ou eliminada.",
@@ -2664,6 +2657,8 @@
"repo.release.message": "Descreva este lançamento",
"repo.release.prerelease_desc": "Marcar como pré-lançamento",
"repo.release.prerelease_helper": "Marcar este lançamento como inadequado para uso em produção.",
"repo.release.make_latest": "Definir como lançamento mais recente",
"repo.release.make_latest_helper": "Rotular este lançamento como sendo o mais recente deste repositório.",
"repo.release.cancel": "Cancelar",
"repo.release.publish": "Publicar lançamento",
"repo.release.save_draft": "Guardar rascunho",
@@ -3141,8 +3136,6 @@
"admin.orgs.members": "Membros",
"admin.orgs.new_orga": "Nova organização",
"admin.repos.repo_manage_panel": "Gestão dos repositórios",
"admin.repos.unadopted": "Repositórios não adoptados",
"admin.repos.unadopted.no_more": "Não foram encontrados mais repositórios não adoptados",
"admin.repos.owner": "Proprietário(a)",
"admin.repos.name": "Nome",
"admin.repos.private": "Privado",
@@ -3681,10 +3674,18 @@
"packages.terraform.lock.error.already_locked": "O estado do Terraform já se encontra bloqueado.",
"packages.terraform.delete.locked": "O estado do Terraform está bloqueado e não pode ser eliminado.",
"packages.terraform.delete.latest": "A última versão de um estado do Terraform não pode ser eliminada.",
"packages.terraform_module.install": "Adicione o módulo à sua configuração Terraform:",
"packages.terraform_module.install_terragrunt": "Ou adicione-o à sua configuração Terragrunt:",
"packages.terraform_module.credentials": "Configure credenciais para este registo em ~/.terraformrc:",
"packages.terraform_module.inputs": "Entradas",
"packages.terraform_module.outputs": "Saídas",
"packages.terraform_module.providers": "Fornecedores obrigatórios",
"packages.terraform_module.submodules": "Submódulos",
"packages.terraform_module.name": "Nome",
"packages.terraform_module.type": "Tipo",
"packages.terraform_module.default": "Padrão",
"packages.terraform_module.description": "Descrição",
"packages.terraform_module.required": "obrigatório",
"packages.vagrant.install": "Para adicionar uma máquina virtual Vagrant, execute o seguinte comando:",
"packages.settings.link": "Vincular este pacote a um repositório",
"packages.settings.link.description": "Se você vincular um pacote a um repositório, o pacote será apresentado na lista de pacotes do repositório.",

View File

@@ -365,8 +365,6 @@
"form.repo_name_been_taken": "Название репозитория уже используется.",
"form.repository_force_private": "Включена принудительная приватность: приватные репозитории не могут быть сделаны публичными.",
"form.repository_files_already_exist": "Файлы уже существуют для этого репозитория. Обратитесь к системному администратору.",
"form.repository_files_already_exist.delete": "Файлы уже существуют для этого репозитория. Вы должны удалить их.",
"form.repository_files_already_exist.adopt_or_delete": "Файлы уже существуют для этого репозитория. Или принять их или удалить их.",
"form.org_name_been_taken": "Название организации уже занято.",
"form.team_name_been_taken": "Название команды уже занято.",
"form.team_no_units_error": "Разрешите доступ хотя бы к одному разделу репозитория.",
@@ -730,14 +728,6 @@
"repo.reactions_more": "и ещё %d",
"repo.unit_disabled": "Администратор сайта отключил этот раздел репозитория.",
"repo.language_other": "Разное",
"repo.adopt_preexisting_label": "Принятые файлы",
"repo.adopt_preexisting": "Принять уже существующие файлы",
"repo.adopt_preexisting_content": "Создать репозиторий из %s",
"repo.adopt_preexisting_success": "Приняты файлы и создан репозиторий из %s",
"repo.delete_preexisting_label": "Удалить",
"repo.delete_preexisting": "Удалить уже существующие файлы",
"repo.delete_preexisting_content": "Удалить файлы из %s",
"repo.delete_preexisting_success": "Удалены непринятые файлы в %s",
"repo.blame_prior": "Показать авторство предшествующих изменений",
"repo.transfer.accept": "Принять трансфер",
"repo.transfer.reject": "Отказаться от перемещения",
@@ -2273,8 +2263,6 @@
"admin.orgs.members": "Участники",
"admin.orgs.new_orga": "Новая организация",
"admin.repos.repo_manage_panel": "Управление репозиториями",
"admin.repos.unadopted": "Непринятые репозитории",
"admin.repos.unadopted.no_more": "Больше непринятых репозиториев не найдено",
"admin.repos.owner": "Владелец",
"admin.repos.name": "Название",
"admin.repos.private": "Личный",

View File

@@ -272,8 +272,6 @@
"form.username_change_not_local_user": "දේශීය නොවන පරිශීලකයින්ට ඔවුන්ගේ පරිශීලක නාමය වෙනස් කිරීමට අවසර නැත.",
"form.repo_name_been_taken": "කෝෂ්ඨයේ නම භාවිතා කර ඇත.",
"form.repository_files_already_exist": "මෙම ගබඩාව සඳහා ලිපිගොනු දැනටමත් පවතී. පද්ධති පරිපාලක අමතන්න.",
"form.repository_files_already_exist.delete": "මෙම ගබඩාව සඳහා ලිපිගොනු දැනටමත් පවතී. ඔබ ඒවා මකා දැමිය යුතුය.",
"form.repository_files_already_exist.adopt_or_delete": "මෙම ගබඩාව සඳහා ලිපිගොනු දැනටමත් පවතී. එක්කෝ ඒවා අනුගමනය කරන්න හෝ ඒවා මකා දමන්න.",
"form.org_name_been_taken": "සංවිධානයේ නම දැනටමත් ගෙන ඇත.",
"form.team_name_been_taken": "කණ්ඩායමේ නම දැනටමත් ගෙන ඇත.",
"form.team_no_units_error": "අවම වශයෙන් එක් ගබඩාවක් වෙත ප්රවේශ වීමට ඉඩ දෙන්න.",
@@ -556,14 +554,6 @@
"repo.reactions_more": "සහ තවත් %d",
"repo.unit_disabled": "අඩවි පරිපාලක විසින් මෙම ගබඩාව අක්රීය කර ඇත.",
"repo.language_other": "වෙනත්",
"repo.adopt_preexisting_label": "ගොනු සම්පාදනය",
"repo.adopt_preexisting": "පෙර පවතින ලිපිගොනු අනුගමනය කරන්න",
"repo.adopt_preexisting_content": "%s වෙතින් කෝෂ්ඨය සාදන්න",
"repo.adopt_preexisting_success": "%sසිට අනුගමනය කරන ලද ගොනු සහ නිර්මාණය කරන ලද ගබඩාව",
"repo.delete_preexisting_label": "මකන්න",
"repo.delete_preexisting": "පෙර පවතින ගොනු මකන්න",
"repo.delete_preexisting_content": "%sහි ගොනු මකන්න",
"repo.delete_preexisting_success": "%sදී සම්මත නොකළ ගොනු මකාදැමුවා",
"repo.blame_prior": "මෙම වෙනසට පෙර දොස් බලන්න",
"repo.transfer.accept": "මාරු කිරීම පිළිගන්න",
"repo.desc.private": "පෞද්ගලික",
@@ -1755,8 +1745,6 @@
"admin.orgs.members": "සාමාජිකයින්",
"admin.orgs.new_orga": "නව සංවිධානය",
"admin.repos.repo_manage_panel": "කෝෂ්ඨ කළමනාකරණය",
"admin.repos.unadopted": "සම්මත නොකළ ගබඩාවලදී",
"admin.repos.unadopted.no_more": "තවත් සම්මත නොකළ ගබඩාවක් සොයාගත නොහැකි විය",
"admin.repos.owner": "හිමිකරු",
"admin.repos.name": "නම",
"admin.repos.private": "පෞද්ගලික",

View File

@@ -348,8 +348,6 @@
"form.repo_name_been_taken": "Meno repozitára sa už používa.",
"form.repository_force_private": "Je aktivované \"Iba súkromne\": súkromné repozitáre nesmú byť zverejnené.",
"form.repository_files_already_exist": "Súbory pre tento repozitár už existujú. Kontaktujte správcu systému.",
"form.repository_files_already_exist.delete": "Súbory pre tento repozitár už existujú. Musíte ich zmazať.",
"form.repository_files_already_exist.adopt_or_delete": "Súbory pre tento repozitár už existujú. Buď ich prijmite, alebo zmažte.",
"form.org_name_been_taken": "Názov organizácie sa už používa.",
"form.team_name_been_taken": "Názov tímu sa už používa.",
"form.team_no_units_error": "Povoliť prístup aspoň do jednej sekcie repozitára.",
@@ -642,14 +640,6 @@
"repo.reactions_more": "a %d ďalších",
"repo.unit_disabled": "Správca stránky zakázal túto sekciu repozitára.",
"repo.language_other": "Iný",
"repo.adopt_preexisting_label": "Prijať súbory",
"repo.adopt_preexisting": "Prijať už existujúce súbory",
"repo.adopt_preexisting_content": "Vytvoriť repozitár z %s",
"repo.adopt_preexisting_success": "Prijaté súbory a vytvorený repozitár z %s",
"repo.delete_preexisting_label": "Vymazať",
"repo.delete_preexisting": "Vymazať už existujúce súbory",
"repo.delete_preexisting_content": "Vymazať súbory v %s",
"repo.delete_preexisting_success": "Vymazané neprijaté súbory v %s",
"repo.transfer.accept": "Prijať prevod",
"repo.transfer.reject": "Odmietnuť prevod",
"repo.desc.private": "Súkromný",

View File

@@ -229,8 +229,6 @@
"form.username_been_taken": "Användarnamnet är redan taget.",
"form.repo_name_been_taken": "Namnet för utvecklingskatalogen är upptaget.",
"form.repository_files_already_exist": "Filer finns redan för denna utvecklingskatalog. Kontakta systemadministratören.",
"form.repository_files_already_exist.delete": "Filer finns redan för denna utvecklingskatalog. Du måste ta bort dem.",
"form.repository_files_already_exist.adopt_or_delete": "Filer finns redan för denna utvecklingskatalog. Antingen anta dem eller ta bort dem.",
"form.org_name_been_taken": "Organisationsnamnet är redan taget.",
"form.team_name_been_taken": "Teamnamnet är redan taget.",
"form.team_no_units_error": "Tillåt åtkomst för åtminstone en del av utvecklingskatalogen.",
@@ -462,10 +460,6 @@
"repo.reactions_more": "och %d flera",
"repo.unit_disabled": "Webbplatsens administratör har inaktiverat denna utvecklingskatalog.",
"repo.language_other": "Övrigt",
"repo.adopt_preexisting_content": "Skapa utvecklingskatalog från %s",
"repo.delete_preexisting_label": "Radera",
"repo.delete_preexisting": "Ta bort befintliga filer",
"repo.delete_preexisting_content": "Ta bort filer i %s",
"repo.desc.private": "Privat",
"repo.desc.public": "Publik",
"repo.desc.template": "Mall",

View File

@@ -500,9 +500,6 @@
"form.repo_name_been_taken": "Depo adı zaten kullanılıyor.",
"form.repository_force_private": "Gizliyi Zorla devrede: gizli depolar herkese açık yapılamaz.",
"form.repository_files_already_exist": "Bu depo için dosyalar zaten var. Sistem yöneticisine başvurun.",
"form.repository_files_already_exist.adopt": "Bu depo için dosyalar zaten var ve yalnızca Kabul Edilebilir.",
"form.repository_files_already_exist.delete": "Bu depo için dosyalar zaten var. Onları silmelisiniz.",
"form.repository_files_already_exist.adopt_or_delete": "Bu depo için dosyalar zaten var. Ya kabul edin ya da silin.",
"form.org_name_been_taken": "Organizasyon adı zaten kullanılıyor.",
"form.team_name_been_taken": "Takım adı zaten alınmış.",
"form.team_no_units_error": "En az bir depo bölümüne erişimine izin ver.",
@@ -955,15 +952,6 @@
"repo.reactions_more": "ve %d daha fazla",
"repo.unit_disabled": "Site yöneticisi bu depo bölümünü devre dışı bıraktı.",
"repo.language_other": "Diğer",
"repo.adopt_search": "Kabul edilmeyen depoları aramak için kullanıcı adını girin... (tümünü bulmak için boş bırakın)",
"repo.adopt_preexisting_label": "Dosyaları Kabul Et",
"repo.adopt_preexisting": "Önceden var olan dosyaları kabul et",
"repo.adopt_preexisting_content": "%s konumundan depo oluştur",
"repo.adopt_preexisting_success": "%s konumundan dosyalar kabul edildi ve depo oluşturuldu",
"repo.delete_preexisting_label": "Sil",
"repo.delete_preexisting": "Önceden var olan dosyaları sil",
"repo.delete_preexisting_content": "%s içindeki dosyaları sil",
"repo.delete_preexisting_success": "%s içindeki kabul edilmeyen dosyalar silindi",
"repo.blame_prior": "Bu değişiklikten önceki suçu görüntüle",
"repo.blame.ignore_revs": "<a href=\"%s\">.git-blame-ignore-revs</a> dosyasındaki sürümler yok sayılıyor. Bunun yerine normal sorumlu görüntüsü için <a href=\"%s\">buraya tıklayın</a>.",
"repo.blame.ignore_revs.failed": "<a href=\"%s\">.git-blame-ignore-revs</a> dosyasındaki sürümler yok sayılamadı.",
@@ -2905,8 +2893,6 @@
"admin.orgs.members": "Üyeler",
"admin.orgs.new_orga": "Yeni Organizasyon",
"admin.repos.repo_manage_panel": "Depo Yönetimi",
"admin.repos.unadopted": "Kabul Edilmemiş Depolar",
"admin.repos.unadopted.no_more": "Kabul edilmemiş başka depo bulunamadı",
"admin.repos.owner": "Sahibi",
"admin.repos.name": "İsim",
"admin.repos.private": "Özel",

View File

@@ -420,8 +420,6 @@
"form.repo_name_been_taken": "Назва сховища вже використовується.",
"form.repository_force_private": "Примусову приватність ввімкнено: приватні сховища не можна зробити загальнодоступними.",
"form.repository_files_already_exist": "Для цього сховища вже існують файли. Зверніться до системного адміністратора.",
"form.repository_files_already_exist.delete": "Для цього сховища вже існують файли. Ви повинні видалити їх.",
"form.repository_files_already_exist.adopt_or_delete": "Для цього сховища вже існують файли. Прийміть їх або видаліть.",
"form.org_name_been_taken": "Назва організації вже зайнята.",
"form.team_name_been_taken": "Назва команди вже зайнята.",
"form.team_no_units_error": "Дозволити доступ до принаймні одного розділу сховища.",
@@ -829,14 +827,6 @@
"repo.reactions_more": "і ще %d",
"repo.unit_disabled": "Адміністратор сайту вимкнув цей розділ сховища.",
"repo.language_other": "Інші",
"repo.adopt_preexisting_label": "Прийняти файли",
"repo.adopt_preexisting": "Прийняти попередньо створені файли",
"repo.adopt_preexisting_content": "Створити сховище з %s",
"repo.adopt_preexisting_success": "Прийняти файли та створити сховище з %s",
"repo.delete_preexisting_label": "Видалити",
"repo.delete_preexisting": "Видалити попередньо створені файли",
"repo.delete_preexisting_content": "Видалити файли з %s",
"repo.delete_preexisting_success": "Видалено неприйняті файли в %s",
"repo.blame_prior": "Переглянути анотацію, що передує цій зміні",
"repo.blame.ignore_revs.failed": "Не вдалося проігнорувати ревізії у <a href=\"%s\">.git-blame-ignore-revs</a>.",
"repo.user_search_tooltip": "Показує не більше 30 користувачів",
@@ -2454,8 +2444,6 @@
"admin.orgs.members": "Учасники",
"admin.orgs.new_orga": "Нова організація",
"admin.repos.repo_manage_panel": "Керування репозиторіями",
"admin.repos.unadopted": "Неприйняті репозиторії",
"admin.repos.unadopted.no_more": "Не знайдено більше неприйнятих репозиторіїв",
"admin.repos.owner": "Власник",
"admin.repos.name": "Назва",
"admin.repos.private": "Приватний",

View File

@@ -546,9 +546,6 @@
"form.repo_name_been_taken": "仓库名称已使用。",
"form.repository_force_private": "「强制私有」已启用:私有仓库不能被公开。",
"form.repository_files_already_exist": "此仓库已存在文件。请联系系统管理员。",
"form.repository_files_already_exist.adopt": "此仓库已存在文件,只能被收录。",
"form.repository_files_already_exist.delete": "此仓库已存在文件,必须先删除他们。",
"form.repository_files_already_exist.adopt_or_delete": "此仓库已存在文件,要么删除他们,要么收录他们。",
"form.org_name_been_taken": "组织名称已使用。",
"form.team_name_been_taken": "团队名称已使用。",
"form.team_no_units_error": "至少选择一项仓库单元。",
@@ -1011,15 +1008,6 @@
"repo.reactions": "回应",
"repo.unit_disabled": "站点管理员已禁用此仓库单元。",
"repo.language_other": "其它",
"repo.adopt_search": "输入用户名以搜索未被收录的仓库…(留空以查找全部)",
"repo.adopt_preexisting_label": "收录仓库",
"repo.adopt_preexisting": "收录已存在的仓库",
"repo.adopt_preexisting_content": "从 %s 创建仓库",
"repo.adopt_preexisting_success": "从 %s 收录仓库成功",
"repo.delete_preexisting_label": "删除",
"repo.delete_preexisting": "删除已存在的文件",
"repo.delete_preexisting_content": "删除 %s 中的文件",
"repo.delete_preexisting_success": "删除 %s 中未收录的文件",
"repo.blame_prior": "查看此更改前的 blame",
"repo.blame.ignore_revs": "忽略 <a href=\"%s\">.git-blame-ignore-revs</a> 的修订。点击 <a href=\"%s\">绕过</a> 并查看正常的 Blame 视图。",
"repo.blame.ignore_revs.failed": "忽略 <a href=\"%s\">.git-blame-ignore-revs</a> 版本失败。",
@@ -3133,8 +3121,6 @@
"admin.orgs.members": "成员",
"admin.orgs.new_orga": "创建新的组织",
"admin.repos.repo_manage_panel": "仓库管理",
"admin.repos.unadopted": "未收录仓库",
"admin.repos.unadopted.no_more": "找不到更多未被收录的仓库",
"admin.repos.owner": "所有者",
"admin.repos.name": "名称",
"admin.repos.private": "私有库",

View File

@@ -409,8 +409,6 @@
"form.repo_name_been_taken": "儲存庫名稱已被使用。",
"form.repository_force_private": "已啟用「強制私有」:私有儲存庫不能被公開。",
"form.repository_files_already_exist": "此儲存庫的檔案已存在,請聯絡系統管理有。",
"form.repository_files_already_exist.delete": "此儲存庫的檔案已存在,您必須刪除它們。",
"form.repository_files_already_exist.adopt_or_delete": "此儲存庫的檔案已存在,您可以接管或刪除它們。",
"form.org_name_been_taken": "組織名稱已被使用。",
"form.team_name_been_taken": "團隊名稱已被使用。",
"form.team_no_units_error": "請至少選擇一個儲存庫區域。",
@@ -820,14 +818,6 @@
"repo.reactions_more": "再多添加 %d個",
"repo.unit_disabled": "網站管理員已經停用這個儲存庫區域。",
"repo.language_other": "其他",
"repo.adopt_preexisting_label": "接管檔案",
"repo.adopt_preexisting": "接管既有的檔案",
"repo.adopt_preexisting_content": "從 %s 建立儲存庫",
"repo.adopt_preexisting_success": "從 %s 接管檔案並建立儲存庫",
"repo.delete_preexisting_label": "刪除",
"repo.delete_preexisting": "刪除既有的檔案",
"repo.delete_preexisting_content": "刪除 %s 中的檔案",
"repo.delete_preexisting_success": "刪除 %s 中未接管的檔案",
"repo.blame_prior": "檢視此變更前的 Blame",
"repo.blame.ignore_revs": "忽略 <a href=\"%s\">.git-blame-ignore-revs</a> 中的修訂。點擊 <a href=\"%s\">這裡</a> 以繞過並查看正常的 Blame 視圖。",
"repo.blame.ignore_revs.failed": "忽略 <a href=\"%s\">.git-blame-ignore-revs</a> 中的修訂失敗。",
@@ -2528,8 +2518,6 @@
"admin.orgs.members": "成員數",
"admin.orgs.new_orga": "新增組織",
"admin.repos.repo_manage_panel": "儲存庫管理",
"admin.repos.unadopted": "未接管的儲存庫",
"admin.repos.unadopted.no_more": "找不到其他未接管的儲存庫",
"admin.repos.owner": "擁有者",
"admin.repos.name": "名稱",
"admin.repos.private": "私有",

View File

@@ -1,9 +1,9 @@
{
"type": "module",
"packageManager": "pnpm@12.16.1",
"packageManager": "pnpm@12.17.0",
"engines": {
"node": ">= 22.18.0",
"pnpm": ">= 12.16.1"
"pnpm": ">= 12.17.0"
},
"dependencies": {
"@codemirror/autocomplete": "6.20.4",
@@ -33,7 +33,7 @@
"asciinema-player": "3.17.0",
"chart.js": "4.6.1",
"chartjs-plugin-zoom": "2.2.0",
"clippie": "4.3.0",
"clippie": "4.3.1",
"codemirror-lang-elixir": "4.0.1",
"colord": "2.10.0",
"compare-versions": "6.1.1",
@@ -46,13 +46,13 @@
"jquery": "4.0.0",
"js-yaml": "5.5.0",
"katex": "0.19.1",
"mermaid": "12.2.0",
"mermaid": "12.3.0",
"online-3d-viewer": "0.18.0",
"pdfobject": "2.3.1",
"postcss": "8.5.32",
"rolldown-license-plugin": "3.0.14",
"sortablejs": "1.15.7",
"swagger-ui-dist": "5.34.0",
"swagger-ui-dist": "5.34.1",
"tailwindcss": "3.4.19",
"tippy.js": "6.3.7",
"toastify-js": "1.12.0",
@@ -67,45 +67,44 @@
"@eslint/json": "2.1.1",
"@playwright/test": "1.64.1",
"@stylistic/eslint-plugin": "5.10.0",
"@stylistic/stylelint-plugin": "5.3.1",
"@stylistic/stylelint-plugin": "6.0.0",
"@types/codemirror": "5.60.18",
"@types/jquery": "4.0.1",
"@types/katex": "0.16.8",
"@types/node": "26.6.5",
"@types/node": "26.6.6",
"@types/pdfobject": "2.2.5",
"@types/sortablejs": "1.15.9",
"@types/swagger-ui-dist": "3.30.6",
"@types/toastify-js": "1.12.4",
"@typescript-eslint/parser": "8.72.1",
"@vitejs/plugin-vue": "6.0.10",
"@vitest/browser-playwright": "5.0.5",
"@vitest/browser-playwright": "5.1.0",
"@vitest/eslint-plugin": "1.6.28",
"eslint": "10.13.0",
"eslint": "10.14.0",
"eslint-import-resolver-typescript": "4.4.5",
"eslint-plugin-import-x": "4.17.1",
"eslint-plugin-playwright": "2.12.1",
"eslint-plugin-regexp": "3.3.1",
"eslint-plugin-playwright": "2.12.2",
"eslint-plugin-regexp": "3.3.3",
"eslint-plugin-unicorn": "79.0.0",
"eslint-plugin-vue": "10.12.0",
"eslint-plugin-vue-scoped-css": "3.1.3",
"eslint-plugin-wc": "3.1.0",
"globals": "17.13.0",
"globals": "17.14.0",
"jiti": "2.7.0",
"linguist-languages": "9.5.0",
"markdownlint-cli": "0.50.0",
"material-icon-theme": "5.40.0",
"postcss-html": "2.0.0",
"spectral-cli-bundle": "1.0.16",
"stylelint": "17.16.0",
"stylelint-config-recommended": "18.0.0",
"stylelint": "18.0.0",
"stylelint-config-recommended": "19.0.0",
"stylelint-declaration-block-no-ignored-properties": "3.0.0",
"stylelint-declaration-strict-value": "1.12.1",
"stylelint-value-no-unknown-custom-properties": "6.1.1",
"svgo": "4.1.0",
"typescript": "6.0.3",
"typescript-eslint": "8.72.1",
"vitest": "5.0.5",
"vitest": "5.1.0",
"vue-eslint-parser": "10.4.1",
"vue-tsc": "3.3.13"
"vue-tsc": "3.3.14"
}
}

1238
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,9 +5,9 @@ requires-python = ">=3.12"
[dependency-groups]
dev = [
"djlint==1.47.1",
"djlint==1.49.9",
"yamllint==1.38.0",
"zizmor==1.31.1",
"zizmor==1.32.0",
]
[tool.djlint]

View File

@@ -13,6 +13,7 @@ import (
"net/http"
"net/url"
"path"
"strings"
"time"
activities_model "gitea.dev/models/activities"
@@ -28,7 +29,6 @@ import (
"gitea.dev/modules/charset"
"gitea.dev/modules/fileicon"
"gitea.dev/modules/git"
"gitea.dev/modules/htmlutil"
"gitea.dev/modules/lfs"
"gitea.dev/modules/log"
"gitea.dev/modules/markup"
@@ -152,27 +152,16 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
return true
}
func markupRenderToHTML(ctx *context.Context, renderCtx *markup.RenderContext, renderer markup.Renderer, input io.Reader) (escaped *charset.EscapeStatus, output template.HTML, err error) {
markupRd, markupWr := io.Pipe()
defer markupWr.Close()
done := make(chan struct{})
go func() {
sb := &htmlutil.HTMLBuilder{}
if markup.RendererNeedPostProcess(renderer) {
escaped, _ = charset.EscapeControlReader(markupRd, sb, ctx.Locale, charset.EscapeOptionsForView())
} else {
escaped = &charset.EscapeStatus{}
_, _ = io.Copy(sb.OriginWriter(), markupRd)
}
output = sb.HTMLString()
close(done)
}()
err = markup.RenderWithRenderer(renderCtx, renderer, input, markupWr)
_ = markupWr.CloseWithError(err)
<-done
return escaped, output, err
func markupRenderToHTML(ctx *context.Context, renderCtx *markup.RenderContext, renderer markup.Renderer, input io.Reader) (*charset.EscapeStatus, template.HTML, error) {
sb := &strings.Builder{}
if err := markup.RenderWithRenderer(renderCtx, renderer, input, sb); err != nil {
return nil, "", err
}
if !markup.RendererNeedPostProcess(renderer) {
return &charset.EscapeStatus{}, template.HTML(sb.String()), nil
}
escaped, output := charset.EscapeControlHTML(template.HTML(sb.String()), ctx.Locale, charset.EscapeOptionsForView())
return escaped, output, nil
}
func checkHomeCodeViewable(ctx *context.Context) {

View File

@@ -8,7 +8,6 @@ import (
"bytes"
gocontext "context"
"html/template"
"io"
"net/http"
"net/url"
"path"
@@ -20,7 +19,6 @@ import (
"gitea.dev/modules/base"
"gitea.dev/modules/charset"
"gitea.dev/modules/git"
"gitea.dev/modules/htmlutil"
"gitea.dev/modules/log"
"gitea.dev/modules/markup"
"gitea.dev/modules/markup/markdown"
@@ -252,22 +250,8 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
rctx := renderhelper.NewRenderContextRepoWiki(ctx, ctx.Repo.Repository)
renderFn := func(data []byte) (escaped *charset.EscapeStatus, output template.HTML, err error) {
buf := &htmlutil.HTMLBuilder{}
markupRd, markupWr := io.Pipe()
defer markupWr.Close()
done := make(chan struct{})
go func() {
escaped, _ = charset.EscapeControlReader(markupRd, buf, ctx.Locale, charset.EscapeOptionsForView())
output = buf.HTMLString()
buf.Reset()
close(done)
}()
err = markdown.Render(rctx, bytes.NewReader(data), markupWr)
_ = markupWr.CloseWithError(err)
<-done
return escaped, output, err
renderFn := func(data []byte) (*charset.EscapeStatus, template.HTML, error) {
return markupRenderToHTML(ctx, rctx, markdown.Renderer{}, bytes.NewReader(data))
}
ctx.Data["EscapeStatus"], ctx.Data["WikiContentHTML"], err = renderFn(data)

View File

@@ -339,12 +339,11 @@ type DiffInlineComputed struct {
// computeDiffInline makes a DiffInline with computed content, e.g.: Unicode escaping, truncation hint, etc
func computeDiffInline(s template.HTML, isTruncated bool, locale translation.Locale) DiffInlineComputed {
sb, w := htmlutil.NewHTMLStringWriter()
status, _ := charset.EscapeControlReader(strings.NewReader(string(s)), w, locale)
status, content := charset.EscapeControlHTML(s, locale)
if isTruncated {
w.WriteFormatf(`<span class="ui label diff-line-truncated">%s</span>`, locale.Tr("repo.diff.line_truncated"))
content += htmlutil.HTMLFormat(`<span class="ui label diff-line-truncated">%s</span>`, locale.Tr("repo.diff.line_truncated"))
}
return DiffInlineComputed{EscapeStatus: status, IsTruncated: isTruncated, Content: template.HTML(sb.String())}
return DiffInlineComputed{EscapeStatus: status, IsTruncated: isTruncated, Content: content}
}
func (diffSection *DiffSection) getLineContentForRender(lineIdx int, diffLine *DiffLine, fileLanguage string, highlightLines map[int]template.HTML) template.HTML {

View File

@@ -1,14 +1,14 @@
import {fileURLToPath} from 'node:url';
import type {Config} from 'stylelint';
const cssVarFiles = [
fileURLToPath(new URL('web_src/css/base.css', import.meta.url)),
fileURLToPath(new URL('web_src/css/themes/theme-gitea-light.css', import.meta.url)),
fileURLToPath(new URL('web_src/css/themes/theme-gitea-dark.css', import.meta.url)),
];
export default {
extends: 'stylelint-config-recommended',
referenceFiles: [
'web_src/css/base.css',
'web_src/css/modules/animations.css',
'web_src/css/themes/theme-gitea-light.css',
'web_src/css/themes/theme-gitea-dark.css',
].map((file) => fileURLToPath(new URL(file, import.meta.url))),
reportUnscopedDisables: true,
reportNeedlessDisables: true,
reportInvalidScopeDisables: true,
@@ -16,7 +16,6 @@ export default {
plugins: [
'stylelint-declaration-strict-value',
'stylelint-declaration-block-no-ignored-properties',
'stylelint-value-no-unknown-custom-properties',
'@stylistic/stylelint-plugin',
],
ignoreFiles: [
@@ -30,6 +29,7 @@ export default {
},
],
rules: {
'@stylistic/aspect-ratio-notation': null,
'@stylistic/at-rule-name-case': null,
'@stylistic/at-rule-name-newline-after': null,
'@stylistic/at-rule-name-space-after': null,
@@ -51,6 +51,7 @@ export default {
'@stylistic/declaration-block-semicolon-newline-before': null,
'@stylistic/declaration-block-semicolon-space-after': null,
'@stylistic/declaration-block-semicolon-space-before': 'never',
'@stylistic/declaration-block-single-line-max-declarations': null,
'@stylistic/declaration-block-trailing-semicolon': null,
'@stylistic/declaration-colon-newline-after': null,
'@stylistic/declaration-colon-space-after': 'always',
@@ -73,6 +74,8 @@ export default {
'@stylistic/media-feature-parentheses-space-inside': null,
'@stylistic/media-feature-range-operator-space-after': 'always',
'@stylistic/media-feature-range-operator-space-before': 'always',
'@stylistic/media-feature-slash-space-after': 'always',
'@stylistic/media-feature-slash-space-before': 'always',
'@stylistic/media-query-list-comma-newline-after': null,
'@stylistic/media-query-list-comma-newline-before': null,
'@stylistic/media-query-list-comma-space-after': null,
@@ -108,11 +111,14 @@ export default {
'@stylistic/value-list-comma-space-after': null,
'@stylistic/value-list-comma-space-before': null,
'@stylistic/value-list-max-empty-lines': 0,
'@stylistic/value-slash-newline-after': null,
'@stylistic/value-slash-newline-before': null,
'@stylistic/value-slash-space-after': 'always',
'@stylistic/value-slash-space-before': 'always',
'at-rule-no-unknown': [true, {ignoreAtRules: ['tailwind']}],
'at-rule-no-vendor-prefix': true,
'block-no-redundant-nested-style-rules': true,
'color-no-invalid-hex': true,
'csstools/value-no-unknown-custom-properties': [true, {importFrom: cssVarFiles}],
'declaration-block-no-duplicate-properties': [true, {ignore: ['consecutive-duplicates-with-different-values']}],
'declaration-block-no-redundant-longhand-properties': [true, {ignoreShorthands: ['flex-flow', 'overflow', 'grid-template']}],
'declaration-property-unit-disallowed-list': null,
@@ -127,13 +133,14 @@ export default {
'media-feature-name-no-vendor-prefix': true,
'no-descending-specificity': null,
'no-invalid-position-at-import-rule': [true, {ignoreAtRules: ['tailwind']}],
'no-unknown-animations': null, // disabled until stylelint supports multi-file linting
'no-unknown-custom-media': null, // disabled until stylelint supports multi-file linting
'no-unknown-custom-properties': null, // disabled until stylelint supports multi-file linting
'no-unknown-animations': true,
'no-unknown-custom-media': true,
'no-unknown-custom-properties': true,
'plugin/declaration-block-no-ignored-properties': true,
'property-no-vendor-prefix': true,
'scale-unlimited/declaration-strict-value': [['/color$/', 'fill', 'stroke', 'font-weight'], {ignoreValues: '/^(inherit|transparent|unset|initial|currentcolor|none)$/', ignoreAtRules: ['@font-face', '@page'], ignoreFunctions: true, disableFix: true, expandShorthand: true}],
'selector-attribute-quotes': 'always',
'selector-no-deprecated': [true, {ignoreSelectors: ['tt']}], // markup sanitizer allows <tt>
'selector-no-vendor-prefix': true,
'selector-pseudo-element-colon-notation': 'double',
'selector-type-case': 'lower',

191
uv.lock generated
View File

@@ -39,7 +39,7 @@ wheels = [
[[package]]
name = "djlint"
version = "1.47.1"
version = "1.49.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
@@ -51,87 +51,87 @@ dependencies = [
{ name = "regex" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a0/c1/31856d5e1b065b9b8bca7107cc0bb5ce297e1060a1f3b3e7134a4192e3a6/djlint-1.47.1.tar.gz", hash = "sha256:a5808be5246295fef25540dfafad037599bd9a35798816f0e397af7caed97fac", size = 133895, upload-time = "2026-10-26T15:59:16.285Z" }
sdist = { url = "https://files.pythonhosted.org/packages/d9/7b/a464825c09d0453c292a0e36de9dbe32c39efdf941ca4186abd65b6b543c/djlint-1.49.9.tar.gz", hash = "sha256:358f4f6afa0431b7526f18764ea38f470becbbfcced825e90bcb406e48592afe", size = 167818, upload-time = "2026-11-03T22:13:23.542Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/df/a5432169b81cfb0dcea5413b694fc5b943da964871581eb0c23d291256d4/djlint-1.47.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:56ede76130f0bc70d3870c8ad1cff225f77c87da98d3aa86e9ba1c744361f053", size = 1376098, upload-time = "2026-10-26T15:57:17.633Z" },
{ url = "https://files.pythonhosted.org/packages/8a/71/9a8ea07c86d04716d544d022525e258bfde3c56efb648d4f629006b00999/djlint-1.47.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9ead63b9043d16a810a564a798c7b9cd3e447750f961e80bf07afc41c38daa4", size = 1298457, upload-time = "2026-10-26T15:57:19.132Z" },
{ url = "https://files.pythonhosted.org/packages/55/28/ae72366245c1f8c6c96376852454e27884d76c3e31dbf8d876d55de61665/djlint-1.47.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b309430b0a780e8c0a81077195ca5c8551e55d348f9c982400247cbada67e0a2", size = 1435700, upload-time = "2026-10-26T15:57:20.472Z" },
{ url = "https://files.pythonhosted.org/packages/25/17/6cd5cd431e2f6076f94023a50e5cffc1795fbc0b9dfc4e81998509c2f27e/djlint-1.47.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50ec15222043dda4966ef92082b47cd52f2aa68eb44dd1fd7727cfdaa8d95362", size = 1343628, upload-time = "2026-10-26T15:57:21.857Z" },
{ url = "https://files.pythonhosted.org/packages/ff/72/6dbc8e59c7f8a92f55effe4b29bbde53b9ebb00ec87777360f6c03564fd4/djlint-1.47.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e37ce257468c31954c38414e607059e6e0f7bf1aa96ee1bea6baf1ecae717d2", size = 1379373, upload-time = "2026-10-26T15:57:23.419Z" },
{ url = "https://files.pythonhosted.org/packages/78/d4/b31bd410630ec4d2d66bafd15584544b66ba9fe07ccd9ec685b847f3453b/djlint-1.47.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfb518c57e28c8a4aa2e6e704c20d1939bc6068e723572867c5c971d991adca1", size = 1402116, upload-time = "2026-10-26T15:57:24.776Z" },
{ url = "https://files.pythonhosted.org/packages/d0/0b/ab84f8f035e10c8e5e29bb81a12a6ab58df9ff7ed15fe7d614e617b69bf6/djlint-1.47.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec0f7fea1b83e69953851cac99c41974b1a31f2f3c99fd09eaab0dfe1f69b752", size = 1363902, upload-time = "2026-10-26T15:57:26.16Z" },
{ url = "https://files.pythonhosted.org/packages/da/5f/cbf071e73f24d5b6f577b78d2d75c346105c9637f76a3f2bef5a6842ebb2/djlint-1.47.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:df63eb7fb0246ef878e23dc0f5fb627766c4ece7f608af19ee0122e6fe9e39c2", size = 1403265, upload-time = "2026-10-26T15:57:27.545Z" },
{ url = "https://files.pythonhosted.org/packages/4b/cd/eedb6b51a7b589ee152876ae25d56afbc9a44166e93150de8f281a4cc81e/djlint-1.47.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:716400ce6d11c3ef79cf6a4a694b03751c2236341eea651df712140e6a672396", size = 1465785, upload-time = "2026-10-26T15:57:29.053Z" },
{ url = "https://files.pythonhosted.org/packages/b2/c9/bcec368b6678d7931e5ae0aac10d8b3c12d22257e3ae6f2d31d6687ef2a3/djlint-1.47.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cdc0c2624982fe31a693649e6b3590c67d3192a9c421a4bb5023aa57984214ab", size = 1425978, upload-time = "2026-10-26T15:57:30.471Z" },
{ url = "https://files.pythonhosted.org/packages/bc/7a/fdad03a52c8be45d4c79f0572a5e74dfeb2e22ca0ab14f5740ea419ebcb6/djlint-1.47.1-cp312-cp312-win32.whl", hash = "sha256:6184184ce3e30076acb11e6217cb874df1c25d7ad4ba7283845704fef1aecffa", size = 1035523, upload-time = "2026-10-26T15:57:32.229Z" },
{ url = "https://files.pythonhosted.org/packages/97/70/95cbfab120bc74d7f21c56803c701d12300c182d7e39d8df7eff5461cc14/djlint-1.47.1-cp312-cp312-win_amd64.whl", hash = "sha256:04f0a6adf3af836fd5b41ca08f8e807808b363e5011782e95d69b473a76f8868", size = 1169623, upload-time = "2026-10-26T15:57:33.612Z" },
{ url = "https://files.pythonhosted.org/packages/17/78/c1a046f7e7f4580b1950e4934b16632b57f58f622d88588326363909deae/djlint-1.47.1-cp312-cp312-win_arm64.whl", hash = "sha256:e03b464afe9cba226192c0408f9d37f7269cd56bc95ea113b4fe107d1237f1a8", size = 1100302, upload-time = "2026-10-26T15:57:35.027Z" },
{ url = "https://files.pythonhosted.org/packages/c6/d9/eaaac7cd66ecad9d3ee01c59518ca907ca45ab8e9cbc7d153ec8c8705191/djlint-1.47.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5b3a79703b0758dbe747d82537b96347f707876f20ef75cc3e9c62aa32c699e5", size = 1360330, upload-time = "2026-10-26T15:57:37.393Z" },
{ url = "https://files.pythonhosted.org/packages/e0/db/99365eeff09481949aa42ec49cd6a0927dc73818e0b4013f037c5953984d/djlint-1.47.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0aa581ac7520cba9dce314f1376ff9dfc94df14e4fa1e948f5e193170641ac69", size = 1278921, upload-time = "2026-10-26T15:57:38.813Z" },
{ url = "https://files.pythonhosted.org/packages/a5/bb/42491ee6745aa79fe87de9b9685f35795a9ef0341608c2c053298297f4fc/djlint-1.47.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bfb64629dcdb4c6dc08b82458a42bf7d4904dc2a78eb843ceae5f2d7a4789e85", size = 1432584, upload-time = "2026-10-26T15:57:40.458Z" },
{ url = "https://files.pythonhosted.org/packages/1f/7a/8ecb7506a1f505728461fd6484db554cdf67eff9d76ddfe5f8c94a1498f1/djlint-1.47.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63226a0e9063c7ed5bbacb39877019696e9cad74c034fc010f62bc184ab3c3cd", size = 1339780, upload-time = "2026-10-26T15:57:41.939Z" },
{ url = "https://files.pythonhosted.org/packages/91/95/0d9972b920730cdf7da4d6ee019c6f3e161d455ee8294b68db06cde58fc9/djlint-1.47.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9583c1d18d51e9ebebda15b3c0c2446fa8e9adef460d8b5928ebdd555c3a93b8", size = 1380037, upload-time = "2026-10-26T15:57:43.279Z" },
{ url = "https://files.pythonhosted.org/packages/9c/fb/512d5060b74ad66b694b7abdd2c186588bd040ad9f1833b488353a0dffa9/djlint-1.47.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd0f581f0b3818aa1f3a1f57daa3ba7efe242fd9e2c8c3b5e52f71e46bb1bd6e", size = 1399498, upload-time = "2026-10-26T15:57:44.692Z" },
{ url = "https://files.pythonhosted.org/packages/48/cf/61496651e2c65bcc0ec847bd0de00e395aa1de3ef47557cb30c3b508dd13/djlint-1.47.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:da28574492e524bbc6f11590f71ec584d7936023c6490dd15a4a819c43735af7", size = 1359457, upload-time = "2026-10-26T15:57:46.251Z" },
{ url = "https://files.pythonhosted.org/packages/82/9d/18c7697361c3304ffdaa07c382a368c0e99fbf2556c07ae5c0e86862e011/djlint-1.47.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6f66d413ebb472cb56874acbfe846680df694f33f96753881e93c19003567c62", size = 1399653, upload-time = "2026-10-26T15:57:47.676Z" },
{ url = "https://files.pythonhosted.org/packages/48/ee/60a8973cf94994afb6631345b41711c8892a93b36181c77e203c5a39ba35/djlint-1.47.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de9e918c1982b47a2d97e4161b29d5791c9867547530d2b65abff38f82b302a2", size = 1462502, upload-time = "2026-10-26T15:57:49.054Z" },
{ url = "https://files.pythonhosted.org/packages/e7/82/f6604e064290d6fd7fc995a6bf1fd57206e95da8260b65f9710fec932a98/djlint-1.47.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:95923ee819ec440339e80ea27973e4bbbd2a295f1b8056aef7c882e088331549", size = 1424688, upload-time = "2026-10-26T15:57:50.341Z" },
{ url = "https://files.pythonhosted.org/packages/ec/fc/8d6731f751f4f7ddbbfef2f9960016920a2a3bcf6d7cf5e7d972cf971aaf/djlint-1.47.1-cp313-cp313-win32.whl", hash = "sha256:d1b23695036db32d49290eabda7c05248868ae1c7305f946ce88d2932e7c27b3", size = 1037484, upload-time = "2026-10-26T15:57:51.678Z" },
{ url = "https://files.pythonhosted.org/packages/aa/5b/b4120b9577cb4a20404217c4a1bf832240c3b4184fe7893bba542fbe1539/djlint-1.47.1-cp313-cp313-win_amd64.whl", hash = "sha256:bfd7376c48d74571d0b8d65713c906e9b4050f5b5159331e99fb613a08ac04f1", size = 1173020, upload-time = "2026-10-26T15:57:52.967Z" },
{ url = "https://files.pythonhosted.org/packages/ea/d0/3e36d8f3f506175bfbd0889a071e822ce5a86a42bd104450f096baf59715/djlint-1.47.1-cp313-cp313-win_arm64.whl", hash = "sha256:f73282bd2b177fc9180c4c96def44e3f25e4e003e1e9bbf6cf174458fc191113", size = 1098519, upload-time = "2026-10-26T15:57:55.495Z" },
{ url = "https://files.pythonhosted.org/packages/a8/5a/dc2fcf49e21d86a69b3757951a3c6fc3b623d0769e1a4c1faa7991c0e261/djlint-1.47.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:991a48add8cd0ff47c16ad837e7f87c476b1c30325a38d93bdb09bd830fbbc15", size = 1353599, upload-time = "2026-10-26T15:57:56.838Z" },
{ url = "https://files.pythonhosted.org/packages/3a/44/e7558c55f56a8954259c8fa4cb8e3b9d4ac3c6e53b9434f4336b98f5edf8/djlint-1.47.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1e7ed8a593bbf0b19bd2d62c6a18b6cc28d085f54a5c082396470a314ee951da", size = 1278982, upload-time = "2026-10-26T15:57:58.331Z" },
{ url = "https://files.pythonhosted.org/packages/6f/73/4efede4b76fadd5097ca00595cb9d78b3d02099a3095a37c67d5ab852be4/djlint-1.47.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:523f4601ab2da683a0522f633e7dba6b17882856ccca830aabf92a10026904c0", size = 1429077, upload-time = "2026-10-26T15:57:59.764Z" },
{ url = "https://files.pythonhosted.org/packages/63/79/261acbb16ab69fe7d0603be81955b5f11e0c2fceb2d25ad0027a6b90da05/djlint-1.47.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd431c5474f0334ecff6b98308d192f8b493f86529fea572cbbe20e173008ef6", size = 1350369, upload-time = "2026-10-26T15:58:01.274Z" },
{ url = "https://files.pythonhosted.org/packages/ba/7d/c3ec3946c4a50b8472a6538aa0c5a2321ca1d3a46cf92ddf19de08c37db3/djlint-1.47.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1856c705b0a8b6a17b4a016860be95c2234ec4372013c5c5c80a88a84f4fb8e3", size = 1367496, upload-time = "2026-10-26T15:58:02.652Z" },
{ url = "https://files.pythonhosted.org/packages/c3/7a/ddba76c5d1889a54b66ca45da953cf03e0b8bda87bf45efaa909ba849692/djlint-1.47.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d09083baa160674c96bd9de08dd599f88ed3260e0e367e54b3d66c2fa17d9dd8", size = 1399818, upload-time = "2026-10-26T15:58:04.73Z" },
{ url = "https://files.pythonhosted.org/packages/e0/c3/c471c5767814291459ed0915fe65c6b332e817bda1dec8de69a90fd96930/djlint-1.47.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4f31cda7691b32246c9a7c329e885571d2da02d8ca6aec2ac9e5366f5f48b964", size = 1374385, upload-time = "2026-10-26T15:58:06.076Z" },
{ url = "https://files.pythonhosted.org/packages/c5/c1/5371eeeebf5d1dc5d9e77792b89ab4b5c9b0a25077471f26f7eb0d77e176/djlint-1.47.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2366ebc6b7e0f54bc82074bf0b4b8abec5df480f53a761778152e0ddb8e52acf", size = 1385063, upload-time = "2026-10-26T15:58:07.518Z" },
{ url = "https://files.pythonhosted.org/packages/17/02/69351be26359013d2f262f4b937dd9507940e91bb0f17389defb8031a983/djlint-1.47.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:b8b8e7f8f1135264a399a332d85f1ddb49cd70fd4d3b879bd0cd00f8a66dc10c", size = 1458847, upload-time = "2026-10-26T15:58:08.982Z" },
{ url = "https://files.pythonhosted.org/packages/67/2f/029627c9e93cc94fa7f759972c87e43e2d779f10bb724f217058ba8be776/djlint-1.47.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b41b631c2eeff42fe54224b7858a272484e49b81200efc625637812a3fa8e405", size = 1424474, upload-time = "2026-10-26T15:58:10.528Z" },
{ url = "https://files.pythonhosted.org/packages/dc/cb/d901ec068e0623d2bc80a73e70f7772acc36cfc7da938a02fa45444d8395/djlint-1.47.1-cp314-cp314-win32.whl", hash = "sha256:a062aa1ba3a702fb58b60989d493fc7ecd44cf89ca912e09142dd548aa99a455", size = 1050756, upload-time = "2026-10-26T15:58:12.083Z" },
{ url = "https://files.pythonhosted.org/packages/dd/04/cac35f360bc858ca69d743c379fcf08b235d5278acb61b22662c37aea788/djlint-1.47.1-cp314-cp314-win_amd64.whl", hash = "sha256:5192191d96867bd33d1d751943796cfebd6843a8b5ebfc3e1ff32b056cb9f12c", size = 1193682, upload-time = "2026-10-26T15:58:13.624Z" },
{ url = "https://files.pythonhosted.org/packages/fa/cc/e0023da0550e0cbf8838c9f49d1d3fd650dc19525fd7c9ec7316176516f9/djlint-1.47.1-cp314-cp314-win_arm64.whl", hash = "sha256:4bae9b411397af00326d0d73b9299ecf58681ba30eced9ccf7f191902280a5f3", size = 1121315, upload-time = "2026-10-26T15:58:15.272Z" },
{ url = "https://files.pythonhosted.org/packages/9c/c9/3c2aabd7d5f8d9cbf1f06cc9fa9bccc01aef41ec828a42f4f2ed2892867a/djlint-1.47.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:72cf2d584e18c60a5b0e494d43fc642a9ef17e3ffd8f4b1061fb6c2c02888f07", size = 1472482, upload-time = "2026-10-26T15:58:17.054Z" },
{ url = "https://files.pythonhosted.org/packages/cd/26/29701317d92787ad648eba6a61a1df4522455195e68df25adff74ce467f2/djlint-1.47.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:32073e027407d22208a5b889207f13d8d3687660f11ebeb3f6bea9e418eeeb17", size = 1395769, upload-time = "2026-10-26T15:58:18.467Z" },
{ url = "https://files.pythonhosted.org/packages/98/d4/08832392e921c18fc5c1cb156b04914b16c3fdd9c8a8ad97275ba5d78ccd/djlint-1.47.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:336726deff7b3725b549629e337dba08781c98d3c6a3e669191ba51c0f476718", size = 1487625, upload-time = "2026-10-26T15:58:19.838Z" },
{ url = "https://files.pythonhosted.org/packages/b4/dc/962a0306875200675f9fc3c0e44091d8d3462f2a0f66474fb08c5ecd5aaf/djlint-1.47.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e977c57d241003dea219ed0720e7b450d128c054f34bb75d58a3dea23c111ae", size = 1410416, upload-time = "2026-10-26T15:58:21.236Z" },
{ url = "https://files.pythonhosted.org/packages/81/2c/8893fc83c1d515b68fca9f5b9540ef1bb2c053903db9d92dd3744d56768a/djlint-1.47.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6024d904f4b9f24c8f0a0e52345bf23e19d37025f4f0c3481a679b7fbfe200ad", size = 1411702, upload-time = "2026-10-26T15:58:22.668Z" },
{ url = "https://files.pythonhosted.org/packages/db/e3/9aad3647030fa563d18d12fd7e917550d97766917c8df480ac7eaff98887/djlint-1.47.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b32cce4b54f22de76c744bb084a46af0daa6bc0c2ab566d3f5cf6b719d98e702", size = 1465991, upload-time = "2026-10-26T15:58:24.11Z" },
{ url = "https://files.pythonhosted.org/packages/11/76/e6cdfc475abbd1f561fe5eac5207523bbe1758847786981be4be7cf938b1/djlint-1.47.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:baee4ebdd8e19bc5d055a993afdc9f8c592134e33c78676ded854d0cad6c321c", size = 1428887, upload-time = "2026-10-26T15:58:25.595Z" },
{ url = "https://files.pythonhosted.org/packages/c5/95/8bbd5d21df39137284445d154507a65defceeb54504267c1ffd1c895928e/djlint-1.47.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4f5470b6a83b278c53db036122939d7680682c8116c484a63d08edb57321bd33", size = 1450332, upload-time = "2026-10-26T15:58:27.044Z" },
{ url = "https://files.pythonhosted.org/packages/67/9c/9fa4e9768d7422b3ba6f98ef30982a42283aad0504de146c1c6582737180/djlint-1.47.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:aa0c5fdeb38b4eeaaf00f65f0d0d2feae05fe90a24567adaf9b654ae9b5a2f2c", size = 1516008, upload-time = "2026-10-26T15:58:28.625Z" },
{ url = "https://files.pythonhosted.org/packages/77/02/005ca5c7602ddb758b566a6433cf91f3f71eaff8b88365cd1c843fe6e73c/djlint-1.47.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:064ffc82bd1a2dc261fe5c1adab1a1ab5e4a782908ffdef077e42c1575d8f8df", size = 1491623, upload-time = "2026-10-26T15:58:29.951Z" },
{ url = "https://files.pythonhosted.org/packages/75/ad/794edc34c294dec8ddf6dbdc57d5a71a9968208473baeb3920060440062c/djlint-1.47.1-cp314-cp314t-win32.whl", hash = "sha256:3814e432c773f2ff398a7a0c5015a4e51d3d2fc9ddec662306b86ec8cc5d8637", size = 1109215, upload-time = "2026-10-26T15:58:31.426Z" },
{ url = "https://files.pythonhosted.org/packages/26/34/bddf82a782470d7f1f4291eefbf19b8578e58ac04f90805596a0d2132524/djlint-1.47.1-cp314-cp314t-win_amd64.whl", hash = "sha256:af64c57c325d57ede40e02e5698336e289b2683b1e97f1e4dcea8be4d1242c2d", size = 1252469, upload-time = "2026-10-26T15:58:32.723Z" },
{ url = "https://files.pythonhosted.org/packages/77/fa/67988c0544f6c21e470cdd778033cea372fdffd01c161c5dfabf0de40062/djlint-1.47.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7a5f90c915320511ec34ba7731537a80793f07c0c7c8e0e650b2e1b2dab7b0c5", size = 1173908, upload-time = "2026-10-26T15:58:34.734Z" },
{ url = "https://files.pythonhosted.org/packages/5f/97/71293654a10fd55795b20ec4c34f415165c7e7ccdf2bba735b98df471062/djlint-1.47.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:3d20924e95a09094c43d8a9424137170ae69816e0aa0d3a787d2876d262a4512", size = 1353587, upload-time = "2026-10-26T15:58:36.15Z" },
{ url = "https://files.pythonhosted.org/packages/c3/ab/b62a764fb98823bf2e468f78956cec44d0896bedac5b726be45a3384224a/djlint-1.47.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:7e60e48e173732bf4687b7650990284676378d37ad82f258a26409a0cb17b674", size = 1280267, upload-time = "2026-10-26T15:58:37.928Z" },
{ url = "https://files.pythonhosted.org/packages/c1/f0/cc8a9101066ffd7ef6cdf69fdc30014dd6519a5f43e4727731ca432dd0eb/djlint-1.47.1-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d2eb216dde020dd1cf22d9b6af82458544d51e9321f102592398f98cbf8fc2ad", size = 1322874, upload-time = "2026-10-26T15:58:39.221Z" },
{ url = "https://files.pythonhosted.org/packages/ee/d8/a4eb475dc0452371ea9e707f5085eb96d5845eefe148fefbeae3cc9d1159/djlint-1.47.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21f358b69116a80bbb6f1ffc8f3adfe4cf51dd4b039b7d06d17ba15996e2019", size = 1351905, upload-time = "2026-10-26T15:58:40.604Z" },
{ url = "https://files.pythonhosted.org/packages/aa/4d/56f310d41460066f9cbe66ac41198c45719f267de05c94b5afa583336d2d/djlint-1.47.1-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7d5bf0cfed6f8311f225600071de7342da5bbf7ea394a676090d00c9d94edc60", size = 1416396, upload-time = "2026-10-26T15:58:42.209Z" },
{ url = "https://files.pythonhosted.org/packages/6b/ee/ad561585bdc9b259ae2877e923084025ca3780ac44b61650a603603943ae/djlint-1.47.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2a4e51b6738af0c55b2333ea8f02f2549d8e14bdd670864f18bf7ddf13fb564", size = 1407397, upload-time = "2026-10-26T15:58:43.642Z" },
{ url = "https://files.pythonhosted.org/packages/b3/4b/c9ff1cba7db19321af3dc80239eb8efa6dd6808e30dce49d36f35f8a742f/djlint-1.47.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:7a1c95088a81a1b41dba7a78aca09427cc5b51bba486b50a2b47e229c4c5ffc2", size = 1375463, upload-time = "2026-10-26T15:58:45.243Z" },
{ url = "https://files.pythonhosted.org/packages/ca/88/88799dbf0f09588de5d3d2fc10e6987599d7faf79cd34e62626ab53bd686/djlint-1.47.1-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:0329888219304d091f99e704a30aababb32e04f684a29e5c274959859d4894ee", size = 1436234, upload-time = "2026-10-26T15:58:46.633Z" },
{ url = "https://files.pythonhosted.org/packages/82/29/1eb591d3f9f5ea4ecd1379db2504e446b0b7d9a03fbf610319748b6a13ff/djlint-1.47.1-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:5319d1cecd961627ff79a1fee868b2bf6d022752183137544535bbc155f10076", size = 1352554, upload-time = "2026-10-26T15:58:48.035Z" },
{ url = "https://files.pythonhosted.org/packages/6e/15/0155ec20f80cc0aa9c52b58e909cd99602a40cea068e764411872d985f1f/djlint-1.47.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:6b6cb189a28539c696a3e22212d063f97c47efd2a485588a6bb6d1e8f3474232", size = 1434240, upload-time = "2026-10-26T15:58:49.609Z" },
{ url = "https://files.pythonhosted.org/packages/13/f8/fe20320754d5146887b4c4d4c821e63f9afe137a4b26c81ad101e0278957/djlint-1.47.1-cp315-cp315-win32.whl", hash = "sha256:67a51db35f7394c9c8c7f0129e4cb11421cda7782d8f6d0f3f9c49175c4567b8", size = 1050631, upload-time = "2026-10-26T15:58:50.888Z" },
{ url = "https://files.pythonhosted.org/packages/07/42/1a7766ecc038a6dd0289e646e0551a90f5efd1c76aab35ba6fa41e47d3fe/djlint-1.47.1-cp315-cp315-win_amd64.whl", hash = "sha256:a099a37a926d754228d7401a16a651ba70031edc62e42aee52a48f202a56d345", size = 1193463, upload-time = "2026-10-26T15:58:52.263Z" },
{ url = "https://files.pythonhosted.org/packages/4f/ad/d48e0d6cd0e87053c9e4706bc2d4a9458c0234bc4f8e19a482f810e21181/djlint-1.47.1-cp315-cp315-win_arm64.whl", hash = "sha256:f45d691724ff3e5d6839b60ecc22f6f85d18d69e4b9e7d08fc392d117c710f00", size = 1120819, upload-time = "2026-10-26T15:58:53.688Z" },
{ url = "https://files.pythonhosted.org/packages/9a/ee/1322fe1ba6d7f2174dd28803b6a2651b44c1aa2c7bc3a0cd47df6af6e5ba/djlint-1.47.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:69b0c7cf6412e5624f9a3d3db55d516c6457b1ed4de21d43e011f704c112231f", size = 1470037, upload-time = "2026-10-26T15:58:55.049Z" },
{ url = "https://files.pythonhosted.org/packages/69/a9/9d5006e4046b5d7192563555414910e1eafbfb73d46ad812c84f736586bb/djlint-1.47.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:7edad406b98aaa3d1812dee550bf0f66ca5a31379d23d689fe86a2409b885d73", size = 1395520, upload-time = "2026-10-26T15:58:56.528Z" },
{ url = "https://files.pythonhosted.org/packages/d7/26/214ca606cf35effd6ff7737964cfc9ad68fe284c2474b9963ff0a5891568/djlint-1.47.1-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ed465a79c11b129b675331cdc14e39e55a8ce579f567d21e00bbf23ed6dbe625", size = 1371478, upload-time = "2026-10-26T15:58:58.253Z" },
{ url = "https://files.pythonhosted.org/packages/32/e1/0ea1f0223158b47875707faa50e54097ffb977528e434e0da5dfd402e593/djlint-1.47.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f36832653e109163106d70674412fb8ef2f2fb56a159c27f5adc20bc72922a63", size = 1406022, upload-time = "2026-10-26T15:58:59.708Z" },
{ url = "https://files.pythonhosted.org/packages/43/01/48d65a8cac90083dff22c5bfa78c8485e20ef9f6c031f93f6f7929787169/djlint-1.47.1-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f9d735dda0315625c7812cabd8a5502c10a934155913bab86030162a5cb77e9d", size = 1445539, upload-time = "2026-10-26T15:59:01.093Z" },
{ url = "https://files.pythonhosted.org/packages/63/8d/71758dd0ba8e6cd29315fa4004ce08ea569d201c91b6e712a1d85633c62f/djlint-1.47.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f80d61358cbd9349158d1b174cffdb71eacf2b8d9dbbbc4eec2c2af2c6008a5e", size = 1465753, upload-time = "2026-10-26T15:59:02.456Z" },
{ url = "https://files.pythonhosted.org/packages/fd/3a/c87c8b1bfd70016309d8547cdea35202aba83a1aeae5adf361fec46afb77/djlint-1.47.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:6674d806e908ac854a8e00946bcff86224d1fca8f5df2eb9b944a2446ee30a40", size = 1422787, upload-time = "2026-10-26T15:59:04.065Z" },
{ url = "https://files.pythonhosted.org/packages/b9/9f/ad2a1f2ee6d88e40a398ca34da7c32d31fdd706dc8581df4ca03138ee89f/djlint-1.47.1-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:cf801bd3727b437708716465d5cd408ce021b417e84a078af79ccfff25268186", size = 1491166, upload-time = "2026-10-26T15:59:05.402Z" },
{ url = "https://files.pythonhosted.org/packages/32/9c/3f781bbf10f76a5522de0e9ae283664656264c6d5cd3b7340a4692ac54ea/djlint-1.47.1-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:1a39fdf3a43ede970267aa0427125dc2965353e46a835277a04025318c4268a8", size = 1401031, upload-time = "2026-10-26T15:59:07.062Z" },
{ url = "https://files.pythonhosted.org/packages/e9/1a/ae350aa2ab5423dbd0757dff4fdd31ddcf0002aace65227f62b65a8f20e9/djlint-1.47.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8f0e854d760743b752693d69e363d00a9f7dd06140a4948c146e8c1c49d9aa8f", size = 1488946, upload-time = "2026-10-26T15:59:08.4Z" },
{ url = "https://files.pythonhosted.org/packages/c6/25/17b7da46bd5a62966f918999ea530c5f9d4a5ff03e035924448ddfd107e9/djlint-1.47.1-cp315-cp315t-win32.whl", hash = "sha256:83d3cb7aafc2a9db43396b09fe27318d3b63aaa877c18bdfe3f3abf058b140b8", size = 1106570, upload-time = "2026-10-26T15:59:10.121Z" },
{ url = "https://files.pythonhosted.org/packages/7d/aa/61bd8f69ca1ca6c2636a64d11099969d8c94c132e270b9f942c5dd18d151/djlint-1.47.1-cp315-cp315t-win_amd64.whl", hash = "sha256:a74d9a6505188b41e31b7139a4bcaeb486081cd13242310b3f9d6fefc52a1fa6", size = 1249662, upload-time = "2026-10-26T15:59:11.914Z" },
{ url = "https://files.pythonhosted.org/packages/22/68/812dbf2d1b24ffe6adf988684a8e37109d053f7260dcba1ebe3b9a0ed876/djlint-1.47.1-cp315-cp315t-win_arm64.whl", hash = "sha256:9c58e0c1f1d5abd73e82f975c21aee94a05a5d8eb09cea99b7e83683dcd0fe1a", size = 1171290, upload-time = "2026-10-26T15:59:13.251Z" },
{ url = "https://files.pythonhosted.org/packages/28/6d/8c06648afed17048caf47b4794622a1ec8c65da3d89f47f97df4813922c4/djlint-1.47.1-py3-none-any.whl", hash = "sha256:35875aeec48b9601606c64fdcd15f09d1dc2beb7acd564aa6523dcd36904b602", size = 168953, upload-time = "2026-10-26T15:59:14.803Z" },
{ url = "https://files.pythonhosted.org/packages/b8/23/5a87506817b817bd98e81aa968055b42b1e02bc20f0ed0021ce6a2b5e86a/djlint-1.49.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:37a44b047b8ede2d168ea77e6920f010296ff19eea53665af10fdb3d77072e32", size = 1724909, upload-time = "2026-11-03T22:11:21.377Z" },
{ url = "https://files.pythonhosted.org/packages/80/38/7689ca602688725aa0248b89ccee1ea404d13266ba124efc395e7e78c9e9/djlint-1.49.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c629888f4270fd2c1cd3640bea44c8206806df1bfd85a1f899f7dd76a571dfd3", size = 1620276, upload-time = "2026-11-03T22:11:23.125Z" },
{ url = "https://files.pythonhosted.org/packages/db/1c/f2ad28a21fc8f7282c85ad4441a3d30730b4150570dfd38058ba64b33827/djlint-1.49.9-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:351bb6473997665aff87f6be1f3b525d202cf529689c697f99b5767fd6f6ab9c", size = 1769657, upload-time = "2026-11-03T22:11:24.541Z" },
{ url = "https://files.pythonhosted.org/packages/80/ab/bf4c9098d7c2067bcee818e1b3371b892c43aea9216949cf51024b484f23/djlint-1.49.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47ead6a46d5f518b095f2871d394a4b9dfeae3393e8f44f86c9b6d659390c1d2", size = 1641217, upload-time = "2026-11-03T22:11:25.899Z" },
{ url = "https://files.pythonhosted.org/packages/3e/88/82d07389cf02f4759e9f532d3f960b7029860c0767ea6c217045685c0d75/djlint-1.49.9-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9eaa34fa0024e307b00cd370cd5d7c171b191dd1a6ee9d09ea2605be04404874", size = 1708632, upload-time = "2026-11-03T22:11:27.259Z" },
{ url = "https://files.pythonhosted.org/packages/68/b2/84bb707ceaecff46597b368abcbea8ac68d221de9e129860340f5d17b324/djlint-1.49.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ed7d95fa5aaed1a772c83d2aaa2b25648f69a69be11d99224c0a70bc06be23f6", size = 1724854, upload-time = "2026-11-03T22:11:28.766Z" },
{ url = "https://files.pythonhosted.org/packages/fb/ec/2de16a5ebe7b02d2e054e309f39a6d9d047168a97c262907f964bf6fa8e6/djlint-1.49.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:221e84eccdb41574da43edc543fba1c511196b7f3f2f56e7c86bbac0670f8784", size = 1665767, upload-time = "2026-11-03T22:11:30.26Z" },
{ url = "https://files.pythonhosted.org/packages/e9/51/27ef851af421352cd9225c1dcaffeccb2ab4113f36b59ce14a5bcd7fd7b1/djlint-1.49.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:449a2442b84a0f5e97c3ff53783f852ab4eda8cc3ac8d9592f87e824a077ef25", size = 1732366, upload-time = "2026-11-03T22:11:31.964Z" },
{ url = "https://files.pythonhosted.org/packages/99/70/71ab64c95cb2171b5f37f6e5416a88cb49001ea902ec3b4964f94d9d2bfe/djlint-1.49.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1d305e59bf4095bc46445fce9e3af615f7989aa25c2cf20134a391e3c096a100", size = 1804842, upload-time = "2026-11-03T22:11:33.401Z" },
{ url = "https://files.pythonhosted.org/packages/4e/71/ad73533d0f025692190788aad5659e9a4b5be20709eb3d33916499d886cb/djlint-1.49.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc33c30a38dac308b937df9d17efdd233295c4015191a10ded074297d25948bd", size = 1750923, upload-time = "2026-11-03T22:11:34.801Z" },
{ url = "https://files.pythonhosted.org/packages/6a/66/72f9895219d1fa26f524f27927646de12f59bfd5c0a9cdb03033d5ae2554/djlint-1.49.9-cp312-cp312-win32.whl", hash = "sha256:a60d26bcd23290a0b709f8bff01a5df6bdc1c726ccc66115da5fd1a9a7a5cdf7", size = 1268030, upload-time = "2026-11-03T22:11:36.26Z" },
{ url = "https://files.pythonhosted.org/packages/c9/f1/32dc750fff4aa312fab11f2cd75b95db8c5e258f5a5bd5ef269e00837e2b/djlint-1.49.9-cp312-cp312-win_amd64.whl", hash = "sha256:89d7cd5bf2e4aafeb8358917870c4dd06106a85cc0f937ccf97e3a479025c36f", size = 1433262, upload-time = "2026-11-03T22:11:37.534Z" },
{ url = "https://files.pythonhosted.org/packages/30/e8/82c0407c7d211ab68267dafd73ac9dfcf8e20a63d608198a268392639392/djlint-1.49.9-cp312-cp312-win_arm64.whl", hash = "sha256:57f0410aea4a7a67db1f01969d9e4b5a86e5ec708f8c1b13cbbb7827102a4948", size = 1351796, upload-time = "2026-11-03T22:11:38.933Z" },
{ url = "https://files.pythonhosted.org/packages/a3/03/741589ddb98de5f161bd43ed99477d1b09bc31ae8df0d770a5c85490ebaf/djlint-1.49.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d57877ac38f559a0902527e76b37802c0647a44a8fbaf058684c37edebae73", size = 1705172, upload-time = "2026-11-03T22:11:40.479Z" },
{ url = "https://files.pythonhosted.org/packages/80/b4/4760b6e49b3cdbb6ef4ea4b016f48f337437c13f280e10b8a834936dcc66/djlint-1.49.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:843173c373cf438bbad33d3112a14bb8b017fc5aafc9a01e49099b98a108791e", size = 1595223, upload-time = "2026-11-03T22:11:41.966Z" },
{ url = "https://files.pythonhosted.org/packages/c8/e0/c1db8311189ca979b4ded239301531cf25f2bb9823e1769fadc78fbbdedb/djlint-1.49.9-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e56877189fc2ba213a3cb5e8f540cd789827b14a0fffab648c14b3a3c138a550", size = 1766917, upload-time = "2026-11-03T22:11:44.652Z" },
{ url = "https://files.pythonhosted.org/packages/09/43/05dd3cac483cb2a69678ec2d58d3d6e5876661dfb210f3182ddfd2ebca1e/djlint-1.49.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b398c119f1446558986fd66b497ad25064330324fce1e7a6f4d68b2cf2ef7293", size = 1637737, upload-time = "2026-11-03T22:11:46.058Z" },
{ url = "https://files.pythonhosted.org/packages/74/8b/918d921c5fd61858961a6797f79d117f5c5bd97d5bf62b0242a33038a364/djlint-1.49.9-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fefe5db198a5bf5aa81694c4b41beb009c501d1a6bec87196502b59e4dc76716", size = 1708581, upload-time = "2026-11-03T22:11:47.471Z" },
{ url = "https://files.pythonhosted.org/packages/21/9f/d4a987274262978788815acaaaa02666c1884dd98654bc51db9a0c4629b3/djlint-1.49.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6eb11b402d60f6361ff889fe72b8a8e9fefeca0c361697d9d13b4c9dd043f733", size = 1720514, upload-time = "2026-11-03T22:11:48.932Z" },
{ url = "https://files.pythonhosted.org/packages/d6/c5/165092417b153c23b800e148d70fad59c9eeda016bd14437cf17b7c8ce18/djlint-1.49.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1a07653a14ef142752efe2f20bf61f4c341623b6fc4d99011178168929c65357", size = 1662005, upload-time = "2026-11-03T22:11:50.476Z" },
{ url = "https://files.pythonhosted.org/packages/1b/53/dcd09dff73e7e5cc046434575b5985917a496797dd9e7bf7cd8cd2951b75/djlint-1.49.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:19c144e14055000ce2306ade2233289f58f298db67e1d3c820f3ac1ad13ce149", size = 1729133, upload-time = "2026-11-03T22:11:52.35Z" },
{ url = "https://files.pythonhosted.org/packages/63/94/e0fc091548b6ef8460ce07b1c62623b9881ac6f08b2b25b5a887b167485a/djlint-1.49.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6da86699aff62b39087b2bd42d6bc4bf1f876b151917ea48013ea6d7cc6f5097", size = 1801235, upload-time = "2026-11-03T22:11:53.874Z" },
{ url = "https://files.pythonhosted.org/packages/48/ea/524191ee30e0cdf53533341e4de385348f24c8e7bc04c3aa98eeafdfe958/djlint-1.49.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:604bc4e4f44e47db9c10df2e15df0d23bf88e163d91b8bf4c311400a23b99f4c", size = 1747189, upload-time = "2026-11-03T22:11:55.274Z" },
{ url = "https://files.pythonhosted.org/packages/a0/81/c55367de83ba4e533c619c7199e293751219f047a742ecd92d99bb5c1e2b/djlint-1.49.9-cp313-cp313-win32.whl", hash = "sha256:f86837e4cd6b78db4dbddb6211bbd24cc32ca8b5799fc7d4ee62e7d6c741c85c", size = 1271723, upload-time = "2026-11-03T22:11:56.886Z" },
{ url = "https://files.pythonhosted.org/packages/b3/59/b0420cd281fe898b153b4bdc4e6b28f7b30b7cd2c617c51b0b6e46ca97a5/djlint-1.49.9-cp313-cp313-win_amd64.whl", hash = "sha256:989703471a693b38de85c77a49a7b510537221ef0e4196b0ef6f29dc027ad3bd", size = 1438516, upload-time = "2026-11-03T22:11:58.378Z" },
{ url = "https://files.pythonhosted.org/packages/48/ee/a2e2e11e0110171189551c1866bd99296e18c1c500b8764ae29e0c387680/djlint-1.49.9-cp313-cp313-win_arm64.whl", hash = "sha256:f719732246afba0923a826780a26b7c4bdd92538387dcd881b5f5d3b0e86f40e", size = 1351259, upload-time = "2026-11-03T22:11:59.777Z" },
{ url = "https://files.pythonhosted.org/packages/a5/62/8738d8bea1f569f5b16c514916f749a1543303107f9176ae98ee35180824/djlint-1.49.9-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:59ed17cd292cb584f672b3de96cc9d967bcd7ee3696ba3b32f5294e1c5735a86", size = 1695783, upload-time = "2026-11-03T22:12:01.12Z" },
{ url = "https://files.pythonhosted.org/packages/e0/b2/58223df6fdbb5c6cb680b2e374470d5eb20c29df8a51ea3e40c0bb9be867/djlint-1.49.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2abe04b8e3246be7c3d669ec07e396d93fa9a91846de58dd2ae78a838aa59b91", size = 1597883, upload-time = "2026-11-03T22:12:02.399Z" },
{ url = "https://files.pythonhosted.org/packages/6d/df/c7e038f2d1b26ff0e2be12a3dfe62fc4bebaca311225ce97985a012b8044/djlint-1.49.9-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7f9a85ca4d93ee643497e7d9a51990d5083bedd5305be27ce2e8cc5b5f166e50", size = 1763331, upload-time = "2026-11-03T22:12:03.744Z" },
{ url = "https://files.pythonhosted.org/packages/48/86/41fafa2c89ecc93c9e09e7d637e0cba63501887f00f1468e7ee9a0290410/djlint-1.49.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01d3c38c41bca3f2fcf490a2b1fa7e3fa79af2c9e123a8c40460ddc4e7a71953", size = 1652220, upload-time = "2026-11-03T22:12:05.065Z" },
{ url = "https://files.pythonhosted.org/packages/fa/65/3ff79e8592428b01d9a0e7c83c92bc9f49a84c6a7623c68983f4c60b3c7c/djlint-1.49.9-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:77f3c13b10695d6b3aed270961e9604b8f2d681b6d28ec719d9cabacf8ca7d67", size = 1692118, upload-time = "2026-11-03T22:12:06.944Z" },
{ url = "https://files.pythonhosted.org/packages/51/86/80ef9ed86e36739041b07d9044746a7dcd4df48e1d228fe675dd0d5d1533/djlint-1.49.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5215030adfdbf0232ef0e292f9eb4aa3c9ad3c87cc2bf008a379359906501c2f", size = 1720609, upload-time = "2026-11-03T22:12:08.568Z" },
{ url = "https://files.pythonhosted.org/packages/c8/10/34feceb8272886d012fcd7af33423f607579866b8ac459a460905c699acb/djlint-1.49.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3d5d85f029881c2a4334777c91ee64fdb8420d3911be65a4051158b05a1db92a", size = 1681535, upload-time = "2026-11-03T22:12:10.094Z" },
{ url = "https://files.pythonhosted.org/packages/a3/3e/a3da9f1a37b43313aeb3cef5fa2878be024c818c6e4f044947ad4d8158cc/djlint-1.49.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d24ddfcda53efec10fbd6210899c0751d3664ac4044cdc83b1f85b3e2d339513", size = 1709825, upload-time = "2026-11-03T22:12:11.591Z" },
{ url = "https://files.pythonhosted.org/packages/df/13/424292be36471a8510289847020d0a51593a481e3773d4999f8d4be33e62/djlint-1.49.9-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:219ec8f91c472cab3e1cde127729f725ed593448fa50398a1736962ca08ffa88", size = 1796913, upload-time = "2026-11-03T22:12:13.369Z" },
{ url = "https://files.pythonhosted.org/packages/f1/d7/4a6ea9cce7e6dd49d24c6056eb56a6da8d7a066de44d112335882da27170/djlint-1.49.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:89a9c557c3688d4397ea93e4efe63ff59f29593eae9e6e7a022060419d8c6ca2", size = 1747869, upload-time = "2026-11-03T22:12:14.922Z" },
{ url = "https://files.pythonhosted.org/packages/9f/df/8cbb1b83468c5cb744e54f5b3605ad440e9a51990614fd842156750f11ba/djlint-1.49.9-cp314-cp314-win32.whl", hash = "sha256:447c830a75233d995a1b2c12f3336eeca67848bea988f44226285560f2a4b8df", size = 1286115, upload-time = "2026-11-03T22:12:17.126Z" },
{ url = "https://files.pythonhosted.org/packages/48/3f/19d55e5eeef21e6cbe6ce22efe2b6eef6274c0e7de1509c1f64a2e431d5c/djlint-1.49.9-cp314-cp314-win_amd64.whl", hash = "sha256:48d71bef43b0c91b9c5b05715a57b62e61d0e4894b7aa444c1208cdcc1f63780", size = 1469810, upload-time = "2026-11-03T22:12:18.623Z" },
{ url = "https://files.pythonhosted.org/packages/fe/9a/aaaa8396e40804d39afc31546cbf4cb7528fcff449475a371aa4856ebf97/djlint-1.49.9-cp314-cp314-win_arm64.whl", hash = "sha256:8b6215c3734299d061cbae83a6b6fd05852510fff3228dc13c90c57d99f97169", size = 1382370, upload-time = "2026-11-03T22:12:20.069Z" },
{ url = "https://files.pythonhosted.org/packages/28/f3/54c93e3ddc87598d4b1a1151eb2734bf492794df55467e8b7648a5c3c67c/djlint-1.49.9-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:06dc9c6456d4e4df6e920ed5ca3a0c4d66323fe3c6ba6d92ec7d4f93366066a3", size = 1849710, upload-time = "2026-11-03T22:12:21.566Z" },
{ url = "https://files.pythonhosted.org/packages/0a/ac/6ccc83ab00423086102abce514be3dcf9ee928be10d244a81fd7815af2c0/djlint-1.49.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:330a88c63f23b0a2786f22e867c2d68106d69b17d5f9acad198a60b68fcac657", size = 1749015, upload-time = "2026-11-03T22:12:23.004Z" },
{ url = "https://files.pythonhosted.org/packages/3d/e7/90d8762e020075915534a66c5da48f1ac3f6635e3a085f139af04a4e328a/djlint-1.49.9-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:08c23b42c7d938bb3db38780a71b00c112149f32a86cb0a981c8789dd7d7c005", size = 1855906, upload-time = "2026-11-03T22:12:24.547Z" },
{ url = "https://files.pythonhosted.org/packages/1f/82/300d9f2e55a9c0535a8f86726fc4cb386623f4f95654726328e15e39d8ae/djlint-1.49.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13cd225771fac68ab5ec5d8c487b43713afa674a463b2537bea2fe22232a8968", size = 1737739, upload-time = "2026-11-03T22:12:26.01Z" },
{ url = "https://files.pythonhosted.org/packages/c3/8b/51441ed7907a0907c6c66b6bb2c779b79cef988c09a2d9dcf21081951097/djlint-1.49.9-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4e24dbbc03e5a1a9266f756cf1d66d36503f712c8ed1b81ca61da046f7ab4810", size = 1766602, upload-time = "2026-11-03T22:12:27.495Z" },
{ url = "https://files.pythonhosted.org/packages/3f/98/b02e3eec45fae58c38eb5424ae81db04a3ad73e9c7e20c19a69f1ea796dd/djlint-1.49.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fab30fe0267dda15dd0684fcd0732f63140af4de19a5c7414116b07d47fa7b11", size = 1820089, upload-time = "2026-11-03T22:12:29.134Z" },
{ url = "https://files.pythonhosted.org/packages/8a/30/9c7bbcf4b8da96c6808ab6b91b342680bf9e05d6edddd908b46086d69a8d/djlint-1.49.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:45edbd784e73b773139d51ab4090dc95a94a7e023312fa4839d6a0aeeb065227", size = 1763038, upload-time = "2026-11-03T22:12:30.628Z" },
{ url = "https://files.pythonhosted.org/packages/16/d6/258b1a0cb33079e765ead3bfbddc49309b27b4504bf3df6223fcb8e196f7/djlint-1.49.9-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:2fbffa0c2db6b74a923071ad1f8f3e54eca28c0aded31f2b60eaa8a9803593f3", size = 1808511, upload-time = "2026-11-03T22:12:32.029Z" },
{ url = "https://files.pythonhosted.org/packages/eb/36/ce553fb4385025b087548085618a49a732442064f370d20b5a7d3425b557/djlint-1.49.9-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fc479016dbe7a543aca54981da24486db3dd5aa21196f099195a069a7de82c24", size = 1891926, upload-time = "2026-11-03T22:12:33.724Z" },
{ url = "https://files.pythonhosted.org/packages/20/9c/f89801bc34c83a73a4bc2f64a32b5b483fdc44d9ed14d5d1e541fd76b33d/djlint-1.49.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:68d6bd79378cc44e55d8e2a19f1dc87b42d065ef68ae7fc0650944934bb991fb", size = 1848900, upload-time = "2026-11-03T22:12:35.394Z" },
{ url = "https://files.pythonhosted.org/packages/bc/eb/04f30fe45ca81a7ef052bbf4bbdf0daed98868d2027543ae004db0b85270/djlint-1.49.9-cp314-cp314t-win32.whl", hash = "sha256:feabc15c95846bffd4058ef454d9d83513a3d9bccc07358302b04e8ba609ca3c", size = 1364181, upload-time = "2026-11-03T22:12:36.781Z" },
{ url = "https://files.pythonhosted.org/packages/6c/b2/cddde5f6f1c85626856d95a5778cd2b31025fc7871ef05db16ac3b0cbf57/djlint-1.49.9-cp314-cp314t-win_amd64.whl", hash = "sha256:8260abb9f78a370f941104d6b0ea931dd97fd588f8230e0cbd3ba1ea249af4e7", size = 1538336, upload-time = "2026-11-03T22:12:38.151Z" },
{ url = "https://files.pythonhosted.org/packages/6d/13/8d5ae5edbc3c21de1aad9bae1bbba6f5c157625625cf3a83a2a5320b0eb7/djlint-1.49.9-cp314-cp314t-win_arm64.whl", hash = "sha256:c1f62c185bb111f2f2130823fe1362f471ed0bdf8940cd0856cb8804edbdd2b6", size = 1443443, upload-time = "2026-11-03T22:12:39.686Z" },
{ url = "https://files.pythonhosted.org/packages/3c/1a/ffce9d096ca28db9e970acaea55dffda946b4ac7f124cf513848b94dded7/djlint-1.49.9-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:d421c390090feed60e34ba0580d2e17fb0e4d092b450b672dc47be66cd61c851", size = 1696072, upload-time = "2026-11-03T22:12:41.489Z" },
{ url = "https://files.pythonhosted.org/packages/68/59/abca5f9fd2f7a409f262637b04a5fe40d943474ba4de34df7a30475f3035/djlint-1.49.9-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2c9c7d4fac2cb6ffd5aa359bbcda826a9519f6893bc114e060acb7a1a3414c60", size = 1600312, upload-time = "2026-11-03T22:12:43.049Z" },
{ url = "https://files.pythonhosted.org/packages/dc/1d/80cad48dc524b9445bc861e03ea3002b0fd2533d96840e1c4ad0c6336962/djlint-1.49.9-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d4155b63ab3f5728a0b27e3a4abb312eceea3b60758f7f6a0165dc96ee19c5df", size = 1626569, upload-time = "2026-11-03T22:12:44.553Z" },
{ url = "https://files.pythonhosted.org/packages/7f/6e/20171ad91fdf25d4eae27886c1ea21db5f38bff990c862970c1d3fb6ecf7/djlint-1.49.9-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97aac034bf3ee7415f0bffc7df398dd5bfc584bc8af8f204448237444cb8596e", size = 1653991, upload-time = "2026-11-03T22:12:46.082Z" },
{ url = "https://files.pythonhosted.org/packages/d8/35/ecf40a4803ca4266f8e1ddb87b9e8f3ec4e8e4add11e11e7b1076964c3e8/djlint-1.49.9-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4b7bdf3e667061c1de0d59d665b99111bbe4d738d7ab9c06f8a108ce1a7e0d57", size = 1756628, upload-time = "2026-11-03T22:12:47.612Z" },
{ url = "https://files.pythonhosted.org/packages/91/98/6e78479566d3c077eeb172c6e365b7bdb8865679aadea6751662f33e6269/djlint-1.49.9-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f113ef9ce2f8543c69ef0dd4eb8587cd73993d92798577073b957ee556704f31", size = 1731801, upload-time = "2026-11-03T22:12:49.122Z" },
{ url = "https://files.pythonhosted.org/packages/29/84/4c43c29dfe5ae51ef711c1cad8b791dd3a9c95c13233589fffcfd895e75b/djlint-1.49.9-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:7f0ba38d9ccd0ccfd5a077ff6f0319c94cf3b4158f307bf6bf58e4b60b9a37d4", size = 1683782, upload-time = "2026-11-03T22:12:50.828Z" },
{ url = "https://files.pythonhosted.org/packages/f6/d2/f84488a7b9cadba789199e911821cbcec6da7439d759b367107de825dc22/djlint-1.49.9-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:b06f31469acc10561e0003f3eabade657cd90d91cd3321ff5413501834325c33", size = 1772276, upload-time = "2026-11-03T22:12:52.268Z" },
{ url = "https://files.pythonhosted.org/packages/28/c7/f8bba7abb8756c7f70e330b3a8d76d44e03532bd5a5f1154151b6c701773/djlint-1.49.9-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:8fd99ae49705ac3001911299676384317e302abee8b87163169c3fc4eff32bda", size = 1661285, upload-time = "2026-11-03T22:12:54.184Z" },
{ url = "https://files.pythonhosted.org/packages/b5/90/6b4ae9808aab466b6f755b4d4e8a56bc3fc0aca5a4da237a79ea246f2e4b/djlint-1.49.9-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:4841d7e391d7e269cf44d4df7610997ed04b06d362245ddd785b3e050ab7f721", size = 1760864, upload-time = "2026-11-03T22:12:55.787Z" },
{ url = "https://files.pythonhosted.org/packages/fa/49/0b58e057e38f33dc8138739c2f6cc33447396a6d754699444705a586a901/djlint-1.49.9-cp315-cp315-win32.whl", hash = "sha256:eeffd090393f0e3c0d6960c49c411c4a2612b5ed9e9b84234784763b17960697", size = 1285882, upload-time = "2026-11-03T22:12:57.472Z" },
{ url = "https://files.pythonhosted.org/packages/5e/55/d293cf72ba07243592f0871416f6eddde3622cc52955f8afc27796d2f240/djlint-1.49.9-cp315-cp315-win_amd64.whl", hash = "sha256:58745663e4c902383a18a68d18f26ce3cef668081f7f7dffb7ef86a4ee0a9c0c", size = 1469634, upload-time = "2026-11-03T22:12:59.293Z" },
{ url = "https://files.pythonhosted.org/packages/36/08/9ba7c3d380c0639703ead141ff4d079f83a26cc7d9e93f952aa72a35dee7/djlint-1.49.9-cp315-cp315-win_arm64.whl", hash = "sha256:1e7611d926178bf6ac6786c5abc7f2984b98f50bf5d6e007d22f9c443781d77f", size = 1381895, upload-time = "2026-11-03T22:13:01.041Z" },
{ url = "https://files.pythonhosted.org/packages/07/35/1dbe89177b7506e72b73e8b6b3f7c40b6c16dd5ea621d5a3a2984676c4a2/djlint-1.49.9-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e1587621430f765c5430d1fcb3f9e8ddc92e3b1f25501f64418b9af3aaf0a5e0", size = 1843571, upload-time = "2026-11-03T22:13:02.626Z" },
{ url = "https://files.pythonhosted.org/packages/7e/aa/4a60a16ad466ec91070906f3f271110bc2cc75ed63e16cdaaff86c6422a0/djlint-1.49.9-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:7d20a7eceec141124dce3682f65aaa6ebe35f2c34e443544adcbe7d4c96c9875", size = 1747993, upload-time = "2026-11-03T22:13:04.082Z" },
{ url = "https://files.pythonhosted.org/packages/4c/da/c40791a36d22c2266c4e8769d8675072085f247f09f92bbd2a93efa13d67/djlint-1.49.9-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:08500394d23c1e2e5623924a10a9f56a1513a6c3f554b16292e86952c0f310bc", size = 1703273, upload-time = "2026-11-03T22:13:05.534Z" },
{ url = "https://files.pythonhosted.org/packages/24/8f/0071ec5ef6e66075e5654715b4208d1fa4f380738dc47c7c38545582370e/djlint-1.49.9-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c1feccb00999bfeb9b4606cdffea1327735083f3324d4dcedbbcf272930700f", size = 1729543, upload-time = "2026-11-03T22:13:07.081Z" },
{ url = "https://files.pythonhosted.org/packages/f1/38/1bf052deb00e21be64cc53611ea8e2f5a5906c02cf3543da694029e9d300/djlint-1.49.9-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:767c8f17f81d4bcce080bb9d90b7ba6a037154cdf0e506617d277307e89b048c", size = 1803758, upload-time = "2026-11-03T22:13:08.552Z" },
{ url = "https://files.pythonhosted.org/packages/5e/21/bd7c5d65905195573456c385c989d38af827f1fa7d0282b98709f38cee2e/djlint-1.49.9-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ba8c5f221c4f04a3032de1eadff4481b9d230354c8959427c0c623cb36caf9c", size = 1815585, upload-time = "2026-11-03T22:13:10.257Z" },
{ url = "https://files.pythonhosted.org/packages/05/5a/36d27461237dc96ae2f766520737819160944dc0fd9d821b51ec324f976c/djlint-1.49.9-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:9ed40180804f0136e8d7a02fd74ea167cfe00291885f35ea701ec844b5e209cb", size = 1755744, upload-time = "2026-11-03T22:13:11.648Z" },
{ url = "https://files.pythonhosted.org/packages/75/e4/7778c2340d86fc930e73ea465a70ca73375fcc7529b7645fb80ae388ed38/djlint-1.49.9-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:714e963125e1a8b78d20a0a422c619490201b53427187940d589a2ec8a87ee69", size = 1855615, upload-time = "2026-11-03T22:13:13.112Z" },
{ url = "https://files.pythonhosted.org/packages/f5/0b/0fa6f63be6e419ac2c2559a693651113889c73f8f31fcb54a8392c237e01/djlint-1.49.9-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:3deb34e6567c3ec995ae2a961033e133199ca92b4bdaede77863f615a1453b31", size = 1736812, upload-time = "2026-11-03T22:13:14.558Z" },
{ url = "https://files.pythonhosted.org/packages/97/cf/f9763783eda5aeeb86e888016f02fdddb5e733518c4f9748553f0ea1359e/djlint-1.49.9-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:68364dd3c0dae8f1930616964e01042e11362aa662b8bc046e1a8b2b3f262503", size = 1842783, upload-time = "2026-11-03T22:13:16.126Z" },
{ url = "https://files.pythonhosted.org/packages/f9/06/3a9ab3dffd6164c03476f63dfb266d073e5f4d0947c766958b5e97a4cdf2/djlint-1.49.9-cp315-cp315t-win32.whl", hash = "sha256:98a504054f313969ce6e2f80dd3fcb7c60cb85292e6675a4051487cc15b91862", size = 1362166, upload-time = "2026-11-03T22:13:17.807Z" },
{ url = "https://files.pythonhosted.org/packages/27/a3/1a534338064f7067fc4ef07bd33d9492a80c5450f6b719f97223dabfe2b7/djlint-1.49.9-cp315-cp315t-win_amd64.whl", hash = "sha256:6912e81bea680edbccd9c7a82390487e0f6a3808a205abd8a51e75cd2425fea0", size = 1534768, upload-time = "2026-11-03T22:13:19.351Z" },
{ url = "https://files.pythonhosted.org/packages/b3/79/7f42ea4482a005cc73bace317dbde230a129557220d7e14413cc72986ea3/djlint-1.49.9-cp315-cp315t-win_arm64.whl", hash = "sha256:20c74168ee440a6c30832c52bea8f457df4d8fc2d7163b0338f1aa53f3b4a927", size = 1441253, upload-time = "2026-11-03T22:13:20.987Z" },
{ url = "https://files.pythonhosted.org/packages/db/eb/eca406a1990cec216223c188535daa711ac31043cdff369d9baeb2349b31/djlint-1.49.9-py3-none-any.whl", hash = "sha256:d2a11538fe455908fa5cf3d342a4995e0a9fb75993fcd12f376cd88e02f11ccf", size = 206138, upload-time = "2026-11-03T22:13:22.386Z" },
]
[[package]]
@@ -159,9 +159,9 @@ dev = [
[package.metadata.requires-dev]
dev = [
{ name = "djlint", specifier = "==1.47.1" },
{ name = "djlint", specifier = "==1.49.9" },
{ name = "yamllint", specifier = "==1.38.0" },
{ name = "zizmor", specifier = "==1.31.1" },
{ name = "zizmor", specifier = "==1.32.0" },
]
[[package]]
@@ -362,18 +362,19 @@ wheels = [
[[package]]
name = "zizmor"
version = "1.31.1"
version = "1.32.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/80/c2/196780fd38e0ea7a47d85d802c14e5ec683d0637bfe1b6def9f85f26d66b/zizmor-1.31.1.tar.gz", hash = "sha256:eb9c8a3e2c1080810fdb68bc36717b2a9d61283bb98e3a48689f5a852fc48e9f", size = 594485, upload-time = "2026-10-15T23:13:16.564Z" }
sdist = { url = "https://files.pythonhosted.org/packages/84/c5/9c9d931f6d4d3e55c14467a579dfea567d1bc15e4bb4a2fc6e5fbf931ca2/zizmor-1.32.0.tar.gz", hash = "sha256:f0b664d394576e08605fe8094e8e992056d74b808f30c0c9ca9ed227001dcf67", size = 604400, upload-time = "2026-11-02T23:31:21.6Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/57/05/a5274bb38456ab8b73a0b0a906d4029fc720b2041847649458e8938c3a47/zizmor-1.31.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9696d3c10919a3a2eb086c102f1bc10717f53ef3700a0d6c55a709c274995476", size = 9269139, upload-time = "2026-10-15T23:12:56.864Z" },
{ url = "https://files.pythonhosted.org/packages/d8/8f/aeb02ac2a769e9b35991633ea04a43481616b2895c82cc5cac58aeeafd0d/zizmor-1.31.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4a70ee3c2721122aff04d5bbad5e448d15384f45de2ecb3c9493fe9dac2bc95f", size = 8875029, upload-time = "2026-10-15T23:12:59.127Z" },
{ url = "https://files.pythonhosted.org/packages/17/a9/a2e0721c169d116074f07cddf98a939886d422acd393537efd99a331475b/zizmor-1.31.1-py3-none-manylinux_2_24_aarch64.whl", hash = "sha256:d9b36840c560a8abe39d9ef3d077239aabf6d572c5c2b629c970592a617dbf6f", size = 9186694, upload-time = "2026-10-15T23:13:01.094Z" },
{ url = "https://files.pythonhosted.org/packages/d1/e1/84f627f914e34084013b8dc7bf6aa701970b96c08ebae6d69b3f6e6dfeb9/zizmor-1.31.1-py3-none-manylinux_2_28_armv7l.whl", hash = "sha256:d8a5f86fbf93e65e9d42de9eb4c1855d195c5e9cdeef4f228093ad6711bd8ee4", size = 8773695, upload-time = "2026-10-15T23:13:03.22Z" },
{ url = "https://files.pythonhosted.org/packages/7c/f7/ee2c8eedc7bf07f443a41aa12f828c7846fd17bab184c22403afd0cbb137/zizmor-1.31.1-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:58e878eb2dbd2c6183c105e1ac28c14f7dd1eca44a783f1fe2a69647d012c410", size = 9579409, upload-time = "2026-10-15T23:13:05.208Z" },
{ url = "https://files.pythonhosted.org/packages/2c/53/0841490dde334d8ecf590c008922d942da8bbb51a053ad61fd596591465f/zizmor-1.31.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5ccb17fd820bb1ddc63cc9a715e97c063025487e585f640389a86d9dfc97cda", size = 9217780, upload-time = "2026-10-15T23:13:07.272Z" },
{ url = "https://files.pythonhosted.org/packages/bd/38/0acb97bd772750f102a08d95fb894483c2bf2d0798a0a68367fbfe8e3e1a/zizmor-1.31.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:385732e55ca152a013b0863213b67be32f94157775354b8ad23cc9c5d70cdc82", size = 8734956, upload-time = "2026-10-15T23:13:09.163Z" },
{ url = "https://files.pythonhosted.org/packages/ba/48/a9b5bf90d2ac6db62c133e5e7a06b120dc2bf1f55addc88e363d9342c9fb/zizmor-1.31.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e7fdf82d31cc67eb1d5030bf2372b25ee2a1c3ad05017e18da70ed138c4accd6", size = 9672323, upload-time = "2026-10-15T23:13:11.207Z" },
{ url = "https://files.pythonhosted.org/packages/04/11/72b978ddcae70dc943b341d427e4f85185e3796bc6b50b5573579febbf8b/zizmor-1.31.1-py3-none-win32.whl", hash = "sha256:d1d2cdc23e7b11f2d6cbda0df3bee62ee7993a60647650f51c316ccd33365469", size = 7925780, upload-time = "2026-10-15T23:13:13.026Z" },
{ url = "https://files.pythonhosted.org/packages/3e/3d/e3091f06bc629532025035654a6376dc673244f8e0a11489e6aff8a330e6/zizmor-1.31.1-py3-none-win_amd64.whl", hash = "sha256:3b35b393e8d437e275c7e399047c9892ccc290f3fc5e6aeb9f65a5d3b2a470e0", size = 9029164, upload-time = "2026-10-15T23:13:14.727Z" },
{ url = "https://files.pythonhosted.org/packages/98/19/e5eeae31466ee7fe7919050bca7993ecade4878801cd2174d05b1c2da166/zizmor-1.32.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aa4b4e216321dd5cf202cd79fc83296468f0eed79d850cd65ac8187a6bbc5496", size = 9416965, upload-time = "2026-11-02T23:30:59.361Z" },
{ url = "https://files.pythonhosted.org/packages/cd/68/a258299c0fdb3c266c2df0d422da6380df5602c6b0373af3fbe461231290/zizmor-1.32.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:0a999c98015becd9f69919ce01febadfb1c2be9b8ec2ce9ef7eb13ff23ba8eba", size = 8979489, upload-time = "2026-11-02T23:31:01.724Z" },
{ url = "https://files.pythonhosted.org/packages/be/18/8d66db6e98c89f5d647236e282062d8ccc73f7ba759f7ef8dd6204683518/zizmor-1.32.0-py3-none-manylinux_2_24_aarch64.whl", hash = "sha256:0cdd38fca6eb34ceb567548548d706332e3535ea66894b9168c048e03207b68c", size = 9319662, upload-time = "2026-11-02T23:31:03.763Z" },
{ url = "https://files.pythonhosted.org/packages/68/14/8f4750ef28bdb7234abd0c9be5ebc8c328cdcafa84dd8f7082db711bdd31/zizmor-1.32.0-py3-none-manylinux_2_28_armv7l.whl", hash = "sha256:bddcdb0e37d1aa53c9f831c55627a5829d0d552cb0afb4b80fbe16a3a3140366", size = 8884062, upload-time = "2026-11-02T23:31:05.671Z" },
{ url = "https://files.pythonhosted.org/packages/6f/b2/45f4fcb6f428e774750709ecf5320ba6d96393c03b941d9f37a4586f6924/zizmor-1.32.0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:84a6acb975accc13408786a2bd274b572537ca19c933ebbc13e78f3988562071", size = 9722222, upload-time = "2026-11-02T23:31:07.513Z" },
{ url = "https://files.pythonhosted.org/packages/ac/86/50f103c3a9f705297807c5dced4554b9fd675837f600eaa9582a97988e52/zizmor-1.32.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d34dcfa702875202b4163d90ebb9cc5222f3d1a7d4b72bf796d87b5a15b24194", size = 9335684, upload-time = "2026-11-02T23:31:09.544Z" },
{ url = "https://files.pythonhosted.org/packages/71/9c/a465f96566aefb152c3411f6b30867913b6ae4e7a730242a801b6a1216ff/zizmor-1.32.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3f404b26791ed06a5ea9eaa0bfd5b973fc5228bac7db8b3c5ec7f0c7ad2ed16d", size = 8846777, upload-time = "2026-11-02T23:31:11.898Z" },
{ url = "https://files.pythonhosted.org/packages/00/ec/aafd81a32c317509de5a3482c3d8c3c165b4c073d0fdf1e0a54671e1ad63/zizmor-1.32.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd818f99d833b86cd432d5412d620d936b5df074b33404fff8b67acff55d3259", size = 9819812, upload-time = "2026-11-02T23:31:14.098Z" },
{ url = "https://files.pythonhosted.org/packages/21/aa/535adba18c93ed5739ed1ea3e4742a42a29e26ae2071026eae01d586538c/zizmor-1.32.0-py3-none-win32.whl", hash = "sha256:eaedf57859f026a0a7da2a6b574517b1fe01e256c6875b3319a06ee1cee026a7", size = 8029245, upload-time = "2026-11-02T23:31:15.871Z" },
{ url = "https://files.pythonhosted.org/packages/0f/1f/1ed88cac316f248c7851860bd209ce2a2abf1a2481d887b8a78619dd4a39/zizmor-1.32.0-py3-none-win_amd64.whl", hash = "sha256:9cd1dd7734042f40ca0faa2a31fb4e9033dede620d996af2f903744b8f04fca9", size = 9194896, upload-time = "2026-11-02T23:31:17.425Z" },
{ url = "https://files.pythonhosted.org/packages/ff/74/4629954a4ccfcd3434509b5228f0357f934a16abc455cf1d2a1b4f7346cc/zizmor-1.32.0-py3-none-win_arm64.whl", hash = "sha256:913fd3943bc1358aa6e23b33fe01cc98bf67af23985258b8fbf24eaa2f8728ea", size = 8654150, upload-time = "2026-11-02T23:31:19.812Z" },
]

View File

@@ -411,8 +411,7 @@ select.ui.dropdown {
.ui.dropdown select.noselection ~ .remove.icon,
.ui.dropdown input[value=""] ~ .remove.icon,
.ui.dropdown input:not([value]) ~ .remove.icon,
.ui.dropdown.loading > .remove.icon {
.ui.dropdown input:not([value]) ~ .remove.icon {
display: none;
}
@@ -520,40 +519,6 @@ select.ui.dropdown {
color: var(--color-placeholder-text);
}
.ui.loading.dropdown > i.icon {
height: 1em !important;
}
.ui.loading.selection.dropdown > i.icon {
padding: 1.5em 1.28571429em !important;
}
.ui.loading.dropdown > i.icon::before {
position: absolute;
content: "";
top: 50%;
left: 50%;
margin: -0.64285714em 0 0 -0.64285714em;
width: 1.28571429em;
height: 1.28571429em;
border-radius: 500rem;
border: 0.2em solid var(--color-secondary);
}
.ui.loading.dropdown > i.icon::after {
position: absolute;
content: "";
top: 50%;
left: 50%;
box-shadow: 0 0 0 1px transparent;
margin: -0.64285714em 0 0 -0.64285714em;
width: 1.28571429em;
height: 1.28571429em;
animation: loader 0.6s infinite linear;
border: 0.2em solid var(--color-text-light-2);
border-radius: 500rem;
}
.ui.dropdown .loading.menu {
display: block;
visibility: hidden;

View File

@@ -12,10 +12,11 @@ type IssueInfo = {
const issueInfoCache = new Map<string, IssueInfo>();
async function getIssueInfo(url: string): Promise<IssueInfo> {
async function getIssueInfo(url: string): Promise<IssueInfo | null> {
if (issueInfoCache.has(url)) return issueInfoCache.get(url)!;
const resp = await GET(url);
if (!resp.ok) throw new Error(resp.statusText || 'Unknown network error');
// fetch already logs network errors in console, we can ignore network errors here
if (!resp.ok) return null;
const data = await resp.json();
issueInfoCache.set(url, data);
return data;
@@ -26,6 +27,8 @@ async function showRefIssuePopup(link: HTMLAnchorElement, info: IssuePathInfo) {
getIssueInfo(`${window.config.appSubUrl}/${info.ownerName}/${info.repoName}/${info.pathType}/${info.indexString}/info`),
import('../components/ContextPopup.vue'),
]);
if (!data) return;
const el = document.createElement('div');
const app = createApp(ContextPopup, {
issue: data.convertedIssue,
@@ -56,21 +59,24 @@ export function initRefIssueContextPopup() {
link.setAttribute('data-ref-issue-popup', '');
// delay so a mouse passing over the link doesn't fire a fetch
let timer: TimeoutId;
const cancel = () => {
let timer: TimeoutId | undefined;
const stopDelayedPopup = () => {
if (!timer) return;
clearTimeout(timer);
timer = undefined;
link.removeAttribute('data-ref-issue-popup');
link.removeEventListener('mouseleave', cancel);
link.removeEventListener('mouseleave', stopDelayedPopup);
};
timer = setTimeout(async () => {
link.removeEventListener('mouseleave', cancel);
link.removeEventListener('mouseleave', stopDelayedPopup);
try {
await showRefIssuePopup(link, issuePathInfo);
} catch (err) {
console.error('Failed to load issue info:', err);
link.removeAttribute('data-ref-issue-popup');
console.error('Failed to load issue popup info:', err);
} finally {
stopDelayedPopup();
}
}, 300);
link.addEventListener('mouseleave', cancel);
link.addEventListener('mouseleave', stopDelayedPopup);
});
}