]> rtime.felk.cvut.cz Git - frescor/fosa.git/commitdiff
Additions to fosa time to be used with FRSH
authortelleriam <telleriam@35b4ef3e-fd22-0410-ab77-dab3279adceb>
Wed, 12 Mar 2008 12:35:07 +0000 (12:35 +0000)
committertelleriam <telleriam@35b4ef3e-fd22-0410-ab77-dab3279adceb>
Wed, 12 Mar 2008 12:35:07 +0000 (12:35 +0000)
git-svn-id: http://www.frescor.org/private/svn/frescor/fosa/trunk@1042 35b4ef3e-fd22-0410-ab77-dab3279adceb

include/fosa_opaque_types_time.h
include/fosa_time_numeric.h
include/fosa_time_timespec.h
src_marte/tests/test_time/fosa_test_time.c

index 5d2b14623438e5ca81c8cc37417382cdfb1a89ee..d1f6ab0c581e36cca0cb339ec6878a5d39ff7e83 100644 (file)
    -  numeric type (long, .long long, short)
 **/
 
-
 #define FOSA_TIME_TIMESPEC
 
 typedef struct timespec FOSA_REL_TIME_T_OPAQUE;
 typedef struct timespec FOSA_ABS_TIME_T_OPAQUE;
 
 
-
-
 /*
+
 #define FOSA_TIME_NUMERIC
 #define FOSA_TIME_BASE 9    // 9 for nanosecods
                             // 6 for microseconds
@@ -120,14 +118,16 @@ typedef unsigned long long FOSA_ABS_TIME_T_OPAQUE;
    -  struct timespec
    -  numeric type (long, .long long, short)
 **/
-
+/*
 #define FOSA_TIME_TIMESPEC
 
 typedef struct timespec FOSA_REL_TIME_T_OPAQUE;
 typedef struct timespec FOSA_ABS_TIME_T_OPAQUE;
 
+*/
 
 /*
+
 #define FOSA_TIME_NUMERIC
 #define FOSA_TIME_BASE 9    // 9 for nanosecods
                             // 6 for microseconds
@@ -137,6 +137,7 @@ typedef long long FOSA_REL_TIME_T_OPAQUE;
 typedef unsigned long long FOSA_ABS_TIME_T_OPAQUE;
 
 */
+
 /**
    Possible additions:  FOSA_ABS_TIME_MAX, FOSA_ABS_TIME_MIN,
    FOSA_REL_TIME_MAX, FOSA_REL_TIME_MIN to protect
index d78f7b98a97fe68b2dc77f526a6d947874b952a2..360f5d4527d2ee9d9fd011f9222efeef7d7e22ed 100644 (file)
@@ -77,6 +77,9 @@
 #define msec_to_fosa_time(msec) (msec) * 1000000
 #define fosa_time_to_usec(time) (time) / 1000
 #define usec_to_fosa_time(usec) (usec) * 1000
+#define fosa_time_to_nsec(time) (time) 
+#define nsec_to_fosa_time(nsec) (nsec)
+
 
 #define timespec_to_fosa_time(time_type, tspec)  ((time_type) (tspec).tv_sec) * 1000000000 + (time_type) (tspec).tv_nsec
 
@@ -86,7 +89,8 @@ do { \
     (tspec).tv_nsec = (time) % 1000000000; \
 } while(0)
 
-
+#define fosa_time_to_double(time)  (double) (time) * 1e-9;
+#define fosa_double_to_time(time_type, time) (time_type) (time * 1e9)
 
 #endif
 
@@ -96,6 +100,8 @@ do { \
 #define msec_to_fosa_time(msec) (msec) * 1000
 #define fosa_time_to_usec(time) (time)
 #define usec_to_fosa_time(usec) (usec)
+#define fosa_time_to_nsec(time) (time) * 1000
+#define nsec_to_fosa_time(nsec) (nsec) / 1000
 
 #define timespec_to_fosa_time(time_type, tspec) ( (time_type) (tspec).tv_sec) * 1000000 + (time_type) (tspec).tv_nsec/1000
 
@@ -105,6 +111,8 @@ do { \
     (tspec).tv_nsec = ( (time) % 1000000) * 1000; \
 } while(0)
 
+#define fosa_time_to_double(time)  (double) (time) * 1e-6;
+#define fosa_double_to_time(time_type, time) (time_type) (time * 1e6)
 
 #endif
 
@@ -114,6 +122,8 @@ do { \
 #define msec_to_fosa_time(msec) (msec)
 #define fosa_time_to_usec(time) (time) * 1000
 #define usec_to_fosa_time(usec) (usec) / 1000
+#define fosa_time_to_nsec(time) (time) * 1000000
+#define nsec_to_fosa_time(nsec) (nsec) / 1000000
 
 #define timespec_to_fosa_time(time_type, tspec) ( (time_type) (tspec).tv_sec) * 1000 + (time_type) (tspec).tv_nsec/1000000
 
@@ -123,6 +133,9 @@ do { \
     (tspec).tv_nsec = ( (time) % 1000) * 1000000; \
 } while(0)
 
+#define fosa_time_to_double(time)  (double) (time) * 1e-3;
+#define fosa_double_to_time(time_type, time) (time_type) (time) * 1e3
+
 
 #endif
 
@@ -189,6 +202,29 @@ static inline fosa_rel_time_t fosa_rel_time_decr(fosa_rel_time_t total, fosa_rel
     return result;
 }
 
+// ---------------------------------------------------------
+
+
+static inline fosa_rel_time_t fosa_rel_time_times_integer(fosa_rel_time_t time, long multiplier)
+{
+    fosa_rel_time_t result;
+
+    result = time * multiplier;
+
+    return result;
+}
+
+
+// ---------------------------------------------------------
+
+static inline fosa_rel_time_t fosa_rel_time_divided_by_integer(fosa_rel_time_t time, long divider)
+{
+    return time / divider;
+}
+
+
+
+
 
 /* Comparison */
 /**************/
@@ -237,6 +273,54 @@ static inline bool fosa_rel_time_smaller_or_equal(fosa_rel_time_t relt1, fosa_re
 }
 
 
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_equal(fosa_rel_time_t relt1, fosa_rel_time_t relt2)
+{
+    bool result;
+
+    result = relt1 == relt2;
+
+    return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_equal(fosa_abs_time_t abst1, fosa_abs_time_t abst2)
+{
+    bool result;
+
+    result = abst1 == abst2;
+
+    return result;
+}
+
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_is_null(fosa_rel_time_t relt)
+{
+    bool result;
+
+    result = relt == 0;
+
+    return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_is_null(fosa_abs_time_t abst)
+{
+    bool result;
+
+    result = abst == 0;
+
+    return result;
+}
+
+
+
 /* Conversion */
 /**************/
 static inline fosa_rel_time_t fosa_msec_to_rel_time(long msec)
@@ -330,6 +414,52 @@ static inline long fosa_abs_time_to_usec(fosa_abs_time_t abst)
 }
 
 
+
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_nsec_to_rel_time(long nsec)
+{
+    fosa_rel_time_t result;
+
+    result = nsec_to_fosa_time((fosa_rel_time_t ) nsec);
+
+    return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_rel_time_to_nsec(fosa_rel_time_t relt)
+{
+    long result;
+
+    result = fosa_time_to_nsec(relt);
+
+    return result;
+}
+
+
+// --------------------------------------------------
+
+static inline fosa_abs_time_t fosa_nsec_to_abs_time(long nsec)
+{
+    fosa_abs_time_t result;
+
+    result = nsec_to_fosa_time( (fosa_abs_time_t) nsec);
+
+    return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_abs_time_to_nsec(fosa_abs_time_t abst)
+{
+    long result;
+
+    result = fosa_time_to_nsec(abst);
+
+    return result;
+}
+
 // --------------------------------------------------
 
 static inline fosa_rel_time_t fosa_timespec_to_rel_time(struct timespec time_tspec)
@@ -375,4 +505,29 @@ static inline struct timespec fosa_abs_time_to_timespec(fosa_abs_time_t abst)
 }
 
 
+
+// --------------------------------------------------
+
+static inline double fosa_rel_time_to_double(fosa_rel_time_t relt)
+{
+    double result;
+
+    result = fosa_time_to_double(relt);
+    return result;
+}
+
+
+// --------------------------------------------------
+
+static inline double fosa_double_to_rel_time(double time)
+{
+    fosa_rel_time_t result;
+
+    result = fosa_double_to_time(fosa_rel_time_t, time);
+    return result;
+}
+
+
+
+
 #endif             /* !FOSA_TIME_H_ */
index 4d5f2b5b26e2c636032272e567d8618fba6f273f..942d9e5515f1f0246557aff3f21ea69a19216af3 100644 (file)
 #ifndef        FOSA_TIME_TIMESPEC_H_
 #define        FOSA_TIME_TIMESPEC_H_
 
+#include <stdlib.h>
+#include <assert.h>
 
 /**********************************/
 /* T I M E S P E C   M A C R O S  */
 /**********************************/
 
+#define normalize_timespec(t1) \
+do \
+{ \
+    if ((t1).tv_nsec >= 1000000000) \
+    { \
+        (t1).tv_sec++; \
+        (t1).tv_nsec -= 1000000000; \
+    } \
+} while(0)
+
+
 #define add_timespec(sum, t1, t2) \
 do { \
     (sum).tv_sec = (t1).tv_sec + (t2).tv_sec; \
     (sum).tv_nsec = (t1).tv_nsec + (t2).tv_nsec; \
-    if ((sum).tv_nsec >= 1000000000) \
-    { \
-        (sum).tv_sec++; \
-        (sum).tv_nsec -= 1000000000; \
-    } \
+    normalize_timespec(sum); \
 } while(0)
 
 
+
 // -------------------------------------------------------------------
 
 /* TODO:  Test that for past > future we obtain a correct negative
@@ -149,7 +159,34 @@ do { \
    ( ((t1).tv_sec % 2148) * 1000000 + (t1).tv_nsec/1000 )
 
 
+// ---------------------------------------------------------
+
+#define nsec_to_timespec(tspec, nsec) \
+do { \
+    if ((nsec) >= 1000000000) { \
+        (tspec).tv_sec = (nsec)/1000000000; \
+        (tspec).tv_nsec = (nsec) % 1000000000; \
+    } else { \
+        (tspec).tv_sec = 0; \
+        (tspec).tv_nsec = (nsec); \
+    } \
+} while(0)
+
+// ---------------------------------------------------------
+
+#define timespec_to_nsec(t1) \
+   ( ((t1).tv_sec % 2) * 1000000000 + (t1).tv_nsec )
+
+
+
+// ---------------------------------------------------------
+
+#define timespec_equal(t1, t2) ( (t1).tv_sec == (t2).tv_sec ) && ( (t1).tv_nsec == (t2).tv_nsec )
+
+#define timespec_is_null(t1) ( (t1).tv_sec == 0 ) && ( (t1).tv_nsec == 0 )
 
+
+  
 /***************************************/
 /* T I M E S P E C   F U N C T I O N S */
 /***************************************/
@@ -171,8 +208,6 @@ static inline fosa_abs_time_t fosa_abs_time_decr(fosa_abs_time_t base, fosa_rel_
 {
     fosa_abs_time_t result;
 
-
-
     substract_timespec(result, base, interval);
 
     return result;
@@ -204,7 +239,6 @@ static inline fosa_rel_time_t fosa_rel_time_add(fosa_rel_time_t relt1, fosa_rel_
 }
     
 
-
 // ---------------------------------------------------------
 
 static inline fosa_rel_time_t fosa_rel_time_decr(fosa_rel_time_t total, fosa_rel_time_t part)
@@ -216,6 +250,224 @@ static inline fosa_rel_time_t fosa_rel_time_decr(fosa_rel_time_t total, fosa_rel
     return result;
 }
 
+// ---------------------------------------------------------
+
+/**
+ * exact_long_multiply_smaller_10e5()
+ *
+ * Same as below but with operands smaller than 10000 which allows
+ * to perform all component multiplications without an overflow risk. 
+ **/
+static inline struct timespec exact_long_multiply_smaller_10e5(long t, long k)
+{
+    /* Since operands are smaller than 10e5 we can use 1000 */
+    /* the base without risking to cause overflows in the   */
+    /* operations.                                          */
+    /********************************************************/
+    assert(t < 10000);
+    assert(k < 10000);
+
+    struct timespec result;
+
+    long base = 1000;
+
+    long t_high = t / base;
+    long t_low = t % base;
+    long k_high = k / base;
+    long k_low = k % base;
+
+    long thkh = t_high * k_high;
+    long thkl = t_high * k_low;
+    long tlkh = t_low * k_high;
+    long tlkl = t_low * k_low;
+
+    long thkl_high = thkl / base;
+    long tlkh_high = tlkh / base;
+    long thkl_low = thkl % base;
+    long tlkh_low = tlkh % base;
+
+    long c2 = thkh + thkl_high + tlkh_high; // Normalized at 10^6
+    long c1 = thkl_low + tlkh_low;  // Normalized at 10^3
+    long c0 = tlkl;
+
+    result.tv_sec = c2/1000 + c1/1000000;
+    result.tv_nsec = (c2 % 1000) * 1000000 + (c1 % 1000000) * 1000 + c0;
+
+    result.tv_sec += (result.tv_nsec / 1000000000);
+    result.tv_nsec %= 1000000000;
+
+    return result;
+}
+
+    
+// -------------------------------------------------------------    
+
+    
+
+/**
+ * exact_long_multiply()
+ *
+ * This function performs an exact long * long operations on operands
+ * lower than 1e9 without using more than 32bit (1e9) arithmetic.
+ *
+ * To achieve this we decompose the operands in high and low:
+ *
+ * num = (num/base) * base + (num % base)
+ *        ^^^^^^^^           ^^^^^^^^^^^^
+ *        high component     low component
+ *
+ * t * k = (th*kh + th*kl/base + tl*kh/base  )*base^2
+ *         +  (th*kl % base)*base + (tl*kh % base) * base + tl*kl
+ *
+ * The problem is that we cannot use an exact base because sqrt(1e9)
+ * is not a multiple of 1e9 (in fact it is not even integer).
+ *
+ * So we use as a base 100000 which means that the last term tl*kl may
+ * need another exact calculation with a lower base (100)
+ **/
+static inline struct timespec exact_long_multiply(long t, long k)
+{
+    struct timespec result;
+
+    long t_high;
+    long t_low;
+    long k_high;
+    long k_low;
+
+    long base = 100000;  /* Power of 10 closest to sqrt(1e9) from
+                          * above */
+
+    t_high = t / base;
+    t_low = t % base;  // Between 0 99999
+    k_high = k / base;
+    k_low = k % base;  // Between 0 99999
+
+    /* These numbers are always lower than 1e9 */
+    long thkh = t_high * k_high;
+    long thkl = t_high * k_low;
+    long tlkh = t_low * k_high;
+
+    long thkl_high = thkl / base;
+    long thkl_low = thkl % base;
+    long tlkh_high = tlkh / base;
+    long tlkh_low = tlkh % base;
+
+    /* We can calculate the base^2 term (note however that this is 10
+     * times the tv_sec component because it is multiplied by 10^10 */
+    long c2 = thkh + thkl_high + tlkh_high;  // scaled to 10^10
+    long c1 = thkl_low + tlkh_low;  // scaled to 10^5
+
+    struct timespec c0;
+
+    /* Now we can write the initial values of result */
+    result.tv_sec = c2*10 + c1/10000;
+    result.tv_nsec = (c1 % 10000) * 100000;
+
+    normalize_timespec(result);
+
+    /* To calculate c0 we must check if there is a risk of overflow */
+    /* Remember operands cannot be larger than 99999 and result     */
+    /* larger than 1e9.                                             */
+    /****************************************************************/
+    bool overflow_risk;
+    overflow_risk = false;
+
+    if (
+        ( (t_low > 31622) && (k_low >= 10000) ) ||
+        ( (k_low > 31622) && (t_low >= 10000) )
+        )
+    {
+        overflow_risk = true;
+    }
+    
+    if (! overflow_risk)
+    {
+        c0.tv_sec = 0;
+        c0.tv_nsec = t_low * k_low;
+        normalize_timespec(c0);
+    }
+    else
+    {
+        c0 = exact_long_multiply_smaller_10e5(t_low, k_low);
+    }
+    add_timespec(result, result, c0);
+
+    return result;
+}
+    
+// -------------------------------------------------------------    
+
+
+static inline fosa_rel_time_t fosa_rel_time_times_integer(fosa_rel_time_t time, long multiplier)
+{
+    struct timespec result;
+    struct timespec intermediate;
+
+    result.tv_sec = time.tv_sec * multiplier;  // No overflow check here
+    result.tv_nsec = 0;
+
+    intermediate = exact_long_multiply(time.tv_nsec, multiplier);
+
+    add_timespec(result, result, intermediate);
+    
+    return result;
+}
+
+// ---------------------------------------------------------
+
+static inline fosa_rel_time_t fosa_rel_time_divided_by_integer(fosa_rel_time_t time, long divider)
+{
+    struct timespec result;
+    long reminder;
+
+
+    result.tv_sec = time.tv_sec / divider;
+    result.tv_nsec = 0;
+
+    /* We iterate until the reminder is lower than 2 (to later fit in
+     * a 32 bit signed integer multiplied by 1e9 */
+
+    reminder = time.tv_sec % divider;
+
+
+    if (reminder == 0)
+    {
+        /* We are lucky no reminder so no need to transfer it to the
+           nsec scale.
+        */
+        result.tv_nsec = time.tv_nsec/divider;
+        return result;
+    }
+
+    long enhacer;
+    long back_enhacer;
+    long next_dividend;
+    int next_numeral; /* Between 0 and 9 */
+    enhacer = 1;
+    do
+    {
+        enhacer *= 10;
+        back_enhacer = 1000000000 / enhacer;
+        next_numeral = (time.tv_nsec / back_enhacer) % 10;
+        
+        // Note:  a possible overflow may happen here with large denominators
+        if (reminder > 200000000)
+        {
+            /* An overflow is going to be produced */
+            abort();
+        }
+        next_dividend = reminder * 10 + next_numeral;
+        
+        result.tv_nsec += (next_dividend / divider) * back_enhacer;
+        reminder = next_dividend % divider;
+    } while (back_enhacer > 1);
+
+    
+    return result;
+}
+
+// ---------------------------------------------------------
+
 
 /* Comparison */
 /**************/
@@ -264,6 +516,55 @@ static inline bool fosa_rel_time_smaller_or_equal(fosa_rel_time_t relt1, fosa_re
 }
 
 
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_equal(fosa_rel_time_t relt1, fosa_rel_time_t relt2)
+{
+    bool result;
+
+    result = timespec_equal(relt1, relt2);
+
+    return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_equal(fosa_abs_time_t abst1, fosa_abs_time_t abst2)
+{
+    bool result;
+
+    result = timespec_equal(abst1, abst2);
+
+    return result;
+}
+
+// -----------------------------------------------------------
+
+static inline bool fosa_rel_time_is_null(fosa_rel_time_t relt)
+{
+    bool result;
+
+    result = timespec_is_null(relt);
+
+    return result;
+}
+
+
+// -----------------------------------------------------------
+
+static inline bool fosa_abs_time_is_null(fosa_abs_time_t abst)
+{
+    bool result;
+
+    result = timespec_is_null(abst);
+
+    return result;
+}
+
+
+
+
 /* Conversion */
 /**************/
 static inline fosa_rel_time_t fosa_msec_to_rel_time(long msec)
@@ -358,6 +659,51 @@ static inline long fosa_abs_time_to_usec(fosa_abs_time_t abst)
     return result;
 }
 
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_nsec_to_rel_time(long nsec)
+{
+    fosa_rel_time_t result;
+
+    nsec_to_timespec(result, nsec);
+
+    return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_rel_time_to_nsec(fosa_rel_time_t relt)
+{
+    long result;
+
+    result = timespec_to_nsec(relt);
+
+    return result;
+}
+
+
+// --------------------------------------------------
+
+static inline fosa_abs_time_t fosa_nsec_to_abs_time(long nsec)
+{
+    fosa_abs_time_t result;
+
+    nsec_to_timespec(result, nsec);
+
+    return result;
+}
+
+// --------------------------------------------------
+
+static inline long fosa_abs_time_to_nsec(fosa_abs_time_t abst)
+{
+    long result;
+
+    result = timespec_to_nsec(abst);
+
+    return result;
+}
+
 
 // --------------------------------------------------
 
@@ -387,5 +733,27 @@ static inline struct timespec fosa_abs_time_to_timespec(fosa_abs_time_t abst)
     return (struct timespec) abst;
 }
 
+// --------------------------------------------------
+
+static inline double fosa_rel_time_to_double(fosa_rel_time_t relt)
+{
+    double result;
+
+    result = relt.tv_nsec*0.000000001 + (double)relt.tv_sec;
+
+    return result;
+}
+
+// --------------------------------------------------
+
+static inline fosa_rel_time_t fosa_double_to_rel_time(double time)
+{
+    fosa_rel_time_t result;
+
+    result.tv_sec = (long) time;
+    result.tv_nsec = (long) ( (time - (double)result.tv_sec) * 1e9 );
+
+    return result;
+}
 
 #endif             /* !FOSA_TIME_TIMESPEC_H_ */
index c335402037ee1bb3fa8add37f4ce5bcca6bfb76b..d8a26b5347323c22fc1a2c13b888a6d7a4ed75f2 100644 (file)
@@ -109,6 +109,45 @@ int main()
     /* fosa_rel_time_decr (negative) */
     rel_time_result = fosa_rel_time_decr(rel_time2, rel_time1);
 //    assert( check_exact_rel_msec(rel_time_result, 1100) );
+
+/*
+    struct timespec t1 = {0, 876352172};
+    fosa_rel_time_t t1_rel = fosa_timespec_to_rel_time(t1);
+    long factor = 573102543;
+    struct timespec product = {502239658, 336773396};
+    fosa_rel_time_t product_rel = fosa_timespec_to_rel_time(product);
+*/
+
+    struct timespec t1 = {0, 876352172};
+    struct timespec product = {50223965,  570771688};
+    long factor = 57310254;
+    struct timespec product_divided_by_17 = {2954350, 915927746};  // inexact division
+    struct timespec product_divided_by_3 = {16741321, 856923896};  // exact division
+
+    fosa_rel_time_t t1_rel = fosa_timespec_to_rel_time(t1);
+    fosa_rel_time_t product_rel = fosa_timespec_to_rel_time(product);
+    fosa_rel_time_t product_17_rel = fosa_timespec_to_rel_time(product_divided_by_17);
+    fosa_rel_time_t product_3_rel = fosa_timespec_to_rel_time(product_divided_by_3);
+
+    /* fosa_rel_time_times_integer */
+    /* fosa_rel_time_divided_by_integer */
+    rel_time_result = fosa_rel_time_times_integer(rel_time2, 4);
+    assert(  check_exact_rel_msec(rel_time_result, 1600) );
+
+    rel_time_result = fosa_rel_time_divided_by_integer(rel_time_result, 4);
+    assert(  check_exact_rel_msec(rel_time_result, 400) );
+
+    rel_time_result = fosa_rel_time_times_integer(t1_rel, factor);
+    assert(  fosa_rel_time_equal(rel_time_result, product_rel) );
+
+    rel_time_result = fosa_rel_time_divided_by_integer(product_rel, factor);
+    assert(  fosa_rel_time_equal(rel_time_result, t1_rel) );
+    
+    rel_time_result = fosa_rel_time_divided_by_integer(product_rel, 17);
+    assert(  fosa_rel_time_equal(rel_time_result, product_17_rel) );
+    
+    rel_time_result = fosa_rel_time_divided_by_integer(product_rel, 3);
+    assert(  fosa_rel_time_equal(rel_time_result, product_3_rel) );
     
     /* fosa_abs_time_smaller */
     test = fosa_abs_time_smaller(abs_time1, abs_time2);
@@ -202,6 +241,8 @@ int main()
     test = memcmp(&tspec_result, &tspec2, sizeof(tspec_result) );
     assert(test == 0);
 
+
+
     printf("End of test OK!!\n");
 
     return 0;