// File: /workspace/github_c_makefile_star2_O3/c-zhou[P]oatk/run_syncasm.c
// Function: syncasm
int syncasm(char **file_in, int n_file, size_t m_data, int k, int s, int bubble_size, int tip_size, int min_k_cov, double min_a_cov_f,
        double weak_cross, int do_ec, int do_unzip, int n_threads, char *out, scg_meta_t *meta, int VERBOSE)
{
    FILE *fo;
    sstream_t *sr_rdr;
    scg_t *scg;
    sr_db_t *sr_db;
    syncmer_db_t *scm_db;
    scg_ra_v *ra_db;
    int ret = 0;

    scg = 0;
    sr_db = 0;
    scm_db = 0;
    ra_db = 0;

    sr_rdr = sstream_open(file_in, n_file);
    if (sr_rdr == 0) {
        fprintf(stderr, "[E::%s] failed to open files: %s\n", __func__, strerror(errno));
        ret = 1;
        goto do_clean;
    }

    MYMALLOC(sr_db, 1);
    sr_db_init(sr_db, k, s);
    sr_read(sr_rdr, sr_db, m_data, n_threads);
    fprintf(stderr, "[M::%s] collected syncmers from %lu target sequence(s)\n", __func__, sr_rdr->n_seq);
    sstream_close(sr_rdr);
    if (sr_db_validate(sr_db)) {
        ret = 1;
        goto do_clean;
    }
    sr_db_stat(sr_db, stderr, VERBOSE);

    if (min_k_cov == 0) {
        min_k_cov = sr_db->stats->kmer_peak_het > 0? (sr_db->stats->kmer_peak_het * 10) : (sr_db->stats->kmer_peak_hom * 10);
        fprintf(stderr, "[M::%s] set minimum kmer coverage as %d\n", __func__, min_k_cov);
    }

#ifdef DEBUG_SYNCMER_SEQ
    uint32_t i;
    fo = open_outstream(out, "_syncmer_debug.fa");
    for (i = 0; i < sr_db->n; ++i) print_all_syncmers_on_seq(&sr_db->a[i], s, k, fo);
    fclose(fo);
#endif

    // make syncmer database
    scm_db = collect_syncmer_from_reads(sr_db);
    
    // syncmer_link_coverage_analysis(sr_db, scm_db, min_k_cov, 30, 30, .7, 0, 0, 0, VERBOSE);
    
    if (do_ec) {
        // make syncmer graph with all syncmers for error correction
        scg = make_syncmer_graph(sr_db, scm_db, 0, 0.);
#ifdef DEBUG_GRAPH_ERROR_CORRECTION
        // save sequence in graph
        fo = open_outstream(out, "_syncmer_hoco.gfa");
        scg_consensus(sr_db, scg, 1, 1, fo);
        fclose(fo);
#endif
        // do consensus in hoco space
        scg_consensus(sr_db, scg, 1, 1, 0);
        // naive error finding without checking arc coverage
#ifdef DEBUG_GRAPH_ERROR_CORRECTION
        fo = open_outstream(out, ".ec.fa");
#else
        fo = 0;
#endif
        read_error_correction(sr_db, scg, 0.02, min_k_cov, min_k_cov * 10, min_k_cov, min_a_cov_f, n_threads, fo, VERBOSE);
#ifdef DEBUG_GRAPH_ERROR_CORRECTION
        fclose(fo);
        fo = open_outstream(out, "_syncmer_hoco.noerr.gfa");
        scg_print(scg, fo, 0);
        fclose(fo);
#endif
        sr_db_stat(sr_db, stderr, VERBOSE);
        scg_destroy(scg); scg = 0;
        // goto do_clean;
    }

    // make syncmer graph
    fprintf(stderr, "[M::%s] make syncmer graph\n", __func__);
    scg = make_syncmer_graph(sr_db, scm_db, min_k_cov, min_a_cov_f);
    if (!scg || scg_is_empty(scg)) {
        fprintf(stderr, "[E::%s] empty syncmer graph\n", __func__);
        ret = 1;
        goto do_clean;
    }
    fprintf(stderr, "[M::%s] syncmer graph stats\n", __func__);
    scg_stat(scg, stderr, 0);
    if (VERBOSE > 1) scg_subgraph_stat(scg, stderr);

#ifdef DEBUG_SYNCMER_GRAPH
    fo = open_outstream(out, "_syncmer.gfa");
    scg_consensus(sr_db, scg, 0, 0, fo);
    fclose(fo);
    MYCALLOC(ra_db, 1);
    scg_read_alignment(sr_db, ra_db, scg, n_threads, 0);
    fprintf(stderr, "[DEBUG_SYNCMER_GRAPH::%s] read alignment\n", __func__);
    scg_rv_print(ra_db, stderr);
    scg_ra_v_destroy(ra_db);
#endif

    // make unitigs
    fprintf(stderr, "[M::%s] syncmer graph unitigging\n", __func__);
    process_mergeable_unitigs(scg);
    fprintf(stderr, "[M::%s] syncmer graph stats after unitigging\n", __func__);
    scg_stat(scg, stderr, 0);
    fo = open_outstream(out, ".utg.gfa");
    scg_consensus(sr_db, scg, 0, 0, fo);
    fclose(fo);

    if (VERBOSE > 1) scg_subgraph_stat(scg, stderr);

#ifdef DEBUG_GRAPH_UNITIG
    scg_print_unitig_syncmer_list(scg, stderr);
    MYCALLOC(ra_db, 1);
    scg_read_alignment(sr_db, ra_db, scg, n_threads, 0);
    fprintf(stderr, "[DEBUG_GRAPH_UNITIG::%s] read alignment\n", __func__);
    scg_rv_print(ra_db, stderr);
    scg_ra_v_destroy(ra_db);
#endif

    // do basic cleanup
    // already have consensus information
    fprintf(stderr, "[M::%s] syncmer graph cleanup\n", __func__);
    uint64_t cleaned = 1;
    while (cleaned) {
        // do not do bubble popping before unzipping to avoid removing haplotypes
        cleaned = 0;
        if (do_unzip <= 0) {
            cleaned += asmg_pop_bubble(scg->utg_asmg, bubble_size, 0, 0, 1, 0, VERBOSE);
            cleaned += asmg_remove_weak_crosslink(scg->utg_asmg, weak_cross, 10, 0, VERBOSE);
        }
        cleaned += asmg_drop_tip(scg->utg_asmg, INT32_MAX, tip_size, 1, 0, VERBOSE);
    }
    process_mergeable_unitigs(scg);
    
#ifdef DEBUG_GRAPH_MULTIPLEX
    fprintf(stderr, "[M::%s] syncmer graph stats after cleanup\n", __func__);
    scg_stat(scg, stderr, 0);
    fo = open_outstream(out, ".utg.clean.gfa");
    scg_consensus(sr_db, scg, 0, 0, fo);
    fclose(fo);
#endif

#ifdef DEBUG_GRAPH_MULTIPLEX
    scg_print_unitig_syncmer_list(scg, stderr);
#endif

    MYCALLOC(ra_db, 1);
    // do read threading
    if (do_unzip > 0) {
        fprintf(stderr, "[M::%s] assembly graph unzipping\n", __func__);
        int round, updated;
        uint32_t max_n_scm;

        // set max_n_scm for maximum repeats of ~15Kb which reach the HiFi read length limit
        max_n_scm = ceil(30000.0 / k);

        // do multiplexing
        round = 0;
        updated = 1;
        while (updated != 0 && round < do_unzip) {
            ++round;
            scg_read_alignment(sr_db, ra_db, scg, n_threads, 1);
            // scg_rv_print(ra_db, stderr);
            scg_update_utg_cov(scg);
            updated = scg_multiplex(scg, ra_db, max_n_scm, 10, .3);
            if (VERBOSE > 0) {
                fprintf(stderr, "[M::%s] syncmer graph stats after multiplexing round %d\n", __func__, round);
                scg_stat(scg, stderr, 0);
            }
#ifdef DEBUG_GRAPH_MULTIPLEX
            char *out1;
            MYMALLOC(out1, strlen(out) + 36);
            sprintf(out1, "%s.utg.unzip.r%02d.gfa", out, round);
            fo = open_outstream(out1, "");
            scg_consensus(sr_db, scg, 0, 0, fo);
            fclose(fo);
            free(out1);
            scg_print_unitig_syncmer_list(scg, stderr);
#endif
        }
        
        // arc coverage estimation from aligned reads
        // to remove weak cross arcs
        // only arc coverage is required
        scg_read_alignment(sr_db, ra_db, scg, n_threads, 1);
        scg_ra_arc_coverage(scg, sr_db, ra_db, 0, VERBOSE);
        asmg_remove_weak_crosslink(scg->utg_asmg, weak_cross, 10, 0, VERBOSE);

#ifdef DEBUG_GRAPH_MULTIPLEX
        fprintf(stderr, "[M::%s] syncmer graph stats after multiplexing\n", __func__);
        scg_stat(scg, stderr, 0);
        fo = open_outstream(out, ".utg.multiplex.gfa");
        scg_consensus(sr_db, scg, 0, 0, fo);
        fclose(fo);
#endif

        // do demultiplexing
        scg_demultiplex(scg);
        // the arc coverage is lost
        scg_read_alignment(sr_db, ra_db, scg, n_threads, 0);
        scg_ra_utg_coverage(scg, sr_db, ra_db, VERBOSE);
        scg_ra_arc_coverage(scg, sr_db, ra_db, 1, VERBOSE);
        
#ifdef DEBUG_GRAPH_MULTIPLEX
        fprintf(stderr, "[M::%s] syncmer graph stats after unzipping\n", __func__);
        scg_stat(scg, stderr, 0);
        fo = open_outstream(out, ".utg.unzip.gfa");
        scg_consensus(sr_db, scg, 0, 0, fo);
        fclose(fo);
#else
        // consensus infomration is required for basic cleanup
        scg_consensus(sr_db, scg, 0, 0, 0);
#endif

        // do basic cleanup
        cleaned = 1;
        while (cleaned) {
            cleaned = 0;
            cleaned += asmg_pop_bubble(scg->utg_asmg, bubble_size, 0, 0, 1, 0, VERBOSE);
            cleaned += asmg_remove_weak_crosslink(scg->utg_asmg, weak_cross, 10, 0, VERBOSE);
            cleaned += asmg_drop_tip(scg->utg_asmg, INT32_MAX, tip_size, 1, 0, VERBOSE);
        }
        process_mergeable_unitigs(scg);

#ifdef DEBUG_GRAPH_UNITIG
        scg_print_unitig_syncmer_list(scg, stderr);
#endif

#ifdef DEBUG_GRAPH_ALIGNMENT
        fprintf(stderr, "[DEBUG_GRAPH_ALIGNMENT::%s] read alignment\n", __func__);
        scg_rv_print(ra_db, stderr);
#endif
    }

    // unitig and arc coverage estimation
    scg_read_alignment(sr_db, ra_db, scg, n_threads, 0);
    scg_ra_utg_coverage(scg, sr_db, ra_db, VERBOSE);
    scg_ra_arc_coverage(scg, sr_db, ra_db, 1, VERBOSE);

    fprintf(stderr, "[M::%s] syncmer graph stats after final processing\n", __func__);
    scg_stat(scg, stderr, 0);
    fo = open_outstream(out, ".utg.final.gfa");
    scg_consensus(sr_db, scg, 0, 0, fo);
    fclose(fo);

do_clean:
    if (meta) {
        scg_meta_clean(meta);
        meta->k = k;
        meta->s = s;
        meta->scg = scg;
        meta->scm_db = scm_db;
        meta->sr_db = sr_db;
        meta->ra_db = ra_db;
    } else {
        scg_destroy(scg);
        syncmer_db_destroy(scm_db);
        sr_db_destroy(sr_db);
        scg_ra_v_destroy(ra_db);
    }

    return ret;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movsd %xmm1, 0x38(%rsp)
movsd %xmm0, 0x18(%rsp)
movl %r9d, %ebp
movl %r8d, %r13d
movl %ecx, %r12d
movq %rdx, %rbx
movq 0xb0(%rsp), %r15
callq 0x1c15f
testq %rax, %rax
movl %r13d, 0x44(%rsp)
movl %r12d, 0x24(%rsp)
jne 0x3816
callq 0x26e2
movl $0x1, %r12d
xorl %ebx, %ebx
movq $0x0, 0x10(%rsp)
jmp 0x3891
movq %rax, %r14
movl %ebp, 0x30(%rsp)
movl $0x28, %edi
callq 0x2310
movq %rax, %rbp
movq %rax, %rdi
movl %r12d, %esi
movl %r13d, %edx
callq 0xdb03
movq %r14, %rdi
movq %rbp, %rsi
movq %rbx, %rdx
movl 0xa0(%rsp), %ecx
callq 0xd676
movq 0x2279c(%rip), %r13     # 0x25ff0
movq (%r13), %rdi
movq (%r14), %rcx
leaq 0x1b850(%rip), %rsi     # 0x1f0b2
leaq 0x1b841(%rip), %rdx     # 0x1f0aa
xorl %ebx, %ebx
xorl %eax, %eax
callq 0x2280
movq %r14, %rdi
callq 0x1c0d4
movq %rbp, 0x10(%rsp)
movq %rbp, %rdi
callq 0xeed4
movl $0x1, %r12d
testl %eax, %eax
je 0x38fe
xorl %r13d, %r13d
xorl %ebp, %ebp
testq %r15, %r15
movl 0x24(%rsp), %r14d
je 0x38ca
movq %r15, %rdi
callq 0x4c59
movl %r14d, (%r15)
movl 0x44(%rsp), %eax
movl %eax, 0x4(%r15)
movq %rbx, 0x8(%r15)
movq %r13, 0x10(%r15)
movq 0x10(%rsp), %rax
movq %rax, 0x18(%r15)
movq %rbp, 0x20(%r15)
jmp 0x38ec
movq %rbx, %rdi
callq 0x4c1c
movq %r13, %rdi
callq 0xf03d
movq 0x10(%rsp), %rdi
callq 0xefb7
movq %rbp, %rdi
callq 0x1aa60
movl %r12d, %eax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl 0xb8(%rsp), %edx
movl 0x90(%rsp), %ebp
movl 0x88(%rsp), %ebx
movq (%r13), %rsi
movq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0xdc95
testl %ebx, %ebx
jne 0x3961
movq 0x20(%r14), %rcx
movl 0x44(%rcx), %eax
testl %eax, %eax
jg 0x3936
movl 0x40(%rcx), %eax
addl %eax, %eax
leal (%rax,%rax,4), %ebx
movq 0x226ae(%rip), %rax     # 0x25ff0
movq (%rax), %rdi
leaq 0x1b79e(%rip), %rsi     # 0x1f0ea
leaq 0x1b757(%rip), %rdx     # 0x1f0aa
movl %ebx, %ecx
xorl %eax, %eax
callq 0x2280
movq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0xf719
movq %rax, %r13
testl %ebp, %ebp
movq 0x2267b(%rip), %rbp     # 0x25ff0
je 0x3a0e
xorps %xmm0, %xmm0
movq %r14, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x4ca0
movq %rax, 0x28(%rsp)
movq %r14, %rdi
movq %rax, %rsi
movl $0x1, %edx
movl $0x1, %ecx
xorl %r8d, %r8d
callq 0x6049
leal (%rbx,%rbx), %eax
leal (%rax,%rax,4), %ecx
movl 0xb8(%rsp), %ebp
movl %ebp, 0x8(%rsp)
movq $0x0, (%rsp)
movsd 0x1b63f(%rip), %xmm0    # 0x1f008
movq %r14, %rdi
movq 0x28(%rsp), %rsi
movl %ebx, %edx
movl %ebx, %r8d
movsd 0x18(%rsp), %xmm1
movl 0xa0(%rsp), %r9d
callq 0x2e2f
movq 0x22600(%rip), %rax     # 0x25ff0
movq (%rax), %rsi
movq %r14, %rdi
movl %ebp, %edx
movq 0x225f1(%rip), %rbp     # 0x25ff0
callq 0xdc95
movq 0x28(%rsp), %rdi
callq 0x4c1c
movq (%rbp), %rdi
leaq 0x1b6fa(%rip), %rsi     # 0x1f113
leaq 0x1b68a(%rip), %rdx     # 0x1f0aa
xorl %eax, %eax
callq 0x2280
movq %r14, %rdi
movq %r13, %rsi
movl %ebx, %edx
movsd 0x18(%rsp), %xmm0
callq 0x4ca0
movq %rax, %rbx
testq %rax, %rax
je 0x3aa0
movq %rbx, %rdi
callq 0x5b3a
testl %eax, %eax
jne 0x3aa0
movq 0xa8(%rsp), %r15
movq (%rbp), %rdi
leaq 0x1b6eb(%rip), %rsi     # 0x1f14c
leaq 0x1b642(%rip), %rdx     # 0x1f0aa
xorl %eax, %eax
callq 0x2280
movq (%rbp), %rsi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x5b73
movq %rbp, %r14
movq (%rbp), %rsi
cmpl $0x2, 0xb8(%rsp)
jl 0x3aaa
movq %rbx, %rdi
movq %r15, %rdx
movq 0x10(%rsp), %rcx
callq 0x25e1
jmp 0x3abd
callq 0x26c3
jmp 0x3894
movq %rsi, %rdi
movq %rbx, %rsi
movq %r15, %rdx
movq 0x10(%rsp), %rcx
callq 0x2550
movl 0x30(%rsp), %ebp
movq (%r14), %rdi
leaq 0x1b6f7(%rip), %rsi     # 0x1f1c2
leaq 0x1b5d8(%rip), %rdx     # 0x1f0aa
xorl %eax, %eax
callq 0x2280
movslq %ebp, %rsi
movslq 0x80(%rsp), %r14
movl 0xb8(%rsp), %ebp
movq %rsi, 0x18(%rsp)
cmpl $0x0, 0x98(%rsp)
jle 0x3aff
xorl %r15d, %r15d
jmp 0x3b3c
movq 0x8(%rbx), %rdi
movl %ebp, (%rsp)
xorl %edx, %edx
xorl %ecx, %ecx
movl $0x1, %r8d
xorl %r9d, %r9d
callq 0x16f90
movq %rax, %r12
movq 0x8(%rbx), %rdi
movsd 0x38(%rsp), %xmm0
movsd 0x1b4e3(%rip), %xmm1    # 0x1f010
xorl %esi, %esi
movl %ebp, %edx
callq 0x16d36
movq %rax, %r15
addq %r12, %r15
movq 0x8(%rbx), %rdi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movq %r14, %rdx
movl $0x1, %ecx
xorl %r8d, %r8d
movl %ebp, %r9d
callq 0x16797
addq %r15, %rax
movq 0x18(%rsp), %rsi
jne 0x3af0
movq %rbx, %rdi
callq 0x7356
movl $0x1, %edi
movl $0x18, %esi
callq 0x2250
movq %rax, %rbp
cmpl $0x0, 0x98(%rsp)
jle 0x3d77
movq %r13, 0x30(%rsp)
movq 0x2245a(%rip), %rax     # 0x25ff0
movq (%rax), %rdi
leaq 0x1b641(%rip), %rsi     # 0x1f1e1
leaq 0x1b503(%rip), %rdx     # 0x1f0aa
xorl %eax, %eax
callq 0x2280
xorps %xmm1, %xmm1
cvtsi2sdl 0x24(%rsp), %xmm1
movsd 0x1b459(%rip), %xmm0    # 0x1f018
divsd %xmm1, %xmm0
callq 0x24e0
cvttsd2si %xmm0, %r15
movl $0x1, %r12d
movq 0x10(%rsp), %rdi
movl 0xa0(%rsp), %ecx
movq %rbp, %rsi
movq %rbx, %rdx
movl $0x1, %r8d
callq 0x1aabc
movq %rbx, %rdi
callq 0x5e76
movq %rbx, %rdi
movq %rbp, %rsi
movl %r15d, %edx
movsd 0x1b407(%rip), %xmm0    # 0x1f010
movsd 0x1b40f(%rip), %xmm1    # 0x1f020
callq 0x7385
movl %eax, %r13d
cmpl $0x0, 0xb8(%rsp)
jg 0x3c48
testl %r13d, %r13d
movq 0x10(%rsp), %rdi
movl 0xa0(%rsp), %ecx
je 0x3c55
leal 0x1(%r12), %eax
cmpl 0x98(%rsp), %r12d
movl %eax, %r12d
jl 0x3bdf
jmp 0x3c55
movl %r12d, %edi
movq %rbx, %rsi
callq 0x2687
jmp 0x3c23
movq %rdi, %r15
movq %rbp, %rsi
movq %rbx, %rdx
movl %ecx, %r12d
movl $0x1, %r8d
callq 0x1aabc
movq %rbx, %rdi
movq %r15, %rsi
movq %rbp, %rdx
xorl %ecx, %ecx
movl 0xb8(%rsp), %r13d
movl %r13d, %r8d
callq 0xbef2
movq 0x8(%rbx), %rdi
movsd 0x1b37d(%rip), %xmm1    # 0x1f010
movsd 0x38(%rsp), %xmm0
xorl %esi, %esi
movl %r13d, %edx
callq 0x16d36
movq %rbx, %rdi
callq 0x92e0
movq %r15, %rdi
movq %rbp, %rsi
movq %rbx, %rdx
movl %r12d, %ecx
xorl %r8d, %r8d
callq 0x1aabc
movq %rbx, %rdi
movq %r15, %rsi
movq %rbp, %rdx
movl %r13d, %ecx
callq 0xa9dc
movq %rbx, %rdi
movq %r15, %rsi
movq %rbp, 0x28(%rsp)
movq %rbp, %rdx
movl $0x1, %ecx
movl %r13d, %r8d
callq 0xbef2
movq %r15, %rdi
movq %rbx, %rsi
xorl %edx, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x6049
movq 0x18(%rsp), %rbp
movq 0x8(%rbx), %rdi
movl %r13d, (%rsp)
movq %rbp, %rsi
xorl %edx, %edx
xorl %ecx, %ecx
movl $0x1, %r8d
xorl %r9d, %r9d
callq 0x16f90
movq %rax, %r15
movq 0x8(%rbx), %rdi
movsd 0x38(%rsp), %xmm0
movsd 0x1b2dc(%rip), %xmm1    # 0x1f010
xorl %esi, %esi
movl %r13d, %edx
callq 0x16d36
movq %rax, %r12
addq %r15, %r12
movq 0x8(%rbx), %rdi
movl $0x7fffffff, %esi       # imm = 0x7FFFFFFF
movq %r14, %rdx
movl $0x1, %ecx
xorl %r8d, %r8d
movl %r13d, %r9d
callq 0x16797
addq %r12, %rax
jne 0x3d02
movq %rbx, %rdi
callq 0x7356
movq 0x30(%rsp), %r13
movq 0x28(%rsp), %rbp
xorl %r12d, %r12d
movq 0x10(%rsp), %r15
movq %r15, %rdi
movq %rbp, %rsi
movq %rbx, %rdx
movl 0xa0(%rsp), %ecx
xorl %r8d, %r8d
callq 0x1aabc
movq %rbx, %rdi
movq %r15, %rsi
movq %rbp, %rdx
movl 0xb8(%rsp), %r14d
movl %r14d, %ecx
callq 0xa9dc
movq %rbx, %rdi
movq %r15, %rsi
movq %rbp, %rdx
movl $0x1, %ecx
movl %r14d, %r8d
callq 0xbef2
movq 0x22223(%rip), %r14     # 0x25ff0
movq (%r14), %rdi
leaq 0x1b465(%rip), %rsi     # 0x1f23c
leaq 0x1b2cc(%rip), %rdx     # 0x1f0aa
xorl %eax, %eax
callq 0x2280
movq (%r14), %rsi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x5b73
leaq 0x1b477(%rip), %rsi     # 0x1f270
movq 0xa8(%rsp), %rdi
callq 0x1cb4d
movq %rax, %r14
movq %r15, %rdi
movq %rbx, %rsi
xorl %edx, %edx
xorl %ecx, %ecx
movq %rax, %r8
callq 0x6049
movq %r14, %rdi
callq 0x2140
movq 0xb0(%rsp), %r15
jmp 0x3896