9511_project03

project 3 for algorithms & programming I (9511) prof. Cardozo
Index Commits Files Refs README LICENSE
commit e89839f281cac8a05411172f4294b3e714e6377d
parent b0bd63f5cbe875194b8929d20802394ca794da5a
Author: Martin J. Klöckner <64109770+klewer-martin@users.noreply.github.com>
Date:   Thu, 29 Jul 2021 22:28:39 -0300

Merge pull request #3 from klewer-martin/segunda_entrega

Segunda entrega
Diffstat:
MMakefile | 25+++++++++++++++++--------
Mexamples/input_gen.py | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Minclude/cla.h | 19+++++++++----------
Dinclude/io.h | 67-------------------------------------------------------------------
Dinclude/sort.h | 18------------------
Minclude/status.h | 11++++++-----
Minclude/user.h | 28++++++++++++++++++----------
Ainclude/utils.h | 43+++++++++++++++++++++++++++++++++++++++++++
Ainclude/vector.h | 40++++++++++++++++++++++++++++++++++++++++
Msource/cla.c | 74++++++++++++++++++++++++++++++++++++++++++--------------------------------
Dsource/io.c | 247-------------------------------------------------------------------------------
Msource/main.c | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Dsource/sort.c | 53-----------------------------------------------------
Msource/status.c | 23-----------------------
Msource/user.c | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Asource/utils.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/vector.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17 files changed, 812 insertions(+), 549 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,13 +1,13 @@
 CC=gcc
-CFLAGS=-pedantic -Wall
+CFLAGS=-pedantic -Wall -g
 SRCFOLDER=source
 HFOLDER=include
 PROGNAME=main
 
 all: main clean
 
-main: cla.o status.o sort.o io.o main.o user.o 
-    $(CC) $(CFLAGS) main.o cla.o status.o io.o sort.o user.o -o $(PROGNAME)
+main: cla.o status.o utils.o main.o user.o vector.o
+    $(CC) $(CFLAGS) main.o cla.o status.o utils.o user.o vector.o -o $(PROGNAME)
 
 main.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h $(HFOLDER)/user.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/main.c
@@ -15,14 +15,14 @@ main.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h $(HFOLDER)/user.h
 cla.o: $(HFOLDER)/cla.h $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/cla.c
 
+vector.o: $(HFOLDER)/vector.h $(HFOLDER)/status.h
+    $(CC) $(CFLAGS) -c $(SRCFOLDER)/vector.c
+
 status.o: $(HFOLDER)/status.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/status.c
 
-io.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
-    $(CC) $(CFLAGS) -c $(SRCFOLDER)/io.c
-
-sort.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
-    $(CC) $(CFLAGS) -c $(SRCFOLDER)/sort.c
+utils.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
+    $(CC) $(CFLAGS) -c $(SRCFOLDER)/utils.c
 
 user.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
     $(CC) $(CFLAGS) -c $(SRCFOLDER)/user.c
@@ -30,6 +30,9 @@ user.o: $(HFOLDER)/status.h $(HFOLDER)/user.h
 clean:
     rm *.o
 
+run5:
+    ./main -fmt csv -out output.csv -in examples/test_file_5.csv -ti 1320498000 -tf 1320498046
+
 run20:
     ./main -fmt csv -out output.csv -in examples/test_file_20.csv -ti 1320498000 -tf 1320498046
 
@@ -48,9 +51,15 @@ run5k:
 run50k:
     ./main -fmt csv -out output.csv -in examples/test_file_50k.csv -ti 1320498000 -tf 1420529000
 
+run100k:
+    ./main -fmt csv -out output.csv -in examples/test_file_100k.csv -ti 1320498000 -tf 1420529000
+
 run500k:
     ./main -fmt csv -out output.csv -in examples/test_file_500k.csv -ti 1320498000 -tf 1420529000
 
+run50m:
+    ./main -fmt csv -out output.csv -in examples/test_file_50m.csv -ti 1320498000 -tf 1420529000
+
 run50xml:
     ./main -fmt xml -out output.xml -in examples/test_file_50.csv -ti 1320498000 -tf 1320498049
 
diff --git a/examples/input_gen.py b/examples/input_gen.py
@@ -2,7 +2,7 @@ from string import digits
 from time import strftime, gmtime
 from random import randint, choice
 
-LINES = 500000
+LINES = 10000
 
 # OUTPUT:
 #     ID_TRANSACCION, ID_USUARIO, FECHA, MONTO, NUMERO DE TRAJETA, DESCRIPCION
@@ -10,19 +10,99 @@ LINES = 500000
 
 descs = [ "Compras supermercado", "Pago tarjeta", "Compras libreria", "Pago Mecanico", "Pago Dentista", "Pago Servicios online", "Compras Ferreteria",  "Compras Accesorios Informatica", "Compras farmacia", "Ventas online", "Extraccion cajero" ]
 
-def card_number_generator():
-    return ''.join(choice(digits) for i in range(1, 16))
+def calculate_luhn(cc):
+    num = list(map(int, str(cc)))
+    check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
+    return 0 if check_digit == 10 else check_digit
+
+def generate_card(type):
+    """
+    Prefill some values based on the card type
+    """
+    card_types = ["americanexpress","visa13", "visa16","mastercard","discover"]
+
+    def prefill(t):
+        # typical number of digits in credit card
+        def_length = 16
+
+        """
+        Prefill with initial numbers and return it including the total number of digits
+        remaining to fill
+        """
+        if t == card_types[0]:
+            # american express starts with 3 and is 15 digits long
+            # override the def lengths
+            return [3, randint(4,7)], 13
+
+        elif t == card_types[1] or t == card_types[2]:
+            # visa starts with 4
+            if t.endswith("16"):
+                return [4], def_length - 1
+            else:
+                return [4], 12
+
+        elif t == card_types[3]:
+            # master card start with 5 and is 16 digits long
+            return [5, randint(1,5)], def_length - 2
+
+        elif t == card_types[4]:
+            # discover card starts with 6011 and is 16 digits long
+            return [6, 0, 1, 1], def_length - 4
+
+        else:
+            # this section probably not even needed here
+            return [], def_length
+
+    def finalize(nums):
+        """
+        Make the current generated list pass the Luhn check by checking and adding
+        the last digit appropriately bia calculating the check sum
+        """
+        check_sum = 0
+
+        #is_even = True if (len(nums) + 1 % 2) == 0 else False
+
+        """
+        Reason for this check offset is to figure out whether the final list is going
+        to be even or odd which will affect calculating the check_sum.
+        This is mainly also to avoid reversing the list back and forth which is specified
+        on the Luhn algorithm.
+        """
+        check_offset = (len(nums) + 1) % 2
+
+        for i, n in enumerate(nums):
+            if (i + check_offset) % 2 == 0:
+                n_ = n*2
+                check_sum += n_ -9 if n_ > 9 else n_
+            else:
+                check_sum += n
+        return nums + [10 - (check_sum % 10) ]
+
+    # main body
+    t = type.lower()
+    if t not in card_types:
+        print("Unknown type: '%s'" % type)
+        print("Please pick one of these supported types: %s" % card_types)
+        return
+
+    initial, rem = prefill(t)
+    so_far = initial + [randint(1,9) for x in range(rem - 1)]
+    return ("".join(map(str,finalize(so_far))))
 
 def generate_file(max_lines):
     id_transaction_base = 123400
     id_user_base = 1
-    id_user_max = 20000
+    id_user_max = 30000
     amount_base = 1
     amount_max = 10000
     for i in range(max_lines):
         id_transaction = (i + id_transaction_base)
         id_user = randint(id_user_base, id_user_max)
-        card_nr = card_number_generator() 
+
+        card_nr = generate_card("visa16")
+        while calculate_luhn(card_nr) != 0:
+            card_nr = generate_card("visa16")
+
         date = strftime("%d.%m.%Y %H:%M:%S", gmtime(1320487200 + i))
         
         j = randint(1, len(descs) - 1)
diff --git a/include/cla.h b/include/cla.h
@@ -21,19 +21,18 @@ typedef enum {
 } flags_t;
 
 typedef struct {
-    char *fmt, *fi, *fo;
-    unsigned long ti, tf, parsed_lines;
+    char *fmt;
+    FILE *fi, *fo;
+    unsigned long ti, tf;
 } ADT_cla_t, *cla_t;
 
-status_t validate_arguments(int argc, char **argv);
-status_t check_flags_position(int argc, char **argv);
-status_t check_flags_repeated(int argc, char **argv);
+status_t validate_arguments(int, char **, cla_t);
+status_t check_flags_position(int, char **);
+status_t check_flags_repeated(int, char **);
 
-status_t cla_create(cla_t *cla);
-status_t cla_setup(int argc, char **argv, cla_t *cla);
-status_t cla_destroy(cla_t *cla);
-
-void clean(cla_t cla);
+status_t cla_create(cla_t *);
+status_t cla_setup(int, char **, cla_t);
+status_t cla_destroy(cla_t);
 
 extern const char *available_flags[FLAGS_MAX];
 extern const char *available_formats[FORMATS_MAX];
diff --git a/include/io.h b/include/io.h
@@ -1,67 +0,0 @@
-#ifndef IO__H
-#define IO__H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cla.h"
-#include "user.h"
-#include "status.h"
-
-#define _XOPEN_SOURCE
-#define __USE_XOPEN
-#include <time.h>
-
-#define INIT_SIZE        1000
-#define INPUT_FILE_FIELDS 6
-
-#define BUFFER_SIZE        1000
-#define GROWTH_FACTOR     2
-
-#define INPUT_FILE_DELIM ","
-#define CSV_OUTPUT_DELIM    ","
-
-#define XML_HEADER        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
-#define XML_ROOT_OPEN    "<root>"
-#define XML_ROOT_CLOSE    "</root>"
-
-#define XML_ROW_OPEN    "<row>"
-#define XML_ROW_CLOSE    "</row>"
-
-#define XML_ID_OPEN        "<user>"
-#define XML_ID_CLOSE    "</user>"
-
-#define XML_CREDIT_OPEN        "<credits>"
-#define XML_CREDIT_CLOSE    "</credits>"
-
-#define XML_DEBT_OPEN    "<debits>"
-#define XML_DEBT_CLOSE    "</debits>"
-
-/* typedef enum { */
-/*     POS_ID_TXN, */
-/*     POS_USER_ID, */
-/*     POS_TXN_DATE, */
-/*     POS_AMOUNT, */
-/*     POS_CARD_NUMBER, */
-/*     POS_DESC */
-/* } csv_pos_t; */
-
-status_t process_file(cla_t cla, user_t **users, size_t *i);
-
-status_t string_split(char *s, char **data, char *delim);
-
-status_t load_values(FILE *, cla_t *data);
-
-status_t export_data(cla_t cla, const user_t *users, size_t size);
-void clean_data(char **data);
-
-status_t export_data_as_csv(FILE *fo, const user_t *users, size_t size);
-status_t export_data_as_xml(FILE *fo, const user_t *users, size_t size);
-
-status_t destroy_data(char **data);
-status_t get_date(time_t *e, char **data);
-
-void clean_buffer(char *buf);
-
-#endif
diff --git a/include/sort.h b/include/sort.h
@@ -1,18 +0,0 @@
-#ifndef SORT__H
-#define SORT__H
-
-#include "cla.h"
-#include "user.h"
-#include "status.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-int credit_minmax(const void *, const void *);
-int credit_maxmix(const void *, const void *);
-
-int debt_minmax(const void *, const void *);
-int debt_maxmin(const void *, const void *);
-
-
-#endif
diff --git a/include/status.h b/include/status.h
@@ -5,10 +5,11 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
-#define ERROR_RETRY_MSG "Verifique y vuelva a intentar"
-#define EXIT_SUCCESS_MSG "Ejecución terminada exitosamente"
-#define USERS_REGISTERED_MSG    "Usuarios registrados: "
-#define PROCESED_LINES_MSG        "Lineas procesadas: "
+#define MSG_ERROR_RETRY                "Verifique y vuelva a intentar"
+#define MSG_EXIT_SUCCESS            "Ejecución terminada exitosamente"
+#define MSG_USERS_REGISTERED        "Usuarios registrados"
+#define MSG_PROCESED_LINES            "Lineas procesadas"
+#define STR_INVALID_CARD_NUMBER        "Número no válido"
 
 #define STATUS_T_MAX 12
 
@@ -17,6 +18,7 @@ typedef enum {
     ERROR_MEMORY,
     ERROR_WRONG_FLAGS,
     ERROR_WRONG_TIME,
+    ERROR_INVALID_POS,
     ERROR_MISSING_ARGS,
     ERROR_OPENING_FILE,
     ERROR_CORRUPT_DATA,
@@ -37,7 +39,6 @@ typedef enum {
 } csv_pos_t;
 
 void show_status(status_t st);
-void free_arrays(size_t num,...);
 
 extern const char *status_strings[STATUS_T_MAX];
 
diff --git a/include/user.h b/include/user.h
@@ -2,21 +2,29 @@
 #define USER__H
 
 #include "status.h"
+#include "utils.h"
+
+#define OUT_FILE_DELIM    ","
+
+typedef unsigned long ulong;
 
 typedef struct {
-    size_t id;
-    long credit, debt;
-} ADT_user_t, *user_t;
+    /* id: user id / c: user credits / d: user debits */
+    ulong id, c, d;
+} ADT_user_t;
+
+status_t user_create(ADT_user_t **);
+status_t user_destroy(ADT_user_t **);
+status_t user_set_data(ADT_user_t *, char **);
+status_t user_add_amount(ADT_user_t *, long);
 
-user_t user_find(const user_t *users, int id, size_t size);
-user_t user_dup(user_t src);
+int user_equals(const void *, const void *);
 
-status_t user_create(user_t *usr);
-status_t user_set_data(user_t *user, char **data);
+status_t user_print_as_csv(const void *, FILE *);
+status_t user_print_as_xml(const void *, FILE *);
 
-void user_clean(user_t usr);
+int user_comparator_credits_minmax(const void *, const void *);
+int user_comparator_credits_maxmin(const void *, const void *);
 
-status_t sort_users(user_t *users, size_t size, char *order);
-status_t destroy_users(user_t *users, size_t size);
 
 #endif
diff --git a/include/utils.h b/include/utils.h
@@ -0,0 +1,43 @@
+#ifndef UTILS__H
+#define UTILS__H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "cla.h"
+#include "user.h"
+#include "status.h"
+
+#define _XOPEN_SOURCE
+#define __USE_XOPEN
+#include <time.h>
+
+#define IN_FILE_MAX_LEN    100
+#define IN_FILE_DELIM    ","
+#define IN_FILE_FIELDS    6
+#define IN_FILE_FIELDS_MAX_LEN    50
+
+#define STR_FMT_CSV "csv"
+#define STR_FMT_XML "xml"
+
+#define CARD_NO_VALID_LEN 16
+
+#define XML_STR_HEADER    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+#define XML_STR_ROOT    "root"
+#define XML_STR_ROW        "row"
+#define XML_STR_ID        "user"
+#define XML_STR_CREDIT    "credits"
+#define XML_STR_DEBIT    "debits"
+
+status_t get_date(time_t *, char **);
+status_t array_destroy(char **, size_t);
+status_t string_split(char *, char **, char *);
+
+bool is_valid_card(char *);
+
+void clean_array(char **);
+void clean_buffer(char *);
+
+#endif
diff --git a/include/vector.h b/include/vector.h
@@ -0,0 +1,40 @@
+#ifndef VECTOR__H
+#define VECTOR__H
+
+#define VECTOR_INIT_SIZE        10
+#define VECTOR_GROWTH_FACTOR    2
+
+#include <stdlib.h>
+
+#include "utils.h"
+#include "status.h"
+
+typedef status_t (*printer_t)(const void *, FILE *);
+typedef int (*comparator_t)(const void *, const void *);
+
+typedef struct {
+    void **a;
+    size_t size, alloc;
+
+    printer_t printer;
+    comparator_t comparator;
+
+} ADT_Vector_t;
+
+status_t ADT_Vector_create(ADT_Vector_t **);
+status_t ADT_Vector_add(ADT_Vector_t **, void *);
+status_t ADT_Vector_destroy(ADT_Vector_t **);
+
+status_t ADT_Vector_set(ADT_Vector_t **, void *, size_t);
+status_t ADT_Vector_print(const ADT_Vector_t *, FILE *);
+status_t ADT_Vector_sort(ADT_Vector_t *, comparator_t);
+
+void *ADT_Vector_get_elem(const ADT_Vector_t *v, void *e);
+
+status_t ADT_Vector_set_printer(ADT_Vector_t *, printer_t);
+status_t ADT_Vector_set_comparator(ADT_Vector_t *, comparator_t);
+
+status_t ADT_Vector_export_as_xml(const ADT_Vector_t *, FILE *);
+status_t ADT_Vector_export_as_csv(const ADT_Vector_t *, FILE *);
+
+#endif
diff --git a/source/cla.c b/source/cla.c
@@ -3,17 +3,20 @@
 const char *available_flags[] = { "-fmt", "-out", "-in", "-ti", "-tf" };
 const char *available_formats[] = { "csv", "xml" };
 
-status_t validate_arguments(int argc,  char **argv)
+status_t validate_arguments(int argc, char **argv, cla_t cla)
 {
     status_t st;
 
-    if(argv == NULL) return ERROR_NULL_POINTER;
+    if(argv == NULL || cla == NULL) return ERROR_NULL_POINTER;
     if((argc == NO_ARGS_ENTERED) || (argc != NORMAL_AMOUNT_ARGS))
         return ERROR_MISSING_ARGS;
 
     if((st = check_flags_position(argc, argv))) return st;
     if((st = check_flags_repeated(argc, argv))) return st;
 
+    /* Asigna a la estructura 'cla' los argumentos ingresados */
+    if((st = cla_setup(argc, argv, cla))) return st;
+
     return OK;
 }
 
@@ -60,25 +63,45 @@ status_t check_flags_repeated(int argc, char **argv)
     return OK;
 }
 
-status_t cla_setup(int argc, char **argv, cla_t *cla)
+status_t cla_setup(int argc, char **argv, cla_t cla)
 {
     char *endptr;
     size_t i;
+    FILE *fp;
     flags_t f;
 
     for(i = 1; i < argc; i += 2) {
         for(f = FLAG_FMT; f < FLAGS_MAX; f++) {
             if(!strcmp(available_flags[f], argv[i])) {
                 switch (f) {
-                    case FLAG_FMT: strcpy((*cla)->fmt, argv[i + 1]); break;
-                    case FLAG_OUT: strcpy((*cla)->fo, argv[i + 1]); break;
-                    case FLAG_IN: strcpy((*cla)->fi, argv[i + 1]); break;
-                    case FLAG_TI: (*cla)->ti = strtoul(argv[i + 1], &endptr, 10); 
-                                  if(*endptr != '\0') return ERROR_WRONG_TIME;
-                                  break;
-                    case FLAG_TF: (*cla)->tf = strtoul(argv[i + 1], &endptr, 10); 
-                                  if(*endptr != '\0') return ERROR_WRONG_TIME;
-                                  break;
+                    case FLAG_FMT: 
+                        strcpy(cla->fmt, argv[i + 1]);
+                       break;
+
+                    case FLAG_OUT:
+                       if((fp = fopen(argv[i + 1], "wt")) == NULL)
+                           return ERROR_OPENING_FILE;
+
+                       cla->fo = fp; 
+                       break;
+
+                    case FLAG_IN:
+                       if((fp = fopen(argv[i + 1], "rt")) == NULL)
+                           return ERROR_OPENING_FILE;
+
+                       cla->fi = fp; 
+                       break;
+
+                    case FLAG_TI:
+                       cla->ti = strtoul(argv[i + 1], &endptr, 10); 
+                       if(*endptr != '\0') return ERROR_WRONG_TIME;
+                       break;
+
+                    case FLAG_TF:
+                       cla->tf = strtoul(argv[i + 1], &endptr, 10); 
+                       if(*endptr != '\0') return ERROR_WRONG_TIME;
+                       break;
+
                     default: return ERROR_FLAG_NOT_FOUND;
                 }
             }
@@ -101,34 +124,21 @@ status_t cla_create(cla_t *cla)
         return ERROR_MEMORY;
     }
 
-    if(((*cla)->fo = calloc(sizeof(char), 100)) == NULL) {
-        free((*cla)->fmt);
-        free(cla);
-        cla = NULL;
-        return ERROR_MEMORY;
-    }
-
-    if(((*cla)->fi = calloc(sizeof(char), 100)) == NULL) {
-        free((*cla)->fo);
-        free((*cla)->fmt);
-        free(cla);
-        cla = NULL;
-        return ERROR_MEMORY;
-    }
+    (*cla)->fi = NULL;
+    (*cla)->fo = NULL;
 
     return OK;
 }
 
-status_t cla_destroy(cla_t *cla)
+status_t cla_destroy(cla_t cla)
 {
     if(cla == NULL) return ERROR_NULL_POINTER;
 
-    free((*cla)->fmt);
-    free((*cla)->fo);
-    free((*cla)->fi);
-    free(*cla);
+    if(cla->fi != NULL) fclose(cla->fi);
+    if(cla->fo != NULL)    fclose(cla->fo);
 
-    *cla = NULL;
+    free(cla->fmt);
+    free(cla);
 
     return OK;
 }
diff --git a/source/io.c b/source/io.c
@@ -1,247 +0,0 @@
-#include "../include/io.h"
-
-/* Lee los datos del archivo de entrada linea por linea mientras los procesa y asigna a un arreglo de usuarios */
-status_t process_file(cla_t cla, user_t **users, size_t *size)
-{
-    FILE *fpi;
-    char *buffer, **data;
-    time_t epoch;
-    size_t alloc_size;
-    user_t user, user_found, *tmp;
-    status_t st;
-
-    *size = cla->parsed_lines = 0;
-    alloc_size = INIT_SIZE;
-    user = user_found = NULL;
-
-    if((fpi = fopen(cla->fi, "rt")) == NULL) {
-        *users = NULL;
-        return ERROR_OPENING_FILE;
-    }
-
-    if((data = (char **)malloc(sizeof(char *) * INPUT_FILE_FIELDS)) == NULL) {
-        fclose(fpi);
-        return ERROR_MEMORY;
-    }
-
-    if((buffer = calloc(sizeof(char), BUFFER_SIZE)) == NULL) {
-        destroy_data(data);
-        fclose(fpi);
-        return ERROR_MEMORY;
-    }
-
-    if(user_create(&user) != OK) {
-        free(buffer);
-        destroy_data(data);
-        fclose(fpi);
-    }
-
-    /* En caso de haber algun error users no es liberado, se libera luego en main */
-    if(((*users) = (user_t *)malloc(sizeof(user_t) * INIT_SIZE)) == NULL) {
-        free(buffer);
-        free(user);
-        destroy_data(data);
-        fclose(fpi);
-    }
-
-    /* Lee los datos de el archivo de entrada linea por linea */ 
-    while(fgets(buffer, BUFFER_SIZE, fpi) != NULL) {
-        /* Extiende el arreglo de usuarios en caso de que haya poca memoria */
-        if(*size == alloc_size) {
-            alloc_size *= GROWTH_FACTOR;
-            if((tmp = realloc((*users), alloc_size * sizeof(user_t))) == NULL) {
-                fclose(fpi);
-                free(buffer);
-                destroy_data(data);
-                return ERROR_MEMORY;
-            }
-            (*users) = tmp;
-        }
-
-        /* Divide el buffer en subarreglos segun un caracter delimitador */
-        if((st = string_split(buffer, data, INPUT_FILE_DELIM)) != OK) {
-            fclose(fpi);
-            free(buffer);
-            destroy_data(data);
-            return st;
-        }
-
-        /* Asigna a 'user' id, creditos y debitos cargados en data */
-        if((st = user_set_data(&user, data)) != OK) {
-            destroy_data(data);
-            free(buffer);
-            fclose(fpi);
-            return st;
-        }
-
-        /* Transforma la fecha leida a tiempo UNIX en segundos */
-        if((st = get_date(&epoch, data)) != OK) {
-            destroy_data(data);
-            free(buffer);
-            fclose(fpi);
-            return st;
-        }
-
-        /* Comprueba que la fecha leida este dentro del rango de fechas ingresadas en CLA */
-        if(epoch < cla->ti) continue;
-        else if(epoch > cla->tf) {
-            free(user);
-            destroy_data(data);
-            free(buffer);
-            fclose(fpi);
-            return OK;
-        }
-
-        /* Busca el numero de id en los usuarios ya ingresados, si no lo encuentra agrega un usuario nuevo al arreglo de usuarios */
-        if((user_found = user_find(*users, user->id, *size)) != NULL) {
-            user_found->credit += user->credit;
-            user_found->debt += user->debt;
-        } else {
-            (*users)[(*size)++] = user_dup(user);
-        }
-
-        cla->parsed_lines++;
-
-        user_clean(user);
-        clean_data(data);
-        clean_buffer(buffer);
-    } /* End while */
-
-    free(user);
-    destroy_data(data);
-    free(buffer);
-    fclose(fpi);
-    return OK;
-}
-
-
-status_t string_split(char *s, char **data, char *delim)
-{
-    char *p, *tmp;
-    size_t fields = 0;
-
-    for(p = s; (tmp = strtok(p, delim)); p = NULL)
-        data[fields++] = strdup(tmp);
-
-    if(fields != INPUT_FILE_FIELDS)
-        return ERROR_CORRUPT_DATA;
-
-    return OK;
-}
-
-status_t destroy_data(char **data)
-{
-    size_t i;
-
-    if(data == NULL) return ERROR_NULL_POINTER;
-
-    for(i = 0; i < INPUT_FILE_FIELDS; i++) {
-        free(data[i]);
-        data[i] = NULL;
-    }
-
-    free(data);
-    return OK;
-}
-
-status_t export_data(cla_t cla, const user_t *users, size_t size)
-{
-    FILE *fo;
-
-    if(users == NULL) return ERROR_NULL_POINTER;
-
-    if((fo = fopen(cla->fo, "wt")) == NULL)
-        return ERROR_OPENING_FILE;
-
-    if(!strcmp(cla->fmt, "csv")) {
-        export_data_as_csv(fo, users, size);
-    } else if(!strcmp(cla->fmt, "xml")) {
-        export_data_as_xml(fo, users, size);
-    } else return ERROR_FORMAT_NOT_FOUND;
-
-    fclose(fo);
-    return OK;
-}
-
-status_t export_data_as_csv(FILE *fo, const user_t *users, size_t size)
-{
-    size_t i;
-
-    if(fo == NULL || users == NULL)
-        return ERROR_NULL_POINTER;
-
-    for(i = 0; i < size; i++)
-        fprintf(fo, "%ld%s%ld%s%ld\n", users[i]->id, CSV_OUTPUT_DELIM,\
-                users[i]->credit, CSV_OUTPUT_DELIM, users[i]->debt);
-
-    return OK;
-}
-
-status_t export_data_as_xml(FILE *fo, const user_t *users, size_t size)
-{
-    size_t i;
-
-    if(fo == NULL || users == NULL)
-        return ERROR_NULL_POINTER;
-
-    fprintf(fo, "%s\n%s\n", XML_HEADER, XML_ROOT_OPEN);
-
-    for(i = 0; i < size; i++) {
-        fprintf(fo, "\t%s\n", XML_ROW_OPEN);
-        fprintf(fo, "\t\t%s%ld%s\n", XML_ID_OPEN, users[i]->id, XML_ID_CLOSE);
-        fprintf(fo, "\t\t%s%ld%s\n", XML_CREDIT_OPEN, users[i]->credit, XML_CREDIT_CLOSE);
-        fprintf(fo, "\t\t%s%ld%s\n", XML_DEBT_OPEN, users[i]->debt, XML_DEBT_CLOSE);
-        fprintf(fo, "\t%s\n", XML_ROW_CLOSE);
-    }
-
-    fprintf(fo, "%s\n", XML_ROOT_CLOSE);
-    return OK;
-}
-
-void clean_buffer(char *buf)
-{
-    size_t i;
-
-    for(i = 0; i < BUFFER_SIZE; i++)
-        buf[i] = '\0';
-}
-
-void clean_data(char **data)
-{
-    size_t i;
-
-    for(i = 0; i < INPUT_FILE_FIELDS; i++) {
-        free(data[i]);
-        data[i] = NULL;
-    }
-}
-
-status_t get_date(time_t *e, char **data)
-{
-    struct tm tm;
-
-    if(e == NULL || data == NULL) return ERROR_NULL_POINTER;
-
-    /* Desactiva el horario de verano */
-    tm.tm_isdst = 0;
-
-    switch(data[POS_TXN_DATE][2]) {
-        case '/': 
-            strptime(data[2], "%d/%m/%Y %H:%M:%S", &tm);
-            *e = mktime(&tm);
-            break;
-        case '-':
-            strptime(data[2], "%d-%m-%Y %H:%M:%S", &tm);
-            *e = mktime(&tm);
-            break;
-        case '.':
-            strptime(data[2], "%d.%m.%Y %H:%M:%S", &tm);
-            *e = mktime(&tm);
-            break;
-
-        default: return ERROR_CORRUPT_DATA; break;
-    }
-
-    return OK;
-}
-
diff --git a/source/main.c b/source/main.c
@@ -1,75 +1,221 @@
-#include "../include/io.h"
 #include "../include/cla.h"
 #include "../include/user.h"
-#include "../include/sort.h"
+#include "../include/utils.h"
 #include "../include/status.h"
-
-/* "ca" - creditos ascendentes | "cd" - creditos descendentes
- * "da" - debitos ascendentes  | "dd" - debitos descendentes */
-#define SORTING_ORDER    "cd"
-#define PRINT_EXIT_SUCCESS_MSG
+#include "../include/vector.h"
 
 int main (int argc, char *argv[])
 {
     status_t st;
     cla_t cla;
-    user_t *users;
-    size_t size;
+    ADT_Vector_t *v;
+    ADT_user_t *user, *user_tmp;
+    char buffer[IN_FILE_MAX_LEN];
+    char *endptr, **data;
+    size_t i;
+    long amount;
+    time_t epoch;
 
-    /* Valida que los argumentos sean correctos */
-    if((st = validate_arguments(argc, argv)) != OK) {
+    /* Asigna memoria a cla (c.l.a.: "command line arguments") */
+    if((st = cla_create(&cla)) != OK) {
         show_status(st);
         return st;
     }
 
-    /* Asigna memoria a cla */
-    if((st = cla_create(&cla)) != OK) {
+    /* Valida que los argumentos sean correctos y asigna valores a cla */
+    if((st = validate_arguments(argc, argv, cla)) != OK) {
         show_status(st);
+        cla_destroy(cla);
         return st;
     }
 
-    /* Asigna a la estructura 'cla' los argumentos ingresados */
-    if((st = cla_setup(argc, argv, &cla)) != OK) {
+    /* Crea un vector */
+    if((st = ADT_Vector_create(&v)) != OK) {
         show_status(st);
+        cla_destroy(cla);
         return st;
     }
 
-    /* Carga en users los usuarios desde el archivo de entrada */
-    if((st = process_file(cla, &users, &size)) != OK) {
-        show_status(st);
-        cla_destroy(&cla);
-        destroy_users(users, size);
-        return st;
+    /* Crea un arreglo de cadenas de caracteres */
+    if((data = malloc(sizeof(char *) * IN_FILE_FIELDS)) == NULL) {
+        show_status(ERROR_MEMORY);
+        cla_destroy(cla);
+        ADT_Vector_destroy(&v);
+        return ERROR_MEMORY;
     }
 
-    /* Ordena los usuarios con orden SORTING_ORDER */
-    if((st = sort_users(users, size, SORTING_ORDER)) != OK) {
+    for(i = 0; i < IN_FILE_FIELDS; i++) {
+        if((data[i] = calloc(sizeof(char), IN_FILE_FIELDS_MAX_LEN)) == NULL) {
+            show_status(ERROR_MEMORY);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return ERROR_MEMORY;
+        }
+    }
+
+    /* Setea el comparador a ADT_Vector */    
+    if((st = ADT_Vector_set_comparator(v, user_equals)) != OK) {
         show_status(st);
-        cla_destroy(&cla);
-        destroy_users(users, size);
+        cla_destroy(cla);
+        ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
         return st;
     }
 
-    /* Imprime los datos cargados en users a un archivo de salida */
-    if((st = export_data(cla, users, size)) != OK) {
+    /* Crea un usuario temporal */
+    if((st = user_create(&user_tmp)) != OK) {
         show_status(st);
-        cla_destroy(&cla);
-        destroy_users(users, size);
+        cla_destroy(cla);
+        ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
         return st;
     }
 
+    /* Lee linea por linea del archivo de entrada */
+    while(fgets(buffer, IN_FILE_MAX_LEN, cla->fi)) {
+
+        /* Separa la linea leida segun un caracter delimitador */
+        if((st = string_split(buffer, data, IN_FILE_DELIM)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            free(user_tmp);
+            return st;
+        }
+
+        /* Setea el usuario temporal con los datos obtenidos de la linea */
+        if((st = user_set_data(user_tmp, data)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            free(user_tmp);
+            return st;
+        }
+
+        amount = strtol(data[POS_AMOUNT], &endptr, 10);
+        if(*endptr != '\0') {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            free(user_tmp);
+            return ERROR_CORRUPT_DATA;
+        }
 
-#ifdef PRINT_EXIT_SUCCESS_MSG
+        /* Transforma el tiempo de la linea leida a formato UNIX */
+        get_date(&epoch, data);
 
-    /* Imprime un mensaje para darle a conocer al usuario
-     * que todo se ejecuto correctamente    */
-    printf("\n%s\n%s%ld\n%s%ld\n", EXIT_SUCCESS_MSG, USERS_REGISTERED_MSG,\
-            size, PROCESED_LINES_MSG, cla->parsed_lines);
+        /* Comprueba que el tiempo de la linea leida no supere los argumentos ingresados */
+        if(epoch < cla->ti) continue;
+        else if(epoch > cla->tf) break;
 
-#endif
+        /* Solo imprime en el archivo de salida las transacciones realizadas con una tarjeta valida */
+        if(!is_valid_card(data[POS_CARD_NUMBER])) {
+            fprintf(stderr, "%s: %s\n",STR_INVALID_CARD_NUMBER, data[POS_CARD_NUMBER]);
+            continue;
+        }
 
-    cla_destroy(&cla);
-    destroy_users(users, size);
+        /* Busca el id del usuario en el vector */
+        if((user = ADT_Vector_get_elem(v, user_tmp)) != NULL) {
+            /* Si lo encuentra le suma el monto correspondiente */
+            if((st = user_add_amount(user, amount)) != OK) {
+                show_status(st);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                free(user_tmp);
+                return st;
+            }
+        }
+
+        /* Si no lo encuentra crea un usuario nuevo */
+        else { 
+            if((st = user_create(&user)) != OK) {
+                show_status(st);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                free(user_tmp);
+                return st;
+            }
+
+            if((st = user_set_data(user, data))) {
+                show_status(st);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                free(user_tmp);
+                return st;
+            }
+
+            /* Y lo agrega al vector */
+            if((st = ADT_Vector_add(&v, user)) != OK){
+                show_status(st);
+                free(user_tmp);
+                cla_destroy(cla);
+                ADT_Vector_destroy(&v);
+                array_destroy(data, IN_FILE_FIELDS);
+                free(user_tmp);
+                return st;
+            }
+        }
+        clean_buffer(buffer);
+        clean_array(data);
+    } /* End while */
+
+    /* Ordena el vector con los usuarios */
+    if((st = ADT_Vector_sort(v, user_comparator_credits_maxmin)) != OK) {
+        show_status(st);
+        free(user_tmp);
+        cla_destroy(cla);
+        ADT_Vector_destroy(&v);
+        array_destroy(data, IN_FILE_FIELDS);
+        return st;
+    }
+
+    /* Setea el impresor a ADT_Vector */
+    if(!strcmp(cla->fmt, STR_FMT_CSV)) {
+        if((st = ADT_Vector_set_printer(v, user_print_as_csv)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return st;
+        }
+        /* E imprime el vector con los usuarios */
+        if((st = ADT_Vector_export_as_csv(v, cla->fo)) != OK) {
+            show_status(st);
+            free(user_tmp);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return st;
+        }
+    }
+    else if(!strcmp(cla->fmt, STR_FMT_XML)) {
+        if((st = ADT_Vector_set_printer(v, user_print_as_xml)) != OK) {
+            show_status(st);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return st;
+        }
+        if((st = ADT_Vector_export_as_xml(v, cla->fo)) != OK) {
+            show_status(st);
+            free(user_tmp);
+            cla_destroy(cla);
+            ADT_Vector_destroy(&v);
+            array_destroy(data, IN_FILE_FIELDS);
+            return st;
+        }
+    }
 
+    free(user_tmp);
+    cla_destroy(cla);
+    ADT_Vector_destroy(&v);
+    array_destroy(data, IN_FILE_FIELDS);
     return OK;
 }
diff --git a/source/sort.c b/source/sort.c
@@ -1,53 +0,0 @@
-#include "../include/sort.h"
-
-int credit_minmax(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->credit > (*B)->credit) ? 1 : 0;
-}
-
-int credit_maxmin(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->credit > (*B)->credit) ? 0 : 1;
-}
-
-int debt_minmax(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->debt > (*B)->debt) ? 1 : 0;
-}
-
-int debt_maxmin(const void *a, const void *b)
-{
-    user_t *A = (user_t *)a;
-    user_t *B = (user_t *)b;
-
-    return ((*A)->debt > (*B)->debt) ? 0 : 1;
-}
-
-status_t sort_users(user_t *users, size_t l, char *order)
-{
-    if(users == NULL || order == NULL)
-        return ERROR_NULL_POINTER;
-
-    if(!strcmp(order, "ca"))
-        qsort(users, l, sizeof(user_t), credit_minmax);
-
-    if(!strcmp(order, "cd"))
-        qsort(users, l, sizeof(user_t), credit_maxmin);
-
-    if(!strcmp(order, "da"))
-        qsort(users, l, sizeof(user_t), debt_minmax);
-
-    if(!strcmp(order, "dd"))
-        qsort(users, l, sizeof(user_t), debt_maxmin);
-
-    return OK;
-}
diff --git a/source/status.c b/source/status.c
@@ -18,27 +18,4 @@ const char *status_strings[] = {
 void show_status(status_t st)
 {
     fprintf(stderr, "\n%s\n", status_strings[st]);
-    fprintf(stderr, "%s\n", ERROR_RETRY_MSG);
-}
-
-void free_arrays(size_t num,...)
-{
-    va_list valist;
-    size_t i;
-
-    va_start(valist, num);
-
-    for(i = 0; i < num; i++)
-        free(va_arg(valist, char *));
-}
-
-void close_streams(size_t num,...)
-{
-    va_list valist;
-    size_t i;
-
-    va_start(valist, num);
-
-    for(i = 0; i < num; i++)
-        free(va_arg(valist, FILE *));
 }
diff --git a/source/user.c b/source/user.c
@@ -1,76 +1,118 @@
 #include "../include/user.h"
 
-status_t user_create(user_t *usr)
+status_t user_create(ADT_user_t **user)
 {
-    if(((*usr) = (user_t)malloc(sizeof(ADT_user_t))) == NULL)
+    if((*user = (ADT_user_t *)malloc(sizeof(ADT_user_t))) == NULL)
         return ERROR_MEMORY;
 
-    (*usr)->id = 0;
-    (*usr)->credit = 0;
-    (*usr)->debt = 0;
+    (*user)->id = 0;
+    (*user)->c = 0;
+    (*user)->d = 0;
 
     return OK;
 }
 
-void user_clean(user_t usr)
+status_t user_destroy(ADT_user_t **user)
 {
-    usr->id = 0;
-    usr->credit = 0;
-    usr->debt = 0;
+    if(user == NULL) return ERROR_NULL_POINTER;
+
+    free(*user);
+    *user = NULL;
+
+    return OK;
 }
 
-status_t user_set_data(user_t *user, char **data) 
+status_t user_set_data(ADT_user_t *user, char **data) 
 {
     char *endptr;
     long amount;
 
     if(data == NULL || user == NULL) return ERROR_NULL_POINTER;
 
-    (*user)->id = strtol(data[POS_USER_ID], &endptr, 10);
+    user->id = strtol(data[POS_USER_ID], &endptr, 10);
     if(*endptr != '\0') return ERROR_CORRUPT_DATA;
 
     amount = strtol(data[POS_AMOUNT], &endptr, 10);
     if(*endptr != '\0') return ERROR_CORRUPT_DATA;
 
-    if(amount > 0) (*user)->credit = amount;
-    else if(amount < 0) (*user)->debt = -amount; /* '-=' Para eliminar el menos    */
+    if(amount > 0) user->c = amount;
+    else if(amount < 0) user->d = -amount; /* '-=' Para eliminar el menos    */
+
+    return OK;
+}
+
+status_t user_add_amount(ADT_user_t *user, long amount)
+{
+    if(user == NULL) return ERROR_NULL_POINTER;
+
+    if(amount > 0) user->c += amount;
+    else if(amount < 0) user->d -= amount; /* '-=' Para eliminar el menos    */
 
     return OK;
 }
 
-user_t user_dup(user_t src)
+int user_equals(const void *a, const void *b)
 {
-    user_t dst = NULL;
+    ADT_user_t *A, *B;
 
-    user_create(&dst);
+    if(a == NULL || b == NULL) return ERROR_NULL_POINTER;
 
-    dst->id = src->id;
-    dst->credit = src->credit;
-    dst->debt = src->debt;
+    A = (ADT_user_t *)a;
+    B = (ADT_user_t *)b;
 
-    return dst;
+    if(A->id == B->id) return 1;
+
+    return 0;
 }
 
-user_t user_find(const user_t *users, int id, size_t size)
+status_t user_print_as_csv(const void *u, FILE *fp)
 {
-    size_t i;
-    for(i = 0; i < size; i++) {
-        if(users[i]->id == id) {
-            return users[i];
-        }
-    }
-    return NULL;
+    if(u == NULL || fp == NULL) return ERROR_NULL_POINTER;
+
+    ADT_user_t *user = (ADT_user_t *)u;
+
+    fprintf(fp, "%ld%s%ld%s%ld\n", user->id, OUT_FILE_DELIM, user->c, OUT_FILE_DELIM, user->d);
+
+    return OK;
 }
 
-status_t destroy_users(user_t *users, size_t size)
+status_t user_print_as_xml(const void *u, FILE *fp)
 {
-    size_t i;
+    if(u == NULL || fp == NULL) return ERROR_NULL_POINTER;
 
-    if(users == NULL) return ERROR_NULL_POINTER;
+    ADT_user_t *user = (ADT_user_t *)u;
 
-    for(i = 0; i < size; i++)
-        free(users[i]);
+    fprintf(fp, "\t\t<%s>%ld</%s>\n", XML_STR_ID, user->id, XML_STR_ID);
+    fprintf(fp, "\t\t<%s>%ld</%s>\n", XML_STR_CREDIT, user->c, XML_STR_CREDIT);
+    fprintf(fp, "\t\t<%s>%ld</%s>\n", XML_STR_DEBIT, user->d, XML_STR_DEBIT);
 
-    free(users);
     return OK;
 }
+
+int user_comparator_credits_minmax(const void *a, const void *b)
+{
+    ADT_user_t *A, *B;
+
+    if(a == NULL || b == NULL) return ERROR_NULL_POINTER;
+
+    A = *(ADT_user_t **)a;
+    B = *(ADT_user_t **)b;
+
+    if(A->c > B->c) return 1;
+    else if(A->c == B->c) return 0;
+    return -1;
+}  
+
+int user_comparator_credits_maxmin(const void *a, const void *b)
+{
+    ADT_user_t *A, *B;
+
+    if(a == NULL || b == NULL) return ERROR_NULL_POINTER;
+
+    A = *(ADT_user_t **)a;
+    B = *(ADT_user_t **)b;
+
+    if(A->c < B->c) return 1;
+    else if(A->c == B->c) return 0;
+    return -1;
+}  
diff --git a/source/utils.c b/source/utils.c
@@ -0,0 +1,106 @@
+#include "../include/utils.h"
+
+status_t string_split(char *s, char **data, char *delim)
+{
+    char *p, *tmp;
+    size_t fields = 0;
+
+    if(s == NULL || data == NULL || delim == NULL)
+        return ERROR_NULL_POINTER;
+
+    for(p = s; (tmp = strtok(p, delim)); p = NULL)
+        strcpy(data[fields++], tmp);
+
+    if(fields != IN_FILE_FIELDS)
+        return ERROR_CORRUPT_DATA;
+
+    return OK;
+}
+
+
+void clean_buffer(char *buf)
+{
+    size_t i;
+
+    for(i = 0; i < IN_FILE_MAX_LEN; i++)
+        buf[i] = '\0';
+}
+
+void clean_array(char **data)
+{
+    size_t i, j;
+
+    for(i = 0; i < IN_FILE_FIELDS; i++) {
+        for(j = 0; j < IN_FILE_FIELDS_MAX_LEN; j++)
+            data[i][j] = '\0';
+    }
+}
+
+status_t array_destroy(char **data, size_t fields)
+{
+    size_t i;
+
+    if(data == NULL) return ERROR_NULL_POINTER;
+
+    for(i = 0; i < fields; i++) {
+        free(data[i]);
+        data[i] = NULL;
+    }
+
+    free(data);
+    return OK;
+}
+
+status_t get_date(time_t *e, char **data)
+{
+    struct tm tm;
+
+    if(e == NULL || data == NULL) return ERROR_NULL_POINTER;
+
+    /* Desactiva el horario de verano */
+    tm.tm_isdst = 0;
+
+    switch(data[POS_TXN_DATE][2]) {
+        case '/': 
+            strptime(data[2], "%d/%m/%Y %H:%M:%S", &tm);
+            *e = mktime(&tm);
+            break;
+        case '-':
+            strptime(data[2], "%d-%m-%Y %H:%M:%S", &tm);
+            *e = mktime(&tm);
+            break;
+        case '.':
+            strptime(data[2], "%d.%m.%Y %H:%M:%S", &tm);
+            *e = mktime(&tm);
+            break;
+
+        default: return ERROR_CORRUPT_DATA; break;
+    }
+    return OK;
+}
+
+bool is_valid_card(char *card_no)
+{
+    size_t i, j, k;
+    int arr[4][4], sum;
+    char tmp[2];
+
+    if(card_no == NULL) return false;
+    if(strlen(card_no) != CARD_NO_VALID_LEN) return false;
+
+    for(i = 0, k = 0; i < 4; i++) {
+        for(j = 0; j < 4; j++) {
+            arr[i][j] = (card_no[k++] - '0');
+            if(j % 2) {
+                arr[i][j] *= 2;
+                sprintf(tmp, "%d", arr[i][j]);
+                if(!(strlen(tmp) - 1)) arr[i][j] = (tmp[0] - '0');
+                else arr[i][j] = ((tmp[0] - '0') + (tmp[1] - '0'));
+
+            }
+            sum += arr[i][j];
+        }
+    }
+
+    return (sum % 10) ? false : true;
+}
diff --git a/source/vector.c b/source/vector.c
@@ -0,0 +1,187 @@
+#include "../include/vector.h"
+
+status_t ADT_Vector_create(ADT_Vector_t **v)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    if((*v = (ADT_Vector_t *)malloc(sizeof(ADT_Vector_t))) == NULL)
+        return ERROR_MEMORY;
+
+    if(((*v)->a = (void **)malloc(sizeof(void *) * VECTOR_INIT_SIZE)) == NULL)
+        return ERROR_MEMORY;
+
+    (*v)->size = 0;
+    (*v)->alloc = VECTOR_INIT_SIZE;
+    (*v)->printer = NULL;
+    (*v)->comparator = NULL;
+
+    return OK;
+}
+
+status_t ADT_Vector_add(ADT_Vector_t **v, void *e)
+{
+    void *tmp;
+
+    if(v == NULL || e == NULL) return ERROR_NULL_POINTER;
+
+    /* Extends the array in case low memory left */
+    if(((*v)->size + 1) == (*v)->alloc) {
+        if((tmp = (void **)realloc((*v)->a, sizeof(void *) * (*v)->alloc * VECTOR_GROWTH_FACTOR)) == NULL)
+            return ERROR_MEMORY;
+        else {
+            (*v)->a = tmp;
+            (*v)->alloc *= VECTOR_GROWTH_FACTOR;
+        }
+    }
+
+    (*v)->a[(*v)->size++] = e;
+
+    return OK;
+}
+
+status_t ADT_Vector_destroy(ADT_Vector_t **v)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    for(size_t i = 0; i < (*v)->size; i++) {
+        free((*v)->a[i]);
+        (*v)->a[i] = NULL;
+    }
+
+    free((*v)->a);
+    free(*v);
+    *v = NULL;
+
+    return OK;
+}
+
+status_t ADT_Vector_set(ADT_Vector_t **v, void *e, size_t pos)
+{
+    void ** aux;
+    size_t i, alloc_size;
+
+    if(v == NULL || e == NULL) return ERROR_NULL_POINTER;
+    else if(pos > (*v)->size) return ERROR_INVALID_POS;
+
+    alloc_size = (*v)->alloc;
+
+    /* Cuenta cuanto tiene que alargar el arreglo p/ que entre el nuevo elemento */
+    while(pos >= alloc_size) {
+        alloc_size *= VECTOR_GROWTH_FACTOR;
+    }
+
+    /* Extiende el arreglo en caso de que no haya memoria suficiente */
+    if(pos > (*v)->alloc) {
+        if((aux = (void **)realloc((*v)->a, sizeof(void *) * alloc_size)) == NULL)
+            return ERROR_MEMORY;
+        else {
+            (*v)->a = aux;
+            (*v)->alloc = alloc_size;
+        }
+    }
+
+    for(i = (*v)->size; i < pos; i++) {
+        (*v)->a[pos] = NULL;
+    }
+
+    (*v)->a[pos] = e;
+
+    if(pos >= (*v)->size) {
+        (*v)->size = (pos + 1);
+    }
+
+    return OK;
+}
+
+void *ADT_Vector_get_elem(const ADT_Vector_t *v, void *e)
+{
+    size_t i;
+
+    if(v == NULL || e == NULL) return NULL;
+
+    for(i = 0; i < v->size; i++) { 
+        if(v->comparator(e, v->a[i])) {
+            return v->a[i];
+        }
+    }
+
+    return NULL;
+}
+
+status_t ADT_Vector_print(const ADT_Vector_t *v, FILE *fp)
+{
+    status_t st;
+    size_t i;
+
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    for(i = 0; i < v->size; i++)
+        if((st = v->printer(v->a[i], fp)) != OK)
+            return st;
+
+    return OK;
+}
+
+status_t ADT_Vector_sort(ADT_Vector_t *v, comparator_t pf)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    /* Quick sort */
+    qsort(v->a, v->size, sizeof(void *), pf);
+
+    return OK;
+}
+
+status_t ADT_Vector_set_printer(ADT_Vector_t *v, printer_t pf)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    v->printer = pf;
+
+    return OK;
+}
+
+status_t ADT_Vector_set_comparator(ADT_Vector_t *v, comparator_t pf)
+{
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    v->comparator = pf;
+
+    return OK;
+}
+
+status_t ADT_Vector_export_as_csv(const ADT_Vector_t *v, FILE *fp)
+{
+    status_t st;
+    size_t i;
+
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    for(i = 0; i < v->size; i++)
+        if((st = v->printer(v->a[i], fp)) != OK)
+            return st;
+
+    return OK;
+}
+
+status_t ADT_Vector_export_as_xml(const ADT_Vector_t *v, FILE *fp)
+{
+    status_t st;
+    size_t i;
+
+    if(v == NULL) return ERROR_NULL_POINTER;
+
+    fprintf(fp, "%s\n", XML_STR_HEADER);
+    fprintf(fp, "<%s>\n", XML_STR_ROOT);
+
+    for(i = 0; i < v->size; i++){
+        fprintf(fp, "\t<%s>\n", XML_STR_ROW);
+        if((st = v->printer(v->a[i], fp)) != OK)
+            return st;
+
+        fprintf(fp, "\t</%s>\n", XML_STR_ROW);
+    }
+
+    fprintf(fp, "</%s>\n", XML_STR_ROOT);
+    return OK;
+}