center.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. package data
  2. import (
  3. "bytes"
  4. "strconv"
  5. "time"
  6. "go-common/app/admin/main/up/model/datamodel"
  7. "go-common/app/admin/main/up/util/hbaseutil"
  8. "go-common/app/interface/main/creative/model/data"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. "github.com/tsuna/gohbase/hrpc"
  12. "golang.org/x/net/context"
  13. )
  14. // ViewerBase visitor data analysis.
  15. func (d *Dao) ViewerBase(c context.Context, mid int64, dt time.Time) (res *datamodel.ViewerBaseInfo, err error) {
  16. var (
  17. result *hrpc.Result
  18. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  19. key = hbaseMd5Key(mid)
  20. genTableName = generateTableNameFunc(HBaseUpViewerBase, dt, -7)
  21. )
  22. defer cancel()
  23. if result, err = d.getDataWithBackup(ctx, d.hbase, genTableName, 2, key); err != nil {
  24. log.Error("ViewerBase d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", HBaseUpViewerBase, mid, key, err)
  25. err = ecode.CreativeDataErr
  26. return
  27. }
  28. if result == nil || len(result.Cells) == 0 {
  29. log.Warn("ViewerBase no data tableName(%s)|mid(%d)|key(%v)", HBaseUpViewerBase, mid, key)
  30. return
  31. }
  32. res = &datamodel.ViewerBaseInfo{}
  33. families := make(map[string]string, 2)
  34. families["f"] = ""
  35. families["g"] = ""
  36. fb := &datamodel.ViewerBaseData{}
  37. gb := &datamodel.ViewerBaseData{}
  38. for _, c := range result.Cells {
  39. if c == nil {
  40. continue
  41. }
  42. if _, ok := families[string(c.Family)]; ok {
  43. var data = gb
  44. if string(c.Family) == "f" {
  45. data = fb
  46. }
  47. v, _ := strconv.ParseInt(string(c.Value[:]), 10, 64)
  48. /*
  49. f:plat0 web-pc播放
  50. f:plat1 web-h5播放
  51. f:plat2 站外播放
  52. f:plat3 ios播放
  53. f:plat4 android播放
  54. */
  55. switch {
  56. case bytes.Equal(c.Qualifier, []byte("male")):
  57. data.Male = v
  58. case bytes.Equal(c.Qualifier, []byte("female")):
  59. data.Female = v
  60. case bytes.Equal(c.Qualifier, []byte("age1")):
  61. data.Age1 = v
  62. case bytes.Equal(c.Qualifier, []byte("age2")):
  63. data.Age2 = v
  64. case bytes.Equal(c.Qualifier, []byte("age3")):
  65. data.Age3 = v
  66. case bytes.Equal(c.Qualifier, []byte("age4")):
  67. data.Age4 = v
  68. case bytes.Equal(c.Qualifier, []byte("plat0")):
  69. data.PlatPC = v
  70. case bytes.Equal(c.Qualifier, []byte("plat1")):
  71. data.PlatH5 = v
  72. case bytes.Equal(c.Qualifier, []byte("plat2")):
  73. data.PlatOut = v
  74. case bytes.Equal(c.Qualifier, []byte("plat3")):
  75. data.PlatIOS = v
  76. case bytes.Equal(c.Qualifier, []byte("plat4")):
  77. data.PlatAndroid = v
  78. case bytes.Equal(c.Qualifier, []byte("else")):
  79. data.PlatOtherApp = v
  80. }
  81. }
  82. }
  83. res.Fans = fb
  84. res.Guest = gb
  85. return
  86. }
  87. // ViewerArea visitor area data analysis.
  88. func (d *Dao) ViewerArea(c context.Context, mid int64, dt time.Time) (res *datamodel.ViewerAreaInfo, err error) {
  89. var (
  90. result *hrpc.Result
  91. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  92. key = hbaseMd5Key(mid)
  93. genTableName = generateTableNameFunc(HBaseUpViewerArea, dt, -7)
  94. )
  95. defer cancel()
  96. if result, err = d.getDataWithBackup(ctx, d.hbase, genTableName, 2, key); err != nil {
  97. log.Error("ViewerArea d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", HBaseUpViewerArea, mid, key, err)
  98. err = ecode.CreativeDataErr
  99. return
  100. }
  101. if result == nil || len(result.Cells) == 0 {
  102. log.Warn("ViewerArea no data tableName(%s)|mid(%d)|key(%v)", HBaseUpViewerArea, mid, key)
  103. return
  104. }
  105. res = &datamodel.ViewerAreaInfo{}
  106. families := make(map[string]string, 2)
  107. families["f"] = ""
  108. families["g"] = ""
  109. for _, c := range result.Cells {
  110. if c == nil {
  111. continue
  112. }
  113. if _, ok := families[string(c.Family)]; ok {
  114. a := string(c.Qualifier[:])
  115. var list = &res.Guest
  116. v, _ := strconv.ParseInt(string(c.Value[:]), 10, 64)
  117. if string(c.Family) == "f" {
  118. list = &res.Fans
  119. }
  120. *list = append(*list, datamodel.ViewerAreaData{Area: a, Viewers: v})
  121. }
  122. }
  123. return
  124. }
  125. // ViewerTrend visitor trend data analysis.
  126. func (d *Dao) ViewerTrend(c context.Context, mid int64, dt time.Time) (res map[string]*data.Trend, err error) {
  127. var (
  128. result *hrpc.Result
  129. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  130. genTableName = generateTableNameFunc(HBaseUpViewerTrend, dt, -7)
  131. key = hbaseMd5Key(mid)
  132. )
  133. defer cancel()
  134. if result, err = d.getDataWithBackup(ctx, d.hbase, genTableName, 2, key); err != nil {
  135. log.Error("ViewerTrend d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", HBaseUpViewerTrend, mid, key, err)
  136. err = ecode.CreativeDataErr
  137. return
  138. }
  139. if result == nil || len(result.Cells) == 0 {
  140. log.Warn("ViewerTrend no data tableName(%s)|mid(%d)|key(%v)", HBaseUpViewerTrend, mid, key)
  141. return
  142. }
  143. families := make(map[string]string, 4)
  144. families["fs"] = ""
  145. families["ft"] = ""
  146. families["gs"] = ""
  147. families["gt"] = ""
  148. res = make(map[string]*data.Trend)
  149. ftd := &data.Trend{}
  150. gtd := &data.Trend{}
  151. ty := make(map[int]int64)
  152. tg := make(map[int]int64)
  153. nty := make(map[int]int64)
  154. ntg := make(map[int]int64)
  155. for _, c := range result.Cells {
  156. if c == nil {
  157. continue
  158. }
  159. if _, ok := families[string(c.Family)]; ok {
  160. if string(c.Family) == "fs" {
  161. tid, _ := strconv.Atoi(string(c.Qualifier[:]))
  162. v, _ := strconv.ParseInt(string(c.Value[:]), 10, 64)
  163. ty[tid] = v
  164. ftd.Ty = ty
  165. } else if string(c.Family) == "gs" {
  166. tid, _ := strconv.Atoi(string(c.Qualifier[:]))
  167. v, _ := strconv.ParseInt(string(c.Value[:]), 10, 64)
  168. nty[tid] = v
  169. gtd.Ty = nty
  170. }
  171. if string(c.Family) == "ft" {
  172. o, _ := strconv.Atoi(string(c.Qualifier[:]))
  173. v, _ := strconv.ParseInt(string(c.Value[:]), 10, 64)
  174. tg[o] = v
  175. ftd.Tag = tg
  176. } else if string(c.Family) == "gt" {
  177. o, _ := strconv.Atoi(string(c.Qualifier[:]))
  178. v, _ := strconv.ParseInt(string(c.Value[:]), 10, 64)
  179. ntg[o] = v
  180. gtd.Tag = ntg
  181. }
  182. }
  183. }
  184. res["fan"] = ftd
  185. res["guest"] = gtd
  186. return
  187. }
  188. // RelationFansDay up relation 30 days analysis.
  189. func (d *Dao) RelationFansDay(c context.Context, mid int64) (res datamodel.RelationFanHistoryData, err error) {
  190. var (
  191. result *hrpc.Result
  192. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  193. tableName = HBaseUpRelationFansDay
  194. key = hbaseMd5Key(mid)
  195. parser = hbaseutil.Parser{
  196. ParseIntFunc: hbaseutil.StringToUint,
  197. }
  198. )
  199. defer cancel()
  200. if result, err = d.hbase.GetStr(ctx, tableName, key); err != nil {
  201. log.Error("RelationFansDay d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", tableName, mid, key, err)
  202. err = ecode.CreativeDataErr
  203. return
  204. }
  205. if result == nil || len(result.Cells) == 0 {
  206. log.Warn("RelationFansDay no data tableName(%s)|mid(%d)|key(%v)", tableName, mid, key)
  207. return
  208. }
  209. if err = parser.Parse(result.Cells, &res); err != nil {
  210. log.Error("parse cell fail, err=%v", err)
  211. return
  212. }
  213. /*
  214. families := make(map[string]string, 2)
  215. families["a"] = "" //某日新增关注量
  216. families["u"] = "" //某日取关量
  217. fd := make(map[string]int)
  218. nfd := make(map[string]int)
  219. for _, c := range result.Cells {
  220. if c == nil {
  221. continue
  222. }
  223. if _, ok := families[string(c.Family)]; ok {
  224. if string(c.Family) == "a" {
  225. k := string(c.Qualifier[:])
  226. v, _ := strconv.Atoi(string(c.Value[:]))
  227. fd[k] = v
  228. } else if string(c.Family) == "u" {
  229. k := string(c.Qualifier[:])
  230. v, _ := strconv.Atoi(string(c.Value[:]))
  231. nfd[k] = v
  232. }
  233. }
  234. }
  235. res["follow"] = fd
  236. res["unfollow"] = nfd
  237. */
  238. return
  239. }
  240. // RelationFansHistory up relation history.
  241. func (d *Dao) RelationFansHistory(c context.Context, mid int64, month string) (res datamodel.RelationFanHistoryData, err error) {
  242. var (
  243. result *hrpc.Result
  244. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  245. tableName = HBaseUpRelationFansHistory
  246. key = string(hbaseMd5Key(mid)) + "_" + month
  247. parser = hbaseutil.Parser{ParseIntFunc: hbaseutil.StringToUint}
  248. )
  249. defer cancel()
  250. if result, err = d.hbase.GetStr(ctx, tableName, key); err != nil {
  251. log.Error("RelationFansHistory d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", tableName, mid, key, err)
  252. err = ecode.CreativeDataErr
  253. return
  254. }
  255. if result == nil || len(result.Cells) == 0 {
  256. log.Warn("RelationFansHistory no data tableName(%s)|mid(%d)|key(%v)", tableName, mid, key)
  257. return
  258. }
  259. if err = parser.Parse(result.Cells, &res); err != nil {
  260. log.Error("parse cell fail, err=%v", err)
  261. return
  262. }
  263. return
  264. }
  265. // RelationFansMonth up relation 400 days analysis.
  266. func (d *Dao) RelationFansMonth(c context.Context, mid int64) (res datamodel.RelationFanHistoryData, err error) {
  267. var (
  268. result *hrpc.Result
  269. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  270. tableName = HBaseUpRelationFansMonth
  271. key = hbaseMd5Key(mid)
  272. parser = hbaseutil.Parser{ParseIntFunc: hbaseutil.StringToUint}
  273. )
  274. defer cancel()
  275. if result, err = d.hbase.GetStr(ctx, tableName, key); err != nil {
  276. log.Error("RelationFansMonth d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", tableName, mid, key, err)
  277. err = ecode.CreativeDataErr
  278. return
  279. }
  280. if result == nil || len(result.Cells) == 0 {
  281. log.Warn("RelationFansMonth no data tableName(%s)|mid(%d)|key(%v)", tableName, mid, key)
  282. return
  283. }
  284. if err = parser.Parse(result.Cells, &res); err != nil {
  285. log.Error("parse cell fail, err=%v", err)
  286. return
  287. }
  288. return
  289. }
  290. // ViewerActionHour visitor action hour analysis.
  291. func (d *Dao) ViewerActionHour(c context.Context, mid int64, dt string) (res map[string]*data.ViewerActionHour, err error) {
  292. var (
  293. result *hrpc.Result
  294. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  295. tableName = HBaseUpViewerActionHour + dt
  296. key = hbaseMd5Key(mid)
  297. )
  298. defer cancel()
  299. if result, err = d.hbase.GetStr(ctx, tableName, key); err != nil {
  300. log.Error("ViewerActionHour d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", tableName, mid, key, err)
  301. err = ecode.CreativeDataErr
  302. return
  303. }
  304. if result == nil || len(result.Cells) == 0 {
  305. log.Warn("ViewerActionHour no data tableName(%s)|mid(%d)|key(%v)", tableName, mid, key)
  306. return
  307. }
  308. families := make(map[string]string, 4)
  309. families["fp"] = "" //播放数
  310. families["fr"] = "" //评论数
  311. families["fd"] = "" //弹幕数
  312. families["fe"] = "" //充电数
  313. families["fs"] = "" //承包数
  314. res = make(map[string]*data.ViewerActionHour)
  315. view := make(map[int]int)
  316. reply := make(map[int]int)
  317. danmu := make(map[int]int)
  318. elec := make(map[int]int)
  319. con := make(map[int]int)
  320. fah := &data.ViewerActionHour{}
  321. gah := &data.ViewerActionHour{}
  322. for _, c := range result.Cells {
  323. if c == nil {
  324. continue
  325. }
  326. if _, ok := families[string(c.Family)]; ok {
  327. if string(c.Family) == "fp" {
  328. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  329. v, _ := strconv.Atoi(string(c.Value[:]))
  330. view[k] = v
  331. fah.View = view
  332. } else if string(c.Family) == "gp" {
  333. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  334. v, _ := strconv.Atoi(string(c.Value[:]))
  335. view[k] = v
  336. gah.View = view
  337. }
  338. if string(c.Family) == "fr" {
  339. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  340. v, _ := strconv.Atoi(string(c.Value[:]))
  341. reply[k] = v
  342. fah.Reply = reply
  343. } else if string(c.Family) == "gr" {
  344. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  345. v, _ := strconv.Atoi(string(c.Value[:]))
  346. reply[k] = v
  347. gah.Reply = reply
  348. }
  349. if string(c.Family) == "fd" {
  350. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  351. v, _ := strconv.Atoi(string(c.Value[:]))
  352. danmu[k] = v
  353. fah.Dm = danmu
  354. } else if string(c.Family) == "gd" {
  355. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  356. v, _ := strconv.Atoi(string(c.Value[:]))
  357. danmu[k] = v
  358. gah.Dm = danmu
  359. }
  360. if string(c.Family) == "fe" {
  361. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  362. v, _ := strconv.Atoi(string(c.Value[:]))
  363. elec[k] = v
  364. fah.Elec = elec
  365. } else if string(c.Family) == "ge" {
  366. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  367. v, _ := strconv.Atoi(string(c.Value[:]))
  368. elec[k] = v
  369. gah.Elec = elec
  370. }
  371. if string(c.Family) == "fs" {
  372. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  373. v, _ := strconv.Atoi(string(c.Value[:]))
  374. con[k] = v
  375. fah.Contract = con
  376. } else if string(c.Family) == "gs" {
  377. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  378. v, _ := strconv.Atoi(string(c.Value[:]))
  379. con[k] = v
  380. gah.Contract = con
  381. }
  382. }
  383. }
  384. res["fan"] = fah
  385. res["not_fan"] = gah
  386. return
  387. }
  388. // UpIncr for Play/Dm/Reply/Fav/Share/Elec/Coin incr.
  389. func (d *Dao) UpIncr(c context.Context, mid int64, ty int8, now string) (res *data.UpDataIncrMeta, err error) {
  390. var (
  391. result *hrpc.Result
  392. ctx, cancel = context.WithTimeout(c, d.hbaseTimeOut)
  393. tableName string
  394. IncrKey string
  395. key = hbaseMd5Key(mid)
  396. )
  397. defer cancel()
  398. switch {
  399. case ty == data.Play:
  400. tableName = HBaseUpPlayInc + now
  401. case ty == data.Dm:
  402. tableName = HBaseUpDmInc + now
  403. case ty == data.Reply:
  404. tableName = HBaseUpReplyInc + now
  405. case ty == data.Share:
  406. tableName = HBaseUpShareInc + now
  407. case ty == data.Coin:
  408. tableName = HBaseUpCoinInc + now
  409. case ty == data.Fav:
  410. tableName = HBaseUpFavInc + now
  411. case ty == data.Elec:
  412. tableName = HBaseUpElecInc + now
  413. }
  414. IncrKey, _ = data.IncrTy(ty)
  415. if result, err = d.hbase.GetStr(ctx, tableName, key); err != nil {
  416. log.Error("UpIncr d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", tableName, mid, key, err)
  417. err = ecode.CreativeDataErr
  418. return
  419. }
  420. if result == nil || len(result.Cells) == 0 {
  421. log.Warn("UpIncr no data tableName(%s)|mid(%d)|key(%v)", tableName, mid, key)
  422. return
  423. }
  424. families := make(map[string]string, 4)
  425. families["u"] = "" //单日播放增量 u:play ...
  426. families["av"] = "" //播放top稿件 av:1
  427. families["v"] = "" //top稿件播放增量 v:1
  428. families["rk"] = "" //up主播放量排名 rk: [tid]
  429. aids := make(map[int]int64)
  430. incs := make(map[int]int)
  431. rk := make(map[int]int)
  432. var incr int
  433. for _, c := range result.Cells {
  434. if c == nil {
  435. continue
  436. }
  437. if _, ok := families[string(c.Family)]; ok {
  438. if string(c.Family) == "av" {
  439. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  440. v, _ := strconv.ParseInt(string(c.Value[:]), 10, 64)
  441. aids[k] = v
  442. } else if string(c.Family) == "v" {
  443. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  444. v, _ := strconv.Atoi(string(c.Value[:]))
  445. incs[k] = v
  446. } else if string(c.Family) == "rk" {
  447. k, _ := strconv.Atoi(string(c.Qualifier[:]))
  448. v, _ := strconv.Atoi(string(c.Value[:]))
  449. rk[k] = v
  450. } else if string(c.Family) == "u" {
  451. if bytes.Equal(c.Qualifier, []byte(IncrKey)) {
  452. v, _ := strconv.Atoi(string(c.Value[:]))
  453. if v < 0 {
  454. v = 0
  455. }
  456. incr = v
  457. }
  458. }
  459. }
  460. }
  461. res = &data.UpDataIncrMeta{}
  462. res.Incr = incr
  463. res.TopAIDList = aids
  464. res.TopIncrList = incs
  465. res.Rank = rk
  466. return
  467. }
  468. // ThirtyDayArchive for Play/Dm/Reply/Fav/Share/Elec/Coin for archive 30 days.
  469. func (d *Dao) ThirtyDayArchive(c context.Context, mid int64, ty int8) (res []*data.ThirtyDay, err error) {
  470. var (
  471. result *hrpc.Result
  472. ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
  473. tableName string
  474. key = hbaseMd5Key(mid)
  475. )
  476. defer cancel()
  477. switch {
  478. case ty == data.Play:
  479. tableName = HBasePlayArc
  480. case ty == data.Dm:
  481. tableName = HBaseDmArc
  482. case ty == data.Reply:
  483. tableName = HBaseReplyArc
  484. case ty == data.Share:
  485. tableName = HBaseShareArc
  486. case ty == data.Coin:
  487. tableName = HBaseCoinArc
  488. case ty == data.Fav:
  489. tableName = HBaseFavArc
  490. case ty == data.Elec:
  491. tableName = HBaseElecArc
  492. case ty == data.Like:
  493. tableName = HBaseLikeArc
  494. }
  495. if result, err = d.hbase.GetStr(ctx, tableName, key); err != nil {
  496. log.Error("ThirtyDayArchive d.hbase.GetStr tableName(%s)|mid(%d)|key(%v)|error(%v)", tableName, mid, key, err)
  497. err = ecode.CreativeDataErr
  498. return
  499. }
  500. if result == nil || len(result.Cells) == 0 {
  501. log.Warn("ThirtyDay no data tableName(%s)|mid(%d)|key(%v)", tableName, mid, key)
  502. return
  503. }
  504. res = make([]*data.ThirtyDay, 0, len(result.Cells))
  505. for _, c := range result.Cells {
  506. if c == nil {
  507. continue
  508. }
  509. qual := string(c.Qualifier[:])
  510. val := string(c.Value[:])
  511. if string(c.Family) == "u" {
  512. t, v, err := parseKeyValue(qual, val)
  513. if err != nil {
  514. break
  515. }
  516. td := &data.ThirtyDay{}
  517. td.DateKey = t
  518. td.TotalIncr = v
  519. res = append(res, td)
  520. }
  521. }
  522. log.Info("ThirtyDayArchive mid(%d) type(%d) return data(%+v)", mid, ty, res)
  523. return
  524. }
  525. func parseKeyValue(k string, v string) (timestamp, value int64, err error) {
  526. tm, err := time.Parse("20060102", k)
  527. if err != nil {
  528. log.Error("time.Parse error(%v)", err)
  529. return
  530. }
  531. timestamp = tm.Unix()
  532. value, err = strconv.ParseInt(v, 10, 64)
  533. if err != nil {
  534. log.Error("strconv.ParseInt error(%v)", err)
  535. }
  536. return
  537. }