'Returns a table from the data in the given text file.
Rows are expected to be separated by a newline.
Columns are expected to be separated by the given separator (by default, comma).
Strings will be converted to int, float, bool, date or None if headers are parsed.
For other data types, a custom string decoder can be given.
A preprocess(str) function can be given to change the file content before parsing.'

@classmethod
def load(cls, path, separator=',', decoder=(lambda v: v), headers=False, preprocess=None, password=None, **kwargs):

    data = open(path, 'rU')
    data = (data if (not password) else decrypt_string(data.read(), password))
    data = (data if (not password) else StringIO(data.replace('\r\n', '\n').replace('\r', '\n')))
    data = (data if (not preprocess) else StringIO(preprocess(data.read())))
    data.seek(((data.readline().startswith(BOM_UTF8) and len(BOM_UTF8)) or 0))
    data = csvlib.reader(data, delimiter=separator)
    (i, n) = (kwargs.get('start'), kwargs.get('count'))
    if ((i is not None) and (n is not None)):
        data = list(islice(data, i, (i + n)))
    elif (i is not None):
        data = list(islice(data, i, None))
    elif (n is not None):
        data = list(islice(data, n))
    else:
        data = list(data)
    if headers:
        fields = [csv_header_decode(field) for field in data.pop(0)]
        fields += ([(None, None)] * (max(([0] + [len(row) for row in data])) - len(fields)))
    else:
        fields = []
    if (not fields):
        data = [[decoder((decode_utf8(v) if (v != 'None') else None)) for v in row] for row in data]
    else:
        for (i, row) in enumerate(data):
            for (j, v) in enumerate(row):
                type = fields[j][1]
                if (row[j] == 'None'):
                    row[j] = decoder(None)
                elif (type is None):
                    row[j] = decoder(decode_utf8(v))
                elif (type in (STRING, TEXT)):
                    row[j] = decode_utf8(v)
                elif (type == INTEGER):
                    row[j] = int(row[j])
                elif (type == FLOAT):
                    row[j] = float(row[j])
                elif (type == BOOLEAN):
                    row[j] = bool(row[j])
                elif (type == DATE):
                    row[j] = date(row[j])
                elif (type == BLOB):
                    row[j] = v
                else:
                    row[j] = decoder(decode_utf8(v))
    return cls(rows=data, fields=fields, **kwargs)
