// File: /workspace/github_cpp_makefile_star2_O3/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, 0x3ddb6(%rip)     # 0x45310
je 0x756a
leaq 0x3dd45(%rip), %rsi     # 0x452a8
callq 0x12734
jmp 0x7576
leaq 0x3dd37(%rip), %rsi     # 0x452a8
callq 0x1177a
testb %al, %al
je 0x76f8
movl 0x3e5e4(%rip), %edi     # 0x45b68
movl 0x3e5da(%rip), %esi     # 0x45b64
callq 0x9d07
movq %rax, 0x10(%rsp)
movl 0x3e5cd(%rip), %r12d    # 0x45b68
movslq %r12d, %rdi
movl $0x4, %esi
callq 0x4140
movq %rax, %r13
movq %rax, 0x3e5d6(%rip)     # 0x45b88
movslq 0x3e5ab(%rip), %rbx     # 0x45b64
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x3e5db(%rip)     # 0x45ba8
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, %r15
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x50(%rsp)
movl 0x3e563(%rip), %ebp     # 0x45b58
testl %ebp, %ebp
jle 0x76ff
xorl %eax, %eax
leaq 0xc(%rsp), %rcx
movq 0x10(%rsp), %r11
cmpb $0x0, 0x3e5b0(%rip)     # 0x45bc0
je 0x7656
movq 0x3e517(%rip), %rdx     # 0x45b30
movq 0x3e520(%rip), %rsi     # 0x45b40
movslq (%rsi,%rax,4), %r8
movl (%rdx,%r8,4), %edi
movl %edi, 0xc(%rsp)
movq 0x3e4ed(%rip), %rsi     # 0x45b20
movl (%rsi,%rax,4), %esi
testl %edi, %edi
js 0x76c5
movq 0x3e4f3(%rip), %rdi     # 0x45b38
movl (%rdi,%rax,4), %edi
testl %edi, %edi
jle 0x76dc
leaq (%rdx,%r8,4), %rdx
jmp 0x767d
movq 0x3e4cb(%rip), %rdx     # 0x45b28
movl (%rdx,%rax,4), %r8d
movl %r8d, 0xc(%rsp)
movq 0x3e4b3(%rip), %rdx     # 0x45b20
movl (%rdx,%rax,4), %esi
movl $0x1, %edi
movq %rcx, %rdx
testl %r8d, %r8d
js 0x76c5
movslq %esi, %rsi
movl %edi, %edi
xorl %r8d, %r8d
movslq (%rdx,%r8,4), %r9
movl %r9d, 0xc(%rsp)
movq (%r11,%r9,8), %r10
cmpb $0x0, (%r10,%rsi)
jne 0x76b5
movb $0x1, (%r10,%rsi)
movq 0x3e4e3(%rip), %r13     # 0x45b88
incl (%r13,%r9,4)
movq 0x3e4f7(%rip), %r9      # 0x45ba8
incl (%r9,%rsi,4)
incq %r8
cmpq %r8, %rdi
jne 0x7685
movl 0x3e495(%rip), %ebp     # 0x45b58
jmp 0x76dc
movslq %esi, %rdx
movl (%r15,%rdx,4), %esi
testl %esi, %esi
jne 0x76d6
incl 0x3e4aa(%rip)           # 0x45b80
incl %esi
movl %esi, (%r15,%rdx,4)
incq %rax
movslq %ebp, %rdx
cmpq %rdx, %rax
jl 0x7609
movl %ebp, 0x30(%rsp)
movl 0x3e472(%rip), %r12d    # 0x45b68
jmp 0x7703
xorl %eax, %eax
jmp 0x8010
movl %ebp, 0x30(%rsp)
movl 0x3e47b(%rip), %eax     # 0x45b84
movl %r12d, %r14d
testl %r12d, %r12d
jle 0x772b
xorl %ecx, %ecx
addl (%r13,%rcx,4), %eax
movl %eax, 0x3e466(%rip)     # 0x45b84
incq %rcx
cmpq %rcx, %r14
jne 0x7713
movl %r12d, %ecx
jmp 0x772d
xorl %ecx, %ecx
movl %r12d, %ebx
movl %ecx, 0xc(%rsp)
movslq %eax, %r12
movl $0x60, %esi
movq %r12, %rdi
callq 0x4140
movq %rax, 0x3e445(%rip)     # 0x45b90
movl %ebx, %r13d
movslq %ebx, %rax
movq %rax, %rbp
leaq (,%rax,8), %rdi
callq 0x4330
movq %rax, 0x3e438(%rip)     # 0x45ba0
shlq $0x3, %r12
movq %r12, %rdi
callq 0x4330
movq %rax, 0x3e41d(%rip)     # 0x45b98
movslq 0x3e3e2(%rip), %rbx     # 0x45b64
movl $0x8, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x3e422(%rip)     # 0x45bb8
movq %r12, %rdi
callq 0x4330
movq %rax, 0x3e40b(%rip)     # 0x45bb0
movslq 0x3e3d4(%rip), %rdi     # 0x45b80
movl $0x60, %esi
callq 0x4140
movq %rax, 0x3e3bb(%rip)     # 0x45b78
testq %rbx, %rbx
jle 0x77df
xorl %eax, %eax
xorl %ecx, %ecx
movq 0x50(%rsp), %rdx
cmpl $0x0, (%r15,%rax,4)
jle 0x77d7
movl %ecx, (%rdx,%rax,4)
incl %ecx
incq %rax
cmpq %rax, %rbx
jne 0x77cb
movl $0x4, %esi
movq %rbp, %rdi
callq 0x4140
movq %rax, %r12
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %r12, %rdi
movq %rax, %r11
movl %r13d, %r12d
testl %r13d, %r13d
jle 0x7840
xorl %eax, %eax
xorl %ecx, %ecx
movl %ecx, (%rdi,%rax,4)
movslq %ecx, %rcx
leaq (,%rcx,8), %rdx
addq 0x3e375(%rip), %rdx     # 0x45b98
movq 0x3e376(%rip), %rsi     # 0x45ba0
movq %rdx, (%rsi,%rax,8)
movq 0x3e353(%rip), %rdx     # 0x45b88
addl (%rdx,%rax,4), %ecx
incq %rax
cmpq %rax, %r14
jne 0x780e
movq %r15, 0x48(%rsp)
testl %ebx, %ebx
movq 0x10(%rsp), %r9
jle 0x7885
xorl %eax, %eax
xorl %ecx, %ecx
movl %ecx, (%r11,%rax,4)
movslq %ecx, %rcx
leaq (,%rcx,8), %rdx
addq 0x3e348(%rip), %rdx     # 0x45bb0
movq 0x3e349(%rip), %rsi     # 0x45bb8
movq %rdx, (%rsi,%rax,8)
movq 0x3e32e(%rip), %rdx     # 0x45ba8
addl (%rdx,%rax,4), %ecx
incq %rax
cmpq %rax, %rbx
jne 0x7852
movl 0x30(%rsp), %r14d
testl %r14d, %r14d
movq %r11, 0x28(%rsp)
jle 0x7bbf
pxor %xmm0, %xmm0
xorl %r15d, %r15d
movq $0x0, 0x38(%rsp)
movq %rdi, 0x20(%rsp)
cmpb $0x0, 0x3e30c(%rip)     # 0x45bc0
je 0x78e8
movq 0x3e273(%rip), %rcx     # 0x45b30
movq 0x3e27c(%rip), %rax     # 0x45b40
movslq (%rax,%r15,4), %rdx
movq 0x3e269(%rip), %rax     # 0x45b38
movl (%rax,%r15,4), %eax
movl (%rcx,%rdx,4), %esi
movl %esi, 0xc(%rsp)
testl %eax, %eax
jle 0x7b9f
leaq (%rcx,%rdx,4), %r10
jmp 0x7901
movq 0x3e239(%rip), %rax     # 0x45b28
movl (%rax,%r15,4), %eax
movl %eax, 0xc(%rsp)
movl $0x1, %eax
leaq 0xc(%rsp), %r10
movl %eax, %r13d
xorl %ebp, %ebp
movq %r10, 0x18(%rsp)
movq %r15, 0x30(%rsp)
movslq (%r10,%rbp,4), %rbx
movl %ebx, 0xc(%rsp)
movq 0x3e201(%rip), %rax     # 0x45b20
movl (%rax,%r15,4), %r12d
movslq %r12d, %rax
testq %rbx, %rbx
js 0x798c
movq (%r9,%rbx,8), %rcx
movzbl (%rcx,%rax), %ecx
cmpl $0x1, %ecx
je 0x7a46
cmpl $0x2, %ecx
je 0x7af2
testl %ecx, %ecx
jne 0x7b33
movq 0x3d684(%rip), %rax     # 0x44fd8
movq (%rax), %rdi
leaq 0x302c7(%rip), %r14     # 0x37c25
movq %r14, %rsi
movl %ebx, %edx
movl %r12d, %ecx
xorl %eax, %eax
callq 0x4360
cmpb $0x1, 0x3d968(%rip)     # 0x452dc
jne 0x7b7e
movq 0x40(%rsp), %rdi
movq %r14, %rsi
movl %ebx, %edx
movl %r12d, %ecx
jmp 0x7b77
movq %r13, %r15
movq 0x50(%rsp), %rcx
movslq (%rcx,%rax,4), %rcx
movq 0x3e1d9(%rip), %r13     # 0x45b78
leaq (%rcx,%rcx,2), %r14
shlq $0x5, %r14
cmpq $0x0, 0x10(%r13,%r14)
jne 0x7a39
leaq (%r14,%r13), %rcx
movq 0x48(%rsp), %rdx
movslq (%rdx,%rax,4), %rbx
movl %ebx, (%rcx)
movl %r12d, 0x5c(%r13,%r14)
movl $0xffffffff, 0x58(%r13,%r14) # imm = 0xFFFFFFFF
movabsq $-0x100000000, %rax     # imm = 0xFFFFFFFF00000000
movq %rax, 0x4(%r13,%r14)
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x10(%r13,%r14)
cmpb $0x0, 0x3e1c8(%rip)     # 0x45bc0
je 0x7a0c
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x18(%r13,%r14)
pxor %xmm0, %xmm0
movdqu %xmm0, 0x40(%r13,%r14)
movdqu %xmm0, 0x30(%r13,%r14)
movdqu %xmm0, 0x20(%r13,%r14)
movq 0x10(%rsp), %r9
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %r11
movq 0x18(%rsp), %r10
movq %r15, %r13
movq 0x30(%rsp), %r15
jmp 0x7b33
movq 0x38(%rsp), %r14
movslq %r14d, %r14
movq %r14, %rcx
shlq $0x5, %rcx
leaq (%rcx,%rcx,2), %rcx
movq 0x3e130(%rip), %rdx     # 0x45b90
addq %rcx, %rdx
movq 0x3e12e(%rip), %rsi     # 0x45b98
movslq (%rdi,%rbx,4), %r10
movq %rdx, (%rsi,%r10,8)
movq 0x3e117(%rip), %rdx     # 0x45b90
addq %rcx, %rdx
movq 0x3e12d(%rip), %rsi     # 0x45bb0
movslq (%r11,%rax,4), %r8
movq %rdx, (%rsi,%r8,8)
movq 0x3e0fe(%rip), %rdx     # 0x45b90
movq $0x1, (%rdx,%rcx)
movl %ebx, 0x58(%rdx,%rcx)
movl %r12d, 0x5c(%rdx,%rcx)
movl $0xffffffff, 0x8(%rdx,%rcx) # imm = 0xFFFFFFFF
leal 0x1(%r10), %esi
movq 0x18(%rsp), %r10
movdqu %xmm0, 0x10(%rdx,%rcx)
movdqu %xmm0, 0x20(%rdx,%rcx)
movdqu %xmm0, 0x30(%rdx,%rcx)
movdqu %xmm0, 0x40(%rdx,%rcx)
movq $0x0, 0x50(%rdx,%rcx)
movl %esi, (%rdi,%rbx,4)
leal 0x1(%r8), %ecx
movl %ecx, (%r11,%rax,4)
movq (%r9,%rbx,8), %rcx
movb $0x2, (%rcx,%rax)
incl %r14d
movq %r14, 0x38(%rsp)
jmp 0x7b33
movl (%rdi,%rbx,4), %eax
movq 0x3e09c(%rip), %rcx     # 0x45b98
movl %eax, %edx
sarl $0x1f, %edx
andl %eax, %edx
decl %edx
movq %rax, %rsi
decq %rsi
testl %eax, %eax
jle 0x7b23
movl %esi, %r8d
movq (%rcx,%r8,8), %r8
decl %eax
decq %rsi
cmpl %r12d, 0x5c(%r8)
jne 0x7b0b
jmp 0x7b25
movl %edx, %eax
cltq
movq (%rcx,%rax,8), %rax
cmpl %r12d, 0x5c(%rax)
jne 0x7b41
incl (%rax)
incq %rbp
cmpq %r13, %rbp
jne 0x7910
jmp 0x7b98
movq 0x3d490(%rip), %rax     # 0x44fd8
movq (%rax), %rdi
leaq 0x30112(%rip), %r14     # 0x37c64
movq %r14, %rsi
movl %r12d, %edx
movl %ebx, %ecx
xorl %eax, %eax
callq 0x4360
cmpb $0x1, 0x3d774(%rip)     # 0x452dc
jne 0x7b7e
movq 0x40(%rsp), %rdi
movq %r14, %rsi
movl %r12d, %edx
movl %ebx, %ecx
xorl %eax, %eax
callq 0x4360
movq 0x10(%rsp), %r9
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %r11
pxor %xmm0, %xmm0
movq 0x18(%rsp), %r10
jmp 0x7b33
movl 0x3dfb9(%rip), %r14d    # 0x45b58
incq %r15
movslq %r14d, %rax
cmpq %rax, %r15
jl 0x78ad
movl 0x3dfb3(%rip), %r12d    # 0x45b68
movslq 0x3dfa8(%rip), %rbx     # 0x45b64
movslq %r12d, %rbp
callq 0x42d0
movq 0x28(%rsp), %rdi
callq 0x42d0
movq 0x48(%rsp), %rdi
callq 0x42d0
movl $0x4, %esi
movq %rbp, %rdi
callq 0x4140
movq %rax, %r13
movl $0x4, %esi
movq %rbx, %rdi
callq 0x4140
movq %rax, 0x20(%rsp)
testl %r14d, %r14d
jle 0x7e7b
xorl %r9d, %r9d
xorl %r12d, %r12d
movq 0x10(%rsp), %r8
movq %r13, 0x48(%rsp)
movq 0x3df06(%rip), %rax     # 0x45b20
movslq (%rax,%r9,4), %rbp
cmpb $0x0, 0x3df9b(%rip)     # 0x45bc0
je 0x7c59
movq 0x3df02(%rip), %rcx     # 0x45b30
movq 0x3df0b(%rip), %rax     # 0x45b40
movslq (%rax,%r9,4), %rdx
movq 0x3def8(%rip), %rax     # 0x45b38
movl (%rax,%r9,4), %eax
movl (%rcx,%rdx,4), %esi
movl %esi, 0xc(%rsp)
testl %eax, %eax
jle 0x7e65
leaq (%rcx,%rdx,4), %r14
jmp 0x7c72
movq 0x3dec8(%rip), %rax     # 0x45b28
movl (%rax,%r9,4), %eax
movl %eax, 0xc(%rsp)
movl $0x1, %eax
leaq 0xc(%rsp), %r14
movl %eax, %r10d
xorl %r15d, %r15d
movq %r9, 0x38(%rsp)
movq %r10, 0x18(%rsp)
movq %r14, 0x28(%rsp)
movslq (%r14,%r15,4), %rbx
movl %ebx, 0xc(%rsp)
testq %rbx, %rbx
js 0x7d36
movq (%r8,%rbx,8), %rax
movzbl (%rax,%rbp), %eax
cmpb $0x1, %al
jle 0x7e2f
cmpl $0x3, %eax
je 0x7d85
cmpl $0x2, %eax
jne 0x7e1e
movl %r12d, 0x30(%rsp)
movq 0x3deda(%rip), %r12     # 0x45ba0
movq (%r12,%rbx,8), %rax
movslq (%r13,%rbx,4), %r14
movq (%rax,%r14,8), %r13
movslq (%r13), %rdi
movl $0x4, %esi
callq 0x4140
movq 0x38(%rsp), %r9
movq %rax, 0x10(%r13)
movq (%r12,%rbx,8), %rax
movq (%rax,%r14,8), %r13
movq 0x10(%r13), %rax
movl %r9d, (%rax)
cmpb $0x0, 0x3dec0(%rip)     # 0x45bc0
je 0x7de9
movslq (%r13), %rdi
movl $0x4, %esi
callq 0x4140
movq 0x38(%rsp), %r9
movq %rax, 0x18(%r13)
movq (%r12,%rbx,8), %rax
movq (%rax,%r14,8), %r13
movq 0x18(%r13), %rax
movl 0x30(%rsp), %r12d
movl %r12d, (%rax)
jmp 0x7dee
movq 0x50(%rsp), %rax
movslq (%rax,%rbp,4), %rcx
movq 0x3de32(%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, 0x3de56(%rip)     # 0x45bc0
je 0x7e21
addq %rcx, %rax
movq 0x18(%rax), %rcx
movslq 0x4(%rax), %rax
movl %r12d, -0x4(%rcx,%rax,4)
jmp 0x7e21
movl (%r13,%rbx,4), %eax
movq 0x3de0f(%rip), %rdx     # 0x45ba0
movl %eax, %ecx
sarl $0x1f, %ecx
andl %eax, %ecx
decl %ecx
movq (%rdx,%rbx,8), %rdx
movq %rax, %rsi
decq %rsi
testl %eax, %eax
jle 0x7dba
movl %esi, %edi
movq (%rdx,%rdi,8), %rdi
decl %eax
decq %rsi
cmpl %ebp, 0x5c(%rdi)
jne 0x7da4
jmp 0x7dbc
movl %ecx, %eax
cltq
movq (%rdx,%rax,8), %rax
cmpl %ebp, 0x5c(%rax)
jne 0x7e3f
movslq 0x4(%rax), %rcx
movq 0x10(%rax), %rdx
movl %r9d, (%rdx,%rcx,4)
cmpb $0x0, 0x3dde6(%rip)     # 0x45bc0
je 0x7de4
movq 0x18(%rax), %rdx
movl %r12d, (%rdx,%rcx,4)
incl 0x4(%rax)
jmp 0x7e1e
movl 0x30(%rsp), %r12d
incl 0x4(%r13)
movq 0x20(%rsp), %rax
incl (%rax,%rbp,4)
incl %r14d
movq 0x48(%rsp), %r13
movl %r14d, (%r13,%rbx,4)
movq 0x10(%rsp), %r8
movq (%r8,%rbx,8), %rax
movb $0x3, (%rax,%rbp)
movq 0x28(%rsp), %r14
movq 0x18(%rsp), %r10
incl %r12d
incq %r15
cmpq %r10, %r15
jne 0x7c87
jmp 0x7e5e
movl %ebx, %edi
movl %ebp, %esi
movq 0x40(%rsp), %rdx
callq 0x4a8c
jmp 0x7e4d
movl %ebp, %edi
movl %ebx, %esi
movq 0x40(%rsp), %rdx
callq 0x4a3e
movq 0x18(%rsp), %r10
movq 0x38(%rsp), %r9
movq 0x10(%rsp), %r8
jmp 0x7e1e
movl 0x3dcf3(%rip), %r14d    # 0x45b58
incq %r9
movslq %r14d, %rax
cmpq %rax, %r9
jl 0x7c13
movl 0x3dced(%rip), %r12d    # 0x45b68
movq %r13, %rdi
callq 0x42d0
movq 0x20(%rsp), %rdi
callq 0x42d0
movq 0x50(%rsp), %rdi
callq 0x42d0
movq 0x10(%rsp), %rdi
movl %r12d, %esi
callq 0x9d5a
movslq 0x3dcb9(%rip), %rax     # 0x45b64
testq %rax, %rax
jle 0x7eed
movq 0x3dcf1(%rip), %rcx     # 0x45ba8
movq 0x3dcfa(%rip), %rdx     # 0x45bb8
xorl %esi, %esi
cmpl $0x0, (%rcx,%rsi,4)
jle 0x7ee5
movq (%rdx,%rsi,8), %rdi
xorl %r8d, %r8d
movq (%rdi,%r8,8), %r9
movl $0x0, 0x4(%r9)
incq %r8
movslq (%rcx,%rsi,4), %r9
cmpq %r9, %r8
jl 0x7ecd
incq %rsi
cmpq %rax, %rsi
jne 0x7ec0
movslq 0x3dc8c(%rip), %rcx     # 0x45b80
testq %rcx, %rcx
jle 0x800e
movq 0x3dc74(%rip), %rax     # 0x45b78
leal 0x3(%rcx), %edx
decq %rcx
movq %rcx, %xmm0
pshufd $0x44, %xmm0, %xmm0     # xmm0 = xmm0[0,1,0,1]
shrl $0x2, %edx
shlq $0x7, %rdx
leaq (%rdx,%rdx,2), %rcx
movdqa 0x2f299(%rip), %xmm1    # 0x371c0
movdqa 0x2f2a1(%rip), %xmm2    # 0x371d0
xorl %edx, %edx
movdqa 0x2f2a7(%rip), %xmm3    # 0x371e0
pxor %xmm3, %xmm0
pcmpeqd %xmm4, %xmm4
movdqa 0x2f2a7(%rip), %xmm5    # 0x371f0
movdqa %xmm2, %xmm6
pxor %xmm3, %xmm6
movdqa %xmm6, %xmm7
pcmpgtd %xmm0, %xmm7
pcmpeqd %xmm0, %xmm6
pshufd $0xf5, %xmm6, %xmm8     # xmm8 = xmm6[1,1,3,3]
pand %xmm7, %xmm8
pshufd $0xf5, %xmm7, %xmm6     # xmm6 = xmm7[1,1,3,3]
por %xmm8, %xmm6
movd %xmm6, %esi
notl %esi
testb $0x1, %sil
je 0x7f86
movl $0x0, 0x4(%rax,%rdx)
pxor %xmm4, %xmm6
pextrw $0x4, %xmm6, %esi
testb $0x1, %sil
je 0x7f9d
movl $0x0, 0x64(%rax,%rdx)
movdqa %xmm1, %xmm6
pxor %xmm3, %xmm6
movdqa %xmm6, %xmm7
pcmpgtd %xmm0, %xmm7
pcmpeqd %xmm0, %xmm6
pshufd $0xf5, %xmm6, %xmm8     # xmm8 = xmm6[1,1,3,3]
pand %xmm7, %xmm8
pshufd $0xf5, %xmm7, %xmm6     # xmm6 = xmm7[1,1,3,3]
por %xmm8, %xmm6
pxor %xmm4, %xmm6
pextrw $0x0, %xmm6, %esi
testb $0x1, %sil
je 0x7fe0
movl $0x0, 0xc4(%rax,%rdx)
pextrw $0x4, %xmm6, %esi
testb $0x1, %sil
je 0x7ff6
movl $0x0, 0x124(%rax,%rdx)
paddq %xmm5, %xmm2
paddq %xmm5, %xmm1
addq $0x180, %rdx            # imm = 0x180
cmpq %rdx, %rcx
jne 0x7f49
movb $0x1, %al
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq