kline.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. var myChart;
  2. var app = new Vue({
  3. el: '#app',
  4. data: {
  5. MA5: '',
  6. MA10: '',
  7. MA30: '',
  8. volMA5: '',
  9. volMA10: '',
  10. current: "15m",
  11. tabs: [{
  12. 'label': '1分钟',
  13. 'value': "1m"
  14. },
  15. {
  16. 'label': '15分钟',
  17. 'value': "15m"
  18. },
  19. {
  20. 'label': '30分钟',
  21. 'value': "30m"
  22. },
  23. {
  24. 'label': '1小时',
  25. 'value': "1H"
  26. },
  27. {
  28. 'label': '4小时',
  29. 'value': "4H"
  30. },
  31. {
  32. 'label': '1天',
  33. 'value': "1D"
  34. },
  35. ],
  36. category: 2,
  37. categoryList: [{
  38. 'label': '深度',
  39. 'value': 1
  40. },
  41. {
  42. 'label': '成交',
  43. 'value': 2
  44. },
  45. {
  46. 'label': '简介',
  47. 'value': 3
  48. },
  49. ],
  50. txData: {}, //交易数据统计
  51. buyList: [],
  52. sellList: [],
  53. dealHis: [],
  54. tokenInfo: {},
  55. page: 1,
  56. // 保存商品id
  57. typeId: '',
  58. // 保存socket对象
  59. webSocket: ''
  60. },
  61. created() {
  62. this.getTxData()
  63. // this.getDepth()
  64. // 保存商品id
  65. this.typeId = getQueryString('type');
  66. },
  67. mounted() {
  68. myChart = echarts.init(document.getElementById('main'));
  69. this.draw()
  70. this.getKline();
  71. // 获取成交记录
  72. this.getDealHis();
  73. },
  74. methods: {
  75. // 返回上一页
  76. back() {
  77. uni.navigateBack()
  78. },
  79. scoketInit() {
  80. const that = this;
  81. // 初始化websocket
  82. that.webSocket = new WebSocket("wss://wsaws.okx.com:8443/ws/v5/public");
  83. that.webSocket.onopen = function(event) {
  84. that.webSocket.send(JSON.stringify({
  85. "op": "subscribe",
  86. "args": [{
  87. "channel": "mark-price-candle1Y",
  88. "instId": "BTC-USDT"
  89. }]
  90. }))
  91. }
  92. // 监听socket回复事件
  93. that.webSocket.addEventListener('message', function(event) {
  94. console.log(event, '返回');
  95. });
  96. },
  97. // 获取24小时交易数据统计
  98. getTxData() {
  99. this.txData = txData;
  100. },
  101. // 初始化数据结构
  102. dataInit(data, type) {
  103. let items;
  104. if (type == 1) {
  105. items = data.map(function(item) {
  106. return item[0];
  107. });
  108. }
  109. if (type == 2) {
  110. items = data.map(function(item) {
  111. return [+item[1], +item[2], +item[3], +item[4], +item[5]];
  112. });
  113. }
  114. if (type == 3) {
  115. items = data.map(function(item, index) {
  116. return [index, item[5], item[1] > item[2] ? 1 : -1];
  117. });
  118. }
  119. return items
  120. },
  121. // 初始化时间
  122. initDay(time,fmt) {
  123. let ret;
  124. const opt = {
  125. "Y+": time.getFullYear().toString(), //年
  126. "m+": (time.getMonth()+1).toString(), //月
  127. "d+": time.getDate().toString(), //日
  128. "H+": time.getHours().toString(), //小时
  129. "M+": time.getMinutes().toString(), //分
  130. "S+": time.getSeconds().toString() //秒
  131. };
  132. for (let k in opt) {
  133. ret = new RegExp("("+k+")").exec(fmt)
  134. if(ret){
  135. fmt = fmt.replace(ret[1],(ret[1].length==1)?(opt[k]):(opt[k].padStart(ret[1].length,"0")));
  136. }
  137. }
  138. return fmt;
  139. },
  140. // 获取k线数据,生成k线
  141. getKline() {
  142. console.log('qq');
  143. const that = this;
  144. axiosGet('/api/v5/market/history-candles', {
  145. instId: that.typeId,
  146. bar: that.current,
  147. limit: 100
  148. }).then((res) => {
  149. const ar = res.map((e) => {
  150. let dateTime = new Date(+e[0]);
  151. e[0] = that.initDay(dateTime,"YYYY-mm-dd HH:MM:SS");
  152. return
  153. })
  154. that.setKline(that.dataInit(res, 1), that.dataInit(res, 2), that.dataInit(res, 3))
  155. }).catch((e) => {
  156. console.log(e);
  157. })
  158. },
  159. // 设置线条数据
  160. setKline(dates, data, volumes) {
  161. var dataMA5 = this.calculateMA(5, data);
  162. var dataMA10 = this.calculateMA(10, data);
  163. var dataMA30 = this.calculateMA(30, data);
  164. var volumeMA5 = this.calculateMA(5, volumes);
  165. var volumeMA10 = this.calculateMA(10, volumes);
  166. myChart.setOption({
  167. xAxis: [
  168. {
  169. data: dates
  170. },
  171. {
  172. data: dates
  173. },
  174. ],
  175. series: [{
  176. name: '日K',
  177. data: data
  178. },
  179. {
  180. name: 'MA5',
  181. data: dataMA5
  182. },
  183. {
  184. name: 'MA10',
  185. data: dataMA10
  186. },
  187. {
  188. name: 'MA30',
  189. data: dataMA30
  190. },
  191. {
  192. name: 'Volume',
  193. data: volumes
  194. },
  195. {
  196. name: 'VolumeMA5',
  197. data: volumeMA5
  198. },
  199. {
  200. name: 'VolumeMA10',
  201. data: volumeMA10
  202. },
  203. ]
  204. })
  205. },
  206. // 列表条数不足补全
  207. addItem(list, type) {
  208. // type: 1开头加,2末尾加
  209. list = list || [];
  210. let len = 20 - list.length;
  211. if (len > 0) {
  212. for (let i = 0; i < len; i++) {
  213. if (type == 1) {
  214. list.unshift({})
  215. } else {
  216. list.push({})
  217. }
  218. }
  219. }
  220. return list;
  221. },
  222. // 获取深度数据
  223. // getDepth() {
  224. // this.buyList = this.addItem(depthList().buyList || []);
  225. // this.sellList = this.addItem(depthList().sellList || []);
  226. // },
  227. // 获取成交记录
  228. getDealHis() {
  229. const that = this;
  230. axiosGet('/api/v5/market/history-trades', {
  231. instId: that.typeId,
  232. limit: 100
  233. }).then((res) => {
  234. // 处理返回数据
  235. this.dealHis = res.map((e)=>{
  236. const dateTime = new Date(+e.ts)
  237. return {
  238. "date": that.initDay(dateTime,"mm-dd HH:MM:SS"),
  239. // 1买入 2卖出
  240. "takerFlag": e.side=='buy'?"1":'2',
  241. "price": e.px,
  242. "amount": e.sz
  243. }
  244. })
  245. }).catch((e) => {
  246. console.log(e);
  247. })
  248. },
  249. // 获取项目简介信息
  250. getTokenInfo() {
  251. this.tokenInfo = tokenInfo;
  252. },
  253. // 切换tab
  254. switchTab(val) {
  255. if (this.current == val){ return};
  256. this.current = val;
  257. this.getKline()
  258. },
  259. // 切换类目
  260. switchCategory(val) {
  261. if (this.category == val) return;
  262. this.category = val;
  263. if (this.category == 1) {
  264. this.getDepth()
  265. } else if (this.category == 2) {
  266. this.getDealHis()
  267. } else {
  268. this.getTokenInfo()
  269. }
  270. },
  271. // 截取数字字符串 保留precision小数
  272. formatterNum(value, precision) {
  273. // console.log(value)
  274. let reg = new RegExp('^\\d+(?:\\.\\d{0,' + precision + '})?')
  275. return value.toString().match(reg)
  276. },
  277. // 计算MA
  278. calculateMA(dayCount, data) {
  279. var result = [];
  280. for (var i = 0, len = data.length; i < len; i++) {
  281. if (i < dayCount) {
  282. result.push('-');
  283. continue;
  284. }
  285. var sum = 0;
  286. for (var j = 0; j < dayCount; j++) {
  287. sum += data[i - j][1];
  288. }
  289. // console.log(sum, dayCount)
  290. result.push((sum / dayCount).toFixed(2));
  291. }
  292. return result;
  293. },
  294. // 绘制(配置项)
  295. draw() {
  296. let that = this;
  297. var upColor = '#03ad91';
  298. var downColor = '#dd345b';
  299. var colorList = ['#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83', '#ca8622',
  300. '#bda29a', '#6e7074',
  301. '#546570', '#c4ccd3'
  302. ];
  303. var labelFont = 'bold 12px Sans-serif';
  304. var option = {
  305. backgroundColor: '#0d1723',
  306. title: {
  307. show: false
  308. },
  309. legend: {
  310. show: false
  311. },
  312. visualMap: {
  313. show: false,
  314. seriesIndex: 4,
  315. dimension: 2,
  316. pieces: [{
  317. value: 1,
  318. color: downColor
  319. }, {
  320. value: -1,
  321. color: upColor
  322. }]
  323. },
  324. grid: [{
  325. top: '5%',
  326. left: 20,
  327. right: 20,
  328. height: '70%'
  329. },
  330. {
  331. top: '80%',
  332. left: 20,
  333. right: 20,
  334. height: '16%'
  335. },
  336. ],
  337. axisPointer: { //坐标轴指示器配置项
  338. link: {
  339. xAxisIndex: 'all'
  340. },
  341. label: {
  342. backgroundColor: '#0d1723',
  343. color: '#fff',
  344. borderColor: 'rgb(99, 117, 139)',
  345. borderWidth: 1,
  346. borderRadius: 2,
  347. fontSize: 10
  348. }
  349. },
  350. xAxis: [{
  351. type: 'category', //坐标轴类型。(value:数值轴,适用于连续数据。,category:类目轴,适用于离散的类目数据,time: 时间轴,适用于连续的时序数据,log:对数轴。适用于对数数据)
  352. data: [], //类目数据,在类目轴(type: 'category')中有效。
  353. scale: true,
  354. boundaryGap: false, //坐标轴两边留白策略,类目轴和非类目轴的设置和表现不一样。
  355. axisLine: {
  356. show: false
  357. }, //坐标轴轴线相关设置
  358. axisTick: {
  359. show: false
  360. }, //坐标轴刻度相关设置。
  361. axisLabel: {
  362. show: false,
  363. }, //坐标轴刻度标签的相关设置。
  364. splitLine: {
  365. show: false,
  366. lineStyle: {
  367. color: 'rgba(255,255,255, 0.1)'
  368. }
  369. }, //坐标轴在 grid 区域中的分隔线。
  370. min: 'dataMin', //坐标轴刻度最小值。可以设置成特殊值 'dataMin',此时取数据在该轴上的最小值作为最小刻度。
  371. max: 'dataMax', //坐标轴刻度最大值。可以设置成特殊值 'dataMax',此时取数据在该轴上的最大值作为最大刻度。
  372. axisPointer: {
  373. label: {
  374. margin: 200
  375. }
  376. },
  377. }, {
  378. type: 'category',
  379. gridIndex: 1, //x 轴所在的 grid 的索引,默认位于第一个 grid。
  380. data: [], //类目数据,在类目轴(type: 'category')中有效。
  381. scale: true,
  382. boundaryGap: false, //坐标轴两边留白策略,类目轴和非类目轴的设置和表现不一样。
  383. axisLine: {
  384. show: false,
  385. lineStyle: {
  386. color: 'rgba(255,255,255,1)',
  387. width: 1
  388. }
  389. }, //坐标轴轴线相关设置
  390. axisTick: {
  391. show: false
  392. }, //坐标轴刻度相关设置。
  393. axisLabel: { //坐标轴刻度标签的相关设置。
  394. show: true,
  395. margin: 6,
  396. fontSize: 10,
  397. color: 'rgba(99, 117, 139, 1.0)',
  398. formatter: function(value) {
  399. return echarts.format.formatTime('MM-dd', value);
  400. }
  401. },
  402. splitNumber: 20,
  403. splitLine: {
  404. show: false,
  405. lineStyle: {
  406. color: 'rgba(255,255,255, 0.1)'
  407. }
  408. }, //坐标轴在 grid 区域中的分隔线。
  409. min: 'dataMin', //坐标轴刻度最小值。可以设置成特殊值 'dataMin',此时取数据在该轴上的最小值作为最小刻度。
  410. max: 'dataMax', //坐标轴刻度最大值。可以设置成特殊值 'dataMax',此时取数据在该轴上的最大值作为最大刻度。
  411. // axisPointer: { show: true, type: 'none', label: { show: false }},
  412. }],
  413. yAxis: [{
  414. type: 'value', //坐标轴类型。(value:数值轴,适用于连续数据。,category:类目轴,适用于离散的类目数据,time: 时间轴,适用于连续的时序数据,log:对数轴。适用于对数数据)
  415. position: 'right', //y 轴的位置。'left','right'
  416. scale: true, //是否是脱离 0 值比例。设置成 true 后坐标刻度不会强制包含零刻度。在双数值轴的散点图中比较有用。(在设置 min 和 max 之后该配置项无效。)
  417. axisLine: {
  418. show: true
  419. }, //坐标轴轴线相关设置。
  420. axisTick: {
  421. show: true,
  422. inside: true
  423. }, //坐标轴刻度相关设置。
  424. axisLabel: { //坐标轴刻度标签的相关设置。
  425. show: true,
  426. color: 'rgba(99, 117, 139, 1.0)',
  427. inside: true,
  428. fontSize: 10,
  429. formatter: function(value) {
  430. return Number(value).toFixed(2)
  431. }
  432. },
  433. splitLine: {
  434. show: false,
  435. lineStyle: {
  436. color: 'rgba(255,255,255, 0.1)'
  437. }
  438. }, //坐标轴在 grid 区域中的分隔线。
  439. }, {
  440. type: 'value',
  441. position: 'right',
  442. scale: true,
  443. gridIndex: 1,
  444. axisLine: {
  445. show: false
  446. },
  447. axisTick: {
  448. show: false
  449. },
  450. axisLabel: {
  451. show: false
  452. },
  453. splitLine: {
  454. show: false
  455. }
  456. }],
  457. animation: false, //是否开启动画。
  458. color: colorList,
  459. tooltip: {
  460. show: true, //是否显示提示框组件,包括提示框浮层和 axisPointer。
  461. trigger: 'axis', //触发类型。item,axis,none
  462. formatter(params) {
  463. let tooltip = '';
  464. let time = '',
  465. open = 0,
  466. high = 0,
  467. low = 0,
  468. close = 0,
  469. amount = 0;
  470. for (var i = 0; i < params.length; i++) {
  471. if (params[i].seriesName === '日K') {
  472. time = params[i].name;
  473. open = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  474. 1], 2)) : 0;
  475. close = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  476. 2], 2)) : 0;
  477. low = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  478. 3], 2)) : 0;
  479. high = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  480. 4], 2)) : 0;
  481. amount = params[i].data.length > 1 ? Number(that.formatterNum(params[i]
  482. .data[5], 2)) : 0;
  483. // console.log(time,open,close,low,high,amount)
  484. tooltip = '<div class="charts-tooltip">' +
  485. '<div class="charts-tooltip-row"><div class="ctr-label">' + '时间' +
  486. '</div><div class="ctr-value">' + time + '</div></div>' +
  487. '<div class="charts-tooltip-row"><div class="ctr-label">' + '开' +
  488. '</div><div class="ctr-value">' + open + '</div></div>' +
  489. '<div class="charts-tooltip-row"><div class="ctr-label">' + '高' +
  490. '</div><div class="ctr-value">' + high + '</div></div>' +
  491. '<div class="charts-tooltip-row"><div class="ctr-label">' + '低' +
  492. '</div><div class="ctr-value">' + low + '</div></div>' +
  493. '<div class="charts-tooltip-row"><div class="ctr-label">' + '收' +
  494. '</div><div class="ctr-value">' + close + '</div></div>' +
  495. '<div class="charts-tooltip-row"><div class="ctr-label">' + '数量' +
  496. '</div><div class="ctr-value">' + amount + '</div></div></div>';
  497. }
  498. if (params[i].seriesName === 'MA5') {
  499. that.MA5 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  500. .data, 2)) : 0
  501. }
  502. if (params[i].seriesName === 'MA10') {
  503. that.MA10 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  504. .data, 2)) : 0
  505. }
  506. if (params[i].seriesName === 'MA30') {
  507. that.MA30 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  508. .data, 2)) : 0
  509. }
  510. if (params[i].seriesName === 'VolumeMA5') {
  511. that.volMA5 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  512. .data, 2)) : 0
  513. }
  514. if (params[i].seriesName === 'VolumeMA10') {
  515. that.volMA10 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  516. .data, 2)) : 0
  517. }
  518. }
  519. return tooltip;
  520. },
  521. triggerOn: 'click', //提示框触发的条件 'mousemove','click','mousemove|click','none'
  522. textStyle: {
  523. fontSize: 10
  524. }, //提示框浮层的文本样式
  525. backgroundColor: 'rgba(30,42,66,0.8);', //提示框浮层的背景颜色。
  526. borderColor: '#2f3a56', //提示框浮层的边框颜色。
  527. borderWidth: 2,
  528. position: function(pos, params, el, elRect, size) { //提示框浮层的位置,默认不设置时位置会跟随鼠标的位置。
  529. var obj = {
  530. top: 20
  531. };
  532. obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 10;
  533. return obj;
  534. },
  535. axisPointer: { //坐标轴指示器配置项。
  536. label: {
  537. color: 'rgba(255,255,255,.87)',
  538. fontSize: 9,
  539. backgroundColor: '#020204',
  540. borderColor: "#9c9fa4",
  541. shadowBlur: 0,
  542. borderWidth: 0.5,
  543. padding: [4, 2, 3, 2],
  544. },
  545. animation: false,
  546. type: 'cross',
  547. lineStyle: {
  548. color: {
  549. type: 'linear',
  550. x: 0,
  551. y: 0,
  552. x2: 0,
  553. y2: 1,
  554. colorStops: [{
  555. offset: 0,
  556. color: 'rgba(30, 42, 66, 0.1)' // 0% 处的颜色
  557. }, {
  558. offset: 0.7,
  559. color: 'rgba(30, 42, 66,0.9)' // 100% 处的颜色
  560. }, {
  561. offset: 1,
  562. color: 'rgba(30, 42, 66,0.2)' // 100% 处的颜色
  563. }]
  564. },
  565. width: 10,
  566. shadowColor: 'rgba(30, 42, 66,0.7)',
  567. shadowBlur: 0,
  568. shadowOffsetY: 68,
  569. }
  570. }
  571. },
  572. dataZoom: [{ //用于区域缩放
  573. type: 'inside',
  574. xAxisIndex: [0, 1],
  575. realtime: false,
  576. start: 50,
  577. end: 100,
  578. }],
  579. series: [{
  580. type: 'candlestick',
  581. name: '日K',
  582. data: [],
  583. itemStyle: {
  584. color: upColor,
  585. color0: downColor,
  586. borderColor: upColor,
  587. borderColor0: downColor
  588. },
  589. markPoint: {
  590. symbol: 'rect',
  591. symbolSize: [-10, 0.5],
  592. symbolOffset: [5, 0],
  593. itemStyle: {
  594. color: 'rgba(255,255,255,.87)'
  595. },
  596. label: {
  597. color: 'rgba(255,255,255,.87)',
  598. offset: [10, 0],
  599. fontSize: 10,
  600. align: 'left',
  601. formatter: function(params) {
  602. return Number(params.value).toFixed(2)
  603. }
  604. },
  605. data: [{
  606. name: 'max',
  607. type: 'max',
  608. valueDim: 'highest'
  609. },
  610. {
  611. name: 'min',
  612. type: 'min',
  613. valueDim: 'lowest'
  614. }
  615. ]
  616. },
  617. },
  618. {
  619. name: 'MA5',
  620. type: 'line',
  621. data: [],
  622. symbol: 'none', //去除圆点
  623. smooth: true,
  624. lineStyle: {
  625. normal: {
  626. opacity: 1,
  627. width: 1,
  628. color: "#eef4ba"
  629. }
  630. },
  631. z: 5
  632. },
  633. {
  634. name: 'MA10',
  635. type: 'line',
  636. data: [],
  637. symbol: 'none', //去除圆点
  638. smooth: true,
  639. lineStyle: {
  640. normal: {
  641. opacity: 1,
  642. width: 1,
  643. color: '#83c1c5'
  644. }
  645. },
  646. z: 4
  647. },
  648. {
  649. name: 'MA30',
  650. type: 'line',
  651. data: [],
  652. symbol: 'none', //去除圆点
  653. smooth: true,
  654. lineStyle: {
  655. normal: {
  656. opacity: 1,
  657. width: 1,
  658. color: '#b39cd8'
  659. }
  660. },
  661. z: 3
  662. },
  663. {
  664. name: 'Volume',
  665. type: 'bar',
  666. xAxisIndex: 1,
  667. yAxisIndex: 1,
  668. data: []
  669. },
  670. {
  671. name: 'VolumeMA5',
  672. type: 'line',
  673. xAxisIndex: 1,
  674. yAxisIndex: 1,
  675. data: [],
  676. symbol: 'none', //去除圆点
  677. smooth: true,
  678. lineStyle: {
  679. normal: {
  680. opacity: 1,
  681. width: 1,
  682. color: "#eef4ba"
  683. }
  684. },
  685. z: 5
  686. },
  687. {
  688. name: 'VolumeMA10',
  689. type: 'line',
  690. xAxisIndex: 1,
  691. yAxisIndex: 1,
  692. data: [],
  693. symbol: 'none', //去除圆点
  694. smooth: true,
  695. lineStyle: {
  696. normal: {
  697. opacity: 1,
  698. width: 1,
  699. color: '#83c1c5'
  700. }
  701. },
  702. z: 4
  703. },
  704. ]
  705. };
  706. myChart.setOption(option);
  707. // 加载上一页数据
  708. myChart.on('datazoom', function(params) {
  709. let num = params.batch[0]['start'];
  710. if (num == 0) {
  711. console.log('到最左边了')
  712. }
  713. })
  714. window.addEventListener('resize', () => {
  715. myChart.resize()
  716. })
  717. }
  718. }
  719. })