|
@@ -29,6 +29,10 @@ public class BFRecordExport {
|
|
|
public var originSoundVolumn: Float = 1.0 // 无录音时原声大小
|
|
|
public var originSoundInRecordVolumn: Float = 0.0 // 录音时原声大小
|
|
|
|
|
|
+ var titleStickers = [PQEditSubTitleModel]()
|
|
|
+ var voiceList = [PQEditVisionTrackMaterialsModel]()
|
|
|
+ var videoStickers = [PQEditVisionTrackMaterialsModel]()
|
|
|
+
|
|
|
public var data: [BFRecordItemModel]? {
|
|
|
didSet {
|
|
|
if data?.count ?? 0 > 0 {
|
|
@@ -57,10 +61,11 @@ public class BFRecordExport {
|
|
|
// 1,背景视频素材
|
|
|
if let itemModels = data {
|
|
|
var totalDur = 0.0
|
|
|
- var titleStickers = [PQEditSubTitleModel]()
|
|
|
- var voiceList = [PQEditVisionTrackMaterialsModel]()
|
|
|
- var videoStickers = [PQEditVisionTrackMaterialsModel]()
|
|
|
|
|
|
+ titleStickers.removeAll()
|
|
|
+ voiceList.removeAll()
|
|
|
+ videoStickers.removeAll()
|
|
|
+
|
|
|
// 切割视频素材
|
|
|
for (_, itemModel) in itemModels.enumerated() {
|
|
|
// 保留录音部分时,是否按录音顺序合成最终视频;
|
|
@@ -77,28 +82,114 @@ public class BFRecordExport {
|
|
|
model1.timelineIn < model2.timelineIn
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- if itemModel.mediaType == .Image {
|
|
|
- // 图片素材
|
|
|
- if !synthesisAll, itemModel.voiceStickers.count == 0 {
|
|
|
- // 图片无录音在保留模式里不合成
|
|
|
- continue
|
|
|
+
|
|
|
+ switch itemModel.mediaType {
|
|
|
+ case .Image:
|
|
|
+ totalDur += parseImage(synthesisAll: synthesisAll, itemModel: itemModel, totalDur: totalDur)
|
|
|
+
|
|
|
+ case .some(.Video):
|
|
|
+ let dur = parseVideo(synthesisAll: synthesisAll, itemModel: itemModel, totalDur: totalDur)
|
|
|
+ if dur >= 0 {
|
|
|
+ totalDur += dur
|
|
|
+ }else{
|
|
|
+ // -1 时出错
|
|
|
+ return
|
|
|
}
|
|
|
+ case .some(.Camera):
|
|
|
+ totalDur += parseCamera(synthesisAll: synthesisAll, itemModel: itemModel, totalDur: totalDur)
|
|
|
+
|
|
|
+ case .none:
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ // 视频处理
|
|
|
+
|
|
|
+ }
|
|
|
+ beginExport(synthesisAll: synthesisAll)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func parseImage(synthesisAll: Bool, itemModel: BFRecordItemModel, totalDur:Double) -> Double{
|
|
|
+ if !synthesisAll, itemModel.voiceStickers.count == 0 {
|
|
|
+ // 图片无录音在保留模式里不合成
|
|
|
+ return 0
|
|
|
+ }
|
|
|
|
|
|
- var duration = itemModel.materialDuraion.seconds
|
|
|
- if itemModel.voiceStickers.count == 0 {
|
|
|
- // 图片无录音保持2s
|
|
|
- duration = 2
|
|
|
- let voice = PQEditVisionTrackMaterialsModel()
|
|
|
- voice.model_in = 0.0
|
|
|
- voice.out = 2.0
|
|
|
- voice.aptDuration = 2.0
|
|
|
+ var duration = itemModel.materialDuraion.seconds
|
|
|
+ if itemModel.voiceStickers.count == 0 {
|
|
|
+ // 图片无录音保持2s
|
|
|
+ duration = 2
|
|
|
+ let voice = PQEditVisionTrackMaterialsModel()
|
|
|
+ voice.model_in = 0.0
|
|
|
+ voice.out = 2.0
|
|
|
+ voice.aptDuration = 2.0
|
|
|
// voice.voiceType = VOICETYPT.None.rawValue
|
|
|
- voice.volumeGain = 100
|
|
|
- voiceList.append(voice)
|
|
|
- } else {
|
|
|
- //
|
|
|
- for mod in itemModel.voiceStickers {
|
|
|
+ voice.volumeGain = 100
|
|
|
+ voiceList.append(voice)
|
|
|
+ } else {
|
|
|
+ //
|
|
|
+ for mod in itemModel.voiceStickers {
|
|
|
+ let sticker = PQEditVisionTrackMaterialsModel()
|
|
|
+ sticker.model_in = 0
|
|
|
+ sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
|
|
|
+ sticker.timelineIn = totalDur + mod.startCMTime.seconds
|
|
|
+ sticker.timelineOut = totalDur + mod.endCMTime.seconds
|
|
|
+ sticker.aptDuration = sticker.out
|
|
|
+ sticker.duration = sticker.out
|
|
|
+ sticker.locationPath = mod.wavFilePath
|
|
|
+ sticker.volumeGain = 100 // Float64(model.volume)
|
|
|
+ voiceList.append(sticker)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let sticker = splitBaseMaterial(timelineIn: totalDur, model_in: 0, duration: duration)
|
|
|
+ sticker.originalData = itemModel.coverImg?.pngData()
|
|
|
+ sticker.volumeGain = 0
|
|
|
+ sticker.type = StickerType.IMAGE.rawValue
|
|
|
+ videoStickers.append(sticker)
|
|
|
+ BFLog(1, message: "image sticker - timIn:\(sticker.timelineIn), modIn:\(sticker.model_in), dur:\(duration)")
|
|
|
+
|
|
|
+ for titleS in itemModel.titleStickers {
|
|
|
+// let leng = titleS.timelineOut - titleS.timelineIn
|
|
|
+ let newTitleSticker = PQEditSubTitleModel()
|
|
|
+ titleStickers.append(newTitleSticker)
|
|
|
+ newTitleSticker.text = titleS.text
|
|
|
+ newTitleSticker.setting = titleS.setting
|
|
|
+ newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
+ newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
+ }
|
|
|
+
|
|
|
+ return duration
|
|
|
+ }
|
|
|
+
|
|
|
+ func parseVideo(synthesisAll: Bool, itemModel: BFRecordItemModel, totalDur:Double) -> Double {
|
|
|
+
|
|
|
+ var subDur = 0.0
|
|
|
+
|
|
|
+ if let localPath = itemModel.localPath {
|
|
|
+ if !FileManager.default.fileExists(atPath: localPath) {
|
|
|
+ let error = NSError(domain: "err", code: ExportError.FileNotExist.rawValue, userInfo: ["msg": "file not exist"])
|
|
|
+ exportCompletion?(error as Error, nil)
|
|
|
+ return subDur
|
|
|
+ }
|
|
|
+
|
|
|
+// voiceList.append(contentsOf: itemModel.voiceStickers)
|
|
|
+
|
|
|
+ if synthesisAll {
|
|
|
+ let drangs = itemModel.dealedDurationRanges
|
|
|
+ for srange in drangs {
|
|
|
+ let range = srange.range
|
|
|
+ let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
|
|
|
+ sticker.locationPath = localPath
|
|
|
+ sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
|
|
|
+ videoStickers.append(sticker)
|
|
|
+ subDur += range.duration.seconds
|
|
|
+
|
|
|
+ if srange.isRecord {
|
|
|
+ // 处理voice
|
|
|
+ if let mod = itemModel.voiceStickers.first(where: { m in
|
|
|
+ m.startCMTime.seconds == range.start.seconds
|
|
|
+ }) {
|
|
|
let sticker = PQEditVisionTrackMaterialsModel()
|
|
|
sticker.model_in = 0
|
|
|
sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
|
|
@@ -111,152 +202,118 @@ public class BFRecordExport {
|
|
|
voiceList.append(sticker)
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- let sticker = splitBaseMaterial(timelineIn: totalDur, model_in: 0, duration: duration)
|
|
|
- sticker.originalData = itemModel.coverImg?.pngData()
|
|
|
- sticker.volumeGain = 0
|
|
|
- sticker.type = StickerType.IMAGE.rawValue
|
|
|
- videoStickers.append(sticker)
|
|
|
- BFLog(1, message: "image sticker - timIn:\(sticker.timelineIn), modIn:\(sticker.model_in), dur:\(duration)")
|
|
|
-
|
|
|
- for titleS in itemModel.titleStickers {
|
|
|
-// let leng = titleS.timelineOut - titleS.timelineIn
|
|
|
- let newTitleSticker = PQEditSubTitleModel()
|
|
|
- titleStickers.append(newTitleSticker)
|
|
|
- newTitleSticker.text = titleS.text
|
|
|
- newTitleSticker.setting = titleS.setting
|
|
|
- newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
- newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
- }
|
|
|
+ for titleS in itemModel.titleStickers {
|
|
|
+ let newTitleSticker = PQEditSubTitleModel()
|
|
|
+ titleStickers.append(newTitleSticker)
|
|
|
+ newTitleSticker.text = titleS.text
|
|
|
+ newTitleSticker.setting = titleS.setting
|
|
|
+ newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
+ newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
+ }
|
|
|
|
|
|
- totalDur += duration
|
|
|
- continue
|
|
|
- }else if itemModel.mediaType == .Camera {
|
|
|
- videoStickers.append(contentsOf: itemModel.videoStickers)
|
|
|
- //
|
|
|
- for mod in itemModel.voiceStickers {
|
|
|
- let sticker = PQEditVisionTrackMaterialsModel()
|
|
|
- sticker.model_in = 0
|
|
|
- sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
|
|
|
- sticker.timelineIn = totalDur + mod.startCMTime.seconds
|
|
|
- sticker.timelineOut = totalDur + mod.endCMTime.seconds
|
|
|
- sticker.aptDuration = sticker.out
|
|
|
- sticker.duration = sticker.out
|
|
|
- sticker.locationPath = mod.wavFilePath
|
|
|
- sticker.volumeGain = 100 // Float64(model.volume)
|
|
|
- voiceList.append(sticker)
|
|
|
- }
|
|
|
-
|
|
|
- continue
|
|
|
+ } else {
|
|
|
+ // 只保留录音部分
|
|
|
+ var drangs = itemModel.dealedDurationRanges.filter { srange in
|
|
|
+ srange.isRecord == true
|
|
|
}
|
|
|
|
|
|
- // 视频处理
|
|
|
- if let localPath = itemModel.localPath {
|
|
|
- if !FileManager.default.fileExists(atPath: localPath) {
|
|
|
- let error = NSError(domain: "err", code: ExportError.FileNotExist.rawValue, userInfo: ["msg": "file not exist"])
|
|
|
- exportCompletion?(error as Error, nil)
|
|
|
- return
|
|
|
+ let needSort = false
|
|
|
+ if needSort {
|
|
|
+ drangs.sort { range1, range2 in
|
|
|
+ range1.index < range2.index
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
-// voiceList.append(contentsOf: itemModel.voiceStickers)
|
|
|
-
|
|
|
- if synthesisAll {
|
|
|
- var subDur = 0.0
|
|
|
- let drangs = itemModel.dealedDurationRanges
|
|
|
- for srange in drangs {
|
|
|
- let range = srange.range
|
|
|
- let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
|
|
|
- sticker.locationPath = localPath
|
|
|
- sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
|
|
|
- videoStickers.append(sticker)
|
|
|
- subDur += range.duration.seconds
|
|
|
-
|
|
|
- if srange.isRecord {
|
|
|
- // 处理voice
|
|
|
- if let mod = itemModel.voiceStickers.first(where: { m in
|
|
|
- m.startCMTime.seconds == range.start.seconds
|
|
|
- }) {
|
|
|
- let sticker = PQEditVisionTrackMaterialsModel()
|
|
|
- sticker.model_in = 0
|
|
|
- sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
|
|
|
- sticker.timelineIn = totalDur + mod.startCMTime.seconds
|
|
|
- sticker.timelineOut = totalDur + mod.endCMTime.seconds
|
|
|
- sticker.aptDuration = sticker.out
|
|
|
- sticker.duration = sticker.out
|
|
|
- sticker.locationPath = mod.wavFilePath
|
|
|
- sticker.volumeGain = 100 // Float64(model.volume)
|
|
|
- voiceList.append(sticker)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for titleS in itemModel.titleStickers {
|
|
|
- let newTitleSticker = PQEditSubTitleModel()
|
|
|
- titleStickers.append(newTitleSticker)
|
|
|
- newTitleSticker.text = titleS.text
|
|
|
- newTitleSticker.setting = titleS.setting
|
|
|
- newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
- newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
- }
|
|
|
-
|
|
|
- totalDur += subDur
|
|
|
- } else {
|
|
|
- // 只保留录音部分
|
|
|
- var subDur = 0.0
|
|
|
- var drangs = itemModel.dealedDurationRanges.filter { srange in
|
|
|
- srange.isRecord == true
|
|
|
- }
|
|
|
-
|
|
|
- if needSort {
|
|
|
- drangs.sort { range1, range2 in
|
|
|
- range1.index < range2.index
|
|
|
- }
|
|
|
- }
|
|
|
+ for (index, srange) in drangs.enumerated() {
|
|
|
+ let range = srange.range
|
|
|
+ let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
|
|
|
+ sticker.locationPath = localPath
|
|
|
+ sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
|
|
|
+ videoStickers.append(sticker)
|
|
|
|
|
|
- for (index, srange) in drangs.enumerated() {
|
|
|
- let range = srange.range
|
|
|
- let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
|
|
|
- sticker.locationPath = localPath
|
|
|
- sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
|
|
|
- videoStickers.append(sticker)
|
|
|
-
|
|
|
- let voiceSticker = itemModel.voiceStickers[index]
|
|
|
- let voice = PQEditVisionTrackMaterialsModel()
|
|
|
- voice.model_in = 0
|
|
|
- voice.out = voiceSticker.endCMTime.seconds - voiceSticker.startCMTime.seconds
|
|
|
- voice.timelineIn = totalDur + subDur
|
|
|
- voice.timelineOut = totalDur + subDur + voice.out
|
|
|
- voice.aptDuration = voice.out
|
|
|
- voice.duration = voice.out
|
|
|
- voice.locationPath = voiceSticker.wavFilePath
|
|
|
- voice.volumeGain = 100 // Float64(model.volume)
|
|
|
- voiceList.append(voice)
|
|
|
-
|
|
|
- let titleModels = itemModel.titleStickers.filter { mod in
|
|
|
- mod.recordId == voiceSticker.recordId
|
|
|
- }
|
|
|
-
|
|
|
- // 字幕的时间点是以相关录音的原点为坐标计算的。
|
|
|
- for titleS in titleModels {
|
|
|
- let newTitleSticker = PQEditSubTitleModel()
|
|
|
- titleStickers.append(newTitleSticker)
|
|
|
- newTitleSticker.text = titleS.text
|
|
|
- newTitleSticker.setting = titleS.setting
|
|
|
- newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur + subDur , preferredTimescale: 1000) - voiceSticker.startCMTime
|
|
|
- newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur + subDur, preferredTimescale: 1000) - voiceSticker.startCMTime
|
|
|
- BFLog(1, message: "timein - \(newTitleSticker.timelineIn), out - \(newTitleSticker.timelineOut)")
|
|
|
- }
|
|
|
- subDur += range.duration.seconds
|
|
|
- }
|
|
|
-
|
|
|
- totalDur += subDur
|
|
|
+ let voiceSticker = itemModel.voiceStickers[index]
|
|
|
+ let voice = PQEditVisionTrackMaterialsModel()
|
|
|
+ voice.model_in = 0
|
|
|
+ voice.out = voiceSticker.endCMTime.seconds - voiceSticker.startCMTime.seconds
|
|
|
+ voice.timelineIn = totalDur + subDur
|
|
|
+ voice.timelineOut = totalDur + subDur + voice.out
|
|
|
+ voice.aptDuration = voice.out
|
|
|
+ voice.duration = voice.out
|
|
|
+ voice.locationPath = voiceSticker.wavFilePath
|
|
|
+ voice.volumeGain = 100 // Float64(model.volume)
|
|
|
+ voiceList.append(voice)
|
|
|
+
|
|
|
+ let titleModels = itemModel.titleStickers.filter { mod in
|
|
|
+ mod.recordId == voiceSticker.recordId
|
|
|
}
|
|
|
+
|
|
|
+ // 字幕的时间点是以相关录音的原点为坐标计算的。
|
|
|
+ for titleS in titleModels {
|
|
|
+ let newTitleSticker = PQEditSubTitleModel()
|
|
|
+ titleStickers.append(newTitleSticker)
|
|
|
+ newTitleSticker.text = titleS.text
|
|
|
+ newTitleSticker.setting = titleS.setting
|
|
|
+ newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur + subDur , preferredTimescale: 1000) - voiceSticker.startCMTime
|
|
|
+ newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur + subDur, preferredTimescale: 1000) - voiceSticker.startCMTime
|
|
|
+ BFLog(1, message: "timein - \(newTitleSticker.timelineIn), out - \(newTitleSticker.timelineOut)")
|
|
|
+ }
|
|
|
+ subDur += range.duration.seconds
|
|
|
}
|
|
|
}
|
|
|
- beginExport(synthesisAll: synthesisAll, videoStickers: videoStickers, voiceList: voiceList, titleStickers: titleStickers)
|
|
|
}
|
|
|
+ return subDur
|
|
|
}
|
|
|
|
|
|
+ func parseCamera(synthesisAll: Bool, itemModel: BFRecordItemModel, totalDur:Double) -> Double {
|
|
|
+
|
|
|
+ var duration = itemModel.materialDuraion.seconds
|
|
|
+
|
|
|
+ // 视频分解
|
|
|
+ for mod in itemModel.videoStickers {
|
|
|
+ let sticker = PQEditVisionTrackMaterialsModel()
|
|
|
+ sticker.type = StickerType.VIDEO.rawValue
|
|
|
+ sticker.canvasFillType = stickerContentMode.aspectFitStr.rawValue
|
|
|
+ sticker.model_in = 0
|
|
|
+ sticker.out = (mod.timelineCMOut - mod.timelineCMIn).seconds
|
|
|
+ sticker.timelineIn = totalDur + mod.timelineCMIn.seconds
|
|
|
+ sticker.timelineOut = totalDur + mod.timelineCMOut.seconds
|
|
|
+ sticker.aptDuration = sticker.out
|
|
|
+ sticker.duration = sticker.out
|
|
|
+ sticker.locationPath = mod.locationPath.replacingOccurrences(of: documensDirectory, with: "")
|
|
|
+ sticker.volumeGain = 1 // Float64(model.volume)
|
|
|
+ videoStickers.append(sticker)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 音频分解
|
|
|
+ for mod in itemModel.voiceStickers {
|
|
|
+ let sticker = PQEditVisionTrackMaterialsModel()
|
|
|
+ sticker.model_in = 0
|
|
|
+ sticker.type = StickerType.VOICE.rawValue
|
|
|
+ sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
|
|
|
+ sticker.timelineIn = totalDur + mod.startCMTime.seconds
|
|
|
+ sticker.timelineOut = totalDur + mod.endCMTime.seconds
|
|
|
+ sticker.aptDuration = sticker.out
|
|
|
+ sticker.duration = sticker.out
|
|
|
+ sticker.locationPath = mod.wavFilePath
|
|
|
+ sticker.volumeGain = 100 // Float64(model.volume)
|
|
|
+ voiceList.append(sticker)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 字幕分解
|
|
|
+ for titleS in itemModel.titleStickers {
|
|
|
+ let newTitleSticker = PQEditSubTitleModel()
|
|
|
+ titleStickers.append(newTitleSticker)
|
|
|
+ newTitleSticker.text = titleS.text
|
|
|
+ newTitleSticker.setting = titleS.setting
|
|
|
+ newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
+ newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
|
|
|
+ }
|
|
|
+
|
|
|
+ return duration
|
|
|
+ }
|
|
|
+
|
|
|
public func cancelExport() {
|
|
|
exporter?.cancel()
|
|
|
|
|
@@ -304,7 +361,7 @@ public class BFRecordExport {
|
|
|
|
|
|
// 因为titleStickers 是传递过来的,会修改timelinein,需要重新生成,以免影响原来的数据
|
|
|
// voiceList是考虑到图片有时候没有录音,在保留全部时,需要添加一个2秒的空sticker
|
|
|
- func beginExport(synthesisAll: Bool, videoStickers: [PQEditVisionTrackMaterialsModel], voiceList: [PQEditVisionTrackMaterialsModel], titleStickers: [PQEditSubTitleModel]) {
|
|
|
+ func beginExport(synthesisAll: Bool) {
|
|
|
// 输出视频地址
|
|
|
// exprotVideo()
|
|
|
// return;
|
|
@@ -350,6 +407,8 @@ public class BFRecordExport {
|
|
|
return partialResult + (srange.isRecord ? srange.range.duration.seconds : 0)
|
|
|
}
|
|
|
}
|
|
|
+ }else if itemModell.mediaType == .Camera {
|
|
|
+ modelDuraion = itemModell.materialDuraion.seconds
|
|
|
}
|
|
|
return (partialResult ?? 0) + modelDuraion
|
|
|
}) else {
|