|
@@ -9,6 +9,7 @@ import (
|
|
|
"eta/eta_api/utils"
|
|
|
"fmt"
|
|
|
"strconv"
|
|
|
+ "strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
@@ -20,7 +21,7 @@ type SpeechRecognitionCommonController struct {
|
|
|
controllers.BaseCommonController
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
@@ -71,17 +72,139 @@ func (this *SpeechRecognitionCommonController) RecTaskCallback() {
|
|
|
}
|
|
|
utils.FileLog.Info("RecTaskCallback, 3")
|
|
|
|
|
|
+
|
|
|
+
|
|
|
br.Code = 0
|
|
|
br.Message = "success"
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) Convert() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var req speech_recognition.SpeechRecognitionConvertReq
|
|
|
+ if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = "参数解析失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if req.MenuId <= 0 {
|
|
|
+ br.Msg = "请选择目录"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if len(req.Files) == 0 {
|
|
|
+ br.Msg = "请上传转写文件"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for _, r := range req.Files {
|
|
|
+ if r.FileName == "" && r.ResourceUrl == "" {
|
|
|
+ br.Msg = "转写文件有误,请检查"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ speeches := make([]*speech_recognition.SpeechRecognition, 0)
|
|
|
+ nowTime := time.Now().Local()
|
|
|
+ for _, v := range req.Files {
|
|
|
+ t := new(speech_recognition.SpeechRecognition)
|
|
|
+ t.FileName = v.FileName
|
|
|
+ t.ResourceUrl = v.ResourceUrl
|
|
|
+ t.MenuId = req.MenuId
|
|
|
+
|
|
|
+ t.SysUserId = sysUser.AdminId
|
|
|
+ t.SysUserName = sysUser.RealName
|
|
|
+ t.State = speech_recognition.SpeechRecognitionStateWait
|
|
|
+ t.CreateTime = nowTime
|
|
|
+ t.ModifyTime = nowTime
|
|
|
+ speeches = append(speeches, t)
|
|
|
+ }
|
|
|
+ speechOb := new(speech_recognition.SpeechRecognition)
|
|
|
+ if e := speechOb.CreateMulti(speeches); e != nil {
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "批量新增转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ go func() {
|
|
|
+ services.BatchConvertSpeech(speeches)
|
|
|
+ }()
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "操作成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) ConvertList() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ states := []int{speech_recognition.SpeechRecognitionStateWait, speech_recognition.SpeechRecognitionStateFail}
|
|
|
+ speechOb := new(speech_recognition.SpeechRecognition)
|
|
|
+ cond := fmt.Sprintf(` %s = ? AND %s IN (%s)`, speech_recognition.SpeechRecognitionCols.SysUserId, speech_recognition.SpeechRecognitionCols.State, utils.GetOrmInReplace(len(states)))
|
|
|
+ pars := make([]interface{}, 0)
|
|
|
+ pars = append(pars, sysUser.AdminId, states)
|
|
|
+ list, e := speechOb.GetItemsByCondition(cond, pars, []string{}, "")
|
|
|
+ if e != nil {
|
|
|
+ br.Msg = "获取失败"
|
|
|
+ br.ErrMsg = "获取转写文件列表失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ resp := make([]*speech_recognition.SpeechRecognitionItem, 0)
|
|
|
+ for _, v := range list {
|
|
|
+ resp = append(resp, speech_recognition.FormatSpeechRecognition2Item(v))
|
|
|
+ }
|
|
|
+
|
|
|
+ br.Data = resp
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "获取成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
-func (this *SpeechRecognitionCommonController) Save() {
|
|
|
+func (this *SpeechRecognitionController) Save() {
|
|
|
br := new(models.BaseResponse).Init()
|
|
|
defer func() {
|
|
|
if br.ErrMsg == "" {
|
|
@@ -128,3 +251,432 @@ func (this *SpeechRecognitionCommonController) Save() {
|
|
|
br.Success = true
|
|
|
br.Msg = "操作成功"
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) RemoveFile() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var req speech_recognition.SpeechRecognitionRemoveFileReq
|
|
|
+ if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = "参数解析失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if req.SpeechRecognitionId <= 0 {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = fmt.Sprintf("参数有误, SpeechRecognitionId: %d", req.SpeechRecognitionId)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ speechOb := new(speech_recognition.SpeechRecognition)
|
|
|
+ speechItem, e := speechOb.GetItemById(req.SpeechRecognitionId)
|
|
|
+ if e != nil {
|
|
|
+ if e.Error() == utils.ErrNoRow() {
|
|
|
+ br.Msg = "转写文件不存在,请刷新页面"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "获取转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ speechItem.FileState = speech_recognition.SpeechRecognitionFileRemoveFlag
|
|
|
+ speechItem.ModifyTime = time.Now().Local()
|
|
|
+ updateCols := []string{speech_recognition.SpeechRecognitionCols.FileState, speech_recognition.SpeechRecognitionCols.ModifyTime}
|
|
|
+ if e = speechItem.Update(updateCols); e != nil {
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "软删除转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "操作成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) Rename() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var req speech_recognition.SpeechRecognitionRenameReq
|
|
|
+ if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = "参数解析失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if req.SpeechRecognitionId <= 0 {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = fmt.Sprintf("参数有误, SpeechRecognitionId: %d", req.SpeechRecognitionId)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ req.FileName = strings.TrimSpace(req.FileName)
|
|
|
+ if req.FileName == "" {
|
|
|
+ br.Msg = "请输入文件名称"
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ speechOb := new(speech_recognition.SpeechRecognition)
|
|
|
+ speechItem, e := speechOb.GetItemById(req.SpeechRecognitionId)
|
|
|
+ if e != nil {
|
|
|
+ if e.Error() == utils.ErrNoRow() {
|
|
|
+ br.Msg = "转写文件不存在,请刷新页面"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "获取转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ {
|
|
|
+ cond := fmt.Sprintf(` %s = ? AND %s <> ?`, speech_recognition.SpeechRecognitionCols.FileName, speech_recognition.SpeechRecognitionCols.SpeechRecognitionId)
|
|
|
+ pars := make([]interface{}, 0)
|
|
|
+ pars = append(pars, req.FileName, req.SpeechRecognitionId)
|
|
|
+ exists, e := speechOb.GetItemByCondition(cond, pars, "")
|
|
|
+ if e != nil && e.Error() != utils.ErrNoRow() {
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "获取同名转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if exists != nil && exists.SpeechRecognitionId > 0 {
|
|
|
+ br.Msg = "分类名称已存在,请重新输入"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ speechItem.FileName = req.FileName
|
|
|
+ speechItem.ModifyTime = time.Now().Local()
|
|
|
+ updateCols := []string{speech_recognition.SpeechRecognitionCols.FileName, speech_recognition.SpeechRecognitionCols.ModifyTime}
|
|
|
+ if e = speechItem.Update(updateCols); e != nil {
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "转写文件重命名失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "操作成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) Remove() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var req speech_recognition.SpeechRecognitionRemoveReq
|
|
|
+ if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = "参数解析失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if req.SpeechRecognitionId <= 0 {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = fmt.Sprintf("参数有误, SpeechRecognitionId: %d", req.SpeechRecognitionId)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ speechOb := new(speech_recognition.SpeechRecognition)
|
|
|
+ speechItem, e := speechOb.GetItemById(req.SpeechRecognitionId)
|
|
|
+ if e != nil {
|
|
|
+ if e.Error() == utils.ErrNoRow() {
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "操作成功"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "获取转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if e = speechItem.Del(); e != nil {
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "删除转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ go func() {
|
|
|
+ mappingOb := new(speech_recognition.SpeechRecognitionTagMapping)
|
|
|
+ _ = mappingOb.ClearMappingBySpeechId(req.SpeechRecognitionId)
|
|
|
+ }()
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "操作成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) SaveTag() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var req speech_recognition.SpeechRecognitionSaveTagReq
|
|
|
+ if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = "参数解析失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if req.SpeechRecognitionId <= 0 {
|
|
|
+ br.Msg = "参数有误"
|
|
|
+ br.ErrMsg = fmt.Sprintf("参数有误, SpeechRecognitionId: %d", req.SpeechRecognitionId)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ speechOb := new(speech_recognition.SpeechRecognition)
|
|
|
+ _, e := speechOb.GetItemById(req.SpeechRecognitionId)
|
|
|
+ if e != nil {
|
|
|
+ if e.Error() == utils.ErrNoRow() {
|
|
|
+ br.Msg = "转写文件不存在,请刷新页面"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "获取转写文件失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ mappingOb := new(speech_recognition.SpeechRecognitionTagMapping)
|
|
|
+ if e = mappingOb.ClearMappingBySpeechId(req.SpeechRecognitionId); e != nil {
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "清除转写文件标签失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if len(req.TagIds) > 0 {
|
|
|
+ mappings := make([]*speech_recognition.SpeechRecognitionTagMapping, 0)
|
|
|
+ for _, v := range req.TagIds {
|
|
|
+ if v <= 0 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ mappings = append(mappings, &speech_recognition.SpeechRecognitionTagMapping{
|
|
|
+ TagId: v,
|
|
|
+ SpeechRecognitionId: req.SpeechRecognitionId,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if e = mappingOb.CreateMulti(mappings); e != nil {
|
|
|
+ br.Msg = "操作失败"
|
|
|
+ br.ErrMsg = "批量新增转写文件标签失败, Err: " + e.Error()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "操作成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) List() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "获取成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) Detail() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "获取成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (this *SpeechRecognitionController) Move() {
|
|
|
+ br := new(models.BaseResponse).Init()
|
|
|
+ defer func() {
|
|
|
+ if br.ErrMsg == "" {
|
|
|
+ br.IsSendEmail = false
|
|
|
+ }
|
|
|
+ this.Data["json"] = br
|
|
|
+ this.ServeJSON()
|
|
|
+ }()
|
|
|
+ sysUser := this.SysUser
|
|
|
+ if sysUser == nil {
|
|
|
+ br.Msg = "请登录"
|
|
|
+ br.ErrMsg = "请登录,SysUser Is Empty"
|
|
|
+ br.Ret = 408
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ br.Ret = 200
|
|
|
+ br.Success = true
|
|
|
+ br.Msg = "操作成功"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|