// File: /workspace/github_cpp_makefile_star2_O2/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, 0x388c1(%rip)     # 0x3e330
je 0x5a7f
leaq 0x38850(%rip), %rsi     # 0x3e2c8
callq 0xef2e
jmp 0x5a8b
leaq 0x38842(%rip), %rsi     # 0x3e2c8
callq 0xe272
testb %al, %al
je 0x5c05
movl 0x390ef(%rip), %edi     # 0x3eb88
movl 0x390e5(%rip), %esi     # 0x3eb84
callq 0x82e9
movq %rax, %r12
movslq 0x390da(%rip), %rdi     # 0x3eb88
pushq $0x4
popq %rbx
movq %rbx, %rsi
callq 0x4130
movq %rax, 0x390e8(%rip)     # 0x3eba8
movslq 0x390bd(%rip), %r15     # 0x3eb84
movq %r15, %rdi
movq %rbx, %rsi
callq 0x4130
movq %rax, 0x390ef(%rip)     # 0x3ebc8
movq %r15, %rdi
movq %rbx, %rsi
callq 0x4130
movq %r15, %rdi
movq %rax, %r14
movq %rbx, %rsi
callq 0x4130
movq %rax, 0x50(%rsp)
xorl %eax, %eax
pushq $0x1
popq %rcx
leaq 0xc(%rsp), %rdx
xorl %esi, %esi
movslq 0x3906e(%rip), %rbx     # 0x3eb78
cmpq %rbx, %rsi
jge 0x5c0c
movb 0x390c6(%rip), %r8b     # 0x3ebe0
testb %r8b, %r8b
je 0x5b37
movq 0x3903a(%rip), %rdi     # 0x3eb60
movslq (%rdi,%rsi,4), %rdi
shlq $0x2, %rdi
addq 0x3901b(%rip), %rdi     # 0x3eb50
jmp 0x5b46
leaq (,%rsi,4), %rdi
addq 0x39002(%rip), %rdi     # 0x3eb48
movl (%rdi), %r9d
movl %r9d, 0xc(%rsp)
movq 0x38feb(%rip), %rdi     # 0x3eb40
movslq (%rdi,%rsi,4), %rdi
testl %r9d, %r9d
js 0x5b89
testb %r8b, %r8b
je 0x5ba7
movq 0x38ff6(%rip), %r8      # 0x3eb60
movslq (%r8,%rsi,4), %r10
shlq $0x2, %r10
addq 0x38fd7(%rip), %r10     # 0x3eb50
movq 0x38fd8(%rip), %r8      # 0x3eb58
movl (%r8,%rsi,4), %r8d
movq %r10, %r9
jmp 0x5bbc
movl (%r14,%rdi,4), %r8d
testl %r8d, %r8d
jne 0x5b98
incl 0x39008(%rip)           # 0x3eba0
incl %r8d
movl %r8d, (%r14,%rdi,4)
incq %rsi
jmp 0x5b03
leaq (,%rsi,4), %r10
addq 0x38f92(%rip), %r10     # 0x3eb48
movq %rdx, %r9
movl %ecx, %r8d
movl (%r10), %r10d
movl %r10d, 0xc(%rsp)
testl %r8d, %r8d
cmovlel %eax, %r8d
xorl %r10d, %r10d
cmpq %r10, %r8
je 0x5b9f
movslq (%r9,%r10,4), %r11
movl %r11d, 0xc(%rsp)
movq (%r12,%r11,8), %rbx
cmpb $0x0, (%rbx,%rdi)
jne 0x5c00
movb $0x1, (%rbx,%rdi)
movq 0x38fb7(%rip), %rbx     # 0x3eba8
incl (%rbx,%r11,4)
movq 0x38fcc(%rip), %r11     # 0x3ebc8
incl (%r11,%rdi,4)
incq %r10
jmp 0x5bce
xorl %eax, %eax
jmp 0x646f
movq %r14, 0x38(%rsp)
movslq 0x38f70(%rip), %r15     # 0x3eb88
movl 0x38f86(%rip), %eax     # 0x3eba4
movq 0x38f83(%rip), %rcx     # 0x3eba8
xorl %edx, %edx
testl %r15d, %r15d
movl $0x0, %r14d
cmovgl %r15d, %r14d
cmpq %rdx, %r14
je 0x5c47
addl (%rcx,%rdx,4), %eax
movl %eax, 0x38f62(%rip)     # 0x3eba4
incq %rdx
jmp 0x5c34
movq %r12, 0x48(%rsp)
movl %r14d, 0xc(%rsp)
movslq %eax, %rbp
pushq $0x60
popq %r13
movq %rbp, %rdi
movq %r13, %rsi
callq 0x4130
movq %rax, 0x38f46(%rip)     # 0x3ebb0
leaq (,%r15,8), %rdi
callq 0x4330
movq %rax, 0x38f42(%rip)     # 0x3ebc0
shlq $0x3, %rbp
movq %rbp, %rdi
callq 0x4330
movq %rax, 0x38f27(%rip)     # 0x3ebb8
movslq 0x38eec(%rip), %r12     # 0x3eb84
pushq $0x8
popq %rsi
movq %r12, %rdi
callq 0x4130
movq %rax, 0x38f2e(%rip)     # 0x3ebd8
movq %rbp, %rdi
callq 0x4330
movq %rax, 0x38f17(%rip)     # 0x3ebd0
movslq 0x38ee0(%rip), %rdi     # 0x3eba0
movq %r13, %rsi
callq 0x4130
movq %rax, 0x38ec9(%rip)     # 0x3eb98
xorl %eax, %eax
testl %r12d, %r12d
movl $0x0, %r13d
cmovgl %r12d, %r13d
xorl %ecx, %ecx
cmpq %rax, %r13
je 0x5cff
movq 0x38(%rsp), %rdx
cmpl $0x0, (%rdx,%rax,4)
jle 0x5cfa
movq 0x50(%rsp), %rdx
movl %ecx, (%rdx,%rax,4)
incl %ecx
incq %rax
jmp 0x5ce0
pushq $0x4
popq %rbp
movq %r15, %rdi
movq %rbp, %rsi
callq 0x4130
movq %rax, %r15
movq %r12, %rdi
movq %rbp, %rsi
callq 0x4130
movq %r15, %rdi
movq %rax, 0x18(%rsp)
xorl %eax, %eax
xorl %ecx, %ecx
cmpq %rax, %r14
je 0x5d5b
movl %ecx, (%rdi,%rax,4)
movslq %ecx, %rcx
leaq (,%rcx,8), %rdx
addq 0x38e77(%rip), %rdx     # 0x3ebb8
movq 0x38e78(%rip), %rsi     # 0x3ebc0
movq %rdx, (%rsi,%rax,8)
movq 0x38e55(%rip), %rdx     # 0x3eba8
addl (%rdx,%rax,4), %ecx
incq %rax
jmp 0x5d27
xorl %eax, %eax
xorl %ecx, %ecx
cmpq %rax, %r13
je 0x5d98
movq 0x18(%rsp), %rdx
movl %ecx, (%rdx,%rax,4)
movslq %ecx, %rcx
leaq (,%rcx,8), %rdx
addq 0x38e52(%rip), %rdx     # 0x3ebd0
movq 0x38e53(%rip), %rsi     # 0x3ebd8
movq %rdx, (%rsi,%rax,8)
movq 0x38e38(%rip), %rdx     # 0x3ebc8
addl (%rdx,%rax,4), %ecx
incq %rax
jmp 0x5d5f
pushq $0x4
popq %rsi
xorps %xmm0, %xmm0
xorl %r10d, %r10d
movq $0x0, 0x28(%rsp)
movq 0x48(%rsp), %r15
movq %rdi, 0x30(%rsp)
movslq %ebx, %rax
cmpq %rax, %r10
jge 0x60a4
cmpb $0x0, 0x38e19(%rip)     # 0x3ebe0
je 0x5def
movq 0x38d90(%rip), %rax     # 0x3eb60
movslq (%rax,%r10,4), %rax
shlq $0x2, %rax
addq 0x38d71(%rip), %rax     # 0x3eb50
movq 0x38d72(%rip), %rcx     # 0x3eb58
movl (%rcx,%r10,4), %r14d
movq %rax, %r11
jmp 0x5e09
leaq (,%r10,4), %rax
addq 0x38d4a(%rip), %rax     # 0x3eb48
leaq 0xc(%rsp), %r11
pushq $0x1
popq %rcx
movl %ecx, %r14d
movl (%rax), %eax
movl %eax, 0xc(%rsp)
testl %r14d, %r14d
movl $0x0, %eax
cmovlel %eax, %r14d
xorl %ebp, %ebp
movq %r10, 0x20(%rsp)
movq %r11, 0x10(%rsp)
cmpq %r14, %rbp
je 0x6096
movslq (%r11,%rbp,4), %r12
movl %r12d, 0xc(%rsp)
movq 0x38d00(%rip), %rax     # 0x3eb40
movl (%rax,%r10,4), %ebx
movslq %ebx, %rax
testq %r12, %r12
js 0x5ea9
movq (%r15,%r12,8), %rcx
movzbl (%rcx,%rax), %ecx
cmpl $0x1, %ecx
je 0x5ed3
cmpl $0x2, %ecx
je 0x5f7b
testl %ecx, %ecx
jne 0x6044
movq 0x38167(%rip), %rax     # 0x3dfd8
movq (%rax), %rdi
leaq 0x29d5a(%rip), %r13     # 0x2fbd5
movq %r13, %rsi
movl %r12d, %edx
movl %ebx, %ecx
xorl %eax, %eax
callq 0x4380
cmpb $0x1, 0x3846b(%rip)     # 0x3e2fc
jne 0x6089
movq 0x40(%rsp), %rdi
movq %r13, %rsi
movl %r12d, %edx
movl %ebx, %ecx
jmp 0x6082
movq 0x50(%rsp), %rcx
movslq (%rcx,%rax,4), %rcx
movq 0x38cdf(%rip), %r15     # 0x3eb98
imulq $0x60, %rcx, %r13
cmpq $0x0, 0x10(%r15,%r13)
je 0x5fb4
movq 0x48(%rsp), %r15
jmp 0x6044
movq 0x28(%rsp), %r13
movslq %r13d, %r13
imulq $0x60, %r13, %rcx
movq 0x38cca(%rip), %rdx     # 0x3ebb0
addq %rcx, %rdx
movq 0x38cc8(%rip), %r8      # 0x3ebb8
movslq (%rdi,%r12,4), %r9
movq %rdx, (%r8,%r9,8)
movq 0x38cb1(%rip), %rdx     # 0x3ebb0
addq %rcx, %rdx
movq 0x38cc7(%rip), %r11     # 0x3ebd0
movq 0x18(%rsp), %r10
movslq (%r10,%rax,4), %r8
movq %rdx, (%r11,%r8,8)
movq 0x10(%rsp), %r11
movq 0x38c8e(%rip), %rdx     # 0x3ebb0
movq $0x1, (%rdx,%rcx)
movl %r12d, 0x58(%rdx,%rcx)
movl %ebx, 0x5c(%rdx,%rcx)
orl $-0x1, 0x8(%rdx,%rcx)
incl %r9d
movups %xmm0, 0x10(%rdx,%rcx)
movups %xmm0, 0x20(%rdx,%rcx)
andq $0x0, 0x50(%rdx,%rcx)
movups %xmm0, 0x30(%rdx,%rcx)
movups %xmm0, 0x40(%rdx,%rcx)
movl %r9d, (%rdi,%r12,4)
leal 0x1(%r8), %ecx
movl %ecx, (%r10,%rax,4)
movq 0x20(%rsp), %r10
movq (%r15,%r12,8), %rcx
movb $0x2, (%rcx,%rax)
incl %r13d
movq %r13, 0x28(%rsp)
jmp 0x6044
movl (%rdi,%r12,4), %eax
movq 0x38c32(%rip), %rcx     # 0x3ebb8
movl %eax, %edx
sarl $0x1f, %edx
andl %eax, %edx
decl %edx
movq %rax, %r9
decq %r9
testl %eax, %eax
jle 0x6035
movl %r9d, %r8d
movq (%rcx,%r8,8), %r8
decl %eax
decq %r9
cmpl %ebx, 0x5c(%r8)
jne 0x5f95
jmp 0x6037
leaq (%r15,%r13), %rcx
movq 0x38(%rsp), %rdx
movslq (%rdx,%rax,4), %r12
movl %r12d, (%rcx)
movl %ebx, 0x5c(%r15,%r13)
orl $-0x1, 0x58(%r15,%r13)
movabsq $-0x100000000, %rax     # imm = 0xFFFFFFFF00000000
movq %rax, 0x4(%r15,%r13)
movq %r12, %rdi
movq %rsi, %rbx
callq 0x4130
movq %rax, 0x10(%r15,%r13)
cmpb $0x0, 0x38beb(%rip)     # 0x3ebe0
je 0x6007
movq %r12, %rdi
movq %rbx, %rsi
callq 0x4130
movq %rax, 0x18(%r15,%r13)
xorps %xmm0, %xmm0
movups %xmm0, 0x40(%r15,%r13)
movups %xmm0, 0x30(%r15,%r13)
movups %xmm0, 0x20(%r15,%r13)
movq 0x48(%rsp), %r15
movq 0x30(%rsp), %rdi
movq %rbx, %rsi
movq 0x20(%rsp), %r10
movq 0x10(%rsp), %r11
jmp 0x6044
movl %edx, %eax
cltq
movq (%rcx,%rax,8), %rax
cmpl %ebx, 0x5c(%rax)
jne 0x604c
incl (%rax)
incq %rbp
jmp 0x5e27
movq 0x37f85(%rip), %rax     # 0x3dfd8
movq (%rax), %rdi
leaq 0x29bb7(%rip), %r13     # 0x2fc14
movq %r13, %rsi
movl %ebx, %edx
movl %r12d, %ecx
xorl %eax, %eax
callq 0x4380
cmpb $0x1, 0x38289(%rip)     # 0x3e2fc
jne 0x6089
movq 0x40(%rsp), %rdi
movq %r13, %rsi
movl %ebx, %edx
movl %r12d, %ecx
xorl %eax, %eax
callq 0x4380
movq 0x30(%rsp), %rdi
pushq $0x4
popq %rsi
xorps %xmm0, %xmm0
jmp 0x6029
incq %r10
movl 0x38ad9(%rip), %ebx     # 0x3eb78
jmp 0x5db4
callq 0x42c0
movq 0x18(%rsp), %rdi
callq 0x42c0
movq 0x38(%rsp), %rdi
callq 0x42c0
movslq 0x38ac4(%rip), %rdi     # 0x3eb88
pushq $0x4
popq %r14
movq %r14, %rsi
callq 0x4130
movslq 0x38aad(%rip), %rdi     # 0x3eb84
movq %r14, %rsi
movq %rax, %r14
callq 0x4130
movq %rax, 0x38(%rsp)
xorl %r8d, %r8d
xorl %r13d, %r13d
movq %r14, 0x30(%rsp)
movslq %ebx, %rax
cmpq %rax, %r8
jge 0x63d9
cmpb $0x0, 0x38adb(%rip)     # 0x3ebe0
je 0x612d
movq 0x38a52(%rip), %rax     # 0x3eb60
movslq (%rax,%r8,4), %rax
shlq $0x2, %rax
addq 0x38a33(%rip), %rax     # 0x3eb50
movq 0x38a34(%rip), %rcx     # 0x3eb58
movl (%rcx,%r8,4), %r9d
movq %rax, %r10
jmp 0x6147
leaq (,%r8,4), %rax
addq 0x38a0c(%rip), %rax     # 0x3eb48
leaq 0xc(%rsp), %r10
pushq $0x1
popq %rcx
movl %ecx, %r9d
movq 0x389f2(%rip), %rcx     # 0x3eb40
movslq (%rcx,%r8,4), %rbx
movl (%rax), %eax
movl %eax, 0xc(%rsp)
testl %r9d, %r9d
movl $0x0, %eax
cmovlel %eax, %r9d
xorl %ebp, %ebp
movq %r8, 0x28(%rsp)
movq %r9, 0x10(%rsp)
movq %r10, 0x18(%rsp)
cmpq %r9, %rbp
je 0x63cb
movslq (%r10,%rbp,4), %r12
movl %r12d, 0xc(%rsp)
testq %r12, %r12
js 0x622a
movq (%r15,%r12,8), %rax
movzbl (%rax,%rbx), %eax
cmpb $0x1, %al
jle 0x631e
cmpl $0x3, %eax
je 0x6275
cmpl $0x2, %eax
jne 0x6313
movl %r13d, 0x20(%rsp)
movq 0x38a02(%rip), %r13     # 0x3ebc0
movq (%r13,%r12,8), %rax
movslq (%r14,%r12,4), %r14
movq (%rax,%r14,8), %r15
movslq (%r15), %rdi
pushq $0x4
popq %rsi
callq 0x4130
movq 0x28(%rsp), %r8
movq %rax, 0x10(%r15)
movq (%r13,%r12,8), %rax
movq (%rax,%r14,8), %r15
movq 0x10(%r15), %rax
movl %r8d, (%rax)
cmpb $0x0, 0x389ea(%rip)     # 0x3ebe0
je 0x62dc
movslq (%r15), %rdi
pushq $0x4
popq %rsi
callq 0x4130
movq 0x28(%rsp), %r8
movq %rax, 0x18(%r15)
movq (%r13,%r12,8), %rax
movq (%rax,%r14,8), %r15
movq 0x18(%r15), %rax
movl 0x20(%rsp), %r13d
movl %r13d, (%rax)
jmp 0x62e1
movq 0x50(%rsp), %rax
movslq (%rax,%rbx,4), %rcx
movq 0x3895e(%rip), %rax     # 0x3eb98
imulq $0x60, %rcx, %rcx
movq 0x10(%rax,%rcx), %rdx
movslq 0x4(%rax,%rcx), %rsi
leal 0x1(%rsi), %edi
movl %edi, 0x4(%rax,%rcx)
movl %r8d, (%rdx,%rsi,4)
cmpb $0x0, 0x38986(%rip)     # 0x3ebe0
je 0x6316
addq %rcx, %rax
movq 0x18(%rax), %rcx
movslq 0x4(%rax), %rax
movl %r13d, -0x4(%rcx,%rax,4)
jmp 0x6316
movl (%r14,%r12,4), %eax
movq 0x38940(%rip), %rdx     # 0x3ebc0
movl %eax, %ecx
sarl $0x1f, %ecx
andl %eax, %ecx
decl %ecx
movq (%rdx,%r12,8), %rdx
movq %rax, %rsi
decq %rsi
testl %eax, %eax
jle 0x62a9
movl %esi, %edi
movq (%rdx,%rdi,8), %rdi
decl %eax
decq %rsi
cmpl %ebx, 0x5c(%rdi)
jne 0x6293
jmp 0x62ab
movl %ecx, %eax
cltq
movq (%rdx,%rax,8), %rax
cmpl %ebx, 0x5c(%rax)
jne 0x6366
movslq 0x4(%rax), %rcx
movq 0x10(%rax), %rdx
movl %r8d, (%rdx,%rcx,4)
cmpb $0x0, 0x38913(%rip)     # 0x3ebe0
je 0x62d7
movq 0x18(%rax), %rdx
movl %r13d, (%rdx,%rcx,4)
incl 0x4(%rax)
jmp 0x6313
movl 0x20(%rsp), %r13d
incl 0x4(%r15)
movq 0x38(%rsp), %rax
incl (%rax,%rbx,4)
incl %r14d
movq 0x30(%rsp), %rax
movl %r14d, (%rax,%r12,4)
movq %rax, %r14
movq 0x48(%rsp), %r15
movq (%r15,%r12,8), %rax
movb $0x3, (%rax,%rbx)
movq 0x10(%rsp), %r9
movq 0x18(%rsp), %r10
incl %r13d
incq %rbp
jmp 0x6175
movq 0x37cb3(%rip), %rax     # 0x3dfd8
movq (%rax), %rdi
leaq 0x29918(%rip), %rsi     # 0x2fc47
movl %r12d, %edx
movl %ebx, %ecx
xorl %eax, %eax
callq 0x4380
movq 0x18(%rsp), %r10
movq 0x10(%rsp), %r9
movq 0x28(%rsp), %r8
cmpb $0x1, 0x37fab(%rip)     # 0x3e2fc
jne 0x6313
movq 0x40(%rsp), %rdi
leaq 0x298e8(%rip), %rsi     # 0x2fc47
movl %r12d, %edx
movl %ebx, %ecx
jmp 0x63b0
movq 0x37c6b(%rip), %rax     # 0x3dfd8
movq (%rax), %rdi
leaq 0x2989d(%rip), %rsi     # 0x2fc14
movl %ebx, %edx
movl %r12d, %ecx
xorl %eax, %eax
callq 0x4380
movq 0x18(%rsp), %r10
movq 0x10(%rsp), %r9
movq 0x28(%rsp), %r8
cmpb $0x1, 0x37f63(%rip)     # 0x3e2fc
jne 0x6313
movq 0x40(%rsp), %rdi
leaq 0x29869(%rip), %rsi     # 0x2fc14
movl %ebx, %edx
movl %r12d, %ecx
xorl %eax, %eax
callq 0x4380
movq 0x18(%rsp), %r10
movq 0x10(%rsp), %r9
movq 0x28(%rsp), %r8
jmp 0x6313
incq %r8
movl 0x387a4(%rip), %ebx     # 0x3eb78
jmp 0x60f2
movq %r14, %rdi
callq 0x42c0
movq 0x38(%rsp), %rdi
callq 0x42c0
movq 0x50(%rsp), %rdi
callq 0x42c0
movl 0x3878d(%rip), %esi     # 0x3eb88
movq %r15, %rdi
callq 0x8342
movl 0x3877b(%rip), %eax     # 0x3eb84
movq 0x387b8(%rip), %rcx     # 0x3ebc8
xorl %edx, %edx
testl %eax, %eax
cmovlel %edx, %eax
cmpq %rax, %rdx
je 0x6445
movq 0x387b5(%rip), %rsi     # 0x3ebd8
xorl %edi, %edi
movslq (%rcx,%rdx,4), %r8
cmpq %r8, %rdi
jge 0x6440
movq (%rsi,%rdx,8), %r8
movq (%r8,%rdi,8), %r8
andl $0x0, 0x4(%r8)
incq %rdi
jmp 0x6425
incq %rdx
jmp 0x6417
movl 0x38755(%rip), %edx     # 0x3eba0
movq 0x38746(%rip), %rax     # 0x3eb98
xorl %ecx, %ecx
testl %edx, %edx
cmovlel %ecx, %edx
imulq $0x60, %rdx, %rdx
cmpq %rcx, %rdx
je 0x646d
andl $0x0, 0x4(%rax,%rcx)
addq $0x60, %rcx
jmp 0x645d
movb $0x1, %al
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq