Get weblogo data for a sequence alignment.

    Returns a list of tuples: (posn, letter_counts, entropy, weight)
495451
def read_logodata(handle):
    
    seqs = weblogolib.read_seq_data(handle,
                                    alphabet=unambiguous_protein_alphabet)
    ldata = weblogolib.LogoData.from_seqs(seqs)
    letters = ldata.alphabet.letters()
    counts = ldata.counts.array
    logodata = []
    for i, coldata, entropy, weight in zip(range(len(counts)), counts,
                                           ldata.entropy, ldata.weight):
        cnts = dict((let, int(cnt))
                    for let, cnt in zip(letters, coldata))
        logodata.append((i + 1, cnts, entropy, weight))
    return logodata
812092
def get_nts(self):
        """"""
        data = []
        nt_obj = None
        with open(self.fin) as fin_stream:
            for lnum, line in enumerate(fin_stream, 1):
                try:
                    line = line.rstrip('\r\n') # chomp
                    # Obtain Data if headers have been collected from the first line
                    if nt_obj is not None:
                        flds = re.split(self.sep, line)
                        self.convert_ints_floats(flds)
                        flds[6] = [s.strip() for s in flds[6].split(',')]
                        ntdata = nt_obj._make(flds)
                        data.append(ntdata)
                    # Obtain the header
                    else:
                        nt_obj = self._init_nt_hdr(line)
                except RuntimeError:
                    # Print headers
                    #if nt_obj is not None:
                    #  sys.stdout.write("{HDRS}\n".format(HDRS='\n'.join(nt_obj._fields)))
                    flds = re.split(self.sep, line)
                    print(len(flds), "FIELDS")
                    print(flds)
                    #raise Exception("{FIN}({LNUM}): {LINE}\n".format(
                    #  FIN=self.fin, LNUM=lnum, LINE=line))
                    # JUST SKIP LINES WITH INCOMPLETE DATA, BUT PRINT ERROR MESSAGE
                    sys.stdout.write("**ERROR: {FIN}({LNUM}): {LINE}\n".format(
                        FIN=self.fin, LNUM=lnum, LINE=line))
            if self.log is not None:
                self.log.write("  {:9} lines READ:  {}\n".format(len(data), self.fin))
        return data
320084
def getpexts(lsp):
    '''
    
    '''
    lines=lsp.split('\n');
    #unfortunately regex doesn't work here
    lns,planens = zip(
        *[ (i,int(re.search('^ *extract *([0-9]+)',line).group(1)))
           for i,line in enumerate(lines)
           if re.search('^ *extract *[0-9]+', line)]);
    if len(lns) == 0: return [];
    end = lns[-1];
    
    for i,line in enumerate(lines[end+1:]):
        if re.match(' *\[',line): break;
    end += i;
    lineranges = zip(lns,(lns+(end,))[1:]);
    planes=dict()
    for (i,end),plane in zip(lineranges,planens):
        d=dict();
        labels = [
            'species',
            'direction',
            'position',];
        datarx = [
            '^ *species *([0-9]+)',
            '^ *direction *([xXyYzZ])',
            '^ *at *(.*)',];
        convs  = [
            lambda s: int(s),
            lambda i: i,
            lambda s: np.array(
                map(float,s.split(' '))),
        ];
        for line in lines[i:end]:
            for label,rx,conv in zip(labels,datarx,convs):
                if re.match(rx,line):
                    d[label]=conv(re.match(rx,line).group(1));
                pass
            pass
        planes[plane] = d;
    return planes;
1120340
def _read_phi(self, wt):
        

        self.vocabulary = {}
        phi_features = {}

        # TODO: make this encoding-safe.
        with open(wt, "r") as f:
            reader = csv.reader(f, delimiter=' ')
            topics = defaultdict(list)
            for line in reader:
                w, term = int(line[0]), unicode(line[1])
                self.vocabulary[w] = term

                for l in line[2:]:
                    k, c = l.split(':')    # Topic and assignment count.
                    topics[int(k)].append((w, int(c)))

        for k, data in topics.iteritems():
            nfeature = Feature(data).norm

            phi_features[k] = nfeature
        self.phi = FeatureSet(phi_features)
1081527
def pair_hmm_align_unaligned_seqs(seqs, moltype=DNA_cogent, params={}):
    

    seqs = LoadSeqs(data=seqs, moltype=moltype, aligned=False)
    try:
        s1, s2 = seqs.values()
    except ValueError:
        raise ValueError(
            "Pairwise aligning of seqs requires exactly two seqs.")

    try:
        gap_open = params['gap_open']
    except KeyError:
        gap_open = 5
    try:
        gap_extend = params['gap_extend']
    except KeyError:
        gap_extend = 2
    try:
        score_matrix = params['score_matrix']
    except KeyError:
        score_matrix = make_dna_scoring_dict(
            match=1, transition=-1, transversion=-1)

    return local_pairwise(s1, s2, score_matrix, gap_open, gap_extend)
416761
def from_string(data):
        
       
        root=ET.fromstring(data)
        speciesnode=root.find('structure').iter('species')
        elements = []
        positions = []
        vectors=[]
        lockxyz=[]
        # get title
        title_in=str(root.find('title').text)
        # Read elements and coordinates
        for nodes in speciesnode:
            symbol = nodes.get('speciesfile').split('.')[0]
            if len(symbol.split('_'))==2:
              symbol=symbol.split('_')[0]
            if Element.is_valid_symbol(symbol):
                # Try to recognize the element symbol
                element = symbol
            else:
                raise NLValueError("Unknown element!")
            natoms = nodes.getiterator('atom')
            for atom in natoms:
                x, y, z = atom.get('coord').split()
                positions.append([float(x), float(y), float(z)])
                elements.append(element)
                # Obtain lockxyz for each atom
                if atom.get('lockxyz') is not None:
                    lxy=[]
                    for l in atom.get('lockxyz').split():
                        if l=='True' or l=='true':
                            lxyz.append(True)
                        else:
                            lxyz.append(False)
                    lockxyz.append(lxyz)
                else:
                    lockxyz.append([False, False, False])
        #check the atomic positions type
        if 'cartesian' in root.find('structure').attrib.keys():
          if root.find('structure').attrib['cartesian']:
            cartesian=True
            for i in range(len(positions)):
                for j in range(3):
                    positions[i][j]=positions[i][j]*ExcitingInput.bohr2ang
            print(positions)
        else:
          cartesian=False
        # get the scale attribute
        scale_in=root.find('structure').find('crystal').get('scale')
        if scale_in:
            scale=float(scale_in)*ExcitingInput.bohr2ang
        else:
            scale=ExcitingInput.bohr2ang
       # get the stretch attribute
        stretch_in=root.find('structure').find('crystal').get('stretch')
        if stretch_in:
          stretch=np.array([float(a) for a in stretch_in])
        else:
          stretch=np.array([1.0,1.0,1.0])
        # get basis vectors and scale them accordingly
        basisnode=root.find('structure').find('crystal').iter('basevect')
        for vect in basisnode:
          x, y, z=vect.text.split()
          vectors.append([float(x)*stretch[0]*scale,
                          float(y)*stretch[1]*scale,
                          float(z)*stretch[2]*scale])
        # create lattice and structure object
        lattice_in=Lattice(vectors)
        structure_in=Structure(lattice_in,elements,positions,coords_are_cartesian=cartesian)

        return ExcitingInput(structure_in, title_in, lockxyz)
456064
def _get_sequences(self, *sequences):
        
        # by words
        if not self.qval:
            return [s.split() for s in sequences]
        # by chars
        if self.qval == 1:
            return sequences
        # by n-grams
        return [find_ngrams(s, self.qval) for s in sequences]
757050
def get_sentence_xpath_tuples(filename_url_or_filelike,
                              xpath_to_text=TEXT_FINDER_XPATH):
    

    parsed_html = get_html_tree(filename_url_or_filelike)

    try:
        xpath_finder = parsed_html.getroot().getroottree().getpath
    except(AttributeError):
        xpath_finder = parsed_html.getroottree().getpath

    nodes_with_text = parsed_html.xpath(xpath_to_text)

    sent_xpath_pairs = [
        # hard-code paragraph breaks (there has to be a better way)
        ('\n\n' + s, xpath_finder(n)) if e == 0
        else (s, xpath_finder(n))
        for n in nodes_with_text
        for e, s in enumerate(SENTENCE_TOKEN_PATTERN.split(
            BRACKET_PATTERN.sub('', ''.join(n.xpath('.//text()')))))
        if s.endswith(tuple(SENTENCE_ENDING))
        ]

    return sent_xpath_pairs
910453
def get_selected_text_metrics(self):
        

        selected_text = self.get_selected_text()
        if not selected_text:
            return tuple()

        return (selected_text, self.get_cursor_line(), self.get_cursor_column() - len(selected_text))
334077
def get_proteininfo_fields(poolnames=False, genecentric=False):
    """"""
    allfields = OrderedDict()
    basefields = {
            False: [
                prottabledata.HEADER_GENEID, prottabledata.HEADER_GENENAME,
                prottabledata.HEADER_DESCRIPTION, prottabledata.HEADER_COVERAGE,
                prottabledata.HEADER_NO_PROTEIN, prottabledata.HEADER_CONTENTPROT,
                ],
            'genes': [
                prottabledata.HEADER_GENENAME, prottabledata.HEADER_PROTEINS,
                prottabledata.HEADER_DESCRIPTION],
            'assoc': [
                prottabledata.HEADER_GENEID, prottabledata.HEADER_PROTEINS,
                prottabledata.HEADER_DESCRIPTION],
            }[genecentric]
    poolfields = [prottabledata.HEADER_NO_UNIPEP,
                  prottabledata.HEADER_NO_PEPTIDE,
                  prottabledata.HEADER_NO_PSM,
                  ]
    for field in basefields:
        allfields[field] = False
    for field in poolfields:
        allfields[field] = poolnames
    return allfields
930810
def gotonext(self):
        """"""
        wslist = []
        while self.pos < len(self.field):
            if self.field[self.pos] in self.LWS + '\n\r':
                if self.field[self.pos] not in '\n\r':
                    wslist.append(self.field[self.pos])
                self.pos += 1
            elif self.field[self.pos] == '(':
                self.commentlist.append(self.getcomment())
            else:
                break
        return EMPTYSTRING.join(wslist)
991145
def bamtag(sam):
    ''' 
    '''
    from pysam import AlignmentFile

    start_time = time.time()

    sam_file = open_bamfile(sam)
    out_file = AlignmentFile("-", "wh", template=sam_file)
    track = sam_file.fetch(until_eof=True)

    # peek at first alignment to determine the annotations
    if is_python3():
        queryalignment = next(track)
    else:
        queryalignment = track.next()
    annotations = detect_alignment_annotations(queryalignment)
    track = itertools.chain([queryalignment], track)

    re_string = construct_transformed_regex(annotations)
    parser_re = re.compile(re_string)

    for count, aln in enumerate(track, start=1):
        if count and not count % 1000000:
            logger.info("Processed %d alignments." % count)

        match = parser_re.match(aln.qname)
        tags = aln.tags

        if "cellular" in annotations:
            aln.tags += [('XC', match.group('CB'))]
        if "molecular" in annotations:
            aln.tags += [('RX', match.group('MB'))]
        if "sample" in annotations:
            aln.tags += [('XS', match.group('SB'))]

        out_file.write(aln)

    total_time = time.time() - start_time
    logger.info('BAM tag conversion done - {:.3}s, {:,} alns/min'.format(total_time, int(60. * count / total_time)))
    logger.info("Processed %d alignments." % count)
886323
def get_bp_stats(sam, genomes, s2b, qual):
    
    for read in parse_sam(sam, qual):
        ref = read[2] # scaffold that read mapped to
        if ref not in s2b:
            continue
        genome = s2b[ref] # genome that scaffold belongs to
        refs = genomes[genome][ref][sam.name]['bp_stats']
        ref_start = int(read[3]) - 1 # position of start of alignment on reference
        ref_pos = int(read[3]) - 1 # for keeping track of reference region
        sequence = list(read[9]) # read sequence
        cigar = parse_cigar(read[5]) # parsed cigar string
        cigar_start = 0 # for keeping track of start of cigar regions
        bases = [] # bases to compare with reference
        for cigar_pos, status in cigar:
            if status == 'D': # deletion compared to reference
                refs[ref_pos - 1]['Del'].append(cigar_pos)
                for b in range(0, cigar_pos):
                    bases.append(False)
                ref_pos += cigar_pos
            else:
                cigar_stop = cigar_start + cigar_pos
                if status == 'M': # aligned to reference
                    for b in sequence[cigar_start:cigar_stop]: # bases for cigar region
                        bases.append(b)
                    ref_pos += cigar_pos
                elif status == 'I': # insertion compared to reference
                    refs[ref_pos - 1]['In'].append(cigar_pos)
                else:
                    print('# unrecognized cigar character: %s' % (status), file=sys.stderr)
                    exit()
                cigar_start += cigar_pos
        # add base to frequency at each position
        for base, position in zip(bases, list(range(ref_start, ref_start + len(bases)))):
            if base is False:
                continue
            try:
                refs[position][base.upper()] += 1
            except IndexError:
                continue
    return genomes
966584
def get_summary_metrics(self, align_metrics, dup_metrics,
            insert_metrics=None, hybrid_metrics=None, vrn_vals=None,
            rnaseq_metrics=None):
        
        with open(align_metrics) as in_handle:
            align_vals = self._parse_align_metrics(in_handle)
        if dup_metrics:
            with open(dup_metrics) as in_handle:
                dup_vals = self._parse_dup_metrics(in_handle)
        else:
            dup_vals = {}
        (insert_vals, hybrid_vals, rnaseq_vals) = (None, None, None)
        if insert_metrics and file_exists(insert_metrics):
            with open(insert_metrics) as in_handle:
                insert_vals = self._parse_insert_metrics(in_handle)
        if hybrid_metrics and file_exists(hybrid_metrics):
            with open(hybrid_metrics) as in_handle:
                hybrid_vals = self._parse_hybrid_metrics(in_handle)
        if rnaseq_metrics and file_exists(rnaseq_metrics):
            with open(rnaseq_metrics) as in_handle:
                rnaseq_vals = self._parse_rnaseq_metrics(in_handle)

        return self._tabularize_metrics(align_vals, dup_vals, insert_vals,
                hybrid_vals, vrn_vals, rnaseq_vals)
776694
def parse_reports(self):
    

    self.qualimap_rnaseq_genome_results = dict()
    regexes = {
        'reads_aligned': r"read(?:s| pairs) aligned\s*=\s*([\d,]+)",
        'total_alignments': r"total alignments\s*=\s*([\d,]+)",
        'non_unique_alignments': r"non-unique alignments\s*=\s*([\d,]+)",
        'reads_aligned_genes': r"aligned to genes\s*=\s*([\d,]+)",
        'ambiguous_alignments': r"ambiguous alignments\s*=\s*([\d,]+)",
        'not_aligned': r"not aligned\s*=\s*([\d,]+)",
        '5_3_bias': r"5'-3' bias\s*=\s*([\d,\.]+)$",
        'reads_aligned_exonic': r"exonic\s*=\s*([\d,]+)",
        'reads_aligned_intronic': r"intronic\s*=\s*([\d,]+)",
        'reads_aligned_intergenic': r"intergenic\s*=\s*([\d,]+)",
        'reads_aligned_overlapping_exon': r"overlapping exon\s*=\s*([\d,]+)",
    }
    for f in self.find_log_files('qualimap/rnaseq/rnaseq_results'):
        d = dict()

        # Get the sample name
        s_name_regex = re.search(r"bam file\s*=\s*(.+)", f['f'], re.MULTILINE)
        if s_name_regex:
            d['bam_file'] = s_name_regex.group(1)
            s_name = self.clean_s_name(d['bam_file'], f['root'])
        else:
            log.warn("Couldn't find an input filename in genome_results file {}/{}".format(f['root'], f['fn']))
            return None

        # Check for and 'fix' European style decimal places / thousand separators
        comma_regex = re.search(r"exonic\s*=\s*[\d\.]+ \(\d{1,3},\d+%\)", f['f'], re.MULTILINE)
        if comma_regex:
            log.debug("Trying to fix European comma style syntax in Qualimap report {}/{}".format(f['root'], f['fn']))
            f['f'] = f['f'].replace('.','')
            f['f'] = f['f'].replace(',','.')

        # Go through all numeric regexes
        for k, r in regexes.items():
            r_search = re.search(r, f['f'], re.MULTILINE)
            if r_search:
                try:
                    d[k] = float(r_search.group(1).replace(',',''))
                except UnicodeEncodeError:
                    # Qualimap reports infinity (\u221e) when 3' bias denominator is zero
                    pass
                except ValueError:
                    d[k] = r_search.group(1)

        # Add to general stats table
        for k in ['5_3_bias', 'reads_aligned']:
            try:
                self.general_stats_data[s_name][k] = d[k]
            except KeyError:
                pass

        # Save results
        if s_name in self.qualimap_rnaseq_genome_results:
            log.debug("Duplicate genome results sample name found! Overwriting: {}".format(s_name))
        self.qualimap_rnaseq_genome_results[s_name] = d
        self.add_data_source(f, s_name=s_name, section='rna_genome_results')


    #### Coverage profile
    self.qualimap_rnaseq_cov_hist = dict()
    for f in self.find_log_files('qualimap/rnaseq/coverage', filehandles=True):
        s_name = self.get_s_name(f)
        d = dict()
        for l in f['f']:
            if l.startswith('#'):
                continue
            coverage, count = l.split(None, 1)
            coverage = int(round(float(coverage)))
            count = float(count)
            d[coverage] = count

        if len(d) == 0:
            log.debug("Couldn't parse contents of coverage histogram file {}".format(f['fn']))
            return None

        # Save results
        if s_name in self.qualimap_rnaseq_cov_hist:
            log.debug("Duplicate coverage histogram sample name found! Overwriting: {}".format(s_name))
        self.qualimap_rnaseq_cov_hist[s_name] = d
        self.add_data_source(f, s_name=s_name, section='rna_coverage_histogram')

    # Filter to strip out ignored sample names
    self.qualimap_rnaseq_genome_results = self.ignore_samples(self.qualimap_rnaseq_genome_results)
    self.qualimap_rnaseq_cov_hist = self.ignore_samples(self.qualimap_rnaseq_cov_hist)

    #### Plots

    # Genomic Origin Bar Graph
    # NB: Ignore 'Overlapping Exon' in report - these make the numbers add up to > 100%
    if len(self.qualimap_rnaseq_genome_results) > 0:
        gorigin_cats = OrderedDict()
        gorigin_cats['reads_aligned_exonic'] = {'name': 'Exonic'}
        gorigin_cats['reads_aligned_intronic'] = {'name': 'Intronic'}
        gorigin_cats['reads_aligned_intergenic'] = {'name': 'Intergenic'}
        gorigin_pconfig = {
            'id': 'qualimap_genomic_origin',
            'title': 'Qualimap RNAseq: Genomic Origin',
            'ylab': 'Number of reads',
            'cpswitch_c_active': False
        }
        genomic_origin_helptext = '''
        There are currently three main approaches to map reads to transcripts in an
        RNA-seq experiment: mapping reads to a reference genome to identify expressed
        transcripts that are annotated (and discover those that are unknown), mapping
        reads to a reference transcriptome, and <i>de novo</i> assembly of transcript
        sequences (<a href="https://doi.org/10.1186/s13059-016-0881-8"
        target="_blank">Conesa et al. 2016</a>).

        For RNA-seq QC analysis, QualiMap can be used to assess alignments produced by
        the first of these approaches. For input, it requires a GTF annotation file
        along with a reference genome, which can be used to reconstruct the exon
        structure of known transcripts. This allows mapped reads to be grouped by
        whether they originate in an exonic region (for QualiMap, this may include
        5&#8242; and 3&#8242; UTR regions as well as protein-coding exons), an intron,
        or an intergenic region (see the <a href="http://qualimap.bioinfo.cipf.es/doc_html/index.html"
        target="_blank">Qualimap 2 documentation</a>).

        The inferred genomic origins of RNA-seq reads are presented here as a bar graph
        showing either the number or percentage of mapped reads in each read dataset
        that have been assigned to each type of genomic region. This graph can be used
        to assess the proportion of useful reads in an RNA-seq experiment. That
        proportion can be reduced by the presence of intron sequences, especially if
        depletion of ribosomal RNA was used during sample preparation (<a href="https://doi.org/10.1038/nrg3642"
        target="_blank">Sims et al. 2014</a>). It can also be reduced by off-target
        transcripts, which are detected in greater numbers at the sequencing depths
        needed to detect poorly-expressed transcripts (<a href="https://doi.org/10.1101/gr.124321.111"
        target="_blank">Tarazona et al. 2011</a>).'''
        self.add_section (
            name = 'Genomic origin of reads',
            anchor = 'qualimap-reads-genomic-origin',
            description = 'Classification of mapped reads as originating in exonic, intronic or intergenic regions. These can be displayed as either the number or percentage of mapped reads.',
            helptext = genomic_origin_helptext,
            plot = bargraph.plot(self.qualimap_rnaseq_genome_results, gorigin_cats, gorigin_pconfig)
        )

    if len(self.qualimap_rnaseq_cov_hist) > 0:
        coverage_profile_helptext = '''
        There are currently three main approaches to map reads to transcripts in an
        RNA-seq experiment: mapping reads to a reference genome to identify expressed
        transcripts that are annotated (and discover those that are unknown), mapping
        reads to a reference transcriptome, and <i>de novo</i> assembly of transcript
        sequences (<a href="https://doi.org/10.1186/s13059-016-0881-8"
        target="_blank">Conesa et al. 2016</a>).

        For RNA-seq QC analysis, QualiMap can be used to assess alignments produced by
        the first of these approaches. For input, it requires a GTF annotation file
        along with a reference genome, which can be used to reconstruct the exon
        structure of known transcripts. QualiMap uses this information to calculate the
        depth of coverage along the length of each annotated transcript. For a set of
        reads mapped to a transcript, the depth of coverage at a given base position is
        the number of high-quality reads that map to the transcript at that position
        (<a href="https://doi.org/10.1038/nrg3642" target="_blank">Sims et al. 2014</a>).

        QualiMap calculates coverage depth at every base position of each annotated
        transcript. To enable meaningful comparison between transcripts, base positions
        are rescaled to relative positions expressed as percentage distance along each
        transcript (*0%, 1%, &#8230;, 99%*). For the set of transcripts with at least
        one mapped read, QualiMap plots the cumulative mapped-read depth (y-axis) at
        each relative transcript position (x-axis). This plot shows the gene coverage
        profile across all mapped transcripts for each read dataset. It provides a
        visual way to assess positional biases, such as an accumulation of mapped reads
        at the 3&#8242; end of transcripts, which may indicate poor RNA quality in the
        original sample (<a href="https://doi.org/10.1186/s13059-016-0881-8"
        target="_blank">Conesa et al. 2016</a>).'''
        self.add_section (
            name = 'Gene Coverage Profile',
            anchor = 'qualimap-genome-fraction-coverage',
            description = 'Mean distribution of coverage depth across the length of all mapped transcripts.',
            helptext = coverage_profile_helptext,
            plot = linegraph.plot(self.qualimap_rnaseq_cov_hist, {
                'id': 'qualimap_gene_coverage_profile',
                'title': 'Qualimap RNAseq: Coverage Profile Along Genes (total)',
                'ylab': 'Coverage',
                'xlab': 'Transcript Position (%)',
                'ymin': 0,
                'xmin': 0,
                'xmax': 100,
                'tt_label': '<b>{point.x} bp</b>: {point.y:.0f}%',
            })
        )


    #### General Stats
    self.general_stats_headers['5_3_bias'] = {
        'title': "5'-3' bias",
        'format': '{:,.2f}',
    }
    self.general_stats_headers['reads_aligned'] = {
        'title': '{} Aligned'.format(config.read_count_prefix),
        'description': 'Reads Aligned ({})'.format(config.read_count_desc),
        'min': 0,
        'scale': 'RdBu',
        'shared_key': 'read_count',
        'modify': lambda x: x * config.read_count_multiplier
    }

    # Return the number of reports we found
    return len(self.qualimap_rnaseq_genome_results.keys())
1248555
def extract_metas(bs4):
    

    meta_tags = []

    metas = bs4.select('meta')

    for meta in metas:

        meta_content = {}

        meta_attrs = [
            'charset',
            'name',
            'content',
            'property',
            'http-equiv',
            'itemprop'
        ]

        for attr in meta_attrs:
            if meta.has_attr(attr):
                meta_content.update({attr: meta[attr]})

        meta_tags.append(meta_content)

    return meta_tags
835508
async def parseResults(self, api_data):
    
    results = []

    # parse HTML and get results
    parser = lxml.etree.HTMLParser()
    html = lxml.etree.XML(api_data.decode("latin-1"), parser)

    for rank, result in enumerate(__class__.RESULTS_SELECTOR(html), 1):
      # extract url
      metadata_div = result.find("div")
      metadata_json = lxml.etree.tostring(metadata_div, encoding="unicode", method="text")
      metadata_json = json.loads(metadata_json)
      google_url = result.find("a").get("href")
      if google_url is not None:
        query = urllib.parse.urlsplit(google_url).query
      else:
        query = None
      if not query:
        img_url = metadata_json["ou"]
      else:
        query = urllib.parse.parse_qs(query)
        img_url = query["imgurl"][0]
      # extract format
      check_metadata = CoverImageMetadata.NONE
      format = metadata_json["ity"].lower()
      try:
        format = SUPPORTED_IMG_FORMATS[format]
      except KeyError:
        # format could not be identified or is unknown
        format = None
        check_metadata = CoverImageMetadata.FORMAT
      # extract size
      if not query:
        size = metadata_json["ow"], metadata_json["oh"]
      else:
        size = tuple(map(int, (query["w"][0], query["h"][0])))
      # extract thumbnail url
      thumbnail_url = metadata_json["tu"]
      # result
      results.append(GoogleImagesCoverSourceResult(img_url,
                                                   size,
                                                   format,
                                                   thumbnail_url=thumbnail_url,
                                                   source=self,
                                                   rank=rank,
                                                   check_metadata=check_metadata))

    return results