<?php

namespace FOP;

class Imap {
  
  

  
  

    // --- Statische Methoden ---
  
  public static function iterateMails($postbox, $mailbox, $latestuid) { 
    
    
    // --- BLOCK: main ---
    
		$nmsgs = imap_check($mailbox)->Nmsgs;
		$maxmsg = $latestuid == 0 ? 0 : imap_msgno($mailbox, $latestuid);
		if(($nmsgs < 1) || ($nmsgs <= $maxmsg)) return;
		$mailids = imap_fetch_overview($mailbox, ($maxmsg + 1) . ':' . intval($nmsgs));
		
		$memory_attachment = 0;	
		$memory_limit = str_replace(array('G', 'M', 'K'), array('000000000', '000000', '000'), ini_get('memory_limit'));
		if ($memory_limit < 500000000) ini_set('memory_limit', '-1'); //Set memory limit war noch nicht integriert, für noch größere emails andere lösungen
		if (ini_get('memory_limit') == -1) {
			$memory_limit = 1000000000;
		} else {
			$memory_limit = $memory_limit - 30000000;
			if (ini_get('max_execution_time') < 120) {
				ini_set('max_execution_time', 120);
			}
		}
		
		$timer = time() + ini_get('max_execution_time');
		for ($i=0; $i < count($mailids); $i++){
			$mailid = $mailids[$i]->msgno;
			$uid = $mailids[$i]->uid;
			$flags = array('seen' => $mailids[$i]->seen, 'draft' => $mailids[$i]->draft, 'deleted' => $mailids[$i]->deleted, 'answered' => $mailids[$i]->answered, 'flagged' => $mailids[$i]->flagged, 'recent' =>$mailids[$i]->recent);
			if($mailids[$i]->udate >= $postbox['syncdate']){

				// da nach der Änderung mit saveContent (commit 7ab16413259781c4087fca57ddcce83f0e4bcfe4) der Garbage Collector funktionieren sollte
				// zur Sicherheit bleibt die memory überprüfung
				
				//TODO:Mit ZBateson Mimeparser die email zerlegen, auslagern und Dann in Datenbank				

				
				if ((memory_get_usage() < $memory_limit) || ($timer >= time() + 5)){
					// Download der Mail
					$mail = \FOP\Imap::getMail($mailbox, $mailid, $uid, $flags, null/*threadlist - TODO: momentan unbenutzt, später mal für Re:-Erkennung*/, true);
					\FOP\Database::beginTransaction();
						if ($postbox['type'] == 'revision_doc' && call_user_func(function($postbox, $mail){
							
		// Standards
		$default = \Tables\Doc::getDefaults();

		$default['boxid'] = $postbox['id'];
		$default['msgid'] = $mail['msgno'];
		$default['postboxtype'] = $postbox['type'];

		/* Insert Attachements */
		foreach($mail['attachments'] as $file) {
			$data = $default;
			$file_id = \FOP\Files::uploadFromFile($file['path'], $file['filename']);
			$data['file'] = $file_id;

			

			\Tables\Doc::sanitizeDefaults($data, false);
			$id = \Tables\Doc::create($data, true);
		}
		return true; // als gelesen markieren
	
						}, $postbox, $mail)) {
							/* return true bedeutet, Nachricht als gelesen markieren */
						imap_setflag_full($mailbox, $uid, '\\Seen', ST_UID); /* TODO: Seen, Answered, Flagged, Deleted, Draft */
						};
					if ($postbox['type'] == 'fop_mail_host_box' && call_user_func(function($postbox, $mail){
							
		$zustand = \FOP\Database::query('SELECT zustand FROM fop_mail_host_box WHERE '.qi('ID').' = ' . \FOP\Database::quote($postbox['id']) . ' LIMIT 1')->fetchColumn();

		if ($zustand != 2) {
			$data = \Tables\Fop_mail_host_box_dir_email::getDefaults();

			$data['boxid'] = $postbox['id'];
			$data['msgid'] = $mail['msgno'];
			$data['uid'] =  $mail['uid'];
			$data['type'] = $postbox['type'];
			if(isset($mail['hcol'])) $data[$mail['hcol']] = $mail['header'];

			$dirID = \Tables\Fop_mail_host_box_dir::createMailDirectory($postbox['dirFull'], $postbox['check'], $postbox['id'], $postbox['dir']);
			$data['seen'] = $mail['flags']['seen'];
			$data['subject'] = mb_check_encoding($mail['subject'], 'UTF-8') ? $mail['subject'] : "\u{FFFD}";
			$data['content'] = $mail['html'];
			$data['timestamp'] = $mail['received'];
			$data['senderDisplay'] = mb_check_encoding($mail['from']['display'], 'UTF-8') ?  $mail['from']['display'] : "\u{FFFD}";
			$data['senderEmail'] = $mail['from']['email'];
			$data['directory'] = $dirID;
			$data['status'] = 1;
			\Tables\Fop_mail_host_box_dir_email::sanitizeDefaults($data, false);
			//\Tables\Fop_mail_host_box_dir_email_reply::create(	
			/*letzter Check ob mail schon vorhanden (nur zur Absicherung das keine Mails mehr doppelt geladen werden)*/
			$checkID = \FOP\Database::query('SELECT uid FROM fop_mail_host_box_dir_email WHERE directory = ' . \FOP\Database::quote($dirID) . ' AND uid = ' . \FOP\Database::quote($data['uid']) . ' LIMIT 1')->fetchColumn();
			if ($checkID == false) {
				/*Alles mit status umbauen*/

				try {
					$emailID = \Tables\Fop_mail_host_box_dir_email::create($data, true);
					// wurde die Threading-Logik ersatzlos gelöscht? commit 9ad186ee46ebecaa004ae1a7713eb73e93cef678
					// self::mailThread($mail['threadlist'], $emailID, $data['directory']);

					foreach ($mail['to'] AS $to) {
						\Tables\Fop_mail_host_box_dir_email_recipient::create([
							'email' => $emailID,
							'type' => 1,
							'display' => $to['display'],
							'address' => $to['email']
						]);
					}
					foreach ($mail['cc'] AS $cc) {
						\Tables\Fop_mail_host_box_dir_email_recipient::create([
							'email' => $emailID,
							'type' => 2,
							'display' => $cc['display'],
							'address' => $cc['email']
						]);
					}

					/* Insert Attachements */
					$fileData = array();
					foreach($mail['attachments'] as $attachment) {
						$file_id = \FOP\Files::uploadFromFile($attachment['path'], $attachment['filename']);
						$fileData['file'] = $file_id;
						$fileData['email'] = $emailID;


						$fileID = \Tables\Fop_mail_host_box_dir_email_attachment::create($fileData);
					}
				} catch (\PDOException $e) {
					// invalid characters in message
					error_log($e->getMessage());
				} catch (\FOP\AccessDeniedException $e) {
					// duplicate insert: ignore
				}
			}
		}
	
						}, $postbox, $mail)) {
							/* return true bedeutet, Nachricht als gelesen markieren */
						imap_setflag_full($mailbox, $uid, '\\Seen', ST_UID); /* TODO: Seen, Answered, Flagged, Deleted, Draft */
						};
					/*TODO: Überprüfen ob das so stimmt vorallem mit der maxmessage findemich*/

					// latestuid hochzählen
					// innerhalb der Transaction, damit im Fehlerfall keine Emails doppelt behandelt werden
					\FOP\Database::query('INSERT INTO fop_imaplistener(mailboxid, latestuid, type, directorystr) VALUES (' . \FOP\Database::quote($postbox['id']) . ', ' . intval($uid) .', ' . \FOP\Database::quote($postbox['type']) . ', ' . \FOP\Database::quote($postbox['dir']) . ')' . (\FOP\Database::getDriver() == 'mysql' ? ' ON DUPLICATE KEY UPDATE latestuid=VALUES(latestuid)' : ' ON CONFLICT (type, mailboxid, directorystr) DO UPDATE SET latestuid = excluded.latestuid'));

					\FOP\Database::commitTransaction();
				} else {
					return;
				}
				imap_gc($mailbox, IMAP_GC_ENV | IMAP_GC_TEXTS);
			}
		}
	
    
  }

  public static function generateHostString($hostname, $port, $auth) { 
    
    
    // --- BLOCK: main ---
    
		if ($port == 0){
			if ($auth == 'ssl' || $auth == 'SSL/TLS') {
				$port = 993;
			} else {
				$port = 143;
			}
		}

		$hoststr = '{' . $hostname . ':' . $port . '/imap';
		switch ($auth) {
			case 'ssl': case 'SSL/TLS':
				$hoststr .= '/ssl';
				break;
			case 'novalidate-cert': case 'SSL/TLS novalidate-cert':
				$hoststr .= '/ssl/novalidate-cert';
				break;
			case 'starttls': case 'STARTTLS':
				$hoststr .= '/tls';
				break;
			case 'notls': case 'NOTLS':
				$hoststr .= '/notls';
				break;
			case 'nossl': case 'NOSSL':
				$hoststr .= '/nossl';
				break;
			default:
				break;
		}
		$hoststr .= '}';
		return $hoststr;
	
    
  }

  public static function extractDirName($hoststr, $constr) { 
    
    
    // --- BLOCK: main ---
    
		$constr = str_replace($hoststr, '', $constr);
		return $constr;
	
    
  }

  public static function getImapListenerMailboxes() { 
    
    
    // --- BLOCK: main ---
    
		$mailboxes = array();

		
			$hostname = \RevisionEmail\Doc::getHost();
			$port = \RevisionEmail\Doc::getPort();
			$auth = \RevisionEmail\Doc::getAuth();
			$username = \RevisionEmail\Doc::getUsername();
			$password = \Types\Password::decryptSymmetric(\RevisionEmail\Doc::getPassword()); // decrypt symmetric encrypted password
			$syncdate = \RevisionEmail\Doc::getSyncdate();
			$syncdate = \FOP\Sanitizers::parseDate($syncdate); 
			if ($hostname != 'eg. imap.example.com') {
				$hoststr = self::generateHostString($hostname, $port, $auth);
				$r = imap_open($hoststr, $username, $password, NULL, 1, array('DISABLE_AUTHENTICATOR' => 'GSSAPI'));
				if (!$r) $hoststr = self::generateHostString($hostname, $port, $auth, true);
				$mailboxes['revision_doc'][1]['imap'] = imap_open($hoststr, $username, $password, NULL, 1, array('DISABLE_AUTHENTICATOR' => 'GSSAPI'));
				$mailboxes['revision_doc'][1]['path'] = $hoststr;
				$mailboxes['revision_doc'][1]['syncdate'] = $syncdate;
				$mailboxes['revision_doc'][1]['latestuid'] = array();

				$result = \FOP\Database::query('SELECT latestuid, directorystr FROM fop_imaplistener WHERE type = \'revision_doc\' AND mailboxid = 1')->fetchAll(\PDO::FETCH_ASSOC);

				foreach ($result as $res) {
					$latestuidcol = ($res['latestuid']) ? $res['latestuid'] : 0;
					$mailboxes['revision_doc'][1]['latestuid'][$res['directorystr']] = $latestuidcol;
				}
			}
		
			$serverrows = \FOP\Database::query('SELECT '.qi('fop_mail_host').'.'.qi('ID').' AS '.qi('ID').', '.qi('fop_mail_host').'.'.qi('imap_host').' AS hostname, '.qi('fop_mail_host').'.'.qi('imap_port').' AS port, '.qi('fop_mail_host').'.'.qi('imap_auth').' AS auth FROM '.qi('fop_mail_host').'')->fetchAll(\PDO::FETCH_ASSOC);
			$servers = [];
			foreach ($serverrows as $row){
				$servers[$row['ID']] = $row;
			}
			$tblmailboxes = \FOP\Database::query('SELECT '.qi('fop_mail_host_box').'.'.qi('ID').' AS '.qi('ID').', '.qi('fop_mail_host_box').'.'.qi('email_server').' AS mailbox, '.qi('fop_mail_host_box').'.'.qi('user').' AS username, '.qi('fop_mail_host_box').'.'.qi('password').' AS password, '.qi('fop_mail_host_box').'.'.qi('syncdate').' AS syncdate FROM '.qi('fop_mail_host_box').' WHERE (zustand = 1 OR zustand = 3 OR zustand = 0 OR zustand IS NULL) AND '.qi('fop_mail_host_box').'.'.qi('email_server').' IN (SELECT '.qi('fop_mail_host').'.'.qi('ID').' FROM '.qi('fop_mail_host').') ORDER BY '.(\FOP\Database::getDriver() == 'mysql' ? 'RAND' : 'RANDOM').'()')->fetchAll(\PDO::FETCH_ASSOC);
			foreach ($tblmailboxes as $row){
				$row['password'] = \Types\Password::decryptSymmetric($row['password']);
				$server = $servers[$row['mailbox']];
				$connected = true;
				$hoststr = self::generateHostString($server['hostname'], $server['port'], $server['auth']);
				if (!($r = @imap_open($hoststr, $row['username'], $row['password'], NULL, 1, array('DISABLE_AUTHENTICATOR' => 'GSSAPI')))) {
					// TODO: Fehlermeldung besser aufbereiten
					$e = implode(', ', imap_errors() ?: []);
					\FOP\Database::query('UPDATE fop_mail_host_box SET hoststr = NULL, zustand = 1, status = ' . \FOP\Database::quote($e) .' WHERE '.qi('ID').' = ' . \FOP\Database::quote($row['ID']));
					//error_log('IMAP Error in getImapListenerMailboxes '.qi('fop_mail_host_box').' ID='.$row['ID'].': ' . $e);
					$connected = false;
				} else {
					/* TODO Hook: LastSync-Zustände setzen */
					$mailboxes['fop_mail_host_box'][$row['ID']]['imap'] = $r;
					$mailboxes['fop_mail_host_box'][$row['ID']]['path'] = $hoststr;
					$mailboxes['fop_mail_host_box'][$row['ID']]['syncdate'] = $row['syncdate'];
					$mailboxes['fop_mail_host_box'][$row['ID']]['latestuid'] = [];

					$result = \FOP\Database::query('SELECT latestuid, directorystr FROM fop_imaplistener WHERE type = \'fop_mail_host_box\' AND mailboxid = ' . intval($row['ID']))->fetchAll(\PDO::FETCH_ASSOC);

					foreach ($result as $res) {
						$latestuidcol = ($res['latestuid']) ? $res['latestuid'] : 0;
						$mailboxes['fop_mail_host_box'][$row['ID']]['latestuid'][$res['directorystr']] = $latestuidcol;
					}
				}
			}
		

		return $mailboxes;
	
    
  }

  public static function getImapListenerCron() { 
    
    
    // --- BLOCK: main ---
    
		if($mailboxes = self::getImapListenerMailboxes()) {
			foreach ($mailboxes as $type => $row){
				foreach ($row as $id => $mailbox) {
					try {
						$list = imap_getmailboxes($mailbox['imap'], $mailbox['path'], "*");
						$delimiter = ''; //Emailclientcreate
						if ($list) foreach ($list as $key => $box) {
							imap_reopen($mailbox['imap'], $box->name);
							$dir = self::extractDirName($mailbox['path'], $box->name);
							$check = imap_mailboxmsginfo($mailbox['imap']);
							$delimiter = $box->delimiter; //EMailclientcreate
							$postbox = array('type' => $type, 'id' => $id, 'dir' => $dir, 'dirFull' => $box, 'check' => $check, 'syncdate' => $mailbox['syncdate']);
							self::iterateMails($postbox, $mailbox['imap'],isset($mailbox['latestuid'][$dir]) ? $mailbox['latestuid'][$dir] : 0);
						
						}
					} catch(Exception $e){
						error_log('[FOP-ImapListener] Error occured while running Hooks for Mailbox: ' . $id);
					}	
				}
			}
		}
	
    
  }

  public static function getMail($mailbox, $msgno, $uid, $flags, $threadlist, $loadAttachments) { 
    
    
    // --- BLOCK: main ---
    
		$mail = array('msgno' => $msgno, 'uid' => $uid, 'flags' => $flags, 'threadlist' => $threadlist);

		$body = imap_fetchbody($mailbox, $msgno, "", \FT_PEEK);

		$message = \ZBateson\MailMimeParser\Message::from($body, false);
		

		/* General things like Subject, From, To, CC, Received */
		$mail['subject'] = $message->getHeaderValue('Subject');

		$from = $message->getHeader('From');
		if ($from) {
			$mail['from'] = array('display' => $from->getPersonName(), 'email' => $from->getEmail());
		} else {
			$mail['from'] = array('display' => '', 'email' => '');
		}

		$to = $message->getHeader('To');
		$mail['to'] = array();

		if ($to) {
			foreach($to->getAddresses() as $addr) {
				$arr = array('display' => $addr->getName(), 'email' => $addr->getEmail());
				array_push($mail['to'], $arr);
			}
		}

		$cc = $message->getHeader('cc');
		$mail['cc'] = array();

		if ($cc) {
			foreach ($cc->getAddresses() as $addr) {
				$arr = array('display' => $addr->getName(), 'email' => $addr->getEmail());
				array_push($mail['cc'], $arr);
			}
		}

		$date = $message->getHeader('date');
		if ($date && $date->getDateTime()) {
			$mail['received'] = $date->getDateTime()->format('U');
		} else {
			$mail['received'] = time();
		}

		$text = $message->getTextContent(0, 'UTF-8'); // Text als UTF-8
		$html = $message->getHtmlContent(0, 'ASCII//TRANSLIT'); // HTML in binär lesen - der DOMDocument Parser liest dann den charset header ein
		self::convertBetween($text, $html);
		$html = self::inlineReplacements($html, $message);
		$ics = NULL;
		$attachments = $message->getAllAttachmentParts();
	//	if(!is_string($html)) $html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"><html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"></head><body></body></html>';               
		$attachmentsList = array();
		foreach($attachments as $file) {
			if ($file->hasContent() && $file->getContentDisposition() == 'attachment' && $loadAttachments) {
				$attachmentdata = \FOP\Imap::extractAttachment($file);	
         	if (isset($attachmentdata['html'])) $html .= '<br><br>' . $attachmentdata['html'];
				if	(isset($attachmentdata['att'])) array_push($attachmentsList, $attachmentdata['att']);
			} else if ($file->getContentDisposition() == 'inline' && $file->getContentType() == 'message/rfc822') {
				
				$message2 = \ZBateson\MailMimeParser\Message::from($file->getContent(), false);
				$text2 = $message2->getTextContent();
				$html2 = $message2->getHtmlContent();
				self::convertBetween($text2, $html2);
				$html2 = self::inlineReplacements($html2, $message2);
				$text .= "\n\n";
				$text .= $text2;
				$html .= '<br><br>';
				$html .= $html2;

				$attachments2 = $message2->getAllAttachmentParts();
				foreach($attachments2 as $file2) if ($file2->hasContent()) {
					if (($file2->getContentDisposition() == 'attachment' && $loadAttachments) || $file2->getContentType() == 'message/rfc822') {
						$attachmentdata = \FOP\Imap::extractAttachment($file2);	
						if	(isset($attachmentdata['html'])) $html .= $attachmentdata['html'];
						if	(isset($attachmentdata['att'])) 	array_push($attachmentsList, $attachmentdata['att']);
					}
				}
			}
		}	
		// Entfernt Umlaute aus ANSI-kodierten Dokumenten
		$mail['text'] = iconv('UTF-8','UTF-8//IGNORE', (!$text ? NULL : $text));
		$mail['html'] = iconv('UTF-8','UTF-8//IGNORE', $html);

		$mail['attachments'] = $attachmentsList;
		return $mail;
    
  }

  public static function extractAttachment($file) { 
    
    
    // --- BLOCK: main ---
    
			$attachment = array();
			$attachment['filename'] = $file->getFilename();
			$attachment['type'] = $file->getContentType();
			$filename = tempnam(sys_get_temp_dir(), 'fop');
			register_shutdown_function(function () use ($filename) {
				@unlink($filename);
			});
			$file->saveContent($filename);
			$attachment['path'] = $filename;
			// TODO: hier war mal der ICS-Parse-Code (calendars/attendees.fop) drin
			// man könnte noch das Attribut 'html' im return zurückgeben, um eine Kalenderevent-Vorschau unter der E-Mail einzublenden (Ringo-Code!)
			return ['att' =>  $attachment];
		
    
  }

  public static function convertBetween(&$text, &$html) { 
    
    
    // --- BLOCK: main ---
    
		if (!$html && !ctype_space($text)) {
			$html = '<p>' . nl2br(htmlentities($text)) . '</p>';
		}

		if (!$text) {
			if ($html) {
				$text = \Soundasleep\Html2Text::convert($html, array('ignore_errors' => true));
			}
		}
	
    
  }

  public static function inlineReplacements($html, $message) { 
    
    
    // --- BLOCK: main ---
    
		libxml_use_internal_errors(TRUE);
 		if ( ! $html ) {
			return $html;
		}
		$doc = new \DOMDocument();

		/* Stackoverflow: https://stackoverflow.com/a/8218649
								https://wordpress.stackexchange.com/questions/273069/warning-domdocumentloadhtml-empty-string-supplied-as-input-in-functions*/
		$doc->loadHTML($html, LIBXML_NOERROR | LIBXML_NOWARNING);

		// email with own body: extract contents into div
		$xpath = new \DOMXPath($doc);
		$body = $xpath->query('//body')[0] ?? null;
		if ($body) {
			// create <div> and copy the body there
			$doc = new \DOMDocument;
			$div = $doc->createElement('div');
			$doc->appendChild($div);
			foreach ($body->childNodes AS $child) {
				$div->appendChild($doc->importNode($child, true));
			}
		}

		// search for CID: and replace them with data:base64 - TODO: also allow fop-files URLs
		$xpath = new \DOMXPath($doc);
		$elements = $xpath->query("//*[@src]");
		foreach ($elements as $element) {
			$attr = $element->getAttribute('src');
			if (strtoupper(substr($attr, 0, 4)) == 'CID:') {
				$contentID = substr($attr, 4);

				$contentPart = $message->getPartByContentID($contentID);
				if ($contentPart) {
					$uri = 'data:' . $contentPart->getContentType() . ';base64,' . base64_encode($contentPart->getContent());
					$element->setAttribute('src', $uri);
				}
			}
		}
		return $doc->saveHTML();
	
    
  }

  public static function imapConfig($options, $i_0, $till_array_) { 
    
    
    // --- BLOCK: main ---
    
			if(sizeof($options)==$i) return $till;
			if(sizeof($till)==0) $till[] = '';
			$opt = $options[$i];
			$new = array();
			foreach($till as $t) {
				foreach($opt as $o) {
					if(strlen($o)==0) $new[] = $t;
					else $new[] = $t.'/'.$o;
				}
			}
			return self::imapConfig($options, $i+1, $new);
	
    
  }

  public static function imap_test($server, $port, $dir, $username, $passw, $sec) { 
    
    
    // --- BLOCK: main ---
    
		$options = array();
		//$options[] = array('debug');
		$options[] = array('imap', 'imap4'); //nntp pop3, 'imap2', 'imap2bis', 'imap4rev1'
		$options[] = array('', 'norsh');
		if ($sec === 'ssl') {
			$options[] = array('ssl');
		}
		$options[] = array('', 'validate-cert', 'novalidate-cert');
		if ($sec === 'starttls') {
			$options[] = array('tls', 'notls');
		}
		$configOptions = self::imapConfig($options);
		$matches = array();
		foreach($configOptions as $c) {
				$mbox = @imap_open('{'.$server.':'.$port.$c.'}'.$dir, $username, $passw);
				$e = imap_errors() ?: [];
				if(isset($e[0]) || !empty($e[0])){
					preg_match('/(?:[)([^]]*)(?:])/', $e[0], $matches, PREG_UNMATCHED_AS_NULL);
					if(isset($matches[1]) || !empty($matches[1])) {
						if ($matches[1] == 'AUTHENTICATIONFAILED') {
							$error = array('if' => false, 'error' => $e[0]);
							return $error;
						}
					}
				}
				if (false !== $mbox){
					if($mbox = @imap_open('{'.$server.':'.$port.$c.'}'.$dir, $username, $passw, NULL, 1, array('DISABLE_AUTHENTICATOR' => 'GSSAPI'))) {
						imap_close($mbox);
						$hoststr = array('if' => true, 'str' => '{'.$server.':'.$port.$c.'}'.$dir, 'auth' => 1);
						return $hoststr;
					} else { 
						$hoststr = array('if' => true, 'str' => '{'.$server.':'.$port.$c.'}'.$dir, 'auth' => 0);
						return $hoststr;
					}
				}	
		}
		$error = array('if' => false, 'error' => 'CONNECTION NOT POSSIBLE');
		return $error;

	
	
    
  }


  
  

  
  
}



