|
@@ -0,0 +1,541 @@
|
|
|
|
+//index.js
|
|
|
|
+//获取应用实例
|
|
|
|
+const WX_REG = "http://wxapp2.qmth.com.cn/"
|
|
|
|
+const ZH_CN = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十',
|
|
|
|
+ '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十',
|
|
|
|
+ '三十一', '三十二', '三十三', '三十四', '三十五', '三十六', '三十七', '三十八', '三十九', '四十',
|
|
|
|
+ '四十一', '四十二', '四十三', '四十四', '四十五', '四十六', '四十七', '四十八', '四十九', '五十']
|
|
|
|
+const II = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩',
|
|
|
|
+ '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳']
|
|
|
|
+import {
|
|
|
|
+ Api
|
|
|
|
+} from "../../utils/api";
|
|
|
|
+const API = new Api()
|
|
|
|
+const app = getApp()
|
|
|
|
+const RECORD_CONFIG = {
|
|
|
|
+ duration: 120000,
|
|
|
|
+ sampleRate: 44100,
|
|
|
|
+ numberOfChannels: 1,
|
|
|
|
+ encodeBitRate: 128000,
|
|
|
|
+ format: 'mp3',
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Page({
|
|
|
|
+ data: {
|
|
|
|
+ audio: '',
|
|
|
|
+ updated: false,
|
|
|
|
+ isRecord: false,
|
|
|
|
+ recordTime: 0.0,
|
|
|
|
+ duration: "00:00",
|
|
|
|
+ windowWidth: 0,
|
|
|
|
+ maskOpacity: 0,
|
|
|
|
+
|
|
|
|
+ paper: {
|
|
|
|
+ courseId: 0,
|
|
|
|
+ courseName: "",
|
|
|
|
+ examRecordDataId: 0,
|
|
|
|
+ examStudentId: 0,
|
|
|
|
+ questionMainNumber: 0,
|
|
|
|
+ questionOrder: 0,
|
|
|
|
+ subNumber: 0
|
|
|
|
+ },
|
|
|
|
+ currentQuestionTitle: '请扫描题目',
|
|
|
|
+
|
|
|
|
+ audioList: [],
|
|
|
|
+ histories: [],
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ secret: '',
|
|
|
|
+
|
|
|
|
+ recordHandler: 0,
|
|
|
|
+
|
|
|
|
+ recordManager: null,
|
|
|
|
+
|
|
|
|
+ paperStruct: [],
|
|
|
|
+
|
|
|
|
+ resetData: function() {
|
|
|
|
+ this.secret = ''
|
|
|
|
+ this.setData({
|
|
|
|
+ audio: '',
|
|
|
|
+ updated: false,
|
|
|
|
+ isRecord: false,
|
|
|
|
+ recordTime: 0.0,
|
|
|
|
+ duration: "00:00",
|
|
|
|
+ windowWidth: 0,
|
|
|
|
+ maskOpacity: 0,
|
|
|
|
+
|
|
|
|
+ paper: {
|
|
|
|
+ courseId: 0,
|
|
|
|
+ courseName: "",
|
|
|
|
+ examRecordDataId: 0,
|
|
|
|
+ examStudentId: 0,
|
|
|
|
+ questionMainNumber: 0,
|
|
|
|
+ questionOrder: 0,
|
|
|
|
+ subNumber: 0
|
|
|
|
+ },
|
|
|
|
+ currentQuestionTitle: '请扫描题目',
|
|
|
|
+
|
|
|
|
+ audioList: [],
|
|
|
|
+ histories: [],
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ scanQuestion: function(e) {
|
|
|
|
+ // 正在录音 禁止操作
|
|
|
|
+ if (this.data.isRecord) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const that = this
|
|
|
|
+ wx.scanCode({
|
|
|
|
+ onlyFromCamera: true,
|
|
|
|
+ scanType: ['qrCode'],
|
|
|
|
+ success: function(res) {
|
|
|
|
+ console.log(res)
|
|
|
|
+ if (res) {
|
|
|
|
+ that.secret = res.result.replace(WX_REG, '')
|
|
|
|
+ that.checkQrcode(that.secret, true)
|
|
|
|
+ } else {
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '扫码失败',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ lockRecord: false,
|
|
|
|
+
|
|
|
|
+ audioAction: function(e) {
|
|
|
|
+ if (this.lockRecord) {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!this.data.paper || !this.data.paper.questionOrder) {
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '请重新扫描题目二维码',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.lockRecord = true
|
|
|
|
+ this.startRecord()
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ startRecord: function() {
|
|
|
|
+ const that = this
|
|
|
|
+ if (!this.data.isRecord) {
|
|
|
|
+ if (this.data.audio) {
|
|
|
|
+ wx.showModal({
|
|
|
|
+ title: '提示',
|
|
|
|
+ content: '已存在未上传的录音,是否开始重新录音',
|
|
|
|
+ confirmText: '开始录音',
|
|
|
|
+ success(res) {
|
|
|
|
+ if (res.confirm) {
|
|
|
|
+ that.recordManager.start(RECORD_CONFIG)
|
|
|
|
+ } else {
|
|
|
|
+ that.lockRecord = false
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ wx.showLoading({
|
|
|
|
+ title: '',
|
|
|
|
+ mask: true
|
|
|
|
+ })
|
|
|
|
+ that.recordManager.start(RECORD_CONFIG)
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ that.recordManager.stop()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 显示题目列表
|
|
|
|
+ */
|
|
|
|
+ showListPanel() {
|
|
|
|
+ const player = this.selectComponent("#player")
|
|
|
|
+ if (player != null) {
|
|
|
|
+ console.log(player)
|
|
|
|
+ player.stop()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!this.secret) {
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '请先扫描题目',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 正在录音 禁止操作
|
|
|
|
+ if (this.data.isRecord) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ wx.showLoading({
|
|
|
|
+ title: '正在加载',
|
|
|
|
+ mask: true
|
|
|
|
+ })
|
|
|
|
+ const that = this
|
|
|
|
+
|
|
|
|
+ /*if (this.paperStruct && this.paperStruct.length > 0 && this.data.paperthis.paperStruct[0].examRecordDataId == this.data.paper.examRecordDataId) {
|
|
|
|
+ API.getUploadedAudioAnswerList(this.data.paper.examRecordDataId).then(list => {
|
|
|
|
+ that.__inline_getAnswerListSuccess(list)
|
|
|
|
+ }).catch(e => {
|
|
|
|
+ console.log(e)
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '加载失败',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ this.hideActionPanel()
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+
|
|
|
|
+ }*/
|
|
|
|
+
|
|
|
|
+ API.getPaperStruct(this.data.paper.examRecordDataId).then(list => {
|
|
|
|
+ var struct = []
|
|
|
|
+ if (list.defaultPaper.questionGroupList && Array.isArray(list.defaultPaper.questionGroupList) && list.defaultPaper.questionGroupList.length > 0) {
|
|
|
|
+ list.defaultPaper.questionGroupList.forEach(item => {
|
|
|
|
+ struct.push(item.groupName)
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ this.paperStruct = struct
|
|
|
|
+ return API.getUploadedAudioAnswerList(this.data.paper.examRecordDataId)
|
|
|
|
+ }).then(list => {
|
|
|
|
+ that.__inline_getAnswerListSuccess(list)
|
|
|
|
+ }).catch(e => {
|
|
|
|
+ console.log(e)
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '加载失败',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ this.hideActionPanel()
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ __inline_getAnswerListSuccess: function(list) {
|
|
|
|
+ //list = TEST_LIST
|
|
|
|
+
|
|
|
|
+ var histories = []
|
|
|
|
+ if (list && Array.isArray(list) && list.length > 0) {
|
|
|
|
+ list.forEach(item => {
|
|
|
|
+ if (item.mainNumber <= this.paperStruct.length && item.mainNumber > 0) {
|
|
|
|
+ let index = histories.findIndex((v) => {
|
|
|
|
+ return v && v['idx'] === item.mainNumber
|
|
|
|
+ })
|
|
|
|
+ if (index > -1) {
|
|
|
|
+ histories[index]['answers'].push(item)
|
|
|
|
+ } else {
|
|
|
|
+ histories[item.mainNumber] = {
|
|
|
|
+ idx: item.mainNumber,
|
|
|
|
+ title: this.paperStruct[item.mainNumber - 1],
|
|
|
|
+ answers: new Array(item)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error('试题结构异常')
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.setData({
|
|
|
|
+ histories: histories,
|
|
|
|
+ maskOpacity: 0.6
|
|
|
|
+ })
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 关闭题目列表
|
|
|
|
+ */
|
|
|
|
+ hideActionPanel() {
|
|
|
|
+ this.setData({
|
|
|
|
+ maskOpacity: 0
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ uploadAudio(e) {
|
|
|
|
+ // 正在录音 禁止操作
|
|
|
|
+ if (this.data.isRecord) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const filepath = this.data.audio
|
|
|
|
+ const that = this
|
|
|
|
+ wx.showLoading({
|
|
|
|
+ title: '正在上传录音',
|
|
|
|
+ mask: true
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ const duration = filepath
|
|
|
|
+ wx.getFileInfo({
|
|
|
|
+ filePath: filepath,
|
|
|
|
+ success: function(res) {
|
|
|
|
+ console.log(res)
|
|
|
|
+ // 获取上传签名
|
|
|
|
+ API.getSign(that.data.paper.examRecordDataId, that.data.paper.examStudentId,
|
|
|
|
+ that.data.paper.questionOrder, res.digest)
|
|
|
|
+ .then(res => {
|
|
|
|
+ // 上传文件
|
|
|
|
+ console.log(res)
|
|
|
|
+ return API.uploadFile(filepath, res.policy, res.signature, res.uploadUrl)
|
|
|
|
+ }).then(res => {
|
|
|
|
+ console.log(res)
|
|
|
|
+ //文件上传成功后通知服务端
|
|
|
|
+ return API.notifyServer(that.data.paper.examRecordDataId, that.data.paper.examStudentId, that.data.paper.questionOrder, res.url)
|
|
|
|
+ }).then(res => {
|
|
|
|
+ // 轮询答案处理结果
|
|
|
|
+ const _startTime = new Date().getTime()
|
|
|
|
+ var times = 10
|
|
|
|
+ const handler = setInterval(function() {
|
|
|
|
+ API.getNotifyResult(that.data.paper.examRecordDataId, that.data.paper.examStudentId, that.data.paper.questionOrder, res)
|
|
|
|
+ .then(res => {
|
|
|
|
+ console.log(res)
|
|
|
|
+ if (res) {
|
|
|
|
+ clearInterval(handler)
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '上传成功,继续扫描下一题',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ var paper = that.data.paper
|
|
|
|
+ paper['questionMainNumber'] = 0
|
|
|
|
+ paper['questionOrder'] = 0
|
|
|
|
+ paper['subNumber'] = 0
|
|
|
|
+ that.setData({
|
|
|
|
+ audio: '',
|
|
|
|
+ updated: false,
|
|
|
|
+ paper: paper,
|
|
|
|
+ currentQuestionTitle: '请扫描题目'
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ throw '答案未同步'
|
|
|
|
+ }
|
|
|
|
+ }).catch(exceptions => {
|
|
|
|
+ times--
|
|
|
|
+ if (new Date().getTime() - _startTime >= 1000 * 10 || times < 0) {
|
|
|
|
+ clearInterval(handler)
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '上传失败,请重新上传',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }, 1000)
|
|
|
|
+ }).catch(exceptions => {
|
|
|
|
+ console.log('catch', exceptions)
|
|
|
|
+ var error = '上传失败,请重新上传'
|
|
|
|
+ try {
|
|
|
|
+ if (exceptions.statusCode == 500) {
|
|
|
|
+ error = exceptions.data.desc
|
|
|
|
+ }
|
|
|
|
+ } catch (e) {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: error,
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ removeAudio(e) {
|
|
|
|
+ const that = this
|
|
|
|
+ wx.showModal({
|
|
|
|
+ title: '提示',
|
|
|
|
+ content: '删除后无法恢复,是否直接删除',
|
|
|
|
+ confirmText: '直接删除',
|
|
|
|
+ confirmColor: '#ff0000',
|
|
|
|
+ success(res) {
|
|
|
|
+ if (res.confirm) {
|
|
|
|
+ that.setData({
|
|
|
|
+ audio: ''
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ onRecordStart() {
|
|
|
|
+ this.lockRecord = false
|
|
|
|
+ console.log("record start")
|
|
|
|
+ const that = this
|
|
|
|
+
|
|
|
|
+ this.setData({
|
|
|
|
+ audio: '',
|
|
|
|
+ updated: false,
|
|
|
|
+ isRecord: true
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ this.recordHandler = setInterval(function() {
|
|
|
|
+ var recordTime = that.data.recordTime + 0.1
|
|
|
|
+ var second = parseInt(recordTime)
|
|
|
|
+ var msc = parseInt((recordTime - second) * 10) * 10
|
|
|
|
+ var duration = (second > 9 ? second : ('0' + second)) + ":" + (msc > 0 ? msc : "00")
|
|
|
|
+ that.setData({
|
|
|
|
+ isRecord: true,
|
|
|
|
+ recordTime: recordTime,
|
|
|
|
+ duration: duration
|
|
|
|
+ })
|
|
|
|
+ }, 100)
|
|
|
|
+ },
|
|
|
|
+ onRecordStop(audioPath) {
|
|
|
|
+ this.lockRecord = false
|
|
|
|
+ console.log("record stop", audioPath)
|
|
|
|
+ clearInterval(this.recordHandler)
|
|
|
|
+ this.recordHandler = 0
|
|
|
|
+
|
|
|
|
+ this.setData({
|
|
|
|
+ audio: audioPath,
|
|
|
|
+ recordTime: 0,
|
|
|
|
+ duration: "00:00",
|
|
|
|
+ isRecord: false,
|
|
|
|
+ updated: false
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ onShow: function() {
|
|
|
|
+ /*if (this.secret) {
|
|
|
|
+ this.checkQrcode(this.secret, false)
|
|
|
|
+ }*/
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ showConfirmDialog: function(msg, confirm, callback) {
|
|
|
|
+ const confirmText = confirm ? confirm : '确定'
|
|
|
|
+ wx.showModal({
|
|
|
|
+ title: '提示',
|
|
|
|
+ content: msg,
|
|
|
|
+ showCancel: false,
|
|
|
|
+ confirmText: confirmText,
|
|
|
|
+ success(res) {
|
|
|
|
+ if (res.confirm) {
|
|
|
|
+ console.log('用户点击确定')
|
|
|
|
+ if (callback) {
|
|
|
|
+ callback.apply()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ onLoad: function(options) {
|
|
|
|
+ console.log(options)
|
|
|
|
+ const encodeReg = encodeURIComponent(WX_REG)
|
|
|
|
+ if (options && options.q && options.q.indexOf(encodeReg) == 0) {
|
|
|
|
+ this.secret = options.q.replace(encodeReg, '')
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const that = this
|
|
|
|
+
|
|
|
|
+ this.recordManager = wx.getRecorderManager()
|
|
|
|
+ this.recordManager.onError(function(res) {
|
|
|
|
+ console.log(res)
|
|
|
|
+ that.lockRecord = false
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '录音出错',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ this.recordManager.onStart(function () {
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ that.onRecordStart()
|
|
|
|
+ })
|
|
|
|
+ this.recordManager.onStop(function (res) {
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ that.onRecordStop(res.tempFilePath)
|
|
|
|
+ })
|
|
|
|
+ this.recordManager.onInterruptionBegin(function () {
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ console.log("onInterruptionBegin")
|
|
|
|
+ that.lockRecord = false
|
|
|
|
+ that.recordManager.stop()
|
|
|
|
+ })
|
|
|
|
+ this.recordManager.onInterruptionEnd(function () {
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ that.lockRecord = false
|
|
|
|
+ console.log("onInterruptionEnd")
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ API.setTokenValidCallback(this.tokenValidCallback)
|
|
|
|
+
|
|
|
|
+ wx.onAppHide(() => {
|
|
|
|
+ console.log("index onAppHide")
|
|
|
|
+ if (that.data.isRecord) {
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ that.recordManager.stop()
|
|
|
|
+
|
|
|
|
+ that.lockRecord = false
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ checkQrcode: function(code, fromScan) {
|
|
|
|
+ if (fromScan) {
|
|
|
|
+ wx.showLoading({
|
|
|
|
+ title: '正在加载',
|
|
|
|
+ mask: true
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const that = this
|
|
|
|
+ API.checkQrcode(code)
|
|
|
|
+ .then(function(res) {
|
|
|
|
+ const title = `第${ZH_CN.length >= res.questionMainNumber ? ZH_CN[res.questionMainNumber - 1] : res.questionMainNumber}大题 第${II.length >= res.subNumber ? II[res.subNumber-1] : res.subNumber}小题 `
|
|
|
|
+ that.setData({
|
|
|
|
+ audio: '',
|
|
|
|
+ isRecord: false,
|
|
|
|
+ updated: false,
|
|
|
|
+ paper: res,
|
|
|
|
+ currentQuestionTitle: title,
|
|
|
|
+ })
|
|
|
|
+ if (fromScan) {
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ wx.showToast({
|
|
|
|
+ title: '扫码成功',
|
|
|
|
+ icon: 'none'
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .catch(function(error) {
|
|
|
|
+ wx.hideLoading()
|
|
|
|
+ var errorMsg = error
|
|
|
|
+ if (errorMsg.indexOf('request:fail') == 0) {
|
|
|
|
+ errorMsg = "网络请求失败,请稍后重试"
|
|
|
|
+ }
|
|
|
|
+ that.showConfirmDialog(`${errorMsg}`, '确定', function() {
|
|
|
|
+ console.log('callback')
|
|
|
|
+ wx.reLaunch({
|
|
|
|
+ url: '/pages/index/index',
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ tokenValidCallback: function() {
|
|
|
|
+ this.showConfirmDialog('二维码已过期,请重新扫描题目', '立即扫描', function() {
|
|
|
|
+ console.log('callback')
|
|
|
|
+ this.scanQuestion()
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ onUnload: function() {
|
|
|
|
+ const that = this
|
|
|
|
+ wx.offAppHide(() => {
|
|
|
|
+ console.log("index offAppHide")
|
|
|
|
+ if (that.data.isRecord) {
|
|
|
|
+ that.recordManager.stop()
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+})
|