Browse Source

Merge pull request '合入 #2414, #2183, #2170' (#2480) from zouap_static into V20220718

Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/2480
Reviewed-by: lewis <747342561@qq.com>
fix-2452
lewis 2 years ago
parent
commit
e2c5dceee5
61 changed files with 14197 additions and 278 deletions
  1. +252
    -3
      models/ai_model_manage.go
  2. +52
    -11
      models/cloudbrain.go
  3. +1
    -0
      models/models.go
  4. +1
    -1
      models/user_business_analysis.go
  5. +201
    -32
      modules/modelarts/modelarts.go
  6. +111
    -0
      modules/modelarts/resty.go
  7. +44
    -3
      modules/setting/setting.go
  8. +43
    -0
      modules/storage/minio_ext.go
  9. +77
    -7
      modules/storage/obs.go
  10. +8
    -0
      options/locale/locale_en-US.ini
  11. +8
    -0
      options/locale/locale_zh-CN.ini
  12. +386
    -0
      public/self/ztree/css/awesomeStyle/awesome.css
  13. +146
    -0
      public/self/ztree/css/awesomeStyle/awesome.less
  14. +480
    -0
      public/self/ztree/css/awesomeStyle/fa.less
  15. BIN
      public/self/ztree/css/awesomeStyle/img/loading.gif
  16. +33
    -0
      public/self/ztree/css/demo.css
  17. BIN
      public/self/ztree/css/metroStyle/img/line_conn.png
  18. BIN
      public/self/ztree/css/metroStyle/img/loading.gif
  19. BIN
      public/self/ztree/css/metroStyle/img/metro.gif
  20. BIN
      public/self/ztree/css/metroStyle/img/metro.png
  21. +96
    -0
      public/self/ztree/css/metroStyle/metroStyle.css
  22. BIN
      public/self/ztree/css/zTreeStyle/img/diy/1_close.png
  23. BIN
      public/self/ztree/css/zTreeStyle/img/diy/1_open.png
  24. BIN
      public/self/ztree/css/zTreeStyle/img/diy/2.png
  25. BIN
      public/self/ztree/css/zTreeStyle/img/diy/3.png
  26. BIN
      public/self/ztree/css/zTreeStyle/img/diy/4.png
  27. BIN
      public/self/ztree/css/zTreeStyle/img/diy/5.png
  28. BIN
      public/self/ztree/css/zTreeStyle/img/diy/6.png
  29. BIN
      public/self/ztree/css/zTreeStyle/img/diy/7.png
  30. BIN
      public/self/ztree/css/zTreeStyle/img/diy/8.png
  31. BIN
      public/self/ztree/css/zTreeStyle/img/diy/9.png
  32. BIN
      public/self/ztree/css/zTreeStyle/img/line_conn.gif
  33. BIN
      public/self/ztree/css/zTreeStyle/img/loading.gif
  34. BIN
      public/self/ztree/css/zTreeStyle/img/zTreeStandard.gif
  35. BIN
      public/self/ztree/css/zTreeStyle/img/zTreeStandard.png
  36. +99
    -0
      public/self/ztree/css/zTreeStyle/zTreeStyle.css
  37. +167
    -0
      public/self/ztree/js/jquery-1.4.4.min.js
  38. +3878
    -0
      public/self/ztree/js/jquery.ztree.all.js
  39. +2019
    -0
      public/self/ztree/js/jquery.ztree.core.js
  40. +652
    -0
      public/self/ztree/js/jquery.ztree.excheck.js
  41. +1207
    -0
      public/self/ztree/js/jquery.ztree.exedit.js
  42. +405
    -0
      public/self/ztree/js/jquery.ztree.exhide.js
  43. +6
    -0
      routers/api/v1/api.go
  44. +192
    -14
      routers/api/v1/repo/cloudbrain.go
  45. +72
    -2
      routers/api/v1/repo/modelarts.go
  46. +795
    -0
      routers/repo/ai_model_convert.go
  47. +80
    -13
      routers/repo/ai_model_manage.go
  48. +111
    -81
      routers/repo/modelarts.go
  49. +3
    -0
      routers/repo/repo.go
  50. +8
    -1
      routers/routes/routes.go
  51. +1
    -1
      templates/repo/cloudbrain/benchmark/index.tmpl
  52. +290
    -0
      templates/repo/cloudbrain/trainjob/show.tmpl
  53. +10
    -1
      templates/repo/create.tmpl
  54. +253
    -44
      templates/repo/grampus/trainjob/show.tmpl
  55. +289
    -2
      templates/repo/modelarts/trainjob/show.tmpl
  56. +586
    -0
      templates/repo/modelmanage/convertIndex.tmpl
  57. +854
    -0
      templates/repo/modelmanage/convertshowinfo.tmpl
  58. +244
    -49
      templates/repo/modelmanage/index.tmpl
  59. +12
    -3
      templates/repo/modelmanage/showinfo.tmpl
  60. +23
    -5
      web_src/js/components/Model.vue
  61. +2
    -5
      web_src/js/components/UserAnalysis.vue

+ 252
- 3
models/ai_model_manage.go View File

@@ -2,6 +2,7 @@ package models


import ( import (
"fmt" "fmt"
"time"


"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@@ -39,6 +40,40 @@ type AiModelManage struct {
IsCanDelete bool IsCanDelete bool
} }


type AiModelConvert struct {
ID string `xorm:"pk"`
Name string `xorm:"INDEX NOT NULL"`
Status string `xorm:"NULL"`
StatusResult string `xorm:"NULL"`
SrcEngine int `xorm:"NOT NULL DEFAULT 0"`
RepoId int64 `xorm:"INDEX NULL"`
ModelId string `xorm:"NOT NULL"`
ModelName string `xorm:"NULL"`
ModelVersion string `xorm:"NOT NULL"`
ModelPath string `xorm:"NULL"`
DestFormat int `xorm:"NOT NULL DEFAULT 0"`
NetOutputFormat int `xorm:"NULL"`
UserId int64 `xorm:"NOT NULL"`
CloudBrainTaskId string `xorm:"NULL"`
ModelArtsVersionId string `xorm:"NULL"`
ContainerID string
ContainerIp string
RunTime int64 `xorm:"NULL"`
TrainJobDuration string
InputShape string `xorm:"varchar(2000)"`
InputDataFormat string `xorm:"NOT NULL"`
Description string `xorm:"varchar(2000)"`
Path string `xorm:"varchar(400) NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
StartTime timeutil.TimeStamp
EndTime timeutil.TimeStamp
UserName string
UserRelAvatarLink string
IsCanOper bool
IsCanDelete bool
}

type AiModelQueryOptions struct { type AiModelQueryOptions struct {
ListOptions ListOptions
RepoID int64 // include all repos if empty RepoID int64 // include all repos if empty
@@ -47,7 +82,124 @@ type AiModelQueryOptions struct {
SortType string SortType string
New int New int
// JobStatus CloudbrainStatus // JobStatus CloudbrainStatus
Type int
Type int
Status int
}

func (a *AiModelConvert) IsGpuTrainTask() bool {
if a.SrcEngine == 0 || a.SrcEngine == 1 {
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 { func SaveModelToDb(model *AiModelManage) error {
@@ -63,6 +215,20 @@ func SaveModelToDb(model *AiModelManage) error {
return nil return nil
} }


func QueryModelConvertById(id string) (*AiModelConvert, error) {
sess := x.NewSession()
defer sess.Close()
sess.Select("*").Table(new(AiModelConvert)).Where("id='" + id + "'")
aiModelManageConvertList := make([]*AiModelConvert, 0)
err := sess.Find(&aiModelManageConvertList)
if err == nil {
if len(aiModelManageConvertList) == 1 {
return aiModelManageConvertList[0], nil
}
}
return nil, err
}

func QueryModelById(id string) (*AiModelManage, error) { func QueryModelById(id string) (*AiModelManage, error) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
@@ -74,14 +240,28 @@ func QueryModelById(id string) (*AiModelManage, error) {
if len(aiModelManageList) == 1 { if len(aiModelManageList) == 1 {
return aiModelManageList[0], nil return aiModelManageList[0], nil
} }
} else {
log.Info("error=" + err.Error())
} }
return nil, err return nil, err
} }


func DeleteModelById(id string) error {
func DeleteModelConvertById(id string) error {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() 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{ re, err := sess.Delete(&AiModelManage{
ID: id, ID: id,
}) })
@@ -90,7 +270,6 @@ func DeleteModelById(id string) error {
} }
log.Info("success to delete from db.re=" + fmt.Sprint((re))) log.Info("success to delete from db.re=" + fmt.Sprint((re)))
return nil return nil

} }


func ModifyModelDescription(id string, description string) error { func ModifyModelDescription(id string, description string) error {
@@ -201,3 +380,73 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) {


return aiModelManages, count, nil return aiModelManages, count, nil
} }

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
}

+ 52
- 11
models/cloudbrain.go View File

@@ -164,12 +164,11 @@ type Cloudbrain struct {
FlavorName string //规格名称 FlavorName string //规格名称
EngineName string //引擎名称 EngineName string //引擎名称
TotalVersionCount int //任务的所有版本数量,包括删除的 TotalVersionCount int //任务的所有版本数量,包括删除的

LabelName string //标签名称
ModelName string //模型名称
ModelVersion string //模型版本
CkptName string //权重文件名称
ResultUrl string //推理结果的obs路径
LabelName string //标签名称
ModelName string //模型名称
ModelVersion string //模型版本
CkptName string //权重文件名称
ResultUrl string //推理结果的obs路径


User *User `xorm:"-"` User *User `xorm:"-"`
Repo *Repository `xorm:"-"` Repo *Repository `xorm:"-"`
@@ -933,6 +932,28 @@ type NotebookDelResult struct {
InstanceID string `json:"instance_id"` InstanceID string `json:"instance_id"`
} }


type CreateUserImageTrainJobParams struct {
JobName string `json:"job_name"`
Description string `json:"job_desc"`
Config UserImageConfig `json:"config"`
WorkspaceID string `json:"workspace_id"`
}

type UserImageConfig struct {
WorkServerNum int `json:"worker_server_num"`
AppUrl string `json:"app_url"` //训练作业的代码目录
BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下
Parameter []Parameter `json:"parameter"`
DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL
TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL
LogUrl string `json:"log_url"`
UserImageUrl string `json:"user_image_url"`
UserCommand string `json:"user_command"`
CreateVersion bool `json:"create_version"`
Flavor Flavor `json:"flavor"`
PoolID string `json:"pool_id"`
}

type CreateTrainJobParams struct { type CreateTrainJobParams struct {
JobName string `json:"job_name"` JobName string `json:"job_name"`
Description string `json:"job_desc"` Description string `json:"job_desc"`
@@ -980,6 +1001,11 @@ type CreateTrainJobVersionParams struct {
Config TrainJobVersionConfig `json:"config"` Config TrainJobVersionConfig `json:"config"`
} }


type CreateTrainJobVersionUserImageParams struct {
Description string `json:"job_desc"`
Config TrainJobVersionUserImageConfig `json:"config"`
}

type TrainJobVersionConfig struct { type TrainJobVersionConfig struct {
WorkServerNum int `json:"worker_server_num"` WorkServerNum int `json:"worker_server_num"`
AppUrl string `json:"app_url"` //训练作业的代码目录 AppUrl string `json:"app_url"` //训练作业的代码目录
@@ -994,6 +1020,21 @@ type TrainJobVersionConfig struct {
PreVersionId int64 `json:"pre_version_id"` PreVersionId int64 `json:"pre_version_id"`
} }


type TrainJobVersionUserImageConfig struct {
WorkServerNum int `json:"worker_server_num"`
AppUrl string `json:"app_url"` //训练作业的代码目录
BootFileUrl string `json:"boot_file_url"` //训练作业的代码启动文件,需要在代码目录下
Parameter []Parameter `json:"parameter"`
DataUrl string `json:"data_url"` //训练作业需要的数据集OBS路径URL
TrainUrl string `json:"train_url"` //训练作业的输出文件OBS路径URL
LogUrl string `json:"log_url"`
Flavor Flavor `json:"flavor"`
PoolID string `json:"pool_id"`
PreVersionId int64 `json:"pre_version_id"`
UserImageUrl string `json:"user_image_url"`
UserCommand string `json:"user_command"`
}

type CreateConfigParams struct { type CreateConfigParams struct {
ConfigName string `json:"config_name"` ConfigName string `json:"config_name"`
Description string `json:"config_desc"` Description string `json:"config_desc"`
@@ -1430,7 +1471,7 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) {
return cloudbrains, count, nil return cloudbrains, count, nil
} }


func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error) {
func QueryModelTrainJobVersionList(jobId string) ([]*Cloudbrain, int, error) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()


@@ -1445,7 +1486,7 @@ func QueryModelTrainJobVersionList(jobId string) ([]*CloudbrainInfo, int, error)
) )


sess.OrderBy("cloudbrain.created_unix DESC") sess.OrderBy("cloudbrain.created_unix DESC")
cloudbrains := make([]*CloudbrainInfo, 0)
cloudbrains := make([]*Cloudbrain, 0)
if err := sess.Table(&Cloudbrain{}).Where(cond). if err := sess.Table(&Cloudbrain{}).Where(cond).
Find(&cloudbrains); err != nil { Find(&cloudbrains); err != nil {
return nil, 0, fmt.Errorf("Find: %v", err) return nil, 0, fmt.Errorf("Find: %v", err)
@@ -1467,9 +1508,9 @@ func QueryModelTrainJobList(repoId int64) ([]*CloudbrainInfo, int, error) {
cond = cond.And( cond = cond.And(
builder.Eq{"job_type": "TRAIN"}, builder.Eq{"job_type": "TRAIN"},
) )
cond = cond.And(
builder.In("type", 0, 1),
)
// cond = cond.And(
// builder.In("type", 0, 1),
// )


cloudbrains := make([]*CloudbrainInfo, 0) cloudbrains := make([]*CloudbrainInfo, 0)
if err := sess.Select("job_id,display_job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC"). if err := sess.Select("job_id,display_job_name").Table(&Cloudbrain{}).Where(cond).OrderBy("created_unix DESC").


+ 1
- 0
models/models.go View File

@@ -144,6 +144,7 @@ func init() {
new(WechatBindLog), new(WechatBindLog),
new(OrgStatistic), new(OrgStatistic),
new(SearchRecord), new(SearchRecord),
new(AiModelConvert),
) )


tablesStatistic = append(tablesStatistic, tablesStatistic = append(tablesStatistic,


+ 1
- 1
models/user_business_analysis.go View File

@@ -362,7 +362,7 @@ func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, q
var cond = builder.NewCond() var cond = builder.NewCond()
if len(userName) > 0 { if len(userName) > 0 {
cond = cond.And( cond = cond.And(
builder.Like{"name", userName},
builder.Like{"lower(name)", strings.ToLower(userName)},
) )
} }
allCount, err := statictisSess.Where(cond).Count(queryObj) allCount, err := statictisSess.Where(cond).Count(queryObj)


+ 201
- 32
modules/modelarts/modelarts.go View File

@@ -19,14 +19,14 @@ import (


const ( const (
//notebook //notebook
storageTypeOBS = "obs"
autoStopDuration = 4 * 60 * 60
autoStopDurationMs = 4 * 60 * 60 * 1000
DataSetMountPath = "/home/ma-user/work"
NotebookEnv = "Python3"
NotebookType = "Ascend"
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)"
storageTypeOBS = "obs"
autoStopDuration = 4 * 60 * 60
autoStopDurationMs = 4 * 60 * 60 * 1000
MORDELART_USER_IMAGE_ENGINE_ID = -1
DataSetMountPath = "/home/ma-user/work"
NotebookEnv = "Python3"
NotebookType = "Ascend"
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)"


//train-job //train-job
// ResourcePools = "{\"resource_pool\":[{\"id\":\"pool1328035d\", \"value\":\"专属资源池\"}]}" // ResourcePools = "{\"resource_pool\":[{\"id\":\"pool1328035d\", \"value\":\"专属资源池\"}]}"
@@ -98,6 +98,8 @@ type GenerateTrainJobReq struct {
VersionCount int VersionCount int
EngineName string EngineName string
TotalVersionCount int TotalVersionCount int
UserImageUrl string
UserCommand string
DatasetName string DatasetName string
} }


@@ -136,6 +138,7 @@ type VersionInfo struct {
Version []struct { Version []struct {
ID int `json:"id"` ID int `json:"id"`
Value string `json:"value"` Value string `json:"value"`
Url string `json:"url"`
} `json:"version"` } `json:"version"`
} }


@@ -314,15 +317,107 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc


func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) {
createTime := timeutil.TimeStampNow() createTime := timeutil.TimeStampNow()
jobResult, err := createTrainJob(models.CreateTrainJobParams{
var jobResult *models.CreateTrainJobResult
var createErr error
if req.EngineID < 0 {
jobResult, createErr = createTrainJobUserImage(models.CreateUserImageTrainJobParams{
JobName: req.JobName,
Description: req.Description,
Config: models.UserImageConfig{
WorkServerNum: req.WorkServerNumber,
AppUrl: req.CodeObsPath,
BootFileUrl: req.BootFileUrl,
DataUrl: req.DataUrl,
TrainUrl: req.TrainUrl,
LogUrl: req.LogUrl,
PoolID: req.PoolID,
CreateVersion: true,
Flavor: models.Flavor{
Code: req.FlavorCode,
},
Parameter: req.Parameters,
UserImageUrl: req.UserImageUrl,
UserCommand: req.UserCommand,
},
})
} else {
jobResult, createErr = createTrainJob(models.CreateTrainJobParams{
JobName: req.JobName,
Description: req.Description,
Config: models.Config{
WorkServerNum: req.WorkServerNumber,
AppUrl: req.CodeObsPath,
BootFileUrl: req.BootFileUrl,
DataUrl: req.DataUrl,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
LogUrl: req.LogUrl,
PoolID: req.PoolID,
CreateVersion: true,
Flavor: models.Flavor{
Code: req.FlavorCode,
},
Parameter: req.Parameters,
},
})
}
if createErr != nil {
log.Error("CreateJob failed: %v", createErr.Error())
return createErr
}
jobId := strconv.FormatInt(jobResult.JobID, 10)
createErr = models.CreateCloudbrain(&models.Cloudbrain{
Status: TransTrainJobStatus(jobResult.Status),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobId,
JobName: req.JobName,
DisplayJobName: req.DisplayJobName,
JobType: string(models.JobTypeTrain),
Type: models.TypeCloudBrainTwo,
VersionID: jobResult.VersionID,
VersionName: jobResult.VersionName,
Uuid: req.Uuid,
DatasetName: req.DatasetName,
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
ComputeResource: models.NPUResource,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,
Parameters: req.Params,
BootFile: req.BootFile,
DataUrl: req.DataUrl,
LogUrl: req.LogUrl,
FlavorCode: req.FlavorCode,
Description: req.Description,
WorkServerNumber: req.WorkServerNumber,
FlavorName: req.FlavorName,
EngineName: req.EngineName,
VersionCount: req.VersionCount,
TotalVersionCount: req.TotalVersionCount,
CreatedUnix: createTime,
UpdatedUnix: createTime,
})

if createErr != nil {
log.Error("CreateCloudbrain(%s) failed:%v", req.DisplayJobName, createErr.Error())
return createErr
}
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobId, req.DisplayJobName, models.ActionCreateTrainTask)
return nil
}

func GenerateModelConvertTrainJob(req *GenerateTrainJobReq) (*models.CreateTrainJobResult, error) {

return createTrainJobUserImage(models.CreateUserImageTrainJobParams{
JobName: req.JobName, JobName: req.JobName,
Description: req.Description, Description: req.Description,
Config: models.Config{
Config: models.UserImageConfig{
WorkServerNum: req.WorkServerNumber, WorkServerNum: req.WorkServerNumber,
AppUrl: req.CodeObsPath, AppUrl: req.CodeObsPath,
BootFileUrl: req.BootFileUrl, BootFileUrl: req.BootFileUrl,
DataUrl: req.DataUrl, DataUrl: req.DataUrl,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl, TrainUrl: req.TrainUrl,
LogUrl: req.LogUrl, LogUrl: req.LogUrl,
PoolID: req.PoolID, PoolID: req.PoolID,
@@ -330,20 +425,83 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
Flavor: models.Flavor{ Flavor: models.Flavor{
Code: req.FlavorCode, Code: req.FlavorCode,
}, },
Parameter: req.Parameters,
Parameter: req.Parameters,
UserImageUrl: req.UserImageUrl,
UserCommand: req.UserCommand,
}, },
}) })
if err != nil {
log.Error("CreateJob failed: %v", err.Error())
return err
}

func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) {
createTime := timeutil.TimeStampNow()
var jobResult *models.CreateTrainJobResult
var createErr error
log.Info(" req.EngineID =" + fmt.Sprint(req.EngineID))
if req.EngineID < 0 {
jobResult, createErr = createTrainJobVersionUserImage(models.CreateTrainJobVersionUserImageParams{
Description: req.Description,
Config: models.TrainJobVersionUserImageConfig{
WorkServerNum: req.WorkServerNumber,
AppUrl: req.CodeObsPath,
BootFileUrl: req.BootFileUrl,
DataUrl: req.DataUrl,
TrainUrl: req.TrainUrl,
LogUrl: req.LogUrl,
PoolID: req.PoolID,
Flavor: models.Flavor{
Code: req.FlavorCode,
},
Parameter: req.Parameters,
PreVersionId: req.PreVersionId,
UserImageUrl: req.UserImageUrl,
UserCommand: req.UserCommand,
},
}, jobId)
} else {
jobResult, createErr = createTrainJobVersion(models.CreateTrainJobVersionParams{
Description: req.Description,
Config: models.TrainJobVersionConfig{
WorkServerNum: req.WorkServerNumber,
AppUrl: req.CodeObsPath,
BootFileUrl: req.BootFileUrl,
DataUrl: req.DataUrl,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
LogUrl: req.LogUrl,
PoolID: req.PoolID,
Flavor: models.Flavor{
Code: req.FlavorCode,
},
Parameter: req.Parameters,
PreVersionId: req.PreVersionId,
},
}, jobId)
}
if createErr != nil {
log.Error("CreateJob failed: %v", createErr.Error())
return createErr
} }


jobId := strconv.FormatInt(jobResult.JobID, 10)
err = models.CreateCloudbrain(&models.Cloudbrain{
var jobTypes []string
jobTypes = append(jobTypes, string(models.JobTypeTrain))
repo := ctx.Repo.Repository
VersionTaskList, VersionListCount, createErr := models.CloudbrainsVersionList(&models.CloudbrainsOptions{
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobTypes: jobTypes,
JobID: strconv.FormatInt(jobResult.JobID, 10),
})
if createErr != nil {
ctx.ServerError("Cloudbrain", createErr)
return createErr
}
//将当前版本的isLatestVersion设置为"1"和任务数量更新,任务数量包括当前版本数VersionCount和历史创建的总版本数TotalVersionCount

createErr = models.CreateCloudbrain(&models.Cloudbrain{
Status: TransTrainJobStatus(jobResult.Status), Status: TransTrainJobStatus(jobResult.Status),
UserID: ctx.User.ID, UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,
JobID: jobId,
JobID: strconv.FormatInt(jobResult.JobID, 10),
JobName: req.JobName, JobName: req.JobName,
DisplayJobName: req.DisplayJobName, DisplayJobName: req.DisplayJobName,
JobType: string(models.JobTypeTrain), JobType: string(models.JobTypeTrain),
@@ -354,6 +512,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
DatasetName: req.DatasetName, DatasetName: req.DatasetName,
CommitID: req.CommitID, CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion, IsLatestVersion: req.IsLatestVersion,
PreVersionName: req.PreVersionName,
ComputeResource: models.NPUResource, ComputeResource: models.NPUResource,
EngineID: req.EngineID, EngineID: req.EngineID,
TrainUrl: req.TrainUrl, TrainUrl: req.TrainUrl,
@@ -362,45 +521,54 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
BootFile: req.BootFile, BootFile: req.BootFile,
DataUrl: req.DataUrl, DataUrl: req.DataUrl,
LogUrl: req.LogUrl, LogUrl: req.LogUrl,
PreVersionId: req.PreVersionId,
FlavorCode: req.FlavorCode, FlavorCode: req.FlavorCode,
Description: req.Description, Description: req.Description,
WorkServerNumber: req.WorkServerNumber, WorkServerNumber: req.WorkServerNumber,
FlavorName: req.FlavorName, FlavorName: req.FlavorName,
EngineName: req.EngineName, EngineName: req.EngineName,
VersionCount: req.VersionCount,
TotalVersionCount: req.TotalVersionCount,
TotalVersionCount: VersionTaskList[0].TotalVersionCount + 1,
VersionCount: VersionListCount + 1,
CreatedUnix: createTime, CreatedUnix: createTime,
UpdatedUnix: createTime, UpdatedUnix: createTime,
}) })
if createErr != nil {
log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, createErr.Error())
return createErr
}


if err != nil {
log.Error("CreateCloudbrain(%s) failed:%v", req.DisplayJobName, err.Error())
return err
//将训练任务的上一版本的isLatestVersion设置为"0"
createErr = models.SetVersionCountAndLatestVersion(strconv.FormatInt(jobResult.JobID, 10), VersionTaskList[0].VersionName, VersionCount, NotLatestVersion, TotalVersionCount)
if createErr != nil {
ctx.ServerError("Update IsLatestVersion failed", createErr)
return createErr
} }
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobId, req.DisplayJobName, models.ActionCreateTrainTask)
return nil
return createErr
} }


func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) {
func GenerateTrainJobVersionByUserImage(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) {
createTime := timeutil.TimeStampNow() createTime := timeutil.TimeStampNow()
jobResult, err := createTrainJobVersion(models.CreateTrainJobVersionParams{
jobResult, err := createTrainJobUserImage(models.CreateUserImageTrainJobParams{
JobName: req.JobName,
Description: req.Description, Description: req.Description,
Config: models.TrainJobVersionConfig{
Config: models.UserImageConfig{
WorkServerNum: req.WorkServerNumber, WorkServerNum: req.WorkServerNumber,
AppUrl: req.CodeObsPath, AppUrl: req.CodeObsPath,
BootFileUrl: req.BootFileUrl, BootFileUrl: req.BootFileUrl,
DataUrl: req.DataUrl, DataUrl: req.DataUrl,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl, TrainUrl: req.TrainUrl,
LogUrl: req.LogUrl, LogUrl: req.LogUrl,
PoolID: req.PoolID, PoolID: req.PoolID,
CreateVersion: true,
Flavor: models.Flavor{ Flavor: models.Flavor{
Code: req.FlavorCode, Code: req.FlavorCode,
}, },
Parameter: req.Parameters, Parameter: req.Parameters,
PreVersionId: req.PreVersionId,
UserImageUrl: req.UserImageUrl,
UserCommand: req.UserCommand,
}, },
}, jobId)
})
if err != nil { if err != nil {
log.Error("CreateJob failed: %v", err.Error()) log.Error("CreateJob failed: %v", err.Error())
return err return err
@@ -438,7 +606,8 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
IsLatestVersion: req.IsLatestVersion, IsLatestVersion: req.IsLatestVersion,
PreVersionName: req.PreVersionName, PreVersionName: req.PreVersionName,
ComputeResource: models.NPUResource, ComputeResource: models.NPUResource,
EngineID: req.EngineID,
EngineID: MORDELART_USER_IMAGE_ENGINE_ID,
Image: req.UserImageUrl,
TrainUrl: req.TrainUrl, TrainUrl: req.TrainUrl,
BranchName: req.BranchName, BranchName: req.BranchName,
Parameters: req.Params, Parameters: req.Params,


+ 111
- 0
modules/modelarts/resty.go View File

@@ -472,6 +472,62 @@ sendjob:
return &result, nil return &result, nil
} }


func createTrainJobUserImage(createJobParams models.CreateUserImageTrainJobParams) (*models.CreateTrainJobResult, error) {
checkSetting()
client := getRestyClient()
var result models.CreateTrainJobResult

retry := 0

sendjob:
res, err := client.R().
SetHeader("Content-Type", "application/json").
SetAuthToken(TOKEN).
SetBody(createJobParams).
SetResult(&result).
Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob)

if err != nil {
return nil, fmt.Errorf("resty create train-job: %s", err)
}

req, _ := json.Marshal(createJobParams)
log.Info("%s", req)

if res.StatusCode() == http.StatusUnauthorized && retry < 1 {
retry++
_ = getToken()
goto sendjob
}

if res.StatusCode() != http.StatusOK {
var temp models.ErrorResult
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil {
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
log.Error("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
BootFileErrorMsg := "Invalid OBS path '" + createJobParams.Config.BootFileUrl + "'."
DataSetErrorMsg := "Invalid OBS path '" + createJobParams.Config.DataUrl + "'."
if temp.ErrorMsg == BootFileErrorMsg {
log.Error("启动文件错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("启动文件错误!")
}
if temp.ErrorMsg == DataSetErrorMsg {
log.Error("数据集错误!createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createTrainJob failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}

if !result.IsSuccess {
log.Error("createTrainJob failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("createTrainJob failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func createTrainJob(createJobParams models.CreateTrainJobParams) (*models.CreateTrainJobResult, error) { func createTrainJob(createJobParams models.CreateTrainJobParams) (*models.CreateTrainJobResult, error) {
checkSetting() checkSetting()
client := getRestyClient() client := getRestyClient()
@@ -583,6 +639,61 @@ sendjob:
return &result, nil return &result, nil
} }


func createTrainJobVersionUserImage(createJobVersionParams models.CreateTrainJobVersionUserImageParams, jobID string) (*models.CreateTrainJobResult, error) {
checkSetting()
client := getRestyClient()
var result models.CreateTrainJobResult

retry := 0

sendjob:
res, err := client.R().
SetHeader("Content-Type", "application/json").
SetAuthToken(TOKEN).
SetBody(createJobVersionParams).
SetResult(&result).
Post(HOST + "/v1/" + setting.ProjectID + urlTrainJob + "/" + jobID + "/versions")

if err != nil {
return nil, fmt.Errorf("resty create train-job version: %s", err)
}

req, _ := json.Marshal(createJobVersionParams)
log.Info("%s", req)

if res.StatusCode() == http.StatusUnauthorized && retry < 1 {
retry++
_ = getToken()
goto sendjob
}

if res.StatusCode() != http.StatusOK {
var temp models.ErrorResult
if err = json.Unmarshal([]byte(res.String()), &temp); err != nil {
log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error())
return &result, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error())
}
BootFileErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.BootFileUrl + "'."
DataSetErrorMsg := "Invalid OBS path '" + createJobVersionParams.Config.DataUrl + "'."
if temp.ErrorMsg == BootFileErrorMsg {
log.Error("启动文件错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("启动文件错误!")
}
if temp.ErrorMsg == DataSetErrorMsg {
log.Error("数据集错误!createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
return &result, fmt.Errorf("数据集错误!")
}
return &result, fmt.Errorf("createTrainJobVersion failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg)
}

if !result.IsSuccess {
log.Error("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg)
return &result, fmt.Errorf("createTrainJobVersion failed(%s): %s", result.ErrorCode, result.ErrorMsg)
}

return &result, nil
}

func GetResourceSpecs() (*models.GetResourceSpecsResult, error) { func GetResourceSpecs() (*models.GetResourceSpecsResult, error) {
checkSetting() checkSetting()
client := getRestyClient() client := getRestyClient()


+ 44
- 3
modules/setting/setting.go View File

@@ -479,9 +479,10 @@ var (
TrainResourceSpecs string TrainResourceSpecs string
InferenceGpuTypes string InferenceGpuTypes string
InferenceResourceSpecs string InferenceResourceSpecs string
MaxModelSize float64
MaxDatasetNum int MaxDatasetNum int
CullIdleTimeout string
CullInterval string
CullIdleTimeout string
CullInterval string


//benchmark config //benchmark config
IsBenchmarkEnabled bool IsBenchmarkEnabled bool
@@ -631,6 +632,24 @@ var (
OrgName string OrgName string
TeamName string TeamName string
}{} }{}

ModelConvert = struct {
GPU_PYTORCH_IMAGE string
GpuQueue string
GPU_TENSORFLOW_IMAGE string
NPU_MINDSPORE_16_IMAGE string
PytorchOnnxBootFile string
PytorchTrTBootFile string
MindsporeBootFile string
TensorFlowNpuBootFile string
TensorFlowGpuBootFile string
ConvertRepoPath string
GPU_Resource_Specs_ID int
NPU_FlavorCode string
NPU_PoolID string
NPU_MINDSPORE_IMAGE_ID int
NPU_TENSORFLOW_IMAGE_ID int
}{}
) )


// DateLang transforms standard language locale name to corresponding value in datetime plugin. // DateLang transforms standard language locale name to corresponding value in datetime plugin.
@@ -1330,10 +1349,11 @@ func NewContext() {
MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400)
TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("") TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("")
TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("") TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("")
MaxModelSize = sec.Key("MAX_MODEL_SIZE").MustFloat64(500)
InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("") InferenceGpuTypes = sec.Key("INFERENCE_GPU_TYPES").MustString("")
InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("") InferenceResourceSpecs = sec.Key("INFERENCE_RESOURCE_SPECS").MustString("")
SpecialPools = sec.Key("SPECIAL_POOL").MustString("") SpecialPools = sec.Key("SPECIAL_POOL").MustString("")
MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5) MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5)
CullIdleTimeout = sec.Key("CULL_IDLE_TIMEOUT").MustString("900") CullIdleTimeout = sec.Key("CULL_IDLE_TIMEOUT").MustString("900")
CullInterval = sec.Key("CULL_INTERVAL").MustString("60") CullInterval = sec.Key("CULL_INTERVAL").MustString("60")
@@ -1431,6 +1451,27 @@ func NewContext() {
Course.TeamName = sec.Key("team_name").MustString("") Course.TeamName = sec.Key("team_name").MustString("")


GetGrampusConfig() GetGrampusConfig()

getModelConvertConfig()
}

func getModelConvertConfig() {
sec := Cfg.Section("model_convert")
ModelConvert.GPU_PYTORCH_IMAGE = sec.Key("GPU_PYTORCH_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tensorRT_7_zouap")
ModelConvert.GpuQueue = sec.Key("GpuQueue").MustString("openidgx")
ModelConvert.GPU_TENSORFLOW_IMAGE = sec.Key("GPU_TENSORFLOW_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tf2onnx")
ModelConvert.NPU_MINDSPORE_16_IMAGE = sec.Key("NPU_MINDSPORE_16_IMAGE").MustString("swr.cn-south-222.ai.pcl.cn/openi/mindspore1.6.1_train_v1_openi:v3_ascend")
ModelConvert.PytorchOnnxBootFile = sec.Key("PytorchOnnxBootFile").MustString("convert_pytorch.py")
ModelConvert.PytorchTrTBootFile = sec.Key("PytorchTrTBootFile").MustString("convert_pytorch_tensorrt.py")
ModelConvert.MindsporeBootFile = sec.Key("MindsporeBootFile").MustString("convert_mindspore.py")
ModelConvert.TensorFlowNpuBootFile = sec.Key("TensorFlowNpuBootFile").MustString("convert_tensorflow.py")
ModelConvert.TensorFlowGpuBootFile = sec.Key("TensorFlowGpuBootFile").MustString("convert_tensorflow_gpu.py")
ModelConvert.ConvertRepoPath = sec.Key("ConvertRepoPath").MustString("https://git.openi.org.cn/zouap/npu_test")
ModelConvert.GPU_Resource_Specs_ID = sec.Key("GPU_Resource_Specs_ID").MustInt(1)
ModelConvert.NPU_FlavorCode = sec.Key("NPU_FlavorCode").MustString("modelarts.bm.910.arm.public.1")
ModelConvert.NPU_PoolID = sec.Key("NPU_PoolID").MustString("pool7908321a")
ModelConvert.NPU_MINDSPORE_IMAGE_ID = sec.Key("NPU_MINDSPORE_IMAGE_ID").MustInt(121)
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35)
} }


func GetGrampusConfig() { func GetGrampusConfig() {


+ 43
- 0
modules/storage/minio_ext.go View File

@@ -217,6 +217,49 @@ func GetOneLevelAllObjectUnderDirMinio(bucket string, prefixRootPath string, rel


} }


func MinioGetFilesSize(bucketName string, Files []string) int64 {
_, core, err := getClients()
var fileTotalSize int64
fileTotalSize = 0
if err != nil {
log.Error("getClients failed:", err.Error())
return fileTotalSize
}
for _, file := range Files {
log.Info("file=" + file)
meta, err := core.StatObject(bucketName, file, miniov6.StatObjectOptions{})
if err != nil {
log.Info("Get file error:" + err.Error())
}
fileTotalSize += meta.Size
}
return fileTotalSize
}

func MinioCopyFiles(bucketName string, srcPath string, destPath string, Files []string) (int64, error) {
_, core, err := getClients()
var fileTotalSize int64
fileTotalSize = 0
if err != nil {
log.Error("getClients failed:", err.Error())
return fileTotalSize, err
}

for _, file := range Files {
srcObjectName := srcPath + file
destObjectName := destPath + file
log.Info("srcObjectName=" + srcObjectName + " destObjectName=" + destObjectName)
meta, err := core.StatObject(bucketName, srcObjectName, miniov6.StatObjectOptions{})
if err != nil {
log.Info("Get file error:" + err.Error())
}
core.CopyObject(bucketName, srcObjectName, bucketName, destObjectName, meta.UserMetadata)
fileTotalSize += meta.Size
}

return fileTotalSize, nil
}

func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) { func MinioPathCopy(bucketName string, srcPath string, destPath string) (int64, error) {
_, core, err := getClients() _, core, err := getClients()
var fileTotalSize int64 var fileTotalSize int64


+ 77
- 7
modules/storage/obs.go View File

@@ -264,7 +264,47 @@ func ObsModelDownload(JobName string, fileName string) (io.ReadCloser, error) {
} }
} }


func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPath string) (int64, error) {
func ObsGetFilesSize(srcBucket string, Files []string) int64 {
var fileTotalSize int64
for _, file := range Files {
log.Info("file=" + file)
out, err := ObsCli.GetObjectMetadata(&obs.GetObjectMetadataInput{
Bucket: srcBucket,
Key: file,
})
if err != nil {
log.Info("Get File error, error=" + err.Error())
continue
}
fileTotalSize += out.ContentLength
}
return fileTotalSize
}

func ObsCopyManyFile(srcBucket string, srcPath string, destBucket string, destPath string, Files []string) (int64, error) {

var fileTotalSize int64

for _, file := range Files {
srcKey := srcPath + file
destKey := destPath + file
log.Info("srcKey=" + srcKey + " destKey=" + destKey)
out, err := ObsCli.GetObjectMetadata(&obs.GetObjectMetadataInput{
Bucket: srcBucket,
Key: srcKey,
})
if err != nil {
log.Info("Get File error, error=" + err.Error())
continue
}
obsCopyFile(srcBucket, srcKey, destBucket, destKey)
fileTotalSize += out.ContentLength
}

return fileTotalSize, nil
}

func ObsCopyAllFile(srcBucket string, srcPath string, destBucket string, destPath string) (int64, error) {
input := &obs.ListObjectsInput{} input := &obs.ListObjectsInput{}
input.Bucket = srcBucket input.Bucket = srcBucket
// 设置每页100个对象 // 设置每页100个对象
@@ -330,6 +370,7 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative
output, err := ObsCli.ListObjects(input) output, err := ObsCli.ListObjects(input)
fileInfos := make([]FileInfo, 0) fileInfos := make([]FileInfo, 0)
prefixLen := len(input.Prefix) prefixLen := len(input.Prefix)
fileMap := make(map[string]bool, 0)
if err == nil { if err == nil {
for _, val := range output.Contents { for _, val := range output.Contents {
log.Info("val key=" + val.Key) log.Info("val key=" + val.Key)
@@ -338,23 +379,51 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative
if val.Key == input.Prefix { if val.Key == input.Prefix {
continue continue
} }
if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") {
fileName = val.Key[prefixLen:]
log.Info("fileName =" + fileName)
files := strings.Split(fileName, "/")
if fileMap[files[0]] {
continue continue
} else {
fileMap[files[0]] = true
} }
if strings.HasSuffix(val.Key, "/") {
ParenDir := relativePath
fileName = files[0]
if len(files) > 1 {
isDir = true isDir = true
fileName = val.Key[prefixLen : len(val.Key)-1]
relativePath += val.Key[prefixLen:]
ParenDir += fileName + "/"
} else { } else {
isDir = false isDir = false
fileName = val.Key[prefixLen:]
} }

// if strings.Contains(val.Key[prefixLen:len(val.Key)-1], "/") {

// files := strings.Split(fileName, "/")
// fileName = files[0]
// isDir = true
// if fileMap[files[0]] {
// continue
// } else {
// fileMap[files[0]] = true
// }
// } else {
// if strings.HasSuffix(val.Key, "/") {
// isDir = true
// fileName = val.Key[prefixLen : len(val.Key)-1]
// relativePath += val.Key[prefixLen:]
// } else {
// isDir = false
// fileName = val.Key[prefixLen:]
// }
// fileMap[fileName] = true
// }

fileInfo := FileInfo{ fileInfo := FileInfo{
ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"), ModTime: val.LastModified.Local().Format("2006-01-02 15:04:05"),
FileName: fileName, FileName: fileName,
Size: val.Size, Size: val.Size,
IsDir: isDir, IsDir: isDir,
ParenDir: relativePath,
ParenDir: ParenDir,
} }
fileInfos = append(fileInfos, fileInfo) fileInfos = append(fileInfos, fileInfo)
} }
@@ -424,6 +493,7 @@ func GetObsListObject(jobName, outPutPath, parentDir, versionName string) ([]Fil
input := &obs.ListObjectsInput{} input := &obs.ListObjectsInput{}
input.Bucket = setting.Bucket input.Bucket = setting.Bucket
input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, outPutPath, versionName, parentDir), "/") input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, outPutPath, versionName, parentDir), "/")
log.Info("bucket=" + input.Bucket + " Prefix=" + input.Prefix)
strPrefix := strings.Split(input.Prefix, "/") strPrefix := strings.Split(input.Prefix, "/")
output, err := ObsCli.ListObjects(input) output, err := ObsCli.ListObjects(input)
fileInfos := make([]FileInfo, 0) fileInfos := make([]FileInfo, 0)


+ 8
- 0
options/locale/locale_en-US.ini View File

@@ -1218,6 +1218,14 @@ model.manage.Recall = Recall
model.manage.sava_model = Sava Model model.manage.sava_model = Sava Model
model.manage.model_manage = ModelManage model.manage.model_manage = ModelManage
model.manage.model_accuracy = Model Accuracy model.manage.model_accuracy = Model Accuracy
model.convert=Model Transformation
model.list=Model List
model.manage.create_new_convert_task=Create Model Transformation Task

modelconvert.manage.create_error1=A model transformation task with the same name already exists.
modelconvert.manage.create_error2=Only one running model transformation task can be created.
modelconvert.manage.model_not_exist=The model does not exist.
modelconvert.manage.no_operate_right=No operation permission.


grampus.train_job.ai_center = AI Center grampus.train_job.ai_center = AI Center
grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。 grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。


+ 8
- 0
options/locale/locale_zh-CN.ini View File

@@ -1230,6 +1230,14 @@ model.manage.Recall = 召回率
model.manage.sava_model = 保存模型 model.manage.sava_model = 保存模型
model.manage.model_manage = 模型管理 model.manage.model_manage = 模型管理
model.manage.model_accuracy = 模型精度 model.manage.model_accuracy = 模型精度
model.convert=模型转换任务
model.list=模型列表
model.manage.create_new_convert_task=创建模型转换任务

modelconvert.manage.create_error1=相同的名称模型转换任务已经存在。
modelconvert.manage.create_error2=只能创建一个正在运行的模型转换任务。
modelconvert.manage.model_not_exist=选择的模型不存在。
modelconvert.manage.no_operate_right=无操作权限。


grampus.train_job.ai_center=智算中心 grampus.train_job.ai_center=智算中心
grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。 grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。


+ 386
- 0
public/self/ztree/css/awesomeStyle/awesome.css View File

@@ -0,0 +1,386 @@
/*-------------------------------------
zTree Style using fontawesome instead of images

version: 1.1
author: Mike King
email: mikkelking @ hotmail . com
website: http://code.google.com/p/jquerytree/

-------------------------------------*/
/* Definitions ----------------------*/
/* End of Definitions ---------------*/
/* Imports -------------------------*/
/* End of Imports ------------------*/
.ztree * {
padding: 0;
margin: 0;
font-size: 12px;
font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif;
background-color: #af0000;
}
.ztree {
margin: 0;
padding: 5px;
color: #ffffff;
background-color: #af0000;
}
.ztree li {
padding: 0;
margin: 0;
list-style: none;
line-height: 17px;
text-align: left;
white-space: nowrap;
outline: 0;
}
.ztree li ul {
margin: 0px;
padding: 0 0 0 18px;
}
.ztree li a {
padding-right: 3px;
margin: 0;
cursor: pointer;
height: 17px;
color: #ffffff;
background-color: transparent;
text-decoration: none;
vertical-align: top;
display: inline-block;
}
.ztree li a input.rename {
height: 14px;
width: 80px;
padding: 0;
margin: 0;
color: #af0000;
background-color: #ffffff;
font-size: 12px;
border: 1px #585956 solid;
*border: 0px;
}
.ztree li a:hover {
text-decoration: underline;
}
.ztree li a.curSelectedNode {
padding-top: 0px;
background-color: #af4040;
color: #ffff00;
height: 17px;
opacity: 0.8;
}
.ztree li a.curSelectedNode_Edit {
padding-top: 0px;
background-color: transparent;
color: #ffff00;
height: 17px;
border: 1px #666 solid;
opacity: 0.8;
}
.ztree li a.tmpTargetNode_inner {
padding-top: 0px;
background-color: #aaa;
color: #ffff00;
height: 17px;
border: 1px #666 solid;
opacity: 0.8;
filter: alpha(opacity=80);
}
.ztree li span {
line-height: 17px;
margin-right: 2px;
background-color: transparent;
}
.ztree li span.button {
line-height: 0;
margin: 0;
padding: 0;
width: 15px;
height: 17px;
display: inline-block;
vertical-align: top;
border: 0px solid;
cursor: pointer;
outline: none;
background-color: transparent;
background-repeat: no-repeat;
background-attachment: scroll;
}
.ztree li span.button::before {
color: #ffffff;
font-family: FontAwesome;
padding-top: 10px;
}
.ztree li span.button.chk {
margin: 0px;
cursor: auto;
width: 12px;
display: inline-block;
padding-top: 10px;
padding-left: 2px;
}
.ztree li span.button.chk.checkbox_false_full::before {
content: "\f096";
}
.ztree li span.button.chk.checkbox_false_full_focus::before {
content: "\f096";
color: #ffff00;
}
.ztree li span.button.chk.checkbox_false_part::before {
content: "\f096";
color: #aaaaaa;
}
.ztree li span.button.chk.checkbox_false_part_focus::before {
content: "\f096";
color: #cad96c;
}
.ztree li span.button.chk.checkbox_false_disable::before {
content: "\f096";
color: #808080;
}
.ztree li span.button.chk.checkbox_true_full::before {
content: "\f046";
}
.ztree li span.button.chk.checkbox_true_full_focus::before {
content: "\f046";
}
.ztree li span.button.chk.checkbox_true_part::before {
content: "\f14a";
}
.ztree li span.button.chk.checkbox_true_part_focus::before {
content: "\f14a";
color: #ffff00;
}
.ztree li span.button.chk.checkbox_true_full_focus::before {
content: "\f046";
color: #ffff00;
}
.ztree li span.button.chk.checkbox_true_part::before {
content: "\f046";
color: #aaaaaa;
}
.ztree li span.button.chk.checkbox_true_part_focus::before {
content: "\f046";
color: #cad96c;
}
.ztree li span.button.chk.checkbox_true_disable::before {
content: "\f046";
color: #808080;
}
.ztree li span.button.chk.radio_false_full::before {
content: "\f10c";
}
.ztree li span.button.chk.radio_false_full_focus::before {
content: "\f10c";
color: #ffff00;
}
.ztree li span.button.chk.radio_false_part::before {
content: "\f10c";
color: #aaaaaa;
}
.ztree li span.button.chk.radio_false_part_focus::before {
content: "\f10c";
color: #ffff00;
}
.ztree li span.button.chk.radio_false_disable::before {
content: "\f1db";
color: #808080;
}
.ztree li span.button.chk.radio_true_full::before {
content: "\f192";
}
.ztree li span.button.chk.radio_true_full_focus::before {
content: "\f192";
color: #ffff00;
}
.ztree li span.button.chk.radio_true_part::before {
content: "\f192";
color: #aaaaaa;
}
.ztree li span.button.chk.radio_true_part_focus::before {
content: "\f192";
color: #aaaaaa;
}
.ztree li span.button.chk.radio_true_disable::before {
content: "\f1db";
color: #808080;
}
.ztree li span.button.switch {
width: 15px;
height: 17px;
}
.ztree li span.button.root_open::before {
content: "\f078";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.root_close::before {
content: "\f054";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.roots_open::before {
content: "\f078";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.roots_close::before {
content: "\f054";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.center_open::before {
content: "\f078";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.center_close::before {
content: "\f054";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.bottom_open::before {
content: "\f078";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.bottom_close::before {
content: "\f054";
padding-top: 10px;
padding-left: 2px;
display: inline-block;
}
.ztree li span.button.root_docu {
background: none;
}
.ztree li span.button.roots_docu::before {
content: "\f022";
padding-left: 2px;
display: inline-block;
color: #ffffff;
}
.ztree li span.button.center_docu::before {
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #ffffff;
}
.ztree li span.button.bottom_docu::before {
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #ffffff;
}
.ztree li span.button.noline_docu {
background: none;
}
.ztree li span.button.ico_open::before {
content: "\f115";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #ffffff;
}
.ztree li span.button.ico_close::before {
content: "\f114";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #ffffff;
}
.ztree li span.button.ico_docu::before {
content: "\f022";
font-family: FontAwesome;
padding-top: 10px;
padding-left: 2px;
display: inline-block;
color: #ffffff;
}
.ztree li span.button.edit {
margin-left: 4px;
margin-right: -1px;
vertical-align: top;
*vertical-align: middle;
padding-top: 10px;
}
.ztree li span.button.edit::before {
content: "\f044";
font-family: FontAwesome;
}
.ztree li span.button.remove {
margin-left: 4px;
margin-right: -1px;
vertical-align: top;
*vertical-align: middle;
padding-top: 10px;
}
.ztree li span.button.remove::before {
content: "\f1f8";
font-family: FontAwesome;
}
.ztree li span.button.add {
margin-left: 4px;
margin-right: -1px;
vertical-align: top;
*vertical-align: middle;
padding-top: 10px;
}
.ztree li span.button.add::before {
content: "\f067";
font-family: FontAwesome;
}
.ztree li span.button.ico_loading {
margin-right: 2px;
background: url(./img/loading.gif) no-repeat scroll 0 0 transparent;
vertical-align: top;
*vertical-align: middle;
}
ul.tmpTargetzTree {
background-color: #FFE6B0;
opacity: 0.8;
filter: alpha(opacity=80);
}
span.tmpzTreeMove_arrow {
width: 16px;
height: 17px;
display: inline-block;
padding: 0;
margin: 2px 0 0 1px;
border: 0 none;
position: absolute;
background-color: transparent;
background-attachment: scroll;
}
span.tmpzTreeMove_arrow::before {
content: "\f04b";
font-family: FontAwesome;
color: #ffff00;
}
ul.ztree.zTreeDragUL {
margin: 0;
padding: 0;
position: absolute;
width: auto;
height: auto;
overflow: hidden;
background-color: #cfcfcf;
border: 1px #ffff00 dotted;
opacity: 0.8;
filter: alpha(opacity=80);
}
.ztreeMask {
z-index: 10000;
background-color: #cfcfcf;
opacity: 0.0;
filter: alpha(opacity=0);
position: absolute;
}

+ 146
- 0
public/self/ztree/css/awesomeStyle/awesome.less View File

@@ -0,0 +1,146 @@
/*-------------------------------------
zTree Style using fontawesome instead of images

version: 1.1
author: Mike King
email: mikkelking @ hotmail . com
website: http://code.google.com/p/jquerytree/

-------------------------------------*/

/* Definitions ----------------------*/
@font-size: 12px;
// Regular icon and text color is white, which suits any medium -> dark background
@color-normal: white;
// Background color
@color-bg: #af0000;
// Highlight color
@color-highlight: yellow;
// Partially selected (checkboxes, radio buttons)
@color-partial: #aaaaaa;
// Partially selected and focused (checkboxes, radio buttons)
@color-partfocus: #cad96c;
// Disabled altogether
@color-disabled: #808080;
// Editing color
@color-edit: yellow;
@w: 15px;
@h: 17px;
@pad-left: 2px;
@pad-top: 10px;
/* End of Definitions ---------------*/

/* Imports -------------------------*/
@import "fa.less";
/* End of Imports ------------------*/

.ztree * {padding:0; margin:0; font-size:@font-size; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif; background-color: @color-bg;}
.ztree {
margin:0; padding:5px; color:@color-normal; background-color: @color-bg;
li {
padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0;
ul {
margin: 0px; padding:0 0 0 18px;
}
ul.line { }
a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent;
text-decoration:none; vertical-align:top; display: inline-block;
input.rename {height:14px; width:80px; padding:0; margin:0;
color: @color-bg; background-color: @color-normal;
font-size:@font-size; border:1px #585956 solid; *border:0px}
}
a:hover {text-decoration:underline}
a.curSelectedNode {padding-top:0px; background-color:#af4040; color:@color-highlight; height:@h; opacity:0.8;}
a.curSelectedNode_Edit {padding-top:0px; background-color:transparent; color:@color-highlight; height:@h; border:1px #666 solid; opacity:0.8;}
a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:@color-highlight; height:@h; border:1px #666 solid;
opacity:0.8; filter:alpha(opacity=80)}
a.tmpTargetNode_prev {}
a.tmpTargetNode_next {}
span {line-height:@h; margin-right:2px; background-color:transparent;}
span.button {line-height:0; margin:0; padding: 0; width:@w; height:@h; display: inline-block; vertical-align:top;
border:0px solid; cursor: pointer;outline:none;
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
&::before{color: @color-normal; font-family: FontAwesome; padding-top:@pad-top;}
&.chk { margin:0px; cursor: auto; width: 12px;
display: inline-block;padding-top:@pad-top;padding-left:@pad-left;
&.checkbox_false_full::before {content: @fa-square-o;}
&.checkbox_false_full_focus::before {content: @fa-square-o; color:@color-highlight;}
&.checkbox_false_part::before {content: @fa-square-o;color: @color-partial;}
&.checkbox_false_part_focus::before {content: @fa-square-o; color:@color-partfocus;}
&.checkbox_false_disable::before {content: @fa-square-o; color:@color-disabled;}
&.checkbox_true_full::before {content: @fa-check-square-o;}
&.checkbox_true_full_focus::before {content: @fa-check-square-o;}
&.checkbox_true_part::before {content: @fa-check-square;}
&.checkbox_true_part_focus::before {content: @fa-check-square; color: @color-highlight}
&.checkbox_true_full_focus::before {content: @fa-check-square-o; color: @color-highlight}
&.checkbox_true_part::before {content: @fa-check-square-o;color: @color-partial}
&.checkbox_true_part_focus::before {content: @fa-check-square-o;color: @color-partfocus;}
&.checkbox_true_disable::before {content: @fa-check-square-o;color: @color-disabled}
&.radio_false_full::before {content: @fa-circle-o;}
&.radio_false_full_focus::before {content: @fa-circle-o;color: @color-highlight}
&.radio_false_part::before {content: @fa-circle-o;color: @color-partial}
&.radio_false_part_focus::before {content: @fa-circle-o;color: @color-highlight}
&.radio_false_disable::before {content: @fa-circle-thin;color: @color-disabled}
&.radio_true_full::before {content: @fa-dot-circle-o;}
&.radio_true_full_focus::before {content: @fa-dot-circle-o;color: @color-highlight}
&.radio_true_part::before {content: @fa-dot-circle-o;color: @color-partial}
&.radio_true_part_focus::before {content: @fa-dot-circle-o;color: @color-partial;}
&.radio_true_disable::before {content: @fa-circle-thin;color: @color-disabled}
}
&.switch {width:@w; height:@h}
&.root_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.root_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.roots_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.roots_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.center_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.center_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.bottom_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.bottom_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;}
&.noline_open{}
&.noline_close{}
&.root_docu{ background:none;}
&.roots_docu::before{content: @fa-list-alt;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.center_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.bottom_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.noline_docu{ background:none;}
&.ico_open::before {content: @fa-folder-open-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.ico_close::before {content: @fa-folder-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.ico_docu::before{content: @fa-list-alt;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;}
&.edit {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;}
&.edit::before{content: @fa-pencil-square-o;font-family: FontAwesome;}
&.remove {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;}
&.remove::before{content: @fa-trash;font-family: FontAwesome;}

&.add {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;}
&.add::before{content: @fa-plus;font-family: FontAwesome;}

&.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}
}

}
}


ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}

// this is the arrow that moves
span.tmpzTreeMove_arrow{width:16px; height:@h; display: inline-block;
padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;
background-color:transparent; background-attachment: scroll;
}
span.tmpzTreeMove_arrow::before{content: @fa-play;font-family: FontAwesome;color: @color-highlight;
}
// outline

ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden;
background-color:#cfcfcf; border:1px @color-highlight dotted; opacity:0.8; filter:alpha(opacity=80)}
.ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}


+ 480
- 0
public/self/ztree/css/awesomeStyle/fa.less View File

@@ -0,0 +1,480 @@
@fa-glass: "\f000";
@fa-music: "\f001";
@fa-search: "\f002";
@fa-envelope-o: "\f003";
@fa-heart: "\f004";
@fa-star: "\f005";
@fa-star-o: "\f006";
@fa-user: "\f007";
@fa-film: "\f008";
@fa-th-large: "\f009";
@fa-th: "\f00a";
@fa-th-list: "\f00b";
@fa-check: "\f00c";
@fa-times: "\f00d";
@fa-search-plus: "\f00e";
@fa-search-minus: "\f010";
@fa-power-off: "\f011";
@fa-signal: "\f012";
@fa-cog: "\f013";
@fa-trash-o: "\f014";
@fa-home: "\f015";
@fa-file-o: "\f016";
@fa-clock-o: "\f017";
@fa-road: "\f018";
@fa-download: "\f019";
@fa-arrow-circle-o-down: "\f01a";
@fa-arrow-circle-o-up: "\f01b";
@fa-inbox: "\f01c";
@fa-play-circle-o: "\f01d";
@fa-repeat: "\f01e";
@fa-refresh: "\f021";
@fa-list-alt: "\f022";
@fa-lock: "\f023";
@fa-flag: "\f024";
@fa-headphones: "\f025";
@fa-volume-off: "\f026";
@fa-volume-down: "\f027";
@fa-volume-up: "\f028";
@fa-qrcode: "\f029";
@fa-barcode: "\f02a";
@fa-tag: "\f02b";
@fa-tags: "\f02c";
@fa-book: "\f02d";
@fa-bookmark: "\f02e";
@fa-print: "\f02f";
@fa-camera: "\f030";
@fa-font: "\f031";
@fa-bold: "\f032";
@fa-italic: "\f033";
@fa-text-height: "\f034";
@fa-text-width: "\f035";
@fa-align-left: "\f036";
@fa-align-center: "\f037";
@fa-align-right: "\f038";
@fa-align-justify: "\f039";
@fa-list: "\f03a";
@fa-outdent: "\f03b";
@fa-indent: "\f03c";
@fa-video-camera: "\f03d";
@fa-picture-o: "\f03e";
@fa-pencil: "\f040";
@fa-map-marker: "\f041";
@fa-adjust: "\f042";
@fa-tint: "\f043";
@fa-pencil-square-o: "\f044";
@fa-share-square-o: "\f045";
@fa-check-square-o: "\f046";
@fa-arrows: "\f047";
@fa-step-backward: "\f048";
@fa-fast-backward: "\f049";
@fa-backward: "\f04a";
@fa-play: "\f04b";
@fa-pause: "\f04c";
@fa-stop: "\f04d";
@fa-forward: "\f04e";
@fa-fast-forward: "\f050";
@fa-step-forward: "\f051";
@fa-eject: "\f052";
@fa-chevron-left: "\f053";
@fa-chevron-right: "\f054";
@fa-plus-circle: "\f055";
@fa-minus-circle: "\f056";
@fa-times-circle: "\f057";
@fa-check-circle: "\f058";
@fa-question-circle: "\f059";
@fa-info-circle: "\f05a";
@fa-crosshairs: "\f05b";
@fa-times-circle-o: "\f05c";
@fa-check-circle-o: "\f05d";
@fa-ban: "\f05e";
@fa-arrow-left: "\f060";
@fa-arrow-right: "\f061";
@fa-arrow-up: "\f062";
@fa-arrow-down: "\f063";
@fa-share: "\f064";
@fa-expand: "\f065";
@fa-compress: "\f066";
@fa-plus: "\f067";
@fa-minus: "\f068";
@fa-asterisk: "\f069";
@fa-exclamation-circle: "\f06a";
@fa-gift: "\f06b";
@fa-leaf: "\f06c";
@fa-fire: "\f06d";
@fa-eye: "\f06e";
@fa-eye-slash: "\f070";
@fa-exclamation-triangle: "\f071";
@fa-plane: "\f072";
@fa-calendar: "\f073";
@fa-random: "\f074";
@fa-comment: "\f075";
@fa-magnet: "\f076";
@fa-chevron-up: "\f077";
@fa-chevron-down: "\f078";
@fa-retweet: "\f079";
@fa-shopping-cart: "\f07a";
@fa-folder: "\f07b";
@fa-folder-open: "\f07c";
@fa-arrows-v: "\f07d";
@fa-arrows-h: "\f07e";
@fa-bar-chart: "\f080";
@fa-twitter-square: "\f081";
@fa-facebook-square: "\f082";
@fa-camera-retro: "\f083";
@fa-key: "\f084";
@fa-cogs: "\f085";
@fa-comments: "\f086";
@fa-thumbs-o-up: "\f087";
@fa-thumbs-o-down: "\f088";
@fa-star-half: "\f089";
@fa-heart-o: "\f08a";
@fa-sign-out: "\f08b";
@fa-linkedin-square: "\f08c";
@fa-thumb-tack: "\f08d";
@fa-external-link: "\f08e";
@fa-sign-in: "\f090";
@fa-trophy: "\f091";
@fa-github-square: "\f092";
@fa-upload: "\f093";
@fa-lemon-o: "\f094";
@fa-phone: "\f095";
@fa-square-o: "\f096";
@fa-bookmark-o: "\f097";
@fa-phone-square: "\f098";
@fa-twitter: "\f099";
@fa-facebook: "\f09a";
@fa-github: "\f09b";
@fa-unlock: "\f09c";
@fa-credit-card: "\f09d";
@fa-rss: "\f09e";
@fa-hdd-o: "\f0a0";
@fa-bullhorn: "\f0a1";
@fa-bell: "\f0f3";
@fa-certificate: "\f0a3";
@fa-hand-o-right: "\f0a4";
@fa-hand-o-left: "\f0a5";
@fa-hand-o-up: "\f0a6";
@fa-hand-o-down: "\f0a7";
@fa-arrow-circle-left: "\f0a8";
@fa-arrow-circle-right: "\f0a9";
@fa-arrow-circle-up: "\f0aa";
@fa-arrow-circle-down: "\f0ab";
@fa-globe: "\f0ac";
@fa-wrench: "\f0ad";
@fa-tasks: "\f0ae";
@fa-filter: "\f0b0";
@fa-briefcase: "\f0b1";
@fa-arrows-alt: "\f0b2";
@fa-users: "\f0c0";
@fa-link: "\f0c1";
@fa-cloud: "\f0c2";
@fa-flask: "\f0c3";
@fa-scissors: "\f0c4";
@fa-files-o: "\f0c5";
@fa-paperclip: "\f0c6";
@fa-floppy-o: "\f0c7";
@fa-square: "\f0c8";
@fa-bars: "\f0c9";
@fa-list-ul: "\f0ca";
@fa-list-ol: "\f0cb";
@fa-strikethrough: "\f0cc";
@fa-underline: "\f0cd";
@fa-table: "\f0ce";
@fa-magic: "\f0d0";
@fa-truck: "\f0d1";
@fa-pinterest: "\f0d2";
@fa-pinterest-square: "\f0d3";
@fa-google-plus-square: "\f0d4";
@fa-google-plus: "\f0d5";
@fa-money: "\f0d6";
@fa-caret-down: "\f0d7";
@fa-caret-up: "\f0d8";
@fa-caret-left: "\f0d9";
@fa-caret-right: "\f0da";
@fa-columns: "\f0db";
@fa-sort: "\f0dc";
@fa-sort-desc: "\f0dd";
@fa-sort-asc: "\f0de";
@fa-envelope: "\f0e0";
@fa-linkedin: "\f0e1";
@fa-undo: "\f0e2";
@fa-gavel: "\f0e3";
@fa-tachometer: "\f0e4";
@fa-comment-o: "\f0e5";
@fa-comments-o: "\f0e6";
@fa-bolt: "\f0e7";
@fa-sitemap: "\f0e8";
@fa-umbrella: "\f0e9";
@fa-clipboard: "\f0ea";
@fa-lightbulb-o: "\f0eb";
@fa-exchange: "\f0ec";
@fa-cloud-download: "\f0ed";
@fa-cloud-upload: "\f0ee";
@fa-user-md: "\f0f0";
@fa-stethoscope: "\f0f1";
@fa-suitcase: "\f0f2";
@fa-bell-o: "\f0a2";
@fa-coffee: "\f0f4";
@fa-cutlery: "\f0f5";
@fa-file-text-o: "\f0f6";
@fa-building-o: "\f0f7";
@fa-hospital-o: "\f0f8";
@fa-ambulance: "\f0f9";
@fa-medkit: "\f0fa";
@fa-fighter-jet: "\f0fb";
@fa-beer: "\f0fc";
@fa-h-square: "\f0fd";
@fa-plus-square: "\f0fe";
@fa-angle-double-left: "\f100";
@fa-angle-double-right: "\f101";
@fa-angle-double-up: "\f102";
@fa-angle-double-down: "\f103";
@fa-angle-left: "\f104";
@fa-angle-right: "\f105";
@fa-angle-up: "\f106";
@fa-angle-down: "\f107";
@fa-desktop: "\f108";
@fa-laptop: "\f109";
@fa-tablet: "\f10a";
@fa-mobile: "\f10b";
@fa-circle-o: "\f10c";
@fa-quote-left: "\f10d";
@fa-quote-right: "\f10e";
@fa-spinner: "\f110";
@fa-circle: "\f111";
@fa-reply: "\f112";
@fa-github-alt: "\f113";
@fa-folder-o: "\f114";
@fa-folder-open-o: "\f115";
@fa-smile-o: "\f118";
@fa-frown-o: "\f119";
@fa-meh-o: "\f11a";
@fa-gamepad: "\f11b";
@fa-keyboard-o: "\f11c";
@fa-flag-o: "\f11d";
@fa-flag-checkered: "\f11e";
@fa-terminal: "\f120";
@fa-code: "\f121";
@fa-reply-all: "\f122";
@fa-star-half-o: "\f123";
@fa-location-arrow: "\f124";
@fa-crop: "\f125";
@fa-code-fork: "\f126";
@fa-chain-broken: "\f127";
@fa-question: "\f128";
@fa-info: "\f129";
@fa-exclamation: "\f12a";
@fa-superscript: "\f12b";
@fa-subscript: "\f12c";
@fa-eraser: "\f12d";
@fa-puzzle-piece: "\f12e";
@fa-microphone: "\f130";
@fa-microphone-slash: "\f131";
@fa-shield: "\f132";
@fa-calendar-o: "\f133";
@fa-fire-extinguisher: "\f134";
@fa-rocket: "\f135";
@fa-maxcdn: "\f136";
@fa-chevron-circle-left: "\f137";
@fa-chevron-circle-right: "\f138";
@fa-chevron-circle-up: "\f139";
@fa-chevron-circle-down: "\f13a";
@fa-html5: "\f13b";
@fa-css3: "\f13c";
@fa-anchor: "\f13d";
@fa-unlock-alt: "\f13e";
@fa-bullseye: "\f140";
@fa-ellipsis-h: "\f141";
@fa-ellipsis-v: "\f142";
@fa-rss-square: "\f143";
@fa-play-circle: "\f144";
@fa-ticket: "\f145";
@fa-minus-square: "\f146";
@fa-minus-square-o: "\f147";
@fa-level-up: "\f148";
@fa-level-down: "\f149";
@fa-check-square: "\f14a";
@fa-pencil-square: "\f14b";
@fa-external-link-square: "\f14c";
@fa-share-square: "\f14d";
@fa-compass: "\f14e";
@fa-caret-square-o-down: "\f150";
@fa-caret-square-o-up: "\f151";
@fa-caret-square-o-right: "\f152";
@fa-eur: "\f153";
@fa-gbp: "\f154";
@fa-usd: "\f155";
@fa-inr: "\f156";
@fa-jpy: "\f157";
@fa-rub: "\f158";
@fa-krw: "\f159";
@fa-btc: "\f15a";
@fa-file: "\f15b";
@fa-file-text: "\f15c";
@fa-sort-alpha-asc: "\f15d";
@fa-sort-alpha-desc: "\f15e";
@fa-sort-amount-asc: "\f160";
@fa-sort-amount-desc: "\f161";
@fa-sort-numeric-asc: "\f162";
@fa-sort-numeric-desc: "\f163";
@fa-thumbs-up: "\f164";
@fa-thumbs-down: "\f165";
@fa-youtube-square: "\f166";
@fa-youtube: "\f167";
@fa-xing: "\f168";
@fa-xing-square: "\f169";
@fa-youtube-play: "\f16a";
@fa-dropbox: "\f16b";
@fa-stack-overflow: "\f16c";
@fa-instagram: "\f16d";
@fa-flickr: "\f16e";
@fa-adn: "\f170";
@fa-bitbucket: "\f171";
@fa-bitbucket-square: "\f172";
@fa-tumblr: "\f173";
@fa-tumblr-square: "\f174";
@fa-long-arrow-down: "\f175";
@fa-long-arrow-up: "\f176";
@fa-long-arrow-left: "\f177";
@fa-long-arrow-right: "\f178";
@fa-apple: "\f179";
@fa-windows: "\f17a";
@fa-android: "\f17b";
@fa-linux: "\f17c";
@fa-dribbble: "\f17d";
@fa-skype: "\f17e";
@fa-foursquare: "\f180";
@fa-trello: "\f181";
@fa-female: "\f182";
@fa-male: "\f183";
@fa-gittip: "\f184";
@fa-sun-o: "\f185";
@fa-moon-o: "\f186";
@fa-archive: "\f187";
@fa-bug: "\f188";
@fa-vk: "\f189";
@fa-weibo: "\f18a";
@fa-renren: "\f18b";
@fa-pagelines: "\f18c";
@fa-stack-exchange: "\f18d";
@fa-arrow-circle-o-right: "\f18e";
@fa-arrow-circle-o-left: "\f190";
@fa-caret-square-o-left: "\f191";
@fa-dot-circle-o: "\f192";
@fa-wheelchair: "\f193";
@fa-vimeo-square: "\f194";
@fa-try: "\f195";
@fa-plus-square-o: "\f196";
@fa-space-shuttle: "\f197";
@fa-slack: "\f198";
@fa-envelope-square: "\f199";
@fa-wordpress: "\f19a";
@fa-openid: "\f19b";
@fa-university: "\f19c";
@fa-graduation-cap: "\f19d";
@fa-yahoo: "\f19e";
@fa-google: "\f1a0";
@fa-reddit: "\f1a1";
@fa-reddit-square: "\f1a2";
@fa-stumbleupon-circle: "\f1a3";
@fa-stumbleupon: "\f1a4";
@fa-delicious: "\f1a5";
@fa-digg: "\f1a6";
@fa-pied-piper: "\f1a7";
@fa-pied-piper-alt: "\f1a8";
@fa-drupal: "\f1a9";
@fa-joomla: "\f1aa";
@fa-language: "\f1ab";
@fa-fax: "\f1ac";
@fa-building: "\f1ad";
@fa-child: "\f1ae";
@fa-paw: "\f1b0";
@fa-spoon: "\f1b1";
@fa-cube: "\f1b2";
@fa-cubes: "\f1b3";
@fa-behance: "\f1b4";
@fa-behance-square: "\f1b5";
@fa-steam: "\f1b6";
@fa-steam-square: "\f1b7";
@fa-recycle: "\f1b8";
@fa-car: "\f1b9";
@fa-taxi: "\f1ba";
@fa-tree: "\f1bb";
@fa-spotify: "\f1bc";
@fa-deviantart: "\f1bd";
@fa-soundcloud: "\f1be";
@fa-database: "\f1c0";
@fa-file-pdf-o: "\f1c1";
@fa-file-word-o: "\f1c2";
@fa-file-excel-o: "\f1c3";
@fa-file-powerpoint-o: "\f1c4";
@fa-file-image-o: "\f1c5";
@fa-file-archive-o: "\f1c6";
@fa-file-audio-o: "\f1c7";
@fa-file-video-o: "\f1c8";
@fa-file-code-o: "\f1c9";
@fa-vine: "\f1ca";
@fa-codepen: "\f1cb";
@fa-jsfiddle: "\f1cc";
@fa-life-ring: "\f1cd";
@fa-circle-o-notch: "\f1ce";
@fa-rebel: "\f1d0";
@fa-empire: "\f1d1";
@fa-git-square: "\f1d2";
@fa-git: "\f1d3";
@fa-hacker-news: "\f1d4";
@fa-tencent-weibo: "\f1d5";
@fa-qq: "\f1d6";
@fa-weixin: "\f1d7";
@fa-paper-plane: "\f1d8";
@fa-paper-plane-o: "\f1d9";
@fa-history: "\f1da";
@fa-circle-thin: "\f1db";
@fa-header: "\f1dc";
@fa-paragraph: "\f1dd";
@fa-sliders: "\f1de";
@fa-share-alt: "\f1e0";
@fa-share-alt-square: "\f1e1";
@fa-bomb: "\f1e2";
@fa-futbol-o: "\f1e3";
@fa-tty: "\f1e4";
@fa-binoculars: "\f1e5";
@fa-plug: "\f1e6";
@fa-slideshare: "\f1e7";
@fa-twitch: "\f1e8";
@fa-yelp: "\f1e9";
@fa-newspaper-o: "\f1ea";
@fa-wifi: "\f1eb";
@fa-calculator: "\f1ec";
@fa-paypal: "\f1ed";
@fa-google-wallet: "\f1ee";
@fa-cc-visa: "\f1f0";
@fa-cc-mastercard: "\f1f1";
@fa-cc-discover: "\f1f2";
@fa-cc-amex: "\f1f3";
@fa-cc-paypal: "\f1f4";
@fa-cc-stripe: "\f1f5";
@fa-bell-slash: "\f1f6";
@fa-bell-slash-o: "\f1f7";
@fa-trash: "\f1f8";
@fa-copyright: "\f1f9";
@fa-at: "\f1fa";
@fa-eyedropper: "\f1fb";
@fa-paint-brush: "\f1fc";
@fa-birthday-cake: "\f1fd";
@fa-area-chart: "\f1fe";
@fa-pie-chart: "\f200";
@fa-line-chart: "\f201";
@fa-lastfm: "\f202";
@fa-lastfm-square: "\f203";
@fa-toggle-off: "\f204";
@fa-toggle-on: "\f205";
@fa-bicycle: "\f206";
@fa-bus: "\f207";
@fa-ioxhost: "\f208";
@fa-angellist: "\f209";
@fa-cc: "\f20a";
@fa-ils: "\f20b";
@fa-meanpath: "\f20c";


BIN
public/self/ztree/css/awesomeStyle/img/loading.gif View File

Before After
Width: 16  |  Height: 16  |  Size: 381 B

+ 33
- 0
public/self/ztree/css/demo.css View File

@@ -0,0 +1,33 @@
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;padding: 0;border: 0;outline: 0;font-weight: inherit;font-style: inherit;font-size: 100%;font-family: inherit;vertical-align: baseline;}
body {color: #2f332a;font: 15px/21px Arial, Helvetica, simsun, sans-serif;background: #f0f6e4 \9;}
h1, h2, h3, h4, h5, h6 {color: #2f332a;font-weight: bold;font-family: Helvetica, Arial, sans-serif;padding-bottom: 5px;}
h1 {font-size: 24px;line-height: 34px;text-align: center;}
h2 {font-size: 14px;line-height: 24px;padding-top: 5px;}
h6 {font-weight: normal;font-size: 12px;letter-spacing: 1px;line-height: 24px;text-align: center;}
a {color:#3C6E31;text-decoration: underline;}
a:hover {background-color:#3C6E31;color:white;}
input.radio {margin: 0 2px 0 8px;}
input.radio.first {margin-left:0;}
input.empty {color: lightgray;}
code {color: #2f332a;}
.highlight_red {color:#A60000;}
.highlight_green {color:#A7F43D;}
li {list-style: circle;font-size: 12px;}
li.title {list-style: none;}
ul.list {margin-left: 17px;}

div.content_wrap {width: 600px;height:380px;}
div.content_wrap div.left{float: left;width: 250px;}
div.content_wrap div.right{float: right;width: 340px;}
div.zTreeDemoBackground {width:250px;height:362px;text-align:left;}

ul.ztree {margin-top: 10px;border: 1px solid #617775;background: #f0f6e4;width:220px;height:360px;overflow-y:scroll;overflow-x:auto;}
ul.log {border: 1px solid #617775;background: #f0f6e4;width:300px;height:170px;overflow: hidden;}
ul.log.small {height:45px;}
ul.log li {color: #666666;list-style: none;padding-left: 10px;}
ul.log li.dark {background-color: #E3E3E3;}

/* ruler */
div.ruler {height:20px; width:220px; background-color:#f0f6e4;border: 1px solid #333; margin-bottom: 5px; cursor: pointer}
div.ruler div.cursor {height:20px; width:30px; background-color:#3C6E31; color:white; text-align: right; padding-right: 5px; cursor: pointer}

BIN
public/self/ztree/css/metroStyle/img/line_conn.png View File

Before After
Width: 11  |  Height: 2  |  Size: 933 B

BIN
public/self/ztree/css/metroStyle/img/loading.gif View File

Before After
Width: 16  |  Height: 16  |  Size: 381 B

BIN
public/self/ztree/css/metroStyle/img/metro.gif View File

Before After
Width: 210  |  Height: 126  |  Size: 4.7 kB

BIN
public/self/ztree/css/metroStyle/img/metro.png View File

Before After
Width: 210  |  Height: 126  |  Size: 5.3 kB

+ 96
- 0
public/self/ztree/css/metroStyle/metroStyle.css View File

@@ -0,0 +1,96 @@
/*-------------------------------------
zTree Style

version: 3.4
author: Hunter.z
email: hunter.z@263.net
website: http://code.google.com/p/jquerytree/

-------------------------------------*/

.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}
.ztree {margin:0; padding:5px; color:#333}
.ztree li{padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0}
.ztree li ul{ margin:0; padding:0 0 0 18px}
.ztree li ul.line{ background:url(./img/line_conn.png) 0 0 repeat-y;}

.ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; vertical-align:top; display: inline-block}
.ztree li a:hover {text-decoration:underline}
.ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; opacity:0.8;}
.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; border:1px #666 solid; opacity:0.8;}
.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid;
opacity:0.8; filter:alpha(opacity=80)}
.ztree li a.tmpTargetNode_prev {}
.ztree li a.tmpTargetNode_next {}
.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;
font-size:12px; border:1px #585956 solid; *border:0px}
.ztree li span {line-height:21px; margin-right:2px}
.ztree li span.button {line-height:0; margin:0; padding: 0; width:21px; height:21px; display: inline-block; vertical-align:middle;
border:0 none; cursor: pointer;outline:none;
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
background-image:url("./img/metro.png"); *background-image:url("./img/metro.gif")}

.ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto}
.ztree li span.button.chk.checkbox_false_full {background-position: -5px -5px;}
.ztree li span.button.chk.checkbox_false_full_focus {background-position: -5px -26px;}
.ztree li span.button.chk.checkbox_false_part {background-position: -5px -48px;}
.ztree li span.button.chk.checkbox_false_part_focus {background-position: -5px -68px;}
.ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;}
.ztree li span.button.chk.checkbox_true_full {background-position: -26px -5px;}
.ztree li span.button.chk.checkbox_true_full_focus {background-position: -26px -26px;}
.ztree li span.button.chk.checkbox_true_part {background-position: -26px -48px;}
.ztree li span.button.chk.checkbox_true_part_focus {background-position: -26px -68px;}
.ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;}
.ztree li span.button.chk.radio_false_full {background-position: -47px -5px;}
.ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;}
.ztree li span.button.chk.radio_false_part {background-position: -47px -47px;}
.ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;}
.ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;}
.ztree li span.button.chk.radio_true_full {background-position: -68px -5px;}
.ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;}
.ztree li span.button.chk.radio_true_part {background-position: -68px -47px;}
.ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;}
.ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;}

.ztree li span.button.switch {width:21px; height:21px}
.ztree li span.button.root_open{background-position:-105px -63px}
.ztree li span.button.root_close{background-position:-126px -63px}
.ztree li span.button.roots_open{background-position: -105px 0;}
.ztree li span.button.roots_close{background-position: -126px 0;}
.ztree li span.button.center_open{background-position: -105px -21px;}
.ztree li span.button.center_close{background-position: -126px -21px;}
.ztree li span.button.bottom_open{background-position: -105px -42px;}
.ztree li span.button.bottom_close{background-position: -126px -42px;}
.ztree li span.button.noline_open{background-position: -105px -84px;}
.ztree li span.button.noline_close{background-position: -126px -84px;}
.ztree li span.button.root_docu{ background:none;}
.ztree li span.button.roots_docu{background-position: -84px 0;}
.ztree li span.button.center_docu{background-position: -84px -21px;}
.ztree li span.button.bottom_docu{background-position: -84px -42px;}
.ztree li span.button.noline_docu{ background:none;}

.ztree li span.button.ico_open{margin-right:2px; background-position: -147px -21px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.ico_close{margin-right:2px; margin-right:2px; background-position: -147px 0; vertical-align:top; *vertical-align:middle}
.ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.edit:hover {
background-position: -168px -21px;
}
.ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.remove:hover {
background-position: -168px -42px;
}
.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle}
.ztree li span.button.add:hover {
background-position: -168px 0;
}
.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}

ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}

span.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
background-position:-168px -84px; background-image:url("./img/metro.png"); *background-image:url("./img/metro.gif")}

ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}
.ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}

BIN
public/self/ztree/css/zTreeStyle/img/diy/1_close.png View File

Before After
Width: 16  |  Height: 16  |  Size: 601 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/1_open.png View File

Before After
Width: 16  |  Height: 16  |  Size: 580 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/2.png View File

Before After
Width: 16  |  Height: 16  |  Size: 570 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/3.png View File

Before After
Width: 16  |  Height: 16  |  Size: 762 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/4.png View File

Before After
Width: 16  |  Height: 16  |  Size: 399 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/5.png View File

Before After
Width: 16  |  Height: 16  |  Size: 710 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/6.png View File

Before After
Width: 16  |  Height: 16  |  Size: 432 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/7.png View File

Before After
Width: 16  |  Height: 16  |  Size: 534 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/8.png View File

Before After
Width: 16  |  Height: 16  |  Size: 529 B

BIN
public/self/ztree/css/zTreeStyle/img/diy/9.png View File

Before After
Width: 16  |  Height: 16  |  Size: 467 B

BIN
public/self/ztree/css/zTreeStyle/img/line_conn.gif View File

Before After
Width: 9  |  Height: 2  |  Size: 45 B

BIN
public/self/ztree/css/zTreeStyle/img/loading.gif View File

Before After
Width: 16  |  Height: 16  |  Size: 381 B

BIN
public/self/ztree/css/zTreeStyle/img/zTreeStandard.gif View File

Before After
Width: 160  |  Height: 97  |  Size: 6.6 kB

BIN
public/self/ztree/css/zTreeStyle/img/zTreeStandard.png View File

Before After
Width: 160  |  Height: 97  |  Size: 11 kB

+ 99
- 0
public/self/ztree/css/zTreeStyle/zTreeStyle.css View File

@@ -0,0 +1,99 @@
/*-------------------------------------
zTree Style

version: 3.5.19
author: Hunter.z
email: hunter.z@263.net
website: http://code.google.com/p/jquerytree/

-------------------------------------*/

.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}
.ztree {margin:0; padding:5px; color:#333;margin-top: 0; height: 100%; max-height: 400px; overflow-y: scroll;}
.ztree::-webkit-scrollbar-track{background-color: #FFF;}
.ztree li{padding:5px 0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0; position: relative;}
.ztree li ul{ margin:0; padding:0 0 0 18px}
/*.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;}*/

.ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent;
text-decoration:none; vertical-align:top; display: inline-block}
.ztree li a:hover {text-decoration:none;}
.ztree li a:hover .node_name::after{content: '';position: absolute;left: 0;right: 0;top: 0;background-color: #f7f7f7;height: 100%;z-index: -1;}
.ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}
.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}
.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid;
opacity:0.8; filter:alpha(opacity=80)}
.ztree li a.tmpTargetNode_prev {}
.ztree li a.tmpTargetNode_next {}
.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;
font-size:12px; border:1px #7EC4CC solid; *border:0px}
.ztree li span {line-height:16px; margin-right:2px}
.ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle;
border:0 none; cursor: pointer;outline:none;
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")}

.ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto}
.ztree li span.button.chk.checkbox_false_full {background-position:0 0}
.ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px}
.ztree li span.button.chk.checkbox_false_part {background-position:0 -28px}
.ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px}
.ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px}
.ztree li span.button.chk.checkbox_true_full {background-position:-14px 0}
.ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px}
.ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px}
.ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px}
.ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px}
.ztree li span.button.chk.radio_false_full {background-position:-28px 0}
.ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px}
.ztree li span.button.chk.radio_false_part {background-position:-28px -28px}
.ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px}
.ztree li span.button.chk.radio_false_disable {background-position:-28px -56px}
.ztree li span.button.chk.radio_true_full {background-position:-42px 0}
.ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px}
.ztree li span.button.chk.radio_true_part {background-position:-42px -28px}
.ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px}
.ztree li span.button.chk.radio_true_disable {background-position:-42px -56px}

.ztree li span.button.switch {width:18px; height:18px}
.ztree li span.button.root_open{background-position:-92px -54px}
.ztree li span.button.root_close{background-position:-74px -54px}
.ztree li span.button.roots_open{background-position:-92px 0}
.ztree li span.button.roots_close{background-position:-74px 0}
.ztree li span.button.center_open{background-position:-92px -18px}
.ztree li span.button.center_close{background-position:-74px -18px}
.ztree li span.button.bottom_open{background-position:-92px -36px}
.ztree li span.button.bottom_close{background-position:-74px -36px}
.ztree li span.button.noline_open{background-position:-92px -72px}
.ztree li span.button.noline_close{background-position:-74px -72px}
.ztree li span.button.root_docu{ background:none;}
.ztree li span.button.roots_docu{background-position:-56px 0}
.ztree li span.button.center_docu{background-position:-56px -18px}
.ztree li span.button.bottom_docu{background-position:-56px -36px}
.ztree li span.button.noline_docu{ background:none;}

.ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle}
.ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle}

.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}

ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}

span.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;
background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
background-position:-110px -80px; background-image:url("./img/zTreeStandard.png"); *background-image:url("./img/zTreeStandard.gif")}

ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}
.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}

/* level style*/
/*.ztree li span.button.level0 {
display:none;
}
.ztree li ul.level0 {
padding:0;
background:none;
}*/

+ 167
- 0
public/self/ztree/js/jquery-1.4.4.min.js View File

@@ -0,0 +1,167 @@
/*!
* jQuery JavaScript Library v1.4.4
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Thu Nov 11 19:04:53 2010 -0500
*/
(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this,
a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=
c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",
colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),
l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,
"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=
a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=
w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===
"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});
c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,
[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));
return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==
B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===
i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=
i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,
"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-
0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===
"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;
for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),
i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;
c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},
not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,
"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=
c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,
b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):
this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-
1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);

+ 3878
- 0
public/self/ztree/js/jquery.ztree.all.js
File diff suppressed because it is too large
View File


+ 2019
- 0
public/self/ztree/js/jquery.ztree.core.js
File diff suppressed because it is too large
View File


+ 652
- 0
public/self/ztree/js/jquery.ztree.excheck.js View File

@@ -0,0 +1,652 @@
/*
* JQuery zTree excheck
* v3.5.48
* http://treejs.cn/
*
* Copyright (c) 2010 Hunter.z
*
* Licensed same as jquery - MIT License
* http://www.opensource.org/licenses/mit-license.php
*
* Date: 2020-11-21
*/

(function ($) {
//default consts of excheck
var _consts = {
event: {
CHECK: "ztree_check"
},
id: {
CHECK: "_check"
},
checkbox: {
STYLE: "checkbox",
DEFAULT: "chk",
DISABLED: "disable",
FALSE: "false",
TRUE: "true",
FULL: "full",
PART: "part",
FOCUS: "focus"
},
radio: {
STYLE: "radio",
TYPE_ALL: "all",
TYPE_LEVEL: "level"
}
},
//default setting of excheck
_setting = {
check: {
enable: false,
autoCheckTrigger: false,
chkStyle: _consts.checkbox.STYLE,
nocheckInherit: false,
chkDisabledInherit: false,
radioType: _consts.radio.TYPE_LEVEL,
chkboxType: {
"Y": "ps",
"N": "ps"
}
},
data: {
key: {
checked: "checked"
}
},
callback: {
beforeCheck: null,
onCheck: null
}
},
//default root of excheck
_initRoot = function (setting) {
var r = data.getRoot(setting);
r.radioCheckedList = [];
},
//default cache of excheck
_initCache = function (treeId) {
},
//default bind event of excheck
_bindEvent = function (setting) {
var o = setting.treeObj,
c = consts.event;
o.bind(c.CHECK, function (event, srcEvent, treeId, node) {
event.srcEvent = srcEvent;
tools.apply(setting.callback.onCheck, [event, treeId, node]);
});
},
_unbindEvent = function (setting) {
var o = setting.treeObj,
c = consts.event;
o.unbind(c.CHECK);
},
//default event proxy of excheck
_eventProxy = function (e) {
var target = e.target,
setting = data.getSetting(e.data.treeId),
tId = "", node = null,
nodeEventType = "", treeEventType = "",
nodeEventCallback = null, treeEventCallback = null;

if (tools.eqs(e.type, "mouseover")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "mouseoverCheck";
}
} else if (tools.eqs(e.type, "mouseout")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "mouseoutCheck";
}
} else if (tools.eqs(e.type, "click")) {
if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode" + consts.id.CHECK) !== null) {
tId = tools.getNodeMainDom(target).id;
nodeEventType = "checkNode";
}
}
if (tId.length > 0) {
node = data.getNodeCache(setting, tId);
switch (nodeEventType) {
case "checkNode" :
nodeEventCallback = _handler.onCheckNode;
break;
case "mouseoverCheck" :
nodeEventCallback = _handler.onMouseoverCheck;
break;
case "mouseoutCheck" :
nodeEventCallback = _handler.onMouseoutCheck;
break;
}
}
var proxyResult = {
stop: nodeEventType === "checkNode",
node: node,
nodeEventType: nodeEventType,
nodeEventCallback: nodeEventCallback,
treeEventType: treeEventType,
treeEventCallback: treeEventCallback
};
return proxyResult
},
//default init node of excheck
_initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {
if (!n) return;
var checked = data.nodeChecked(setting, n);
n.checkedOld = checked;
if (typeof n.nocheck == "string") n.nocheck = tools.eqs(n.nocheck, "true");
n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck);
if (typeof n.chkDisabled == "string") n.chkDisabled = tools.eqs(n.chkDisabled, "true");
n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled);
if (typeof n.halfCheck == "string") n.halfCheck = tools.eqs(n.halfCheck, "true");
n.halfCheck = !!n.halfCheck;
n.check_Child_State = -1;
n.check_Focus = false;
n.getCheckStatus = function () {
return data.getCheckStatus(setting, n);
};

if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && checked) {
var r = data.getRoot(setting);
r.radioCheckedList.push(n);
}
},
//add dom for check
_beforeA = function (setting, node, html) {
if (setting.check.enable) {
data.makeChkFlag(setting, node);
html.push("<span ID='", node.tId, consts.id.CHECK, "' class='", view.makeChkClass(setting, node), "' treeNode", consts.id.CHECK, (node.nocheck === true ? " style='display:none;'" : ""), "></span>");
}
},
//update zTreeObj, add method of check
_zTreeTools = function (setting, zTreeTools) {
zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) {
var nodeChecked = data.nodeChecked(setting, node);
if (node.chkDisabled === true) return;
if (checked !== true && checked !== false) {
checked = !nodeChecked;
}
callbackFlag = !!callbackFlag;

if (nodeChecked === checked && !checkTypeFlag) {
return;
} else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) {
return;
}
if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) {
data.nodeChecked(setting, node, checked);
var checkObj = $$(node, consts.id.CHECK, this.setting);
if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
view.setChkClass(this.setting, checkObj, node);
view.repairParentChkClassWithSelf(this.setting, node);
if (callbackFlag) {
this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]);
}
}
}

zTreeTools.checkAllNodes = function (checked) {
view.repairAllChk(this.setting, !!checked);
}

zTreeTools.getCheckedNodes = function (checked) {
checked = (checked !== false);
var children = data.nodeChildren(setting, data.getRoot(this.setting));
return data.getTreeCheckedNodes(this.setting, children, checked);
}

zTreeTools.getChangeCheckedNodes = function () {
var children = data.nodeChildren(setting, data.getRoot(this.setting));
return data.getTreeChangeCheckedNodes(this.setting, children);
}

zTreeTools.setChkDisabled = function (node, disabled, inheritParent, inheritChildren) {
disabled = !!disabled;
inheritParent = !!inheritParent;
inheritChildren = !!inheritChildren;
view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren);
view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent);
}

var _updateNode = zTreeTools.updateNode;
zTreeTools.updateNode = function (node, checkTypeFlag) {
if (_updateNode) _updateNode.apply(zTreeTools, arguments);
if (!node || !this.setting.check.enable) return;
var nObj = $$(node, this.setting);
if (nObj.get(0) && tools.uCanDo(this.setting)) {
var checkObj = $$(node, consts.id.CHECK, this.setting);
if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node);
view.setChkClass(this.setting, checkObj, node);
view.repairParentChkClassWithSelf(this.setting, node);
}
}
},
//method of operate data
_data = {
getRadioCheckedList: function (setting) {
var checkedList = data.getRoot(setting).radioCheckedList;
for (var i = 0, j = checkedList.length; i < j; i++) {
if (!data.getNodeCache(setting, checkedList[i].tId)) {
checkedList.splice(i, 1);
i--;
j--;
}
}
return checkedList;
},
getCheckStatus: function (setting, node) {
if (!setting.check.enable || node.nocheck || node.chkDisabled) return null;
var checked = data.nodeChecked(setting, node),
r = {
checked: checked,
half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (checked ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0)))
};
return r;
},
getTreeCheckedNodes: function (setting, nodes, checked, results) {
if (!nodes) return [];
var onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL);
results = !results ? [] : results;
for (var i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i];
var children = data.nodeChildren(setting, node);
var nodeChecked = data.nodeChecked(setting, node);
if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked == checked) {
results.push(node);
if (onlyOne) {
break;
}
}
data.getTreeCheckedNodes(setting, children, checked, results);
if (onlyOne && results.length > 0) {
break;
}
}
return results;
},
getTreeChangeCheckedNodes: function (setting, nodes, results) {
if (!nodes) return [];
results = !results ? [] : results;
for (var i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i];
var children = data.nodeChildren(setting, node);
var nodeChecked = data.nodeChecked(setting, node);
if (node.nocheck !== true && node.chkDisabled !== true && nodeChecked != node.checkedOld) {
results.push(node);
}
data.getTreeChangeCheckedNodes(setting, children, results);
}
return results;
},
makeChkFlag: function (setting, node) {
if (!node) return;
var chkFlag = -1;
var children = data.nodeChildren(setting, node);
if (children) {
for (var i = 0, l = children.length; i < l; i++) {
var cNode = children[i];
var nodeChecked = data.nodeChecked(setting, cNode);
var tmp = -1;
if (setting.check.chkStyle == consts.radio.STYLE) {
if (cNode.nocheck === true || cNode.chkDisabled === true) {
tmp = cNode.check_Child_State;
} else if (cNode.halfCheck === true) {
tmp = 2;
} else if (nodeChecked) {
tmp = 2;
} else {
tmp = cNode.check_Child_State > 0 ? 2 : 0;
}
if (tmp == 2) {
chkFlag = 2;
break;
} else if (tmp == 0) {
chkFlag = 0;
}
} else if (setting.check.chkStyle == consts.checkbox.STYLE) {
if (cNode.nocheck === true || cNode.chkDisabled === true) {
tmp = cNode.check_Child_State;
} else if (cNode.halfCheck === true) {
tmp = 1;
} else if (nodeChecked) {
tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1;
} else {
tmp = (cNode.check_Child_State > 0) ? 1 : 0;
}
if (tmp === 1) {
chkFlag = 1;
break;
} else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) {
chkFlag = 1;
break;
} else if (chkFlag === 2 && tmp > -1 && tmp < 2) {
chkFlag = 1;
break;
} else if (tmp > -1) {
chkFlag = tmp;
}
}
}
}
node.check_Child_State = chkFlag;
}
},
//method of event proxy
_event = {},
//method of event handler
_handler = {
onCheckNode: function (event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId);
if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true;
var nodeChecked = data.nodeChecked(setting, node);
data.nodeChecked(setting, node, !nodeChecked);
view.checkNodeRelation(setting, node);
var checkObj = $$(node, consts.id.CHECK, setting);
view.setChkClass(setting, checkObj, node);
view.repairParentChkClassWithSelf(setting, node);
setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]);
return true;
},
onMouseoverCheck: function (event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId),
checkObj = $$(node, consts.id.CHECK, setting);
node.check_Focus = true;
view.setChkClass(setting, checkObj, node);
return true;
},
onMouseoutCheck: function (event, node) {
if (node.chkDisabled === true) return false;
var setting = data.getSetting(event.data.treeId),
checkObj = $$(node, consts.id.CHECK, setting);
node.check_Focus = false;
view.setChkClass(setting, checkObj, node);
return true;
}
},
//method of tools for zTree
_tools = {},
//method of operate ztree dom
_view = {
checkNodeRelation: function (setting, node) {
var pNode, i, l,
r = consts.radio;
var nodeChecked = data.nodeChecked(setting, node);
if (setting.check.chkStyle == r.STYLE) {
var checkedList = data.getRadioCheckedList(setting);
if (nodeChecked) {
if (setting.check.radioType == r.TYPE_ALL) {
for (i = checkedList.length - 1; i >= 0; i--) {
pNode = checkedList[i];
var pNodeChecked = data.nodeChecked(setting, pNode);
if (pNodeChecked && pNode != node) {
data.nodeChecked(setting, pNode, false);
checkedList.splice(i, 1);

view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
if (pNode.parentTId != node.parentTId) {
view.repairParentChkClassWithSelf(setting, pNode);
}
}
}
checkedList.push(node);
} else {
var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting);
var children = data.nodeChildren(setting, parentNode);
for (i = 0, l = children.length; i < l; i++) {
pNode = children[i];
var pNodeChecked = data.nodeChecked(setting, pNode);
if (pNodeChecked && pNode != node) {
data.nodeChecked(setting, pNode, false);
view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode);
}
}
}
} else if (setting.check.radioType == r.TYPE_ALL) {
for (i = 0, l = checkedList.length; i < l; i++) {
if (node == checkedList[i]) {
checkedList.splice(i, 1);
break;
}
}
}

} else {
var children = data.nodeChildren(setting, node);
if (nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.Y.indexOf("s") > -1)) {
view.setSonNodeCheckBox(setting, node, true);
}
if (!nodeChecked && (!children || children.length == 0 || setting.check.chkboxType.N.indexOf("s") > -1)) {
view.setSonNodeCheckBox(setting, node, false);
}
if (nodeChecked && setting.check.chkboxType.Y.indexOf("p") > -1) {
view.setParentNodeCheckBox(setting, node, true);
}
if (!nodeChecked && setting.check.chkboxType.N.indexOf("p") > -1) {
view.setParentNodeCheckBox(setting, node, false);
}
}
},
makeChkClass: function (setting, node) {
var c = consts.checkbox, r = consts.radio,
fullStyle = "";
var nodeChecked = data.nodeChecked(setting, node);
if (node.chkDisabled === true) {
fullStyle = c.DISABLED;
} else if (node.halfCheck) {
fullStyle = c.PART;
} else if (setting.check.chkStyle == r.STYLE) {
fullStyle = (node.check_Child_State < 1) ? c.FULL : c.PART;
} else {
fullStyle = nodeChecked ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL : c.PART) : ((node.check_Child_State < 1) ? c.FULL : c.PART);
}
var chkName = setting.check.chkStyle + "_" + (nodeChecked ? c.TRUE : c.FALSE) + "_" + fullStyle;
chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName;
return consts.className.BUTTON + " " + c.DEFAULT + " " + chkName;
},
repairAllChk: function (setting, checked) {
if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) {
var root = data.getRoot(setting);
var children = data.nodeChildren(setting, root);
for (var i = 0, l = children.length; i < l; i++) {
var node = children[i];
if (node.nocheck !== true && node.chkDisabled !== true) {
data.nodeChecked(setting, node, checked);
}
view.setSonNodeCheckBox(setting, node, checked);
}
}
},
repairChkClass: function (setting, node) {
if (!node) return;
data.makeChkFlag(setting, node);
if (node.nocheck !== true) {
var checkObj = $$(node, consts.id.CHECK, setting);
view.setChkClass(setting, checkObj, node);
}
},
repairParentChkClass: function (setting, node) {
if (!node || !node.parentTId) return;
var pNode = node.getParentNode();
view.repairChkClass(setting, pNode);
view.repairParentChkClass(setting, pNode);
},
repairParentChkClassWithSelf: function (setting, node) {
if (!node) return;
var children = data.nodeChildren(setting, node);
if (children && children.length > 0) {
view.repairParentChkClass(setting, children[0]);
} else {
view.repairParentChkClass(setting, node);
}
},
repairSonChkDisabled: function (setting, node, chkDisabled, inherit) {
if (!node) return;
if (node.chkDisabled != chkDisabled) {
node.chkDisabled = chkDisabled;
}
view.repairChkClass(setting, node);
var children = data.nodeChildren(setting, node);
if (children && inherit) {
for (var i = 0, l = children.length; i < l; i++) {
var sNode = children[i];
view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit);
}
}
},
repairParentChkDisabled: function (setting, node, chkDisabled, inherit) {
if (!node) return;
if (node.chkDisabled != chkDisabled && inherit) {
node.chkDisabled = chkDisabled;
}
view.repairChkClass(setting, node);
view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit);
},
setChkClass: function (setting, obj, node) {
if (!obj) return;
if (node.nocheck === true) {
obj.hide();
} else {
obj.show();
}
obj.attr('class', view.makeChkClass(setting, node));
},
setParentNodeCheckBox: function (setting, node, value, srcNode) {
var checkObj = $$(node, consts.id.CHECK, setting);
if (!srcNode) srcNode = node;
data.makeChkFlag(setting, node);
if (node.nocheck !== true && node.chkDisabled !== true) {
data.nodeChecked(setting, node, value);
view.setChkClass(setting, checkObj, node);
if (setting.check.autoCheckTrigger && node != srcNode) {
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
}
}
if (node.parentTId) {
var pSign = true;
if (!value) {
var pNodes = data.nodeChildren(setting, node.getParentNode());
for (var i = 0, l = pNodes.length; i < l; i++) {
var pNode = pNodes[i];
var nodeChecked = data.nodeChecked(setting, pNode);
if ((pNode.nocheck !== true && pNode.chkDisabled !== true && nodeChecked)
|| ((pNode.nocheck === true || pNode.chkDisabled === true) && pNode.check_Child_State > 0)) {
pSign = false;
break;
}
}
}
if (pSign) {
view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode);
}
}
},
setSonNodeCheckBox: function (setting, node, value, srcNode) {
if (!node) return;
var checkObj = $$(node, consts.id.CHECK, setting);
if (!srcNode) srcNode = node;

var hasDisable = false;
var children = data.nodeChildren(setting, node);
if (children) {
for (var i = 0, l = children.length; i < l; i++) {
var sNode = children[i];
view.setSonNodeCheckBox(setting, sNode, value, srcNode);
if (sNode.chkDisabled === true) hasDisable = true;
}
}

if (node != data.getRoot(setting) && node.chkDisabled !== true) {
if (hasDisable && node.nocheck !== true) {
data.makeChkFlag(setting, node);
}
if (node.nocheck !== true && node.chkDisabled !== true) {
data.nodeChecked(setting, node, value);
if (!hasDisable) node.check_Child_State = (children && children.length > 0) ? (value ? 2 : 0) : -1;
} else {
node.check_Child_State = -1;
}
view.setChkClass(setting, checkObj, node);
if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) {
setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]);
}
}

}
},

_z = {
tools: _tools,
view: _view,
event: _event,
data: _data
};
$.extend(true, $.fn.zTree.consts, _consts);
$.extend(true, $.fn.zTree._z, _z);

var zt = $.fn.zTree,
tools = zt._z.tools,
consts = zt.consts,
view = zt._z.view,
data = zt._z.data,
event = zt._z.event,
$$ = tools.$;

data.nodeChecked = function (setting, node, newChecked) {
if (!node) {
return false;
}
var key = setting.data.key.checked;
if (typeof newChecked !== 'undefined') {
if (typeof newChecked === "string") {
newChecked = tools.eqs(newChecked, "true");
}
newChecked = !!newChecked;
node[key] = newChecked;
} else if (typeof node[key] == "string"){
node[key] = tools.eqs(node[key], "true");
} else {
node[key] = !!node[key];
}
return node[key];
};

data.exSetting(_setting);
data.addInitBind(_bindEvent);
data.addInitUnBind(_unbindEvent);
data.addInitCache(_initCache);
data.addInitNode(_initNode);
data.addInitProxy(_eventProxy, true);
data.addInitRoot(_initRoot);
data.addBeforeA(_beforeA);
data.addZTreeTools(_zTreeTools);

var _createNodes = view.createNodes;
view.createNodes = function (setting, level, nodes, parentNode, index) {
if (_createNodes) _createNodes.apply(view, arguments);
if (!nodes) return;
view.repairParentChkClassWithSelf(setting, parentNode);
}
var _removeNode = view.removeNode;
view.removeNode = function (setting, node) {
var parentNode = node.getParentNode();
if (_removeNode) _removeNode.apply(view, arguments);
if (!node || !parentNode) return;
view.repairChkClass(setting, parentNode);
view.repairParentChkClass(setting, parentNode);
}

var _appendNodes = view.appendNodes;
view.appendNodes = function (setting, level, nodes, parentNode, index, initFlag, openFlag) {
var html = "";
if (_appendNodes) {
html = _appendNodes.apply(view, arguments);
}
if (parentNode) {
data.makeChkFlag(setting, parentNode);
}
return html;
}
})(jQuery);

+ 1207
- 0
public/self/ztree/js/jquery.ztree.exedit.js
File diff suppressed because it is too large
View File


+ 405
- 0
public/self/ztree/js/jquery.ztree.exhide.js View File

@@ -0,0 +1,405 @@
/*
* JQuery zTree exHideNodes
* v3.5.48
* http://treejs.cn/
*
* Copyright (c) 2010 Hunter.z
*
* Licensed same as jquery - MIT License
* http://www.opensource.org/licenses/mit-license.php
*
* Date: 2020-11-21
*/

(function ($) {
var _setting = {
data: {
key: {
isHidden: "isHidden"
}
}
};
//default init node of exLib
var _initNode = function (setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) {
var isHidden = data.isHidden(setting, n);
data.isHidden(setting, n, isHidden);
data.initHideForExCheck(setting, n);
},
//add dom for check
_beforeA = function (setting, node, html) {
},
//update zTreeObj, add method of exLib
_zTreeTools = function (setting, zTreeTools) {
zTreeTools.showNodes = function (nodes, options) {
view.showNodes(setting, nodes, options);
}
zTreeTools.showNode = function (node, options) {
if (!node) {
return;
}
view.showNodes(setting, [node], options);
}
zTreeTools.hideNodes = function (nodes, options) {
view.hideNodes(setting, nodes, options);
}
zTreeTools.hideNode = function (node, options) {
if (!node) {
return;
}
view.hideNodes(setting, [node], options);
}

var _checkNode = zTreeTools.checkNode;
if (_checkNode) {
zTreeTools.checkNode = function (node, checked, checkTypeFlag, callbackFlag) {
if (!!node && !!data.isHidden(setting, node)) {
return;
}
_checkNode.apply(zTreeTools, arguments);
}
}
},
//method of operate data
_data = {
initHideForExCheck: function (setting, n) {
var isHidden = data.isHidden(setting, n);
if (isHidden && setting.check && setting.check.enable) {
if (typeof n._nocheck == "undefined") {
n._nocheck = !!n.nocheck
n.nocheck = true;
}
n.check_Child_State = -1;
if (view.repairParentChkClassWithSelf) {
view.repairParentChkClassWithSelf(setting, n);
}
}
},
initShowForExCheck: function (setting, n) {
var isHidden = data.isHidden(setting, n);
if (!isHidden && setting.check && setting.check.enable) {
if (typeof n._nocheck != "undefined") {
n.nocheck = n._nocheck;
delete n._nocheck;
}
if (view.setChkClass) {
var checkObj = $$(n, consts.id.CHECK, setting);
view.setChkClass(setting, checkObj, n);
}
if (view.repairParentChkClassWithSelf) {
view.repairParentChkClassWithSelf(setting, n);
}
}
}
},
//method of operate ztree dom
_view = {
clearOldFirstNode: function (setting, node) {
var n = node.getNextNode();
while (!!n) {
if (n.isFirstNode) {
n.isFirstNode = false;
view.setNodeLineIcos(setting, n);
break;
}
if (n.isLastNode) {
break;
}
n = n.getNextNode();
}
},
clearOldLastNode: function (setting, node, openFlag) {
var n = node.getPreNode();
while (!!n) {
if (n.isLastNode) {
n.isLastNode = false;
if (openFlag) {
view.setNodeLineIcos(setting, n);
}
break;
}
if (n.isFirstNode) {
break;
}
n = n.getPreNode();
}
},
makeDOMNodeMainBefore: function (html, setting, node) {
var isHidden = data.isHidden(setting, node);
html.push("<li ", (isHidden ? "style='display:none;' " : ""), "id='", node.tId, "' class='", consts.className.LEVEL, node.level, "' tabindex='0' hidefocus='true' treenode>");
},
showNode: function (setting, node, options) {
data.isHidden(setting, node, false);
data.initShowForExCheck(setting, node);
$$(node, setting).show();
},
showNodes: function (setting, nodes, options) {
if (!nodes || nodes.length == 0) {
return;
}
var pList = {}, i, j;
for (i = 0, j = nodes.length; i < j; i++) {
var n = nodes[i];
if (!pList[n.parentTId]) {
var pn = n.getParentNode();
pList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode();
}
view.showNode(setting, n, options);
}
for (var tId in pList) {
var children = data.nodeChildren(setting, pList[tId]);
view.setFirstNodeForShow(setting, children);
view.setLastNodeForShow(setting, children);
}
},
hideNode: function (setting, node, options) {
data.isHidden(setting, node, true);
node.isFirstNode = false;
node.isLastNode = false;
data.initHideForExCheck(setting, node);
view.cancelPreSelectedNode(setting, node);
$$(node, setting).hide();
},
hideNodes: function (setting, nodes, options) {
if (!nodes || nodes.length == 0) {
return;
}
var pList = {}, i, j;
for (i = 0, j = nodes.length; i < j; i++) {
var n = nodes[i];
if ((n.isFirstNode || n.isLastNode) && !pList[n.parentTId]) {
var pn = n.getParentNode();
pList[n.parentTId] = (pn === null) ? data.getRoot(setting) : n.getParentNode();
}
view.hideNode(setting, n, options);
}
for (var tId in pList) {
var children = data.nodeChildren(setting, pList[tId]);
view.setFirstNodeForHide(setting, children);
view.setLastNodeForHide(setting, children);
}
},
setFirstNode: function (setting, parentNode) {
var children = data.nodeChildren(setting, parentNode);
var isHidden = data.isHidden(setting, children[0], false);
if (children.length > 0 && !isHidden) {
children[0].isFirstNode = true;
} else if (children.length > 0) {
view.setFirstNodeForHide(setting, children);
}
},
setLastNode: function (setting, parentNode) {
var children = data.nodeChildren(setting, parentNode);
var isHidden = data.isHidden(setting, children[0]);
if (children.length > 0 && !isHidden) {
children[children.length - 1].isLastNode = true;
} else if (children.length > 0) {
view.setLastNodeForHide(setting, children);
}
},
setFirstNodeForHide: function (setting, nodes) {
var n, i, j;
for (i = 0, j = nodes.length; i < j; i++) {
n = nodes[i];
if (n.isFirstNode) {
break;
}
var isHidden = data.isHidden(setting, n);
if (!isHidden && !n.isFirstNode) {
n.isFirstNode = true;
view.setNodeLineIcos(setting, n);
break;
} else {
n = null;
}
}
return n;
},
setFirstNodeForShow: function (setting, nodes) {
var n, i, j, first, old;
for (i = 0, j = nodes.length; i < j; i++) {
n = nodes[i];
var isHidden = data.isHidden(setting, n);
if (!first && !isHidden && n.isFirstNode) {
first = n;
break;
} else if (!first && !isHidden && !n.isFirstNode) {
n.isFirstNode = true;
first = n;
view.setNodeLineIcos(setting, n);
} else if (first && n.isFirstNode) {
n.isFirstNode = false;
old = n;
view.setNodeLineIcos(setting, n);
break;
} else {
n = null;
}
}
return {"new": first, "old": old};
},
setLastNodeForHide: function (setting, nodes) {
var n, i;
for (i = nodes.length - 1; i >= 0; i--) {
n = nodes[i];
if (n.isLastNode) {
break;
}
var isHidden = data.isHidden(setting, n);
if (!isHidden && !n.isLastNode) {
n.isLastNode = true;
view.setNodeLineIcos(setting, n);
break;
} else {
n = null;
}
}
return n;
},
setLastNodeForShow: function (setting, nodes) {
var n, i, j, last, old;
for (i = nodes.length - 1; i >= 0; i--) {
n = nodes[i];
var isHidden = data.isHidden(setting, n);
if (!last && !isHidden && n.isLastNode) {
last = n;
break;
} else if (!last && !isHidden && !n.isLastNode) {
n.isLastNode = true;
last = n;
view.setNodeLineIcos(setting, n);
} else if (last && n.isLastNode) {
n.isLastNode = false;
old = n;
view.setNodeLineIcos(setting, n);
break;
} else {
n = null;
}
}
return {"new": last, "old": old};
}
},

_z = {
view: _view,
data: _data
};
$.extend(true, $.fn.zTree._z, _z);

var zt = $.fn.zTree,
tools = zt._z.tools,
consts = zt.consts,
view = zt._z.view,
data = zt._z.data,
event = zt._z.event,
$$ = tools.$;

data.isHidden = function (setting, node, newIsHidden) {
if (!node) {
return false;
}
var key = setting.data.key.isHidden;
if (typeof newIsHidden !== 'undefined') {
if (typeof newIsHidden === "string") {
newIsHidden = tools.eqs(newIsHidden, "true");
}
newIsHidden = !!newIsHidden;
node[key] = newIsHidden;
} else if (typeof node[key] == "string"){
node[key] = tools.eqs(node[key], "true");
} else {
node[key] = !!node[key];
}
return node[key];
};

data.exSetting(_setting);
data.addInitNode(_initNode);
data.addBeforeA(_beforeA);
data.addZTreeTools(_zTreeTools);

// Override method in core
var _dInitNode = data.initNode;
data.initNode = function (setting, level, node, parentNode, isFirstNode, isLastNode, openFlag) {
var tmpPNode = (parentNode) ? parentNode : data.getRoot(setting),
children = tmpPNode[setting.data.key.children];
data.tmpHideFirstNode = view.setFirstNodeForHide(setting, children);
data.tmpHideLastNode = view.setLastNodeForHide(setting, children);
if (openFlag) {
view.setNodeLineIcos(setting, data.tmpHideFirstNode);
view.setNodeLineIcos(setting, data.tmpHideLastNode);
}
isFirstNode = (data.tmpHideFirstNode === node);
isLastNode = (data.tmpHideLastNode === node);
if (_dInitNode) _dInitNode.apply(data, arguments);
if (openFlag && isLastNode) {
view.clearOldLastNode(setting, node, openFlag);
}
};

var _makeChkFlag = data.makeChkFlag;
if (!!_makeChkFlag) {
data.makeChkFlag = function (setting, node) {
if (!!node && !!data.isHidden(setting, node)) {
return;
}
_makeChkFlag.apply(data, arguments);
}
}

var _getTreeCheckedNodes = data.getTreeCheckedNodes;
if (!!_getTreeCheckedNodes) {
data.getTreeCheckedNodes = function (setting, nodes, checked, results) {
if (!!nodes && nodes.length > 0) {
var p = nodes[0].getParentNode();
if (!!p && !!data.isHidden(setting, p)) {
return [];
}
}
return _getTreeCheckedNodes.apply(data, arguments);
}
}

var _getTreeChangeCheckedNodes = data.getTreeChangeCheckedNodes;
if (!!_getTreeChangeCheckedNodes) {
data.getTreeChangeCheckedNodes = function (setting, nodes, results) {
if (!!nodes && nodes.length > 0) {
var p = nodes[0].getParentNode();
if (!!p && !!data.isHidden(setting, p)) {
return [];
}
}
return _getTreeChangeCheckedNodes.apply(data, arguments);
}
}

var _expandCollapseSonNode = view.expandCollapseSonNode;
if (!!_expandCollapseSonNode) {
view.expandCollapseSonNode = function (setting, node, expandFlag, animateFlag, callback) {
if (!!node && !!data.isHidden(setting, node)) {
return;
}
_expandCollapseSonNode.apply(view, arguments);
}
}

var _setSonNodeCheckBox = view.setSonNodeCheckBox;
if (!!_setSonNodeCheckBox) {
view.setSonNodeCheckBox = function (setting, node, value, srcNode) {
if (!!node && !!data.isHidden(setting, node)) {
return;
}
_setSonNodeCheckBox.apply(view, arguments);
}
}

var _repairParentChkClassWithSelf = view.repairParentChkClassWithSelf;
if (!!_repairParentChkClassWithSelf) {
view.repairParentChkClassWithSelf = function (setting, node) {
if (!!node && !!data.isHidden(setting, node)) {
return;
}
_repairParentChkClassWithSelf.apply(view, arguments);
}
}
})(jQuery);

+ 6
- 0
routers/api/v1/api.go View File

@@ -930,6 +930,12 @@ func RegisterRoutes(m *macaron.Macaron) {
}) })
}) })
}, reqRepoReader(models.UnitTypeCloudBrain)) }, reqRepoReader(models.UnitTypeCloudBrain))
m.Group("/modelmanage", func() {
m.Get("/:id", repo.GetCloudbrainModelConvertTask)
m.Get("/:id/log", repo.CloudbrainForModelConvertGetLog)
m.Get("/:id/modelartlog", repo.TrainJobForModelConvertGetLog)
m.Get("/:id/model_list", repo.CloudBrainModelConvertList)
}, reqRepoReader(models.UnitTypeModelManage))
m.Group("/modelarts", func() { m.Group("/modelarts", func() {
m.Group("/notebook", func() { m.Group("/notebook", func() {
//m.Get("/:jobid", repo.GetModelArtsNotebook) //m.Get("/:jobid", repo.GetModelArtsNotebook)


+ 192
- 14
routers/api/v1/repo/cloudbrain.go View File

@@ -6,17 +6,19 @@
package repo package repo


import ( import (
"code.gitea.io/gitea/modules/setting"
"encoding/json" "encoding/json"
"net/http" "net/http"
"sort" "sort"
"strings" "strings"
"time" "time"


"code.gitea.io/gitea/modules/setting"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cloudbrain" "code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
routerRepo "code.gitea.io/gitea/routers/repo" routerRepo "code.gitea.io/gitea/routers/repo"
) )
@@ -217,21 +219,87 @@ func InferencJobResultList(ctx *context.APIContext) {


} }


func CloudbrainGetLog(ctx *context.Context) {
func GetCloudbrainModelConvertTask(ctx *context.APIContext) {
var (
err error
)
ID := ctx.Params(":id") ID := ctx.Params(":id")
job, err := models.GetCloudbrainByID(ID)
job, err := models.QueryModelConvertById(ID)
if err != nil { if err != nil {
log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
ctx.NotFound(err)
log.Error("GetCloudbrainByID failed:", err)
return return
} }
if job.IsGpuTrainTask() {
jobResult, err := cloudbrain.GetJob(job.CloudBrainTaskId)
if err != nil {
ctx.NotFound(err)
log.Error("GetJob failed:", err)
return
}
result, _ := models.ConvertToJobResultPayload(jobResult.Payload)
if err != nil {
ctx.NotFound(err)
log.Error("ConvertToJobResultPayload failed:", err)
return
}

job.Status = result.JobStatus.State
taskRoles := result.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
if result.JobStatus.State != string(models.JobWaiting) && result.JobStatus.State != string(models.JobFailed) {
job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP
job.ContainerID = taskRes.TaskStatuses[0].ContainerID
job.Status = taskRes.TaskStatuses[0].State
}

if result.JobStatus.State != string(models.JobWaiting) {
models.ModelComputeAndSetDuration(job, result)
err = models.UpdateModelConvert(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"ID": ID,
"JobName": result.Config.JobName,
"JobStatus": result.JobStatus.State,
"SubState": result.JobStatus.SubState,
"CreatedTime": time.Unix(result.JobStatus.CreatedTime/1000, 0).Format("2006-01-02 15:04:05"),
"CompletedTime": time.Unix(result.JobStatus.CompletedTime/1000, 0).Format("2006-01-02 15:04:05"),
})
} else {


result, err := modelarts.GetTrainJob(job.CloudBrainTaskId, job.ModelArtsVersionId)
if err != nil {
log.Error("get modelart job failed:", err)
ctx.NotFound(err)
return
}

job.Status = modelarts.TransTrainJobStatus(result.IntStatus)
job.RunTime = result.Duration / 1000
job.TrainJobDuration = models.ConvertDurationToStr(job.RunTime)
err = models.UpdateModelConvert(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"ID": ID,
"JobStatus": job.Status,
})

}

}

func CloudbrainGetLogByJobId(jobId string, jobName string) map[string]interface{} {
var hits []models.Hits var hits []models.Hits
result, err := cloudbrain.GetJobLog(job.JobID)
result, err := cloudbrain.GetJobLog(jobId)
if err != nil { if err != nil {
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
log.Error("GetJobLog failed: %v", err)
return nil
} }
hits = result.Hits.Hits hits = result.Hits.Hits


@@ -240,7 +308,7 @@ func CloudbrainGetLog(ctx *context.Context) {
for { for {
resultNext, err := cloudbrain.GetJobAllLog(result.ScrollID) resultNext, err := cloudbrain.GetJobAllLog(result.ScrollID)
if err != nil { if err != nil {
log.Error("GetJobAllLog failed: %v", err, ctx.Data["MsgID"])
log.Error("GetJobAllLog failed: %v", err)
} else { } else {
for _, hit := range resultNext.Hits.Hits { for _, hit := range resultNext.Hits.Hits {
hits = append(hits, hit) hits = append(hits, hit)
@@ -265,12 +333,122 @@ func CloudbrainGetLog(ctx *context.Context) {
content += log.Source.Message + "\n" content += log.Source.Message + "\n"
} }


ctx.JSON(http.StatusOK, map[string]interface{}{
"JobName": job.JobName,
return map[string]interface{}{
"JobName": jobName,
"Content": content, "Content": content,
})
}

}

func CloudbrainForModelConvertGetLog(ctx *context.Context) {
ID := ctx.Params(":id")
job, err := models.QueryModelConvertById(ID)
if err != nil {
log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}

result := CloudbrainGetLogByJobId(job.CloudBrainTaskId, job.Name)
if result == nil {
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}
ctx.JSON(http.StatusOK, result)
}

func CloudbrainGetLog(ctx *context.Context) {
ID := ctx.Params(":id")
job, err := models.GetCloudbrainByID(ID)
if err != nil {
log.Error("GetCloudbrainByJobName failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}

result := CloudbrainGetLogByJobId(job.JobID, job.JobName)
if result == nil {
log.Error("GetJobLog failed: %v", err, ctx.Data["MsgID"])
ctx.ServerError(err.Error(), err)
return
}
ctx.JSON(http.StatusOK, result)
}

func CloudBrainModelConvertList(ctx *context.APIContext) {
var (
err error
)

ID := ctx.Params(":id")
parentDir := ctx.Query("parentDir")
dirArray := strings.Split(parentDir, "/")

job, err := models.QueryModelConvertById(ID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", job.Name, err.Error())
return
}
if job.IsGpuTrainTask() {
//get dirs
dirs, err := routerRepo.GetModelDirs(job.ID, parentDir)
if err != nil {
log.Error("GetModelDirs failed:%v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetModelDirs failed:", err)
return
}

var fileInfos []storage.FileInfo
err = json.Unmarshal([]byte(dirs), &fileInfos)
if err != nil {
log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("json.Unmarshal failed:", err)
return
}

for i, fileInfo := range fileInfos {
temp, _ := time.Parse("2006-01-02 15:04:05", fileInfo.ModTime)
fileInfos[i].ModTime = temp.Local().Format("2006-01-02 15:04:05")
}

sort.Slice(fileInfos, func(i, j int) bool {
return fileInfos[i].ModTime > fileInfos[j].ModTime
})

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": ID,
"VersionName": "",
"StatusOK": 0,
"Path": dirArray,
"Dirs": fileInfos,
"task": job,
"PageIsCloudBrain": true,
})
} else {
var jobID = ctx.Params(":id")
var versionName = "V0001"
parentDir := ctx.Query("parentDir")
dirArray := strings.Split(parentDir, "/")

models, err := storage.GetObsListObject(job.ID, "output/", parentDir, versionName)
if err != nil {
log.Info("get TrainJobListModel failed:", err)
ctx.ServerError("GetObsListObject:", err)
return
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"VersionName": versionName,
"StatusOK": 0,
"Path": dirArray,
"Dirs": models,
"task": job,
"PageIsCloudBrain": true,
})
}


return
} }


func CloudBrainModelList(ctx *context.APIContext) { func CloudBrainModelList(ctx *context.APIContext) {


+ 72
- 2
routers/api/v1/repo/modelarts.go View File

@@ -6,14 +6,15 @@
package repo package repo


import ( import (
"code.gitea.io/gitea/modules/grampus"
"code.gitea.io/gitea/modules/setting"
"encoding/json" "encoding/json"
"net/http" "net/http"
"path" "path"
"strconv" "strconv"
"strings" "strings"


"code.gitea.io/gitea/modules/grampus"
"code.gitea.io/gitea/modules/setting"

"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cloudbrain" "code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
@@ -242,6 +243,75 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) {


} }


func TrainJobForModelConvertGetLog(ctx *context.APIContext) {
var (
err error
)

var jobID = ctx.Params(":id")
var baseLine = ctx.Query("base_line")
var order = ctx.Query("order")
var lines = ctx.Query("lines")
lines_int, err := strconv.Atoi(lines)
if err != nil {
log.Error("change lines(%d) string to int failed", lines_int)
}

if order != modelarts.OrderDesc && order != modelarts.OrderAsc {
log.Error("order(%s) check failed", order)
ctx.JSON(http.StatusBadRequest, map[string]interface{}{
"err_msg": "order check failed",
})
return
}

resultLogFile, result, err := trainJobForModelConvertGetLogContent(jobID, baseLine, order, lines_int)
if err != nil {
log.Error("trainJobGetLog(%s) failed:%v", jobID, err.Error())
// ctx.RenderWithErr(err.Error(), tplModelArtsTrainJobShow, nil)
ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"LogFileName": "",
"StartLine": "0",
"EndLine": "0",
"Content": "",
"Lines": 0,
})
return
}

ctx.Data["log_file_name"] = resultLogFile.LogFileList[0]

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"LogFileName": resultLogFile.LogFileList[0],
"StartLine": result.StartLine,
"EndLine": result.EndLine,
"Content": result.Content,
"Lines": result.Lines,
})
}

func trainJobForModelConvertGetLogContent(jobID string, baseLine string, order string, lines int) (*models.GetTrainJobLogFileNamesResult, *models.GetTrainJobLogResult, error) {
task, err := models.QueryModelConvertById(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error())
return nil, nil, err
}
resultLogFile, err := modelarts.GetTrainJobLogFileNames(task.CloudBrainTaskId, task.ModelArtsVersionId)
if err != nil {
log.Error("GetTrainJobLogFileNames(%s) failed:%v", task.CloudBrainTaskId, err.Error())
return nil, nil, err
}
result, err := modelarts.GetTrainJobLog(task.CloudBrainTaskId, task.ModelArtsVersionId, baseLine, resultLogFile.LogFileList[0], order, lines)
if err != nil {
log.Error("GetTrainJobLog(%s) failed:%v", task.CloudBrainTaskId, err.Error())
return nil, nil, err
}

return resultLogFile, result, err
}

func TrainJobGetLog(ctx *context.APIContext) { func TrainJobGetLog(ctx *context.APIContext) {
var ( var (
err error err error


+ 795
- 0
routers/repo/ai_model_convert.go View File

@@ -0,0 +1,795 @@
package repo

import (
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/cloudbrain"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/timeutil"
uuid "github.com/satori/go.uuid"
)

const (
tplModelManageConvertIndex = "repo/modelmanage/convertIndex"
tplModelConvertInfo = "repo/modelmanage/convertshowinfo"
PYTORCH_ENGINE = 0
TENSORFLOW_ENGINE = 1
MINDSPORE_ENGIN = 2
ModelMountPath = "/model"
CodeMountPath = "/code"
DataSetMountPath = "/dataset"
LogFile = "log.txt"
DefaultBranchName = "master"
SubTaskName = "task1"
//GpuQueue = "openidgx"
Success = "S000"
//GPU_PYTORCH_IMAGE = "dockerhub.pcl.ac.cn:5000/user-images/openi:tensorRT_7_zouap"
//GPU_TENSORFLOW_IMAGE = "dockerhub.pcl.ac.cn:5000/user-images/openi:tf2onnx"
//NPU_MINDSPORE_16_IMAGE = "swr.cn-south-222.ai.pcl.cn/openi/mindspore1.6.1_train_v1_openi:v3_ascend"
//PytorchOnnxBootFile = "convert_pytorch.py"
//PytorchTrTBootFile = "convert_pytorch_tensorrt.py"
//MindsporeBootFile = "convert_mindspore.py"
//TensorFlowNpuBootFile = "convert_tensorflow.py"
//TensorFlowGpuBootFile = "convert_tensorflow_gpu.py"

//ConvertRepoPath = "https://git.openi.org.cn/zouap/npu_test"

CONVERT_FORMAT_ONNX = 0
CONVERT_FORMAT_TRT = 1

NetOutputFormat_FP32 = 0
NetOutputFormat_FP16 = 1

NPU_MINDSPORE_IMAGE_ID = 35
NPU_TENSORFLOW_IMAGE_ID = 121

//GPU_Resource_Specs_ID = 1 //cpu 1, gpu 1

//NPU_FlavorCode = "modelarts.bm.910.arm.public.1"
//NPU_PoolID = "pool7908321a"
)

var (
TrainResourceSpecs *models.ResourceSpecs
)

func SaveModelConvert(ctx *context.Context) {
log.Info("save model convert start.")
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
ctx.JSON(200, map[string]string{
"result_code": "1",
"message": ctx.Tr("repo.modelconvert.manage.no_operate_right"),
})
return
}
name := ctx.Query("name")
desc := ctx.Query("desc")
modelId := ctx.Query("modelId")
modelPath := ctx.Query("ModelFile")
SrcEngine := ctx.QueryInt("SrcEngine")
InputShape := ctx.Query("inputshape")
InputDataFormat := ctx.Query("inputdataformat")
DestFormat := ctx.QueryInt("DestFormat")
NetOutputFormat := ctx.QueryInt("NetOutputFormat")

task, err := models.QueryModelById(modelId)
if err != nil {
log.Error("no such model!", err.Error())
ctx.JSON(200, map[string]string{
"result_code": "1",
"message": ctx.Tr("repo.modelconvert.manage.model_not_exist"),
})
return
}

convertList, err := models.QueryModelConvertByRepoID(ctx.Repo.Repository.ID)
if err == nil {
for _, convert := range convertList {
if convert.Name == name {
log.Info("convert.Name=" + name + " convert.id=" + convert.ID)
ctx.JSON(200, map[string]string{
"result_code": "1",
"message": ctx.Tr("repo.modelconvert.manage.create_error1"),
})
return
}
}
}

convertList, err = models.QueryModelConvertByUserID(ctx.User.ID)
if err == nil {
for _, convert := range convertList {
if isRunningTask(convert.Status) {
log.Info("convert.Status=" + convert.Status + " convert.id=" + convert.ID)
ctx.JSON(200, map[string]string{
"result_code": "1",
"message": ctx.Tr("repo.modelconvert.manage.create_error2"),
})
return
}
}
}

uuid := uuid.NewV4()
id := uuid.String()
modelConvert := &models.AiModelConvert{
ID: id,
Name: name,
Description: desc,
Status: string(models.JobWaiting),
SrcEngine: SrcEngine,
RepoId: ctx.Repo.Repository.ID,
ModelName: task.Name,
ModelVersion: task.Version,
ModelId: modelId,
ModelPath: modelPath,
DestFormat: DestFormat,
NetOutputFormat: NetOutputFormat,
InputShape: InputShape,
InputDataFormat: InputDataFormat,
UserId: ctx.User.ID,
}
models.SaveModelConvert(modelConvert)
go goCreateTask(modelConvert, ctx, task)

ctx.JSON(200, map[string]string{
"result_code": "0",
})
}

func isRunningTask(status string) bool {
stopStatus := []string{"COMPLETED", "STOPPED", "FAILED", "START_FAILED", "STOPPING", "SUCCEEDED"}
for _, sta := range stopStatus {
if sta == status {
return false
}
}
return true
}

func goCreateTask(modelConvert *models.AiModelConvert, ctx *context.Context, task *models.AiModelManage) error {
if modelConvert.IsGpuTrainTask() {
log.Info("create gpu train job.")
return createGpuTrainJob(modelConvert, ctx, task)
} else {
//create npu job
log.Info("create npu train job.")
return createNpuTrainJob(modelConvert, ctx, task.Path)
}
}

func createNpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context, modelRelativePath string) error {
VersionOutputPath := "V0001"
codeLocalPath := setting.JobPath + modelConvert.ID + modelarts.CodePath
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + modelConvert.ID + modelarts.CodePath
outputObsPath := "/" + setting.Bucket + modelarts.JobPath + modelConvert.ID + modelarts.OutputPath + VersionOutputPath + "/"
logObsPath := "/" + setting.Bucket + modelarts.JobPath + modelConvert.ID + modelarts.LogPath + VersionOutputPath + "/"
dataPath := "/" + modelRelativePath

_, err := ioutil.ReadDir(codeLocalPath)
if err == nil {
deleteLocalDir(codeLocalPath)
}
if err := downloadConvertCode(setting.ModelConvert.ConvertRepoPath, codeLocalPath, DefaultBranchName); err != nil {
log.Error("downloadCode failed, server timed out: %s (%v)", setting.ModelConvert.ConvertRepoPath, err)
return err
}
if err := obsMkdir(setting.CodePathPrefix + modelConvert.ID + modelarts.OutputPath + VersionOutputPath + "/"); err != nil {
log.Error("Failed to obsMkdir_output: %s (%v)", modelConvert.ID+modelarts.OutputPath, err)
return err
}
if err := obsMkdir(setting.CodePathPrefix + modelConvert.ID + modelarts.LogPath + VersionOutputPath + "/"); err != nil {
log.Error("Failed to obsMkdir_log: %s (%v)", modelConvert.ID+modelarts.LogPath, err)
return err
}
if err := uploadCodeToObs(codeLocalPath, modelConvert.ID, ""); err != nil {
log.Error("Failed to uploadCodeToObs: %s (%v)", modelConvert.ID, err)
return err
}
deleteLocalDir(codeLocalPath)

intputshape := strings.Split(modelConvert.InputShape, ",")
n := "256"
c := "1"
h := "28"
w := "28"
if len(intputshape) == 4 {
n = intputshape[0]
c = intputshape[1]
h = intputshape[2]
w = intputshape[3]
}

var engineId int64
engineId = int64(NPU_MINDSPORE_IMAGE_ID)
bootfile := setting.ModelConvert.MindsporeBootFile
if modelConvert.SrcEngine == TENSORFLOW_ENGINE {
engineId = int64(NPU_TENSORFLOW_IMAGE_ID)
bootfile = setting.ModelConvert.TensorFlowNpuBootFile
}
userCommand := "/bin/bash /home/work/run_train.sh 's3://" + codeObsPath + "' 'code/" + bootfile + "' '/tmp/log/train.log' --'data_url'='s3://" + dataPath + "' --'train_url'='s3://" + outputObsPath + "'"
userCommand += " --'model'='" + modelConvert.ModelPath + "'"
userCommand += " --'n'='" + fmt.Sprint(n) + "'"
userCommand += " --'c'='" + fmt.Sprint(c) + "'"
userCommand += " --'h'='" + fmt.Sprint(h) + "'"
userCommand += " --'w'='" + fmt.Sprint(w) + "'"

req := &modelarts.GenerateTrainJobReq{
JobName: modelConvert.ID,
DisplayJobName: modelConvert.Name,
DataUrl: dataPath,
Description: modelConvert.Description,
CodeObsPath: codeObsPath,
BootFileUrl: codeObsPath + bootfile,
BootFile: bootfile,
TrainUrl: outputObsPath,
FlavorCode: setting.ModelConvert.NPU_FlavorCode,
WorkServerNumber: 1,
IsLatestVersion: modelarts.IsLatestVersion,
EngineID: engineId,
LogUrl: logObsPath,
PoolID: setting.ModelConvert.NPU_PoolID,
//Parameters: param,
BranchName: DefaultBranchName,
UserImageUrl: setting.ModelConvert.NPU_MINDSPORE_16_IMAGE,
UserCommand: userCommand,
}
result, err := modelarts.GenerateModelConvertTrainJob(req)
if err == nil {
log.Info("jobId=" + fmt.Sprint(result.JobID) + " versionid=" + fmt.Sprint(result.VersionID))
models.UpdateModelConvertModelArts(modelConvert.ID, fmt.Sprint(result.JobID), fmt.Sprint(result.VersionID))
} else {
log.Info("create modelarts taks failed.error=" + err.Error())
models.UpdateModelConvertFailed(modelConvert.ID, "FAILED", err.Error())
}
return err
}

func downloadConvertCode(repopath string, codePath, branchName string) error {
//add "file:///" prefix to make the depth valid
if err := git.Clone(repopath, codePath, git.CloneRepoOptions{Branch: branchName, Depth: 1}); err != nil {
log.Error("Failed to clone repository: %s (%v)", repopath, err)
return err
}
log.Info("srcPath=" + repopath + " codePath=" + codePath)
configFile, err := os.OpenFile(codePath+"/.git/config", os.O_RDWR, 0666)
if err != nil {
log.Error("open file(%s) failed:%v", codePath+"/,git/config", err)
return err
}

defer configFile.Close()

pos := int64(0)
reader := bufio.NewReader(configFile)
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
log.Error("not find the remote-url")
return nil
} else {
log.Error("read error: %v", err)
return err
}
}

if strings.Contains(line, "url") && strings.Contains(line, ".git") {
originUrl := "\turl = " + repopath + "\n"
if len(line) > len(originUrl) {
originUrl += strings.Repeat(" ", len(line)-len(originUrl))
}
bytes := []byte(originUrl)
_, err := configFile.WriteAt(bytes, pos)
if err != nil {
log.Error("WriteAt failed:%v", err)
return err
}
break
}

pos += int64(len(line))
}

return nil
}

func downloadFromObsToLocal(task *models.AiModelManage, localPath string) error {
path := Model_prefix + models.AttachmentRelativePath(task.ID) + "/"
allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, path)
if err == nil {
_, errState := os.Stat(localPath)
if errState != nil {
if err = os.MkdirAll(localPath, os.ModePerm); err != nil {
return err
}
}
for _, oneFile := range allFile {
if oneFile.IsDir {
log.Info(" dir name:" + oneFile.FileName)
} else {
allFileName := localPath + "/" + oneFile.FileName
index := strings.LastIndex(allFileName, "/")
if index != -1 {
parentDir := allFileName[0:index]
if err = os.MkdirAll(parentDir, os.ModePerm); err != nil {
log.Info("make dir may be error," + err.Error())
}
}
fDest, err := os.Create(allFileName)
if err != nil {
log.Info("create file error, download file failed: %s\n", err.Error())
return err
}
body, err := storage.ObsDownloadAFile(setting.Bucket, path+oneFile.FileName)
if err != nil {
log.Info("download file failed: %s\n", err.Error())
return err
} else {
defer body.Close()
p := make([]byte, 1024)
var readErr error
var readCount int
// 读取对象内容
for {
readCount, readErr = body.Read(p)
if readCount > 0 {
fDest.Write(p[:readCount])
}
if readErr != nil {
break
}
}
}
}
}
} else {
log.Info("error,msg=" + err.Error())
return err
}
return nil
}

func createGpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context, model *models.AiModelManage) error {
modelRelativePath := model.Path
command := ""
IMAGE_URL := setting.ModelConvert.GPU_PYTORCH_IMAGE
dataActualPath := setting.Attachment.Minio.RealPath + modelRelativePath

if modelConvert.SrcEngine == PYTORCH_ENGINE {
if modelConvert.DestFormat == CONVERT_FORMAT_ONNX {
command = getGpuModelConvertCommand(modelConvert.ID, modelConvert.ModelPath, modelConvert, setting.ModelConvert.PytorchOnnxBootFile)
} else if modelConvert.DestFormat == CONVERT_FORMAT_TRT {
command = getGpuModelConvertCommand(modelConvert.ID, modelConvert.ModelPath, modelConvert, setting.ModelConvert.PytorchTrTBootFile)
} else {
return errors.New("Not support the format.")
}
} else if modelConvert.SrcEngine == TENSORFLOW_ENGINE {
IMAGE_URL = setting.ModelConvert.GPU_TENSORFLOW_IMAGE
if modelConvert.DestFormat == CONVERT_FORMAT_ONNX {
command = getGpuModelConvertCommand(modelConvert.ID, modelConvert.ModelPath, modelConvert, setting.ModelConvert.TensorFlowGpuBootFile)
} else {
return errors.New("Not support the format.")
}
//如果模型在OBS上,需要下载到本地,并上传到minio中
if model.Type == models.TypeCloudBrainTwo {
relatetiveModelPath := setting.JobPath + modelConvert.ID + "/dataset"
log.Info("local dataset path:" + relatetiveModelPath)
downloadFromObsToLocal(model, relatetiveModelPath)
uploadCodeToMinio(relatetiveModelPath+"/", modelConvert.ID, "/dataset/")
deleteLocalDir(relatetiveModelPath)
dataActualPath = setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/dataset"
}
}
log.Info("dataActualPath=" + dataActualPath)

log.Info("command=" + command)

codePath := setting.JobPath + modelConvert.ID + CodeMountPath
downloadConvertCode(setting.ModelConvert.ConvertRepoPath, codePath, DefaultBranchName)

uploadCodeToMinio(codePath+"/", modelConvert.ID, CodeMountPath+"/")
deleteLocalDir(codePath)

minioCodePath := setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/code"
log.Info("minio codePath=" + minioCodePath)

modelPath := setting.JobPath + modelConvert.ID + ModelMountPath + "/"
log.Info("local modelPath=" + modelPath)
mkModelPath(modelPath)

uploadCodeToMinio(modelPath, modelConvert.ID, ModelMountPath+"/")
deleteLocalDir(modelPath)

minioModelPath := setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/model"
log.Info("minio model path=" + minioModelPath)

if TrainResourceSpecs == nil {
json.Unmarshal([]byte(setting.TrainResourceSpecs), &TrainResourceSpecs)
}
resourceSpec := TrainResourceSpecs.ResourceSpec[setting.ModelConvert.GPU_Resource_Specs_ID]
jobResult, err := cloudbrain.CreateJob(modelConvert.ID, models.CreateJobParams{
JobName: modelConvert.ID,
RetryCount: 1,
GpuType: setting.ModelConvert.GpuQueue,
Image: IMAGE_URL,
TaskRoles: []models.TaskRole{
{
Name: SubTaskName,
TaskNumber: 1,
MinSucceededTaskCount: 1,
MinFailedTaskCount: 1,
CPUNumber: resourceSpec.CpuNum,
GPUNumber: resourceSpec.GpuNum,
MemoryMB: resourceSpec.MemMiB,
ShmMB: resourceSpec.ShareMemMiB,
Command: command,
NeedIBDevice: false,
IsMainRole: false,
UseNNI: false,
},
},
Volumes: []models.Volume{
{
HostPath: models.StHostPath{
Path: minioCodePath,
MountPath: CodeMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: dataActualPath,
MountPath: DataSetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: minioModelPath,
MountPath: ModelMountPath,
ReadOnly: false,
},
},
},
})
if err != nil {
log.Error("CreateJob failed:", err.Error(), ctx.Data["MsgID"])
models.UpdateModelConvertFailed(modelConvert.ID, "FAILED", err.Error())
return err
}
if jobResult.Code != Success {
log.Error("CreateJob(%s) failed:%s", modelConvert.ID, jobResult.Msg, ctx.Data["MsgID"])
models.UpdateModelConvertFailed(modelConvert.ID, "FAILED", err.Error())
return errors.New(jobResult.Msg)
}

var jobID = jobResult.Payload["jobId"].(string)
log.Info("jobId=" + jobID)
models.UpdateModelConvertCBTI(modelConvert.ID, jobID)

return nil
}

func deleteLocalDir(dirpath string) {
//TODO delete
_err := os.RemoveAll(dirpath)
if _err == nil {
log.Info("Delete local file:" + dirpath)
} else {
log.Info("Delete local file error: path=" + dirpath)
}
}

func getGpuModelConvertCommand(name string, modelFile string, modelConvert *models.AiModelConvert, bootfile string) string {
var command string

inputshape := strings.Split(modelConvert.InputShape, ",")
n := "256"
c := "1"
h := "28"
w := "28"
if len(inputshape) == 4 {
n = inputshape[0]
c = inputshape[1]
h = inputshape[2]
w = inputshape[3]
}
command += "python3 /code/" + bootfile + " --model " + modelFile + " --n " + n + " --c " + c + " --h " + h + " --w " + w
if modelConvert.DestFormat == CONVERT_FORMAT_TRT {
if modelConvert.NetOutputFormat == NetOutputFormat_FP16 {
command += " --fp16 True"
} else {
command += " --fp16 False"
}
}
command += " > " + ModelMountPath + "/" + name + "-" + LogFile
return command
}

func DeleteModelConvert(ctx *context.Context) {
log.Info("delete model convert start.")
id := ctx.Params(":id")
task, err := models.QueryModelConvertById(id)
if err == nil {
go deleteCloudBrainTask(task)
}
err = models.DeleteModelConvertById(id)
//TODO delete OBS文件及云脑任务
if err != nil {
ctx.JSON(500, err.Error())
} else {
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelmanage/convert_model")
}
}

func deleteCloudBrainTask(task *models.AiModelConvert) {
if task.IsGpuTrainTask() {
log.Info("delete cloudbrain one resource.")
dirPath := setting.CBCodePathPrefix + task.ID + "/"
err := storage.Attachments.DeleteDir(dirPath)
if err != nil {
log.Error("DeleteDir(%s) failed:%v", dirPath, err)
}
} else {
log.Info("delete cloudbrain two resource.")
_, err := modelarts.DelTrainJob(task.CloudBrainTaskId)
if err != nil {
log.Error("DelTrainJob(%s) failed:%v", task.CloudBrainTaskId, err.Error())
}
DeleteJobStorage(task.ID)
}
}

func StopModelConvert(ctx *context.Context) {
id := ctx.Params(":id")
log.Info("stop model convert start.id=" + id)
job, err := models.QueryModelConvertById(id)
if err != nil {
ctx.ServerError("Not found task.", err)
return
}
if job.IsGpuTrainTask() {
err = cloudbrain.StopJob(job.CloudBrainTaskId)
if err != nil {
log.Error("Stop cloudbrain Job(%s) failed:%v", job.CloudBrainTaskId, err)
}
} else {
_, err = modelarts.StopTrainJob(job.CloudBrainTaskId, job.ModelArtsVersionId)
if err != nil {
log.Error("Stop modelarts Job(%s) failed:%v", job.CloudBrainTaskId, err)
}
}
job.Status = string(models.JobStopped)
if job.EndTime == 0 {
job.EndTime = timeutil.TimeStampNow()
}
models.ModelConvertSetDuration(job)
err = models.UpdateModelConvert(job)
if err != nil {
log.Error("UpdateModelConvert failed:", err)
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelmanage/convert_model")
}

func ShowModelConvertInfo(ctx *context.Context) {
ctx.Data["ID"] = ctx.Query("ID")
ctx.Data["isModelManage"] = true
ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage)

job, err := models.QueryModelConvertById(ctx.Query("ID"))
if err == nil {
if job.TrainJobDuration == "" {
job.TrainJobDuration = "00:00:00"
}
ctx.Data["task"] = job
} else {
ctx.ServerError("Not found task.", err)
return
}
ctx.Data["Name"] = job.Name
ctx.Data["canDownload"] = isOper(ctx, job.UserId)
user, err := models.GetUserByID(job.UserId)
if err == nil {
job.UserName = user.Name
job.UserRelAvatarLink = user.RelAvatarLink()
}

if job.IsGpuTrainTask() {
ctx.Data["npu_display"] = "none"
ctx.Data["gpu_display"] = "block"
if job.CloudBrainTaskId == "" {
ctx.Data["ExitDiagnostics"] = ""
ctx.Data["AppExitDiagnostics"] = ""
ctx.HTML(200, tplModelConvertInfo)
return
}
result, err := cloudbrain.GetJob(job.CloudBrainTaskId)
if err != nil {
log.Info("error:" + err.Error())
ctx.Data["error"] = err.Error()
ctx.HTML(200, tplModelConvertInfo)
return
}
if result != nil {
jobRes, _ := models.ConvertToJobResultPayload(result.Payload)
ctx.Data["result"] = jobRes
taskRoles := jobRes.TaskRoles
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
ctx.Data["taskRes"] = taskRes
ctx.Data["ExitDiagnostics"] = taskRes.TaskStatuses[0].ExitDiagnostics
ctx.Data["AppExitDiagnostics"] = jobRes.JobStatus.AppExitDiagnostics

job.Status = jobRes.JobStatus.State

if jobRes.JobStatus.State != string(models.JobWaiting) && jobRes.JobStatus.State != string(models.JobFailed) {
job.ContainerIp = taskRes.TaskStatuses[0].ContainerIP
job.ContainerID = taskRes.TaskStatuses[0].ContainerID
job.Status = taskRes.TaskStatuses[0].State
}
if jobRes.JobStatus.State != string(models.JobWaiting) {
models.ModelComputeAndSetDuration(job, jobRes)
err = models.UpdateModelConvert(job)
if err != nil {
log.Error("UpdateModelConvert failed:", err)
}
}
}
} else {
if job.CloudBrainTaskId != "" {
result, err := modelarts.GetTrainJob(job.CloudBrainTaskId, job.ModelArtsVersionId)
if err != nil {
log.Info("error:" + err.Error())
ctx.Data["error"] = err.Error()
return
}
job.Status = modelarts.TransTrainJobStatus(result.IntStatus)
job.RunTime = result.Duration / 1000
job.TrainJobDuration = models.ConvertDurationToStr(job.RunTime)
err = models.UpdateModelConvert(job)
if err != nil {
log.Error("UpdateJob failed:", err)
}
}
ctx.Data["npu_display"] = "block"
ctx.Data["gpu_display"] = "none"
ctx.Data["ExitDiagnostics"] = ""
ctx.Data["AppExitDiagnostics"] = ""
}

ctx.HTML(200, tplModelConvertInfo)
}

func ConvertModelTemplate(ctx *context.Context) {
ctx.Data["isModelManage"] = true
ctx.Data["TRAIN_COUNT"] = 0
SetModelCount(ctx)
ctx.Data["ModelManageAccess"] = ctx.Repo.CanWrite(models.UnitTypeModelManage)
ShowModelConvertPageInfo(ctx)
ctx.HTML(200, tplModelManageConvertIndex)
}

func ShowModelConvertPageInfo(ctx *context.Context) {
log.Info("ShowModelConvertInfo start.")
if !isQueryRight(ctx) {
log.Info("no right.")
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
return
}
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
repoId := ctx.Repo.Repository.ID
modelResult, count, err := models.QueryModelConvert(&models.AiModelQueryOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: pageSize,
},
RepoID: repoId,
})
if err != nil {
log.Info("query db error." + err.Error())
ctx.ServerError("Cloudbrain", err)
return
}
ctx.Data["MODEL_CONVERT_COUNT"] = count
userIds := make([]int64, len(modelResult))
for i, model := range modelResult {
model.IsCanOper = isOper(ctx, model.UserId)
model.IsCanDelete = isCanDelete(ctx, model.UserId)
userIds[i] = model.UserId
}
userNameMap := queryUserName(userIds)
for _, model := range modelResult {
value := userNameMap[model.UserId]
if value != nil {
model.UserName = value.Name
model.UserRelAvatarLink = value.RelAvatarLink()
}
}
pager := context.NewPagination(int(count), page, pageSize, 5)
ctx.Data["Page"] = pager
ctx.Data["Tasks"] = modelResult

}

func ModelConvertDownloadModel(ctx *context.Context) {
log.Info("enter here......")
id := ctx.Params(":id")
job, err := models.QueryModelConvertById(id)
if err != nil {
ctx.ServerError("Not found task.", err)
return
}
AllDownload := ctx.QueryBool("AllDownload")
if AllDownload {
if job.IsGpuTrainTask() {
path := setting.CBCodePathPrefix + job.ID + "/model/"
allFile, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, path)
if err == nil {
returnFileName := job.Name + ".zip"
MinioDownloadManyFile(path, ctx, returnFileName, allFile)
} else {
log.Info("error,msg=" + err.Error())
ctx.ServerError("no file to download.", err)
}
} else {
Prefix := path.Join(setting.TrainJobModelPath, job.ID, "output/", "V0001", "") + "/"
log.Info("bucket=" + setting.Bucket + "prefix=" + Prefix)
allFile, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, Prefix)
if err == nil {
returnFileName := job.Name + ".zip"
ObsDownloadManyFile(Prefix, ctx, returnFileName, allFile)
} else {
log.Info("error,msg=" + err.Error())
ctx.ServerError("no file to download.", err)
}
}
} else {
parentDir := ctx.Query("parentDir")
fileName := ctx.Query("fileName")
jobName := ctx.Query("jobName")
if job.IsGpuTrainTask() {
filePath := "jobs/" + jobName + "/model/" + parentDir
url, err := storage.Attachments.PresignedGetURL(filePath, fileName)
if err != nil {
log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("PresignedGetURL", err)
return
}
//ctx.JSON(200, url)
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect)
} else {
ObjectKey := path.Join(setting.TrainJobModelPath, job.ID, "output/", "V0001", parentDir, fileName)
log.Info("ObjectKey=" + ObjectKey)
url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, ObjectKey)
if err != nil {
log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"])
ctx.ServerError("GetObsCreateSignedUrl", err)
return
}
http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusTemporaryRedirect)
}
}

}

+ 80
- 13
routers/repo/ai_model_manage.go View File

@@ -26,6 +26,7 @@ const (
tplModelInfo = "repo/modelmanage/showinfo" tplModelInfo = "repo/modelmanage/showinfo"
MODEL_LATEST = 1 MODEL_LATEST = 1
MODEL_NOT_LATEST = 0 MODEL_NOT_LATEST = 0
MODEL_MAX_SIZE = 1024 * 1024 * 1024
) )


func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) error { func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, engine int, ctx *context.Context) error {
@@ -58,14 +59,16 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
} }
} }
cloudType := aiTask.Type cloudType := aiTask.Type
modelSelectedFile := ctx.Query("modelSelectedFile")
//download model zip //train type //download model zip //train type
if cloudType == models.TypeCloudBrainTwo {
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl)
if aiTask.ComputeResource == models.NPUResource {
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile)
if err != nil { if err != nil {
log.Info("download model from CloudBrainTwo faild." + err.Error()) log.Info("download model from CloudBrainTwo faild." + err.Error())
return err return err
} }
} else if cloudType == models.TypeCloudBrainOne {
cloudType = models.TypeCloudBrainTwo
} else if aiTask.ComputeResource == models.GPUResource {
var ResourceSpecs *models.ResourceSpecs var ResourceSpecs *models.ResourceSpecs
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
for _, tmp := range ResourceSpecs.ResourceSpec { for _, tmp := range ResourceSpecs.ResourceSpec {
@@ -74,12 +77,24 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
aiTask.FlavorName = flaverName aiTask.FlavorName = flaverName
} }
} }
modelPath, modelSize, err = downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl)
modelPath, modelSize, err = downloadModelFromCloudBrainOne(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile)
if err != nil { if err != nil {
log.Info("download model from CloudBrainOne faild." + err.Error()) log.Info("download model from CloudBrainOne faild." + err.Error())
return err return err
} }
}
cloudType = models.TypeCloudBrainOne
}
// else if cloudType == models.TypeC2Net {
// if aiTask.ComputeResource == models.NPUResource {
// modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl, modelSelectedFile)
// if err != nil {
// log.Info("download model from CloudBrainTwo faild." + err.Error())
// return err
// }
// } else if aiTask.ComputeResource == models.GPUResource {

// }
// }
accuracy := make(map[string]string) accuracy := make(map[string]string)
accuracy["F1"] = "" accuracy["F1"] = ""
accuracy["Recall"] = "" accuracy["Recall"] = ""
@@ -163,7 +178,8 @@ func SaveModel(ctx *context.Context) {
description := ctx.Query("Description") description := ctx.Query("Description")
engine := ctx.QueryInt("Engine") engine := ctx.QueryInt("Engine")
trainTaskCreate := ctx.QueryBool("trainTaskCreate") trainTaskCreate := ctx.QueryBool("trainTaskCreate")
log.Info("engine=" + fmt.Sprint(engine))
modelSelectedFile := ctx.Query("modelSelectedFile")
log.Info("engine=" + fmt.Sprint(engine) + " modelSelectedFile=" + modelSelectedFile)
if !trainTaskCreate { if !trainTaskCreate {
if !ctx.Repo.CanWrite(models.UnitTypeModelManage) { if !ctx.Repo.CanWrite(models.UnitTypeModelManage) {
//ctx.NotFound(ctx.Req.URL.RequestURI(), nil) //ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -176,6 +192,10 @@ func SaveModel(ctx *context.Context) {
ctx.Error(500, fmt.Sprintf("JobId or VersionName is null.")) ctx.Error(500, fmt.Sprintf("JobId or VersionName is null."))
return return
} }
if modelSelectedFile == "" {
ctx.Error(500, fmt.Sprintf("Not selected model file."))
return
}


if name == "" || version == "" { if name == "" || version == "" {
ctx.Error(500, fmt.Sprintf("name or version is null.")) ctx.Error(500, fmt.Sprintf("name or version is null."))
@@ -193,11 +213,22 @@ func SaveModel(ctx *context.Context) {
log.Info("save model end.") log.Info("save model end.")
} }


func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) {
func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) {
objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/")
if trainUrl != "" { if trainUrl != "" {
objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/") objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/")
} }
prefix := objectkey + "/"

filterFiles := strings.Split(modelSelectedFile, ";")
Files := make([]string, 0)
for _, shortFile := range filterFiles {
Files = append(Files, prefix+shortFile)
}
totalSize := storage.ObsGetFilesSize(setting.Bucket, Files)
if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE {
return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.")
}


modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "") modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "")
log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey)
@@ -206,26 +237,33 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir
return "", 0, err return "", 0, err
} }
if len(modelDbResult) == 0 { if len(modelDbResult) == 0 {
return "", 0, errors.New("cannot create model, as model is empty.")
return "", 0, errors.New("Cannot create model, as model is empty.")
} }


prefix := objectkey + "/"
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/"

size, err := storage.ObsCopyManyFile(setting.Bucket, prefix, setting.Bucket, destKeyNamePrefix)
size, err := storage.ObsCopyManyFile(setting.Bucket, prefix, setting.Bucket, destKeyNamePrefix, filterFiles)


dataActualPath := setting.Bucket + "/" + destKeyNamePrefix dataActualPath := setting.Bucket + "/" + destKeyNamePrefix
return dataActualPath, size, nil return dataActualPath, size, nil
} }


func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) {
func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) {
modelActualPath := storage.GetMinioPath(jobName, "/model/") modelActualPath := storage.GetMinioPath(jobName, "/model/")
log.Info("modelActualPath=" + modelActualPath) log.Info("modelActualPath=" + modelActualPath)
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/"
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/"
bucketName := setting.Attachment.Minio.Bucket bucketName := setting.Attachment.Minio.Bucket
log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName) log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName)
size, err := storage.MinioPathCopy(bucketName, modelSrcPrefix, destKeyNamePrefix)
filterFiles := strings.Split(modelSelectedFile, ";")
Files := make([]string, 0)
for _, shortFile := range filterFiles {
Files = append(Files, modelSrcPrefix+shortFile)
}
totalSize := storage.MinioGetFilesSize(bucketName, Files)
if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE {
return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.")
}
size, err := storage.MinioCopyFiles(bucketName, modelSrcPrefix, destKeyNamePrefix, filterFiles)
if err == nil { if err == nil {
dataActualPath := bucketName + "/" + destKeyNamePrefix dataActualPath := bucketName + "/" + destKeyNamePrefix
return dataActualPath, size, nil return dataActualPath, size, nil
@@ -459,6 +497,35 @@ func QueryTrainJobList(ctx *context.Context) {


} }


func QueryTrainModelList(ctx *context.Context) {
log.Info("query train job list. start.")
jobName := ctx.Query("jobName")
taskType := ctx.QueryInt("type")
VersionName := ctx.Query("VersionName")
if taskType == models.TypeCloudBrainTwo {
objectkey := path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, VersionName) + "/"
modelDbResult, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, objectkey)
log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey)
if err != nil {
log.Info("get TypeCloudBrainTwo TrainJobListModel failed:", err)
} else {
ctx.JSON(200, modelDbResult)
return
}
} else if taskType == models.TypeCloudBrainOne {
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/"
bucketName := setting.Attachment.Minio.Bucket
modelDbResult, err := storage.GetAllObjectByBucketAndPrefixMinio(bucketName, modelSrcPrefix)
if err != nil {
log.Info("get TypeCloudBrainOne TrainJobListModel failed:", err)
} else {
ctx.JSON(200, modelDbResult)
return
}
}
ctx.JSON(200, "")
}

func DownloadSingleModelFile(ctx *context.Context) { func DownloadSingleModelFile(ctx *context.Context) {
log.Info("DownloadSingleModelFile start.") log.Info("DownloadSingleModelFile start.")
id := ctx.Params(":ID") id := ctx.Params(":ID")


+ 111
- 81
routers/repo/modelarts.go View File

@@ -984,7 +984,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
flavorCode := form.Flavor flavorCode := form.Flavor
params := form.Params params := form.Params
poolID := form.PoolID poolID := form.PoolID
isSaveParam := form.IsSaveParam
//isSaveParam := form.IsSaveParam
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
codeLocalPath := setting.JobPath + jobName + modelarts.CodePath codeLocalPath := setting.JobPath + jobName + modelarts.CodePath
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath
@@ -1129,45 +1129,45 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
} }


//save param config //save param config
if isSaveParam == "on" {
saveparams := append(param, models.Parameter{
Label: modelarts.TrainUrl,
Value: outputObsPath,
}, models.Parameter{
Label: modelarts.DataUrl,
Value: dataPath,
})
if form.ParameterTemplateName == "" {
log.Error("ParameterTemplateName is empty")
trainJobNewDataPrepare(ctx)
ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobNew, &form)
return
}
_, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{
ConfigName: form.ParameterTemplateName,
Description: form.PrameterDescription,
DataUrl: dataPath,
AppUrl: codeObsPath,
BootFileUrl: codeObsPath + bootFile,
TrainUrl: outputObsPath,
Flavor: models.Flavor{
Code: flavorCode,
},
WorkServerNum: workServerNumber,
EngineID: int64(engineID),
LogUrl: logObsPath,
PoolID: poolID,
Parameter: saveparams,
})
if err != nil {
log.Error("Failed to CreateTrainJobConfig: %v", err)
trainJobErrorNewDataPrepare(ctx, form)
ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobNew, &form)
return
}
}
// if isSaveParam == "on" {
// saveparams := append(param, models.Parameter{
// Label: modelarts.TrainUrl,
// Value: outputObsPath,
// }, models.Parameter{
// Label: modelarts.DataUrl,
// Value: dataPath,
// })
// if form.ParameterTemplateName == "" {
// log.Error("ParameterTemplateName is empty")
// trainJobNewDataPrepare(ctx)
// ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobNew, &form)
// return
// }
// _, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{
// ConfigName: form.ParameterTemplateName,
// Description: form.PrameterDescription,
// DataUrl: dataPath,
// AppUrl: codeObsPath,
// BootFileUrl: codeObsPath + bootFile,
// TrainUrl: outputObsPath,
// Flavor: models.Flavor{
// Code: flavorCode,
// },
// WorkServerNum: workServerNumber,
// EngineID: int64(engineID),
// LogUrl: logObsPath,
// PoolID: poolID,
// Parameter: saveparams,
// })
// if err != nil {
// log.Error("Failed to CreateTrainJobConfig: %v", err)
// trainJobErrorNewDataPrepare(ctx, form)
// ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobNew, &form)
// return
// }
// }


req := &modelarts.GenerateTrainJobReq{ req := &modelarts.GenerateTrainJobReq{
JobName: jobName, JobName: jobName,
@@ -1195,6 +1195,9 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
TotalVersionCount: modelarts.TotalVersionCount, TotalVersionCount: modelarts.TotalVersionCount,
DatasetName: datasetNames, DatasetName: datasetNames,
} }
userCommand, userImageUrl := getUserCommand(engineID, req)
req.UserCommand = userCommand
req.UserImageUrl = userImageUrl


//将params转换Parameters.Parameter,出错时返回给前端 //将params转换Parameters.Parameter,出错时返回给前端
var Parameters modelarts.Parameters var Parameters modelarts.Parameters
@@ -1213,6 +1216,30 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm)
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job")
} }


func getUserCommand(engineId int, req *modelarts.GenerateTrainJobReq) (string, string) {
userImageUrl := ""
userCommand := ""
if engineId < 0 {
userCommand = "/bin/bash /home/work/run_train.sh 's3://" + req.CodeObsPath + "' 'code/" + req.BootFile + "' '/tmp/log/train.log' --'data_url'='s3://" + req.DataUrl + "' --'train_url'='s3://" + req.TrainUrl + "'"
var versionInfos modelarts.VersionInfo
if err := json.Unmarshal([]byte(setting.EngineVersions), &versionInfos); err != nil {
log.Info("json parse err." + err.Error())
} else {
for _, engine := range versionInfos.Version {
if engine.ID == engineId {
userImageUrl = engine.Url
break
}
}
}
for _, param := range req.Parameters {
userCommand += " --'" + param.Label + "'='" + param.Value + "'"
}
return userCommand, userImageUrl
}
return userCommand, userImageUrl
}

func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) { func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) {
ctx.Data["PageIsTrainJob"] = true ctx.Data["PageIsTrainJob"] = true
var jobID = ctx.Params(":jobid") var jobID = ctx.Params(":jobid")
@@ -1249,7 +1276,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
flavorCode := form.Flavor flavorCode := form.Flavor
params := form.Params params := form.Params
poolID := form.PoolID poolID := form.PoolID
isSaveParam := form.IsSaveParam
//isSaveParam := form.IsSaveParam
repo := ctx.Repo.Repository repo := ctx.Repo.Repository
codeLocalPath := setting.JobPath + jobName + modelarts.CodePath codeLocalPath := setting.JobPath + jobName + modelarts.CodePath
codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath + VersionOutputPath + "/" codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath + VersionOutputPath + "/"
@@ -1369,46 +1396,46 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
}) })
} }


//save param config
if isSaveParam == "on" {
saveparams := append(param, models.Parameter{
Label: modelarts.TrainUrl,
Value: outputObsPath,
}, models.Parameter{
Label: modelarts.DataUrl,
Value: dataPath,
})
if form.ParameterTemplateName == "" {
log.Error("ParameterTemplateName is empty")
versionErrorDataPrepare(ctx, form)
ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobVersionNew, &form)
return
}
_, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{
ConfigName: form.ParameterTemplateName,
Description: form.PrameterDescription,
DataUrl: dataPath,
AppUrl: codeObsPath,
BootFileUrl: codeObsPath + bootFile,
TrainUrl: outputObsPath,
Flavor: models.Flavor{
Code: flavorCode,
},
WorkServerNum: workServerNumber,
EngineID: int64(engineID),
LogUrl: logObsPath,
PoolID: poolID,
Parameter: saveparams,
})
if err != nil {
log.Error("Failed to CreateTrainJobConfig: %v", err)
versionErrorDataPrepare(ctx, form)
ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form)
return
}
}
// //save param config
// if isSaveParam == "on" {
// saveparams := append(param, models.Parameter{
// Label: modelarts.TrainUrl,
// Value: outputObsPath,
// }, models.Parameter{
// Label: modelarts.DataUrl,
// Value: dataPath,
// })
// if form.ParameterTemplateName == "" {
// log.Error("ParameterTemplateName is empty")
// versionErrorDataPrepare(ctx, form)
// ctx.RenderWithErr("保存作业参数时,作业参数名称不能为空", tplModelArtsTrainJobVersionNew, &form)
// return
// }
// _, err := modelarts.CreateTrainJobConfig(models.CreateConfigParams{
// ConfigName: form.ParameterTemplateName,
// Description: form.PrameterDescription,
// DataUrl: dataPath,
// AppUrl: codeObsPath,
// BootFileUrl: codeObsPath + bootFile,
// TrainUrl: outputObsPath,
// Flavor: models.Flavor{
// Code: flavorCode,
// },
// WorkServerNum: workServerNumber,
// EngineID: int64(engineID),
// LogUrl: logObsPath,
// PoolID: poolID,
// Parameter: saveparams,
// })
// if err != nil {
// log.Error("Failed to CreateTrainJobConfig: %v", err)
// versionErrorDataPrepare(ctx, form)
// ctx.RenderWithErr("保存作业参数失败:"+err.Error(), tplModelArtsTrainJobVersionNew, &form)
// return
// }
// }


task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, PreVersionName) task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, PreVersionName)
if err != nil { if err != nil {
@@ -1443,6 +1470,9 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ
TotalVersionCount: latestTask.TotalVersionCount + 1, TotalVersionCount: latestTask.TotalVersionCount + 1,
DatasetName: datasetNames, DatasetName: datasetNames,
} }
userCommand, userImageUrl := getUserCommand(engineID, req)
req.UserCommand = userCommand
req.UserImageUrl = userImageUrl


err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) err = modelarts.GenerateTrainJobVersion(ctx, req, jobID)
if err != nil { if err != nil {


+ 3
- 0
routers/repo/repo.go View File

@@ -195,8 +195,11 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
} }
ctx.Data["ContextUser"] = ctxUser ctx.Data["ContextUser"] = ctxUser
if !form.AutoAgree { if !form.AutoAgree {
ctx.Data["CheckedAutoAgree"] = ""
ctx.RenderWithErr(ctx.Tr("repo.template.one_promise"), tplCreate, form) ctx.RenderWithErr(ctx.Tr("repo.template.one_promise"), tplCreate, form)
return return
} else {
ctx.Data["CheckedAutoAgree"] = "checked"
} }
if ctx.HasError() { if ctx.HasError() {
ctx.HTML(200, tplCreate) ctx.HTML(200, tplCreate)


+ 8
- 1
routers/routes/routes.go View File

@@ -500,7 +500,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/email2user", user.Email2User) m.Get("/email2user", user.Email2User)
m.Get("/recover_account", user.ResetPasswd) m.Get("/recover_account", user.ResetPasswd)
m.Post("/recover_account", user.ResetPasswdPost) m.Post("/recover_account", user.ResetPasswdPost)
m.Post("/recover_account_by_phone",bindIgnErr(auth.ResetPassWordByPhoneForm{}), user.ResetPasswdByPhonePost)
m.Post("/recover_account_by_phone", bindIgnErr(auth.ResetPassWordByPhoneForm{}), user.ResetPasswdByPhonePost)
m.Get("/forgot_password", user.ForgotPasswd) m.Get("/forgot_password", user.ForgotPasswd)
m.Post("/forgot_password", user.ForgotPasswdPost) m.Post("/forgot_password", user.ForgotPasswdPost)
m.Post("/logout", user.SignOut) m.Post("/logout", user.SignOut)
@@ -1136,19 +1136,26 @@ func RegisterRoutes(m *macaron.Macaron) {
}, context.RepoRef()) }, context.RepoRef())
m.Group("/modelmanage", func() { m.Group("/modelmanage", func() {
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel)
m.Post("/create_model_convert", reqRepoModelManageWriter, repo.SaveModelConvert)
m.Post("/create_new_model", repo.SaveNewNameModel) m.Post("/create_new_model", repo.SaveNewNameModel)
m.Delete("/delete_model", repo.DeleteModel) m.Delete("/delete_model", repo.DeleteModel)
m.Post("/delete_model_convert/:id", repo.DeleteModelConvert)
m.Post("/convert_stop/:id", repo.StopModelConvert)
m.Put("/modify_model", repo.ModifyModelInfo) m.Put("/modify_model", repo.ModifyModelInfo)
m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate)
m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate)
m.Get("/show_model_info", repo.ShowModelInfo) m.Get("/show_model_info", repo.ShowModelInfo)
m.Get("/show_model_convert_info", repo.ShowModelConvertInfo)
m.Get("/show_model_info_api", repo.ShowSingleModel) m.Get("/show_model_info_api", repo.ShowSingleModel)
m.Get("/show_model_api", repo.ShowModelPageInfo) m.Get("/show_model_api", repo.ShowModelPageInfo)
m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel) m.Get("/show_model_child_api", repo.ShowOneVersionOtherModel)
m.Get("/query_train_job", reqRepoCloudBrainReader, repo.QueryTrainJobList) m.Get("/query_train_job", reqRepoCloudBrainReader, repo.QueryTrainJobList)
m.Get("/query_train_model", reqRepoCloudBrainReader, repo.QueryTrainModelList)
m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList) m.Get("/query_train_job_version", reqRepoCloudBrainReader, repo.QueryTrainJobVersionList)
m.Get("/query_model_for_predict", reqRepoModelManageReader, repo.QueryModelListForPredict) m.Get("/query_model_for_predict", reqRepoModelManageReader, repo.QueryModelListForPredict)
m.Get("/query_modelfile_for_predict", reqRepoModelManageReader, repo.QueryModelFileForPredict) m.Get("/query_modelfile_for_predict", reqRepoModelManageReader, repo.QueryModelFileForPredict)
m.Get("/query_onelevel_modelfile", reqRepoModelManageReader, repo.QueryOneLevelModelFile) m.Get("/query_onelevel_modelfile", reqRepoModelManageReader, repo.QueryOneLevelModelFile)
m.Get("/download_model_convert/:id", reqRepoModelManageReader, repo.ModelConvertDownloadModel)
m.Group("/:ID", func() { m.Group("/:ID", func() {
m.Get("", repo.ShowSingleModel) m.Get("", repo.ShowSingleModel)
m.Get("/downloadsingle", repo.DownloadSingleModelFile) m.Get("/downloadsingle", repo.DownloadSingleModelFile)


+ 1
- 1
templates/repo/cloudbrain/benchmark/index.tmpl View File

@@ -64,7 +64,7 @@
<div class="dataset list"> <div class="dataset list">


<!-- 表头 --> <!-- 表头 -->
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="ui grid stackable" style="background: #f0f0f0;">
<div class="row"> <div class="row">
<div class="three wide column padding0" style="width: 18% !important;"> <div class="three wide column padding0" style="width: 18% !important;">
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span>


+ 290
- 0
templates/repo/cloudbrain/trainjob/show.tmpl View File

@@ -1,4 +1,5 @@
{{template "base/head" .}} {{template "base/head" .}}
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">
<style> <style>
.according-panel-heading { .according-panel-heading {
box-sizing: border-box; box-sizing: border-box;
@@ -200,6 +201,19 @@
padding-left: 1rem; padding-left: 1rem;
padding-top: 0.5rem; padding-top: 0.5rem;
} }
.menuContent{
position: absolute;
background: #ffffff;
left: 0;
right: 26px;
top: 36px;
z-index:999;
border: 1px solid #96c8da;
border-top: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%);
}
</style> </style>
<div id="mask"> <div id="mask">
<div id="loadingPage"> <div id="loadingPage">
@@ -236,6 +250,16 @@
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<span class="accordion-panel-title-content"> <span class="accordion-panel-title-content">
<span> <span>
<div style="float: right;">
{{if and ($.canDownload) (eq .Status "SUCCEEDED") ($.Permission.CanWrite $.UnitTypeModelManage) }}
<a class="ti-action-menu-item" id="{{.VersionName}}-create-model"
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{else}}
<a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model"
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{end}}

</div>
<div class="ac-display-inblock title_text acc-margin-bottom"> <div class="ac-display-inblock title_text acc-margin-bottom">
<span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span> <span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span>


@@ -504,12 +528,278 @@
</div> </div>
</div> </div>
</div> </div>
<!--
<div id="menuContent" class="menuContent" style="display:none; position: absolute;z-index:9999">
<ul id="treeDemo" class="ztree" style="margin-top:0; width: 83%; height: 100%;"></ul>
</div> -->
<!-- 创建模型 -->
<div id="newmodel">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">导入新模型</h4>
</div>
<div class="content content-padding">
<form id="formId" method="POST" class="ui form">
<div class="ui error message">
</div>
{{$.CsrfTokenHtml}}
<input type="hidden" name="trainTaskCreate" value="true">

<div class="required inline field">
<label>训练任务</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input type="hidden" id="VersionName" name="VersionName" value="V0001">
<input style="width: 45%;" id="JobName" readonly required>
</div>

<div class="required inline field" id="modelname">
<label>模型名称</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25"
onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>
<div class="unite min_title inline field required">
<label>模型框架</label>
<div class="ui dropdown selection search width70" id="choice_Engine">
<input type="hidden" id="Engine" name="Engine" required>
<div class="default text">选择模型框架</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-Engine">
<option class="active item" data-value="0">PyTorch</option>
<option class="item" data-value="1">TensorFlow</option>
<option class="item" data-value="4">PaddlePaddle</option>
<option class="item" data-value="5">OneFlow</option>
<option class="item" data-value="6">MXNet</option>
<option class="item" data-value="3">Other</option>
</div>
</div>

</div>
<div class="unite min_title inline fields required">
<div class="field required">
<label for="modelSelectedFile">模型文件</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
<div id="menuContent" class="menuContent" style="display:none;">
<ul id="treeDemo" class="ztree"></ul>
</div>
</div>
</div>
<div class="inline field">
<label>模型标签</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255"
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3"
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}'
onchange="this.value=this.value.substring(0, 255)"
onkeydown="this.value=this.value.substring(0, 255)"
onkeyup="this.value=this.value.substring(0, 256)"></textarea>
</div>

<div class="inline field" style="margin-left: 75px;">
<button onclick="createModel()" type="button" class="ui create_train_job green button"
style="position: absolute;">
{{.i18n.Tr "repo.model.manage.sava_model"}}
</button>
</div>
</form>
<div class="actions" style="display: inline-block;margin-left: 180px;">
<button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div>
</div>



</div>
</div>


</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script>
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script>


<script> <script>
var setting = {
check: {
enable: true,
chkboxType: {"Y":"ps", "N":"ps"}
},
view: {
dblClickExpand: false
},
callback: {
beforeClick: beforeClick,
onCheck: onCheck
}
};

function beforeClick(treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo");
zTree.checkNode(treeNode, !treeNode.checked, null, true);
return false;
}
function onCheck(e, treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo"),
nodes = zTree.getCheckedNodes(true),
v = "";
for (var i=0, l=nodes.length; i<l; i++) {
if(nodes[i].isParent){
continue;
}
var pathNodes = nodes[i].getPath();
var path ="";
for(var j=0;j<pathNodes.length;j++){
if(j ==0){
path += pathNodes[j].name;
}else{
path += "/" + pathNodes[j].name;
}
}
v += path + ";";
}
if (v.length > 0 ) v = v.substring(0, v.length-1);
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", v);
}
function showMenu() {
var cityObj = $("#modelSelectedFile");
var cityOffset = $("#modelSelectedFile").offset();
//$("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast");
$("#menuContent").slideDown("fast");
$("body").bind("mousedown", onBodyDown);
}
function hideMenu() {
$("#menuContent").fadeOut("fast");
$("body").unbind("mousedown", onBodyDown);
}
function onBodyDown(event) {
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) {
hideMenu();
}
}

function loadSelectedModelFile(trainJob){
console.log("trainJob=" + trainJob);
$('#choice_file').dropdown('clear')
$("#model-file").empty()
if(trainJob ==null || trainJob ==""){
console.log("trainJob is null");
}else{
$.get(`/${userName}/${repoPath}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=0&VersionName=${trainJob.VersionName}`, (data) => {
const n_length = data.length
let file_html=''
let firstFileName =''
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
break;
}
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
}
}
convertToNode(zNodes,nodesMap);
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
})
}
}

function convertToNode(nodeList,nodesMap){
var keyList = Object.keys(nodesMap);
keyList.sort(function(a,b){
return a-b;
});
var isFirst = true;
for(var i=0; i<keyList.length;i++){
var node = {};
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}
function showcreate(obj) {
$('.ui.modal.second')
.modal({
centered: false,
onShow: function () {
$('input[name="Version"]').addClass('model_disabled')
// $('input[name="JobId"]').text(obj.JobName)
$('#JobName').val(obj.DisplayJobName).addClass('model_disabled')
$('input[name="JobId"]').val(obj.JobID)
$('input[name="VersionName"]').val("V0001")
$('#choice_Engine .default.text').text("PyTorch");
$('#choice_Engine input[name="Engine"]').val(0)
$('#choice_Engine .default.text').css({ "color": "rgb(0, 0, 0,0.87)" })
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
createModelName();
loadSelectedModelFile(obj);
},
onHide: function () {
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", "");
document.getElementById("formId").reset();
$('.ui.dimmer').css({ "background-color": "" })
$('.ui.error.message').text()
$('.ui.error.message').css('display', 'none')
}
})
.modal('show')
}
function createModel() {
let url_href = `/${userName}/${repoPath}/modelmanage/create_new_model`
let data = $("#formId").serialize()
$("#mask").css({ "display": "block", "z-index": "9999" })
$.ajax({
url: url_href,
type: 'POST',
data: data,
success: function (res) {
$('input[name="Engine_name"]').val("");
$('input[name="Engine"]').val("");
location.href = `/${userName}/${repoPath}/modelmanage/show_model`
$('.ui.modal.second').modal('hide')
},
error: function (xhr) {
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
$('.ui.error.message').text(xhr.responseText)
$('.ui.error.message').css('display', 'block')
},
complete: function (xhr) {
$("#mask").css({ "display": "none", "z-index": "1" })
}
})

}
function createModelName() {
let repoName = location.pathname.split('/')[2]
let modelName = repoName + '_model_' + Math.random().toString(36).substr(2, 4)
$('#name').val(modelName)
$('#version').val("0.0.1")
}

$('.menu .item').tab() $('.menu .item').tab()


$(document).ready(function () { $(document).ready(function () {


+ 10
- 1
templates/repo/create.tmpl View File

@@ -80,6 +80,15 @@
<label>{{.i18n.Tr "repo.template.issue_labels"}}</label> <label>{{.i18n.Tr "repo.template.issue_labels"}}</label>
</div> </div>
</div> </div>
<div class="inline field">
<div class="ui checkbox" id="auto-init">
<input class="hidden" name="auto_agree" type="checkbox" {{.CheckedAutoAgree}}>
<label
style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}}
<a target="_blank"
href="/home/term/">{{.i18n.Tr "repo.openi_use_agreement"}}</a></label>
</div>
</div>
</div> </div>


<div id="non_template"> <div id="non_template">
@@ -152,7 +161,7 @@
</div> </div>
<div class="inline field"> <div class="inline field">
<div class="ui checkbox" id="auto-init"> <div class="ui checkbox" id="auto-init">
<input class="hidden" name="auto_agree" type="checkbox">
<input class="hidden" name="auto_agree" type="checkbox" {{.CheckedAutoAgree}}>
<label <label
style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}} style="width: 76%;text-align: justify;line-height: 1.5;">{{.i18n.Tr "repo.use_repo_agreement"}}
<a target="_blank" <a target="_blank"


+ 253
- 44
templates/repo/grampus/trainjob/show.tmpl View File

@@ -1,4 +1,5 @@
{{template "base/head" .}} {{template "base/head" .}}
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">
<style> <style>
.according-panel-heading { .according-panel-heading {
box-sizing: border-box; box-sizing: border-box;
@@ -194,6 +195,19 @@
padding-left: 1rem; padding-left: 1rem;
padding-top: 0.5rem; padding-top: 0.5rem;
} }
.menuContent{
position: absolute;
background: #ffffff;
left: 0;
right: 26px;
top: 36px;
z-index:999;
border: 1px solid #96c8da;
border-top: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%);
}
</style> </style>
<div id="mask"> <div id="mask">
<div id="loadingPage"> <div id="loadingPage">
@@ -234,6 +248,7 @@
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
</div> </div>
<div class="ac-display-inblock title_text acc-margin-bottom"> <div class="ac-display-inblock title_text acc-margin-bottom">


<span class="cti-mgRight-sm"> <span class="cti-mgRight-sm">
@@ -260,6 +275,16 @@
class="redo icon redo-color"></i></span> class="redo icon redo-color"></i></span>


</div> </div>
<div style="float: right;">
{{if and ($.canDownload) (eq .Status "SUCCEEDED") ($.Permission.CanWrite $.UnitTypeModelManage) }}
<a class="ti-action-menu-item" id="{{.VersionName}}-create-model"
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{else}}
<a class="ti-action-menu-item disabled" id="{{.VersionName}}-create-model"
onclick="showcreate({{.}})">{{$.i18n.Tr "repo.modelarts.create_model"}}</a>
{{end}}

</div>
</span> </span>
</span> </span>
</div> </div>
@@ -514,7 +539,7 @@
</div> </div>
</div> </div>
<!-- 创建模型 --> <!-- 创建模型 -->
<div id="newmodel">
<div id="newmodel">
<div class="ui modal second"> <div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> <div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header">导入新模型</h4> <h4 id="model_header">导入新模型</h4>
@@ -526,17 +551,11 @@
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<input type="hidden" name="trainTaskCreate" value="true"> <input type="hidden" name="trainTaskCreate" value="true">


<div class="two inline fields ">
<div class="required ten wide field">
<label style="margin-left: -23px;">选择训练任务</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input class="width83" id="JobName" readonly required>

</div>
<div class="required six widde field">
<label>版本</label>
<input class="width70" id="VersionName" name="VersionName" readonly required>
</div>
<div class="required inline field">
<label>训练任务</label>
<input type="hidden" class="width83" id="JobId" name="JobId" readonly required>
<input type="hidden" id="VersionName" name="VersionName" value="V0001">
<input style="width: 45%;" id="JobName" readonly required>
</div> </div>


<div class="required inline field" id="modelname"> <div class="required inline field" id="modelname">
@@ -546,8 +565,36 @@
</div> </div>
<div class="required inline field" id="verionname"> <div class="required inline field" id="verionname">
<label>模型版本</label> <label>模型版本</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required
maxlength="255">
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
</div>
<div class="unite min_title inline field required">
<label>模型框架</label>
<div class="ui dropdown selection search width70" id="choice_Engine">
<input type="hidden" id="Engine" name="Engine" required>
<div class="default text">选择模型框架</div>
<i class="dropdown icon"></i>
<div class="menu" id="job-Engine">
<option class="active item" data-value="0">PyTorch</option>
<option class="item" data-value="1">TensorFlow</option>
<option class="item" data-value="2">MindSpore</option>
<option class="item" data-value="4">PaddlePaddle</option>
<option class="item" data-value="5">OneFlow</option>
<option class="item" data-value="6">MXNet</option>
<option class="item" data-value="3">Other</option>
</div>
</div>

</div>
<div class="unite min_title inline fields required">
<div class="field required">
<label for="modelSelectedFile">模型文件</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
<div id="menuContent" class="menuContent" style="display:none;">
<ul id="treeDemo" class="ztree"></ul>
</div>
</div>
</div> </div>
<div class="inline field"> <div class="inline field">
<label>模型标签</label> <label>模型标签</label>
@@ -578,39 +625,135 @@


</div> </div>
</div> </div>

</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script>
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script>


<script> <script>
$('.menu .item').tab()
$(document).ready(function () {
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } });
});
$(document).ready(function () {
$('.secondary.menu .item').tab();
});

let userName
let repoPath
let jobID
let downlaodFlag = {{ $.canDownload }}
$(document).ready(function () {
let url = window.location.href;
let urlArr = url.split('/')
userName = urlArr.slice(-5)[0]
repoPath = urlArr.slice(-4)[0]
jobID = urlArr.slice(-1)[0]
})
function stopBubbling(e) {
e = window.event || e;
if (e.stopPropagation) {
e.stopPropagation(); //阻止事件 冒泡传播
} else {
e.cancelBubble = true; //ie兼容
}
var setting = {
check: {
enable: true,
chkboxType: {"Y":"ps", "N":"ps"}
},
view: {
dblClickExpand: false
},
callback: {
beforeClick: beforeClick,
onCheck: onCheck
}
};

function beforeClick(treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo");
zTree.checkNode(treeNode, !treeNode.checked, null, true);
return false;
}
function onCheck(e, treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo"),
nodes = zTree.getCheckedNodes(true),
v = "";
for (var i=0, l=nodes.length; i<l; i++) {
if(nodes[i].isParent){
continue;
}
var pathNodes = nodes[i].getPath();
var path ="";
for(var j=0;j<pathNodes.length;j++){
if(j ==0){
path += pathNodes[j].name;
}else{
path += "/" + pathNodes[j].name;
}
}
v += path + ";";
}
if (v.length > 0 ) v = v.substring(0, v.length-1);
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", v);
}
function showMenu() {
var cityObj = $("#modelSelectedFile");
var cityOffset = $("#modelSelectedFile").offset();
//$("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast");
$("#menuContent").slideDown("fast");
$("body").bind("mousedown", onBodyDown);
}
function hideMenu() {
$("#menuContent").fadeOut("fast");
$("body").unbind("mousedown", onBodyDown);
}
function onBodyDown(event) {
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) {
hideMenu();
}
}

function loadSelectedModelFile(trainJob){
console.log("trainJob=" + trainJob);
$('#choice_file').dropdown('clear')
$("#model-file").empty()
if(trainJob ==null || trainJob ==""){
console.log("trainJob is null");
}else{
let type = trainJob.Type;
if(type == 2){
if(trainJob.ComputeResource=="NPU"){
type=1;
}else{
type=0;
}
}
$.get(`/${userName}/${repoPath}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=${type}&VersionName=${trainJob.VersionName}`, (data) => {
const n_length = data.length
let file_html=''
let firstFileName =''
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
break;
}
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
}
}
convertToNode(zNodes,nodesMap);
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
})
}
} }


function showcreate(obj) {
function convertToNode(nodeList,nodesMap){
var keyList = Object.keys(nodesMap);
keyList.sort(function(a,b){
return a-b;
});
var isFirst = true;
for(var i=0; i<keyList.length;i++){
var node = {};
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}
function showcreate(obj) {
$('.ui.modal.second') $('.ui.modal.second')
.modal({ .modal({
centered: false, centered: false,
@@ -619,11 +762,33 @@
// $('input[name="JobId"]').text(obj.JobName) // $('input[name="JobId"]').text(obj.JobName)
$('#JobName').val(obj.DisplayJobName).addClass('model_disabled') $('#JobName').val(obj.DisplayJobName).addClass('model_disabled')
$('input[name="JobId"]').val(obj.JobID) $('input[name="JobId"]').val(obj.JobID)
$('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled')
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
createModelName()
$('input[name="VersionName"]').val("V0001")
if(obj.ComputeResource=="NPU"){
if (obj.EngineName != null && obj.EngineName != "") {
srcEngine = obj.EngineName.split('-')[0]
srcEngine = srcEngine.trim().toLowerCase();
if (srcEngine == 'tensorflow') {
$('#choice_Engine .default.text').text("TensorFlow");
$('#choice_Engine input[name="Engine"]').val(1)
}
if (srcEngine == 'mindspore') {
$('#choice_Engine .default.text').text("MindSpore");
$('#choice_Engine input[name="Engine"]').val(1)
}
}
}else{
$('#choice_Engine .default.text').text("PyTorch");
$('#choice_Engine input[name="Engine"]').val(0)
}
$('#choice_Engine .default.text').css({ "color": "rgb(0, 0, 0,0.87)" })
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
createModelName();
loadSelectedModelFile(obj);
}, },
onHide: function () { onHide: function () {
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", "");
document.getElementById("formId").reset(); document.getElementById("formId").reset();
$('.ui.dimmer').css({ "background-color": "" }) $('.ui.dimmer').css({ "background-color": "" })
$('.ui.error.message').text() $('.ui.error.message').text()
@@ -641,6 +806,8 @@
type: 'POST', type: 'POST',
data: data, data: data,
success: function (res) { success: function (res) {
$('input[name="Engine_name"]').val("");
$('input[name="Engine"]').val("");
location.href = `/${userName}/${repoPath}/modelmanage/show_model` location.href = `/${userName}/${repoPath}/modelmanage/show_model`
$('.ui.modal.second').modal('hide') $('.ui.modal.second').modal('hide')
}, },
@@ -662,6 +829,48 @@
$('#name').val(modelName) $('#name').val(modelName)
$('#version').val("0.0.1") $('#version').val("0.0.1")
} }

$('.menu .item').tab()
$(document).ready(function () {
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } });
});
$(document).ready(function () {
$('.secondary.menu .item').tab();
});

let userName
let repoPath
let jobID
let downlaodFlag = {{ $.canDownload }}
$(document).ready(function () {
let url = window.location.href;
let urlArr = url.split('/')
userName = urlArr.slice(-5)[0]
repoPath = urlArr.slice(-4)[0]
jobID = urlArr.slice(-1)[0]
})
function stopBubbling(e) {
e = window.event || e;
if (e.stopPropagation) {
e.stopPropagation(); //阻止事件 冒泡传播
} else {
e.cancelBubble = true; //ie兼容
}
}

function renderSize(value) {
if (null == value || value == '') {
return "0 Bytes";
}
var unitArr = new Array("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB");
var index = 0;
var srcsize = parseFloat(value);
index = Math.floor(Math.log(srcsize) / Math.log(1024));
var size = srcsize / Math.pow(1024, index);
size = size.toFixed(0);//保留的小数位数
return size + unitArr[index];
}
function refreshStatus(version_name) { function refreshStatus(version_name) {
$.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}?version_name=${version_name}`, (data) => { $.get(`/api/v1/repos/${userName}/${repoPath}/grampus/train-job/${jobID}?version_name=${version_name}`, (data) => {
// header status and duration // header status and duration


+ 289
- 2
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -1,4 +1,5 @@
{{template "base/head" .}} {{template "base/head" .}}
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">
<style> <style>
.according-panel-heading { .according-panel-heading {
box-sizing: border-box; box-sizing: border-box;
@@ -200,6 +201,19 @@
padding-left: 1rem; padding-left: 1rem;
padding-top: 0.5rem; padding-top: 0.5rem;
} }
.menuContent{
position: absolute;
background: #ffffff;
left: 0;
right: 26px;
top: 36px;
z-index:999;
border: 1px solid #96c8da;
border-top: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%);
}
</style> </style>
<div id="mask"> <div id="mask">
<div id="loadingPage"> <div id="loadingPage">
@@ -565,6 +579,10 @@
</div> </div>
</div> </div>
</div> </div>
<!--
<div id="menuContent" class="menuContent" style="display:none; position: absolute;z-index:9999">
<ul id="treeDemo" class="ztree" style="margin-top:0; width: 83%; height: 100%;"></ul>
</div> -->
<!-- 创建模型 --> <!-- 创建模型 -->
<div id="newmodel"> <div id="newmodel">
<div class="ui modal second"> <div class="ui modal second">
@@ -605,6 +623,17 @@
<input type="hidden" id="Engine" name="Engine" required> <input type="hidden" id="Engine" name="Engine" required>
<input style="width: 45%;" id="Engine_name" name="Engine_name" readonly required maxlength="255"> <input style="width: 45%;" id="Engine_name" name="Engine_name" readonly required maxlength="255">
</div> </div>
<div class="unite min_title inline fields required">
<div class="field required">
<label for="modelSelectedFile">模型文件</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
<div id="menuContent" class="menuContent" style="display:none;">
<ul id="treeDemo" class="ztree"></ul>
</div>
</div>
</div>
<div class="inline field"> <div class="inline field">
<label>模型标签</label> <label>模型标签</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255" <input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255"
@@ -637,7 +666,124 @@
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}


<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script>
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script>

<script> <script>
var setting = {
check: {
enable: true,
chkboxType: {"Y":"ps", "N":"ps"}
},
view: {
dblClickExpand: false
},
callback: {
beforeClick: beforeClick,
onCheck: onCheck
}
};

function beforeClick(treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo");
zTree.checkNode(treeNode, !treeNode.checked, null, true);
return false;
}
function onCheck(e, treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo"),
nodes = zTree.getCheckedNodes(true),
v = "";
for (var i=0, l=nodes.length; i<l; i++) {
if(nodes[i].isParent){
continue;
}
var pathNodes = nodes[i].getPath();
var path ="";
for(var j=0;j<pathNodes.length;j++){
if(j ==0){
path += pathNodes[j].name;
}else{
path += "/" + pathNodes[j].name;
}
}
v += path + ";";
}
if (v.length > 0 ) v = v.substring(0, v.length-1);
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", v);
}
function showMenu() {
var cityObj = $("#modelSelectedFile");
var cityOffset = $("#modelSelectedFile").offset();
//$("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast");
$("#menuContent").slideDown("fast");
$("body").bind("mousedown", onBodyDown);
}
function hideMenu() {
$("#menuContent").fadeOut("fast");
$("body").unbind("mousedown", onBodyDown);
}
function onBodyDown(event) {
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) {
hideMenu();
}
}

function loadSelectedModelFile(trainJob){
console.log("trainJob=" + trainJob);
$('#choice_file').dropdown('clear')
$("#model-file").empty()
if(trainJob ==null || trainJob ==""){
console.log("trainJob is null");
}else{
$.get(`/${userName}/${repoPath}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=1&VersionName=${trainJob.VersionName}`, (data) => {
const n_length = data.length
let file_html=''
let firstFileName =''
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
break;
}
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
}
}
convertToNode(zNodes,nodesMap);
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
})
}
}

function convertToNode(nodeList,nodesMap){
var keyList = Object.keys(nodesMap);
keyList.sort(function(a,b){
return a-b;
});
var isFirst = true;
for(var i=0; i<keyList.length;i++){
var node = {};
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}

$('.menu .item').tab() $('.menu .item').tab()
$(document).ready(function () { $(document).ready(function () {
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); $('.ui.accordion').accordion({ selector: { trigger: '.icon' } });
@@ -676,7 +822,7 @@
$('#JobName').val(obj.DisplayJobName).addClass('model_disabled') $('#JobName').val(obj.DisplayJobName).addClass('model_disabled')
$('input[name="JobId"]').val(obj.JobID) $('input[name="JobId"]').val(obj.JobID)
$('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled') $('input[name="VersionName"]').val(obj.VersionName).addClass('model_disabled')
if(obj.EngineID ==122 || obj.EngineID ==35){
if(obj.EngineID ==122 || obj.EngineID ==35 || obj.EngineID ==-1){
$('input[name="Engine_name"]').val("MindSpore").addClass('model_disabled'); $('input[name="Engine_name"]').val("MindSpore").addClass('model_disabled');
$('input[name="Engine"]').val(2); $('input[name="Engine"]').val(2);
} }
@@ -685,9 +831,12 @@
$('input[name="Engine"]').val(1); $('input[name="Engine"]').val(1);
} }
$('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" }) $('.ui.dimmer').css({ "background-color": "rgb(136, 136, 136,0.7)" })
createModelName()
createModelName();
loadSelectedModelFile(obj);
}, },
onHide: function () { onHide: function () {
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", "");
document.getElementById("formId").reset(); document.getElementById("formId").reset();
$('.ui.dimmer').css({ "background-color": "" }) $('.ui.dimmer').css({ "background-color": "" })
$('.ui.error.message').text() $('.ui.error.message').text()
@@ -802,5 +951,143 @@
console.log(err); console.log(err);
}); });
} }
function debounce(fn, delay) {
let timer;
return (...args) => {
// 判断定时器是否存在,清除定时器
if (timer) {
clearTimeout(timer);
}

// 重新调用setTimeout
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
const fn = debounce(logScroll, 500)
function logScroll(version_name) {
let container = document.querySelector(`#log${version_name}`)
let scrollTop = container.scrollTop
let scrollHeight = container.scrollHeight
let clientHeight = container.clientHeight
let scrollLeft = container.scrollLeft
if (((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight + 1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight)) && parseInt(scrollTop) !== 0 && scrollLeft == 0) {
let end_line = $(`#log${version_name} input[name=end_line]`).val()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${end_line}&lines=50&order=desc`, (data) => {
if (data.Lines == 0) {
$(`.message${version_name} #header`).text('您已翻阅至日志底部')
$(`.message${version_name}`).css('display', 'block')
setTimeout(function () {
$(`.message${version_name}`).css('display', 'none')
}, 1000)
} else {
if (end_line === data.EndLine) {
return
}
else {
$(`#log${version_name} input[name=end_line]`).val(data.EndLine)
$(`#log${version_name}`).append('<pre>' + data.Content)
}

}
}).fail(function (err) {
console.log(err);
});
}
if ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].includes(scrollTop) && scrollLeft == 0) {
let start_line = $(`#log${version_name} input[name=start_line]`).val()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${start_line}&lines=50&order=asc`, (data) => {
if (data.Lines == 0) {
$(`.message${version_name} #header`).text('您已翻阅至日志顶部')
$(`.message${version_name}`).css('display', 'block')
setTimeout(function () {
$(`.message${version_name}`).css('display', 'none')
}, 1000)
} else {
$(`#log${version_name} input[name=start_line]`).val(data.StartLine) //如果变动就改变所对应的值
$(`#log${version_name}`).prepend('<pre>' + data.Content)
}
}).fail(function (err) {
console.log(err);
});
}
}
function scrollAnimation(dom, currentY, targetY, currentX) {
let needScrollTop = targetY - currentY;
let _currentY = currentY;
setTimeout(() => {
// 一次调用滑动帧数,每次调用会不一样
//取总距离的十分之一
const dist = Math.ceil(needScrollTop / 10);
_currentY += dist;
//移动一个十分之一
dom.scrollTo(currentX || 0, _currentY, 'smooth');
// 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果
if (needScrollTop > 10 || needScrollTop < -10) {
scrollAnimation(dom, _currentY, targetY)
} else {
dom.scrollTo(0, targetY, 'smooth')
}
}, 1)
}

$('.log_top').click(function () {
// let logContentDom = document.querySelector('.log')
// if(!logContentDom)
// return
// let version_name = $('.log_top').data('version')
let version_name = $(this).data('version')
let logContentDom = document.querySelector(`#log${version_name}`)

$(`#log_file${version_name}`).siblings('pre').remove()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=asc`, (data) => {

$(`#log${version_name} input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值
$(`#log${version_name} input[name=start_line]`).val(data.StartLine)
$(`#log${version_name}`).prepend('<pre>' + data.Content)
$(`.message${version_name} #header`).text('您已翻阅至日志顶部')
$(`.message${version_name}`).css('display', 'block')
setTimeout(function () {
$(`.message${version_name}`).css('display', 'none')
}, 1000)
scrollAnimation(logContentDom, logContentDom.scrollTop, 0);
})

})
$('.log_bottom').click(function (e) {
let version_name = $(this).data('version')
let logContentDom = document.querySelector(`#log${version_name}`)
$(`#log_file${version_name}`).siblings('pre').remove()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=&lines=50&order=desc`, (data) => {

$(`#log${version_name} input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值
$(`#log${version_name} input[name=start_line]`).val(data.StartLine)
$(`#log${version_name}`).append('<pre>' + data.Content)
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/log?version_name=${version_name}&base_line=${data.EndLine}&lines=50&order=desc`, (data) => {
if (data.Lines == 0) {
$(`.message${version_name} #header`).text('您已翻阅至日志底部')
$(`.message${version_name}`).css('display', 'block')
setTimeout(function () {
$(`.message${version_name}`).css('display', 'none')
}, 1000)
} else {
if (end_line === data.EndLine) {
return
}
else {
$(`#log${version_name} input[name=end_line]`).val(data.EndLine)
$(`#log${version_name}`).append('<pre>' + data.Content)
}

}
}).fail(function (err) {
console.log(err);
});
scrollAnimation(logContentDom, logContentDom.scrollTop + 1, logContentDom.scrollHeight - logContentDom.clientHeight);
})
})


</script> </script>

+ 586
- 0
templates/repo/modelmanage/convertIndex.tmpl View File

@@ -0,0 +1,586 @@
<!-- 头部导航栏 -->
{{template "base/head" .}}
<!-- 弹窗 -->
<style>
.inline.fields .right.aligned label{
width: 100% !important;
text-align: right;
}
.inline .ui.dropdown .text {
color: rgba(0, 0, 0, .87) !important;
left: 15px !important;
}
.text_color {
color: rgb(0 0 0 / 87%);
}
</style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
{{$repository := .Repository.ID}}
<!-- 提示框 -->
<div class="alert"></div>

<div class="repository release dataset-list view">
{{template "repo/header" .}}
<!-- 列表容器 -->
<div class="ui container" id="loadContainer">
{{template "base/alert" .}}
<div class="ui two column stackable grid">
<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="item" href="{{.RepoLink}}/modelmanage/show_model">{{$.i18n.Tr "repo.model.list"}}</a>
<a class="active item" href="{{.RepoLink}}/modelmanage/convert_model">{{$.i18n.Tr "repo.model.convert"}}</a>
</div>
</div>
<div class="column right aligned">
<!-- -->
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" onclick="showcreate(this)">{{$.i18n.Tr "repo.model.manage.create_new_convert_task"}}</a>
</div>
</div>
{{if eq .MODEL_CONVERT_COUNT 0}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过模型转换任务</div>
<div class="bgtask-content">
{{if eq .MODEL_COUNT 0}}
<div class="bgtask-content-txt">请您先导入<a href="{{.RepoLink}}/modelmanage/show_model">模型</a>,然后再对其进行转换。</div>
{{end}}
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a
href="https://git.openi.org.cn/zeizei/OpenI_Learning">小白训练营课程。</a></div>

</div>
</div>
{{else}}
<!-- 中下列表展示区 -->
<div class="ui grid">
<div class="row" style="padding-top: 0;">
<div class="ui sixteen wide column">
<!-- 任务展示 -->
<div class="dataset list" id="model_convert_list">
<!-- 表头 -->
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="row">
<div class="three wide column padding0">
<span style="margin:0 6px">任务名称</span>
</div>
<div class="two wide column text center padding0">
<span>状态</span>
</div>
<div class="two wide column text center padding0">
<span>原模型框架</span>
</div>
<div class="two wide column text center padding0">
<span>转换后格式</span>
</div>
<div class="two wide column text center padding0">
<span>创建时间</span>
</div>
<div class="one wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span>
</div>
<div class="three wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span>
</div>
</div>
</div>
{{range .Tasks}}
<div class="ui grid stackable item">
<div class="row">
<div class="three wide column padding0">
<a class="title" href="{{$.RepoLink}}/modelmanage/show_model_convert_info?ID={{.ID}}" title="{{.Name}}" style="font-size: 14px;">
<span class="fitted" style="width: 90%;vertical-align: middle;">{{.Name}}</span>
</a>
</div>
<div class="two wide column padding0" style="padding-left: 2.2rem !important;">
<span class="job-status" id="{{.ID}}" data-repopath="{{$.RepoRelPath}}/modelmanage" data-jobid="{{.ID}}" data-version="">
<span><i id="{{.ID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.ID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
</div>
<div class="two wide column center padding0">
<span style="font-size: 12px;">{{if eq .SrcEngine 0}}PyTorch {{else if eq .SrcEngine 1}}TensorFlow{{else if eq .SrcEngine 2}}MindSpore {{end}}</span>
</div>
<div class="two wide column center padding0">
<span style="font-size: 12px;">{{if eq .DestFormat 0}}ONNX {{else if eq .DestFormat 1}}TensorRT {{end}}</span>
</div>
<div class="two wide column center padding0">
<span style="font-size: 12px;" class="">{{TimeSinceUnix .CreatedUnix $.Lang}}</span>
</div>
<div class="one wide column text center padding0">
<a href="{{AppSubUrl}}/{{.UserName}}" title="{{.UserName}}"><img class="ui avatar image" src="{{.UserRelAvatarLink}}"></a>
</div>
<div class="three wide column text center padding0">
<div class="ui compact buttons" >
<!-- 停止任务 -->
<form id="stopForm-{{.ID}}" style="margin-left:-1px;" action="{{$.RepoLink}}/modelmanage/convert_stop/{{.ID}}" method="post">
{{$.CsrfTokenHtml}}
{{if .IsCanDelete}}
<a id="ai-stop-{{.ID}}" href="javascript:stopTask('{{.ID}}');" class='ui basic model_stop {{if eq .Status "COMPLETED" "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' >
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a class="ui basic disabled button">{{$.i18n.Tr "repo.stop"}} </a>
{{end}}
</form>
<!-- 删除任务 -->
<form id="delForm-{{.ID}}" action="{{$.RepoLink}}/modelmanage/delete_model_convert/{{.ID}}" method="post">
{{$.CsrfTokenHtml}}
{{if .IsCanDelete}}
<a id="ai-delete-{{.ID}}" class='ui basic ai_delete blue button' style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{else}}
<a class="ui basic disabled button">{{$.i18n.Tr "repo.delete"}} </a>
{{end}}
</form>

{{if .IsCanOper}}
<a id="ai-download-{{.ID}}" href="{{$.Repository.HTMLURL}}/modelmanage/download_model_convert/{{.ID}}?AllDownload=true&a=1" class='ui basic {{if eq .Status "SUCCEEDED" "COMPLETED"}}blue {{else}}disabled {{end}}button' style="border-radius: .28571429rem;">
下载
</a>
{{else}}
<a class="ui basic disabled button">下载</a>
{{end}}
</div>
</div>
</div>
</div>
{{end}}
<div id="app" style="margin-top: 2rem;">
<div class="center">
<el-pagination
background
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[10]"
:page-size="10"
layout="total, sizes, prev, pager, next, jumper"
:total="{{.Page.Paginater.Total}}">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
{{end}}
</div>

</div>

</div>

<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal first">
<div class="ui icon header">
<i class="trash icon"></i> 删除模型
</div>

<div class="content">
<p>你确认删除该模型转换任务么?一旦删除不可恢复。</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}}
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}}
</div>
</div>
</div>
</div>
<div id="newmodelconvert">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4 id="model_header"></h4>
</div>
<div class="content content-padding">
<div id="formdiv" class="ui form" >
<input type="hidden" name="initModel" value="{{$.MODEL_COUNT}}">
<div class="ui error message">
<!-- <p>asdasdasd</p> -->
</div>
<input type="hidden" name="_csrf" value="">
<div class="unite min_title required inline fields" id="task_name">
<div class="three wide field right aligned">
<label for="model_convert_name">任务名称</label>
</div>
<div class="twelve wide field">
<input id="model_convert_name" name="model_convert_name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="choice_model">模型名称</label>
</div>
<div class="ui dropdown selection search eight wide field loading" id="choice_model" name="choice_model">
<div class="default text">选择模型</div>
<i class="dropdown icon"></i>
<div class="menu" id="model-name">
</div>
</div>
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="choice_version">模型版本</label>
</div>
<div class="ui dropdown selection search eight wide field" id="choice_version">
<input type="hidden" id="ModelVersion" name="ModelVersion" required>
<div class="default text">选择版本</div>
<i class="dropdown icon"></i>
<div class="menu" id="model-version">

</div>
</div>
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="choice_file">模型文件</label>
</div>
<div class="ui dropdown selection search eight wide field" id="choice_file">
<input type="hidden" id="ModelFile" name="ModelFile" required>
<div class="default text">选择模型文件</div>
<i class="dropdown icon"></i>
<div class="menu" id="model-file">

</div>
</div>
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="SrcEngine">原模型框架</label>
</div>
<select id="SrcEngine" class="ui search dropdown eight wide field" placeholder="" style='color:#000000;' name="SrcEngine" onchange="javascript:srcEngineChanged()">
</select>
</div>
<div class="unite min_title required inline fields" id="inputdataformat_div">
<div class="three wide field right aligned">
<label for="inputdataformat">输入数据格式</label>
</div>
<select id="inputdataformat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="inputdataformat">
<option name="NCHW" value="NCHW">NCHW</option>
<option name="NHWC" value="NHWC">NHWC</option>
</select>
</div>
<div class="unite min_title required inline fields" id="inputshape_div">
<div class="three wide field right aligned">
<label for="inputshape">输入张量形状</label>
</div>
<div class="eight wide field">
<input id="inputshape" name="inputshape" placeholder="如:1,1,32,32,与输入数据格式对应。" required maxlength="25">
</div>
</div>
<div class="unite min_title inline fields required">
<div class="three wide field right aligned">
<label for="DestFormat">转换后格式</label>
</div>
<select id="DestFormat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="DestFormat">
</select>
</div>
<div class="unite min_title inline fields">
<div class="three wide field right aligned">
<label for="NetOutputFormat">网络输出数据类型&nbsp;&nbsp;</label>
</div>
<select id="NetOutputFormat" class="ui search dropdown eight wide field" placeholder="" style='width:50%' name="NetOutputFormat">

</select>
</div>
<div class="unite min_title inline fields">
<div class="three wide field right aligned">
<label for="Description">任务描述&nbsp;&nbsp;</label>
</div>
<div class="twelve wide field">
<textarea id="Description" name="Description" rows="1" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea>
</div>
</div>
<div class="unite min_title inline field">
<button id="submitId" name="submitId" type="button" class="ui create_train_job green button" style="position: absolute;margin-left: 150px;">
新建任务
</button>
</div>
</div>
<div class="actions" style="display: inline-block;margin-left: 250px;">
<button class="ui button cancel" >{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div>
</div>
</div>

</div>


{{template "base/footer" .}}

<script>
let repolink = {{.RepoLink}}
let repoId = {{$repository}}
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config;
$('input[name="_csrf"]').val(csrf)
var modelData;

function inputshapeNotValid(value){
if(value == null || value ==""){
return true;
}
var tmps = value.split(",");
if(tmps.length ==4){
return false;
}else{
return true;
}
}

$('#submitId').click(function(){
let data={};
data['_csrf']=csrf
data['name']= $('#model_convert_name').val()

if(data['name']==""){
$('.ui.error.message').text("请输入任务名称。")
$('.ui.error.message').css('display','block')
$("#task_name").addClass("error")
return false
}else{
$("#task_name").removeClass("error")
}

data['desc']= $('#Description').val()
data['modelId'] = $('#ModelVersion').val()
data['SrcEngine'] = $('#SrcEngine').val();
data['inputshape']= $('#inputshape').val();

if(inputshapeNotValid(data['inputshape'])){
$('.ui.error.message').text("格式输入错误,请输入如:1,1,32,32,与输入数据格式对应。")
$('.ui.error.message').css('display','block')
$("#inputshape_div").addClass("error")
return false
}else{
$("#inputshape_div").removeClass("error")
}

data['inputdataformat']= $('#inputdataformat').val();
data['DestFormat'] = $('#DestFormat').val();
data['NetOutputFormat']= $('#NetOutputFormat').val();
data['ModelFile'] = $('#ModelFile').val();

$.post(`${repolink}/modelmanage/create_model_convert`,data,(result) => {
console.log("result=" + result);
if(result.result_code ==0){
$('.ui.modal.second').modal('hide');
window.location.reload();
}else{
$('.ui.error.message').text(result.message)
$('.ui.error.message').css('display','block')
}
})
})

function stopTask(id){
console.log("stop form stopForm-" + id);
document.getElementById("stopForm-" + id).submit();
}

function createModelName(){
let repoName = location.pathname.split('/')[2]
let modelName = repoName + '_modelConvert_' + Math.random().toString(36).substr(2, 4)
$('#model_convert_name').val(modelName)
}
function showcreate(obj){
$('.ui.modal.second')
.modal({
centered: false,
onShow:function(){
$('#model_header').text("创建模型转换任务")
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
createModelName()
loadModelList()
},
onHide:function(){
//document.getElementById("formId").reset();
$('#model_convert_name').val("")
$('#choice_model').dropdown('clear')
$('#choice_version').dropdown('clear')
$('#choice_file').dropdown('clear')
console.log("div hidde ....");
$('.ui.dimmer').css({"background-color":""})
$('.ui.error.message').text()
$('.ui.error.message').css('display','none')
$("#task_name").removeClass("error")
$("#inputshape_div").removeClass("error")
}
})
.modal('show')
}

$(function(){
$('#choice_model').dropdown({
onChange:function(value){
$("#choice_model").addClass("loading")
$('#choice_version').dropdown('clear')
$('#choice_file').dropdown('clear')
$("#model-version").empty()
$("#model-file").empty()
loadModelVersion(value)
$("#choice_model").removeClass("loading")
}
})

$('#choice_version').dropdown({
onChange:function(value){
console.log("model version:" + value);
$('#choice_version input[name="ModelVersion"]').val(value)
loadModelFile(value);
}
})

$('#choice_file').dropdown({
onChange:function(value){
console.log("model file:" + value);
$('#choice_file input[name="ModelFile"]').val(value)
}
})

})

function srcEngineChanged(){
var ele = window.document.getElementById("SrcEngine");
var index=ele.selectedIndex;
var options=ele.options;
var option = options[index];
console.log("SrcEngine value=" + option);
let destFormatHtml = "<option name=\"ONNX\" value=\"0\">ONNX</option>";
let netOutputFormatHtml = "<option name=\"FP32\" value=\"0\">FP32</option>";
if(option==null || option =="undefined" || option.value == 0){
destFormatHtml += "<option name=\"TensorRT\" value=\"1\">TensorRT</option>"
netOutputFormatHtml += "<option name=\"FP16\" value=\"1\">FP16</option>";
}
$('#DestFormat').html(destFormatHtml);
$('#NetOutputFormat').html(netOutputFormatHtml);
}
function loadModelList(){
$.get(`${repolink}/modelmanage/query_model_for_predict?repoId=${repoId}`, (data) => {
modelData = data
let nameList = data.nameList
const n_length = nameList.length
let train_html=''
for (let i=0;i<n_length;i++){
train_html += `<div class="item" data-value="${nameList[i]}">${nameList[i]}</div>`
train_html += '</div>'
}
$("#model-name").append(train_html)
$("#choice_model").removeClass("loading")
$('#choice_model .default.text').text(nameList[0])
loadModelVersion(nameList[0])
})
}
function loadModelFile(modelId){
console.log("modelId=" + modelId);
$('#choice_file').dropdown('clear')
$("#model-file").empty()
if(modelId ==null || modelId ==""){
console.log("modelId is null");
}else{
$.get(`${repolink}/modelmanage/query_modelfile_for_predict?ID=${modelId}`, (data) => {
const n_length = data.length
let file_html=''
let firstFileName =''
for (let i=0;i<n_length;i++){
if(isModel(data[i].FileName)){
if(firstFileName ==''){
firstFileName = data[i].FileName;
}
file_html += `<div class="item" data-value="${data[i].FileName}">${data[i].FileName}</div>`
file_html += '</div>'
}else{
console.log("not model. filename=" + data[i].FileName);
}
}
$("#model-file").append(file_html)
$('#choice_file .default.text').text(firstFileName)
$('#choice_file input[name="ModelFile"]').val(firstFileName)
})

}
}
function isModel(filename){
var postfix=[".pth",".pkl",".onnx",".mindir",".ckpt",".pb"];
for(var i =0; i<postfix.length;i++){
if(filename.substring(filename.length-postfix[i].length)==postfix[i]){
return true;
}
}
return false;
}
function loadModelVersion(value){
console.log("value=" + value);
if(value ==null || value ==""){
}else{
let nameMap = modelData.nameMap
let versionList = nameMap[value]
n_length = versionList.length
let train_html=''
for (let i=0;i<n_length;i++){
train_html += `<div class="item" data-value="${versionList[i].ID}">${versionList[i].Version}</div>`
train_html += '</div>'
}
$("#model-version").append(train_html)
$('#choice_version .default.text').text(versionList[0].Version)
$('#choice_version input[name="ModelVersion"]').val(versionList[0].ID)
loadModelFile(versionList[0].ID);
}
setEngineValue(value);
}
function setEngineValue(value){
$('#SrcEngine').dropdown('clear');
console.log("setEngineValue value=" + value);
let html = ""
html +="<option name=\"PyTorch\" " + getSelected(0,value) + " value=\"0\">PyTorch</option>";
html +="<option name=\"TensorFlow\" " + getSelected(1,value) + " value=\"1\">TensorFlow</option>";
html +="<option name=\"MindSpore\" " + getSelected(2,value) + " value=\"2\">MindSpore</option>";
$('#SrcEngine').html(html);
srcEngineChanged();
}
function getSelected(engineOption, modelName){
if(modelName ==null || modelName ==""){
return "";
}
let nameMap = modelData.nameMap
let versionList = nameMap[modelName]
if(versionList != null && versionList.length >0){
if(versionList[0].Engine == engineOption){
return "selected=\"selected\"";
}else{
if(versionList[0].Engine==122 && engineOption==2){
return "selected=\"selected\"";
}
if(versionList[0].Engine==121 && engineOption==1){
return "selected=\"selected\"";
}
}
}
return "";
}
</script>


+ 854
- 0
templates/repo/modelmanage/convertshowinfo.tmpl View File

@@ -0,0 +1,854 @@
{{template "base/head" .}}
<style>
.according-panel-heading{
box-sizing: border-box;
padding: 8px 16px;
color: #252b3a;
background-color: #f2f5fc;
line-height: 1.5;
cursor: pointer;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
}
.accordion-panel-title {
margin-top: 0;
margin-bottom: 0;
color: #252b3a;
}
.accordion-panel-title-content{
vertical-align: middle;
display: inline-block;
width: calc(100% - 32px);
cursor: default;
}
.acc-margin-bottom {
margin-bottom: 5px;
}
.title_text {
font-size: 12px;
}
.ac-display-inblock {
display: inline-block;
}
.cti-mgRight-sm {
margin-right: 8px;
}
.ac-text-normal {
font-size: 14px;
color: #575d6c;
}
.uc-accordionTitle-black {
color: #333;
}
.accordion-border{
border:1px solid #cce2ff;
}
.padding0{
padding: 0 !important;
}
.content-pad{
padding: 15px 35px;
}
.content-margin{
margin:10px 5px ;
}
.tab_2_content {
min-height: 360px;
margin-left: 10px;
}
.ac-grid {
display: block;
*zoom: 1;
}
.ac-grid-col {
float: left;
width: 100%;
}
.ac-grid-col2 .ac-grid-col {
width: 50%;
}
.ti-form {
text-align: left;
max-width: 100%;
vertical-align: middle;
}
.ti-form>tbody {
font-size: 12px;
}
.ti-form>tbody, .ti-form>tbody>tr {
vertical-align: inherit;
}
.ti-text-form-label {
padding-bottom: 20px;
padding-right: 20px;
color: #8a8e99;
font-size: 12px;
white-space: nowrap !important;
width: 80px;
line-height: 30px;
}
.ti-text-form-content{
line-height: 30px;
padding-bottom: 20px;
}
.ti-form>tbody>tr>td {
vertical-align: top;
white-space: normal;
}
td, th {
padding: 0;
}
.info_text {
padding-bottom: 20px;
padding-right: 20px;
font-size: 12px;
}
.ac-grid-col .text-span {
width: 450px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.redo-color{
color: #3291F8;
}
.ti-action-menu-item:not(:last-child){
margin-right: 10px;
padding-right: 11px;
text-decoration: none!important;
color: #526ecc;
cursor: pointer;
display: inline-block;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
-khtml-user-select: none;
user-select: none;
position: relative;
}
.ti-action-menu-item:not(:last-child):after {
content: "";
display: inline-block;
position: absolute;
height: 12px;
right: 0;
top: 50%;
-webkit-transform: translateY(-6px);
-ms-transform: translateY(-6px);
-o-transform: translateY(-6px);
transform: translateY(-6px);
border-right: 1px solid #dfe1e6;
}
.text-width80{
width: 100px;
line-height: 30px;
}
.border-according-model{
border: 1px solid #dfe1e6;
}
.disabled {
cursor: default;
pointer-events: none;
color: rgba(0,0,0,.6) !important;
opacity: .45 !important;
}
.pad20{
border:0px !important;
}
.model_file_bread{
margin-bottom: -0.5rem !important;
padding-left: 1rem;
padding-top: 0.5rem ;
}
</style>
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<div class="repository">
{{template "repo/header" .}}
<div class="ui container">
<h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb">
<a class="section" href="{{$.RepoLink}}/modelmanage/convert_model">
模型转换任务
</a>
<div class="divider"> / </div>
<div class="active section">{{.Name}}</div>
</div>
</h4>
{{with .task}}
<div class="ui accordion border-according-model" id="accordion" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.CloudBrainTaskId}}" data-version="1">
<input type="hidden" id="jobId_input" name="jobId_input" value="{{.CloudBrainTaskId}}">
<div class="active title padding0">
<div class="according-panel-heading">
<div class="accordion-panel-title">
<i class="dropdown icon"></i>
<span class="accordion-panel-title-content">
<span>
<div class="ac-display-inblock title_text acc-margin-bottom">
<span class="cti-mgRight-sm">{{TimeSinceUnix1 .CreatedUnix}}</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}:
<span id="status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span>
<span class="cti-mgRight-sm uc-accordionTitle-black" id="duration-span">{{.TrainJobDuration}}</span>
</div>
</span>
</span>
</div>
</div>
</div>
<div class="active content">
<div class="content-pad">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a id="gpuruntimeinfo" style="display: {{$.gpu_display}};" class="item" data-tab="second" onclick="javascript:parseInfo()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a>
<a id="gpulog" style="display: {{$.gpu_display}};" class="item" data-tab="third" onclick="loadLog()">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a id="npulog" style="display: {{$.npu_display}};" class="item log_bottom" data-tab="five" data-version="">{{$.i18n.Tr "repo.modelarts.log"}}</a>
<a class="item" data-tab="four" onclick="loadModelFile()">{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first">
<div style="padding-top: 10px;">
<div class="tab_2_content">
<div class="ac-grid ac-grid-col2">
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.cloudbrain_task"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.Name}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.status"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="status">
{{.Status}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
输入张量形状
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="InputShape">
{{.InputShape}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
输入数据格式
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="InputDataFormat">
{{.InputDataFormat}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.start_time"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w">
<span style="font-size: 12px;" class="">{{TimeSinceUnix1 .CreatedUnix}}</span>
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="duration">
{{.TrainJobDuration}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
网络输出数据类型
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" id="duration">
{{if eq .NetOutputFormat 0}}FP32 {{else if eq .NetOutputFormat 1}}FP16 {{end}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="ac-grid-col">
<table class="ti-form">
<tbody class="ti-text-form">
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
模型名称
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.ModelName}}
</div>
</td>
</tr>


<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
模型版本
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.ModelVersion}}
</div>
</td>
</tr>


<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
模型文件
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{.ModelPath}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
原模型框架
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{if eq .SrcEngine 0}}PyTorch {{else if eq .SrcEngine 1}}Tensorflow{{else if eq .SrcEngine 2}}MindSpore {{end}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
转换后格式
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w">
{{if eq .DestFormat 0}}ONNX {{else if eq .DestFormat 1}}TensorRT {{end}}
</div>
</td>
</tr>
<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.modelarts.train_job.description"}}
</td>
<td class="ti-text-form-content">
<div class="text-span text-span-w" title="{{.Description}}">
{{.Description}}
</div>
</td>
</tr>

<tr class="ti-no-ng-animate">
<td class="ti-no-ng-animate ti-text-form-label text-width80">
{{$.i18n.Tr "repo.cloudbrain_creator"}}
</td>

<td class="ti-text-form-content">
<div class="text-span text-span-w" id="username">
{{.UserName}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>

<div class="ui tab" data-tab="second">
<div>
<div class="ui message message" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log" id="log" style="height: 390px !important; overflow: auto;">
<input type="hidden" id="json_value" value="{{$.AppExitDiagnostics}}">
<input type="hidden" id="ExitDiagnostics" value="{{$.ExitDiagnostics}}">
<span id="info_display" class="info_text">
</span>
</div>

</div>

</div>

<div class="ui tab" data-tab="third">
<div>
<div class="ui message message" style="display: none;">
<div id="header"></div>
</div>
<div class="ui attached log" id="log" style="height: 300px !important; overflow: auto;">
<input type="hidden" name="end_line">
<input type="hidden" name="start_line">
<pre id="log_file"></pre>
</div>
</div>
</div>

<div class="ui tab" data-tab="five">
<div style="position: relative;">
<span>
<a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;" class="log_top" data-version="V0001"><i class="icon-to-top"></i></a>
</span>
<span>
<a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;" class="log_bottom" data-version="V0001"><i class="icon-to-bottom"></i></a>
</span>
<div id="log_npu_message" class="ui message message" style="display: none;">
<div id="log_npu_header"></div>
</div>
<div class="ui attached log" onscroll="fn()" id="log_npu" style="height: 300px !important; overflow: auto;">
<input type="hidden" name="end_line" value>
<input type="hidden" name="start_line" value>
<pre id="log_file_npu"></pre>
</div>
</div>
</div>

<div class="ui tab" data-tab="four">
<input type="hidden" name="model" value="-1">
<input type="hidden" name="modelback" value="-1">
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb'>
<div class="active section"></div>
<div class="divider"> / </div>

</div>
<div id="dir_list">
</div>
</div>

</div>
</div>
</div>
{{end}} {{template "base/paginate" .}}
</div>
<!-- 确认模态框 -->
</div>
{{template "base/footer" .}}

<script>
$('.menu .item').tab()

$(document).ready(function(){
$('.ui.accordion').accordion({selector:{trigger:'.icon'}});
});
$(document).ready(function(){
$('.secondary.menu .item').tab();
});
let userName
let repoPath
let jobID = {{$.task.CloudBrainTaskId}}
let downlaodFlag = {{$.canDownload}}
let taskID = {{$.task.ID}}
let realJobName = {{$.task.ID}}
$(document).ready(function(){
let url = window.location.href;
let urlArr = url.split('/')
userName = urlArr.slice(-4)[0]
repoPath = urlArr.slice(-3)[0]
console.log("userName=" + userName + " repoPath=" + repoPath);
})
function stopBubbling(e) {
e = window.event || e;
if (e.stopPropagation) {
e.stopPropagation(); //阻止事件 冒泡传播
} else {
e.cancelBubble = true; //ie兼容
}
}
let timeid = window.setInterval(loadJobStatus, 30000);
$(document).ready(loadJobStatus);

function loadLog(version_name){
document.getElementById("mask").style.display = "block"
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/log?version_name=${version_name}&lines=50&order=asc`, (data) => {
$('input[name=end_line]').val(data.EndLine)
$('input[name=start_line]').val(data.StartLine)
$(`#log_file`).text(data.Content)
document.getElementById("mask").style.display = "none"
}).fail(function(err) {
console.log(err);
document.getElementById("mask").style.display = "none"
});
}
function loadModelFile(version_name,parents,filename,init){
parents = parents || ''
filename = filename || ''
init = init || ''
console.log("start")
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/model_list?version_name=${version_name}&parentDir=${parents}`, (data) => {
$(`#dir_list`).empty()
renderDir(data,version_name)
if(init==="init"){
$(`input[name=model]`).val("")
$(`input[name=modelback]`).val(version_name)
$(`#file_breadcrumb`).empty()
let htmlBread = "/"
$(`#file_breadcrumb`).append(htmlBread)
}else{
renderBrend(version_name,parents,filename,init)
}
}).fail(function(err) {
console.log(err,version_name);
});
}
function renderBrend(version_name,parents,filename,init){
if(init=="folder"){
let htmlBrend = ""
let sectionName=$(`#file_breadcrumb .active.section`).text()
let parents1 = $(`input[name=model]`).val()
let filename1 = $(`input[name=modelback]`).val()
if(parents1===""){
$(`#file_breadcrumb .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','','init')">${sectionName}</a>`)
}else{
$(`#file_breadcrumb .active.section`).replaceWith(`<a class='section' onclick="loadModelFile('${version_name}','${parents1}','${filename1}')">${sectionName}</a>`)
}
htmlBrend += `<div class='active section'>${filename}</div>`
htmlBrend += "<div class='divider'> / </div>"
$(`#file_breadcrumb`).append(htmlBrend)
$(`input[name=model]`).val(parents)
$(`input[name=modelback]`).val(filename)
}else{
$(`input[name=model]`).val(parents)
$(`input[name=modelback]`).val(filename)
$(`#file_breadcrumb a.section:contains(${filename})`).nextAll().remove()
$(`#file_breadcrumb a.section:contains(${filename})`).replaceWith(`<div class='active section'>${filename}</div>`)
//$(`#file_breadcrumb div.section:contains(${filename})`).append("<div class='divider'> / </div>")
}
}
function renderDir(data,version_name){
let html=""
html += "<div class='ui grid' style='margin:0;'>"
html += "<div class='row' style='padding: 0;'>"
html += "<div class='ui sixteen wide column' style='padding:1rem;'>"
html += "<div class='dir list'>"
html += "<table id='repo-files-table' class='ui single line table pad20'>"
html += '<tbody>'
for(let i=0;i<data.Dirs.length;i++){
let dirs_size = renderSize(data.Dirs[i].Size)
html += "<tr>"
html += "<td class='name six wid'>"
html += "<span class='truncate'>"
html += "<span class='octicon octicon-file-directory'>"
html += "</span>"
if(data.Dirs[i].IsDir){
html += `<a onclick="loadModelFile('${version_name}','${data.Dirs[i].ParenDir}','${data.Dirs[i].FileName}','folder')">`
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>"
}else{
if(downlaodFlag){
html += `<a href="/${userName}/${repoPath}/modelmanage/download_model_convert/${taskID}?fileName=${data.Dirs[i].FileName}&parentDir=${data.Dirs[i].ParenDir}&jobName=${realJobName}">`
}
else{
html += `<a class="disabled">`
}
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data.Dirs[i].FileName + "</span>"
}
html += '</a>'
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
if(data.Dirs[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>"

html += "<td class='text right age three wide'>"
html += "<span class='truncate has-emoji'>" + data.Dirs[i].ModTime + "</span>"
html += "</td>"
html += "</tr>"
}
html += "</tbody>"
html += "</table>"
html += "</div>"
html += "</div>"
html += "</div>"
html += "</div>"
$(`#dir_list`).append(html)
}
function renderSize(value){
if(null==value||value==''){
return "0 Bytes";
}
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
var index=0;
var srcsize = parseFloat(value);
index=Math.floor(Math.log(srcsize)/Math.log(1024));
var size =srcsize/Math.pow(1024,index);
size=size.toFixed(0);//保留的小数位数
return size+unitArr[index];
}

function loadJobStatus() {
$(".ui.accordion.border-according-model").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const versionname = job.dataset.version

let status = $(`#status-span`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED','SUCCEEDED','STOPPED'].includes(status)){
return
}
let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED","SUCCEEDED","STOPPED"]
$.get(`/api/v1/repos/${repoPath}/modelmanage/${taskID}?version_name=${versionname}`, (data) => {
$(`#status-span span`).text(data.JobStatus)
$(`#status-span i`).attr("class",data.JobStatus)
$('#status').text(data.JobStatus)
}).fail(function(err) {
console.log(err);
});
});
};

function parseInfo(){
let jsonValue = document.getElementById("json_value").value;
let jsonObj = JSON.parse(jsonValue);
let podRoleName = jsonObj["podRoleName"];
let html = "";
if (podRoleName != null){
let task0 = podRoleName["task1-0"];
let podEvents = jsonObj["podEvents"];
let podEventArray = podEvents[task0];
if(podEventArray != null){
for(var i=0; i < podEventArray.length;i++){
if (podEventArray[i]["reason"]!="") {
html +="<p><b>[" +podEventArray[i]["reason"] + "]</b></p>";
html +="<p>" +podEventArray[i]["message"] + "</p>";
html +="<p>" +podEventArray[i]["action"] + "</p>";
}
}
}
let extras= jsonObj["extras"];
if(extras != null){
for(var i=0; i < extras.length;i++){
if (extras[i]["reason"]!="") {
html +="<p><b>[" +extras[i]["reason"] + "]</b></p>";
html +="<p>" +extras[i]["message"] + "</p>";
html +="<p>" +extras[i]["action"] + "</p>";
}
}
}
}

let string = document.getElementById("ExitDiagnostics").value;
string = string.replace(/\r\n/g,"<br>")
string = string.replace(/\n/g,"<br>");
string = string.replace(/(\r\n)|(\n)/g,'<br>');

if (string!=""){
html +="<p><b>[ExitDiagnostics]</b></p>";
html +="<p>" +string + "</p>";
}
document.getElementById("info_display").innerHTML=html;
}
function debounce(fn,delay){
let timer;
return (...args) => {
// 判断定时器是否存在,清除定时器
if (timer) {
clearTimeout(timer);
}

// 重新调用setTimeout
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
const fn = debounce(logScroll, 500)
function logScroll(version_name) {
let container = document.querySelector(`#log_npu`)
let scrollTop = container.scrollTop
let scrollHeight = container.scrollHeight
let clientHeight = container.clientHeight
let scrollLeft = container.scrollLeft
if(((parseInt(scrollTop) + clientHeight == scrollHeight || parseInt(scrollTop) + clientHeight +1 == scrollHeight || parseInt(scrollTop) + clientHeight - 1 == scrollHeight)) && parseInt(scrollTop)!==0 && scrollLeft==0){
let end_line = $(`#log_npu input[name=end_line]`).val()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=${end_line}&lines=50&order=desc`, (data) => {
if (data.Lines == 0){
$(`#log_npu_header`).text('您已翻阅至日志底部')
$(`#log_npu_message`).css('display', 'block')
setTimeout(function(){
$(`#log_npu_message`).css('display', 'none')
}, 1000)
}else{
if(end_line===data.EndLine){
return
}
else{
$(`#log_npu input[name=end_line]`).val(data.EndLine)
$(`#log_npu`).append('<pre>' + data.Content)
}

}
}).fail(function(err) {
console.log(err);
});
}
if([0,1,2,3,4,5,6,7,8,9,10].includes(scrollTop) && scrollLeft==0){
let start_line = $(`#log_npu input[name=start_line]`).val()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=${start_line}&lines=50&order=asc`, (data) => {
if (data.Lines == 0){
$(`#log_npu_header`).text('您已翻阅至日志顶部')
$(`#log_npu_message`).css('display', 'block')
setTimeout(function(){
$(`#log_npu_message`).css('display', 'none')
}, 1000)
}else{
$(`#log_npu input[name=start_line]`).val(data.StartLine) //如果变动就改变所对应的值
$(`#log_npu`).prepend('<pre>' + data.Content)
}
}).fail(function(err) {
console.log(err);
});
}
}
function scrollAnimation(dom, currentY, targetY, currentX) {
let needScrollTop = targetY - currentY;
let _currentY = currentY;
setTimeout(() => {
// 一次调用滑动帧数,每次调用会不一样
//取总距离的十分之一
const dist = Math.ceil(needScrollTop / 10);
_currentY += dist;
//移动一个十分之一
dom.scrollTo(currentX || 0, _currentY,'smooth');
// 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果
if (needScrollTop > 10 || needScrollTop < -10) {
scrollAnimation(dom, _currentY, targetY)
} else {
dom.scrollTo(0, targetY,'smooth')
}
}, 1)
}

$('.log_top').click(function(){

let logContentDom = document.querySelector(`#log_npu`)
$(`#log_file_npu`).siblings('pre').remove()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=&lines=50&order=asc`, (data) => {
$(`#log_npu input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值
$(`#log_npu input[name=start_line]`).val(data.StartLine)
$(`#log_npu`).prepend('<pre>' + data.Content)
$(`#log_npu_header`).text('您已翻阅至日志顶部')
$(`#log_npu_message`).css('display', 'block')
setTimeout(function(){
$(`#log_npu_message`).css('display', 'none')
}, 1000)
scrollAnimation(logContentDom, logContentDom.scrollTop, 0);
})

})
$('.log_bottom').click(function(e){

let logContentDom = document.querySelector(`#log_npu`)
$(`#log_file_npu`).siblings('pre').remove()
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=&lines=50&order=desc`, (data) => {
$(`#log_npu input[name=end_line]`).val(data.EndLine) //如果变动就改变所对应的值
$(`#log_npu input[name=start_line]`).val(data.StartLine)
$(`#log_npu`).append('<pre>' + data.Content)
$.get(`/api/v1/repos/${userName}/${repoPath}/modelmanage/${taskID}/modelartlog?version_name=V0001&base_line=${data.EndLine}&lines=50&order=desc`, (data) => {
if (data.Lines == 0){
$(`#log_npu_header`).text('您已翻阅至日志底部')
$(`#log_npu_message`).css('display', 'block')
setTimeout(function(){
$(`#log_npu_message`).css('display', 'none')
}, 1000)
}else{
if(end_line===data.EndLine){
return
}
else{
$(`#log_npu input[name=end_line]`).val(data.EndLine)
$(`#log_npu`).append('<pre>' + data.Content)
}

}
}).fail(function(err) {
console.log(err);
});
scrollAnimation(logContentDom, logContentDom.scrollTop+1, logContentDom.scrollHeight - logContentDom.clientHeight);
})
})
</script>

+ 244
- 49
templates/repo/modelmanage/index.tmpl View File

@@ -1,10 +1,33 @@
<!-- 头部导航栏 --> <!-- 头部导航栏 -->
{{template "base/head" .}} {{template "base/head" .}}
<style> <style>
.inline.fields .right.aligned label{
width: 100% !important;
text-align: right;
}
.inline .ui.dropdown .text { .inline .ui.dropdown .text {
color: rgba(0, 0, 0, .87) !important color: rgba(0, 0, 0, .87) !important
} }
.newtext{
left: 15px !important
}
.menuContent{
position: absolute;
background: #ffffff;
left: 0;
right: 26px;
top: 36px;
z-index:999;
border: 1px solid #96c8da;
border-top: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 3px 0 rgb(34 36 38 / 15%);
}
</style> </style>
<link rel="stylesheet" href="/self/ztree/css/zTreeStyle/zTreeStyle.css" type="text/css">


<!-- 弹窗 --> <!-- 弹窗 -->
<div id="mask"> <div id="mask">
<div id="loadingPage"> <div id="loadingPage">
@@ -25,7 +48,12 @@
<div class="ui container {{if ne $.MODEL_COUNT 0}}active loader {{end}}" id="loadContainer"> <div class="ui container {{if ne $.MODEL_COUNT 0}}active loader {{end}}" id="loadContainer">
{{template "base/alert" .}} {{template "base/alert" .}}
<div class="ui two column stackable grid"> <div class="ui two column stackable grid">
<div class="column"></div>
<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/modelmanage/show_model">{{$.i18n.Tr "repo.model.list"}}</a>
<a class="item" href="{{.RepoLink}}/modelmanage/convert_model">{{$.i18n.Tr "repo.model.convert"}}</a>
</div>
</div>
<div class="column right aligned"> <div class="column right aligned">
<!-- --> <!-- -->
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" <a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}"
@@ -95,6 +123,7 @@
</div> </div>
</div> </div>
</div> </div>

<div id="newmodel"> <div id="newmodel">
<div class="ui modal second"> <div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);"> <div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
@@ -107,20 +136,21 @@
<!-- <p>asdasdasd</p> --> <!-- <p>asdasdasd</p> -->
</div> </div>
<input type="hidden" name="_csrf" value=""> <input type="hidden" name="_csrf" value="">
<div class="two inline fields ">
<div class="required ten wide field">
<label style="margin-left: -23px;">选择训练任务</label>
<div class="ui dropdown selection search width83 loading" id="choice_model">
<div class="inline fields">
<div class="required two wide field right aligned">
<label for="JobId">选择训练任务</label>
</div>
<div class="required thirteen wide inline field">
<div class="ui dropdown selection search loading" id="choice_model">
<input type="hidden" id="JobId" name="JobId" required> <input type="hidden" id="JobId" name="JobId" required>
<div class="default text">选择训练任务</div> <div class="default text">选择训练任务</div>
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<div class="menu" id="job-name"> <div class="menu" id="job-name">
</div> </div>
</div> </div>
</div>
<div class="required six widde field">
<label>版本</label>
<div class="ui dropdown selection search width70" id="choice_version">
<label for="VersionName">版本</label>
<span>&nbsp;</span>
<div class="ui dropdown selection search" id="choice_version">
<input type="hidden" id="VersionName" name="VersionName" required> <input type="hidden" id="VersionName" name="VersionName" required>
<div class="default text">选择版本</div> <div class="default text">选择版本</div>
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
@@ -130,21 +160,30 @@
</div> </div>
</div> </div>
</div> </div>
<div class="required inline field" id="modelname">
<label>模型名称</label>
<input style="width: 45%;" id="name" name="Name" required maxlength="25"
onkeyup="this.value=this.value.replace(/[, ]/g,'')">
<div class="required inline fields" id="modelname">
<div class="two wide field right aligned">
<label for="Name">模型名称</label>
</div>
<div class="eight wide field">
<input id="name" name="Name" required maxlength="25" onkeyup="this.value=this.value.replace(/[, ]/g,'')">
</div>
</div> </div>
<div class="required inline field" id="verionname">
<label>模型版本</label>
<input style="width: 45%;" id="version" name="Version" value="" readonly required maxlength="255">
<div class="required inline fields" id="verionname">
<div class="two wide field right aligned">
<label for="Version">模型版本</label>
</div>
<div class="eight wide field">
<input id="version" name="Version" value="" readonly required maxlength="255">
</div>
</div> </div>


<div class="unite min_title inline field required">
<label>模型框架</label>
<div class="ui dropdown selection search width70" id="choice_Engine">
<div class="unite min_title inline fields required">
<div class="two wide field right aligned">
<label for="Engine">模型框架</label>
</div>
<div class="ui ten wide field dropdown selection search" id="choice_Engine">
<input type="hidden" id="Engine" name="Engine" required> <input type="hidden" id="Engine" name="Engine" required>
<div class="default text">选择模型框架</div>
<div class="default text newtext">选择模型框架</div>
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<div class="menu" id="job-Engine"> <div class="menu" id="job-Engine">


@@ -152,28 +191,48 @@
</div> </div>


</div> </div>
<div class="inline field">
<label>模型标签</label>
<input style="width: 83%;margin-left: 7px;" id="label" name="Label" maxlength="255"
placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>

<div class="unite min_title inline fields required">
<div class="two wide field right aligned">
<label for="modelSelectedFile">模型文件</label>
</div>
<div class="thirteen wide field" style="position:relative">
<input id="modelSelectedFile" type="text" readonly required onclick="showMenu();" name="modelSelectedFile" >
<div id="menuContent" class="menuContent" style="display:none;">
<ul id="treeDemo" class="ztree"></ul>
</div>
</div>
</div> </div>
<div class="inline field">
<label for="description">模型描述</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3"
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}'
onchange="this.value=this.value.substring(0, 255)"
onkeydown="this.value=this.value.substring(0, 255)"
onkeyup="this.value=this.value.substring(0, 256)"></textarea>

<div class="inline fields">
<div class="two wide field right aligned">
<label for="Label">模型标签 &nbsp</label>
</div>
<div class="thirteen wide field">
<input id="label" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
</div>
<div class="inline fields">
<div class="two wide field right aligned">
<label for="description">模型描述 &nbsp</label>
</div>
<div class="thirteen wide field">
<textarea id="Description" name="Description" rows="3"
maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}'
onchange="this.value=this.value.substring(0, 255)"
onkeydown="this.value=this.value.substring(0, 255)"
onkeyup="this.value=this.value.substring(0, 256)"></textarea>
</div>
</div> </div>


<div class="inline field" style="margin-left: 75px;">
<div class="inline field" style="margin-left: 105px;">
<button id="submitId" type="button" class="ui create_train_job green button" <button id="submitId" type="button" class="ui create_train_job green button"
style="position: absolute;"> style="position: absolute;">
{{.i18n.Tr "repo.model.manage.sava_model"}} {{.i18n.Tr "repo.model.manage.sava_model"}}
</button> </button>
</div> </div>
</form> </form>
<div class="actions" style="display: inline-block;margin-left: 180px;">
<div class="actions" style="display: inline-block;margin-left: 220px;">
<button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button> <button class="ui button cancel">{{.i18n.Tr "repo.cloudbrain.cancel"}}</button>
</div> </div>
</div> </div>
@@ -181,10 +240,79 @@


</div> </div>



{{template "base/footer" .}} {{template "base/footer" .}}


<script>
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.core.js"></script>
<script type="text/javascript" src="/self/ztree/js/jquery.ztree.excheck.js"></script>
<script type="text/javascript">
var setting = {
check: {
enable: true,
chkboxType: {"Y":"ps", "N":"ps"}
},
view: {
dblClickExpand: false
},
callback: {
beforeClick: beforeClick,
onCheck: onCheck
}
};

function beforeClick(treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo");
zTree.checkNode(treeNode, !treeNode.checked, null, true);
return false;
}
function onCheck(e, treeId, treeNode) {
var zTree = $.fn.zTree.getZTreeObj("treeDemo"),
nodes = zTree.getCheckedNodes(true),
v = "";
for (var i=0, l=nodes.length; i<l; i++) {
if(nodes[i].isParent){
continue;
}
var pathNodes = nodes[i].getPath();
var path ="";
for(var j=0;j<pathNodes.length;j++){
if(j ==0){
path += pathNodes[j].name;
}else{
path += "/" + pathNodes[j].name;
}
}
v += path + ";";
}
if (v.length > 0 ) v = v.substring(0, v.length-1);
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", v);
}
function showMenu() {
var cityObj = $("#modelSelectedFile");
var cityOffset = $("#modelSelectedFile").offset();
// $("#menuContent").css({left:cityOffset.left + "px", top:cityOffset.top + cityObj.outerHeight() + "px"}).slideDown("fast");
$("#menuContent").slideDown("fast");

$("body").bind("mousedown", onBodyDown);
}
function hideMenu() {
$("#menuContent").fadeOut("fast");
$("body").unbind("mousedown", onBodyDown);
}
function onBodyDown(event) {
if (!(event.target.id == "menuBtn" || event.target.id == "modelSelectedFile" || event.target.id == "menuContent" || $(event.target).parents("#menuContent").length>0)) {
hideMenu();
}
}

$(document).ready(function(){
//$.fn.zTree.init($("#treeDemo"), setting, zNodes);
});
let repolink = {{.RepoLink }} let repolink = {{.RepoLink }}
let repoId = {{ $repository }} let repoId = {{ $repository }}
const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config; const { _AppSubUrl, _StaticUrlPrefix, csrf } = window.config;
@@ -207,9 +335,10 @@
$("#job-name").empty() $("#job-name").empty()
createModelName() createModelName()
loadTrainList() loadTrainList()

}, },
onHide: function () { onHide: function () {
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", "");
document.getElementById("formId").reset(); document.getElementById("formId").reset();
$('#choice_model').dropdown('clear') $('#choice_model').dropdown('clear')
$('#choice_version').dropdown('clear') $('#choice_version').dropdown('clear')
@@ -226,7 +355,7 @@
$(function () { $(function () {
$('#choice_model').dropdown({ $('#choice_model').dropdown({
onChange: function (value) { onChange: function (value) {
$(".ui.dropdown.selection.search.width70").addClass("loading")
$("#choice_version").addClass("loading")
$('#choice_version').dropdown('clear') $('#choice_version').dropdown('clear')
$("#job-version").empty() $("#job-version").empty()
loadTrainVersion(value) loadTrainVersion(value)
@@ -240,6 +369,7 @@
for (var i = 0; i < modelData.length; i++) { for (var i = 0; i < modelData.length; i++) {
if (modelData[i].VersionName == value) { if (modelData[i].VersionName == value) {
setEngine(modelData[i]) setEngine(modelData[i])
loadModelFile(modelData[i])
break; break;
} }
} }
@@ -273,12 +403,12 @@
train_html += '</div>' train_html += '</div>'
} }
$("#job-name").append(train_html) $("#job-name").append(train_html)
$(".ui.dropdown.selection.search.width83").removeClass("loading")
$("#choice_model").removeClass("loading")
$('#choice_model .default.text').text(data[0].DisplayJobName) $('#choice_model .default.text').text(data[0].DisplayJobName)
$('#choice_model input[name="JobId"]').val(data[0].JobID) $('#choice_model input[name="JobId"]').val(data[0].JobID)
loadTrainVersion() loadTrainVersion()
}else{ }else{
$(".ui.dropdown.selection.search.width83").removeClass("loading")
$("#choice_model").removeClass("loading")
} }
}) })
} }
@@ -294,7 +424,7 @@
} }
if (data.length) { if (data.length) {
$("#job-version").append(train_html) $("#job-version").append(train_html)
$(".ui.dropdown.selection.search.width70").removeClass("loading")
$("#choice_version").removeClass("loading")
var versionName = data[0].VersionName; var versionName = data[0].VersionName;
if (versionName == null || versionName == "") { if (versionName == null || versionName == "") {
versionName = "V0001"; versionName = "V0001";
@@ -302,47 +432,112 @@
$('#choice_version .default.text').text(versionName) $('#choice_version .default.text').text(versionName)
$('#choice_version input[name="VersionName"]').val(versionName) $('#choice_version input[name="VersionName"]').val(versionName)
setEngine(data[0]) setEngine(data[0])
loadModelFile(data[0])
} }


}) })
} }

function loadModelFile(trainJob){
console.log("trainJob=" + trainJob);
$('#choice_file').dropdown('clear')
$("#model-file").empty()
if(trainJob ==null || trainJob ==""){
console.log("trainJob is null");
}else{
let type = trainJob.Type;
if(type == 2){
if(trainJob.ComputeResource=="NPU"){
type=1;
}else{
type=0;
}
}
$.get(`${repolink}/modelmanage/query_train_model?jobName=${trainJob.JobName}&type=${type}&VersionName=${trainJob.VersionName}`, (data) => {
const n_length = data.length
let file_html=''
let firstFileName =''
var zNodes=[];
var nodesMap={};
for (let i=0;i<n_length;i++){
parentNodeMap = nodesMap;
var fileSplits = data[i].FileName.split("/");
for(let j=0;j < fileSplits.length;j++){
if(fileSplits[j] == ""){
break;
}
if(parentNodeMap[fileSplits[j]] == null){
parentNodeMap[fileSplits[j]] = {};
}
parentNodeMap = parentNodeMap[fileSplits[j]]
}
}
convertToNode(zNodes,nodesMap);
$.fn.zTree.init($("#treeDemo"), setting, zNodes);
})
}
}
function convertToNode(nodeList,nodesMap){
var keyList = Object.keys(nodesMap);
keyList.sort(function(a,b){
return a-b;
});
var isFirst = true;
for(var i=0; i<keyList.length;i++){
var node = {};
node["name"] = keyList[i];
nodeList.push(node);
if(nodesMap[keyList[i]] != null && Object.keys(nodesMap[keyList[i]]).length >0){
node["children"]=[];
if(isFirst){
node["open"] = true;
isFirst= false;
}
convertToNode(node["children"],nodesMap[keyList[i]]);
}
}
}
function setEngine(modelVersion) { function setEngine(modelVersion) {
console.log("modelVersion=" + modelVersion); console.log("modelVersion=" + modelVersion);
$('#choice_Engine').dropdown('clear') $('#choice_Engine').dropdown('clear')
$("#job-Engine").empty() $("#job-Engine").empty()
if (modelVersion.EngineName != null && modelVersion.EngineName != "") { if (modelVersion.EngineName != null && modelVersion.EngineName != "") {
srcEngine = modelVersion.EngineName.split('-')[0] srcEngine = modelVersion.EngineName.split('-')[0]
srcEngine = srcEngine.trim();
let selectedText = "Pytorch";
srcEngine = srcEngine.trim().toLowerCase();
let selectedText = "PyTorch";
let selectedValue = 0; let selectedValue = 0;
let itemHtml = "<option class=\"item\" data-value=\"0\">Pytorch</option>";
if (srcEngine == 'TensorFlow') {
let itemHtml = "<option class=\"item\" data-value=\"0\">PyTorch</option>";
if (srcEngine == 'tensorflow') {
selectedText = "TensorFlow"; selectedText = "TensorFlow";
selectedValue = 1; selectedValue = 1;
itemHtml += "<option class=\"active item\" data-value=\"1\">TensorFlow</option>"; itemHtml += "<option class=\"active item\" data-value=\"1\">TensorFlow</option>";
} else { } else {
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>"; itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>";
} }
if (srcEngine == 'MindSpore') {
if (srcEngine == 'mindspore') {
selectedText = "MindSpore"; selectedText = "MindSpore";
selectedValue = 2; selectedValue = 2;
itemHtml += "<option class=\"active item\" data-value=\"2\">MindSpore</option>"; itemHtml += "<option class=\"active item\" data-value=\"2\">MindSpore</option>";
} else { } else {
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>"; itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>";
} }
itemHtml += "<option class=\"item\" data-value=\"4\">PaddlePaddle</option>"
itemHtml += "<option class=\"item\" data-value=\"5\">OneFlow</option>"
itemHtml += "<option class=\"item\" data-value=\"6\">MXNet</option>"
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>"


$('#choice_Engine .default.text').text(selectedText) $('#choice_Engine .default.text').text(selectedText)
$('#choice_Engine input[name="Engine"]').val(selectedValue) $('#choice_Engine input[name="Engine"]').val(selectedValue)
$("#job-Engine").append(itemHtml); $("#job-Engine").append(itemHtml);
$("#choice_Engine").addClass('disabled')
$("#choice_Engine").removeClass('disabled');
} else { } else {
let itemHtml = "<option class=\"active item\" data-value=\"0\">Pytorch</option>";
let itemHtml = "<option class=\"active item\" data-value=\"0\">PyTorch</option>";
itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>" itemHtml += "<option class=\"item\" data-value=\"1\">TensorFlow</option>"
itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>" itemHtml += "<option class=\"item\" data-value=\"2\">MindSpore</option>"
itemHtml += "<option class=\"item\" data-value=\"4\">PaddlePaddle</option>"
itemHtml += "<option class=\"item\" data-value=\"5\">OneFlow</option>"
itemHtml += "<option class=\"item\" data-value=\"6\">MXNet</option>"
itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>" itemHtml += "<option class=\"item\" data-value=\"3\">Other</option>"
$('#choice_Engine .default.text').text("Pytorch");
$('#choice_Engine .default.text').text("PyTorch");
$('#choice_Engine input[name="Engine"]').val(0) $('#choice_Engine input[name="Engine"]').val(0)
$("#job-Engine").append(itemHtml); $("#job-Engine").append(itemHtml);
$("#choice_Engine").removeClass('disabled'); $("#choice_Engine").removeClass('disabled');


+ 12
- 3
templates/repo/modelmanage/showinfo.tmpl View File

@@ -234,12 +234,21 @@ function loadInfo(){
} }
function getEngineName(model){ function getEngineName(model){
if(model.Engine == 0){ if(model.Engine == 0){
return "Pytorch";
return "PyTorch";
}else if(model.Engine == 1 || model.Engine == 121){ }else if(model.Engine == 1 || model.Engine == 121){
return "TensorFlow"; return "TensorFlow";
}else if(model.Engine == 2 || model.Engine == 122){
}else if(model.Engine == 2 || model.Engine == 122 || model.Engine == 35){
return "MindSpore"; return "MindSpore";
}else{
}else if(model.Engine == 3){
return "Other";
}else if(model.Engine == 4){
return "PaddlePaddle";
}else if(model.Engine == 5){
return "OneFlow";
}else if(model.Engine == 6){
return "MXNet";
}
else{
return "Other" return "Other"
} }
} }


+ 23
- 5
web_src/js/components/Model.vue View File

@@ -65,7 +65,7 @@
min-width="8.5%" min-width="8.5%"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<span class="text-over">{{ scope.row.EngineName}}</span>
<span class="text-over" :title="scope.row.EngineName">{{ scope.row.EngineName}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@@ -203,6 +203,7 @@ export default {
$('#model_header').text("创建模型新版本") $('#model_header').text("创建模型新版本")
$('input[name="Name"]').addClass('model_disabled') $('input[name="Name"]').addClass('model_disabled')
$('input[name="Name"]').attr('readonly','readonly') $('input[name="Name"]').attr('readonly','readonly')
$('input[name="modelSelectedFile"]').attr('readonly','readonly')
$('input[name="Version"]').addClass('model_disabled') $('input[name="Version"]').addClass('model_disabled')
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"}) $('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
$("#job-name").empty() $("#job-name").empty()
@@ -216,6 +217,9 @@ export default {
document.getElementById("formId").reset(); document.getElementById("formId").reset();
$('input[name="Name"]').removeClass('model_disabled') $('input[name="Name"]').removeClass('model_disabled')
$('input[name="Name"]').removeAttr('readonly') $('input[name="Name"]').removeAttr('readonly')
$('input[name="modelSelectedFile"]').removeAttr('readonly')
var cityObj = $("#modelSelectedFile");
cityObj.attr("value", "");
$('#choice_model').dropdown('clear') $('#choice_model').dropdown('clear')
$('#choice_version').dropdown('clear') $('#choice_version').dropdown('clear')
$('#choice_Engine').dropdown('clear') $('#choice_Engine').dropdown('clear')
@@ -231,18 +235,26 @@ export default {
let versionname = document.getElementById("VersionName").value let versionname = document.getElementById("VersionName").value
let name= document.getElementById("name").value let name= document.getElementById("name").value
let version= document.getElementById("version").value let version= document.getElementById("version").value
let modelSelectedFile = document.getElementById("modelSelectedFile").value
if(jobid==""){ if(jobid==""){
$(".required.ten.wide.field").addClass("error") $(".required.ten.wide.field").addClass("error")
return false return false
}else{ }else{
$(".required.ten.wide.field").removeClass("error") $(".required.ten.wide.field").removeClass("error")
} }
if(modelSelectedFile==""){
$("#modelSelectedFile").addClass("error")
return false
}else{
$("#modelSelectedFile").removeClass("error")
}
if(versionname==""){ if(versionname==""){
$(".required.six.widde.field").addClass("error") $(".required.six.widde.field").addClass("error")
return false return false
}else{ }else{
$(".required.six.widde.field").removeClass("error") $(".required.six.widde.field").removeClass("error")
} }
if(name==""){ if(name==""){
$("#modelname").addClass("error") $("#modelname").addClass("error")
return false return false
@@ -273,8 +285,8 @@ export default {
type:'POST', type:'POST',
data:data, data:data,
success:function(res){ success:function(res){
// context.loadrefresh1(row)
context.getModelList() context.getModelList()
$("input[name='modelSelectedFile']").val("")
$('.ui.modal.second').modal('hide') $('.ui.modal.second').modal('hide')
if(initModel==='0'){ if(initModel==='0'){
location.reload() location.reload()
@@ -350,15 +362,21 @@ export default {
}, },
getEngineName(model){ getEngineName(model){
if(model.Engine == 0){ if(model.Engine == 0){
return "Pytorch";
return "PyTorch";
}else if(model.Engine == 1 || model.Engine == 121){ }else if(model.Engine == 1 || model.Engine == 121){
return "TensorFlow"; return "TensorFlow";
}else if(model.Engine == 2 || model.Engine == 122 || model.Engine == 35){ }else if(model.Engine == 2 || model.Engine == 122 || model.Engine == 35){
return "MindSpore"; return "MindSpore";
}else{
}else if(model.Engine == 4){
return "PaddlePaddle";
}else if(model.Engine == 5){
return "OneFlow";
}else if(model.Engine == 6){
return "MXNet";
}
else{
return "Other" return "Other"
} }

}, },
getModelList(){ getModelList(){
try { try {


+ 2
- 5
web_src/js/components/UserAnalysis.vue View File

@@ -226,11 +226,8 @@
width="120px" width="120px"
align="center"> align="center">
</el-table-column> </el-table-column>
<el-table-column
prop="Phone"
label="手机"
width="120px"
align="center">
<el-table-column prop="Phone" label="是否手机验证" width="120px" align="center">
<template slot-scope="scope"> {{scope.row.Phone ? '是' : '否'}} </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="RegistDate" prop="RegistDate"


Loading…
Cancel
Save