// File: /workspace/github_cpp_makefile_star2_O1/myudelson[P]hmm-scalable/trainhmm.cpp
// Function: read_and_structure_data(char const*, _IO_FILE*)
bool read_and_structure_data(const char *filename, FILE *fid_console) {
    bool readok = true;
    if(param.binaryinput==0) {
        readok = InputUtil::readTxt(filename, &param);
    } else {
        readok = InputUtil::readBin(filename, &param);
    }
    if(! readok ) {
        return false;
    }
    
	//	2. distribute data into nK skill bins
	//		create
	//          skill_group_map[nK][nG] - explicit 'sparse' map of skills and groups, here 1 means done
	//			k_numg[nK]        - number of groups per skill                 RETAIN
	
	NDAT t = 0;
    NDAT t_stacked = 0;
	NCAT g, k;
//	NPAR o;
	NPAR **skill_group_map = init2D<NPAR>(param.nK, param.nG); // binary map of skills to groups
	param.k_numg = Calloc(NCAT, (size_t)param.nK);
	param.g_numk = Calloc(NCAT, (size_t)param.nG);
    NDAT *count_null_skill_group = Calloc(NDAT, (size_t)param.nG); // count null skill occurences per group
    NCAT *index_null_skill_group = Calloc(NCAT, (size_t)param.nG); // index of group in compressed array
    
	// Pass A
	for(t=0; t<param.N; t++) {
        if(param.multiskill==0)
            k = param.dat_skill[t];//[t];
        else
//            k = param.dat_multiskill->get(t)[1]; // #0 is count, #1 is first element
            k = param.dat_skill_stacked[ param.dat_skill_rix[t] ]; // first skill of multi-skill

        g = param.dat_group[t];//[t];
		// null skill : just count
		if( k < 0 ) {
            if(count_null_skill_group[g]==0) param.n_null_skill_group++;
            count_null_skill_group[g]++;
			continue;
		}
        NCAT *ar;
        int n;
        if(param.multiskill==0) {
            k = param.dat_skill[t];
            ar = &k;
            n = 1;
        } else {
//            ar = &param.dat_multiskill->get(t)[1];
//            n = param.dat_multiskill->get(t)[0];
            k = param.dat_skill_stacked[ param.dat_skill_rix[t] ];
            ar = &param.dat_skill_stacked[ param.dat_skill_rix[t] ];
            n = param.dat_skill_rcount[t];
        }
        for(int l=0; l<n; l++) {
            k = ar[l];
            if( skill_group_map[k][g] == 0 ) {
                skill_group_map[k][g] = 1;
                param.k_numg[k]++;
                param.g_numk[g]++;
            }
        }
	}
    for(k=0; k<param.nK; k++) param.nSeq += param.k_numg[k];
    param.all_data = Calloc(struct data, (size_t)param.nSeq);
    
	// Section B
	param.k_g_data = Malloc(struct data **, (size_t)param.nK);
	param.k_data = Malloc(struct data *, (size_t)param.nSeq);
    //	for(k=0; k<param.nK; k++)
    //		param.k_g_data[k] = Calloc(struct data*, param.k_numg[k]);
	param.g_k_data = Calloc(struct data **, (size_t)param.nG);
	param.g_data = Malloc(struct data *, (size_t)param.nSeq);
    //	for(g=0; g<param.nG; g++)
    //		param.g_k_data[g] = Calloc(struct data*, param.g_numk[g]);
	param.null_skills = Calloc(struct data, (size_t)param.n_null_skill_group);
    // index compressed array of null-skill-BY-group
    NCAT idx = 0;
	for(g=0; g<param.nG; g++)
        if( count_null_skill_group[g] >0 ) index_null_skill_group[g] = idx++;
    
	// Pass C
	NDAT *k_countg = Calloc(NDAT, (size_t)param.nK); // track current group in skill
	NDAT *g_countk = Calloc(NDAT, (size_t)param.nG); // track current skill in group
    // set k_countg and g_countk pointers to relative positions
    NDAT sumk=0, sumg=0;
    for(k=0; k<param.nK; k++) {
        k_countg[k] = sumk;
        param.k_g_data[k] = &param.k_data[sumk];
        sumk += param.k_numg[k];
    }
    for(g=0; g<param.nG; g++) {
        g_countk[g] = sumg;
        param.g_k_data[g] = &param.g_data[sumg];
        sumg += param.g_numk[g];
    }
    
    NDAT n_all_data = 0;
	for(t=0; t<param.N; t++) {
        NCAT *ar;
        int n;
        if(param.multiskill==0) {
            k = param.dat_skill[t];
            ar = &k;
            n = 1;
        } else {
//            ar = &param.dat_multiskill->get(t)[1];
//            n = param.dat_multiskill->get(t)[0];
            k = param.dat_skill_stacked[ param.dat_skill_rix[t] ];
            ar = &param.dat_skill_stacked[ param.dat_skill_rix[t] ];
            n = param.dat_skill_rcount[t];
        }
        for(int l=0; l<n; l++) {
            k = ar[l];
            g = param.dat_group[t];//[t];
            // now allocate space for the data
            if( k < 0 ) {
                NCAT gidx = index_null_skill_group[g];
                if( param.null_skills[gidx].ix != NULL) // was obs // check if we allocated it already
                    continue;
                param.null_skills[gidx].n = count_null_skill_group[g];
				param.null_skills[gidx].g = g;
				param.null_skills[gidx].k = -1;
                param.null_skills[gidx].cnt = 0;
                param.null_skills[gidx].t   = -1;
                //                param.null_skills[gidx].obs = Calloc(NPAR, count_null_skill_group[g]);
				param.null_skills[gidx].ix = Calloc(NDAT, (size_t)count_null_skill_group[g]);
				if(param.multiskill!=0)
					param.null_skills[gidx].ix_stacked = Calloc(NDAT, (size_t)count_null_skill_group[g]);
                // no time for null skills is necessary
//                if(param.time)
//                    param.null_skills[gidx].time = Calloc(int, (size_t)count_null_skill_group[g]);
                param.null_skills[gidx].alpha = NULL;
                param.null_skills[gidx].beta = NULL;
                param.null_skills[gidx].gamma = NULL;
				param.null_skills[gidx].xi = NULL;
                param.null_skills[gidx].c = NULL;
//                param.null_skills[gidx].time = NULL; // no longer used
                param.null_skills[gidx].p_O_param = 0.0;
                continue;
            }
            if( skill_group_map[k][g]==0) {
                fprintf(stderr, "ERROR! position [%d,%d] in skill_group_map should have been 1\n",k,g);
                if(param.duplicate_console==1) fprintf(fid_console,"ERROR! position [%d,%d] in skill_group_map should have been 1\n",k,g);
            } else if( skill_group_map[k][g]==1 ) { // insert new sequence and grab new data
                // link
                param.k_data[ k_countg[k] ] = &param.all_data[n_all_data]; // in linear array
                param.g_data[ g_countk[g] ] = &param.all_data[n_all_data]; // in linear array
                // param.k_g_data[k] and param.g_k_data[g] are already linked
                //                param.k_g_data[k][ k_countg[k] ] = Calloc(struct data, 1); // grab
                //                param.g_k_data[g][ g_countk[g] ] = param.k_g_data[k][ k_countg[k] ]; // relink
                //                param.k_g_data[k][ k_countg[k] ]->n = 1; // init data << VV
                //                param.k_g_data[k][ k_countg[k] ]->k = k; // init k
                //                param.k_g_data[k][ k_countg[k] ]->g = g; // init g
                //                param.k_g_data[k][ k_countg[k] ]->cnt = 0;
                //                param.k_g_data[k][ k_countg[k] ]->obs = NULL;
                //                param.k_g_data[k][ k_countg[k] ]->alpha = NULL;
                //                param.k_g_data[k][ k_countg[k] ]->beta = NULL;
                //                param.k_g_data[k][ k_countg[k] ]->gamma = NULL;
                //                param.k_g_data[k][ k_countg[k] ]->xi = NULL;
                //                param.k_g_data[k][ k_countg[k] ]->c = NULL;
                //                param.k_g_data[k][ k_countg[k] ]->p_O_param = 0.0;
                //                param.k_g_data[k][ k_countg[k] ]->loglik = 0.0;
                param.all_data[n_all_data].n = 1; // init data << VV
                param.all_data[n_all_data].k = k; // init k
                param.all_data[n_all_data].g = g; // init g
                param.all_data[n_all_data].cnt = 0;
                param.all_data[n_all_data].t   = -1;
                //                param.all_data[n_all_data].obs = NULL;
                param.all_data[n_all_data].ix = NULL;
                param.all_data[n_all_data].ix_stacked = NULL;
                param.all_data[n_all_data].alpha = NULL;
                param.all_data[n_all_data].beta = NULL;
                param.all_data[n_all_data].gamma = NULL;
                param.all_data[n_all_data].xi = NULL;
                param.all_data[n_all_data].c = NULL;
                param.all_data[n_all_data].p_O_param = 0.0;
                param.all_data[n_all_data].loglik = 0.0;
                k_countg[k]++; // count
                g_countk[g]++; // count
                skill_group_map[k][g] = 2; // mark
                n_all_data++;
            } else if( skill_group_map[k][g]== 2) { // update data count, LINEAR SEARCH :(
                int gidx;
                //                for(gidx=(k_countg[k]-(NCAT)1); gidx>=0 && param.k_g_data[k][gidx]->g!=g; gidx--)
                //                    ;
                for(gidx=(k_countg[k]-1); gidx>=0 && param.k_data[gidx]->g!=g; gidx--)
                    ;
                if( param.k_data[gidx]->g==g)
                    param.k_data[gidx]->n++;
                else {
                    fprintf(stderr, "ERROR! position of group %d in skill %d not found\n",g,k);
                    if(param.duplicate_console==1) fprintf(fid_console,"ERROR! position of group %d in skill %d not found\n",g,k);
                }
            }
        }
	}
	// recycle
	free(k_countg);
	free(g_countk);
    free(count_null_skill_group);
    
    //	3 fill data
    //		pass A
    //			fill k_g_data.data (g_k_data is already linked)
    //				using skill_group_map as marker, 3 - data grabbed
	k_countg = Calloc(NDAT, (size_t)param.nK); // track current group in skill
	g_countk = Calloc(NDAT, (size_t)param.nG); // track current skill in group
	for(t=0; t<param.N; t++) {
		g = param.dat_group[t];
//		o = param.dat_obs->get(t);
//        if(param.sliced)
//            tm = param.dat_slice[t];
        NCAT *ar;
        int n;
        if(param.multiskill==0) {
            k = param.dat_skill[t];
            ar = &k;
            n = 1;
        } else {
//            ar = &param.dat_multiskill->get(t)[1];
//            n = param.dat_multiskill->get(t)[0];
            k = param.dat_skill_stacked[ param.dat_skill_rix[t] ];
            ar = &param.dat_skill_stacked[ param.dat_skill_rix[t] ];
            n = param.dat_skill_rcount[t];
        }
        for(int l=0; l<n; l++) {
            k = ar[l];
            if( k < 0 ) {
                NCAT gidx = index_null_skill_group[g];
                //                param.null_skills[gidx].obs[ param.null_skills[gidx].cnt++ ] = o; // use .cnt as counter
				param.null_skills[gidx].ix[ param.null_skills[gidx].cnt++ ] = t; // use .cnt as counter
				if(param.multiskill!=0)
					param.null_skills[gidx].ix_stacked[ param.null_skills[gidx].cnt-1 ] = t_stacked; // use prior value version of cnt that was increased for ix
                continue;
            }
            if( skill_group_map[k][g]<2) {
                fprintf(stderr, "ERROR! position [%d,%d] in skill_group_map should have been 2\n",k,g);
                if(param.duplicate_console==1) fprintf(fid_console, "ERROR! position [%d,%d] in skill_group_map should have been 2\n",k,g);
            } else if( skill_group_map[k][g]==2 ) { // grab data and insert first dat point
//                param.k_g_data[k][ k_countg[k] ]->obs = Calloc(NPAR, (size_t)param.k_g_data[k][ k_countg[k] ]->n); // grab
//                param.k_g_data[k][ k_countg[k] ]->obs[0] = o; // insert
                param.k_g_data[k][ k_countg[k] ]->ix = Calloc(NDAT, (size_t)param.k_g_data[k][ k_countg[k] ]->n); // grab
                param.k_g_data[k][ k_countg[k] ]->ix[0] = t; // insert
                if(param.multiskill!=0) {
                    param.k_g_data[k][ k_countg[k] ]->ix_stacked = Calloc(NDAT, (size_t)param.k_g_data[k][ k_countg[k] ]->n); // grab
                    param.k_g_data[k][ k_countg[k] ]->ix_stacked[0] = t_stacked; // first stacked index
                }
                param.k_g_data[k][ k_countg[k] ]->cnt++; // increase data counter
                k_countg[k]++; // count unique groups forward
                g_countk[g]++; // count unique skills forward
                skill_group_map[k][g] = 3; // mark
            } else if( skill_group_map[k][g]== 3) { // insert next data point and inc counter, LINEAR SEARCH :(
                NCAT gidx;
                //			for(gidx=0; gidx < k_countg[k] && param.k_g_data[k][gidx]->g!=g; gidx++)
                for(gidx=(k_countg[k]-(NCAT)1); gidx>=0 && param.k_g_data[k][gidx]->g!=g; gidx--)
                    ; // skip
                if( param.k_g_data[k][gidx]->g==g ) {
                    NDAT pos = param.k_g_data[k][ gidx ]->cnt; // copy position
                    //                    param.k_g_data[k][ gidx ]->obs[pos] = o; // insert
                    param.k_g_data[k][ gidx ]->ix[pos] = t; // insert
                    if(param.multiskill!=0)
                        param.k_g_data[k][ gidx ]->ix_stacked[pos] = t_stacked; // insert
                    param.k_g_data[k][ gidx ]->cnt++; // increase data counter
                }
                else {
                    fprintf(stderr, "ERROR! position of group %d in skill %d not found\n",g,k);
                    if(param.duplicate_console==1) fprintf(fid_console, "ERROR! position of group %d in skill %d not found\n",g,k);
                }
            }
            t_stacked++;
        }// all skills on the row
    } // all t
	// recycle
	free(k_countg);
	free(g_countk);
    free(index_null_skill_group);
    // we delete linear column data in the end now
    //    if(param.cv_folds==0 && param.structure != STRUCTURE_SKILL_T) {
    //        if(param.multiskill==0) {
    //            delete param.dat_skill;//.clear();
    //            param.dat_skill = NULL;
    //        }
    //        else {
    //            delete param.dat_multiskill;
    //            param.dat_multiskill = NULL;
    //        }
    //        delete param.dat_group;
    //        delete param.dat_obs;
    //        delete param.dat_item;
    //        param.dat_group = NULL;
    //        param.dat_obs   = NULL;
    //        param.dat_item  = NULL;
    //    }
	free2D<NPAR>(skill_group_map, param.nK);
    // reset `cnt'
    for(g=0; g<param.nG; g++) // for all groups
        for(k=0; k<param.g_numk[g]; k++) // for all skills in it
            param.g_k_data[g][k]->cnt = 0;
    for(NCAT x=0; x<param.n_null_skill_group; x++)
        param.null_skills[x].cnt = 0;

    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rsi, 0x40(%rsp)
cmpl $0x0, 0x3dd13(%rip)     # 0x45310
je 0x760d
leaq 0x3dca2(%rip), %rsi     # 0x452a8
callq 0x12694
jmp 0x7619
leaq 0x3dc94(%rip), %rsi     # 0x452a8
callq 0x11532
testb %al, %al
je 0x7ff8
movb %al, 0xf(%rsp)
movl 0x3e53d(%rip), %edi     # 0x45b68
movl 0x3e533(%rip), %esi     # 0x45b64
callq 0x9bd5
movq %rax, %r14
movslq 0x3e528(%rip), %rdi     # 0x45b68
movl $0x4, %esi
callq 0x4140
movq %rax, 0x3e537(%rip)     # 0x45b88
movslq 0x3e50c(%rip), %rbx     # 0x45b64
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x3e53c(%rip)     # 0x45ba8
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, %r15
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %r14, %r11
movq %rax, 0x50(%rsp)
cmpl $0x0, 0x3e4c0(%rip)     # 0x45b58
jle 0x7799
xorl %eax, %eax
leaq 0x8(%rsp), %rcx
movb 0x3e514(%rip), %sil     # 0x45bc0
testb %sil, %sil
je 0x76c9
movq 0x3e488(%rip), %rdx     # 0x45b40
movslq (%rdx,%rax,4), %rdx
shlq $0x2, %rdx
addq 0x3e469(%rip), %rdx     # 0x45b30
jmp 0x76d8
leaq (,%rax,4), %rdx
addq 0x3e450(%rip), %rdx     # 0x45b28
movl (%rdx), %edi
movl %edi, 0x8(%rsp)
movq 0x3e43b(%rip), %rdx     # 0x45b20
movslq (%rdx,%rax,4), %rdx
testl %edi, %edi
js 0x771a
testb %sil, %sil
je 0x7730
movq 0x3e437(%rip), %rsi     # 0x45b30
movq 0x3e440(%rip), %rdi     # 0x45b40
movslq (%rdi,%rax,4), %rdi
leaq (%rsi,%rdi,4), %rsi
movl (%rsi), %edi
movl %edi, 0x8(%rsp)
movq 0x3e423(%rip), %rdi     # 0x45b38
movl (%rdi,%rax,4), %edi
jmp 0x7746
movl (%r15,%rdx,4), %esi
testl %esi, %esi
jne 0x7728
incl 0x3e458(%rip)           # 0x45b80
incl %esi
movl %esi, (%r15,%rdx,4)
jmp 0x7786
movq 0x3e3f1(%rip), %rsi     # 0x45b28
movl (%rsi,%rax,4), %esi
movl %esi, 0x8(%rsp)
movl $0x1, %edi
movq %rcx, %rsi
testl %edi, %edi
jle 0x7786
movl %edi, %edi
xorl %r8d, %r8d
movslq (%rsi,%r8,4), %r9
movl %r9d, 0x8(%rsp)
movq (%r11,%r9,8), %r10
cmpb $0x0, (%r10,%rdx)
jne 0x777e
movb $0x1, (%r10,%rdx)
movq 0x3e419(%rip), %r10     # 0x45b88
incl (%r10,%r9,4)
movq 0x3e42e(%rip), %r9      # 0x45ba8
incl (%r9,%rdx,4)
incq %r8
cmpq %r8, %rdi
jne 0x774f
incq %rax
movslq 0x3e3c8(%rip), %rdx     # 0x45b58
cmpq %rdx, %rax
jl 0x76a5
movslq 0x3e3c8(%rip), %r14     # 0x45b68
testq %r14, %r14
movq %r11, 0x18(%rsp)
jle 0x77cc
movl 0x3e3d4(%rip), %ecx     # 0x45b84
movq 0x3e3d1(%rip), %rdx     # 0x45b88
xorl %eax, %eax
addl (%rdx,%rax,4), %ecx
movl %ecx, 0x3e3c2(%rip)     # 0x45b84
incq %rax
cmpq %rax, %r14
jne 0x77b9
jmp 0x77ce
xorl %eax, %eax
movl %eax, 0x8(%rsp)
movslq 0x3e3ab(%rip), %rbx     # 0x45b84
movl $0x60, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x3e3a3(%rip)     # 0x45b90
leaq (,%r14,8), %rdi
callq 0x4330
movq %rax, 0x3e39f(%rip)     # 0x45ba0
shlq $0x3, %rbx
movq %rbx, %rdi
callq 0x4330
movq %rax, 0x3e384(%rip)     # 0x45b98
movslq 0x3e349(%rip), %r13     # 0x45b64
movl $0x8, %esi
movq %r13, %rdi
callq 0x4140
movq %rax, 0x3e389(%rip)     # 0x45bb8
movq %rbx, %rdi
callq 0x4330
movq %rax, 0x3e372(%rip)     # 0x45bb0
movslq 0x3e33b(%rip), %rdi     # 0x45b80
movl $0x60, %esi
callq 0x4140
movq %rax, 0x3e322(%rip)     # 0x45b78
testq %r13, %r13
jle 0x7878
xorl %eax, %eax
xorl %ecx, %ecx
movq 0x50(%rsp), %rdx
cmpl $0x0, (%r15,%rax,4)
jle 0x7870
movl %ecx, (%rdx,%rax,4)
incl %ecx
incq %rax
cmpq %rax, %r13
jne 0x7864
movl $0x4, %esi
movq %r14, %rdi
callq 0x4140
movq %rax, 0x20(%rsp)
movl $0x4, %esi
movq %r13, %rdi
callq 0x4140
testl %r14d, %r14d
movq %r15, 0x48(%rsp)
jle 0x78e6
xorl %r9d, %r9d
xorl %ecx, %ecx
movq 0x18(%rsp), %r8
movq 0x20(%rsp), %rdi
movl %ecx, (%rdi,%r9,4)
movslq %ecx, %rcx
leaq (,%rcx,8), %rdx
addq 0x3e2d2(%rip), %rdx     # 0x45b98
movq 0x3e2d3(%rip), %rsi     # 0x45ba0
movq %rdx, (%rsi,%r9,8)
movq 0x3e2b0(%rip), %rdx     # 0x45b88
addl (%rdx,%r9,4), %ecx
incq %r9
cmpq %r9, %r14
jne 0x78b0
jmp 0x78f3
xorl %r9d, %r9d
movq 0x18(%rsp), %r8
movq 0x20(%rsp), %rdi
movl %r9d, 0x8(%rsp)
testl %r13d, %r13d
jle 0x7936
xorl %r9d, %r9d
xorl %ecx, %ecx
movl %ecx, (%rax,%r9,4)
movslq %ecx, %rcx
leaq (,%rcx,8), %rdx
addq 0x3e298(%rip), %rdx     # 0x45bb0
movq 0x3e299(%rip), %rsi     # 0x45bb8
movq %rdx, (%rsi,%r9,8)
movq 0x3e27e(%rip), %rdx     # 0x45ba8
addl (%rdx,%r9,4), %ecx
incq %r9
cmpq %r9, %r13
jne 0x7902
movq %rax, 0x30(%rsp)
cmpl $0x0, 0x3e216(%rip)     # 0x45b58
jle 0x7c66
xorps %xmm0, %xmm0
xorl %r10d, %r10d
xorl %r11d, %r11d
cmpb $0x0, 0x3e268(%rip)     # 0x45bc0
je 0x7984
movq 0x3e1cf(%rip), %rax     # 0x45b30
movq 0x3e1d8(%rip), %rcx     # 0x45b40
movslq (%rcx,%r10,4), %rcx
leaq (%rax,%rcx,4), %r15
movl (%r15), %eax
movl %eax, 0x8(%rsp)
movq 0x3e1ba(%rip), %rax     # 0x45b38
movl (%rax,%r10,4), %eax
jmp 0x799d
movq 0x3e19d(%rip), %rax     # 0x45b28
movl (%rax,%r10,4), %eax
movl %eax, 0x8(%rsp)
movl $0x1, %eax
leaq 0x8(%rsp), %r15
testl %eax, %eax
jle 0x7c53
movl %eax, %ebp
xorl %ebx, %ebx
movq %r10, 0x38(%rsp)
movq %rbp, 0x28(%rsp)
movslq (%r15,%rbx,4), %r14
movl %r14d, 0x8(%rsp)
movq 0x3e15d(%rip), %rax     # 0x45b20
movl (%rax,%r10,4), %r13d
movslq %r13d, %rax
testq %r14, %r14
js 0x7a3d
movq (%r8,%r14,8), %rcx
movzbl (%rcx,%rax), %ecx
cmpl $0x1, %ecx
je 0x7af9
cmpl $0x2, %ecx
je 0x7b95
testl %ecx, %ecx
jne 0x7bde
movq %r15, 0x10(%rsp)
movq %r10, %rbp
movq %r11, %r12
movq 0x3d5d5(%rip), %rax     # 0x44fd8
movq (%rax), %rdi
leaq 0x301c8(%rip), %r15     # 0x37bd5
movq %r15, %rsi
movl %r14d, %edx
movl %r13d, %ecx
xorl %eax, %eax
callq 0x4360
cmpb $0x1, 0x3d8b8(%rip)     # 0x452dc
jne 0x7c36
movq 0x40(%rsp), %rdi
movq %r15, %rsi
movl %r14d, %edx
movl %r13d, %ecx
jmp 0x7c2f
movq %r15, %r12
movq 0x50(%rsp), %rcx
movslq (%rcx,%rax,4), %rcx
movq 0x3e128(%rip), %rbp     # 0x45b78
leaq (%rcx,%rcx,2), %r15
shlq $0x5, %r15
cmpq $0x0, 0x10(%rbp,%r15)
jne 0x7aec
movq %r11, 0x10(%rsp)
leaq (%r15,%rbp), %rcx
movq 0x48(%rsp), %rdx
movslq (%rdx,%rax,4), %r14
movl %r14d, (%rcx)
movl %r13d, 0x5c(%rbp,%r15)
movl $0xffffffff, 0x58(%rbp,%r15) # imm = 0xFFFFFFFF
movabsq $-0x100000000, %rax     # imm = 0xFFFFFFFF00000000
movq %rax, 0x4(%rbp,%r15)
movl $0x4, %esi
movq %r14, %rdi
callq 0x4140
movq %rax, 0x10(%rbp,%r15)
cmpb $0x0, 0x3e111(%rip)     # 0x45bc0
je 0x7ac3
movl $0x4, %esi
movq %r14, %rdi
callq 0x4140
movq %rax, 0x18(%rbp,%r15)
xorps %xmm0, %xmm0
movups %xmm0, 0x40(%rbp,%r15)
movups %xmm0, 0x30(%rbp,%r15)
movups %xmm0, 0x20(%rbp,%r15)
movq 0x18(%rsp), %r8
movq 0x20(%rsp), %rdi
movq 0x10(%rsp), %r11
movq 0x38(%rsp), %r10
movq %r12, %r15
movq 0x28(%rsp), %rbp
jmp 0x7bde
movslq %r11d, %r11
movq %r11, %rcx
shlq $0x5, %rcx
leaq (%rcx,%rcx,2), %rcx
movq 0x3e082(%rip), %rdx     # 0x45b90
addq %rcx, %rdx
movq 0x3e080(%rip), %rsi     # 0x45b98
movslq (%rdi,%r14,4), %r9
movq %rdx, (%rsi,%r9,8)
movq 0x3e069(%rip), %rdx     # 0x45b90
addq %rcx, %rdx
movq 0x3e07f(%rip), %rsi     # 0x45bb0
movq 0x30(%rsp), %r12
movslq (%r12,%rax,4), %r9
movq %rdx, (%rsi,%r9,8)
movq 0x3e04b(%rip), %rdx     # 0x45b90
movq $0x1, (%rdx,%rcx)
movl %r14d, 0x58(%rdx,%rcx)
movl %r13d, 0x5c(%rdx,%rcx)
movl $0xffffffff, 0x8(%rdx,%rcx) # imm = 0xFFFFFFFF
movups %xmm0, 0x10(%rdx,%rcx)
movups %xmm0, 0x20(%rdx,%rcx)
movups %xmm0, 0x30(%rdx,%rcx)
movups %xmm0, 0x40(%rdx,%rcx)
movq $0x0, 0x50(%rdx,%rcx)
incl (%rdi,%r14,4)
leal 0x1(%r9), %ecx
movl %ecx, (%r12,%rax,4)
movq (%r8,%r14,8), %rcx
movb $0x2, (%rcx,%rax)
incl %r11d
jmp 0x7bde
movl (%rdi,%r14,4), %eax
movq 0x3dff8(%rip), %rdx     # 0x45b98
movl %eax, %ecx
sarl $0x1f, %ecx
andl %eax, %ecx
decl %ecx
movq %rax, %rsi
decq %rsi
testl %eax, %eax
jle 0x7bc7
movl %esi, %r9d
movq (%rdx,%r9,8), %r9
decl %eax
decq %rsi
cmpl %r13d, 0x5c(%r9)
jne 0x7baf
jmp 0x7bc9
movl %ecx, %eax
movq 0x3dfc8(%rip), %rcx     # 0x45b98
cltq
movq (%rcx,%rax,8), %rax
cmpl %r13d, 0x5c(%rax)
jne 0x7bec
incl (%rax)
incq %rbx
cmpq %rbp, %rbx
jne 0x79b3
jmp 0x7c53
movq %r15, 0x10(%rsp)
movq %r10, %rbp
movq %r11, %r12
movq 0x3d3da(%rip), %rax     # 0x44fd8
movq (%rax), %rdi
leaq 0x3000c(%rip), %r15     # 0x37c14
movq %r15, %rsi
movl %r13d, %edx
movl %r14d, %ecx
xorl %eax, %eax
callq 0x4360
cmpb $0x1, 0x3d6bd(%rip)     # 0x452dc
jne 0x7c36
movq 0x40(%rsp), %rdi
movq %r15, %rsi
movl %r13d, %edx
movl %r14d, %ecx
xorl %eax, %eax
callq 0x4360
movq 0x18(%rsp), %r8
movq 0x20(%rsp), %rdi
xorps %xmm0, %xmm0
movq %r12, %r11
movq %rbp, %r10
movq 0x10(%rsp), %r15
jmp 0x7aef
incq %r10
movslq 0x3defb(%rip), %rax     # 0x45b58
cmpq %rax, %r10
jl 0x7951
callq 0x42d0
movq 0x30(%rsp), %rdi
callq 0x42d0
movq 0x48(%rsp), %rdi
callq 0x42d0
movslq 0x3dee2(%rip), %rdi     # 0x45b68
movl $0x4, %esi
callq 0x4140
movq %rax, %r13
movslq 0x3deca(%rip), %rdi     # 0x45b64
movl $0x4, %esi
callq 0x4140
movq 0x18(%rsp), %rbx
movq %rax, 0x20(%rsp)
cmpl $0x0, 0x3dea3(%rip)     # 0x45b58
jle 0x7f41
xorl %r9d, %r9d
xorl %r15d, %r15d
movq %r13, 0x48(%rsp)
cmpb $0x0, 0x3def3(%rip)     # 0x45bc0
je 0x7cf9
movq 0x3de5a(%rip), %rax     # 0x45b30
movq 0x3de63(%rip), %rcx     # 0x45b40
movslq (%rcx,%r9,4), %rcx
leaq (%rax,%rcx,4), %r10
movl (%r10), %eax
movl %eax, 0x8(%rsp)
movq 0x3de45(%rip), %rax     # 0x45b38
movl (%rax,%r9,4), %eax
jmp 0x7d12
movq 0x3de28(%rip), %rax     # 0x45b28
movl (%rax,%r9,4), %eax
movl %eax, 0x8(%rsp)
movl $0x1, %eax
leaq 0x8(%rsp), %r10
testl %eax, %eax
jle 0x7f2e
movq 0x3ddff(%rip), %rcx     # 0x45b20
movslq (%rcx,%r9,4), %rbp
movl %eax, %r11d
xorl %r12d, %r12d
movq %r9, 0x10(%rsp)
movq %r10, 0x30(%rsp)
movq %r11, 0x38(%rsp)
movslq (%r10,%r12,4), %r14
movl %r14d, 0x8(%rsp)
testq %r14, %r14
js 0x7e2c
movq (%rbx,%r14,8), %rax
movzbl (%rax,%rbp), %eax
cmpb $0x1, %al
jle 0x7eeb
cmpl $0x3, %eax
je 0x7e7b
cmpl $0x2, %eax
jne 0x7f1f
movl %r15d, 0x28(%rsp)
movq 0x3de26(%rip), %r15     # 0x45ba0
movq (%r15,%r14,8), %rax
movslq (%r13,%r14,4), %rcx
movq (%rax,%rcx,8), %rax
movslq (%rax), %rdi
movl $0x4, %esi
callq 0x4140
movq 0x10(%rsp), %r9
movq (%r15,%r14,8), %rcx
movslq (%r13,%r14,4), %rbx
movq (%rcx,%rbx,8), %rcx
movq %rax, 0x10(%rcx)
movq (%r15,%r14,8), %rax
movq (%rax,%rbx,8), %r13
movq 0x10(%r13), %rax
movl %r9d, (%rax)
cmpb $0x0, 0x3de00(%rip)     # 0x45bc0
je 0x7deb
movslq (%r13), %rdi
movl $0x4, %esi
callq 0x4140
movq 0x10(%rsp), %r9
movq %rax, 0x18(%r13)
movq (%r15,%r14,8), %rax
movq (%rax,%rbx,8), %rax
movq 0x18(%rax), %rax
movl 0x28(%rsp), %ecx
movl %ecx, (%rax)
movq (%r15,%r14,8), %rax
movq (%rax,%rbx,8), %rax
incl 0x4(%rax)
movq 0x20(%rsp), %rax
incl (%rax,%rbp,4)
leal 0x1(%rbx), %eax
movq 0x48(%rsp), %r13
movl %eax, (%r13,%r14,4)
movq 0x18(%rsp), %rbx
movq (%rbx,%r14,8), %rax
movb $0x3, (%rax,%rbp)
movl 0x28(%rsp), %r15d
movq 0x30(%rsp), %r10
movq 0x38(%rsp), %r11
jmp 0x7f1f
movq 0x50(%rsp), %rax
movslq (%rax,%rbp,4), %rcx
movq 0x3dd3c(%rip), %rax     # 0x45b78
leaq (%rcx,%rcx,2), %rcx
shlq $0x5, %rcx
movq 0x10(%rax,%rcx), %rdx
movslq 0x4(%rax,%rcx), %rsi
leal 0x1(%rsi), %edi
movl %edi, 0x4(%rax,%rcx)
movl %r9d, (%rdx,%rsi,4)
cmpb $0x0, 0x3dd60(%rip)     # 0x45bc0
je 0x7f22
addq %rcx, %rax
movq 0x18(%rax), %rcx
movslq 0x4(%rax), %rax
movl %r15d, -0x4(%rcx,%rax,4)
jmp 0x7f22
movl (%r13,%r14,4), %eax
movq 0x3dd19(%rip), %rdx     # 0x45ba0
movl %eax, %ecx
sarl $0x1f, %ecx
andl %eax, %ecx
decl %ecx
movq %rax, %rsi
decq %rsi
testl %eax, %eax
jle 0x7eb1
movq (%rdx,%r14,8), %rdi
movl %esi, %r8d
movq (%rdi,%r8,8), %rdi
decl %eax
decq %rsi
cmpl %ebp, 0x5c(%rdi)
jne 0x7e96
jmp 0x7eb3
movl %ecx, %eax
movq 0x3dce6(%rip), %rcx     # 0x45ba0
movq (%rcx,%r14,8), %rcx
cltq
movq (%rcx,%rax,8), %rax
cmpl %ebp, 0x5c(%rax)
jne 0x7efc
movslq 0x4(%rax), %rcx
movq 0x10(%rax), %rdx
movl %r9d, (%rdx,%rcx,4)
cmpb $0x0, 0x3dce4(%rip)     # 0x45bc0
je 0x7ee6
movq 0x18(%rax), %rdx
movl %r15d, (%rdx,%rcx,4)
incl 0x4(%rax)
jmp 0x7f1f
movl %r14d, %edi
movl %ebp, %esi
movq 0x40(%rsp), %rdx
callq 0x4a8c
jmp 0x7f0b
movl %ebp, %edi
movl %r14d, %esi
movq 0x40(%rsp), %rdx
callq 0x4a3e
movq 0x38(%rsp), %r11
movq 0x30(%rsp), %r10
movq 0x10(%rsp), %r9
movq 0x18(%rsp), %rbx
incl %r15d
incq %r12
cmpq %r11, %r12
jne 0x7d3a
incq %r9
movslq 0x3dc20(%rip), %rax     # 0x45b58
cmpq %rax, %r9
jl 0x7cc6
movq %r13, %rdi
callq 0x42d0
movq 0x20(%rsp), %rdi
callq 0x42d0
movq 0x50(%rsp), %rdi
callq 0x42d0
movl 0x3dc05(%rip), %esi     # 0x45b68
movq %rbx, %rdi
callq 0x9c28
movslq 0x3dbf2(%rip), %r10     # 0x45b64
testq %r10, %r10
jle 0x7fbe
movq 0x3dc2a(%rip), %rcx     # 0x45ba8
movq 0x3dc33(%rip), %rdx     # 0x45bb8
xorl %esi, %esi
movb 0xf(%rsp), %al
cmpl $0x0, (%rcx,%rsi,4)
movl $0x0, %edi
jle 0x7fb4
movq (%rdx,%rsi,8), %r8
xorl %edi, %edi
movq (%r8,%rdi,8), %r9
movl $0x0, 0x4(%r9)
incq %rdi
movslq (%rcx,%rsi,4), %r9
cmpq %r9, %rdi
jl 0x7f9c
incq %rsi
cmpq %r10, %rsi
jne 0x7f8b
jmp 0x7fc6
movl 0x8(%rsp), %edi
movb 0xf(%rsp), %al
movl %edi, 0x8(%rsp)
movslq 0x3dbaf(%rip), %rcx     # 0x45b80
testq %rcx, %rcx
jle 0x7ff8
movq 0x3db9b(%rip), %rsi     # 0x45b78
shlq $0x5, %rcx
leaq (%rcx,%rcx,2), %rcx
xorl %edx, %edx
movl $0x0, 0x4(%rsi,%rdx)
addq $0x60, %rdx
cmpq %rdx, %rcx
jne 0x7fe7
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq