{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from collections import defaultdict, OrderedDict\n", "import warnings\n", "import gffutils\n", "import pybedtools\n", "import pandas as pd\n", "import copy\n", "import os\n", "import re\n", "from gffutils.pybedtools_integration import tsses\n", "from copy import deepcopy\n", "from collections import OrderedDict, Callable\n", "import errno\n", "\n", "def mkdir_p(path):\n", " try:\n", " os.makedirs(path)\n", " except OSError as exc: # Python >2.5\n", " if exc.errno == errno.EEXIST and os.path.isdir(path):\n", " pass\n", " else:\n", " raise\n", "\n", "class DefaultOrderedDict(OrderedDict):\n", " # Source: http://stackoverflow.com/a/6190500/562769\n", " def __init__(self, default_factory=None, *a, **kw):\n", " if (default_factory is not None and\n", " not isinstance(default_factory, Callable)):\n", " raise TypeError('first argument must be callable')\n", " OrderedDict.__init__(self, *a, **kw)\n", " self.default_factory = default_factory\n", "\n", " def __getitem__(self, key):\n", " try:\n", " return OrderedDict.__getitem__(self, key)\n", " except KeyError:\n", " return self.__missing__(key)\n", "\n", " def __missing__(self, key):\n", " if self.default_factory is None:\n", " raise KeyError(key)\n", " self[key] = value = self.default_factory()\n", " return value\n", "\n", " def __reduce__(self):\n", " if self.default_factory is None:\n", " args = tuple()\n", " else:\n", " args = self.default_factory,\n", " return type(self), args, None, None, self.items()\n", "\n", " def copy(self):\n", " return self.__copy__()\n", "\n", " def __copy__(self):\n", " return type(self)(self.default_factory, self)\n", "\n", " def __deepcopy__(self, memo):\n", " import copy\n", " return type(self)(self.default_factory,\n", " copy.deepcopy(self.items()))\n", "\n", " def __repr__(self):\n", " return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,\n", " OrderedDict.__repr__(self))\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "gtf = '/home/cmb-panasas2/skchoudh/genomes/escherichia_coli_str_k_12_substr_mg1655/annotation/Escherichia_coli_str_k_12_substr_mg1655.ASM584v2.38.gtf'\n", "gtf_db = '/home/cmb-panasas2/skchoudh/genomes/escherichia_coli_str_k_12_substr_mg1655/annotation/Escherichia_coli_str_k_12_substr_mg1655.ASM584v2.38.gtf.db'\n", "prefix = '/home/cmb-panasas2/skchoudh/github_projects/riboraptor/riboraptor/annotation/MG1655/ASM584v2.38/'\n", "chrsizes = '/home/cmb-panasas2/skchoudh/genomes/escherichia_coli_str_k_12_substr_mg1655/fasta/Escherichia_coli_str_k_12_substr_mg1655.ASM584v2.dna.toplevel.sizes'\n", "mkdir_p(prefix)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "db = gffutils.create_db(gtf, dbfn=gtf_db, disable_infer_genes=True, disable_infer_transcripts=True, merge_strategy='merge', force=True)\n", "def create_gene_dict(db):\n", " '''\n", " Store each feature line db.all_features() as a dict of dicts\n", " '''\n", " gene_dict = DefaultOrderedDict(lambda: DefaultOrderedDict(lambda: DefaultOrderedDict(list)))\n", " for line_no, feature in enumerate(db.all_features()):\n", " gene_ids = feature.attributes['gene_id']\n", " feature_type = feature.featuretype\n", " if feature_type == 'gene':\n", " if len(gene_ids)!=1:\n", " logging.warning('Found multiple gene_ids on line {} in gtf'.format(line_no))\n", " break\n", " else:\n", " gene_id = gene_ids[0]\n", " gene_dict[gene_id]['gene'] = feature\n", " else:\n", " transcript_ids = feature.attributes['transcript_id']\n", "\n", " for gene_id in gene_ids:\n", " for transcript_id in transcript_ids:\n", " gene_dict[gene_id][transcript_id][feature_type].append(feature)\n", " return gene_dict\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CDS\n", "exon\n", "gene\n", "start_codon\n", "stop_codon\n", "transcript\n" ] } ], "source": [ "db = gffutils.FeatureDB(gtf_db, keep_order=True)\n", "gene_dict = create_gene_dict(db)\n", "for x in db.featuretypes():\n", " print(x)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def get_gene_list(gene_dict):\n", " return list(set(gene_dict.keys()))\n", "\n", "def get_UTR_regions(gene_dict, gene_id, transcript, cds):\n", " if len(cds)==0:\n", " return [], []\n", " utr5_regions = []\n", " utr3_regions = []\n", " utrs = gene_dict[gene_id][transcript]['UTR']\n", " first_cds = cds[0]\n", " last_cds = cds[-1]\n", " for utr in utrs:\n", " ## Push all cds at once\n", " ## Sort later to remove duplicates\n", " strand = utr.strand\n", " if strand == '+':\n", " if utr.stop < first_cds.start:\n", " utr.feature_type = 'five_prime_UTR'\n", " utr5_regions.append(utr)\n", " elif utr.start > last_cds.stop:\n", " utr.feature_type = 'three_prime_UTR'\n", " utr3_regions.append(utr)\n", " else:\n", " raise RuntimeError('Error with cds')\n", " elif strand == '-':\n", " if utr.stop < first_cds.start:\n", " utr.feature_type = 'three_prime_UTR'\n", " utr3_regions.append(utr)\n", " elif utr.start > last_cds.stop:\n", " utr.feature_type = 'five_prime_UTR'\n", " utr5_regions.append(utr) \n", " else:\n", " raise RuntimeError('Error with cds') \n", " return utr5_regions, utr3_regions\n", " \n", "def create_bed(regions, bedtype='0'):\n", " '''Create bed from list of regions\n", " bedtype: 0 or 1\n", " 0-Based or 1-based coordinate of the BED\n", " '''\n", " bedstr = ''\n", " for region in regions:\n", " assert len(region.attributes['gene_id']) == 1\n", " ## GTF start is 1-based, so shift by one while writing \n", " ## to 0-based BED format\n", " if bedtype == '0':\n", " start = region.start - 1\n", " else:\n", " start = region.start\n", " bedstr += '{}\\t{}\\t{}\\t{}\\t{}\\t{}\\n'.format(region.chrom,\n", " start,\n", " region.stop,\n", " re.sub('\\.\\d+', '', region.attributes['gene_id'][0]),\n", " '.',\n", " region.strand)\n", " return bedstr\n", "\n", "def rename_regions(regions, gene_id):\n", " regions = list(regions)\n", " if len(regions) == 0:\n", " return []\n", " for region in regions:\n", " region.attributes['gene_id'] = gene_id\n", " return regions\n", "\n", "def merge_regions(db, regions):\n", " if len(regions) == 0:\n", " return []\n", " merged = db.merge(sorted(list(regions), key=lambda x: x.start))\n", " return merged\n", "\n", "def merge_regions_nostrand(db, regions):\n", " if len(regions) == 0:\n", " return []\n", " merged = db.merge(sorted(list(regions), key=lambda x: x.start), ignore_strand=True)\n", " return merged" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gene_bed = ''\n", "exon_bed = ''\n", "intron_bed = ''\n", "start_codon_bed = ''\n", "stop_codon_bed = ''\n", "cds_bed = ''\n", "\n", "gene_list = []\n", "\n", "for gene_id in get_gene_list(gene_dict):\n", " gene_list.append(gene_dict[gene_id]['gene'])\n", " exon_regions, intron_regions = [], []\n", " star_codon_regions, stop_codon_regions = [], []\n", " cds_regions = []\n", " \n", " for feature in gene_dict[gene_id].keys():\n", " if feature == 'gene':\n", " continue\n", " cds = list(gene_dict[gene_id][feature]['CDS'])\n", " exons = list(gene_dict[gene_id][feature]['exon'])\n", " merged_exons = merge_regions(db, exons)\n", " introns = db.interfeatures(merged_exons)\n", " exon_regions += exons\n", " intron_regions += introns\n", " cds_regions += cds \n", " \n", " merged_exons = merge_regions(db, exon_regions)\n", " renamed_exons = rename_regions(merged_exons, gene_id)\n", " \n", " merged_introns = merge_regions(db, intron_regions)\n", " renamed_introns = rename_regions(merged_introns, gene_id)\n", " \n", " merged_cds = merge_regions(db, cds_regions)\n", " renamed_cds = rename_regions(merged_cds, gene_id)\n", " \n", " exon_bed += create_bed(renamed_exons)\n", " intron_bed += create_bed(renamed_introns)\n", " cds_bed += create_bed(renamed_cds)\n", " \n", "gene_bed = create_bed(gene_list)\n", "gene_bedtool = pybedtools.BedTool(gene_bed, from_string=True)\n", "exon_bedtool = pybedtools.BedTool(exon_bed, from_string=True)\n", "intron_bedtool = pybedtools.BedTool(intron_bed, from_string=True)\n", "cds_bedtool = pybedtools.BedTool(cds_bed, from_string=True)\n", "\n", "gene_bedtool.remove_invalid().sort().saveas(os.path.join(prefix, 'gene.bed.gz'))\n", "exon_bedtool.remove_invalid().sort().saveas(os.path.join(prefix, 'exon.bed.gz'))\n", "intron_bedtool.remove_invalid().sort().saveas(os.path.join(prefix, 'intron.bed.gz'))\n", "cds_bedtool.remove_invalid().sort().saveas(os.path.join(prefix, 'cds.bed.gz'))\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "for gene_id in get_gene_list(gene_dict):\n", " start_codons = []\n", " stop_codons = []\n", " for start_codon in db.children(gene_id, featuretype='start_codon'):\n", " ## 1 -based stop\n", " ## 0-based start handled while converting to bed\n", " start_codon.stop = start_codon.start\n", " start_codons.append(start_codon)\n", " for stop_codon in db.children(gene_id, featuretype='stop_codon'):\n", " stop_codon.start = stop_codon.stop\n", " stop_codon.stop = stop_codon.stop+1\n", " stop_codons.append(stop_codon)\n", " merged_start_codons = merge_regions(db, start_codons)\n", " renamed_start_codons = rename_regions(merged_start_codons, gene_id)\n", " merged_stop_codons = merge_regions(db, stop_codons)\n", " renamed_stop_codons = rename_regions(merged_stop_codons, gene_id)\n", " \n", " start_codon_bed += create_bed(renamed_start_codons) \n", " stop_codon_bed += create_bed(renamed_stop_codons)\n", "\n", " \n", "start_codon_bedtool = pybedtools.BedTool(start_codon_bed, from_string=True)\n", "stop_codon_bedtool = pybedtools.BedTool(stop_codon_bed, from_string=True)\n", "start_codon_bedtool.remove_invalid().sort().saveas(os.path.join(prefix, 'start_codon.bed.gz'))\n", "stop_codon_bedtool.remove_invalid().sort().saveas(os.path.join(prefix, 'stop_codon.bed.gz'))" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
chromstartendnamescorestrand
0Chromosome34854163485818b3356.-
1Chromosome30673423068080b2922.-
2Chromosome26450152647325b2519.-
3Chromosome26444352644864b2518.-
4Chromosome34812883483199b3352.+
5Chromosome34832013484221b3353.+
6Chromosome15837641583959b1500.-
7Chromosome26386652639283b2513.-
8Chromosome26374762638652b2512.-
9Chromosome26358862637356b2511.-
10Chromosome26356012635814b2510.-
11Chromosome26431312644283b2517.-
12Chromosome26418332642844b2516.-
13Chromosome26406882641804b2515.-
14Chromosome26393032640575b2514.-
15Chromosome30662793067173b2921.-
16Chromosome34076063409055b3258.+
17Chromosome30714613072622b2926.-
18Chromosome30726743073691b2927.-
19Chromosome34861193486749b3357.+
20Chromosome30689493069807b2924.-
21Chromosome22955852296320b2199.-
22Chromosome22953792295586b2198.-
23Chromosome22949032295380b2197.-
24Chromosome22929632294904b2196.-
25Chromosome22924092292964b2195.-
26Chromosome22913602292410b2194.-
27Chromosome22904992291144b2193.+
28Chromosome22890672290081b2192.-
29Chromosome42185954220329b4016.+
.....................
4111Chromosome33767843377420b3229.-
4112Chromosome20210872021498b1946.+
4113Chromosome33703493371036b3223.-
4114Chromosome33678263368951b3220.+
4115Chromosome33690163369478b3221.-
4116Chromosome33737003374489b3226.-
4117Chromosome33748683376233b3227.+
4118Chromosome33710863372574b3224.-
4119Chromosome33726853373576b3225.-
4120Chromosome38139313814384b3640.+
4121Chromosome19629741965050b1879.-
4122Chromosome39775243978601b4481.+
4123Chromosome38144933815087b3641.+
4124Chromosome44599024460364b4237.-
4125Chromosome29330432933688b2800.-
4126Chromosome38151293815768b3642.-
4127Chromosome42136824214123b4012.-
4128Chromosome38166753817536b3644.+
4129Chromosome38177593818581b3645.+
4130Chromosome38214273822048b3648.+
4131Chromosome38221053822378b3649.+
4132Chromosome38188733819488b3646.+
4133Chromosome32841693284643b3138.+
4134Chromosome32846843285485b3139.+
4135Chromosome32819753283127b3136.+
4136Chromosome32831423284000b3137.+
4137Chromosome32789133280191b3132.+
4138Chromosome32802163280687b3133.+
4139Chromosome32773363277798b3130.+
4140Chromosome32778583278665b3131.-
\n", "

4141 rows × 6 columns

\n", "
" ], "text/plain": [ " chrom start end name score strand\n", "0 Chromosome 3485416 3485818 b3356 . -\n", "1 Chromosome 3067342 3068080 b2922 . -\n", "2 Chromosome 2645015 2647325 b2519 . -\n", "3 Chromosome 2644435 2644864 b2518 . -\n", "4 Chromosome 3481288 3483199 b3352 . +\n", "5 Chromosome 3483201 3484221 b3353 . +\n", "6 Chromosome 1583764 1583959 b1500 . -\n", "7 Chromosome 2638665 2639283 b2513 . -\n", "8 Chromosome 2637476 2638652 b2512 . -\n", "9 Chromosome 2635886 2637356 b2511 . -\n", "10 Chromosome 2635601 2635814 b2510 . -\n", "11 Chromosome 2643131 2644283 b2517 . -\n", "12 Chromosome 2641833 2642844 b2516 . -\n", "13 Chromosome 2640688 2641804 b2515 . -\n", "14 Chromosome 2639303 2640575 b2514 . -\n", "15 Chromosome 3066279 3067173 b2921 . -\n", "16 Chromosome 3407606 3409055 b3258 . +\n", "17 Chromosome 3071461 3072622 b2926 . -\n", "18 Chromosome 3072674 3073691 b2927 . -\n", "19 Chromosome 3486119 3486749 b3357 . +\n", "20 Chromosome 3068949 3069807 b2924 . -\n", "21 Chromosome 2295585 2296320 b2199 . -\n", "22 Chromosome 2295379 2295586 b2198 . -\n", "23 Chromosome 2294903 2295380 b2197 . -\n", "24 Chromosome 2292963 2294904 b2196 . -\n", "25 Chromosome 2292409 2292964 b2195 . -\n", "26 Chromosome 2291360 2292410 b2194 . -\n", "27 Chromosome 2290499 2291144 b2193 . +\n", "28 Chromosome 2289067 2290081 b2192 . -\n", "29 Chromosome 4218595 4220329 b4016 . +\n", "... ... ... ... ... ... ...\n", "4111 Chromosome 3376784 3377420 b3229 . -\n", "4112 Chromosome 2021087 2021498 b1946 . +\n", "4113 Chromosome 3370349 3371036 b3223 . -\n", "4114 Chromosome 3367826 3368951 b3220 . +\n", "4115 Chromosome 3369016 3369478 b3221 . -\n", "4116 Chromosome 3373700 3374489 b3226 . -\n", "4117 Chromosome 3374868 3376233 b3227 . +\n", "4118 Chromosome 3371086 3372574 b3224 . -\n", "4119 Chromosome 3372685 3373576 b3225 . -\n", "4120 Chromosome 3813931 3814384 b3640 . +\n", "4121 Chromosome 1962974 1965050 b1879 . -\n", "4122 Chromosome 3977524 3978601 b4481 . +\n", "4123 Chromosome 3814493 3815087 b3641 . +\n", "4124 Chromosome 4459902 4460364 b4237 . -\n", "4125 Chromosome 2933043 2933688 b2800 . -\n", "4126 Chromosome 3815129 3815768 b3642 . -\n", "4127 Chromosome 4213682 4214123 b4012 . -\n", "4128 Chromosome 3816675 3817536 b3644 . +\n", "4129 Chromosome 3817759 3818581 b3645 . +\n", "4130 Chromosome 3821427 3822048 b3648 . +\n", "4131 Chromosome 3822105 3822378 b3649 . +\n", "4132 Chromosome 3818873 3819488 b3646 . +\n", "4133 Chromosome 3284169 3284643 b3138 . +\n", "4134 Chromosome 3284684 3285485 b3139 . +\n", "4135 Chromosome 3281975 3283127 b3136 . +\n", "4136 Chromosome 3283142 3284000 b3137 . +\n", "4137 Chromosome 3278913 3280191 b3132 . +\n", "4138 Chromosome 3280216 3280687 b3133 . +\n", "4139 Chromosome 3277336 3277798 b3130 . +\n", "4140 Chromosome 3277858 3278665 b3131 . -\n", "\n", "[4141 rows x 6 columns]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cds_bedtool.to_dataframe()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python [default]", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.15" } }, "nbformat": 4, "nbformat_minor": 2 }