2005-02-03 11:57:46 +00:00
|
|
|
#include <applicat.h>
|
|
|
|
#include <automask.h>
|
2005-10-10 11:26:19 +00:00
|
|
|
#include <defmask.h>
|
2005-02-03 11:57:46 +00:00
|
|
|
#include <recarray.h>
|
|
|
|
#include <relation.h>
|
|
|
|
|
2007-02-06 23:50:51 +00:00
|
|
|
#include "../cg/cglib01.h"
|
2005-02-03 11:57:46 +00:00
|
|
|
#include "calib01.h"
|
2005-10-10 11:26:19 +00:00
|
|
|
#include "calib02.h"
|
|
|
|
|
2005-02-03 11:57:46 +00:00
|
|
|
#include "ca2.h"
|
|
|
|
#include "ca2200a.h"
|
|
|
|
|
|
|
|
#include "movana.h"
|
|
|
|
#include "rmovana.h"
|
|
|
|
#include "rip.h"
|
|
|
|
#include "rrip.h"
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
// MASCHERA
|
|
|
|
//--------------------------------------------------------------------
|
2005-10-10 11:26:19 +00:00
|
|
|
class TRib_movanal_msk : public TAnal_report_mask
|
2005-02-03 11:57:46 +00:00
|
|
|
{
|
|
|
|
protected:
|
2005-10-10 11:26:19 +00:00
|
|
|
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
|
|
|
|
|
|
|
|
void save_to_ini();
|
|
|
|
void load_from_ini();
|
2005-02-03 11:57:46 +00:00
|
|
|
|
|
|
|
public:
|
2005-10-10 11:26:19 +00:00
|
|
|
TRib_movanal_msk();
|
2005-02-03 11:57:46 +00:00
|
|
|
};
|
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
void TRib_movanal_msk::save_to_ini()
|
|
|
|
{
|
|
|
|
TConfig ini(CONFIG_DITTA, "ca");
|
|
|
|
|
|
|
|
// Cancella tutte le variabili di pareggio
|
|
|
|
int j;
|
|
|
|
for (j = 1; ini.remove("Pareggio", j); j++);
|
|
|
|
|
|
|
|
TSheet_field& sf = sfield(F_RIGHE);
|
|
|
|
const int idx = sf.cid2index(F_CODCAUS);
|
|
|
|
|
|
|
|
// Salva tutte le righe dello sheet nel formato
|
|
|
|
// Pareggio(1) = Causale|Costo|Commessa|Fase
|
|
|
|
j = 0;
|
|
|
|
FOR_EACH_SHEET_ROW(sf, i, row)
|
2005-02-03 11:57:46 +00:00
|
|
|
{
|
2005-10-10 11:26:19 +00:00
|
|
|
TToken_string par = row->get(idx); // Codice causale
|
|
|
|
if (!par.blank())
|
|
|
|
{
|
|
|
|
TAnal_bill bill;
|
|
|
|
const int flags = get_row_bill(sf, i, bill);
|
|
|
|
if (flags != 0)
|
|
|
|
{
|
|
|
|
if (flags & 1) par.add(bill.costo(), 1);
|
|
|
|
if (flags & 2) par.add(bill.commessa(), 2);
|
|
|
|
if (flags & 4) par.add(bill.fase(), 3);
|
|
|
|
ini.set("Pareggio", par, NULL, true, ++j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-02-03 11:57:46 +00:00
|
|
|
}
|
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
void TRib_movanal_msk::load_from_ini()
|
2005-02-03 11:57:46 +00:00
|
|
|
{
|
2005-10-10 11:26:19 +00:00
|
|
|
// Svuota lo sheet
|
|
|
|
TSheet_field& sf = sfield(F_RIGHE);
|
|
|
|
sf.destroy();
|
|
|
|
|
|
|
|
// Carica tutte le variabili di pareggio nello sheet
|
|
|
|
TConfig ini(CONFIG_DITTA, "ca");
|
|
|
|
TToken_string par;
|
|
|
|
for (int j = 1; ; j++)
|
|
|
|
{
|
|
|
|
par = ini.get("Pareggio", NULL, j);
|
|
|
|
if (par.empty_items())
|
|
|
|
break;
|
|
|
|
const TAnal_bill bill("", par.get(1), par.get(2), par.get(3));
|
|
|
|
set_row_bill(sf, -1, bill);
|
|
|
|
}
|
|
|
|
}
|
2005-02-03 11:57:46 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
bool TRib_movanal_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
|
|
|
|
{
|
|
|
|
switch (o.dlg())
|
|
|
|
{
|
2007-02-06 23:50:51 +00:00
|
|
|
case F_DATAINI:
|
|
|
|
case F_DATAFIN:
|
|
|
|
if (e == fe_close)
|
|
|
|
{
|
|
|
|
const int anno = get_int(F_ANNO);
|
|
|
|
|
|
|
|
TEsercizi_contabili esc; //..le date devono essere incluse nell'esercizio selezionato!
|
|
|
|
const TDate data(o.get());
|
|
|
|
if (!data.empty() && esc.date2esc(data) != anno)
|
|
|
|
return error_box(TR("La data deve appartenere all'anno selezionato"));
|
|
|
|
}
|
|
|
|
break;
|
2005-10-10 11:26:19 +00:00
|
|
|
case DLG_OK:
|
|
|
|
case DLG_SAVEREC:
|
|
|
|
if (e == fe_button)
|
|
|
|
save_to_ini();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return TAnal_report_mask::on_field_event(o, e, jolly);
|
|
|
|
}
|
2005-02-03 11:57:46 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
TRib_movanal_msk::TRib_movanal_msk() : TAnal_report_mask("ca2200a")
|
2005-02-03 11:57:46 +00:00
|
|
|
{
|
2005-10-10 11:26:19 +00:00
|
|
|
create_sheet(F_RIGHE);
|
|
|
|
load_from_ini();
|
2005-02-03 11:57:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
// APPLICAZIONE
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
class TRib_movanal_app : public TSkeleton_application
|
|
|
|
{
|
2005-02-23 09:30:28 +00:00
|
|
|
TCache_ripartizioni _cache_rip;
|
2005-03-09 12:06:35 +00:00
|
|
|
bool _definitivo;
|
2005-10-10 11:26:19 +00:00
|
|
|
TAssoc_array _caus_cms;
|
2005-02-03 11:57:46 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
virtual const char* extra_modules() const { return "cm"; } //deve funzionare anche per le commesse
|
2005-03-02 15:28:14 +00:00
|
|
|
|
2005-02-03 11:57:46 +00:00
|
|
|
protected:
|
|
|
|
virtual void main_loop();
|
|
|
|
|
2008-04-15 14:29:54 +00:00
|
|
|
bool explode_rows(const TRecord_array& input_rows, TRecord_array& output_rows, const int annoes,
|
|
|
|
const char tipomov);
|
2005-10-10 11:26:19 +00:00
|
|
|
bool pareggia_commessa(TAnal_mov& anal_mov);
|
2005-02-03 11:57:46 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
public:
|
|
|
|
bool cappotta_movimento(TAnal_mov& anal_mov);
|
2007-02-06 23:50:51 +00:00
|
|
|
TRib_movanal_app(){}
|
2005-10-10 11:26:19 +00:00
|
|
|
};
|
2005-02-03 11:57:46 +00:00
|
|
|
|
2008-04-15 14:29:54 +00:00
|
|
|
bool TRib_movanal_app::explode_rows(const TRecord_array& input_rows, TRecord_array& output_rows,
|
|
|
|
const int annoes, const char tipomov)
|
2005-03-02 13:37:46 +00:00
|
|
|
{
|
|
|
|
bool ho_cambiato_qualchecosa = false;
|
2005-02-23 09:30:28 +00:00
|
|
|
for (int r = 1; r <= input_rows.rows(); r++)
|
|
|
|
{
|
|
|
|
const TRectype& rec = input_rows.row(r);
|
2007-07-16 15:01:42 +00:00
|
|
|
TAnal_bill zio(rec);
|
|
|
|
const int rmovana_indbil = zio.indicatore_bilancio();
|
2008-05-13 13:22:22 +00:00
|
|
|
const TAnal_ripartizioni_batch& rrip = _cache_rip.righe(rec.get(RMOVANA_CODCCOSTO), rec.get(RMOVANA_CODCMS),
|
|
|
|
rec.get(RMOVANA_CODFASE), annoes, rmovana_indbil, tipomov);
|
2007-06-22 14:13:07 +00:00
|
|
|
//ci sono righe di ripartizione
|
2007-06-22 15:07:47 +00:00
|
|
|
const int righe_ripartizione = rrip.rows();
|
|
|
|
bool ripartisci = righe_ripartizione > 0;
|
2007-07-09 14:39:00 +00:00
|
|
|
|
2007-06-22 14:13:07 +00:00
|
|
|
if (ripartisci)
|
2005-02-23 09:30:28 +00:00
|
|
|
{
|
|
|
|
// Importo totale da distribuire arrotondato ai decimali della valuta di conto
|
|
|
|
TGeneric_distrib distrib(rec.get_real(RMOVANA_IMPORTO), TCurrency::get_firm_dec());
|
|
|
|
|
|
|
|
// Calcolo tutte le percentuali da ripartire
|
|
|
|
int i;
|
2007-06-22 15:07:47 +00:00
|
|
|
for (i = 1; i <= righe_ripartizione; i++)
|
2005-03-16 12:12:22 +00:00
|
|
|
distrib.add(rrip[i].get_real(RRIP_RIPARTO));
|
2005-02-23 09:30:28 +00:00
|
|
|
|
2007-06-22 15:07:47 +00:00
|
|
|
for (i = 1; i <= righe_ripartizione; i++)
|
2005-02-23 09:30:28 +00:00
|
|
|
{
|
|
|
|
const real imp = distrib.get(); // Legge la quota da distribuire
|
2007-02-07 00:12:05 +00:00
|
|
|
|
|
|
|
if (imp != ZERO)
|
|
|
|
{
|
|
|
|
TRectype* newrec = new TRectype(rec);
|
|
|
|
newrec->put(RMOVANA_NUMRIG, output_rows.rows() + 1);
|
|
|
|
newrec->put(RMOVANA_IMPORTO, imp); //e la mette nella nuova riga
|
|
|
|
//poi copia i valori dei campi cdc,cms,fsc,in quelli di tipo ori (nello stesso record)
|
2007-07-10 15:23:41 +00:00
|
|
|
ca_copia_campo(rec, RMOVANA_CODCCOSTO, *newrec, RMOVANA_CODCCORI);
|
|
|
|
ca_copia_campo(rec, RMOVANA_CODCMS, *newrec, RMOVANA_CODCMSORI);
|
|
|
|
ca_copia_campo(rec, RMOVANA_CODFASE, *newrec, RMOVANA_CODFASEORI);
|
|
|
|
ca_copia_campo(rec, RMOVANA_CODCONTO, *newrec, RMOVANA_CODCONTORI);
|
2007-02-07 00:12:05 +00:00
|
|
|
//e mette nei campi std i valori che trova nelle righe ripartizione
|
2007-07-10 15:23:41 +00:00
|
|
|
ca_copia_campo(rrip[i], RRIP_CODCOSTO, *newrec, RMOVANA_CODCCOSTO);
|
|
|
|
ca_copia_campo(rrip[i], RRIP_CODCMS, *newrec, RMOVANA_CODCMS);
|
|
|
|
ca_copia_campo(rrip[i], RRIP_CODFASE, *newrec, RMOVANA_CODFASE);
|
|
|
|
ca_copia_campo(rrip[i], RRIP_CODCONTO, *newrec, RMOVANA_CODCONTO);
|
2007-02-07 00:12:05 +00:00
|
|
|
|
|
|
|
output_rows.add_row(newrec);
|
|
|
|
ho_cambiato_qualchecosa = true;
|
|
|
|
}
|
2005-02-23 09:30:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else //nessuna riga di ripartizione->aggiungo la riga input all'output
|
|
|
|
{
|
2005-03-09 12:06:35 +00:00
|
|
|
TRectype* newrec = new TRectype(rec);
|
|
|
|
newrec->put(RMOVANA_NUMRIG, output_rows.rows() + 1);
|
|
|
|
output_rows.add_row(newrec);
|
2005-02-23 09:30:28 +00:00
|
|
|
}
|
2005-02-03 11:57:46 +00:00
|
|
|
}
|
2005-03-02 13:37:46 +00:00
|
|
|
return ho_cambiato_qualchecosa;
|
|
|
|
}
|
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
bool TRib_movanal_app::pareggia_commessa(TAnal_mov& anal_mov)
|
|
|
|
{
|
|
|
|
bool ho_cambiato_qualchecosa = false;
|
2005-03-02 13:37:46 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
const TString& codcaus = anal_mov.get(MOVANA_CODCAUS);
|
|
|
|
const TAnal_bill* cms = (const TAnal_bill*)_caus_cms.objptr(codcaus);
|
|
|
|
if (cms != NULL) // La causale del movimento e' tra quelle da pareggiare
|
|
|
|
{
|
|
|
|
const TImporto totdoc(anal_mov.get_char(MOVANA_SEZIONE), anal_mov.get_real(MOVANA_TOTDOC));
|
|
|
|
if (!totdoc.is_zero()) // Movimento da pareggiare
|
|
|
|
{
|
|
|
|
TRecord_array& body = anal_mov.body();
|
|
|
|
// Cerco la commessa/fase/costo tra le righe esistenti
|
2006-12-29 14:16:28 +00:00
|
|
|
int i;
|
|
|
|
for (i = body.last_row(); i > 0; i--)
|
2005-10-10 11:26:19 +00:00
|
|
|
{
|
|
|
|
const TRectype& row = body[i];
|
|
|
|
if ((cms->costo().blank() || row.get(RMOVANA_CODCCOSTO) == cms->costo()) &&
|
|
|
|
(cms->commessa().blank() || row.get(RMOVANA_CODCMS) == cms->commessa()) &&
|
|
|
|
(cms->fase().blank() || row.get(RMOVANA_CODFASE) == cms->fase()))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Se non trovo nessuna riga compatibile, me la creo
|
|
|
|
if (i <= 0)
|
|
|
|
{
|
|
|
|
TRectype& rmovana = anal_mov.new_row();
|
|
|
|
rmovana.put(RMOVANA_DESCR, TR("Pareggio commessa"));
|
|
|
|
rmovana.put(RMOVANA_CODCCOSTO, cms->costo());
|
|
|
|
rmovana.put(RMOVANA_CODCMS, cms->commessa());
|
|
|
|
rmovana.put(RMOVANA_CODFASE, cms->fase());
|
|
|
|
i = rmovana.get_int(RMOVANA_NUMRIG);
|
|
|
|
}
|
2005-03-02 13:37:46 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
// Sottraggo all'importo della riga il totale documento,
|
|
|
|
// il quale verra' quindi azzerato
|
|
|
|
TRectype& rmovana = body[i];
|
|
|
|
TImporto importo(rmovana.get_char(RMOVANA_SEZIONE), rmovana.get_real(RMOVANA_IMPORTO));
|
|
|
|
importo -= totdoc;
|
|
|
|
importo.normalize();
|
|
|
|
rmovana.put(RMOVANA_SEZIONE, importo.sezione());
|
|
|
|
rmovana.put(RMOVANA_IMPORTO, importo.valore());
|
|
|
|
anal_mov.put(MOVANA_TOTDOC, ZERO);
|
|
|
|
|
|
|
|
ho_cambiato_qualchecosa = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ho_cambiato_qualchecosa;
|
|
|
|
}
|
2005-02-23 09:30:28 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
bool TRib_movanal_app::cappotta_movimento(TAnal_mov& anal_mov)
|
|
|
|
{
|
2005-03-02 13:37:46 +00:00
|
|
|
TRecord_array& input_rows = anal_mov.body(); //record_array con le righe del mov_anal (INPUT)
|
|
|
|
|
|
|
|
//Per prima cosa prende le righe del movimento su RMOVANA e le ricompatta..
|
2007-06-29 10:02:47 +00:00
|
|
|
TRecord_array compact_rows = input_rows; //record array con le righe compattate da creare con la..
|
|
|
|
compact_rows.destroy_rows(); //..implode_rows(); intanto le azzera per sicurezza
|
2005-03-02 13:37:46 +00:00
|
|
|
//Imploditore
|
2007-07-10 15:23:41 +00:00
|
|
|
ca_implode_rows(input_rows, compact_rows);
|
2005-03-02 13:37:46 +00:00
|
|
|
|
|
|
|
//..poi lo riesplode in tutte le righe che possono nascere secondo le regole delle ripartizioni!
|
|
|
|
TRecord_array output_rows = input_rows; //crea il record_array di output come copia dell'INPUT..
|
|
|
|
output_rows.destroy_rows(); //..e poi lo pulisce
|
2005-03-09 12:06:35 +00:00
|
|
|
|
|
|
|
bool do_rewrite = false;
|
2005-03-02 13:37:46 +00:00
|
|
|
//Esploditore
|
2008-04-15 14:29:54 +00:00
|
|
|
if (explode_rows(compact_rows, output_rows, anal_mov.get_int(MOVANA_ANNOES), anal_mov.get_char(MOVANA_TIPOMOV)))
|
2005-03-09 12:06:35 +00:00
|
|
|
{
|
|
|
|
input_rows = output_rows; //rimette i record elaborati negli originali
|
|
|
|
do_rewrite = true;
|
|
|
|
}
|
2005-10-10 11:26:19 +00:00
|
|
|
if (pareggia_commessa(anal_mov))
|
|
|
|
do_rewrite = true;
|
|
|
|
|
|
|
|
if (_definitivo) //se l'elaborazione e' definitiva...
|
2005-03-09 12:06:35 +00:00
|
|
|
{
|
|
|
|
anal_mov.put(MOVANA_BLOCCATO, 'X'); //..mette bloccato = X nella testata del movimento
|
|
|
|
do_rewrite = true;
|
|
|
|
}
|
2005-10-10 11:26:19 +00:00
|
|
|
|
|
|
|
return do_rewrite; //se ha elaborato delle righe e/o e' una elaborazione definitiva, riscrive la..
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cappotta_callback(const TRelation& rel, void* pJolly)
|
|
|
|
{
|
|
|
|
TRib_movanal_app& app = *(TRib_movanal_app*)pJolly;
|
|
|
|
const long numreg = rel.curr().get_long(MOVANA_NUMREG);
|
|
|
|
TAnal_mov anal_mov(numreg);
|
2007-06-29 10:02:47 +00:00
|
|
|
//se va tutto bene riscrive l'intero movimento analitico con conseguente ricalcolo saldi
|
2005-10-10 11:26:19 +00:00
|
|
|
if (app.cappotta_movimento(anal_mov))
|
|
|
|
anal_mov.rewrite(rel.lfile());
|
|
|
|
|
2005-02-03 11:57:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TRib_movanal_app::main_loop()
|
|
|
|
{
|
2005-10-10 11:26:19 +00:00
|
|
|
TRib_movanal_msk mask;
|
|
|
|
while (mask.run() == K_ENTER)
|
2005-02-03 11:57:46 +00:00
|
|
|
{
|
2005-10-10 11:26:19 +00:00
|
|
|
// avvisa l'utente scapestrato che se fa una elaborazione definitiva
|
|
|
|
// blocchera' i movimenti che processa
|
|
|
|
_definitivo = mask.get_bool(F_DEFINITIVO);
|
2005-02-03 11:57:46 +00:00
|
|
|
//deve scandire il file MOVANA con chiave 2 (per data e numero di registrazione)
|
|
|
|
TRelation rel_movana(LF_MOVANA);
|
|
|
|
TRectype darec(LF_MOVANA), arec(LF_MOVANA);
|
2007-02-06 23:50:51 +00:00
|
|
|
const TDate & dal = mask.get_date(F_DATAINI);
|
2007-06-22 14:13:07 +00:00
|
|
|
darec.put(MOVANA_DATACOMP, dal);
|
2007-02-06 23:50:51 +00:00
|
|
|
const TDate & al = mask.get_date(F_DATAFIN);
|
2007-06-22 14:13:07 +00:00
|
|
|
arec.put(MOVANA_DATACOMP, al);
|
2007-06-21 14:59:20 +00:00
|
|
|
_cache_rip.set_esercizio(mask.get_int(F_ANNO));
|
2005-02-03 11:57:46 +00:00
|
|
|
|
2005-10-10 11:26:19 +00:00
|
|
|
TCursor cur_movana(&rel_movana, "BLOCCATO!=\"X\"", 2, &darec, &arec);
|
2005-02-03 11:57:46 +00:00
|
|
|
const long items = cur_movana.items();
|
|
|
|
if (items > 0)
|
|
|
|
{
|
2005-03-09 12:06:35 +00:00
|
|
|
bool run = yesno_box(FR("Si desidera elaborare %ld movimenti?"), items);
|
|
|
|
if (run && _definitivo)
|
2005-10-10 11:26:19 +00:00
|
|
|
run = yesno_box(TR("E' stata selezionata l'elaborazione definitiva\nSi desidera proseguire?"));
|
2005-03-09 12:06:35 +00:00
|
|
|
if (run)
|
|
|
|
{
|
2005-10-10 11:26:19 +00:00
|
|
|
// Riempie la lista della causali dei movimenti da pareggiare
|
|
|
|
_caus_cms.destroy();
|
|
|
|
TSheet_field& sf = mask.sfield(F_RIGHE);
|
2007-06-22 14:13:07 +00:00
|
|
|
const int pos_codcaus = sf.cid2index(F_CODCAUS);
|
2005-10-10 11:26:19 +00:00
|
|
|
FOR_EACH_SHEET_ROW(sf, i, row)
|
|
|
|
{
|
2007-06-22 14:13:07 +00:00
|
|
|
const TString4 codcaus = row->get(pos_codcaus);
|
|
|
|
if (codcaus.full())
|
2005-10-10 11:26:19 +00:00
|
|
|
{
|
|
|
|
TAnal_bill* bill = new TAnal_bill;
|
|
|
|
if (mask.get_row_bill(sf, i, *bill) != 0)
|
|
|
|
_caus_cms.add(codcaus, bill);
|
|
|
|
else
|
|
|
|
delete bill;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-15 14:29:54 +00:00
|
|
|
cur_movana.scan(cappotta_callback, this, TR("Ripartizione movimenti..."));
|
2005-03-09 12:06:35 +00:00
|
|
|
}
|
2005-02-03 11:57:46 +00:00
|
|
|
}
|
|
|
|
else
|
2005-03-09 12:06:35 +00:00
|
|
|
message_box(TR("Non ci sono movimenti da elaborare nel periodo selezionato"));
|
2005-02-03 11:57:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ca2200(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
TRib_movanal_app app;
|
2008-04-15 14:29:54 +00:00
|
|
|
app.run(argc, argv, TR("Ripartizione movimenti di analitica"));
|
2005-02-03 11:57:46 +00:00
|
|
|
return 0;
|
|
|
|
}
|