123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687openCoreopenAsynctypet=|RaggedofintlistInt.Map.toption|Rectangular[@@derivingsexp]letcreate_verbosecsv=letrectangular=matchList.transposecsvwith|None->false|Some(_:stringlistlist)->trueinmatchrectangularwith|true->Rectangular|false->List.mapicsv~f:(funirow->List.lengthrow,i+1)|>Int.Map.of_alist_multi|>Some|>Ragged;;letis_rectangularcsv=letrow_length=ref(-1)inPipe.fold_without_pushbackcsv~init:true~f:(funaccumrow->match!row_lengthwith(* Initialize to the length of the header row *)|-1->row_length:=Delimited.Read.Row.lengthrow;accum|row_length->ifDelimited.Read.Row.lengthrow=row_lengththenaccumelse(Pipe.close_readcsv;false));;letcreate_streaming?sepreader=letcsv=Delimited.Read.pipe_of_reader?sepDelimited.Read.Row.builderreaderinmatch%bindis_rectangularcsvwith|true->returnRectangular|false->return(RaggedNone);;typeclump=|Oneofint|Spanofint*intletstring_of_clump=function|Onei->Int.to_stringi|Span(lo,hi)->Int.to_stringlo^"-"^Int.to_stringhi;;letstring_of_clumpsclumps=String.concat~sep:","(List.map~f:string_of_clumpclumps)letto_clumpsns=List.sort~compare:Int.comparens|>List.group~break:(funab->a+1<>b)|>List.map~f:(function|[]->assertfalse|[i]->Onei|x::xs->Span(x,List.last_exnxs));;letto_error_stringt=matchtwith|Rectangular->Ok()|RaggedNone->Error[[""]]|Ragged(Somerow_indexes_by_length)->letcsv=letrows=row_indexes_by_length|>Map.to_alist|>List.map~f:(fun(n,rows_with_n_cols)->n,List.lengthrows_with_n_cols,to_clumpsrows_with_n_cols)|>List.sort~compare:(funab->letsize(_,n,_)=nin-Int.compare(sizea)(sizeb))|>List.map~f:(fun(a,b,clumps)->[Int.to_stringa;Int.to_stringb;string_of_clumpsclumps])in["N";"number of lines with N columns";"lines with N columns"]::rowsinErrorcsv;;