Files correlati : ve6.exe Ricompilazione Demo : [ ] Commento : Riportata la versione 3.1 patch 979 git-svn-id: svn://10.65.10.50/trunk@15623 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			467 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			467 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <applicat.h>
 | |
| #include <automask.h>
 | |
| #include <printer.h>
 | |
| #include <progind.h>
 | |
| 
 | |
| #include "celib.h"
 | |
| #include "../ve/velib.h"
 | |
| #include "../ca/commesse.h"
 | |
| 
 | |
| #include "ce4200a.h"
 | |
| #include "ce4200.h"
 | |
| 
 | |
| #include "ammce.h"
 | |
| #include "cespi.h"
 | |
| #include "salcecms.h"
 | |
| 
 | |
| //===============================================================================================
 | |
| //maschera
 | |
| 
 | |
| class TCalc_cesp_cms_mask: public TAutomask 
 | |
| {
 | |
| public:
 | |
|   virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
 | |
| 
 | |
|   TCalc_cesp_cms_mask():TAutomask("ce4200a") {}
 | |
| 
 | |
| };
 | |
| 
 | |
| bool TCalc_cesp_cms_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
 | |
| {
 | |
| /*  switch (o.dlg())
 | |
|   {
 | |
|     default: break;
 | |
|   }*/
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| //===============================================================================================
 | |
| //form
 | |
| class TCalc_cesp_cms_form : public TForm
 | |
| {
 | |
|   TDitta_cespiti _ditta;
 | |
| 
 | |
| protected:
 | |
|   bool validate(TForm_item &cf, TToken_string &s);
 | |
| public:
 | |
|   TCalc_cesp_cms_form();
 | |
| 
 | |
|   virtual ~TCalc_cesp_cms_form();
 | |
| };
 | |
|   
 | |
| TCalc_cesp_cms_form::TCalc_cesp_cms_form() :TForm ("ce4200a")
 | |
| {
 | |
| } 
 | |
| 
 | |
| TCalc_cesp_cms_form::~TCalc_cesp_cms_form()
 | |
| { 
 | |
| }
 | |
| 
 | |
| bool TCalc_cesp_cms_form::validate(TForm_item &cf, TToken_string &s)
 | |
| {
 | |
|   if (s == "_DESCRCAT")
 | |
|   {
 | |
|     const int codcat = cursor()->curr().get_int(DOC_NDOC);
 | |
|     const TRectype& cat =_ditta.categoria(0, "", codcat);
 | |
|     cf.set(cat.get("S0"));
 | |
|     return true; //ricava la descrizione del cespite e la manda in stampa
 | |
|   }
 | |
| 
 | |
|   return TForm::validate(cf,s);
 | |
| }
 | |
| 
 | |
| 
 | |
| //===============================================================================================
 | |
| //Applicazione
 | |
| 
 | |
| class TCalc_cesp_cms : public TSkeleton_application
 | |
| { 
 | |
|   TCalc_cesp_cms_mask* _mask;
 | |
|   TCalc_cesp_cms_form* _form;
 | |
| 	bool _soloperc;
 | |
| 
 | |
| protected:
 | |
|   virtual void main_loop();
 | |
|   virtual bool create();
 | |
|   virtual bool destroy();
 | |
| 
 | |
| public:
 | |
|   void utilizzo_per_cms(const TRectype& ammce_rec);
 | |
|   real calc_perc_util_cesp(const TRectype& salcecms_rec, const TDate& dtinices, const TDate& dtfineces);
 | |
|   void delete_cespi_docs();
 | |
|   TRiga_documento& cerca_riga(TDocumento& doc_cesp, const TString& idcesp, const TString& codcms) const;
 | |
|   void elabora_docs();
 | |
|   bool stampa_docs();
 | |
| };
 | |
| 
 | |
| //Calcolo % utilizzo del cespite nella commessa
 | |
| //---------------------------------------------
 | |
| // percutil = a quella dei saldi per commessa (SALCECMS_PERCUTIL) 
 | |
| // percutil = percutil/100  normalizzazione
 | |
| // Se si devono considerare le date...
 | |
| //    stabilisce l'intervallo di date di riferimento per calcolare il numero dei giorni di utilizzo
 | |
| //    del cespite nella commessa delta_cms = (dtfine-dtini+1)/(dtfineces-dtinices+1)
 | |
| //    dove:
 | |
| //    dtinices e dtfineces sono le date di inizio e fine cespite
 | |
| //    dtini e dtfine sono le date di inizio e fine UTILIZZO del cespite nella commessa
 | |
| //    quindi la percentuale di utilizzo del cespite nella commessa risultera' come:
 | |
| //    percutil = percutil * delta_cms
 | |
| // fine Se
 | |
| //
 | |
| real TCalc_cesp_cms::calc_perc_util_cesp(const TRectype& salcecms_rec, const TDate& dtinices, const TDate& dtfineces)
 | |
| { 
 | |
| //adeesso prende la percentuale di utilizzo del cespite nella commessa..
 | |
|   real percutil = salcecms_rec.get_real(SALCECMS_PERCUTIL);
 | |
| //normalizza la percentuale...
 | |
|   percutil = percutil / CENTO;
 | |
| 
 | |
| 	if (!_soloperc)
 | |
| 	{
 | |
| //prende il codice commessa del record..
 | |
| 	  TString80 codcms = salcecms_rec.get(SALCECMS_CODCMS);
 | |
| //..ed accede cosi' alla tabella delle commesse
 | |
| 		const TRectype& cms = cache().get(LF_COMMESSE, codcms);
 | |
| //prende le date di inizio e fine commessa dalla tabella per poterle confrontare con le date limite
 | |
| //del cespite nell'esercizio  
 | |
| 	  TDate dtfine = dtfineces;
 | |
| //se esiste una data di proroga (DATAPROR) -> la data fine commessa e' la data proroga,altrimenti e'
 | |
| //la normale data fine commessa (DATAFINE)
 | |
|     TDate dtfinecms = cms.get_date(COMMESSE_DATAPROR);
 | |
|     if (!dtfinecms.ok())
 | |
| 		  dtfinecms = cms.get_date(COMMESSE_DATAFINE);
 | |
| 	  if (dtfinecms.ok() && (dtfinecms < dtfineces))
 | |
| 
 | |
| 		  dtfine = dtfinecms;
 | |
| 
 | |
| 		TDate dtini = dtinices;
 | |
| 		const TDate dtinicms = cms.get_date(COMMESSE_DATAINIZIO);
 | |
| 		if ((dtinicms.ok()) && (dtinicms > dtinices))
 | |
| 	    dtini = dtinicms;
 | |
| //intervallo giorni di utilizzo cespite nella commessa
 | |
| 		const real delta_cms = real(dtfine - dtini + 1) / real(dtfineces - dtinices + 1);
 | |
| 
 | |
| //...e la porta in giorni rispetto al totale di utilizzo dei giorni del cespite nell'esercizio
 | |
| //(il 100% sono i giorni di utilizzo del cespite in tutte le commesse dell'esercizio)
 | |
| 		percutil *= delta_cms;
 | |
| 	}
 | |
| 
 | |
|   return percutil;
 | |
| }
 | |
| 
 | |
| TRiga_documento& TCalc_cesp_cms::cerca_riga(TDocumento& doc_cesp, const TString& idcesp, const TString& codcms) const
 | |
| {
 | |
|   //deve raggruppare per commessa?
 | |
|   const bool groupcms = _mask->get_bool(F_CMSGROUP);
 | |
|   //se c'e' il flag di raggruppamento per commessa...
 | |
|   if (groupcms)
 | |
|   {
 | |
|     for (int i =1; i < doc_cesp.rows(); i++)
 | |
|     {
 | |
|       TRiga_documento& rigadoc = doc_cesp[i];
 | |
|       if (rigadoc.get(RDOC_CODCMS) == codcms)
 | |
|         return rigadoc; //se esiste gia' una riga con codice cespite e codice commessa correnti
 | |
|     } 
 | |
|   }
 | |
|   const TString4 tiporiga = _mask->get(F_TIPORIGA);
 | |
|   TRiga_documento& rigadoc = doc_cesp.new_row(tiporiga);
 | |
|   rigadoc.put(RDOC_CODCMS, codcms);
 | |
|   if (groupcms) //se raggruppa per cms tanto vale mettere la descrizione della commessa
 | |
|     rigadoc.put(RDOC_DESCR, cache().get(LF_COMMESSE, codcms, COMMESSE_DESCRIZ));
 | |
|   else  //se non raggruppa puo' usare anche il codice cespite, che scrive in codart
 | |
|   {
 | |
|     rigadoc.put(RDOC_CODART, idcesp);
 | |
|     rigadoc.put(RDOC_DESCR, cache().get(LF_CESPI, idcesp, CESPI_DESC));
 | |
|   }
 | |
|   rigadoc.put(RDOC_QTA, 1);
 | |
|   rigadoc.put(RDOC_DATACONS, TDate(TODAY)); //data di elaborazione
 | |
|   rigadoc.put(RDOC_CODIVA, _mask->get(F_CODIVA)); //codice IVA obbligatorio
 | |
|   return rigadoc;
 | |
| }
 | |
| 
 | |
| void TCalc_cesp_cms::utilizzo_per_cms(const TRectype& ammce_rec)
 | |
| {
 | |
|   const bool groupcms = _mask->get_bool(F_CMSGROUP);
 | |
| 
 | |
| //totale quote del cespite in esame per l'esercizio corrente (per tutte le commesse)
 | |
|   real qtot = ammce_rec.get_real(AMMCE_QNOR);
 | |
|   qtot += ammce_rec.get_real(AMMCE_QACC);
 | |
|   qtot += ammce_rec.get_real(AMMCE_QANT);
 | |
| 
 | |
|   if (qtot != ZERO)
 | |
|   {
 | |
| //controllo su date inizio e fine del periodo di utilizzo del cespite nell'esercizio selezionato
 | |
|     const TString16 idcesp = ammce_rec.get(CESPI_IDCESPITE);
 | |
|     const TRectype& cespi = cache().get(LF_CESPI, idcesp);
 | |
|     const int codcat = cespi.get_int(CESPI_CODCAT);
 | |
| 	  const TString80 cmsgen(_mask->get(F_CMSGEN));
 | |
| 
 | |
|     const TDate dtinies = _mask->get_date(F_INIZIO_ES);
 | |
|     const TDate dtfines = _mask->get_date(F_FINE_ES);
 | |
| 
 | |
|     TDate dtfine = dtfines;
 | |
|     const TDate dtalien = cespi.get_date(CESPI_DTALIEN);
 | |
|     if (dtalien.ok() && (dtalien < dtfines))
 | |
|       dtfine = dtalien;
 | |
|   
 | |
|     TDate dtini = dtinies;
 | |
|     const TDate dtfunz = cespi.get_date(CESPI_DTFUNZ);
 | |
|     if (dtfunz.ok() && (dtfunz > dtinies))
 | |
|       dtini = dtfunz;
 | |
|   //..a questo punto dtini e dtfine rappresentano il periodo di utilizzo del cespite 
 | |
|   //nell'esercizio selezionato
 | |
|   //quindi il periodo di utilizzo del cespite nell'esercizio,in giorni,sara'...
 | |
|     const long delta_cesp = dtfine - dtini + 1;
 | |
|     
 | |
|   //Adesso si controlla la durata di ogni commessa (alla quale il cespite ha partecipato) durante
 | |
|   //l'esercizio delezionato
 | |
|     const int current_ese = ammce_rec.get_int(AMMCE_CODES);
 | |
| 
 | |
|   //crea un record array dove memorizzare i record del file salcecms riguardanti il cespite e 
 | |
|   //l'esercizio selezionati
 | |
|     //dalla 2.2 sara' possibile sostituire le 5 righe seguenti con le 4 commentate
 | |
|     //TToken_string key;
 | |
|     //key.add(idcesp);
 | |
|     //key.add(current_ese);
 | |
|     //TRecord_array salcecms(key, LF_SALCECMS);
 | |
|     TRecord_array salcecms(LF_SALCECMS, "NRIGA");
 | |
|     TRectype* key = new TRectype(LF_SALCECMS);
 | |
|     key->put("IDCESPITE",idcesp);
 | |
|     key->put("CODES",current_ese);
 | |
|     salcecms.read(key);
 | |
| 
 | |
|     const TString4 codnum = _mask->get(F_CODNUM);    
 | |
|     const TString4 tiporiga = _mask->get(F_TIPORIGA);
 | |
|     //documento con la categoria del cespite in oggetto, la numerazione indicata sulla maschera,
 | |
|     //l'anno dell'esercizio selezionato; se esiste gia' non lo deve creare ma aggiungervi solo le righe
 | |
|     TDocumento doc_cesp('D', current_ese, codnum, codcat);
 | |
|     const bool doc_exist = doc_cesp.rows() > 0;
 | |
|     if (!doc_exist)
 | |
|     {
 | |
| 		  doc_cesp.put(DOC_TIPODOC, _mask->get(F_TIPODOC));
 | |
|       doc_cesp.put(DOC_DATADOC, _mask->get(F_GENERA_DOC));
 | |
|     }
 | |
| 		//completa la testata con i dati della maschera
 | |
| 		doc_cesp.put(DOC_TIPOCF, 'F');
 | |
| 		doc_cesp.put(DOC_CODCF, _mask->get(F_CODCF));
 | |
| 		doc_cesp.put(DOC_NUMDOCRIF, _mask->get(F_NUMDOCRIF));
 | |
| 
 | |
| 
 | |
|   //ciclo su SALCECMS data una chiave idcespite + esercizio (si fa solo se salcecms non e' vuoto,
 | |
|   //e' inutile perdere tempo..)
 | |
|     if (salcecms.rows() > 0)
 | |
|     {
 | |
|   //crea documento relativo al cespite in questione (nell'esercizio);ogni riga del documento
 | |
|   //sara' relativa ad una commessa
 | |
| 
 | |
|       TGeneric_distrib distrib(qtot, TCurrency::get_firm_dec());
 | |
|       int i;
 | |
|       for (i=1; i<=salcecms.last_row(); i++ )
 | |
|       {
 | |
|         const real perc = calc_perc_util_cesp(salcecms[i], dtini, dtfine);
 | |
|         distrib.add(perc);
 | |
|       }
 | |
|   //e riempiamo 'sta riga!
 | |
|       for (i=1; i<=salcecms.last_row(); i++ )
 | |
|       {
 | |
|   //per prima cosa deve sapere se e' da creare o da modificare...
 | |
|         const TString & codcms = salcecms[i].get(SALCECMS_CODCMS);  //codice commessa
 | |
|         TRiga_documento& rigadoc = cerca_riga(doc_cesp, idcesp, codcms);
 | |
| //se c'e' il flag di raggruppamento per commessa...         
 | |
|         const real quota = distrib.get();          
 | |
|         if (groupcms)
 | |
|         {
 | |
|           real somma = rigadoc.get(RDOC_PREZZO);
 | |
|           somma += quota;
 | |
|           rigadoc.put(RDOC_PREZZO, somma);          //ammortamento cespite per la commessa
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|           rigadoc.put(RDOC_PREZZO, quota);          //ammortamento cespite per la commessa
 | |
|           const real perc_cms = salcecms[i].get_real(SALCECMS_PERCUTIL);
 | |
|           rigadoc.put(RDOC_QTAGG1, perc_cms);       //% utilizzo cespite nella commessa
 | |
|           rigadoc.put(RDOC_QTAGG2, dtfine - dtini); //giorni di utilizzo cespite nella commessa
 | |
|           rigadoc.put(RDOC_QTAGG3, delta_cesp);     //giorni di utilizzo cespite nell'esercizio
 | |
|           real perc = quota * CENTO / qtot; perc.round(2);  //percentuale della quota
 | |
|           rigadoc.put(RDOC_QTAGG4, perc);
 | |
|         }
 | |
|       }
 | |
|   //scrittura del documento sul file
 | |
| 	    doc_cesp.write();
 | |
| 
 | |
|     }//fine if (salcecms.rows()>0)
 | |
| 		else
 | |
|     {
 | |
| 			if (cmsgen.not_empty())
 | |
| 			{
 | |
|         TRiga_documento& rigadoc = cerca_riga(doc_cesp, idcesp, cmsgen);
 | |
| //se c'e' il flag di raggruppamento per commessa...                  
 | |
|         if (groupcms)
 | |
|         {
 | |
|           real somma = rigadoc.get(RDOC_PREZZO);
 | |
|           somma += qtot;
 | |
|           rigadoc.put(RDOC_PREZZO, somma);          //ammortamento cespite per la commessa
 | |
|         }
 | |
|         else
 | |
|           rigadoc.put(RDOC_PREZZO, qtot);          //ammortamento cespite per la commessa
 | |
| 
 | |
| 		    doc_cesp.write();
 | |
| 			}
 | |
|     }
 | |
|   }//fine if(qtot!=0)
 | |
| }
 | |
| 
 | |
| void TCalc_cesp_cms::delete_cespi_docs()
 | |
| {
 | |
|   const int anno = _mask->get_int(F_ESERCIZIO);
 | |
|   const TString& codnum = _mask->get(F_CODNUM);
 | |
| 
 | |
|   TRelation rel_doc(LF_DOC);
 | |
| 
 | |
|   TRectype& rec = rel_doc.curr();
 | |
|   rec.put(DOC_PROVV, "D");
 | |
|   rec.put(DOC_ANNO, anno);
 | |
|   rec.put(DOC_CODNUM, codnum);
 | |
| 
 | |
|   TCursor cur_doc (&rel_doc, "", 1, &rec, &rec);
 | |
|   const long items = cur_doc.items();
 | |
|   cur_doc.freeze();
 | |
|   TProgind progind(items, "Eliminazione vecchi documenti in corso...", false, true);
 | |
| 
 | |
|   for (cur_doc = 0; cur_doc.pos() < items; ++cur_doc)
 | |
|   { 
 | |
|     progind.addstatus(1);
 | |
|     TDocumento doc(rec);
 | |
|     doc.remove();
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| void TCalc_cesp_cms::elabora_docs()
 | |
| {
 | |
|   //deve accoppare tutti i documenti con ANNO e NUM che trova nella maschera
 | |
|   delete_cespi_docs();
 | |
| 
 | |
|   TRectype darec(LF_AMMCE),arec(LF_AMMCE);
 | |
|   const int esercizio = _mask->get_int(F_ESERCIZIO);    
 | |
| 	const TString80 da_cespite(_mask->get(F_DA_IDCESPITE));
 | |
| 	const TString80 a_cespite(_mask->get(F_A_IDCESPITE));
 | |
| 	
 | |
| 	if (!da_cespite.empty())
 | |
| 		darec.put(AMMCE_IDCESPITE, da_cespite);
 | |
| 	if (!a_cespite.empty())
 | |
| 		arec.put(AMMCE_IDCESPITE, a_cespite);
 | |
|   TString filtro;
 | |
|   filtro.format("(CODES==%d)&&(TPSALDO==2)&&(TPAMM==1)",esercizio);
 | |
| 
 | |
|   TRelation rel(LF_AMMCE);
 | |
|   TCursor cur(&rel, filtro, 1, &darec, &arec);
 | |
|   const long items = cur.items();
 | |
|   cur.freeze();
 | |
|   TProgind progind(items, "Elaborazione documenti in corso...", false, true);
 | |
| //ciclo sui cespiti di AMMCE nel codes selezionato
 | |
|   for (cur=0; cur.pos()<items; ++cur)
 | |
|   { 
 | |
|     progind.addstatus(1);
 | |
|     utilizzo_per_cms(cur.curr());
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool TCalc_cesp_cms::stampa_docs()
 | |
| {
 | |
| 
 | |
| //setta la testata del form
 | |
|   _form->find_field('H', odd_page, FR_CODDITTA).set(_mask->get(F_DITTA));
 | |
|   _form->find_field('H', odd_page, FR_RAGSOC).set(_mask->get(F_RAGSOC));
 | |
|   _form->find_field('H', odd_page, FR_ESERCIZIO).set(_mask->get(F_ESERCIZIO));
 | |
|   _form->find_field('H', odd_page, FR_DATAINIZIO).set(_mask->get(F_INIZIO_ES));
 | |
|   _form->find_field('H', odd_page, FR_DATAFINE).set(_mask->get(F_FINE_ES));
 | |
| 
 | |
| //stampa i documenti via form (ci vuole una setregion)
 | |
|   TCursor& curform = *_form->cursor();
 | |
|   TRectype darec(curform.curr());
 | |
|   darec.put(RDOC_PROVV, 'D');
 | |
|   darec.put(RDOC_ANNO, _mask->get_int(F_ESERCIZIO));
 | |
|   darec.put(RDOC_CODNUM, _mask->get(F_CODNUM));
 | |
| //  darec.put(RDOC_NDOC, );	da usare se si volesse aggiungere la ricerca per categoria (NDOC)
 | |
|   TRectype arec(darec);
 | |
| //  arec.put(RDOC_NDOC, );
 | |
|   curform.setregion(darec, arec);
 | |
| 	TString filtro;
 | |
| 	const TString& dacespite = _mask->get(F_DA_IDCESPITE);
 | |
| 	const TString& acespite = _mask->get(F_A_IDCESPITE);
 | |
| 	if (dacespite.not_empty())
 | |
| 		filtro << "(CODART>='" << dacespite << "')" ;
 | |
| 
 | |
| 	if (acespite.not_empty())
 | |
| 	{
 | |
| 		if (dacespite.not_empty())
 | |
| 			filtro << "&&";
 | |
| 		filtro << "(CODART<='" << acespite << "')" ;
 | |
| 	}
 | |
| 	curform.setfilter(filtro);
 | |
| 
 | |
|   _form->print();
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool TCalc_cesp_cms::create()
 | |
| {
 | |
|   _mask = new TCalc_cesp_cms_mask;
 | |
|   _form = new TCalc_cesp_cms_form;
 | |
| 
 | |
|   TConfig config_doc ("ce4200a.ini", "Main");
 | |
|   _mask->set(F_CODNUM, config_doc.get("CODNUM"));
 | |
|   _mask->set(F_TIPODOC, config_doc.get("TIPODOC"));
 | |
|   _mask->set(F_TIPORIGA, config_doc.get("TIPORIGA"));
 | |
|   _mask->set(F_CODIVA, config_doc.get("CODIVA"));
 | |
| 	_mask->set(F_CODCF, config_doc.get("CODCF"));
 | |
| 	_mask->set(F_NUMDOCRIF, config_doc.get("NUMDOCRIF"));
 | |
|   _mask->set(F_CMSGEN, config_doc.get("CMSGEN"));
 | |
| 
 | |
|   return TSkeleton_application::create();
 | |
| }
 | |
| 
 | |
| bool TCalc_cesp_cms::destroy()
 | |
| {
 | |
|   delete _mask;
 | |
|   delete _form;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void TCalc_cesp_cms::main_loop()
 | |
| {
 | |
|   KEY k = K_ENTER;
 | |
|   while (k != K_QUIT)
 | |
|   {
 | |
|     k = _mask->run();
 | |
| 		_soloperc = _mask->get_bool(F_SOLOPERC);
 | |
| 
 | |
|     switch (k)
 | |
|     {
 | |
|       case K_ENTER:
 | |
|         elabora_docs();
 | |
|       break;
 | |
| 
 | |
|       case K_ESC: 
 | |
|         if (stampa_docs() && !_mask->get_bool(F_DEFINITIVA))
 | |
| 					//eventuale eliminazione dei documenti appena creati (richiesta di Eva Braun)
 | |
| 					delete_cespi_docs();
 | |
|       break;
 | |
| 
 | |
|       default:
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| int ce4200(int argc, char* argv[])
 | |
| {
 | |
|   TCalc_cesp_cms a;
 | |
|   a.run(argc,argv,TR("Calcolo e stampa cespiti per commessa"));
 | |
|   return 0;
 | |
| }
 |