V20221228
into V20211228
@@ -55,6 +55,8 @@ coverage.all | |||
!/custom/conf/templates | |||
/custom/conf/app.ini | |||
!/custom/conf/app.ini.sample | |||
/custom/public/kanban | |||
/custom/public/annual-report | |||
/data | |||
/indexers | |||
/log | |||
@@ -0,0 +1,4 @@ | |||
# Ignore artifacts: | |||
dist | |||
build | |||
coverage |
@@ -0,0 +1 @@ | |||
{} |
@@ -85,8 +85,10 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G | |||
GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations/migration-test,$(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list -mod=vendor ./... | grep -v /vendor/))) | |||
WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f) | |||
WEBPACK_SOURCES := $(shell find web_src/js web_src/less web_src/vuepages -type f) | |||
WEBPACK_CONFIGS := webpack.config.js | |||
WEBPACK_CONFIGS_TMP := webpack_temp.config.js | |||
WEBPACK_CONFIGS_PRO := webpack_pro.config.js | |||
WEBPACK_DEST := public/js/index.js public/css/index.css | |||
WEBPACK_DEST_DIRS := public/js public/css public/fonts | |||
@@ -290,7 +292,7 @@ lint-backend: golangci-lint revive vet swagger-check swagger-validate test-vendo | |||
.PHONY: lint-frontend | |||
lint-frontend: node_modules | |||
npx eslint web_src/js webpack.config.js | |||
npx eslint web_src/js $(WEBPACK_CONFIGS) | |||
npx stylelint web_src/less | |||
.PHONY: watch-frontend | |||
@@ -504,7 +506,7 @@ install: $(wildcard *.go) | |||
build: frontend backend | |||
.PHONY: frontend | |||
frontend: node-check $(FOMANTIC_DEST) $(WEBPACK_DEST) | |||
frontend: node-check webpack_prepare $(FOMANTIC_DEST) $(WEBPACK_DEST) webpack_end | |||
.PHONY: backend | |||
backend: go-check generate $(EXECUTABLE) | |||
@@ -596,6 +598,19 @@ $(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules | |||
.PHONY: webpack | |||
webpack: $(WEBPACK_DEST) | |||
webpack_prepare: | |||
if [ $(filter bindata,$(TAGS_SPLIT))x = "bindata"x ]; then \ | |||
echo "prepare"; \ | |||
cp $(WEBPACK_CONFIGS) $(WEBPACK_CONFIGS_TMP); \ | |||
cp $(WEBPACK_CONFIGS_PRO) $(WEBPACK_CONFIGS); \ | |||
fi | |||
webpack_end: | |||
if [ $(filter bindata,$(TAGS_SPLIT))x = "bindata"x ]; then \ | |||
echo "end"; \ | |||
mv $(WEBPACK_CONFIGS_TMP) $(WEBPACK_CONFIGS); \ | |||
fi | |||
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json | node_modules | |||
rm -rf $(WEBPACK_DEST_DIRS) | |||
@@ -2,7 +2,7 @@ | |||
<h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1> | |||
[![release](https://img.shields.io/badge/release-1.21.11.1-blue)](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||
[![release](https://img.shields.io/badge/release-1.21.11.1-blue)](https://openi.pcl.ac.cn/OpenI/aiforge/releases/latest) | |||
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) | |||
@@ -10,7 +10,7 @@ | |||
启智AI开发协作平台是一个在线Web应用,旨在为人工智能算法、模型开发提供在线协同工作环境,它提供了<b>代码托管、数据集管理与共享、免费云端算力资源支持(GPU/NPU)、共享镜像</b>等功能。 | |||
[启智AI开发协作平台](https://git.openi.org.cn) 是使用本项目构建的在线服务,您可以直接点击链接访问试用。 | |||
[启智AI开发协作平台](https://openi.pcl.ac.cn) 是使用本项目构建的在线服务,您可以直接点击链接访问试用。 | |||
本项目是基于[Gitea](https://github.com/go-gitea/gitea)发展而来的,我们对其进行了Fork并基于此扩展了人工智能开发中需要的功能,如数据集管理和模型训练等。对于和代码托管相关的功能,您可以参考[Gitea的文档](https://docs.gitea.io/zh-cn/)。 | |||
@@ -20,7 +20,7 @@ | |||
后端服务涵盖了AI模型开发流水线,包括代码协同开发、数据管理、模型调试、训练、推理和部署等(*目前尚未支持模型部署*)。在不同的开发阶段,我们还将提供丰富的开发工具供用户使用,如数据标注、数据筛选、模型转换、模型压缩、代码检测等。我们也欢迎社区提供更多丰富的工具接入,提高利用平台进行开发的效率。 | |||
![系统架构图](assets/架构图.png) | |||
## 在线服务使用 | |||
本项目的在线服务平台的详细使用帮助文档,可参阅本项目[百科](https://git.openi.org.cn/OpenI/aiforge/wiki)内容。 | |||
本项目的在线服务平台的详细使用帮助文档,可参阅本项目[百科](https://openi.pcl.ac.cn/OpenI/aiforge/wiki)内容。 | |||
- 如何创建账号 | |||
- 如何创建组织及管理成员权限 | |||
- 如何创建项目仓库 | |||
@@ -39,13 +39,22 @@ | |||
[从源代码安装说明](https://docs.gitea.io/zh-cn/install-from-source/) | |||
## 授权许可 | |||
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://git.openi.org.cn/OpenI/aiforge/src/branch/develop/LICENSE) 文件中。 | |||
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://openi.pcl.ac.cn/OpenI/aiforge/src/branch/develop/LICENSE) 文件中。 | |||
## 需要帮助? | |||
如果您在使用或者开发过程中遇到问题,可以在以下渠道咨询: | |||
- 点击[这里](https://git.openi.org.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**) | |||
- 点击[这里](https://openi.pcl.ac.cn/OpenI/aiforge/issues)在线提交问题(点击页面右上角绿色按钮**创建任务**) | |||
- 加入微信群实时交流,获得进一步的支持 | |||
<img src="https://git.openi.org.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px /> | |||
<img src="https://openi.pcl.ac.cn/OpenI/aiforge/wiki/raw/img/wechatgroup.jpg" width=200px /> | |||
## 启智社区小白训练营: | |||
- 结合案例给大家详细讲解如何使用社区平台,帮助无技术背景的小白成长为启智社区达人 (https://git.openi.org.cn/zeizei/OpenI_Learning) | |||
- 结合案例给大家详细讲解如何使用社区平台,帮助无技术背景的小白成长为启智社区达人 (https://openi.pcl.ac.cn/zeizei/OpenI_Learning) | |||
## 平台引用 | |||
如果本平台对您的科研工作提供了帮助,可在论文致谢中加入: | |||
英文版:```Thanks for the support provided by OpenI Community (https://openi.pcl.ac.cn).``` | |||
中文版:```感谢启智社区提供的技术支持(https://openi.pcl.ac.cn)。``` | |||
如果您的成果中引用了本平台,也欢迎在下述开源项目中提交您的成果信息: | |||
https://openi.pcl.ac.cn/OpenIOSSG/references |
@@ -6,6 +6,7 @@ | |||
package cmd | |||
import ( | |||
"code.gitea.io/gitea/services/repository" | |||
"encoding/json" | |||
"fmt" | |||
"net/http" | |||
@@ -208,6 +209,21 @@ func runServ(c *cli.Context) error { | |||
os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) | |||
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey)) | |||
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) | |||
//set environment for pre-receive hook script | |||
if verb == "git-receive-pack" { | |||
os.Setenv(models.EnvRepoMaxFileSize, fmt.Sprint(setting.Repository.Upload.FileMaxSize)) | |||
os.Setenv(models.EnvRepoMaxSize, fmt.Sprint(setting.Repository.RepoMaxSize)) | |||
os.Setenv(models.EnvPushSizeCheckFlag, fmt.Sprint(setting.Repository.Upload.ShellFlag)) | |||
if setting.Repository.Upload.ShellFlag == repository.SHELL_FLAG_ON { | |||
env, _ := private.GetHookConfig(username, reponame) | |||
if env != nil && len(env) > 0 { | |||
repoSize := env[models.EnvRepoSize] | |||
if repoSize != "" { | |||
os.Setenv(models.EnvRepoSize, repoSize) | |||
} | |||
} | |||
} | |||
} | |||
//LFS token authentication | |||
if verb == lfsAuthenticateVerb { | |||
@@ -11,6 +11,11 @@ RUN_USER = git | |||
; Either "dev", "prod" or "test", default is "dev" | |||
RUN_MODE = dev | |||
; Is show MLOps | |||
MLOPS = true | |||
; If the MLOPS host is not set, the default setting is AppSubUrl | |||
MLOPS_HOST = https://dev-1-37.apulis.com.cn | |||
[repository] | |||
ROOT = | |||
SCRIPT_TYPE = bash | |||
@@ -1141,3 +1146,9 @@ growth_issue=0.2 | |||
growth_contributors=0.2 | |||
growth_commit=0.2 | |||
growth_comments=0.2 | |||
[grampus] | |||
USERNAME = | |||
PASSWORD = | |||
SERVER_HOST = |
@@ -24,11 +24,27 @@ | |||
.am-pt-20{ padding-top: 2.0rem !important;} | |||
.am-pt-30{ padding-top: 3.0rem !important;} | |||
.am-pl-30{ padding-left: 3.0rem !important;} | |||
.am-pl-50{ padding-left: 5.0em !important;} | |||
.am-ml-10{ margin-left: 1.0rem !important;} | |||
.am-ml-30{ margin-left: 3.0rem !important;} | |||
.am-pr-30{ padding-right: 3.0rem !important;} | |||
.am-mr-30{ margin-right: 3.0rem !important;} | |||
.am-lh-18{ line-height: 1.8em;} | |||
.nowrap{ | |||
white-space: nowrap; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
} | |||
.nowrap-2 { | |||
max-height: 2.837em; | |||
line-height: 1.4285em; | |||
overflow: hidden; | |||
display: -webkit-box; | |||
-webkit-line-clamp: 2; | |||
-webkit-box-orient: vertical; | |||
} | |||
.opacity5{ opacity:0.5;} | |||
.radius15{ border-radius:1.5rem !important; } | |||
.radius10{ border-radius:1.0rem !important; } | |||
@@ -42,16 +58,30 @@ | |||
box-shadow: 0 2px 4px 0 rgba(34,36,38,.3); | |||
} | |||
.ui.blue { | |||
color: #0366d6; | |||
} | |||
.ui.secondary.hometop.segment{ | |||
background: #DFE9F0; | |||
padding-top: 0; | |||
border: none; | |||
margin-bottom: 90px; | |||
margin-bottom: 11em; | |||
} | |||
.ui.secondary.hometop.segment #navbar{ | |||
z-index: 10; | |||
} | |||
.ui.secondary.c2net.segment{ | |||
padding-bottom: 3em; | |||
padding-top: 2em; | |||
color: rgba(0,0,0,.87); | |||
background-image: linear-gradient(to bottom left,var(--tw-gradient-stops)); | |||
--tw-gradient-from: #f5f3ff; | |||
--tw-gradient-stops: var(--tw-gradient-from),#fff,var(--tw-gradient-to,hsla(0,0%,100%,0)); | |||
--tw-gradient-to: rgba(219,234,254,0.4); | |||
border-top: 1px solid rgba(243,244,246,1)!important; | |||
border-bottom: 1px solid rgba(243,244,246,1)!important; | |||
} | |||
.hometop .ui.secondary.menu .active.item{ | |||
color: #000; | |||
@@ -68,6 +98,7 @@ | |||
.homebanner{ | |||
position: relative; | |||
padding: 100px 32px 80px; | |||
padding-bottom: 0; | |||
z-index: 9; | |||
} | |||
.homebanner .ui.header .sub.header{ | |||
@@ -75,10 +106,15 @@ | |||
} | |||
.bannerpic{ | |||
position: absolute; | |||
right: 50px; | |||
right: 0px; | |||
bottom: -64px; | |||
width: 560px; | |||
z-index: 6; | |||
} | |||
.homebanner .ui.button{ | |||
font-weight: normal; | |||
} | |||
.ui[class*="very padded"].segment.i-code{ | |||
padding-left: 6.0rem; | |||
} | |||
@@ -109,53 +145,254 @@ | |||
.i-code-pic > img{ | |||
margin-bottom: -3.0rem; | |||
} | |||
.i-env .ui.cards>.card{ | |||
box-shadow:none; | |||
} | |||
.i-env .ui.cards>.card>.image{ | |||
background: none; | |||
width: 60%; | |||
margin: auto; | |||
} | |||
.i-env .ui.cards>.card>.content{ | |||
border-top: none; | |||
} | |||
.leftline01{ | |||
#homenews{ | |||
position: relative; | |||
z-index: 9; | |||
bottom: -6em; | |||
} | |||
#homenews > p{ | |||
color: #BBBBBB; | |||
margin-left: 2.3em; | |||
} | |||
.homenews{ | |||
border-radius: 2em; | |||
background-color: rgba(16, 16, 16, .9); | |||
position: relative; | |||
padding-left: 2.3em !important; | |||
} | |||
.homeorg, .homepro, .homemodel, .i-env{ | |||
position: relative; | |||
padding-bottom: 3em; | |||
} | |||
.homenews::before{ | |||
content: ''; | |||
position: absolute; | |||
left: 3.0rem; | |||
left: 3em; | |||
top: 0; | |||
bottom: 0; | |||
border-left: 2px solid #505559; | |||
border-bottom: 2px solid #505559; | |||
border-radius: 0 0 0 2.0rem; | |||
width: 2.0rem; | |||
background-color: rgba(105, 192, 255, .4); | |||
width: 2px; | |||
} | |||
.homenews .time-since{ | |||
padding-left: 1em; | |||
color: #888888; | |||
} | |||
.homenews a{ | |||
color: #69C0FF; | |||
} | |||
.homenews .ui.list>.item>.content{ | |||
color: #E8E8E8; | |||
line-height: 1.8em; | |||
width: calc(100% - 3.75em) !important; | |||
} | |||
.homenews .ui.list>.item{ | |||
padding: 0; | |||
} | |||
.newslist{ | |||
height: 260px; | |||
overflow: hidden; | |||
} | |||
.leftline02{ | |||
.leftline01, .leftline03, .leftline04{ | |||
position: absolute; | |||
width: 5em; | |||
border-radius: 0 0 0 4.0em; | |||
border-left: 2px solid #3291F8; | |||
border-bottom: 2px solid #3291F8; | |||
top: -5em; | |||
bottom: 0; | |||
left: 2em; | |||
z-index: 6; | |||
} | |||
.leftline02, .leftline02-2 { | |||
position: absolute; | |||
left: 7.0em; | |||
top: -2px; | |||
bottom: 2px; | |||
height: auto; | |||
border-top: 2px solid #3291F8; | |||
border-right: 2px solid #3291F8; | |||
border-radius: 0 4.0em 0 0; | |||
width: 10em; | |||
z-index: 6; | |||
} | |||
.leftline02::after, .leftline02-2::after{ | |||
content: ''; | |||
position: absolute; | |||
left: 5rem; | |||
top: calc(-5.0rem - 2px); | |||
border-top: 2px solid #505559; | |||
border-right: 2px solid #505559; | |||
border-radius: 0 2.0rem 0 0; | |||
width: 17.5rem; | |||
height: 6.0rem; | |||
transform: translate(55%,50%); | |||
right: 0; | |||
bottom: 0; | |||
width: 1.0em; | |||
height: 1.0em; | |||
background-color: #FFF; | |||
border: 2px solid #3291F8; | |||
border-radius: 1em; | |||
} | |||
.leftline03{ | |||
border-radius: 4.0em 0 0 0; | |||
border-top: 2px solid #3291F8; | |||
border-bottom:none; | |||
top: -2.0em; | |||
} | |||
.leftline02-2{ | |||
border-color: rgba(105, 192, 255, .4); | |||
width: 7em; | |||
z-index: 5; | |||
} | |||
.leftline02-2::after{ | |||
border-color: rgba(105, 192, 255, .4); | |||
} | |||
.leftline04{ | |||
border-radius: 0; | |||
border-top: none; | |||
border-bottom: none; | |||
} | |||
.homeorg-tit{ | |||
padding-left: 5em !important; | |||
} | |||
.homeorg-tit::after{ | |||
content: ''; | |||
position: absolute; | |||
width: 1.6em; | |||
height: 1.6em; | |||
background-color: #FFF; | |||
border: 2px solid #3291F8; | |||
left: 2.3em; | |||
top: 1.3em; | |||
border-radius: 1em; | |||
z-index: 9; | |||
} | |||
.homeorg-list .card{ | |||
/* background-image: linear-gradient(#FFF, #FFF 60%, #DFF0EF) !important; */ | |||
box-shadow: none !important; | |||
} | |||
.homeorg-list .card .ui.small.header .content{ | |||
width: calc(100% - 3.75em); | |||
} | |||
.homepro-tit{ | |||
z-index: 9; | |||
position: relative; | |||
} | |||
.homepro-list, .homeorg-list{ | |||
position: relative; | |||
z-index: 9; | |||
padding: 1.0em 1.0em 3.0em; | |||
overflow: hidden; | |||
} | |||
.homepro-list .ui.card{ | |||
border-radius: 15px; | |||
background-color: #FFF; | |||
box-shadow: 0px 5px 10px 0px rgba(105, 192, 255, .3); | |||
border: 1px solid rgba(105, 192, 255, .4); | |||
/* min-height: 10.8em; */ | |||
} | |||
.homepro-list .ui.card>.content>.header{ | |||
line-height: 40px !important; | |||
} | |||
.homepro-list .swiper-pagination-bullet-active, .homeorg-list .swiper-pagination-bullet-active{ | |||
width: 40px; | |||
border-radius: 4px; | |||
} | |||
.i-env > div{ | |||
position: relative; | |||
} | |||
.event-list .ui.card>.image>img{ | |||
height: 146px !important; | |||
} | |||
@media only screen and (max-width: 767px) { | |||
.mobile-margin-left-20 { | |||
margin-left: 20px !important; | |||
} | |||
.mobile-text-align-center { | |||
text-align: center !important; | |||
} | |||
.mobile-justify-content-center { | |||
justify-content: center !important; | |||
} | |||
.am-mt-30{ margin-top: 1.5rem !important;} | |||
.ui.secondary.hometop.segment{ | |||
margin-bottom: 2.0rem; | |||
margin-bottom: 5.0rem; | |||
} | |||
.bannerpic, .i-code-pic{ | |||
.bannerpic{ | |||
display: none; | |||
} | |||
.i-code h2::before { | |||
left: calc(-5.0rem + 6px); | |||
#homenews{ | |||
bottom: -3em; | |||
} | |||
.i-code h2.am-bw::before{ | |||
left: calc(-4.0rem + 6px); | |||
#homenews > p { | |||
margin-left: 1.0em; | |||
} | |||
.homenews{ | |||
padding-left: 1.3em !important; | |||
border-radius: 1.5em; | |||
} | |||
.homenews::before{ | |||
left: 2em; | |||
} | |||
.homepro-tit > p{ | |||
background: #FFF; | |||
} | |||
.homeorg{ | |||
/* padding-left: 3.5em; */ | |||
} | |||
.homeorg-tit::after { | |||
left: -2.3em; | |||
} | |||
.homeorg-list{ | |||
margin: 0 0 2.0em !important; | |||
} | |||
.homeorg-list > .column{ | |||
width: 3em !important; | |||
margin-left: -0.5em; | |||
padding: 0.5rem 0 0 !important; | |||
} | |||
.homeorg-list .card{ | |||
background: none !important; | |||
} | |||
.homeorg-list .card > .content{ | |||
padding: 0 !important; | |||
} | |||
.homeorg-list > .column .card .ui.header>img{ | |||
width: 3.0em; | |||
height: 3.0em; | |||
border-radius: 2.0em; | |||
border: 2px solid #FFF; | |||
} | |||
.homeorg-list > .column .card .ui.header > .content{ | |||
display: none; | |||
} | |||
.leftline01{ | |||
width: calc(50% - 4.0rem); | |||
width: 4.0em; | |||
bottom: 4em; | |||
border-radius: 0 0 0 3.0em; | |||
} | |||
.leftline02, .leftline02-2{ | |||
left: 6.0em; | |||
top: calc(-4.0em - 2px); | |||
border-radius: 0 3.0em 3.0em 0; | |||
width: calc(50% - 6.0em); | |||
} | |||
.leftline02{ | |||
left: calc(50% - 1.0rem); | |||
top: calc(-3.5rem - 2px); | |||
.leftline02-2 { | |||
width: calc(50% - 8.0em); | |||
} | |||
.i-env .ui.cards>.card>.content .description{ | |||
display: none; | |||
} | |||
} | |||
@@ -181,4 +418,40 @@ | |||
@media only screen and (min-width: 1920px) { | |||
} | |||
/* rotation3D */ | |||
#app{ | |||
width: 800px; | |||
margin: 0 auto; | |||
} | |||
.rotation3D-baseMap{ | |||
position: absolute; left: 0; right: 0; top: 270px; margin: auto; | |||
width: 800px; height: 516px; | |||
background: url("../rotation3D/img/baseMap.png") no-repeat; | |||
background-size: cover; | |||
} | |||
.rotation3D-baseMap::before{ | |||
position: absolute; | |||
margin: auto; z-index: 99; | |||
left:50%; top: -150px; | |||
transform:translate(-50%,0); | |||
width: 342px; height: 470px; display: block; content: ''; | |||
background: url("../rotation3D/img/baseLogo.svg"); | |||
/*animation: 10s bounceUpDown infinite;*/ | |||
} | |||
.rotation3D-baseMap::after{ | |||
position: absolute; | |||
margin: auto; z-index: 100; | |||
left:50%; top:0; | |||
transform:translate(-50%,0); | |||
width: 110px; height: 86px; display: block; content: ''; | |||
background: url("../rotation3D/img/brain.svg"); | |||
animation: 6s bounceUpDown infinite; | |||
mix-blend-mode: color-dodge; | |||
} | |||
@keyframes bounceUpDown{ | |||
0% {transform: translate(-50%, 0px);} | |||
50% {transform: translate(-50%, -15px);} | |||
100% {transform: translate(-50%, 0px);} | |||
} |
@@ -0,0 +1 @@ | |||
/* placeholder-home.css */ |
@@ -0,0 +1 @@ | |||
/* placeholder.css */ |
@@ -0,0 +1,45 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- Generator: Adobe Illustrator 26.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | |||
viewBox="0 0 160 64" style="enable-background:new 0 0 160 64;" xml:space="preserve"> | |||
<style type="text/css"> | |||
.st0{fill:#FFFFFF;} | |||
.st1{display:none;fill:#FFFFFF;} | |||
</style> | |||
<g> | |||
<path class="st0" d="M105.3,33.3H87.1c-2.6,0.1-4,1.3-4,3.8v8.3c0.1,2.2,1.5,3.3,4,3.5h18c2.5-0.1,3.8-1.3,3.9-3.6v-8.2 | |||
c0.1-2-1.4-3.6-3.4-3.8C105.6,33.3,105.4,33.3,105.3,33.3z M104.6,43.9c-0.1,1-0.7,1.5-1.9,1.7H89.3c-1.3-0.3-1.8-0.7-1.9-1.7v-5.4 | |||
c0-1,0.8-1.9,1.8-1.9c0,0,0.1,0,0.1,0h13.1c1.1,0,2,0.8,2.1,2L104.6,43.9z"/> | |||
<path class="st0" d="M81,25.3v-4.7c0-1.1,0.9-2.1,2.1-2.1h19c1.4-0.1,2.1,0.5,2.1,1.8v3.3c0,1.1-0.7,1.7-1.9,1.7H82.8v3.2H105 | |||
c2.3,0,3.6-1.1,3.6-3.2v-6.4c0.2-1.8-1.1-3.4-2.8-3.6c-0.3,0-0.5,0-0.8,0h-9.7v-2.6h-4.6v2.6H80.3c-2.6,0-3.9,1.2-3.9,3.9v12.3 | |||
c0,5.8-0.9,11.6-2.6,17.1l4.3,0.8c1.8-5.5,2.7-11.3,2.8-17.1v-7.2H81z"/> | |||
<path class="st0" d="M116.2,30.4l4.4,2.4c2.6-1.9,4.4-4.6,5.1-7.6h7.8v-3.2h-7.1c0.2-1.3,0.3-2.6,0.3-3.9h6.6v-3.2h-12.3v-2h-4.6 | |||
V18h5.8c0,1.3-0.1,2.6-0.3,3.9h-6.7v3.3h5.8C120.4,27.5,118.6,29.4,116.2,30.4z"/> | |||
<path class="st0" d="M126.5,26.7c1.2,1.8,2.1,3.8,2.9,5.8h4.9c-0.8-2-1.8-4-2.9-5.8H126.5z"/> | |||
<path class="st0" d="M145.4,33.5h-24.7c-2.4,0.3-3.8,1.4-3.9,3.5v6.2h28.4v1.3c0,1.1-0.7,1.7-2.1,1.7h-19.7c-1.3,0-1.9-0.5-1.9-1.5 | |||
h-4.5V46c0,1.9,1.6,3.5,3.5,3.6h25.1c2.6-0.1,4-1.3,4-3.5v-9C149.2,35,147.5,33.5,145.4,33.5z M145,39.9h-23.7v-1.1 | |||
c0-1,0.8-1.9,1.8-1.9c0,0,0.1,0,0.1,0H143c1.3,0,2.1,0.7,2.1,1.9L145,39.9z"/> | |||
<path class="st0" d="M147.3,14h-8.2c-2.2,0.1-3.5,1.1-3.8,2.9v11.7c0.1,1.6,1.4,2.9,3.1,2.9h8.7c1.9-0.1,3.1-1.1,3.1-2.9V17 | |||
C150.4,15.4,149.4,14.3,147.3,14z M146,26.2c0,1.4-0.7,2.1-1.9,2.1h-2.4c-1,0-1.8-0.8-1.8-1.8c0-0.1,0-0.1,0-0.2v-7 | |||
c0-1,0.8-1.9,1.8-1.9c0,0,0.1,0,0.1,0h2c1.1,0,2.1,0.8,2.1,1.9l0,0L146,26.2z"/> | |||
</g> | |||
<path class="st1" d="M67.2,44.1V20c0-2.6-1.4-5.1-3.7-6.4l-20.9-12c-2.3-1.3-5.1-1.3-7.4,0l-20.9,12c-2.3,1.3-3.7,3.8-3.7,6.4v24.1 | |||
c0,2.6,1.4,5.1,3.7,6.4l20.9,12c2.3,1.3,5.1,1.3,7.4,0l20.9-12C65.8,49.2,67.2,46.7,67.2,44.1z"/> | |||
<path class="st0" d="M61.9,15.4L42,3.9c-1.9-1.1-4.3-1.1-6.2,0L15.9,15.4c-1.9,1.1-3.1,3.2-3.1,5.4v22.9c0,2.2,1.2,4.3,3.1,5.4 | |||
l3.8,2c0.8,0.4,0.8,1,0.8,1.9c0,0,0,0.1,0,0.1c0.1,1.6,1.8,3.5,4.2,3.5c2.3,0,4.3-1.9,4.4-4.2c0-1.6-0.8-3.1-2.3-3.9 | |||
c-0.6-0.3-1.7-0.5-2.9-0.4c-0.9,0.1-1,0.6-2.8-0.5l-2.8-1.6c-0.8-0.5-1.7-1.3-1.6-2.3V22c0-1.8,0.8-2.8,2.1-3.5L37,7.8 | |||
C38.1,7,40.2,7.2,41.5,8l16.4,9.5c2.9,1.6,3,3,3,4v19.7c0,2.3-1.5,4-2.3,4.5l-15.1,8.5C42.8,54.5,42,54,42,53.3l0-2.5 | |||
c0-0.1,0-0.3,0-0.4v-2.5c0-0.8,0.4-1.6,1.1-2l8.8-5.7c1.4-0.9,2-1.7,2-3.8L53.7,28c0-1,0.4-1.9,1.2-2.5c1.5-1.3,2-3.7,0.8-5.6 | |||
c-0.8-1.4-2.4-2.2-4-2c-1.6,0.1-2.8,1-3.5,2.4c-0.5,1-0.6,2.2-0.3,3.3c0.2,0.8,0.7,1.4,1.3,2c0.7,0.6,1.2,1.5,1.2,2.5v7.2 | |||
c0,1.1-0.5,2.1-1.5,2.7l-5.5,2.8c-0.7,0.5-1.6,0-1.6-0.8l-0.2-17.1c0-1,0.5-1.9,1.2-2.5c0.4-0.3,0.7-0.8,1-1.3 | |||
c0.7-1.3,0.7-2.9-0.1-4.3c-0.8-1.4-2.5-2.2-4.1-2.1c-2.9,0.3-4.6,3.1-3.8,5.7c0.2,0.8,0.7,1.4,1.3,2c0.7,0.6,1.2,1.5,1.2,2.5v9.9 | |||
c0,0.8-0.8,1.3-1.5,0.9L34,32.5c-0.7-0.4-1.2-1.2-1.2-2.1v-2.2c0-1,0.4-1.9,1.2-2.5c1.5-1.3,2-3.7,0.8-5.6c-0.8-1.3-2.4-2.1-4-2 | |||
c-2.9,0.2-4.7,3.1-3.8,5.7c0.2,0.8,0.7,1.5,1.3,2c0.7,0.6,1.2,1.5,1.2,2.5l0,3.5c0,1,0,2,1.6,3.1l5.5,3c0.7,0.4,1.2,1.2,1.2,2.1v4.5 | |||
c0,0.8-0.8,1.3-1.5,0.9L26.6,41c-0.7-0.4-1.2-1.2-1.2-2.1l-0.2-6.1c0-1,0.4-1.8,1.1-2.5c1.4-1.3,1.9-3.4,0.9-5.3 | |||
c-0.8-1.4-2.4-2.3-4-2.2c-2.9,0.2-4.6,3-3.8,5.6c0.2,0.7,0.7,1.4,1.2,1.9c0.7,0.6,1.1,1.5,1.1,2.5l-0.5,6.8c0,1.9,0.3,2.8,1.8,3.5 | |||
l11.8,6.3c1,0.6,1.6,1.7,1.6,2.8l0,3.1c0,3.1,4.3,5.7,8.7,3.3l16.4-9.8c1.9-1,3.2-3,3.4-5.2V20.7C65,18.5,63.8,16.5,61.9,15.4z | |||
M24.2,50.7c1.1,0,2,0.9,2,2c0,1.1-0.9,2-2,2c-1.1,0-2-0.9-2-2C22.2,51.7,23.1,50.7,24.2,50.7z M48.7,21.5c0-1.1,0.9-2,2-2 | |||
s2,0.9,2,2c0,1.1-0.9,2-2,2S48.7,22.6,48.7,21.5z M30.6,23.8c-1.1,0-2-0.9-2-2s0.9-2,2-2c1.1,0,2,0.9,2,2S31.8,23.8,30.6,23.8z | |||
M22.2,26.4c0-1.1,0.9-2,2-2c1.1,0,2,0.9,2,2s-0.9,2-2,2C23.1,28.4,22.2,27.5,22.2,26.4z M40,17.9c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2 | |||
c1.1,0,2,0.9,2,2C42,17,41.1,17.9,40,17.9z"/> | |||
</svg> |
@@ -0,0 +1 @@ | |||
/* placeholder-home.js */ |
@@ -0,0 +1 @@ | |||
/* placeholder.js */ |
@@ -0,0 +1,1250 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | |||
viewBox="0 0 342 470" style="enable-background:new 0 0 342 470;" xml:space="preserve"> | |||
<style type="text/css"> | |||
.st0{fill:url(#SVGID_1_);} | |||
.st1{fill:url(#Shape_00000122695819581411568980000009497889965072766366_);} | |||
.st2{opacity:0.1;} | |||
.st3{fill:none;stroke:#FFFFFF;stroke-width:0.28;} | |||
.st4{fill:url(#Shape-3_00000108267555528354346850000003067232586542845062_);} | |||
.st5{fill:url(#Shape-4_00000170962892825198117240000016507644302800111752_);} | |||
.st6{fill:url(#Shape-5_00000152233876515447885360000003511306910976081557_);} | |||
.st7{fill:url(#Shape-6_00000130648495190739671840000000046973013901678768_);} | |||
.st8{opacity:0.3;} | |||
.st9{fill:url(#Shape-8_00000067238065472127621960000006688745836265094844_);} | |||
.st10{fill:url(#Shape-9_00000092456954712643526090000013987617450999243420_);} | |||
.st11{fill:url(#Shape-10_00000071530715909169841760000001219864674538182321_);} | |||
.st12{fill:url(#Shape-11_00000165230558524865277990000001984831809446982565_);} | |||
.st13{fill:url(#Shape-12_00000156578567257238376930000013792221941525112461_);} | |||
.st14{opacity:0.7;fill:url(#Shape-13_00000008126306159044654420000001950760845656686511_);enable-background:new ;} | |||
.st15{fill:url(#Shape-14_00000016065736020663034800000004369015118147551141_);} | |||
.st16{fill:url(#Shape-15_00000181064846143977355770000013065309429994795172_);} | |||
.st17{fill:url(#Shape-16_00000031208842933427054440000012996998913138616501_);} | |||
.st18{fill:url(#Shape-17_00000042004590833602562210000013828198405825221524_);} | |||
.st19{fill:url(#Shape-18_00000162343186294817706670000009737502018486435718_);} | |||
.st20{fill:url(#Shape-19_00000110467135021763194980000003285448470310495882_);} | |||
.st21{fill:#FF9E00;} | |||
.st22{fill:#FFFA00;} | |||
.st23{fill:#FFD500;} | |||
.st24{fill:#0670F4;} | |||
.st25{fill:#0E36CA;} | |||
.st26{fill:#0D46DA;} | |||
.st27{fill:#00FCFF;} | |||
.st28{fill:#C1FDFF;} | |||
.st29{fill:#D5FDFF;} | |||
.st30{fill:url(#SVGID_00000028292880454227640480000007941185209136214710_);} | |||
.st31{fill:url(#SVGID_00000154385744779633976780000005015552716553969280_);} | |||
.st32{fill:url(#SVGID_00000006709808785551018910000013165181589207510424_);} | |||
.st33{fill:url(#SVGID_00000095338393378708966320000014319984612975200675_);} | |||
.st34{fill:url(#SVGID_00000068668409858590940130000015473191643683796407_);} | |||
.st35{fill:url(#SVGID_00000028288024236176209350000016805078944731773867_);} | |||
.st36{opacity:0.9;fill:url(#SVGID_00000052083955581105786130000014221709174240235702_);enable-background:new ;} | |||
.st37{opacity:0.9;fill:url(#SVGID_00000054967982296223834670000016083193669441212831_);enable-background:new ;} | |||
.st38{opacity:0.9;fill:url(#SVGID_00000058550955804546596240000010683206481702016433_);enable-background:new ;} | |||
.st39{opacity:0.9;fill:url(#SVGID_00000163043534529015062880000009083868386549199238_);enable-background:new ;} | |||
.st40{opacity:0.7;} | |||
.st41{fill:url(#SVGID_00000022541865909815407100000001966414287944324258_);} | |||
.st42{fill:url(#SVGID_00000147900851745622378370000015873506469329059251_);} | |||
.st43{fill:url(#SVGID_00000145055013217083447570000004918368404700113808_);} | |||
.st44{opacity:0.9;fill:url(#SVGID_00000078738074373176931370000005247352960480890810_);enable-background:new ;} | |||
.st45{opacity:0.9;fill:url(#SVGID_00000154427465430184299350000014008109346215955108_);enable-background:new ;} | |||
.st46{opacity:0.9;fill:url(#SVGID_00000026130062154451319530000009591557964573573052_);enable-background:new ;} | |||
.st47{opacity:0.9;fill:url(#SVGID_00000071535581989694575550000006424478893357759619_);enable-background:new ;} | |||
.st48{fill:url(#SVGID_00000103264614985634555370000015439510514986295434_);} | |||
.st49{fill:url(#SVGID_00000026846880724049010360000004318742928612435385_);} | |||
.st50{fill:url(#SVGID_00000097491734475124487120000017280595404574408586_);} | |||
.st51{opacity:0.9;fill:url(#SVGID_00000132797865532330196930000016589769163445796508_);enable-background:new ;} | |||
.st52{opacity:0.9;fill:url(#SVGID_00000168112339364709499370000010561862793508189619_);enable-background:new ;} | |||
.st53{opacity:0.9;fill:url(#SVGID_00000016776904099699711580000006027847166532311213_);enable-background:new ;} | |||
.st54{opacity:0.9;fill:url(#SVGID_00000046319016626353319110000001507482231880905125_);enable-background:new ;} | |||
.st55{fill:url(#SVGID_00000015347636505443995880000009639486512516552109_);} | |||
.st56{fill:url(#SVGID_00000183235989598679666860000008675740694265734795_);} | |||
.st57{fill:url(#SVGID_00000057145868332245323390000003648288391810730120_);} | |||
.st58{opacity:0.9;fill:url(#SVGID_00000052089054271150011360000006380279030166986132_);enable-background:new ;} | |||
.st59{opacity:0.9;fill:url(#SVGID_00000053524630414669161260000014167420226363617973_);enable-background:new ;} | |||
.st60{opacity:0.9;fill:url(#SVGID_00000102509884178040304740000009453014021517178797_);enable-background:new ;} | |||
.st61{opacity:0.9;fill:url(#SVGID_00000030477380050973659050000012784180663325317543_);enable-background:new ;} | |||
.st62{fill:url(#SVGID_00000091715724373744771480000018381079266578924952_);} | |||
.st63{fill:url(#SVGID_00000119802247028098950750000007807224728487343238_);} | |||
.st64{fill:#DCCAFF;} | |||
.st65{fill:url(#SVGID_00000168828291550228940780000008712892453049646482_);} | |||
.st66{opacity:0.1;fill:url(#Shape-25_00000064352820151925633680000000538003253376652973_);enable-background:new ;} | |||
.st67{opacity:0.1;fill:url(#Shape-26_00000058578484037833382700000001443243348334247842_);enable-background:new ;} | |||
.st68{opacity:0.2;fill:url(#Shape-27_00000021087063130939724030000008785947539258868150_);enable-background:new ;} | |||
.st69{opacity:0.4;fill:url(#Shape-28_00000139984370226791585180000007783386812744376985_);enable-background:new ;} | |||
.st70{opacity:0.3;fill:url(#Shape-29_00000042729723539120537750000007554992902734426797_);enable-background:new ;} | |||
.st71{opacity:0.8;fill:url(#Shape-30_00000116193469163751414410000014389267924888205229_);enable-background:new ;} | |||
.st72{opacity:0.3;fill:url(#Shape-31_00000106850944086934364040000006754821160458469791_);enable-background:new ;} | |||
.st73{opacity:0.9;} | |||
.st74{fill:url(#SVGID_00000009548216845904308100000007854279399613521282_);} | |||
.st75{fill:url(#SVGID_00000005946657920056642410000013858148092140242342_);} | |||
.st76{fill:url(#SVGID_00000073713187741169993790000000518297220273631625_);} | |||
.st77{fill:url(#SVGID_00000059309463566938012110000017242277441342374043_);} | |||
.st78{opacity:0.2;fill:url(#Shape-33_00000092442636229672753120000015708534850319685025_);enable-background:new ;} | |||
.st79{opacity:0.2;fill:url(#Shape-34_00000134958529537706583570000013531478499757925764_);enable-background:new ;} | |||
.st80{opacity:0.3;fill:url(#Shape-35_00000183966536320522018980000015656474600764335774_);enable-background:new ;} | |||
.st81{fill:url(#Shape-36_00000170990332344004291830000018267268661377741450_);} | |||
.st82{fill:url(#Shape-37_00000081606422858984196810000010929270223930003892_);} | |||
.st83{fill:url(#Shape-38_00000012458674817368296390000007645479619492313786_);} | |||
.st84{fill:url(#Shape-39_00000116945922626526355790000011743352812616268682_);} | |||
.st85{opacity:0.3;fill:url(#Shape-40_00000086677837877112201530000004355660159683157898_);enable-background:new ;} | |||
.st86{fill:url(#Shape-41_00000181072257639661971490000013152471877230270889_);} | |||
.st87{fill:url(#Shape-42_00000029013825415492016220000014598397158487279492_);} | |||
.st88{opacity:0.2;fill:url(#Shape-43_00000057870855683888429600000006717933375613710484_);enable-background:new ;} | |||
.st89{fill:url(#Shape-44_00000043445091589589969460000004866174366055113897_);} | |||
.st90{fill:url(#SVGID_00000049914507342881612690000006947427049092657283_);} | |||
.st91{fill:url(#SVGID_00000062886325047818555730000010750219106956600486_);} | |||
.st92{fill:url(#SVGID_00000039855526018585779520000008358089142857900196_);} | |||
.st93{fill:url(#SVGID_00000159453068813583809450000016564471048711535496_);} | |||
.st94{fill:url(#SVGID_00000134221892980377044910000000824006706549954479_);} | |||
.st95{fill:url(#Shape-45_00000121983145399346318480000017454074114138980021_);} | |||
.st96{fill:url(#Shape-46_00000056413757225724440660000013227819678561858705_);} | |||
.st97{fill:url(#SVGID_00000081614301598355860140000013115952882911281563_);} | |||
.st98{fill:url(#SVGID_00000018926841404133431160000004363987530718928829_);} | |||
.st99{fill:url(#SVGID_00000170973902844277814280000011391250150203830458_);} | |||
.st100{fill:url(#SVGID_00000016781894814342093450000000425864608846005892_);} | |||
.st101{fill:url(#SVGID_00000085245970713286330730000013740508628486946721_);} | |||
.st102{fill:url(#SVGID_00000163055017777087957720000005454895562531643312_);} | |||
.st103{fill:url(#SVGID_00000077302191023187935940000015456585497225833140_);} | |||
.st104{fill:url(#SVGID_00000180339343354334441320000012833881165672081034_);} | |||
.st105{fill:url(#SVGID_00000096033939601719065930000002030735641467470505_);} | |||
.st106{opacity:0.4;fill:url(#Shape-48_00000094605520090581675820000009029972832137256374_);enable-background:new ;} | |||
.st107{opacity:0.4;fill:url(#Shape-49_00000081627112398329943590000003802171881972280741_);enable-background:new ;} | |||
.st108{opacity:0.4;} | |||
.st109{fill:#FFFFFF;} | |||
.st110{fill:url(#SVGID_00000023984037287111958640000000638087594766373052_);} | |||
.st111{fill:url(#SVGID_00000065068286938501304560000001747638327604614276_);} | |||
.st112{fill:url(#SVGID_00000118362122578489129280000008325696647302340015_);} | |||
.st113{fill:url(#SVGID_00000063625050672048026430000010620158812897610639_);} | |||
.st114{fill:url(#SVGID_00000160160255246035492840000011145811528394086550_);} | |||
.st115{fill:url(#SVGID_00000137096698933832844710000001994592634361541522_);} | |||
.st116{fill:url(#SVGID_00000028283920064565737470000017374870854956641424_);} | |||
.st117{fill:url(#Shape-50_00000008114939600830930650000006400205404160199078_);} | |||
.st118{fill:url(#Shape-51_00000165940789856988529460000001895047031287773092_);} | |||
.st119{fill:url(#Shape-52_00000071536093562577904190000014204231495092591776_);} | |||
.st120{fill:url(#SVGID_00000104667689609266550840000001590343809853163664_);} | |||
.st121{fill:url(#SVGID_00000174565000182971844360000009855163291799870106_);} | |||
.st122{fill:url(#SVGID_00000101801150018074089040000006999532880097025439_);} | |||
.st123{fill:url(#SVGID_00000010285869994318200550000017907693555620668052_);} | |||
.st124{fill:url(#SVGID_00000040553462087727254830000018074551645053105837_);} | |||
.st125{fill:#FFCDA4;} | |||
.st126{fill:#F2B588;} | |||
.st127{fill:url(#SVGID_00000151537022301235923430000015311765200172483981_);} | |||
.st128{fill:url(#SVGID_00000095318817484922321070000012112191509524194441_);} | |||
.st129{opacity:0.3;fill:url(#SVGID_00000090282202284851546380000005436398103980201888_);enable-background:new ;} | |||
.st130{fill:url(#SVGID_00000176044504512350597090000016535704918049643914_);} | |||
.st131{fill:url(#SVGID_00000147205081033068325400000014263989530912263078_);} | |||
.st132{fill:#0726A5;} | |||
.st133{fill:#FFCBA2;} | |||
</style> | |||
<g id="图层_2_00000028314812550504214100000011184653534585739162_"> | |||
<g id="图层_1-2"> | |||
<radialGradient id="SVGID_1_" cx="168.6775" cy="1400.7551" r="197.2173" gradientTransform="matrix(1 0 0 1 0 -1216.3)" gradientUnits="userSpaceOnUse"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.4335" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
<stop offset="0.81" style="stop-color:#D8E6FF;stop-opacity:0.12"/> | |||
</radialGradient> | |||
<path class="st0" d="M294.2,344.5l-1.8-2.3c-0.2-0.3-0.4-0.7-0.8-1c-16.1-21.4-48.4-55.7-48.4-111.1c0-68.9,4.3-157.7,24.4-231.9 | |||
H65.9c20.3,74.1,24.4,163,24.4,231.9c0,58.3-30.4,93.3-45.5,114.5h0.9c-0.3,0.9-0.4,1.8-0.4,2.7c0,16.9,55.7,30.6,124.5,30.6 | |||
s124.4-13.7,124.4-30.6c0-0.9-0.2-1.9-0.4-2.7L294.2,344.5z"/> | |||
<g id="main_system"> | |||
<linearGradient id="Shape_00000178178190290349774510000015233560893010072992_" gradientUnits="userSpaceOnUse" x1="183.1534" y1="-517.9744" x2="328.6692" y2="-492.206" gradientTransform="matrix(1 0 0 -1 0 -136)"> | |||
<stop offset="0" style="stop-color:#91BFDB"/> | |||
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape" style="fill:url(#Shape_00000178178190290349774510000015233560893010072992_);" d="M397.1,375.7 | |||
c0,24.4-110.9,33.1-207.2,33.1S90.5,394,90.5,375.7s3.2-33.1,99.4-33.1S397.1,352.8,397.1,375.7z"/> | |||
<g id="Group"> | |||
<g id="Shape-2" class="st2"> | |||
<line class="st3" x1="93.1" y1="395.7" x2="93.2" y2="418"/> | |||
<line class="st3" x1="115.2" y1="401.9" x2="115.2" y2="424.1"/> | |||
<line class="st3" x1="141" y1="405.8" x2="141" y2="428"/> | |||
<line class="st3" x1="196.2" y1="405.9" x2="196.2" y2="428"/> | |||
<line class="st3" x1="221.8" y1="402.1" x2="221.8" y2="424.2"/> | |||
<line class="st3" x1="243.8" y1="395.9" x2="243.8" y2="418.1"/> | |||
<line class="st3" x1="260.7" y1="387.9" x2="260.7" y2="409.9"/> | |||
<line class="st3" x1="271.2" y1="378.6" x2="271.2" y2="399.4"/> | |||
<line class="st3" x1="65.4" y1="378.4" x2="65.4" y2="399.4"/> | |||
<line class="st3" x1="76.1" y1="387.7" x2="76.1" y2="409.7"/> | |||
</g> | |||
<linearGradient id="Shape-3_00000145760133362343895620000015494310892322915463_" gradientUnits="userSpaceOnUse" x1="-4695.894" y1="-1404.8131" x2="-4695.0723" y2="-1404.8131" gradientTransform="matrix(260.74 0 0 150.88 1224468.75 212327.9531)"> | |||
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/> | |||
<stop offset="0.12" style="stop-color:#FEFEFE"/> | |||
<stop offset="0.52" style="stop-color:#C3D0D7"/> | |||
<stop offset="0.83" style="stop-color:#D2DDE2"/> | |||
<stop offset="1" style="stop-color:#CDE1E4"/> | |||
</linearGradient> | |||
<path id="Shape-3" style="fill:url(#Shape-3_00000145760133362343895620000015494310892322915463_);" d="M274.5,367.4v-18.7 | |||
h-17.1c-4.5-2.4-9.2-4.6-14-6.2c-41.7-15.1-109.2-15.2-150.6-0.2c-4.9,1.8-9.7,3.9-14.3,6.5H61.9v19.3 | |||
c-0.1,10.5,9.4,20.9,31.3,28.9c41.7,15.1,109.1,15.2,150.6,0.2C266.2,388.9,274.7,378,274.5,367.4z"/> | |||
<linearGradient id="Shape-4_00000071556748890164118890000017416756969037191558_" gradientUnits="userSpaceOnUse" x1="61.7996" y1="-1129.3312" x2="274.7628" y2="-1129.3312" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#D6DCDF"/> | |||
<stop offset="0.8" style="stop-color:#FBFBFC"/> | |||
<stop offset="1" style="stop-color:#EEECEE"/> | |||
</linearGradient> | |||
<path id="Shape-4" style="fill:url(#Shape-4_00000071556748890164118890000017416756969037191558_);" d="M243.8,374.8 | |||
c-41.4,15-108.9,15-150.6-0.2s-41.9-39.6-0.4-54.7s108.9-15,150.6,0.2S285.2,359.8,243.8,374.8z"/> | |||
<linearGradient id="Shape-5_00000180340779580305511340000000771215996181478573_" gradientUnits="userSpaceOnUse" x1="166.7489" y1="-1151.7883" x2="171.0751" y2="-1177.7562" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#66EDF0"/> | |||
<stop offset="0.52" style="stop-color:#FCFCFC"/> | |||
<stop offset="1" style="stop-color:#FDFDFD"/> | |||
</linearGradient> | |||
<path id="Shape-5" style="fill:url(#Shape-5_00000180340779580305511340000000771215996181478573_);" d="M153.8,373.5 | |||
c9.7,0.7,19.5,0.5,29.2-0.2l6.4,9.1c-13.7,1.6-27.4,1.6-41.1,0L153.8,373.5z"/> | |||
<linearGradient id="Shape-6_00000059309760233537008680000015072254621288308152_" gradientUnits="userSpaceOnUse" x1="-4691.7974" y1="-1403.4999" x2="-4691.1182" y2="-1403.5109" gradientTransform="matrix(210.65 0 0 93.82 988467.6875 132026.375)"> | |||
<stop offset="0" style="stop-color:#5BEFF1"/> | |||
<stop offset="0.48" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-6" style="fill:url(#Shape-6_00000059309760233537008680000015072254621288308152_);" d="M243.8,366.8 | |||
c-33.4,9.3-87.8,9.2-121.5-0.2c-33.6-9.4-33.8-24.6-0.4-34c33.4-9.3,87.8-9.2,121.5,0.2S277.2,357.5,243.8,366.8z"/> | |||
<g id="Shape-7" class="st8"> | |||
<polyline class="st3" points="243.4,320.2 93.1,374.7 93.2,396.8 "/> | |||
<polyline class="st3" points="221.2,314 115.2,380.8 115.2,403.1 "/> | |||
<polyline class="st3" points="195.5,310.1 141,384.8 141,406.9 "/> | |||
<polyline class="st3" points="140.4,310.1 196.2,384.9 196.2,407 "/> | |||
<polyline class="st3" points="114.7,313.9 221.8,381 221.8,403.2 "/> | |||
<polyline class="st3" points="92.7,320 243.8,374.9 243.8,397 "/> | |||
<polyline class="st3" points="75.8,327.9 260.7,366.9 260.7,388.8 "/> | |||
<polyline class="st3" points="65.3,337.3 271.3,357.6 271.3,378.4 "/> | |||
<line class="st3" x1="61.8" y1="347.3" x2="274.8" y2="347.5"/> | |||
<polyline class="st3" points="271.1,337.6 65.4,357.3 65.4,378.4 "/> | |||
<polyline class="st3" points="260.3,328.1 76.1,366.7 76.1,388.7 "/> | |||
</g> | |||
<radialGradient id="Shape-8_00000158733441478465335610000004571177335950995117_" cx="-4688.001" cy="-1394.5853" r="0.5038" gradientTransform="matrix(179.29 0 0 65.1 840676.625 91121.4297)" gradientUnits="userSpaceOnUse"> | |||
<stop offset="0.52" style="stop-color:#6A88CB"/> | |||
<stop offset="1" style="stop-color:#C2C6CA;stop-opacity:0"/> | |||
</radialGradient> | |||
<path id="Shape-8" style="fill:url(#Shape-8_00000158733441478465335610000004571177335950995117_);" d="M231.2,369 | |||
c-35.3,12.8-92.7,12.7-128.1-0.1c-35.5-12.8-35.7-33.7-0.4-46.5s92.7-12.7,128.1,0.1S266.6,356.2,231.2,369z"/> | |||
<linearGradient id="Shape-9_00000146497141956463728220000004586364667823936442_" gradientUnits="userSpaceOnUse" x1="93.7691" y1="-1127.861" x2="239.3361" y2="-1127.4558" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/> | |||
<stop offset="0.12" style="stop-color:#FEFEFE"/> | |||
<stop offset="0.52" style="stop-color:#C3D0D7"/> | |||
<stop offset="0.83" style="stop-color:#C8CED3"/> | |||
<stop offset="1" style="stop-color:#C2C6CA"/> | |||
</linearGradient> | |||
<path id="Shape-9" style="fill:url(#Shape-9_00000146497141956463728220000004586364667823936442_);" d="M218.8,364.5 | |||
c-28.5,10.3-74.7,10.3-103.4-0.1s-28.8-27.2-0.3-37.6s74.7-10.3,103.4,0.1S247.3,354.1,218.8,364.5z"/> | |||
<linearGradient id="Shape-10_00000031206731980968605630000001700956864725006976_" gradientUnits="userSpaceOnUse" x1="-4693.501" y1="-1404.2642" x2="-4692.6792" y2="-1404.2642" gradientTransform="matrix(227.64 0 0 131.39 1068501.75 184833.1719)"> | |||
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/> | |||
<stop offset="0.12" style="stop-color:#FEFEFE"/> | |||
<stop offset="0.52" style="stop-color:#C3D0D7"/> | |||
<stop offset="0.83" style="stop-color:#D2DDE2"/> | |||
<stop offset="1" style="stop-color:#CDE1E4"/> | |||
</linearGradient> | |||
<path id="Shape-10" style="fill:url(#Shape-10_00000031206731980968605630000001700956864725006976_);" d="M261.1,326l-0.2-11.9 | |||
l-10.3-2.6c-5.3-3.5-10.8-6.2-16.8-8.3c-36.4-13.1-95.1-13.3-131.1-0.1c-6,2.1-11.6,4.9-16.9,8.4L75.7,314l0.2,12.6v1.1l0,0 | |||
c0.7,8.3,9.9,16.5,27.3,22.9c36.4,13.1,95.1,13.3,131.1,0.1C253,343.9,261.9,334.9,261.1,326z"/> | |||
<linearGradient id="Shape-11_00000085950511406540719030000013699986810275359133_" gradientUnits="userSpaceOnUse" x1="-4693.4814" y1="-1404.1786" x2="-4692.3643" y2="-1404.1786" gradientTransform="matrix(227.38 0 0 131.39 1067276 184810.1719)"> | |||
<stop offset="0" style="stop-color:#D6DCDF"/> | |||
<stop offset="0.8" style="stop-color:#FBFBFC"/> | |||
<stop offset="1" style="stop-color:#EEECEE"/> | |||
</linearGradient> | |||
<path id="Shape-11" style="fill:url(#Shape-11_00000085950511406540719030000013699986810275359133_);" d="M234,339 | |||
c-36,13.1-94.8,13-131.1-0.1s-36.5-34.5-0.4-47.6c36-13.1,94.7-13,131.1,0.1C269.9,304.5,270.1,325.8,234,339z"/> | |||
<linearGradient id="Shape-12_00000013892298855937169510000007985557031648015280_" gradientUnits="userSpaceOnUse" x1="168.7642" y1="-1136.3141" x2="219.9114" y2="-1132.152" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#66EDF0"/> | |||
<stop offset="0.52" style="stop-color:#FCFCFC"/> | |||
<stop offset="1" style="stop-color:#FDFDFD"/> | |||
</linearGradient> | |||
<path id="Shape-12" style="fill:url(#Shape-12_00000013892298855937169510000007985557031648015280_);" d="M155.3,351.9v4.9 | |||
c0,0,6.7,0.5,13,0.5c7.9,0,13-0.5,13-0.5V352C172.8,352.5,164.1,352.4,155.3,351.9z"/> | |||
<linearGradient id="Shape-13_00000064333335148225958600000018360436247913531013_" gradientUnits="userSpaceOnUse" x1="-4398.5752" y1="-1395.9125" x2="-4398.1699" y2="-1394.8937" gradientTransform="matrix(13.71 0 0 24.9 60447.8086 35122.3555)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-13" style="opacity:0.7;fill:url(#Shape-13_00000064333335148225958600000018360436247913531013_);enable-background:new ;" d=" | |||
M137.9,358.6V370c0,0,7.2,1.1,11.2,1.4v-11.7C149.1,359.7,142.2,359.3,137.9,358.6z"/> | |||
<linearGradient id="Shape-14_00000167393322824028187890000017452476633985115545_" gradientUnits="userSpaceOnUse" x1="-3174.8132" y1="-1394.9221" x2="-3174.7368" y2="-1394.1992" gradientTransform="matrix(2.8 0 0 22.7 9024.4199 32008.8613)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-14" style="fill:url(#Shape-14_00000167393322824028187890000017452476633985115545_);" d="M136.3,358.4v11.3 | |||
l-2.2-0.4L134,358L136.3,358.4z"/> | |||
<linearGradient id="Shape-15_00000162352495989453854700000006277651567223056573_" gradientUnits="userSpaceOnUse" x1="-4678.0532" y1="-1402.1262" x2="-4677.2319" y2="-1402.1262" gradientTransform="matrix(128.49 0 0 74.25 601315.9375 104411.4688)"> | |||
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/> | |||
<stop offset="0.59" style="stop-color:#6DFFCB"/> | |||
<stop offset="1" style="stop-color:#78FFD6"/> | |||
</linearGradient> | |||
<path id="Shape-15" style="fill:url(#Shape-15_00000162352495989453854700000006277651567223056573_);" d="M205.8,317.1 | |||
c-20.4,7.4-53.6,7.3-74.1-0.1c-20.6-7.4-20.6-19.5-0.2-26.9s53.6-7.3,74,0.1S226.2,309.6,205.8,317.1z"/> | |||
<linearGradient id="Shape-16_00000153668204644255466410000009863565607959374214_" gradientUnits="userSpaceOnUse" x1="-4688.4077" y1="-1403.0204" x2="-4687.7285" y2="-1403.0314" gradientTransform="matrix(180.64 0 0 91.86 847058.25 129197.0469)"> | |||
<stop offset="0" style="stop-color:#C4D0D7"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-16" style="fill:url(#Shape-16_00000153668204644255466410000009863565607959374214_);" d="M231.5,332 | |||
c-28.7,9.2-75.2,9.1-104.2-0.1s-29-24.1-0.3-33.3s75.4-9.1,104.2,0.1S260.2,322.9,231.5,332z"/> | |||
<linearGradient id="Shape-17_00000081607492502552466440000007433058223660923029_" gradientUnits="userSpaceOnUse" x1="-4685.3496" y1="-1402.9875" x2="-4684.5391" y2="-1402.9875" gradientTransform="matrix(158.96 0 0 91.86 744883 129192.7344)"> | |||
<stop offset="1.000000e-02" style="stop-color:#E6E6E6"/> | |||
<stop offset="0.12" style="stop-color:#FEFEFE"/> | |||
<stop offset="0.52" style="stop-color:#C3D0D7"/> | |||
<stop offset="0.83" style="stop-color:#DAE5EA"/> | |||
<stop offset="1" style="stop-color:#CDE1E4"/> | |||
</linearGradient> | |||
<path id="Shape-17" style="fill:url(#Shape-17_00000081607492502552466440000007433058223660923029_);" d="M233.4,313.6v-8.2 | |||
h-1.9c-2.7-4.1-8.5-4.5-17.3-7.7c-25.3-9.2-66.4-9.3-91.6-0.1c-8.8,3.2-14.5,3.7-17.1,7.8h-1.8v9l0,0c0.1,6,6.6,11.9,19.2,16.5 | |||
c25.4,9.2,66.5,9.3,91.7,0.1C227.7,326.2,234,319.8,233.4,313.6z"/> | |||
<linearGradient id="Shape-18_00000000935785368065642490000001491826445201081248_" gradientUnits="userSpaceOnUse" x1="111.9444" y1="-1088.2948" x2="239.703" y2="-1085.6005" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#E8E8E8"/> | |||
<stop offset="0.53" style="stop-color:#FBFBFC"/> | |||
</linearGradient> | |||
<path id="Shape-18" style="fill:url(#Shape-18_00000000935785368065642490000001491826445201081248_);" d="M214.6,321.8 | |||
c-25.2,9.2-66.3,9.1-91.7-0.1s-25.5-24.1-0.3-33.3s66.3-9.1,91.7,0.1S239.9,312.6,214.6,321.8z"/> | |||
<linearGradient id="Shape-19_00000159470190286743471590000007947123095774400143_" gradientUnits="userSpaceOnUse" x1="-4688.3633" y1="-1403.1714" x2="-4687.8926" y2="-1403.1821" gradientTransform="matrix(180.64 0 0 91.86 847058.25 129197.0469)"> | |||
<stop offset="0" style="stop-color:#C4D0D7"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-19" style="fill:url(#Shape-19_00000159470190286743471590000007947123095774400143_);" d="M211.9,313.6 | |||
c-20.2,6.7-52.8,6.6-73.1-0.1s-20.4-17.5-0.2-24.2s52.8-6.6,73.1,0.1S232.1,306.9,211.9,313.6z"/> | |||
<ellipse class="st21" cx="169.8" cy="299.6" rx="46.7" ry="18.4"/> | |||
<rect x="123.1" y="283.4" class="st21" width="93.3" height="16.3"/> | |||
<ellipse class="st22" cx="169.8" cy="283.4" rx="46.7" ry="18.6"/> | |||
<ellipse class="st23" cx="169.8" cy="283" rx="46.7" ry="18.4"/> | |||
<ellipse class="st24" cx="169.8" cy="281.8" rx="39.6" ry="15.7"/> | |||
<ellipse class="st25" cx="169.8" cy="281.8" rx="27.5" ry="10.8"/> | |||
<ellipse class="st26" cx="169.8" cy="281.8" rx="20.9" ry="8.2"/> | |||
<ellipse class="st27" cx="169.8" cy="281.8" rx="16" ry="6.4"/> | |||
<path class="st28" d="M179.2,281.8c0,2.1-4.2,3.7-9.4,3.7c-5.3,0-9.4-1.6-9.4-3.7s4.2-3.7,9.4-3.7 | |||
C175,278.1,179.2,279.7,179.2,281.8z"/> | |||
<ellipse class="st29" cx="203.1" cy="280.9" rx="2.8" ry="1.1"/> | |||
<ellipse class="st29" cx="169" cy="268.3" rx="2.8" ry="1.1"/> | |||
<path class="st29" d="M139.7,281.2c0,0.7-1.3,1.1-2.8,1.1s-2.8-0.5-2.8-1.1s1.3-1.1,2.8-1.1S139.7,280.6,139.7,281.2z"/> | |||
<ellipse class="st29" cx="148.6" cy="293.1" rx="2.8" ry="1.1"/> | |||
<ellipse class="st29" cx="189.2" cy="293.1" rx="2.8" ry="1.1"/> | |||
<linearGradient id="SVGID_00000139277114413283346430000003203015687710406051_" gradientUnits="userSpaceOnUse" x1="203.143" y1="819.6531" x2="203.0444" y2="875.5317" gradientTransform="matrix(1 0 0 1 0 -592.21)"> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/> | |||
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000139277114413283346430000003203015687710406051_);" d="M206.6,277.1c0,1.2-1.5,2.2-3.5,2.2 | |||
l0,0c-2,0-3.5-1-3.5-2.2v-50.5l0,0v-0.1c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V277.1z"/> | |||
<linearGradient id="SVGID_00000183221014587477581410000000706386369785952431_" gradientUnits="userSpaceOnUse" x1="169.1382" y1="807.0799" x2="169.0506" y2="862.9583" gradientTransform="matrix(1 0 0 1 0 -592.21)"> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/> | |||
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000183221014587477581410000000706386369785952431_);" d="M172.6,264.5c0,1.2-1.5,2.2-3.5,2.2 | |||
l0,0c-2,0-3.5-1-3.5-2.2V214l0,0v-0.1c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V264.5z"/> | |||
<linearGradient id="SVGID_00000039096372971356690410000012421145682396891277_" gradientUnits="userSpaceOnUse" x1="189.4431" y1="826.3558" x2="189.3446" y2="888.3239" gradientTransform="matrix(1 0 0 1 0 -592.21)"> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/> | |||
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000039096372971356690410000012421145682396891277_);" d="M192.9,289.5c0,1.2-1.5,2.2-3.5,2.2 | |||
l0,0c-2,0-3.5-1-3.5-2.2v-56.4l0,0V233c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V289.5z"/> | |||
<linearGradient id="SVGID_00000013163074585285730020000005816107648387152776_" gradientUnits="userSpaceOnUse" x1="148.6431" y1="826.3557" x2="148.5445" y2="888.3237" gradientTransform="matrix(1 0 0 1 0 -592.21)"> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/> | |||
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000013163074585285730020000005816107648387152776_);" d="M152.1,289.5c0,1.2-1.5,2.2-3.5,2.2 | |||
l0,0c-2,0-3.5-1-3.5-2.2v-56.4l0,0V233c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V289.5z"/> | |||
<linearGradient id="SVGID_00000033367422727462969740000017109666248109283748_" gradientUnits="userSpaceOnUse" x1="136.9382" y1="819.653" x2="136.8506" y2="875.5316" gradientTransform="matrix(1 0 0 1 0 -592.21)"> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/> | |||
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000033367422727462969740000017109666248109283748_);" d="M140.4,277.1c0,1.2-1.5,2.2-3.5,2.2 | |||
l0,0c-2,0-3.5-1-3.5-2.2v-50.5l0,0v-0.1c0-0.8,1.5-1.4,3.5-1.4s3.5,0.7,3.5,1.4v0.1l0,0V277.1z"/> | |||
</g> | |||
<g id="Group-2"> | |||
<g id="Shape-20"> | |||
<linearGradient id="SVGID_00000066491685535550283050000010067348639462920879_" gradientUnits="userSpaceOnUse" x1="83.7" y1="-1141.8" x2="96.2" y2="-1141.8" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#91BFDB"/> | |||
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000066491685535550283050000010067348639462920879_);" d="M96.2,359.8c0,1.5-4.5,2.2-8.4,2.2 | |||
s-4.1-1-4.1-2.2s0.1-2.2,4.1-2.2C91.7,357.6,96.2,358.3,96.2,359.8z"/> | |||
<linearGradient id="SVGID_00000028319550724681881430000017225317771668268424_" gradientUnits="userSpaceOnUse" x1="89.9811" y1="-1142.4447" x2="82.3912" y2="-1140.8129" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000028319550724681881430000017225317771668268424_);enable-background:new ;" d=" | |||
M90.5,359.7v-0.8h-0.1c-0.1-0.3-0.5-0.4-1-0.7c-1.6-0.9-3.6-0.9-5.3,0c-0.5,0.3-0.9,0.3-1,0.8H83v0.8l0,0 | |||
c0.1,0.7,0.4,1.2,1.1,1.5c1.6,0.9,3.6,0.9,5.3,0C89.9,361,90.4,360.3,90.5,359.7z"/> | |||
<linearGradient id="SVGID_00000078734006496365647220000003596442759833680783_" gradientUnits="userSpaceOnUse" x1="74.6527" y1="-1139.2683" x2="91.3549" y2="-1141.5902" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000078734006496365647220000003596442759833680783_);enable-background:new ;" d=" | |||
M89.4,360.5c-1.6,0.9-3.6,0.9-5.3,0c-1.4-0.9-1.4-2.2,0-3.1c1.6-0.9,3.6-0.9,5.3,0C90.8,358.2,90.8,359.6,89.4,360.5z"/> | |||
<linearGradient id="SVGID_00000016778492564968718270000007715733383074586243_" gradientUnits="userSpaceOnUse" x1="-4461.2017" y1="-1399.1519" x2="-4461.1797" y2="-1399.8967" gradientTransform="matrix(17.18 0 0 41.2 76732.1953 58011.2617)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000016778492564968718270000007715733383074586243_);enable-background:new ;" d=" | |||
M92.6,339.1c-0.9-0.9-2-1.2-2.7-0.4l-3.6,3.4c-1,1-1.6,2.4-1.6,3.8l0,0v12.3l0,0c0,0.5,1,1.1,2.2,1.1s2.1-0.4,2.2-0.9v-0.1 | |||
v-12.2c0-0.3,0.1-0.5,0.3-0.9l3.6-3.5C93.7,341,93.3,340,92.6,339.1z"/> | |||
<linearGradient id="SVGID_00000110445505960899282040000008185106537552059583_" gradientUnits="userSpaceOnUse" x1="87.1364" y1="-1123.8972" x2="94.5402" y2="-1120.8854" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000110445505960899282040000008185106537552059583_);enable-background:new ;" d=" | |||
M92.8,341.8c-0.9,0.5-2.1,0.3-2.6-0.5c-0.8-0.7-0.9-1.9-0.3-2.7c0.7-0.5,1.6-0.4,2.6,0.5C93.4,340.1,93.4,341.2,92.8,341.8z"/> | |||
<g class="st40"> | |||
<linearGradient id="SVGID_00000051370268289873400610000018298761055778287753_" gradientUnits="userSpaceOnUse" x1="-4205.8408" y1="-1377.0852" x2="-4204.7896" y2="-1376.0007" gradientTransform="matrix(8.51 0 0 9.65 35874.4414 13634.9932)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000051370268289873400610000018298761055778287753_);" d="M82.9,347.3c1.5,2.3,4.2,3.6,6.9,3.5 | |||
v1.3c-2.5,0.4-5-0.4-6.9-2.2V347.3L82.9,347.3z"/> | |||
<linearGradient id="SVGID_00000022539495148538625040000011656406462773614524_" gradientUnits="userSpaceOnUse" x1="-4203.5879" y1="-1360.5885" x2="-4202.3726" y2="-1359.7999" gradientTransform="matrix(8.48 0 0 6.06 35729.3945 8596.1113)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000022539495148538625040000011656406462773614524_);" d="M82.9,350.6c0,0,1.1,2.3,6.9,2.2v0.9 | |||
c0,0-5,0.3-6.9-1.8V350.6z"/> | |||
</g> | |||
</g> | |||
<g id="Shape-21"> | |||
<linearGradient id="SVGID_00000053529045596386359860000012693715221203522699_" gradientUnits="userSpaceOnUse" x1="-4537.0894" y1="-1374.7428" x2="-4536.6074" y2="-1374.7318" gradientTransform="matrix(24.44 0 0 8.38 111101.9062 11894.1025)"> | |||
<stop offset="0" style="stop-color:#91BFDB"/> | |||
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000053529045596386359860000012693715221203522699_);" d="M229.8,373.8c0,1.6-4.8,2.2-8.9,2.2 | |||
c-4.1,0-4.3-1-4.3-2.2s0.1-2.2,4.3-2.2C225.1,371.6,229.8,372.3,229.8,373.8z"/> | |||
<linearGradient id="SVGID_00000016041242089640294250000005076626961659910032_" gradientUnits="userSpaceOnUse" x1="-4419.8472" y1="-1374.6202" x2="-4420.3838" y2="-1374.6202" gradientTransform="matrix(14.67 0 0 8.48 65064.1992 12030.4795)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000016041242089640294250000005076626961659910032_);enable-background:new ;" d=" | |||
M215.8,373.6v-0.8h0.1c0.1-0.4,0.5-0.4,1.1-0.7c1.8-0.9,3.8-0.9,5.6,0c0.5,0.3,0.9,0.3,1.1,0.8h0.1v0.9l0,0 | |||
c-0.1,0.7-0.5,1.3-1.2,1.5c-1.8,0.9-3.8,0.9-5.6,0C216.3,375,215.9,374.4,215.8,373.6z"/> | |||
<linearGradient id="SVGID_00000034051049874645699850000001054443060867366060_" gradientUnits="userSpaceOnUse" x1="210.2652" y1="-1156.347" x2="223.9993" y2="-1154.1678" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000034051049874645699850000001054443060867366060_);enable-background:new ;" d=" | |||
M216.9,374.4c1.8,0.9,3.8,0.9,5.6,0c1.5-0.9,1.5-2.2,0-3.1c-1.8-0.9-3.8-0.9-5.6,0C215.3,372.2,215.3,373.5,216.9,374.4z"/> | |||
<linearGradient id="SVGID_00000140705939172839159610000000673615029388288165_" gradientUnits="userSpaceOnUse" x1="-4461.4771" y1="-1400.4607" x2="-4461.4556" y2="-1401.49" gradientTransform="matrix(17.1 0 0 49.17 76508.5 69238.9375)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000140705939172839159610000000673615029388288165_);enable-background:new ;" d=" | |||
M213.6,349.5c0.8-0.9,2-1,2.8-0.3l3.7,3.5c1.1,1,1.8,2.4,1.8,3.8v16.4l0,0c0,0.5-1,1.1-2.3,1.1s-2.3-0.4-2.3-1.1v-16.3 | |||
c0-0.3-0.1-0.7-0.4-0.9l-3.7-3.5C212.6,351.5,212.7,350.2,213.6,349.5L213.6,349.5z"/> | |||
<linearGradient id="SVGID_00000016069627382271396290000009179125164610461070_" gradientUnits="userSpaceOnUse" x1="211.3378" y1="-1132.3972" x2="217.6791" y2="-1132.7916" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000016069627382271396290000009179125164610461070_);enable-background:new ;" d=" | |||
M213.1,352.2c0.9,0.5,2.1,0.3,2.7-0.5c0.9-0.7,1-1.8,0.3-2.6c0,0,0,0,0-0.1c-0.9-0.5-2.1-0.3-2.8,0.5 | |||
C212.7,350.2,212.5,351.4,213.1,352.2C213.1,352.1,213.1,352.2,213.1,352.2z"/> | |||
<g class="st40"> | |||
<linearGradient id="SVGID_00000023992425455839354290000003462269822397537668_" gradientUnits="userSpaceOnUse" x1="-4209.4048" y1="-1378.4917" x2="-4208.3643" y2="-1377.4075" gradientTransform="matrix(8.51 0 0 9.65 36039.0703 13662.6221)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000023992425455839354290000003462269822397537668_);" d="M217.2,361.4 | |||
c1.5,2.3,4.2,3.6,6.9,3.5v1.3c-2.5,0.4-5-0.4-6.9-2.2V361.4L217.2,361.4z"/> | |||
<linearGradient id="SVGID_00000161610153219861893360000018069820855094444985_" gradientUnits="userSpaceOnUse" x1="-4207.1631" y1="-1362.8098" x2="-4205.9478" y2="-1362.0103" gradientTransform="matrix(8.48 0 0 6.06 35894.0234 8623.752)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000161610153219861893360000018069820855094444985_);" d="M217.2,364.8c0,0,1.1,2.3,6.9,2.2 | |||
v0.9c0,0-5,0.3-6.9-1.8V364.8z"/> | |||
</g> | |||
</g> | |||
<g id="Shape-22"> | |||
<linearGradient id="SVGID_00000101097610753023437160000010300393479110564788_" gradientUnits="userSpaceOnUse" x1="-4537.3999" y1="-1373.2405" x2="-4536.9399" y2="-1373.2295" gradientTransform="matrix(24.44 0 0 8.38 111140.0703 11867.9131)"> | |||
<stop offset="0" style="stop-color:#91BFDB"/> | |||
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000101097610753023437160000010300393479110564788_);" d="M259.7,360.2c0,1.6-4.6,2.2-8.5,2.2 | |||
s-4.1-1-4.1-2.2s0.1-2.2,4.1-2.2S259.7,358.7,259.7,360.2z"/> | |||
<linearGradient id="SVGID_00000057826871241478005110000007594934890897262214_" gradientUnits="userSpaceOnUse" x1="-4420.3882" y1="-1373.1334" x2="-4420.9033" y2="-1373.1334" gradientTransform="matrix(14.67 0 0 8.48 65102.3398 12004.2705)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000057826871241478005110000007594934890897262214_);enable-background:new ;" d=" | |||
M246.3,360v-0.8h0.1c0.1-0.3,0.5-0.4,1-0.7c1.6-0.9,3.7-0.9,5.4,0c0.5,0.3,0.9,0.3,1,0.8h0.1v0.9l0,0c-0.1,0.7-0.4,1.2-1.1,1.5 | |||
c-1.6,0.9-3.7,0.9-5.4,0C246.8,361.3,246.3,360.8,246.3,360z"/> | |||
<linearGradient id="SVGID_00000034069503416819206880000007783290857966879909_" gradientUnits="userSpaceOnUse" x1="241.1007" y1="-1144.2089" x2="255.5578" y2="-1139.4556" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000034069503416819206880000007783290857966879909_);enable-background:new ;" d=" | |||
M247.4,360.8c1.6,0.9,3.7,0.9,5.4,0c1.5-0.9,1.5-2.2,0-3.1c-1.6-0.9-3.7-0.9-5.4,0C245.9,358.6,245.9,359.9,247.4,360.8z"/> | |||
<linearGradient id="SVGID_00000074402755482888099360000011871301802014376069_" gradientUnits="userSpaceOnUse" x1="-4463.228" y1="-1399.1514" x2="-4463.2495" y2="-1399.8962" gradientTransform="matrix(17.18 0 0 41.2 76926.3984 58012.0977)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000074402755482888099360000011871301802014376069_);enable-background:new ;" d=" | |||
M244.2,339.5c1-0.9,2-1.2,2.7-0.4l3.6,3.5c1.1,1,1.6,2.4,1.8,3.8l0,0v12.3l0,0c0,0.5-1,1.1-2.2,1.1s-2.1-0.4-2.2-0.9v-0.1 | |||
v-12.3c0-0.3-0.1-0.7-0.3-0.9l-3.6-3.5C243,341.4,243.4,340.4,244.2,339.5z"/> | |||
<linearGradient id="SVGID_00000034800493623832042920000008020736596099291557_" gradientUnits="userSpaceOnUse" x1="235.944" y1="-1125.0896" x2="250.39" y2="-1121.2892" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000034800493623832042920000008020736596099291557_);enable-background:new ;" d=" | |||
M243.9,342.2c0.9,0.5,2.1,0.3,2.6-0.5c0.8-0.7,1-1.9,0.3-2.7c-0.7-0.5-1.6-0.4-2.6,0.5C243.3,340.4,243.3,341.6,243.9,342.2z" | |||
/> | |||
<g class="st40"> | |||
<linearGradient id="SVGID_00000006704291500926620380000004171103234775810997_" gradientUnits="userSpaceOnUse" x1="-4208.7266" y1="-1376.4762" x2="-4207.8501" y2="-1375.5673" gradientTransform="matrix(8.47 0 0 9.55 35885.875 13484.8174)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000006704291500926620380000004171103234775810997_);" d="M246.3,349c0,0,1.3,3.5,4.9,3.5v1.3 | |||
c-2,0.3-3.8-0.5-4.9-2.2V349z"/> | |||
<linearGradient id="SVGID_00000177484813400042119220000011015524536336387207_" gradientUnits="userSpaceOnUse" x1="-4210.5615" y1="-1360.016" x2="-4209.5977" y2="-1359.3917" gradientTransform="matrix(8.51 0 0 6.07 36075.9102 8607.5488)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000177484813400042119220000011015524536336387207_);" d="M246.3,352.4c0,0,0.9,2.3,4.9,2.2 | |||
v0.9c0,0-3.6,0.3-4.9-1.8V352.4z"/> | |||
</g> | |||
</g> | |||
<g id="Shape-23"> | |||
<linearGradient id="SVGID_00000150793386108511341090000013432375121497242256_" gradientUnits="userSpaceOnUse" x1="111" y1="-1155.8" x2="123.6828" y2="-1155.8" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#91BFDB"/> | |||
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000150793386108511341090000013432375121497242256_);" d="M123.7,373.8c0,1.5-4.6,2.2-8.5,2.2 | |||
s-4.2-1-4.2-2.2s0.1-2.2,4.2-2.2C119.1,371.6,123.7,372.3,123.7,373.8z"/> | |||
<linearGradient id="SVGID_00000173862521492696290410000004963765814931415984_" gradientUnits="userSpaceOnUse" x1="117.3702" y1="-1156.4034" x2="109.6817" y2="-1154.7496" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000173862521492696290410000004963765814931415984_);enable-background:new ;" d=" | |||
M117.9,373.6v-0.8h-0.1c-0.2-0.3-0.5-0.4-1-0.7c-1.6-0.9-3.7-0.9-5.4,0c-0.5,0.3-0.9,0.3-1,0.8h-0.1v0.9l0,0 | |||
c0.1,0.7,0.4,1.2,1.1,1.5c1.6,0.9,3.7,0.9,5.4,0C117.3,374.9,117.7,374.4,117.9,373.6z"/> | |||
<linearGradient id="SVGID_00000020398109177578560470000006450052471999083696_" gradientUnits="userSpaceOnUse" x1="101.8376" y1="-1153.1447" x2="118.7699" y2="-1155.4994" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000020398109177578560470000006450052471999083696_);enable-background:new ;" d=" | |||
M116.8,374.4c-1.6,0.9-3.7,0.9-5.4,0c-1.5-0.9-1.5-2.2,0-3.1c1.6-0.9,3.7-0.9,5.4,0C118.2,372.2,118.2,373.5,116.8,374.4z"/> | |||
<linearGradient id="SVGID_00000146469520690687921700000001834666537324208572_" gradientUnits="userSpaceOnUse" x1="-4459.6167" y1="-1398.7903" x2="-4459.5947" y2="-1399.6775" gradientTransform="matrix(17.18 0 0 41.2 76732.1953 58011.2617)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000146469520690687921700000001834666537324208572_);enable-background:new ;" d=" | |||
M119.9,349.4c-0.9-0.9-2-1.2-2.7-0.4l-3.6,3.5c-1.1,1-1.6,2.4-1.8,3.8l0,0v12.3v3.9c0,0.5,1,1.1,2.2,1.1s2.1-0.4,2.2-0.9v-0.1 | |||
v-16.2c0-0.3,0.1-0.7,0.3-0.9l3.6-3.5C121.1,351.3,120.8,350.3,119.9,349.4z"/> | |||
<linearGradient id="SVGID_00000146461411017424176850000008273474735748943006_" gradientUnits="userSpaceOnUse" x1="114.4784" y1="-1134.2108" x2="121.9807" y2="-1131.1552" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="1.000000e-02" style="stop-color:#5C6672"/> | |||
<stop offset="0.28" style="stop-color:#5F87B2"/> | |||
<stop offset="0.81" style="stop-color:#A7DFF9"/> | |||
</linearGradient> | |||
<path style="opacity:0.9;fill:url(#SVGID_00000146461411017424176850000008273474735748943006_);enable-background:new ;" d=" | |||
M120.3,352.1c-0.9,0.5-2.1,0.3-2.7-0.5c-0.8-0.7-1-1.9-0.3-2.7c0.7-0.7,1.8-0.4,2.6,0.5C120.7,350.4,120.9,351.5,120.3,352.1z" | |||
/> | |||
<g class="st40"> | |||
<linearGradient id="SVGID_00000085959571847769126780000003905589832501502136_" gradientUnits="userSpaceOnUse" x1="-4202.5493" y1="-1376.0286" x2="-4201.4976" y2="-1374.9441" gradientTransform="matrix(8.51 0 0 9.65 35874.4414 13634.9932)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000085959571847769126780000003905589832501502136_);" d="M111,357.6c1.5,2.3,4.2,3.6,6.9,3.5 | |||
v1.3c-2.5,0.4-5.1-0.4-6.9-2.2V357.6L111,357.6z"/> | |||
<linearGradient id="SVGID_00000101066731764067032500000013534230380051260331_" gradientUnits="userSpaceOnUse" x1="-4200.2793" y1="-1358.8921" x2="-4199.064" y2="-1358.1035" gradientTransform="matrix(8.48 0 0 6.06 35729.3945 8596.1113)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="0.99" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000101066731764067032500000013534230380051260331_);" d="M111,360.9c0,0,1.1,2.3,6.9,2.2v0.9 | |||
c0,0-5,0.3-6.9-1.8V360.9z"/> | |||
</g> | |||
</g> | |||
</g> | |||
<path id="Shape-24" class="st64" d="M101.5,377.4c0,0,2,0.7,5.5,1.5c1.8,0.4,3.9,1,6.4,1.5c2.4,0.5,5.4,1.1,8.4,1.6 | |||
c1.5,0.2,3.2,0.5,4.9,0.8l2.6,0.4l2.6,0.3c0.9,0.1,1.9,0.2,2.7,0.3l2.8,0.3c2,0.2,3.9,0.4,5.9,0.5l3.1,0.2l3.1,0.2 | |||
c2.1,0.1,4.2,0.2,6.4,0.3c1.1,0.1,2.1,0.1,3.2,0.1s2.2,0.1,3.2,0.1h3.3h1.6h1.6c2.2,0,4.3,0,6.5-0.1h3.1l3.2-0.1l3.2-0.1l3.1-0.2 | |||
c1-0.1,2.1-0.1,3.1-0.2l3.1-0.3l3-0.3l3-0.3l2.8-0.3c1-0.1,1.9-0.2,2.7-0.4l2.6-0.4l1.3-0.2l1.3-0.2l4.9-0.9 | |||
c1.5-0.3,3.1-0.5,4.5-0.9s2.7-0.5,3.9-0.9l3.5-0.8l1.5-0.3l1.4-0.3l5.5-1.4l-5.5,1.4c-0.4,0.1-0.9,0.2-1.4,0.3l-1.5,0.3l-3.5,0.8 | |||
c-1.2,0.3-2.6,0.5-3.9,0.9s-2.8,0.5-4.5,0.9l-4.9,0.9l-1.3,0.2l-1.3,0.2l-2.6,0.4c-0.9,0.1-1.9,0.2-2.7,0.4l-2.8,0.3l-3,0.3 | |||
l-3,0.3l-3.1,0.3c-1,0.1-2.1,0.1-3.1,0.2l-3.2,0.2l-3.2,0.1c-1.1,0-2.2,0.1-3.2,0.1l-3.2,0.1c-2.2,0.1-4.3,0.1-6.5,0.1H167h-1.6 | |||
h-3.3l-3.2-0.1c-1.1,0-2.2-0.1-3.2-0.1c-2.1-0.1-4.3-0.2-6.4-0.4l-3.1-0.2l-3-0.3c-2-0.1-3.9-0.4-5.9-0.7l-2.8-0.3 | |||
c-0.9-0.1-1.9-0.2-2.7-0.3l-2.7-0.4l-2.6-0.4c-1.8-0.2-3.3-0.5-4.9-0.8c-3.1-0.5-5.9-1.1-8.4-1.6s-4.6-1.1-6.4-1.5 | |||
C103.5,378,101.5,377.4,101.5,377.4z"/> | |||
</g> | |||
<radialGradient id="SVGID_00000152945109931711952980000000514259528298555047_" cx="164.9579" cy="-350.9658" r="213.7317" gradientTransform="matrix(1 0 0 -1 0 -136)" gradientUnits="userSpaceOnUse"> | |||
<stop offset="0" style="stop-color:#2AC6FF;stop-opacity:0.7"/> | |||
<stop offset="0.6704" style="stop-color:#2AC6FF;stop-opacity:0.3"/> | |||
<stop offset="0.9329" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</radialGradient> | |||
<path style="fill:url(#SVGID_00000152945109931711952980000000514259528298555047_);" d="M294.2,344.5l-1.8-2.3 | |||
c-0.2-0.3-0.4-0.7-0.8-1c-16.1-21.4-48.4-55.7-48.4-111.1c0-68.9,4.3-157.7,24.4-231.9H65.9c20.3,74.1,24.4,163,24.4,231.9 | |||
c0,58.3-30.4,93.3-45.5,114.5h0.9c-0.3,0.9-0.4,1.8-0.4,2.7c0,16.9,55.7,30.6,124.5,30.6s124.4-13.7,124.4-30.6 | |||
c0-0.9-0.2-1.9-0.4-2.7L294.2,344.5z"/> | |||
<linearGradient id="Shape-25_00000062897884857159563720000017493666428800170661_" gradientUnits="userSpaceOnUse" x1="-3138.2468" y1="-1399.6875" x2="-3138.2468" y2="-1399.1289" gradientTransform="matrix(2.13 0 0 135.17 6832.7236 189269.7344)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="0.41" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-25" style="opacity:0.1;fill:url(#Shape-25_00000062897884857159563720000017493666428800170661_);enable-background:new ;" d=" | |||
M148.3,81.3c-0.5,0-1,0.4-1,1l0,0v102.2c0,0.5,0.4,1,0.9,1s1-0.4,1-0.9l0,0V82.3C149.3,81.7,148.9,81.3,148.3,81.3L148.3,81.3z"/> | |||
<linearGradient id="Shape-26_00000096747381355368235380000013244751307849799820_" gradientUnits="userSpaceOnUse" x1="-3141.8672" y1="-1399.7417" x2="-3141.8672" y2="-1399.1831" gradientTransform="matrix(2.13 0 0 135.17 6894.334 189301.5781)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="0.41" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-26" style="opacity:0.1;fill:url(#Shape-26_00000096747381355368235380000013244751307849799820_);enable-background:new ;" d=" | |||
M202.2,105.8c-0.5,0-1,0.4-1,1v102.1c0,0.5,0.4,1,0.9,1s1-0.4,1-0.9l0,0V106.9C203.2,106.4,202.7,105.8,202.2,105.8z"/> | |||
<linearGradient id="Shape-27_00000119823744966612805220000010319973446294606232_" gradientUnits="userSpaceOnUse" x1="-3136.2" y1="-1399.7588" x2="-3136.2" y2="-1399.1892" gradientTransform="matrix(2.13 0 0 135.17 6791.6636 189308.4531)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="0.41" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-27" style="opacity:0.2;fill:url(#Shape-27_00000119823744966612805220000010319973446294606232_);enable-background:new ;" d=" | |||
M111.6,110.1c-0.5,0-1,0.4-1,1l0,0v102.2c0,0.5,0.4,1,0.9,1s1-0.4,1-1l0,0V111.1C112.6,110.6,112.2,110.2,111.6,110.1L111.6,110.1 | |||
z"/> | |||
<linearGradient id="Shape-28_00000103240500498414136000000006526299530864732311_" gradientUnits="userSpaceOnUse" x1="-2292.4885" y1="-1395.9701" x2="-2292.4885" y2="-1395.4005" gradientTransform="matrix(1.38 0 0 87.55 3393.5439 122396.2578)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="0.41" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-28" style="opacity:0.4;fill:url(#Shape-28_00000103240500498414136000000006526299530864732311_);enable-background:new ;" d=" | |||
M230,172.8c-0.3,0-0.7,0.3-0.7,0.7l0,0v66.2c0,0.3,0.2,0.7,0.5,0.7l0,0c0.3,0,0.7-0.3,0.7-0.7l0,0v-66.2 | |||
C230.6,173.2,230.3,172.8,230,172.8z"/> | |||
<linearGradient id="Shape-29_00000003076700492934946240000003238066575396519355_" gradientUnits="userSpaceOnUse" x1="-3137.2019" y1="-1396.8502" x2="-3137.2019" y2="-1396.2916" gradientTransform="matrix(2.13 0 0 94.53 6812.8838 132233.6719)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="0.41" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-29" style="opacity:0.3;fill:url(#Shape-29_00000003076700492934946240000003238066575396519355_);enable-background:new ;" d=" | |||
M130.6,191.5c-0.5,0-1,0.4-0.9,1v70.9c0,0.5,0.4,1,0.9,1s1-0.4,1-0.9l0,0v-70.9C131.5,191.9,131.1,191.5,130.6,191.5z"/> | |||
<linearGradient id="Shape-30_00000142141291087823972360000005780631530962408337_" gradientUnits="userSpaceOnUse" x1="165.1285" y1="-976.6299" x2="164.8766" y2="-910.3356" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.5"/> | |||
<stop offset="0.99" style="stop-color:#12FFF7;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-30" style="opacity:0.8;fill:url(#Shape-30_00000142141291087823972360000005780631530962408337_);enable-background:new ;" d=" | |||
M165.3,195.1c-24.6,0-48-3.5-65.4-10s-27.4-15.2-27.4-24.4s9.5-17.9,26.9-24.2s40.5-10,65.3-10s47.9,3.5,65.4,10 | |||
s27.4,15.2,27.4,24.4s-9.5,17.7-26.9,24.2c-2.6,1-5.5,2-8.5,2.8c-11.2,3.2-22.7,5.1-34.2,6.1C180.5,194.8,172.9,195.1,165.3,195.1 | |||
z M164.7,127.1c-24.5,0-47.5,3.5-64.7,10c-17.3,6.4-26.6,14.7-26.6,23.7s9.6,17.4,26.9,23.9s40.4,10,64.9,10 | |||
c7.6,0,15.1-0.3,22.3-1c11.5-1,22.9-3.1,34-6.1c3-0.9,5.8-1.8,8.4-2.7c17.1-6.4,26.5-14.8,26.5-23.7s-9.6-17.5-26.9-23.9 | |||
C212.3,130.8,189.3,127.1,164.7,127.1z"/> | |||
<linearGradient id="Shape-31_00000047765179999079558420000018338508616989585558_" gradientUnits="userSpaceOnUse" x1="-4556.9941" y1="-423.3402" x2="-4561.7476" y2="-464.8384" gradientTransform="matrix(77.04 0 0 111.08 359914.0938 155486.75)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="1" style="stop-color:#2AFADF"/> | |||
</linearGradient> | |||
<path id="Shape-31" style="opacity:0.3;fill:url(#Shape-31_00000047765179999079558420000018338508616989585558_);enable-background:new ;" d=" | |||
M235.5,241.1c-6.9,2.7-14,4.9-21.2,6.6c-2.6,0.7-4.7-0.9-4.7-3.3v-28.1c0-2.4,2.1-4.7,4.7-5.4c7.2-1.6,14.3-3.8,21.2-6.6 | |||
c3.4-1.4,6.8-2.8,10-4.5c20.4-10.4,30.8-24,31.4-37.6v34.3c0.5,14.5-9.9,29-31.4,40.1C242.3,238.2,238.9,239.7,235.5,241.1z"/> | |||
<g id="Shape-32" class="st73"> | |||
<linearGradient id="SVGID_00000083767028849843557540000003015893000703474077_" gradientUnits="userSpaceOnUse" x1="-3997.0054" y1="-1331.5676" x2="-3997.0054" y2="-1330.6367" gradientTransform="matrix(4.67 0 0 12.58 18914.2656 16962.2617)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000083767028849843557540000003015893000703474077_);" points="250.3,228.9 250.3,221.8 | |||
246.2,223.9 246.2,231.6 "/> | |||
<linearGradient id="SVGID_00000000215917149092826270000018230445423745942943_" gradientUnits="userSpaceOnUse" x1="-4006.7764" y1="-1383.0823" x2="-4006.7654" y2="-1381.5378" gradientTransform="matrix(4.74 0 0 36.55 19216.0312 50684.7617)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000000215917149092826270000018230445423745942943_);" d="M226.1,240.6c-1.3,0.4-2.7,0.9-4.1,1.3 | |||
l-0.1-26.9c1.3-0.4,2.7-0.8,4.1-1.2L226.1,240.6z"/> | |||
<linearGradient id="SVGID_00000127760218784342968640000002359079861741369269_" gradientUnits="userSpaceOnUse" x1="-4002.3381" y1="-1369.6538" x2="-4002.3381" y2="-1368.5916" gradientTransform="matrix(4.7 0 0 25.06 19043.0879 34513.9961)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000127760218784342968640000002359079861741369269_);" d="M234.2,237.6l-2.2,0.9l-1.9,0.8 | |||
l-0.1-17.7h0.1l1.9-0.8c0.8-0.3,1.4-0.5,2.2-0.9V237.6z"/> | |||
<linearGradient id="SVGID_00000025411509199572341930000014536893160322097330_" gradientUnits="userSpaceOnUse" x1="-4005.9248" y1="-1380.2017" x2="-4005.9248" y2="-1379.1831" gradientTransform="matrix(4.73 0 0 34.85 19188.4746 48291.8477)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000025411509199572341930000014536893160322097330_);" d="M242.5,233.6l-1.3,0.7 | |||
c-0.9,0.4-1.8,0.9-2.7,1.3l-0.1-24.8l4.1-2.1V233.6z"/> | |||
</g> | |||
<linearGradient id="Shape-33_00000137132446951879004030000008177934085669183874_" gradientUnits="userSpaceOnUse" x1="247.2798" y1="-966.5903" x2="243.775" y2="-1045.7864" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#30E4E5"/> | |||
<stop offset="1" style="stop-color:#2AFADF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-33" style="opacity:0.2;fill:url(#Shape-33_00000137132446951879004030000008177934085669183874_);enable-background:new ;" d=" | |||
M277.1,199.4v95.5l-67.2,39.4v-89.2c0.3,2,2.3,3.2,4.7,2.6c7.2-1.6,14.3-3.8,21.2-6.6c3.4-1.4,6.8-2.8,10-4.5 | |||
C265.8,226.3,276.2,212.8,277.1,199.4z"/> | |||
<linearGradient id="Shape-34_00000017487326329354270790000004505123412309728175_" gradientUnits="userSpaceOnUse" x1="-4586.5684" y1="-1389.8807" x2="-4591.4204" y2="-1389.8807" gradientTransform="matrix(27.05 0 0 59.5 124361.1797 82796.8516)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="1" style="stop-color:#2AFADF"/> | |||
</linearGradient> | |||
<path id="Shape-34" style="opacity:0.2;fill:url(#Shape-34_00000017487326329354270790000004505123412309728175_);enable-background:new ;" d=" | |||
M249,119.2c-0.7-0.3-1.4-0.8-2.2-1.1c-1.2-0.5-2.2-3-2.2-5.3V79.4c0-2.4,1-3.8,2.2-3.3c0.8,0.3,1.4,0.7,2.2,1.1 | |||
c24,12.3,25.6,31.5,4.7,44.7C252.1,120.9,250.5,120.1,249,119.2z"/> | |||
<linearGradient id="Shape-35_00000182508484054447651870000016260184141608580785_" gradientUnits="userSpaceOnUse" x1="-4667.9175" y1="-1396.4476" x2="-4665.9023" y2="-1396.4476" gradientTransform="matrix(73.17 0 0 97.58 341653.125 136403.875)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="1" style="stop-color:#2AFADF"/> | |||
</linearGradient> | |||
<path id="Shape-35" style="opacity:0.3;fill:url(#Shape-35_00000182508484054447651870000016260184141608580785_);enable-background:new ;" d=" | |||
M268.2,142.8c0.1,8.5-6.2,17.1-18.9,23.7c-1.9,1-3.9,1.9-6,2.7c-7.8,3.1-15.9,5-24.2,6c-3.3,0.4-6.6,0.7-10,0.9 | |||
c-2.4,0.2-4.6-1.4-4.8-3.8c0-0.1,0-0.2,0-0.3v-33.5c0-2.4,2.2-4.3,4.8-4.4c3.3-0.1,6.7-0.4,10-0.9c8.3-1,16.4-3.1,24.2-6.1 | |||
c2.1-0.9,4.2-1.8,6-2.7c12.7-6.5,18.9-15,18.9-23.5V142.8z"/> | |||
<linearGradient id="Shape-36_00000134951791006757682060000002162209820624686987_" gradientUnits="userSpaceOnUse" x1="225.9564" y1="-904.1375" x2="222.7145" y2="-937.75" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path id="Shape-36" style="fill:url(#Shape-36_00000134951791006757682060000002162209820624686987_);" d="M234.1,150.1 | |||
c0,6.4-5,14.1-11.4,17.3s-11.4,0.7-11.4-5.7s5-14.1,11.4-17.3C229,141.2,234.1,143.7,234.1,150.1z M222.7,163.8 | |||
c4.3-2.2,7.7-7.4,7.7-11.7s-3.5-6-7.8-3.9s-7.8,7.4-7.7,11.7C215,164.1,218.4,165.9,222.7,163.8L222.7,163.8z"/> | |||
<linearGradient id="Shape-37_00000106120806841072813860000004463379643489448371_" gradientUnits="userSpaceOnUse" x1="-4573.8359" y1="-1375.6361" x2="-4572.96" y2="-1375.6361" gradientTransform="matrix(24.13 0 0 31.7 110559.8047 43764.2852)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path id="Shape-37" style="fill:url(#Shape-37_00000106120806841072813860000004463379643489448371_);" d="M229.4,156.3 | |||
c-1.3,3.2-3.7,5.7-6.7,7.4c-4.3,2.2-7.8,0.4-7.8-3.9c0-4.4,3.4-9.6,7.7-11.7l0,0v-3.7l0,0c-6.2,3.2-11.4,11-11.4,17.3 | |||
c0,6.4,5.1,9,11.4,5.7c4.3-2.4,7.7-6,9.7-10.5L229.4,156.3z"/> | |||
<linearGradient id="Shape-38_00000103972781162050256340000014581144695034338738_" gradientUnits="userSpaceOnUse" x1="-4570.1318" y1="-1373.7581" x2="-4568.1167" y2="-1373.7581" gradientTransform="matrix(23.4 0 0 30.11 107153.7891 41508.875)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path id="Shape-38" style="fill:url(#Shape-38_00000103972781162050256340000014581144695034338738_);" d="M262,139.8 | |||
c0,5.7-4.5,12.7-10.2,15.6c-5.7,2.8-10.3,0.5-10.3-5.1s4.5-12.7,10.2-15.6C257.4,131.8,262,134.1,262,139.8z M251.8,152 | |||
c3.8-2,6.9-6.7,6.9-10.6c0-3.9-3.2-5.5-7-3.5s-6.9,6.7-6.9,10.6C244.8,152.5,248,154,251.8,152z"/> | |||
<linearGradient id="Shape-39_00000025423177438856170250000006332888040414474649_" gradientUnits="userSpaceOnUse" x1="-4426.6255" y1="-1371.6255" x2="-4425.7603" y2="-1371.6255" gradientTransform="matrix(11.7 0 0 28.37 52017.5625 39058.5156)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path id="Shape-39" style="fill:url(#Shape-39_00000025423177438856170250000006332888040414474649_);" d="M251.7,134.6 | |||
c-5.7,2.8-10.2,9.9-10.2,15.6c0,3.5,1.8,5.8,4.4,6.2l1.8-3.7c-1.8-0.4-2.8-1.9-2.8-4.3c0-3.9,3.1-8.7,6.9-10.6l0,0L251.7,134.6 | |||
L251.7,134.6z"/> | |||
<linearGradient id="Shape-40_00000021118273186128926250000015044912358265521326_" gradientUnits="userSpaceOnUse" x1="-4665.3408" y1="-1397.1777" x2="-4662.8545" y2="-1397.1777" gradientTransform="matrix(69.21 0 0 106.39 322845.875 148760.2031)"> | |||
<stop offset="0" style="stop-color:#4C83FF"/> | |||
<stop offset="1" style="stop-color:#2AFADF"/> | |||
</linearGradient> | |||
<path id="Shape-40" style="opacity:0.3;fill:url(#Shape-40_00000021118273186128926250000015044912358265521326_);enable-background:new ;" d=" | |||
M121.7,107.5v44.9c0,2.4-2.1,3.7-4.6,2.8c-9.6-3.1-19.1-6.8-28.1-11.4c-8.8-4.4-17-9.7-24.4-16c-2-2-3.3-4.6-3.4-7.3V75.6 | |||
c0-2.4,1.5-2.8,3.4-1.2C72,80.6,80.3,86,89,90.4c9.1,4.6,18.5,8.3,28.1,11.4C119.6,102.5,121.5,104.8,121.7,107.5z"/> | |||
<linearGradient id="Shape-41_00000005975336679041812930000005759237068217401271_" gradientUnits="userSpaceOnUse" x1="138.8851" y1="-878.1784" x2="67.1695" y2="-905.581" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path id="Shape-41" style="fill:url(#Shape-41_00000005975336679041812930000005759237068217401271_);" d="M85.1,101.2 | |||
c8.4,4.3,15.3,14.8,15.3,23.3s-6.9,12-15.3,7.8S69.8,117.5,69.8,109S76.7,96.9,85.1,101.2z M85,127.3c5.7,3,10.4,0.5,10.4-5.3 | |||
s-4.6-12.9-10.4-15.9s-10.4-0.5-10.4,5.3S79.3,124.4,85,127.3L85,127.3z"/> | |||
<linearGradient id="Shape-42_00000122712814098058905890000007017593085226539443_" gradientUnits="userSpaceOnUse" x1="-4521.1196" y1="-1373.542" x2="-4520.2432" y2="-1373.542" gradientTransform="matrix(17.49 0 0 30.28 79147.5156 41703.7031)"> | |||
<stop offset="0" style="stop-color:#2AFADF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.8"/> | |||
</linearGradient> | |||
<path id="Shape-42" style="fill:url(#Shape-42_00000122712814098058905890000007017593085226539443_);" d="M85.1,101.2 | |||
c8.4,4.3,15.3,14.8,15.3,23.3l-4.9-2.5c0-5.8-4.6-12.9-10.4-15.9V101.2z"/> | |||
<linearGradient id="Shape-43_00000030453719429377122740000013557076259559090617_" gradientUnits="userSpaceOnUse" x1="109.0421" y1="-913.4399" x2="80.9496" y2="-976.8318" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#30E4E5"/> | |||
<stop offset="0.6" style="stop-color:#2AFADF;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-43" style="opacity:0.2;fill:url(#Shape-43_00000030453719429377122740000013557076259559090617_);enable-background:new ;" d=" | |||
M121.7,152.3V222l-60.6-29.8v-71.7c0.1,2.7,1.4,5.4,3.4,7.3c7.4,6.2,15.7,11.6,24.4,16c9.1,4.6,18.5,8.3,28.1,11.4 | |||
C119.6,156,121.7,154.7,121.7,152.3z"/> | |||
<linearGradient id="Shape-44_00000176727814201571328480000011766605898265965704_" gradientUnits="userSpaceOnUse" x1="249.2" y1="-1232.5" x2="287.6426" y2="-1232.5" gradientTransform="matrix(1 0 0 -1 0 -782)"> | |||
<stop offset="0" style="stop-color:#91BFDB"/> | |||
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<polygon id="Shape-44" style="fill:url(#Shape-44_00000176727814201571328480000011766605898265965704_);" points="249.2,460.7 | |||
271,457.3 287.6,446.1 274.3,440.3 "/> | |||
<linearGradient id="SVGID_00000042695819913126177250000000172513830783411371_" gradientUnits="userSpaceOnUse" x1="-4654.0396" y1="-1402.9192" x2="-4653.481" y2="-1403.2366" gradientTransform="matrix(75.74 0 0 55.03 352723.9688 77637.6016)"> | |||
<stop offset="1.000000e-02" style="stop-color:#009FFC"/> | |||
<stop offset="0.56" style="stop-color:#1595F4"/> | |||
<stop offset="1" style="stop-color:#2090F0"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000042695819913126177250000000172513830783411371_);" points="244.6,425.2 249.2,433.2 | |||
279.7,415.2 275.4,407.6 "/> | |||
<linearGradient id="SVGID_00000117638879148804653300000015399300247122409869_" gradientUnits="userSpaceOnUse" x1="-4644.7964" y1="-1405.0366" x2="-4644.709" y2="-1404.4231" gradientTransform="matrix(65.77 0 0 97.87 305750.0312 137920.9688)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000117638879148804653300000015399300247122409869_);" points="249.2,433.2 249.2,460.7 | |||
279.7,440.7 279.7,415.2 "/> | |||
<linearGradient id="SVGID_00000085224804945207263520000014360999943671216563_" gradientUnits="userSpaceOnUse" x1="-4353.3867" y1="-1395.6317" x2="-4353.4966" y2="-1396.1903" gradientTransform="matrix(12.39 0 0 17.46 54185.7148 24803.7129)"> | |||
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/> | |||
<stop offset="0.59" style="stop-color:#6DFFCB"/> | |||
<stop offset="1" style="stop-color:#78FFD6"/> | |||
</linearGradient> | |||
<polyline style="fill:url(#SVGID_00000085224804945207263520000014360999943671216563_);" points="244.6,425.2 249.2,433.2 | |||
248.2,433.2 243.4,425.1 244.6,425.2 "/> | |||
<linearGradient id="SVGID_00000057131615203601934700000015143495052675431324_" gradientUnits="userSpaceOnUse" x1="-4352.3335" y1="-1403.6678" x2="-4352.2788" y2="-1403.8651" gradientTransform="matrix(12.35 0 0 59.18 53998.4648 83513.9609)"> | |||
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/> | |||
<stop offset="0.59" style="stop-color:#6DFFCB"/> | |||
<stop offset="1" style="stop-color:#78FFD6"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000057131615203601934700000015143495052675431324_);" points="248.2,433.2 248.2,459.4 | |||
243.5,456.5 243.5,457.3 249.2,460.7 249.2,433.2 "/> | |||
<linearGradient id="SVGID_00000029010345686687337160000011462027730732656565_" gradientUnits="userSpaceOnUse" x1="-4281.1147" y1="-1393.7373" x2="-4280.3813" y2="-1394.3835" gradientTransform="matrix(10.3 0 0 11.87 44341.7695 17001.1699)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000029010345686687337160000011462027730732656565_);" points="243.5,456.5 248.2,453.9 | |||
248.2,459.4 "/> | |||
<linearGradient id="Shape-45_00000098906919044303374130000006733002538008474547_" gradientUnits="userSpaceOnUse" x1="-4647.6909" y1="-1401.2917" x2="-4647.1543" y2="-1401.2148" gradientTransform="matrix(68.73 0 0 38.94 319689.0938 54981.9297)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon id="Shape-45" style="fill:url(#Shape-45_00000098906919044303374130000006733002538008474547_);" points="275.4,407.6 | |||
274.7,407.1 243.4,425.1 244.6,425.2 "/> | |||
<linearGradient id="Shape-46_00000155104190746461959110000008164066156702385284_" gradientUnits="userSpaceOnUse" x1="-4651.0366" y1="-1404.4684" x2="-4650.7954" y2="-1404.1398" gradientTransform="matrix(72.46 0 0 96.76 337260.875 136272.1094)"> | |||
<stop offset="1.000000e-02" style="stop-color:#55FFB5"/> | |||
<stop offset="0.59" style="stop-color:#6DFFCB"/> | |||
<stop offset="1" style="stop-color:#78FFD6"/> | |||
</linearGradient> | |||
<path id="Shape-46" style="fill:url(#Shape-46_00000155104190746461959110000008164066156702385284_);" d="M243.4,420.8l31.2-18.1 | |||
c0.7-0.4,1.1-1.2,1.1-2l0.3-23.9c0-0.8-0.4-1.1-1-0.8l-31.2,18.1c-0.7,0.4-1,1.2-1,2l-0.3,23.9 | |||
C242.4,420.8,242.8,421.1,243.4,420.8z"/> | |||
<g id="Shape-47" class="st40"> | |||
<linearGradient id="SVGID_00000101076599354358181930000006343129837226329520_" gradientUnits="userSpaceOnUse" x1="-4352.7603" y1="-1398.1875" x2="-4352.8589" y2="-1397.7163" gradientTransform="matrix(12.28 0 0 25.58 53724.875 36168.9766)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000101076599354358181930000006343129837226329520_);" d="M275.8,393.5c0,0,0,0.9,0,2.3 | |||
c0,0.7,0,1.5,0,2.4c0,0.4,0,0.9,0,1.3s0,0.9,0,1.4c0,0.4-0.2,1-0.4,1.3c-0.1,0.2-0.3,0.3-0.5,0.5c-0.2,0.1-0.4,0.2-0.5,0.3 | |||
l-2.1,1.2l-2.1,1.1l2-1.2l2.1-1.2c0.4-0.2,0.8-0.4,1-0.8c0.2-0.3,0.4-0.8,0.4-1.2c0-0.4,0-1,0-1.4s0-0.9,0-1.3 | |||
c0-0.9,0-1.6,0.1-2.4C275.8,394.4,275.8,393.5,275.8,393.5z"/> | |||
</g> | |||
<linearGradient id="SVGID_00000025437517784366984770000010747534483800912309_" gradientUnits="userSpaceOnUse" x1="-4462.6445" y1="-1386.6772" x2="-4462.1733" y2="-1386.6772" gradientTransform="matrix(17.68 0 0 11.8 79164.0781 16746.4414)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000025437517784366984770000010747534483800912309_);" points="274,381.6 265.8,386.4 | |||
265.8,385.6 274,380.9 "/> | |||
<linearGradient id="SVGID_00000014603506014971141140000003413487988091619970_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1381.9902" x2="-4391.9395" y2="-1381.9902" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13597.9766)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000014603506014971141140000003413487988091619970_);" points="272.3,384.7 265.8,388.4 | |||
265.8,387.6 272.3,383.9 "/> | |||
<linearGradient id="SVGID_00000057835095209813497070000006025639477437015717_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1382.2275" x2="-4391.9395" y2="-1382.2275" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13602.2461)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000057835095209813497070000006025639477437015717_);" points="272.3,386.6 265.8,390.4 | |||
265.8,389.6 272.3,385.9 "/> | |||
<linearGradient id="SVGID_00000112619206826002184200000001160212017524668599_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1382.4702" x2="-4391.9395" y2="-1382.4702" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13606.5156)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000112619206826002184200000001160212017524668599_);" points="272.3,388.6 265.8,392.3 | |||
265.8,391.6 272.3,387.9 "/> | |||
<linearGradient id="SVGID_00000014619903439646413060000003573965781630823350_" gradientUnits="userSpaceOnUse" x1="-4462.6445" y1="-1387.7568" x2="-4462.1733" y2="-1387.7568" gradientTransform="matrix(17.68 0 0 11.8 79164.0781 16769.0801)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000014619903439646413060000003573965781630823350_);" points="274,391.6 265.8,396.3 | |||
265.8,395.6 274,390.8 "/> | |||
<linearGradient id="SVGID_00000135687018638205079420000002421485263476320680_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1383.1858" x2="-4391.9395" y2="-1383.1858" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13619.3066)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000135687018638205079420000002421485263476320680_);" points="272.3,394.6 265.8,398.2 | |||
265.8,397.6 272.3,393.9 "/> | |||
<linearGradient id="SVGID_00000033353309158504731440000001683089570208010429_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1383.4285" x2="-4391.9395" y2="-1383.4285" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13623.5762)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000033353309158504731440000001683089570208010429_);" points="272.3,396.6 265.8,400.2 | |||
265.8,399.6 272.3,395.8 "/> | |||
<linearGradient id="SVGID_00000129923475701508823520000005680875115117715122_" gradientUnits="userSpaceOnUse" x1="-4392.3994" y1="-1383.6606" x2="-4391.9395" y2="-1383.6606" gradientTransform="matrix(13.8 0 0 9.56 60880.3164 13627.8457)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000129923475701508823520000005680875115117715122_);" points="272.3,398.6 265.8,402.3 | |||
265.8,401.5 272.3,397.8 "/> | |||
<linearGradient id="Shape-48_00000020372391056104230850000014324465669750481819_" gradientUnits="userSpaceOnUse" x1="-4538.2388" y1="-1403.8259" x2="-4538.3047" y2="-1403.3442" gradientTransform="matrix(25.5 0 0 71.67 115982.2188 100989.3438)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<polygon id="Shape-48" style="opacity:0.4;fill:url(#Shape-48_00000020372391056104230850000014324465669750481819_);enable-background:new ;" points=" | |||
259.7,385 250.1,417 252,415.9 261.9,383.7 "/> | |||
<linearGradient id="Shape-49_00000158746474549493822570000018370522913050869146_" gradientUnits="userSpaceOnUse" x1="-4587.5259" y1="-1404.0281" x2="-4587.6245" y2="-1403.5239" gradientTransform="matrix(35.56 0 0 77.83 163397.2344 109641.4844)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/> | |||
</linearGradient> | |||
<polygon id="Shape-49" style="opacity:0.4;fill:url(#Shape-49_00000158746474549493822570000018370522913050869146_);enable-background:new ;" points=" | |||
263.6,382.7 253.8,414.9 260.3,411.1 270.3,378.6 "/> | |||
<g class="st108"> | |||
<polygon class="st109" points="262.4,390.4 247.8,398.8 247.8,398.7 262.4,390.2 "/> | |||
</g> | |||
<g class="st108"> | |||
<polygon class="st109" points="262.4,393.4 247.8,402 247.8,401.9 262.4,393.3 "/> | |||
</g> | |||
<g class="st108"> | |||
<polygon class="st109" points="262.4,396.6 247.8,405.1 247.8,405 262.4,396.5 "/> | |||
</g> | |||
<g class="st108"> | |||
<polygon class="st109" points="262.4,399.8 247.8,408.3 247.8,408.1 262.4,399.7 "/> | |||
</g> | |||
<g class="st108"> | |||
<polygon class="st109" points="262.4,403 247.8,411.4 247.8,411.3 262.4,402.8 "/> | |||
</g> | |||
<linearGradient id="SVGID_00000076567543439310601720000004045448953772141723_" gradientUnits="userSpaceOnUse" x1="-3294.0398" y1="-1400.6531" x2="-3294.0398" y2="-1401.113" gradientTransform="matrix(3.13 0 0 37.05 10559.5449 52306.3789)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000076567543439310601720000004045448953772141723_);" points="249.9,413.6 248.5,414.5 | |||
248.5,398 249.9,397.1 "/> | |||
<linearGradient id="SVGID_00000079488291248167022160000006589743079914859678_" gradientUnits="userSpaceOnUse" x1="-3294.5764" y1="-1396.5031" x2="-3294.5764" y2="-1396.0323" gradientTransform="matrix(3.13 0 0 20.21 10562.6748 28634.0879)"> | |||
<stop offset="1.000000e-02" style="stop-color:#009FFC"/> | |||
<stop offset="0.56" style="stop-color:#1595F4"/> | |||
<stop offset="1" style="stop-color:#2090F0"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000079488291248167022160000006589743079914859678_);" points="251.4,412.7 249.9,413.6 | |||
249.9,405 251.4,404.2 "/> | |||
<linearGradient id="SVGID_00000067926720751569274880000009097307530463908492_" gradientUnits="userSpaceOnUse" x1="-3295.7585" y1="-1398.5204" x2="-3295.7585" y2="-1398.9913" gradientTransform="matrix(3.13 0 0 26.95 10569.625 38095.2344)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000067926720751569274880000009097307530463908492_);" points="254.7,410.8 253.1,411.7 | |||
253.1,400 254.7,399.1 "/> | |||
<linearGradient id="SVGID_00000000212797735812424900000012527227039377536170_" gradientUnits="userSpaceOnUse" x1="-3296.2793" y1="-1401.8259" x2="-3296.2793" y2="-1401.366" gradientTransform="matrix(3.13 0 0 43.78 10572.7549 61771.4961)"> | |||
<stop offset="1.000000e-02" style="stop-color:#009FFC"/> | |||
<stop offset="0.56" style="stop-color:#1595F4"/> | |||
<stop offset="1" style="stop-color:#2090F0"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000000212797735812424900000012527227039377536170_);" points="256.1,410.1 254.7,410.8 | |||
254.7,391.3 256.1,390.5 "/> | |||
<linearGradient id="SVGID_00000098184852967546321720000017918665523034777504_" gradientUnits="userSpaceOnUse" x1="-3297.3301" y1="-1390.7391" x2="-3297.3301" y2="-1391.1991" gradientTransform="matrix(3.13 0 0 13.48 10579.2441 19151.5078)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000098184852967546321720000017918665523034777504_);" points="259.4,408.1 257.8,409 | |||
257.8,403.6 259.4,402.7 "/> | |||
<linearGradient id="SVGID_00000099643791442660283550000003955445333089008051_" gradientUnits="userSpaceOnUse" x1="-3297.998" y1="-1400.3435" x2="-3297.998" y2="-1399.8726" gradientTransform="matrix(3.13 0 0 33.68 10582.835 47560.3516)"> | |||
<stop offset="1.000000e-02" style="stop-color:#009FFC"/> | |||
<stop offset="0.56" style="stop-color:#1595F4"/> | |||
<stop offset="1" style="stop-color:#2090F0"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000099643791442660283550000003955445333089008051_);" points="260.8,407.3 259.4,408.1 | |||
259.4,393.3 260.8,392.5 "/> | |||
<linearGradient id="SVGID_00000139981804617803399270000013206585361592540318_" gradientUnits="userSpaceOnUse" x1="-4573.7271" y1="-1401.5767" x2="-4573.2671" y2="-1401.5767" gradientTransform="matrix(31.99 0 0 43.44 146560.3125 61289.4375)"> | |||
<stop offset="1.000000e-02" style="stop-color:#00C6FB"/> | |||
<stop offset="0.12" style="stop-color:#00B6F8"/> | |||
<stop offset="0.52" style="stop-color:#0085F1"/> | |||
<stop offset="0.83" style="stop-color:#0066EC"/> | |||
<stop offset="1" style="stop-color:#005BEA"/> | |||
</linearGradient> | |||
<polygon style="fill:url(#SVGID_00000139981804617803399270000013206585361592540318_);" points="262.4,406.5 247.5,415.1 | |||
247.5,395 247.6,394.8 247.6,414.9 262.4,406.3 "/> | |||
<linearGradient id="Shape-50_00000140719076435951959120000006641442635192087477_" gradientUnits="userSpaceOnUse" x1="-4655.9185" y1="-1402.9375" x2="-4655.9624" y2="-1403.0032" gradientTransform="matrix(78.92 0 0 57.93 367701.5 81679.6797)"> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0" style="stop-color:#0D55FF;stop-opacity:0"/> | |||
<stop offset="0.65" style="stop-color:#04CEFF;stop-opacity:0.14"/> | |||
<stop offset="1" style="stop-color:#00FCFF;stop-opacity:0.2"/> | |||
</linearGradient> | |||
<polygon id="Shape-50" style="fill:url(#Shape-50_00000140719076435951959120000006641442635192087477_);" points="244.6,425.2 | |||
243.4,425.1 240.4,419.8 277,398.2 275.4,407.6 "/> | |||
<linearGradient id="Shape-51_00000147939181360286582920000004146921999076484486_" gradientUnits="userSpaceOnUse" x1="-4353.4653" y1="-1402.2626" x2="-4353.4541" y2="-1401.704" gradientTransform="matrix(12.39 0 0 31.04 54185.7031 43981.7422)"> | |||
<stop offset="0" style="stop-color:#FFFFFF"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<polyline id="Shape-51" style="fill:url(#Shape-51_00000147939181360286582920000004146921999076484486_);" points="249.2,471.7 | |||
249.2,460.7 243.5,457.3 243.4,458.3 248.1,461 "/> | |||
<linearGradient id="Shape-52_00000133514124685140248980000012016277643264497070_" gradientUnits="userSpaceOnUse" x1="-4650.8057" y1="-1400.7756" x2="-4650.313" y2="-1400.7756" gradientTransform="matrix(71.6 0 0 27.35 333266.75 38764.7188)"> | |||
<stop offset="0" style="stop-color:#91BFDB"/> | |||
<stop offset="0.6" style="stop-color:#A8E9EB;stop-opacity:0.5"/> | |||
<stop offset="1" style="stop-color:#EFF3F6;stop-opacity:0"/> | |||
</linearGradient> | |||
<path id="Shape-52" style="fill:url(#Shape-52_00000133514124685140248980000012016277643264497070_);" d="M271.6,457.3 | |||
c2.3-0.1,5.8-2.3,30.2-1.5c3.6-1.2,2.3-4.6,1.1-5.7c-1.2-1.1-12.5,0.4-16.4,1.2c-3.9,0.8-15,3.2-15.4,5.4"/> | |||
<g id="Shape-53"> | |||
<linearGradient id="SVGID_00000054984489780984634950000007063448993696825000_" gradientUnits="userSpaceOnUse" x1="-4313.8755" y1="-1382.7407" x2="-4314.3354" y2="-1382.7407" gradientTransform="matrix(11.1 0 0 6.07 48165.1211 8850.4492)"> | |||
<stop offset="0" style="stop-color:#2A2ED0"/> | |||
<stop offset="0.1" style="stop-color:#3133D1"/> | |||
<stop offset="0.25" style="stop-color:#433FD6"/> | |||
<stop offset="0.42" style="stop-color:#6255DC"/> | |||
<stop offset="0.61" style="stop-color:#8C72E6"/> | |||
<stop offset="0.81" style="stop-color:#C297F2"/> | |||
<stop offset="1" style="stop-color:#FCBFFF"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000054984489780984634950000007063448993696825000_);" d="M272.9,457.5c0,0,0.1,0.7-0.2,1 | |||
c-0.3,0.3-1.8,0.1-2.7-0.4c-0.8-0.3-1.5-0.8-2.2-1.4c-0.1-0.3,0-0.7,0.2-0.9C268.2,455.6,272.9,457.5,272.9,457.5z"/> | |||
<linearGradient id="SVGID_00000080918987833476237920000016819689408787064764_" gradientUnits="userSpaceOnUse" x1="-4299.2207" y1="-1380.0359" x2="-4299.0454" y2="-1379.6963" gradientTransform="matrix(10.7 0 0 5.64 46274.793 8242.5244)"> | |||
<stop offset="0.1" style="stop-color:#89F7FE"/> | |||
<stop offset="0.28" style="stop-color:#87F2FE"/> | |||
<stop offset="0.5" style="stop-color:#81E4FE"/> | |||
<stop offset="0.73" style="stop-color:#76CCFF"/> | |||
<stop offset="0.97" style="stop-color:#68ABFF"/> | |||
<stop offset="1" style="stop-color:#66A6FF"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000080918987833476237920000016819689408787064764_);" d="M272.7,456.4c0,0,0.7,1.2-0.2,1.6 | |||
c-1.1,0.4-4.9-1.4-4.5-2.2c0.3-0.5,1.2-0.3,2.5-0.3C271.4,455.5,272.2,455.9,272.7,456.4z"/> | |||
<linearGradient id="SVGID_00000160875980869004348870000016218684430427734656_" gradientUnits="userSpaceOnUse" x1="-4314.251" y1="-1382.3303" x2="-4315.248" y2="-1382.3523" gradientTransform="matrix(11.1 0 0 6.07 48178.8828 8845.9297)"> | |||
<stop offset="0" style="stop-color:#2A2ED0"/> | |||
<stop offset="0.1" style="stop-color:#3133D1"/> | |||
<stop offset="0.25" style="stop-color:#433FD6"/> | |||
<stop offset="0.42" style="stop-color:#6255DC"/> | |||
<stop offset="0.61" style="stop-color:#8C72E6"/> | |||
<stop offset="0.81" style="stop-color:#C297F2"/> | |||
<stop offset="1" style="stop-color:#FCBFFF"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000160875980869004348870000016218684430427734656_);" d="M279.3,455.3c0,0,0.1,0.7-0.2,1 | |||
c-0.3,0.3-1.8,0.1-2.7-0.4c-0.8-0.3-1.5-0.9-2.2-1.4c-0.1-0.3,0-0.7,0.2-0.9C274.6,453.4,279.3,455.3,279.3,455.3z"/> | |||
<linearGradient id="SVGID_00000138549545104016646050000011419445232965228706_" gradientUnits="userSpaceOnUse" x1="-4300.1392" y1="-1379.9625" x2="-4300.9165" y2="-1379.5682" gradientTransform="matrix(10.7 0 0 5.64 46288.5508 8237.4941)"> | |||
<stop offset="0.1" style="stop-color:#89F7FE"/> | |||
<stop offset="0.28" style="stop-color:#87F2FE"/> | |||
<stop offset="0.5" style="stop-color:#81E4FE"/> | |||
<stop offset="0.73" style="stop-color:#76CCFF"/> | |||
<stop offset="0.97" style="stop-color:#68ABFF"/> | |||
<stop offset="1" style="stop-color:#66A6FF"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000138549545104016646050000011419445232965228706_);" d="M279.1,454.2c0,0,0.7,1.2-0.2,1.6 | |||
c-1.1,0.4-4.9-1.4-4.5-2.2c0.3-0.5,1.2-0.3,2.5-0.3C277.8,453.3,278.5,453.7,279.1,454.2z"/> | |||
<linearGradient id="SVGID_00000012439461484347364750000007568484484384575618_" gradientUnits="userSpaceOnUse" x1="-4509.1016" y1="-1403.5773" x2="-4509.123" y2="-1404.2782" gradientTransform="matrix(21.74 0 0 66.22 98302.5234 93415.1875)"> | |||
<stop offset="0" style="stop-color:#1E2275"/> | |||
<stop offset="1" style="stop-color:#0046BC"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000012439461484347364750000007568484484384575618_);" d="M279,426.5c0.5,2.6,0.5,5.3,0,7.9 | |||
c-0.7,2.6,0,19.9,0,19.9s-0.7,0.9-2.3,0.1c0,0-0.8-6.5-1-11.9c-0.1-3.9-0.2-7.2-0.2-7.8l-1.5,0.7c-0.5,2.7-0.9,5.5-1.1,8.3 | |||
c0,2.7-0.1,13-0.1,13c-0.5,0.4-1.4,0.4-2,0c0,0-1.2-10.8-1.5-13.7c-0.3-2.8,1-14.5,1-14.5S276,425.1,279,426.5z"/> | |||
<path class="st125" d="M272.3,410c0,0,0.4,2.1,0.4,2.4s1.9-0.9,2.2-1.3l-0.3-2.3C273.7,409,272.9,409.3,272.3,410z"/> | |||
<path class="st126" d="M272.3,410l0.4,2.4c0.5-0.7,0.9-1.5,1-2.3C273.7,410,273.7,408.4,272.3,410z"/> | |||
<linearGradient id="SVGID_00000085217106529308597890000006205264978108892050_" gradientUnits="userSpaceOnUse" x1="-4097.0649" y1="-1373.2161" x2="-4097.5254" y2="-1373.2161" gradientTransform="matrix(7.17 0 0 5.93 29652.7383 8555.3711)"> | |||
<stop offset="1.000000e-02" style="stop-color:#6A9DFF"/> | |||
<stop offset="0.27" style="stop-color:#4872EB"/> | |||
<stop offset="0.6" style="stop-color:#2141D3"/> | |||
<stop offset="0.86" style="stop-color:#0922C4"/> | |||
<stop offset="1" style="stop-color:#0017BF"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000085217106529308597890000006205264978108892050_);" d="M275,410.8c0.2,0.2,0.4,0.5,0.7,0.8 | |||
c-0.7,1.2-2,2-3.3,2l0.4-1.3L275,410.8z"/> | |||
<linearGradient id="SVGID_00000020394213504040997820000013097059723123130259_" gradientUnits="userSpaceOnUse" x1="-4503.46" y1="-1402.0055" x2="-4503.3394" y2="-1401.3702" gradientTransform="matrix(21.11 0 0 39.74 95340.4531 56123.2578)"> | |||
<stop offset="1.000000e-02" style="stop-color:#FB6583"/> | |||
<stop offset="0.13" style="stop-color:#FC7688"/> | |||
<stop offset="0.53" style="stop-color:#FDA797"/> | |||
<stop offset="0.83" style="stop-color:#FFC6A0"/> | |||
<stop offset="1" style="stop-color:#FFD1A3"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000020394213504040997820000013097059723123130259_);" d="M275.6,411.6c1,0,1.9,0.7,2.1,1.8 | |||
c0.5,2.6,1,5.4,1.2,8.1c0,1.5,0.7,4.5,0.4,5.7c-0.2,1-2,1.4-4.2,2.4c-1.6,0.9-3.7,0.8-5.4-0.2c-0.7-0.5,0.2-3.3,0.1-4.6 | |||
c-0.1-1.3-0.1-3.7,0-4.5s-0.1-4.3,2.4-6.6C273.3,412.8,274.4,412.2,275.6,411.6z"/> | |||
<linearGradient id="SVGID_00000181058967435089559130000006669968388613110451_" gradientUnits="userSpaceOnUse" x1="-3775.5581" y1="-1390.2045" x2="-3775.6128" y2="-1389.3502" gradientTransform="matrix(4.71 0 0 29.57 18050.4395 41817.6797)"> | |||
<stop offset="1.000000e-02" style="stop-color:#FB6583"/> | |||
<stop offset="0.13" style="stop-color:#FC7688"/> | |||
<stop offset="0.53" style="stop-color:#FDA797"/> | |||
<stop offset="0.83" style="stop-color:#FFC6A0"/> | |||
<stop offset="1" style="stop-color:#FFD1A3"/> | |||
</linearGradient> | |||
<path style="opacity:0.3;fill:url(#SVGID_00000181058967435089559130000006669968388613110451_);enable-background:new ;" d=" | |||
M271.6,416.2c0,0-0.5,5.9-0.7,8c-0.1,1.5,0.4,5.4,0,5.7c-0.4-0.1-0.8-0.3-1.1-0.5c-0.9-0.5-0.1-3.2,0-3.9c0.1-0.8,0-2.7,0-4.3 | |||
c0-1.9,0.3-4.7,0.7-4.9C271,416.2,271.3,416.2,271.6,416.2z"/> | |||
<linearGradient id="SVGID_00000122710278541649656810000007312387862833113729_" gradientUnits="userSpaceOnUse" x1="-4572.3774" y1="-1397.1755" x2="-4572.0815" y2="-1396.6389" gradientTransform="matrix(31.64 0 0 21.28 144939.8594 30149.8242)"> | |||
<stop offset="1.000000e-02" style="stop-color:#FB6583"/> | |||
<stop offset="0.13" style="stop-color:#FC7688"/> | |||
<stop offset="0.53" style="stop-color:#FDA797"/> | |||
<stop offset="0.83" style="stop-color:#FFC6A0"/> | |||
<stop offset="1" style="stop-color:#FFD1A3"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000122710278541649656810000007312387862833113729_);" d="M273.6,414.5c0,0,0.7,0.8-0.3,1.9 | |||
s-6.9,2.5-8.2,2.3c-3.7-0.7-6-8.5-6-8.5l1.6-1.3c0,0,2.8,7.3,5.4,6.9C269.1,415,272.3,412.6,273.6,414.5z"/> | |||
<path class="st125" d="M270.2,405.4c0,0-0.8,4.5,0,5.3s2.8-0.2,2.8-0.2s2.3-1.4,1.3-2.8C273.4,406.1,270.2,405.4,270.2,405.4z"/> | |||
<linearGradient id="SVGID_00000166643334475131779910000005720074573264916131_" gradientUnits="userSpaceOnUse" x1="-4412.3691" y1="-1392.0507" x2="-4412.5332" y2="-1392.5873" gradientTransform="matrix(14.75 0 0 18.16 65368.8008 25736.9492)"> | |||
<stop offset="0" style="stop-color:#1E2275"/> | |||
<stop offset="1" style="stop-color:#0046BC"/> | |||
</linearGradient> | |||
<path style="fill:url(#SVGID_00000166643334475131779910000005720074573264916131_);" d="M275.6,410c0,0-1.8,1-2.3,0.4 | |||
c-0.7-0.7-0.9-1.6-0.5-2.5c0.1-0.7-0.3-1.1-0.7-0.3c-0.2,0.5-0.1,0.8-0.4,0.7s-0.1-0.3-0.1-0.8c0.1-0.5-0.2-1-0.7-1.2 | |||
c-0.5-0.3-0.9-1-0.9-1.5c0-1.9,1.8-3.2,4.2-2.1c2.1,1,2.8,2.5,2.6,3.5C276.6,407.1,276.4,409.5,275.6,410z"/> | |||
<polygon class="st132" points="275.6,434.7 276.6,434.2 275.7,439.9 "/> | |||
<path class="st133" d="M260.3,409c-0.1-0.2-0.1-0.4-0.1-0.7c0.1-0.2,0.5-0.5,0.4-0.7c-0.1-0.1-0.7,0.4-0.7,0.3s0-1.1-0.2-1.1 | |||
s-0.2,0.7-0.2,1c0,0-1,0.4-0.8,1c0.1,0.3,0.3,0.7,0.4,1L260.3,409z"/> | |||
</g> | |||
</g> | |||
</g> | |||
</svg> |
@@ -0,0 +1,128 @@ | |||
/* | |||
椭圆会使内部失真 transform: rotateX(50deg); | |||
*/ | |||
.rotation3D{ | |||
position: relative; width: 800px; height: 600px; user-select: none; | |||
margin: 0 auto; | |||
/* border: 1px solid white; border-radius: 100%; */ | |||
/* cursor: move; */ | |||
} | |||
.rotation3D .center{ | |||
display: none; | |||
position: absolute; left: 50%; top: 50%; | |||
transform: translate(-50%, -50%); | |||
} | |||
.rotation3D .itemList{ position: absolute; width: 100%; height: 100%; z-index: 20; } | |||
.rotation3D .lineList{ | |||
position: absolute; width: 100%; height: 100%; z-index: 10; | |||
transform-style: preserve-3d; | |||
} | |||
/*---------------------------点样式---------------------------*/ | |||
.rotation3D__item{ | |||
position: absolute; display: block; width: 161px; height: 188px; | |||
text-align: center; line-height: 30px; font-size: 16px; color: white; | |||
/*background: #2292ef; border-radius: 4px;*/ | |||
/*cursor: pointer; */ | |||
} | |||
.rotation3D__item .scale{ position: absolute; top: 0; width: 100%; height: 100%; } | |||
.rotation3D__item .cont{ position: relative; z-index: 2; } | |||
.rotation3D__item .cont .iconfont { font-size: 28px; margin-top: 30px; margin-bottom: 96px; display: block; height: 35px;} | |||
.rotation3D__item .cont p{ color: #101010; } | |||
.lineList .rotation3D__line:nth-child(5n+0) .dot{ | |||
} | |||
.lineList .rotation3D__line:nth-child(5n+1) .dot{ | |||
animation-delay: 1s; | |||
} | |||
.lineList .rotation3D__line:nth-child(5n+2) .dot{ | |||
animation-delay: 3s; | |||
} | |||
.lineList .rotation3D__line:nth-child(5n+3) .dot{ | |||
animation-delay: 2s; | |||
} | |||
.lineList .rotation3D__line:nth-child(5n+3) .dot{ | |||
animation-delay: 4s; | |||
} | |||
.rotation3D__item.blue{ color: #01e9fc; } | |||
.rotation3D__item.green{ color: #b4b3ca; } | |||
.rotation3D__item.yellow{ color: #ffd200; } | |||
/*底座*/ | |||
.rotation3D__item .baseImg{ position: absolute; width: 100%; height: 100%; z-index: 1; } | |||
.rotation3D__item.blue .baseImg{ background: url("img/idc-red.png"); } | |||
.rotation3D__item.green .baseImg{ background: url("img/idc-green.png"); } | |||
.rotation3D__item.yellow .baseImg{ background: url("img/idc-yellow.png"); } | |||
/*--------------------------- | |||
线样式 | |||
线高为总高的一般 | |||
---------------------------*/ | |||
.rotation3D__line{ | |||
position: absolute; left: 50%; top: 50%; | |||
display: block; | |||
width: 30px; | |||
height: 50%; | |||
padding-top: 60px; color: #fff; font-size: 50px; | |||
/*background: #fff;*/ | |||
/*原点设置在中间*/ | |||
transform-origin: 50% 0; | |||
transform-style: preserve-3d; | |||
overflow: hidden; | |||
} | |||
.rotation3D__line .pos{ position: absolute; top: 0; left: 15px;} | |||
.rotation3D__line svg { position: absolute; top: 0; } | |||
.rotation3D__line svg path { | |||
stroke: #fff; fill: none; | |||
stroke-width: 2; | |||
animation: path-animation 100s linear 0s infinite normal; | |||
} | |||
@keyframes path-animation { | |||
0% { stroke-dashoffset:500; } | |||
100% { stroke-dashoffset:0; } | |||
} | |||
.rotation3D__line .dot { | |||
position: absolute; top: 0; left: 0; text-align: center; | |||
/*width: 35px; height: 35px; font-size: 35px; */ | |||
width: 19px; height: 19px; font-size: 19px; | |||
} | |||
.rotation3D__line .dot1,.rotation3D__line .dot3,.rotation3D__line .dot4{ | |||
animation: svg-path-animation 6s ease-in-out 0s infinite normal; | |||
} | |||
.rotation3D__line .dot1{ | |||
offset-path: path("M0 400, 0 0"); offset-distance: 0%; | |||
} | |||
.rotation3D__line .dot2{ | |||
offset-path: path("M0 200, 0 0"); offset-distance: 0%; | |||
background: #ffd200; border-radius: 100%; | |||
font-size: 22px; color: #000; | |||
} | |||
.rotation3D__line .dot3{ | |||
offset-path: path("M20 400 S 0 200, 20 0"); offset-distance: 0%; | |||
} | |||
.rotation3D__line .dot4{ | |||
position: relative; | |||
offset-path: path("M20 0 S 40 200, 20 400"); offset-distance: 0%; | |||
} | |||
@keyframes svg-path-animation { | |||
from {offset-distance: 100%;} | |||
to {offset-distance: 0%;} | |||
} | |||
.dot1 > span{ | |||
position: absolute; | |||
font-size: 12px; | |||
color: #888; | |||
transform:scale(0.80); | |||
transform-origin:left; | |||
white-space: nowrap; | |||
} | |||
/*颜色*/ | |||
.rotation3D__line.blue { color: #07b2f9; } | |||
.rotation3D__line.green { color: #ac94ee; } | |||
.rotation3D__line.yellow { color: #ffd500; } | |||
.rotation3D__line.blue svg path { stroke: #07b2f9; } | |||
.rotation3D__line.green svg path { stroke: #ac94ee; } | |||
.rotation3D__line.yellow svg path { stroke: #ffd500; } |
@@ -0,0 +1,380 @@ | |||
var cancelFrame = window.cancelAnimationFrame || window.cancelRequestAnimationFrame; | |||
var requestFrame = window.requestAnimationFrame; | |||
var time = !window.performance || !window.performance.now ? | |||
function () {return +new Date()}: | |||
function () {return performance.now()}; | |||
/** | |||
* 计算两点距离 | |||
* @param points | |||
* @returns {number} | |||
* distance([{x:0,y:0},{x:1,y:1}]); | |||
*/ | |||
var distance = function(points) { | |||
var p1=points[0]; | |||
var p2=points[1]; | |||
var a = p2.x-p1.x; | |||
var b = p2.y-p1.y; | |||
return Math.sqrt(a*a+b*b); | |||
}; | |||
/** | |||
* 圆公式 | |||
* @param rotation 弧度 | |||
* 计算公式: | |||
* Math.PI; //圆周率 | |||
* Math.sin(); //正弦 x -左 +右 | |||
* Math.cos; //余弦 y -下 +上 | |||
*/ | |||
var circleMath = { | |||
/** | |||
* 根据弧度计算角度 | |||
* @param rotation 弧度 | |||
* rotation, farScale, xs, xr, ys, yr, itemWidth | |||
*/ | |||
// parseRotate: function (rotation) { | |||
// return (180 / Math.PI * rotation) - 180; | |||
// }, | |||
parseRotate: function (rotation, self) { | |||
var sin = Math.sin(rotation), cos = Math.cos(rotation); | |||
var sin_cos = sin*cos; //得出偏移正负值,从0°向左依次 +-+- | |||
var angle = (180 / Math.PI * rotation) - 180; | |||
var lastAngle = angle; | |||
// console.log('rotation',rotation) | |||
// console.log('sin',sin) | |||
// console.log('cos',cos) | |||
// console.log('sin*cos',sin*cos); | |||
// console.log('统一偏移角度',self.yr * (sin_cos/Math.PI)) | |||
lastAngle = angle + (self.yr * (sin_cos/(Math.PI+1))); | |||
return lastAngle; | |||
}, | |||
/** | |||
* 计算scale,x,y | |||
* scale 最小尺寸 + ((1 - 最小尺寸) * (sin正弦 + 1) * 0.5) | |||
* x x起点 + (尺寸 * cos余弦 * x半径) - 元素宽度一半 | |||
* y y起点 + (尺寸 * sin正弦 * x半径) - 元素宽度一半 | |||
* farScale, xs, xr, ys, yr, itemWidth | |||
*/ | |||
parseSXY: function (rotation, self) { | |||
var farScale=self.farScale; | |||
var itemWidth=self.itemWidth; | |||
var xs=self.xs; var xr=self.xr; var ys=self.ys; var yr=self.yr; | |||
var sin = Math.sin(rotation), cos = Math.cos(rotation); | |||
var scale = farScale + ((1 - farScale) * (sin + 1) * 0.5); //单个尺寸 | |||
// 按设置尺寸 | |||
// var x = xs + (scale * cos * xr) - (itemWidth * 0.5); | |||
// var y = ys + (scale * sin * yr) - (itemWidth * 0.5); | |||
// 不使用压缩 | |||
// var x = xs + (cos * xs) - (itemWidth * 0.5); | |||
// var y = ys + (sin * ys) - (itemWidth * 0.5); | |||
// 使用压缩 | |||
var x = xs + (cos * xr) - (itemWidth * 0.5); | |||
var y = ys + (sin * yr) - (itemWidth * 0.5); | |||
var distanceNumber = distance([ | |||
{x:self.$rotation.width()/2 - self.$item.width()/2, y:self.$rotation.height()/2 - self.$item.height()/2}, | |||
{x:x,y:y}] | |||
); | |||
// console.log({x:self.$rotation.width()/2, y:self.$rotation.height()/2}) | |||
// console.log('x,y',x,y) | |||
// console.log('两点距离',distanceNumber) | |||
return { | |||
x: x, | |||
y: y, | |||
scale: scale, | |||
distanceNumber: distanceNumber, | |||
} | |||
}, | |||
} | |||
/** | |||
* 3D旋转 | |||
* @param id | |||
*/ | |||
var Rotation3D = window.Rotation3D = function (_opts) { | |||
var self=this; | |||
this.$rotation = $(_opts.id) | |||
this.$lineList = this.$rotation.find('.lineList') | |||
this.$item = this.$rotation.find('.rotation3D__item') | |||
this.$line = this.$rotation.find('.rotation3D__line') | |||
this.itemWidth = this.$item.width(); | |||
this.itemHeight = this.$item.height(); | |||
this.length = this.$item.length; | |||
// 圆计算 | |||
this.rotation = Math.PI / 2; //圆周率/2 | |||
this.destRotation = this.rotation; | |||
var xr = this.$rotation.width() * 0.5; | |||
var yr = this.$rotation.height() * 0.5; | |||
var xRadius = _opts.xRadius || 0; | |||
var yRadius = _opts.yRadius || 0; | |||
var opts = Object.assign({ | |||
farScale: 1, // 最小尺寸 | |||
xs: xr, // x起点 | |||
ys: yr, // y起点 | |||
xr: xr - xRadius, // x半径-压缩 | |||
yr: yr - yRadius, // y半径-压缩 | |||
// 播放 | |||
autoPlay:false, | |||
autoPlayDelay:3000, | |||
currenIndex:-1, | |||
fps:30, | |||
speed:4, | |||
},_opts) | |||
Object.assign(this, opts) | |||
// 遍历子元素 | |||
this.$item.each(function (index) { | |||
$(this).click(function () { | |||
$(this).addClass('active').siblings().removeClass('active') | |||
self.goTo(index) | |||
}) | |||
}) | |||
// 当前控件进入离开 | |||
this.$rotation.mouseenter(function () { | |||
clearInterval(self.autoPlayTimer) | |||
}) | |||
this.$rotation.mouseleave(function () { | |||
self.onAutoPlay() | |||
}) | |||
this.onAutoPlay() | |||
this.onDrag() | |||
this.render() | |||
} | |||
/** | |||
* item样式 | |||
* x x起点 + (尺寸 * 余弦 * x压缩) - 元素宽度一半 | |||
* y y起点 + (尺寸 * 正弦 * y压缩) - 元素宽度一半 | |||
*/ | |||
Rotation3D.prototype.itemStyle = function($item, index, rotation) { | |||
//console.log("itemStyle=" + rotation + " index=" + index); | |||
var parseSXY = circleMath.parseSXY(rotation, this); | |||
var scale = parseSXY.scale; | |||
var x = parseSXY.x; | |||
var y = parseSXY.y; | |||
var $line = this.$lineList.find('.rotation3D__line').eq(index); | |||
//设置当前子菜单的位置(left,top) = (x,y) | |||
$item.find('.scale').css({ | |||
'transform': `scale(${scale})`, | |||
// 'top': `${this.itemWidth * (1-scale) }`, | |||
}) | |||
$item.css({ | |||
position: 'absolute', | |||
display: 'inline-block', | |||
// opacity: scale, | |||
'z-index': parseInt(scale * 100), | |||
'transform-origin': '0px 0px', | |||
// 'transform': `translate(${x}px, ${y}px) scale(${scale})`, | |||
'transform': `translate(${x}px, ${y}px)`, | |||
}); | |||
/** | |||
* 线样式 | |||
*/ | |||
$line.css({ | |||
height:parseSXY.distanceNumber, | |||
}) | |||
$line.find('svg').css({ | |||
height:parseSXY.distanceNumber, | |||
}) | |||
$line.find('.dot1').css({ | |||
'offset-path':`path("M0 ${parseSXY.distanceNumber}, 0 0")`, | |||
}) | |||
$line.find('#path1').attr({ | |||
'd':`M0 ${parseSXY.distanceNumber}, 0 0`, | |||
}) | |||
$line.find('.dot2').css({ | |||
'offset-path':`path("M0 ${parseSXY.distanceNumber/2}, 0 0")`, | |||
}) | |||
$line.find('#path2').attr({ | |||
'd':`M0 ${parseSXY.distanceNumber}, 0 0`, | |||
}) | |||
$line.find('.dot3').css({ | |||
'offset-path':`path("M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0")`, | |||
}) | |||
$line.find('#path3').attr({ | |||
'd':`M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0`, | |||
}) | |||
$line.find('.dot4').css({ | |||
'offset-path':`path("M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}")`, | |||
}) | |||
$line.find('#path4').attr({ | |||
'd':`M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}`, | |||
}) | |||
} | |||
/** | |||
* line样式 | |||
*/ | |||
Rotation3D.prototype.lineStyle = function($line, index, rotation) { | |||
var rotate = circleMath.parseRotate(rotation, this) | |||
//console.log("lineStyle=" + rotation + " index=" + index); | |||
$line.css({ | |||
transform: 'rotate(' + rotate + 'deg)', | |||
}) | |||
this.$lineList.css({ | |||
// transform: `rotateX(${this.yRadius / 3}deg)`, | |||
}) | |||
} | |||
/** | |||
* 旋转至index | |||
*/ | |||
Rotation3D.prototype.goTo = function (index) { | |||
var self = this; | |||
this.currenIndex = index; | |||
//console.log('goTo currenIndex', index); | |||
/** | |||
* 1.计算floatIndex,用于控死amdiff | |||
*/ | |||
var itemsRotated = this.length * ((Math.PI / 2) - this.rotation) / (2 * Math.PI); | |||
var floatIndex = itemsRotated % this.length; | |||
if (floatIndex < 0) { floatIndex = floatIndex + this.length; } | |||
/** | |||
* 2.计算diff,判断方向正反 | |||
*/ | |||
var diff = index - (floatIndex % this.length); | |||
if (2 * Math.abs(diff) > this.length) { | |||
diff -= (diff > 0) ? this.length : -this.length; | |||
} | |||
// 停止任何正在进行的旋转 | |||
this.destRotation += (2 * Math.PI / this.length) * -diff; | |||
this.scheduleNextFrame(); | |||
} | |||
/** | |||
* 定时器渐近旋转 | |||
*/ | |||
Rotation3D.prototype.scheduleNextFrame = function () { | |||
var self = this | |||
this.lastTime = time(); | |||
// 暂停 | |||
var pause = function () { | |||
cancelFrame ? cancelFrame(this.timer) : clearTimeout(self.timer); | |||
self.timer = 0; | |||
} | |||
// 渐进播放 | |||
var playFrame = function () { | |||
var rem = self.destRotation - self.rotation; | |||
var now = time(), dt = (now - self.lastTime) * 0.002; | |||
self.lastTime = now; | |||
// console.log('rem',rem) | |||
if (Math.abs(rem) < 0.003) { | |||
self.rotation = self.destRotation; | |||
pause(); | |||
} else { | |||
// 渐近地接近目的地 | |||
self.rotation = self.destRotation - rem / (1 + (self.speed * dt)); | |||
self.scheduleNextFrame(); | |||
} | |||
self.render(); | |||
} | |||
this.timer = cancelFrame ? | |||
requestFrame(playFrame) : | |||
setTimeout(playFrame, 1000 / this.fps); | |||
} | |||
/** | |||
* 更新 | |||
*/ | |||
Rotation3D.prototype.render = function () { | |||
var self=this; | |||
// 图形间隔:弧度 | |||
var spacing = 2 * Math.PI / this.$item.length; | |||
var itemRotation = this.rotation; | |||
var lineRotation = this.rotation + (Math.PI/2); | |||
this.$item.each(function (index) { | |||
self.itemStyle($(this), index, itemRotation) | |||
itemRotation += spacing; | |||
}) | |||
this.$line.each(function (index) { | |||
self.lineStyle($(this), index, lineRotation) | |||
lineRotation += spacing; | |||
}) | |||
} | |||
/** | |||
* 自动播放 | |||
*/ | |||
Rotation3D.prototype.onAutoPlay = function () { | |||
var self = this; | |||
if (this.autoPlay) { | |||
this.autoPlayTimer = setInterval(function () { | |||
if (self.currenIndex < 0) { | |||
self.currenIndex = self.length - 1 | |||
} | |||
//console.log("autoPlayTimer...."); | |||
self.goTo(self.currenIndex); | |||
self.currenIndex--; //倒叙 | |||
}, this.autoPlayDelay) | |||
} | |||
} | |||
/** | |||
* 拖拽 | |||
*/ | |||
Rotation3D.prototype.onDrag = function () { | |||
var self = this; | |||
var startX, startY, moveX, moveY, endX, endY; | |||
//console.log("onDrag...."); | |||
// 拖拽:三个事件-按下 移动 抬起 | |||
//按下 | |||
this.$rotation.mousedown(function (e) { | |||
startX = e.pageX; startY = e.pageY; | |||
//console.log("mousedown...."); | |||
// 移动 | |||
$(document).mousemove(function (e) { | |||
// console.log('移动'); | |||
endX = e.pageX; endY = e.pageY; | |||
moveX = endX - startX; moveY = endY - startY; | |||
// console.log('x,y',moveX,moveY); | |||
}) | |||
// 抬起 | |||
$(document).mouseup(function (e) { | |||
endX = e.pageX; endY = e.pageY; | |||
moveX = endX - startX; moveY = endY - startY; | |||
//console.log("mouseup...."); | |||
// 每40旋转一步 | |||
var moveIndex = parseInt(Math.abs(moveX) / 50) | |||
//console.log('moveIndex',moveIndex) | |||
if (moveIndex > 0) { | |||
// console.log(moveX<0 ? '向左' : '向右') | |||
if (moveX < 0) { //向左 | |||
self.currenIndex = self.currenIndex - moveIndex | |||
play(moveIndex) | |||
} else { //向右 | |||
self.currenIndex = self.currenIndex + moveIndex | |||
play(moveIndex) | |||
} | |||
} | |||
// 解绑 | |||
$(document).unbind("mousemove"); | |||
$(document).unbind("mouseup"); | |||
}) | |||
}) | |||
function play() { | |||
if (self.currenIndex == 0) { | |||
self.currenIndex = self.length - 1 | |||
} | |||
self.goTo(self.currenIndex % self.length); | |||
} | |||
} |
@@ -22,16 +22,25 @@ require ( | |||
github.com/PuerkitoBio/goquery v1.5.0 | |||
github.com/RichardKnop/machinery v1.6.9 | |||
github.com/RoaringBitmap/roaring v0.4.23 // indirect | |||
github.com/alecthomas/chroma v0.10.0 | |||
github.com/alibabacloud-go/darabonba-openapi v0.1.18 | |||
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 | |||
github.com/alibabacloud-go/tea v1.1.17 | |||
github.com/alibabacloud-go/tea-utils v1.4.3 | |||
github.com/alibabacloud-go/tea-xml v1.1.2 // indirect | |||
github.com/bgentry/speakeasy v0.1.0 // indirect | |||
github.com/blevesearch/bleve v1.0.7 | |||
github.com/clbanning/mxj/v2 v2.5.5 // indirect | |||
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 // indirect | |||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect | |||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect | |||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect | |||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible | |||
github.com/disintegration/imaging v1.6.2 | |||
github.com/dustin/go-humanize v1.0.0 | |||
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 | |||
github.com/elliotchance/orderedmap v1.4.0 | |||
github.com/emirpasic/gods v1.12.0 | |||
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a | |||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect | |||
@@ -42,6 +51,7 @@ require ( | |||
github.com/go-enry/go-enry/v2 v2.3.0 | |||
github.com/go-git/go-billy/v5 v5.0.0 | |||
github.com/go-git/go-git/v5 v5.0.0 | |||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a | |||
github.com/go-ini/ini v1.56.0 // indirect | |||
github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92 | |||
github.com/go-openapi/jsonreference v0.19.3 // indirect | |||
@@ -52,9 +62,11 @@ require ( | |||
github.com/gobwas/glob v0.2.3 | |||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 | |||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 | |||
github.com/golang/mock v1.6.0 // indirect | |||
github.com/golang/protobuf v1.4.1 // indirect | |||
github.com/gomodule/redigo v2.0.0+incompatible | |||
github.com/google/go-github/v24 v24.0.1 | |||
github.com/google/uuid v1.1.1 | |||
github.com/gorilla/context v1.1.1 | |||
github.com/gorilla/websocket v1.4.0 | |||
github.com/hashicorp/go-retryablehttp v0.6.6 // indirect | |||
@@ -87,6 +99,7 @@ require ( | |||
github.com/niklasfasching/go-org v0.1.9 | |||
github.com/oliamb/cutter v0.2.2 | |||
github.com/olivere/elastic/v7 v7.0.9 | |||
github.com/patrickmn/go-cache v2.1.0+incompatible | |||
github.com/pkg/errors v0.9.1 | |||
github.com/pquerna/otp v1.2.0 | |||
github.com/prometheus/client_golang v1.1.0 | |||
@@ -94,12 +107,11 @@ require ( | |||
github.com/prometheus/procfs v0.0.4 // indirect | |||
github.com/quasoft/websspi v1.0.0 | |||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect | |||
github.com/robfig/cron/v3 v3.0.1 | |||
github.com/satori/go.uuid v1.2.0 | |||
github.com/sergi/go-diff v1.1.0 | |||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b // indirect | |||
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd | |||
github.com/stretchr/testify v1.4.0 | |||
github.com/stretchr/testify v1.7.0 | |||
github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect | |||
github.com/tinylib/msgp v1.1.2 // indirect | |||
github.com/tstranex/u2f v1.0.0 | |||
@@ -110,25 +122,25 @@ require ( | |||
github.com/urfave/cli v1.22.1 | |||
github.com/xanzy/go-gitlab v0.31.0 | |||
github.com/yohcop/openid-go v1.0.0 | |||
github.com/yuin/goldmark v1.1.27 | |||
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 | |||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 | |||
golang.org/x/mod v0.3.0 // indirect | |||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 | |||
github.com/yuin/goldmark v1.4.13 | |||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 | |||
github.com/yuin/goldmark-meta v1.1.0 | |||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 | |||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d | |||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f | |||
golang.org/x/text v0.3.2 | |||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 | |||
golang.org/x/text v0.3.3 | |||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect | |||
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 | |||
golang.org/x/tools v0.1.1 | |||
google.golang.org/appengine v1.6.5 // indirect | |||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect | |||
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | |||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | |||
gopkg.in/ini.v1 v1.52.0 | |||
gopkg.in/ini.v1 v1.56.0 | |||
gopkg.in/ldap.v3 v3.0.2 | |||
gopkg.in/macaron.v1 v1.3.9 // indirect | |||
gopkg.in/testfixtures.v2 v2.5.0 | |||
gopkg.in/yaml.v2 v2.2.8 | |||
gopkg.in/yaml.v2 v2.3.0 | |||
mvdan.cc/xurls/v2 v2.1.0 | |||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 | |||
xorm.io/builder v0.3.7 | |||
@@ -39,11 +39,9 @@ gitea.com/macaron/inject v0.0.0-20190803172902-8375ba841591/go.mod h1:h6E4kLao1Y | |||
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a h1:aOKEXkDTnh4euoH0so/THLXeHtQuqHmDPb1xEk6Ehok= | |||
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a/go.mod h1:h6E4kLao1Yko6DOU6QDnQPcuoNzvbZqzj2mtPcEn1aM= | |||
gitea.com/macaron/macaron v1.3.3-0.20190803174002-53e005ff4827/go.mod h1:/rvxMjIkOq4BM8uPUb+VHuU02ZfAO6R4+wD//tiCiRw= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb h1:amL0md6orTj1tXY16ANzVU9FmzQB+W7aJwp8pVDbrmA= | |||
gitea.com/macaron/macaron v1.3.3-0.20190821202302-9646c0587edb/go.mod h1:0coI+mSPSwbsyAbOuFllVS38awuk9mevhLD52l50Gjs= | |||
gitea.com/macaron/macaron v1.4.0 h1:FY1QDGqyuUzs21K6ChkbYbRUfwL7v2aUrhNEJ0IgsAw= | |||
gitea.com/macaron/macaron v1.4.0/go.mod h1:P7hfDbQjcW22lkYkXlxdRIfWOXxH2+K4EogN4Q0UlLY= | |||
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705 h1:mvkQGAlON1Z6Y8pqa/+FpYIskk54mazuECUfZK5oTg0= | |||
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705/go.mod h1:1ujH0jD6Ca4iK9NL0Q2a7fG2chvXx5hVa7hBfABwpkA= | |||
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d h1:XLww3CvnFZkXVwauN67fniDaIpIqsE+9KVcxlZKlvLU= | |||
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d/go.mod h1:FanKy3WjWb5iw/iZBPk4ggoQT9FcM6bkBPvmDmsH6tY= | |||
@@ -70,7 +68,6 @@ github.com/RichardKnop/machinery v1.6.9 h1:dQu1c7ENgPFrN9qWweEe7xDDvNYGSqEyprK0G | |||
github.com/RichardKnop/machinery v1.6.9/go.mod h1:BO7MG/5tvdpgMVkOT8V94SEf8x8H8aceRzTt8Tx1IMc= | |||
github.com/RichardKnop/redsync v1.2.0 h1:gK35hR3zZkQigHKm8wOGb9MpJ9BsrW6MzxezwjTcHP0= | |||
github.com/RichardKnop/redsync v1.2.0/go.mod h1:9b8nBGAX3bE2uCfJGSnsDvF23mKyHTZzmvmj5FH3Tp0= | |||
github.com/RoaringBitmap/roaring v0.4.21 h1:WJ/zIlNX4wQZ9x8Ey33O1UaD9TCTakYsdLFSBcTwH+8= | |||
github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= | |||
github.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo= | |||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= | |||
@@ -79,8 +76,39 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx | |||
github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= | |||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= | |||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= | |||
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= | |||
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= | |||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | |||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | |||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= | |||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= | |||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= | |||
github.com/alibabacloud-go/darabonba-openapi v0.1.14/go.mod h1:w4CosR7O/kapCtEEMBm3JsQqWBU/CnZ2o0pHorsTWDI= | |||
github.com/alibabacloud-go/darabonba-openapi v0.1.18 h1:3eUVmAr7WCJp7fgIvmCd9ZUyuwtJYbtUqJIed5eXCmk= | |||
github.com/alibabacloud-go/darabonba-openapi v0.1.18/go.mod h1:PB4HffMhJVmAgNKNq3wYbTUlFvPgxJpTzd1F5pTuUsc= | |||
github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= | |||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50= | |||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= | |||
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9 h1:z+OU7LbWtQitWJ8SAn55hEQkJPCsEPJc97TvGCZV+4s= | |||
github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.9/go.mod h1:AT91gCNJPsemf4lHLNgWTf/RsgmpdOprWvQ3FYvtwGk= | |||
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= | |||
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= | |||
github.com/alibabacloud-go/openapi-util v0.0.10/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= | |||
github.com/alibabacloud-go/openapi-util v0.0.11 h1:iYnqOPR5hyEEnNZmebGyRMkkEJRWUEjDiiaOHZ5aNhA= | |||
github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= | |||
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= | |||
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= | |||
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= | |||
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= | |||
github.com/alibabacloud-go/tea v1.1.17 h1:05R5DnaJXe9sCNIe8KUgWHC/z6w/VZIwczgUwzRnul8= | |||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= | |||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= | |||
github.com/alibabacloud-go/tea-utils v1.4.3 h1:8SzwmmRrOnQ09Hf5a9GyfJc0d7Sjv6fmsZoF4UDbFjo= | |||
github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= | |||
github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M= | |||
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= | |||
github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY= | |||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= | |||
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= | |||
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= | |||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= | |||
@@ -128,6 +156,8 @@ github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQ | |||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= | |||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= | |||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= | |||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= | |||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= | |||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | |||
github.com/corbym/gocrest v1.0.3 h1:gwEdq6RkTmq+09CTuM29DfKOCtZ7G7bcyxs3IZ6EVdU= | |||
github.com/corbym/gocrest v1.0.3/go.mod h1:maVFL5lbdS2PgfOQgGRWDYTeunSWQeiEgoNdTABShCs= | |||
@@ -140,11 +170,9 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7 | |||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | |||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= | |||
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= | |||
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d h1:XMf4E1U+b9E3ElF0mjvfXZdflBRZz4gLp16nQ/QSHQM= | |||
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= | |||
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 h1:vZryARwW4PSFXd9arwegEywvMTvPuXL3/oa+4L5NTe8= | |||
github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= | |||
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b h1:bZ9rKU2/V8sY+NulSfxDOnXTWcs1rySqdF1sVepihvo= | |||
github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= | |||
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 h1:0WMIDtuXCKEm4wtAJgAAXa/qtM5O9MariLwgHaRlYmk= | |||
github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= | |||
@@ -169,13 +197,16 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs | |||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= | |||
github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 h1:bpWCJ5MddHsv4Xtl3azkK89mZzd/vvut32mvAnKbyUA= | |||
github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | |||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg= | |||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | |||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= | |||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= | |||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= | |||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= | |||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | |||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | |||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | |||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= | |||
@@ -185,8 +216,9 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1 | |||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= | |||
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 h1:mhPg/0hGebcpiiQLqJD2PWWyoHRLEdZ3sXKaEvT1EQU= | |||
github.com/editorconfig/editorconfig-core-go/v2 v2.1.1/go.mod h1:/LuhWJiQ9Gvo1DhVpa4ssm5qeg8rrztdtI7j/iCie2k= | |||
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= | |||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= | |||
github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A= | |||
github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= | |||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= | |||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= | |||
github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a h1:M1bRpaZAn4GSsqu3hdK2R8H0AH9O6vqCTCbm2oAFGfE= | |||
@@ -230,6 +262,8 @@ github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp | |||
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= | |||
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg= | |||
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA= | |||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno= | |||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw= | |||
github.com/go-ini/ini v1.56.0 h1:6HjxSjqdmgnujDPhlzR4a44lxK3w03WPN8te0SoUSeM= | |||
github.com/go-ini/ini v1.56.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= | |||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= | |||
@@ -306,7 +340,6 @@ github.com/go-swagger/go-swagger v0.21.0 h1:AX9mdfzp6eJtUe92nFrWmbK7ocRgkCDPJs0F | |||
github.com/go-swagger/go-swagger v0.21.0/go.mod h1:tDb8PdDVFcaE8EPXkMOsuxpL3UEPiwu1UDZar9Z/1RY= | |||
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= | |||
github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= | |||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= | |||
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= | |||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= | |||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= | |||
@@ -327,16 +360,17 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er | |||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= | |||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | |||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= | |||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= | |||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= | |||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= | |||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= | |||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | |||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | |||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= | |||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= | |||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= | |||
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= | |||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= | |||
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= | |||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= | |||
@@ -349,7 +383,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z | |||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | |||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | |||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= | |||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | |||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= | |||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
@@ -375,10 +408,10 @@ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+ | |||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= | |||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= | |||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= | |||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= | |||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | |||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= | |||
@@ -406,7 +439,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo | |||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= | |||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= | |||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= | |||
github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY= | |||
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= | |||
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= | |||
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= | |||
@@ -441,8 +473,9 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx | |||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= | |||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | |||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | |||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= | |||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | |||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= | |||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | |||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
@@ -458,7 +491,6 @@ github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+ | |||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= | |||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | |||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | |||
github.com/klauspost/compress v1.9.2 h1:LfVyl+ZlLlLDeQ/d2AqfGIIH4qEDu0Ed2S5GyhCWIWY= | |||
github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= | |||
github.com/klauspost/compress v1.10.2 h1:Znfn6hXZAHaLPNnlqUYRrBSReFHYybslgv4PTiyz6P0= | |||
github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= | |||
@@ -472,7 +504,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN | |||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | |||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | |||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= | |||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | |||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | |||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | |||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | |||
@@ -545,7 +576,6 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 | |||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= | |||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c h1:3wkDRdxK92dF+c1ke2dtj7ZzemFWBHB9plnJOtlwdFA= | |||
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= | |||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY= | |||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= | |||
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= | |||
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= | |||
@@ -580,6 +610,8 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt | |||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= | |||
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= | |||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= | |||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= | |||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= | |||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= | |||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= | |||
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg= | |||
@@ -588,7 +620,6 @@ github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= | |||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= | |||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= | |||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= | |||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | |||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |||
@@ -635,8 +666,6 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn | |||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | |||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkNDhPdWN3REluVa46HQOVuVkjkd2sWnrABNQ= | |||
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= | |||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= | |||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= | |||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | |||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= | |||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= | |||
@@ -684,13 +713,15 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx | |||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= | |||
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= | |||
github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= | |||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= | |||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= | |||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= | |||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | |||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= | |||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= | |||
@@ -715,12 +746,13 @@ github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9 h1:wR6aLKdbJ5E8m+NZ | |||
github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= | |||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= | |||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | |||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | |||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | |||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= | |||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | |||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= | |||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= | |||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= | |||
@@ -731,10 +763,11 @@ github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7 | |||
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= | |||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= | |||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= | |||
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU= | |||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= | |||
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= | |||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= | |||
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= | |||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= | |||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= | |||
github.com/toqueteos/trie v1.0.0 h1:8i6pXxNUXNRAqP246iibb7w/pSFquNTQ+uNfriG7vlk= | |||
github.com/toqueteos/trie v1.0.0/go.mod h1:Ywk48QhEqhU1+DwhMkJ2x7eeGxDHiGkAdc9+0DYcbsM= | |||
@@ -746,7 +779,6 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr | |||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= | |||
github.com/unknwon/cae v1.0.0 h1:i39lOFaBXZxhGjQOy/RNbi8uzettCs6OQxpR0xXohGU= | |||
github.com/unknwon/cae v1.0.0/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= | |||
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= | |||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
@@ -771,13 +803,18 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q | |||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= | |||
github.com/yohcop/openid-go v1.0.0 h1:EciJ7ZLETHR3wOtxBvKXx9RV6eyHZpCaSZ1inbBaUXE= | |||
github.com/yohcop/openid-go v1.0.0/go.mod h1:/408xiwkeItSPJZSTPF7+VtZxPkPrRRpRNK2vjGh6yI= | |||
github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
github.com/yuin/goldmark v1.1.25 h1:isv+Q6HQAmmL2Ofcmg8QauBmDPlUUnSoNhEcC940Rds= | |||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
github.com/yuin/goldmark v1.1.27 h1:nqDD4MMMQA0lmWq03Z2/myGPYLQoXtmi0rGVs95ntbo= | |||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 h1:gZucqLjL1eDzVWrXj4uiWeMbAopJlBR2mKQAsTGdPwo= | |||
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60/go.mod h1:i9VhcIHN2PxXMbQrKqXNueok6QNONoPjNMoj9MygVL0= | |||
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | |||
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= | |||
github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= | |||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= | |||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | |||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg= | |||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU= | |||
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= | |||
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= | |||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= | |||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= | |||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | |||
@@ -813,17 +850,18 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U | |||
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20190907121410-71b5226ff739/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ= | |||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= | |||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= | |||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= | |||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | |||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | |||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | |||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | |||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U= | |||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | |||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | |||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | |||
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | |||
@@ -832,12 +870,12 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk | |||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | |||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | |||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= | |||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= | |||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | |||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= | |||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= | |||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= | |||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | |||
@@ -865,10 +903,12 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL | |||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= | |||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= | |||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | |||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
@@ -876,7 +916,6 @@ golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAG | |||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= | |||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= | |||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | |||
@@ -886,8 +925,11 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ | |||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= | |||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= | |||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | |||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
@@ -915,24 +957,27 @@ golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7w | |||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20190907184412-d223b2b6db03/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= | |||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= | |||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= | |||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI= | |||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= | |||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | |||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= | |||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= | |||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
@@ -955,17 +1000,19 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw | |||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | |||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | |||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | |||
golang.org/x/tools v0.0.0-20200225230052-807dcd883420 h1:4RJNOV+2rLxMEfr6QIpC7GEv9MjD6ApGXTCLrNF9+eA= | |||
golang.org/x/tools v0.0.0-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | |||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 h1:azwY/v0y0K4mFHVsg5+UrTgchqALYWpqVo6vL5OmkmI= | |||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= | |||
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | |||
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ= | |||
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | |||
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= | |||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= | |||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= | |||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= | |||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= | |||
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= | |||
@@ -984,7 +1031,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 | |||
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | |||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
google.golang.org/appengine v1.6.4 h1:WiKh4+/eMB2HaY7QhCfW/R7MuRAoA8QMCSJA6jP5/fo= | |||
google.golang.org/appengine v1.6.4/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | |||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= | |||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= | |||
@@ -1016,7 +1062,6 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY | |||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= | |||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= | |||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= | |||
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= | |||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= | |||
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY= | |||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | |||
@@ -1027,7 +1072,6 @@ gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8 | |||
gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= | |||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= | |||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
@@ -1040,8 +1084,8 @@ gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= | |||
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= | |||
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y= | |||
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||
gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= | |||
gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= | |||
gopkg.in/macaron.v1 v1.3.9 h1:Dw+DDRYdXgQyEsPlfAfKz+UA5qVUrH3KPD7JhmZ9MFc= | |||
@@ -1058,12 +1102,13 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= | |||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= | |||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= | |||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | |||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= | |||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= | |||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | |||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | |||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= | |||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |||
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | |||
@@ -1078,13 +1123,11 @@ sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2 | |||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= | |||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= | |||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= | |||
xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= | |||
xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= | |||
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI= | |||
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= | |||
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw= | |||
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= | |||
xorm.io/xorm v0.8.0 h1:iALxgJrX8O00f8Jk22GbZwPmxJNgssV5Mv4uc2HL9PM= | |||
xorm.io/xorm v0.8.0/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY= | |||
xorm.io/xorm v1.0.1 h1:/lITxpJtkZauNpdzj+L9CN/3OQxZaABrbergMcJu+Cw= | |||
xorm.io/xorm v1.0.1/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY= |
@@ -0,0 +1,688 @@ | |||
<!DOCTYPE html> | |||
<html lang="en-US"> | |||
<head data-suburl=""> | |||
<meta charset="utf-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
<meta http-equiv="x-ua-compatible" content="ie=edge"> | |||
<title> OpenI</title> | |||
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials"> | |||
<script> | |||
if ('serviceWorker' in navigator) { | |||
navigator.serviceWorker.register('/serviceworker.js').then(function(registration) { | |||
console.info('ServiceWorker registration successful with scope: ', registration.scope); | |||
}, function(err) { | |||
console.info('ServiceWorker registration failed: ', err); | |||
}); | |||
} | |||
</script> | |||
<meta name="theme-color" content="#6cc644"> | |||
<meta name="author" content="OpenI - open i project management" /> | |||
<meta name="description" content="Efficient code management center, you can host and review code" /> | |||
<meta name="keywords" content="OpenI,git"> | |||
<meta name="referrer" content="no-referrer" /> | |||
<meta name="_csrf" content="R3EY-tMaxCo3C6fhAmc_WpVunPc6MTY1NzcwODA3NTE2MjQ4NTgzMQ" /> | |||
<script> | |||
/* | |||
@licstart The following is the entire license notice for the | |||
JavaScript code in this page. | |||
Copyright (c) 2016 The Gitea Authors | |||
Copyright (c) 2015 The Gogs Authors | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in | |||
all copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. | |||
--- | |||
Licensing information for additional javascript libraries can be found at: | |||
{{StaticUrlPrefix}}/vendor/librejs.html | |||
@licend The above is the entire license notice | |||
for the JavaScript code in this page. | |||
*/ | |||
</script> | |||
<script> | |||
window.config = { | |||
AppSubUrl: '', | |||
StaticUrlPrefix: '', | |||
csrf: 'R3EY-tMaxCo3C6fhAmc_WpVunPc6MTY1NzcwODA3NTE2MjQ4NTgzMQ', | |||
HighlightJS: false, | |||
Minicolors: false, | |||
SimpleMDE: false, | |||
Tribute: false, | |||
U2F: false, | |||
Heatmap: false, | |||
heatmapUser: null, | |||
NotificationSettings: { | |||
MinTimeout: 10000 , | |||
TimeoutStep: 10000 , | |||
MaxTimeout: 60000 , | |||
EventSourceUpdateTime: 10000 , | |||
}, | |||
}; | |||
</script> | |||
<link rel="shortcut icon" href="/img/favicon.png"> | |||
<link rel="mask-icon" href="/img/openi-safari.svg" color="#609926"> | |||
<link rel="fluid-icon" href="/img/gitea-lg.png" title="OpenI"> | |||
<link rel="stylesheet" href="/vendor/assets/font-awesome/css/font-awesome.min.css"> | |||
<link rel="preload" as="font" href="/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
<link rel="preload" as="font" href="/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
<link rel="stylesheet" href="/css/git.openi.css"> | |||
<link rel="stylesheet" href="/fomantic/semantic.min.css?v=eef985e4d4b587d055fc7c3eff3f18e9"> | |||
<link rel="stylesheet" href="/css/index.css?v=eef985e4d4b587d055fc7c3eff3f18e9"> | |||
<noscript> | |||
<style> | |||
.dropdown:hover > .menu { display: block; } | |||
.ui.secondary.menu .dropdown.item > .menu { margin-top: 0; } | |||
</style> | |||
</noscript> | |||
<style class="list-search-style"></style> | |||
<meta property="og:title" content="OpenI"> | |||
<meta property="og:type" content="website" /> | |||
<meta property="og:image" content="/img/gitea-lg.png" /> | |||
<meta property="og:url" content="https://openi.pcl.ac.cn/" /> | |||
<meta property="og:description" content="Efficient code management center, you can host and review code"> | |||
<meta property="og:site_name" content="OpenI" /> | |||
<script> | |||
var _hmt = _hmt || []; | |||
(function() { | |||
var hm = document.createElement("script"); | |||
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; | |||
var s = document.getElementsByTagName("script")[0]; | |||
s.parentNode.insertBefore(hm, s); | |||
})(); | |||
</script> | |||
<script src="/self/func.js" type="text/javascript"></script> | |||
<link rel="stylesheet" href="/RemixIcon_Fonts_v2.5.0/fonts/remixicon.css"> | |||
<link rel="stylesheet" href="/swiper/swiper-bundle.min.css"> | |||
<script src="/swiper/swiper-bundle.min.js"></script> | |||
<link rel="stylesheet" href="/rotation3D/rotation3D.css"> | |||
</head> | |||
<body> | |||
<div class="full height"> | |||
<noscript>This website works better with JavaScript.</noscript> | |||
<div class="ui top secondary stackable main menu following bar dark"> | |||
<div class="ui container" id="navbar"> | |||
<div class="item brand" style="justify-content: space-between;"> | |||
<a href="https://openi.org.cn/"> | |||
<img class="ui mini image" src="/img/logo-w.svg"> | |||
</a> | |||
<div class="ui basic icon button mobile-only" id="navbar-expand-toggle"> | |||
<i class="sidebar icon"></i> | |||
</div> | |||
</div> | |||
<div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div> | |||
<div class="item brand" style="margin-left: 0.9rem;"> | |||
<a href="/"> | |||
<img class="ui mini image" style="height: 1.3rem;" src="/img/git-logo.svg"> | |||
</a> | |||
</div> | |||
<div class="item edge"> | |||
<div class="dropdown-menu"> | |||
<a class=" item lfpd" href="/user/login"> | |||
Home <i class="dropdown icon mglf"></i> | |||
</a> | |||
<div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
<a style="border: none;color: #000;" class=" item" href="/user/login">Issues</a> | |||
<a style="border: none;color: #000; white-space: nowrap;" class=" item" href="/user/login">Pull Requests</a> | |||
<a style="border: none;color: #000;" class=" item" href="/user/login">Milestones</a> | |||
<a style="border: none;color: #000;" class=" item" href="/cloudbrains">Cloudbrain Task</a> | |||
</div> | |||
</div> | |||
</div> | |||
<a class="item" href="/explore/repos">Repositories</a> | |||
<a class="item" href="/explore/datasets">Datasets</a> | |||
<div class="ui simple dropdown item" id='dropdown_PageHome'> | |||
Explore | |||
<i class="dropdown icon"></i> | |||
<div class="menu" > | |||
<a class="item" href="/explore/users">Users</a> | |||
<a class="item" href="/explore/organizations">Organizations</a> | |||
<a class="item" href="/explore/images">Cloudbrain Mirror</a> | |||
<a class="item" href="/OpenI">OpenI Projects</a> | |||
</div> | |||
</div> | |||
<div class="right stackable menu"> | |||
<form id="searchForm" class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/all/search/" method="post"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="" placeholder="Search..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value=""> | |||
<input type="hidden" name="sort" value="hot"> | |||
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
</button> | |||
</div> | |||
</form> | |||
<a class="item" href="/user/sign_up"> | |||
<svg class="svg octicon-person" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-person" /></svg> Register | |||
</a> | |||
<a class="item" rel="nofollow" href="/user/login"> | |||
<svg class="svg octicon-sign-in" width="16" height="16" aria-hidden="true"><use xlink:href="#octicon-sign-in" /></svg> Sign In | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="notic_content" id ="notic_content" style="display: block; position: relative"> | |||
<div class="ui container"> | |||
<marquee behavior="scroll" direction="left"> | |||
<a href=https://openi.org.cn/html/2022/notices_0701/636.html class="a_width" style = 'margin-left: 0px !important;' target="_blank"> | |||
<i class="ri-arrow-right-s-line"></i> | |||
“我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认>>> | |||
</a> | |||
<a href=https://openi.pcl.ac.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md class="a_width" target="_blank"> | |||
<i class="ri-arrow-right-s-line"></i> | |||
7月中下旬登录启智AI协作平台,需登记手机号码啦>>> | |||
</a> | |||
<a href=https://openi.org.cn/html/2022/dongtai_0628/634.html class="a_width" target="_blank"> | |||
<i class="ri-arrow-right-s-line"></i> | |||
智算网络Beta版本上线,大大缩短算力排队时间,速来体验吧~>>> | |||
</a> | |||
<a href=https://wj.qq.com/s2/10362208/5c0c class="a_width" target="_blank"> | |||
<i class="ri-arrow-right-s-line"></i> | |||
启智AI协作平台问卷调查,邀请您参加>>> | |||
</a> | |||
</marquee> | |||
<div class="item right" style="position:absolute;right: 1px;top:0px;"> | |||
<i class="ri-close-fill x_icon" onclick="closeNoice()"></i> | |||
</div> | |||
</div> | |||
</div> | |||
<script> | |||
function closeNoice(){ | |||
document.getElementById("notic_content").style.display='none' | |||
localStorage.setItem("isCloseNotice",true) | |||
} | |||
function isShowNotice(){ | |||
var current_notice = localStorage.getItem("notices") | |||
if (current_notice != "f43dc1a5866fbf7a29c92a1eef3b6a020d4a30de"){ | |||
localStorage.setItem('notices',"f43dc1a5866fbf7a29c92a1eef3b6a020d4a30de"); | |||
isNewNotice=true; | |||
localStorage.setItem("isCloseNotice",false) | |||
}else{ | |||
isNewNotice=false; | |||
} | |||
let isShowNoticeTag = false; | |||
let notices= [{"Title":"“我为开源打榜狂”上榜领奖者名单公示1周,10万奖金被瓜分,请大家自行确认\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/notices_0701/636.html","Visible":1},{"Title":"7月中下旬登录启智AI协作平台,需登记手机号码啦\u003e\u003e\u003e","Link":"https://openi.pcl.ac.cn/OpenIOSSG/promote/src/branch/master/notice/Other_notes/RegisterMobileNumber.md","Visible":1},{"Title":"智算网络Beta版本上线,大大缩短算力排队时间,速来体验吧~\u003e\u003e\u003e","Link":"https://openi.org.cn/html/2022/dongtai_0628/634.html","Visible":1},{"Title":"启智AI协作平台问卷调查,邀请您参加\u003e\u003e\u003e","Link":"https://wj.qq.com/s2/10362208/5c0c","Visible":1}] | |||
if(notices != null && notices!=''){ | |||
for (i =0;i<notices.length;i++){ | |||
if (notices[i].Visible==1){ | |||
isShowNoticeTag =true; | |||
break; | |||
} | |||
} | |||
} | |||
if (isShowNoticeTag){ | |||
if(isNewNotice){ | |||
document.getElementById("notic_content").style.display='block' | |||
}else{ | |||
isCloseNotice = localStorage.getItem("isCloseNotice") | |||
if (JSON.parse(isCloseNotice)){ | |||
document.getElementById("notic_content").style.display='none' | |||
}else{ | |||
document.getElementById("notic_content").style.display='block' | |||
} | |||
} | |||
}else{ | |||
if (document.getElementById("notic_content") != null){ | |||
document.getElementById("notic_content").style.display='none' | |||
} | |||
} | |||
} | |||
if(!("" == true || "" =='true')) { | |||
isShowNotice(); | |||
} | |||
</script> | |||
<div class="ui vertical masthead secondary hometop segment"> | |||
<div class="ui container" style="position: relative;"> | |||
<div class="ui center homebanner"> | |||
<h1 class="ui huge header"> | |||
Explore Better AI | |||
<div class="sub header"> | |||
OpenI AI Development Cooperation Platform | |||
</div> | |||
</h1> | |||
<p class="ui am-lh-18">The one-stop collaborative development environment for AI field provides AI development pipeline integrating code development, data management, model debugging, reasoning and evaluation</p> | |||
<a class="circular huge ui secondary button" href="/user/login">Use Now <i class="right arrow icon"></i></a> | |||
</div> | |||
<div class="bannerpic"><img class="ui fluid image" src="/img/gitopeni-index-01.svg"></div> | |||
<div id="homenews"> | |||
<p>* Only show the dynamics of open source projects</p> | |||
<div class="ui grid"> | |||
<div class="sixteen wide mobile twelve wide tablet ten wide computer column homenews"> | |||
<div class="newslist"> | |||
<div class="ui mini aligned list swiper-wrapper" id="newmessage"> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui container homeorg"> | |||
<div class="ui stackable grid"> | |||
<div class="sixteen wide tablet four wide computer column homeorg-tit"> | |||
<h2>Recommended Organizations</h2> | |||
<p><span class="ui text grey">These excellent organizations are using the OpenI AI Collaboration Platform for collaborative development of projects. To show your organization here, </span><a href="/OpenIOSSG/promote/">Click here to submit.</a></p> | |||
<a href="/explore/organizations" class="circular ui primary basic button">More Organizations <i class="arrow circle right icon"></i></a> | |||
</div> | |||
<div class="sixteen wide tablet twelve wide computer column"> | |||
<div class="homeorg-list"> | |||
<div class="swiper-wrapper" id="recommendorg"> | |||
</div> | |||
<div class="swiper-pagination"></div> | |||
</div> | |||
</div> | |||
<div class="sixteen wide tablet four wide computer column homeorg-tit"> | |||
<h2>Community Activities</h2> | |||
<p><span class="ui text grey">The community has prepared a wealth of activities, waiting for you to participate!</p> | |||
</div> | |||
<div class="sixteen wide tablet twelve wide computer column"> | |||
<div class="event-list"> | |||
<div class="swiper-wrapper" id="recommendactivity"> | |||
</div> | |||
<div class="swiper-pagination"></div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="leftline01"></div> | |||
</div> | |||
<div class="ui container homepro"> | |||
<div class="leftline02"></div> | |||
<div class="leftline02-2"></div> | |||
<div class="ui center homepro-tit am-mb-20"> | |||
<h2>Recommended Projects</h2> | |||
<p><span class="ui text grey">Excellent AI projects recommendation. To show your project here, </span><a href="/OpenIOSSG/promote/">Click here to submit.</a>Click here to <a href="/explore/">explore more projects.</a></p> | |||
</div> | |||
<div class="homepro-list"> | |||
<div class="swiper-wrapper" id="recommendrepo"> | |||
</div> | |||
<div class="swiper-pagination"></div> | |||
</div> | |||
</div> | |||
<div class="ui vertical masthead secondary c2net segment"> | |||
<div class="ui container"> | |||
<div class="ui center am-pt-30 am-pb-30"> | |||
<h2>智算网络</h2> | |||
<p><span class="ui text grey">人工智能算力网络推进联盟已接入10家智算中心,算力总规模1542P</p> | |||
</div> | |||
<div id="app" v-cloak> | |||
<div class="rotation3D-baseMap"></div> | |||
<div id="rotation3D" class="rotation3D"> | |||
<button class="center">中心</button> | |||
<div class="itemList"> | |||
<div class="rotation3D__item" :class="item.type" v-for="item in itemList"> | |||
<div class="scale"> | |||
<div class="baseImg"></div> | |||
<div class="cont"> | |||
<i class="iconfont" :class="item.icon"></i> | |||
<p></p> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="lineList"> | |||
<div class="rotation3D__line" v-for="item in itemList" :class="item.type"> | |||
<div v-if="item.type=='blue'" class="pos"> | |||
<svg width="50" height="400"> | |||
<path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
</svg> | |||
<div class="dot dot1 ri-arrow-left-s-line"><span></span></div> | |||
</div> | |||
<div v-if="item.type=='yellow'" class="pos"> | |||
<svg width="10" height="400"> | |||
<path id="path2" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
</svg> | |||
<div class="dot dot2"><i class="el-icon-close"></i></div> | |||
</div> | |||
<div v-if="item.type=='green'" class="pos"> | |||
<svg width="50" height="400"> | |||
<path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/> | |||
</svg> | |||
<div class="dot dot1 ri-arrow-left-s-line"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<a name="fourth"></a> | |||
<div class="ui container i-env"> | |||
<div class="ui center am-pb-30"> | |||
<h2>Collaborative Development Environment</h2> | |||
<p><span class="ui text grey">Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms.</p> | |||
</div> | |||
<div class="ui four doubling cards"> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-01.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">Unified Management of Development Elements</h3> | |||
<div class="description ui text grey"> | |||
The platform provides four elements of AI development: unified management of model code, data set, model and execution environment. | |||
</div> | |||
</div> | |||
</div> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-02.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">Data Collaboration and Sharing</h3> | |||
<div class="description ui text grey"> | |||
By uploading data sets in the project, many project members cooperate to complete data preprocessing. You can also establish a better model with community developers by setting the data as a public dataset. | |||
</div> | |||
</div> | |||
</div> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-03.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">Model Management and Sharing</h3> | |||
<div class="description ui text grey"> | |||
Associate the model with the code version, you can adjust the model in different ways based on the historical version of the code and save the results. The trained model can be open and shared, so that more people can use the model to test and give feedback. | |||
</div> | |||
</div> | |||
</div> | |||
<div class="card"> | |||
<div class="image"> | |||
<img src="/img/i-pic-04.jpg"> | |||
</div> | |||
<div class="content"> | |||
<h3 class="ui centered small header">Once Configuration, Multiple Reuse</h3> | |||
<div class="description ui text grey"> | |||
Provide execution environment sharing, Once Configuration, Multiple Reuse. Lower the threshold of model development, and avoid spending repetitive time configuring complex environments. | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<a name="fifth"></a> | |||
<div class="ui container"> | |||
<div class="ui very padded inverted segment radius15"> | |||
<div class="ui stackable grid"> | |||
<div class="six wide column"> | |||
<img class="ui centered large image" src="/img/i-yunnao.svg"> | |||
</div> | |||
<div class="ten wide column am-pt-30"> | |||
<h2 class="ui grey inverted header">PengCheng Cloudbrain Open Source Collaboration</h2> | |||
<p class="am-lh-18 ui text grey"> | |||
The platform has been connected with Pengcheng Cloudbrain and can use the rich computing resources of Pengcheng Cloudbrain to complete AI development tasks.<br> | |||
Pengcheng Cloudbrain's existing AI computing power is 100p FLOPS@FP16 (billions of half precision floating-point calculations per second), the main hardware infrastructure is composed of GPU server equipped with NVIDIA Tesla V100 and Atlas 900 AI cluster equipped with Kunpeng and Ascend processors.<br> | |||
Developers can freely choose the corresponding computing resources according to their needs, and can test the adaptability, performance, stability of the model in different hardware environments.<br> | |||
If your model requires more computing resources, you can also apply for it separately.<br> | |||
</p> | |||
<a class="ui blue basic button am-mt-20" href="/user/login">Use Now</a> | |||
<a class="ui grey basic button am-mt-20" href="mailto:aiforge@openi.org.cn">Apply Separately</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="am-mt-30"></div> | |||
<script src="/self/js/jquery.min.js" type="text/javascript"></script> | |||
<script src="/home/home.js?v=eef985e4d4b587d055fc7c3eff3f18e9" type="text/javascript"></script> | |||
</div> | |||
<footer> | |||
<div class="ui container"> | |||
<div class="ui grid"> | |||
<div class="sixteen wide mobile eight wide tablet eight wide computer column"> | |||
<div class="ui three column grid"> | |||
<div class="column ui vertical text menu"> | |||
<div class="header item">Community</div> | |||
<a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">Council</a> | |||
<a href="https://openi.org.cn/html/Club/2019/0227/14.html" class="item">Technical Committee</a> | |||
<a href="https://openi.org.cn/html/Club/2019/0228/17.html" class="item">Join OpenI</a> | |||
<a href="/home/term/" class="item">Use agreement</a> | |||
</div> | |||
<div class="column ui vertical text menu"> | |||
<div class="header item">News</div> | |||
<a href="https://openi.org.cn/html/news/dongtai/" class="item">Community News</a> | |||
<a href="https://openi.org.cn/html/news/huodong/" class="item">Member news</a> | |||
<a href="https://openi.org.cn/html/news/zixun/" class="item">Industry Advisory</a> | |||
</div> | |||
<div class="column ui vertical text menu"> | |||
<div class="header item">help</div> | |||
<div class="ui language bottom floating slide up dropdown link item"> | |||
<i class="world icon"></i> | |||
<div class="text">English</div> | |||
<div class="menu"> | |||
<a lang="en-US" class="item active selected" href="#">English</a> | |||
<a lang="zh-CN" class="item " href="?lang=zh-CN">简体中文</a> | |||
</div> | |||
</div> | |||
<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning" class=" item a_margin" target="_blank"><i class="ri-creative-commons-by-line footer_icon" ></i><p class="footer_icon">Tutorial</p> </a> | |||
<a href="/api/swagger" class=" item a_margin"><i class="ri-exchange-line footer_icon" > </i><p class="footer_icon">API</p> </a> | |||
<a href="/user/login" class=" item a_margin" ><i class="ri-mail-send-line footer_icon" ></i><p class="footer_icon">Feedback</p></a> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="sixteen wide mobile eight wide tablet eight wide computer column" style=" margin:2.0rem 0"> | |||
Copyright: New Generation Artificial Intelligence Open Source Open Platform (OpenI) <a href="http://beian.miit.gov.cn/" target="_blank">京ICP备18004880号</a> | |||
<br> | |||
Powered_by 鹏城实验室云脑、<a href="https://www.trustie.net/" target="_blank">Trustie确实</a>、gitea | |||
<br> | |||
</div> | |||
</div> | |||
</div> | |||
</footer> | |||
<script src="/js/jquery.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
<script rel="stylesheet" src="/vendor/plugins/jquery.particleground/jquery.particleground.min.js"></script> | |||
<script src="/fomantic/semantic.min.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
<script src="/js/index.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
<script src="/rotation3D/vue-2.6.10.min.js"></script> | |||
<script src="/rotation3D/rotation3D.js?v=eef985e4d4b587d055fc7c3eff3f18e9"></script> | |||
<script> | |||
var app = new Vue({ | |||
el: "#app", | |||
data: { | |||
itemList: [ | |||
{ name:'鹏城云脑一号', type:'blue', icon:'', }, | |||
{ name:'鹏城云脑二号', type:'blue', icon:'', }, | |||
{ name:'北大人工智能集群系统', type:'green', icon:'', }, | |||
{ name:'合肥类脑智能开放平台', type:'green', icon:'', }, | |||
{ name:'武汉人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'西安未来人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'……', type:'yellow', icon:'', }, | |||
{ name:'中原人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'成都人工智能计算中心', type:'green', icon:'', }, | |||
{ name:'横琴先进智能计算中心', type:'green', icon:'', }, | |||
{ name:'国家超级计算济南中心', type:'green', icon:'', }, | |||
], | |||
}, | |||
mounted: function () { | |||
new Rotation3D({ | |||
id: '#rotation3D', | |||
farScale: 0.6, | |||
xRadius: 0, | |||
yRadius: 130, | |||
}) | |||
}, | |||
methods: {}, | |||
}); | |||
</script> | |||
</body> | |||
</html> | |||
@@ -58,7 +58,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *models.User) *models.PullReq | |||
assert.NoError(t, err) | |||
assert.NotEmpty(t, baseRepo) | |||
headRepo, err := repo_module.ForkRepository(actor, forkOrg, baseRepo, "repo-pr-update", "desc") | |||
headRepo, err := repo_module.ForkRepository(actor, forkOrg, baseRepo, "repo-pr-update", "desc", "") | |||
assert.NoError(t, err) | |||
assert.NotEmpty(t, headRepo) | |||
@@ -49,6 +49,25 @@ const ( | |||
ActionApprovePullRequest // 21 | |||
ActionRejectPullRequest // 22 | |||
ActionCommentPull // 23 | |||
ActionUploadAttachment //24 | |||
ActionCreateDebugGPUTask //25 | |||
ActionCreateDebugNPUTask //26 | |||
ActionCreateTrainTask //27 | |||
ActionCreateInferenceTask // 28 | |||
ActionCreateBenchMarkTask //29 | |||
ActionCreateNewModelTask //30 | |||
ActionCreateGPUTrainTask //31 | |||
ActionCreateGrampusNPUTrainTask //32 | |||
ActionCreateGrampusGPUTrainTask //33 | |||
ActionBindWechat //34 | |||
ActionDatasetRecommended //35 | |||
ActionCreateImage //36 | |||
ActionImageRecommend //37 | |||
ActionChangeUserAvatar //38 | |||
ActionCreateGrampusNPUDebugTask //39 | |||
ActionCreateGrampusGPUDebugTask //40 | |||
ActionCreateGrampusGCUDebugTask //41 | |||
) | |||
// Action represents user operation type and other information to | |||
@@ -70,6 +89,19 @@ type Action struct { | |||
IsTransformed bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
Content string `xorm:"TEXT"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
Cloudbrain *Cloudbrain `xorm:"-"` | |||
} | |||
type ActionShow struct { | |||
OpType ActionType | |||
TaskType TaskType | |||
RepoLink string | |||
ShortRepoFullDisplayName string | |||
Content string | |||
RefName string | |||
IssueInfos []string | |||
CommentLink string | |||
Cloudbrain *CloudbrainShow4Action | |||
} | |||
// GetOpType gets the ActionType of this action. | |||
@@ -164,12 +196,24 @@ func (a *Action) GetRepoName() string { | |||
return a.Repo.Name | |||
} | |||
// GetRepoName returns the name of the action repository. | |||
func (a *Action) GetRepoDisplayName() string { | |||
a.loadRepo() | |||
return a.Repo.DisplayName() | |||
} | |||
// ShortRepoName returns the name of the action repository | |||
// trimmed to max 33 chars. | |||
func (a *Action) ShortRepoName() string { | |||
return base.EllipsisString(a.GetRepoName(), 33) | |||
} | |||
// ShortRepoName returns the name of the action repository | |||
// trimmed to max 33 chars. | |||
func (a *Action) ShortRepoDisplayName() string { | |||
return base.EllipsisString(a.GetRepoDisplayName(), 33) | |||
} | |||
// GetRepoPath returns the virtual path to the action repository. | |||
func (a *Action) GetRepoPath() string { | |||
return path.Join(a.GetRepoUserName(), a.GetRepoName()) | |||
@@ -181,6 +225,12 @@ func (a *Action) ShortRepoPath() string { | |||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName()) | |||
} | |||
// ShortRepoPath returns the virtual path to the action repository | |||
// trimmed to max 20 + 1 + 33 chars. | |||
func (a *Action) ShortRepoFullDisplayName() string { | |||
return path.Join(a.ShortRepoUserName(), a.ShortRepoDisplayName()) | |||
} | |||
// GetRepoLink returns relative link to action repository. | |||
func (a *Action) GetRepoLink() string { | |||
if len(setting.AppSubURL) > 0 { | |||
@@ -189,6 +239,40 @@ func (a *Action) GetRepoLink() string { | |||
return "/" + a.GetRepoPath() | |||
} | |||
func (a *Action) ToShow() *ActionShow { | |||
actionShow := &ActionShow{} | |||
actionShow.OpType = a.OpType | |||
actionShow.TaskType = GetTaskTypeFromAction(a.OpType) | |||
actionShow.Content = a.Content | |||
actionShow.RefName = a.RefName | |||
if strings.Contains(a.Content, "|") && a.IsIssueAction() { | |||
actionShow.IssueInfos = a.GetIssueInfos() | |||
} | |||
if a.Repo != nil { | |||
actionShow.RepoLink = a.GetRepoLink() | |||
actionShow.ShortRepoFullDisplayName = a.ShortRepoFullDisplayName() | |||
} | |||
if a.Comment != nil { | |||
actionShow.CommentLink = a.GetCommentLink() | |||
} | |||
if a.Cloudbrain != nil { | |||
c := &CloudbrainShow4Action{ | |||
ID: a.Cloudbrain.ID, | |||
JobID: a.Cloudbrain.JobID, | |||
Type: a.Cloudbrain.Type, | |||
JobType: a.Cloudbrain.JobType, | |||
DisplayJobName: a.Cloudbrain.DisplayJobName, | |||
ComputeResource: a.Cloudbrain.ComputeResource, | |||
} | |||
actionShow.Cloudbrain = c | |||
} | |||
return actionShow | |||
} | |||
// GetRepositoryFromMatch returns a *Repository from a username and repo strings | |||
func GetRepositoryFromMatch(ownerName string, repoName string) (*Repository, error) { | |||
var err error | |||
@@ -286,6 +370,42 @@ func (a *Action) GetIssueContent() string { | |||
return issue.Content | |||
} | |||
func (a *Action) IsCloudbrainAction() bool { | |||
switch a.OpType { | |||
case ActionCreateDebugGPUTask, | |||
ActionCreateDebugNPUTask, | |||
ActionCreateTrainTask, | |||
ActionCreateInferenceTask, | |||
ActionCreateBenchMarkTask, | |||
ActionCreateGPUTrainTask, | |||
ActionCreateGrampusGPUDebugTask, | |||
ActionCreateGrampusNPUDebugTask, | |||
ActionCreateGrampusNPUTrainTask, | |||
ActionCreateGrampusGPUTrainTask, | |||
ActionCreateGrampusGCUDebugTask: | |||
return true | |||
} | |||
return false | |||
} | |||
func (a *Action) IsIssueAction() bool { | |||
switch a.OpType { | |||
case ActionCreateIssue, | |||
ActionCloseIssue, | |||
ActionClosePullRequest, | |||
ActionReopenIssue, | |||
ActionReopenPullRequest, | |||
ActionCommentPull, | |||
ActionCommentIssue, | |||
ActionCreatePullRequest, | |||
ActionApprovePullRequest, | |||
ActionRejectPullRequest, | |||
ActionMergePullRequest: | |||
return true | |||
} | |||
return false | |||
} | |||
// GetFeedsOptions options for retrieving feeds | |||
type GetFeedsOptions struct { | |||
RequestedUser *User // the user we want activity for | |||
@@ -346,6 +466,26 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { | |||
return actions, nil | |||
} | |||
func GetLast20PublicFeeds(opTypes []int) ([]*Action, error) { | |||
cond := builder.NewCond() | |||
cond = cond.And(builder.Eq{"is_private": false}) | |||
cond = cond.And(builder.Eq{"is_deleted": false}) | |||
cond = cond.And(builder.Expr("user_id=act_user_id")) | |||
cond = cond.And(builder.In("op_type", opTypes)) | |||
actions := make([]*Action, 0, 20) | |||
if err := x.Limit(30).Desc("id").Where(cond).Find(&actions); err != nil { | |||
return nil, fmt.Errorf("Find: %v", err) | |||
} | |||
if err := ActionList(actions).LoadAttributes(); err != nil { | |||
return nil, fmt.Errorf("LoadAttributes: %v", err) | |||
} | |||
return actions, nil | |||
} | |||
func GetUnTransformedActions() ([]*Action, error) { | |||
actions := make([]*Action, 0, 10) | |||
err := x.Where("op_type = ?", ActionCommitRepo). | |||
@@ -355,3 +495,18 @@ func GetUnTransformedActions() ([]*Action, error) { | |||
Find(&actions) | |||
return actions, err | |||
} | |||
func GetActionByIds(ids []int64) ([]*Action, error) { | |||
if len(ids) == 0 { | |||
return nil, nil | |||
} | |||
actions := make([]*Action, 0) | |||
err := x.In("id", ids).Find(&actions) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if err := ActionList(actions).LoadAllAttributes(); err != nil { | |||
return nil, fmt.Errorf("ActionList loadAttributes: %v", err) | |||
} | |||
return actions, nil | |||
} |
@@ -4,7 +4,11 @@ | |||
package models | |||
import "fmt" | |||
import ( | |||
"fmt" | |||
"strconv" | |||
"xorm.io/builder" | |||
) | |||
// ActionList defines a list of actions | |||
type ActionList []*Action | |||
@@ -26,6 +30,9 @@ func (actions ActionList) loadUsers(e Engine) ([]*User, error) { | |||
userIDs := actions.getUserIDs() | |||
userMaps := make(map[int64]*User, len(userIDs)) | |||
if len(userIDs) == 0 { | |||
return make([]*User, 0), nil | |||
} | |||
err := e. | |||
In("id", userIDs). | |||
Find(&userMaps) | |||
@@ -61,6 +68,9 @@ func (actions ActionList) loadRepositories(e Engine) ([]*Repository, error) { | |||
repoIDs := actions.getRepoIDs() | |||
repoMaps := make(map[int64]*Repository, len(repoIDs)) | |||
if len(repoIDs) == 0 { | |||
return make([]*Repository, 0), nil | |||
} | |||
err := e. | |||
In("id", repoIDs). | |||
Find(&repoMaps) | |||
@@ -79,6 +89,133 @@ func (actions ActionList) LoadRepositories() ([]*Repository, error) { | |||
return actions.loadRepositories(x) | |||
} | |||
func (actions ActionList) getCommentIDs() []int64 { | |||
commentIDs := make(map[int64]struct{}, len(actions)) | |||
for _, action := range actions { | |||
if action.CommentID == 0 { | |||
continue | |||
} | |||
if _, ok := commentIDs[action.CommentID]; !ok { | |||
commentIDs[action.CommentID] = struct{}{} | |||
} | |||
} | |||
return keysInt64(commentIDs) | |||
} | |||
func (actions ActionList) loadComments(e Engine) ([]*Comment, error) { | |||
if len(actions) == 0 { | |||
return nil, nil | |||
} | |||
commentIDs := actions.getCommentIDs() | |||
commentMaps := make(map[int64]*Comment, len(commentIDs)) | |||
if len(commentIDs) == 0 { | |||
return make([]*Comment, 0), nil | |||
} | |||
err := e. | |||
In("id", commentIDs). | |||
Find(&commentMaps) | |||
if err != nil { | |||
return nil, fmt.Errorf("find comment: %v", err) | |||
} | |||
for _, action := range actions { | |||
if action.CommentID > 0 { | |||
action.Comment = commentMaps[action.CommentID] | |||
} | |||
} | |||
return valuesComment(commentMaps), nil | |||
} | |||
// LoadComments loads actions' all comments | |||
func (actions ActionList) LoadComments() ([]*Comment, error) { | |||
return actions.loadComments(x) | |||
} | |||
func (actions ActionList) getCloudbrainIDs() []int64 { | |||
cloudbrainIDs := make(map[int64]struct{}, 0) | |||
for _, action := range actions { | |||
if !action.IsCloudbrainAction() { | |||
continue | |||
} | |||
cloudbrainId, _ := strconv.ParseInt(action.Content, 10, 64) | |||
if _, ok := cloudbrainIDs[cloudbrainId]; !ok { | |||
cloudbrainIDs[cloudbrainId] = struct{}{} | |||
} | |||
} | |||
return keysInt64(cloudbrainIDs) | |||
} | |||
func (actions ActionList) getCloudbrainJobIDs() []string { | |||
cloudbrainJobIDs := make(map[string]struct{}, 0) | |||
for _, action := range actions { | |||
if !action.IsCloudbrainAction() { | |||
continue | |||
} | |||
if _, ok := cloudbrainJobIDs[action.Content]; !ok { | |||
cloudbrainJobIDs[action.Content] = struct{}{} | |||
} | |||
} | |||
return keysString(cloudbrainJobIDs) | |||
} | |||
func (actions ActionList) loadCloudbrains(e Engine) ([]*Cloudbrain, error) { | |||
if len(actions) == 0 { | |||
return nil, nil | |||
} | |||
cloudbrainIDs := actions.getCloudbrainIDs() | |||
cloudbrainJobIDs := actions.getCloudbrainJobIDs() | |||
cloudbrainMaps := make(map[int64]*Cloudbrain, len(cloudbrainIDs)) | |||
if len(cloudbrainIDs) == 0 { | |||
return make([]*Cloudbrain, 0), nil | |||
} | |||
//由于各个类型的云脑任务在发布action的时候,content字段保存的ID含义不同,部分取的是ID,部分取的是jobId | |||
//所以在查询action对应的cloudbrain对象时,以这两个字段做为条件查询 | |||
cond := builder.Or(builder.In("id", cloudbrainIDs)).Or(builder.In("job_id", cloudbrainJobIDs)) | |||
err := e. | |||
Where(cond).Unscoped(). | |||
Find(&cloudbrainMaps) | |||
if err != nil { | |||
return nil, fmt.Errorf("find cloudbrain: %v", err) | |||
} | |||
cloudBrainJobIdMap := make(map[string]*Cloudbrain, len(cloudbrainIDs)) | |||
for _, v := range cloudbrainMaps { | |||
cloudBrainJobIdMap[v.JobID] = v | |||
} | |||
for _, action := range actions { | |||
if !action.IsCloudbrainAction() { | |||
continue | |||
} | |||
cloudbrainId, _ := strconv.ParseInt(action.Content, 10, 64) | |||
if cloudbrainId > 0 { | |||
if c, ok := cloudbrainMaps[cloudbrainId]; ok { | |||
if c.DisplayJobName == action.RefName || c.JobName == action.RefName { | |||
action.Cloudbrain = c | |||
continue | |||
} | |||
} | |||
} | |||
if c, ok := cloudBrainJobIdMap[action.Content]; ok { | |||
if c.DisplayJobName == action.RefName || c.JobName == action.RefName { | |||
action.Cloudbrain = c | |||
continue | |||
} | |||
} | |||
} | |||
return valuesCloudbrain(cloudbrainMaps), nil | |||
} | |||
// LoadComments loads actions' all comments | |||
func (actions ActionList) LoadCloudbrains() ([]*Comment, error) { | |||
return actions.loadComments(x) | |||
} | |||
// loadAttributes loads all attributes | |||
func (actions ActionList) loadAttributes(e Engine) (err error) { | |||
if _, err = actions.loadUsers(e); err != nil { | |||
@@ -96,3 +233,30 @@ func (actions ActionList) loadAttributes(e Engine) (err error) { | |||
func (actions ActionList) LoadAttributes() error { | |||
return actions.loadAttributes(x) | |||
} | |||
// LoadAllAttributes loads all attributes of the actions | |||
// compare with LoadAttributes() ,LoadAllAttributes() loads Comment and Cloudbrain attribute | |||
func (actions ActionList) LoadAllAttributes() error { | |||
return actions.loadAllAttributes(x) | |||
} | |||
// loadAllAttributes | |||
func (actions ActionList) loadAllAttributes(e Engine) (err error) { | |||
if _, err = actions.loadUsers(e); err != nil { | |||
return | |||
} | |||
if _, err = actions.loadRepositories(e); err != nil { | |||
return | |||
} | |||
if _, err = actions.loadComments(e); err != nil { | |||
return | |||
} | |||
if _, err = actions.loadCloudbrains(e); err != nil { | |||
return | |||
} | |||
return nil | |||
} |
@@ -0,0 +1,49 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"encoding/json" | |||
) | |||
type AdminOperateLog struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
BizType string | |||
OperateType string | |||
OldValue string `xorm:"TEXT"` | |||
NewValue string `xorm:"TEXT"` | |||
RelatedId string `xorm:"INDEX"` | |||
Comment string | |||
CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
CreatedBy int64 | |||
} | |||
type LogValues struct { | |||
Params []LogValue | |||
} | |||
type LogValue struct { | |||
Key string | |||
Val interface{} | |||
} | |||
func (l *LogValues) Add(key string, val interface{}) *LogValues { | |||
l.Params = append(l.Params, LogValue{Key: key, Val: val}) | |||
return l | |||
} | |||
func (l *LogValues) JsonString() string { | |||
if len(l.Params) == 0 { | |||
return "" | |||
} | |||
b, err := json.Marshal(l) | |||
if err != nil { | |||
log.Error("LogValues JsonString error . %v", err) | |||
return "" | |||
} | |||
return string(b) | |||
} | |||
func InsertAdminOperateLog(log AdminOperateLog) (int64, error) { | |||
return x.Insert(&log) | |||
} |
@@ -2,6 +2,7 @@ package models | |||
import ( | |||
"fmt" | |||
"time" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
@@ -11,31 +12,70 @@ import ( | |||
) | |||
type AiModelManage struct { | |||
ID string `xorm:"pk"` | |||
Name string `xorm:"INDEX NOT NULL"` | |||
Version string `xorm:"NOT NULL"` | |||
VersionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
New int `xorm:"NOT NULL"` | |||
Type int `xorm:"NOT NULL"` | |||
Size int64 `xorm:"NOT NULL"` | |||
Description string `xorm:"varchar(2000)"` | |||
Label string `xorm:"varchar(1000)"` | |||
Path string `xorm:"varchar(400) NOT NULL"` | |||
DownloadCount int `xorm:"NOT NULL DEFAULT 0"` | |||
Engine int64 `xorm:"NOT NULL DEFAULT 0"` | |||
Status int `xorm:"NOT NULL DEFAULT 0"` | |||
Accuracy string `xorm:"varchar(1000)"` | |||
AttachmentId string `xorm:"NULL"` | |||
RepoId int64 `xorm:"INDEX NULL"` | |||
CodeBranch string `xorm:"varchar(400) NULL"` | |||
CodeCommitID string `xorm:"NULL"` | |||
UserId int64 `xorm:"NOT NULL"` | |||
UserName string | |||
UserRelAvatarLink string | |||
TrainTaskInfo string `xorm:"text NULL"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
IsCanOper bool | |||
ID string `xorm:"pk" json:"id"` | |||
Name string `xorm:"INDEX NOT NULL" json:"name"` | |||
ModelType int `xorm:"NULL" json:"modelType"` | |||
Version string `xorm:"NOT NULL" json:"version"` | |||
VersionCount int `xorm:"NOT NULL DEFAULT 0" json:"versionCount"` | |||
New int `xorm:"NOT NULL" json:"new"` | |||
Type int `xorm:"NOT NULL" json:"type"` | |||
Size int64 `xorm:"NOT NULL" json:"size"` | |||
Description string `xorm:"varchar(2000)" json:"description"` | |||
Label string `xorm:"varchar(1000)" json:"label"` | |||
Path string `xorm:"varchar(400) NOT NULL" json:"path"` | |||
DownloadCount int `xorm:"NOT NULL DEFAULT 0" json:"downloadCount"` | |||
Engine int64 `xorm:"NOT NULL DEFAULT 0" json:"engine"` | |||
Status int `xorm:"NOT NULL DEFAULT 0" json:"status"` | |||
StatusDesc string `xorm:"varchar(500)" json:"statusDesc"` | |||
Accuracy string `xorm:"varchar(1000)" json:"accuracy"` | |||
AttachmentId string `xorm:"NULL" json:"attachmentId"` | |||
RepoId int64 `xorm:"INDEX NULL" json:"repoId"` | |||
CodeBranch string `xorm:"varchar(400) NULL" json:"codeBranch"` | |||
CodeCommitID string `xorm:"NULL" json:"codeCommitID"` | |||
UserId int64 `xorm:"NOT NULL" json:"userId"` | |||
IsPrivate bool `xorm:"DEFAULT true" json:"isPrivate"` | |||
UserName string `json:"userName"` | |||
UserRelAvatarLink string `json:"userRelAvatarLink"` | |||
TrainTaskInfo string `xorm:"text NULL" json:"trainTaskInfo"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created" json:"createdUnix"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"` | |||
IsCanOper bool `json:"isCanOper"` | |||
IsCanDelete bool `json:"isCanDelete"` | |||
IsCanDownload bool `json:"isCanDownload"` | |||
} | |||
type AiModelConvert struct { | |||
ID string `xorm:"pk" json:"id"` | |||
Name string `xorm:"INDEX NOT NULL" json:"name"` | |||
Status string `xorm:"NULL" json:"status"` | |||
StatusResult string `xorm:"NULL" json:"statusResult"` | |||
SrcEngine int `xorm:"NOT NULL DEFAULT 0" json:"srcEngine"` | |||
RepoId int64 `xorm:"INDEX NULL" json:"repoId"` | |||
ModelId string `xorm:"NOT NULL" json:"modelId"` | |||
ModelName string `xorm:"NULL" json:"modelName"` | |||
ModelVersion string `xorm:"NOT NULL" json:"modelVersion"` | |||
ModelPath string `xorm:"NULL" json:"modelPath"` | |||
DestFormat int `xorm:"NOT NULL DEFAULT 0" json:"destFormat"` | |||
NetOutputFormat int `xorm:"NULL" json:"netOutputFormat"` | |||
UserId int64 `xorm:"NOT NULL" json:"userId"` | |||
CloudBrainTaskId string `xorm:"NULL" json:"cloudBrainTaskId"` | |||
ModelArtsVersionId string `xorm:"NULL" json:"modelArtsVersionId"` | |||
ContainerID string `json:"containerID"` | |||
ContainerIp string `json:"containerIp"` | |||
RunTime int64 `xorm:"NULL" json:"runTime"` | |||
TrainJobDuration string `json:"trainJobDuration"` | |||
InputShape string `xorm:"varchar(2000)" json:"inputShape"` | |||
InputDataFormat string `xorm:"NOT NULL" json:"inputDataFormat"` | |||
Description string `xorm:"varchar(2000)" json:"description"` | |||
Path string `xorm:"varchar(400) NOT NULL" json:"path"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created" json:"createdUnix"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"` | |||
StartTime timeutil.TimeStamp `json:"startTime"` | |||
EndTime timeutil.TimeStamp `json:"endTime"` | |||
UserName string `json:"userName"` | |||
UserRelAvatarLink string `json:"userRelAvatarLink"` | |||
IsCanOper bool `json:"isCanOper"` | |||
IsCanDelete bool `json:"isCanDelete"` | |||
} | |||
type AiModelQueryOptions struct { | |||
@@ -46,7 +86,126 @@ type AiModelQueryOptions struct { | |||
SortType string | |||
New int | |||
// JobStatus CloudbrainStatus | |||
Type int | |||
Type int | |||
Status int | |||
IsOnlyThisRepo bool | |||
IsQueryPrivate bool | |||
} | |||
func (a *AiModelConvert) IsGpuTrainTask() bool { | |||
if a.SrcEngine == 0 || a.SrcEngine == 1 || a.SrcEngine == 4 || a.SrcEngine == 6 { | |||
return true | |||
} | |||
return false | |||
} | |||
func ModelComputeAndSetDuration(task *AiModelConvert, result JobResultPayload) { | |||
if task.StartTime == 0 { | |||
task.StartTime = timeutil.TimeStamp(result.JobStatus.CreatedTime / 1000) | |||
} | |||
if task.EndTime == 0 { | |||
if result.JobStatus.CompletedTime > 0 { | |||
task.EndTime = timeutil.TimeStamp(result.JobStatus.CompletedTime / 1000) | |||
} | |||
} | |||
var d int64 | |||
if task.StartTime == 0 { | |||
d = 0 | |||
} else if task.EndTime == 0 { | |||
d = time.Now().Unix() - task.StartTime.AsTime().Unix() | |||
} else { | |||
d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix() | |||
} | |||
if d < 0 { | |||
d = 0 | |||
} | |||
task.RunTime = d | |||
task.TrainJobDuration = ConvertDurationToStr(d) | |||
} | |||
func ModelConvertSetDuration(task *AiModelConvert) { | |||
var d int64 | |||
if task.StartTime == 0 { | |||
d = 0 | |||
} else if task.EndTime == 0 { | |||
d = time.Now().Unix() - task.StartTime.AsTime().Unix() | |||
} else { | |||
d = task.EndTime.AsTime().Unix() - task.StartTime.AsTime().Unix() | |||
} | |||
if d < 0 { | |||
d = 0 | |||
} | |||
task.RunTime = d | |||
task.TrainJobDuration = ConvertDurationToStr(d) | |||
} | |||
func UpdateModelConvertModelArts(id string, CloudBrainTaskId string, VersionId string) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("cloud_brain_task_id,model_arts_version_id").Update(&AiModelConvert{ | |||
CloudBrainTaskId: CloudBrainTaskId, | |||
ModelArtsVersionId: VersionId, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func UpdateModelConvertFailed(id string, status string, statusResult string) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("status", "status_result").Update(&AiModelConvert{ | |||
Status: status, | |||
StatusResult: statusResult, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func UpdateModelConvertCBTI(id string, CloudBrainTaskId string) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("cloud_brain_task_id").Update(&AiModelConvert{ | |||
CloudBrainTaskId: CloudBrainTaskId, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update cloud_brain_task_id from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func UpdateModelConvert(job *AiModelConvert) error { | |||
return updateModelConvert(x, job) | |||
} | |||
func updateModelConvert(e Engine, job *AiModelConvert) error { | |||
var sess *xorm.Session | |||
sess = e.Where("id = ?", job.ID) | |||
_, err := sess.Cols("status", "train_job_duration", "run_time", "start_time", "end_time", "updated_unix").Update(job) | |||
return err | |||
} | |||
func SaveModelConvert(modelConvert *AiModelConvert) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Insert(modelConvert) | |||
if err != nil { | |||
log.Info("insert modelConvert error." + err.Error()) | |||
return err | |||
} | |||
log.Info("success to save modelConvert db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func SaveModelToDb(model *AiModelManage) error { | |||
@@ -62,25 +221,57 @@ func SaveModelToDb(model *AiModelManage) error { | |||
return nil | |||
} | |||
func QueryModelById(id string) (*AiModelManage, error) { | |||
func QueryModelConvertByName(name string, repoId int64) ([]*AiModelConvert, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sess.Select("*").Table("ai_model_manage"). | |||
Where("id='" + id + "'") | |||
aiModelManageList := make([]*AiModelManage, 0) | |||
err := sess.Find(&aiModelManageList) | |||
sess.Select("*").Table(new(AiModelConvert)). | |||
Where("name='" + name + "' and repo_id=" + fmt.Sprint(repoId)).OrderBy("created_unix desc") | |||
aiModelManageConvertList := make([]*AiModelConvert, 0) | |||
err := sess.Find(&aiModelManageConvertList) | |||
if err == nil { | |||
if len(aiModelManageList) == 1 { | |||
return aiModelManageList[0], nil | |||
} | |||
return aiModelManageConvertList, nil | |||
} | |||
return nil, err | |||
} | |||
func DeleteModelById(id string) error { | |||
func QueryModelConvertById(id string) (*AiModelConvert, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re := new(AiModelConvert) | |||
isExist, err := sess.Table(new(AiModelConvert)).ID(id).Get(re) | |||
if err == nil && isExist { | |||
return re, nil | |||
} | |||
return nil, err | |||
} | |||
func QueryModelById(id string) (*AiModelManage, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re := new(AiModelManage) | |||
isExist, err := sess.Table(new(AiModelManage)).ID(id).Get(re) | |||
if err == nil && isExist { | |||
return re, nil | |||
} | |||
return nil, err | |||
} | |||
func DeleteModelConvertById(id string) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Delete(&AiModelConvert{ | |||
ID: id, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to delete AiModelManageConvert from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func DeleteModelById(id string) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Delete(&AiModelManage{ | |||
ID: id, | |||
}) | |||
@@ -89,7 +280,6 @@ func DeleteModelById(id string) error { | |||
} | |||
log.Info("success to delete from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func ModifyModelDescription(id string, description string) error { | |||
@@ -106,6 +296,69 @@ func ModifyModelDescription(id string, description string) error { | |||
return nil | |||
} | |||
func ModifyModelPrivate(id string, isPrivate bool) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("is_private").Update(&AiModelManage{ | |||
IsPrivate: isPrivate, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update isPrivate from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func ModifyLocalModel(id string, name, label, description string, engine int, isPrivate bool) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("name", "label", "description", "engine", "is_private").Update(&AiModelManage{ | |||
Description: description, | |||
Name: name, | |||
Label: label, | |||
Engine: int64(engine), | |||
IsPrivate: isPrivate, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update description from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func ModifyModelSize(id string, size int64) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("size").Update(&AiModelManage{ | |||
Size: size, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update size from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func ModifyModelStatus(id string, modelSize int64, status int, modelPath string, statusDesc string) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("size", "status", "path", "status_desc").Update(&AiModelManage{ | |||
Size: modelSize, | |||
Status: status, | |||
Path: modelPath, | |||
StatusDesc: statusDesc, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update ModelStatus from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func ModifyModelNewProperty(id string, new int, versioncount int) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
@@ -141,6 +394,18 @@ func QueryModelByName(name string, repoId int64) []*AiModelManage { | |||
return aiModelManageList | |||
} | |||
func QueryModelByPath(path string) (*AiModelManage, error) { | |||
modelManage := new(AiModelManage) | |||
has, err := x.Where("path=?", path).Get(modelManage) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if !has { | |||
return nil, ErrNotExist{} | |||
} | |||
return modelManage, nil | |||
} | |||
func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
@@ -176,6 +441,16 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||
) | |||
} | |||
if (opts.Status) >= 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.status": opts.Status}, | |||
) | |||
} | |||
if !opts.IsQueryPrivate { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.is_private": false}, | |||
) | |||
} | |||
count, err := sess.Where(cond).Count(new(AiModelManage)) | |||
if err != nil { | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
@@ -200,3 +475,79 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||
return aiModelManages, count, nil | |||
} | |||
func QueryModelConvertCountByRepoID(repoId int64) int64 { | |||
convert := new(AiModelConvert) | |||
total, _ := x.Where("repo_id =?", repoId).Count(convert) | |||
return total | |||
} | |||
func QueryModelConvertByRepoID(repoId int64) ([]*AiModelConvert, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Eq{"ai_model_convert.repo_id": repoId}, | |||
) | |||
sess.OrderBy("ai_model_convert.created_unix DESC") | |||
aiModelManageConvert := make([]*AiModelConvert, 0) | |||
if err := sess.Table(new(AiModelConvert)).Where(cond). | |||
Find(&aiModelManageConvert); err != nil { | |||
return nil, fmt.Errorf("Find: %v", err) | |||
} | |||
return aiModelManageConvert, nil | |||
} | |||
func QueryModelConvertByUserID(userID int64) ([]*AiModelConvert, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Eq{"ai_model_convert.user_id": userID}, | |||
) | |||
sess.OrderBy("ai_model_convert.created_unix DESC") | |||
aiModelManageConvert := make([]*AiModelConvert, 0) | |||
if err := sess.Table(new(AiModelConvert)).Where(cond). | |||
Find(&aiModelManageConvert); err != nil { | |||
return nil, fmt.Errorf("Find: %v", err) | |||
} | |||
return aiModelManageConvert, nil | |||
} | |||
func QueryModelConvert(opts *AiModelQueryOptions) ([]*AiModelConvert, int64, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
if opts.RepoID > 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_convert.repo_id": opts.RepoID}, | |||
) | |||
} | |||
if opts.UserID > 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_convert.user_id": opts.UserID}, | |||
) | |||
} | |||
count, err := sess.Where(cond).Count(new(AiModelConvert)) | |||
if err != nil { | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
} | |||
if opts.Page >= 0 && opts.PageSize > 0 { | |||
var start int | |||
if opts.Page == 0 { | |||
start = 0 | |||
} else { | |||
start = (opts.Page - 1) * opts.PageSize | |||
} | |||
sess.Limit(opts.PageSize, start) | |||
} | |||
sess.OrderBy("ai_model_convert.created_unix DESC") | |||
aiModelManageConvert := make([]*AiModelConvert, 0, setting.UI.IssuePagingNum) | |||
if err := sess.Table(new(AiModelConvert)).Where(cond). | |||
Find(&aiModelManageConvert); err != nil { | |||
return nil, 0, fmt.Errorf("Find: %v", err) | |||
} | |||
return aiModelManageConvert, count, nil | |||
} |
@@ -9,6 +9,8 @@ import ( | |||
"fmt" | |||
"io" | |||
"path" | |||
"strings" | |||
"time" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/obs" | |||
@@ -18,6 +20,7 @@ import ( | |||
"code.gitea.io/gitea/modules/timeutil" | |||
gouuid "github.com/satori/go.uuid" | |||
"xorm.io/builder" | |||
"xorm.io/xorm" | |||
) | |||
@@ -38,7 +41,9 @@ type Attachment struct { | |||
UploaderID int64 `xorm:"INDEX DEFAULT 0"` // Notice: will be zero before this column added | |||
CommentID int64 | |||
Name string | |||
Description string `xorm:"TEXT"` | |||
DownloadCount int64 `xorm:"DEFAULT 0"` | |||
UseNumber int64 `xorm:"DEFAULT 0"` | |||
Size int64 `xorm:"DEFAULT 0"` | |||
IsPrivate bool `xorm:"DEFAULT false"` | |||
DecompressState int32 `xorm:"DEFAULT 0"` | |||
@@ -47,6 +52,8 @@ type Attachment struct { | |||
FileChunk *FileChunk `xorm:"-"` | |||
CanDel bool `xorm:"-"` | |||
Uploader *User `xorm:"-"` | |||
Md5 string `xorm:"-"` | |||
} | |||
type AttachmentUsername struct { | |||
@@ -78,6 +85,30 @@ func (a *Attachment) IncreaseDownloadCount() error { | |||
return nil | |||
} | |||
func IncreaseAttachmentUseNumber(uuid string) error { | |||
uuidArray := strings.Split(uuid, ";") | |||
for i := range uuidArray { | |||
uuidArray[i] = "'" + uuidArray[i] + "'" | |||
} | |||
uuidInCondition := "(" + strings.Join(uuidArray, ",") + ")" | |||
// Update use number. | |||
if _, err := x.Exec("UPDATE `attachment` SET use_number=use_number+1 WHERE uuid in " + uuidInCondition); err != nil { | |||
return fmt.Errorf("increase attachment use count: %v", err) | |||
} | |||
return nil | |||
} | |||
func (a *Attachment) UpdateDatasetUpdateUnix() error { | |||
// Update download count. | |||
if _, err := x.Exec("UPDATE `dataset` SET updated_unix="+fmt.Sprint(time.Now().Unix())+" WHERE id=?", a.DatasetID); err != nil { | |||
return fmt.Errorf("UpdateDatasetUpdateUnix: %v", err) | |||
} | |||
return nil | |||
} | |||
// APIFormat converts models.Attachment to api.Attachment | |||
func (a *Attachment) APIFormat() *api.Attachment { | |||
return &api.Attachment{ | |||
@@ -88,12 +119,26 @@ func (a *Attachment) APIFormat() *api.Attachment { | |||
Size: a.Size, | |||
UUID: a.UUID, | |||
DownloadURL: a.DownloadURL(), | |||
S3DownloadURL: a.S3DownloadURL(), | |||
} | |||
} | |||
// DownloadURL returns the download url of the attached file | |||
func (a *Attachment) DownloadURL() string { | |||
return fmt.Sprintf("%sattachments/%s", setting.AppURL, a.UUID) | |||
return fmt.Sprintf("%sattachments/%s?type=%d", setting.AppURL, a.UUID, a.Type) | |||
} | |||
// S3DownloadURL returns the s3 download url of the attached file | |||
func (a *Attachment) S3DownloadURL() string { | |||
url := "" | |||
if a.Type == TypeCloudBrainOne { | |||
url, _ = storage.Attachments.PresignedGetURL(setting.Attachment.Minio.BasePath+AttachmentRelativePath(a.UUID), a.Name) | |||
} else if a.Type == TypeCloudBrainTwo { | |||
objectName := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(a.UUID[0:1], a.UUID[1:2], a.UUID, a.Name)), "/") | |||
url, _ = storage.ObsGetPreSignedUrl(objectName, a.Name) | |||
} | |||
return url | |||
} | |||
// AttachmentRelativePath returns the relative path | |||
@@ -214,6 +259,17 @@ func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) { | |||
return getAttachmentsByCommentID(x, commentID) | |||
} | |||
func GetAttachmentByDatasetIdFileName(fileName string, datasetId int64) (*Attachment, error) { | |||
attach := &Attachment{DatasetID: datasetId, Name: fileName} | |||
has, err := x.Get(attach) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, err | |||
} | |||
return attach, nil | |||
} | |||
func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) { | |||
attachments := make([]*Attachment, 0, 10) | |||
return attachments, e.Where("comment_id=?", commentID).Find(&attachments) | |||
@@ -313,6 +369,18 @@ func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) { | |||
func UpdateAttachment(atta *Attachment) error { | |||
return updateAttachment(x, atta) | |||
} | |||
func UpdateAttachmentDescription(atta *Attachment) error { | |||
return updateAttachmentDescription(x, atta) | |||
} | |||
func updateAttachmentDescription(e Engine, atta *Attachment) error { | |||
var sess *xorm.Session | |||
sess = e.ID(atta.ID) | |||
_, err := sess.Cols("description").Update(atta) | |||
return err | |||
} | |||
func updateAttachment(e Engine, atta *Attachment) error { | |||
var sess *xorm.Session | |||
@@ -413,19 +481,6 @@ func getPrivateAttachments(e Engine, userID int64) ([]*AttachmentUsername, error | |||
return attachments, nil | |||
} | |||
func getAllUserAttachments(e Engine, userID int64) ([]*AttachmentUsername, error) { | |||
attachments := make([]*AttachmentUsername, 0, 10) | |||
if err := e.Table("attachment").Join("LEFT", "`user`", "attachment.uploader_id "+ | |||
"= `user`.id").Where("decompress_state= ? and attachment.type = ? and (uploader_id= ? or is_private = ?)", DecompressStateDone, TypeCloudBrainOne, userID, false).Find(&attachments); err != nil { | |||
return nil, err | |||
} | |||
return attachments, nil | |||
} | |||
func GetAllUserAttachments(userID int64) ([]*AttachmentUsername, error) { | |||
return getAllUserAttachments(x, userID) | |||
} | |||
func getModelArtsUserAttachments(e Engine, userID int64) ([]*AttachmentUsername, error) { | |||
attachments := make([]*AttachmentUsername, 0, 10) | |||
if err := e.Table("attachment").Join("LEFT", "`user`", "attachment.uploader_id "+ | |||
@@ -487,6 +542,43 @@ func GetAttachmentSizeByDatasetID(datasetID int64) (int64, error) { | |||
return total, nil | |||
} | |||
func AttachmentsByDatasetOption(datasets []int64, opts *SearchDatasetOptions) ([]*Attachment, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.In("attachment.dataset_id", datasets)) | |||
if opts.JustNeedZipFile { | |||
cond = cond.And(builder.Gt{"attachment.decompress_state": 0}) | |||
} | |||
if opts.PublicOnly { | |||
cond = cond.And(builder.Eq{"attachment.is_private": false}) | |||
} | |||
if opts.CloudBrainType >= 0 { | |||
cond = cond.And(builder.Eq{"attachment.type": opts.CloudBrainType}) | |||
} | |||
if opts.UploadAttachmentByMe { | |||
cond = cond.And( | |||
builder.Eq{"attachment.uploader_id": opts.User.ID}, | |||
) | |||
} | |||
attachments := make([]*Attachment, 0) | |||
if err := sess.Table(&Attachment{}).Where(cond).Desc("id"). | |||
Find(&attachments); err != nil { | |||
return nil, fmt.Errorf("Find: %v", err) | |||
} | |||
return attachments, nil | |||
} | |||
func GetAllAttachmentSize() (int64, error) { | |||
return x.SumInt(&Attachment{}, "size") | |||
} | |||
func GetAllDatasetContributorByDatasetId(datasetId int64) ([]*User, error) { | |||
r := make([]*User, 0) | |||
if err := x.Select("distinct(public.user.*)").Table("attachment").Join("LEFT", "user", "public.user.ID = attachment.uploader_id").Where("attachment.dataset_id = ?", datasetId).Find(&r); err != nil { | |||
return nil, err | |||
} | |||
return r, nil | |||
} |
@@ -0,0 +1,181 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"path/filepath" | |||
"strings" | |||
"xorm.io/builder" | |||
) | |||
type Badge struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
Name string | |||
LightedIcon string `xorm:"varchar(2048)"` | |||
GreyedIcon string `xorm:"varchar(2048)"` | |||
Url string `xorm:"varchar(2048)"` | |||
CategoryId int64 | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
DeletedAt timeutil.TimeStamp `xorm:"deleted"` | |||
} | |||
func (m *Badge) ToUserShow() *Badge4UserShow { | |||
return &Badge4UserShow{ | |||
Name: m.Name, | |||
LightedIcon: GetIconOuterLink(m.LightedIcon), | |||
GreyedIcon: GetIconOuterLink(m.GreyedIcon), | |||
Url: m.Url, | |||
} | |||
} | |||
type GetBadgeOpts struct { | |||
BadgeType BadgeType | |||
CategoryId int64 | |||
ListOpts ListOptions | |||
} | |||
type BadgeAndCategory struct { | |||
Badge Badge `xorm:"extends"` | |||
Category BadgeCategory `xorm:"extends"` | |||
} | |||
func (*BadgeAndCategory) TableName() string { | |||
return "badge" | |||
} | |||
func (m *BadgeAndCategory) ToShow() *Badge4AdminShow { | |||
return &Badge4AdminShow{ | |||
ID: m.Badge.ID, | |||
Name: m.Badge.Name, | |||
LightedIcon: GetIconOuterLink(m.Badge.LightedIcon), | |||
GreyedIcon: GetIconOuterLink(m.Badge.GreyedIcon), | |||
Url: m.Badge.Url, | |||
CategoryName: m.Category.Name, | |||
CategoryId: m.Category.ID, | |||
CreatedUnix: m.Badge.CreatedUnix, | |||
UpdatedUnix: m.Badge.UpdatedUnix, | |||
} | |||
} | |||
type Badge4AdminShow struct { | |||
ID int64 | |||
Name string | |||
LightedIcon string | |||
GreyedIcon string | |||
Url string | |||
CategoryName string | |||
CategoryId int64 | |||
CreatedUnix timeutil.TimeStamp | |||
UpdatedUnix timeutil.TimeStamp | |||
} | |||
func (m Badge4AdminShow) ToDTO() Badge { | |||
return Badge{ | |||
Name: m.Name, | |||
LightedIcon: m.LightedIcon, | |||
GreyedIcon: m.GreyedIcon, | |||
Url: m.Url, | |||
CategoryId: m.CategoryId, | |||
} | |||
} | |||
type BadgeOperateReq struct { | |||
ID int64 | |||
Name string | |||
LightedIcon string | |||
GreyedIcon string | |||
Url string | |||
CategoryId int64 | |||
} | |||
func (m BadgeOperateReq) ToDTO() Badge { | |||
return Badge{ | |||
Name: m.Name, | |||
LightedIcon: m.LightedIcon, | |||
GreyedIcon: m.GreyedIcon, | |||
Url: m.Url, | |||
CategoryId: m.CategoryId, | |||
} | |||
} | |||
type Badge4UserShow struct { | |||
Name string | |||
LightedIcon string | |||
GreyedIcon string | |||
Url string | |||
} | |||
type BadgeShowWithStatus struct { | |||
Badge *Badge4UserShow | |||
IsLighted bool | |||
} | |||
type UserAllBadgeInCategory struct { | |||
CategoryName string | |||
CategoryId int64 | |||
LightedNum int | |||
Badges []*BadgeShowWithStatus | |||
} | |||
func GetBadgeList(opts GetBadgeOpts) (int64, []*BadgeAndCategory, error) { | |||
if opts.ListOpts.Page <= 0 { | |||
opts.ListOpts.Page = 1 | |||
} | |||
var cond = builder.NewCond() | |||
if opts.BadgeType > 0 { | |||
cond = cond.And(builder.Eq{"badge_category.type": opts.BadgeType}) | |||
} | |||
if opts.CategoryId > 0 { | |||
cond = cond.And(builder.Eq{"badge_category.id": opts.CategoryId}) | |||
} | |||
n, err := x.Join("INNER", "badge_category", "badge_category.ID = badge.category_id").Where(cond).Count(&BadgeAndCategory{}) | |||
if err != nil { | |||
return 0, nil, err | |||
} | |||
r := make([]*BadgeAndCategory, 0) | |||
if err = x.Join("INNER", "badge_category", "badge_category.ID = badge.category_id").Where(cond).OrderBy("badge.created_unix desc").Limit(opts.ListOpts.PageSize, (opts.ListOpts.Page-1)*opts.ListOpts.PageSize).Find(&r); err != nil { | |||
return 0, nil, err | |||
} | |||
return n, r, nil | |||
} | |||
func AddBadge(m Badge) (int64, error) { | |||
return x.Insert(&m) | |||
} | |||
func UpdateBadgeById(id int64, param Badge) (int64, error) { | |||
return x.ID(id).Update(¶m) | |||
} | |||
func DelBadge(id int64) (int64, error) { | |||
return x.ID(id).Delete(&Badge{}) | |||
} | |||
func GetBadgeById(id int64) (*Badge, error) { | |||
m := &Badge{} | |||
has, err := x.ID(id).Get(m) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, &ErrRecordNotExist{} | |||
} | |||
return m, nil | |||
} | |||
func GetBadgeByCategoryId(categoryId int64) ([]*Badge, error) { | |||
r := make([]*Badge, 0) | |||
err := x.Where("category_id = ?", categoryId).Find(&r) | |||
return r, err | |||
} | |||
func GetCustomIconByHash(hash string) string { | |||
if len(hash) == 0 { | |||
return "" | |||
} | |||
return filepath.Join(setting.IconUploadPath, hash) | |||
} | |||
func GetIconOuterLink(hash string) string { | |||
return strings.TrimRight(setting.AppSubURL, "/") + "/show/icon/" + hash | |||
} |
@@ -0,0 +1,94 @@ | |||
package models | |||
import "code.gitea.io/gitea/modules/timeutil" | |||
type BadgeType int | |||
const ( | |||
CustomizeBadge = iota + 1 | |||
SystemBadge | |||
) | |||
type BadgeCategory struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
Name string | |||
Position int64 | |||
Type BadgeType | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
DeletedAt timeutil.TimeStamp `xorm:"deleted"` | |||
} | |||
func (m *BadgeCategory) ToShow() *BadgeCategory4Show { | |||
return &BadgeCategory4Show{ | |||
ID: m.ID, | |||
Name: m.Name, | |||
Position: m.Position, | |||
Type: m.Type, | |||
CreatedUnix: m.CreatedUnix, | |||
} | |||
} | |||
type BadgeCategory4Show struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
Name string | |||
Position int64 | |||
Type BadgeType | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
} | |||
func (m BadgeCategory4Show) ToDTO() BadgeCategory { | |||
return BadgeCategory{ | |||
ID: m.ID, | |||
Name: m.Name, | |||
Position: m.Position, | |||
Type: m.Type, | |||
CreatedUnix: m.CreatedUnix, | |||
} | |||
} | |||
func GetBadgeCategoryListPaging(opts ListOptions) (int64, []*BadgeCategory, error) { | |||
n, err := x.Count(&BadgeCategory{}) | |||
if err != nil { | |||
return 0, nil, err | |||
} | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
} | |||
r := make([]*BadgeCategory, 0) | |||
if err := x.OrderBy("position asc,created_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&r); err != nil { | |||
return 0, nil, err | |||
} | |||
return n, r, nil | |||
} | |||
func GetBadgeCategoryList() ([]*BadgeCategory, error) { | |||
r := make([]*BadgeCategory, 0) | |||
if err := x.OrderBy("position asc,created_unix desc").Find(&r); err != nil { | |||
return nil, err | |||
} | |||
return r, nil | |||
} | |||
func AddBadgeCategory(m BadgeCategory) (int64, error) { | |||
return x.Insert(&m) | |||
} | |||
func UpdateBadgeCategoryById(id int64, param BadgeCategory) (int64, error) { | |||
return x.ID(id).Update(¶m) | |||
} | |||
func DelBadgeCategory(id int64) (int64, error) { | |||
return x.ID(id).Delete(&BadgeCategory{}) | |||
} | |||
func GetBadgeCategoryById(id int64) (*BadgeCategory, error) { | |||
m := &BadgeCategory{} | |||
has, err := x.ID(id).Get(m) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrRecordNotExist{} | |||
} | |||
return m, nil | |||
} |
@@ -0,0 +1,159 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"xorm.io/builder" | |||
) | |||
const ( | |||
ActionAddBadgeUser = 1 | |||
ActionDelBadgeUser = 2 | |||
) | |||
type BadgeUser struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
UserId int64 `xorm:"unique(user_badge)"` | |||
BadgeId int64 `xorm:"unique(user_badge) index"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created index"` | |||
} | |||
type BadgeUserLog struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
UserId int64 `xorm:"index"` | |||
BadgeId int64 `xorm:"index"` | |||
Action int | |||
CreatedUnix timeutil.TimeStamp `xorm:"created index"` | |||
} | |||
type BadgeUserDetail struct { | |||
BadgeUser BadgeUser `xorm:"extends"` | |||
User User `xorm:"extends"` | |||
} | |||
func (*BadgeUserDetail) TableName() string { | |||
return "badge_user" | |||
} | |||
func (m *BadgeUserDetail) ToShow() *BadgeUser4SHow { | |||
return &BadgeUser4SHow{ | |||
ID: m.BadgeUser.ID, | |||
UserId: m.BadgeUser.UserId, | |||
Name: m.User.Name, | |||
Avatar: m.User.RelAvatarLink(), | |||
Email: m.User.Email, | |||
CreatedUnix: m.BadgeUser.CreatedUnix, | |||
} | |||
} | |||
type BadgeUser4SHow struct { | |||
ID int64 | |||
UserId int64 | |||
Name string | |||
Avatar string | |||
Email string | |||
CreatedUnix timeutil.TimeStamp | |||
} | |||
type AddBadgeUsersReq struct { | |||
BadgeId int64 | |||
Users string | |||
} | |||
type DelBadgeUserReq struct { | |||
ID int64 | |||
} | |||
type GetUserBadgesOpts struct { | |||
CategoryId int64 | |||
ListOptions | |||
} | |||
func AddBadgeUser(m BadgeUser) (int64, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sess.Begin() | |||
n, err := sess.Insert(&m) | |||
if err != nil || n == 0 { | |||
return 0, err | |||
} | |||
_, err = sess.Insert(&BadgeUserLog{ | |||
UserId: m.UserId, | |||
BadgeId: m.BadgeId, | |||
Action: ActionAddBadgeUser, | |||
}) | |||
if err != nil { | |||
sess.Rollback() | |||
return 0, err | |||
} | |||
return n, sess.Commit() | |||
} | |||
func DelBadgeUser(id int64) (int64, error) { | |||
m := BadgeUser{} | |||
has, err := x.ID(id).Get(&m) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if !has { | |||
return 0, ErrRecordNotExist{} | |||
} | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sess.Begin() | |||
n, err := x.ID(m.ID).Delete(&BadgeUser{}) | |||
if err != nil || n == 0 { | |||
return 0, err | |||
} | |||
_, err = sess.Insert(&BadgeUserLog{ | |||
UserId: m.UserId, | |||
BadgeId: m.BadgeId, | |||
Action: ActionDelBadgeUser, | |||
}) | |||
if err != nil { | |||
sess.Rollback() | |||
return 0, err | |||
} | |||
return n, sess.Commit() | |||
} | |||
func GetBadgeUsers(badgeId int64, opts ListOptions) (int64, []BadgeUserDetail, error) { | |||
n, err := x.Join("LEFT", "public.user", "public.user.ID = badge_user.user_id").Where("badge_user.badge_id = ?", badgeId).Count(&BadgeUserDetail{}) | |||
if err != nil { | |||
return 0, nil, err | |||
} | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
} | |||
m := make([]BadgeUserDetail, 0) | |||
err = x.Join("LEFT", "public.user", "public.user.ID = badge_user.user_id").Where("badge_user.badge_id = ?", badgeId).OrderBy("badge_user.id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&m) | |||
if err != nil { | |||
return 0, nil, err | |||
} | |||
return n, m, nil | |||
} | |||
func GetUserBadgesPaging(userId int64, opts GetUserBadgesOpts) ([]*Badge, error) { | |||
cond := builder.NewCond() | |||
cond = cond.And(builder.Eq{"badge_user.user_id": userId}) | |||
if opts.CategoryId > 0 { | |||
cond = cond.And(builder.Eq{"badge.category_id": opts.CategoryId}) | |||
} | |||
r := make([]*Badge, 0) | |||
err := x.Join("INNER", "badge_user", "badge_user.badge_id = badge.id").Where(cond).OrderBy("badge_user.id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&r) | |||
return r, err | |||
} | |||
func CountUserBadges(userId int64) (int64, error) { | |||
return x.Where("user_id = ?", userId).Count(&BadgeUser{}) | |||
} | |||
func GetUserBadges(userId, categoryId int64) ([]*Badge, error) { | |||
cond := builder.NewCond() | |||
cond = cond.And(builder.Eq{"badge_user.user_id": userId}) | |||
if categoryId > 0 { | |||
cond = cond.And(builder.Eq{"badge.category_id": categoryId}) | |||
} | |||
r := make([]*Badge, 0) | |||
err := x.Join("INNER", "badge_user", "badge_user.badge_id = badge.id").Where(cond).OrderBy("badge_user.created_unix desc").Find(&r) | |||
return r, err | |||
} |
@@ -0,0 +1,37 @@ | |||
package models | |||
type BaseMessage struct { | |||
Code int | |||
Message string | |||
} | |||
var BaseOKMessage = BaseMessage{ | |||
0, "", | |||
} | |||
func BaseErrorMessage(message string) BaseMessage { | |||
return BaseMessage{ | |||
1, message, | |||
} | |||
} | |||
type BaseMessageApi struct { | |||
Code int `json:"code"` | |||
Message string `json:"message"` | |||
} | |||
var BaseOKMessageApi = BaseMessageApi{ | |||
0, "", | |||
} | |||
func BaseErrorMessageApi(message string) BaseMessageApi { | |||
return BaseMessageApi{ | |||
1, message, | |||
} | |||
} | |||
type BaseMessageWithDataApi struct { | |||
Code int `json:"code"` | |||
Message string `json:"message"` | |||
Data interface{} `json:"data"` | |||
} |
@@ -0,0 +1,597 @@ | |||
package models | |||
import ( | |||
"fmt" | |||
"strings" | |||
"unicode/utf8" | |||
"xorm.io/builder" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
const RECOMMOND_TYPE = 5 | |||
const NORMAL_TYPE = 0 | |||
const IMAGE_STATUS_COMMIT = 0 | |||
const IMAGE_STATUS_SUCCESS = 1 | |||
const IMAGE_STATUS_Failed = 2 | |||
type Image struct { | |||
ID int64 `xorm:"pk autoincr" json:"id"` | |||
Type int `xorm:"INDEX NOT NULL" json:"type"` //0 normal 5官方推荐,中间值保留为后续扩展 | |||
CloudbrainType int `xorm:"INDEX NOT NULL" json:"cloudbrainType"` //0 云脑一 1云脑二 | |||
UID int64 `xorm:"INDEX NOT NULL" json:"uid"` | |||
IsPrivate bool `xorm:"INDEX NOT NULL" json:"isPrivate"` | |||
Tag string `xorm:"varchar(100) UNIQUE" json:"tag"` | |||
Description string `xorm:"varchar(765)" json:"description"` | |||
Topics []string `xorm:"TEXT JSON" json:"topics"` | |||
Place string `xorm:"varchar(300)" json:"place"` | |||
NumStars int `xorm:"NOT NULL DEFAULT 0" json:"numStars"` | |||
IsStar bool `xorm:"-" json:"isStar"` | |||
UserName string `xorm:"-" json:"userName"` | |||
RelAvatarLink string `xorm:"-" json:"relAvatarLink"` | |||
Status int `xorm:"INDEX NOT NULL DEFAULT 0" json:"status"` //0代表正在提交,1提交完成,2提交失败 | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"createdUnix"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"updatedUnix"` | |||
} | |||
type ImageList []*Image | |||
type ImageStar struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
UID int64 `xorm:"UNIQUE(s)"` | |||
ImageID int64 `xorm:"UNIQUE(s)"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
} | |||
type ImageTopic struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
Name string `xorm:"UNIQUE VARCHAR(105)"` | |||
ImageCount int | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
} | |||
type ImageTopicRelation struct { | |||
ImageID int64 `xorm:"UNIQUE(s)"` | |||
TopicID int64 `xorm:"UNIQUE(s)"` | |||
} | |||
type SearchImageOptions struct { | |||
Keyword string | |||
UID int64 | |||
Status int | |||
IncludePublicOnly bool | |||
IncludeOfficialOnly bool | |||
IncludePrivateOnly bool | |||
IncludeStarByMe bool | |||
IncludeCustom bool | |||
IncludeOwnerOnly bool | |||
Topics string | |||
CloudbrainType int | |||
ListOptions | |||
SearchOrderBy | |||
} | |||
type ErrorImageTagExist struct { | |||
Tag string | |||
} | |||
type ErrorImageCommitting struct { | |||
Tag string | |||
} | |||
type ImagesPageResult struct { | |||
Count int64 `json:"count"` | |||
Images []*Image `json:"images"` | |||
} | |||
func (err ErrorImageTagExist) Error() string { | |||
return fmt.Sprintf("Image already exists [tag: %s]", err.Tag) | |||
} | |||
func (err ErrorImageCommitting) Error() string { | |||
return fmt.Sprintf("Image already exists [tag: %s]", err.Tag) | |||
} | |||
type ErrImageNotExist struct { | |||
ID int64 | |||
Tag string | |||
} | |||
func (err ErrImageNotExist) Error() string { | |||
return fmt.Sprintf("Image does not exist [id: %d] [tag: %s]", err.ID, err.Tag) | |||
} | |||
func IsErrorImageCommitting(err error) bool { | |||
_, ok := err.(ErrorImageCommitting) | |||
return ok | |||
} | |||
func IsErrImageNotExist(err error) bool { | |||
_, ok := err.(ErrImageNotExist) | |||
return ok | |||
} | |||
func IsErrImageTagExist(err error) bool { | |||
_, ok := err.(ErrorImageTagExist) | |||
return ok | |||
} | |||
func IsImageExist(tag string) (bool, error) { | |||
return x.Exist(&Image{ | |||
Tag: tag, | |||
}) | |||
} | |||
func IsImageExistByUser(tag string, uid int64) (bool, error) { | |||
return x.Exist(&Image{ | |||
Tag: tag, | |||
UID: uid, | |||
Status: IMAGE_STATUS_SUCCESS, | |||
}) | |||
} | |||
type FindImageTopicOptions struct { | |||
ListOptions | |||
ImageID int64 | |||
Keyword string | |||
} | |||
func (opts *FindImageTopicOptions) toConds() builder.Cond { | |||
var cond = builder.NewCond() | |||
if opts.ImageID > 0 { | |||
cond = cond.And(builder.Eq{"image_topic_relation.image_id": opts.ImageID}) | |||
} | |||
if opts.Keyword != "" { | |||
cond = cond.And(builder.Like{"image_topic.name", strings.ToLower(opts.Keyword)}) | |||
} | |||
return cond | |||
} | |||
func GetImageByID(id int64) (*Image, error) { | |||
rel := new(Image) | |||
has, err := x. | |||
ID(id). | |||
Get(rel) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrImageNotExist{ID: id} | |||
} | |||
return rel, nil | |||
} | |||
func GetImageByTag(tag string) (*Image, error) { | |||
image := &Image{Tag: tag} | |||
has, err := x. | |||
Get(image) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrImageNotExist{Tag: tag} | |||
} | |||
return image, nil | |||
} | |||
func SanitizeAndValidateImageTopics(topics []string) (validTopics []string, invalidTopics []string) { | |||
validTopics = make([]string, 0) | |||
mValidTopics := make(map[string]struct{}) | |||
invalidTopics = make([]string, 0) | |||
for _, topic := range topics { | |||
topic = strings.TrimSpace(strings.ToLower(topic)) | |||
// ignore empty string | |||
if len(topic) == 0 { | |||
continue | |||
} | |||
// ignore same topic twice | |||
if _, ok := mValidTopics[topic]; ok { | |||
continue | |||
} | |||
if utf8.RuneCountInString(topic) <= 35 { | |||
validTopics = append(validTopics, topic) | |||
mValidTopics[topic] = struct{}{} | |||
} else { | |||
invalidTopics = append(invalidTopics, topic) | |||
} | |||
} | |||
return validTopics, invalidTopics | |||
} | |||
func FindImageTopics(opts *FindImageTopicOptions) (topics []*ImageTopic, err error) { | |||
sess := x.Select("image_topic.*").Where(opts.toConds()) | |||
if opts.ImageID > 0 { | |||
sess.Join("INNER", "image_topic_relation", "image_topic_relation.topic_id = image_topic.id") | |||
} | |||
if opts.PageSize != 0 && opts.Page != 0 { | |||
sess = opts.setSessionPagination(sess) | |||
} | |||
return topics, sess.Desc("image_topic.image_count").Find(&topics) | |||
} | |||
func SaveImageTopics(imageID int64, topicNames ...string) error { | |||
topics, err := FindImageTopics(&FindImageTopicOptions{ | |||
ImageID: imageID, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err := sess.Begin(); err != nil { | |||
return err | |||
} | |||
var addedTopicNames []string | |||
for _, topicName := range topicNames { | |||
if strings.TrimSpace(topicName) == "" { | |||
continue | |||
} | |||
var found bool | |||
for _, t := range topics { | |||
if strings.EqualFold(topicName, t.Name) { | |||
found = true | |||
break | |||
} | |||
} | |||
if !found { | |||
addedTopicNames = append(addedTopicNames, topicName) | |||
} | |||
} | |||
var removeTopics []*ImageTopic | |||
for _, t := range topics { | |||
var found bool | |||
for _, topicName := range topicNames { | |||
if strings.EqualFold(topicName, t.Name) { | |||
found = true | |||
break | |||
} | |||
} | |||
if !found { | |||
removeTopics = append(removeTopics, t) | |||
} | |||
} | |||
for _, topicName := range addedTopicNames { | |||
_, err := addTopicByNameToImage(sess, imageID, topicName) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
for _, topic := range removeTopics { | |||
err := removeTopicFromImage(sess, imageID, topic) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
topicNames = make([]string, 0, 25) | |||
if err := sess.Table("image_topic").Cols("name"). | |||
Join("INNER", "image_topic_relation", "image_topic_relation.topic_id = image_topic.id"). | |||
Where("image_topic_relation.image_id = ?", imageID).Desc("image_topic.image_count").Find(&topicNames); err != nil { | |||
return err | |||
} | |||
if _, err := sess.ID(imageID).Cols("topics").Update(&Image{ | |||
Topics: topicNames, | |||
}); err != nil { | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
func addTopicByNameToImage(e Engine, imageID int64, topicName string) (*ImageTopic, error) { | |||
var topic ImageTopic | |||
has, err := e.Where("name = ?", topicName).Get(&topic) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if !has { | |||
topic.Name = topicName | |||
topic.ImageCount = 1 | |||
if _, err := e.Insert(&topic); err != nil { | |||
return nil, err | |||
} | |||
} else { | |||
topic.ImageCount++ | |||
if _, err := e.ID(topic.ID).Cols("image_count").Update(&topic); err != nil { | |||
return nil, err | |||
} | |||
} | |||
if _, err := e.Insert(&ImageTopicRelation{ | |||
ImageID: imageID, | |||
TopicID: topic.ID, | |||
}); err != nil { | |||
return nil, err | |||
} | |||
return &topic, nil | |||
} | |||
func removeTopicFromImage(e Engine, imageId int64, topic *ImageTopic) error { | |||
topic.ImageCount-- | |||
if _, err := e.ID(topic.ID).Cols("image_count").Update(topic); err != nil { | |||
return err | |||
} | |||
if _, err := e.Delete(&ImageTopicRelation{ | |||
ImageID: imageId, | |||
TopicID: topic.ID, | |||
}); err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func SearchImage(opts *SearchImageOptions) (ImageList, int64, error) { | |||
cond := SearchImageCondition(opts) | |||
return SearchImageByCondition(opts, cond) | |||
} | |||
func SearchImageCondition(opts *SearchImageOptions) builder.Cond { | |||
var cond = builder.NewCond() | |||
if len(opts.Keyword) > 0 { | |||
var subQueryCond = builder.NewCond() | |||
for _, v := range strings.Split(opts.Keyword, ",") { | |||
subQueryCond = subQueryCond.Or(builder.Like{"LOWER(image_topic.name)", strings.ToLower(v)}) | |||
} | |||
subQuery := builder.Select("image_topic_relation.image_id").From("image_topic_relation"). | |||
Join("INNER", "image_topic", "image_topic.id = image_topic_relation.topic_id"). | |||
Where(subQueryCond). | |||
GroupBy("image_topic_relation.image_id") | |||
var keywordCond = builder.In("id", subQuery) | |||
var likes = builder.NewCond() | |||
for _, v := range strings.Split(opts.Keyword, ",") { | |||
likes = likes.Or(builder.Like{"LOWER(tag)", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) | |||
} | |||
keywordCond = keywordCond.Or(likes) | |||
cond = cond.And(keywordCond) | |||
} | |||
if len(opts.Topics) > 0 { //标签精确匹配 | |||
var subQueryCond = builder.NewCond() | |||
for _, v := range strings.Split(opts.Keyword, ",") { | |||
subQueryCond = subQueryCond.Or(builder.Eq{"LOWER(image_topic.name)": strings.ToLower(v)}) | |||
subQuery := builder.Select("image_topic_relation.image_id").From("image_topic_relation"). | |||
Join("INNER", "image_topic", "image_topic.id = image_topic_relation.topic_id"). | |||
Where(subQueryCond). | |||
GroupBy("image_topic_relation.image_id") | |||
var topicCond = builder.In("id", subQuery) | |||
cond = cond.And(topicCond) | |||
} | |||
} | |||
if opts.IncludePublicOnly { | |||
cond = cond.And(builder.Eq{"is_private": false}) | |||
} | |||
if opts.IncludePrivateOnly { | |||
cond = cond.And(builder.Eq{"is_private": true}) | |||
} | |||
if opts.IncludeOwnerOnly { | |||
cond = cond.And(builder.Eq{"uid": opts.UID}) | |||
} | |||
if opts.IncludeOfficialOnly { | |||
cond = cond.And(builder.Eq{"type": RECOMMOND_TYPE}) | |||
} | |||
if opts.Status >= 0 { | |||
cond = cond.And(builder.Eq{"status": opts.Status}) | |||
} | |||
if opts.IncludeStarByMe { | |||
subQuery := builder.Select("image_id").From("image_star"). | |||
Where(builder.Eq{"uid": opts.UID}) | |||
var starCond = builder.In("id", subQuery) | |||
cond = cond.And(starCond) | |||
} | |||
if opts.CloudbrainType > 0 { | |||
cond = cond.And(builder.Eq{"cloudbrain_type": opts.CloudbrainType}) | |||
} | |||
return cond | |||
} | |||
func SearchImageByCondition(opts *SearchImageOptions, cond builder.Cond) (ImageList, int64, error) { | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
} | |||
var err error | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
images := make(ImageList, 0, opts.PageSize) | |||
count, err := sess.Where(cond).Count(new(Image)) | |||
if err != nil { | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
} | |||
sess.Where(cond).OrderBy(opts.SearchOrderBy.String()) | |||
if opts.PageSize > 0 { | |||
sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) | |||
} | |||
if err = sess.Find(&images); err != nil { | |||
return nil, 0, fmt.Errorf("Images: %v", err) | |||
} | |||
if err = images.loadAttributes(sess, opts.UID); err != nil { | |||
return nil, 0, fmt.Errorf("LoadAttributes: %v", err) | |||
} | |||
return images, count, nil | |||
} | |||
func (images ImageList) loadAttributes(e Engine, uid int64) error { | |||
if len(images) == 0 { | |||
return nil | |||
} | |||
set := make(map[int64]struct{}) | |||
for i := range images { | |||
set[images[i].UID] = struct{}{} | |||
} | |||
// Load creators. | |||
users := make(map[int64]*User, len(set)) | |||
if err := e.Table("\"user\""). | |||
Cols("name", "lower_name", "avatar", "email"). | |||
Where("id > 0"). | |||
In("id", keysInt64(set)). | |||
Find(&users); err != nil { | |||
return fmt.Errorf("find users: %v", err) | |||
} | |||
for i := range images { | |||
if users[images[i].UID] != nil { | |||
images[i].UserName = users[images[i].UID].Name | |||
images[i].RelAvatarLink = users[images[i].UID].RelAvatarLink() | |||
} else { | |||
images[i].UserName = "" | |||
images[i].RelAvatarLink = "" | |||
} | |||
if uid == -1 { | |||
images[i].IsStar = false | |||
} else { | |||
images[i].IsStar = isImageStaring(e, uid, images[i].ID) | |||
} | |||
} | |||
return nil | |||
} | |||
func GetCommittingImageCount() int { | |||
total, err := x.Where("status =?", 0).Count(new(Image)) | |||
if err != nil { | |||
return 0 | |||
} | |||
return int(total) | |||
} | |||
func CreateLocalImage(image *Image) error { | |||
_, err := x.Insert(image) | |||
return err | |||
} | |||
func UpdateLocalImage(image *Image) error { | |||
_, err := x.ID(image.ID).Cols("description", "is_private", "status").Update(image) | |||
return err | |||
} | |||
func UpdateLocalImageStatus(image *Image) error { | |||
_, err := x.ID(image.ID).Cols("status").Update(image) | |||
return err | |||
} | |||
func UpdateAutoIncrementIndex() { | |||
x.Exec("SELECT setval('image_id_seq', (SELECT MAX(id) from image))") | |||
} | |||
func DeleteLocalImage(id int64) error { | |||
image := new(Image) | |||
_, err := x.ID(id).Delete(image) | |||
return err | |||
} | |||
//star or unstar Image | |||
func StarImage(userID, imageID int64, star bool) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err := sess.Begin(); err != nil { | |||
return err | |||
} | |||
if star { | |||
if isImageStaring(sess, userID, imageID) { | |||
return nil | |||
} | |||
if _, err := sess.Insert(&ImageStar{UID: userID, ImageID: imageID}); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `image` SET num_stars = num_stars + 1 WHERE id = ?", imageID); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `user` SET num_image_stars = num_image_stars + 1 WHERE id = ?", userID); err != nil { | |||
return err | |||
} | |||
} else { | |||
if !isImageStaring(sess, userID, imageID) { | |||
return nil | |||
} | |||
if _, err := sess.Delete(&ImageStar{0, userID, imageID, 0}); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `image` SET num_stars = num_stars - 1 WHERE id = ?", imageID); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `user` SET num_image_stars = num_image_stars - 1 WHERE id = ?", userID); err != nil { | |||
return err | |||
} | |||
} | |||
return sess.Commit() | |||
} | |||
func IsImageStaring(userID, datasetID int64) bool { | |||
return isImageStaring(x, userID, datasetID) | |||
} | |||
func isImageStaring(e Engine, userID, imageID int64) bool { | |||
has, _ := e.Get(&ImageStar{0, userID, imageID, 0}) | |||
return has | |||
} | |||
func RecommendImage(imageId int64, recommond bool) error { | |||
image := Image{Type: GetRecommondType(recommond)} | |||
_, err := x.ID(imageId).Cols("type").Update(image) | |||
return err | |||
} | |||
func GetRecommondType(recommond bool) int { | |||
if recommond { | |||
return RECOMMOND_TYPE | |||
} else { | |||
return NORMAL_TYPE | |||
} | |||
} |
@@ -0,0 +1,136 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
type CloudbrainSpec struct { | |||
CloudbrainID int64 `xorm:"pk"` | |||
SpecId int64 `xorm:"index"` | |||
SourceSpecId string | |||
AccCardsNum int | |||
AccCardType string `xorm:"index"` | |||
CpuCores int | |||
MemGiB float32 | |||
GPUMemGiB float32 | |||
ShareMemGiB float32 | |||
ComputeResource string | |||
UnitPrice int | |||
QueueId int64 | |||
QueueCode string | |||
Cluster string | |||
AiCenterCode string `xorm:"index"` | |||
AiCenterName string | |||
IsExclusive bool | |||
ExclusiveOrg string | |||
CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
} | |||
func (s CloudbrainSpec) ConvertToSpecification() *Specification { | |||
return &Specification{ | |||
ID: s.SpecId, | |||
SourceSpecId: s.SourceSpecId, | |||
AccCardsNum: s.AccCardsNum, | |||
AccCardType: s.AccCardType, | |||
CpuCores: s.CpuCores, | |||
MemGiB: s.MemGiB, | |||
GPUMemGiB: s.GPUMemGiB, | |||
ShareMemGiB: s.ShareMemGiB, | |||
ComputeResource: s.ComputeResource, | |||
UnitPrice: s.UnitPrice, | |||
QueueId: s.QueueId, | |||
QueueCode: s.QueueCode, | |||
Cluster: s.Cluster, | |||
AiCenterCode: s.AiCenterCode, | |||
AiCenterName: s.AiCenterName, | |||
IsExclusive: s.IsExclusive, | |||
ExclusiveOrg: s.ExclusiveOrg, | |||
} | |||
} | |||
func NewCloudBrainSpec(cloudbrainId int64, s Specification) CloudbrainSpec { | |||
return CloudbrainSpec{ | |||
CloudbrainID: cloudbrainId, | |||
SpecId: s.ID, | |||
SourceSpecId: s.SourceSpecId, | |||
AccCardsNum: s.AccCardsNum, | |||
AccCardType: s.AccCardType, | |||
CpuCores: s.CpuCores, | |||
MemGiB: s.MemGiB, | |||
GPUMemGiB: s.GPUMemGiB, | |||
ShareMemGiB: s.ShareMemGiB, | |||
ComputeResource: s.ComputeResource, | |||
UnitPrice: s.UnitPrice, | |||
QueueId: s.QueueId, | |||
QueueCode: s.QueueCode, | |||
Cluster: s.Cluster, | |||
AiCenterCode: s.AiCenterCode, | |||
AiCenterName: s.AiCenterName, | |||
IsExclusive: s.IsExclusive, | |||
ExclusiveOrg: s.ExclusiveOrg, | |||
} | |||
} | |||
var StatusChangeChan = make(chan *Cloudbrain, 50) | |||
func InsertCloudbrainSpec(c CloudbrainSpec) (int64, error) { | |||
return x.Insert(&c) | |||
} | |||
func GetCloudbrainSpecByID(cloudbrainId int64) (*CloudbrainSpec, error) { | |||
r := &CloudbrainSpec{} | |||
if has, err := x.Where("cloudbrain_id = ?", cloudbrainId).Get(r); err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, nil | |||
} | |||
return r, nil | |||
} | |||
func FindCloudbrainTask(page, pageSize int) ([]*Cloudbrain, error) { | |||
r := make([]*Cloudbrain, 0) | |||
err := x.Unscoped(). | |||
Limit(pageSize, (page-1)*pageSize). | |||
OrderBy("cloudbrain.id"). | |||
Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return r, nil | |||
} | |||
func CountNoSpecHistoricTask() (int64, error) { | |||
n, err := x.Unscoped(). | |||
Where(" 1=1 and not exists (select 1 from cloudbrain_spec where cloudbrain.id = cloudbrain_spec.cloudbrain_id)"). | |||
Count(&Cloudbrain{}) | |||
if err != nil { | |||
return 0, err | |||
} | |||
return n, nil | |||
} | |||
// GetResourceSpecMapByCloudbrainIDs | |||
func GetResourceSpecMapByCloudbrainIDs(ids []int64) (map[int64]*Specification, error) { | |||
specs := make([]*CloudbrainSpec, 0) | |||
if err := x.In("cloudbrain_id", ids).Find(&specs); err != nil { | |||
return nil, err | |||
} | |||
r := make(map[int64]*Specification, len(ids)) | |||
for _, s := range specs { | |||
r[s.CloudbrainID] = s.ConvertToSpecification() | |||
} | |||
return r, nil | |||
} | |||
func GetCloudbrainTaskUnitPrice(task Cloudbrain) (int, error) { | |||
s, err := GetCloudbrainSpecByID(task.ID) | |||
if err != nil { | |||
return 0, err | |||
} | |||
var n = 1 | |||
if task.WorkServerNumber > 1 { | |||
n = task.WorkServerNumber | |||
} | |||
return s.UnitPrice * n, nil | |||
} |
@@ -0,0 +1,490 @@ | |||
package models | |||
import ( | |||
"strconv" | |||
"time" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"code.gitea.io/gitea/modules/util" | |||
"xorm.io/builder" | |||
) | |||
type TaskDetail struct { | |||
ID int64 `json:"ID"` | |||
JobID string `json:"JobID"` | |||
JobName string `json:"JobName"` | |||
DisplayJobName string `json:"DisplayJobName"` | |||
Status string `json:"Status"` | |||
JobType string `json:"JobType"` | |||
CreatedUnix timeutil.TimeStamp `json:"CreatedUnix"` | |||
WaitTime string `json:"WaitTime"` | |||
RunTime string `json:"RunTime"` | |||
StartTime timeutil.TimeStamp `json:"StartTime"` | |||
EndTime timeutil.TimeStamp `json:"EndTime"` | |||
ComputeResource string `json:"ComputeResource"` | |||
Type int `json:"Type"` | |||
UserName string `json:"UserName"` | |||
RepoName string `json:"RepoName"` | |||
RepoAlias string `json:"RepoAlias"` | |||
RepoID int64 `json:"RepoID"` | |||
IsDelete bool `json:"IsDelete"` | |||
CardNum int `json:"CardNum"` | |||
CardType string `json:"CardType"` | |||
CardDuration string `json:"CardDuration"` | |||
AiCenter string `json:"AiCenter"` | |||
FlavorName string `json:"FlavorName"` | |||
WorkServerNum int64 `json:"WorkServerNum"` | |||
Spec *Specification `json:"Spec"` | |||
} | |||
type CloudbrainDurationStatistic struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
Cluster string | |||
AiCenterCode string `xorm:"INDEX"` | |||
AiCenterName string | |||
ComputeResource string | |||
AccCardType string `xorm:"INDEX"` | |||
DateTime timeutil.TimeStamp `xorm:"INDEX DEFAULT 0"` | |||
DateTimeUnix timeutil.TimeStamp `xorm:"INDEX DEFAULT 0"` | |||
DayTime string `xorm:"INDEX"` | |||
HourTime int `xorm:"INDEX"` | |||
CardsUseDuration int | |||
CardsTotalDuration int | |||
CardsTotalNum int | |||
DeletedUnix timeutil.TimeStamp `xorm:"deleted"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
} | |||
type DurationStatisticOptions struct { | |||
BeginTime time.Time | |||
EndTime time.Time | |||
AiCenterCode string | |||
} | |||
type DurationRateStatistic struct { | |||
AiCenterTotalDurationStat map[string]int `json:"aiCenterTotalDurationStat"` | |||
AiCenterUsageDurationStat map[string]int `json:"aiCenterUsageDurationStat"` | |||
UsageRate map[string]float64 `json:"UsageRate"` | |||
} | |||
type ResourceDetail struct { | |||
QueueCode string | |||
Cluster string `xorm:"notnull"` | |||
AiCenterCode string | |||
AiCenterName string | |||
ComputeResource string | |||
AccCardType string | |||
CardsTotalNum int | |||
IsAutomaticSync bool | |||
} | |||
type DateUsageStatistic struct { | |||
Date string `json:"date"` | |||
UsageDuration int `json:"usageDuration"` | |||
TotalDuration int `json:"totalDuration"` | |||
UsageRate float64 `json:"usageRate"` | |||
} | |||
type HourTimeStatistic struct { | |||
HourTimeUsageDuration map[string]int `json:"hourTimeUsageDuration"` | |||
HourTimeTotalDuration map[string]int `json:"hourTimeTotalDuration"` | |||
HourTimeUsageRate map[string]float64 `json:"hourTimeUsageRate"` | |||
} | |||
type CloudbrainTypeDuration []struct { | |||
Type int `xorm:"type"` | |||
DurationSum int `xorm:"durationSum"` | |||
CardDurationSum int `xorm:"cardDurationSum"` | |||
Count int `xorm:"count"` | |||
} | |||
type CloudbrainAllDuration struct { | |||
DurationSum int `xorm:"durationSum"` | |||
CardDurationSum int `xorm:"cardDurationSum"` | |||
Count int `xorm:"count"` | |||
} | |||
func GetTodayCreatorCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
countSql := "SELECT count(distinct user_id) FROM " + | |||
"public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) | |||
return x.SQL(countSql).Count() | |||
} | |||
func GetTodayCloudbrainCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
countSql := "SELECT count(*) FROM " + | |||
"public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<=" + strconv.FormatInt(endTime.Unix(), 10) | |||
return x.SQL(countSql).Count() | |||
} | |||
func GetTodayRunningCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
countSql := "SELECT count(*) FROM " + | |||
"public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<=" + strconv.FormatInt(endTime.Unix(), 10) + " and (status='" + string(JobRunning) + "'" + | |||
" or status='" + string(ModelArtsTrainJobInit) + "')" | |||
return x.SQL(countSql).Count() | |||
} | |||
func GetTodayWaitingCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||
countSql := "SELECT count(*) FROM " + | |||
"public.cloudbrain where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) + | |||
" and created_unix<=" + strconv.FormatInt(endTime.Unix(), 10) + " and status='" + string(JobWaiting) + "'" | |||
return x.SQL(countSql).Count() | |||
} | |||
func GetCreatorCount() (int64, error) { | |||
countSql := "SELECT count(distinct user_id) FROM public.cloudbrain" | |||
return x.SQL(countSql).Count() | |||
} | |||
func GetCloudbrainTypeCount() ([]map[string]string, error) { | |||
countSql := "SELECT type,count(*) num FROM public.cloudbrain group by type order by num desc" | |||
return x.QueryString(countSql) | |||
} | |||
func GetCloudbrainStatusCount() ([]map[string]string, error) { | |||
countSql := "SELECT status,count(*) num FROM public.cloudbrain group by status order by num desc" | |||
return x.QueryString(countSql) | |||
} | |||
func GetCloudbrainTpyeDurationSum() ([]map[string]string, error) { | |||
countSql := "SELECT type,sum(duration) FROM public.cloudbrain group by type order by sum(duration) desc" | |||
return x.QueryString(countSql) | |||
} | |||
func GetRecordBeginTime() ([]*CloudbrainInfo, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sess.OrderBy("cloudbrain.id ASC limit 1") | |||
cloudbrains := make([]*CloudbrainInfo, 0) | |||
if err := sess.Table(&Cloudbrain{}).Unscoped(). | |||
Find(&cloudbrains); err != nil { | |||
log.Info("find error.") | |||
} | |||
return cloudbrains, nil | |||
} | |||
func GetAllStatusCloudBrain() map[string]int { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
cloudbrains := make([]*CloudbrainInfo, 0) | |||
if err := sess.Table(&Cloudbrain{}).Unscoped(). | |||
Find(&cloudbrains); err != nil { | |||
log.Info("find error.") | |||
} | |||
cloudBrainStatusResult := make(map[string]int) | |||
for _, cloudbrain := range cloudbrains { | |||
if _, ok := cloudBrainStatusResult[cloudbrain.Status]; !ok { | |||
cloudBrainStatusResult[cloudbrain.Status] = 1 | |||
} else { | |||
cloudBrainStatusResult[cloudbrain.Status] += 1 | |||
} | |||
} | |||
return cloudBrainStatusResult | |||
} | |||
func GetWaittingTop() ([]*CloudbrainInfo, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Eq{"cloudbrain.status": string(JobWaiting)}, | |||
) | |||
sess.OrderBy("cloudbrain.created_unix ASC limit 10") | |||
cloudbrains := make([]*CloudbrainInfo, 0, 10) | |||
if err := sess.Table(&Cloudbrain{}).Where(cond). | |||
Find(&cloudbrains); err != nil { | |||
log.Info("find error.") | |||
} | |||
var ids []int64 | |||
for _, task := range cloudbrains { | |||
ids = append(ids, task.RepoID) | |||
} | |||
repositoryMap, err := GetRepositoriesMapByIDs(ids) | |||
if err == nil { | |||
for _, task := range cloudbrains { | |||
task.Repo = repositoryMap[task.RepoID] | |||
} | |||
} | |||
return cloudbrains, nil | |||
} | |||
func GetRunningTop() ([]*CloudbrainInfo, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Eq{"cloudbrain.status": string(JobRunning)}, | |||
) | |||
sess.OrderBy("cloudbrain.duration DESC limit 10") | |||
cloudbrains := make([]*CloudbrainInfo, 0, 10) | |||
if err := sess.Table(&Cloudbrain{}).Where(cond). | |||
Find(&cloudbrains); err != nil { | |||
log.Info("find error.") | |||
} | |||
var ids []int64 | |||
for _, task := range cloudbrains { | |||
ids = append(ids, task.RepoID) | |||
} | |||
repositoryMap, err := GetRepositoriesMapByIDs(ids) | |||
if err == nil { | |||
for _, task := range cloudbrains { | |||
task.Repo = repositoryMap[task.RepoID] | |||
} | |||
} | |||
return cloudbrains, nil | |||
} | |||
func getCreatePeriodCount(dateBeginTime string, dateEndTime string, hourBeginTime string, hourEndTime string) (int64, error) { | |||
countSql := "SELECT count(*) FROM " + | |||
"public.cloudbrain where to_char(to_timestamp(created_unix), 'YYYY-MM-DD') >= '" + dateBeginTime + | |||
"' and to_char(to_timestamp(created_unix), 'YYYY-MM-DD') < '" + dateEndTime + | |||
"' and to_char(to_timestamp(created_unix), 'HH24:MI:SS') >= '" + hourBeginTime + | |||
"' and to_char(to_timestamp(created_unix), 'HH24:MI:SS') < '" + hourEndTime + "'" | |||
return x.SQL(countSql).Count() | |||
} | |||
//SELECT * FROM xxx WHERE NOT ((endTime < hourBeginTime) OR (startTime > hourEndTime)) | |||
func getRunPeriodCount(dateBeginTime string, dateEndTime string, hourBeginTime string, hourEndTime string) (int64, error) { | |||
countSql := "SELECT count(*) FROM " + | |||
"public.cloudbrain where not ((to_char(to_timestamp(start_time), ' HH24:MI:SS') > '" + hourEndTime + | |||
"') or (to_char(to_timestamp(end_time), 'HH24:MI:SS') < '" + hourBeginTime + "'))" + | |||
" and (to_char(to_timestamp(start_time), 'YYYY-MM-DD') >= '" + dateBeginTime + | |||
"' and to_char(to_timestamp(start_time), 'YYYY-MM-DD') < '" + dateEndTime + "')" | |||
return x.SQL(countSql).Count() | |||
} | |||
func GetCreateHourPeriodCount(dateBeginTime string, dateEndTime string) (map[string]interface{}, error) { | |||
//0 to 23 for each hour, | |||
dateHourMap := make(map[string]interface{}) | |||
var slice = []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23} | |||
for key, value := range slice { | |||
hourBeginHour := util.AddZero(value) + ":00:00" | |||
hourEndHour := util.AddZero(value+1) + ":00:00" | |||
cout, err := getCreatePeriodCount(dateBeginTime, dateEndTime, hourBeginHour, hourEndHour) | |||
if err != nil { | |||
log.Error("Can not query getCreatePeriodCount.", err) | |||
return nil, nil | |||
} | |||
dateHourMap[strconv.Itoa(key)] = cout | |||
} | |||
return dateHourMap, nil | |||
} | |||
func GetRunHourPeriodCount(dateBeginTime string, dateEndTime string) (map[string]interface{}, error) { | |||
dateHourMap := make(map[string]interface{}) | |||
var slice = []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23} | |||
for key, value := range slice { | |||
hourBeginHour := util.AddZero(value) + ":00:00" | |||
hourEndHour := util.AddZero(value+1) + ":00:00" | |||
cout, err := getRunPeriodCount(dateBeginTime, dateEndTime, hourBeginHour, hourEndHour) | |||
if err != nil { | |||
log.Error("Can not query getRunPeriodCount.", err) | |||
return nil, nil | |||
} | |||
dateHourMap[strconv.Itoa(key)] = cout | |||
} | |||
return dateHourMap, nil | |||
} | |||
func GetCloudbrainRunning() ([]*CloudbrainInfo, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Eq{"cloudbrain.status": string(JobRunning)}, | |||
) | |||
sess.OrderBy("cloudbrain.created_unix ASC") | |||
cloudbrains := make([]*CloudbrainInfo, 0, 10) | |||
if err := sess.Table(&Cloudbrain{}).Where(cond). | |||
Find(&cloudbrains); err != nil { | |||
log.Info("find error.") | |||
} | |||
return cloudbrains, nil | |||
} | |||
func GetCloudbrainByTime(beginTime int64, endTime int64) ([]*CloudbrainInfo, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.Or( | |||
builder.And(builder.Gte{"cloudbrain.end_time": beginTime}, builder.Lte{"cloudbrain.start_time": beginTime}, builder.Gt{"cloudbrain.start_time": 0}), | |||
) | |||
cond = cond.Or( | |||
builder.And(builder.Gte{"cloudbrain.start_time": beginTime}, builder.Lte{"cloudbrain.start_time": endTime}, builder.Gt{"cloudbrain.start_time": 0}), | |||
) | |||
cond = cond.Or( | |||
builder.And(builder.Eq{"cloudbrain.status": string(JobRunning)}, builder.Lte{"cloudbrain.start_time": beginTime}), | |||
) | |||
sess.OrderBy("cloudbrain.id ASC") | |||
cloudbrains := make([]*CloudbrainInfo, 0, 10) | |||
if err := sess.Table(&Cloudbrain{}).Unscoped().Where(cond). | |||
Find(&cloudbrains); err != nil { | |||
log.Error("find error.") | |||
return nil, err | |||
} | |||
return cloudbrains, nil | |||
} | |||
func GetSpecByAiCenterCodeAndType(aiCenterCode string, accCardType string) ([]*CloudbrainSpec, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.And(builder.Eq{"cloudbrain_spec.ai_center_code": aiCenterCode}, builder.Eq{"cloudbrain_spec.acc_card_type": accCardType}), | |||
) | |||
cloudbrainSpecs := make([]*CloudbrainSpec, 0, 10) | |||
if err := sess.Table(&CloudbrainSpec{}).Where(cond). | |||
Find(&cloudbrainSpecs); err != nil { | |||
log.Error("find error.") | |||
return nil, err | |||
} | |||
return cloudbrainSpecs, nil | |||
} | |||
func InsertCloudbrainDurationStatistic(cloudbrainDurationStatistic *CloudbrainDurationStatistic) (int64, error) { | |||
return xStatistic.Insert(cloudbrainDurationStatistic) | |||
} | |||
func getDurationStatistic(cb *CloudbrainDurationStatistic) (*CloudbrainDurationStatistic, error) { | |||
has, err := x.Get(cb) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrJobNotExist{} | |||
} | |||
return cb, nil | |||
} | |||
func GetCanUseCardInfo() ([]*ResourceQueue, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sess.OrderBy("resource_queue.cluster DESC, resource_queue.ai_center_code ASC") | |||
ResourceQueues := make([]*ResourceQueue, 0, 10) | |||
if err := sess.Table(&ResourceQueue{}).Find(&ResourceQueues); err != nil { | |||
log.Error("find error.") | |||
return nil, err | |||
} | |||
return ResourceQueues, nil | |||
} | |||
func GetCardDurationStatistics(opts *DurationStatisticOptions) ([]*CloudbrainDurationStatistic, error) { | |||
sess := xStatistic.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
if opts.BeginTime.Unix() > 0 && opts.EndTime.Unix() > 0 { | |||
cond = cond.And( | |||
builder.And(builder.Gte{"cloudbrain_duration_statistic.date_time_unix": opts.BeginTime.Unix()}, builder.Lt{"cloudbrain_duration_statistic.date_time_unix": opts.EndTime.Unix()}), | |||
) | |||
} | |||
if opts.AiCenterCode != "" { | |||
cond = cond.And( | |||
builder.Eq{"cloudbrain_duration_statistic.ai_center_code": opts.AiCenterCode}, | |||
) | |||
} | |||
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0, 10) | |||
if err := sess.Table(&CloudbrainDurationStatistic{}).Where(cond). | |||
Find(&CloudbrainDurationStatistics); err != nil { | |||
log.Error("find error.") | |||
return nil, err | |||
} | |||
return CloudbrainDurationStatistics, nil | |||
} | |||
func GetDurationRecordBeginTime() ([]*CloudbrainDurationStatistic, error) { | |||
sess := xStatistic.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Gt{"cloudbrain_duration_statistic.date_time_unix": 0}, | |||
) | |||
sess.OrderBy("cloudbrain_duration_statistic.date_time_unix ASC limit 1") | |||
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0) | |||
if err := sess.Table(&CloudbrainDurationStatistic{}).Where(cond).Find(&CloudbrainDurationStatistics); err != nil { | |||
log.Error("find error.") | |||
return nil, err | |||
} | |||
return CloudbrainDurationStatistics, nil | |||
} | |||
func GetDurationRecordUpdateTime() ([]*CloudbrainDurationStatistic, error) { | |||
sess := xStatistic.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Gt{"cloudbrain_duration_statistic.date_time_unix": 1577808000}, | |||
) | |||
sess.OrderBy("cloudbrain_duration_statistic.date_time_unix DESC limit 1") | |||
CloudbrainDurationStatistics := make([]*CloudbrainDurationStatistic, 0) | |||
if err := sess.Table(&CloudbrainDurationStatistic{}).Where(cond).Find(&CloudbrainDurationStatistics); err != nil { | |||
log.Error("find error.") | |||
return nil, err | |||
} | |||
return CloudbrainDurationStatistics, nil | |||
} | |||
func DeleteCloudbrainDurationStatistic(beginTime timeutil.TimeStamp, endTime timeutil.TimeStamp) error { | |||
sess := xStatistic.NewSession() | |||
defer sess.Close() | |||
if _, err := sess.Exec("DELETE FROM cloudbrain_duration_statistic WHERE cloudbrain_duration_statistic.date_time_unix BETWEEN ? AND ?", beginTime, endTime); err != nil { | |||
log.Error("DELETE cloudbrain_duration_statistic data error.") | |||
return err | |||
} | |||
return nil | |||
} | |||
func GetCloudbrainTypeCardDuration() (CloudbrainTypeDuration, error) { | |||
query := ` | |||
SELECT | |||
cloudbrain.type, | |||
SUM(cloudbrain.duration) as durationSum, | |||
SUM( | |||
COALESCE(cloudbrain.duration * | |||
CASE | |||
WHEN cloudbrain.work_server_number = 0 THEN 1 | |||
ELSE COALESCE(cloudbrain.work_server_number, 1) | |||
END * | |||
COALESCE(cloudbrain_spec.acc_cards_num, 1), 0) | |||
) as cardDurationSum, | |||
COUNT(*) as count | |||
FROM cloudbrain | |||
LEFT JOIN cloudbrain_spec | |||
ON cloudbrain.id = cloudbrain_spec.cloudbrain_id | |||
GROUP BY cloudbrain.type | |||
` | |||
// 执行查询 | |||
var results CloudbrainTypeDuration | |||
if err := x.SQL(query).Find(&results); err != nil { | |||
panic(err) | |||
} | |||
return results, nil | |||
} | |||
func GetCloudbrainAllCardDuration() (CloudbrainAllDuration, error) { | |||
query := ` | |||
SELECT | |||
SUM(cloudbrain.duration) as durationSum, | |||
SUM( | |||
COALESCE(cloudbrain.duration * | |||
CASE | |||
WHEN cloudbrain.work_server_number = 0 THEN 1 | |||
ELSE COALESCE(cloudbrain.work_server_number, 1) | |||
END * | |||
COALESCE(cloudbrain_spec.acc_cards_num, 1), 0) | |||
) as cardDurationSum, | |||
COUNT(*) as count | |||
FROM cloudbrain | |||
LEFT JOIN cloudbrain_spec | |||
ON cloudbrain.id = cloudbrain_spec.cloudbrain_id | |||
` | |||
// 执行查询 | |||
var result CloudbrainAllDuration | |||
if _, err := x.SQL(query).Get(&result); err != nil { | |||
panic(err) | |||
} | |||
return result, nil | |||
} |
@@ -0,0 +1,68 @@ | |||
package models | |||
import ( | |||
"time" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
const ( | |||
TempJobId = "TEMP" | |||
TempVersionId = TempJobId | |||
TempJobStatus = TempJobId | |||
) | |||
type CloudbrainTemp struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
JobID string `xorm:"NOT NULL DEFAULT 'TEMP'"` | |||
VersionID string `xorm:"NOT NULL DEFAULT 'TEMP'"` | |||
JobName string `xorm:"NOT NULL "` | |||
Type int `xorm:"NOT NULL "` | |||
JobType string `xorm:"INDEX NOT NULL DEFAULT 'DEBUG'"` | |||
Status string `xorm:"INDEX NOT NULL DEFAULT 'TEMP'"` | |||
QueryTimes int `xorm:"INDEX NOT NULL DEFAULT 0"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
DeletedAt time.Time `xorm:"deleted"` | |||
} | |||
func InsertCloudbrainTemp(temp *CloudbrainTemp) (err error) { | |||
if _, err = x.Insert(temp); err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func getCloudBrainTemp(temp *CloudbrainTemp) (*CloudbrainTemp, error) { | |||
has, err := x.Get(temp) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrJobNotExist{} | |||
} | |||
return temp, nil | |||
} | |||
func GetCloudBrainTempJobs() ([]*CloudbrainTemp, error) { | |||
jobs := make([]*CloudbrainTemp, 0, 10) | |||
return jobs, x.In("status", TempJobStatus, string(ModelArtsStopping), string(ModelArtsTrainJobKilling)). | |||
And("query_times < ?", setting.MaxTempQueryTimes). | |||
Limit(100). | |||
Find(&jobs) | |||
} | |||
func DeleteCloudbrainTemp(temp *CloudbrainTemp) error { | |||
return deleteCloudbrainTemp(x, temp) | |||
} | |||
func deleteCloudbrainTemp(e Engine, temp *CloudbrainTemp) error { | |||
_, err := e.ID(temp.ID).Delete(temp) | |||
return err | |||
} | |||
func UpdateCloudbrainTemp(temp *CloudbrainTemp) error { | |||
_, err := x.ID(temp.ID).AllCols().Update(temp) | |||
return err | |||
} |
@@ -1,8 +1,6 @@ | |||
package models | |||
import ( | |||
"fmt" | |||
"code.gitea.io/gitea/modules/log" | |||
"xorm.io/xorm" | |||
) | |||
@@ -18,13 +16,13 @@ type CustomMigrationStatic struct { | |||
} | |||
var customMigrations = []CustomMigration{ | |||
{"Custom v1 Topic struct change to support chinese", syncTopicStruct}, | |||
//手机号功能可以不启用,不启用时手机号为空串,为了避免启用时唯一性约束报错,定制唯一性约束(对null和空字符串不做唯一性检查) | |||
{"set phone number unique index", setPhoneNumberUniqueIndex}, | |||
} | |||
var customMigrationsStatic = []CustomMigrationStatic{ | |||
{"Delete organization user history data ", deleteNotDisplayUser}, | |||
{"update issue_fixed_rate to 1 if num_issues is 0 ", updateIssueFixedRate}, | |||
} | |||
var customMigrationsStatic []CustomMigrationStatic | |||
func MigrateCustom(x *xorm.Engine) { | |||
@@ -36,44 +34,32 @@ func MigrateCustom(x *xorm.Engine) { | |||
} | |||
} | |||
} | |||
func MigrateCustomStatic(x *xorm.Engine, static *xorm.Engine) { | |||
for _, m := range customMigrationsStatic { | |||
log.Info("Migration: %s", m.Description) | |||
if err := m.Migrate(x, static); err != nil { | |||
log.Error("Migration: %v", err) | |||
} | |||
} | |||
} | |||
func syncTopicStruct(x *xorm.Engine) error { | |||
func setPhoneNumberUniqueIndex(x *xorm.Engine) error { | |||
query := "ALTER TABLE topic ALTER COLUMN name TYPE varchar(105);" | |||
query := "CREATE UNIQUE INDEX IF NOT EXISTS \"UQE_user_phone_number\" ON \"user\" (phone_number) WHERE phone_number IS NOT NULL and phone_number !='';" | |||
_, err := x.Exec(query) | |||
return err | |||
} | |||
func deleteNotDisplayUser(x *xorm.Engine, static *xorm.Engine) error { | |||
querySQL := "select id,name from public.user where type=1" | |||
rows, err := x.Query(querySQL) | |||
if err != nil { | |||
log.Info("select db failed,err:", err) | |||
return err | |||
} | |||
func syncTopicStruct(x *xorm.Engine) error { | |||
for i, userRow := range rows { | |||
log.Info("delete zuzi user, i=" + fmt.Sprint(i) + " userName=" + string(userRow["name"])) | |||
deleteSql := "delete from user_business_analysis where id=" + string(userRow["id"]) + " and name='" + string(userRow["name"]) + "'" | |||
static.Exec(deleteSql) | |||
} | |||
query := "ALTER TABLE topic ALTER COLUMN name TYPE varchar(105);" | |||
return nil | |||
_, err := x.Exec(query) | |||
return err | |||
} | |||
func updateIssueFixedRate(x *xorm.Engine, static *xorm.Engine) error { | |||
@@ -4,6 +4,11 @@ import ( | |||
"errors" | |||
"fmt" | |||
"sort" | |||
"strings" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"xorm.io/builder" | |||
@@ -17,11 +22,14 @@ const ( | |||
type Dataset struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
Title string `xorm:"INDEX NOT NULL"` | |||
Status int32 `xorm:"INDEX"` // normal_private: 0, pulbic: 1, is_delete: 2 | |||
Title string `xorm:"INDEX NOT NULL""` | |||
Status int32 `xorm:"INDEX""` // normal_private: 0, pulbic: 1, is_delete: 2 | |||
Category string | |||
Description string `xorm:"TEXT"` | |||
DownloadTimes int64 | |||
UseCount int64 `xorm:"DEFAULT 0"` | |||
NumStars int `xorm:"INDEX NOT NULL DEFAULT 0"` | |||
Recommend bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
License string | |||
Task string | |||
ReleaseID int64 `xorm:"INDEX"` | |||
@@ -35,6 +43,11 @@ type Dataset struct { | |||
Attachments []*Attachment `xorm:"-"` | |||
} | |||
type DatasetWithStar struct { | |||
Dataset | |||
IsStaring bool | |||
} | |||
func (d *Dataset) IsPrivate() bool { | |||
switch d.Status { | |||
case DatasetStatusPrivate: | |||
@@ -56,25 +69,28 @@ func (datasets DatasetList) loadAttributes(e Engine) error { | |||
} | |||
set := make(map[int64]struct{}) | |||
userIdSet := make(map[int64]struct{}) | |||
datasetIDs := make([]int64, len(datasets)) | |||
for i := range datasets { | |||
set[datasets[i].UserID] = struct{}{} | |||
userIdSet[datasets[i].UserID] = struct{}{} | |||
set[datasets[i].RepoID] = struct{}{} | |||
datasetIDs[i] = datasets[i].ID | |||
} | |||
// Load owners. | |||
users := make(map[int64]*User, len(set)) | |||
users := make(map[int64]*User, len(userIdSet)) | |||
repos := make(map[int64]*Repository, len(set)) | |||
if err := e. | |||
Where("id > 0"). | |||
In("id", keysInt64(set)). | |||
In("id", keysInt64(userIdSet)). | |||
Cols("id", "lower_name", "name", "full_name", "email"). | |||
Find(&users); err != nil { | |||
return fmt.Errorf("find users: %v", err) | |||
} | |||
if err := e. | |||
Where("id > 0"). | |||
In("id", keysInt64(set)). | |||
Cols("id", "owner_id", "owner_name", "lower_name", "name", "description", "alias", "lower_alias", "is_private"). | |||
Find(&repos); err != nil { | |||
return fmt.Errorf("find repos: %v", err) | |||
} | |||
@@ -86,38 +102,126 @@ func (datasets DatasetList) loadAttributes(e Engine) error { | |||
return nil | |||
} | |||
func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions) error { | |||
if len(datasets) == 0 { | |||
return nil | |||
} | |||
datasetIDs := make([]int64, len(datasets)) | |||
for i := range datasets { | |||
datasetIDs[i] = datasets[i].ID | |||
} | |||
attachments, err := AttachmentsByDatasetOption(datasetIDs, opts) | |||
if err != nil { | |||
return fmt.Errorf("GetAttachmentsByDatasetIds failed error: %v", err) | |||
} | |||
permissionMap := make(map[int64]bool, len(datasets)) | |||
for _, attachment := range attachments { | |||
for i := range datasets { | |||
if attachment.DatasetID == datasets[i].ID { | |||
if !attachment.IsPrivate { | |||
datasets[i].Attachments = append(datasets[i].Attachments, attachment) | |||
} else { | |||
permission, ok := permissionMap[datasets[i].ID] | |||
if !ok { | |||
permission = false | |||
datasets[i].Repo.GetOwner() | |||
if !permission { | |||
if datasets[i].Repo.OwnerID == opts.User.ID { | |||
permission = true | |||
} else { | |||
isCollaborator, _ := datasets[i].Repo.IsCollaborator(opts.User.ID) | |||
isInRepoTeam, _ := datasets[i].Repo.IsInRepoTeam(opts.User.ID) | |||
if isCollaborator || isInRepoTeam { | |||
permission = true | |||
} | |||
} | |||
} | |||
permissionMap[datasets[i].ID] = permission | |||
} | |||
if permission { | |||
datasets[i].Attachments = append(datasets[i].Attachments, attachment) | |||
} | |||
} | |||
} | |||
} | |||
} | |||
for i := range datasets { | |||
if datasets[i].Attachments == nil { | |||
datasets[i].Attachments = []*Attachment{} | |||
} | |||
datasets[i].Repo.Owner = nil | |||
} | |||
return nil | |||
} | |||
type SearchDatasetOptions struct { | |||
Keyword string | |||
OwnerID int64 | |||
RepoID int64 | |||
IncludePublic bool | |||
Keyword string | |||
OwnerID int64 | |||
User *User | |||
RepoID int64 | |||
IncludePublic bool | |||
RecommendOnly bool | |||
Category string | |||
Task string | |||
License string | |||
DatasetIDs []int64 | |||
ExcludeDatasetId int64 | |||
ListOptions | |||
SearchOrderBy | |||
IsOwner bool | |||
IsOwner bool | |||
StarByMe bool | |||
CloudBrainType int //0 cloudbrain 1 modelarts -1 all | |||
PublicOnly bool | |||
JustNeedZipFile bool | |||
NeedAttachment bool | |||
UploadAttachmentByMe bool | |||
QueryReference bool | |||
} | |||
func CreateDataset(dataset *Dataset) (err error) { | |||
if _, err = x.Insert(dataset); err != nil { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err := sess.Begin(); err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func CreateDefaultDatasetToRepo(repo *Repository) (err error) { | |||
dataset := &Dataset{RepoID: repo.ID} | |||
has, err := x.Get(dataset) | |||
datasetByRepoId := &Dataset{RepoID: dataset.RepoID} | |||
has, err := sess.Get(datasetByRepoId) | |||
if err != nil { | |||
return err | |||
} | |||
if !has { | |||
dataset.Status = DatasetStatusPrivate | |||
dataset.Title = repo.Name | |||
if err = CreateDataset(dataset); err != nil { | |||
return err | |||
} | |||
if has { | |||
return fmt.Errorf("The dataset already exists.") | |||
} | |||
return nil | |||
if _, err = sess.Insert(dataset); err != nil { | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
func RecommendDataset(dataSetId int64, recommend bool) error { | |||
dataset := Dataset{Recommend: recommend} | |||
_, err := x.ID(dataSetId).Cols("recommend").Update(dataset) | |||
return err | |||
} | |||
func SearchDataset(opts *SearchDatasetOptions) (DatasetList, int64, error) { | |||
@@ -129,36 +233,88 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.Neq{"dataset.status": DatasetStatusDeleted}) | |||
if len(opts.Keyword) > 0 { | |||
cond = cond.And(builder.Like{"dataset.title", opts.Keyword}) | |||
} | |||
cond = generateFilterCond(opts, cond) | |||
if opts.RepoID > 0 { | |||
cond = cond.And(builder.Eq{"dataset.repo_id": opts.RepoID}) | |||
} | |||
if opts.IncludePublic { | |||
if opts.ExcludeDatasetId > 0 { | |||
cond = cond.And(builder.Neq{"dataset.id": opts.ExcludeDatasetId}) | |||
} | |||
if opts.PublicOnly { | |||
cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) | |||
cond = cond.And(builder.Eq{"attachment.is_private": false}) | |||
} else if opts.IncludePublic { | |||
cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) | |||
cond = cond.And(builder.Eq{"attachment.is_private": false}) | |||
if opts.OwnerID > 0 { | |||
if len(opts.Keyword) == 0 { | |||
cond = cond.Or(builder.Eq{"repository.owner_id": opts.OwnerID}) | |||
} else { | |||
subCon := builder.NewCond() | |||
subCon = subCon.And(builder.Eq{"repository.owner_id": opts.OwnerID}, builder.Like{"dataset.title", opts.Keyword}) | |||
cond = cond.Or(subCon) | |||
subCon := builder.NewCond() | |||
subCon = subCon.And(builder.Eq{"repository.owner_id": opts.OwnerID}) | |||
subCon = generateFilterCond(opts, subCon) | |||
cond = cond.Or(subCon) | |||
} | |||
} | |||
} else if opts.OwnerID > 0 { | |||
} else if opts.OwnerID > 0 && !opts.StarByMe && !opts.UploadAttachmentByMe { | |||
cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID}) | |||
if !opts.IsOwner { | |||
cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) | |||
cond = cond.And(builder.Eq{"attachment.is_private": false}) | |||
} | |||
} | |||
if len(opts.DatasetIDs) > 0 { | |||
if opts.StarByMe || (opts.RepoID == 0 && opts.QueryReference) { | |||
cond = cond.And(builder.In("dataset.id", opts.DatasetIDs)) | |||
} else { | |||
subCon := builder.NewCond() | |||
subCon = subCon.And(builder.In("dataset.id", opts.DatasetIDs)) | |||
subCon = generateFilterCond(opts, subCon) | |||
cond = cond.Or(subCon) | |||
} | |||
} else { | |||
if opts.StarByMe { | |||
cond = cond.And(builder.Eq{"dataset.id": -1}) | |||
} | |||
} | |||
return cond | |||
} | |||
func generateFilterCond(opts *SearchDatasetOptions, cond builder.Cond) builder.Cond { | |||
if len(opts.Keyword) > 0 { | |||
cond = cond.And(builder.Or(builder.Like{"LOWER(dataset.title)", strings.ToLower(opts.Keyword)}, builder.Like{"LOWER(dataset.description)", strings.ToLower(opts.Keyword)})) | |||
} | |||
if len(opts.Category) > 0 { | |||
cond = cond.And(builder.Eq{"dataset.category": opts.Category}) | |||
} | |||
if len(opts.Task) > 0 { | |||
cond = cond.And(builder.Eq{"dataset.task": opts.Task}) | |||
} | |||
if len(opts.License) > 0 { | |||
cond = cond.And(builder.Eq{"dataset.license": opts.License}) | |||
} | |||
if opts.RecommendOnly { | |||
cond = cond.And(builder.Eq{"dataset.recommend": opts.RecommendOnly}) | |||
} | |||
if opts.JustNeedZipFile { | |||
cond = cond.And(builder.Gt{"attachment.decompress_state": 0}) | |||
} | |||
if opts.CloudBrainType >= 0 { | |||
cond = cond.And(builder.Eq{"attachment.type": opts.CloudBrainType}) | |||
} | |||
if opts.UploadAttachmentByMe { | |||
cond = cond.And(builder.Eq{"attachment.uploader_id": opts.User.ID}) | |||
} | |||
return cond | |||
} | |||
func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (DatasetList, int64, error) { | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
@@ -169,18 +325,25 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da | |||
defer sess.Close() | |||
datasets := make(DatasetList, 0, opts.PageSize) | |||
selectColumnsSql := "distinct dataset.id,dataset.title, dataset.status, dataset.category, dataset.description, dataset.download_times, dataset.license, dataset.task, dataset.release_id, dataset.user_id, dataset.repo_id, dataset.created_unix,dataset.updated_unix,dataset.num_stars,dataset.recommend,dataset.use_count" | |||
count, err := sess.Join("INNER", "repository", "repository.id = dataset.repo_id").Where(cond).Count(new(Dataset)) | |||
count, err := sess.Distinct("dataset.id").Join("INNER", "repository", "repository.id = dataset.repo_id"). | |||
Join("INNER", "attachment", "attachment.dataset_id=dataset.id"). | |||
Where(cond).Count(new(Dataset)) | |||
if err != nil { | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
} | |||
sess.Select("dataset.*").Join("INNER", "repository", "repository.id = dataset.repo_id").Where(cond).OrderBy(opts.SearchOrderBy.String()) | |||
builderQuery := builder.Dialect(setting.Database.Type).Select("id", "title", "status", "category", "description", "download_times", "license", "task", "release_id", "user_id", "repo_id", "created_unix", "updated_unix", "num_stars", "recommend", "use_count").From(builder.Dialect(setting.Database.Type).Select(selectColumnsSql).From("dataset").Join("INNER", "repository", "repository.id = dataset.repo_id"). | |||
Join("INNER", "attachment", "attachment.dataset_id=dataset.id"). | |||
Where(cond), "d").OrderBy(opts.SearchOrderBy.String()) | |||
if opts.PageSize > 0 { | |||
sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) | |||
builderQuery.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) | |||
} | |||
if err = sess.Find(&datasets); err != nil { | |||
if err = sess.SQL(builderQuery).Find(&datasets); err != nil { | |||
return nil, 0, fmt.Errorf("Dataset: %v", err) | |||
} | |||
@@ -188,6 +351,12 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da | |||
return nil, 0, fmt.Errorf("LoadAttributes: %v", err) | |||
} | |||
if opts.NeedAttachment { | |||
if err = datasets.loadAttachmentAttributes(opts); err != nil { | |||
return nil, 0, fmt.Errorf("LoadAttributes: %v", err) | |||
} | |||
} | |||
return datasets, count, nil | |||
} | |||
@@ -231,13 +400,23 @@ func getDatasetAttachments(e Engine, typeCloudBrain int, isSigned bool, user *Us | |||
sort.Sort(sortedRels) | |||
// Select attachments | |||
err = e. | |||
Asc("dataset_id"). | |||
In("dataset_id", sortedRels.ID). | |||
And("type = ?", typeCloudBrain). | |||
Find(&attachments, Attachment{}) | |||
if err != nil { | |||
return err | |||
if typeCloudBrain == -1 { | |||
err = e. | |||
Asc("dataset_id"). | |||
In("dataset_id", sortedRels.ID). | |||
Find(&attachments, Attachment{}) | |||
if err != nil { | |||
return err | |||
} | |||
} else { | |||
err = e. | |||
Asc("dataset_id"). | |||
In("dataset_id", sortedRels.ID). | |||
And("type = ?", typeCloudBrain). | |||
Find(&attachments, Attachment{}) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
// merge join | |||
@@ -253,7 +432,13 @@ func getDatasetAttachments(e Engine, typeCloudBrain int, isSigned bool, user *Us | |||
if err != nil { | |||
return err | |||
} | |||
attachment.FileChunk = fileChunks[0] | |||
if len(fileChunks) > 0 { | |||
attachment.Md5 = fileChunks[0].Md5 | |||
} else { | |||
log.Error("has attachment record, but has no file_chunk record") | |||
attachment.Md5 = "no_record" | |||
} | |||
attachment.CanDel = CanDelAttachment(isSigned, user, attachment) | |||
sortedRels.Rel[currentIndex].Attachments = append(sortedRels.Rel[currentIndex].Attachments, attachment) | |||
} | |||
@@ -285,6 +470,29 @@ func UpdateDataset(ctx DBContext, rel *Dataset) error { | |||
return err | |||
} | |||
func IncreaseDatasetUseCount(uuid string) { | |||
IncreaseAttachmentUseNumber(uuid) | |||
attachments, _ := GetAttachmentsByUUIDs(strings.Split(uuid, ";")) | |||
countMap := make(map[int64]int) | |||
for _, attachment := range attachments { | |||
value, ok := countMap[attachment.DatasetID] | |||
if ok { | |||
countMap[attachment.DatasetID] = value + 1 | |||
} else { | |||
countMap[attachment.DatasetID] = 1 | |||
} | |||
} | |||
for key, value := range countMap { | |||
x.Exec("UPDATE `dataset` SET use_count=use_count+? WHERE id=?", value, key) | |||
} | |||
} | |||
// GetDatasetByID returns Dataset with given ID. | |||
func GetDatasetByID(id int64) (*Dataset, error) { | |||
rel := new(Dataset) | |||
@@ -301,9 +509,6 @@ func GetDatasetByID(id int64) (*Dataset, error) { | |||
} | |||
func GetDatasetByRepo(repo *Repository) (*Dataset, error) { | |||
if err := CreateDefaultDatasetToRepo(repo); err != nil { | |||
return nil, err | |||
} | |||
dataset := &Dataset{RepoID: repo.ID} | |||
has, err := x.Get(dataset) | |||
if err != nil { | |||
@@ -312,10 +517,16 @@ func GetDatasetByRepo(repo *Repository) (*Dataset, error) { | |||
if has { | |||
return dataset, nil | |||
} else { | |||
return nil, errors.New("Not Found") | |||
return nil, ErrNotExist{repo.ID} | |||
} | |||
} | |||
func GetDatasetStarByUser(user *User) ([]*DatasetStar, error) { | |||
datasetStars := make([]*DatasetStar, 0) | |||
err := x.Cols("id", "uid", "dataset_id", "created_unix").Where("uid=?", user.ID).Find(&datasetStars) | |||
return datasetStars, err | |||
} | |||
func DeleteDataset(datasetID int64, uid int64) error { | |||
var err error | |||
sess := x.NewSession() | |||
@@ -367,3 +578,36 @@ func IncreaseDownloadCount(datasetID int64) error { | |||
return nil | |||
} | |||
func GetCollaboratorDatasetIdsByUserID(userID int64) []int64 { | |||
var datasets []int64 | |||
_ = x.Table("dataset").Join("INNER", "collaboration", "dataset.repo_id = collaboration.repo_id and collaboration.mode>0 and collaboration.user_id=?", userID). | |||
Cols("dataset.id").Find(&datasets) | |||
return datasets | |||
} | |||
func GetTeamDatasetIdsByUserID(userID int64) []int64 { | |||
var datasets []int64 | |||
_ = x.Table("dataset").Join("INNER", "team_repo", "dataset.repo_id = team_repo.repo_id"). | |||
Join("INNER", "team_user", "team_repo.team_id=team_user.team_id and team_user.uid=?", userID). | |||
Cols("dataset.id").Find(&datasets) | |||
return datasets | |||
} | |||
func UpdateDatasetCreateUser(ID int64, user *User) error { | |||
_, err := x.Where("id = ?", ID).Cols("user_id").Update(&Dataset{ | |||
UserID: user.ID, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func QueryDatasetGroupByTask() ([]map[string]interface{}, error) { | |||
rows, err := x.QueryInterface("SELECT count(*) as total,task FROM public.dataset where task <>'' group by task order by total desc limit 7") | |||
if err != nil { | |||
return nil, err | |||
} | |||
return rows, nil | |||
} |
@@ -4,26 +4,27 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/log" | |||
) | |||
import "code.gitea.io/gitea/modules/log" | |||
// GetUserDataSetPermission returns the user permissions to the data_set | |||
func GetUserDataSetPermission(dataSet *Dataset, user *User) (isPermit bool, err error) { | |||
isPermit = false | |||
switch dataSet.Status { | |||
case DatasetStatusDeleted: | |||
log.Error("the data_set has been deleted") | |||
case DatasetStatusPrivate: | |||
if !user.IsAdmin && user.ID != dataSet.UserID { | |||
log.Error("the user is not admin nor the owner of the data_set") | |||
if user != nil { | |||
switch dataSet.Status { | |||
case DatasetStatusDeleted: | |||
log.Error("the data_set has been deleted") | |||
case DatasetStatusPrivate: | |||
if !user.IsAdmin && user.ID != dataSet.UserID { | |||
log.Error("the user is not admin nor the owner of the data_set") | |||
} | |||
isPermit = true | |||
case DatasetStatusPublic: | |||
isPermit = true | |||
default: | |||
log.Error("the status of data_set is wrong") | |||
} | |||
isPermit = true | |||
case DatasetStatusPublic: | |||
isPermit = true | |||
default: | |||
log.Error("the status of data_set is wrong") | |||
} | |||
return isPermit, nil | |||
@@ -0,0 +1,88 @@ | |||
package models | |||
import ( | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
type DatasetReference struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
RepoID int64 `xorm:"INDEX unique"` | |||
DatasetID string `xorm:"TEXT"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
} | |||
func GetDatasetIdsByRepoID(repoID int64) []int64 { | |||
var datasets []int64 | |||
var datasetIds []string | |||
_ = x.Table("dataset_reference").Where("repo_id=?", repoID). | |||
Cols("dataset_reference.dataset_id").Find(&datasetIds) | |||
if len(datasetIds) > 0 { | |||
for _, datasetIdStr := range strings.Split(datasetIds[0], ",") { | |||
datasetId, err := strconv.ParseInt(datasetIdStr, 10, 64) | |||
if err != nil { | |||
continue | |||
} | |||
datasets = append(datasets, datasetId) | |||
} | |||
} | |||
return datasets | |||
} | |||
func HasReferenceDataset(repoID int64) bool { | |||
var datasetIds []string | |||
_ = x.Table("dataset_reference").Where("repo_id=?", repoID). | |||
Cols("dataset_reference.dataset_id").Find(&datasetIds) | |||
return len(datasetIds) > 0 | |||
} | |||
func getReferenceDatasetStr(repoID int64) string { | |||
var datasetIds []string | |||
_ = x.Table("dataset_reference").Where("repo_id=?", repoID). | |||
Cols("dataset_reference.dataset_id").Find(&datasetIds) | |||
if len(datasetIds) > 0 { | |||
return datasetIds[0] | |||
} | |||
return "" | |||
} | |||
func DeleteReferenceDatasetIdsByRepoID(repoID int64) error { | |||
_, err := x.Exec("delete from dataset_reference where repo_id=?", repoID) | |||
return err | |||
} | |||
func NewDatasetIdsByRepoID(repoID int64, datasetIds []int64) error { | |||
if len(datasetIds) == 0 { //关联数据集数组为空 | |||
DeleteReferenceDatasetIdsByRepoID(repoID) | |||
} | |||
var datasetsStrArray []string | |||
for _, datasetId := range datasetIds { | |||
datasetsStrArray = append(datasetsStrArray, strconv.FormatInt(datasetId, 10)) | |||
} | |||
newDatasetStr := strings.Join(datasetsStrArray, ",") | |||
oldDatasetStr := getReferenceDatasetStr(repoID) | |||
if newDatasetStr == oldDatasetStr { //关联数据集无变化,不需要处理 | |||
return nil | |||
} | |||
if oldDatasetStr != "" { //已经存在关联数据集 | |||
_, err := x.Exec("update dataset_reference set dataset_id=? where repo_id=?", newDatasetStr, repoID) | |||
return err | |||
} else { | |||
datasetReference := DatasetReference{ | |||
DatasetID: newDatasetStr, | |||
RepoID: repoID, | |||
} | |||
_, err := x.Insert(datasetReference) | |||
return err | |||
} | |||
} |
@@ -0,0 +1,77 @@ | |||
package models | |||
import "code.gitea.io/gitea/modules/timeutil" | |||
type DatasetStar struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
UID int64 `xorm:"UNIQUE(s)"` | |||
DatasetID int64 `xorm:"UNIQUE(s)"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
} | |||
// StarRepo or unstar repository. | |||
func StarDataset(userID, datasetID int64, star bool) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err := sess.Begin(); err != nil { | |||
return err | |||
} | |||
if star { | |||
if isDatasetStaring(sess, userID, datasetID) { | |||
return nil | |||
} | |||
if _, err := sess.Insert(&DatasetStar{UID: userID, DatasetID: datasetID}); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `dataset` SET num_stars = num_stars + 1 WHERE id = ?", datasetID); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `user` SET num_dataset_stars = num_dataset_stars + 1 WHERE id = ?", userID); err != nil { | |||
return err | |||
} | |||
} else { | |||
if !isDatasetStaring(sess, userID, datasetID) { | |||
return nil | |||
} | |||
if _, err := sess.Delete(&DatasetStar{0, userID, datasetID, 0}); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `dataset` SET num_stars = num_stars - 1 WHERE id = ?", datasetID); err != nil { | |||
return err | |||
} | |||
if _, err := sess.Exec("UPDATE `user` SET num_dataset_stars = num_dataset_stars - 1 WHERE id = ?", userID); err != nil { | |||
return err | |||
} | |||
} | |||
return sess.Commit() | |||
} | |||
func IsDatasetStaringByRepoId(userID, repoID int64) bool { | |||
dataset, _ := GetDatasetByRepo(&Repository{ID: repoID}) | |||
if dataset == nil { | |||
return false | |||
} | |||
return isDatasetStaring(x, userID, dataset.ID) | |||
} | |||
func IsDatasetStaring(userID, datasetID int64) bool { | |||
return isDatasetStaring(x, userID, datasetID) | |||
} | |||
func isDatasetStaring(e Engine, userID, datasetID int64) bool { | |||
has, _ := e.Get(&DatasetStar{0, userID, datasetID, 0}) | |||
return has | |||
} | |||
func GetDatasetIdsStarByUser(userID int64) []int64 { | |||
var datasets []int64 | |||
_ = x.Table("dataset_star").Where("uid=?", userID). | |||
Cols("dataset_star.dataset_id").Find(&datasets) | |||
return datasets | |||
} |
@@ -0,0 +1,203 @@ | |||
DELETE FROM public.dataset_es; | |||
DROP FOREIGN TABLE public.dataset_es; | |||
DROP TRIGGER IF EXISTS es_insert_dataset on public.dataset; | |||
DROP FUNCTION public.insert_dataset_data(); | |||
DROP TRIGGER IF EXISTS es_udpate_dataset_file_name on public.attachment; | |||
DROP FUNCTION public.udpate_dataset_file_name; | |||
DROP TRIGGER IF EXISTS es_update_dataset on public.dataset; | |||
DROP FUNCTION public.update_dataset; | |||
DROP TRIGGER IF EXISTS es_delete_dataset on public.dataset; | |||
DROP FUNCTION public.delete_dataset; | |||
CREATE FOREIGN TABLE public.dataset_es | |||
( | |||
id bigint NOT NULL, | |||
title character varying(255), | |||
status integer, | |||
category character varying(255), | |||
description text, | |||
download_times bigint, | |||
license character varying(255), | |||
task character varying(255), | |||
release_id bigint, | |||
user_id bigint, | |||
repo_id bigint, | |||
created_unix bigint, | |||
updated_unix bigint, | |||
file_name text, | |||
file_desc text | |||
)SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'dataset-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
DELETE FROM public.dataset_es; | |||
INSERT INTO public.dataset_es( | |||
id, | |||
title, | |||
status, | |||
category, | |||
description, | |||
download_times, | |||
license, task, | |||
release_id, | |||
user_id, | |||
repo_id, | |||
created_unix, | |||
updated_unix, | |||
file_name, | |||
file_desc | |||
) | |||
SELECT | |||
b.id, | |||
b.title, | |||
b.status, | |||
b.category, | |||
b.description, | |||
b.download_times, | |||
b.license, | |||
b.task, | |||
b.release_id, | |||
b.user_id, | |||
b.repo_id, | |||
b.created_unix, | |||
b.updated_unix, | |||
(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment a where a.dataset_id=b.id and a.is_private=false), | |||
(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment a where a.dataset_id=b.id and a.is_private=false) | |||
FROM public.dataset b,public.repository c where b.repo_id=c.id and c.is_private=false; | |||
DROP TRIGGER IF EXISTS es_insert_dataset on public.dataset; | |||
CREATE OR REPLACE FUNCTION public.insert_dataset_data() RETURNS trigger AS | |||
$def$ | |||
DECLARE | |||
privateValue boolean=false; | |||
BEGIN | |||
select into privateValue is_private from public.repository where id=NEW.repo_id; | |||
if not privateValue then | |||
INSERT INTO public.dataset_es( | |||
id, | |||
title, | |||
status, | |||
category, | |||
description, | |||
download_times, | |||
license, | |||
task, | |||
release_id, | |||
user_id, | |||
repo_id, | |||
created_unix, | |||
updated_unix) | |||
VALUES ( | |||
NEW.id, | |||
NEW.title, | |||
NEW.status, | |||
NEW.category, | |||
NEW.description, | |||
NEW.download_times, | |||
NEW.license, | |||
NEW.task, | |||
NEW.release_id, | |||
NEW.user_id, | |||
NEW.repo_id, | |||
NEW.created_unix, | |||
NEW.updated_unix | |||
); | |||
end if; | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_insert_dataset | |||
AFTER INSERT ON public.dataset | |||
FOR EACH ROW EXECUTE PROCEDURE insert_dataset_data(); | |||
ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_insert_dataset; | |||
DROP TRIGGER IF EXISTS es_udpate_dataset_file_name on public.attachment; | |||
CREATE OR REPLACE FUNCTION public.udpate_dataset_file_name() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if (TG_OP = 'UPDATE') then | |||
update public.dataset_es SET file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.dataset_id and is_private=false) where id=NEW.dataset_id; | |||
elsif (TG_OP = 'INSERT') then | |||
update public.dataset_es SET file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.dataset_id and is_private=false) where id=NEW.dataset_id; | |||
elsif (TG_OP = 'DELETE') then | |||
update public.dataset_es SET file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=OLD.dataset_id and is_private=false) where id=OLD.dataset_id; | |||
update public.dataset_es SET file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=OLD.dataset_id and is_private=false) where id=OLD.dataset_id; | |||
end if; | |||
return NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_udpate_dataset_file_name | |||
AFTER INSERT OR UPDATE OR DELETE ON public.attachment | |||
FOR EACH ROW EXECUTE PROCEDURE udpate_dataset_file_name(); | |||
ALTER TABLE public.attachment ENABLE ALWAYS TRIGGER es_udpate_dataset_file_name; | |||
DROP TRIGGER IF EXISTS es_update_dataset on public.dataset; | |||
CREATE OR REPLACE FUNCTION public.update_dataset() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if (NEW.status=0) then | |||
delete from public.dataset_es where id=NEW.id; | |||
elsif (NEW.status=1) then | |||
UPDATE public.dataset_es | |||
SET description=NEW.description, | |||
title=NEW.title, | |||
category=NEW.category, | |||
task=NEW.task, | |||
download_times=NEW.download_times, | |||
updated_unix=NEW.updated_unix, | |||
file_name=(select array_to_string(array_agg(name order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false), | |||
file_desc=(select array_to_string(array_agg(description order by created_unix desc),'-#,#-') from public.attachment where dataset_id=NEW.id and is_private=false) | |||
where id=NEW.id; | |||
end if; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_update_dataset | |||
AFTER UPDATE ON public.dataset | |||
FOR EACH ROW EXECUTE PROCEDURE update_dataset(); | |||
ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_update_dataset; | |||
DROP TRIGGER IF EXISTS es_delete_dataset on public.dataset; | |||
CREATE OR REPLACE FUNCTION public.delete_dataset() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
DELETE FROM public.dataset_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_delete_dataset | |||
AFTER DELETE ON public.dataset | |||
FOR EACH ROW EXECUTE PROCEDURE delete_dataset(); | |||
ALTER TABLE public.dataset ENABLE ALWAYS TRIGGER es_delete_dataset; |
@@ -0,0 +1,227 @@ | |||
delete from public.issue_es; | |||
DROP FOREIGN TABLE public.issue_es; | |||
DROP TRIGGER IF EXISTS es_insert_issue on public.issue; | |||
DROP FUNCTION public.insert_issue_data; | |||
DROP TRIGGER IF EXISTS es_udpate_issue_comment on public.comment; | |||
DROP FUNCTION udpate_issue_comment; | |||
DROP TRIGGER IF EXISTS es_update_issue on public.issue; | |||
DROP FUNCTION public.update_issue; | |||
DROP TRIGGER IF EXISTS es_delete_issue on public.issue; | |||
DROP FUNCTION public.delete_issue; | |||
CREATE FOREIGN TABLE public.issue_es | |||
( | |||
id bigint NOT NULL, | |||
repo_id bigint, | |||
index bigint, | |||
poster_id bigint, | |||
original_author character varying(255), | |||
original_author_id bigint, | |||
name character varying(255) , | |||
content text, | |||
comment text, | |||
milestone_id bigint, | |||
priority integer, | |||
is_closed boolean, | |||
is_pull boolean, | |||
pr_id bigint, | |||
num_comments integer, | |||
ref character varying(255), | |||
deadline_unix bigint, | |||
created_unix bigint, | |||
updated_unix bigint, | |||
closed_unix bigint, | |||
is_locked boolean NOT NULL, | |||
amount bigint, | |||
is_transformed boolean NOT NULL | |||
)SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'issue-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
delete from public.issue_es; | |||
INSERT INTO public.issue_es( | |||
id, | |||
repo_id, | |||
index, | |||
poster_id, | |||
original_author, | |||
original_author_id, | |||
name, | |||
content, | |||
milestone_id, | |||
priority, | |||
is_closed, | |||
is_pull, | |||
num_comments, | |||
ref, | |||
deadline_unix, | |||
created_unix, | |||
updated_unix, | |||
closed_unix, | |||
is_locked, | |||
amount, | |||
is_transformed,comment,pr_id) | |||
SELECT | |||
b.id, | |||
b.repo_id, | |||
b.index, | |||
b.poster_id, | |||
b.original_author, | |||
b.original_author_id, | |||
b.name, | |||
b.content, | |||
b.milestone_id, | |||
b.priority, | |||
b.is_closed, | |||
b.is_pull, | |||
b.num_comments, | |||
b.ref, | |||
b.deadline_unix, | |||
b.created_unix, | |||
b.updated_unix, | |||
b.closed_unix, | |||
b.is_locked, | |||
b.amount, | |||
b.is_transformed, | |||
(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment a where a.issue_id=b.id), | |||
(select id from public.pull_request d where b.id=d.issue_id and b.is_pull=true) | |||
FROM public.issue b,public.repository c where b.repo_id=c.id and c.is_private=false; | |||
CREATE OR REPLACE FUNCTION public.insert_issue_data() RETURNS trigger AS | |||
$def$ | |||
DECLARE | |||
privateValue boolean=false; | |||
BEGIN | |||
select into privateValue is_private from public.repository where id=NEW.repo_id; | |||
if not privateValue then | |||
INSERT INTO public.issue_es( | |||
id, | |||
repo_id, | |||
index, | |||
poster_id, | |||
original_author, | |||
original_author_id, | |||
name, | |||
content, | |||
milestone_id, | |||
priority, | |||
is_closed, | |||
is_pull, | |||
num_comments, | |||
ref, | |||
deadline_unix, | |||
created_unix, | |||
updated_unix, | |||
closed_unix, | |||
is_locked, | |||
amount, | |||
is_transformed) | |||
VALUES ( | |||
NEW.id, | |||
NEW.repo_id, | |||
NEW.index, | |||
NEW.poster_id, | |||
NEW.original_author, | |||
NEW.original_author_id, | |||
NEW.name, | |||
NEW.content, | |||
NEW.milestone_id, | |||
NEW.priority, | |||
NEW.is_closed, | |||
NEW.is_pull, | |||
NEW.num_comments, | |||
NEW.ref, | |||
NEW.deadline_unix, | |||
NEW.created_unix, | |||
NEW.updated_unix, | |||
NEW.closed_unix, | |||
NEW.is_locked, | |||
NEW.amount, | |||
NEW.is_transformed | |||
); | |||
end if; | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_insert_issue on public.issue; | |||
CREATE TRIGGER es_insert_issue | |||
AFTER INSERT ON public.issue | |||
FOR EACH ROW EXECUTE PROCEDURE insert_issue_data(); | |||
ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_insert_issue; | |||
CREATE OR REPLACE FUNCTION public.udpate_issue_comment() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if (TG_OP = 'DELETE') then | |||
update public.issue_es SET comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=OLD.issue_id) where id=OLD.issue_id; | |||
elsif (TG_OP = 'UPDATE') then | |||
update public.issue_es SET comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=NEW.issue_id) where id=NEW.issue_id; | |||
end if; | |||
return null; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_udpate_issue_comment on public.comment; | |||
CREATE TRIGGER es_udpate_issue_comment | |||
AFTER DELETE OR UPDATE ON public.comment | |||
FOR EACH ROW EXECUTE PROCEDURE udpate_issue_comment(); | |||
ALTER TABLE public.comment ENABLE ALWAYS TRIGGER es_udpate_issue_comment; | |||
CREATE OR REPLACE FUNCTION public.update_issue() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
UPDATE public.issue_es | |||
SET content=NEW.content, | |||
name=NEW.name, | |||
is_closed=NEW.is_closed, | |||
num_comments=NEW.num_comments, | |||
updated_unix=NEW.updated_unix, | |||
comment=(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment where issue_id=NEW.id) | |||
where id=NEW.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_update_issue on public.issue; | |||
CREATE TRIGGER es_update_issue | |||
AFTER UPDATE ON public.issue | |||
FOR EACH ROW EXECUTE PROCEDURE update_issue(); | |||
ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_update_issue; | |||
CREATE OR REPLACE FUNCTION public.delete_issue() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
DELETE FROM public.issue_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
DROP TRIGGER IF EXISTS es_delete_issue on public.issue; | |||
CREATE TRIGGER es_delete_issue | |||
AFTER DELETE ON public.issue | |||
FOR EACH ROW EXECUTE PROCEDURE delete_issue(); | |||
ALTER TABLE public.issue ENABLE ALWAYS TRIGGER es_delete_issue; |
@@ -0,0 +1,549 @@ | |||
-- 要处理项目从私有变为公有,并且从公有变成私有的情况 | |||
DELETE FROM public.repository_es; | |||
DROP FOREIGN table if exists public.repository_es; | |||
DROP TRIGGER IF EXISTS es_insert_repository on public.repository; | |||
DROP FUNCTION public.insert_repository_data; | |||
DROP TRIGGER IF EXISTS es_update_repository on public.repository; | |||
DROP FUNCTION public.update_repository; | |||
DROP TRIGGER IF EXISTS es_delete_repository on public.repository; | |||
DROP FUNCTION public.delete_repository; | |||
DROP TRIGGER IF EXISTS es_udpate_repository_lang on public.language_stat; | |||
DROP FUNCTION public.udpate_repository_lang; | |||
CREATE FOREIGN TABLE public.repository_es ( | |||
id bigint NOT NULL, | |||
owner_id bigint, | |||
owner_name character varying(255), | |||
lower_name character varying(255) NOT NULL, | |||
name character varying(255) NOT NULL, | |||
description text, | |||
website character varying(2048), | |||
original_service_type integer, | |||
original_url character varying(2048), | |||
default_branch character varying(255), | |||
num_watches integer, | |||
num_stars integer, | |||
num_forks integer, | |||
num_issues integer, | |||
num_closed_issues integer, | |||
num_pulls integer, | |||
num_closed_pulls integer, | |||
num_milestones integer DEFAULT 0 NOT NULL, | |||
num_closed_milestones integer DEFAULT 0 NOT NULL, | |||
is_private boolean, | |||
is_empty boolean, | |||
is_archived boolean, | |||
is_mirror boolean, | |||
status integer DEFAULT 0 NOT NULL, | |||
is_fork boolean DEFAULT false NOT NULL, | |||
fork_id bigint, | |||
is_template boolean DEFAULT false NOT NULL, | |||
template_id bigint, | |||
size bigint DEFAULT 0 NOT NULL, | |||
is_fsck_enabled boolean DEFAULT true NOT NULL, | |||
close_issues_via_commit_in_any_branch boolean DEFAULT false NOT NULL, | |||
topics text, | |||
avatar character varying(64), | |||
created_unix bigint, | |||
updated_unix bigint, | |||
contract_address character varying(255), | |||
block_chain_status integer DEFAULT 0 NOT NULL, | |||
balance character varying(255) DEFAULT '0'::character varying NOT NULL, | |||
clone_cnt bigint DEFAULT 0 NOT NULL, | |||
license character varying(100), | |||
download_cnt bigint DEFAULT 0 NOT NULL, | |||
num_commit bigint DEFAULT 0 NOT NULL, | |||
git_clone_cnt bigint DEFAULT 0 NOT NULL, | |||
creator_id bigint NOT NULL DEFAULT 0, | |||
repo_type integer NOT NULL DEFAULT 0, | |||
lang character varying(2048), | |||
alias character varying(255), | |||
lower_alias character varying(255) | |||
) SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'repository-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
delete from public.repository_es; | |||
INSERT INTO public.repository_es (id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
lang, | |||
alias, | |||
lower_alias | |||
) | |||
SELECT | |||
id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat a where a.repo_id=b.id), | |||
alias, | |||
lower_alias | |||
FROM public.repository b where b.is_private=false; | |||
DROP TRIGGER IF EXISTS es_insert_repository on public.repository; | |||
CREATE OR REPLACE FUNCTION public.insert_repository_data() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if not NEW.is_private then | |||
INSERT INTO public.repository_es (id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
alias, | |||
lower_alias) VALUES | |||
(NEW.id, | |||
NEW.owner_id, | |||
NEW.owner_name, | |||
NEW.lower_name, | |||
NEW.name, | |||
NEW.description, | |||
NEW.website, | |||
NEW.original_service_type, | |||
NEW.original_url, | |||
NEW.default_branch, | |||
NEW.num_watches, | |||
NEW.num_stars, | |||
NEW.num_forks, | |||
NEW.num_issues, | |||
NEW.num_closed_issues, | |||
NEW.num_pulls, | |||
NEW.num_closed_pulls, | |||
NEW.num_milestones, | |||
NEW.num_closed_milestones, | |||
NEW.is_private, | |||
NEW.is_empty, | |||
NEW.is_archived, | |||
NEW.is_mirror, | |||
NEW.status, | |||
NEW.is_fork, | |||
NEW.fork_id, | |||
NEW.is_template, | |||
NEW.template_id, | |||
NEW.size, | |||
NEW.is_fsck_enabled, | |||
NEW.close_issues_via_commit_in_any_branch, | |||
NEW.topics, | |||
NEW.avatar, | |||
NEW.created_unix, | |||
NEW.updated_unix, | |||
NEW.contract_address, | |||
NEW.block_chain_status, | |||
NEW.balance, | |||
NEW.clone_cnt, | |||
NEW.num_commit, | |||
NEW.git_clone_cnt, | |||
NEW.creator_id, | |||
NEW.repo_type, | |||
NEW.alias, | |||
NEW.lower_alias); | |||
end if; | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_insert_repository | |||
AFTER INSERT ON public.repository | |||
FOR EACH ROW EXECUTE PROCEDURE insert_repository_data(); | |||
ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_insert_repository; | |||
DROP TRIGGER IF EXISTS es_update_repository on public.repository; | |||
CREATE OR REPLACE FUNCTION public.update_repository() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
if OLD.is_private != NEW.is_private then | |||
if OLD.is_private and not NEW.is_private then | |||
--insert | |||
INSERT INTO public.repository_es (id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
lang, | |||
alias, | |||
lower_alias) | |||
SELECT | |||
id, | |||
owner_id, | |||
owner_name, | |||
lower_name, | |||
name, | |||
description, | |||
website, | |||
original_service_type, | |||
original_url, | |||
default_branch, | |||
num_watches, | |||
num_stars, | |||
num_forks, | |||
num_issues, | |||
num_closed_issues, | |||
num_pulls, | |||
num_closed_pulls, | |||
num_milestones, | |||
num_closed_milestones, | |||
is_private, | |||
is_empty, | |||
is_archived, | |||
is_mirror, | |||
status, | |||
is_fork, | |||
fork_id, | |||
is_template, | |||
template_id, | |||
size, | |||
is_fsck_enabled, | |||
close_issues_via_commit_in_any_branch, | |||
topics, | |||
avatar, | |||
created_unix, | |||
updated_unix, | |||
contract_address, | |||
block_chain_status, | |||
balance, | |||
clone_cnt, | |||
num_commit, | |||
git_clone_cnt, | |||
creator_id, | |||
repo_type, | |||
(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat a where a.repo_id=b.id), | |||
alias, | |||
lower_alias | |||
FROM public.repository b where b.id=NEW.id; | |||
INSERT INTO public.dataset_es( | |||
id, | |||
title, | |||
status, | |||
category, | |||
description, | |||
download_times, | |||
license, task, | |||
release_id, | |||
user_id, | |||
repo_id, | |||
created_unix, | |||
updated_unix,file_name) | |||
SELECT | |||
b.id, | |||
b.title, | |||
b.status, | |||
b.category, | |||
b.description, | |||
b.download_times, | |||
b.license, | |||
b.task, | |||
b.release_id, | |||
b.user_id, | |||
b.repo_id, | |||
b.created_unix, | |||
b.updated_unix,(select array_to_string(array_agg(name order by created_unix desc),',') from public.attachment a where a.dataset_id=b.id and a.is_private=false) | |||
FROM public.dataset b where b.repo_id=NEW.id; | |||
INSERT INTO public.issue_es( | |||
id, | |||
repo_id, | |||
index, | |||
poster_id, | |||
original_author, | |||
original_author_id, | |||
name, | |||
content, | |||
milestone_id, | |||
priority, | |||
is_closed, | |||
is_pull, | |||
num_comments, | |||
ref, | |||
deadline_unix, | |||
created_unix, | |||
updated_unix, | |||
closed_unix, | |||
is_locked, | |||
amount, | |||
is_transformed,comment,pr_id) | |||
SELECT | |||
b.id, | |||
b.repo_id, | |||
b.index, | |||
b.poster_id, | |||
b.original_author, | |||
b.original_author_id, | |||
b.name, | |||
b.content, | |||
b.milestone_id, | |||
b.priority, | |||
b.is_closed, | |||
b.is_pull, | |||
b.num_comments, | |||
b.ref, | |||
b.deadline_unix, | |||
b.created_unix, | |||
b.updated_unix, | |||
b.closed_unix, | |||
b.is_locked, | |||
b.amount, | |||
b.is_transformed, | |||
(select array_to_string(array_agg(content order by created_unix desc),',') from public.comment a where a.issue_id=b.id), | |||
(select id from public.pull_request d where d.issue_id=b.id) | |||
FROM public.issue b where b.repo_id=NEW.id; | |||
end if; | |||
if not OLD.is_private and NEW.is_private then | |||
delete from public.issue_es where repo_id=NEW.id; | |||
-- delete from public.dataset_es where repo_id=NEW.id; | |||
delete from public.repository_es where id=NEW.id; | |||
end if; | |||
end if; | |||
if not NEW.is_private then | |||
raise notice 'update repo,the updated_unix is %',NEW.updated_unix; | |||
update public.repository_es SET description=NEW.description, | |||
name=NEW.name, | |||
lower_name=NEW.lower_name, | |||
owner_name=NEW.owner_name, | |||
website=NEW.website, | |||
updated_unix=NEW.updated_unix, | |||
num_watches=NEW.num_watches, | |||
num_stars=NEW.num_stars, | |||
num_forks=NEW.num_forks, | |||
topics=NEW.topics, | |||
alias = NEW.alias, | |||
lower_alias = NEW.lower_alias, | |||
avatar=NEW.avatar | |||
where id=NEW.id; | |||
end if; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_update_repository | |||
AFTER UPDATE ON public.repository | |||
FOR EACH ROW EXECUTE PROCEDURE update_repository(); | |||
ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_update_repository; | |||
DROP TRIGGER IF EXISTS es_delete_repository on public.repository; | |||
CREATE OR REPLACE FUNCTION public.delete_repository() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
delete from public.issue_es where repo_id=OLD.id; | |||
delete from public.dataset_es where repo_id=OLD.id; | |||
DELETE FROM public.repository_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_delete_repository | |||
AFTER DELETE ON public.repository | |||
FOR EACH ROW EXECUTE PROCEDURE delete_repository(); | |||
ALTER TABLE public.repository ENABLE ALWAYS TRIGGER es_delete_repository; | |||
DROP TRIGGER IF EXISTS es_udpate_repository_lang on public.language_stat; | |||
CREATE OR REPLACE FUNCTION public.udpate_repository_lang() RETURNS trigger AS | |||
$def$ | |||
DECLARE | |||
privateValue bigint; | |||
BEGIN | |||
if (TG_OP = 'UPDATE') then | |||
select into privateValue updated_unix from public.repository where id=NEW.repo_id; | |||
update public.repository_es SET updated_unix=privateValue,lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||
elsif (TG_OP = 'INSERT') then | |||
select into privateValue updated_unix from public.repository where id=NEW.repo_id; | |||
update public.repository_es SET updated_unix=privateValue,lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||
elsif (TG_OP = 'DELETE') then | |||
if exists(select 1 from public.repository where id=OLD.repo_id) then | |||
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=OLD.repo_id) where id=OLD.repo_id; | |||
end if; | |||
end if; | |||
return NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_udpate_repository_lang | |||
AFTER INSERT OR UPDATE OR DELETE ON public.language_stat | |||
FOR EACH ROW EXECUTE PROCEDURE udpate_repository_lang(); | |||
ALTER TABLE public.language_stat ENABLE ALWAYS TRIGGER es_udpate_repository_lang; |
@@ -0,0 +1,317 @@ | |||
DELETE FROM public.user_es; | |||
DROP FOREIGN table if exists public.user_es; | |||
DROP TRIGGER IF EXISTS es_insert_user on public.user; | |||
DROP FUNCTION public.insert_user_data; | |||
DROP TRIGGER IF EXISTS es_update_user on public.user; | |||
DROP FUNCTION public.update_user; | |||
DROP TRIGGER IF EXISTS es_delete_user on public.user; | |||
DROP FUNCTION public.delete_user; | |||
CREATE FOREIGN TABLE public.user_es | |||
( | |||
id bigint NOT NULL , | |||
lower_name character varying(255) NULL, | |||
name character varying(255) NULL, | |||
full_name character varying(255), | |||
email character varying(255), | |||
keep_email_private boolean, | |||
email_notifications_preference character varying(20) , | |||
passwd character varying(255) , | |||
passwd_hash_algo character varying(255) , | |||
must_change_password boolean NOT NULL DEFAULT false, | |||
login_type integer, | |||
login_source bigint NOT NULL DEFAULT 0, | |||
login_name character varying(255) , | |||
type integer, | |||
location character varying(255), | |||
website character varying(255), | |||
rands character varying(10), | |||
salt character varying(10), | |||
language character varying(5), | |||
description character varying(255), | |||
created_unix bigint, | |||
updated_unix bigint, | |||
last_login_unix bigint, | |||
last_repo_visibility boolean, | |||
max_repo_creation integer, | |||
is_active boolean, | |||
is_admin boolean, | |||
is_restricted boolean NOT NULL DEFAULT false, | |||
allow_git_hook boolean, | |||
allow_import_local boolean, | |||
allow_create_organization boolean DEFAULT true, | |||
prohibit_login boolean NOT NULL DEFAULT false, | |||
avatar character varying(2048) , | |||
avatar_email character varying(255), | |||
use_custom_avatar boolean, | |||
num_followers integer, | |||
num_following integer NOT NULL DEFAULT 0, | |||
num_stars integer, | |||
num_repos integer, | |||
num_teams integer, | |||
num_members integer, | |||
visibility integer NOT NULL DEFAULT 0, | |||
repo_admin_change_team_access boolean NOT NULL DEFAULT false, | |||
diff_view_style character varying(255), | |||
theme character varying(255), | |||
token character varying(1024) , | |||
public_key character varying(255), | |||
private_key character varying(255), | |||
is_operator boolean NOT NULL DEFAULT false, | |||
num_dataset_stars integer NOT NULL DEFAULT 0 | |||
) SERVER multicorn_es | |||
OPTIONS | |||
( | |||
host '192.168.207.94', | |||
port '9200', | |||
index 'user-es-index', | |||
rowid_column 'id', | |||
default_sort '_id' | |||
) | |||
; | |||
delete from public.user_es; | |||
INSERT INTO public.user_es( | |||
id, | |||
lower_name, | |||
name, | |||
full_name, | |||
email, | |||
keep_email_private, | |||
email_notifications_preference, | |||
must_change_password, | |||
login_type, | |||
login_source, | |||
login_name, | |||
type, | |||
location, | |||
website, | |||
rands, | |||
language, | |||
description, | |||
created_unix, | |||
updated_unix, | |||
last_login_unix, | |||
last_repo_visibility, | |||
max_repo_creation, | |||
is_active, | |||
is_restricted, | |||
allow_git_hook, | |||
allow_import_local, | |||
allow_create_organization, | |||
prohibit_login, | |||
avatar, | |||
avatar_email, | |||
use_custom_avatar, | |||
num_followers, | |||
num_following, | |||
num_stars, | |||
num_repos, | |||
num_teams, | |||
num_members, | |||
visibility, | |||
repo_admin_change_team_access, | |||
diff_view_style, | |||
theme, | |||
is_operator, | |||
num_dataset_stars) | |||
SELECT | |||
id, | |||
lower_name, | |||
name, | |||
full_name, | |||
email, | |||
keep_email_private, | |||
email_notifications_preference, | |||
must_change_password, | |||
login_type, | |||
login_source, | |||
login_name, | |||
type, | |||
location, | |||
website, | |||
rands, | |||
language, | |||
description, | |||
created_unix, | |||
updated_unix, | |||
last_login_unix, | |||
last_repo_visibility, | |||
max_repo_creation, | |||
is_active, | |||
is_restricted, | |||
allow_git_hook, | |||
allow_import_local, | |||
allow_create_organization, | |||
prohibit_login, | |||
avatar, | |||
avatar_email, | |||
use_custom_avatar, | |||
num_followers, | |||
num_following, | |||
num_stars, | |||
num_repos, | |||
num_teams, | |||
num_members, | |||
visibility, | |||
repo_admin_change_team_access, | |||
diff_view_style, | |||
theme, | |||
is_operator, | |||
num_dataset_stars | |||
FROM public.user; | |||
DROP TRIGGER IF EXISTS es_insert_user on public.user; | |||
CREATE OR REPLACE FUNCTION public.insert_user_data() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
INSERT INTO public."user_es"( | |||
id, | |||
lower_name, | |||
name, | |||
full_name, | |||
email, | |||
keep_email_private, | |||
email_notifications_preference, | |||
must_change_password, | |||
login_type, | |||
login_source, | |||
login_name, | |||
type, | |||
location, | |||
website, | |||
rands, | |||
language, | |||
description, | |||
created_unix, | |||
updated_unix, | |||
last_login_unix, | |||
last_repo_visibility, | |||
max_repo_creation, | |||
is_active, | |||
is_restricted, | |||
allow_git_hook, | |||
allow_import_local, | |||
allow_create_organization, | |||
prohibit_login, | |||
avatar, | |||
avatar_email, | |||
use_custom_avatar, | |||
num_followers, | |||
num_following, | |||
num_stars, | |||
num_repos, | |||
num_teams, | |||
num_members, | |||
visibility, | |||
repo_admin_change_team_access, | |||
diff_view_style, | |||
theme, | |||
is_operator, | |||
num_dataset_stars) | |||
VALUES ( | |||
NEW.id, | |||
NEW.lower_name, | |||
NEW.name, | |||
NEW.full_name, | |||
NEW.email, | |||
NEW.keep_email_private, | |||
NEW.email_notifications_preference, | |||
NEW.must_change_password, | |||
NEW.login_type, | |||
NEW.login_source, | |||
NEW.login_name, | |||
NEW.type, | |||
NEW.location, | |||
NEW.website, | |||
NEW.rands, | |||
NEW.language, | |||
NEW.description, | |||
NEW.created_unix, | |||
NEW.updated_unix, | |||
NEW.last_login_unix, | |||
NEW.last_repo_visibility, | |||
NEW.max_repo_creation, | |||
NEW.is_active, | |||
NEW.is_restricted, | |||
NEW.allow_git_hook, | |||
NEW.allow_import_local, | |||
NEW.allow_create_organization, | |||
NEW.prohibit_login, | |||
NEW.avatar, | |||
NEW.avatar_email, | |||
NEW.use_custom_avatar, | |||
NEW.num_followers, | |||
NEW.num_following, | |||
NEW.num_stars, | |||
NEW.num_repos, | |||
NEW.num_teams, | |||
NEW.num_members, | |||
NEW.visibility, | |||
NEW.repo_admin_change_team_access, | |||
NEW.diff_view_style, | |||
NEW.theme, | |||
NEW.is_operator, | |||
NEW.num_dataset_stars | |||
); | |||
RETURN NEW; | |||
END; | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_insert_user | |||
AFTER INSERT ON public.user | |||
FOR EACH ROW EXECUTE PROCEDURE insert_user_data(); | |||
ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_insert_user; | |||
DROP TRIGGER IF EXISTS es_update_user on public.user; | |||
CREATE OR REPLACE FUNCTION public.update_user() RETURNS trigger AS | |||
$def$ | |||
BEGIN | |||
UPDATE public.user_es | |||
SET description=NEW.description, | |||
name=NEW.name, | |||
full_name=NEW.full_name, | |||
location=NEW.location, | |||
website=NEW.website, | |||
email=NEW.email, | |||
num_dataset_stars=NEW.num_dataset_stars, | |||
updated_unix=NEW.updated_unix | |||
where id=NEW.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_update_user | |||
AFTER UPDATE ON public.user | |||
FOR EACH ROW EXECUTE PROCEDURE update_user(); | |||
ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_update_user; | |||
DROP TRIGGER IF EXISTS es_delete_user on public.user; | |||
CREATE OR REPLACE FUNCTION public.delete_user() RETURNS trigger AS | |||
$def$ | |||
declare | |||
BEGIN | |||
DELETE FROM public.user_es where id=OLD.id; | |||
return new; | |||
END | |||
$def$ | |||
LANGUAGE plpgsql; | |||
CREATE TRIGGER es_delete_user | |||
AFTER DELETE ON public.user | |||
FOR EACH ROW EXECUTE PROCEDURE delete_user(); | |||
ALTER TABLE public.user ENABLE ALWAYS TRIGGER es_delete_user; |
@@ -2012,3 +2012,27 @@ func IsErrTagNotExist(err error) bool { | |||
_, ok := err.(ErrTagNotExist) | |||
return ok | |||
} | |||
type ErrRecordNotExist struct { | |||
} | |||
func IsErrRecordNotExist(err error) bool { | |||
_, ok := err.(ErrRecordNotExist) | |||
return ok | |||
} | |||
func (err ErrRecordNotExist) Error() string { | |||
return fmt.Sprintf("record not exist in database") | |||
} | |||
type ErrInsufficientPointsBalance struct { | |||
} | |||
func IsErrInsufficientPointsBalance(err error) bool { | |||
_, ok := err.(ErrInsufficientPointsBalance) | |||
return ok | |||
} | |||
func (err ErrInsufficientPointsBalance) Error() string { | |||
return fmt.Sprintf("Insufficient points balance") | |||
} |
@@ -13,11 +13,6 @@ const ( | |||
FileUploaded | |||
) | |||
const ( | |||
TypeCloudBrainOne int = iota | |||
TypeCloudBrainTwo | |||
) | |||
type FileChunk struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
UUID string `xorm:"uuid UNIQUE"` | |||
@@ -33,6 +28,23 @@ type FileChunk struct { | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
} | |||
type ModelFileChunk struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
UUID string `xorm:"INDEX"` | |||
Md5 string `xorm:"INDEX"` | |||
ModelUUID string `xorm:"INDEX"` | |||
ObjectName string `xorm:"DEFAULT ''"` | |||
IsUploaded int `xorm:"DEFAULT 0"` // not uploaded: 0, uploaded: 1 | |||
UploadID string `xorm:"UNIQUE"` //minio upload id | |||
TotalChunks int | |||
Size int64 | |||
UserID int64 `xorm:"INDEX"` | |||
Type int `xorm:"INDEX DEFAULT 0"` | |||
CompletedParts []string `xorm:"DEFAULT ''"` // chunkNumber+etag eg: ,1-asqwewqe21312312.2-123hjkas | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
} | |||
// GetFileChunkByMD5 returns fileChunk by given id | |||
func GetFileChunkByMD5(md5 string) (*FileChunk, error) { | |||
return getFileChunkByMD5(x, md5) | |||
@@ -54,6 +66,21 @@ func GetFileChunkByMD5AndUser(md5 string, userID int64, typeCloudBrain int) (*Fi | |||
return getFileChunkByMD5AndUser(x, md5, userID, typeCloudBrain) | |||
} | |||
func GetModelFileChunkByMD5AndUser(md5 string, userID int64, typeCloudBrain int, uuid string) (*ModelFileChunk, error) { | |||
return getModelFileChunkByMD5AndUser(x, md5, userID, typeCloudBrain, uuid) | |||
} | |||
func getModelFileChunkByMD5AndUser(e Engine, md5 string, userID int64, typeCloudBrain int, uuid string) (*ModelFileChunk, error) { | |||
fileChunk := new(ModelFileChunk) | |||
if has, err := e.Where("md5 = ? and user_id = ? and type = ? and model_uuid= ?", md5, userID, typeCloudBrain, uuid).Get(fileChunk); err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrFileChunkNotExist{md5, ""} | |||
} | |||
return fileChunk, nil | |||
} | |||
func getFileChunkByMD5AndUser(e Engine, md5 string, userID int64, typeCloudBrain int) (*FileChunk, error) { | |||
fileChunk := new(FileChunk) | |||
@@ -81,6 +108,21 @@ func getFileChunkByUUID(e Engine, uuid string) (*FileChunk, error) { | |||
return fileChunk, nil | |||
} | |||
func GetModelFileChunkByUUID(uuid string) (*ModelFileChunk, error) { | |||
return getModelFileChunkByUUID(x, uuid) | |||
} | |||
func getModelFileChunkByUUID(e Engine, uuid string) (*ModelFileChunk, error) { | |||
fileChunk := new(ModelFileChunk) | |||
if has, err := e.Where("uuid = ?", uuid).Get(fileChunk); err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrFileChunkNotExist{"", uuid} | |||
} | |||
return fileChunk, nil | |||
} | |||
// InsertFileChunk insert a record into file_chunk. | |||
func InsertFileChunk(fileChunk *FileChunk) (_ *FileChunk, err error) { | |||
if _, err := x.Insert(fileChunk); err != nil { | |||
@@ -90,6 +132,14 @@ func InsertFileChunk(fileChunk *FileChunk) (_ *FileChunk, err error) { | |||
return fileChunk, nil | |||
} | |||
// InsertFileChunk insert a record into file_chunk. | |||
func InsertModelFileChunk(fileChunk *ModelFileChunk) (_ *ModelFileChunk, err error) { | |||
if _, err := x.Insert(fileChunk); err != nil { | |||
return nil, err | |||
} | |||
return fileChunk, nil | |||
} | |||
func DeleteFileChunkById(uuid string) (*FileChunk, error) { | |||
return deleteFileChunkById(x, uuid) | |||
} | |||
@@ -111,6 +161,17 @@ func deleteFileChunkById(e Engine, uuid string) (*FileChunk, error) { | |||
} | |||
} | |||
func UpdateModelFileChunk(fileChunk *ModelFileChunk) error { | |||
return updateModelFileChunk(x, fileChunk) | |||
} | |||
func updateModelFileChunk(e Engine, fileChunk *ModelFileChunk) error { | |||
var sess *xorm.Session | |||
sess = e.Where("uuid = ?", fileChunk.UUID) | |||
_, err := sess.Cols("is_uploaded").Update(fileChunk) | |||
return err | |||
} | |||
// UpdateFileChunk updates the given file_chunk in database | |||
func UpdateFileChunk(fileChunk *FileChunk) error { | |||
return updateFileChunk(x, fileChunk) | |||
@@ -132,3 +193,12 @@ func deleteFileChunk(e Engine, fileChunk *FileChunk) error { | |||
_, err := e.ID(fileChunk.ID).Delete(fileChunk) | |||
return err | |||
} | |||
func DeleteModelFileChunk(fileChunk *ModelFileChunk) error { | |||
return deleteModelFileChunk(x, fileChunk) | |||
} | |||
func deleteModelFileChunk(e Engine, fileChunk *ModelFileChunk) error { | |||
_, err := e.ID(fileChunk.ID).Delete(fileChunk) | |||
return err | |||
} |
@@ -11,6 +11,13 @@ func keysInt64(m map[int64]struct{}) []int64 { | |||
} | |||
return keys | |||
} | |||
func keysString(m map[string]struct{}) []string { | |||
var keys = make([]string, 0, len(m)) | |||
for k := range m { | |||
keys = append(keys, k) | |||
} | |||
return keys | |||
} | |||
func valuesRepository(m map[int64]*Repository) []*Repository { | |||
var values = make([]*Repository, 0, len(m)) | |||
@@ -27,3 +34,18 @@ func valuesUser(m map[int64]*User) []*User { | |||
} | |||
return values | |||
} | |||
func valuesComment(m map[int64]*Comment) []*Comment { | |||
var values = make([]*Comment, 0, len(m)) | |||
for _, v := range m { | |||
values = append(values, v) | |||
} | |||
return values | |||
} | |||
func valuesCloudbrain(m map[int64]*Cloudbrain) []*Cloudbrain { | |||
var values = make([]*Cloudbrain, 0, len(m)) | |||
for _, v := range m { | |||
values = append(values, v) | |||
} | |||
return values | |||
} |
@@ -12,15 +12,19 @@ import ( | |||
// env keys for git hooks need | |||
const ( | |||
EnvRepoName = "GITEA_REPO_NAME" | |||
EnvRepoUsername = "GITEA_REPO_USER_NAME" | |||
EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" | |||
EnvPusherName = "GITEA_PUSHER_NAME" | |||
EnvPusherEmail = "GITEA_PUSHER_EMAIL" | |||
EnvPusherID = "GITEA_PUSHER_ID" | |||
EnvKeyID = "GITEA_KEY_ID" | |||
EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" | |||
EnvIsInternal = "GITEA_INTERNAL_PUSH" | |||
EnvRepoName = "GITEA_REPO_NAME" | |||
EnvRepoUsername = "GITEA_REPO_USER_NAME" | |||
EnvRepoIsWiki = "GITEA_REPO_IS_WIKI" | |||
EnvPusherName = "GITEA_PUSHER_NAME" | |||
EnvPusherEmail = "GITEA_PUSHER_EMAIL" | |||
EnvPusherID = "GITEA_PUSHER_ID" | |||
EnvKeyID = "GITEA_KEY_ID" | |||
EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY" | |||
EnvIsInternal = "GITEA_INTERNAL_PUSH" | |||
EnvRepoSize = "REPO_CURRENT_SIZE" | |||
EnvRepoMaxFileSize = "REPO_MAX_FILE_SIZE" | |||
EnvRepoMaxSize = "REPO_MAX_SIZE" | |||
EnvPushSizeCheckFlag = "PUSH_SIZE_CHECK_FLAG" | |||
) | |||
// InternalPushingEnvironment returns an os environment to switch off hooks on push | |||
@@ -69,7 +69,8 @@ type Issue struct { | |||
//block_chain | |||
Amount int64 | |||
IsTransformed bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
IsTransformed bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
StayTop int64 `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
var ( | |||
@@ -775,6 +776,54 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) { | |||
return sess.Commit() | |||
} | |||
func (issue *Issue) ChangeStayTop(doer *User, stayTop int64) (err error) { | |||
issue.StayTop = stayTop | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err = sess.Begin(); err != nil { | |||
return err | |||
} | |||
if err = updateIssueCols(sess, issue, "stay_top"); err != nil { | |||
return fmt.Errorf("UpdateIssueCols,stayTop: %v", err) | |||
} | |||
return sess.Commit() | |||
} | |||
// ChangeRef changes issue ref, as the given user. | |||
func (issue *Issue) ChangeRef(doer *User, newRef string) (err error) { | |||
oldRef := issue.Ref | |||
issue.Ref = newRef | |||
if oldRef == newRef { | |||
return nil | |||
} | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err = sess.Begin(); err != nil { | |||
return err | |||
} | |||
if err = updateIssueCols(sess, issue, "ref"); err != nil { | |||
sess.Rollback() | |||
return fmt.Errorf("UpdateIssueCols: %v", err) | |||
} | |||
var opts = &CreateCommentOptions{ | |||
Type: CommentTypeRef, | |||
Doer: doer, | |||
Repo: issue.Repo, | |||
Issue: issue, | |||
OldRef: oldRef, | |||
NewRef: newRef, | |||
} | |||
if _, err = createComment(sess, opts); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
// GetTasks returns the amount of tasks in the issues content | |||
func (issue *Issue) GetTasks() int { | |||
return len(issueTasksPat.FindAllStringIndex(issue.Content, -1)) | |||
@@ -1081,6 +1130,7 @@ type IssuesOptions struct { | |||
// sortIssuesSession sort an issues-related session based on the provided | |||
// sortType string | |||
func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64) { | |||
sess.Desc("issue.stay_top") | |||
switch sortType { | |||
case "oldest": | |||
sess.Asc("issue.created_unix") | |||
@@ -1931,3 +1981,14 @@ func UpdateReactionsMigrationsByType(gitServiceType structs.GitServiceType, orig | |||
}) | |||
return err | |||
} | |||
func GetMaxStayTop(repoId int64) int64 { | |||
re := new(Issue) | |||
isExist, err := x.Table(new(Issue)).Where("repo_id="+fmt.Sprint(repoId)).Desc("stay_top").Limit(1, 0).Get(re) | |||
if err == nil { | |||
if isExist { | |||
return re.StayTop + 1 | |||
} | |||
} | |||
return 1 | |||
} |
@@ -90,6 +90,8 @@ const ( | |||
CommentTypeReviewRequest | |||
// merge pull request | |||
CommentTypeMergePull | |||
// Ref changed | |||
CommentTypeRef | |||
) | |||
// CommentTag defines comment tag type | |||
@@ -0,0 +1,184 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"xorm.io/builder" | |||
) | |||
type LimitType string | |||
const ( | |||
LimitTypeTask LimitType = "TASK" | |||
LimitTypeRewardPoint LimitType = "REWARD_POINT" | |||
) | |||
func (l LimitType) Name() string { | |||
switch l { | |||
case LimitTypeTask: | |||
return "TASK" | |||
case LimitTypeRewardPoint: | |||
return "REWARD_POINT" | |||
default: | |||
return "" | |||
} | |||
} | |||
type LimitScope string | |||
const ( | |||
LimitScopeAllUsers LimitScope = "ALL_USERS" | |||
LimitScopeSingleUser LimitScope = "SINGLE_USER" | |||
) | |||
func (l LimitScope) Name() string { | |||
switch l { | |||
case LimitScopeAllUsers: | |||
return "ALL_USERS" | |||
case LimitScopeSingleUser: | |||
return "SINGLE_USER" | |||
default: | |||
return "" | |||
} | |||
} | |||
type LimiterRejectPolicy string | |||
const ( | |||
JustReject LimiterRejectPolicy = "JUST_REJECT" | |||
PermittedOnce LimiterRejectPolicy = "PERMITTED_ONCE" | |||
FillUp LimiterRejectPolicy = "FillUp" | |||
) | |||
type LimitConfig struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
Title string | |||
RefreshRate string `xorm:"NOT NULL"` | |||
Scope string `xorm:"NOT NULL"` | |||
LimitNum int64 `xorm:"NOT NULL"` | |||
LimitCode string | |||
LimitType string `xorm:"NOT NULL"` | |||
RelatedId int64 `xorm:"INDEX"` | |||
CreatorId int64 `xorm:"NOT NULL"` | |||
CreatorName string | |||
DeleterId int64 | |||
DeleterName string | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
DeletedAt timeutil.TimeStamp `xorm:"deleted"` | |||
} | |||
type LimitConfigQueryOpts struct { | |||
RefreshRate string | |||
Scope LimitScope | |||
LimitCode string | |||
LimitType LimitType | |||
} | |||
type LimitConfigVO struct { | |||
ID int64 | |||
Title string | |||
RefreshRate string | |||
Scope string | |||
LimitNum int64 | |||
LimitCode string | |||
LimitType string | |||
Creator string | |||
CreatedUnix timeutil.TimeStamp | |||
} | |||
func (l *LimitConfig) ToLimitConfigVO() *LimitConfigVO { | |||
return &LimitConfigVO{ | |||
ID: l.ID, | |||
Title: l.Title, | |||
RefreshRate: l.RefreshRate, | |||
Scope: l.Scope, | |||
LimitNum: l.LimitNum, | |||
LimitCode: l.LimitCode, | |||
LimitType: l.LimitType, | |||
Creator: l.CreatorName, | |||
CreatedUnix: l.CreatedUnix, | |||
} | |||
} | |||
func GetLimitConfigByLimitType(limitType LimitType) ([]LimitConfig, error) { | |||
r := make([]LimitConfig, 0) | |||
err := x.Where(" limit_type = ?", limitType.Name()).Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} else if len(r) == 0 { | |||
return nil, ErrRecordNotExist{} | |||
} | |||
return r, nil | |||
} | |||
func GetLimitersByRelatedIdWithDeleted(limitType LimitType) ([]LimitConfig, error) { | |||
r := make([]LimitConfig, 0) | |||
err := x.Unscoped().Where(" = ?", limitType.Name()).Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} else if len(r) == 0 { | |||
return nil, ErrRecordNotExist{} | |||
} | |||
return r, nil | |||
} | |||
func AddLimitConfig(l *LimitConfig) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
//delete old limit config | |||
cond := builder.NewCond() | |||
cond = cond.And(builder.Eq{"limit_type": l.LimitType}) | |||
cond = cond.And(builder.Eq{"scope": l.Scope}) | |||
if l.LimitCode == "" { | |||
subCond := builder.NewCond() | |||
subCond = subCond.Or(builder.IsNull{"limit_code"}) | |||
subCond = subCond.Or(builder.Eq{"limit_code": ""}) | |||
cond = cond.And(subCond) | |||
} else { | |||
cond = cond.And(builder.Eq{"limit_code": l.LimitCode}) | |||
} | |||
_, err := sess.Where(cond).Delete(&LimitConfig{}) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
//add new config | |||
_, err = sess.Insert(l) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
sess.Commit() | |||
return nil | |||
} | |||
func DeleteLimitConfig(config LimitConfig, deleterId int64, deleterName string) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
_, err := x.ID(config.ID).Update(&LimitConfig{DeleterName: deleterName, DeleterId: deleterId}) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
_, err = x.ID(config.ID).Delete(&LimitConfig{}) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
sess.Commit() | |||
return nil | |||
} | |||
func GetLimitConfigById(id int64) (*LimitConfig, error) { | |||
r := &LimitConfig{} | |||
isOk, err := x.ID(id).Get(r) | |||
if err != nil { | |||
return nil, err | |||
} else if !isOk { | |||
return nil, nil | |||
} | |||
return r, nil | |||
} |
@@ -10,6 +10,26 @@ import ( | |||
"xorm.io/xorm" | |||
) | |||
type AvailablePageSize int | |||
const ( | |||
PageSize15 AvailablePageSize = 15 | |||
PageSize30 AvailablePageSize = 30 | |||
PageSize50 AvailablePageSize = 50 | |||
) | |||
func (s AvailablePageSize) IsLegal() bool { | |||
switch s { | |||
case PageSize30, PageSize50, PageSize15: | |||
return true | |||
} | |||
return false | |||
} | |||
func (s AvailablePageSize) Int() int { | |||
return int(s) | |||
} | |||
// ListOptions options to paginate results | |||
type ListOptions struct { | |||
PageSize int | |||
@@ -766,6 +766,14 @@ func UserSignIn(username, password string) (*User, error) { | |||
if err != nil { | |||
return nil, err | |||
} | |||
//email和用户名方式没找到,用手机号查找 | |||
if !hasUser { | |||
user = &User{PhoneNumber: strings.TrimSpace(username)} | |||
hasUser, err = x.Get(user) | |||
if err != nil { | |||
return nil, err | |||
} | |||
} | |||
if hasUser { | |||
switch user.LoginType { | |||
@@ -129,13 +129,44 @@ func init() { | |||
new(LanguageStat), | |||
new(EmailHash), | |||
new(Dataset), | |||
new(DatasetStar), | |||
new(Cloudbrain), | |||
new(Image), | |||
new(ImageStar), | |||
new(ImageTopic), | |||
new(ImageTopicRelation), | |||
new(FileChunk), | |||
new(ModelFileChunk), | |||
new(BlockChain), | |||
new(RecommendOrg), | |||
new(AiModelManage), | |||
new(OfficialTag), | |||
new(OfficialTagRepos), | |||
new(WechatBindLog), | |||
new(OrgStatistic), | |||
new(SearchRecord), | |||
new(TaskConfig), | |||
new(TaskAccomplishLog), | |||
new(RewardOperateRecord), | |||
new(LimitConfig), | |||
new(RewardPeriodicTask), | |||
new(PointAccountLog), | |||
new(PointAccount), | |||
new(RewardAdminLog), | |||
new(AiModelConvert), | |||
new(ResourceQueue), | |||
new(ResourceSpecification), | |||
new(ResourceScene), | |||
new(ResourceSceneSpec), | |||
new(AdminOperateLog), | |||
new(CloudbrainSpec), | |||
new(CloudbrainTemp), | |||
new(DatasetReference), | |||
new(ScheduleRecord), | |||
new(BadgeCategory), | |||
new(Badge), | |||
new(BadgeUser), | |||
new(BadgeUserLog), | |||
) | |||
tablesStatistic = append(tablesStatistic, | |||
@@ -143,7 +174,19 @@ func init() { | |||
new(SummaryStatistic), | |||
new(UserBusinessAnalysis), | |||
new(UserBusinessAnalysisAll), | |||
new(UserBusinessAnalysisCurrentYear), | |||
new(UserBusinessAnalysisLast30Day), | |||
new(UserBusinessAnalysisLastMonth), | |||
new(UserBusinessAnalysisCurrentMonth), | |||
new(UserBusinessAnalysisCurrentWeek), | |||
new(UserBusinessAnalysisYesterday), | |||
new(UserBusinessAnalysisLastWeek), | |||
new(UserLoginLog), | |||
new(UserMetrics), | |||
new(UserAnalysisPara), | |||
new(Invitation), | |||
new(CloudbrainDurationStatistic), | |||
new(UserSummaryCurrentYear), | |||
) | |||
gonicNames := []string{"SSL", "UID"} | |||
@@ -8,6 +8,7 @@ package models | |||
import ( | |||
"fmt" | |||
"os" | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/modules/log" | |||
@@ -19,6 +20,17 @@ import ( | |||
"xorm.io/xorm" | |||
) | |||
type OrgStatistic struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
OrgID int64 `xorm:"UNIQUE"` | |||
NumScore int `xorm:"INDEX NOT NULL DEFAULT 0"` | |||
} | |||
type OrgScore struct { | |||
*User | |||
Score string | |||
} | |||
// IsOwnedBy returns true if given user is in the owner team. | |||
func (org *User) IsOwnedBy(uid int64) (bool, error) { | |||
return IsOrganizationOwner(org.ID, uid) | |||
@@ -135,6 +147,97 @@ func (org *User) RemoveOrgRepo(repoID int64) error { | |||
return org.removeOrgRepo(x, repoID) | |||
} | |||
func UpdateOrgStatistics() { | |||
ids, err := GetOrganizationsId() | |||
if err != nil { | |||
return | |||
} | |||
for _, id := range ids { | |||
org := User{ID: id} | |||
orgStat := &OrgStatistic{OrgID: id} | |||
numScore, err := org.getOrgStatistics() | |||
if err == nil { | |||
has, _ := x.Get(orgStat) | |||
orgStat.NumScore = numScore | |||
count, err := GetPublicRepositoryCount(&org) | |||
if err != nil || count == 0 { | |||
x.ID(orgStat.ID).Delete(new(OrgStatistic)) | |||
} else if has { | |||
x.ID(orgStat.ID).Cols("num_score").Update(&orgStat) | |||
} else { | |||
x.Insert(orgStat) | |||
} | |||
} | |||
} | |||
} | |||
func (org *User) getOrgStatistics() (int, error) { | |||
count, err := getRepositoryCount(x, org) | |||
if err != nil { | |||
return 0, err | |||
} | |||
err = org.GetRepositories(ListOptions{int(count), 1}) | |||
if err != nil { | |||
return 0, err | |||
} | |||
var numScore = 0 | |||
for _, repo := range org.Repos { | |||
numScore += int(getOpenIByRepoId(repo.ID)) | |||
} | |||
return numScore, nil | |||
} | |||
func FindTopNStarsOrgs(n int) ([]*OrgScore, error) { | |||
sql := "select a.id,sum(b.num_stars) score from \"user\" a ,repository b where a.id=b.owner_id and a.type=1 and a.visibility=0 group by a.id order by score desc limit " + strconv.Itoa(n) | |||
return findTopNOrgs(sql) | |||
} | |||
func FindTopNMembersOrgs(n int) ([]*OrgScore, error) { | |||
sql := "select id, count(user_id) score from" + | |||
" (select org_id as id, uid as user_id from org_user o, \"user\" u where o.org_id=u.id and u.visibility=0 " + | |||
"union select a.id,b.user_id from \"user\" a,collaboration b,repository c " + | |||
"where a.type=1 and a.visibility=0 and a.id=c.owner_id and b.repo_id=c.id) d " + | |||
"group by id order by score desc limit " + strconv.Itoa(n) | |||
return findTopNOrgs(sql) | |||
} | |||
func FindTopNOpenIOrgs(n int) ([]*OrgScore, error) { | |||
sql := "select org_id id,num_score score from org_statistic a, \"user\" b where a.org_id=b.id and b.visibility=0 order by num_score desc limit " + strconv.Itoa(n) | |||
return findTopNOrgs(sql) | |||
} | |||
func findTopNOrgs(sql string) ([]*OrgScore, error) { | |||
resutls, err := x.QueryString(sql) | |||
if err != nil { | |||
return nil, err | |||
} | |||
var orgScore []*OrgScore | |||
for _, record := range resutls { | |||
id, _ := strconv.ParseInt(record["id"], 10, 64) | |||
user, err := getUserByID(x, id) | |||
if err != nil { | |||
continue | |||
} | |||
orgScore = append(orgScore, &OrgScore{user, record["score"]}) | |||
} | |||
return orgScore, nil | |||
} | |||
// CreateOrganization creates record of a new organization. | |||
func CreateOrganization(org, owner *User) (err error) { | |||
if !owner.CanCreateOrganization() { | |||
@@ -180,8 +283,8 @@ func CreateOrganization(org, owner *User) (err error) { | |||
// Add initial creator to organization and owner team. | |||
if _, err = sess.Insert(&OrgUser{ | |||
UID: owner.ID, | |||
OrgID: org.ID, | |||
UID: owner.ID, | |||
OrgID: org.ID, | |||
IsPublic: setting.Service.DefaultOrgMemberVisible, | |||
}); err != nil { | |||
return fmt.Errorf("insert org-user relation: %v", err) | |||
@@ -367,6 +470,14 @@ func isOrganizationMember(e Engine, orgID, uid int64) (bool, error) { | |||
Exist() | |||
} | |||
func IsOrganizationMemberByOrgName(orgName string, uid int64) (bool, error) { | |||
org, _ := GetOrgByName(orgName) | |||
if org != nil { | |||
return IsOrganizationMember(org.ID, uid) | |||
} | |||
return false, nil | |||
} | |||
// IsPublicMembership returns true if given user public his/her membership. | |||
func IsPublicMembership(orgID, uid int64) (bool, error) { | |||
return x. | |||
@@ -0,0 +1,147 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
) | |||
type PointAccountStatus int | |||
// Possible PointAccountStatus types. | |||
const ( | |||
PointAccountNormal int = iota + 1 // 1 | |||
PointAccountFreeze // 2 | |||
PointAccountDeleted // 3 | |||
) | |||
type PointAccount struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
AccountCode string `xorm:"INDEX NOT NULL"` | |||
Balance int64 `xorm:"NOT NULL DEFAULT 0"` | |||
TotalEarned int64 `xorm:"NOT NULL DEFAULT 0"` | |||
TotalConsumed int64 `xorm:"NOT NULL DEFAULT 0"` | |||
UserId int64 `xorm:"INDEX NOT NULL"` | |||
Status int `xorm:"NOT NULL"` | |||
Version int64 `xorm:"NOT NULL"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
} | |||
func (account *PointAccount) Increase(amount int64, sourceId string) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sql := "update point_account set balance = balance + ?,total_earned = total_earned + ? ,version = version + 1 where account_code = ? " | |||
_, err := sess.Exec(sql, amount, amount, account.AccountCode) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
accountLog := &PointAccountLog{ | |||
AccountCode: account.AccountCode, | |||
UserId: account.UserId, | |||
Type: IncreaseAccountBalance, | |||
SourceId: sourceId, | |||
PointsAmount: amount, | |||
BalanceBefore: account.Balance, | |||
BalanceAfter: account.Balance + amount, | |||
AccountVersion: account.Version, | |||
} | |||
_, err = sess.Insert(accountLog) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
sess.Commit() | |||
return nil | |||
} | |||
func (account *PointAccount) Decrease(amount int64, sourceId string) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sql := "update point_account set balance = balance - ?,total_consumed = total_consumed + ? ,version = version + 1 where account_code = ? " | |||
_, err := sess.Exec(sql, amount, amount, account.AccountCode) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
accountLog := &PointAccountLog{ | |||
AccountCode: account.AccountCode, | |||
UserId: account.UserId, | |||
Type: DecreaseAccountBalance, | |||
SourceId: sourceId, | |||
PointsAmount: amount, | |||
BalanceBefore: account.Balance, | |||
BalanceAfter: account.Balance - amount, | |||
AccountVersion: account.Version, | |||
} | |||
_, err = sess.Insert(accountLog) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
sess.Commit() | |||
return nil | |||
} | |||
func GetAccountByUserId(userId int64) (*PointAccount, error) { | |||
p := &PointAccount{} | |||
has, err := x.Where("user_id = ?", userId).Get(p) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if !has { | |||
return nil, ErrRecordNotExist{} | |||
} | |||
return p, nil | |||
} | |||
func InsertAccount(tl *PointAccount) (int64, error) { | |||
return x.Insert(tl) | |||
} | |||
type SearchPointAccountOpts struct { | |||
ListOptions | |||
Keyword string | |||
} | |||
type SearchPointAccountResponse struct { | |||
Records []*UserPointAccount | |||
PageSize int | |||
Page int | |||
Total int64 | |||
} | |||
type UserPointAccount struct { | |||
UserId int64 | |||
UserName string | |||
Email string | |||
Balance int64 | |||
TotalEarned int64 | |||
TotalConsumed int64 | |||
} | |||
func (UserPointAccount) TableName() string { | |||
return "user" | |||
} | |||
func GetPointAccountMapByUserIds(userIds []int64) (map[int64]*PointAccount, error) { | |||
if len(userIds) == 0 { | |||
return make(map[int64]*PointAccount, 0), nil | |||
} | |||
accounts := make([]*PointAccount, 0) | |||
err := x.In("user_id", userIds).Find(&accounts) | |||
if err != nil { | |||
log.Error("GetPointAccountMapByUserIds error.%v", err) | |||
return nil, err | |||
} | |||
accountMap := make(map[int64]*PointAccount, 0) | |||
for _, v := range accounts { | |||
accountMap[v.UserId] = v | |||
} | |||
return accountMap, nil | |||
} | |||
type PointDeductCondition struct { | |||
SpecUnitPrice int | |||
WorkServerNumber int | |||
} |
@@ -0,0 +1,21 @@ | |||
package models | |||
import "code.gitea.io/gitea/modules/timeutil" | |||
const ( | |||
IncreaseAccountBalance = "increase" | |||
DecreaseAccountBalance = "decrease" | |||
) | |||
type PointAccountLog struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
AccountCode string `xorm:"INDEX NOT NULL"` | |||
UserId int64 `xorm:"INDEX NOT NULL"` | |||
Type string `xorm:"NOT NULL"` | |||
SourceId string `xorm:"INDEX NOT NULL"` | |||
PointsAmount int64 `xorm:"NOT NULL"` | |||
BalanceBefore int64 `xorm:"NOT NULL"` | |||
BalanceAfter int64 `xorm:"NOT NULL"` | |||
AccountVersion int64 `xorm:"NOT NULL"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
} |
@@ -11,6 +11,9 @@ import ( | |||
"errors" | |||
"fmt" | |||
"html/template" | |||
"math/rand" | |||
"code.gitea.io/gitea/modules/git" | |||
"xorm.io/xorm" | |||
"code.gitea.io/gitea/modules/blockchain" | |||
@@ -138,6 +141,7 @@ func NewRepoContext() { | |||
// RepositoryStatus defines the status of repository | |||
type RepositoryStatus int | |||
type RepoBlockChainStatus int | |||
type RepoType int | |||
// all kinds of RepositoryStatus | |||
const ( | |||
@@ -151,6 +155,11 @@ const ( | |||
RepoBlockChainFailed | |||
) | |||
const ( | |||
RepoNormal RepoType = iota | |||
RepoCourse | |||
) | |||
// Repository represents a git repository. | |||
type Repository struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
@@ -164,7 +173,8 @@ type Repository struct { | |||
OriginalServiceType api.GitServiceType `xorm:"index"` | |||
OriginalURL string `xorm:"VARCHAR(2048)"` | |||
DefaultBranch string | |||
CreatorID int64 `xorm:"INDEX NOT NULL DEFAULT 0"` | |||
Creator *User `xorm:"-"` | |||
NumWatches int | |||
NumStars int | |||
NumForks int | |||
@@ -173,11 +183,12 @@ type Repository struct { | |||
NumOpenIssues int `xorm:"-"` | |||
NumPulls int | |||
NumClosedPulls int | |||
NumOpenPulls int `xorm:"-"` | |||
NumMilestones int `xorm:"NOT NULL DEFAULT 0"` | |||
NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0"` | |||
NumOpenMilestones int `xorm:"-"` | |||
NumCommit int64 `xorm:"NOT NULL DEFAULT 0"` | |||
NumOpenPulls int `xorm:"-"` | |||
NumMilestones int `xorm:"NOT NULL DEFAULT 0"` | |||
NumClosedMilestones int `xorm:"NOT NULL DEFAULT 0"` | |||
NumOpenMilestones int `xorm:"-"` | |||
NumCommit int64 `xorm:"NOT NULL DEFAULT 0"` | |||
RepoType RepoType `xorm:"NOT NULL DEFAULT 0"` | |||
IsPrivate bool `xorm:"INDEX"` | |||
IsEmpty bool `xorm:"INDEX"` | |||
@@ -212,16 +223,98 @@ type Repository struct { | |||
BlockChainStatus RepoBlockChainStatus `xorm:"NOT NULL DEFAULT 0"` | |||
// git clone and git pull total count | |||
CloneCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||
CloneCnt int64 `xorm:"NOT NULL DEFAULT 0" json:"clone_cnt"` | |||
// only git clone total count | |||
GitCloneCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||
GitCloneCnt int64 `xorm:"NOT NULL DEFAULT 0" json:"git_clone_cnt"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
Hot int64 `xorm:"-"` | |||
Active int64 `xorm:"-"` | |||
Hot int64 `xorm:"-"` | |||
Active int64 `xorm:"-"` | |||
Alias string `xorm:"INDEX"` | |||
LowerAlias string `xorm:"INDEX"` | |||
AiTaskCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||
ModelCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||
DatasetCnt int64 `xorm:"NOT NULL DEFAULT 0"` | |||
LastMonthVisits int64 `xorm:"NOT NULL DEFAULT 0"` | |||
LastFourMonthCommits int64 `xorm:"NOT NULL DEFAULT 0"` | |||
} | |||
// Repository4Card format for front display | |||
type Repository4Card struct { | |||
ID int64 | |||
OwnerID int64 | |||
OwnerName string | |||
LowerName string | |||
Name string | |||
Alias string | |||
NumWatches int | |||
NumStars int | |||
NumForks int | |||
Description string | |||
Topics []string | |||
AiTaskCnt int64 | |||
ModelCnt int64 | |||
DatasetCnt int64 | |||
CreatedUnix timeutil.TimeStamp | |||
UpdatedUnix timeutil.TimeStamp | |||
PrimaryLanguage *LanguageStat | |||
RelAvatarLink string | |||
Contributors []*ContributorInfo | |||
IsPrivate bool | |||
IsFork bool | |||
IsMirror bool | |||
IsOwnerPrivate bool | |||
IsArchived bool | |||
} | |||
type RepositoryShow struct { | |||
Name string | |||
RepoType RepoType | |||
Alias string | |||
} | |||
func (repo *Repository) ToCardFormat() *Repository4Card { | |||
link := repo.RelAvatarLink() | |||
var isOwnerPrivate bool | |||
if repo.Owner != nil && repo.Owner.Visibility.IsPrivate() { | |||
isOwnerPrivate = true | |||
} | |||
result := &Repository4Card{ | |||
ID: repo.ID, | |||
OwnerID: repo.OwnerID, | |||
OwnerName: repo.OwnerName, | |||
LowerName: repo.LowerName, | |||
Name: repo.Name, | |||
NumWatches: repo.NumWatches, | |||
NumStars: repo.NumStars, | |||
NumForks: repo.NumForks, | |||
Description: repo.Description, | |||
Topics: repo.Topics, | |||
AiTaskCnt: repo.AiTaskCnt, | |||
ModelCnt: repo.ModelCnt, | |||
DatasetCnt: repo.DatasetCnt, | |||
CreatedUnix: repo.CreatedUnix, | |||
UpdatedUnix: repo.UpdatedUnix, | |||
PrimaryLanguage: repo.PrimaryLanguage, | |||
RelAvatarLink: link, | |||
Alias: repo.Alias, | |||
IsPrivate: repo.IsPrivate, | |||
IsFork: repo.IsFork, | |||
IsMirror: repo.IsMirror, | |||
IsOwnerPrivate: isOwnerPrivate, | |||
IsArchived: repo.IsArchived, | |||
} | |||
return result | |||
} | |||
type ContributorInfo struct { | |||
RelAvatarLink string | |||
UserName string | |||
Email string | |||
CommitCnt int | |||
} | |||
// SanitizedOriginalURL returns a sanitized OriginalURL | |||
@@ -232,6 +325,14 @@ func (repo *Repository) SanitizedOriginalURL() string { | |||
return util.SanitizeURLCredentials(repo.OriginalURL, false) | |||
} | |||
// GetAlias returns a sanitized OriginalURL | |||
func (repo *Repository) DisplayName() string { | |||
if repo.Alias == "" { | |||
return repo.Name | |||
} | |||
return repo.Alias | |||
} | |||
// ColorFormat returns a colored string to represent this repo | |||
func (repo *Repository) ColorFormat(s fmt.State) { | |||
var ownerName interface{} | |||
@@ -285,6 +386,11 @@ func (repo *Repository) FullName() string { | |||
return repo.OwnerName + "/" + repo.Name | |||
} | |||
// FullDisplayName returns the repository full display name | |||
func (repo *Repository) FullDisplayName() string { | |||
return repo.OwnerName + "/" + repo.DisplayName() | |||
} | |||
// HTMLURL returns the repository HTML URL | |||
func (repo *Repository) HTMLURL() string { | |||
return setting.AppURL + repo.FullName() | |||
@@ -384,7 +490,9 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) | |||
ID: repo.ID, | |||
Owner: repo.Owner.APIFormat(), | |||
Name: repo.Name, | |||
Alias: repo.Alias, | |||
FullName: repo.FullName(), | |||
FullDisplayName: repo.FullDisplayName(), | |||
Description: repo.Description, | |||
Private: repo.IsPrivate, | |||
Template: repo.IsTemplate, | |||
@@ -420,6 +528,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) | |||
AllowRebaseMerge: allowRebaseMerge, | |||
AllowSquash: allowSquash, | |||
AvatarURL: repo.avatarLink(e), | |||
Status: int(repo.Status), | |||
} | |||
} | |||
@@ -547,6 +656,19 @@ func (repo *Repository) GetOwner() error { | |||
return repo.getOwner(x) | |||
} | |||
func (repo *Repository) getCreator(e Engine) (err error) { | |||
if repo.CreatorID == 0 { | |||
return nil | |||
} | |||
repo.Creator, err = getUserByID(e, repo.CreatorID) | |||
return err | |||
} | |||
func (repo *Repository) GetCreator() error { | |||
return repo.getCreator(x) | |||
} | |||
func (repo *Repository) mustOwner(e Engine) *User { | |||
if err := repo.getOwner(e); err != nil { | |||
return &User{ | |||
@@ -632,7 +754,7 @@ func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) { | |||
userIDs[i] = accesses[i].UserID | |||
} | |||
if err = e.In("id", userIDs).Find(&users); err != nil { | |||
if err = e.In("id", userIDs).OrderBy("name asc").Find(&users); err != nil { | |||
return nil, err | |||
} | |||
} | |||
@@ -920,17 +1042,50 @@ func (repo *Repository) DescriptionHTML() template.HTML { | |||
return template.HTML(markup.Sanitize(string(desc))) | |||
} | |||
func isRepositoryExist(e Engine, u *User, repoName string) (bool, error) { | |||
has, err := e.Get(&Repository{ | |||
OwnerID: u.ID, | |||
LowerName: strings.ToLower(repoName), | |||
}) | |||
return has && com.IsDir(RepoPath(u.Name, repoName)), err | |||
func isRepositoryExist(e Engine, u *User, repoName string, alias string) (bool, error) { | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.Eq{"owner_id": u.ID}) | |||
if alias != "" { | |||
subCon := builder.NewCond() | |||
subCon = subCon.Or(builder.Eq{"lower_alias": strings.ToLower(alias)}, builder.Eq{"lower_name": strings.ToLower(repoName)}) | |||
cond = cond.And(subCon) | |||
} else { | |||
cond = cond.And(builder.Eq{"lower_name": strings.ToLower(repoName)}) | |||
} | |||
count, err := e.Where(cond).Count(&Repository{}) | |||
return count > 0 || com.IsDir(RepoPath(u.Name, repoName)), err | |||
} | |||
// IsRepositoryExist returns true if the repository with given name under user has already existed. | |||
func IsRepositoryExist(u *User, repoName string) (bool, error) { | |||
return isRepositoryExist(x, u, repoName) | |||
func IsRepositoryExist(u *User, repoName string, alias string) (bool, error) { | |||
return isRepositoryExist(x, u, repoName, alias) | |||
} | |||
// IsRepositoryAliasExist returns true if the repository with given alias under user has already existed. | |||
func IsRepositoryAliasExist(u *User, alias string) (bool, error) { | |||
return isRepositoryAliasExist(x, u, alias) | |||
} | |||
func isRepositoryAliasExist(e Engine, u *User, alias string) (bool, error) { | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.Eq{"owner_id": u.ID}) | |||
cond = cond.And(builder.Eq{"lower_alias": strings.ToLower(alias)}) | |||
count, err := e.Where(cond).Count(&Repository{}) | |||
return count > 0, err | |||
} | |||
func IsRepositoryAliasAvailable(doer *User, alias string) error { | |||
if err := IsUsableRepoAlias(alias); err != nil { | |||
return err | |||
} | |||
has, err := IsRepositoryAliasExist(doer, alias) | |||
if err != nil { | |||
return fmt.Errorf("IsRepositoryExist: %v", err) | |||
} else if has { | |||
return ErrRepoAlreadyExist{doer.Name, alias} | |||
} | |||
return nil | |||
} | |||
// CloneLink represents different types of clone URLs of repository. | |||
@@ -974,20 +1129,24 @@ func (repo *Repository) CloneLink() (cl *CloneLink) { | |||
} | |||
// CheckCreateRepository check if could created a repository | |||
func CheckCreateRepository(doer, u *User, name string) error { | |||
func CheckCreateRepository(doer, u *User, repoName, alias string) error { | |||
if !doer.CanCreateRepo() { | |||
return ErrReachLimitOfRepo{u.MaxRepoCreation} | |||
} | |||
if err := IsUsableRepoName(name); err != nil { | |||
if err := IsUsableRepoName(repoName); err != nil { | |||
return err | |||
} | |||
if err := IsUsableRepoAlias(alias); err != nil { | |||
return err | |||
} | |||
has, err := isRepositoryExist(x, u, name) | |||
has, err := isRepositoryExist(x, u, repoName, alias) | |||
if err != nil { | |||
return fmt.Errorf("IsRepositoryExist: %v", err) | |||
} else if has { | |||
return ErrRepoAlreadyExist{u.Name, name} | |||
return ErrRepoAlreadyExist{u.Name, repoName} | |||
} | |||
return nil | |||
} | |||
@@ -995,6 +1154,7 @@ func CheckCreateRepository(doer, u *User, name string) error { | |||
// CreateRepoOptions contains the create repository options | |||
type CreateRepoOptions struct { | |||
Name string | |||
Alias string | |||
Description string | |||
OriginalURL string | |||
GitServiceType api.GitServiceType | |||
@@ -1007,6 +1167,8 @@ type CreateRepoOptions struct { | |||
IsMirror bool | |||
AutoInit bool | |||
Status RepositoryStatus | |||
IsCourse bool | |||
Topics []string | |||
} | |||
// GetRepoInitFile returns repository init files | |||
@@ -1035,8 +1197,10 @@ func GetRepoInitFile(tp, name string) ([]byte, error) { | |||
} | |||
var ( | |||
reservedRepoNames = []string{".", ".."} | |||
reservedRepoPatterns = []string{"*.git", "*.wiki"} | |||
reservedRepoNames = []string{".", ".."} | |||
reservedRepoPatterns = []string{"*.git", "*.wiki"} | |||
reservedRepoAliasNames = []string{} | |||
reservedRepoAliasPatterns = []string{} | |||
) | |||
// IsUsableRepoName returns true when repository is usable | |||
@@ -1044,19 +1208,34 @@ func IsUsableRepoName(name string) error { | |||
return isUsableName(reservedRepoNames, reservedRepoPatterns, name) | |||
} | |||
// IsUsableRepoAlias returns true when repository alias is usable | |||
func IsUsableRepoAlias(name string) error { | |||
return isUsableName(reservedRepoAliasNames, reservedRepoAliasPatterns, name) | |||
} | |||
// CreateRepository creates a repository for the user/organization. | |||
func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error) { | |||
func CreateRepository(ctx DBContext, doer, u *User, repo *Repository, opts ...CreateRepoOptions) (err error) { | |||
if repo.Alias == "" { | |||
repo.Alias = repo.Name | |||
} | |||
repo.LowerAlias = strings.ToLower(repo.Alias) | |||
if err = IsUsableRepoName(repo.Name); err != nil { | |||
return err | |||
} | |||
has, err := isRepositoryExist(ctx.e, u, repo.Name) | |||
if err := IsUsableRepoAlias(repo.Alias); err != nil { | |||
return err | |||
} | |||
has, err := isRepositoryExist(ctx.e, u, repo.Name, repo.Alias) | |||
if err != nil { | |||
return fmt.Errorf("IsRepositoryExist: %v", err) | |||
} else if has { | |||
return ErrRepoAlreadyExist{u.Name, repo.Name} | |||
} | |||
isCourse := isCourse(opts) | |||
if isCourse { | |||
repo.CreatorID = doer.ID | |||
} | |||
if _, err = ctx.e.Insert(repo); err != nil { | |||
return err | |||
} | |||
@@ -1090,17 +1269,23 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error | |||
Config: &PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true}, | |||
}) | |||
} else if tp == UnitTypeDatasets { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
Type: tp, | |||
Config: &DatasetConfig{EnableDataset: true}, | |||
}) | |||
if !isCourse { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
Type: tp, | |||
Config: &DatasetConfig{EnableDataset: true}, | |||
}) | |||
} | |||
} else if tp == UnitTypeCloudBrain { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
Type: tp, | |||
Config: &CloudBrainConfig{EnableCloudBrain: true}, | |||
}) | |||
if !isCourse { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
Type: tp, | |||
Config: &CloudBrainConfig{EnableCloudBrain: true}, | |||
}) | |||
} | |||
} else if tp == UnitTypeBlockChain { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
@@ -1108,11 +1293,13 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error | |||
Config: &BlockChainConfig{EnableBlockChain: true}, | |||
}) | |||
} else if tp == UnitTypeModelManage { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
Type: tp, | |||
Config: &ModelManageConfig{EnableModelManage: true}, | |||
}) | |||
if !isCourse { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
Type: tp, | |||
Config: &ModelManageConfig{EnableModelManage: true}, | |||
}) | |||
} | |||
} else { | |||
units = append(units, RepoUnit{ | |||
RepoID: repo.ID, | |||
@@ -1166,7 +1353,7 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error | |||
} | |||
if setting.Service.AutoWatchNewRepos { | |||
if err = watchRepo(ctx.e, doer.ID, repo.ID, true); err != nil { | |||
if err = watchRepo(ctx.e, doer.ID, repo.ID, true, ReceiveAllNotification); err != nil { | |||
return fmt.Errorf("watchRepo: %v", err) | |||
} | |||
} | |||
@@ -1175,13 +1362,17 @@ func CreateRepository(ctx DBContext, doer, u *User, repo *Repository) (err error | |||
return fmt.Errorf("copyDefaultWebhooksToRepo: %v", err) | |||
} | |||
if err = CreateDefaultDatasetToRepo(repo); err != nil { | |||
return fmt.Errorf("models.CreateDefaultDatasetToRepo: %v", err) | |||
} | |||
return nil | |||
} | |||
func isCourse(opts []CreateRepoOptions) bool { | |||
var isCourse = false | |||
if len(opts) > 0 { | |||
isCourse = opts[0].IsCourse | |||
} | |||
return isCourse | |||
} | |||
func countRepositories(userID int64, private bool) int64 { | |||
sess := x.Where("id > 0") | |||
@@ -1232,7 +1423,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error | |||
} | |||
// Check if new owner has repository with same name. | |||
has, err := IsRepositoryExist(newOwner, repo.Name) | |||
has, err := IsRepositoryExist(newOwner, repo.Name, repo.Alias) | |||
if err != nil { | |||
return fmt.Errorf("IsRepositoryExist: %v", err) | |||
} else if has { | |||
@@ -1365,7 +1556,7 @@ func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err | |||
return err | |||
} | |||
has, err := IsRepositoryExist(repo.Owner, newRepoName) | |||
has, err := IsRepositoryExist(repo.Owner, newRepoName, "") | |||
if err != nil { | |||
return fmt.Errorf("IsRepositoryExist: %v", err) | |||
} else if has { | |||
@@ -1434,6 +1625,26 @@ func GetAllRepositoriesCount() (int64, error) { | |||
return x.Count(repo) | |||
} | |||
func GetAllPublicRepositoriesCount() (int64, error) { | |||
repo := new(Repository) | |||
return x.Where("is_private = ?", false).Count(repo) | |||
} | |||
func GetAllMirrorRepositoriesCount() (int64, error) { | |||
repo := new(Repository) | |||
return x.Where("is_mirror = ?", true).Count(repo) | |||
} | |||
func GetAllOrgRepositoriesCount() (int64, error) { | |||
repo := new(Repository) | |||
return x.Table("repository").Join("INNER", []string{"\"user\"", "u"}, "repository.owner_id = u.id and u.type=1").Count(repo) | |||
} | |||
func GetAllForkRepositoriesCount() (int64, error) { | |||
repo := new(Repository) | |||
return x.Where("is_fork = ?", true).Count(repo) | |||
} | |||
func GetAllRepositoriesSize() (int64, error) { | |||
return x.SumInt(&Repository{}, "size") | |||
} | |||
@@ -1473,6 +1684,37 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e | |||
if err != nil { | |||
return err | |||
} | |||
dataset, err := GetDatasetByRepo(repo) | |||
if err != nil && !IsErrNotExist(err) { | |||
return err | |||
} | |||
if dataset != nil { | |||
_, err = e.Where("dataset_id = ?", dataset.ID).Cols("is_private").Update(&Attachment{ | |||
IsPrivate: true, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
//If repo has become private, we need set dataset and dataset_file to private | |||
_, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{ | |||
Status: 0, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
} else { | |||
//If repo has become public, we need set dataset to public | |||
_, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{ | |||
Status: 1, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
} | |||
// Create/Remove git-daemon-export-ok for git-daemon... | |||
@@ -1627,7 +1869,6 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
// Delete dataset attachment record and remove related files | |||
deleteDatasetAttachmentByRepoId(sess, repoID) | |||
if err = deleteBeans(sess, | |||
&Access{RepoID: repo.ID}, | |||
&Action{RepoID: repo.ID}, | |||
@@ -1847,6 +2088,26 @@ func getRepositoryByOwnerAndName(e Engine, ownerName, repoName string) (*Reposit | |||
return &repo, nil | |||
} | |||
// GetRepositoryByOwnerAndAlias returns the repository by given ownername and reponame. | |||
func GetRepositoryByOwnerAndAlias(ownerName, alias string) (*Repository, error) { | |||
return getRepositoryByOwnerAndAlias(x, ownerName, alias) | |||
} | |||
func getRepositoryByOwnerAndAlias(e Engine, ownerName, alias string) (*Repository, error) { | |||
var repo Repository | |||
has, err := e.Table("repository").Select("repository.*"). | |||
Join("INNER", "`user`", "`user`.id = repository.owner_id"). | |||
Where("repository.lower_alias = ?", strings.ToLower(alias)). | |||
And("`user`.lower_name = ?", strings.ToLower(ownerName)). | |||
Get(&repo) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, ErrRepoNotExist{0, 0, ownerName, alias} | |||
} | |||
return &repo, nil | |||
} | |||
// GetRepositoryByName returns the repository by given name under user if exists. | |||
func GetRepositoryByName(ownerID int64, name string) (*Repository, error) { | |||
repo := &Repository{ | |||
@@ -2069,6 +2330,18 @@ func CheckRepoStats(ctx context.Context) error { | |||
"UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", | |||
"repository count 'num_stars'", | |||
}, | |||
//Repository.NumIssues | |||
{ | |||
"SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=false)", | |||
"UPDATE `repository` SET num_issues=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_pull=false) WHERE id=?", | |||
"repository count 'num_issues'", | |||
}, | |||
//Repository.NumPulls | |||
{ | |||
"SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=true)", | |||
"UPDATE `repository` SET num_pulls=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_pull=true) WHERE id=?", | |||
"repository count 'num_pulls'", | |||
}, | |||
// Label.NumIssues | |||
{ | |||
"SELECT label.id FROM `label` WHERE label.num_issues!=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=label.id)", | |||
@@ -2180,6 +2453,75 @@ func CheckRepoStats(ctx context.Context) error { | |||
} | |||
} | |||
// ***** END: Repository.NumForks ***** | |||
// ***** START: Repository.DatasetCnt ***** | |||
desc = "repository count 'dataset_cnt'" | |||
results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.dataset_cnt!=(select count(1) from attachment inner join dataset on attachment.dataset_id = dataset.id where dataset.repo_id = repository.id)") | |||
if err != nil { | |||
log.Error("Select %s: %v", desc, err) | |||
} else { | |||
for _, result := range results { | |||
id := com.StrTo(result["id"]).MustInt64() | |||
select { | |||
case <-ctx.Done(): | |||
log.Warn("CheckRepoStats: Cancelled") | |||
return ErrCancelledf("during %s for repo ID %d", desc, id) | |||
default: | |||
} | |||
log.Trace("Updating %s: %d", desc, id) | |||
err = ResetRepoDatasetNum(id) | |||
if err != nil { | |||
log.Error("Update %s[%d]: %v", desc, id, err) | |||
} | |||
} | |||
} | |||
// ***** END: Repository.DatasetCnt ***** | |||
// ***** START: Repository.ModelCnt ***** | |||
desc = "repository count 'model_cnt'" | |||
results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.model_cnt!=(select count(1) from ai_model_manage where repository.id = ai_model_manage.repo_id and ai_model_manage.size > 0 )") | |||
if err != nil { | |||
log.Error("Select %s: %v", desc, err) | |||
} else { | |||
for _, result := range results { | |||
id := com.StrTo(result["id"]).MustInt64() | |||
select { | |||
case <-ctx.Done(): | |||
log.Warn("CheckRepoStats: Cancelled") | |||
return ErrCancelledf("during %s for repo ID %d", desc, id) | |||
default: | |||
} | |||
log.Trace("Updating %s: %d", desc, id) | |||
err = ResetRepoModelNum(id) | |||
if err != nil { | |||
log.Error("Update %s[%d]: %v", desc, id, err) | |||
} | |||
} | |||
} | |||
// ***** END: Repository.ModelCnt ***** | |||
// ***** START: Repository.AiTaskCnt ***** | |||
desc = "repository count 'ai_task_cnt'" | |||
results, err = x.Query("SELECT repository.id FROM `repository` WHERE repository.ai_task_cnt!=(select count(1) from cloudbrain where repository.id = cloudbrain.repo_id and (cloudbrain.deleted_at is null or cloudbrain.deleted_at = '0001-01-01 00:00:00') )") | |||
if err != nil { | |||
log.Error("Select %s: %v", desc, err) | |||
} else { | |||
for _, result := range results { | |||
id := com.StrTo(result["id"]).MustInt64() | |||
select { | |||
case <-ctx.Done(): | |||
log.Warn("CheckRepoStats: Cancelled") | |||
return ErrCancelledf("during %s for repo ID %d", desc, id) | |||
default: | |||
} | |||
log.Trace("Updating %s: %d", desc, id) | |||
err = ResetRepoAITaskNum(id) | |||
if err != nil { | |||
log.Error("Update %s[%d]: %v", desc, id, err) | |||
} | |||
} | |||
} | |||
// ***** END: Repository.AiTaskCnt ***** | |||
return nil | |||
} | |||
@@ -2519,3 +2861,142 @@ func UpdateRepositoryCommitNum(repo *Repository) error { | |||
return nil | |||
} | |||
func GenerateDefaultRepoName(ownerName string) string { | |||
if len(ownerName) > 5 { | |||
ownerName = ownerName[:5] | |||
} | |||
now := time.Now().Format("20060102150405") | |||
return ownerName + now + fmt.Sprint(rand.Intn(10)) | |||
} | |||
type RepoFile struct { | |||
CommitId string | |||
Content []byte | |||
} | |||
// ReadLatestFileInRepo read latest version of file in repository | |||
// return a RepoFile | |||
func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFile, error) { | |||
var err error | |||
repoPath := RepoPath(userName, repoName) | |||
gitRepo, err := git.OpenRepository(repoPath) | |||
if err != nil { | |||
log.Error("ReadLatestFileInRepo error when OpenRepository,error=%v", err) | |||
return nil, err | |||
} | |||
_, err = gitRepo.GetBranchCommitID(refName) | |||
if err != nil { | |||
log.Error("ReadLatestFileInRepo error when GetBranchCommitID,error=%v", err) | |||
return nil, err | |||
} | |||
commit, err := gitRepo.GetBranchCommit(refName) | |||
if err != nil { | |||
log.Error("ReadLatestFileInRepo error when GetBranchCommit,error=%v", err) | |||
return nil, err | |||
} | |||
blob, err := commit.GetBlobByPath(treePath) | |||
if err != nil { | |||
log.Error("ReadLatestFileInRepo error when GetBlobByPath,error=%v", err) | |||
return nil, err | |||
} | |||
reader, err := blob.DataAsync() | |||
if err != nil { | |||
return nil, err | |||
} | |||
defer func() { | |||
if err = reader.Close(); err != nil { | |||
log.Error("ReadLatestFileInRepo: Close: %v", err) | |||
} | |||
}() | |||
d, _ := ioutil.ReadAll(reader) | |||
commitId := "" | |||
if blob != nil { | |||
commitId = fmt.Sprint(blob.ID) | |||
} | |||
return &RepoFile{CommitId: commitId, Content: d}, nil | |||
} | |||
func ResetRepoAITaskNum(repoId int64) error { | |||
n, err := x.Where("repo_id = ? ", repoId).Count(&Cloudbrain{}) | |||
if err != nil { | |||
return err | |||
} | |||
r := Repository{ | |||
AiTaskCnt: n, | |||
} | |||
_, err = x.Cols("ai_task_cnt").Where("id = ?", repoId).Update(&r) | |||
return err | |||
} | |||
func ResetRepoDatasetNum(repoId int64) error { | |||
n, err := x.Table("attachment").Join("inner", "dataset", "attachment.dataset_id = dataset.id").Where("dataset.repo_id = ?", repoId).Count() | |||
if err != nil { | |||
return err | |||
} | |||
r := Repository{ | |||
DatasetCnt: n, | |||
} | |||
_, err = x.Cols("dataset_cnt").Where("id = ?", repoId).Update(&r) | |||
return err | |||
} | |||
func ResetRepoModelNum(repoId int64) error { | |||
_, err := x.Exec("update repository set model_cnt = (select count(1) from ai_model_manage where ai_model_manage.repo_id = ? and size > 0) where id = ?", repoId, repoId) | |||
return err | |||
} | |||
func operateRepoCol(repoId int64, colName string, amount int64, engines ...*xorm.Engine) error { | |||
var err error | |||
if amount == 0 { | |||
return nil | |||
} | |||
var ee *xorm.Engine | |||
if len(engines) == 0 { | |||
ee = x | |||
} else { | |||
ee = engines[0] | |||
} | |||
if amount > 0 { | |||
_, err = ee.Exec(fmt.Sprintf("update repository set %s = %s + ? where id = ?", colName, colName), amount, repoId) | |||
} else { | |||
_, err = ee.Exec(fmt.Sprintf("update repository set %s = %s - ? where id = ?", colName, colName), -1*amount, repoId) | |||
} | |||
return err | |||
} | |||
func OperateRepoDatasetNum(repoId int64, amount int64, engines ...*xorm.Engine) error { | |||
return operateRepoCol(repoId, "dataset_cnt", amount, engines...) | |||
} | |||
func OperateRepoModelNum(repoId int64, amount int64, engines ...*xorm.Engine) error { | |||
return operateRepoCol(repoId, "model_cnt", amount, engines...) | |||
} | |||
func OperateRepoAITaskNum(repoId int64, amount int64, engines ...*xorm.Engine) error { | |||
return operateRepoCol(repoId, "ai_task_cnt", amount, engines...) | |||
} | |||
func UpdateRepositoryLastFourMonthCommits(repoID int64, amount int64) error { | |||
_, err := x.Exec("update repository set last_four_month_commits = ? where id = ?", amount, repoID) | |||
return err | |||
} | |||
func UpdateRepositoryLastMonthVisits(repoID int64, amount int64) error { | |||
_, err := x.Exec("update repository set last_month_visits = ? where id = ?", amount, repoID) | |||
return err | |||
} | |||
func SyncStatDataToRepo(repo *Repository) { | |||
//Save the visit number of repository in the last month | |||
if lv, err := SumLastMonthNumVisits(repo.ID); err == nil { | |||
UpdateRepositoryLastMonthVisits(repo.ID, lv) | |||
} | |||
//Save the commits number of repository in the last four month | |||
if lc, err := SumLastFourMonthNumCommits(repo.ID); err == nil { | |||
UpdateRepositoryLastFourMonthCommits(repo.ID, lc) | |||
} | |||
} |
@@ -211,20 +211,63 @@ func setKeyContributerDict(contributorDistinctDict map[string]int, email string, | |||
} | |||
} | |||
func GetAllUserKPIStats() (map[string]*git.UserKPIStats, error) { | |||
func GetAllUserPublicRepoKPIStats(startTime time.Time, endTime time.Time) (map[string]*git.UserKPIStats, error) { | |||
authors := make(map[string]*git.UserKPIStats) | |||
repositorys, err := GetAllRepositoriesByFilterCols("owner_name", "name") | |||
repositorys, err := GetAllRepositoriesByFilterCols("owner_name", "name", "is_private") | |||
if err != nil { | |||
return nil, err | |||
} | |||
for _, repository := range repositorys { | |||
authorsOneRepo, err1 := git.GetUserKPIStats(repository.RepoPath()) | |||
if repository.IsPrivate { | |||
continue | |||
} | |||
authorsOneRepo, err1 := git.GetUserKPIStats(repository.RepoPath(), startTime, endTime) | |||
if err1 != nil { | |||
log.Warn("get user kpi status err:"+repository.RepoPath(), err1.Error()) | |||
continue | |||
} | |||
for key, value := range authorsOneRepo { | |||
if _, ok := authors[key]; !ok { | |||
authors[key] = &git.UserKPIStats{ | |||
Name: value.Name, | |||
Email: value.Email, | |||
Commits: 0, | |||
CommitLines: 0, | |||
} | |||
} | |||
if value.Email == "1250125907@qq.com" || value.Email == "peiyongyu-34@163.com" { | |||
log.Info("repo path=" + repository.RepoPath()) | |||
} | |||
authors[key].Commits += value.Commits | |||
authors[key].CommitLines += value.CommitLines | |||
} | |||
} | |||
return authors, nil | |||
} | |||
func GetAllUserKPIStats(startTime time.Time, endTime time.Time) (map[string]*git.UserKPIStats, error) { | |||
authors := make(map[string]*git.UserKPIStats) | |||
repositorys, err := GetAllRepositoriesByFilterCols("owner_name", "name") | |||
if err != nil { | |||
return nil, err | |||
} | |||
for _, repository := range repositorys { | |||
authorsOneRepo, err1 := git.GetUserKPIStats(repository.RepoPath(), startTime, endTime) | |||
if err1 != nil { | |||
log.Warn("get user kpi status err:"+repository.RepoPath(), err1.Error()) | |||
continue | |||
} | |||
// if repository.Name == "yolov5" { | |||
// log.Info("repoName=" + repository.Name + " owner=" + repository.RepoPath()) | |||
// authorsOneRepoJson, _ := json.Marshal(authorsOneRepo) | |||
// log.Info("authorsOneRepoJson=" + string(authorsOneRepoJson)) | |||
// } | |||
for key, value := range authorsOneRepo { | |||
if _, ok := authors[key]; !ok { | |||
authors[key] = &git.UserKPIStats{ | |||
@@ -130,6 +130,20 @@ func (repo *Repository) IsCollaborator(userID int64) (bool, error) { | |||
return repo.isCollaborator(x, userID) | |||
} | |||
func (repo *Repository) IsInRepoTeam(userID int64) (bool, error) { | |||
teams,err:=repo.GetRepoTeams() | |||
if err!=nil || len(teams)==0{ | |||
return false,err | |||
} | |||
for _,team :=range teams{ | |||
if team.IsMember(userID){ | |||
return true,nil | |||
} | |||
} | |||
return false,nil | |||
} | |||
func (repo *Repository) changeCollaborationAccessMode(e Engine, uid int64, mode AccessMode) error { | |||
// Discard invalid input | |||
if mode <= AccessModeNone || mode > AccessModeOwner { | |||
@@ -19,6 +19,7 @@ import ( | |||
// GenerateRepoOptions contains the template units to generate | |||
type GenerateRepoOptions struct { | |||
Name string | |||
Alias string | |||
Description string | |||
Private bool | |||
GitContent bool | |||
@@ -48,9 +48,12 @@ func (repos RepositoryList) loadAttributes(e Engine) error { | |||
set := make(map[int64]struct{}) | |||
repoIDs := make([]int64, len(repos)) | |||
setCreator := make(map[int64]struct{}) | |||
for i := range repos { | |||
set[repos[i].OwnerID] = struct{}{} | |||
repoIDs[i] = repos[i].ID | |||
setCreator[repos[i].CreatorID] = struct{}{} | |||
} | |||
// Load owners. | |||
@@ -61,8 +64,18 @@ func (repos RepositoryList) loadAttributes(e Engine) error { | |||
Find(&users); err != nil { | |||
return fmt.Errorf("find users: %v", err) | |||
} | |||
//Load creator | |||
creators := make(map[int64]*User, len(set)) | |||
if err := e. | |||
Where("id > 0"). | |||
In("id", keysInt64(setCreator)). | |||
Find(&creators); err != nil { | |||
return fmt.Errorf("find create repo users: %v", err) | |||
} | |||
for i := range repos { | |||
repos[i].Owner = users[repos[i].OwnerID] | |||
repos[i].Creator = creators[repos[i].CreatorID] | |||
} | |||
// Load primary language. | |||
@@ -174,6 +187,11 @@ type SearchRepoOptions struct { | |||
// True -> include just has milestones | |||
// False -> include just has no milestone | |||
HasMilestones util.OptionalBool | |||
// None -> include all repos | |||
// True -> include just courses | |||
// False -> include just no courses | |||
Course util.OptionalBool | |||
OnlySearchPrivate bool | |||
} | |||
//SearchOrderBy is used to sort the result | |||
@@ -183,31 +201,49 @@ func (s SearchOrderBy) String() string { | |||
return string(s) | |||
} | |||
type FindReposResponse struct { | |||
Repos []*Repository4Card | |||
Page int | |||
PageSize int | |||
Total int64 | |||
} | |||
// Strings for sorting result | |||
const ( | |||
SearchOrderByAlphabetically SearchOrderBy = "name ASC" | |||
SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" | |||
SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" | |||
SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" | |||
SearchOrderByOldest SearchOrderBy = "created_unix ASC" | |||
SearchOrderByNewest SearchOrderBy = "created_unix DESC" | |||
SearchOrderBySize SearchOrderBy = "size ASC" | |||
SearchOrderBySizeReverse SearchOrderBy = "size DESC" | |||
SearchOrderByID SearchOrderBy = "id ASC" | |||
SearchOrderByIDReverse SearchOrderBy = "id DESC" | |||
SearchOrderByStars SearchOrderBy = "num_stars ASC" | |||
SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" | |||
SearchOrderByForks SearchOrderBy = "num_forks ASC" | |||
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" | |||
SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC" | |||
SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" | |||
SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" | |||
SearchOrderByAlphabetically SearchOrderBy = "name ASC" | |||
SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" | |||
SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" | |||
SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" | |||
SearchOrderByOldest SearchOrderBy = "created_unix ASC" | |||
SearchOrderByNewest SearchOrderBy = "created_unix DESC" | |||
SearchOrderBySize SearchOrderBy = "size ASC" | |||
SearchOrderBySizeReverse SearchOrderBy = "size DESC" | |||
SearchOrderByID SearchOrderBy = "id ASC" | |||
SearchOrderByIDReverse SearchOrderBy = "id DESC" | |||
SearchOrderByStars SearchOrderBy = "num_stars ASC" | |||
SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" | |||
SearchOrderByForks SearchOrderBy = "num_forks ASC" | |||
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" | |||
SearchOrderByDownloadTimes SearchOrderBy = "download_times DESC" | |||
SearchOrderByUseCount SearchOrderBy = "use_count ASC" | |||
SearchOrderByUseCountReverse SearchOrderBy = "use_count DESC" | |||
SearchOrderByHot SearchOrderBy = "(num_watches + num_stars + num_forks + clone_cnt) DESC" | |||
SearchOrderByActive SearchOrderBy = "(num_issues + num_pulls + num_commit) DESC" | |||
SearchOrderByWatches SearchOrderBy = "num_watches DESC" | |||
SearchOrderByDefault SearchOrderBy = "recommend desc,num_stars DESC,updated_unix DESC" | |||
SearchOrderByAiTaskCntReverse SearchOrderBy = "ai_task_cnt desc" | |||
SearchOrderByModelCntReverse SearchOrderBy = "model_cnt desc" | |||
SearchOrderByDatasetCntReverse SearchOrderBy = "dataset_cnt desc" | |||
SearchOrderByLastMonthVisitsReverse SearchOrderBy = "last_month_visits desc" | |||
SearchOrderByLastFourMonthCommitsReverse SearchOrderBy = "last_four_month_commits desc" | |||
) | |||
// SearchRepositoryCondition creates a query condition according search repository options | |||
func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { | |||
var cond = builder.NewCond() | |||
if opts.OnlySearchPrivate { | |||
cond = cond.And(builder.Eq{"is_private": true}) | |||
} | |||
if opts.Private { | |||
if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID { | |||
// OK we're in the context of a User | |||
@@ -320,7 +356,8 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { | |||
if !opts.TopicOnly { | |||
var likes = builder.NewCond() | |||
for _, v := range strings.Split(opts.Keyword, ",") { | |||
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"lower_alias", strings.ToLower(v)}) | |||
likes = likes.Or(builder.Like{"alias", v}) | |||
if opts.IncludeDescription { | |||
likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) | |||
} | |||
@@ -350,6 +387,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { | |||
cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue}) | |||
} | |||
if opts.Course == util.OptionalBoolTrue { | |||
cond = cond.And(builder.Eq{"repo_type": RepoCourse}) | |||
} | |||
if opts.Actor != nil && opts.Actor.IsRestricted { | |||
cond = cond.And(accessibleRepositoryCondition(opts.Actor)) | |||
} | |||
@@ -9,42 +9,45 @@ import ( | |||
// RepoStatistic statistic info of all repository | |||
type RepoStatistic struct { | |||
ID int64 `xorm:"pk autoincr" json:"-"` | |||
RepoID int64 `xorm:"unique(s) NOT NULL" json:"repo_id"` | |||
Name string `xorm:"INDEX" json:"name"` | |||
OwnerName string `json:"ownerName"` | |||
IsPrivate bool `json:"isPrivate"` | |||
IsMirror bool `json:"isMirror"` | |||
Date string `xorm:"unique(s) NOT NULL" json:"date"` | |||
NumWatches int64 `xorm:"NOT NULL DEFAULT 0" json:"watch"` | |||
NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumStars int64 `xorm:"NOT NULL DEFAULT 0" json:"star"` | |||
NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumForks int64 `xorm:"NOT NULL DEFAULT 0" json:"fork"` | |||
NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumDownloads int64 `xorm:"NOT NULL DEFAULT 0" json:"download"` | |||
NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumComments int64 `xorm:"NOT NULL DEFAULT 0" json:"comment"` | |||
NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumVisits int64 `xorm:"NOT NULL DEFAULT 0" json:"view"` | |||
NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issueClosed"` | |||
NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumVersions int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
RepoSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
DatasetSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumModels int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommits int64 `xorm:"NOT NULL DEFAULT 0" json:"commit"` | |||
NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issue"` | |||
NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumPulls int64 `xorm:"NOT NULL DEFAULT 0" json:"pr"` | |||
NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
IssueFixedRate float32 `xorm:"NOT NULL" json:"issueClosedRatio"` | |||
NumContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"contributor"` | |||
NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
ID int64 `xorm:"pk autoincr" json:"-"` | |||
RepoID int64 `xorm:"unique(s) NOT NULL" json:"repo_id"` | |||
Name string `xorm:"INDEX" json:"name"` | |||
Alias string `xorm:"INDEX" json:"alias"` | |||
OwnerName string `json:"ownerName"` | |||
IsPrivate bool `json:"isPrivate"` | |||
IsMirror bool `json:"isMirror"` | |||
IsFork bool `json:"isFork"` | |||
RepoCreatedUnix timeutil.TimeStamp `xorm:"NOT NULL DEFAULT 0" json:"createUnix"` | |||
Date string `xorm:"unique(s) NOT NULL" json:"date"` | |||
NumWatches int64 `xorm:"NOT NULL DEFAULT 0" json:"watch"` | |||
NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumStars int64 `xorm:"NOT NULL DEFAULT 0" json:"star"` | |||
NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumForks int64 `xorm:"NOT NULL DEFAULT 0" json:"fork"` | |||
NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumDownloads int64 `xorm:"NOT NULL DEFAULT 0" json:"download"` | |||
NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumComments int64 `xorm:"NOT NULL DEFAULT 0" json:"comment"` | |||
NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumVisits int64 `xorm:"NOT NULL DEFAULT 0" json:"view"` | |||
NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issueClosed"` | |||
NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumVersions int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
RepoSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
DatasetSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumModels int64 `xorm:"NOT NULL DEFAULT 0" json:"model"` | |||
NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommits int64 `xorm:"NOT NULL DEFAULT 0" json:"commit"` | |||
NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issue"` | |||
NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumPulls int64 `xorm:"NOT NULL DEFAULT 0" json:"pr"` | |||
NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
IssueFixedRate float32 `xorm:"NOT NULL" json:"issueClosedRatio"` | |||
NumContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"contributor"` | |||
NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
@@ -52,6 +55,15 @@ type RepoStatistic struct { | |||
NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumDatasetFile int64 `xorm:"NOT NULL DEFAULT 0" json:"datasetFiles"` | |||
NumCloudbrain int64 `xorm:"NOT NULL DEFAULT 0" json:"cloudbrains"` | |||
NumModelConvert int64 `xorm:"NOT NULL DEFAULT 0" json:"modelConverts"` | |||
NumDatasetFileAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumCloudbrainAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"` | |||
NumModelConvertAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"- "` | |||
NumModelsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"- "` | |||
Impact float64 `xorm:"NOT NULL DEFAULT 0" json:"impact"` | |||
Completeness float64 `xorm:"NOT NULL DEFAULT 0" json:"completeness"` | |||
Liveness float64 `xorm:"NOT NULL DEFAULT 0" json:"liveness"` | |||
@@ -63,6 +75,23 @@ type RepoStatistic struct { | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"-"` | |||
} | |||
func (repo *RepoStatistic) DisplayName() string { | |||
if repo.Alias == "" { | |||
return repo.Name | |||
} | |||
return repo.Alias | |||
} | |||
func getOpenIByRepoId(repoId int64) float64 { | |||
repoStatistic := new(RepoStatistic) | |||
has, err := xStatistic.Cols("radar_total").Where("repo_id=?", repoId).Desc("id").Limit(1).Get(repoStatistic) | |||
if !has || err != nil { | |||
return 0 | |||
} | |||
return repoStatistic.RadarTotal | |||
} | |||
func DeleteRepoStatDaily(date string) error { | |||
sess := xStatistic.NewSession() | |||
defer sess.Close() | |||
@@ -180,3 +209,23 @@ func UpdateRepoStatVisits(repoStat *RepoStatistic) error { | |||
_, err := xStatistic.Exec(sql, repoStat.NumVisits, repoStat.RepoID, repoStat.Date) | |||
return err | |||
} | |||
func SumRepoStatColumn(begin, end time.Time, repoId int64, columnName string) (int64, error) { | |||
res, err := xStatistic.Where("created_unix <= ? and created_unix >= ? and repo_id = ? ", end.Unix(), begin.Unix(), repoId).Sum(&RepoStatistic{}, columnName) | |||
if err != nil { | |||
return 0, err | |||
} | |||
return int64(res), nil | |||
} | |||
func SumLastMonthNumVisits(repoId int64) (int64, error) { | |||
end := time.Now() | |||
begin := end.AddDate(0, 0, -30) | |||
return SumRepoStatColumn(begin, end, repoId, "num_visits") | |||
} | |||
func SumLastFourMonthNumCommits(repoId int64) (int64, error) { | |||
end := time.Now() | |||
begin := end.AddDate(0, 0, -120) | |||
return SumRepoStatColumn(begin, end, repoId, "num_commits_added") | |||
} |
@@ -4,6 +4,7 @@ import ( | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"fmt" | |||
"xorm.io/builder" | |||
) | |||
type OfficialTag struct { | |||
@@ -28,6 +29,7 @@ type OfficialTagRepos struct { | |||
type TagReposBrief struct { | |||
RepoID int64 | |||
RepoName string | |||
Alias string | |||
TagID int64 | |||
} | |||
@@ -41,7 +43,7 @@ type TagsDetail struct { | |||
TagId int64 | |||
TagName string | |||
TagLimit int | |||
RepoList []Repository | |||
RepoList []*Repository | |||
} | |||
func GetTagByID(id int64) (*OfficialTag, error) { | |||
@@ -97,7 +99,7 @@ func UpdateTagReposByID(tagID, orgID int64, repoIdList []int64) error { | |||
func GetTagRepos(tagID, orgID int64) ([]TagReposSelected, error) { | |||
t := make([]TagReposBrief, 0) | |||
const SQLCmd = "select t1.id as repo_id,t1.name as repo_name,t2.id as tag_id from repository t1 left join official_tag_repos t2 on (t1.id = t2.repo_id and t2.tag_id = ?) where t1.owner_id = ? and t1.is_private = false order by t1.updated_unix desc" | |||
const SQLCmd = "select t1.id as repo_id,t1.name as repo_name,t1.alias,t2.id as tag_id from repository t1 left join official_tag_repos t2 on (t1.id = t2.repo_id and t2.tag_id = ?) where t1.owner_id = ? and t1.is_private = false order by t1.updated_unix desc" | |||
if err := x.SQL(SQLCmd, tagID, orgID).Find(&t); err != nil { | |||
return nil, err | |||
@@ -108,9 +110,13 @@ func GetTagRepos(tagID, orgID int64) ([]TagReposSelected, error) { | |||
if v.TagID > 0 { | |||
selected = true | |||
} | |||
repoName := v.Alias | |||
if v.Alias == "" { | |||
repoName = v.RepoName | |||
} | |||
r = append(r, TagReposSelected{ | |||
RepoID: v.RepoID, | |||
RepoName: v.RepoName, | |||
RepoName: repoName, | |||
Selected: selected, | |||
}) | |||
} | |||
@@ -141,8 +147,8 @@ func GetAllOfficialTagRepos(orgID int64, isOwner bool) ([]TagsDetail, error) { | |||
return result, nil | |||
} | |||
func GetOfficialTagDetail(orgID, tagId int64) ([]Repository, error) { | |||
t := make([]Repository, 0) | |||
func GetOfficialTagDetail(orgID, tagId int64) ([]*Repository, error) { | |||
t := make([]*Repository, 0) | |||
const SQLCmd = "select t2.* from official_tag_repos t1 inner join repository t2 on t1.repo_id = t2.id where t1.org_id = ? and t1.tag_id=? order by t2.updated_unix desc" | |||
if err := x.SQL(SQLCmd, orgID, tagId).Find(&t); err != nil { | |||
@@ -161,3 +167,33 @@ func GetAllOfficialTags() ([]OfficialTag, error) { | |||
} | |||
return o, nil | |||
} | |||
type FindSelectedReposOpts struct { | |||
ListOptions | |||
OrgId int64 | |||
OnlyPublic bool | |||
} | |||
func GetSelectedRepos(opts FindSelectedReposOpts) ([]*Repository, error) { | |||
if opts.Page < 1 { | |||
opts.Page = 1 | |||
} | |||
var cond = builder.NewCond() | |||
cond = cond.And(builder.Eq{"official_tag.code": "selected"}) | |||
if opts.OrgId > 0 { | |||
cond = cond.And(builder.Eq{"official_tag_repos.org_id": opts.OrgId}) | |||
} | |||
if opts.OnlyPublic { | |||
cond = cond.And(builder.Eq{"repository.is_private": false}) | |||
} | |||
t := make([]*Repository, 0) | |||
err := x.Join("inner", "official_tag_repos", "repository.id = official_tag_repos.repo_id"). | |||
Join("inner", "official_tag", "official_tag.id = official_tag_repos.tag_id"). | |||
Where(cond).OrderBy("repository.updated_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&t) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return t, nil | |||
} |
@@ -24,7 +24,16 @@ const ( | |||
RepoWatchModeAuto // 3 | |||
) | |||
// NotifyType specifies what kind of watch the user has on a repository | |||
type NotifyType int8 | |||
const ( | |||
RejectAllNotification NotifyType = 0 | |||
ReceiveAllNotification NotifyType = 9 | |||
) | |||
var ActionChan = make(chan *Action, 200) | |||
var ActionChan4Task = make(chan Action, 200) | |||
// Watch is connection request for receiving repository notification. | |||
type Watch struct { | |||
@@ -33,6 +42,7 @@ type Watch struct { | |||
RepoID int64 `xorm:"UNIQUE(watch)"` | |||
Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"` | |||
CreatedUnix int64 `xorm:"created"` | |||
NotifyType NotifyType `xorm:"SMALLINT NOT NULL DEFAULT 0"` | |||
} | |||
// getWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found | |||
@@ -59,8 +69,20 @@ func IsWatching(userID, repoID int64) bool { | |||
return err == nil && isWatchMode(watch.Mode) | |||
} | |||
// GetWatchNotifyType | |||
func GetWatchNotifyType(userID, repoID int64) NotifyType { | |||
watch, err := getWatch(x, userID, repoID) | |||
if err != nil { | |||
return RejectAllNotification | |||
} | |||
return watch.NotifyType | |||
} | |||
func watchRepoMode(e Engine, watch Watch, mode RepoWatchMode) (err error) { | |||
if watch.Mode == mode { | |||
if _, err := e.ID(watch.ID).Cols("notify_type").Update(watch); err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
if mode == RepoWatchModeAuto && (watch.Mode == RepoWatchModeDont || isWatchMode(watch.Mode)) { | |||
@@ -108,7 +130,7 @@ func WatchRepoMode(userID, repoID int64, mode RepoWatchMode) (err error) { | |||
return watchRepoMode(x, watch, mode) | |||
} | |||
func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) { | |||
func watchRepo(e Engine, userID, repoID int64, doWatch bool, notifyTypes ...NotifyType) (err error) { | |||
var watch Watch | |||
if watch, err = getWatch(e, userID, repoID); err != nil { | |||
return err | |||
@@ -118,14 +140,19 @@ func watchRepo(e Engine, userID, repoID int64, doWatch bool) (err error) { | |||
} else if !doWatch { | |||
err = watchRepoMode(e, watch, RepoWatchModeNone) | |||
} else { | |||
notifyType := RejectAllNotification | |||
if len(notifyTypes) > 0 { | |||
notifyType = notifyTypes[0] | |||
} | |||
watch.NotifyType = notifyType | |||
err = watchRepoMode(e, watch, RepoWatchModeNormal) | |||
} | |||
return err | |||
} | |||
// WatchRepo watch or unwatch repository. | |||
func WatchRepo(userID, repoID int64, watch bool) (err error) { | |||
return watchRepo(x, userID, repoID, watch) | |||
func WatchRepo(userID, repoID int64, watch bool, notifyType ...NotifyType) (err error) { | |||
return watchRepo(x, userID, repoID, watch, notifyType...) | |||
} | |||
func getWatchers(e Engine, repoID int64) ([]*Watch, error) { | |||
@@ -155,6 +182,7 @@ func getRepoWatchersIDs(e Engine, repoID int64) ([]int64, error) { | |||
return ids, e.Table("watch"). | |||
Where("watch.repo_id=?", repoID). | |||
And("watch.mode<>?", RepoWatchModeDont). | |||
And("watch.notify_type > ?", RejectAllNotification). | |||
Select("user_id"). | |||
Find(&ids) | |||
} | |||
@@ -182,6 +210,7 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
var permCode []bool | |||
var permIssue []bool | |||
var permPR []bool | |||
var permDataset []bool | |||
for _, act := range actions { | |||
repoChanged := repo == nil || repo.ID != act.RepoID | |||
@@ -199,6 +228,14 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
if _, err = e.InsertOne(act); err != nil { | |||
return fmt.Errorf("insert new actioner: %v", err) | |||
} | |||
// After InsertOne(act),the act has ID | |||
// Send the act to task chan | |||
ActionChan4Task <- *act | |||
// If it has nothing to do with repo, return directly | |||
if act.Repo == nil && act.RepoID == 0 { | |||
return nil | |||
} | |||
if repoChanged { | |||
act.loadRepo() | |||
@@ -225,12 +262,14 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
permCode = make([]bool, len(watchers)) | |||
permIssue = make([]bool, len(watchers)) | |||
permPR = make([]bool, len(watchers)) | |||
permDataset = make([]bool, len(watchers)) | |||
for i, watcher := range watchers { | |||
user, err := getUserByID(e, watcher.UserID) | |||
if err != nil { | |||
permCode[i] = false | |||
permIssue[i] = false | |||
permPR[i] = false | |||
permDataset[i] = false | |||
continue | |||
} | |||
perm, err := getUserRepoPermission(e, repo, user) | |||
@@ -238,11 +277,13 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
permCode[i] = false | |||
permIssue[i] = false | |||
permPR[i] = false | |||
permDataset[i] = false | |||
continue | |||
} | |||
permCode[i] = perm.CanRead(UnitTypeCode) | |||
permIssue[i] = perm.CanRead(UnitTypeIssues) | |||
permPR[i] = perm.CanRead(UnitTypePullRequests) | |||
permDataset[i] = perm.CanRead(UnitTypeDatasets) | |||
} | |||
} | |||
@@ -267,6 +308,10 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
if !permPR[i] { | |||
continue | |||
} | |||
case ActionDatasetRecommended: | |||
if !permDataset[i] { | |||
continue | |||
} | |||
} | |||
if _, err = e.InsertOne(act); err != nil { | |||
@@ -279,14 +324,16 @@ func notifyWatchers(e Engine, actions ...*Action) error { | |||
// NotifyWatchers creates batch of actions for every watcher. | |||
func NotifyWatchers(actions ...*Action) error { | |||
error := notifyWatchers(x, actions...) | |||
producer(actions...) | |||
return notifyWatchers(x, actions...) | |||
return error | |||
} | |||
func producer(actions ...*Action) { | |||
for _, action := range actions { | |||
ActionChan <- action | |||
if !action.IsPrivate { | |||
ActionChan <- action | |||
} | |||
} | |||
} | |||
@@ -302,7 +349,10 @@ func NotifyWatchersActions(acts []*Action) error { | |||
return err | |||
} | |||
} | |||
return sess.Commit() | |||
err := sess.Commit() | |||
producer(acts...) | |||
return err | |||
} | |||
func watchIfAuto(e Engine, userID, repoID int64, isWrite bool) error { | |||
@@ -0,0 +1,351 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"errors" | |||
"strconv" | |||
"strings" | |||
"xorm.io/builder" | |||
) | |||
type ResourceQueue struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
QueueCode string | |||
Cluster string `xorm:"notnull"` | |||
AiCenterCode string | |||
AiCenterName string | |||
ComputeResource string | |||
AccCardType string | |||
CardsTotalNum int | |||
IsAutomaticSync bool | |||
Remark string | |||
DeletedTime timeutil.TimeStamp `xorm:"deleted"` | |||
CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
CreatedBy int64 | |||
UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
UpdatedBy int64 | |||
} | |||
func (r ResourceQueue) ConvertToRes() *ResourceQueueRes { | |||
return &ResourceQueueRes{ | |||
ID: r.ID, | |||
QueueCode: r.QueueCode, | |||
Cluster: r.Cluster, | |||
AiCenterCode: r.AiCenterCode, | |||
AiCenterName: r.AiCenterName, | |||
ComputeResource: r.ComputeResource, | |||
AccCardType: r.AccCardType, | |||
CardsTotalNum: r.CardsTotalNum, | |||
UpdatedTime: r.UpdatedTime, | |||
Remark: r.Remark, | |||
} | |||
} | |||
type ResourceQueueReq struct { | |||
QueueCode string | |||
Cluster string `binding:"Required"` | |||
AiCenterCode string | |||
ComputeResource string `binding:"Required"` | |||
AccCardType string `binding:"Required"` | |||
CardsTotalNum int | |||
CreatorId int64 | |||
IsAutomaticSync bool | |||
Remark string | |||
} | |||
func (r ResourceQueueReq) ToDTO() ResourceQueue { | |||
q := ResourceQueue{ | |||
QueueCode: r.QueueCode, | |||
Cluster: r.Cluster, | |||
AiCenterCode: r.AiCenterCode, | |||
ComputeResource: strings.ToUpper(r.ComputeResource), | |||
AccCardType: strings.ToUpper(r.AccCardType), | |||
CardsTotalNum: r.CardsTotalNum, | |||
IsAutomaticSync: r.IsAutomaticSync, | |||
Remark: r.Remark, | |||
CreatedBy: r.CreatorId, | |||
UpdatedBy: r.CreatorId, | |||
} | |||
if r.Cluster == OpenICluster { | |||
if r.AiCenterCode == AICenterOfCloudBrainOne { | |||
q.AiCenterName = "云脑一" | |||
} else if r.AiCenterCode == AICenterOfCloudBrainTwo { | |||
q.AiCenterName = "云脑二" | |||
} else if r.AiCenterCode == AICenterOfChengdu { | |||
q.AiCenterName = "启智成都智算" | |||
} | |||
} | |||
return q | |||
} | |||
type SearchResourceQueueOptions struct { | |||
ListOptions | |||
Cluster string | |||
AiCenterCode string | |||
ComputeResource string | |||
AccCardType string | |||
} | |||
type ResourceQueueListRes struct { | |||
TotalSize int64 | |||
List []*ResourceQueueRes | |||
} | |||
type ResourceQueueCodesRes struct { | |||
ID int64 | |||
QueueCode string | |||
Cluster string | |||
AiCenterCode string | |||
AiCenterName string | |||
} | |||
func (ResourceQueueCodesRes) TableName() string { | |||
return "resource_queue" | |||
} | |||
type ResourceAiCenterRes struct { | |||
AiCenterCode string | |||
AiCenterName string | |||
} | |||
type GetQueueCodesOptions struct { | |||
Cluster string | |||
} | |||
func NewResourceQueueListRes(totalSize int64, list []ResourceQueue) *ResourceQueueListRes { | |||
resList := make([]*ResourceQueueRes, len(list)) | |||
for i, v := range list { | |||
resList[i] = v.ConvertToRes() | |||
} | |||
return &ResourceQueueListRes{ | |||
TotalSize: totalSize, | |||
List: resList, | |||
} | |||
} | |||
type ResourceQueueRes struct { | |||
ID int64 | |||
QueueCode string | |||
Cluster string | |||
AiCenterCode string | |||
AiCenterName string | |||
ComputeResource string | |||
AccCardType string | |||
CardsTotalNum int | |||
UpdatedTime timeutil.TimeStamp | |||
Remark string | |||
} | |||
func InsertResourceQueue(queue ResourceQueue) (int64, error) { | |||
return x.Insert(&queue) | |||
} | |||
func UpdateResourceQueueById(queueId int64, queue ResourceQueue) (int64, error) { | |||
return x.ID(queueId).Update(&queue) | |||
} | |||
func UpdateResourceCardsTotalNum(queueId int64, queue ResourceQueue) (int64, error) { | |||
return x.ID(queueId).Cols("cards_total_num", "remark").Update(&queue) | |||
} | |||
func SearchResourceQueue(opts SearchResourceQueueOptions) (int64, []ResourceQueue, error) { | |||
var cond = builder.NewCond() | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
} | |||
if opts.Cluster != "" { | |||
cond = cond.And(builder.Eq{"cluster": opts.Cluster}) | |||
} | |||
if opts.AiCenterCode != "" { | |||
cond = cond.And(builder.Eq{"ai_center_code": opts.AiCenterCode}) | |||
} | |||
if opts.ComputeResource != "" { | |||
cond = cond.And(builder.Eq{"compute_resource": opts.ComputeResource}) | |||
} | |||
if opts.AccCardType != "" { | |||
cond = cond.And(builder.Eq{"acc_card_type": opts.AccCardType}) | |||
} | |||
n, err := x.Where(cond).Unscoped().Count(&ResourceQueue{}) | |||
if err != nil { | |||
return 0, nil, err | |||
} | |||
r := make([]ResourceQueue, 0) | |||
err = x.Where(cond).Desc("id").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Unscoped().Find(&r) | |||
if err != nil { | |||
return 0, nil, err | |||
} | |||
return n, r, nil | |||
} | |||
func GetResourceQueueCodes(opts GetQueueCodesOptions) ([]*ResourceQueueCodesRes, error) { | |||
cond := builder.NewCond() | |||
if opts.Cluster != "" { | |||
cond = cond.And(builder.Eq{"cluster": opts.Cluster}) | |||
} | |||
cond = cond.And(builder.Or(builder.IsNull{"deleted_time"}, builder.Eq{"deleted_time": 0})) | |||
r := make([]*ResourceQueueCodesRes, 0) | |||
err := x.Where(cond).OrderBy("cluster desc,ai_center_code asc").Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return r, nil | |||
} | |||
func GetResourceQueue(r *ResourceQueue) (*ResourceQueue, error) { | |||
has, err := x.Get(r) | |||
if err != nil { | |||
return nil, err | |||
} else if !has { | |||
return nil, nil | |||
} | |||
return r, nil | |||
} | |||
func ParseComputeResourceFormGrampus(grampusDeviceKind string) string { | |||
t := strings.Split(grampusDeviceKind, "/") | |||
if len(t) < 2 { | |||
return "" | |||
} | |||
return strings.ToUpper(t[1]) | |||
} | |||
type MemSize struct { | |||
Sizes []string | |||
Hex int | |||
} | |||
var memSize = MemSize{Sizes: []string{"K", "M", "G", "T", "P", "E"}, Hex: 1000} | |||
var iMemSize = MemSize{Sizes: []string{"Ki", "Mi", "Gi", "Ti", "Pi", "Ei"}, Hex: 1024} | |||
func MatchMemSize(memSize MemSize, val string) (int, float32, error) { | |||
for i, v := range memSize.Sizes { | |||
if strings.HasSuffix(val, v) { | |||
s := strings.TrimSuffix(val, v) | |||
f, err := strconv.ParseFloat(s, 32) | |||
if err != nil { | |||
return 0, 0, err | |||
} | |||
return i, float32(f), nil | |||
} | |||
} | |||
return -1, 0, nil | |||
} | |||
//TransferMemSize transfer oldValue format from old index to new index | |||
//eg: memSize.Sizes = []string{"M", "G", "T", "P", "E"}, oldValue = 10 , oldIndex = 1 , newIndex = 0. it means transfer 10G to 10000M | |||
//so it returns 10000 | |||
func TransferMemSize(memSize MemSize, oldValue float32, oldIndex int, newIndex int) float32 { | |||
diff := oldIndex - newIndex | |||
r := oldValue | |||
if diff > 0 { | |||
r = oldValue * float32(diff) * float32(memSize.Hex) | |||
} else if diff < 0 { | |||
r = oldValue / float32(-1*diff) / float32(memSize.Hex) | |||
} | |||
return r | |||
} | |||
//ParseMemSize find the memSize which matches value's format,and parse the number from value | |||
func ParseMemSize(value string, memSize MemSize, newIndex int) (bool, float32, error) { | |||
index, r, err := MatchMemSize(memSize, value) | |||
if err != nil { | |||
return false, 0, err | |||
} | |||
if index < 0 { | |||
return false, 0, nil | |||
} | |||
return true, TransferMemSize(memSize, r, index, newIndex), nil | |||
} | |||
func ParseMemSizeFromGrampus(grampusMemSize string) (float32, error) { | |||
if grampusMemSize == "" { | |||
return 0, nil | |||
} | |||
memflag, memResult, err := ParseMemSize(grampusMemSize, memSize, 2) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if memflag { | |||
return memResult, nil | |||
} | |||
iMemFlag, imemResult, err := ParseMemSize(grampusMemSize, iMemSize, 2) | |||
if err != nil { | |||
return 0, err | |||
} | |||
if iMemFlag { | |||
return imemResult, nil | |||
} | |||
return 0, errors.New("grampus memSize format error") | |||
} | |||
func SyncGrampusQueues(updateList []ResourceQueue, insertList []ResourceQueue, existIds []int64) error { | |||
sess := x.NewSession() | |||
var err error | |||
defer func() { | |||
if err != nil { | |||
sess.Rollback() | |||
} | |||
sess.Close() | |||
}() | |||
//delete queues that no longer exists | |||
deleteQueueIds := make([]int64, 0) | |||
queueCond := builder.NewCond() | |||
queueCond = queueCond.And(builder.NotIn("resource_queue.id", existIds)).And(builder.Eq{"resource_queue.cluster": C2NetCluster}) | |||
if err := sess.Cols("resource_queue.id").Table("resource_queue"). | |||
Where(queueCond).Find(&deleteQueueIds); err != nil { | |||
return err | |||
} | |||
if len(deleteQueueIds) > 0 { | |||
if _, err = sess.In("id", deleteQueueIds).Update(&ResourceQueue{Remark: "自动同步时被下架"}); err != nil { | |||
return err | |||
} | |||
if _, err = sess.In("id", deleteQueueIds).Delete(&ResourceQueue{}); err != nil { | |||
return err | |||
} | |||
//delete specs and scene that no longer exists | |||
deleteSpcIds := make([]int64, 0) | |||
if err := sess.Cols("resource_specification.id").Table("resource_specification"). | |||
In("queue_id", deleteQueueIds).Find(&deleteSpcIds); err != nil { | |||
return err | |||
} | |||
if len(deleteSpcIds) > 0 { | |||
if _, err = sess.In("id", deleteSpcIds).Update(&ResourceSpecification{Status: SpecOffShelf}); err != nil { | |||
return err | |||
} | |||
} | |||
} | |||
//update exists specs | |||
if len(updateList) > 0 { | |||
for _, v := range updateList { | |||
if _, err = sess.ID(v.ID).Update(&v); err != nil { | |||
return err | |||
} | |||
} | |||
} | |||
//insert new specs | |||
if len(insertList) > 0 { | |||
if _, err = sess.Insert(insertList); err != nil { | |||
return err | |||
} | |||
} | |||
return sess.Commit() | |||
} | |||
func GetResourceAiCenters() ([]ResourceAiCenterRes, error) { | |||
r := make([]ResourceAiCenterRes, 0) | |||
err := x.SQL("SELECT t.ai_center_code, t.ai_center_name FROM (SELECT DISTINCT ai_center_code, ai_center_name,cluster FROM resource_queue WHERE (deleted_time IS NULL OR deleted_time=0)) t ORDER BY cluster desc,ai_center_code asc").Find(&r) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return r, nil | |||
} |
@@ -0,0 +1,329 @@ | |||
package models | |||
import ( | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"errors" | |||
"xorm.io/builder" | |||
) | |||
const ( | |||
Exclusive = iota + 1 | |||
NotExclusive | |||
) | |||
type ResourceScene struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
SceneName string | |||
JobType string | |||
IsExclusive bool | |||
ExclusiveOrg string | |||
CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
CreatedBy int64 | |||
UpdatedTime timeutil.TimeStamp `xorm:"updated"` | |||
UpdatedBy int64 | |||
DeleteTime timeutil.TimeStamp `xorm:"deleted"` | |||
DeletedBy int64 | |||
} | |||
type ResourceSceneSpec struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
SceneId int64 `xorm:"unique(idx_scene_spec)"` | |||
SpecId int64 `xorm:"unique(idx_scene_spec)"` | |||
CreatedTime timeutil.TimeStamp `xorm:"created"` | |||
} | |||
type ResourceSceneReq struct { | |||
ID int64 | |||
SceneName string | |||
JobType string | |||
IsExclusive bool | |||
ExclusiveOrg string | |||
CreatorId int64 | |||
SpecIds []int64 | |||
} | |||
type SearchResourceSceneOptions struct { | |||
ListOptions | |||
JobType string | |||
IsExclusive int | |||
AiCenterCode string | |||
QueueId int64 | |||
} | |||
type ResourceSceneListRes struct { | |||
TotalSize int64 | |||
List []ResourceSceneRes | |||
} | |||
func NewResourceSceneListRes(totalSize int64, list []ResourceSceneRes) *ResourceSceneListRes { | |||
return &ResourceSceneListRes{ | |||
TotalSize: totalSize, | |||
List: list, | |||
} | |||
} | |||
type ResourceSceneRes struct { | |||
ID int64 | |||
SceneName string | |||
JobType JobType | |||
IsExclusive bool | |||
ExclusiveOrg string | |||
Specs []ResourceSpecWithSceneId | |||
} | |||
func (ResourceSceneRes) TableName() string { | |||
return "resource_scene" | |||
} | |||
type ResourceSceneBriefRes struct { | |||
ID int64 | |||
SceneName string | |||
} | |||
func (ResourceSceneBriefRes) TableName() string { | |||
return "resource_scene" | |||
} | |||
type ResourceSpecWithSceneId struct { | |||
ID int64 | |||
SourceSpecId string | |||
AccCardsNum int | |||
CpuCores int | |||
MemGiB float32 | |||
GPUMemGiB float32 | |||
ShareMemGiB float32 | |||
UnitPrice int | |||
Status int | |||
UpdatedTime timeutil.TimeStamp | |||
SceneId int64 | |||
//queue | |||
Cluster string | |||
AiCenterCode string | |||
AiCenterName string | |||
QueueCode string | |||
QueueId int64 | |||
ComputeResource string | |||
AccCardType string | |||
} | |||
func (ResourceSpecWithSceneId) TableName() string { | |||
return "resource_specification" | |||
} | |||
func InsertResourceScene(r ResourceSceneReq) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
//check | |||
specs := make([]ResourceSpecification, 0) | |||
cond := builder.In("id", r.SpecIds) | |||
if err := sess.Where(cond).Find(&specs); err != nil { | |||
return err | |||
} | |||
if len(specs) < len(r.SpecIds) { | |||
return errors.New("specIds not correct") | |||
} | |||
rs := ResourceScene{ | |||
SceneName: r.SceneName, | |||
JobType: r.JobType, | |||
IsExclusive: r.IsExclusive, | |||
ExclusiveOrg: r.ExclusiveOrg, | |||
CreatedBy: r.CreatorId, | |||
UpdatedBy: r.CreatorId, | |||
} | |||
_, err := sess.InsertOne(&rs) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
if len(r.SpecIds) == 0 { | |||
return sess.Commit() | |||
} | |||
rss := make([]ResourceSceneSpec, len(r.SpecIds)) | |||
for i, v := range r.SpecIds { | |||
rss[i] = ResourceSceneSpec{ | |||
SceneId: rs.ID, | |||
SpecId: v, | |||
} | |||
} | |||
_, err = sess.Insert(&rss) | |||
if err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
func UpdateResourceScene(r ResourceSceneReq) error { | |||
sess := x.NewSession() | |||
var err error | |||
defer func() { | |||
if err != nil { | |||
sess.Rollback() | |||
} | |||
sess.Close() | |||
}() | |||
// find old scene | |||
old := ResourceScene{} | |||
if has, _ := sess.ID(r.ID).Get(&old); !has { | |||
return errors.New("ResourceScene not exist") | |||
} | |||
//check specification | |||
specs := make([]ResourceSpecification, 0) | |||
cond := builder.In("id", r.SpecIds) | |||
if err := sess.Where(cond).Find(&specs); err != nil { | |||
return err | |||
} | |||
if len(specs) < len(r.SpecIds) { | |||
return errors.New("specIds not correct") | |||
} | |||
//update scene | |||
rs := ResourceScene{ | |||
SceneName: r.SceneName, | |||
IsExclusive: r.IsExclusive, | |||
ExclusiveOrg: r.ExclusiveOrg, | |||
} | |||
if _, err = sess.ID(r.ID).UseBool("is_exclusive").Update(&rs); err != nil { | |||
return err | |||
} | |||
//delete scene spec relation | |||
if _, err = sess.Where("scene_id = ? ", r.ID).Delete(&ResourceSceneSpec{}); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
if len(r.SpecIds) == 0 { | |||
return sess.Commit() | |||
} | |||
//build new scene spec relation | |||
rss := make([]ResourceSceneSpec, len(r.SpecIds)) | |||
for i, v := range r.SpecIds { | |||
rss[i] = ResourceSceneSpec{ | |||
SceneId: r.ID, | |||
SpecId: v, | |||
} | |||
} | |||
if _, err = sess.Insert(&rss); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
func DeleteResourceScene(sceneId int64) error { | |||
sess := x.NewSession() | |||
var err error | |||
defer func() { | |||
if err != nil { | |||
sess.Rollback() | |||
} | |||
sess.Close() | |||
}() | |||
if _, err = sess.ID(sceneId).Delete(&ResourceScene{}); err != nil { | |||
return err | |||
} | |||
if _, err = sess.Where("scene_id = ? ", sceneId).Delete(&ResourceSceneSpec{}); err != nil { | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
func SearchResourceScene(opts SearchResourceSceneOptions) (int64, []ResourceSceneRes, error) { | |||
var cond = builder.NewCond() | |||
if opts.Page <= 0 { | |||
opts.Page = 1 | |||
} | |||
if opts.JobType != "" { | |||
cond = cond.And(builder.Eq{"resource_scene.job_type": opts.JobType}) | |||
} | |||
if opts.IsExclusive == Exclusive { | |||
cond = cond.And(builder.Eq{"resource_scene.is_exclusive": 1}) | |||
} else if opts.IsExclusive == NotExclusive { | |||
cond = cond.And(builder.Eq{"resource_scene.is_exclusive": 0}) | |||
} | |||
if opts.AiCenterCode != "" { | |||
cond = cond.And(builder.Eq{"resource_queue.ai_center_code": opts.AiCenterCode}) | |||
} | |||
if opts.QueueId > 0 { | |||
cond = cond.And(builder.Eq{"resource_queue.id": opts.QueueId}) | |||
} | |||
cond = cond.And(builder.NewCond().Or(builder.Eq{"resource_scene.delete_time": 0}).Or(builder.IsNull{"resource_scene.delete_time"})) | |||
cols := []string{"resource_scene.id", "resource_scene.scene_name", "resource_scene.job_type", "resource_scene.is_exclusive", | |||
"resource_scene.exclusive_org"} | |||
count, err := x.Where(cond). | |||
Distinct("resource_scene.id"). | |||
Join("INNER", "resource_scene_spec", "resource_scene_spec.scene_id = resource_scene.id"). | |||
Join("INNER", "resource_specification", "resource_specification.id = resource_scene_spec.spec_id"). | |||
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id"). | |||
Count(&ResourceSceneRes{}) | |||
if err != nil { | |||
return 0, nil, err | |||
} | |||
r := make([]ResourceSceneRes, 0) | |||
if err = x.Where(cond).Distinct(cols...). | |||
Join("INNER", "resource_scene_spec", "resource_scene_spec.scene_id = resource_scene.id"). | |||
Join("INNER", "resource_specification", "resource_specification.id = resource_scene_spec.spec_id"). | |||
Join("INNER", "resource_queue", "resource_queue.id = resource_specification.queue_id"). | |||
Desc("resource_scene.id"). | |||
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize). | |||
Find(&r); err != nil { | |||
return 0, nil, err | |||
} | |||
if len(r) == 0 { | |||
return 0, r, err | |||
} | |||
//find related specs | |||
sceneIds := make([]int64, 0, len(r)) | |||
for _, v := range r { | |||
sceneIds = append(sceneIds, v.ID) | |||
} | |||
specs := make([]ResourceSpecWithSceneId, 0) | |||
if err := x.Cols("resource_specification.id", "resource_specification.source_spec_id", | |||
"resource_specification.acc_cards_num", "resource_specification.cpu_cores", | |||
"resource_specification.mem_gi_b", "resource_specification.gpu_mem_gi_b", | |||
"resource_specification.share_mem_gi_b", "resource_specification.unit_price", | |||
"resource_specification.status", "resource_specification.updated_time", | |||
"resource_scene_spec.scene_id", "resource_queue.cluster", | |||
"resource_queue.ai_center_code", "resource_queue.acc_card_type", | |||
"resource_queue.id as queue_id", "resource_queue.compute_resource", | |||
"resource_queue.queue_code", "resource_queue.ai_center_name", | |||
).In("resource_scene_spec.scene_id", sceneIds). | |||
Join("INNER", "resource_scene_spec", "resource_scene_spec.spec_id = resource_specification.id"). | |||
Join("INNER", "resource_queue", "resource_queue.ID = resource_specification.queue_id"). | |||
OrderBy("resource_specification.acc_cards_num"). | |||
Find(&specs); err != nil { | |||
return 0, nil, err | |||
} | |||
specsMap := make(map[int64][]ResourceSpecWithSceneId, 0) | |||
for _, v := range specs { | |||
if _, ok := specsMap[v.SceneId]; !ok { | |||
specsMap[v.SceneId] = []ResourceSpecWithSceneId{v} | |||
} else { | |||
specsMap[v.SceneId] = append(specsMap[v.SceneId], v) | |||
} | |||
} | |||
for i, v := range r { | |||
s := specsMap[v.ID] | |||
if s == nil { | |||
s = make([]ResourceSpecWithSceneId, 0) | |||
} | |||
r[i].Specs = s | |||
} | |||
return count, r, nil | |||
} |
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》