|  |  |  | @ -5,20 +5,15 @@ import 'package:easy_localization/easy_localization.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:flutter/cupertino.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:flutter/foundation.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:http/http.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:logging/logging.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/api/chat/chat_api_client.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/app_state/app_state.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/classes/consts.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/classes/utils.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/exceptions/api_exception.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/main.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/models/chat/get_search_user_chat_model.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/models/chat/get_user_login_token_model.dart' as login; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/models/chat/make_user_favotire_unfavorite_chat_model.dart' as fav; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:mohem_flutter_app/widgets/image_picker.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:signalr_netcore/signalr_client.dart'; | 
		
	
		
			
				|  |  |  |  | import 'package:uuid/uuid.dart'; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
	
		
			
				
					|  |  |  | @ -92,12 +87,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     if (isNewChat) userChatHistory = []; | 
		
	
		
			
				|  |  |  |  |     if (!loadMore) paginationVal = 0; | 
		
	
		
			
				|  |  |  |  |     isChatScreenActive = true; | 
		
	
		
			
				|  |  |  |  |     Response response = await ChatApiClient().getSingleUserChatHistory( | 
		
	
		
			
				|  |  |  |  |       senderUID: senderUID, | 
		
	
		
			
				|  |  |  |  |       receiverUID: receiverUID, | 
		
	
		
			
				|  |  |  |  |       loadMore: loadMore, | 
		
	
		
			
				|  |  |  |  |       paginationVal: paginationVal, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |     Response response = await ChatApiClient().getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); | 
		
	
		
			
				|  |  |  |  |     if (response.statusCode == 204) { | 
		
	
		
			
				|  |  |  |  |       if (isNewChat) { | 
		
	
		
			
				|  |  |  |  |         userChatHistory = []; | 
		
	
	
		
			
				
					|  |  |  | @ -107,25 +97,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       if (loadMore) { | 
		
	
		
			
				|  |  |  |  |         List<SingleUserChatModel> temp = getSingleUserChatModel( | 
		
	
		
			
				|  |  |  |  |           response.body, | 
		
	
		
			
				|  |  |  |  |         ).reversed.toList(); | 
		
	
		
			
				|  |  |  |  |         userChatHistory.addAll( | 
		
	
		
			
				|  |  |  |  |           temp, | 
		
	
		
			
				|  |  |  |  |         ); | 
		
	
		
			
				|  |  |  |  |         List<SingleUserChatModel> temp = getSingleUserChatModel(response.body).reversed.toList(); | 
		
	
		
			
				|  |  |  |  |         userChatHistory.addAll(temp); | 
		
	
		
			
				|  |  |  |  |       } else { | 
		
	
		
			
				|  |  |  |  |         userChatHistory = getSingleUserChatModel( | 
		
	
		
			
				|  |  |  |  |           response.body, | 
		
	
		
			
				|  |  |  |  |         ).reversed.toList(); | 
		
	
		
			
				|  |  |  |  |         userChatHistory = getSingleUserChatModel(response.body).reversed.toList(); | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     isLoading = false; | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |     markRead( | 
		
	
		
			
				|  |  |  |  |       userChatHistory, | 
		
	
		
			
				|  |  |  |  |       receiverUID, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     markRead(userChatHistory, receiverUID); | 
		
	
		
			
				|  |  |  |  |     generateConvId(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -139,13 +119,10 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |       for (SingleUserChatModel element in data!) { | 
		
	
		
			
				|  |  |  |  |         if (element.isSeen != null) { | 
		
	
		
			
				|  |  |  |  |           if (!element.isSeen!) { | 
		
	
		
			
				|  |  |  |  |             print("Found Un Read"); | 
		
	
		
			
				|  |  |  |  |             logger.d(jsonEncode(element)); | 
		
	
		
			
				|  |  |  |  |             dynamic data = [ | 
		
	
		
			
				|  |  |  |  |               { | 
		
	
		
			
				|  |  |  |  |                 "userChatHistoryId": element.userChatHistoryId, | 
		
	
		
			
				|  |  |  |  |                 "TargetUserId": element.targetUserId, | 
		
	
		
			
				|  |  |  |  |                 "isDelivered": true, | 
		
	
		
			
				|  |  |  |  |                 "isSeen": true, | 
		
	
		
			
				|  |  |  |  |               } | 
		
	
		
			
				|  |  |  |  |               {"userChatHistoryId": element.userChatHistoryId, "TargetUserId": element.targetUserId, "isDelivered": true, "isSeen": true} | 
		
	
		
			
				|  |  |  |  |             ]; | 
		
	
		
			
				|  |  |  |  |             updateUserChatHistoryStatusAsync(data); | 
		
	
		
			
				|  |  |  |  |           } | 
		
	
	
		
			
				
					|  |  |  | @ -161,17 +138,22 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void updateUserChatHistoryStatusAsync(List data) { | 
		
	
		
			
				|  |  |  |  |     hubConnection.invoke( | 
		
	
		
			
				|  |  |  |  |       "UpdateUserChatHistoryStatusAsync", | 
		
	
		
			
				|  |  |  |  |       args: [data], | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
		
			
				|  |  |  |  |       hubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); | 
		
	
		
			
				|  |  |  |  |     } catch (e) { | 
		
	
		
			
				|  |  |  |  |       throw e; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   List<SingleUserChatModel> getSingleUserChatModel(String str) => List<SingleUserChatModel>.from( | 
		
	
		
			
				|  |  |  |  |         json.decode(str).map( | 
		
	
		
			
				|  |  |  |  |               (x) => SingleUserChatModel.fromJson(x), | 
		
	
		
			
				|  |  |  |  |             ), | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |   void updateUserChatHistoryOnMsg(List data) { | 
		
	
		
			
				|  |  |  |  |     try { | 
		
	
		
			
				|  |  |  |  |       hubConnection.invoke("UpdateUserChatHistoryStatusAsync", args: [data]); | 
		
	
		
			
				|  |  |  |  |     } catch (e) { | 
		
	
		
			
				|  |  |  |  |       throw e; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   List<SingleUserChatModel> getSingleUserChatModel(String str) => List<SingleUserChatModel>.from(json.decode(str).map((x) => SingleUserChatModel.fromJson(x))); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Future<dynamic> uploadAttachments(String userId, File file) async { | 
		
	
		
			
				|  |  |  |  |     dynamic result; | 
		
	
	
		
			
				
					|  |  |  | @ -191,15 +173,15 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void updateUserChatStatus(List<Object?>? args) { | 
		
	
		
			
				|  |  |  |  |     dynamic items = args!.toList(); | 
		
	
		
			
				|  |  |  |  |     for (dynamic cItem in items[0]) { | 
		
	
		
			
				|  |  |  |  |     for (var cItem in items[0]) { | 
		
	
		
			
				|  |  |  |  |       for (SingleUserChatModel chat in userChatHistory) { | 
		
	
		
			
				|  |  |  |  |         if (chat.userChatHistoryId.toString() == cItem["userChatHistoryId"].toString()) { | 
		
	
		
			
				|  |  |  |  |         if (cItem["contantNo"].toString() == chat.contantNo.toString()) { | 
		
	
		
			
				|  |  |  |  |           chat.isSeen = cItem["isSeen"]; | 
		
	
		
			
				|  |  |  |  |           chat.isDelivered = cItem["isDelivered"]; | 
		
	
		
			
				|  |  |  |  |           notifyListeners(); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void onChatSeen(List<Object?>? args) { | 
		
	
	
		
			
				
					|  |  |  | @ -308,14 +290,9 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     userChatHistory.insert(0, data.first); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     var list = [ | 
		
	
		
			
				|  |  |  |  |       { | 
		
	
		
			
				|  |  |  |  |         "userChatHistoryId": data.first.userChatHistoryId, | 
		
	
		
			
				|  |  |  |  |         "TargetUserId": data.first.targetUserId, | 
		
	
		
			
				|  |  |  |  |         "isDelivered": true, | 
		
	
		
			
				|  |  |  |  |         "isSeen": isChatScreenActive ? true : false, | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       {"userChatHistoryId": data.first.userChatHistoryId, "TargetUserId": temp.first.targetUserId, "isDelivered": true, "isSeen": isChatScreenActive ? true : false} | 
		
	
		
			
				|  |  |  |  |     ]; | 
		
	
		
			
				|  |  |  |  |     updateUserChatHistoryStatusAsync(list); | 
		
	
		
			
				|  |  |  |  |     updateUserChatHistoryOnMsg(list); | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -412,34 +389,34 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |       Uint8List? image, | 
		
	
		
			
				|  |  |  |  |       required bool isImageLoaded}) async { | 
		
	
		
			
				|  |  |  |  |     Uuid uuid = const Uuid(); | 
		
	
		
			
				|  |  |  |  |     var contentNo = uuid.v4(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     var msg = message.text; | 
		
	
		
			
				|  |  |  |  |     SingleUserChatModel data = SingleUserChatModel( | 
		
	
		
			
				|  |  |  |  |       chatEventId: chatEventId, | 
		
	
		
			
				|  |  |  |  |       chatSource: 1, | 
		
	
		
			
				|  |  |  |  |       contant: msg, | 
		
	
		
			
				|  |  |  |  |       contantNo: uuid.v4(), | 
		
	
		
			
				|  |  |  |  |       conversationId: chatCID, | 
		
	
		
			
				|  |  |  |  |       createdDate: DateTime.now(), | 
		
	
		
			
				|  |  |  |  |       currentUserId: AppState().chatDetails!.response!.id, | 
		
	
		
			
				|  |  |  |  |       currentUserName: AppState().chatDetails!.response!.userName, | 
		
	
		
			
				|  |  |  |  |       targetUserId: targetUserId, | 
		
	
		
			
				|  |  |  |  |       targetUserName: targetUserName, | 
		
	
		
			
				|  |  |  |  |       isReplied: false, | 
		
	
		
			
				|  |  |  |  |       fileTypeId: fileTypeId, | 
		
	
		
			
				|  |  |  |  |       userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, | 
		
	
		
			
				|  |  |  |  |       fileTypeResponse: isAttachment | 
		
	
		
			
				|  |  |  |  |           ? FileTypeResponse( | 
		
	
		
			
				|  |  |  |  |               fileTypeId: fileTypeId, | 
		
	
		
			
				|  |  |  |  |               fileTypeName: getFileType(getFileExtension(selectedFile.path).toString()), | 
		
	
		
			
				|  |  |  |  |               fileKind: getFileExtension(selectedFile.path), | 
		
	
		
			
				|  |  |  |  |               fileName: selectedFile.path.split("/").last, | 
		
	
		
			
				|  |  |  |  |               fileTypeDescription: getFileTypeDescription(getFileExtension(selectedFile.path).toString()), | 
		
	
		
			
				|  |  |  |  |             ) | 
		
	
		
			
				|  |  |  |  |           : null, | 
		
	
		
			
				|  |  |  |  |       image: image, | 
		
	
		
			
				|  |  |  |  |       isImageLoaded: isImageLoaded, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |         chatEventId: chatEventId, | 
		
	
		
			
				|  |  |  |  |         chatSource: 1, | 
		
	
		
			
				|  |  |  |  |         contant: msg, | 
		
	
		
			
				|  |  |  |  |         contantNo: contentNo, | 
		
	
		
			
				|  |  |  |  |         conversationId: chatCID, | 
		
	
		
			
				|  |  |  |  |         createdDate: DateTime.now(), | 
		
	
		
			
				|  |  |  |  |         currentUserId: AppState().chatDetails!.response!.id, | 
		
	
		
			
				|  |  |  |  |         currentUserName: AppState().chatDetails!.response!.userName, | 
		
	
		
			
				|  |  |  |  |         targetUserId: targetUserId, | 
		
	
		
			
				|  |  |  |  |         targetUserName: targetUserName, | 
		
	
		
			
				|  |  |  |  |         isReplied: false, | 
		
	
		
			
				|  |  |  |  |         fileTypeId: fileTypeId, | 
		
	
		
			
				|  |  |  |  |         userChatReplyResponse: isReply ? UserChatReplyResponse.fromJson(repliedMsg.first.toJson()) : null, | 
		
	
		
			
				|  |  |  |  |         fileTypeResponse: isAttachment | 
		
	
		
			
				|  |  |  |  |             ? FileTypeResponse( | 
		
	
		
			
				|  |  |  |  |                 fileTypeId: fileTypeId, | 
		
	
		
			
				|  |  |  |  |                 fileTypeName: getFileType(getFileExtension(selectedFile.path).toString()), | 
		
	
		
			
				|  |  |  |  |                 fileKind: getFileExtension(selectedFile.path), | 
		
	
		
			
				|  |  |  |  |                 fileName: selectedFile.path.split("/").last, | 
		
	
		
			
				|  |  |  |  |                 fileTypeDescription: getFileTypeDescription(getFileExtension(selectedFile.path).toString()), | 
		
	
		
			
				|  |  |  |  |               ) | 
		
	
		
			
				|  |  |  |  |             : null, | 
		
	
		
			
				|  |  |  |  |         image: image, | 
		
	
		
			
				|  |  |  |  |         isImageLoaded: isImageLoaded); | 
		
	
		
			
				|  |  |  |  |     userChatHistory.insert(0, data); | 
		
	
		
			
				|  |  |  |  |     isFileSelected = false; | 
		
	
		
			
				|  |  |  |  |     isMsgReply = false; | 
		
	
	
		
			
				
					|  |  |  | @ -448,7 +425,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     notifyListeners(); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     String chatData = | 
		
	
		
			
				|  |  |  |  |         '{"contant":"$msg","contantNo":"${uuid.v4()}","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; | 
		
	
		
			
				|  |  |  |  |         '{"contant":"$msg","contantNo":"$contentNo","chatEventId":$chatEventId,"fileTypeId": $fileTypeId,"currentUserId":${AppState().chatDetails!.response!.id},"chatSource":1,"userChatHistoryLineRequestList":[{"isSeen":false,"isDelivered":false,"targetUserId":$targetUserId,"targetUserStatus":1}],"chatReplyId":$chatReplyId,"conversationId":"$chatCID"}'; | 
		
	
		
			
				|  |  |  |  |     await hubConnection.invoke("AddChatUserAsync", args: <Object>[json.decode(chatData)]); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -456,11 +433,7 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |     dynamic contain = searchedChats!.where((ChatUser element) => element.id == targetUserId); | 
		
	
		
			
				|  |  |  |  |     if (contain.isEmpty) { | 
		
	
		
			
				|  |  |  |  |       searchedChats!.add( | 
		
	
		
			
				|  |  |  |  |         ChatUser( | 
		
	
		
			
				|  |  |  |  |           id: targetUserId, | 
		
	
		
			
				|  |  |  |  |           userName: targetUserName, | 
		
	
		
			
				|  |  |  |  |           unreadMessageCount: 0 | 
		
	
		
			
				|  |  |  |  |         ), | 
		
	
		
			
				|  |  |  |  |         ChatUser(id: targetUserId, userName: targetUserName, unreadMessageCount: 0), | 
		
	
		
			
				|  |  |  |  |       ); | 
		
	
		
			
				|  |  |  |  |       notifyListeners(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
	
		
			
				
					|  |  |  | @ -693,17 +666,21 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  |   // } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   void msgScroll() { | 
		
	
		
			
				|  |  |  |  |     scrollController.animateTo( | 
		
	
		
			
				|  |  |  |  |       scrollController.position.minScrollExtent - 100, | 
		
	
		
			
				|  |  |  |  |       duration: const Duration(milliseconds: 500), | 
		
	
		
			
				|  |  |  |  |       curve: Curves.easeIn, | 
		
	
		
			
				|  |  |  |  |     ); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   // Future<void> getDownLoadFile(String fileName) async { | 
		
	
		
			
				|  |  |  |  |   //   var data = await ChatApiClient().downloadURL(fileName: "data"); | 
		
	
		
			
				|  |  |  |  |   //   Image.memory(data); | 
		
	
		
			
				|  |  |  |  |   // } | 
		
	
		
			
				|  |  |  |  |     // scrollController.animateTo( | 
		
	
		
			
				|  |  |  |  |     //    // index: 150, | 
		
	
		
			
				|  |  |  |  |     //     duration: Duration(seconds: 2), | 
		
	
		
			
				|  |  |  |  |     //     curve: Curves.easeInOutCubic); | 
		
	
		
			
				|  |  |  |  |     // scrollController.animateTo( | 
		
	
		
			
				|  |  |  |  |     //   scrollController.position.minScrollExtent - 100, | 
		
	
		
			
				|  |  |  |  |     //   duration: const Duration(milliseconds: 500), | 
		
	
		
			
				|  |  |  |  |     //   curve: Curves.easeIn, | 
		
	
		
			
				|  |  |  |  |     // ); | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | // Future<void> getDownLoadFile(String fileName) async { | 
		
	
		
			
				|  |  |  |  | //   var data = await ChatApiClient().downloadURL(fileName: "data"); | 
		
	
		
			
				|  |  |  |  | //   Image.memory(data); | 
		
	
		
			
				|  |  |  |  | // } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | // void getUserChatHistoryNotDeliveredAsync({required int userId}) async { | 
		
	
		
			
				|  |  |  |  | //   try { | 
		
	
	
		
			
				
					|  |  |  | @ -713,12 +690,4 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { | 
		
	
		
			
				|  |  |  |  | //   } | 
		
	
		
			
				|  |  |  |  | // } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					|  |  |  | 
 |