text:
using CSV
using Base.Test, DataFrames, NullableArrays, DataStreams, WeakRefStrings, Libz, DecFP

if !isdefined(Core, :String)
    typealias String UTF8String
end
if VERSION < v"0.5-dev"
    readstring = readall
end

# dir = joinpath(Pkg.dir("CSV"), "test/test_files")
dir = joinpath(dirname(@__FILE__),"test_files/")

#test on non-existent file
@test_throws ArgumentError CSV.Source("");

#test where datarow > headerrow
@test_throws ArgumentError CSV.Source(joinpath(dir, "test_no_header.csv");datarow=1,header=2);

#test various encodings
# f = CSV.Source(joinpath(dir, "test_utf8_with_BOM.csv"))
f = CSV.Source(joinpath(dir, "test_utf8.csv"))
@test f.options.delim == UInt8(',')
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.schema.header == ["col1","col2","col3"]
@test f.schema.types == [Nullable{Float64},Nullable{Float64},Nullable{Float64}]
@test position(f.data) == 15
ds = Data.stream!(f, DataFrame)
@test ds[1,1].value == 1.0
@test ds[2,1].value == 4.0
@test ds[3,1].value == 7.0
@test ds[1,2].value == 2.0
@test Data.header(ds) == Data.header(f) && Data.types(ds) == Data.types(f)

f = CSV.Source(joinpath(dir, "test_utf8.csv"))
si = CSV.write(joinpath(dir, "new_test_utf8.csv"), f)
# @test Data.isdone(si)
@test Data.header(si) == Data.header(f) && Data.types(si) == Data.types(f)
so = CSV.Source(si)
@test so.options.delim == UInt8(',')
@test so.schema.cols == 3
@test so.schema.rows == 3
@test so.schema.header == ["col1","col2","col3"]
@test so.schema.types == [Nullable{Float64},Nullable{Float64},Nullable{Float64}]
# @test so.datapos == 21
ds = Data.stream!(so, DataFrame)
@test ds[1,1].value == 1.0
@test ds[2,1].value == 4.0
@test ds[3,1].value == 7.0
@test ds[1,2].value == 2.0
@test Data.types(ds) == Data.types(f) == Data.types(si) == Data.types(so)
f = si = so = ds = nothing; gc(); gc()
rm(joinpath(dir, "new_test_utf8.csv"))

# f = CSV.Source(joinpath(dir, "test_utf16_be.csv"))
# f = CSV.Source(joinpath(dir, "test_utf16_le.csv"))
# f = CSV.Source(joinpath(dir, "test_utf16.csv"))
# f = CSV.Source(joinpath(dir, "test_windows.csv"))

#test one column file
f = CSV.Source(joinpath(dir, "test_single_column.csv"))
@test f.options.delim == UInt8(',')
@test f.options.quotechar == UInt8('"')
@test f.options.escapechar == UInt8('\\')
@test position(f.data) == 5
@test f.schema.cols == 1
@test f.schema.rows == 3
@test f.schema.header == ["col1"]
@test f.schema.types == [Nullable{Int}]
ds = Data.stream!(f, DataFrame)
@test ds[1,1].value == 1
@test ds[2,1].value == 2
@test ds[3,1].value == 3

#test empty file
if VERSION > v"0.5.0-dev"
    f = CSV.Source(joinpath(dir, "test_empty_file.csv"))
    @test f.schema.rows == 0
else
    @test_throws ArgumentError CSV.Source(joinpath(dir, "test_empty_file.csv"))
end

#test file with just newlines
f = CSV.Source(joinpath(dir, "test_empty_file_newlines.csv"))
@test f.schema.cols == 1
@test f.schema.rows == 9
@test position(f.data) == 1
@test f.schema.header == [""]
@test f.schema.types == [Nullable{WeakRefString{UInt8}}]

#test with various quotechars, escapechars
f = CSV.Source(joinpath(dir, "test_simple_quoted.csv"))
@test f.schema.cols == 2
@test f.schema.rows == 1
ds = Data.stream!(f, DataFrame)
@test string(ds[1,1].value) == "quoted field 1"
@test string(ds[1,2].value) == "quoted field 2"
f = CSV.Source(joinpath(dir, "test_quoted_delim_and_newline.csv"))
@test f.schema.cols == 2
@test f.schema.rows == 1

#test various newlines
f = CSV.Source(joinpath(dir, "test_crlf_line_endings.csv"))
@test f.schema.header == ["col1","col2","col3"]
@test f.schema.cols == 3
@test f.schema.types == [Nullable{Int},Nullable{Int},Nullable{Int}]
ds = Data.stream!(f, DataFrame)
@test ds[1,1].value == 1
f = CSV.Source(joinpath(dir, "test_newline_line_endings.csv"))
@test f.schema.header == ["col1","col2","col3"]
@test f.schema.cols == 3
@test f.schema.types == [Nullable{Int},Nullable{Int},Nullable{Int}]
f = CSV.Source(joinpath(dir, "test_mac_line_endings.csv"))
@test f.schema.header == ["col1","col2","col3"]
@test f.schema.cols == 3
@test f.schema.types == [Nullable{Int},Nullable{Int},Nullable{Int}]

#test headerrow, datarow, footerskips
f = CSV.Source(joinpath(dir, "test_no_header.csv");header=0,datarow=1)
@test f.schema.header == ["Column1","Column2","Column3"]
@test f.schema.types == [Nullable{Float64},Nullable{Float64},Nullable{Float64}]
@test f.schema.cols == 3
@test f.schema.rows == 3
f = CSV.Source(joinpath(dir, "test_2_footer_rows.csv");header=4,datarow=5,footerskip=2)
@test f.schema.header == ["col1","col2","col3"]
@test f.schema.types == [Nullable{Int},Nullable{Int},Nullable{Int}]
@test f.schema.cols == 3
@test f.schema.rows == 3

#test dates, dateformats
f = CSV.Source(joinpath(dir, "test_dates.csv");types=[Date],dateformat="yyyy-mm-dd")
@test f.schema.cols == 1
@test f.schema.rows == 3
@test f.schema.types == [Nullable{Date}]
ds = Data.stream!(f, DataFrame)
@test ds[1,1].value == Date(2015,1,1)
@test ds[2,1].value == Date(2015,1,2)
@test ds[3,1].value == Date(2015,1,3)
f = CSV.Source(joinpath(dir, "test_excel_date_formats.csv");types=[Date],dateformat="mm/dd/yy")
@test f.schema.cols == 1
@test f.schema.rows == 3
@test f.schema.types == [Nullable{Date}]
f = CSV.Source(joinpath(dir, "test_datetimes.csv");types=[DateTime],dateformat="yyyy-mm-dd HH:MM:SS.s")
@test f.schema.cols == 1
@test f.schema.rows == 3
@test f.schema.types == [Nullable{DateTime}]
ds = Data.stream!(f, DataFrame)
@test ds[1,1].value == DateTime(2015,1,1)
@test ds[2,1].value == DateTime(2015,1,2,0,0,1)
@test ds[3,1].value == DateTime(2015,1,3,0,12,0,1)
# f = CSV.Source(joinpath(dir, "test_mixed_date_formats.csv");types=[Date],formats=["mm/dd/yyyy"])

#test bad types
# f = CSV.Source(joinpath(dir, "test_float_in_int_column.csv");types=[Int,Int,Int])
# f = CSV.Source(joinpath(dir, "test_floats.csv");types=[Float64,Float64,Float64])

#test null/missing values
f = CSV.Source(joinpath(dir, "test_missing_value_NULL.csv"))
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.schema.types == [Nullable{Float64},Nullable{WeakRefString{UInt8}},Nullable{Float64}]
ds = Data.stream!(f, DataFrame)
@test ds[1,1].value == 1.0
@test string(ds[1,2].value) == "2.0"
@test string(ds[2,2].value) == "NULL"
f = CSV.Source(joinpath(dir, "test_missing_value_NULL.csv"); null="NULL")
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.options.null == "NULL"
@test f.schema.types == [Nullable{Float64},Nullable{Float64},Nullable{Float64}]
ds = Data.stream!(f, DataFrame)
@test ds[1,1].value == 1.0
@test string(ds[1,2].value) == "2.0"
@test isnull(ds[2,2])

# uses default missing value ""
f = CSV.Source(joinpath(dir, "test_missing_value.csv"))
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.schema.types == [Nullable{Float64},Nullable{Float64},Nullable{Float64}]

# DataStreams interface
source_file = joinpath(dir, "test_utf8.csv")
sink_file = joinpath(dir, "test_utf8_new.csv")
header = "\"col1\",\"col2\",\"col3\"\n"
values = "1.0,2.0,3.0\n4.0,5.0,6.0\n7.0,8.0,9.0\n"

ds = CSV.read(source_file)
@test size(ds) == (3,3)
ds = CSV.read(source_file, CSV.Sink, sink_file)
@test readstring(sink_file) == header * values
ds = CSV.read(source_file, CSV.Sink, sink_file; append=true)
@test readstring(sink_file) == header * values * values

sink = CSV.Sink(joinpath(dir, "test_utf8_new.csv"))
ds = CSV.read(source_file, sink)
@test readstring(sink_file) == header * values
ds = CSV.read(source_file, sink; append=true)
@test readstring(sink_file) == header * values * values

source = CSV.Source(source_file)
ds = CSV.read(source)
@test size(ds) == (3,3)
source = CSV.Source(source_file)
ds = CSV.read(source, CSV.Sink, sink_file)
@test readstring(sink_file) == header * values
source = CSV.Source(source_file)
ds = CSV.read(source, CSV.Sink, sink_file; append=true)
@test readstring(sink_file) == header * values * values

sink = CSV.Sink(joinpath(dir, "test_utf8_new.csv"))
source = CSV.Source(source_file)
ds = CSV.read(source, sink)
@test readstring(sink_file) == header * values
source = CSV.Source(source_file)
ds = CSV.read(source, sink; append=true)
@test readstring(sink_file) == header * values * values

si = CSV.write(sink_file, CSV.Source, source_file)
@test readstring(sink_file) == header * values
si = CSV.write(sink_file, CSV.Source, source_file; append=true)
@test readstring(sink_file) == header * values * values

source = CSV.Source(source_file)
si = CSV.write(sink_file, source)
@test readstring(sink_file) == header * values
source = CSV.Source(source_file)
si = CSV.write(sink_file, source; append=true)
@test readstring(sink_file) == header * values * values

sink = CSV.Sink(joinpath(dir, "test_utf8_new.csv"))
si = CSV.write(sink, CSV.Source, source_file)
@test readstring(sink_file) == header * values
sink = CSV.Sink(joinpath(dir, "test_utf8_new.csv"); append=true)
si = CSV.write(sink, CSV.Source, source_file; append=true)
@test readstring(sink_file) == header * values * values

source = CSV.Source(source_file)
sink = CSV.Sink(joinpath(dir, "test_utf8_new.csv"))
si = CSV.write(sink, source)
@test readstring(sink_file) == header * values
source = CSV.Source(source_file)
sink = CSV.Sink(joinpath(dir, "test_utf8_new.csv"); append=true)
si = CSV.write(sink, source; append=true)
@test readstring(sink_file) == header * values * values
rm(sink_file)

#other various files found around the internet
f = CSV.Source(joinpath(dir, "baseball.csv"))
@test f.schema.cols == 15
@test f.schema.rows == 35
@test position(f.data) == 59
@test f.schema.header == ["Rk","Year","Age","Tm","Lg","","W","L","W-L%","G","Finish","Wpost","Lpost","W-L%post",""]
@test f.schema.types == [Nullable{Int},Nullable{Int},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Int},Nullable{Float64},Nullable{Int},Nullable{Float64},Nullable{Int},Nullable{Int},Nullable{Float64},Nullable{WeakRefString{UInt8}}]
ds = Data.stream!(f, DataFrame)
# CSV.read(f)

f = CSV.Source(joinpath(dir, "FL_insurance_sample.csv");types=Dict(10=>Float64,12=>Float64))
@test f.schema.cols == 18
@test f.schema.rows == 36634
@test position(f.data) == 243
@test f.schema.header == ["policyID","statecode","county","eq_site_limit","hu_site_limit","fl_site_limit","fr_site_limit","tiv_2011","tiv_2012","eq_site_deductible","hu_site_deductible","fl_site_deductible","fr_site_deductible","point_latitude","point_longitude","line","construction","point_granularity"]
@test f.schema.types == [Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Int},Nullable{Float64},Nullable{Float64},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "FL_insurance_sample.csv");types=Dict{String,DataType}("eq_site_deductible"=>Float64,"fl_site_deductible"=>Float64))
@test f.schema.cols == 18
@test f.schema.rows == 36634
@test position(f.data) == 243
@test f.schema.header == ["policyID","statecode","county","eq_site_limit","hu_site_limit","fl_site_limit","fr_site_limit","tiv_2011","tiv_2012","eq_site_deductible","hu_site_deductible","fl_site_deductible","fr_site_deductible","point_latitude","point_longitude","line","construction","point_granularity"]
@test f.schema.types == [Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Int},Nullable{Float64},Nullable{Float64},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "SacramentocrimeJanuary2006.csv"))
@test f.schema.cols == 9
@test f.schema.rows == 7584
@test position(f.data) == 81
@test f.schema.header == ["cdatetime","address","district","beat","grid","crimedescr","ucr_ncic_code","latitude","longitude"]
@test f.schema.types == [Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Float64},Nullable{Float64}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "Sacramentorealestatetransactions.csv"))
@test f.schema.cols == 12
@test f.schema.rows == 985
@test position(f.data) == 80
@test f.schema.header == ["street","city","zip","state","beds","baths","sq__ft","type","sale_date","price","latitude","longitude"]
@test f.schema.types == [Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Int},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Float64},Nullable{Float64}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "SalesJan2009.csv"))
@test f.schema.cols == 12
@test f.schema.rows == 998
@test position(f.data) == 114
@test f.schema.header == ["Transaction_date","Product","Price","Payment_Type","Name","City","State","Country","Account_Created","Last_Login","Latitude","Longitude"]
@test f.schema.types == [Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Float64},Nullable{Float64}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "stocks.csv"))
@test f.schema.cols == 2
@test f.schema.rows == 30
@test position(f.data) == 24
@test f.schema.header == ["Stock Name","Company Name"]
@test f.schema.types == [Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "TechCrunchcontinentalUSA.csv"))
@test f.schema.cols == 10
@test f.schema.rows == 1460
@test position(f.data) == 88
@test f.schema.header == ["permalink","company","numEmps","category","city","state","fundedDate","raisedAmt","raisedCurrency","round"]
@test f.schema.types == [Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "Fielding.csv"))
@test f.schema.cols == 18
@test f.schema.rows == 167938
@test position(f.data) == 77
@test f.schema.header == ["playerID","yearID","stint","teamID","lgID","POS","G","GS","InnOuts","PO","A","E","DP","PB","WP","SB","CS","ZR"]
@test f.schema.types == [Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Int},Nullable{Int},Nullable{Int},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "latest (1).csv"); header=0, null="\\N")
@test f.schema.cols == 25
@test f.schema.rows == 1000
@test f.schema.header == ["Column$i" for i = 1:f.schema.cols]
@test f.schema.types == [Nullable{WeakRefString{UInt8}},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{Int},Nullable{Date},Nullable{Date},Nullable{Int},Nullable{WeakRefString{UInt8}},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Int},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Float64},Nullable{Int},Nullable{Float64},Nullable{Float64},Nullable{Float64}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "pandas_zeros.csv"))
@test f.schema.cols == 50
@test f.schema.rows == 100000
@test f.schema.header == [string(i) for i = 0:49]
@test f.schema.types == repmat([Nullable{Int}],50)
@time ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "test_header_range.csv");header=1:3)
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.schema.header == ["col1_sub1_part1","col2_sub2_part2","col3_sub3_part3"]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "test_header_range.csv");header=["col1_sub1_part1","col2_sub2_part2","col3_sub3_part3"],datarow=4)
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.schema.header == ["col1_sub1_part1","col2_sub2_part2","col3_sub3_part3"]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "test_basic.csv");types=Dict(2=>Float64))
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.schema.types == [Nullable{Int},Nullable{Float64},Nullable{Int}]
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "test_basic_pipe.csv");delim='|')
@test f.schema.cols == 3
@test f.schema.rows == 3
@test f.schema.types == [Nullable{Int},Nullable{Int},Nullable{Int}]
@test f.options.delim == UInt8('|')
ds = Data.stream!(f, DataFrame)

f = CSV.Source(joinpath(dir, "test_basic_pipe.csv");delim='|',footerskip=1)
@test f.schema.cols == 3
@test f.schema.rows == 2
@test f.schema.types == [Nullable{Int},Nullable{Int},Nullable{Int}]
@test f.options.delim == UInt8('|')
ds = Data.stream!(f, DataFrame)

### io.jl

# Int
io = IOBuffer("0")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = IOBuffer("-1")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(-1)

io = IOBuffer("1")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(1)

io = IOBuffer("2000")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(2000)

io = IOBuffer("0.0")
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
io = IOBuffer("0a")
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
io = IOBuffer("")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(" ")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\t")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(" \t 010")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(10)

io = IOBuffer("\"1_00a0\"")
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
io = IOBuffer("\"0\"")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = IOBuffer("0\n")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = IOBuffer("0\r")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = IOBuffer("0\r\n")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = IOBuffer("0a\n")
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
# Should we handle trailing whitespace?
io = IOBuffer("\t0\t\n")
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)

io = IOBuffer("0,")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = IOBuffer("0,\n")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = IOBuffer("\n")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r\n")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\"\"")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("1234567890")
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(1234567890)

io = IOBuffer("\\N")
v = CSV.parsefield(io,Int,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("\"\\N\"")
v = CSV.parsefield(io,Int,CSV.Options(null="\\N"),1,1)
@test isnull(v)

# Int64 Libz
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("-1")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(-1)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(1)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2000")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(2000)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0.0")))
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a")))
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" ")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" \t 010")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(10)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"1_00a0\"")))
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"0\"")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\n")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r\n")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a\n")))
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)
# Should we handle trailing whitespace?
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t0\t\n")))
@test_throws CSV.CSVError CSV.parsefield(io,Int,CSV.Options(),1,1)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,\n")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\n")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r\n")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\"")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1234567890")))
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(1234567890)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\\N")))
v = CSV.parsefield(io,Int,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\\N\"")))
v = CSV.parsefield(io,Int,CSV.Options(null="\\N"),1,1)
@test isnull(v)

# Float64 Libz
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(1.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("-1.0")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(-1.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2000")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(2000.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a")))
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" ")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" \t 010")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(10.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"1_00a0\"")))
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"0\"")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\n")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r\n")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a\n")))
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)
# Should we handle trailing whitespace?
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t0\t\n")))
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,\n")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\n")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r\n")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\"")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1234567890")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(1234567890.0)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(".1234567890")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(.1234567890)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0.1234567890")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(.1234567890)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"0.1234567890\"")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(.1234567890)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("nan")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(NaN)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("NaN")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(NaN)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("inf")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(Inf)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("infinity")))
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(Inf)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\\N")))
v = CSV.parsefield(io,Float64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\\N\"")))
v = CSV.parsefield(io,Float64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

# Float64
io = IOBuffer("1")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(1.0)

io = IOBuffer("-1.0")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(-1.0)

io = IOBuffer("0")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = IOBuffer("2000")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(2000.0)

io = IOBuffer("0a")
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)
io = IOBuffer("")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(" ")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\t")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(" \t 010")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(10.0)

io = IOBuffer("\"1_00a0\"")
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)
io = IOBuffer("\"0\"")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = IOBuffer("0\n")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = IOBuffer("0\r")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = IOBuffer("0\r\n")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = IOBuffer("0a\n")
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)
# Should we handle trailing whitespace?
io = IOBuffer("\t0\t\n")
@test_throws CSV.CSVError CSV.parsefield(io,Float64,CSV.Options(),1,1)

io = IOBuffer("0,")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = IOBuffer("0,\n")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(0.0)

io = IOBuffer("\n")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r\n")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\"\"")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("1234567890")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(1234567890.0)

io = IOBuffer(".1234567890")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(.1234567890)

io = IOBuffer("0.1234567890")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(.1234567890)

io = IOBuffer("\"0.1234567890\"")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(.1234567890)

io = IOBuffer("nan")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(NaN)

io = IOBuffer("NaN")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(NaN)

io = IOBuffer("inf")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(Inf)

io = IOBuffer("infinity")
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(Inf)

io = IOBuffer("\\N")
v = CSV.parsefield(io,Float64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("\"\\N\"")
v = CSV.parsefield(io,Float64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

# DecFP Libz
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(1.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("-1.0")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(-1.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2000")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(2000.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a")))
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" ")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" \t 010")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(10.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"1_00a0\"")))
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"0\"")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\n")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r\n")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a\n")))
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)
# Should we handle trailing whitespace?
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t0\t\n")))
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,\n")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\n")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r\n")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\"")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1234567890")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(1234567890.0))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(".1234567890")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(.1234567890))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0.1234567890")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(.1234567890))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"0.1234567890\"")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(.1234567890))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("nan")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(NaN))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("NaN")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(NaN))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("inf")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(Inf))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("infinity")))
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(Inf))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\\N")))
v = CSV.parsefield(io,Dec64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\\N\"")))
v = CSV.parsefield(io,Dec64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

# DecFP
io = IOBuffer("1")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(1.0))

io = IOBuffer("-1.0")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(-1.0))

io = IOBuffer("0")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = IOBuffer("2000")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(2000.0))

io = IOBuffer("0a")
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)
io = IOBuffer("")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(" ")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\t")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(" \t 010")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(10.0))

io = IOBuffer("\"1_00a0\"")
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)
io = IOBuffer("\"0\"")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = IOBuffer("0\n")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = IOBuffer("0\r")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = IOBuffer("0\r\n")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = IOBuffer("0a\n")
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)
# Should we handle trailing whitespace?
io = IOBuffer("\t0\t\n")
@test_throws CSV.CSVError CSV.parsefield(io,Dec64,CSV.Options(),1,1)

io = IOBuffer("0,")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = IOBuffer("0,\n")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(0.0))

io = IOBuffer("\n")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r\n")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\"\"")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("1234567890")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(1234567890.0))

io = IOBuffer(".1234567890")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(.1234567890))

io = IOBuffer("0.1234567890")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(.1234567890))

io = IOBuffer("\"0.1234567890\"")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(.1234567890))

io = IOBuffer("nan")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(NaN))

io = IOBuffer("NaN")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(NaN))

io = IOBuffer("inf")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(Inf))

io = IOBuffer("infinity")
v = CSV.parsefield(io,Dec64,CSV.Options(),1,1)
@test v === Nullable(Dec64(Inf))

io = IOBuffer("\\N")
v = CSV.parsefield(io,Dec64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("\"\\N\"")
v = CSV.parsefield(io,Dec64,CSV.Options(null="\\N"),1,1)
@test isnull(v)

# WeakRefString
io = IOBuffer("0")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0"

io = IOBuffer("-1")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "-1"

io = IOBuffer("1")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "1"

io = IOBuffer("2000")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "2000"

io = IOBuffer("0.0")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0.0"

io = IOBuffer("0a")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0a"

io = IOBuffer("")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(" ")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == " "

io = IOBuffer("\t")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "\t"

io = IOBuffer(" \t 010")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == " \t 010"

io = IOBuffer("\"1_00a0\"")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "1_00a0"

io = IOBuffer("\"0\"")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0"

io = IOBuffer("0\n")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0"

io = IOBuffer("0\r")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0"

io = IOBuffer("0\r\n")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0"

io = IOBuffer("0a\n")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0a"

# Should we handle trailing whitespace?
io = IOBuffer("\t0\t\n")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "\t0\t"

io = IOBuffer("0,")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0"

io = IOBuffer("0,\n")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "0"

io = IOBuffer("\n")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r\n")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\"\"")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("1234567890")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "1234567890"

io = IOBuffer("\"hey there\\\"quoted field\\\"\"")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "hey there\\\"quoted field\\\""

io = IOBuffer("\\N")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("\"\\N\"")
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(null="\\N"),1,1)
@test isnull(v)

# Libz
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("-1")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "-1"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "1"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2000")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "2000"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0.0")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0.0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0a"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" ")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == " "

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "\t"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(" \t 010")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == " \t 010"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"1_00a0\"")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "1_00a0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"0\"")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\n")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0\r\n")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0a\n")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0a"

# Should we handle trailing whitespace?
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\t0\t\n")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "\t0\t"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("0,\n")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "0"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\n")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r\n")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\"")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("1234567890")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "1234567890"

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"hey there\\\"quoted field\\\"\"")))
v = CSV.parsefield(io,String,CSV.Options(),1,1)
@test string(get(v)) == "hey there\\\"quoted field\\\""

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\\N")))
v = CSV.parsefield(io,String,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\\N\"")))
v = CSV.parsefield(io,String,CSV.Options(null="\\N"),1,1)
@test isnull(v)

# Date

io = IOBuffer("")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(",")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\n")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r\n")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\"\"")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\\N")
v = CSV.parsefield(io,Date,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("\"\\N\"")
v = CSV.parsefield(io,Date,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("2015-10-05")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("\"2015-10-05\"")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("2015-10-05,")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("2015-10-05\n")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("2015-10-05\r")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("2015-10-05\r\n")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("  \"2015-10-05\",")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("\"2015-10-05\"\n")
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = IOBuffer("\"10/5/2015\"\n")
v = CSV.parsefield(io,Date,CSV.Options(null="",dateformat=Dates.DateFormat("mm/dd/yyyy")),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

# Date Libz
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(",")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\n")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r\n")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\"")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\\N")))
v = CSV.parsefield(io,Date,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\\N\"")))
v = CSV.parsefield(io,Date,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"2015-10-05\"")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05,")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05\n")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05\r")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05\r\n")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("  \"2015-10-05\",")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"2015-10-05\"\n")))
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"10/5/2015\"\n")))
v = CSV.parsefield(io,Date,CSV.Options(null="",dateformat=Dates.DateFormat("mm/dd/yyyy")),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

# DateTime

io = IOBuffer("")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer(",")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\n")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\r\n")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\"\"")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = IOBuffer("\\N")
v = CSV.parsefield(io,DateTime,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("\"\\N\"")
v = CSV.parsefield(io,DateTime,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = IOBuffer("2015-10-05T00:00:01")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("\"2015-10-05T00:00:01\"")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("2015-10-05T00:00:01,")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("2015-10-05T00:00:01\n")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("2015-10-05T00:00:01\r")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("2015-10-05T00:00:01\r\n")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("  \"2015-10-05T00:00:01\",")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("\"2015-10-05T00:00:01\"\n")
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = IOBuffer("\"10/5/2015 00:00:01\"\n")
v = CSV.parsefield(io,DateTime,CSV.Options(null="",dateformat=Dates.DateFormat("mm/dd/yyyy HH:MM:SS")),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

# DateTime Libz
io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer(",")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\n")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\r\n")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\"")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\\N")))
v = CSV.parsefield(io,DateTime,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"\\N\"")))
v = CSV.parsefield(io,DateTime,CSV.Options(null="\\N"),1,1)
@test isnull(v)

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05T00:00:01")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"2015-10-05T00:00:01\"")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05T00:00:01,")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05T00:00:01\n")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05T00:00:01\r")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("2015-10-05T00:00:01\r\n")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("  \"2015-10-05T00:00:01\",")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"2015-10-05T00:00:01\"\n")))
v = CSV.parsefield(io,DateTime,CSV.Options(),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

io = ZlibInflateInputStream(ZlibDeflateInputStream(IOBuffer("\"10/5/2015 00:00:01\"\n")))
v = CSV.parsefield(io,DateTime,CSV.Options(null="",dateformat=Dates.DateFormat("mm/dd/yyyy HH:MM:SS")),1,1)
@test v === Nullable{DateTime}(DateTime(2015,10,5,0,0,1))

# All types
io = IOBuffer("1,1.0,hey there sailor,2015-10-05\n,1.0,hey there sailor,\n1,,hey there sailor,2015-10-05\n1,1.0,,\n,,,")
# io = CSV.Source(io)
v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(1)
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(1.0)
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "hey there sailor"
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(1.0)
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "hey there sailor"
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(1)
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test string(get(v)) == "hey there sailor"
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test v === Nullable{Date}(Date(2015,10,5))

v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test v === Nullable(1)
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test v === Nullable(1.0)
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test isnull(v)
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)

v = CSV.parsefield(io,Int,CSV.Options(),1,1)
@test isnull(v)
v = CSV.parsefield(io,Float64,CSV.Options(),1,1)
@test isnull(v)
v = CSV.parsefield(io,WeakRefString{UInt8},CSV.Options(),1,1)
@test isnull(v)
v = CSV.parsefield(io,Date,CSV.Options(),1,1)
@test isnull(v)


text:
function solve()
    n = parse(Int, readline())
    a = [parse(Int, x) for x in split(readline())]

    M = 1000000007
    ret = 0
    s = a[1]
    for i=2:n
        ret += (a[i] * s) % M
        ret %= M
        s += a[i]
        s %= M
    end
    ret
end

println(solve())

ext: jl

max_stars_repo_name: aishikawa/atcoder-julia

max_issues_repo_name: aishikawa/atcoder-julia

max_forks_repo_name: aishikawa/atcoder-julia


text:
#!/usr/bin/env julia

using Harmonie_namelists, YAML
import Base.ENV

# Usage:
#    Get_namemlist.jl
# Will create the namelists defined in configs (see below)
# Currently output is written to stdout

# Harmonie requires $ENSMBR to be exported. We set it here explicitly.
# ENSMBR is not part of defaults.yaml
Harmonie_namelists.MYENV["ENSMBR"] =1

# Extract some values from ENV
alaro_version = Harmonie_namelists.MYENV["ALARO_VERSION"]
dynamics = Harmonie_namelists.MYENV["DYNAMICS"]
physics  = Harmonie_namelists.MYENV["PHYSICS"]
vert_disc = Harmonie_namelists.MYENV["VERT_DISC"]
domain = Harmonie_namelists.MYENV["DOMAIN"]
mass_flux_scheme = Harmonie_namelists.MYENV["MASS_FLUX_SCHEME"]
simulation_type = Harmonie_namelists.MYENV["SIMULATION_TYPE"]
cisba = Harmonie_namelists.MYENV["CISBA"]

e927_dynamics =  dynamics == "nh" ? "e927_nh" : "empty"
pp_dynamics =  dynamics  == "nh" ? "pp_nh" : "empty"

# Misc
extra_forecast_options= vert_disc

# Surfex
prep_sfx="offline_prep"

default = ["global", "host_specific", "mpp","file"]

sfx_tree_drag_options = "tree_drag"

cisbal=cisba # No need for if-statement ala Harmonie here

# Extra physics options
physics_options = [physics]
physics == "arome" && push!(physics_options, mass_flux_scheme)
physics == "alaro" && push!(physics_options,"alaro$alaro_version")

# musc
domain == "MUSC" && push!(extra_forecast_options,["musc"; "args"])

# Climate simulation
simulation_type == "climate" && push!(extra_forecast_options,["cc01_mse"; "args"])

# varbc
varbc_nam  = ["varbc"]
Harmonie_namelists.MYENV["GNSS_OBS"] == "1" && Harmonie_namelists.MYENV["LVARBC_GNSS"] == "T" && push!(varbc_nam, "varbc_gnss")

# Note: these are not consistent with Get_namelist
# should read this from yaml/toml file
configs = Dict("e927" => [default; dynamics; "dfi"; "args"],
               "forecast" => [default; dynamics;  "surfex"; "args"],
               "e401" => [default; "e401"; "args"],
               "pp"  => [default; "fullpos"; "pp_default"; "pp_surfex"; "pp_arome"  ],    # -r NAMFPC
               "oulan" => ["oulan"],
               "screening" => [default; "screening"; "arome_screening"; "args"],
               "minimization" => [default; "arome_minimization"],
               "screen4d" => [default; "screening"; dynamics; "args"])

io =stdout
for key in keys(configs)
    println(key)
    dicts = read_namelist.(configs[key])
    totdict = merge_namelists(dicts)
    replace_env!(totdict)
    dict2namelist(io,totdict)

end


text:
@recipe f(gp::AbstractGP, x::AbstractArray) = gp(x)
@recipe f(gp::AbstractGP, xmin::Real, xmax::Real) = gp(range(xmin, xmax; length=1_000))

@recipe f(z::AbstractVector, gp::AbstractGP, x::AbstractArray) = (z, gp(x))
@recipe function f(z::AbstractVector, gp::AbstractGP, xmin::Real, xmax::Real)
    return (z, gp(range(xmin, xmax; length=1_000)))
end

@recipe f(gp::FiniteGP) = (gp.x, gp)
@recipe function f(z::AbstractVector, gp::FiniteGP)
    length(z) == length(gp.x) ||
        throw(DimensionMismatch("length of `z` and `gp.x` has to be equal"))

    # compute marginals
    μ, σ2 = mean_and_cov_diag(gp)
    σ = map(sqrt, σ2)

    ribbon := σ
    fillalpha --> 0.3
    linewidth --> 2
    return z, μ
end

"""
    sampleplot(GP::FiniteGP, samples)

Plot samples from the given `FiniteGP`. Make sure to run `using Plots` before using this
function.

# Example
```julia
using Plots
f = GP(SqExponentialKernel())
sampleplot(f(rand(10)), 10; markersize=5)
```
The given example plots 10 samples from the given `FiniteGP`. The `markersize` is modified
from default of 0.5 to 5.
"""
@userplot SamplePlot
@recipe function f(sp::SamplePlot)
    x = sp.args[1].x
    f = sp.args[1].f
    num_samples = sp.args[2]
    @series begin
        samples = rand(f(x, 1e-9), num_samples)
        seriestype --> :line
        linealpha --> 0.2
        markershape --> :circle
        markerstrokewidth --> 0.0
        markersize --> 0.5
        markeralpha --> 0.3
        seriescolor --> "red"
        label --> ""
        x, samples
    end
end


text:
using Pkg #hideall
Pkg.activate("_literate/julia-plots/Project.toml")
Pkg.instantiate()
macro OUTPUT()
    return isdefined(Main, :Franklin) ? Franklin.OUT_PATH[] : "/tmp/"
end;

md"""
## Overview

This tutorial will give some examples of plotting and plotting features in Julia, as well as providing references to some relevant resources. The main plotting library is `Plots.jl`, but there are some others that provide useful features.

## Some Resources

* `Plots.jl` [useful tips](https://docs.juliaplots.org/latest/basics/#Useful-Tips)
* `Plots.jl` [examples](https://docs.juliaplots.org/latest/generated/gr/)
* [Plot attributes](http://docs.juliaplots.org/latest/generated/attributes_plot/)
* [Axis attributes](http://docs.juliaplots.org/latest/generated/attributes_axis/#Axis)
* [Color names](http://juliagraphics.github.io/Colors.jl/stable/namedcolors/)
"""

# ## Demos

using Plots
using Random # hide
Random.seed!(1) # hide

# ### Line Plots
# To generate a basic line plot, use `plot`.

y = rand(5)
plot(y, label="original data", legend=:topright)
savefig(joinpath(@OUTPUT, "line-plot.png")) # hide

# \fig{line-plot.png}

# There's a lot of customization here that can occur, a lot of which is discussed in the docs or can be found with some Googling.

# #### Adding Plot Elements
#
# Now we can add some other lines and point markers.

y2 = rand(5)
y3 = rand(5)
plot!(y2, label="new data")
scatter!(y3, label="even more data")
savefig(joinpath(@OUTPUT, "line-plot-added.png")) # hide

# \fig{line-plot-added.png}

# Remember that an exclamation mark (!) at the end of a function name means that function modifies an object in-place, so `plot!` and `scatter!` modify the current plotting object, they don't create a new plot.

# #### Removing Plot Elements
#
# Sometimes we want to remove legends, axes, grid lines, and ticks.

plot!(legend=false, axis=false, grid=false, ticks=false)
savefig(joinpath(@OUTPUT, "line-plot-removed.png")) #hide

# \fig{line-plot-removed.png}

# #### Aspect Ratio
#
# If we want to have a square aspect ratio, use `ratio = 1`.

v = rand(5)
plot(v, ratio=1, legend=false)
scatter!(v)
savefig(joinpath(@OUTPUT, "square-aspect.png")) #hide

# \fig{square-aspect.png}

# ### Heatmaps

# A heatmap is effectively a plotted matrix with colors chosen according to the values. Use `clim` to specify a fixed range for the color limits.

A = rand(10, 10)
heatmap(A, clim=(0, 1), ratio=1, legend=false, axis=false, ticks=false)
savefig(joinpath(@OUTPUT, "heatmap-basic.png")) #hide

# \fig{heatmap-basic.png}

M = [ 0 1 0; 0 0 0; 1 0 0]
whiteblack = [RGBA(1,1,1,0), RGB(0,0,0)]
heatmap(c=whiteblack, M, aspect_ratio = 1, ticks=.5:3.5, lims=(.5,3.5), gridalpha=1, legend=false, axis=false, ylabel="i", xlabel="j")
savefig(joinpath(@OUTPUT, "heatmap-bw.png")) #hide

# \fig{heatmap-bw.png}

# #### Custom Colors

using Colors

mycolors = [colorant"lightslateblue",colorant"limegreen",colorant"red"]
A = [i for i=50:300, j=1:100]
heatmap(A, c=mycolors, clim=(1,300))
savefig(joinpath(@OUTPUT, "heatmap-colors.png")) #hide

# \fig{heatmap-colors.png}

# ### Plotting Areas Under Curves

y = rand(10)
plot(y, fillrange= y.*0 .+ .5, label= "above/below 1/2", legend =:top)
savefig(joinpath(@OUTPUT, "above-below.png")) #hide

# \fig{above-below.png}

x = LinRange(0,2,100)
y1 = exp.(x)
y2 = exp.(1.3 .* x)
plot(x, y1, fillrange = y2, fillalpha = 0.35, c = 1, label = "Confidence band", legend = :topleft)
savefig(joinpath(@OUTPUT, "confidence.png")) #hide

# \fig{confidence.png}

x = -3:.01:3
areaplot(x, exp.(-x.^2/2)/√(2π),alpha=.25,legend=false)
savefig(joinpath(@OUTPUT, "normal-area.png")) #hide

# \fig{normal-area.png}

M = [1 2 3; 7 8 9; 4 5 6; 0 .5 1.5]
areaplot(1:3, M, seriescolor = [:red :green :blue ], fillalpha = [0.2 0.3 0.4])
savefig(joinpath(@OUTPUT, "area-colored.png")) #hide

# \fig{area-colored.png}

using SpecialFunctions
f = x->exp(-x^2/2)/√(2π)
δ = .01
plot()
x = √2 .* erfinv.(2 .*(δ/2 : δ : 1) .- 1)
areaplot(x, f.(x), seriescolor=[ :red,:blue], legend=false)
plot!(x, f.(x),c=:black)
savefig(joinpath(@OUTPUT, "normal-quantiles.png")) #hide

# \fig{normal-quantiles.png}

# ### Plotting Shapes

rectangle(w, h, x, y) = Shape(x .+ [0,w,w,0], y .+ [0,0,h,h])
circle(r,x,y) = (θ = LinRange(0,2π,500); (x.+r.*cos.(θ), y.+r.*sin.(θ)))
plot(circle(5,0,0), ratio=1, c=:red, fill=true)
plot!(rectangle(5*√2,5*√2,-2.5*√2,-2.5*√2),c=:white,fill=true,legend=false)
savefig(joinpath(@OUTPUT, "circle-rect.png")) #hide

# \fig{circle-rect.png}

# ### Editing Plots Manually

pl = plot(1:4,[1, 4, 9, 16])
savefig(joinpath(@OUTPUT, "basic-plot.png")) #hide

# \fig{basic-plot.png}

pl.attr
#-
pl.series_list[1]
#-
pl[:size]=(300,200)
#-
pl
savefig(joinpath(@OUTPUT, "basic-size.png")) #hide

# \fig{basic-size.png}

# ### Log-Scaled Axes

xx = .1:.1:10
plot(xx.^2, xaxis=:log, yaxis=:log)
savefig(joinpath(@OUTPUT, "log-axes.png")) #hide

# \fig{log-axes.png}

plot(exp.(x), yaxis=:log)
savefig(joinpath(@OUTPUT, "log-exp.png")) #hide

# \fig{log-exp.png}


text:
# ---
# title: 699. Falling Squares
# id: problem699
# author: Tian Jun
# date: 2020-10-31
# difficulty: Hard
# categories: Segment Tree, Ordered Map
# link: <https://leetcode.com/problems/falling-squares/description/>
# hidden: true
# ---
#
# On an infinite number line (x-axis), we drop given squares in the order they
# are given.
#
# The `i`-th square dropped (`positions[i] = (left, side_length)`) is a square
# with the left-most point being `positions[i][0]` and sidelength
# `positions[i][1]`.
#
# The square is dropped with the bottom edge parallel to the number line, and
# from a higher height than all currently landed squares. We wait for each
# square to stick before dropping the next.
#
# The squares are infinitely sticky on their bottom edge, and will remain fixed
# to any positive length surface they touch (either the number line or another
# square). Squares dropped adjacent to each other will not stick together
# prematurely.
#
#
#
# Return a list `ans` of heights. Each height `ans[i]` represents the current
# highest height of any square we have dropped, after dropping squares
# represented by `positions[0], positions[1], ..., positions[i]`.
#
# **Example 1:**
#
#
#
#     Input: [[1, 2], [2, 3], [6, 1]]
#     Output: [2, 5, 5]
#     Explanation:
#
#
# After the first drop of `positions[0] = [1, 2]: _aa _aa ------- `The maximum
# height of any square is 2.
#
# After the second drop of `positions[1] = [2, 3]: __aaa __aaa __aaa _aa__ _aa__
# -------------- `The maximum height of any square is 5. The larger square stays
# on top of the smaller square despite where its center of gravity is, because
# squares are infinitely sticky on their bottom edge.
#
# After the third drop of `positions[1] = [6, 1]: __aaa __aaa __aaa _aa _aa___a
# -------------- `The maximum height of any square is still 5. Thus, we return
# an answer of `[2, 5, 5]`.
#
#
#
#
#
# **Example 2:**
#
#
#
#     Input: [[100, 100], [200, 100]]
#     Output: [100, 100]
#     Explanation: Adjacent squares don't get stuck prematurely - only their bottom edge can stick to surfaces.
#
#
#
#
# **Note:**
#
#   * `1 <= positions.length <= 1000`.
#   * `1 <= positions[i][0] <= 10^8`.
#   * `1 <= positions[i][1] <= 10^6`.
#
#
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


text:
function construct_iter_all(N::Int, order::Int)

    #Construct an ordered iterator going over all moments
    # sequentially in terms of order

    # helper iterator through all possible combinations of
    # N terms each given in range [0, order]
    iter_full = Iterators.product(fill(0:order, N)...)
    iter_all = Iterators.filter(x -> sum(x) == 0, iter_full)
    for i in 1:order
        iter = Iterators.filter(x -> sum(x) == i, iter_full)
        iter_all = Iterators.flatten((iter_all, iter))
    end

    collect(iter_all)

end

# Trim a string of form "(a, b, c, d, ...)" to "abcd..."
trim_key(expr) = filter(x -> !(isspace(x) || x == ')' || x== '(' || x==','), string(expr))

# Expand a symbolic expression (no binomial expansion)
expansion_rule_mod = @acrule ~x * +(~~ys) => sum(map(y-> ~x * y, ~~ys))
expand_mod = Fixpoint(Prewalk(PassThrough(expansion_rule_mod)))
flatten_rule_mod = @rule(~x::isnotflat(+) => flatten_term(+, ~x))
flatten_mod = Fixpoint(PassThrough(flatten_rule_mod))
expand_expr = Fixpoint(PassThrough(Chain([expand_mod, flatten_mod])))

# Note that throughout we use ModelingToolkit to initialise the variables
# but then change their Num type into SymbolicUtils Term{Real} as it's
# easier to handle in symbolic expressions
function define_μ(N::Int, order::Int, iter=construct_iter_all(N, order))

    indices = []
    for i in iter
        push!(indices, trim_key(i))
    end

    @parameters t
    @variables μ[indices](t)

    μs = OrderedDict()
    for (i, idx) in enumerate(iter)
        μs[idx] = sum(idx) == 0 ? 1 : μ[i].val
    end

    μs

end

function define_M(N::Int, order::Int, iter=construct_iter_all(N, order))

    indices = []
    for i in iter
        push!(indices, trim_key(i))
    end

    @parameters t
    @variables M[indices](t)

    Ms = OrderedDict()
    for (i, idx) in enumerate(iter)
        if sum(idx)==0
            Ms[idx] = 1
        elseif sum(idx)==1
            Ms[idx] = 0
        else
            Ms[idx] = M[i].val
        end
    end

    Ms

end

function extract_variables(eqs::Array{Equation, 1}, N::Int, q_order::Int)

    iters = construct_iter_all(N, q_order)
    iter_μ = filter(x -> sum(x) > 0, iters)
    iter_M = filter(x -> sum(x) > 1, iters)

    μs = values(define_μ(N, q_order, iter_μ))
    Ms = values(define_M(N, q_order, iter_M))
    vars = vcat(μs..., Ms...)
    # extract variables from rhs of each equation
    eq_vars = unique(vcat(get_variables.(eqs)...))
    # need this as get_variables does not extract var from `Differential(t)(var(t))`
    diff_vars = [var_from_nested_derivative(eq.lhs)[1] for eq in eqs]
    # filter out the unique ones
    eq_vars = unique(vcat(eq_vars..., diff_vars...))
    # this should preserve the correct ordering

    vars = intersect!(vars, eq_vars)
    vars

end

## Set of functions to deconstruct polynomial propensities ##

#=
    Consider a polynomial propensity function: a₁ = x^2 + c₁*y²*x,
    where x(t) and y(t) are the molecule numbers variables and c₁ is reaction parameter
    First we need to split a₁ into separate terms, i.e. x^2 and c₁*y²*x. Then we
    determine the independent multiplication factor in each term (1 and c₁). Finally,
    we obtain the power each variable is raised to in each term (x to power 2 in term 1;
    x to power 1 and y to power 2 in term 2). Having this information we can proceed
    in constructing raw moment equations. IF any propensity function is non-polynomial
    then the function `polynomial_propensities` will throw an error.
    NOTE: this code might easily break with a newer ModelingToolkit/SymbolicUtils version
    TODO: try to make this functionality less cumbersome and test more rigorously
    TODO: use AbstractAlgebra MPoly
=#

function polynomial_terms(expr, terms)

    if istree(expr)
        if operation(expr) == +
            for arg in arguments(expr)
                polynomial_terms(arg, terms)
            end
        else
            push!(terms, expr)
        end
    else
        push!(terms, expr)
    end

end

function factorise_term(expr, factors, powers, rn)
    if istree(expr)
        args = arguments(expr)
        if length(args) == 1
            if isequal(args[1], rn.iv)
                idx = speciesmap(rn)[expr]
                if powers[idx] != 0
                    error("Same variable occurring multiple times is unexpected in: ", expr)
                else
                    powers[idx] = 1
                end
            else
                error("Unexpected symbolic expression: ", expr)
            end
        else
            op = operation(expr)
            if op == ^
                if length(args) == 2
                    # this is fragile (any change in SymbolicUtils/ModelingToolkit might break it)
                    if args[1] isa Term{Real} && args[2] isa Int && args[2] >= 0  # x(t)^i where i is Int>0
                        idx = speciesmap(rn)[args[1]]
                        if powers[idx] != 0
                            error("Same variable occurring multiple times is unexpected in: ", expr)
                        else
                            powers[idx] = args[2]
                        end
                    elseif args[1] isa SymbolicUtils.Add{Real,Int64,Dict{Any,Number}}
                        error("binomial expansion is not supported for: ", expr)
                    elseif !isa(args[1], Term{Real}) && !isa(args[2], Term{Real})
                        push!(factors, expr)
                    else
                        error("Unexpected expression with ^: ", expr)
                    end
                else
                    error("Only expressions x^n (two symbols) are supported ", expr)
                end
            elseif op == *
                for arg in args
                    factorise_term(arg, factors, powers, rn)
                end
            else
                error("Operation in a polynomial term is unexpected: ", op)
            end
        end
    else
        push!(factors, expr)
    end

end

function polynomial_propensities(a::Vector, rn::Union{ReactionSystem, ReactionSystemMod})

    R = numreactions(rn)
    term_factors = [[] for i = 1:R]
    term_powers = [[] for i = 1:R]
    max_power = 0
    for (ind, expr) in enumerate(a)
        terms = []
        polynomial_terms(expand(expr), terms)
        for term in terms
            factors = []
            powers = zeros(Int, numspecies(rn))
            try
                factorise_term(term, factors, powers, rn)
            catch e
                error("Non-polynomial propensity was included?\n" * string(e))
            end
            factor = isempty(factors) ? 1 : prod(factors)
            max_power = sum(powers) > max_power ? sum(powers) : max_power
            push!(term_factors[ind], factor)
            push!(term_powers[ind], powers)
        end
    end

    term_factors, term_powers, max_power

end

#=

function is_polynomial(expr::Symbolic, rn::Union{ReactionSystem, ReactionSystemMod})

    # checking whether a given symbolic expression is a polynomial in molecule numbers

    #terms = []
    #polynomial_terms(expand(expr), terms)
    #ks = sort(collect(keys(poly[2])), lt=SymbolicUtils.:<ₑ)

    sym2term, term2sym = SymbolicUtils._dicts()
    SymbolicUtils.labels!((sym2term, term2sym), expr)

    ks = collect(keys(term2sym))
    println(ks)

    for expr in ks[findall(istree.(ks))]

        vars = get_variables(expr)

        if sum(in.(species(rn), Ref(vars))) > 0
            # if length is one we have time-dependent variable (molecule number)
            if length(vars) > 1
                return false
            end
        end

    end

    return true

end

is_polynomial(expr::Real, rn::Union{ReactionSystem, ReactionSystemMod}) = true
=#


text:
##########################################################################################
######################### Este archivo contiene las funciones que son ####################
######################### usadas para comunicarse con los jugadores ######################
##########################################################################################

function Init(empate::Bool)     # Función para empezar el juego
    if empate == true           # En caso de que haya habido empate o sea el primer juego
        println("¿Quién empieza? \n Se tiró una moneda y...")
        moneda = rand(1:2)      # Se tira una moneda para saber quien empieza

        # X se modelan con un 1 y las O's con un -1. Se regresa un arreglo para saber el orden
        if moneda == 1
            println("Empiezan X \n \n Miau 1: X \n Miau 2: O")
            return Int8[1, -1]   ## <= estos son los arreglos
        else
            println("Empiezan O \n \n Miau 1: O \n Miau 2: X")
            return Int8[-1, 1]   ## <= estos son los arreglos
        end
    end
end

function NuevoJuego()         # Al final de cada juego se pregunta si se quiere volver a
    check = false             # jugar
    while check == false
        println("¿Jugar de nuevo? [s/n]")
        respuesta = chomp(readline(STDIN))
        if respuesta == "s" || respuesta == "S" || respuesta == "Si" || respuesta == "si"
            return true
            check = true
        elseif respuesta == "n" || respuesta == "N" || respuesta == "No" || respuesta == "no"
            return false
            check = true
        else
            println("Lo siento, respuesta incorrecta")
            check = false
        end
    end
end

function Pregunta_tiro(num::Int8)   # Se le preguntal al jugador donde quiere tirar
    check2 = false
    while check2 == false
        println("¿Donde quieres tirar, Miau $num?")
        loc = parse(Int64, chomp(readline(STDIN)))
        if loc > 9
            println("Solo hay 9 celdas -_-")
            check2 = false
        else
            check2 = true
            return loc
        end
    end
end

function pintar(G::Gato)          # Esta función pinta el tablero en la terminal después
    S = Array(Char, 9)            # de cada tiro
    for i = 1:9
        if G.tablero[i] == 1
            S[i] = 'X'
        elseif G.tablero[i] == -1
            S[i] = 'O'
        else
            S[i] = '-'
        end
    end
    println(transpose(reshape(S, 3, 3)))
end


text:
# This uses MATLAB's definition of the `peaks` function to test `inpaint_nans`

peaks(x, y) = 3 * (1 - x)^2 * exp(-(x^2) - (y + 1)^2) -
    10 * (x/5 - x^3 - y^5) * exp(-x^2 - y^2) -
    1/3 * exp(-(x + 1)^2 - y^2)

xs = LinRange(-3, 3, 50)
ys = LinRange(-3, 3, 50)
Z = [peaks(x, y) for y in ys, x in xs]

# Remove some values in blocks
# Remove some values at random indices (pregenerated for determinism of the test)
# pregenerated via `rand(CartesianIndices(size(Z)), 10)`
# Note I made sure no NaN on the border, need to figure out why different from MATLAB there
idx = [
 vec(CartesianIndices((1:10, 1:10)))
 vec(CartesianIndices((20:40, 20:35)))
 CartesianIndex(45, 8)
 CartesianIndex(41, 24)
 CartesianIndex(5, 30)
 CartesianIndex(15, 22)
 CartesianIndex(17, 18)
 CartesianIndex(9, 11)
 CartesianIndex(3, 21)
 CartesianIndex(42, 26)
 CartesianIndex(16, 16)
 CartesianIndex(22, 42)
]

@testset "Testing on $Type" for T in (Float16, Float32, Float64)
    Z_T = convert.(T, Z)
    @testset "with missing values" begin
        Z_with_missing_values_T = convert(Array{Union{Missing, eltype(Z_T)}} ,Z_T)
        Z_with_missing_values_T[idx] .= missing
        Z_inpainted_missing_T = inpaint(Z_with_missing_values_T)
        @test Z_inpainted_missing_T == inpaint(ismissing, Z_with_missing_values_T)
        @test Z_inpainted_missing_T == inpaint(Z_with_missing_values_T, missing)
    end
    @testset "with NaN values" begin
        Z_with_NaN_values_T = copy(Z_T)
        Z_with_NaN_values_T[idx] .= NaN
        Z_inpainted_NaN_T = inpaint(Z_with_NaN_values_T)
        @test Z_inpainted_NaN_T == inpaint(isnan, Z_with_NaN_values_T)
        @test Z_inpainted_NaN_T == inpaint(Z_with_NaN_values_T, NaN)
    end
end

@testset "Inpainting `NaN`s or `missing`s is the same" begin
    Z_with_missing_values = convert(Array{Union{Missing, eltype(Z)}} ,Z)
    Z_with_missing_values[idx] .= missing
    Z_inpainted_missing = inpaint(Z_with_missing_values)
    Z_with_NaN_values = copy(Z)
    Z_with_NaN_values[idx] .= NaN
    Z_inpainted_NaN = inpaint(Z_with_NaN_values)
    @test Z_inpainted_NaN == Z_inpainted_missing
end

#using Plots
#contourf(ys, xs, Z)
#contourf(ys, xs, Z_with_NaNs)
#contourf(ys, xs, Z_reconstructed)

# @testset "Comparison with MATLAB" begin
#     Z_with_NaN_values = copy(Z)
#     Z_with_NaN_values[idx] .= NaN
#     Z_inpainted_NaN = inpaint(Z_with_NaN_values)#=
#     MATLAB code used to compare both values:
#
#     Z = peaks(50) ;
#     Z_with_NaNs = Z ;
#     Z_with_NaNs(1:10, 1:10) = nan ;
#     Z_with_NaNs(20:40, 20:35) = nan ;
#     Z_with_NaNs(45, 8) = nan ;
#     Z_with_NaNs(41, 24) = nan ;
#     Z_with_NaNs(5, 30) = nan ;
#     Z_with_NaNs(15, 22) = nan ;
#     Z_with_NaNs(17, 18) = nan ;
#     Z_with_NaNs(9, 11) = nan ;
#     Z_with_NaNs(3, 21) = nan ;
#     Z_with_NaNs(42, 26) = nan ;
#     Z_with_NaNs(16, 16) = nan ;
#     Z_with_NaNs(22, 42) = nan ;
#     Z_reconstructed0 = inpaint_nans(Z_with_NaNs) ;
#     inan = find(isnan(Z_with_NaNs)) ;
#     format long
#     for_test_with_Julia = Z_reconstructed0(inan)
#
#     Z_reconstructed3 = inpaint_nans(Z_with_NaNs, 3) ;
#     inan = find(isnan(Z_with_NaNs)) ;
#     format long
#     for_test_with_Julia = Z_reconstructed3(inan)
#     =#
#     #output from MATLAB (with added `[` and `]` to create an array in Julia):
#     for_test_with_Julia0 = [
#       -0.029498484825455
#       -0.026388649032511
#       -0.023224164811533
#       -0.019959714697592
#       -0.016570534539756
#       -0.013067274772867
#       -0.009515737748511
#       -0.006061284483498
#       -0.002954053931593
#       -0.000562233983451
#       -0.024738859622865
#       -0.021849554031150
#       -0.018886708512840
#       -0.015846133780332
#       -0.012745515609159
#       -0.009632984965416
#       -0.006596031513876
#       -0.003768591556022
#       -0.001332853175635
#        0.000486275908415
#       -0.020033882848309
#       -0.017374667993280
#       -0.014606428114350
#       -0.011757181715958
#       -0.008877257234395
#       -0.006043559300535
#       -0.003362033848600
#       -0.000966148114188
#        0.000989133038145
#        0.002331476799184
#       -0.015447533892928
#       -0.012992036440880
#       -0.010369686528229
#       -0.007632954622375
#       -0.004857137895978
#       -0.002143656346511
#        0.000379107679895
#        0.002560141558851
#        0.004236580202934
#        0.005247311276165
#       -0.011060562686287
#       -0.008755973865576
#       -0.006200733071729
#       -0.003462516608642
#       -0.000631555553168
#        0.002173486132572
#        0.004801671545321
#        0.007071916420969
#        0.008786181682142
#        0.009758475053551
#       -0.006974002641464
#       -0.004752793731375
#       -0.002171426761450
#        0.000700684972057
#        0.003775005310586
#        0.006932448068480
#        0.010012028603876
#        0.012803850132208
#        0.015056088124606
#        0.016513669823151
#       -0.003306656703570
#       -0.001102305535409
#        0.001590577322355
#        0.004720027170229
#        0.008225081189160
#        0.012017691152981
#        0.015960720685646
#        0.019843008634245
#        0.023362422101999
#        0.026151282842149
#       -0.000184793939314
#        0.002048303388213
#        0.004900640697375
#        0.008361573956673
#        0.012432323559789
#        0.017104013738851
#        0.022326545579092
#        0.027959080144713
#        0.033703122438236
#        0.039058183237819
#        0.022750875077404
#        0.002276664167332
#        0.004542189596323
#        0.007530709533852
#        0.011296841495850
#        0.015941569838531
#        0.021595958353736
#        0.028391819043663
#        0.036391951923893
#        0.045452985557788
#        0.054969855759669
#        0.004000278866272
#        0.006245896531532
#        0.009246891348237
#        0.013138306385561
#        0.018148210657288
#        0.024608390703909
#        0.032949462589523
#        0.043633483822409
#        0.056996977310186
#        0.072401999091913
#        0.065371006725438
#        1.129882922629364
#        1.988620826083542
#        3.303724922677607
#        3.009995700318911
#        2.522280335893179
#        1.935724677977175
#        1.335626062214603
#        0.786514582285719
#        0.329257265994138
#       -0.012311657560658
#       -0.219872146405397
#       -0.271552277631725
#       -0.141161352351552
#        0.193031222412800
#        0.733937769112330
#        1.452862117914674
#        2.285084082216744
#        3.137081028104408
#        3.903712648745315
#        4.489649932804268
#        4.827799745843459
#        4.888793767353252
#        4.679011144603867
#       -0.347745054253215
#        3.591122343685997
#        3.386431769732992
#        2.989300926148785
#        2.491065998125949
#        1.967669764377622
#        1.478074025887852
#        1.064190275208859
#        0.755382062315507
#        0.575505763016592
#        0.548067726710194
#        0.695792892311918
#        1.033891923622987
#        1.559825281387967
#        2.244540055312318
#        3.029924614704668
#        3.834745050730286
#        4.567802105281467
#        5.144058732563776
#        5.498221851097060
#        5.591050052762111
#        5.406096358679440
#       -0.936349385455035
#        3.605222930686874
#        3.517335900783082
#        3.238434122298406
#        2.855954919299696
#        2.438128155347086
#        2.038640173647655
#        1.698757563008107
#        1.450453032091489
#        1.320251698895966
#        1.331587825880717
#        1.503653343197570
#        1.846464367099045
#        2.354023174309642
#        2.998800289086334
#        3.730582290842233
#        4.481087430169427
#        5.173391472916311
#        5.733154387927366
#        6.097701028234379
#        6.219428978194833
#        6.061349487151569
#        3.341357929388249
#        3.401575746573586
#        3.271910711435003
#        3.032861610516547
#        2.745867386925606
#        2.460181939071189
#        2.215800804391726
#        2.045583984772825
#        1.977088264304427
#        2.033220296675575
#        2.230770425339385
#        2.576833101618545
#        3.064353679782952
#        3.668809993104651
#        4.347878437474010
#        5.044864254124493
#        5.695141212675974
#        6.233486881758082
#        6.599558704652425
#        6.739079041437797
#        6.599355170330182
#        2.841380838344105
#        3.073456166079014
#        3.117835543539121
#        3.043622374128044
#        2.905309952338734
#        2.748350998076220
#        2.611441878223756
#        2.527655274298543
#        2.524998203677983
#        2.626108194716650
#        2.846717602988466
#        3.193021104984742
#        3.658761902188411
#        4.223260384941719
#        4.851462918644687
#        5.496387500127723
#        6.103345823932464
#        6.614403076650654
#        6.971000687331017
#        7.112617051973382
#        6.969952192873624
#        6.455710135848094
#        2.189987011895347
#        2.601613306675576
#        2.830176991678914
#        2.929371693158437
#        2.945987309168736
#        2.921841403893273
#        2.894361950105836
#        2.896616319559052
#        2.956982539367739
#        3.098305237796421
#        3.336388427291948
#        3.677980326506684
#        4.118785337685906
#        4.642244485161791
#        5.219696188434319
#        5.812064622822803
#        6.372579171173087
#        6.849441367135294
#        7.187041793446022
#        7.324410700631058
#        7.189911243175136
#        1.499102206008667
#        2.077388586895414
#        2.480649448955863
#        2.744936031990387
#        2.908506629225304
#        3.009228703433169
#        3.083001636885966
#        3.162638262674267
#        3.276847250223310
#        3.449043317003553
#        3.695861784634070
#        4.025492679764202
#        4.436186506668263
#        4.915390513008766
#        5.439864987537813
#        5.976810042364554
#        6.485601875796809
#        6.919335844318305
#        7.225116240194605
#        7.341923924819143
#        7.194750301845644
#        5.671431293467855
#        0.884976745598062
#        1.596898607694587
#        2.145528754368911
#        2.549428323356424
#        2.837808701585293
#        3.043913463270044
#        3.201453776487057
#        3.342469255905483
#        3.495756563611108
#        3.685408445321751
#        3.929282174234797
#        4.237455450145543
#        4.610911349574935
#        5.040762116817356
#        5.508232517431887
#        5.985389442096245
#        6.436293972558468
#        6.817960282276927
#        7.080307178891673
#        7.164193256342912
#        6.996570380585938
#        0.444088620428157
#        1.241814847582343
#        1.891185699808595
#        2.395684939700155
#        2.775482579377672
#        3.058382230098587
#        3.274952160955224
#        3.455673493226433
#        3.628960314423669
#        3.819456857567038
#        4.046366814253769
#        4.321829435780246
#        4.649535475282198
#        5.023840615981928
#        5.429561704253726
#        5.842449022088037
#        6.230076247051698
#        6.552659960890115
#        6.763181050163189
#        6.806159870783462
#        6.614524945211913
#        0.234143026191824
#        1.063859732965861
#        1.762110299946653
#        2.321268475171566
#        2.753040279660386
#        3.079093031388457
#        3.325844012225440
#        3.521330696754089
#        3.693008503739355
#        3.865840121979854
#        4.060395549437099
#        4.290964061600172
#        4.563882881385299
#        4.876370906745426
#        5.216093759549064
#        5.561498942421485
#        5.882714719785381
#        6.142595115742952
#        6.297397705775117
#        6.296646212478618
#        6.081963803990073
#       -1.304113302100942
#        0.264864119862779
#        1.076767534905692
#        1.774265809474048
#        2.343112646917163
#        2.787626544439828
#        3.123004601683320
#        3.370727451872211
#        3.555626497313267
#        3.703693791323439
#        3.840036588436643
#        3.986682118643480
#        4.160251632071094
#        4.369784660342527
#        4.615119318391659
#        4.886173709300114
#        5.163249686938340
#        5.418184266253171
#        5.615930452864633
#        5.716069561318138
#        5.673903109796492
#        5.441147050863004
#        0.500333652721862
#        1.257203202530716
#        1.914959741995662
#        2.456713472452514
#        2.880827599256626
#        3.196218253087131
#        3.419070278721062
#        3.570536270531234
#        3.674846322700917
#        3.757268272879267
#        3.841591356006739
#        3.947190141471677
#        4.086100541045631
#        4.260738248358979
#        4.462819505382224
#        4.673731340154781
#        4.866178492601913
#        5.006592712913562
#        5.057688910784330
#        4.980774095119175
#        4.737944237149260
#        0.871317132785956
#        1.553561990059058
#        2.148519470287879
#        2.639408555952556
#        3.020287826420123
#        3.294544498578586
#        3.473185081860170
#        3.573522819462547
#        3.617946861824382
#        3.632124219155846
#        3.642188172961322
#        3.671009216682895
#        3.734223756720642
#        3.837018520427409
#        3.972574469877225
#        4.122600578288115
#        4.259745752323171
#        4.351151777011490
#        4.362241567613848
#        4.260135177997217
#        4.016808341160816
#        1.293398270865739
#        1.899455740342281
#        2.425447790453951
#        2.856109671892609
#        3.183005879423897
#        3.405214180617262
#        3.529016116126332
#        3.567878338476723
#        3.542344731244552
#        3.478834009327804
#        3.406616801634568
#        3.353091136842986
#        3.338392516317580
#        3.370892533942903
#        3.445003032596680
#        3.541973003387718
#        3.633374594962175
#        3.686159961794112
#        3.667883809165214
#        3.551069123415919
#        3.316664558966580
#        1.685519048949281
#        2.227541307184004
#        2.691800278815853
#        3.065171251558803
#        3.338693484603954
#        3.508577040151510
#        3.576871840363392
#        3.553065919655749
#        3.455666675448214
#        3.312047105069654
#        3.155349430381984
#        3.018564528651713
#        2.927319796961117
#        2.893701358602887
#        2.913230225978237
#        2.966013724717622
#        3.021614156201549
#        3.045966592750502
#        3.008230606101403
#        2.885938504463028
#        2.668055678350101
#        1.983687274849697
#        2.479169011918075
#        2.895395379835811
#        3.222088867593804
#        3.451629521473798
#        3.578581931945603
#        3.601031762927470
#        3.524104542910332
#        3.363713088576560
#        3.147842640850084
#        2.913547220732306
#        2.699762770641832
#        2.538059845382889
#        2.444573857034302
#        2.416046232820994
#        2.431362332110222
#        2.457920410509647
#        2.460515951035668
#        2.409821718940406
#        2.288130310799809
#        2.091506309587206
#        1.138103428467866
#     ]
#
#     inan = findall(@. isnan(Z_with_NaNs))
#     @test Z_inpainted_NaN[inan] ≈ for_test_with_Julia0
# end


text:
struct AsymptoticQuadraticTest{K<:MatrixKernel,V} <: CalibrationTest
    """Matrix-valued kernel."""
    kernel::K
    """Test statistic."""
    statistic::V
    """Samples of bootstrap statistic assuming strong calibration."""
    straps::Vector{V}
end

AsymptoticQuadraticTest(skce::QuadraticUnbiasedSKCE, data; kwargs...) =
    AsymptoticQuadraticTest(skce.kernel, data; kwargs...)

function AsymptoticQuadraticTest(kernel::MatrixKernel,
                                 data::Tuple{<:AbstractMatrix{<:Real},<:AbstractVector{<:Integer}};
                                 kwargs...)
    # check if the number of predictions and labels is equal
    predictions, labels = CalibrationErrors.get_predictions_labels(data)

    # compute statistic and bootstrap samples
    statistic, straps = _statistic_straps(kernel, predictions, labels; kwargs...)

    AsymptoticQuadraticTest(kernel, statistic, straps)
end

HypothesisTests.testname(::AsymptoticQuadraticTest) =
    "Asymptotic calibration test based on the quadratic unbiased SKCE estimator"

function HypothesisTests.pvalue(test::AsymptoticQuadraticTest)
    @unpack statistic, straps = test

    n = 0
    for strap in straps
        strap ≥ statistic && (n += 1)
    end

    n / length(straps)
end

function _statistic_straps(kernel::MatrixKernel,
                           predictions::AbstractMatrix{<:Real},
                           labels::AbstractVector{<:Integer};
                           nruns::Int = 1_000,
                           rng::AbstractRNG = Random.GLOBAL_RNG)
    nsamples = size(predictions, 2)

    # compute the test statistic and a constant term in the following computation
    statistic = zero(skce_result_type(QuadraticUnbiasedSKCE(kernel), predictions))
    constant = statistic
    for j in 1:nsamples
        # obtain jth data pair
        predictions_j = view(predictions, :, j)
        labels_j = labels[j]

        for i in 1:(j-1)
            val = skce_kernel(kernel, view(predictions, :, i), labels[i], predictions_j,
                        labels_j)
            statistic += val
            constant += 2 * val
        end

        # add diagonal terms to constant
        constant += skce_kernel(kernel, predictions_j, labels_j, predictions_j, labels_j)
    end

    # apply scaling
    statistic *= 2 * inv(nsamples - 1)
    invnsamples = inv(nsamples)
    oneminusinvnsamples = 1 - inv(nsamples)
    twoinvnsamples = 2 * invnsamples
    constant *= oneminusinvnsamples * invnsamples

    # initialize output array of bootstrap statistic
    straps = Vector{typeof(constant)}(undef, nruns)

    # create sampler and initialize array of resampled indices
    resampler = Random.Sampler(rng, Base.OneTo(nsamples))
    resampled_idxs = Vector{Int}(undef, nsamples)

    # for each bootstrap sample
    @inbounds for k in eachindex(straps)
        # resample data set
        rand!(rng, resampled_idxs, resampler)

        # evaluate bootstrap statistic
        s = zero(constant)
        @inbounds for j in 1:nsamples
            # obtain jth resampled data pair
            resampled_idxs_j = resampled_idxs[j]
            resampled_predictions_j = view(predictions, :, resampled_idxs_j)
            resampled_labels_j = labels[resampled_idxs_j]

            # evaluate combinations of bootstrapped samples
            @inbounds for i in 1:(j-1)
                # obtain ith resampled data pair
                resampled_idxs_i = resampled_idxs[i]
                s += skce_kernel(kernel, view(predictions, :, resampled_idxs_i),
                                 labels[resampled_idxs_i], resampled_predictions_j,
                                 resampled_labels_j)
            end

            # substract combinations of bootstrapped samples and original samples
            t = zero(s)
            @inbounds for i in 1:nsamples
                t += skce_kernel(kernel, view(predictions, :, i), labels[i],
                                 resampled_predictions_j, resampled_labels_j)
            end

            # subtract terms
            s -= oneminusinvnsamples * t
        end

        # combine result
        straps[k] = constant + twoinvnsamples * s
    end

    statistic, straps
end