<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def maf_permutation(context_counts, context_to_mut, seq_context, gene_seq, num_permutations=10000, drop_silent=False):
 """Performs null-permutations across all genes and records the results in a format like a MAF file. This could be useful for examining the null permutations because the alternative approaches always summarize the results. With the simulated null-permutations, novel metrics can be applied to create an empirical null-distribution. Parameters context_counts : pd.Series number of mutations for each context context_to_mut : dict dictionary mapping nucleotide context to a list of observed somatic base changes. seq_context : SequenceContext Sequence context for the entire gene sequence (regardless of where mutations occur). The nucleotide contexts are identified at positions along the gene. gene_seq : GeneSequence Sequence of gene of interest num_permutations : int, default: 10000 number of permutations to create for null drop_silent : bool, default=False Flage on whether to drop all silent mutations. Some data sources do not report silent mutations, and the simulations should match this. Returns ------- maf_list : list of tuples list of null mutations with mutation info in a MAF like format """

    mycontexts = context_counts.index.tolist()
    somatic_base, base_context = zip(*[(base, one_context)
                                       for one_context in mycontexts
                                       for base in context_to_mut[one_context]])

    # get random positions determined by sequence context
    tmp_contxt_pos = seq_context.random_pos(context_counts.iteritems(),
                                            num_permutations)
    tmp_mut_pos = np.hstack(pos_array for base, pos_array in tmp_contxt_pos)

    # info about gene
    gene_name = gene_seq.bed.gene_name
    strand = gene_seq.bed.strand
    chrom = gene_seq.bed.chrom
    gene_seq.bed.init_genome_coordinates()  # map seq pos to genome

    # determine result of random positions
    maf_list = []
    for row in tmp_mut_pos:
        # get genome coordinate
        pos2genome = np.vectorize(lambda x: gene_seq.bed.seqpos2genome[x]+1)
        genome_coord = pos2genome(row)

        # get info about mutations
        tmp_mut_info = mc.get_aa_mut_info(row,
                                          somatic_base,
                                          gene_seq)

        # get string describing variant
        var_class = cutils.get_variant_classification(tmp_mut_info['Reference AA'],
                                                      tmp_mut_info['Somatic AA'],
                                                      tmp_mut_info['Codon Pos'])

        # prepare output
        for k, mysomatic_base in enumerate(somatic_base):
            # format DNA change
            ref_nuc = tmp_mut_info['Reference Nuc'][k]
            nuc_pos = row[k]
            dna_change = 'c.{0}{1}>{2}'.format(ref_nuc, nuc_pos, mysomatic_base)

            # format protein change
            ref_aa = tmp_mut_info['Reference AA'][k]
            somatic_aa = tmp_mut_info['Somatic AA'][k]
            codon_pos = tmp_mut_info['Codon Pos'][k]
            protein_change = 'p.{0}{1}{2}'.format(ref_aa, codon_pos, somatic_aa)

            # reverse complement if on negative strand
            if strand == '-':
                ref_nuc = utils.rev_comp(ref_nuc)
                mysomatic_base = utils.rev_comp(mysomatic_base)

            # append results
            if drop_silent and var_class[k].decode() == 'Silent': continue
            maf_line = [gene_name, strand, chrom, genome_coord[k], genome_coord[k],
                        ref_nuc, mysomatic_base, base_context[k], dna_change,
                        protein_change, var_class[k].decode()]
            maf_list.append(maf_line)

    return maf_list