From 23ae82968d03faf92aab2d1f856d15c78059c91a Mon Sep 17 00:00:00 2001 From: BilalKhanWDI Date: Mon, 8 Jul 2024 19:02:03 +0530 Subject: [PATCH] - My list audio listing, handled the model. - Added lazy loading for karaoke - Completed lazy loading of audio books --- WOKA/Audio Books/AudioBookDetailsVC.swift | 18 ++-- WOKA/Audio Books/AudioBookHomeVC.swift | 12 ++- WOKA/Audio Books/AudioBookHomeVM.swift | 21 ++++- WOKA/Audio Books/AudioBooks.storyboard | 48 ++++++++++- WOKA/Audio Books/ListenAudioListingDM.swift | 52 +++++++++++ WOKA/Games/Controller/GamesListVC.swift | 1 - WOKA/Home/Controller/MyListVC.swift | 36 +++++++- WOKA/Home/Model/FavouriteListingDM.swift | 21 +---- WOKA/Home/View/FavouriteCell.swift | 31 +++++++ .../Karaoke/Controller/KaraokeDetailsVC.swift | 15 +++- .../Karaoke/Controller/KaraokeListingVC.swift | 11 ++- WOKA/Karaoke/Karaoke.storyboard | 86 ++++++++++++++----- WOKA/Karaoke/ViewModel/KaraokeListingVM.swift | 25 ++++-- 13 files changed, 308 insertions(+), 69 deletions(-) diff --git a/WOKA/Audio Books/AudioBookDetailsVC.swift b/WOKA/Audio Books/AudioBookDetailsVC.swift index 352c2d8..7e68046 100644 --- a/WOKA/Audio Books/AudioBookDetailsVC.swift +++ b/WOKA/Audio Books/AudioBookDetailsVC.swift @@ -8,7 +8,7 @@ import UIKit protocol ReloadAudioBooksFavLike{ - func updateRows(id : Int, type : FavCellCLick, isFav : Bool? , isLike : Bool? ) + func updateAudioRows(id : Int, type : FavCellCLick, isFav : Bool? , isLike : Bool? ) } class AudioBookDetailsVC : UIViewController{ @@ -54,14 +54,14 @@ class AudioBookDetailsVC : UIViewController{ LikeFavCommonFunc.shareInstance.removeFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in self.audioData?.markAsFavourite = false K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .favourite, isFav: false, isLike: nil) + self.delegate?.updateAudioRows(id: showID, type: .favourite, isFav: false, isLike: nil) self.initView() } }else{ LikeFavCommonFunc.shareInstance.addFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in self.audioData?.markAsFavourite = true K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .favourite, isFav: true, isLike: nil) + self.delegate?.updateAudioRows(id: showID, type: .favourite, isFav: true, isLike: nil) self.initView() } } @@ -74,14 +74,14 @@ class AudioBookDetailsVC : UIViewController{ LikeFavCommonFunc.shareInstance.removeFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in self.continueAudioData?.markAsFavourite = false K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .favourite, isFav: false, isLike: nil) + self.delegate?.updateAudioRows(id: showID, type: .favourite, isFav: false, isLike: nil) self.initView() } }else{ LikeFavCommonFunc.shareInstance.addFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in self.continueAudioData?.markAsFavourite = true K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .favourite, isFav: true, isLike: nil) + self.delegate?.updateAudioRows(id: showID, type: .favourite, isFav: true, isLike: nil) self.initView() } } @@ -100,14 +100,14 @@ class AudioBookDetailsVC : UIViewController{ LikeFavCommonFunc.shareInstance.unlikePost(postID: showID, postType: postType, vc: self) { isDone in self.audioData?.isLiked = false K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: false) + self.delegate?.updateAudioRows(id: showID, type: .liked, isFav: nil, isLike: false) self.initView() } }else{ LikeFavCommonFunc.shareInstance.likePost(postID: showID, postType: postType, vc: self) { isDone in self.audioData?.isLiked = true K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: true) + self.delegate?.updateAudioRows(id: showID, type: .liked, isFav: nil, isLike: true) self.initView() } } @@ -120,14 +120,14 @@ class AudioBookDetailsVC : UIViewController{ LikeFavCommonFunc.shareInstance.unlikePost(postID: showID, postType: postType, vc: self) { isDone in self.continueAudioData?.isLiked = false K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: false) + self.delegate?.updateAudioRows(id: showID, type: .liked, isFav: nil, isLike: false) self.initView() } }else{ LikeFavCommonFunc.shareInstance.likePost(postID: showID, postType: postType, vc: self) { isDone in self.continueAudioData?.isLiked = true K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: true) + self.delegate?.updateAudioRows(id: showID, type: .liked, isFav: nil, isLike: true) self.initView() } } diff --git a/WOKA/Audio Books/AudioBookHomeVC.swift b/WOKA/Audio Books/AudioBookHomeVC.swift index 77a1239..f8cf55c 100644 --- a/WOKA/Audio Books/AudioBookHomeVC.swift +++ b/WOKA/Audio Books/AudioBookHomeVC.swift @@ -24,6 +24,9 @@ class AudioBookHomeVC: UIViewController { @IBOutlet weak var headerTitleLabel: UILabel! @IBOutlet weak var listenView: ShimmerEffectView! + @IBOutlet weak var loadMoreBtn: LocalisedElementsButton! + @IBOutlet weak var loadMoreActivityIndicator: UIActivityIndicatorView! + override func viewDidLoad() { super.viewDidLoad() vm.vc = self @@ -62,6 +65,13 @@ class AudioBookHomeVC: UIViewController { vm.updateTableHeight() } + @IBAction func loadMoreBtn(_ sender: LocalisedElementsButton) { + loadMoreBtn.isHidden = true + vm.pageNo += 1 + loadMoreActivityIndicator.startAnimating() + vm.getShowListing() + } + @IBAction func listenAudioBtnTapped(_ sender: LocalisedElementsButton) { let data = vm.audioListData[vm.indexToLoad] var playerItems = [JwPlayerItemCreate]() @@ -82,7 +92,7 @@ class AudioBookHomeVC: UIViewController { extension AudioBookHomeVC : ReloadAudioBooksFavLike{ - func updateRows(id: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { + func updateAudioRows(id: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { if let isFav{ if let continueDataIndex = vm.continueWatchingData.firstIndex(where:{$0.id == id}) { vm.continueWatchingData[continueDataIndex].markAsFavourite = isFav diff --git a/WOKA/Audio Books/AudioBookHomeVM.swift b/WOKA/Audio Books/AudioBookHomeVM.swift index b5e27d4..7bce370 100644 --- a/WOKA/Audio Books/AudioBookHomeVM.swift +++ b/WOKA/Audio Books/AudioBookHomeVM.swift @@ -14,7 +14,8 @@ class AudioBookHomeVM{ var continueWatchingData = [ContinueAudioListDM.ResultData]() var audioListData = [ListenAudioListingDM.AudioDatum]() var indexToLoad = 0 - + var pageNo = 0 + func initView(){ startShimmer() setupCell() @@ -111,7 +112,10 @@ class AudioBookHomeVM{ func getShowListing(){ // Utilities.startProgressHUD() let headers : HTTPHeaders = ["access-token" : AuthFunc.shareInstance.getAccessToken()] - NetworkManager.shareInstance.apiRequest(url: APIEndPoints.AudioBooks.listen_audio_listing, method: .post,headers: headers) { [weak self](result : Result, NetworkManager.APIError>) in + let params : Parameters = ["api_version" : "v2", + "start" : pageNo, + "limit": 10] + NetworkManager.shareInstance.apiRequest(url: APIEndPoints.AudioBooks.listen_audio_listing, method: .post, parameters: params,headers: headers) { [weak self](result : Result, NetworkManager.APIError>) in switch result{ case .success(let data): guard let self else{ @@ -128,8 +132,7 @@ class AudioBookHomeVM{ case 1: Utilities.dismissProgressHUD() guard let data = data.data?.audioData else{return} - self.audioListData.removeAll() - self.audioListData = data + self.audioListData.append(contentsOf: data) self.vc.audioListingTableView.reloadData() self.vc.tableHeight.constant = self.vc.audioListingTableView.contentSize.height + 100 self.vc.audioListingTableView.layoutIfNeeded() @@ -137,6 +140,16 @@ class AudioBookHomeVM{ self.indexToLoad = 0 self.setInitialData() self.stopShimmer() + + self.vc.loadMoreActivityIndicator.stopAnimating() + self.vc.loadMoreActivityIndicator.hidesWhenStopped = true + + if self.audioListData.count.isMultiple(of: 10){ + // if not multiple of 10, means more data can be there, show more btn + self.vc.loadMoreBtn.isHidden = false + }else{ + self.vc.loadMoreBtn.isHidden = true + } default: break } diff --git a/WOKA/Audio Books/AudioBooks.storyboard b/WOKA/Audio Books/AudioBooks.storyboard index e546a97..b6b9efa 100644 --- a/WOKA/Audio Books/AudioBooks.storyboard +++ b/WOKA/Audio Books/AudioBooks.storyboard @@ -98,10 +98,10 @@ - + + + + + + + + + + + + + + + + + @@ -189,6 +231,8 @@ + + diff --git a/WOKA/Audio Books/ListenAudioListingDM.swift b/WOKA/Audio Books/ListenAudioListingDM.swift index ecf1adc..b962ab6 100644 --- a/WOKA/Audio Books/ListenAudioListingDM.swift +++ b/WOKA/Audio Books/ListenAudioListingDM.swift @@ -93,3 +93,55 @@ struct ListenAudioListingDM: Codable { } +// +//{ +// "id": 6, +// "title": "DADAGIRI KI AISI KI TAISE", +// "description": "

Kalu and Chitta are the two big bullies of the school who don't stop at troubling anyone. They steal someone's food and bully someone. ADI and his friends can't take it all. They go to seek help from the wise sage, Piku Baba. What clever method did Piku Baba tell Kalu and Chitta to teach them a lesson? Has Kalu and Chitta's bullying come to an end? Can ADI and his crew stop them? Listen to this funny story to find out.

", +// "thumbnail_path": "https://wokaland.com/admin/storage/app/public/uploads/Listen/64b2bdf9d277d.png?d=1719904091", +// "audio_url": "https://content.jwplatform.com/videos/tUJ8m9W0-Ysj2G4DQ.mp4", +// "category_master_id": "11", +// "age_range_master_id": "0", +// "tags_keyword": "0", +// "release_date": "2023-07-15 00:00:00", +// "language_master_id": 1, +// "gender_master_id": "0", +// "audio_duration": "00:07:25", +// "media_id": "", +// "content_more_details": [ +// { +// "id": 831, +// "content_id": 6, +// "post_type": 7, +// "language_master_id": 1, +// "title": "DADAGIRI KI AISI KI TAISE", +// "description": "

Kalu and Chitta are the two big bullies of the school who don't stop at troubling anyone. They steal someone's food and bully someone. ADI and his friends can't take it all. They go to seek help from the wise sage, Piku Baba. What clever method did Piku Baba tell Kalu and Chitta to teach them a lesson? Has Kalu and Chitta's bullying come to an end? Can ADI and his crew stop them? Listen to this funny story to find out.

", +// "url": "https://content.jwplatform.com/videos/tUJ8m9W0-Ysj2G4DQ.mp4", +// "tags_keywords": "0" +// }, +// { +// "id": 832, +// "content_id": 6, +// "post_type": 7, +// "language_master_id": 2, +// "title": "दादागिरी की ऐसी की तैसी", +// "description": "

कालू और चिट्टा स्कूल के दो बड़े बदमाश हैं जो किसी को भी सताने से बाज़ नहीं आते। किसी का वे खाना चुरा लेते हैं और किसी के ऊपर दादागिरी जमाते रहते हैं। आदि और उसके दोस्त यह सब सहन नहीं कर पा रहे हैं। वे ज्ञानी साधु, पीकू बाबा से मदद माँगने जाते हैं। कालू और चिट्ठा को सबक सिखानेके लिए। पीकू बाबा ने उन्हें कौन सा खुफिया तरीका बताया? क्या कालू और चिट्टा की दादागिरी ख़त्म हुई? क्या आदि और उसका दल उन्हें रोक पाते हैं? पता लगाने के लिए यह मज़ेदार कहानी सुनो।

", +// "url": "https://content.jwplatform.com/videos/tUJ8m9W0-Ysj2G4DQ.mp4", +// "tags_keywords": "0" +// } +// ], +// "user_video_view": [], +// "category_data": [ +// { +// "id": 11, +// "category_name": "Audio" +// } +// ], +// "age_range_data": [], +// "gender_data": [], +// "mark_as_favourite": false, +// "is_liked": false, +// "views_count": 4763, +// "likes_count": 20, +// "bookmark_count": 15 +// } diff --git a/WOKA/Games/Controller/GamesListVC.swift b/WOKA/Games/Controller/GamesListVC.swift index 143b576..d4e0ea7 100644 --- a/WOKA/Games/Controller/GamesListVC.swift +++ b/WOKA/Games/Controller/GamesListVC.swift @@ -8,7 +8,6 @@ import UIKit class GamesListVC: UIViewController { - @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var headerHeight: NSLayoutConstraint! diff --git a/WOKA/Home/Controller/MyListVC.swift b/WOKA/Home/Controller/MyListVC.swift index a0a56a2..185d267 100644 --- a/WOKA/Home/Controller/MyListVC.swift +++ b/WOKA/Home/Controller/MyListVC.swift @@ -136,7 +136,7 @@ extension MyListVC : CollectionViewSRC{ cell.setData(data: data) case audioBooksCV: if let data = vm.favListingData?.audioData?[indexPath.row]{ - cell.setOtherData(data: data) + cell.setAudioData(data: data) } case karaokeCV: if let data = vm.favListingData?.singKaraokeData?[indexPath.row]{ @@ -410,12 +410,46 @@ extension MyListVC : CollectionViewSRC{ vcPush.vm.categoryID = 18 self.navigationController?.pushViewController(vcPush, animated: true) self.vm.selectedCollection = .webSeriesHindiCV + case audioBooksCV: + guard let audioData = vm.favListingData?.audioData?[indexPath.row] else{return} + + let sb = UIStoryboard(name: K.StoryBoard.audioBooks, bundle: nil) + let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.AudioBooks.audioBookDetailsVC) as! AudioBookDetailsVC + vcPush.modalPresentationStyle = .overCurrentContext + vcPush.modalTransitionStyle = .crossDissolve + vcPush.audioData = audioData + vcPush.delegate = self + self.present(vcPush, animated: true) default: print(indexPath.row) } } } +// MARK: - Delegate for reload + +extension MyListVC : ReloadAudioBooksFavLike{ + + func updateAudioRows(id: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { + if let isFav{ + + if let audioListDataIndex = vm.favListingData?.audioData?.firstIndex(where:{$0.id == id}) { + vm.favListingData?.audioData?[audioListDataIndex].markAsFavourite = isFav + audioBooksCV.reloadItems(at: [IndexPath(row: audioListDataIndex, section: 0)]) + K.GVar.reloadMyList = true + } + } + + if let isLike{ + + if let audioListDataIndex = vm.favListingData?.audioData?.firstIndex(where:{$0.id == id}) { + vm.favListingData?.audioData?[audioListDataIndex].isLiked = isLike + audioBooksCV.reloadItems(at: [IndexPath(row: audioListDataIndex, section: 0)]) + K.GVar.reloadMyList = true + } + } + } +} extension MyListVC : ReloadSeriesFavLike{ func updateRows(index: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { diff --git a/WOKA/Home/Model/FavouriteListingDM.swift b/WOKA/Home/Model/FavouriteListingDM.swift index 5dde493..9d94664 100644 --- a/WOKA/Home/Model/FavouriteListingDM.swift +++ b/WOKA/Home/Model/FavouriteListingDM.swift @@ -15,8 +15,8 @@ struct FavouriteListingDM: Codable { struct ResultData: Codable { var showData: [ShowDatum]? var videoData: [Datum]? - var gameData, audioData, singKaraokeData: [Datum]? - + var gameData, singKaraokeData: [Datum]? + var audioData : [ListenAudioListingDM.AudioDatum]? enum CodingKeys: String, CodingKey { case showData = "show_data" case videoData = "video_data" @@ -69,23 +69,6 @@ struct FavouriteListingDM: Codable { } } - // MARK: - ContentMoreDetail -// struct ContentMoreDetail: Codable { -// let id, contentID, postType, languageMasterID: Int? -// let title, description: String? -// let url: String? -// let tagsKeywords: String? -// -// enum CodingKeys: String, CodingKey { -// case id -// case contentID = "content_id" -// case postType = "post_type" -// case languageMasterID = "language_master_id" -// case title, description, url -// case tagsKeywords = "tags_keywords" -// } -// } - // MARK: - ShowDatum struct ShowDatum: Codable { let id: Int? diff --git a/WOKA/Home/View/FavouriteCell.swift b/WOKA/Home/View/FavouriteCell.swift index f387a6c..8579c17 100644 --- a/WOKA/Home/View/FavouriteCell.swift +++ b/WOKA/Home/View/FavouriteCell.swift @@ -102,4 +102,35 @@ class FavouriteCell: UICollectionViewCell { } } } + + func setAudioData(data : ListenAudioListingDM.AudioDatum){ + //heart.fill , heart , hand.thumbsup.fill , hand.thumbsup + if AuthFunc.shareInstance.getDefaultLanguage() == .english{ + cellTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 1}).first?.title + }else{ + cellTitle.text = data.contentMoreDetails?.filter({$0.languageMasterID == 2}).first?.title + } + totalLikes.text = data.likesCount?.toString() ?? "0" + if let url = data.thumbnailPath{ + cellImage.imageURL(url) + } + + if let favourite = data.markAsFavourite{ + switch favourite{ + case true: + favBtnn.setImage(UIImage(named: "FavouriteAdd"), for: .normal) + case false: + favBtnn.setImage(UIImage(named: "FavouriteRemove"), for: .normal) + } + } + + if let like = data.isLiked{ + switch like{ + case true: + likeBtn.setImage(UIImage(named: "LikeAdd"), for: .normal) + case false: + likeBtn.setImage(UIImage(named: "LikeRemove"), for: .normal) + } + } + } } diff --git a/WOKA/Karaoke/Controller/KaraokeDetailsVC.swift b/WOKA/Karaoke/Controller/KaraokeDetailsVC.swift index 6c1edc8..c28b279 100644 --- a/WOKA/Karaoke/Controller/KaraokeDetailsVC.swift +++ b/WOKA/Karaoke/Controller/KaraokeDetailsVC.swift @@ -23,6 +23,7 @@ class KaraokeDetailsVC: UIViewController { @IBOutlet weak var addView: UIView! @IBOutlet weak var shareView: UIView! @IBOutlet weak var likeView: UIView! + @IBOutlet weak var singNowBtn: LocalisedElementsButton! var karaokeData : KaraokeListingDM.KaraokeDatum? var delegate : ReloadAudioBooksFavLike? @@ -31,6 +32,12 @@ class KaraokeDetailsVC: UIViewController { super.viewDidLoad() initView() tapHandler() + + singNowBtn.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.25).cgColor + singNowBtn.layer.shadowOffset = CGSize(width: 0, height: 3) + singNowBtn.layer.shadowOpacity = 1.0 + singNowBtn.layer.shadowRadius = 10.0 + singNowBtn.layer.masksToBounds = false } func initView(){ @@ -106,14 +113,14 @@ class KaraokeDetailsVC: UIViewController { LikeFavCommonFunc.shareInstance.removeFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in self.karaokeData?.markAsFavourite = false K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .favourite, isFav: false, isLike: nil) + self.delegate?.updateAudioRows(id: showID, type: .favourite, isFav: false, isLike: nil) self.initView() } }else{ LikeFavCommonFunc.shareInstance.addFavourite(postID: showID, postType: postType, categoryID: 0, vc: self) { isDone in self.karaokeData?.markAsFavourite = true K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .favourite, isFav: true, isLike: nil) + self.delegate?.updateAudioRows(id: showID, type: .favourite, isFav: true, isLike: nil) self.initView() } } @@ -130,14 +137,14 @@ class KaraokeDetailsVC: UIViewController { LikeFavCommonFunc.shareInstance.unlikePost(postID: showID, postType: postType, vc: self) { isDone in self.karaokeData?.isLiked = false K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: false) + self.delegate?.updateAudioRows(id: showID, type: .liked, isFav: nil, isLike: false) self.initView() } }else{ LikeFavCommonFunc.shareInstance.likePost(postID: showID, postType: postType, vc: self) { isDone in self.karaokeData?.isLiked = true K.GVar.reloadMyList = true - self.delegate?.updateRows(id: showID, type: .liked, isFav: nil, isLike: true) + self.delegate?.updateAudioRows(id: showID, type: .liked, isFav: nil, isLike: true) self.initView() } } diff --git a/WOKA/Karaoke/Controller/KaraokeListingVC.swift b/WOKA/Karaoke/Controller/KaraokeListingVC.swift index 79e8b4a..a0f377d 100644 --- a/WOKA/Karaoke/Controller/KaraokeListingVC.swift +++ b/WOKA/Karaoke/Controller/KaraokeListingVC.swift @@ -22,6 +22,8 @@ class KaraokeListingVC: UIViewController { @IBOutlet weak var karaokeListingTableView: UITableView! @IBOutlet weak var tableHeight: NSLayoutConstraint! + @IBOutlet weak var loadMoreBtn: LocalisedElementsButton! + @IBOutlet weak var loadMoreActivityIndicator: UIActivityIndicatorView! var vm = KaraokeListingVM() @@ -56,6 +58,13 @@ class KaraokeListingVC: UIViewController { super.viewDidLayoutSubviews() vm.updateTableHeight() } + + @IBAction func loadMoreBtnTapped(_ sender: LocalisedElementsButton) { + loadMoreBtn.isHidden = true + vm.pageNo += 1 + loadMoreActivityIndicator.startAnimating() + vm.getKaraokeListing() + } } // MARK: - CollectionView Delegate and Data Source @@ -169,7 +178,7 @@ extension KaraokeListingVC : TableViewSRC{ } extension KaraokeListingVC : ReloadAudioBooksFavLike{ - func updateRows(id: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { + func updateAudioRows(id: Int, type: FavCellCLick, isFav: Bool?, isLike: Bool?) { if let isFav{ if let continueDataIndex = vm.continueWatchingData.firstIndex(where:{$0.id == id}) { vm.continueWatchingData[continueDataIndex].markAsFavourite = isFav diff --git a/WOKA/Karaoke/Karaoke.storyboard b/WOKA/Karaoke/Karaoke.storyboard index cc96791..7fb8004 100644 --- a/WOKA/Karaoke/Karaoke.storyboard +++ b/WOKA/Karaoke/Karaoke.storyboard @@ -98,10 +98,10 @@ - + + + + + + + + + + + + + + + + + @@ -187,6 +230,8 @@ + + @@ -516,6 +561,7 @@ + @@ -535,17 +581,17 @@ - + - + - + - + - + - + @@ -661,18 +707,19 @@ - + - - - - + - +