Merge branch 'feat/multiple-files-api' of ssh://github.com/denyskon/gitea into feat/multiple-files-api

This commit is contained in:
Denys Konovalov 2025-04-10 11:04:15 +02:00
commit a08510567c
141 changed files with 2188 additions and 1840 deletions

1
.gitattributes vendored
View File

@ -4,6 +4,7 @@
/assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated
/options/fileicon/** linguist-generated
/vendor/** -text -eol linguist-vendored
/web_src/js/vendor/** -text -eol linguist-vendored
Dockerfile.* linguist-language=Dockerfile

View File

@ -11,7 +11,7 @@
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[View this document in Chinese](./README_ZH.md)
[繁體中文](./README.zh-tw.md) | [简体中文](./README.zh-cn.md)
## Purpose

206
README.zh-cn.md Normal file
View File

@ -0,0 +1,206 @@
# Gitea
[![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
[![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[English](./README.md) | [繁體中文](./README.zh-tw.md)
## 目的
这个项目的目标是提供最简单、最快速、最无痛的方式来设置自托管的 Git 服务。
由于 Gitea 是用 Go 语言编写的,它可以在 Go 支持的所有平台和架构上运行,包括 Linux、macOS 和 Windows 的 x86、amd64、ARM 和 PowerPC 架构。这个项目自 2016 年 11 月从 [Gogs](https://gogs.io) [分叉](https://blog.gitea.com/welcome-to-gitea/) 而来,但已经有了很多变化。
在线演示可以访问 [demo.gitea.com](https://demo.gitea.com)。
要访问免费的 Gitea 服务(有一定数量的仓库限制),可以访问 [gitea.com](https://gitea.com/user/login)。
要快速部署您自己的专用 Gitea 实例,可以在 [cloud.gitea.com](https://cloud.gitea.com) 开始免费试用。
## 文件
您可以在我们的官方 [文件网站](https://docs.gitea.com/) 上找到全面的文件。
它包括安装、管理、使用、开发、贡献指南等,帮助您快速入门并有效地探索所有功能。
如果您有任何建议或想要贡献,可以访问 [文件仓库](https://gitea.com/gitea/docs)
## 构建
从源代码树的根目录运行:
TAGS="bindata" make build
如果需要 SQLite 支持:
TAGS="bindata sqlite sqlite_unlock_notify" make build
`build` 目标分为两个子目标:
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定义。
- `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。
需要互联网连接来下载 go 和 npm 模块。从包含预构建前端文件的官方源代码压缩包构建时,不会触发 `frontend` 目标,因此可以在没有 Node.js 的情况下构建。
更多信息https://docs.gitea.com/installation/install-from-source
## 使用
构建后,默认情况下会在源代码树的根目录生成一个名为 `gitea` 的二进制文件。要运行它,请使用:
./gitea web
> [!注意]
> 如果您对使用我们的 API 感兴趣,我们提供了实验性支持,并附有 [文件](https://docs.gitea.com/api)。
## 贡献
预期的工作流程是Fork -> Patch -> Push -> Pull Request
> [!注意]
>
> 1. **在开始进行 Pull Request 之前,您必须阅读 [贡献者指南](CONTRIBUTING.md)。**
> 2. 如果您在项目中发现了漏洞,请私下写信给 **security@gitea.io**。谢谢!
## 翻译
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com)
翻译通过 [Crowdin](https://translate.gitea.com) 进行。如果您想翻译成新的语言,请在 Crowdin 项目中请求管理员添加新语言。
您也可以创建一个 issue 来添加语言,或者在 discord 的 #translation 频道上询问。如果您需要上下文或发现一些翻译问题,可以在字符串上留言或在 Discord 上询问。对于一般的翻译问题,文档中有一个部分。目前有点空,但我们希望随着问题的出现而填充它。
更多信息请参阅 [文件](https://docs.gitea.com/contributing/localization)。
## 官方和第三方项目
我们提供了一个官方的 [go-sdk](https://gitea.com/gitea/go-sdk),一个名为 [tea](https://gitea.com/gitea/tea) 的 CLI 工具和一个 Gitea Action 的 [action runner](https://gitea.com/gitea/act_runner)。
我们在 [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea) 维护了一个 Gitea 相关项目的列表,您可以在那里发现更多的第三方项目,包括 SDK、插件、主题等。
## 通讯
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
如果您有任何文件未涵盖的问题,可以在我们的 [Discord 服务器](https://discord.gg/Gitea) 上与我们联系,或者在 [discourse 论坛](https://forum.gitea.com/) 上创建帖子。
## 作者
- [维护者](https://github.com/orgs/go-gitea/people)
- [贡献者](https://github.com/go-gitea/gitea/graphs/contributors)
- [翻译者](options/locale/TRANSLATORS)
## 支持者
感谢所有支持者! 🙏 [[成为支持者](https://opencollective.com/gitea#backer)]
<a href="https://opencollective.com/gitea#backers" target="_blank"><img src="https://opencollective.com/gitea/backers.svg?width=890"></a>
## 赞助商
通过成为赞助商来支持这个项目。您的标志将显示在这里,并带有链接到您的网站。 [[成为赞助商](https://opencollective.com/gitea#sponsor)]
<a href="https://opencollective.com/gitea/sponsor/0/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/1/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/2/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/3/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/4/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/5/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/6/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/7/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/8/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/9/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/9/avatar.svg"></a>
## 常见问题
**Gitea 怎么发音?**
Gitea 的发音是 [/ɡɪti:/](https://youtu.be/EM71-2uDAoY),就像 "gi-tea" 一样g 是硬音。
**为什么这个项目没有托管在 Gitea 实例上?**
我们正在 [努力](https://github.com/go-gitea/gitea/issues/1029)。
**在哪里可以找到安全补丁?**
在 [发布日志](https://github.com/go-gitea/gitea/releases) 或 [变更日志](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md) 中,搜索关键词 `SECURITY` 以找到安全补丁。
## 许可证
这个项目是根据 MIT 许可证授权的。
请参阅 [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) 文件以获取完整的许可证文本。
## 进一步信息
<details>
<summary>寻找界面概述?查看这里!</summary>
### 登录/注册页面
![Login](https://dl.gitea.com/screenshots/login.png)
![Register](https://dl.gitea.com/screenshots/register.png)
### 用户仪表板
![Home](https://dl.gitea.com/screenshots/home.png)
![Issues](https://dl.gitea.com/screenshots/issues.png)
![Pull Requests](https://dl.gitea.com/screenshots/pull_requests.png)
![Milestones](https://dl.gitea.com/screenshots/milestones.png)
### 用户资料
![Profile](https://dl.gitea.com/screenshots/user_profile.png)
### 探索
![Repos](https://dl.gitea.com/screenshots/explore_repos.png)
![Users](https://dl.gitea.com/screenshots/explore_users.png)
![Orgs](https://dl.gitea.com/screenshots/explore_orgs.png)
### 仓库
![Home](https://dl.gitea.com/screenshots/repo_home.png)
![Commits](https://dl.gitea.com/screenshots/repo_commits.png)
![Branches](https://dl.gitea.com/screenshots/repo_branches.png)
![Labels](https://dl.gitea.com/screenshots/repo_labels.png)
![Milestones](https://dl.gitea.com/screenshots/repo_milestones.png)
![Releases](https://dl.gitea.com/screenshots/repo_releases.png)
![Tags](https://dl.gitea.com/screenshots/repo_tags.png)
#### 仓库问题
![List](https://dl.gitea.com/screenshots/repo_issues.png)
![Issue](https://dl.gitea.com/screenshots/repo_issue.png)
#### 仓库拉取请求
![List](https://dl.gitea.com/screenshots/repo_pull_requests.png)
![Pull Request](https://dl.gitea.com/screenshots/repo_pull_request.png)
![File](https://dl.gitea.com/screenshots/repo_pull_request_file.png)
![Commits](https://dl.gitea.com/screenshots/repo_pull_request_commits.png)
#### 仓库操作
![List](https://dl.gitea.com/screenshots/repo_actions.png)
![Details](https://dl.gitea.com/screenshots/repo_actions_run.png)
#### 仓库活动
![Activity](https://dl.gitea.com/screenshots/repo_activity.png)
![Contributors](https://dl.gitea.com/screenshots/repo_contributors.png)
![Code Frequency](https://dl.gitea.com/screenshots/repo_code_frequency.png)
![Recent Commits](https://dl.gitea.com/screenshots/repo_recent_commits.png)
### 组织
![Home](https://dl.gitea.com/screenshots/org_home.png)
</details>

206
README.zh-tw.md Normal file
View File

@ -0,0 +1,206 @@
# Gitea
[![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
[![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[English](./README.md) | [简体中文](./README.zh-cn.md)
## 目的
這個項目的目標是提供最簡單、最快速、最無痛的方式來設置自託管的 Git 服務。
由於 Gitea 是用 Go 語言編寫的,它可以在 Go 支援的所有平台和架構上運行,包括 Linux、macOS 和 Windows 的 x86、amd64、ARM 和 PowerPC 架構。這個項目自 2016 年 11 月從 [Gogs](https://gogs.io) [分叉](https://blog.gitea.com/welcome-to-gitea/) 而來,但已經有了很多變化。
在線演示可以訪問 [demo.gitea.com](https://demo.gitea.com)。
要訪問免費的 Gitea 服務(有一定數量的倉庫限制),可以訪問 [gitea.com](https://gitea.com/user/login)。
要快速部署您自己的專用 Gitea 實例,可以在 [cloud.gitea.com](https://cloud.gitea.com) 開始免費試用。
## 文件
您可以在我們的官方 [文件網站](https://docs.gitea.com/) 上找到全面的文件。
它包括安裝、管理、使用、開發、貢獻指南等,幫助您快速入門並有效地探索所有功能。
如果您有任何建議或想要貢獻,可以訪問 [文件倉庫](https://gitea.com/gitea/docs)
## 構建
從源代碼樹的根目錄運行:
TAGS="bindata" make build
如果需要 SQLite 支援:
TAGS="bindata sqlite sqlite_unlock_notify" make build
`build` 目標分為兩個子目標:
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定義。
- `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。
需要互聯網連接來下載 go 和 npm 模塊。從包含預構建前端文件的官方源代碼壓縮包構建時,不會觸發 `frontend` 目標,因此可以在沒有 Node.js 的情況下構建。
更多信息https://docs.gitea.com/installation/install-from-source
## 使用
構建後,默認情況下會在源代碼樹的根目錄生成一個名為 `gitea` 的二進制文件。要運行它,請使用:
./gitea web
> [!注意]
> 如果您對使用我們的 API 感興趣,我們提供了實驗性支援,並附有 [文件](https://docs.gitea.com/api)。
## 貢獻
預期的工作流程是Fork -> Patch -> Push -> Pull Request
> [!注意]
>
> 1. **在開始進行 Pull Request 之前,您必須閱讀 [貢獻者指南](CONTRIBUTING.md)。**
> 2. 如果您在項目中發現了漏洞,請私下寫信給 **security@gitea.io**。謝謝!
## 翻譯
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com)
翻譯通過 [Crowdin](https://translate.gitea.com) 進行。如果您想翻譯成新的語言,請在 Crowdin 項目中請求管理員添加新語言。
您也可以創建一個 issue 來添加語言,或者在 discord 的 #translation 頻道上詢問。如果您需要上下文或發現一些翻譯問題,可以在字符串上留言或在 Discord 上詢問。對於一般的翻譯問題,文檔中有一個部分。目前有點空,但我們希望隨著問題的出現而填充它。
更多信息請參閱 [文件](https://docs.gitea.com/contributing/localization)。
## 官方和第三方項目
我們提供了一個官方的 [go-sdk](https://gitea.com/gitea/go-sdk),一個名為 [tea](https://gitea.com/gitea/tea) 的 CLI 工具和一個 Gitea Action 的 [action runner](https://gitea.com/gitea/act_runner)。
我們在 [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea) 維護了一個 Gitea 相關項目的列表,您可以在那裡發現更多的第三方項目,包括 SDK、插件、主題等。
## 通訊
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
如果您有任何文件未涵蓋的問題,可以在我們的 [Discord 服務器](https://discord.gg/Gitea) 上與我們聯繫,或者在 [discourse 論壇](https://forum.gitea.com/) 上創建帖子。
## 作者
- [維護者](https://github.com/orgs/go-gitea/people)
- [貢獻者](https://github.com/go-gitea/gitea/graphs/contributors)
- [翻譯者](options/locale/TRANSLATORS)
## 支持者
感謝所有支持者! 🙏 [[成為支持者](https://opencollective.com/gitea#backer)]
<a href="https://opencollective.com/gitea#backers" target="_blank"><img src="https://opencollective.com/gitea/backers.svg?width=890"></a>
## 贊助商
通過成為贊助商來支持這個項目。您的標誌將顯示在這裡,並帶有鏈接到您的網站。 [[成為贊助商](https://opencollective.com/gitea#sponsor)]
<a href="https://opencollective.com/gitea/sponsor/0/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/1/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/2/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/3/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/4/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/5/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/6/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/7/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/8/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/9/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/9/avatar.svg"></a>
## 常見問題
**Gitea 怎麼發音?**
Gitea 的發音是 [/ɡɪti:/](https://youtu.be/EM71-2uDAoY),就像 "gi-tea" 一樣g 是硬音。
**為什麼這個項目沒有託管在 Gitea 實例上?**
我們正在 [努力](https://github.com/go-gitea/gitea/issues/1029)。
**在哪裡可以找到安全補丁?**
在 [發佈日誌](https://github.com/go-gitea/gitea/releases) 或 [變更日誌](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md) 中,搜索關鍵詞 `SECURITY` 以找到安全補丁。
## 許可證
這個項目是根據 MIT 許可證授權的。
請參閱 [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) 文件以獲取完整的許可證文本。
## 進一步信息
<details>
<summary>尋找界面概述?查看這裡!</summary>
### 登錄/註冊頁面
![Login](https://dl.gitea.com/screenshots/login.png)
![Register](https://dl.gitea.com/screenshots/register.png)
### 用戶儀表板
![Home](https://dl.gitea.com/screenshots/home.png)
![Issues](https://dl.gitea.com/screenshots/issues.png)
![Pull Requests](https://dl.gitea.com/screenshots/pull_requests.png)
![Milestones](https://dl.gitea.com/screenshots/milestones.png)
### 用戶資料
![Profile](https://dl.gitea.com/screenshots/user_profile.png)
### 探索
![Repos](https://dl.gitea.com/screenshots/explore_repos.png)
![Users](https://dl.gitea.com/screenshots/explore_users.png)
![Orgs](https://dl.gitea.com/screenshots/explore_orgs.png)
### 倉庫
![Home](https://dl.gitea.com/screenshots/repo_home.png)
![Commits](https://dl.gitea.com/screenshots/repo_commits.png)
![Branches](https://dl.gitea.com/screenshots/repo_branches.png)
![Labels](https://dl.gitea.com/screenshots/repo_labels.png)
![Milestones](https://dl.gitea.com/screenshots/repo_milestones.png)
![Releases](https://dl.gitea.com/screenshots/repo_releases.png)
![Tags](https://dl.gitea.com/screenshots/repo_tags.png)
#### 倉庫問題
![List](https://dl.gitea.com/screenshots/repo_issues.png)
![Issue](https://dl.gitea.com/screenshots/repo_issue.png)
#### 倉庫拉取請求
![List](https://dl.gitea.com/screenshots/repo_pull_requests.png)
![Pull Request](https://dl.gitea.com/screenshots/repo_pull_request.png)
![File](https://dl.gitea.com/screenshots/repo_pull_request_file.png)
![Commits](https://dl.gitea.com/screenshots/repo_pull_request_commits.png)
#### 倉庫操作
![List](https://dl.gitea.com/screenshots/repo_actions.png)
![Details](https://dl.gitea.com/screenshots/repo_actions_run.png)
#### 倉庫活動
![Activity](https://dl.gitea.com/screenshots/repo_activity.png)
![Contributors](https://dl.gitea.com/screenshots/repo_contributors.png)
![Code Frequency](https://dl.gitea.com/screenshots/repo_code_frequency.png)
![Recent Commits](https://dl.gitea.com/screenshots/repo_recent_commits.png)
### 組織
![Home](https://dl.gitea.com/screenshots/org_home.png)
</details>

View File

@ -1,156 +0,0 @@
# Gitea
[![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
[![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[View this document in English](./README.md)
## 目标
Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux、macOS 和 Windows 以及各种架构,除了 x86 和 amd64还包括 ARM 和 PowerPC。
如果你想试用在线演示和报告问题,请访问 [demo.gitea.com](https://demo.gitea.com/)。
如果你想使用免费的 Gitea 服务(有仓库数量限制),请访问 [gitea.com](https://gitea.com/user/login)。
如果你想在 Gitea Cloud 上快速部署你自己独享的 Gitea 实例,请访问 [cloud.gitea.com](https://cloud.gitea.com) 开始免费试用。
## 文档
关于如何安装请访问我们的 [文档站](https://docs.gitea.com/zh-cn/category/installation),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。
## 编译
在源代码的根目录下执行:
TAGS="bindata" make build
或者如果需要SQLite支持
TAGS="bindata sqlite sqlite_unlock_notify" make build
编译过程会分成2个子任务
- `make backend`,需要 [Go Stable](https://go.dev/dl/),最低版本需求可查看 [go.mod](/go.mod)。
- `make frontend`,需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。
你需要连接网络来下载 go 和 npm modules。当从 tar 格式的源文件编译时,其中包含了预编译的前端文件,因此 `make frontend` 将不会被执行。这允许编译时不需要 Node.js。
更多信息: https://docs.gitea.com/installation/install-from-source
## 使用
编译之后,默认会在根目录下生成一个名为 `gitea` 的文件。你可以这样执行它:
./gitea web
> [!注意]
> 如果你要使用API请参见 [API 文档](https://godoc.org/code.gitea.io/sdk/gitea)。
## 贡献
贡献流程Fork -> Patch -> Push -> Pull Request
> [!注意]
>
> 1. **开始贡献代码之前请确保你已经看过了 [贡献者向导(英文)](CONTRIBUTING.md)**
> 2. 所有的安全问题,请私下发送邮件给 **security@gitea.io**。 谢谢!
## 翻译
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com)
多语言翻译是基于Crowdin进行的。
从 [文档](https://docs.gitea.com/contributing/localization) 中获取更多信息。
## 官方和第三方项目
Gitea 提供官方的 [go-sdk](https://gitea.com/gitea/go-sdk),以及名为 [tea](https://gitea.com/gitea/tea) 的 CLI 工具 和 用于 Gitea Action 的 [action runner](https://gitea.com/gitea/act_runner)。
[gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea) 是一个 Gitea 相关项目的列表,你可以在这里找到更多的第三方项目,包括 SDK、插件、主题等等。
## 作者
- [Maintainers](https://github.com/orgs/go-gitea/people)
- [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
- [Translators](options/locale/TRANSLATORS)
## 授权许可
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) 文件中。
## 更多信息
<details>
<summary>截图</summary>
### 登录界面
![登录](https://dl.gitea.com/screenshots/login.png)
![注册](https://dl.gitea.com/screenshots/register.png)
### 用户首页
![首页](https://dl.gitea.com/screenshots/home.png)
![工单列表](https://dl.gitea.com/screenshots/issues.png)
![合并请求列表](https://dl.gitea.com/screenshots/pull_requests.png)
![里程碑列表](https://dl.gitea.com/screenshots/milestones.png)
### 用户资料
![用户资料](https://dl.gitea.com/screenshots/user_profile.png)
### 探索
![仓库列表](https://dl.gitea.com/screenshots/explore_repos.png)
![用户列表](https://dl.gitea.com/screenshots/explore_users.png)
![组织列表](https://dl.gitea.com/screenshots/explore_orgs.png)
### 仓库
![首页](https://dl.gitea.com/screenshots/repo_home.png)
![提交列表](https://dl.gitea.com/screenshots/repo_commits.png)
![分支列表](https://dl.gitea.com/screenshots/repo_branches.png)
![标签列表](https://dl.gitea.com/screenshots/repo_labels.png)
![里程碑列表](https://dl.gitea.com/screenshots/repo_milestones.png)
![版本发布](https://dl.gitea.com/screenshots/repo_releases.png)
![标签列表](https://dl.gitea.com/screenshots/repo_tags.png)
#### 仓库工单
![列表](https://dl.gitea.com/screenshots/repo_issues.png)
![工单](https://dl.gitea.com/screenshots/repo_issue.png)
#### 仓库合并请求
![列表](https://dl.gitea.com/screenshots/repo_pull_requests.png)
![合并请求](https://dl.gitea.com/screenshots/repo_pull_request.png)
![文件](https://dl.gitea.com/screenshots/repo_pull_request_file.png)
![提交列表](https://dl.gitea.com/screenshots/repo_pull_request_commits.png)
#### 仓库 Actions
![列表](https://dl.gitea.com/screenshots/repo_actions.png)
![Run](https://dl.gitea.com/screenshots/repo_actions_run.png)
#### 仓库动态
![动态](https://dl.gitea.com/screenshots/repo_activity.png)
![贡献者](https://dl.gitea.com/screenshots/repo_contributors.png)
![代码频率](https://dl.gitea.com/screenshots/repo_code_frequency.png)
![最近的提交](https://dl.gitea.com/screenshots/repo_recent_commits.png)
### 组织
![首页](https://dl.gitea.com/screenshots/org_home.png)
</details>

View File

@ -213,6 +213,10 @@ func serveInstalled(ctx *cli.Context) error {
log.Fatal("Can not find APP_DATA_PATH %q", setting.AppDataPath)
}
// the AppDataTempDir is fully managed by us with a safe sub-path
// so it's safe to automatically remove the outdated files
setting.AppDataTempDir("").RemoveOutdated(3 * 24 * time.Hour)
// Override the provided port number within the configuration
if ctx.IsSet("port") {
if err := setPort(ctx.String("port")); err != nil {

View File

@ -197,13 +197,6 @@ RUN_USER = ; git
;; relative paths are made absolute relative to the APP_DATA_PATH
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
;;
;; Directory to create temporary files in when testing public keys using ssh-keygen,
;; default is the system temporary directory.
;SSH_KEY_TEST_PATH =
;;
;; Use `ssh-keygen` to parse public SSH keys. The value is passed to the shell. By default, Gitea does the parsing itself.
;SSH_KEYGEN_PATH =
;;
;; Enable SSH Authorized Key Backup when rewriting all keys, default is false
;SSH_AUTHORIZED_KEYS_BACKUP = false
;;
@ -294,6 +287,9 @@ RUN_USER = ; git
;; Default path for App data
;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
;;
;; Base path for App's temp files, leave empty to use the managed tmp directory in APP_DATA_PATH
;APP_TEMP_PATH =
;;
;; Enable gzip compression for runtime-generated content, static resources excluded
;ENABLE_GZIP = false
;;
@ -1069,15 +1065,6 @@ LEVEL = Info
;; Separate extensions with a comma. To line wrap files without an extension, just put a comma
;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,.livemd,
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.local]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Path for local repository copy. Defaults to `tmp/local-repo` (content gets deleted on gitea restart)
;LOCAL_COPY_PATH = tmp/local-repo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.upload]
@ -1087,9 +1074,6 @@ LEVEL = Info
;; Whether repository file uploads are enabled. Defaults to `true`
;ENABLED = true
;;
;; Path for uploads. Defaults to `data/tmp/uploads` (content gets deleted on gitea restart)
;TEMP_PATH = data/tmp/uploads
;;
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
;ALLOWED_TYPES =
;;
@ -2473,7 +2457,7 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits)
;MERMAID_MAX_SOURCE_CHARACTERS = 5000
;MERMAID_MAX_SOURCE_CHARACTERS = 50000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2594,9 +2578,6 @@ LEVEL = Info
;; Currently, only `minio` and `azureblob` is supported.
;SERVE_DIRECT = false
;;
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
;CHUNKED_UPLOAD_PATH = tmp/package-upload
;;
;; Maximum count of package versions a single owner can have (`-1` means no limits)
;LIMIT_TOTAL_OWNER_COUNT = -1
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)

View File

@ -31,16 +31,19 @@ if [ -e /data/ssh/ssh_host_ecdsa_cert ]; then
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_cert"}
fi
if [ -e /data/ssh/ssh_host_ed25519-cert.pub ]; then
SSH_ED25519_CERT=${SSH_ED25519_CERT:-"/data/ssh/ssh_host_ed25519-cert.pub"}
# In case someone wants to sign the `{keyname}.pub` key by `ssh-keygen -s ca -I identity ...` to
# make use of the ssh-key certificate authority feature (see ssh-keygen CERTIFICATES section),
# the generated key file name is `{keyname}-cert.pub`
if [ -e /data/ssh/ssh_host_ed25519_key-cert.pub ]; then
SSH_ED25519_CERT=${SSH_ED25519_CERT:-"/data/ssh/ssh_host_ed25519_key-cert.pub"}
fi
if [ -e /data/ssh/ssh_host_rsa-cert.pub ]; then
SSH_RSA_CERT=${SSH_RSA_CERT:-"/data/ssh/ssh_host_rsa-cert.pub"}
if [ -e /data/ssh/ssh_host_rsa_key-cert.pub ]; then
SSH_RSA_CERT=${SSH_RSA_CERT:-"/data/ssh/ssh_host_rsa_key-cert.pub"}
fi
if [ -e /data/ssh/ssh_host_ecdsa-cert.pub ]; then
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa-cert.pub"}
if [ -e /data/ssh/ssh_host_ecdsa_key-cert.pub ]; then
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_key-cert.pub"}
fi
if [ -d /etc/ssh ]; then

View File

@ -240,3 +240,10 @@ func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err err
return committer.Commit()
}
func FindGPGKeyWithSubKeys(ctx context.Context, keyID string) ([]*GPGKey, error) {
return db.Find[GPGKey](ctx, FindGPGKeyOptions{
KeyID: keyID,
IncludeSubKeys: true,
})
}

View File

@ -6,27 +6,13 @@ package asymkey
import (
"context"
"fmt"
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"golang.org/x/crypto/ssh"
"xorm.io/builder"
)
// ___________.__ .__ __
// \_ _____/|__| ____ ____ ________________________|__| _____/ |_
// | __) | |/ \ / ___\_/ __ \_ __ \____ \_ __ \ |/ \ __\
// | \ | | | \/ /_/ > ___/| | \/ |_> > | \/ | | \ |
// \___ / |__|___| /\___ / \___ >__| | __/|__| |__|___| /__|
// \/ \//_____/ \/ |__| \/
//
// This file contains functions for fingerprinting SSH keys
//
// The database is used in checkKeyFingerprint however most of these functions probably belong in a module
// checkKeyFingerprint only checks if key fingerprint has been used as public key,
@ -41,29 +27,6 @@ func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
return nil
}
func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) {
// Calculate fingerprint.
tmpPath, err := writeTmpKeyFile(publicKeyContent)
if err != nil {
return "", err
}
defer func() {
if err := util.Remove(tmpPath); err != nil {
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpPath, err)
}
}()
stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
if err != nil {
if strings.Contains(stderr, "is not a public key file") {
return "", ErrKeyUnableVerify{stderr}
}
return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
} else if len(stdout) < 2 {
return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout)
}
return strings.Split(stdout, " ")[1], nil
}
func calcFingerprintNative(publicKeyContent string) (string, error) {
// Calculate fingerprint.
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent))
@ -75,15 +38,12 @@ func calcFingerprintNative(publicKeyContent string) (string, error) {
// CalcFingerprint calculate public key's fingerprint
func CalcFingerprint(publicKeyContent string) (string, error) {
// Call the method based on configuration
useNative := setting.SSH.KeygenPath == ""
calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen)
fp, err := calcFn(publicKeyContent)
fp, err := calcFingerprintNative(publicKeyContent)
if err != nil {
if IsErrKeyUnableVerify(err) {
return "", err
}
return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err)
return "", fmt.Errorf("CalcFingerprint: %w", err)
}
return fp, nil
}

View File

@ -13,12 +13,9 @@ import (
"errors"
"fmt"
"math/big"
"os"
"strconv"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@ -175,20 +172,9 @@ func CheckPublicKeyString(content string) (_ string, err error) {
return content, nil
}
var (
fnName string
keyType string
length int
)
if len(setting.SSH.KeygenPath) == 0 {
fnName = "SSHNativeParsePublicKey"
keyType, length, err = SSHNativeParsePublicKey(content)
} else {
fnName = "SSHKeyGenParsePublicKey"
keyType, length, err = SSHKeyGenParsePublicKey(content)
}
keyType, length, err := SSHNativeParsePublicKey(content)
if err != nil {
return "", fmt.Errorf("%s: %w", fnName, err)
return "", fmt.Errorf("SSHNativeParsePublicKey: %w", err)
}
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
@ -258,56 +244,3 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
}
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
}
// writeTmpKeyFile writes key content to a temporary file
// and returns the name of that file, along with any possible errors.
func writeTmpKeyFile(content string) (string, error) {
tmpFile, err := os.CreateTemp(setting.SSH.KeyTestPath, "gitea_keytest")
if err != nil {
return "", fmt.Errorf("TempFile: %w", err)
}
defer tmpFile.Close()
if _, err = tmpFile.WriteString(content); err != nil {
return "", fmt.Errorf("WriteString: %w", err)
}
return tmpFile.Name(), nil
}
// SSHKeyGenParsePublicKey extracts key type and length using ssh-keygen.
func SSHKeyGenParsePublicKey(key string) (string, int, error) {
tmpName, err := writeTmpKeyFile(key)
if err != nil {
return "", 0, fmt.Errorf("writeTmpKeyFile: %w", err)
}
defer func() {
if err := util.Remove(tmpName); err != nil {
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpName, err)
}
}()
keygenPath := setting.SSH.KeygenPath
if len(keygenPath) == 0 {
keygenPath = "ssh-keygen"
}
stdout, stderr, err := process.GetManager().Exec("SSHKeyGenParsePublicKey", keygenPath, "-lf", tmpName)
if err != nil {
return "", 0, fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
}
if strings.Contains(stdout, "is not a public key file") {
return "", 0, ErrKeyUnableVerify{stdout}
}
fields := strings.Split(stdout, " ")
if len(fields) < 4 {
return "", 0, fmt.Errorf("invalid public key line: %s", stdout)
}
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
length, err := strconv.ParseInt(fields[0], 10, 32)
if err != nil {
return "", 0, err
}
return strings.ToLower(keyType), int(length), nil
}

View File

@ -18,7 +18,6 @@ import (
"github.com/42wim/sshsig"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_SSHParsePublicKey(t *testing.T) {
@ -45,27 +44,6 @@ func Test_SSHParsePublicKey(t *testing.T) {
assert.Equal(t, tc.keyType, keyTypeN)
assert.Equal(t, tc.length, lengthN)
})
if tc.skipSSHKeygen {
return
}
t.Run("SSHKeygen", func(t *testing.T) {
keyTypeK, lengthK, err := SSHKeyGenParsePublicKey(tc.content)
if err != nil {
// Some servers do not support ecdsa format.
if !strings.Contains(err.Error(), "line 1 too long:") {
require.NoError(t, err)
}
}
assert.Equal(t, tc.keyType, keyTypeK)
assert.Equal(t, tc.length, lengthK)
})
t.Run("SSHParseKeyNative", func(t *testing.T) {
keyTypeK, lengthK, err := SSHNativeParsePublicKey(tc.content)
require.NoError(t, err)
assert.Equal(t, tc.keyType, keyTypeK)
assert.Equal(t, tc.length, lengthK)
})
})
}
}
@ -186,14 +164,6 @@ func Test_calcFingerprint(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, tc.fp, fpN)
})
if tc.skipSSHKeygen {
return
}
t.Run("SSHKeygen", func(t *testing.T) {
fpK, err := calcFingerprintSSHKeygen(tc.content)
assert.NoError(t, err)
assert.Equal(t, tc.fp, fpK)
})
})
}
}

View File

@ -235,6 +235,11 @@ func GetDeletedBranchByID(ctx context.Context, repoID, branchID int64) (*Branch,
return &branch, nil
}
func DeleteRepoBranches(ctx context.Context, repoID int64) error {
_, err := db.GetEngine(ctx).Where("repo_id=?", repoID).Delete(new(Branch))
return err
}
func DeleteBranches(ctx context.Context, repoID, doerID int64, branchIDs []int64) error {
return db.WithTx(ctx, func(ctx context.Context) error {
branches := make([]*Branch, 0, len(branchIDs))

View File

@ -11,7 +11,6 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
project_model "code.gitea.io/gitea/models/project"
repo_model "code.gitea.io/gitea/models/repo"
@ -612,7 +611,7 @@ func ResolveIssueMentionsByVisibility(ctx context.Context, issue *Issue, doer *u
unittype = unit.TypePullRequests
}
for _, team := range teams {
if team.AccessMode >= perm.AccessModeAdmin {
if team.HasAdminAccess() {
checked = append(checked, team.ID)
resolved[issue.Repo.Owner.LowerName+"/"+team.LowerName] = true
continue
@ -846,6 +845,7 @@ func DeleteOrphanedIssues(ctx context.Context) error {
// Remove issue attachment files.
for i := range attachmentPaths {
// FIXME: it's not right, because the attachment might not be on local filesystem
system_model.RemoveAllWithNotice(ctx, "Delete issue attachment", attachmentPaths[i])
}
return nil

View File

@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/tempdir"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/testlogger"
@ -114,15 +115,16 @@ func MainTest(m *testing.M) {
setting.CustomConf = giteaConf
}
tmpDataPath, err := os.MkdirTemp("", "data")
tmpDataPath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("data")
if err != nil {
testlogger.Fatalf("Unable to create temporary data path %v\n", err)
}
defer cleanup()
setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
setting.AppDataPath = tmpDataPath
unittest.InitSettings()
unittest.InitSettingsForTesting()
if err = git.InitFull(context.Background()); err != nil {
testlogger.Fatalf("Unable to InitFull: %v\n", err)
}
@ -134,8 +136,5 @@ func MainTest(m *testing.M) {
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
if err := removeAllWithRetry(tmpDataPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
os.Exit(exitStatus)
}

View File

@ -178,12 +178,6 @@ func (org *Organization) HomeLink() string {
return org.AsUser().HomeLink()
}
// CanCreateRepo returns if user login can create a repository
// NOTE: functions calling this assume a failure due to repository count limit; if new checks are added, those functions should be revised
func (org *Organization) CanCreateRepo() bool {
return org.AsUser().CanCreateRepo()
}
// FindOrgMembersOpts represensts find org members conditions
type FindOrgMembersOpts struct {
db.ListOptions

View File

@ -78,7 +78,7 @@ func IsOrganizationAdmin(ctx context.Context, orgID, uid int64) (bool, error) {
return false, err
}
for _, t := range teams {
if t.AccessMode >= perm.AccessModeAdmin {
if t.HasAdminAccess() {
return true, nil
}
}

View File

@ -113,7 +113,7 @@ func (t *Team) LoadUnits(ctx context.Context) (err error) {
// GetUnitNames returns the team units names
func (t *Team) GetUnitNames() (res []string) {
if t.AccessMode >= perm.AccessModeAdmin {
if t.HasAdminAccess() {
return unit.AllUnitKeyNames()
}
@ -126,7 +126,7 @@ func (t *Team) GetUnitNames() (res []string) {
// GetUnitsMap returns the team units permissions
func (t *Team) GetUnitsMap() map[string]string {
m := make(map[string]string)
if t.AccessMode >= perm.AccessModeAdmin {
if t.HasAdminAccess() {
for _, u := range unit.Units {
m[u.NameKey] = t.AccessMode.ToString()
}
@ -153,6 +153,10 @@ func (t *Team) IsMember(ctx context.Context, userID int64) bool {
return isMember
}
func (t *Team) HasAdminAccess() bool {
return t.AccessMode >= perm.AccessModeAdmin
}
// LoadMembers returns paginated members in team of organization.
func (t *Team) LoadMembers(ctx context.Context) (err error) {
t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
@ -238,22 +242,6 @@ func GetTeamByID(ctx context.Context, teamID int64) (*Team, error) {
return t, nil
}
// GetTeamNamesByID returns team's lower name from a list of team ids.
func GetTeamNamesByID(ctx context.Context, teamIDs []int64) ([]string, error) {
if len(teamIDs) == 0 {
return []string{}, nil
}
var teamNames []string
err := db.GetEngine(ctx).Table("team").
Select("lower_name").
In("id", teamIDs).
Asc("name").
Find(&teamNames)
return teamNames, err
}
// IncrTeamRepoNum increases the number of repos for the given team by 1
func IncrTeamRepoNum(ctx context.Context, teamID int64) error {
_, err := db.GetEngine(ctx).Incr("num_repos").ID(teamID).Update(new(Team))

View File

@ -331,7 +331,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
// if user in an owner team
for _, team := range teams {
if team.AccessMode >= perm_model.AccessModeAdmin {
if team.HasAdminAccess() {
perm.AccessMode = perm_model.AccessModeOwner
perm.unitsMode = nil
return perm, nil
@ -399,7 +399,7 @@ func IsUserRepoAdmin(ctx context.Context, repo *repo_model.Repository, user *use
}
for _, team := range teams {
if team.AccessMode >= perm_model.AccessModeAdmin {
if team.HasAdminAccess() {
return true, nil
}
}

View File

@ -558,3 +558,8 @@ func FindTagsByCommitIDs(ctx context.Context, repoID int64, commitIDs ...string)
}
return res, nil
}
func DeleteRepoReleases(ctx context.Context, repoID int64) error {
_, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Delete(new(Release))
return err
}

View File

@ -111,31 +111,31 @@ func (err ErrRepoFilesAlreadyExist) Unwrap() error {
return util.ErrAlreadyExist
}
// CheckCreateRepository check if could created a repository
func CheckCreateRepository(ctx context.Context, doer, u *user_model.User, name string, overwriteOrAdopt bool) error {
if !doer.CanCreateRepo() {
return ErrReachLimitOfRepo{u.MaxRepoCreation}
// CheckCreateRepository check if doer could create a repository in new owner
func CheckCreateRepository(ctx context.Context, doer, owner *user_model.User, name string, overwriteOrAdopt bool) error {
if !doer.CanCreateRepoIn(owner) {
return ErrReachLimitOfRepo{owner.MaxRepoCreation}
}
if err := IsUsableRepoName(name); err != nil {
return err
}
has, err := IsRepositoryModelOrDirExist(ctx, u, name)
has, err := IsRepositoryModelOrDirExist(ctx, owner, name)
if err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return ErrRepoAlreadyExist{u.Name, name}
return ErrRepoAlreadyExist{owner.Name, name}
}
repoPath := RepoPath(u.Name, name)
repoPath := RepoPath(owner.Name, name)
isExist, err := util.IsExist(repoPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
return err
}
if !overwriteOrAdopt && isExist {
return ErrRepoFilesAlreadyExist{u.Name, name}
return ErrRepoFilesAlreadyExist{owner.Name, name}
}
return nil
}

View File

@ -51,14 +51,10 @@ func init() {
db.RegisterModel(new(Upload))
}
// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
func UploadLocalPath(uuid string) string {
return filepath.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
}
// LocalPath returns where uploads are temporarily stored in local file system.
// LocalPath returns where uploads are temporarily stored in local file system based on given UUID.
func (upload *Upload) LocalPath() string {
return UploadLocalPath(upload.UUID)
uuid := upload.UUID
return setting.AppDataTempDir("repo-uploads").JoinPath(uuid[0:1], uuid[1:2], uuid)
}
// NewUpload creates a new upload object.

View File

@ -20,17 +20,21 @@ type Type int
// Enumerate all the unit types
const (
TypeInvalid Type = iota // 0 invalid
TypeCode // 1 code
TypeIssues // 2 issues
TypePullRequests // 3 PRs
TypeReleases // 4 Releases
TypeWiki // 5 Wiki
TypeExternalWiki // 6 ExternalWiki
TypeExternalTracker // 7 ExternalTracker
TypeProjects // 8 Projects
TypePackages // 9 Packages
TypeActions // 10 Actions
TypeInvalid Type = iota // 0 invalid
TypeCode // 1 code
TypeIssues // 2 issues
TypePullRequests // 3 PRs
TypeReleases // 4 Releases
TypeWiki // 5 Wiki
TypeExternalWiki // 6 ExternalWiki
TypeExternalTracker // 7 ExternalTracker
TypeProjects // 8 Projects
TypePackages // 9 Packages
TypeActions // 10 Actions
// FIXME: TEAM-UNIT-PERMISSION: the team unit "admin" permission's design is not right, when a new unit is added in the future,
// admin team won't inherit the correct admin permission for the new unit, need to have a complete fix before adding any new unit.
)
// Value returns integer value for unit type (used by template)
@ -380,20 +384,3 @@ func AllUnitKeyNames() []string {
}
return res
}
// MinUnitAccessMode returns the minial permission of the permission map
func MinUnitAccessMode(unitsMap map[Type]perm.AccessMode) perm.AccessMode {
res := perm.AccessModeNone
for t, mode := range unitsMap {
// Don't allow `TypeExternal{Tracker,Wiki}` to influence this as they can only be set to READ perms.
if t == TypeExternalTracker || t == TypeExternalWiki {
continue
}
// get the minial permission great than AccessModeNone except all are AccessModeNone
if mode > perm.AccessModeNone && (res == perm.AccessModeNone || mode < res) {
res = mode
}
}
return res
}

View File

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/tempdir"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/util"
@ -35,8 +36,8 @@ func fatalTestError(fmtStr string, args ...any) {
os.Exit(1)
}
// InitSettings initializes config provider and load common settings for tests
func InitSettings() {
// InitSettingsForTesting initializes config provider and load common settings for tests
func InitSettingsForTesting() {
setting.IsInTesting = true
log.OsExiter = func(code int) {
if code != 0 {
@ -75,7 +76,7 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
testOpts := util.OptionalArg(testOptsArg, &TestOptions{})
giteaRoot = test.SetupGiteaRoot()
setting.CustomPath = filepath.Join(giteaRoot, "custom")
InitSettings()
InitSettingsForTesting()
fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles}
if err := CreateTestEngine(fixturesOpts); err != nil {
@ -92,15 +93,19 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
setting.SSH.Domain = "try.gitea.io"
setting.Database.Type = "sqlite3"
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
repoRootPath, err := os.MkdirTemp(os.TempDir(), "repos")
repoRootPath, cleanup1, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("repos")
if err != nil {
fatalTestError("TempDir: %v\n", err)
}
defer cleanup1()
setting.RepoRootPath = repoRootPath
appDataPath, err := os.MkdirTemp(os.TempDir(), "appdata")
appDataPath, cleanup2, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("appdata")
if err != nil {
fatalTestError("TempDir: %v\n", err)
}
defer cleanup2()
setting.AppDataPath = appDataPath
setting.AppWorkPath = giteaRoot
setting.StaticRootPath = giteaRoot
@ -153,13 +158,6 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
fatalTestError("tear down failed: %v\n", err)
}
}
if err = util.RemoveAll(repoRootPath); err != nil {
fatalTestError("util.RemoveAll: %v\n", err)
}
if err = util.RemoveAll(appDataPath); err != nil {
fatalTestError("util.RemoveAll: %v\n", err)
}
os.Exit(exitStatus)
}

View File

@ -247,19 +247,20 @@ func (u *User) MaxCreationLimit() int {
return u.MaxRepoCreation
}
// CanCreateRepo returns if user login can create a repository
// NOTE: functions calling this assume a failure due to repository count limit; if new checks are added, those functions should be revised
func (u *User) CanCreateRepo() bool {
// CanCreateRepoIn checks whether the doer(u) can create a repository in the owner
// NOTE: functions calling this assume a failure due to repository count limit; it ONLY checks the repo number LIMIT, if new checks are added, those functions should be revised
func (u *User) CanCreateRepoIn(owner *User) bool {
if u.IsAdmin {
return true
}
if u.MaxRepoCreation <= -1 {
if setting.Repository.MaxCreationLimit <= -1 {
const noLimit = -1
if owner.MaxRepoCreation == noLimit {
if setting.Repository.MaxCreationLimit == noLimit {
return true
}
return u.NumRepos < setting.Repository.MaxCreationLimit
return owner.NumRepos < setting.Repository.MaxCreationLimit
}
return u.NumRepos < u.MaxRepoCreation
return owner.NumRepos < owner.MaxRepoCreation
}
// CanCreateOrganization returns true if user can create organisation.
@ -272,13 +273,12 @@ func (u *User) CanEditGitHook() bool {
return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
}
// CanForkRepo returns if user login can fork a repository
// It checks especially that the user can create repos, and potentially more
func (u *User) CanForkRepo() bool {
// CanForkRepoIn ONLY checks repository count limit
func (u *User) CanForkRepoIn(owner *User) bool {
if setting.Repository.AllowForkWithoutMaximumLimit {
return true
}
return u.CanCreateRepo()
return u.CanCreateRepoIn(owner)
}
// CanImportLocal returns true if user can migrate repository by local path.
@ -1187,29 +1187,28 @@ func GetUsersByEmails(ctx context.Context, emails []string) (map[string]*User, e
for _, email := range emailAddresses {
userIDs.Add(email.UID)
}
users, err := GetUsersMapByIDs(ctx, userIDs.Values())
if err != nil {
return nil, err
}
results := make(map[string]*User, len(emails))
for _, email := range emailAddresses {
user := users[email.UID]
if user != nil {
if user.KeepEmailPrivate {
results[user.LowerName+"@"+setting.Service.NoReplyAddress] = user
} else {
results[email.Email] = user
if len(userIDs) > 0 {
users, err := GetUsersMapByIDs(ctx, userIDs.Values())
if err != nil {
return nil, err
}
for _, email := range emailAddresses {
user := users[email.UID]
if user != nil {
results[user.GetEmail()] = user
}
}
}
users = make(map[int64]*User, len(needCheckUserNames))
users := make(map[int64]*User, len(needCheckUserNames))
if err := db.GetEngine(ctx).In("lower_name", needCheckUserNames.Values()).Find(&users); err != nil {
return nil, err
}
for _, user := range users {
results[user.LowerName+"@"+setting.Service.NoReplyAddress] = user
results[user.GetPlaceholderEmail()] = user
}
return results, nil
}

View File

@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/timeutil"
"github.com/stretchr/testify/assert"
@ -616,3 +617,37 @@ func TestGetInactiveUsers(t *testing.T) {
assert.NoError(t, err)
assert.Empty(t, users)
}
func TestCanCreateRepo(t *testing.T) {
defer test.MockVariableValue(&setting.Repository.MaxCreationLimit)()
const noLimit = -1
doerNormal := &user_model.User{}
doerAdmin := &user_model.User{IsAdmin: true}
t.Run("NoGlobalLimit", func(t *testing.T) {
setting.Repository.MaxCreationLimit = noLimit
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
})
t.Run("GlobalLimit50", func(t *testing.T) {
setting.Repository.MaxCreationLimit = 50
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: noLimit})) // limited by global limit
assert.False(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
assert.True(t, doerNormal.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: 100}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: noLimit}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: noLimit}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 0}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 10, MaxRepoCreation: 100}))
assert.True(t, doerAdmin.CanCreateRepoIn(&user_model.User{NumRepos: 60, MaxRepoCreation: 100}))
})
}

View File

@ -166,15 +166,15 @@ func RemoveContextData(ctx context.Context, tp, key any) {
}
// GetWithContextCache returns the cache value of the given key in the given context.
func GetWithContextCache[T any](ctx context.Context, cacheGroupKey string, cacheTargetID any, f func() (T, error)) (T, error) {
v := GetContextData(ctx, cacheGroupKey, cacheTargetID)
func GetWithContextCache[T, K any](ctx context.Context, groupKey string, targetKey K, f func(context.Context, K) (T, error)) (T, error) {
v := GetContextData(ctx, groupKey, targetKey)
if vv, ok := v.(T); ok {
return vv, nil
}
t, err := f()
t, err := f(ctx, targetKey)
if err != nil {
return t, err
}
SetContextData(ctx, cacheGroupKey, cacheTargetID, t)
SetContextData(ctx, groupKey, targetKey, t)
return t, nil
}

View File

@ -4,6 +4,7 @@
package cache
import (
"context"
"testing"
"time"
@ -30,7 +31,7 @@ func TestWithCacheContext(t *testing.T) {
v = GetContextData(ctx, field, "my_config1")
assert.Nil(t, v)
vInt, err := GetWithContextCache(ctx, field, "my_config1", func() (int, error) {
vInt, err := GetWithContextCache(ctx, field, "my_config1", func(context.Context, string) (int, error) {
return 1, nil
})
assert.NoError(t, err)

View File

@ -0,0 +1,12 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cachegroup
const (
User = "user"
EmailAvatarLink = "email_avatar_link"
UserEmailAddresses = "user_email_addresses"
GPGKeyWithSubKeys = "gpg_key_with_subkeys"
RepoUserPermission = "repo_user_permission"
)

View File

@ -11,7 +11,7 @@ import (
"os"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/setting"
)
// BlamePart represents block of blame - continuous lines with one sha
@ -29,12 +29,13 @@ type BlameReader struct {
bufferedReader *bufio.Reader
done chan error
lastSha *string
ignoreRevsFile *string
ignoreRevsFile string
objectFormat ObjectFormat
cleanupFuncs []func()
}
func (r *BlameReader) UsesIgnoreRevs() bool {
return r.ignoreRevsFile != nil
return r.ignoreRevsFile != ""
}
// NextPart returns next part of blame (sequential code lines with the same commit)
@ -122,36 +123,37 @@ func (r *BlameReader) Close() error {
r.bufferedReader = nil
_ = r.reader.Close()
_ = r.output.Close()
if r.ignoreRevsFile != nil {
_ = util.Remove(*r.ignoreRevsFile)
for _, cleanup := range r.cleanupFuncs {
if cleanup != nil {
cleanup()
}
}
return err
}
// CreateBlameReader creates reader for given repository, commit and file
func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
var ignoreRevsFile *string
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit)
}
cmd := NewCommandNoGlobals("blame", "--porcelain")
if ignoreRevsFile != nil {
// Possible improvement: use --ignore-revs-file /dev/stdin on unix
// There is no equivalent on Windows. May be implemented if Gitea uses an external git backend.
cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile)
}
cmd.AddDynamicArguments(commit.ID.String()).AddDashesAndList(file)
reader, stdout, err := os.Pipe()
if err != nil {
if ignoreRevsFile != nil {
_ = util.Remove(*ignoreRevsFile)
}
return nil, err
}
done := make(chan error, 1)
cmd := NewCommandNoGlobals("blame", "--porcelain")
var ignoreRevsFileName string
var ignoreRevsFileCleanup func() // TODO: maybe it should check the returned err in a defer func to make sure the cleanup could always be executed correctly
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
ignoreRevsFileName, ignoreRevsFileCleanup = tryCreateBlameIgnoreRevsFile(commit)
if ignoreRevsFileName != "" {
// Possible improvement: use --ignore-revs-file /dev/stdin on unix
// There is no equivalent on Windows. May be implemented if Gitea uses an external git backend.
cmd.AddOptionValues("--ignore-revs-file", ignoreRevsFileName)
}
}
cmd.AddDynamicArguments(commit.ID.String()).AddDashesAndList(file)
done := make(chan error, 1)
go func() {
stderr := bytes.Buffer{}
// TODO: it doesn't work for directories (the directories shouldn't be "blamed"), and the "err" should be returned by "Read" but not by "Close"
@ -169,40 +171,44 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
}()
bufferedReader := bufio.NewReader(reader)
return &BlameReader{
output: stdout,
reader: reader,
bufferedReader: bufferedReader,
done: done,
ignoreRevsFile: ignoreRevsFile,
ignoreRevsFile: ignoreRevsFileName,
objectFormat: objectFormat,
cleanupFuncs: []func(){ignoreRevsFileCleanup},
}, nil
}
func tryCreateBlameIgnoreRevsFile(commit *Commit) *string {
func tryCreateBlameIgnoreRevsFile(commit *Commit) (string, func()) {
entry, err := commit.GetTreeEntryByPath(".git-blame-ignore-revs")
if err != nil {
return nil
log.Error("Unable to get .git-blame-ignore-revs file: GetTreeEntryByPath: %v", err)
return "", nil
}
r, err := entry.Blob().DataAsync()
if err != nil {
return nil
log.Error("Unable to get .git-blame-ignore-revs file data: DataAsync: %v", err)
return "", nil
}
defer r.Close()
f, err := os.CreateTemp("", "gitea_git-blame-ignore-revs")
f, cleanup, err := setting.AppDataTempDir("git-repo-content").CreateTempFileRandom("git-blame-ignore-revs")
if err != nil {
return nil
log.Error("Unable to get .git-blame-ignore-revs file data: CreateTempFileRandom: %v", err)
return "", nil
}
filename := f.Name()
_, err = io.Copy(f, r)
_ = f.Close()
if err != nil {
_ = util.Remove(f.Name())
return nil
cleanup()
log.Error("Unable to get .git-blame-ignore-revs file data: Copy: %v", err)
return "", nil
}
return util.ToPointer(f.Name())
return filename, cleanup
}

View File

@ -7,10 +7,13 @@ import (
"context"
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestReadingBlameOutputSha256(t *testing.T) {
setting.AppDataPath = t.TempDir()
ctx, cancel := context.WithCancel(t.Context())
defer cancel()

View File

@ -7,10 +7,13 @@ import (
"context"
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestReadingBlameOutput(t *testing.T) {
setting.AppDataPath = t.TempDir()
ctx, cancel := context.WithCancel(t.Context())
defer cancel()

View File

@ -10,18 +10,19 @@ import (
"testing"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/tempdir"
"github.com/hashicorp/go-version"
"github.com/stretchr/testify/assert"
)
func testRun(m *testing.M) error {
gitHomePath, err := os.MkdirTemp(os.TempDir(), "git-home")
gitHomePath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("git-home")
if err != nil {
return fmt.Errorf("unable to create temp dir: %w", err)
}
defer util.RemoveAll(gitHomePath)
defer cleanup()
setting.Git.HomePath = gitHomePath
if err = InitFull(context.Background()); err != nil {

View File

@ -18,6 +18,7 @@ import (
"time"
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/setting"
)
// GPGSettings represents the default GPG settings for this repository
@ -266,11 +267,11 @@ func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch
// CreateBundle create bundle content to the target path
func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.Writer) error {
tmp, err := os.MkdirTemp(os.TempDir(), "gitea-bundle")
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
if err != nil {
return err
}
defer os.RemoveAll(tmp)
defer cleanup()
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
_, _, err = NewCommand("init", "--bare").RunStdString(ctx, &RunOpts{Dir: tmp, Env: env})

View File

@ -10,8 +10,7 @@ import (
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/setting"
)
// ReadTreeToIndex reads a treeish to the index
@ -59,26 +58,18 @@ func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (tmpIndexFilena
}
}()
removeDirFn := func(dir string) func() { // it can't use the return value "tmpDir" directly because it is empty when error occurs
return func() {
if err := util.RemoveAll(dir); err != nil {
log.Error("failed to remove tmp index dir: %v", err)
}
}
}
tmpDir, err = os.MkdirTemp("", "index")
tmpDir, cancel, err = setting.AppDataTempDir("git-repo-content").MkdirTempRandom("index")
if err != nil {
return "", "", nil, err
}
tmpIndexFilename = filepath.Join(tmpDir, ".tmp-index")
cancel = removeDirFn(tmpDir)
err = repo.ReadTreeToIndex(treeish, tmpIndexFilename)
if err != nil {
return "", "", cancel, err
}
return tmpIndexFilename, tmpDir, cancel, err
return tmpIndexFilename, tmpDir, cancel, nil
}
// EmptyIndex empties the index

View File

@ -9,11 +9,14 @@ import (
"path/filepath"
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRepository_GetLanguageStats(t *testing.T) {
setting.AppDataPath = t.TempDir()
repoPath := filepath.Join(testReposDir, "language_stats_repo")
gitRepo, err := openRepositoryWithDefaultContext(repoPath)
require.NoError(t, err)

View File

@ -12,11 +12,9 @@ import (
"runtime"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)
// RegisterRenderers registers all supported third part renderers according settings
@ -88,16 +86,11 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.
if p.IsInputFile {
// write to temp file
f, err := os.CreateTemp("", "gitea_input")
f, cleanup, err := setting.AppDataTempDir("git-repo-content").CreateTempFileRandom("gitea_input")
if err != nil {
return fmt.Errorf("%s create temp file when rendering %s failed: %w", p.Name(), p.Command, err)
}
tmpPath := f.Name()
defer func() {
if err := util.Remove(tmpPath); err != nil {
log.Warn("Unable to remove temporary file: %s: Error: %v", tmpPath, err)
}
}()
defer cleanup()
_, err = io.Copy(f, input)
if err != nil {

View File

@ -6,6 +6,7 @@ package packages
import (
"io"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util/filebuffer"
)
@ -34,11 +35,11 @@ func NewHashedBuffer() (*HashedBuffer, error) {
// NewHashedBufferWithSize creates a hashed buffer with a specific memory size
func NewHashedBufferWithSize(maxMemorySize int) (*HashedBuffer, error) {
b, err := filebuffer.New(maxMemorySize)
tempDir, err := setting.AppDataTempDir("package-hashed-buffer").MkdirAllSub("")
if err != nil {
return nil, err
}
b := filebuffer.New(maxMemorySize, tempDir)
hash := NewMultiHasher()
combinedWriter := io.MultiWriter(b, hash)

View File

@ -9,10 +9,13 @@ import (
"strings"
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestHashedBuffer(t *testing.T) {
setting.AppDataPath = t.TempDir()
cases := []struct {
MaxMemorySize int
Data string

View File

@ -9,6 +9,8 @@ import (
"encoding/base64"
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
@ -17,6 +19,7 @@ fgAA3AEAAAQAAAAjU3RyaW5ncwAAAADgAQAABAAAACNVUwDkAQAAMAAAACNHVUlEAAAAFAIAACgB
AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`
func TestExtractPortablePdb(t *testing.T) {
setting.AppDataPath = t.TempDir()
createArchive := func(name string, content []byte) []byte {
var buf bytes.Buffer
archive := zip.NewWriter(&buf)

View File

@ -13,6 +13,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/cachegroup"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -131,7 +132,7 @@ func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repo *repo_model
func (pc *PushCommits) AvatarLink(ctx context.Context, email string) string {
size := avatars.DefaultAvatarPixelSize * setting.Avatar.RenderedSizeFactor
v, _ := cache.GetWithContextCache(ctx, "push_commits", email, func() (string, error) {
v, _ := cache.GetWithContextCache(ctx, cachegroup.EmailAvatarLink, email, func(ctx context.Context, email string) (string, error) {
u, err := user_model.GetUserByEmail(ctx, email)
if err != nil {
if !user_model.IsErrUserNotExist(err) {

View File

@ -11,11 +11,7 @@ import (
"strings"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/label"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/options"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@ -121,29 +117,6 @@ func LoadRepoConfig() error {
return nil
}
func CheckInitRepository(ctx context.Context, repo *repo_model.Repository) (err error) {
// Somehow the directory could exist.
isExist, err := gitrepo.IsRepositoryExist(ctx, repo)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repo.FullName(), err)
return err
}
if isExist {
return repo_model.ErrRepoFilesAlreadyExist{
Uname: repo.OwnerName,
Name: repo.Name,
}
}
// Init git bare new repository.
if err = git.InitRepository(ctx, repo.RepoPath(), true, repo.ObjectFormatName); err != nil {
return fmt.Errorf("git.InitRepository: %w", err)
} else if err = gitrepo.CreateDelegateHooks(ctx, repo); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err)
}
return nil
}
// InitializeLabels adds a label set to a repository using a template
func InitializeLabels(ctx context.Context, id int64, labelTemplate string, isOrg bool) error {
list, err := LoadTemplateLabelsByDisplayName(labelTemplate)

View File

@ -4,41 +4,19 @@
package repository
import (
"context"
"fmt"
"os"
"path/filepath"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)
// LocalCopyPath returns the local repository temporary copy path.
func LocalCopyPath() string {
if filepath.IsAbs(setting.Repository.Local.LocalCopyPath) {
return setting.Repository.Local.LocalCopyPath
}
return filepath.Join(setting.AppDataPath, setting.Repository.Local.LocalCopyPath)
}
// CreateTemporaryPath creates a temporary path
func CreateTemporaryPath(prefix string) (string, error) {
if err := os.MkdirAll(LocalCopyPath(), os.ModePerm); err != nil {
log.Error("Unable to create localcopypath directory: %s (%v)", LocalCopyPath(), err)
return "", fmt.Errorf("Failed to create localcopypath directory %s: %w", LocalCopyPath(), err)
}
basePath, err := os.MkdirTemp(LocalCopyPath(), prefix+".git")
func CreateTemporaryPath(prefix string) (string, context.CancelFunc, error) {
basePath, cleanup, err := setting.AppDataTempDir("local-repo").MkdirTempRandom(prefix + ".git")
if err != nil {
log.Error("Unable to create temporary directory: %s-*.git (%v)", prefix, err)
return "", fmt.Errorf("Failed to create dir %s-*.git: %w", prefix, err)
return "", nil, fmt.Errorf("failed to create dir %s-*.git: %w", prefix, err)
}
return basePath, nil
}
// RemoveTemporaryPath removes the temporary path
func RemoveTemporaryPath(basePath string) error {
if _, err := os.Stat(basePath); !os.IsNotExist(err) {
return util.RemoveAll(basePath)
}
return nil
return basePath, cleanup, nil
}

View File

@ -127,7 +127,7 @@ func loadMarkupFrom(rootCfg ConfigProvider) {
}
}
MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000)
MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(50000)
ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10)
ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, 10)

View File

@ -6,8 +6,6 @@ package setting
import (
"fmt"
"math"
"os"
"path/filepath"
"github.com/dustin/go-humanize"
)
@ -67,14 +65,10 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) {
return err
}
Packages.ChunkedUploadPath = filepath.ToSlash(sec.Key("CHUNKED_UPLOAD_PATH").MustString("tmp/package-upload"))
if !filepath.IsAbs(Packages.ChunkedUploadPath) {
Packages.ChunkedUploadPath = filepath.ToSlash(filepath.Join(AppDataPath, Packages.ChunkedUploadPath))
}
if HasInstallLock(rootCfg) {
if err := os.MkdirAll(Packages.ChunkedUploadPath, os.ModePerm); err != nil {
return fmt.Errorf("unable to create chunked upload directory: %s (%v)", Packages.ChunkedUploadPath, err)
Packages.ChunkedUploadPath, err = AppDataTempDir("package-upload").MkdirAllSub("")
if err != nil {
return fmt.Errorf("unable to create chunked upload directory: %w", err)
}
}

View File

@ -11,6 +11,7 @@ import (
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/tempdir"
)
var (
@ -196,3 +197,18 @@ func InitWorkPathAndCfgProvider(getEnvFn func(name string) string, args ArgWorkP
CustomPath = tmpCustomPath.Value
CustomConf = tmpCustomConf.Value
}
// AppDataTempDir returns a managed temporary directory for the application data.
// Using empty sub will get the managed base temp directory, and it's safe to delete it.
// Gitea only creates subdirectories under it, but not the APP_TEMP_PATH directory itself.
// * When APP_TEMP_PATH="/tmp": the managed temp directory is "/tmp/gitea-tmp"
// * When APP_TEMP_PATH is not set: the managed temp directory is "/{APP_DATA_PATH}/tmp"
func AppDataTempDir(sub string) *tempdir.TempDir {
if appTempPathInternal != "" {
return tempdir.New(appTempPathInternal, "gitea-tmp/"+sub)
}
if AppDataPath == "" {
panic("setting.AppDataPath is not set")
}
return tempdir.New(AppDataPath, "tmp/"+sub)
}

View File

@ -62,17 +62,11 @@ var (
// Repository upload settings
Upload struct {
Enabled bool
TempPath string
AllowedTypes string
FileMaxSize int64
MaxFiles int
} `ini:"-"`
// Repository local settings
Local struct {
LocalCopyPath string
} `ini:"-"`
// Pull request settings
PullRequest struct {
WorkInProgressPrefixes []string
@ -181,25 +175,16 @@ var (
// Repository upload settings
Upload: struct {
Enabled bool
TempPath string
AllowedTypes string
FileMaxSize int64
MaxFiles int
}{
Enabled: true,
TempPath: "data/tmp/uploads",
AllowedTypes: "",
FileMaxSize: 50,
MaxFiles: 5,
},
// Repository local settings
Local: struct {
LocalCopyPath string
}{
LocalCopyPath: "tmp/local-repo",
},
// Pull request settings
PullRequest: struct {
WorkInProgressPrefixes []string
@ -308,8 +293,6 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
log.Fatal("Failed to map Repository.Editor settings: %v", err)
} else if err = rootCfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
log.Fatal("Failed to map Repository.Upload settings: %v", err)
} else if err = rootCfg.Section("repository.local").MapTo(&Repository.Local); err != nil {
log.Fatal("Failed to map Repository.Local settings: %v", err)
} else if err = rootCfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
}
@ -361,10 +344,6 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
}
}
if !filepath.IsAbs(Repository.Upload.TempPath) {
Repository.Upload.TempPath = filepath.Join(AppWorkPath, Repository.Upload.TempPath)
}
if err := loadRepoArchiveFrom(rootCfg); err != nil {
log.Fatal("loadRepoArchiveFrom: %v", err)
}

View File

@ -7,6 +7,7 @@ import (
"encoding/base64"
"net"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
@ -59,6 +60,8 @@ var (
// AssetVersion holds a opaque value that is used for cache-busting assets
AssetVersion string
appTempPathInternal string // the temporary path for the app, it is only an internal variable, do not use it, always use AppDataTempDir
Protocol Scheme
UseProxyProtocol bool // `ini:"USE_PROXY_PROTOCOL"`
ProxyProtocolTLSBridging bool //`ini:"PROXY_PROTOCOL_TLS_BRIDGING"`
@ -330,6 +333,19 @@ func loadServerFrom(rootCfg ConfigProvider) {
if !filepath.IsAbs(AppDataPath) {
AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath))
}
if IsInTesting && HasInstallLock(rootCfg) {
// FIXME: in testing, the "app data" directory is not correctly initialized before loading settings
if _, err := os.Stat(AppDataPath); err != nil {
_ = os.MkdirAll(AppDataPath, os.ModePerm)
}
}
appTempPathInternal = sec.Key("APP_TEMP_PATH").String()
if appTempPathInternal != "" {
if _, err := os.Stat(appTempPathInternal); err != nil {
log.Fatal("APP_TEMP_PATH %q is not accessible: %v", appTempPathInternal, err)
}
}
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false)

View File

@ -4,7 +4,6 @@
package setting
import (
"os"
"path/filepath"
"strings"
"text/template"
@ -31,8 +30,6 @@ var SSH = struct {
ServerKeyExchanges []string `ini:"SSH_SERVER_KEY_EXCHANGES"`
ServerMACs []string `ini:"SSH_SERVER_MACS"`
ServerHostKeys []string `ini:"SSH_SERVER_HOST_KEYS"`
KeyTestPath string `ini:"SSH_KEY_TEST_PATH"`
KeygenPath string `ini:"SSH_KEYGEN_PATH"`
AuthorizedKeysBackup bool `ini:"SSH_AUTHORIZED_KEYS_BACKUP"`
AuthorizedPrincipalsBackup bool `ini:"SSH_AUTHORIZED_PRINCIPALS_BACKUP"`
AuthorizedKeysCommandTemplate string `ini:"SSH_AUTHORIZED_KEYS_COMMAND_TEMPLATE"`
@ -57,7 +54,6 @@ var SSH = struct {
ServerCiphers: []string{"chacha20-poly1305@openssh.com", "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com"},
ServerKeyExchanges: []string{"curve25519-sha256", "ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"},
ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"},
KeygenPath: "",
MinimumKeySizeCheck: true,
MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 3071},
ServerHostKeys: []string{"ssh/gitea.rsa", "ssh/gogs.rsa"},
@ -123,7 +119,6 @@ func loadSSHFrom(rootCfg ConfigProvider) {
if len(serverMACs) > 0 {
SSH.ServerMACs = serverMACs
}
SSH.KeyTestPath = os.TempDir()
if err = sec.MapTo(&SSH); err != nil {
log.Fatal("Failed to map SSH settings: %v", err)
}
@ -133,7 +128,6 @@ func loadSSHFrom(rootCfg ConfigProvider) {
}
}
SSH.KeygenPath = sec.Key("SSH_KEYGEN_PATH").String()
SSH.Port = sec.Key("SSH_PORT").MustInt(22)
SSH.ListenPort = sec.Key("SSH_LISTEN_PORT").MustInt(SSH.Port)
SSH.UseProxyProtocol = sec.Key("SSH_SERVER_USE_PROXY_PROTOCOL").MustBool(false)

View File

@ -32,11 +32,6 @@ func Init() error {
builtinUnused()
// FIXME: why 0o644 for a directory .....
if err := os.MkdirAll(setting.SSH.KeyTestPath, 0o644); err != nil {
return fmt.Errorf("failed to create directory %q for ssh key test: %w", setting.SSH.KeyTestPath, err)
}
if len(setting.SSH.TrustedUserCAKeys) > 0 && setting.SSH.AuthorizedPrincipalsEnabled {
caKeysFileName := setting.SSH.TrustedUserCAKeysFile
caKeysFileDir := filepath.Dir(caKeysFileName)

112
modules/tempdir/tempdir.go Normal file
View File

@ -0,0 +1,112 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package tempdir
import (
"os"
"path/filepath"
"time"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
type TempDir struct {
// base is the base directory for temporary files, it must exist before accessing and won't be created automatically.
// for example: base="/system-tmpdir", sub="gitea-tmp"
base, sub string
}
func (td *TempDir) JoinPath(elems ...string) string {
return filepath.Join(append([]string{td.base, td.sub}, elems...)...)
}
// MkdirAllSub works like os.MkdirAll, but the base directory must exist
func (td *TempDir) MkdirAllSub(dir string) (string, error) {
if _, err := os.Stat(td.base); err != nil {
return "", err
}
full := filepath.Join(td.base, td.sub, dir)
if err := os.MkdirAll(full, os.ModePerm); err != nil {
return "", err
}
return full, nil
}
func (td *TempDir) prepareDirWithPattern(elems ...string) (dir, pattern string, err error) {
if _, err = os.Stat(td.base); err != nil {
return "", "", err
}
dir, pattern = filepath.Split(filepath.Join(append([]string{td.base, td.sub}, elems...)...))
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return "", "", err
}
return dir, pattern, nil
}
// MkdirTempRandom works like os.MkdirTemp, the last path field is the "pattern"
func (td *TempDir) MkdirTempRandom(elems ...string) (string, func(), error) {
dir, pattern, err := td.prepareDirWithPattern(elems...)
if err != nil {
return "", nil, err
}
dir, err = os.MkdirTemp(dir, pattern)
if err != nil {
return "", nil, err
}
return dir, func() {
if err := util.RemoveAll(dir); err != nil {
log.Error("Failed to remove temp directory %s: %v", dir, err)
}
}, nil
}
// CreateTempFileRandom works like os.CreateTemp, the last path field is the "pattern"
func (td *TempDir) CreateTempFileRandom(elems ...string) (*os.File, func(), error) {
dir, pattern, err := td.prepareDirWithPattern(elems...)
if err != nil {
return nil, nil, err
}
f, err := os.CreateTemp(dir, pattern)
if err != nil {
return nil, nil, err
}
filename := f.Name()
return f, func() {
_ = f.Close()
if err := util.Remove(filename); err != nil {
log.Error("Unable to remove temporary file: %s: Error: %v", filename, err)
}
}, err
}
func (td *TempDir) RemoveOutdated(d time.Duration) {
var remove func(path string)
remove = func(path string) {
entries, _ := os.ReadDir(path)
for _, entry := range entries {
full := filepath.Join(path, entry.Name())
if entry.IsDir() {
remove(full)
_ = os.Remove(full)
continue
}
info, err := entry.Info()
if err == nil && time.Since(info.ModTime()) > d {
_ = os.Remove(full)
}
}
}
remove(td.JoinPath(""))
}
// New create a new TempDir instance, "base" must be an existing directory,
// "sub" could be a multi-level directory and will be created if not exist
func New(base, sub string) *TempDir {
return &TempDir{base: base, sub: sub}
}
func OsTempDir(sub string) *TempDir {
return New(os.TempDir(), sub)
}

View File

@ -0,0 +1,75 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package tempdir
import (
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestTempDir(t *testing.T) {
base := t.TempDir()
t.Run("Create", func(t *testing.T) {
td := New(base, "sub1/sub2") // make sure the sub dir supports "/" in the path
assert.Equal(t, filepath.Join(base, "sub1", "sub2"), td.JoinPath())
assert.Equal(t, filepath.Join(base, "sub1", "sub2/test"), td.JoinPath("test"))
t.Run("MkdirTempRandom", func(t *testing.T) {
s, cleanup, err := td.MkdirTempRandom("foo")
assert.NoError(t, err)
assert.True(t, strings.HasPrefix(s, filepath.Join(base, "sub1/sub2", "foo")))
_, err = os.Stat(s)
assert.NoError(t, err)
cleanup()
_, err = os.Stat(s)
assert.ErrorIs(t, err, os.ErrNotExist)
})
t.Run("CreateTempFileRandom", func(t *testing.T) {
f, cleanup, err := td.CreateTempFileRandom("foo", "bar")
filename := f.Name()
assert.NoError(t, err)
assert.True(t, strings.HasPrefix(filename, filepath.Join(base, "sub1/sub2", "foo", "bar")))
_, err = os.Stat(filename)
assert.NoError(t, err)
cleanup()
_, err = os.Stat(filename)
assert.ErrorIs(t, err, os.ErrNotExist)
})
t.Run("RemoveOutDated", func(t *testing.T) {
fa1, _, err := td.CreateTempFileRandom("dir-a", "f1")
assert.NoError(t, err)
fa2, _, err := td.CreateTempFileRandom("dir-a", "f2")
assert.NoError(t, err)
_ = os.Chtimes(fa2.Name(), time.Now().Add(-time.Hour), time.Now().Add(-time.Hour))
fb1, _, err := td.CreateTempFileRandom("dir-b", "f1")
assert.NoError(t, err)
_ = os.Chtimes(fb1.Name(), time.Now().Add(-time.Hour), time.Now().Add(-time.Hour))
_, _, _ = fa1.Close(), fa2.Close(), fb1.Close()
td.RemoveOutdated(time.Minute)
_, err = os.Stat(fa1.Name())
assert.NoError(t, err)
_, err = os.Stat(fa2.Name())
assert.ErrorIs(t, err, os.ErrNotExist)
_, err = os.Stat(fb1.Name())
assert.ErrorIs(t, err, os.ErrNotExist)
})
})
t.Run("BaseNotExist", func(t *testing.T) {
td := New(filepath.Join(base, "not-exist"), "sub")
_, _, err := td.MkdirTempRandom("foo")
assert.ErrorIs(t, err, os.ErrNotExist)
})
}

View File

@ -56,7 +56,7 @@ var testMetas = map[string]string{
}
func TestMain(m *testing.M) {
unittest.InitSettings()
unittest.InitSettingsForTesting()
if err := git.InitSimple(context.Background()); err != nil {
log.Fatal("git init failed, err: %v", err)
}

View File

@ -7,16 +7,10 @@ import (
"bytes"
"errors"
"io"
"math"
"os"
)
var (
// ErrInvalidMemorySize occurs if the memory size is not in a valid range
ErrInvalidMemorySize = errors.New("Memory size must be greater 0 and lower math.MaxInt32")
// ErrWriteAfterRead occurs if Write is called after a read operation
ErrWriteAfterRead = errors.New("Write is unsupported after a read operation")
)
var ErrWriteAfterRead = errors.New("write is unsupported after a read operation") // occurs if Write is called after a read operation
type readAtSeeker interface {
io.ReadSeeker
@ -30,34 +24,17 @@ type FileBackedBuffer struct {
maxMemorySize int64
size int64
buffer bytes.Buffer
tempDir string
file *os.File
reader readAtSeeker
}
// New creates a file backed buffer with a specific maximum memory size
func New(maxMemorySize int) (*FileBackedBuffer, error) {
if maxMemorySize < 0 || maxMemorySize > math.MaxInt32 {
return nil, ErrInvalidMemorySize
}
func New(maxMemorySize int, tempDir string) *FileBackedBuffer {
return &FileBackedBuffer{
maxMemorySize: int64(maxMemorySize),
}, nil
}
// CreateFromReader creates a file backed buffer and copies the provided reader data into it.
func CreateFromReader(r io.Reader, maxMemorySize int) (*FileBackedBuffer, error) {
b, err := New(maxMemorySize)
if err != nil {
return nil, err
tempDir: tempDir,
}
_, err = io.Copy(b, r)
if err != nil {
return nil, err
}
return b, nil
}
// Write implements io.Writer
@ -73,7 +50,7 @@ func (b *FileBackedBuffer) Write(p []byte) (int, error) {
n, err = b.file.Write(p)
} else {
if b.size+int64(len(p)) > b.maxMemorySize {
b.file, err = os.CreateTemp("", "gitea-buffer-")
b.file, err = os.CreateTemp(b.tempDir, "gitea-buffer-")
if err != nil {
return 0, err
}
@ -148,7 +125,7 @@ func (b *FileBackedBuffer) Seek(offset int64, whence int) (int64, error) {
func (b *FileBackedBuffer) Close() error {
if b.file != nil {
err := b.file.Close()
os.Remove(b.file.Name())
_ = os.Remove(b.file.Name())
b.file = nil
return err
}

View File

@ -21,7 +21,8 @@ func TestFileBackedBuffer(t *testing.T) {
}
for _, c := range cases {
buf, err := CreateFromReader(strings.NewReader(c.Data), c.MaxMemorySize)
buf := New(c.MaxMemorySize, t.TempDir())
_, err := io.Copy(buf, strings.NewReader(c.Data))
assert.NoError(t, err)
assert.EqualValues(t, len(c.Data), buf.Size())

View File

@ -1112,6 +1112,18 @@
".routers": "folder-routes",
"_routers": "folder-routes",
"__routers__": "folder-routes",
"navigation": "folder-routes",
".navigation": "folder-routes",
"_navigation": "folder-routes",
"__navigation__": "folder-routes",
"navigations": "folder-routes",
".navigations": "folder-routes",
"_navigations": "folder-routes",
"__navigations__": "folder-routes",
"routing": "folder-routes",
".routing": "folder-routes",
"_routing": "folder-routes",
"__routing__": "folder-routes",
"ci": "folder-ci",
".ci": "folder-ci",
"_ci": "folder-ci",
@ -2092,6 +2104,34 @@
".DS_Store": "folder-macos",
"_DS_Store": "folder-macos",
"__DS_Store__": "folder-macos",
"iPhone": "folder-macos",
".iPhone": "folder-macos",
"_iPhone": "folder-macos",
"__iPhone__": "folder-macos",
"iPad": "folder-macos",
".iPad": "folder-macos",
"_iPad": "folder-macos",
"__iPad__": "folder-macos",
"iPod": "folder-macos",
".iPod": "folder-macos",
"_iPod": "folder-macos",
"__iPod__": "folder-macos",
"macbook": "folder-macos",
".macbook": "folder-macos",
"_macbook": "folder-macos",
"__macbook__": "folder-macos",
"macbook-air": "folder-macos",
".macbook-air": "folder-macos",
"_macbook-air": "folder-macos",
"__macbook-air__": "folder-macos",
"macosx": "folder-macos",
".macosx": "folder-macos",
"_macosx": "folder-macos",
"__macosx__": "folder-macos",
"apple": "folder-macos",
".apple": "folder-macos",
"_apple": "folder-macos",
"__apple__": "folder-macos",
"error": "folder-error",
".error": "folder-error",
"_error": "folder-error",
@ -2428,6 +2468,34 @@
".firebase": "folder-firebase",
"_firebase": "folder-firebase",
"__firebase__": "folder-firebase",
"firestore": "folder-firestore",
".firestore": "folder-firestore",
"_firestore": "folder-firestore",
"__firestore__": "folder-firestore",
"cloud-firestore": "folder-firestore",
".cloud-firestore": "folder-firestore",
"_cloud-firestore": "folder-firestore",
"__cloud-firestore__": "folder-firestore",
"firebase-firestore": "folder-firestore",
".firebase-firestore": "folder-firestore",
"_firebase-firestore": "folder-firestore",
"__firebase-firestore__": "folder-firestore",
"cloud-functions": "folder-cloud-functions",
".cloud-functions": "folder-cloud-functions",
"_cloud-functions": "folder-cloud-functions",
"__cloud-functions__": "folder-cloud-functions",
"cloudfunctions": "folder-cloud-functions",
".cloudfunctions": "folder-cloud-functions",
"_cloudfunctions": "folder-cloud-functions",
"__cloudfunctions__": "folder-cloud-functions",
"firebase-cloud-functions": "folder-cloud-functions",
".firebase-cloud-functions": "folder-cloud-functions",
"_firebase-cloud-functions": "folder-cloud-functions",
"__firebase-cloud-functions__": "folder-cloud-functions",
"firebase-cloudfunctions": "folder-cloud-functions",
".firebase-cloudfunctions": "folder-cloud-functions",
"_firebase-cloudfunctions": "folder-cloud-functions",
"__firebase-cloudfunctions__": "folder-cloud-functions",
"svelte": "folder-svelte",
".svelte": "folder-svelte",
"_svelte": "folder-svelte",
@ -2975,6 +3043,14 @@
".zeabur": "folder-zeabur",
"_zeabur": "folder-zeabur",
"__zeabur__": "folder-zeabur",
"kusto": "folder-kusto",
".kusto": "folder-kusto",
"_kusto": "folder-kusto",
"__kusto__": "folder-kusto",
"kql": "folder-kusto",
".kql": "folder-kusto",
"_kql": "folder-kusto",
"__kql__": "folder-kusto",
"meta-inf": "folder-config",
".meta-inf": "folder-config",
"_meta-inf": "folder-config",
@ -2990,7 +3066,19 @@
"ds_store": "folder-macos",
".ds_store": "folder-macos",
"_ds_store": "folder-macos",
"__ds_store__": "folder-macos"
"__ds_store__": "folder-macos",
"iphone": "folder-macos",
".iphone": "folder-macos",
"_iphone": "folder-macos",
"__iphone__": "folder-macos",
"ipad": "folder-macos",
".ipad": "folder-macos",
"_ipad": "folder-macos",
"__ipad__": "folder-macos",
"ipod": "folder-macos",
".ipod": "folder-macos",
"_ipod": "folder-macos",
"__ipod__": "folder-macos"
},
"folderNamesExpanded": {
"rust": "folder-rust-open",
@ -4105,6 +4193,18 @@
".routers": "folder-routes-open",
"_routers": "folder-routes-open",
"__routers__": "folder-routes-open",
"navigation": "folder-routes-open",
".navigation": "folder-routes-open",
"_navigation": "folder-routes-open",
"__navigation__": "folder-routes-open",
"navigations": "folder-routes-open",
".navigations": "folder-routes-open",
"_navigations": "folder-routes-open",
"__navigations__": "folder-routes-open",
"routing": "folder-routes-open",
".routing": "folder-routes-open",
"_routing": "folder-routes-open",
"__routing__": "folder-routes-open",
"ci": "folder-ci-open",
".ci": "folder-ci-open",
"_ci": "folder-ci-open",
@ -5085,6 +5185,34 @@
".DS_Store": "folder-macos-open",
"_DS_Store": "folder-macos-open",
"__DS_Store__": "folder-macos-open",
"iPhone": "folder-macos-open",
".iPhone": "folder-macos-open",
"_iPhone": "folder-macos-open",
"__iPhone__": "folder-macos-open",
"iPad": "folder-macos-open",
".iPad": "folder-macos-open",
"_iPad": "folder-macos-open",
"__iPad__": "folder-macos-open",
"iPod": "folder-macos-open",
".iPod": "folder-macos-open",
"_iPod": "folder-macos-open",
"__iPod__": "folder-macos-open",
"macbook": "folder-macos-open",
".macbook": "folder-macos-open",
"_macbook": "folder-macos-open",
"__macbook__": "folder-macos-open",
"macbook-air": "folder-macos-open",
".macbook-air": "folder-macos-open",
"_macbook-air": "folder-macos-open",
"__macbook-air__": "folder-macos-open",
"macosx": "folder-macos-open",
".macosx": "folder-macos-open",
"_macosx": "folder-macos-open",
"__macosx__": "folder-macos-open",
"apple": "folder-macos-open",
".apple": "folder-macos-open",
"_apple": "folder-macos-open",
"__apple__": "folder-macos-open",
"error": "folder-error-open",
".error": "folder-error-open",
"_error": "folder-error-open",
@ -5421,6 +5549,34 @@
".firebase": "folder-firebase-open",
"_firebase": "folder-firebase-open",
"__firebase__": "folder-firebase-open",
"firestore": "folder-firestore-open",
".firestore": "folder-firestore-open",
"_firestore": "folder-firestore-open",
"__firestore__": "folder-firestore-open",
"cloud-firestore": "folder-firestore-open",
".cloud-firestore": "folder-firestore-open",
"_cloud-firestore": "folder-firestore-open",
"__cloud-firestore__": "folder-firestore-open",
"firebase-firestore": "folder-firestore-open",
".firebase-firestore": "folder-firestore-open",
"_firebase-firestore": "folder-firestore-open",
"__firebase-firestore__": "folder-firestore-open",
"cloud-functions": "folder-cloud-functions-open",
".cloud-functions": "folder-cloud-functions-open",
"_cloud-functions": "folder-cloud-functions-open",
"__cloud-functions__": "folder-cloud-functions-open",
"cloudfunctions": "folder-cloud-functions-open",
".cloudfunctions": "folder-cloud-functions-open",
"_cloudfunctions": "folder-cloud-functions-open",
"__cloudfunctions__": "folder-cloud-functions-open",
"firebase-cloud-functions": "folder-cloud-functions-open",
".firebase-cloud-functions": "folder-cloud-functions-open",
"_firebase-cloud-functions": "folder-cloud-functions-open",
"__firebase-cloud-functions__": "folder-cloud-functions-open",
"firebase-cloudfunctions": "folder-cloud-functions-open",
".firebase-cloudfunctions": "folder-cloud-functions-open",
"_firebase-cloudfunctions": "folder-cloud-functions-open",
"__firebase-cloudfunctions__": "folder-cloud-functions-open",
"svelte": "folder-svelte-open",
".svelte": "folder-svelte-open",
"_svelte": "folder-svelte-open",
@ -5967,7 +6123,15 @@
"zeabur": "folder-zeabur-open",
".zeabur": "folder-zeabur-open",
"_zeabur": "folder-zeabur-open",
"__zeabur__": "folder-zeabur-open"
"__zeabur__": "folder-zeabur-open",
"kusto": "folder-kusto-open",
".kusto": "folder-kusto-open",
"_kusto": "folder-kusto-open",
"__kusto__": "folder-kusto-open",
"kql": "folder-kusto-open",
".kql": "folder-kusto-open",
"_kql": "folder-kusto-open",
"__kql__": "folder-kusto-open"
},
"rootFolderNames": {},
"rootFolderNamesExpanded": {},
@ -6032,8 +6196,6 @@
"ico": "image",
"tif": "image",
"tiff": "image",
"psd": "image",
"psb": "image",
"ami": "image",
"apx": "image",
"avif": "image",
@ -6128,6 +6290,10 @@
"routing.tsx": "routing",
"routing.js": "routing",
"routing.jsx": "routing",
"route.ts": "routing",
"route.tsx": "routing",
"route.js": "routing",
"route.jsx": "routing",
"routes.ts": "routing",
"routes.tsx": "routing",
"routes.js": "routing",
@ -6288,6 +6454,7 @@
"py": "python",
"pyc": "python-misc",
"whl": "python-misc",
"egg": "python-misc",
"url": "url",
"sh": "console",
"ksh": "console",
@ -6780,6 +6947,11 @@
"gltf": "3d",
"glb": "3d",
"svg": "svg",
"ai": "adobe-illustrator",
"ait": "adobe-illustrator",
"psd": "adobe-photoshop",
"psb": "adobe-photoshop",
"psdt": "adobe-photoshop",
"svelte": "svelte",
"svelte.js": "svelte_js",
"svelte.ts": "svelte_ts",
@ -7031,6 +7203,7 @@
"dfxp": "subtitles",
"vtt": "subtitles",
"sub": "subtitles",
"ass": "subtitles",
"beancount": "beancount",
"bean": "beancount",
"epub": "epub",
@ -7272,6 +7445,10 @@
"router.jsx": "routing",
"router.ts": "routing",
"router.tsx": "routing",
"route.js": "routing",
"route.jsx": "routing",
"route.ts": "routing",
"route.tsx": "routing",
"routes.js": "routing",
"routes.jsx": "routing",
"routes.ts": "routing",
@ -7310,6 +7487,11 @@
".pylintrc": "python-misc",
"pyproject.toml": "python-misc",
"py.typed": "python-misc",
".coveragerc": "python-misc",
".coverage": "python-misc",
".scrapy": "python-misc",
"celerybeat-schedule": "python-misc",
"celerybeat.pid": "python-misc",
"ruff.toml": "ruff",
".ruff.toml": "ruff",
"uv.toml": "uv",
@ -9317,6 +9499,11 @@
"drone.yml": "drone_light",
".wakatime-project": "wakatime_light",
"hcl": "hcl_light",
"ai": "adobe-illustrator_light",
"ait": "adobe-illustrator_light",
"psd": "adobe-photoshop_light",
"psb": "adobe-photoshop_light",
"psdt": "adobe-photoshop_light",
"iuml": "uml_light",
"pu": "uml_light",
"puml": "uml_light",

View File

@ -4,6 +4,10 @@
"abc": "<svg viewBox='0 0 24 24'><path fill='#ff5722' d='M13.295 11.033V7.65l2.126-2.136c.774-.763.919-1.981.377-2.929a2.38 2.38 0 0 0-2.068-1.217c-.203 0-.435.029-.619.087-1.044.28-1.749 1.246-1.749 2.33v3.13L8.327 9.98a5.75 5.75 0 0 0-1.208 6.214 5.62 5.62 0 0 0 4.243 3.432v.59a.5.5 0 0 1-.483.482h-1.45v1.934h1.45a2.43 2.43 0 0 0 2.416-2.417v-.483c1.962 0 4.02-1.856 4.02-4.591 0-2.223-1.855-4.108-4.02-4.108m0-7.249c0-.222.106-.396.31-.454a.47.47 0 0 1 .54.222.48.48 0 0 1-.077.59l-.773.83V3.785m-1.933 7.732c-.938.619-1.643 1.682-1.894 2.668l1.894.503v2.948a3.73 3.73 0 0 1-2.484-2.185 3.8 3.8 0 0 1 .802-4.098l1.682-1.769zm1.933 6.283v-4.89c1.13 0 2.107 1.062 2.107 2.232 0 1.691-1.227 2.658-2.107 2.658'/></svg>",
"actionscript": "<svg viewBox='0 -960 960 960'><path fill='#f44336' d='M560-160v-80h120q17 0 28.5-11.5T720-280v-80q0-38 22-69t58-44v-14q-36-13-58-44t-22-69v-80q0-17-11.5-28.5T680-720H560v-80h120q50 0 85 35t35 85v80q0 17 11.5 28.5T840-560h40v160h-40q-17 0-28.5 11.5T800-360v80q0 50-35 85t-85 35zm-280 0q-50 0-85-35t-35-85v-80q0-17-11.5-28.5T120-400H80v-160h40q17 0 28.5-11.5T160-600v-80q0-50 35-85t85-35h120v80H280q-17 0-28.5 11.5T240-680v80q0 38-22 69t-58 44v14q36 13 58 44t22 69v80q0 17 11.5 28.5T280-240h120v80z'/><path fill='#f44336' d='M360-600h80v40h-80zm80 240h40v-200h-40v80h-80v-80h-40v200h40v-80h80zm200-200v-40H530a10 10 0 0 0-10 10v100a10 10 0 0 0 10 10h70v80h-80v40h110a10 10 0 0 0 10-10v-140a10 10 0 0 0-10-10h-70v-40z'/></svg>",
"ada": "<svg viewBox='0 0 24 24'><path fill='#0277bd' d='m2 12 2.9-1.07c.25-1.1.87-1.73.87-1.73a3.996 3.996 0 0 1 5.65 0l1.41 1.41 6.31-6.7c.95 3.81 0 7.62-2.33 10.69L22 19.62s-8.47 1.9-13.4-1.95c-2.63-2.06-3.22-3.26-3.59-4.52zm5.04.21c.37.37.98.37 1.35 0s.37-.97 0-1.34a.96.96 0 0 0-1.35 0c-.37.37-.37.97 0 1.34'/></svg>",
"adobe-illustrator": "<svg viewBox='0 0 32 32'><rect width='28' height='28' x='2' y='2' fill='#5d4037' rx='4'/><path fill='#ffb74d' d='M20.988 9.999a.96.96 0 0 1-.687-.269 1 1 0 0 1-.263-.704.9.9 0 0 1 .278-.681 1 1 0 0 1 .687-.268.93.93 0 0 1 .703.268 1.046 1.046 0 0 1-.015 1.385.9.9 0 0 1-.703.268M20 12h2v10h-2zm-5.63-1.98-.01-.02h-2.08a.12.12 0 0 0-.1.13 4.5 4.5 0 0 1-.06.74c-.05.13-.08.26-.12.37l-.27.78L8 22h2.14l.75-2h5.24l.79 2h2.16zM11.64 18l1.8-4.84.01.04.02.04L14.95 17l.39 1z'/></svg>",
"adobe-illustrator_light": "<svg viewBox='0 0 32 32'><rect width='28' height='28' x='2' y='2' fill='#795548' rx='4'/><path fill='#ffb74d' d='M20.988 9.999a.96.96 0 0 1-.687-.269 1 1 0 0 1-.263-.704.9.9 0 0 1 .278-.681 1 1 0 0 1 .687-.268.93.93 0 0 1 .703.268 1.046 1.046 0 0 1-.015 1.385.9.9 0 0 1-.703.268M20 12h2v10h-2zm-5.63-1.98-.01-.02h-2.08a.12.12 0 0 0-.1.13 4.5 4.5 0 0 1-.06.74c-.05.13-.08.26-.12.37l-.27.78L8 22h2.14l.75-2h5.24l.79 2h2.16zM11.64 18l1.8-4.84.01.04.02.04L14.95 17l.39 1z'/></svg>",
"adobe-photoshop": "<svg viewBox='0 0 32 32'><rect width='28' height='28' x='2' y='2' fill='#37474f' rx='4'/><path fill='#64b5f6' d='M23.744 14.716a3.7 3.7 0 0 0-1.066-.408 5.4 5.4 0 0 0-1.245-.157 2.1 2.1 0 0 0-.666.085.57.57 0 0 0-.345.24.7.7 0 0 0-.089.324.56.56 0 0 0 .111.313 1.3 1.3 0 0 0 .378.324q.386.217.79.397a7.8 7.8 0 0 1 1.71.877 2.7 2.7 0 0 1 .878.998 2.8 2.8 0 0 1 .256 1.238 2.96 2.96 0 0 1-.434 1.599 2.83 2.83 0 0 1-1.244 1.07 4.75 4.75 0 0 1-2.011.384 7 7 0 0 1-1.511-.156 4.2 4.2 0 0 1-1.134-.385.24.24 0 0 1-.122-.228v-2.092a.14.14 0 0 1 .044-.108c.034-.024.067-.012.1.012a4.6 4.6 0 0 0 1.378.59 4.8 4.8 0 0 0 1.311.18 2 2 0 0 0 .923-.169.56.56 0 0 0 .3-.505.65.65 0 0 0-.267-.48 4.6 4.6 0 0 0-1.089-.565 6.6 6.6 0 0 1-1.578-.866 3 3 0 0 1-.844-1.021 2.76 2.76 0 0 1-.256-1.226 3 3 0 0 1 .378-1.455 2.8 2.8 0 0 1 1.167-1.105A4 4 0 0 1 21.533 12a9 9 0 0 1 1.378.108 3.7 3.7 0 0 1 .956.277.2.2 0 0 1 .11.108.7.7 0 0 1 .023.144v1.96a.15.15 0 0 1-.056.12.28.28 0 0 1-.2 0M12.38 10H9.99v-.03h-2v12h2V18h2.39A3.62 3.62 0 0 0 16 14.38v-.76A3.62 3.62 0 0 0 12.38 10M14 14.38A1.626 1.626 0 0 1 12.38 16H9.99v-4h2.39A1.626 1.626 0 0 1 14 13.62Z'/></svg>",
"adobe-photoshop_light": "<svg viewBox='0 0 32 32'><rect width='28' height='28' x='2' y='2' fill='#455a64' rx='4'/><path fill='#64b5f6' d='M23.744 14.716a3.7 3.7 0 0 0-1.066-.408 5.4 5.4 0 0 0-1.245-.157 2.1 2.1 0 0 0-.666.085.57.57 0 0 0-.345.24.7.7 0 0 0-.089.324.56.56 0 0 0 .111.313 1.3 1.3 0 0 0 .378.324q.386.217.79.397a7.8 7.8 0 0 1 1.71.877 2.7 2.7 0 0 1 .878.998 2.8 2.8 0 0 1 .256 1.238 2.96 2.96 0 0 1-.434 1.599 2.83 2.83 0 0 1-1.244 1.07 4.75 4.75 0 0 1-2.011.384 7 7 0 0 1-1.511-.156 4.2 4.2 0 0 1-1.134-.385.24.24 0 0 1-.122-.228v-2.092a.14.14 0 0 1 .044-.108c.034-.024.067-.012.1.012a4.6 4.6 0 0 0 1.378.59 4.8 4.8 0 0 0 1.311.18 2 2 0 0 0 .923-.169.56.56 0 0 0 .3-.505.65.65 0 0 0-.267-.48 4.6 4.6 0 0 0-1.089-.565 6.6 6.6 0 0 1-1.578-.866 3 3 0 0 1-.844-1.021 2.76 2.76 0 0 1-.256-1.226 3 3 0 0 1 .378-1.455 2.8 2.8 0 0 1 1.167-1.105A4 4 0 0 1 21.533 12a9 9 0 0 1 1.378.108 3.7 3.7 0 0 1 .956.277.2.2 0 0 1 .11.108.7.7 0 0 1 .023.144v1.96a.15.15 0 0 1-.056.12.28.28 0 0 1-.2 0M12.38 10H9.99v-.03h-2v12h2V18h2.39A3.62 3.62 0 0 0 16 14.38v-.76A3.62 3.62 0 0 0 12.38 10M14 14.38A1.626 1.626 0 0 1 12.38 16H9.99v-4h2.39A1.626 1.626 0 0 1 14 13.62Z'/></svg>",
"adobe-swc": "<svg viewBox='0 0 32 32'><path fill='#e53935' d='M4 5v22a1 1 0 0 0 1 1h22a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1m20 7c-2.926 0-4.21.722-5.012 2H22v4h-4.582C16.34 20.857 14.393 24 8 24v-4c4.559 0 5.14-1.744 6.103-4.632C15.139 12.258 16.559 8 24 8Z'/></svg>",
"adonis": "<svg viewBox='0 0 180 180'><path fill='#7c4dff' d='m79.579 25.741-66.481 115.15h63.305l11.218-19.433H47.613L79.804 65.7l20.005 34.649 11.423-19.783zm42.118 50.221-45.203 78.297h90.408z' paint-order='fill markers stroke'/></svg>",
"advpl-include.clone": "<svg viewBox='0 0 16 16'><path fill='#00BCD4' fill-rule='evenodd' d='M6.752 1.158C2.234 1.96-.271 6.943 1.758 11.09c2.537 5.185 10.047 5.142 12.511-.07C16.69 5.9 12.321.17 6.752 1.159m.587 2.335c2.576.517 5.233 1.323 5.326 1.615.26.808.256 4.849-.004 5.34-.066.125-1.209-.012-2.08-.247l-.351-.094-.001-.437c-.005-1.308-.138-2.547-.29-2.7-.176-.176-1.312-.545-3.052-.99L5.78 5.697l-.014-.267c-.033-.6.117-1.95.232-2.093.063-.079.315-.05 1.34.157M4.029 5.39c.5.066 1.083.178 1.492.289l.178.048.03.984c.058 1.844.117 2.13.475 2.29.448.2 2.083.679 3.62 1.061l.34.084-.01.653c-.012.735-.083 1.393-.175 1.617l-.062.15-.261-.03c-.976-.113-4.175-.896-5.567-1.362-.611-.205-.759-.284-.811-.435-.23-.66-.23-4.905 0-5.337.054-.1.08-.1.75-.012'/></svg>",
@ -163,8 +167,8 @@
"fastlane": "<svg preserveAspectRatio='xMidYMid' viewBox='0 0 300 300'><path fill='#2979FF' d='M242.745 89.48c-11.223 0-21.398 4.463-28.867 11.7l-47.366-33.917c.295-1.238.469-2.524.469-3.854 0-9.167-7.432-16.6-16.6-16.6s-16.601 7.433-16.601 16.6c0 9.169 7.433 16.6 16.6 16.6 3.21 0 6.197-.927 8.738-2.504L217.1 119.7c4.52-9.428 14.49-16.77 25.645-16.77 15.492 0 28.051 12.558 28.051 28.05 0 12.38-8.02 22.887-19.148 26.608l3.806 12.91c16.703-5.368 28.79-21.03 28.79-39.518 0-22.92-18.579-41.5-41.5-41.5'/><path fill='#E64A19' d='M109.689 49.166c-3.389 10.669-2.22 21.69 2.405 30.977l-46.546 34.784a16.6 16.6 0 0 0-3.523-1.609c-8.716-2.768-18.026 2.053-20.794 10.768s2.053 18.026 10.767 20.794c8.716 2.769 18.026-2.052 20.795-10.767a16.46 16.46 0 0 0 .257-9.062l57.623-42.379c-7.598-7.144-11.567-18.84-8.2-29.444 4.68-14.727 20.411-22.874 35.139-18.195 11.768 3.738 19.334 14.535 19.513 26.238l13.421.28c-.059-17.5-11.299-33.721-28.873-39.304-21.788-6.921-45.063 5.13-51.984 26.92'/><path fill='#00bcd4' d='M32.81 161.347a41.37 41.37 0 0 0 30.043 7.612l18.362 54.878a16.3 16.3 0 0 0-2.621 2.8c-5.338 7.316-3.686 17.611 3.692 22.994 7.377 5.383 17.685 3.815 23.023-3.501 5.34-7.316 3.687-17.61-3.69-22.994a16.53 16.53 0 0 0-8.489-3.13l-22.086-67.718c-9.128 4.87-21.425 4.875-30.402-1.674-12.465-9.097-15.258-26.492-6.237-38.855 7.21-9.88 19.78-13.556 30.9-9.993l4.456-12.536c-16.566-5.525-35.414-.121-46.179 14.631-13.346 18.291-9.214 44.029 9.229 57.486'/><path fill='#8BC34A' d='M245.283 225.838c-3.42-10.583-10.75-18.811-19.884-23.64l17.72-55.05a16.6 16.6 0 0 0 3.796-.739c8.69-2.808 13.47-12.093 10.679-20.737-2.793-8.646-12.102-13.378-20.793-10.57-8.69 2.806-13.472 12.09-10.679 20.736a16.3 16.3 0 0 0 5.036 7.472l-22.334 67.6c10.315 1.374 20.312 8.527 23.71 19.046 4.72 14.61-3.36 30.298-18.044 35.042-11.735 3.791-24.138-.554-31.055-9.908l-11.078 7.543c10.176 14.106 28.706 20.71 46.23 15.048 21.726-7.019 33.678-30.23 26.696-51.843'/><path fill='#A0F' d='M116.724 270.244c9.003-6.587 14.547-16.139 16.291-26.33l57.906-.59a16.5 16.5 0 0 0 1.887 3.366c5.382 7.355 15.706 8.955 23.061 3.574s8.955-15.705 3.575-23.06c-5.382-7.356-15.706-8.956-23.061-3.575a16.4 16.4 0 0 0-5.54 7.137l-71.283.182c1.908 10.217-1.78 21.958-10.73 28.506-12.428 9.093-29.875 6.39-38.968-6.039-7.266-9.932-6.999-23.068-.257-32.585l-10.631-8.123c-10.249 14.11-10.752 33.77.098 48.601 13.453 18.389 39.265 22.389 57.652 8.936'/></svg>",
"favicon": "<svg viewBox='0 0 32 32'><path fill='#ffd54f' d='m16 24 10 6-4-10 8-8-10-.032L16 2l-4 10H2l8 8-4 10Z'/></svg>",
"figma": "<svg viewBox='0 0 32 32'><path fill='#f4511e' d='M12 4h4v8h-4a4 4 0 0 1-4-4 4 4 0 0 1 4-4'/><path fill='#ff8a65' d='M20 12h-4V4h4a4 4 0 0 1 4 4 4 4 0 0 1-4 4'/><rect width='8' height='8' x='16' y='12' fill='#29b6f6' rx='4' transform='rotate(180 20 16)'/><path fill='#7c4dff' d='M12 12h4v8h-4a4 4 0 0 1-4-4 4 4 0 0 1 4-4'/><path fill='#00e676' d='M12 20h4v4a4 4 0 0 1-4 4 4 4 0 0 1-4-4 4 4 0 0 1 4-4'/></svg>",
"file": "<svg viewBox='0 0 24 24'><path fill='#90a4ae' d='M13 9h5.5L13 3.5zM6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4c0-1.11.89-2 2-2m5 2H6v16h12v-9h-7z'/></svg>",
"firebase": "<svg viewBox='0 0 24 24'><path fill='#fbc02d' d='m19.389 18.237-6.742 3.74q-.693.36-1.386 0l-6.65-3.74L16.664 6.092 16.988 6c.277 0 .434.12.461.37zM9.553 6.277 5.35 13.248 7.105 2.212c.028-.25.185-.37.462-.37.185 0 .305.056.37.232l1.985 3.648-.37.554M13.71 7.44l-8.82 8.857 6.696-11.36c.092-.185.23-.268.415-.268s.305.083.37.268z'/></svg>",
"file": "<svg viewBox='0 0 16 16'><path fill='#90a4ae' d='M8.668 6h3.664L8.668 2.332zM4 1.332h5.332l4 4v8c0 .738-.594 1.336-1.332 1.336H4a1.33 1.33 0 0 1-1.332-1.336V2.668A1.33 1.33 0 0 1 4 1.332m3.332 1.336H4v10.664h8v-6H7.332z'/></svg>",
"firebase": "<svg viewBox='0 0 24 24'><path fill='#ff9100' d='M18.217 8.974c-.45-.623-1.482-1.904-3.07-3.808-.689-.825-1.28-1.526-1.57-1.87l-.408-.48-.173-.205-.094-.11-.018-.027-.008-.004-.4-.47-.509.407a11.1 11.1 0 0 0-3.069 3.866 9.5 9.5 0 0 0-.87 2.647q-.06.303-.1.615a9 9 0 0 0-.577-.03 6.2 6.2 0 0 0-1.901.229l-.265.074-.136.238a8 8 0 0 0-1.044 3.68 8 8 0 0 0 5.006 7.697l.197.079.06.02h.002a8 8 0 0 0 2.452.473q.143.005.286.005a7.9 7.9 0 0 0 3.076-.618l.007.003.261-.12a7.99 7.99 0 0 0 4.643-6.981 8.5 8.5 0 0 0-1.778-5.31M9.837 19.82l-.192-.074-.051-.02a6.31 6.31 0 0 1-3.897-6.048 6.2 6.2 0 0 1 .697-2.667 4.6 4.6 0 0 1 .759-.103l.065-.002a8 8 0 0 1 .378 0c.108.005.215.021.322.034a13 13 0 0 0 .918 4.007 10.1 10.1 0 0 0 2.474 3.61 6.4 6.4 0 0 1-1.473 1.263m.351-5.486a11.4 11.4 0 0 1-.767-3.125 4.6 4.6 0 0 1 .95.461 4.73 4.73 0 0 1 1.94 2.884 5 5 0 0 1 .12.649 4.2 4.2 0 0 1-.288 2.023 8.3 8.3 0 0 1-1.955-2.892m1.741 5.858a8 8 0 0 0 .553-.62c.233.177.485.332.73.495a6.3 6.3 0 0 1-1.283.125m5.432-2.97a6.34 6.34 0 0 1-2.212 2.138 12.4 12.4 0 0 1-1.851-1.15 5.84 5.84 0 0 0 .309-3.998 6.02 6.02 0 0 0-2.504-3.664 6.1 6.1 0 0 0-1.679-.74 8 8 0 0 1 .064-.496 9 9 0 0 1 .465-1.598q.117-.298.253-.584l.004-.007c.14-.282.296-.567.481-.872l.073-.12h-.002a9.2 9.2 0 0 1 1.534-1.824l.227.269c.53.628 1.03 1.222 1.483 1.765 1.02 1.223 2.342 2.828 2.852 3.536a6.8 6.8 0 0 1 1.446 4.242 6.3 6.3 0 0 1-.943 3.104'/></svg>",
"flash": "<svg viewBox='0 0 24 24'><path fill='#e53935' d='M20.314 2c-2.957 0-5.341 1.104-7.122 3.252-1.427 1.752-2.354 3.93-3.164 6.034-1.663 4.283-2.781 6.741-6.342 6.741V22c2.958 0 5.342-1.03 7.122-3.194 1.133-1.383 1.957-3.135 2.634-4.827h4.665v-3.973h-3.061c1.207-2.575 2.546-3.973 5.268-3.973z'/></svg>",
"flow": "<svg viewBox='0 0 300 300'><path fill='#fbc02d' fill-opacity='.976' d='m38.75 33.427 77.461 77.47H54.436l61.145 61.16H38.437l93.462 93.478v-77.158l.01-.01v-77.47h-.01V66.982h46.691l20.394 20.393H153.57v76.531h22.05l24.474 24.473h-15.806l-.01-.01v.01h-31.665l-.01-.01v.01h-.313l.313.313v77.148h109.149l-39.2-39.2v-15.806l8.465 8.466v-77.37h-15.682l.017-38.191 30.09 30.086V56.362h-64.874l-22.94-22.934H113.71z'/></svg>",
"folder-admin-open": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#cfd8dc' d='m25 10-7 3.273v4.908c0 4.542 2.986 8.788 7 9.819 4.014-1.031 7-5.277 7-9.82v-4.907zm0 3.273a2.457 2.457 0 1 1-2.333 2.454A2.396 2.396 0 0 1 25 13.273m3.99 9.817A7.6 7.6 0 0 1 25 26.298a7.6 7.6 0 0 1-3.99-3.208 8.4 8.4 0 0 1-.677-1.25c0-1.352 2.108-2.456 4.667-2.456s4.666 1.08 4.666 2.455a8.3 8.3 0 0 1-.676 1.251'/></svg>",
@ -223,6 +227,8 @@
"folder-client": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M15 12a1 1 0 0 0-1 1v10.994h-4v4h12v-4h-6V14h14v-2.006Z'/><path fill='#b3e5fc' d='M31 16h-6a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V17a1 1 0 0 0-1-1m-1 8h-4v-6h4Z'/></svg>",
"folder-cline-open": "<svg viewBox='0 0 32 32'><path fill='#42a5f5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#bbdefb' d='M23 12a2 2 0 0 0-2 2h-1c-2.216 0-4 1.784-4 4l-2 3 2 3c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4l2-3-2-3c0-2.216-1.784-4-4-4h-1a2 2 0 0 0-2-2m-2 6c.554 0 1 .446 1 1v4c0 .554-.446 1-1 1s-1-.446-1-1v-4c0-.554.446-1 1-1m4 0c.554 0 1 .446 1 1v4c0 .554-.446 1-1 1s-1-.446-1-1v-4c0-.554.446-1 1-1'/></svg>",
"folder-cline": "<svg viewBox='0 0 32 32'><path fill='#42a5f5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#bbdefb' d='M23 12a2 2 0 0 0-2 2h-1c-2.216 0-4 1.784-4 4l-2 3 2 3c0 2.216 1.784 4 4 4h6c2.216 0 4-1.784 4-4l2-3-2-3c0-2.216-1.784-4-4-4h-1a2 2 0 0 0-2-2m-2 6c.554 0 1 .446 1 1v4c0 .554-.446 1-1 1s-1-.446-1-1v-4c0-.554.446-1 1-1m4 0c.554 0 1 .446 1 1v4c0 .554-.446 1-1 1s-1-.446-1-1v-4c0-.554.446-1 1-1'/></svg>",
"folder-cloud-functions-open": "<svg xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2' clip-rule='evenodd' viewBox='0 0 32 32'><defs><path id='a' fill='#bbdefb' d='m26 14 2-2 4 4-2 2z'/></defs><path fill='#2196f3' fill-rule='nonzero' d='M28.967 12H9.442c-.859 0-1.627.553-1.898 1.368L4 24V10h24c0-1.097-.903-2-2-2H15.124c-.468 0-.921-.164-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4c-1.097 0-2 .903-2 2v16c0 1.097.903 2 2 2h22l4.805-11.212c.107-.249.162-.517.162-.788 0-1.097-.903-2-2-2'/><path fill='#bbdefb' d='M21.982 17.988h2.037v1.996h-2.037zm-2.983.021h2.037v1.996h-2.037zm5.998 0h1.996v1.996h-1.996zM29 14h3v10h-3z'/><use xlink:href='#a' transform='translate(0 -2)'/><use xlink:href='#a' transform='matrix(1 0 0 -1 0 40)'/><path fill='#bbdefb' d='M14 14h3v10h-3z'/><use xlink:href='#a' transform='matrix(-1 0 0 1 46 -2)'/><use xlink:href='#a' transform='rotate(180 23 20)'/></svg>",
"folder-cloud-functions": "<svg xmlns:xlink='http://www.w3.org/1999/xlink' fill-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2' clip-rule='evenodd' viewBox='0 0 32 32'><defs><path id='a' fill='#bbdefb' d='m26 14 2-2 4 4-2 2z'/></defs><path fill='#2196f3' fill-rule='nonzero' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4c-1.097 0-2 .903-2 2v16c0 1.097.903 2 2 2h24c1.097 0 2-.903 2-2V10c0-1.097-.903-2-2-2H15.124c-.468 0-.921-.164-1.28-.464'/><path fill='#bbdefb' d='M21.982 17.988h2.037v1.996h-2.037zm-2.983.021h2.037v1.996h-2.037zm5.998 0h1.996v1.996h-1.996zM29 14h3v10h-3z'/><use xlink:href='#a' transform='translate(0 -2)'/><use xlink:href='#a' transform='matrix(1 0 0 -1 0 40)'/><path fill='#bbdefb' d='M14 14h3v10h-3z'/><use xlink:href='#a' transform='matrix(-1 0 0 1 46 -2)'/><use xlink:href='#a' transform='rotate(180 23 20)'/></svg>",
"folder-cloudflare-open": "<svg viewBox='0 0 32 32'><path fill='#ff8a65' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#EFEBE9' d='M27.881 19.229a6.591 6.591 0 0 0-12.308-1.759 5.278 5.278 0 0 0 .572 10.524h11.428a4.388 4.388 0 0 0 .308-8.765'/></svg>",
"folder-cloudflare": "<svg viewBox='0 0 32 32'><path fill='#ff8a65' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#EFEBE9' d='M27.881 19.229a6.591 6.591 0 0 0-12.308-1.759 5.278 5.278 0 0 0 .572 10.524h11.428a4.388 4.388 0 0 0 .308-8.765'/></svg>",
"folder-cluster-open": "<svg viewBox='0 0 32 32'><path fill='#26a69a' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><circle cx='21' cy='15' r='3' fill='#b2dfdb'/><circle cx='17' cy='23' r='3' fill='#b2dfdb'/><circle cx='27' cy='27' r='3' fill='#b2dfdb'/></svg>",
@ -273,8 +279,8 @@
"folder-delta": "<svg viewBox='0 0 32 32'><path fill='#ec407a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#f8bbd0' d='M23 17.699 28.337 26H17.663zM23 14l-9 14h18z'/></svg>",
"folder-desktop-open": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#b3e5fc' d='M30 12H14a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6v2h-2v2h8v-2h-2v-2h6a2 2 0 0 0 2-2V14a2 2 0 0 0-2-2m0 12H14V14h16Z'/></svg>",
"folder-desktop": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M30 12H14a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6v2h-2v2h8v-2h-2v-2h6a2 2 0 0 0 2-2V14a2 2 0 0 0-2-2m0 12H14V14h16Z'/></svg>",
"folder-development-open.clone": "<svg viewBox='0 0 32 32'><path fill='#0288D1' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#CFD8DC' d='M18.473 30a1 1 0 0 1-.238-.028 1.137 1.137 0 0 1-.828-1.323L20.5 12.905a1.13 1.13 0 0 1 .507-.744 1.06 1.06 0 0 1 .8-.134 1.14 1.14 0 0 1 .828 1.324l-3.101 15.744a1.12 1.12 0 0 1-.504.743 1.06 1.06 0 0 1-.557.162m6.2-2h-.077a1.08 1.08 0 0 1-.762-.412 1.164 1.164 0 0 1 .113-1.548l5.319-4.967-5.296-4.623a1.165 1.165 0 0 1-.162-1.544 1.08 1.08 0 0 1 .754-.437 1.06 1.06 0 0 1 .81.258l6.244 5.455a1.156 1.156 0 0 1 .003 1.723l-6.218 5.808a1.07 1.07 0 0 1-.729.289Zm-9.31 0a1.07 1.07 0 0 1-.728-.292l-6.226-5.811a1.16 1.16 0 0 1-.01-1.692l.02-.018 6.246-5.454a1.03 1.03 0 0 1 .8-.26 1.08 1.08 0 0 1 .76.436 1.165 1.165 0 0 1-.16 1.547l-5.294 4.62 5.32 4.964a1.156 1.156 0 0 1 .112 1.548 1.07 1.07 0 0 1-.762.412Z'/></svg>",
"folder-development.clone": "<svg viewBox='0 0 32 32'><path fill='#0288D1' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#CFD8DC' d='M18.435 30a1 1 0 0 1-.238-.028 1.137 1.137 0 0 1-.828-1.323l3.093-15.744a1.13 1.13 0 0 1 .507-.744 1.06 1.06 0 0 1 .8-.134 1.14 1.14 0 0 1 .828 1.324l-3.1 15.744a1.12 1.12 0 0 1-.505.743 1.06 1.06 0 0 1-.557.162m6.2-2h-.077a1.08 1.08 0 0 1-.762-.412 1.164 1.164 0 0 1 .113-1.548l5.32-4.967-5.297-4.623a1.165 1.165 0 0 1-.162-1.544 1.08 1.08 0 0 1 .754-.437 1.06 1.06 0 0 1 .81.258l6.244 5.455a1.156 1.156 0 0 1 .004 1.723l-6.22 5.808a1.07 1.07 0 0 1-.728.289Zm-9.31 0a1.07 1.07 0 0 1-.728-.292l-6.225-5.811a1.16 1.16 0 0 1-.01-1.692l.02-.018 6.246-5.454a1.03 1.03 0 0 1 .8-.26 1.08 1.08 0 0 1 .758.436 1.165 1.165 0 0 1-.16 1.547l-5.293 4.62 5.32 4.964a1.156 1.156 0 0 1 .112 1.548 1.07 1.07 0 0 1-.762.412Z'/></svg>",
"folder-development-open.clone": "<svg viewBox='0 0 32 32'><path fill='#0288D1' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#B3E5FC' d='M18.473 30a1 1 0 0 1-.238-.028 1.137 1.137 0 0 1-.828-1.323L20.5 12.905a1.13 1.13 0 0 1 .507-.744 1.06 1.06 0 0 1 .8-.134 1.14 1.14 0 0 1 .828 1.324l-3.101 15.744a1.12 1.12 0 0 1-.504.743 1.06 1.06 0 0 1-.557.162m6.2-2h-.077a1.08 1.08 0 0 1-.762-.412 1.164 1.164 0 0 1 .113-1.548l5.319-4.967-5.296-4.623a1.165 1.165 0 0 1-.162-1.544 1.08 1.08 0 0 1 .754-.437 1.06 1.06 0 0 1 .81.258l6.244 5.455a1.156 1.156 0 0 1 .003 1.723l-6.218 5.808a1.07 1.07 0 0 1-.729.289Zm-9.31 0a1.07 1.07 0 0 1-.728-.292l-6.226-5.811a1.16 1.16 0 0 1-.01-1.692l.02-.018 6.246-5.454a1.03 1.03 0 0 1 .8-.26 1.08 1.08 0 0 1 .76.436 1.165 1.165 0 0 1-.16 1.547l-5.294 4.62 5.32 4.964a1.156 1.156 0 0 1 .112 1.548 1.07 1.07 0 0 1-.762.412Z'/></svg>",
"folder-development.clone": "<svg viewBox='0 0 32 32'><path fill='#0288D1' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#B3E5FC' d='M18.435 30a1 1 0 0 1-.238-.028 1.137 1.137 0 0 1-.828-1.323l3.093-15.744a1.13 1.13 0 0 1 .507-.744 1.06 1.06 0 0 1 .8-.134 1.14 1.14 0 0 1 .828 1.324l-3.1 15.744a1.12 1.12 0 0 1-.505.743 1.06 1.06 0 0 1-.557.162m6.2-2h-.077a1.08 1.08 0 0 1-.762-.412 1.164 1.164 0 0 1 .113-1.548l5.32-4.967-5.297-4.623a1.165 1.165 0 0 1-.162-1.544 1.08 1.08 0 0 1 .754-.437 1.06 1.06 0 0 1 .81.258l6.244 5.455a1.156 1.156 0 0 1 .004 1.723l-6.22 5.808a1.07 1.07 0 0 1-.728.289Zm-9.31 0a1.07 1.07 0 0 1-.728-.292l-6.225-5.811a1.16 1.16 0 0 1-.01-1.692l.02-.018 6.246-5.454a1.03 1.03 0 0 1 .8-.26 1.08 1.08 0 0 1 .758.436 1.165 1.165 0 0 1-.16 1.547l-5.293 4.62 5.32 4.964a1.156 1.156 0 0 1 .112 1.548 1.07 1.07 0 0 1-.762.412Z'/></svg>",
"folder-directive-open": "<svg viewBox='0 0 16 16'><path fill='#f44336' d='M14.484 6H4.72a1 1 0 0 0-.949.684L2 12V5h12a1 1 0 0 0-1-1H7.562a1 1 0 0 1-.64-.232l-.644-.536A1 1 0 0 0 5.638 3H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h11l2.403-5.606A1 1 0 0 0 14.483 6'/><g fill='#ffcdd2'><path d='m11.5 6.001-1.5 2h3z'/><path d='M11 7v2h1V7zm-1 3H8v1.001h2z'/><path d='m9 9-2 1.5L9 12zm2 3h1v2h-1Z'/><path d='m10 13 1.5 2 1.5-2Zm2.715-3v1.001H15v-1Z'/><path d='m14 9 2 1.5-2 1.5Z'/></g></svg>",
"folder-directive": "<svg viewBox='0 0 16 16'><path fill='#f44336' d='m6.922 3.768-.644-.536A1 1 0 0 0 5.638 3H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H7.562a1 1 0 0 1-.64-.232'/><g fill='#ffcdd2'><path d='m11.5 6.001-1.5 2h3z'/><path d='M11 7v2h1V7zm-1 3H8v1.001h2z'/><path d='m9 9-2 1.5L9 12zm2 3h1v2h-1Z'/><path d='m10 13 1.5 2 1.5-2Zm3-3v1.001h2v-1Z'/><path d='m14 9 2 1.5-2 1.5Z'/></g></svg>",
"folder-dist-open": "<svg viewBox='0 0 32 32'><path fill='#e57373' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffcdd2' d='M30 14h-4v-2l-2-2h-4l-2 2v2h-4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V16a2 2 0 0 0-2-2m-10 0v-2h4v2Z'/></svg>",
@ -309,8 +315,10 @@
"folder-fastlane": "<svg viewBox='0 0 32 32'><path fill='#1e88e5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#e3f2fd' d='m15.508 21.618 1.272 3.936a1.456 1.456 0 0 0-.06 1.922 1.35 1.35 0 0 0 .937.486l.1.003a1.33 1.33 0 0 0 .894-.346 1.4 1.4 0 0 0 .207-.231 1.446 1.446 0 0 0-.307-1.972 1.36 1.36 0 0 0-.597-.256l-1.586-5.037a.16.16 0 0 0-.092-.101.15.15 0 0 0-.134.007 1.92 1.92 0 0 1-2.059-.113 1.995 1.995 0 0 1-.423-2.72 1.84 1.84 0 0 1 2.088-.697.16.16 0 0 0 .199-.102l.325-.95a.17.17 0 0 0-.007-.128.16.16 0 0 0-.093-.084 3 3 0 0 0-.978-.167h-.039A3.215 3.215 0 0 0 12 18.296a3.3 3.3 0 0 0 1.321 2.698 3.08 3.08 0 0 0 2.187.624'/><path fill='#e3f2fd' d='M15.802 17.146a1.35 1.35 0 0 0-1.787.535 1.45 1.45 0 0 0-.157 1.074 1.4 1.4 0 0 0 .622.875 1.33 1.33 0 0 0 .706.203 1.36 1.36 0 0 0 1.176-.685 1.47 1.47 0 0 0 .177-.971l4.14-3.149a.17.17 0 0 0 .065-.122.17.17 0 0 0-.05-.13 2.09 2.09 0 0 1-.556-2.063 1.883 1.883 0 0 1 2.383-1.262 1.95 1.95 0 0 1 1.31 1.823.16.16 0 0 0 .155.161l.983.02a.2.2 0 0 0 .114-.047.17.17 0 0 0 .048-.117 3.34 3.34 0 0 0-.945-2.333A3.12 3.12 0 0 0 21.939 10a4 4 0 0 0-.293.014 3.14 3.14 0 0 0-2.162 1.182 3.4 3.4 0 0 0-.457 3.457Zm10.842 10.755a1.4 1.4 0 0 0 .736-.77 1.45 1.45 0 0 0-.005-1.083 1.38 1.38 0 0 0-.744-.763 1.3 1.3 0 0 0-1.047.005 1.4 1.4 0 0 0-.693.672l-5.12.014a.16.16 0 0 0-.123.06.17.17 0 0 0-.033.135 2.08 2.08 0 0 1-.724 2 1.82 1.82 0 0 1-1.4.355 1.86 1.86 0 0 1-1.233-.773 2 2 0 0 1-.016-2.286.17.17 0 0 0-.033-.226l-.778-.613a.15.15 0 0 0-.12-.032.16.16 0 0 0-.105.065 3.36 3.36 0 0 0-.575 2.45 3.3 3.3 0 0 0 1.266 2.153 3.1 3.1 0 0 0 1.874.634 3.15 3.15 0 0 0 2.572-1.349 3.4 3.4 0 0 0 .545-1.264l4.01-.04a1.35 1.35 0 0 0 1.746.656'/><path fill='#e3f2fd' d='m27.718 23.882 1.228-3.945a1.34 1.34 0 0 0 .824-.473 1.44 1.44 0 0 0 .328-1.026 1.366 1.366 0 0 0-2.729-.013 1.5 1.5 0 0 0 .06.553 1.4 1.4 0 0 0 .336.564l-1.603 5.027a.17.17 0 0 0 .016.14.16.16 0 0 0 .115.075 1.952 1.952 0 0 1 .385 3.782 1.84 1.84 0 0 1-2.097-.692.156.156 0 0 0-.217-.037l-.811.572a.16.16 0 0 0-.067.108.17.17 0 0 0 .028.124A3.15 3.15 0 0 0 26.097 30a3.1 3.1 0 0 0 1.871-.63 3.36 3.36 0 0 0 1.165-3.667 3.23 3.23 0 0 0-1.415-1.82Z'/><path fill='#e3f2fd' d='M31.845 17.545a3.15 3.15 0 0 0-5.177-1.459l-3.28-2.432a1.46 1.46 0 0 0-.193-.969 1.37 1.37 0 0 0-.857-.637 1.3 1.3 0 0 0-.308-.038h-.004a1.425 1.425 0 0 0-.003 2.847h.005a1.3 1.3 0 0 0 .631-.16l4.165 3.137a.16.16 0 0 0 .133.027.16.16 0 0 0 .104-.089 1.98 1.98 0 0 1 1.735-1.178h.001a1.933 1.933 0 0 1 1.897 1.963 1.96 1.96 0 0 1-1.296 1.863.166.166 0 0 0-.102.203l.28.98a.16.16 0 0 0 .079.098.15.15 0 0 0 .123.011 3.2 3.2 0 0 0 1.867-1.64 3.4 3.4 0 0 0 .2-2.527'/></svg>",
"folder-favicon-open": "<svg viewBox='0 0 32 32'><path fill='#fbc02d' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124c-.468 0-.921-.164-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#fffde7' d='m24 24 6 4-2-6 4-4h-6l-1.999-6L22 18h-6l4 4-2 6z'/></svg>",
"folder-favicon": "<svg viewBox='0 0 32 32'><path fill='#fbc02d' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#fffde7' d='m24 24 6 4-2-6 4-4h-6l-1.999-6L22 18h-6l4 4-2 6z'/></svg>",
"folder-firebase-open": "<svg viewBox='0 0 32 32'><path fill='#fbc02d' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#fff9c4' d='m32 24.526-6.387 3.314a1.43 1.43 0 0 1-1.313 0L18 24.526l11.419-10.76.307-.08c.261 0 .41.106.437.326zM22.68 13.93l-3.98 6.178 1.662-9.778c.026-.22.175-.327.438-.327a.32.32 0 0 1 .35.205l1.882 3.232-.35.491m3.937 1.03-8.356 7.848 6.343-10.066a.42.42 0 0 1 .395-.237.335.335 0 0 1 .35.237Z'/></svg>",
"folder-firebase": "<svg viewBox='0 0 32 32'><path fill='#fbc02d' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#fff9c4' d='m32 24.526-6.387 3.314a1.43 1.43 0 0 1-1.313 0L18 24.526l11.419-10.76.307-.08c.261 0 .41.106.437.326zM22.68 13.93l-3.98 6.178 1.662-9.778c.026-.22.175-.327.438-.327a.32.32 0 0 1 .35.205l1.882 3.232-.35.491m3.937 1.03-8.356 7.848 6.343-10.066a.42.42 0 0 1 .395-.237.335.335 0 0 1 .35.237Z'/></svg>",
"folder-firebase-open": "<svg viewBox='0 0 32 32'><path fill='#FF9100' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffe0b2' d='M24 28.014s-4.584.213-7-4.014c-.66-1.156-1.006-2.805-1-4 .012-2.264.962-3.881 1.038-4 .117-.181 2.954-.867 4.962 0s3.979 3.215 4 6-2.275 4.565-2.691 4.881.691 1.133.691 1.133M22 25.5c2.051-1.646 1.875-2.063 2-3.5s-1.007-3.071-2-4-2.934-.65-3.5-.5c-2.418 5.405 3.5 8 3.5 8'/><path fill='#ffe0b2' d='m24 28.014 2.527-.941s-1.988-1.265-2.909-2.168C21.381 22.71 20.021 20.085 20 16s4-8 4-8 8.063 6.276 8 12c-.644 8.183-8 8.014-8 8.014m4-3.023c1.044-1.135 1.95-2.042 2-4.991.075-4.381-6-9.5-6-9.5s-1.856 2.393-2 5.5c-.338 7.273 6 8.991 6 8.991'/><path fill='#ffe0b2' d='M22.34 25.64s3.453-.086 5.66-.649c3.451-.879-1.022 2.191-1.022 2.191L24 28.015l-1.313-.536z'/></svg>",
"folder-firebase": "<svg fill-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2' clip-rule='evenodd' viewBox='0 0 32 32'><path fill='#ff9100' fill-rule='nonzero' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4c-1.097 0-2 .903-2 2v16c0 1.097.903 2 2 2h24c1.097 0 2-.903 2-2V10c0-1.097-.903-2-2-2H15.124c-.468 0-.921-.164-1.28-.464'/><path fill='#ffe0b2' d='M24 28.014s-4.584.213-7-4.014c-.66-1.156-1.006-2.805-1-4 .012-2.264.962-3.881 1.038-4 .117-.181 2.954-.867 4.962 0s3.979 3.215 4 6-2.275 4.565-2.691 4.881.691 1.133.691 1.133M22 25.5c2.051-1.646 1.875-2.063 2-3.5s-1.007-3.071-2-4-2.934-.65-3.5-.5c-2.418 5.405 3.5 8 3.5 8'/><path fill='#ffe0b2' d='m24 28.014 2.527-.941s-1.988-1.265-2.909-2.168C21.381 22.71 20.021 20.085 20 16s4-8 4-8 8.063 6.276 8 12c-.644 8.183-8 8.014-8 8.014m4-3.023c1.044-1.135 1.95-2.042 2-4.991.075-4.381-6-9.5-6-9.5s-1.856 2.393-2 5.5c-.338 7.273 6 8.991 6 8.991'/><path fill='#ffe0b2' d='M22.34 25.64s3.453-.086 5.66-.649c3.451-.879-1.022 2.191-1.022 2.191L24 28.015l-1.313-.536z'/></svg>",
"folder-firestore-open": "<svg fill-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2' clip-rule='evenodd' viewBox='0 0 32 32'><path fill='#2196f3' fill-rule='nonzero' d='M28.967 12H9.442c-.859 0-1.627.553-1.898 1.368L4 24V10h24c0-1.097-.903-2-2-2H15.124c-.468 0-.921-.164-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4c-1.097 0-2 .903-2 2v16c0 1.097.903 2 2 2h22l4.805-11.212c.107-.249.162-.517.162-.788 0-1.097-.903-2-2-2'/><path fill='#bbdefb' d='m24 10-8 4v4l8-4 8 4v-4z'/><path fill='#bbdefb' d='M16 20v4l8-4 8 4v-4l-8-4z'/><path fill='#bbdefb' d='m24 24 3-1 4 2-7 3z'/></svg>",
"folder-firestore": "<svg fill-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2' clip-rule='evenodd' viewBox='0 0 32 32'><path fill='#2196f3' fill-rule='nonzero' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4c-1.097 0-2 .903-2 2v16c0 1.097.903 2 2 2h24c1.097 0 2-.903 2-2V10c0-1.097-.903-2-2-2H15.124c-.468 0-.921-.164-1.28-.464'/><path fill='#bbdefb' d='m24 10-8 4v4l8-4 8 4v-4z'/><path fill='#bbdefb' d='M16 20v4l8-4 8 4v-4l-8-4z'/><path fill='#bbdefb' d='m24 24 3-1 4 2-7 3z'/></svg>",
"folder-flow-open": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#fbc02d' fill-opacity='.976' d='m12 10 6.71 6h-4.725l4.672 4h-6.676L20 28.025V12h3.548l1.584 2H22v6h1.98l1.979 2h-3.984l.025.025V28h10l-4-3.033v-1.221l.657.655L28 18h-2v-2.01l4 1.997v-5.99l-6-.999L21.923 10Z'/></svg>",
"folder-flow": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#fbc02d' fill-opacity='.976' d='m12 10 6.71 6h-4.725l4.672 4h-6.676L20 28.025V12h3.548l1.584 2H22v6h1.98l1.979 2h-3.984l.025.025V28h10l-4-3.033v-1.221l.657.655L28 18h-2v-2.01l4 1.997v-5.99l-6-.999L21.923 10Z'/></svg>",
"folder-flutter-open": "<svg viewBox='0 0 32 32'><path fill='#03a9f4' d='M29 12H9.4a2 2 0 0 0-1.9 1.4L4 24V10h24a2 2 0 0 0-2-2H15.1a2 2 0 0 1-1.3-.5l-1.2-1a2 2 0 0 0-1.3-.5H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.8-11.2A2 2 0 0 0 29 12'/><path fill='#b3e5fc' d='m20 10-8 8 4 4 12-12zm4 8-6 6 6 6h8l-6-6 6-6z'/></svg>",
@ -391,6 +399,8 @@
"folder-keys": "<svg viewBox='0 0 32 32'><path fill='#26a69a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b2dfdb' d='M21.651 20a6 6 0 1 0 0 4H26v4h4v-4h2v-4ZM16 24a2 2 0 1 1 2-2 2 2 0 0 1-2 2'/></svg>",
"folder-kubernetes-open": "<svg viewBox='0 0 32 32'><path fill='#448aff' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#bbdefb' d='M22.069 10.463a.6.6 0 0 0-.116.003.59.59 0 0 0-.517.635v.16a3.6 3.6 0 0 0 .08.543 5.2 5.2 0 0 1 .065 1.018.6.6 0 0 1-.186.305l-.013.238a7 7 0 0 0-1.031.157 7.27 7.27 0 0 0-3.706 2.117l-.196-.145a.52.52 0 0 1-.346-.039 5.4 5.4 0 0 1-.765-.69 5 5 0 0 0-.372-.395l-.12-.093a.75.75 0 0 0-.397-.158.6.6 0 0 0-.463.197.61.61 0 0 0 .148.834l.013.013c.026.027.079.067.106.093a4 4 0 0 0 .475.277 5.4 5.4 0 0 1 .848.597.6.6 0 0 1 .106.33l.183.158a7.22 7.22 0 0 0-1.137 5.121l-.25.065a.8.8 0 0 1-.254.253 4.4 4.4 0 0 1-1.018.158 2 2 0 0 0-.543.051l-.144.029h-.013v.013c-.04 0-.08.013-.106.013a.57.57 0 1 0 .339 1.086l.004-.001a1 1 0 0 0 .174-.041 2.7 2.7 0 0 0 .488-.197 7 7 0 0 1 1.018-.292.5.5 0 0 1 .305.119l.263-.039a7.43 7.43 0 0 0 3.27 4.088l-.094.238a.7.7 0 0 1 .042.33 4.2 4.2 0 0 1-.517.913c-.106.159-.199.304-.318.462a.17.17 0 0 1-.052.148c-.013.04-.04.066-.054.106a.57.57 0 0 0 1.072.382c.027-.04.051-.132.078-.132a5 5 0 0 0 .16-.53 5 5 0 0 1 .437-1.017.45.45 0 0 1 .25-.12l.132-.237a7.4 7.4 0 0 0 5.254.013l.105.212a.5.5 0 0 1 .277.183 6 6 0 0 1 .398.954c.04.172.094.344.16.542.027 0 .051.08.078.12.013.039.028.065.041.105a.568.568 0 0 0 .984-.569l-.007-.012a1 1 0 0 1-.052-.16c-.106-.146-.212-.305-.318-.45a7.4 7.4 0 0 1-.501-.9.44.44 0 0 1 .039-.343 1 1 0 0 1-.093-.225 7.44 7.44 0 0 0 3.268-4.113c.08.013.158.025.251.038a.33.33 0 0 1 .305-.106 4.7 4.7 0 0 1 1.018.28 2.6 2.6 0 0 0 .475.196.7.7 0 0 0 .187.028v.013c0 .013.053.013.093.026a.585.585 0 0 0 .635-.491.57.57 0 0 0-.483-.645l-.008-.001a.34.34 0 0 1-.157-.067h-.543a6.6 6.6 0 0 1-1.018-.186.55.55 0 0 1-.253-.238l-.251-.064a7.2 7.2 0 0 0-1.165-5.109l.211-.184a.4.4 0 0 1 .106-.317 5 5 0 0 1 .848-.597 3.3 3.3 0 0 0 .462-.277 1 1 0 0 0 .12-.093c.039-.026.08-.053.08-.08a.556.556 0 0 0-.78-.793c-.04 0-.093.054-.133.08a10 10 0 0 0-.372.395 4.8 4.8 0 0 1-.767.69.5.5 0 0 1-.344.039l-.212.158a7.37 7.37 0 0 0-4.708-2.274l-.013-.253a.45.45 0 0 1-.186-.29 5.2 5.2 0 0 1 .065-1.018 3.6 3.6 0 0 0 .08-.543v-.292a.57.57 0 0 0-.504-.506m-.778 4.408-.16 2.977h-.013a.5.5 0 0 1-.106.28.5.5 0 0 1-.687.118h-.013l-2.434-1.734a5.75 5.75 0 0 1 2.803-1.535c.212-.04.412-.08.61-.106m1.427 0a5.9 5.9 0 0 1 3.4 1.641l-2.421 1.734h-.013a.6.6 0 0 1-.277.067.494.494 0 0 1-.516-.47v-.008Zm-5.727 2.713 2.223 2.024v.013a.34.34 0 0 1 .144.253.483.483 0 0 1-.323.602l-.02.005v.013l-2.858.822a5.9 5.9 0 0 1 .834-3.732m10.013.04a6.18 6.18 0 0 1 .86 3.679l-2.87-.822-.013-.013a.47.47 0 0 1-.238-.157.49.49 0 0 1 .042-.694l.01-.01-.013-.038Zm-5.462 2.144h.912l.568.7-.199.886-.819.398-.819-.398-.212-.886Zm-2.132 2.447h.106a.55.55 0 0 1 .504.382.5.5 0 0 1-.052.28v.038l-1.127 2.74a5.84 5.84 0 0 1-2.366-2.952Zm4.87 0h.319l2.948.475a5.85 5.85 0 0 1-2.367 2.977l-1.14-2.79a.53.53 0 0 1 .24-.662m-2.327 1.199a.51.51 0 0 1 .488.256h.013l1.442 2.607a5 5 0 0 1-.569.157 5.9 5.9 0 0 1-3.214-.157l1.442-2.607h.012c.04-.093.107-.133.2-.2a.5.5 0 0 1 .186-.056'/></svg>",
"folder-kubernetes": "<svg viewBox='0 0 32 32'><path fill='#448aff' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#bbdefb' d='M22.069 10.463a.6.6 0 0 0-.116.003.59.59 0 0 0-.517.635v.16a3.6 3.6 0 0 0 .08.543 5.2 5.2 0 0 1 .065 1.018.6.6 0 0 1-.186.305l-.013.238a7 7 0 0 0-1.031.157 7.27 7.27 0 0 0-3.706 2.117l-.196-.145a.52.52 0 0 1-.346-.039 5.4 5.4 0 0 1-.765-.69 5 5 0 0 0-.372-.395l-.12-.093a.75.75 0 0 0-.397-.158.6.6 0 0 0-.463.197.61.61 0 0 0 .148.834l.013.013c.026.027.079.067.106.093a4 4 0 0 0 .475.277 5.4 5.4 0 0 1 .848.597.6.6 0 0 1 .106.33l.183.158a7.22 7.22 0 0 0-1.137 5.121l-.25.065a.8.8 0 0 1-.254.253 4.4 4.4 0 0 1-1.018.158 2 2 0 0 0-.543.051l-.144.029h-.013v.013c-.04 0-.08.013-.106.013a.57.57 0 1 0 .339 1.086l.004-.001a1 1 0 0 0 .174-.041 2.7 2.7 0 0 0 .488-.197 7 7 0 0 1 1.018-.292.5.5 0 0 1 .305.119l.263-.039a7.43 7.43 0 0 0 3.27 4.088l-.094.238a.7.7 0 0 1 .042.33 4.2 4.2 0 0 1-.517.913c-.106.159-.199.304-.318.462a.17.17 0 0 1-.052.148c-.013.04-.04.066-.054.106a.57.57 0 0 0 1.072.382c.027-.04.051-.132.078-.132a5 5 0 0 0 .16-.53 5 5 0 0 1 .437-1.017.45.45 0 0 1 .25-.12l.132-.237a7.4 7.4 0 0 0 5.254.013l.105.212a.5.5 0 0 1 .277.183 6 6 0 0 1 .398.954c.04.172.094.344.16.542.027 0 .051.08.078.12.013.039.028.065.041.105a.568.568 0 0 0 .984-.569l-.007-.012a1 1 0 0 1-.052-.16c-.106-.146-.212-.305-.318-.45a7.4 7.4 0 0 1-.501-.9.44.44 0 0 1 .039-.343 1 1 0 0 1-.093-.225 7.44 7.44 0 0 0 3.268-4.113c.08.013.158.025.251.038a.33.33 0 0 1 .305-.106 4.7 4.7 0 0 1 1.018.28 2.6 2.6 0 0 0 .475.196.7.7 0 0 0 .187.028v.013c0 .013.053.013.093.026a.585.585 0 0 0 .635-.491.57.57 0 0 0-.483-.645l-.008-.001a.34.34 0 0 1-.157-.067h-.543a6.6 6.6 0 0 1-1.018-.186.55.55 0 0 1-.253-.238l-.251-.064a7.2 7.2 0 0 0-1.165-5.109l.211-.184a.4.4 0 0 1 .106-.317 5 5 0 0 1 .848-.597 3.3 3.3 0 0 0 .462-.277 1 1 0 0 0 .12-.093c.039-.026.08-.053.08-.08a.556.556 0 0 0-.78-.793c-.04 0-.093.054-.133.08a10 10 0 0 0-.372.395 4.8 4.8 0 0 1-.767.69.5.5 0 0 1-.344.039l-.212.158a7.37 7.37 0 0 0-4.708-2.274l-.013-.253a.45.45 0 0 1-.186-.29 5.2 5.2 0 0 1 .065-1.018 3.6 3.6 0 0 0 .08-.543v-.292a.57.57 0 0 0-.504-.506m-.778 4.408-.16 2.977h-.013a.5.5 0 0 1-.106.28.5.5 0 0 1-.687.118h-.013l-2.434-1.734a5.75 5.75 0 0 1 2.803-1.535c.212-.04.412-.08.61-.106m1.427 0a5.9 5.9 0 0 1 3.4 1.641l-2.421 1.734h-.013a.6.6 0 0 1-.277.067.494.494 0 0 1-.516-.47v-.008Zm-5.727 2.713 2.223 2.024v.013a.34.34 0 0 1 .144.253.483.483 0 0 1-.323.602l-.02.005v.013l-2.858.822a5.9 5.9 0 0 1 .834-3.732m10.013.04a6.18 6.18 0 0 1 .86 3.679l-2.87-.822-.013-.013a.47.47 0 0 1-.238-.157.49.49 0 0 1 .042-.694l.01-.01-.013-.038Zm-5.462 2.144h.912l.568.7-.199.886-.819.398-.819-.398-.212-.886Zm-2.132 2.447h.106a.55.55 0 0 1 .504.382.5.5 0 0 1-.052.28v.038l-1.127 2.74a5.84 5.84 0 0 1-2.366-2.952Zm4.87 0h.319l2.948.475a5.85 5.85 0 0 1-2.367 2.977l-1.14-2.79a.53.53 0 0 1 .24-.662m-2.327 1.199a.51.51 0 0 1 .488.256h.013l1.442 2.607a5 5 0 0 1-.569.157 5.9 5.9 0 0 1-3.214-.157l1.442-2.607h.012c.04-.093.107-.133.2-.2a.5.5 0 0 1 .186-.056'/></svg>",
"folder-kusto-open": "<svg viewBox='0 0 32 32'><path fill='#1e88e5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#bbdefb' d='M25 10c-3.878 0-7 3.122-7 7v7h7c3.878 0 7-3.122 7-7s-3.122-7-7-7m3 4h2v6h-2zm-8 2h2v4h-2zm4 2h2v2h-2zm-8 2-3.996.02v2.322L12 24h4zm-4 6v4h4v-4zm6 0v4h4v-4z'/></svg>",
"folder-kusto": "<svg viewBox='0 0 32 32'><path fill='#1e88e5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#bbdefb' d='M25 10c-3.878 0-7 3.122-7 7v7h7c3.878 0 7-3.122 7-7s-3.122-7-7-7m3 4h2v6h-2zm-8 2h2v4h-2zm4 2h2v2h-2zm-8 2-3.996.02v2.322L12 24h4zm-4 6v4h4v-4zm6 0v4h4v-4z'/></svg>",
"folder-layout-open": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#b3e5fc' d='M10 16h6v14h-6zm8 8h6v6h-6zm8 0h6v6h-6zm-8-8h14v6H18z'/></svg>",
"folder-layout": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M10 16h6v14h-6zm8 8h6v6h-6zm8 0h6v6h-6zm-8-8h14v6H18z'/></svg>",
"folder-lefthook-open": "<svg viewBox='0 0 32 32'><path fill='#607d8b' d='M28.97 11.998H9.444a2 2 0 0 0-1.898 1.368L4.001 24V9.998h24.003a2 2 0 0 0-2-2H15.125a2 2 0 0 1-1.28-.464L12.557 6.46a2 2 0 0 0-1.28-.464H4.002a2 2 0 0 0-2.001 2V24A2 2 0 0 0 4 26h22.003l4.806-11.214a2 2 0 0 0-1.838-2.788z'/><path fill='#f44336' d='M14 20v6h-4zm4.026-5.342-2.385.795a1.494 1.494 0 0 0-.867 2.094l.534 1.068 4.696-1.624c.014-.293-.004-.602-.004-.91a1.496 1.496 0 0 0-1.974-1.423m12.886 5.502-5.546-5.18C24.272 13.999 23.85 14 22 14v3.012a3.36 3.36 0 0 1-1.301 2.787L24 24l5.876 1.676c.606-.698.85-1.005 1.38-1.595a2.583 2.583 0 0 0-.344-3.921'/><path fill='#b71c1c' d='m10 26 4-2 4 2-4 2zm10.699-6.2a20 20 0 0 1-2.463 1.314 3.5 3.5 0 0 1-2.236.302v1.339l8.98 4.888a3.22 3.22 0 0 0 4.054-1c.333-.384.505-.582.842-.967zm-5.127-1.89 3.756-1.408a.5.5 0 0 1 .675.492 1.48 1.48 0 0 1-.832 1.42l-1.83.915c-1.399.7-2.717-1.063-1.769-1.419'/></svg>",
@ -443,10 +453,10 @@
"folder-next": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#cfd8dc' d='M24 12a8 8 0 1 0 3.969 14.94L22 19v4.5a.5.5 0 0 1-.5.5h-1a.5.5 0 0 1-.5-.5v-7a.5.5 0 0 1 .5-.5h1.232a.5.5 0 0 1 .416.223l6.736 10.103A7.993 7.993 0 0 0 24 12m4 8h-2v-3.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5Z'/></svg>",
"folder-ngrx-actions-open.clone": "<svg viewBox='0 0 32 32'><path fill='#AB47BC' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#E1BEE7' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-actions.clone": "<svg viewBox='0 0 32 32'><path fill='#AB47BC' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#E1BEE7' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-effects-open.clone": "<svg viewBox='0 0 32 32'><path fill='#00BCD4' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#E0F7FA' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-effects.clone": "<svg viewBox='0 0 32 32'><path fill='#00BCD4' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#E0F7FA' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-entities-open.clone": "<svg viewBox='0 0 32 32'><path fill='#FBC02D' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#FFF3E0' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-entities.clone": "<svg viewBox='0 0 32 32'><path fill='#FBC02D' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#FFF3E0' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-effects-open.clone": "<svg viewBox='0 0 32 32'><path fill='#00BCD4' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#B2EBF2' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-effects.clone": "<svg viewBox='0 0 32 32'><path fill='#00BCD4' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#B2EBF2' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-entities-open.clone": "<svg viewBox='0 0 32 32'><path fill='#FBC02D' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#FFECB3' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-entities.clone": "<svg viewBox='0 0 32 32'><path fill='#FBC02D' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#FFECB3' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-reducer-open.clone": "<svg viewBox='0 0 32 32'><path fill='#EF5350' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#FFCDD2' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-reducer.clone": "<svg viewBox='0 0 32 32'><path fill='#EF5350' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#FFCDD2' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
"folder-ngrx-selectors-open.clone": "<svg viewBox='0 0 32 32'><path fill='#FF6E40' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#FFCCBC' d='m23 9-9 3 1 12 8 4 8-4 1-12Zm-1.869 2.785a2.3 2.3 0 0 1 1.124.324 5.3 5.3 0 0 0 1.214.305 6.63 6.63 0 0 1 4.433 2.834c.448.875.356 1.348-.33 1.7-.59.303-1.799.157-3.554-.432l-1.481-.497-.527.199a3.53 3.53 0 0 0-1.84 1.73 2.9 2.9 0 0 0-.218 1.622 2.9 2.9 0 0 0 .41 1.645c.35.613 1.15 1.395 1.287 1.259.038-.038-.044-.287-.182-.553a1.1 1.1 0 0 1-.178-.595c.038-.061.4.165.802.504a5.6 5.6 0 0 0 2.898 1.333c.787.081.967-.064.377-.307a1.8 1.8 0 0 1-.547-.363c-.23-.252-.243-.244.738-.462a4.6 4.6 0 0 0 1.887-.996c.023-.073-.173-.102-.495-.077-.292.023-.53-.006-.53-.067a3 3 0 0 1 .53-.656 4.93 4.93 0 0 0 1.585-3.596l.08-1.114.258.53a3.2 3.2 0 0 1 .133 2.148c-.168.605-.056.672.253.152.382-.644.505-.543.438.364a3.95 3.95 0 0 1-1.183 2.561c-.627.68-.551.803.207.34.731-.449.83-.379.453.325a6.08 6.08 0 0 1-3.782 2.831 6.2 6.2 0 0 1-2.487.16 7.33 7.33 0 0 1-5.44-3.849 13 13 0 0 0-.836-1.437c-.403-.542-.436-.785-.166-1.197a.92.92 0 0 0 .111-.73c-.257-1.451-.248-1.496.337-2.088.512-.513.543-.581.543-1.182 0-.52.052-.69.29-.925a1 1 0 0 1 .561-.291 2.88 2.88 0 0 0 1.624-.865 1.67 1.67 0 0 1 1.203-.587'/></svg>",
@ -461,7 +471,7 @@
"folder-nuxt": "<svg viewBox='0 0 32 32'><path fill='#546e7a' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#00e676' d='M22.498 27.998h6.927a1.56 1.56 0 0 0 1.127-.617 1.3 1.3 0 0 0 .188-.631 1.26 1.26 0 0 0-.188-.618l-4.685-8.053a1.14 1.14 0 0 0-.443-.443 1.5 1.5 0 0 0-.67-.188 1.29 1.29 0 0 0-1.074.63l-1.182 2.054-2.376-3.986a1.3 1.3 0 0 0-.43-.497 1.52 1.52 0 0 0-1.247 0 1.5 1.5 0 0 0-.51.497l-5.799 9.986a1.2 1.2 0 0 0-.134.618 1.24 1.24 0 0 0 .134.63 1.3 1.3 0 0 0 .497.43 1.3 1.3 0 0 0 .63.188h4.363a4.26 4.26 0 0 0 3.88-2.241l2.12-3.692 1.114-1.933 3.436 5.866h-4.564Zm-4.9-2h-3.04l4.533-7.8 2.28 3.893-1.52 2.667a2.34 2.34 0 0 1-2.267 1.24Z'/></svg>",
"folder-obsidian-open": "<svg fill-rule='evenodd' clip-rule='evenodd' image-rendering='optimizeQuality' shape-rendering='geometricPrecision' text-rendering='geometricPrecision' viewBox='0 0 512 512'><path fill='#673AB7' d='M463.47 192H151.06c-13.77 0-26 8.82-30.35 21.89L64 384V160h384c0-17.67-14.33-32-32-32H241.98a32 32 0 0 1-20.48-7.42l-20.6-17.15c-5.75-4.8-13-7.43-20.48-7.43H64c-17.67 0-32 14.33-32 32v256c0 17.67 14.33 32 32 32h352l76.88-179.39c1.7-3.98 2.59-8.28 2.59-12.61 0-17.67-14.33-32-32-32'/><g fill='#D1C4E9'><path d='M336.2 318.24c8.07-1.51 12.6-2.02 21.66-2.02-34.18-89.72 48.95-139.27 18.63-155.11-17-8.88-52.32 37.77-72.93 56.26l-10.67 37.41c19.77 16.2 36.25 39.63 43.31 63.46m75.04 128.91c13.05 3.85 26.66-5.92 28.52-19.42 1.35-9.81 3.51-20.65 8.24-30.94-2.66-7.51-25.72-71.18-104.74-56.39 7.6 31.4-4.15 64.54-22.83 91.02 33.14.31 59.29 6.45 90.81 15.73'/><path d='M478.76 346.86c7.02-12.43-16.61-22.28-28.74-50.78-10.52-24.69 4.93-53.82-8.18-66.23l-40.17-38.02c-14.09 38.27-40.29 56.91-17.12 123.38 37.13 6.98 67.48 27.2 77.55 58.42 0 0 13.67-21.49 16.66-26.77m-221.26 5.78c-8.21 18.67 17.96 36.81 43.46 63.29 29-40.73 24.17-88.95-15.12-127.91z'/></g></svg>",
"folder-obsidian": "<svg fill-rule='evenodd' clip-rule='evenodd' image-rendering='optimizeQuality' shape-rendering='geometricPrecision' text-rendering='geometricPrecision' viewBox='0 0 512 512'><path fill='#673AB7' d='m221.5 120.58-20.6-17.16A32 32 0 0 0 180.42 96H64c-17.67 0-32 14.33-32 32v256c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32V160c0-17.67-14.33-32-32-32H241.98a32 32 0 0 1-20.48-7.42'/><g fill='#D1C4E9'><path d='M336.2 318.24c8.07-1.51 12.6-2.02 21.66-2.02-34.18-89.72 48.95-139.27 18.63-155.11-17-8.88-52.32 37.77-72.93 56.26l-10.67 37.41c19.77 16.2 36.25 39.63 43.31 63.46m75.04 128.91c13.05 3.85 26.66-5.92 28.52-19.42 1.35-9.81 3.51-20.65 8.24-30.94-2.66-7.51-25.72-71.18-104.74-56.39 7.6 31.4-4.15 64.54-22.83 91.02 33.14.31 59.29 6.45 90.81 15.73'/><path d='M478.76 346.86c7.02-12.43-16.61-22.28-28.74-50.78-10.52-24.69 4.93-53.82-8.18-66.23l-40.17-38.02c-14.09 38.27-40.29 56.91-17.12 123.38 37.13 6.98 67.48 27.2 77.55 58.42 0 0 13.67-21.49 16.66-26.77m-221.26 5.78c-8.21 18.67 17.96 36.81 43.46 63.29 29-40.73 24.17-88.95-15.12-127.91z'/></g></svg>",
"folder-open": "<svg viewBox='0 0 32 32'><path fill='#90a4ae' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/></svg>",
"folder-open": "<svg viewBox='0 0 16 16'><path fill='#90a4ae' d='M14.483 6H4.721a1 1 0 0 0-.949.684L2 12V5h12a1 1 0 0 0-1-1H7.562a1 1 0 0 1-.64-.232l-.644-.536A1 1 0 0 0 5.638 3H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h11l2.403-5.606A1 1 0 0 0 14.483 6'/></svg>",
"folder-other-open": "<svg viewBox='0 0 32 32'><path fill='#ff7043' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffccbc' d='M22 10a10 10 0 1 0 10 10 10 10 0 0 0-10-10m-6 12.125a2 2 0 1 1 2-2 2 2 0 0 1-2 2m6 0a2 2 0 1 1 2-2 2 2 0 0 1-2 2m6 0a2 2 0 1 1 2-2 2 2 0 0 1-2 2'/></svg>",
"folder-other": "<svg viewBox='0 0 32 32'><path fill='#ff7043' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#ffccbc' d='M22 10a10 10 0 1 0 10 10 10 10 0 0 0-10-10m-6 12.125a2 2 0 1 1 2-2 2 2 0 0 1-2 2m6 0a2 2 0 1 1 2-2 2 2 0 0 1-2 2m6 0a2 2 0 1 1 2-2 2 2 0 0 1-2 2'/></svg>",
"folder-packages-open": "<svg viewBox='0 0 32 32'><path fill='#1e88e5' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#bbdefb' d='M31.2 12.933 29.6 10.8A2 2 0 0 0 28 10h-8a2 2 0 0 0-1.6.8l-1.6 2.133a4 4 0 0 0-.8 2.4V26a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V15.333a4 4 0 0 0-.8-2.4M20 12h8l1.5 2h-11Zm6 10v4h-4v-4h-4l6-6 6 6Z'/></svg>",
@ -500,8 +510,8 @@
"folder-queue": "<svg viewBox='0 0 32 32'><path fill='#039be5' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M24 16v-2h-3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h3v-2h-2v-8Zm8-2v-2h-5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h5v-2h-4V14Zm-16 2h2v8h-2z'/></svg>",
"folder-react-components-open": "<svg viewBox='0 0 32 32'><path fill='#00bcd4' d='M24.645 27.333H4.665A2.665 2.665 0 0 1 2 24.667v-16A2.656 2.656 0 0 1 4.646 6h8.01l2.665 2.667h9.324a2.68 2.68 0 0 1 2.664 2.666H4.664v13.334L7.514 14h22.739l-3.037 11.333a2.67 2.67 0 0 1-2.571 2'/><path fill='#b2ebf2' d='M21 18.035a1.923 1.923 0 1 1-.004 0zm-4.738 10.284c.645.395 2.057-.208 3.685-1.768q-.82-.948-1.545-1.977a23 23 0 0 1-2.456-.373c-.522 2.224-.328 3.754.316 4.116m.727-5.966-.297-.532a8 8 0 0 0-.296.894c.277.062.583.116.9.168l-.307-.532m6.692-.79L24.51 20l-.83-1.559c-.305-.55-.633-1.039-.93-1.528-.554-.032-1.137-.032-1.749-.032-.614 0-1.199 0-1.75.032-.298.489-.624.978-.932 1.528L17.49 20l.83 1.56c.307.55.633 1.04.93 1.528.554.031 1.137.031 1.75.031s1.198 0 1.75-.03c.297-.49.623-.978.93-1.53M21 14.573c-.194.23-.4.467-.603.749h1.206c-.204-.282-.408-.52-.603-.75m0 10.856c.194-.228.4-.468.603-.748h-1.206c.204.282.408.519.603.748m4.728-13.746c-.635-.395-2.047.208-3.675 1.768a25 25 0 0 1 1.545 1.975 23 23 0 0 1 2.456.375c.523-2.225.328-3.753-.326-4.116m-.717 5.967.297.53a8 8 0 0 0 .296-.895 16 16 0 0 0-.9-.165zm1.483-7.33c1.505.873 1.668 3.17 1.035 5.854C30.128 16.955 32 18.245 32 20c0 1.758-1.872 3.047-4.473 3.828.635 2.682.472 4.98-1.033 5.854-1.493.873-3.53-.126-5.493-2.029-1.966 1.903-4.002 2.902-5.507 2.029-1.493-.874-1.656-3.172-1.023-5.854C11.874 23.048 10 21.758 10 20s1.874-3.045 4.473-3.825c-.635-2.683-.472-4.981 1.023-5.855 1.503-.873 3.54.125 5.504 2.029 1.964-1.904 4-2.902 5.494-2.029M26.198 20a23 23 0 0 1 .911 2.352c2.149-.656 3.355-1.592 3.355-2.352 0-.758-1.206-1.693-3.355-2.35a24 24 0 0 1-.91 2.35m-10.397 0a24 24 0 0 1-.911-2.35c-2.148.657-3.355 1.592-3.355 2.35 0 .76 1.207 1.696 3.355 2.352a24 24 0 0 1 .91-2.352m9.21 2.352-.306.53c.316-.052.624-.104.899-.168a9 9 0 0 0-.296-.894zm-2.958 4.2c1.628 1.559 3.04 2.162 3.675 1.768.655-.364.85-1.892.326-4.118a23 23 0 0 1-2.455.375 25 25 0 0 1-1.544 1.975m-5.066-8.901.306-.53a14 14 0 0 0-.899.167 9 9 0 0 0 .296.894zm2.958-4.2c-1.628-1.56-3.04-2.162-3.685-1.768-.644.364-.84 1.892-.316 4.117a23 23 0 0 1 2.455-.375 25 25 0 0 1 1.544-1.975Z'/></svg>",
"folder-react-components": "<svg viewBox='0 0 32 32'><path fill='#00bcd4' d='M12.656 6H4.664A2.656 2.656 0 0 0 2 8.648v16.019a2.68 2.68 0 0 0 2.664 2.666h21.313a2.68 2.68 0 0 0 2.664-2.666V11.333a2.665 2.665 0 0 0-2.664-2.666H15.321Z'/><path fill='#b2ebf2' d='M21 18.035a1.923 1.923 0 1 1-.004 0zm-4.738 10.284c.645.395 2.057-.208 3.685-1.768q-.82-.948-1.545-1.977a23 23 0 0 1-2.456-.373c-.522 2.224-.328 3.754.316 4.116m.727-5.966-.297-.532a8 8 0 0 0-.296.894c.277.062.583.116.9.168l-.307-.532m6.692-.79L24.51 20l-.83-1.559c-.305-.55-.633-1.039-.93-1.528-.554-.032-1.137-.032-1.749-.032-.614 0-1.199 0-1.75.032-.298.489-.624.978-.932 1.528L17.49 20l.83 1.56c.307.55.633 1.04.93 1.528.554.031 1.137.031 1.75.031s1.198 0 1.75-.03c.297-.49.623-.978.93-1.53M21 14.573c-.194.23-.4.467-.603.749h1.206c-.204-.282-.408-.52-.603-.75m0 10.856c.194-.228.4-.468.603-.748h-1.206c.204.282.408.519.603.748m4.728-13.746c-.635-.395-2.047.208-3.675 1.768a25 25 0 0 1 1.545 1.975 23 23 0 0 1 2.456.375c.523-2.225.328-3.753-.326-4.116m-.717 5.967.297.53a8 8 0 0 0 .296-.895 16 16 0 0 0-.9-.165zm1.483-7.33c1.505.873 1.668 3.17 1.035 5.854C30.128 16.955 32 18.245 32 20c0 1.758-1.872 3.047-4.473 3.828.635 2.682.472 4.98-1.033 5.854-1.493.873-3.53-.126-5.493-2.029-1.966 1.903-4.002 2.902-5.507 2.029-1.493-.874-1.656-3.172-1.023-5.854C11.874 23.048 10 21.758 10 20s1.874-3.045 4.473-3.825c-.635-2.683-.472-4.981 1.023-5.855 1.503-.873 3.54.125 5.504 2.029 1.964-1.904 4-2.902 5.494-2.029M26.198 20a23 23 0 0 1 .911 2.352c2.149-.656 3.355-1.592 3.355-2.352 0-.758-1.206-1.693-3.355-2.35a24 24 0 0 1-.91 2.35m-10.397 0a24 24 0 0 1-.911-2.35c-2.148.657-3.355 1.592-3.355 2.35 0 .76 1.207 1.696 3.355 2.352a24 24 0 0 1 .91-2.352m9.21 2.352-.306.53c.316-.052.624-.104.899-.168a9 9 0 0 0-.296-.894zm-2.958 4.2c1.628 1.559 3.04 2.162 3.675 1.768.655-.364.85-1.892.326-4.118a23 23 0 0 1-2.455.375 25 25 0 0 1-1.544 1.975m-5.066-8.901.306-.53a14 14 0 0 0-.899.167 9 9 0 0 0 .296.894zm2.958-4.2c-1.628-1.56-3.04-2.162-3.685-1.768-.644.364-.84 1.892-.316 4.117a23 23 0 0 1 2.455-.375 25 25 0 0 1 1.544-1.975Z'/></svg>",
"folder-redux-actions-open.clone": "<svg viewBox='0 0 32 32'><path fill='#AB47BC' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#E1BEE7' stroke='#E1BEE7' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#E1BEE7' stroke='#E1BEE7' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#E1BEE7' stroke='#E1BEE7' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
"folder-redux-actions.clone": "<svg viewBox='0 0 32 32'><path fill='#AB47BC' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#E1BEE7' stroke='#E1BEE7' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#E1BEE7' stroke='#E1BEE7' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#E1BEE7' stroke='#E1BEE7' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
"folder-redux-actions-open.clone": "<svg viewBox='0 0 32 32'><path fill='#AB47BC' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#F3E5F5' stroke='#F3E5F5' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#F3E5F5' stroke='#F3E5F5' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#F3E5F5' stroke='#F3E5F5' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
"folder-redux-actions.clone": "<svg viewBox='0 0 32 32'><path fill='#AB47BC' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#F3E5F5' stroke='#F3E5F5' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#F3E5F5' stroke='#F3E5F5' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#F3E5F5' stroke='#F3E5F5' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
"folder-redux-reducer-open": "<svg viewBox='0 0 32 32'><path fill='#ef5350' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffcdd2' stroke='#ffcdd2' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#ffcdd2' stroke='#ffcdd2' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#ffcdd2' stroke='#ffcdd2' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
"folder-redux-reducer": "<svg viewBox='0 0 32 32'><path fill='#ef5350' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#ffcdd2' stroke='#ffcdd2' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#ffcdd2' stroke='#ffcdd2' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#ffcdd2' stroke='#ffcdd2' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
"folder-redux-selector-open.clone": "<svg viewBox='0 0 32 32'><path fill='#FF6E40' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#FFCCBC' stroke='#FFCCBC' stroke-linejoin='round' stroke-width='.293' d='M25.948 24.114a1.65 1.65 0 0 0 .97-.6 1.8 1.8 0 0 0 .381-1.274 1.72 1.72 0 0 0-1.69-1.596h-.06a1.724 1.724 0 0 0-1.61 1.814 1.85 1.85 0 0 0 .34.985 8.85 8.85 0 0 1-3.863 3.799 6.15 6.15 0 0 1-3.876.771 3.13 3.13 0 0 1-2.32-1.411 3.67 3.67 0 0 1-.18-3.738 5.8 5.8 0 0 1 1.605-1.986.3.3 0 0 0 .098-.313 14 14 0 0 1-.315-1.298.29.29 0 0 0-.172-.213.28.28 0 0 0-.272.036c-3.731 2.836-3.326 6.763-2.188 8.579a5.36 5.36 0 0 0 4.294 2.229q.125 0 .24-.005h.04a6 6 0 0 0 1.5-.188 9.88 9.88 0 0 0 7.078-5.591Z'/><path fill='#FFCCBC' stroke='#FFCCBC' stroke-linejoin='round' stroke-width='.293' d='M30.327 20.428a10.12 10.12 0 0 0-7.774-3.69q-.133 0-.265.003h-.234a1.61 1.61 0 0 0-1.377-.78h-.053a1.62 1.62 0 0 0-1.175.535 1.806 1.806 0 0 0 .039 2.466 1.67 1.67 0 0 0 1.19.494h.064a1.68 1.68 0 0 0 1.375-.886h.27a8.83 8.83 0 0 1 5.126 1.646 6.6 6.6 0 0 1 2.522 3.202 3.48 3.48 0 0 1-.046 2.831 3.39 3.39 0 0 1-3.137 1.97 5.8 5.8 0 0 1-2.32-.522.27.27 0 0 0-.304.054 14 14 0 0 1-1.088.912.294.294 0 0 0 .039.495 7.7 7.7 0 0 0 3.313.84l.192.002a5.66 5.66 0 0 0 4.886-2.948 6.39 6.39 0 0 0-1.243-6.624Z'/><path fill='#FFCCBC' stroke='#FFCCBC' stroke-linejoin='round' stroke-width='.293' d='m17.249 24.295.123-.01-.123.02a1.705 1.705 0 0 0 1.67 1.682h.053a1.715 1.715 0 0 0 1.64-1.778 1.78 1.78 0 0 0-.507-1.224 1.6 1.6 0 0 0-1.187-.493h-.076a9.6 9.6 0 0 1-1.154-5.448 6.83 6.83 0 0 1 1.39-3.853 3.97 3.97 0 0 1 2.842-1.363h.055c2.438 0 3.415 3.34 3.477 4.491a.29.29 0 0 0 .216.265c.299.073.822.246 1.213.384a.27.27 0 0 0 .266-.048.3.3 0 0 0 .105-.247C26.928 12.088 24.204 10 21.804 10a5.96 5.96 0 0 0-5.36 4.39 11.38 11.38 0 0 0 .936 9.155 1.5 1.5 0 0 0-.131.75Z'/></svg>",
@ -518,8 +528,8 @@
"folder-review": "<svg viewBox='0 0 32 32'><path fill='#2196f3' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><circle cx='21' cy='21' r='3' fill='#bbdefb'/><path fill='#bbdefb' d='M21 14c-4.66 0-9.35 2.91-11 7 1.65 4.09 6.34 7 11 7s9.35-2.91 11-7c-1.65-4.09-6.34-7-11-7m0 12a5 5 0 1 1 5-5 5 5 0 0 1-5 5'/></svg>",
"folder-robot-open": "<svg viewBox='0 0 32 32'><path fill='#ff5252' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffcdd2' d='M10.5 26H12v-6h-1.5a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 .5.5M30 20v6h1.5a.5.5 0 0 0 .5-.5v-5a.5.5 0 0 0-.5-.5Zm-8.5-8h-1a.5.5 0 0 0-.5.5V16h-5.5a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-11a.5.5 0 0 0-.5-.5H22v-3.5a.5.5 0 0 0-.5-.5M18 18a2 2 0 1 1-2 2 2 2 0 0 1 2-2m8 8H16v-2h10Zm-2-8a2 2 0 1 1-2 2 2 2 0 0 1 2-2'/></svg>",
"folder-robot": "<svg viewBox='0 0 32 32'><path fill='#ff5252' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#ffcdd2' d='M10.5 26H12v-6h-1.5a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 .5.5M30 20v6h1.5a.5.5 0 0 0 .5-.5v-5a.5.5 0 0 0-.5-.5Zm-8.5-8h-1a.5.5 0 0 0-.5.5V16h-5.5a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-11a.5.5 0 0 0-.5-.5H22v-3.5a.5.5 0 0 0-.5-.5M18 18a2 2 0 1 1-2 2 2 2 0 0 1 2-2m8 8H16v-2h10Zm-2-8a2 2 0 1 1-2 2 2 2 0 0 1 2-2'/></svg>",
"folder-root-open": "<svg viewBox='0 0 32 32'><path fill='#90a4ae' d='M16 5A11 11 0 1 1 5 16 11.01 11.01 0 0 1 16 5m0-3a14 14 0 1 0 14 14A14 14 0 0 0 16 2'/></svg>",
"folder-root": "<svg viewBox='0 0 32 32'><path fill='#90a4ae' d='M16 5A11 11 0 1 1 5 16 11.01 11.01 0 0 1 16 5m0-3a14 14 0 1 0 14 14A14 14 0 0 0 16 2m0 8a6 6 0 1 0 6 6 6 6 0 0 0-6-6'/></svg>",
"folder-root-open": "<svg viewBox='0 0 16 16'><circle cx='8' cy='8' r='6' fill='none' stroke='#90a4ae' stroke-width='2'/></svg>",
"folder-root": "<svg viewBox='0 0 16 16'><circle cx='8' cy='8' r='6' fill='none' stroke='#90a4ae' stroke-width='2'/><circle cx='8' cy='8' r='3' fill='#90a4ae'/></svg>",
"folder-routes-open": "<svg viewBox='0 0 32 32'><path fill='#43a047' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#c8e6c9' d='M17.414 14.586 20 12h-8v8l2.586-2.586 4.91 4.91A1.7 1.7 0 0 1 20 23.541V28h4v-4.459a5.68 5.68 0 0 0-1.676-4.045ZM29.36 12l-5.61 4.93.57.57a5.6 5.6 0 0 1 1.56 2.89L32 15.01Z'/></svg>",
"folder-routes": "<svg viewBox='0 0 32 32'><path fill='#43a047' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#c8e6c9' d='M17.414 14.586 20 12h-8v8l2.586-2.586 4.91 4.91A1.7 1.7 0 0 1 20 23.541V28h4v-4.459a5.68 5.68 0 0 0-1.676-4.045ZM29.36 12l-5.61 4.93.57.57a5.6 5.6 0 0 1 1.56 2.89L32 15.01Z'/></svg>",
"folder-rules-open": "<svg viewBox='0 0 32 32'><path fill='#ef5350' d='M28.967 12H9.442a2 2 0 0 0-1.898 1.368L4 24V10h24a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464l-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h22l4.805-11.212A2 2 0 0 0 28.967 12'/><path fill='#ffcdd2' d='M30 14h-2a3 3 0 0 0-6 0h-2a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V16a2 2 0 0 0-2-2m-5-1a1 1 0 1 1-1 1 1.003 1.003 0 0 1 1-1m-1.547 11.597-3.093-3.093 1.09-1.09 2.003 1.995 5.096-5.096 1.091 1.099Z'/></svg>",
@ -644,7 +654,7 @@
"folder-yarn": "<svg viewBox='0 0 32 32'><path fill='#0288d1' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/><path fill='#b3e5fc' d='M31.445 24.006a7.2 7.2 0 0 0-2.736 1.301 16.2 16.2 0 0 1-4.038 1.886 1.1 1.1 0 0 1-.68.394 42 42 0 0 1-4.455.413c-.805.006-1.296-.212-1.434-.554a1.14 1.14 0 0 1 .58-1.474l.02-.008a2.5 2.5 0 0 1-.357-.27c-.118-.122-.243-.368-.28-.277-.156.392-.237 1.352-.654 1.784a2.04 2.04 0 0 1-2.3.052c-.704-.386.05-1.295.05-1.295a.497.497 0 0 1-.679-.23l-.007-.015a3.56 3.56 0 0 1-.46-2.106 3.92 3.92 0 0 1 1.221-2.08 6.85 6.85 0 0 1 .455-3.144 7.4 7.4 0 0 1 2.187-2.614s-1.34-1.527-.84-2.912c.322-.903.453-.895.56-.935a2.5 2.5 0 0 0 1.003-.61 3.58 3.58 0 0 1 3.046-1.213s.8-2.53 1.546-2.035a13.3 13.3 0 0 1 1.06 2.062s.885-.535.985-.336a8.35 8.35 0 0 1 .361 4.382 10.1 10.1 0 0 1-1.795 3.863 7.9 7.9 0 0 1 1.808 2.778 8.4 8.4 0 0 1 .181 3.722l.024.044a4.44 4.44 0 0 0 2.343-.934 5.77 5.77 0 0 1 2.954-1.147.75.75 0 0 1 .873.62.775.775 0 0 1-.542.888'/></svg>",
"folder-zeabur-open": "<svg fill='none' viewBox='0 0 32 32'><path fill='#7E57C2' d='M29 12H9.4c-.9 0-1.6.6-1.9 1.4L4 24V10h24c0-1.1-.9-2-2-2H15.1c-.5 0-.9-.2-1.3-.5l-1.3-1.1c-.3-.2-.8-.4-1.2-.4H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h22l4.8-11.2c.4-1 0-2.2-1-2.6-.3-.1-.6-.2-.8-.2'/><g fill='#D1C4E9' clip-path='url(#a)'><path d='M20 24h12v6H12v-6h6l8-4H12v-6h20v6z'/><path d='M26 14H12v6h14zm6 10H20v6h12z'/></g><defs><clipPath id='a'><path d='M12 14h20v16H12z'/></clipPath></defs></svg>",
"folder-zeabur": "<svg fill='none' viewBox='0 0 32 32'><path fill='#7E57C2' d='m13.8 7.5-1.3-1.1c-.3-.2-.8-.4-1.2-.4H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h24c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2H15.1c-.5 0-.9-.1-1.3-.5'/><g fill='#D1C4E9' clip-path='url(#a)'><path d='M20 24h12v6H12v-6h6l8-4H12v-6h20v6z'/><path d='M26 14H12v6h14zm6 10H20v6h12z'/></g><defs><clipPath id='a'><path d='M12 14h20v16H12z'/></clipPath></defs></svg>",
"folder": "<svg viewBox='0 0 32 32'><path fill='#90a4ae' d='m13.844 7.536-1.288-1.072A2 2 0 0 0 11.276 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2H15.124a2 2 0 0 1-1.28-.464'/></svg>",
"folder": "<svg viewBox='0 0 16 16'><path fill='#90a4ae' d='m6.922 3.768-.644-.536A1 1 0 0 0 5.638 3H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H7.562a1 1 0 0 1-.64-.232'/></svg>",
"font": "<svg viewBox='0 0 32 32'><path fill='#f44336' d='M24 28h4L18 4h-4L4 28h4l8-19.422'/><path fill='#f44336' d='M8 20h16v4H8z'/></svg>",
"forth": "<svg viewBox='0 0 67.733 67.733'><path fill='#ef5350' d='M10.321 12.006c-.21 0-.38.173-.38.39v12.63c0 .215.17.389.38.389h16.925c.21 0 .38-.174.38-.39v-12.63a.384.384 0 0 0-.38-.389zm30.167 0c-.21 0-.38.173-.38.39v12.63c0 .215.17.389.38.389h16.925c.21 0 .38-.174.38-.39v-12.63a.384.384 0 0 0-.38-.389zM10.321 34.328c-.21 0-.38.173-.38.39v12.63c0 .215.17.389.38.389h16.925c.21 0 .38-.174.38-.39v-12.63a.384.384 0 0 0-.38-.389zm30.167 0c-.21 0-.38.173-.38.39v12.63c0 .215.17.389.38.389h4.053v4.351H40.51a.374.374 0 0 0-.375.375v2.89c0 .207.167.374.375.374h8.303a.373.373 0 0 0 .374-.374v-4.135h3.798a.374.374 0 0 0 .374-.375v-3.106h4.054c.21 0 .38-.174.38-.39v-12.63a.384.384 0 0 0-.38-.389z'/></svg>",
"fortran": "<svg viewBox='0 0 32 32'><path fill='#ff7043' d='M6 4v2h3a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6v2h12v-2h-3a1 1 0 0 1-1-1v-9h4a2 2 0 0 1 2 2v2h2V10h-2v2a2 2 0 0 1-2 2h-4V6h6a4 4 0 0 1 4 4h2V4Z'/></svg>",
@ -738,7 +748,7 @@
"knip": "<svg viewBox='0 0 24 24'><path fill='#EF6C00' d='m18.957 2.998-5.985 5.984 1.995 1.995 6.983-6.982v-.998m-9.975 9.477a.5.5 0 1 1 0-.998.5.5 0 0 1 0 .998M5.99 19.955a1.995 1.995 0 1 1 0-3.99 1.995 1.995 0 0 1 0 3.99m0-11.97a1.995 1.995 0 1 1 0-3.99 1.995 1.995 0 0 1 0 3.99m3.63-.36a3.9 3.9 0 0 0 .36-1.635 3.99 3.99 0 1 0-3.99 3.99c.589 0 1.137-.13 1.636-.36l2.354 2.355-2.354 2.354a3.9 3.9 0 0 0-1.636-.359 3.99 3.99 0 1 0 3.99 3.99c0-.588-.13-1.137-.36-1.636l2.355-2.354 6.982 6.982h2.993v-.997z'/></svg>",
"kotlin": "<svg viewBox='0 0 24 24'><defs><linearGradient id='a' x1='1.725' x2='22.185' y1='22.67' y2='1.982' gradientTransform='translate(1.306 1.129)scale(.89324)' gradientUnits='userSpaceOnUse'><stop offset='0' stop-color='#7C4DFF'/><stop offset='.5' stop-color='#D500F9'/><stop offset='1' stop-color='#EF5350'/></linearGradient></defs><path fill='url(#a)' d='M2.975 2.976v18.048h18.05v-.03l-4.478-4.511-4.48-4.515 4.48-4.515 4.443-4.477z'/></svg>",
"kubernetes": "<svg viewBox='0 0 24 24'><path fill='#448aff' d='M12.074 1.424a.638.638 0 0 0-.686.691v.173c.015.2.044.402.087.588.058.358.085.73.07 1.102a.65.65 0 0 1-.201.33l-.014.258a7 7 0 0 0-1.117.17 7.9 7.9 0 0 0-4.012 2.292l-.213-.157a.56.56 0 0 1-.374-.042 6 6 0 0 1-.829-.747c-.129-.143-.26-.299-.403-.428l-.128-.1a.8.8 0 0 0-.431-.171c-.2 0-.372.07-.501.212-.2.301-.127.675.16.904l.013.014c.03.029.087.072.115.1q.258.172.515.3c.33.186.631.403.918.647a.63.63 0 0 1 .114.358l.2.17a7.82 7.82 0 0 0-1.232 5.546l-.271.07a.84.84 0 0 1-.275.274c-.358.086-.73.17-1.102.17-.186 0-.387 0-.588.057l-.156.03h-.014v.015c-.043 0-.086.014-.115.014a.62.62 0 0 0-.4.789.625.625 0 0 0 .772.386 1 1 0 0 0 .188-.045c.186-.057.37-.127.528-.213a7.4 7.4 0 0 1 1.103-.316c.114 0 .244.057.33.129l.285-.042a8.04 8.04 0 0 0 3.54 4.426l-.1.258a.8.8 0 0 1 .044.358c-.143.344-.33.687-.56.987-.114.172-.215.33-.344.501 0 .043.001.117-.056.16-.014.043-.044.072-.059.114a.615.615 0 0 0 .372.787.62.62 0 0 0 .79-.372c.028-.043.055-.143.083-.143.072-.2.131-.387.174-.574a5.4 5.4 0 0 1 .473-1.102.5.5 0 0 1 .271-.129l.143-.257c1.82.702 3.84.701 5.688.014l.115.23a.53.53 0 0 1 .3.198c.186.33.301.674.43 1.032.043.187.102.373.174.588.028 0 .055.086.084.129.014.043.03.071.044.114a.61.61 0 0 0 .845.216.614.614 0 0 0 .213-.845c-.014-.057-.056-.13-.056-.174-.115-.157-.23-.329-.344-.486-.215-.316-.371-.63-.543-.974a.48.48 0 0 1 .042-.372 1.2 1.2 0 0 1-.1-.244c1.661-1.002 2.951-2.577 3.539-4.454.086.014.17.028.271.042.086-.115.201-.115.33-.115.387.057.73.16 1.103.302q.235.128.514.213c.058.014.116.03.202.03v.015c0 .014.058.013.1.028.344.043.617-.202.689-.532a.617.617 0 0 0-.532-.7c-.057-.014-.127-.03-.17-.072h-.588a7 7 0 0 1-1.102-.202.6.6 0 0 1-.274-.257l-.272-.07a7.8 7.8 0 0 0-1.262-5.531l.23-.2a.44.44 0 0 1 .114-.343c.273-.244.589-.46.918-.647a3.6 3.6 0 0 0 .5-.3 1 1 0 0 0 .13-.1c.043-.028.086-.058.086-.087.258-.243.273-.63 0-.859-.214-.257-.601-.257-.845 0-.043 0-.1.059-.142.087a11 11 0 0 0-.403.428c-.244.272-.53.532-.831.747a.55.55 0 0 1-.372.042l-.23.171a7.98 7.98 0 0 0-5.098-2.462l-.014-.274a.5.5 0 0 1-.201-.314 5.6 5.6 0 0 1 .07-1.102 4 4 0 0 0 .087-.588v-.316a.62.62 0 0 0-.546-.548m-.842 4.773-.174 3.223h-.014a.56.56 0 0 1-.114.302.543.543 0 0 1-.745.13h-.014L7.536 7.973a6.23 6.23 0 0 1 3.035-1.662c.23-.043.446-.086.66-.115zm1.544 0a6.38 6.38 0 0 1 3.682 1.777L13.837 9.85h-.014a.66.66 0 0 1-.3.073.535.535 0 0 1-.56-.518zm-6.2 2.938 2.406 2.19v.015c.086.071.157.16.157.274a.523.523 0 0 1-.372.657v.014l-3.095.89a6.4 6.4 0 0 1 .904-4.04m10.842.042c.73 1.189 1.032 2.595.932 3.984l-3.109-.89-.014-.014a.5.5 0 0 1-.257-.17.53.53 0 0 1 .056-.761l-.014-.042zm-5.915 2.322h.988l.615.758-.215.96-.887.431-.887-.43-.23-.96zm-2.308 2.65h.115c.243 0 .46.17.545.414 0 .1.001.23-.056.302v.042l-1.22 2.966a6.33 6.33 0 0 1-2.563-3.195zm5.274 0h.344l3.193.515a6.34 6.34 0 0 1-2.563 3.223l-1.234-3.022c-.115-.258.002-.558.26-.716m-2.521 1.298a.55.55 0 0 1 .529.277h.014l1.561 2.823a5 5 0 0 1-.615.171 6.4 6.4 0 0 1-3.481-.17l1.561-2.824h.014c.043-.1.115-.144.216-.215a.5.5 0 0 1 .201-.062'/></svg>",
"kusto": "<svg viewBox='0 0 318 315'><path fill='#1e88e5' d='M39.778 280.589c-4.91-2.139-4.99-2.852-4.99-34.058v-28.118H97.36v63.364H69.876c-21.702-.08-28.118-.317-30.098-1.188m69.462-30.494v-31.682h62.573v63.364H109.24zm-.791-89.027c0-51.72.158-54.414 4.435-67.958 4.119-13.068 11.802-25.424 21.94-35.246 16.079-15.603 35.009-23.682 57.582-24.553 16.633-.634 29.702 2.217 43.959 9.504 52.117 26.93 62.968 98.531 21.306 140.272-14.653 14.653-33.187 23.128-54.572 25.03-4.753.395-28.039.791-51.642.791H108.45zm61.78-15.92v-35.246H140.13v70.492h30.098zm40.394 10.297v-24.95h-30.098v49.9h30.098zm40.395-20.198V90.102H220.92v90.293h30.098zm-216.23 40.791V143.96H97.36v64.156H34.788z'/></svg>",
"kusto": "<svg viewBox='0 0 16 16'><path fill='#1e88e5' d='M10 1C7.23 1 5 3.23 5 6v5h5c2.77 0 5-2.23 5-5s-2.23-5-5-5m1.5 3H13v5h-1.5zm-5 1H8v4H6.5zM9 6h1.5v3H9zM1 8v3h3V8zm0 4v2.498a.5.5 0 0 0 .502.502H4v-3zm4 0v3h3v-3z'/></svg>",
"label": "<svg viewBox='0 0 16 16'><path fill='#ffb300' d='m14.709 8.558-7.27-7.247a1 1 0 0 0-.893-.297l-4 .731c-.399.074-.714.38-.8.777l-.732 4.024c-.055.328.057.662.297.892l7.247 7.27c.393.39 1.025.39 1.417 0l4.734-4.733a1.006 1.006 0 0 0 0-1.417m-8.981-2.8c-1.434 1.554-3.65-.764-2.117-2.214 1.411-1.378 3.467.704 2.15 2.178z'/></svg>",
"laravel": "<svg viewBox='0 0 32 32'><path fill='#ff5252' d='M31.963 9.12c-.008-.03-.023-.056-.034-.085a1 1 0 0 0-.07-.156 2 2 0 0 0-.162-.205 1 1 0 0 0-.088-.072 1 1 0 0 0-.083-.068l-.044-.02-.035-.024-6-3a1 1 0 0 0-.894 0l-6 3-.035.024-.044.02a1 1 0 0 0-.083.068.7.7 0 0 0-.187.191 1 1 0 0 0-.064.086 1 1 0 0 0-.069.156c-.01.029-.026.055-.034.085a1 1 0 0 0-.037.265v5.382l-4 2V5.385a1 1 0 0 0-.037-.265c-.008-.03-.023-.056-.034-.085a1 1 0 0 0-.07-.156 1 1 0 0 0-.063-.086.7.7 0 0 0-.187-.191 1 1 0 0 0-.083-.068l-.044-.02-.035-.024-6-3a1 1 0 0 0-.894 0l-6 3-.035.024-.044.02a1 1 0 0 0-.083.068 1 1 0 0 0-.088.072 1 1 0 0 0-.1.119 1 1 0 0 0-.063.086 1 1 0 0 0-.069.156c-.01.029-.026.055-.034.085A1 1 0 0 0 0 5.385v19a1 1 0 0 0 .553.894l6 3 6 3c.014.007.03.005.046.011a.9.9 0 0 0 .802 0c.015-.006.032-.004.046-.01l12-6a1 1 0 0 0 .553-.895v-5.382l5.447-2.724a1 1 0 0 0 .553-.894v-6a1 1 0 0 0-.037-.265M9.236 21.385l4.211-2.106h.001L19 16.503l3.764 1.882L13 23.267ZM24 13.003v3.764l-4-2v-3.764Zm1-5.5 3.764 1.882L25 11.267l-3.764-1.882ZM8 19.767V9.003l4-2v10.764ZM7 3.503l3.764 1.882L7 7.267 3.236 5.385Zm-5 3.5 4 2v16.764l-4-2Zm6 16 4 2v3.764l-4-2Zm16 .764-10 5v-3.764l10-5Zm6-9-4 2v-3.764l4-2Z'/></svg>",
"lefthook": "<svg viewBox='0 0 32 32'><path fill='#f44336' d='M6 16v6H2zm5.106-6.537-3.317 1.775a2.22 2.22 0 0 0-.895 2.873l.333.71L14 11.571v-.193a2.006 2.006 0 0 0-2.894-1.915m18.82 7.545a2 2 0 0 0-.393-.744l-7.89-8.883a2.76 2.76 0 0 0-3.138-.384L16 8v4.559a3.97 3.97 0 0 1-1.566 3.18L16 20l8.457 2.204 4.624-2.979a2 2 0 0 0 .845-2.217'/><path fill='#b71c1c' fill-rule='evenodd' d='m2 22 4-2 4 2-4 2zm12.434-6.262a6 6 0 0 1-1.194.695l-2.544 1.136A6.55 6.55 0 0 1 8 18v.764l9.71 4.855a4.05 4.05 0 0 0 2.343.366 7.8 7.8 0 0 0 2.667-.82 24 24 0 0 0 1.737-.96zm-6.97-1.635 5.829-2.937a.5.5 0 0 1 .712.475c.007.417-.005.871-.005 1.153a2.1 2.1 0 0 1-1.367 2.03l-2.987 1.067c-1.629.581-3.103-1.324-2.182-1.788'/></svg>",

View File

@ -3238,8 +3238,6 @@ config.ssh_domain=Doména SSH serveru
config.ssh_port=Port
config.ssh_listen_port=Port pro naslouchání
config.ssh_root_path=Kořenová cesta
config.ssh_key_test_path=Cesta testu klíčů
config.ssh_keygen_path=Cesta ke generátoru klíčů ('ssh-keygen')
config.ssh_minimum_key_size_check=Kontrola minimální velikosti klíčů
config.ssh_minimum_key_sizes=Minimální velikost klíčů

View File

@ -3235,8 +3235,6 @@ config.ssh_domain=SSH-Server-Domain
config.ssh_port=Port
config.ssh_listen_port=Listen-Port
config.ssh_root_path=Wurzelverzeichnis
config.ssh_key_test_path=Schlüssel-Test-Pfad
config.ssh_keygen_path=Keygen-Pfad („ssh-keygen“)
config.ssh_minimum_key_size_check=Prüfung der Mindestschlüssellänge
config.ssh_minimum_key_sizes=Mindestschlüssellängen

View File

@ -2927,8 +2927,6 @@ config.ssh_domain=Domain Διακομιστή SSH
config.ssh_port=Θύρα
config.ssh_listen_port=Θύρα Ακρόασης
config.ssh_root_path=Ριζική Διαδρομή
config.ssh_key_test_path=Διαδρομή Δοκιμής Κλειδιού
config.ssh_keygen_path=Διαδρομή Keygen ('ssh-keygen')
config.ssh_minimum_key_size_check=Έλεγχος Ελάχιστου Μεγέθους Κλειδιού
config.ssh_minimum_key_sizes=Ελάχιστα Μεγέθη Κλειδιών

View File

@ -3287,8 +3287,6 @@ config.ssh_domain = SSH Server Domain
config.ssh_port = Port
config.ssh_listen_port = Listen Port
config.ssh_root_path = Root Path
config.ssh_key_test_path = Key Test Path
config.ssh_keygen_path = Keygen ('ssh-keygen') Path
config.ssh_minimum_key_size_check = Minimum Key Size Check
config.ssh_minimum_key_sizes = Minimum Key Sizes

View File

@ -2907,8 +2907,6 @@ config.ssh_domain=Dominio del servidor SSH
config.ssh_port=Puerto
config.ssh_listen_port=Puerto de escucha
config.ssh_root_path=Ruta raíz
config.ssh_key_test_path=Ruta de la clave de prueba
config.ssh_keygen_path=Ruta del generador de claves ('ssh-keygen')
config.ssh_minimum_key_size_check=Tamaño mínimo de la clave de verificación
config.ssh_minimum_key_sizes=Tamaños de clave mínimos

View File

@ -2279,8 +2279,6 @@ config.ssh_domain=دامنه سرور SSH
config.ssh_port=درگاه (پورت)
config.ssh_listen_port=گوش دادن به پورت
config.ssh_root_path=مسیر ریشه
config.ssh_key_test_path=مسیر کلید آزمایش
config.ssh_keygen_path=مسیر فایل ssh-keygen
config.ssh_minimum_key_size_check=بررسی حداقل طول کلید
config.ssh_minimum_key_sizes=حداقل اندازه‌ی کلید ها

View File

@ -1538,8 +1538,6 @@ config.ssh_enabled=Käytössä
config.ssh_port=Portti
config.ssh_listen_port=Kuuntele porttia
config.ssh_root_path=Juuren polku
config.ssh_key_test_path=Polku jossa avaimet testataan
config.ssh_keygen_path=Keygen ('ssh-keygen') polku
config.ssh_minimum_key_size_check=Avaimen vähimmäiskoko tarkistus
config.ssh_minimum_key_sizes=Avaimen vähimmäiskoot

View File

@ -1707,11 +1707,11 @@ issues.start_tracking_history=`a commencé son travail %s.`
issues.tracker_auto_close=Le minuteur sera automatiquement arrêté quand le ticket sera fermé.
issues.tracking_already_started=`Vous avez déjà un minuteur en cours sur <a href="%s">un autre ticket</a> !`
issues.stop_tracking=Arrêter le minuteur
issues.stop_tracking_history=a travaillé sur <b>%[1]s</b> %[2]s
issues.stop_tracking_history=a travaillé <b>%[1]s</b> %[2]s
issues.cancel_tracking=Abandonner
issues.cancel_tracking_history=`a abandonné son minuteur %s.`
issues.del_time=Supprimer ce minuteur du journal
issues.add_time_history=a pointé du temps de travail sur <b>%[1]s</b>, %[2]s
issues.add_time_history=a pointé <b>%[1]s</b> de travail %[2]s.
issues.del_time_history=`a supprimé son temps de travail %s.`
issues.add_time_manually=Temps pointé manuellement
issues.add_time_hours=Heures
@ -3274,8 +3274,6 @@ config.ssh_domain=Domaine du serveur SSH
config.ssh_port=Port
config.ssh_listen_port=Port d'écoute
config.ssh_root_path=Emplacement racine
config.ssh_key_test_path=Chemin de test des clés
config.ssh_keygen_path=Chemin vers le générateur de clés (« ssh-keygen »)
config.ssh_minimum_key_size_check=Vérification de la longueur de clé minimale
config.ssh_minimum_key_sizes=Tailles de clé minimales

View File

@ -3282,8 +3282,6 @@ config.ssh_domain=Fearainn Freastalaí SSH
config.ssh_port=Calafort
config.ssh_listen_port=Éist Calafort
config.ssh_root_path=Cosán Fréimhe
config.ssh_key_test_path=Cosán Tástáil Eochair
config.ssh_keygen_path=Keygen ('ssh-keygen') Cosán
config.ssh_minimum_key_size_check=Seiceáil Íosta Méid Eochair
config.ssh_minimum_key_sizes=Méideanna Íosta Eochrach

View File

@ -1412,8 +1412,6 @@ config.ssh_start_builtin_server=Beépített szerver használata
config.ssh_port=Port
config.ssh_listen_port=Figyelő port
config.ssh_root_path=Gyökérkönyvtár
config.ssh_key_test_path=Kulcs ellenőrzés útvonala
config.ssh_keygen_path=Kulcsgeneráló ('ssh-keygen') elérési útja
config.ssh_minimum_key_size_check=Kulcsok minimum méretének ellenőrzése
config.ssh_minimum_key_sizes=Minimális kulcsok méretek

View File

@ -1219,8 +1219,6 @@ config.ssh_enabled=Aktif
config.ssh_port=Port
config.ssh_listen_port=Listen Port
config.ssh_root_path=Path Induk
config.ssh_key_test_path=Path Key Test
config.ssh_keygen_path=Path Keygen ('ssh-keygen')
config.ssh_minimum_key_size_check=Periksa ukuran kunci minimum
config.ssh_minimum_key_sizes=Ukuran kunci minimum

View File

@ -2464,8 +2464,6 @@ config.ssh_domain=Dominio Server Ssh
config.ssh_port=Porta
config.ssh_listen_port=Porta in ascolto
config.ssh_root_path=Percorso Root
config.ssh_key_test_path=Percorso chiave di test
config.ssh_keygen_path=Percorso Keygen ('ssh-keygen')
config.ssh_minimum_key_size_check=Verifica delle dimensioni minime della chiave
config.ssh_minimum_key_sizes=Dimensioni minime della chiave

View File

@ -3272,8 +3272,6 @@ config.ssh_domain=SSHサーバーのドメイン
config.ssh_port=ポート
config.ssh_listen_port=待受ポート
config.ssh_root_path=ルートパス
config.ssh_key_test_path=キーテストパス
config.ssh_keygen_path=キージェネレータ('ssh-keygen')パス
config.ssh_minimum_key_size_check=最小キー長のチェック
config.ssh_minimum_key_sizes=最小キー長

View File

@ -1372,8 +1372,6 @@ config.ssh_start_builtin_server=빌트-인 서버 사용
config.ssh_port=포트
config.ssh_listen_port=수신 대기 포트
config.ssh_root_path=최상위 경로
config.ssh_key_test_path=주 테스트 경로
config.ssh_keygen_path=키 생성 ('ssh-keygen') 경로
config.ssh_minimum_key_size_check=최소 키 사이즈 검사
config.ssh_minimum_key_sizes=최소 키 사이즈

View File

@ -2930,8 +2930,6 @@ config.ssh_domain=SSH servera domēns
config.ssh_port=Ports
config.ssh_listen_port=Klausīšanās ports
config.ssh_root_path=Saknes ceļš
config.ssh_key_test_path=Atslēgu pārbaudes ceļš
config.ssh_keygen_path=Keygen ('ssh-keygen') ceļš
config.ssh_minimum_key_size_check=Minimālā atslēgas lieluma pārbaude
config.ssh_minimum_key_sizes=Minimālais atslēgas lielums

View File

@ -2310,8 +2310,6 @@ config.ssh_start_builtin_server=Gebruik de ingebouwde server
config.ssh_port=Poort
config.ssh_listen_port=Luister op poort
config.ssh_root_path=Root-pad
config.ssh_key_test_path=Pad voor key-tests
config.ssh_keygen_path=Pad van keygen ('ssh-keygen')
config.ssh_minimum_key_size_check=Controleer minimale key-lengte
config.ssh_minimum_key_sizes=Minimale key-lengtes

View File

@ -2198,8 +2198,6 @@ config.ssh_start_builtin_server=Wykorzystaj wbudowany serwer
config.ssh_port=Port
config.ssh_listen_port=Port nasłuchiwania
config.ssh_root_path=Ścieżka do katalogu głównego
config.ssh_key_test_path=Ścieżka do klucza testowego
config.ssh_keygen_path=Ścieżka do generatora ('ssh-keygen')
config.ssh_minimum_key_size_check=Sprawdzanie minimalnej długości klucza
config.ssh_minimum_key_sizes=Minimalne rozmiary kluczy

View File

@ -2878,8 +2878,6 @@ config.ssh_domain=Domínio do servidor SSH
config.ssh_port=Porta
config.ssh_listen_port=Porta de escuta
config.ssh_root_path=Caminho da raiz
config.ssh_key_test_path=Caminho da chave de teste
config.ssh_keygen_path=Caminho do keygen ('ssh-keygen')
config.ssh_minimum_key_size_check=Verificar tamanho mínimo da chave
config.ssh_minimum_key_sizes=Tamanhos mínimos da chave

View File

@ -3286,8 +3286,6 @@ config.ssh_domain=Domínio do servidor SSH
config.ssh_port=Porto
config.ssh_listen_port=Porto de escuta
config.ssh_root_path=Localização base
config.ssh_key_test_path=Localização do teste das chaves
config.ssh_keygen_path=Localização do gerador de chaves ('ssh-keygen')
config.ssh_minimum_key_size_check=Verificação de tamanho mínimo da chave
config.ssh_minimum_key_sizes=Tamanhos mínimos da chave

View File

@ -2870,8 +2870,6 @@ config.ssh_domain=Домен SSH сервера
config.ssh_port=Порт
config.ssh_listen_port=Прослушиваемый порт
config.ssh_root_path=Корневой путь
config.ssh_key_test_path=Путь к тестовому ключу
config.ssh_keygen_path=Путь к генератору ключей ('ssh-keygen')
config.ssh_minimum_key_size_check=Минимальный размер ключа проверки
config.ssh_minimum_key_sizes=Минимальные размеры ключа

View File

@ -2240,8 +2240,6 @@ config.ssh_domain=SSH සේවාදායකය වසම්
config.ssh_port=වරාය
config.ssh_listen_port=සවන් වරාය
config.ssh_root_path=මූල මාර්ගය
config.ssh_key_test_path=ප්රධාන ටෙස්ට් මාර්ගය
config.ssh_keygen_path=Keygen ('ssh-keygen') මාර්ගය
config.ssh_minimum_key_size_check=අවම කී ප්රමාණය පරීක්ෂා
config.ssh_minimum_key_sizes=අවම යතුරෙහි ප්‍රමාණ

View File

@ -1794,8 +1794,6 @@ config.ssh_start_builtin_server=Använd inbyggd Server
config.ssh_port=Port
config.ssh_listen_port=Lyssningsport
config.ssh_root_path=Rotsökväg
config.ssh_key_test_path=Testsökväg för nyckel
config.ssh_keygen_path=Sökväg för nyckelgenerator ('ssh-keygen')
config.ssh_minimum_key_size_check=Kontroll av minsta tillåtna nyckelstorlek
config.ssh_minimum_key_sizes=Minsta tillåtna nyckelstorlek

View File

@ -3106,8 +3106,6 @@ config.ssh_domain=SSH Sunucusu Alan Adı
config.ssh_port=Bağlantı Noktası
config.ssh_listen_port=Port'u Dinle
config.ssh_root_path=Kök Yol
config.ssh_key_test_path=Anahtar Test Yolu
config.ssh_keygen_path=Keygen ('ssh-keygen') Yolu
config.ssh_minimum_key_size_check=Minimum Anahtar Uzunluğu Kontrolü
config.ssh_minimum_key_sizes=Minimum Anahtar Uzunlukları

View File

@ -2290,8 +2290,6 @@ config.ssh_domain=Домен SSH сервера
config.ssh_port=Порт
config.ssh_listen_port=Порт що прослуховується
config.ssh_root_path=Шлях до кореню
config.ssh_key_test_path=Шлях до тестового ключа
config.ssh_keygen_path=Шлях до генератора ключів ('ssh-keygen')
config.ssh_minimum_key_size_check=Мінімальний розмір ключа перевірки
config.ssh_minimum_key_sizes=Мінімальні розміри ключів

View File

@ -3221,8 +3221,6 @@ config.ssh_domain=SSH 服务器域名
config.ssh_port=端口
config.ssh_listen_port=监听端口
config.ssh_root_path=根目录
config.ssh_key_test_path=密钥测试路径
config.ssh_keygen_path=密钥生成器('ssh-keygen')路径
config.ssh_minimum_key_size_check=密钥最小长度检查
config.ssh_minimum_key_sizes=密钥最小长度限制

View File

@ -816,8 +816,6 @@ config.ssh_enabled=已啟用
config.ssh_port=
config.ssh_listen_port=監聽埠
config.ssh_root_path=根路徑
config.ssh_key_test_path=金鑰測試路徑
config.ssh_keygen_path=金鑰產生 (' ssh-keygen ') 路徑
config.ssh_minimum_key_size_check=金鑰最小大小檢查
config.ssh_minimum_key_sizes=金鑰最小大小

View File

@ -3211,8 +3211,6 @@ config.ssh_domain=SSH 伺服器域名
config.ssh_port=連接埠
config.ssh_listen_port=監聽埠
config.ssh_root_path=根路徑
config.ssh_key_test_path=金鑰測試路徑
config.ssh_keygen_path=金鑰產生 (' ssh-keygen ') 路徑
config.ssh_minimum_key_size_check=金鑰最小大小檢查
config.ssh_minimum_key_sizes=金鑰最小大小

783
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,12 +15,12 @@
"@primer/octicons": "19.15.1",
"@silverwind/vue3-calendar-heatmap": "2.0.6",
"add-asset-webpack-plugin": "3.0.0",
"ansi_up": "6.0.2",
"ansi_up": "6.0.5",
"asciinema-player": "3.9.0",
"chart.js": "4.4.8",
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0",
"clippie": "4.1.5",
"clippie": "4.1.6",
"cropperjs": "1.6.2",
"css-loader": "7.1.2",
"dayjs": "1.11.13",
@ -34,7 +34,7 @@
"jquery": "3.7.1",
"katex": "0.16.21",
"license-checker-webpack-plugin": "0.2.1",
"mermaid": "11.5.0",
"mermaid": "11.6.0",
"mini-css-extract-plugin": "2.9.2",
"minimatch": "10.0.1",
"monaco-editor": "0.52.2",
@ -45,14 +45,14 @@
"postcss-loader": "8.1.1",
"postcss-nesting": "13.0.1",
"sortablejs": "1.15.6",
"swagger-ui-dist": "5.20.1",
"swagger-ui-dist": "5.20.7",
"tailwindcss": "3.4.17",
"throttle-debounce": "5.0.2",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
"toastify-js": "1.12.0",
"tributejs": "5.1.3",
"typescript": "5.8.2",
"typescript": "5.8.3",
"uint8-to-base64": "0.2.0",
"vanilla-colorful": "0.7.2",
"vue": "3.5.13",
@ -79,15 +79,15 @@
"@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6",
"@types/toastify-js": "1.12.3",
"@typescript-eslint/eslint-plugin": "8.26.1",
"@typescript-eslint/parser": "8.26.1",
"@vitejs/plugin-vue": "5.2.1",
"@vitest/eslint-plugin": "1.1.37",
"@typescript-eslint/eslint-plugin": "8.29.1",
"@typescript-eslint/parser": "8.29.1",
"@vitejs/plugin-vue": "5.2.3",
"@vitest/eslint-plugin": "1.1.39",
"eslint": "8.57.0",
"eslint-import-resolver-typescript": "3.9.0",
"eslint-import-resolver-typescript": "4.3.2",
"eslint-plugin-array-func": "4.0.0",
"eslint-plugin-github": "5.0.2",
"eslint-plugin-import-x": "4.7.2",
"eslint-plugin-import-x": "4.10.2",
"eslint-plugin-no-jquery": "3.1.1",
"eslint-plugin-no-use-extend-native": "0.5.0",
"eslint-plugin-playwright": "2.2.0",
@ -96,23 +96,23 @@
"eslint-plugin-unicorn": "56.0.1",
"eslint-plugin-vue": "10.0.0",
"eslint-plugin-vue-scoped-css": "2.9.0",
"eslint-plugin-wc": "2.2.1",
"eslint-plugin-wc": "3.0.0",
"happy-dom": "17.4.4",
"markdownlint-cli": "0.44.0",
"material-icon-theme": "5.20.0",
"material-icon-theme": "5.21.1",
"nolyfill": "1.0.44",
"postcss-html": "1.8.0",
"stylelint": "16.16.0",
"stylelint-config-recommended": "15.0.0",
"stylelint": "16.18.0",
"stylelint-config-recommended": "16.0.0",
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
"stylelint-declaration-strict-value": "1.10.11",
"stylelint-define-config": "16.15.0",
"stylelint-define-config": "16.17.0",
"stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "3.3.2",
"type-fest": "4.37.0",
"type-fest": "4.39.1",
"updates": "16.4.2",
"vite-string-plugin": "1.4.4",
"vitest": "3.0.8",
"vitest": "3.1.1",
"vue-tsc": "2.2.8"
},
"browserslist": [

28
poetry.lock generated
View File

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand.
[[package]]
name = "click"
@ -119,18 +119,18 @@ six = ">=1.13.0"
[[package]]
name = "json5"
version = "0.10.0"
version = "0.12.0"
description = "A Python implementation of the JSON5 data format."
optional = false
python-versions = ">=3.8.0"
groups = ["dev"]
files = [
{file = "json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa"},
{file = "json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559"},
{file = "json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db"},
{file = "json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a"},
]
[package.extras]
dev = ["build (==1.2.2.post1)", "coverage (==7.5.3)", "mypy (==1.13.0)", "pip (==24.3.1)", "pylint (==3.2.3)", "ruff (==0.7.3)", "twine (==5.1.1)", "uv (==0.5.1)"]
dev = ["build (==1.2.2.post1)", "coverage (==7.5.4) ; python_version < \"3.9\"", "coverage (==7.8.0) ; python_version >= \"3.9\"", "mypy (==1.14.1) ; python_version < \"3.9\"", "mypy (==1.15.0) ; python_version >= \"3.9\"", "pip (==25.0.1)", "pylint (==3.2.7) ; python_version < \"3.9\"", "pylint (==3.3.6) ; python_version >= \"3.9\"", "ruff (==0.11.2)", "twine (==6.1.0)", "uv (==0.6.11)"]
[[package]]
name = "pathspec"
@ -330,7 +330,7 @@ description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.11\""
markers = "python_version == \"3.10\""
files = [
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
@ -390,27 +390,27 @@ telegram = ["requests"]
[[package]]
name = "typing-extensions"
version = "4.12.2"
version = "4.13.1"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.11\""
markers = "python_version == \"3.10\""
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
{file = "typing_extensions-4.13.1-py3-none-any.whl", hash = "sha256:4b6cf02909eb5495cfbc3f6e8fd49217e6cc7944e145cdda8caa3734777f9e69"},
{file = "typing_extensions-4.13.1.tar.gz", hash = "sha256:98795af00fb9640edec5b8e31fc647597b4691f099ad75f469a2616be1a76dff"},
]
[[package]]
name = "yamllint"
version = "1.36.1"
version = "1.37.0"
description = "A linter for YAML files."
optional = false
python-versions = ">=3.9"
groups = ["dev"]
files = [
{file = "yamllint-1.36.1-py3-none-any.whl", hash = "sha256:3e2ccd47ea12449837adf6b2c56fd9e31172ce42bc1470380806be461f25df66"},
{file = "yamllint-1.36.1.tar.gz", hash = "sha256:a287689daaafc301a80549b2d0170452ebfdcabd826e3fe3b4c66e322d4851fa"},
{file = "yamllint-1.37.0-py3-none-any.whl", hash = "sha256:c03ab4e79ab4af964c8eb16ac9746880fc76a3bb0ffb14925b9a55220ae7dda0"},
{file = "yamllint-1.37.0.tar.gz", hash = "sha256:ead81921d4d87216b2528b7a055664708f9fb8267beb0c427cb706ac6ab93580"},
]
[package.dependencies]
@ -423,4 +423,4 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"]
[metadata]
lock-version = "2.1"
python-versions = "^3.10"
content-hash = "d48a461813418f7b803a7f94713d93076a009a96554e0f4c707be0cc2a95b563"
content-hash = "d8ed1d7f88ff4be57be2c599b9d906dee25d0f6f6e46fdc9051c892c4e812a1c"

View File

@ -6,7 +6,7 @@ python = "^3.10"
[tool.poetry.group.dev.dependencies]
djlint = "1.36.4"
yamllint = "1.36.1"
yamllint = "1.37.0"
[tool.djlint]
profile="golang"

View File

@ -141,26 +141,18 @@ func GetTeam(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, apiTeam)
}
func attachTeamUnits(team *organization.Team, units []string) {
func attachTeamUnits(team *organization.Team, defaultAccessMode perm.AccessMode, units []string) {
unitTypes, _ := unit_model.FindUnitTypes(units...)
team.Units = make([]*organization.TeamUnit, 0, len(units))
for _, tp := range unitTypes {
team.Units = append(team.Units, &organization.TeamUnit{
OrgID: team.OrgID,
Type: tp,
AccessMode: team.AccessMode,
AccessMode: defaultAccessMode,
})
}
}
func convertUnitsMap(unitsMap map[string]string) map[unit_model.Type]perm.AccessMode {
res := make(map[unit_model.Type]perm.AccessMode, len(unitsMap))
for unitKey, p := range unitsMap {
res[unit_model.TypeFromKey(unitKey)] = perm.ParseAccessMode(p)
}
return res
}
func attachTeamUnitsMap(team *organization.Team, unitsMap map[string]string) {
team.Units = make([]*organization.TeamUnit, 0, len(unitsMap))
for unitKey, p := range unitsMap {
@ -214,24 +206,22 @@ func CreateTeam(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
form := web.GetForm(ctx).(*api.CreateTeamOption)
p := perm.ParseAccessMode(form.Permission)
if p < perm.AccessModeAdmin && len(form.UnitsMap) > 0 {
p = unit_model.MinUnitAccessMode(convertUnitsMap(form.UnitsMap))
}
teamPermission := perm.ParseAccessMode(form.Permission, perm.AccessModeNone, perm.AccessModeAdmin)
team := &organization.Team{
OrgID: ctx.Org.Organization.ID,
Name: form.Name,
Description: form.Description,
IncludesAllRepositories: form.IncludesAllRepositories,
CanCreateOrgRepo: form.CanCreateOrgRepo,
AccessMode: p,
AccessMode: teamPermission,
}
if team.AccessMode < perm.AccessModeAdmin {
if len(form.UnitsMap) > 0 {
attachTeamUnitsMap(team, form.UnitsMap)
} else if len(form.Units) > 0 {
attachTeamUnits(team, form.Units)
unitPerm := perm.ParseAccessMode(form.Permission, perm.AccessModeRead, perm.AccessModeWrite)
attachTeamUnits(team, unitPerm, form.Units)
} else {
ctx.APIErrorInternal(errors.New("units permission should not be empty"))
return
@ -304,15 +294,10 @@ func EditTeam(ctx *context.APIContext) {
isAuthChanged := false
isIncludeAllChanged := false
if !team.IsOwnerTeam() && len(form.Permission) != 0 {
// Validate permission level.
p := perm.ParseAccessMode(form.Permission)
if p < perm.AccessModeAdmin && len(form.UnitsMap) > 0 {
p = unit_model.MinUnitAccessMode(convertUnitsMap(form.UnitsMap))
}
if team.AccessMode != p {
teamPermission := perm.ParseAccessMode(form.Permission, perm.AccessModeNone, perm.AccessModeAdmin)
if team.AccessMode != teamPermission {
isAuthChanged = true
team.AccessMode = p
team.AccessMode = teamPermission
}
if form.IncludesAllRepositories != nil {
@ -325,7 +310,8 @@ func EditTeam(ctx *context.APIContext) {
if len(form.UnitsMap) > 0 {
attachTeamUnitsMap(team, form.UnitsMap)
} else if len(form.Units) > 0 {
attachTeamUnits(team, form.Units)
unitPerm := perm.ParseAccessMode(form.Permission, perm.AccessModeRead, perm.AccessModeWrite)
attachTeamUnits(team, unitPerm, form.Units)
}
} else {
attachAdminTeamUnits(team)

View File

@ -181,7 +181,7 @@ func AddOrUpdateCollaborator(ctx *context.APIContext) {
p := perm.AccessModeWrite
if form.Permission != nil {
p = perm.ParseAccessMode(*form.Permission)
p = perm.ParseAccessMode(*form.Permission, perm.AccessModeRead, perm.AccessModeWrite, perm.AccessModeAdmin)
}
if err := repo_service.AddOrUpdateCollaborator(ctx, ctx.Repo.Repository, collaborator, p); err != nil {

View File

@ -14,6 +14,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/cachegroup"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
@ -326,9 +327,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
func loadContextCacheUser(ctx context.Context, id int64) (*user_model.User, error) {
return cache.GetWithContextCache(ctx, "hook_post_receive_user", id, func() (*user_model.User, error) {
return user_model.GetUserByID(ctx, id)
})
return cache.GetWithContextCache(ctx, cachegroup.User, id, user_model.GetUserByID)
}
// handlePullRequestMerging handle pull request merging, a pull request action should push at least 1 commit

View File

@ -284,6 +284,8 @@ func NewTeam(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplTeamNew)
}
// FIXME: TEAM-UNIT-PERMISSION: this design is not right, when a new unit is added in the future,
// admin team won't inherit the correct admin permission for the new unit.
func getUnitPerms(forms url.Values, teamPermission perm.AccessMode) map[unit_model.Type]perm.AccessMode {
unitPerms := make(map[unit_model.Type]perm.AccessMode)
for _, ut := range unit_model.AllRepoUnitTypes {
@ -314,19 +316,14 @@ func getUnitPerms(forms url.Values, teamPermission perm.AccessMode) map[unit_mod
func NewTeamPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.CreateTeamForm)
includesAllRepositories := form.RepoAccess == "all"
p := perm.ParseAccessMode(form.Permission)
unitPerms := getUnitPerms(ctx.Req.Form, p)
if p < perm.AccessModeAdmin {
// if p is less than admin accessmode, then it should be general accessmode,
// so we should calculate the minial accessmode from units accessmodes.
p = unit_model.MinUnitAccessMode(unitPerms)
}
teamPermission := perm.ParseAccessMode(form.Permission, perm.AccessModeNone, perm.AccessModeAdmin)
unitPerms := getUnitPerms(ctx.Req.Form, teamPermission)
t := &org_model.Team{
OrgID: ctx.Org.Organization.ID,
Name: form.TeamName,
Description: form.Description,
AccessMode: p,
AccessMode: teamPermission,
IncludesAllRepositories: includesAllRepositories,
CanCreateOrgRepo: form.CanCreateOrgRepo,
}
@ -485,13 +482,8 @@ func EditTeam(ctx *context.Context) {
func EditTeamPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.CreateTeamForm)
t := ctx.Org.Team
newAccessMode := perm.ParseAccessMode(form.Permission)
unitPerms := getUnitPerms(ctx.Req.Form, newAccessMode)
if newAccessMode < perm.AccessModeAdmin {
// if newAccessMode is less than admin accessmode, then it should be general accessmode,
// so we should calculate the minial accessmode from units accessmodes.
newAccessMode = unit_model.MinUnitAccessMode(unitPerms)
}
teamPermission := perm.ParseAccessMode(form.Permission, perm.AccessModeNone, perm.AccessModeAdmin)
unitPerms := getUnitPerms(ctx.Req.Form, teamPermission)
isAuthChanged := false
isIncludeAllChanged := false
includesAllRepositories := form.RepoAccess == "all"
@ -503,9 +495,9 @@ func EditTeamPost(ctx *context.Context) {
if !t.IsOwnerTeam() {
t.Name = form.TeamName
if t.AccessMode != newAccessMode {
if t.AccessMode != teamPermission {
isAuthChanged = true
t.AccessMode = newAccessMode
t.AccessMode = teamPermission
}
if t.IncludesAllRepositories != includesAllRepositories {

View File

@ -91,12 +91,17 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
ctx.Data["CanForkToUser"] = canForkToUser
ctx.Data["Orgs"] = orgs
// TODO: this message should only be shown for the "current doer" when it is selected, just like the "new repo" page.
// msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", ctx.Doer.MaxCreationLimit())
if canForkToUser {
ctx.Data["ContextUser"] = ctx.Doer
ctx.Data["CanForkRepoInNewOwner"] = true
} else if len(orgs) > 0 {
ctx.Data["ContextUser"] = orgs[0]
ctx.Data["CanForkRepoInNewOwner"] = true
} else {
ctx.Data["CanForkRepo"] = false
ctx.Data["CanForkRepoInNewOwner"] = false
ctx.Flash.Error(ctx.Tr("repo.fork_no_valid_owners"), true)
return nil
}
@ -120,15 +125,6 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
// Fork render repository fork page
func Fork(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_fork")
if ctx.Doer.CanForkRepo() {
ctx.Data["CanForkRepo"] = true
} else {
maxCreationLimit := ctx.Doer.MaxCreationLimit()
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
ctx.Flash.Error(msg, true)
}
getForkRepository(ctx)
if ctx.Written() {
return
@ -141,7 +137,6 @@ func Fork(ctx *context.Context) {
func ForkPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.CreateRepoForm)
ctx.Data["Title"] = ctx.Tr("new_fork")
ctx.Data["CanForkRepo"] = true
ctxUser := checkContextUser(ctx, form.UID)
if ctx.Written() {

View File

@ -29,7 +29,6 @@ import (
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
repo_service "code.gitea.io/gitea/services/repository"
@ -303,17 +302,12 @@ var (
func dummyInfoRefs(ctx *context.Context) {
infoRefsOnce.Do(func() {
tmpDir, err := os.MkdirTemp(os.TempDir(), "gitea-info-refs-cache")
tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-info-refs-cache")
if err != nil {
log.Error("Failed to create temp dir for git-receive-pack cache: %v", err)
return
}
defer func() {
if err := util.RemoveAll(tmpDir); err != nil {
log.Error("RemoveAll: %v", err)
}
}()
defer cleanup()
if err := git.InitRepository(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil {
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)

View File

@ -87,17 +87,13 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User {
return nil
}
if !ctx.Doer.IsAdmin {
orgsAvailable := []*organization.Organization{}
for i := 0; i < len(orgs); i++ {
if orgs[i].CanCreateRepo() {
orgsAvailable = append(orgsAvailable, orgs[i])
}
var orgsAvailable []*organization.Organization
for i := 0; i < len(orgs); i++ {
if ctx.Doer.CanCreateRepoIn(orgs[i].AsUser()) {
orgsAvailable = append(orgsAvailable, orgs[i])
}
ctx.Data["Orgs"] = orgsAvailable
} else {
ctx.Data["Orgs"] = orgs
}
ctx.Data["Orgs"] = orgsAvailable
// Not equal means current user is an organization.
if uid == ctx.Doer.ID || uid == 0 {
@ -154,7 +150,7 @@ func createCommon(ctx *context.Context) {
ctx.Data["Licenses"] = repo_module.Licenses
ctx.Data["Readmes"] = repo_module.Readmes
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
ctx.Data["CanCreateRepoInDoer"] = ctx.Doer.CanCreateRepo()
ctx.Data["CanCreateRepoInDoer"] = ctx.Doer.CanCreateRepoIn(ctx.Doer)
ctx.Data["MaxCreationLimitOfDoer"] = ctx.Doer.MaxCreationLimit()
ctx.Data["SupportedObjectFormats"] = git.DefaultFeatures().SupportedObjectFormats
ctx.Data["DefaultObjectFormat"] = git.Sha1ObjectFormat

View File

@ -109,17 +109,13 @@ func LFSLocks(ctx *context.Context) {
}
// Clone base repo.
tmpBasePath, err := repo_module.CreateTemporaryPath("locks")
tmpBasePath, cleanup, err := repo_module.CreateTemporaryPath("locks")
if err != nil {
log.Error("Failed to create temporary path: %v", err)
ctx.ServerError("LFSLocks", err)
return
}
defer func() {
if err := repo_module.RemoveTemporaryPath(tmpBasePath); err != nil {
log.Error("LFSLocks: RemoveTemporaryPath: %v", err)
}
}()
defer cleanup()
if err := git.Clone(ctx, ctx.Repo.Repository.RepoPath(), tmpBasePath, git.CloneRepoOptions{
Bare: true,

View File

@ -59,6 +59,7 @@ func SettingsCtxData(ctx *context.Context) {
ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush
ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval
ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval
ctx.Data["CanConvertFork"] = ctx.Repo.Repository.IsFork && ctx.Doer.CanCreateRepoIn(ctx.Repo.Repository.Owner)
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
@ -786,7 +787,7 @@ func handleSettingsPostConvertFork(ctx *context.Context) {
return
}
if !ctx.Repo.Owner.CanCreateRepo() {
if !ctx.Doer.CanForkRepoIn(ctx.Repo.Owner) {
maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit()
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
ctx.Flash.Error(msg)

View File

@ -11,6 +11,8 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/cachegroup"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -115,7 +117,7 @@ func ParseCommitWithSignatureCommitter(ctx context.Context, c *git.Commit, commi
}
}
committerEmailAddresses, _ := user_model.GetEmailAddresses(ctx, committer.ID)
committerEmailAddresses, _ := cache.GetWithContextCache(ctx, cachegroup.UserEmailAddresses, committer.ID, user_model.GetEmailAddresses)
activated := false
for _, e := range committerEmailAddresses {
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
@ -209,10 +211,9 @@ func checkKeyEmails(ctx context.Context, email string, keys ...*asymkey_model.GP
}
if key.Verified && key.OwnerID != 0 {
if uid != key.OwnerID {
userEmails, _ = user_model.GetEmailAddresses(ctx, key.OwnerID)
userEmails, _ = cache.GetWithContextCache(ctx, cachegroup.UserEmailAddresses, key.OwnerID, user_model.GetEmailAddresses)
uid = key.OwnerID
user = &user_model.User{ID: uid}
_, _ = user_model.GetUser(ctx, user)
user, _ = cache.GetWithContextCache(ctx, cachegroup.User, uid, user_model.GetUserByID)
}
for _, e := range userEmails {
if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) {
@ -231,10 +232,7 @@ func HashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
if keyID == "" {
return nil
}
keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
KeyID: keyID,
IncludeSubKeys: true,
})
keys, err := cache.GetWithContextCache(ctx, cachegroup.GPGKeyWithSubKeys, keyID, asymkey_model.FindGPGKeyWithSubKeys)
if err != nil {
log.Error("GetGPGKeysByKeyID: %v", err)
return &asymkey_model.CommitVerification{
@ -249,10 +247,7 @@ func HashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
for _, key := range keys {
var primaryKeys []*asymkey_model.GPGKey
if key.PrimaryKeyID != "" {
primaryKeys, err = db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
KeyID: key.PrimaryKeyID,
IncludeSubKeys: true,
})
primaryKeys, err = cache.GetWithContextCache(ctx, cachegroup.GPGKeyWithSubKeys, key.PrimaryKeyID, asymkey_model.FindGPGKeyWithSubKeys)
if err != nil {
log.Error("GetGPGKeysByKeyID: %v", err)
return &asymkey_model.CommitVerification{
@ -272,8 +267,8 @@ func HashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
Name: name,
Email: email,
}
if key.OwnerID != 0 {
owner, err := user_model.GetUserByID(ctx, key.OwnerID)
if key.OwnerID > 0 {
owner, err := cache.GetWithContextCache(ctx, cachegroup.User, key.OwnerID, user_model.GetUserByID)
if err == nil {
signer = owner
} else if !user_model.IsErrUserNotExist(err) {
@ -381,7 +376,7 @@ func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *
}
}
committerEmailAddresses, err := user_model.GetEmailAddresses(ctx, committer.ID)
committerEmailAddresses, err := cache.GetWithContextCache(ctx, cachegroup.UserEmailAddresses, committer.ID, user_model.GetEmailAddresses)
if err != nil {
log.Error("GetEmailAddresses: %v", err)
}

View File

@ -182,7 +182,7 @@ func OrgAssignment(opts OrgAssignmentOptions) func(ctx *Context) {
return
}
for _, team := range teams {
if team.IncludesAllRepositories && team.AccessMode >= perm.AccessModeAdmin {
if team.IncludesAllRepositories && team.HasAdminAccess() {
shouldSeeAllTeams = true
break
}
@ -228,7 +228,7 @@ func OrgAssignment(opts OrgAssignmentOptions) func(ctx *Context) {
return
}
ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.AccessMode >= perm.AccessModeAdmin
ctx.Org.IsTeamAdmin = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.HasAdminAccess()
ctx.Data["IsTeamAdmin"] = ctx.Org.IsTeamAdmin
if opts.RequireTeamAdmin && !ctx.Org.IsTeamAdmin {
ctx.NotFound(err)

View File

@ -14,6 +14,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/cachegroup"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
@ -60,14 +61,14 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
doerID = doer.ID
}
const repoDoerPermCacheKey = "repo_doer_perm_cache"
p, err := cache.GetWithContextCache(ctx, repoDoerPermCacheKey, fmt.Sprintf("%d_%d", pr.BaseRepoID, doerID),
func() (access_model.Permission, error) {
repoUserPerm, err := cache.GetWithContextCache(ctx, cachegroup.RepoUserPermission, fmt.Sprintf("%d-%d", pr.BaseRepoID, doerID),
func(ctx context.Context, _ string) (access_model.Permission, error) {
return access_model.GetUserRepoPermission(ctx, pr.BaseRepo, doer)
})
},
)
if err != nil {
log.Error("GetUserRepoPermission[%d]: %v", pr.BaseRepoID, err)
p.AccessMode = perm.AccessModeNone
repoUserPerm.AccessMode = perm.AccessModeNone
}
apiPullRequest := &api.PullRequest{
@ -107,7 +108,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
RepoID: pr.BaseRepoID,
Repository: ToRepo(ctx, pr.BaseRepo, p),
Repository: ToRepo(ctx, pr.BaseRepo, repoUserPerm),
},
Head: &api.PRBranchInfo{
Name: pr.HeadBranch,

Some files were not shown because too many files have changed in this diff Show More