On Fri, Sep 30, 2005 at 02:08:55AM -0700, Jeremy T. Bouse wrote:
hmmm.... would you mind sending me the .fwb file from which it's
generated?
i'll need to identify where id3AECF776 comes from - i may have
only added things like hosts into service groups.
can you add _service groups_ to service groups?
if you use more of the features of fwbuilder than i have, this sort of
thing is likely to occur.
> The traceback I get from both my fwb data files are similar. The last
> one I ran with the version you sent me is below:
>
> Traceback (most recent call last):
> File "./fw_report.py", line 533, in ?
> f.decode_service_groups(o)
> File "./fw_report.py", line 251, in decode_service_groups
> self.decode_svc_grp(g)
> File "./fw_report.py", line 239, in decode_svc_grp
> self.decode_svc_group_members(l)
> File "./fw_report.py", line 225, in decode_svc_group_members
> print """
> KeyError: u'id3AECF776'
>
>
> Luke Kenneth Casson Leighton wrote:
> > jeremy,
> >
> > i am running - have been running - with 2.0.7.
> >
> > make sure you have an appropriate version of python, 2.2 and 2.3 should
> > do it.
> >
> > also make sure you have, or recommend to people to have,
> > the python xml libraries installed:
> >
> > [EMAIL PROTECTED]:~$ dpkg -l > f
> > vi f
> > /[EMAIL PROTECTED]:~$ vi f
> > [EMAIL PROTECTED]:~$ grep python f | grep xml
> > ii python2.2-xml 0.8.3-4
> > XML tools for Python (2.2.x)
> > ii python2.2-xmlbase 2.2.3-8
> > XML support included in Python (v2.2)
> > ii python2.3-xml 0.8.3-4
> > XML tools for Python (2.3.x)
> >
> >
> > you do not explain what traceback is "failing to complete" - a copy of
> > that traceback would have been helpful, i can only guess what the
> > problem is, therefore.
> >
> > my guess is that you do not have python-xml installed.
> >
> > latest version attached: there was something i had to update, can't
> > remember what it was...
> >
> > l.
> >
> > On Wed, Sep 28, 2005 at 12:46:50PM -0700, Jeremy T. Bouse wrote:
> >
> >> I am currently working on the 2.0.9 packaging of fwbuilder. If you
> >>want to make sure that the script supports atleast 2.0.7 which is
> >>currently in testing I would be willing to consider including in the
> >>examples directory and adding a note in the README.Debian regarding it
> >>with the 2.0.9 upload if you can get back in time. I did find that when
> >>I ran it against a couple of my .fwb files it failed to complete
> >>properly and threw a traceback.
> >>
> >> Also include as an attachment rather than inline next time so I can
> >>just download rather than cut and paste.
> >>
> >> Regards,
> >> Jeremy
> >>
> >>Luke Kenneth Casson Leighton wrote:
> >>
> >>
> >>>Package: fwbuilder
> >>>Version: 2.0.3-2
> >>>Severity: normal
> >>>
> >>>
> >>>attached is a joyously useful program that makes up for the lack of
> >>>print reporting in fwbuilder.
> >>>
> >>>it's a dog, it's hacked, it works. i wouldn't recommend making python a
> >>>dependency because of it, but i _would_ recommend dumping it in the
> >>>/usr/share/doc/fwbuilder/examples directory and referencing it in the
> >>>README.
> >>>
> >>>or makin a separate apt-get install package for it (with a dep on
> >>>python)
> >>>
> >>>l.
> >>>
> >>>#!/usr/bin/env python
> >>>
> >>
> >>>from xml.dom.minidom import parseString, parse
> >>
> >>>
> >>>class fw:
> >>>
> >>> def __init__(self):
> >>>
> >>> self.hosts = {}
> >>> self.descriptions = {}
> >>>
> >>> def print_comment(self, c):
> >>> print '<pre>'
> >>> for l in c.split("\\n"):
> >>> while l:
> >>> bp = l.find(' ', 50)
> >>> if bp < 50: bp = 50
> >>> if len(l) >= 50:
> >>> end = l.rfind(' ')
> >>> if end <= 50:
> >>> bp = end
> >>> print "%s" % l[:bp]
> >>> l = l[bp:]
> >>> print '</pre>'
> >>>
> >>>
> >>> def decode_address_ranges(self, i):
> >>> adrs = []
> >>> print '<table class="tabledataindent">'
> >>> for a in i:
> >>> print '<tr class="tablerow" valign="top">'
> >>> self.descriptions[a.getAttribute('id')] =
> >>> a.getAttribute('name')
> >>> print """
> >>> <td> %s: </td>
> >>> <td> %s </td>
> >>> <td> %s </td>
> >>> """ % \
> >>> (a.getAttribute('name'),
> >>> a.getAttribute('start_address'),
> >>> a.getAttribute('end_address'))
> >>>
> >>> comment = a.getAttribute('comment')
> >>> if comment:
> >>> print '</tr>'
> >>> print '<tr class="tablerow" valign="top">'
> >>> print '<td> </td>'
> >>> print '<td colspan="2">'
> >>> self.print_comment(comment)
> >>> print '</td>'
> >>> print '</tr>'
> >>> print '</table>'
> >>>
> >>> def decode_ipv4(self, i):
> >>> adrs = []
> >>> print '<table class="tabledataindent">'
> >>> for a in i:
> >>> self.descriptions[a.getAttribute('id')] =
> >>> a.getAttribute('name')
> >>> print '<tr class="tablerow" valign="top">'
> >>> print "<td>%s: </td> <td>%s/%s</td>" % \
> >>> (a.getAttribute('name'),
> >>> a.getAttribute('address'),
> >>> a.getAttribute('netmask'))
> >>> print "</tr>"
> >>> comment = a.getAttribute('comment')
> >>> if comment:
> >>> print '</tr>'
> >>> print '<tr class="tablerow" valign="top">'
> >>> print '<td> </td>'
> >>> print '<td colspan="2">'
> >>> self.print_comment(comment)
> >>> print '</td>'
> >>> print '</tr>'
> >>> print '</table>'
> >>>
> >>> def decode_interface(self, i):
> >>> self.descriptions[i.getAttribute('id')] =
> >>> i.getAttribute('name')
> >>>
> >>> print '<tr class="tablerow" valign="top">'
> >>> print "<td>Interface: %-8s </td> <td> %s </td>" % \
> >>> (i.getAttribute('name'), i.getAttribute('label'))
> >>> print "<td>"
> >>> self.decode_ipv4(i.getElementsByTagName('IPv4'))
> >>> print "</td>"
> >>> print "</tr>"
> >>>
> >>> def get_desc(self, id):
> >>> if type(id) is not list:
> >>> id = [id]
> >>> l = []
> >>> for i in id:
> >>> l.append(self.descriptions.get(i, "<unknown: %s>" %
> >>> str(i)))
> >>> return '<br />'.join(l)
> >>>
> >>> def decode_host(self, h):
> >>> self.descriptions[h.getAttribute('id')] =
> >>> h.getAttribute('name')
> >>>
> >>> print "<td>"
> >>>
> >>> print '<table class="tabledata">'
> >>> print '<tr class="tablerow" valign="top"><td>'
> >>> print "Hostname: <br /> %s" % h.getAttribute('name')
> >>> print "</td></tr>"
> >>> print '</table>'
> >>>
> >>> print "</td>"
> >>>
> >>> print "<td>"
> >>>
> >>> print '<table class="tabledata">'
> >>> for i in h.getElementsByTagName('Interface'):
> >>> self.decode_interface(i)
> >>> print '</table>'
> >>>
> >>> print "</td>"
> >>>
> >>> def decode_hosts(self, o):
> >>>
> >>> print '<table class="tabledataindent">'
> >>> hl = o.getElementsByTagName('Host')
> >>> for h in hl:
> >>> print '<tr class="tablerow" valign="top">'
> >>> self.decode_host(h)
> >>> print '</tr>'
> >>> print '</table>'
> >>>
> >>> def decode_svc_icmp(self, t):
> >>>
> >>> self.descriptions[t.getAttribute('id')] =
> >>> t.getAttribute('name')
> >>> print """
> >>> <tr class="section">
> >>>
> >>> <td class="name"> Name: %-10s </td>
> >>> <td class="item"> Code: %s </td>
> >>> <td class="item"> Type: %s </td>
> >>> </tr>
> >>> """ % \
> >>> (t.getAttribute('name'),
> >>> t.getAttribute('code'),
> >>> t.getAttribute('type'))
> >>>
> >>> def decode_svc_tcp(self, t):
> >>>
> >>> self.descriptions[t.getAttribute('id')] =
> >>> t.getAttribute('name')
> >>>
> >>> start = int(t.getAttribute('dst_range_start'))
> >>> end = int(t.getAttribute('dst_range_end'))
> >>>
> >>> if start == end:
> >>> dest = '%d' % start
> >>> else:
> >>> dest = '%d-%d' % (start, end)
> >>>
> >>> print """
> >>> <tr class="section">
> >>>
> >>> <td class="name"> Name: %-10s </td>
> >>> <td class="item"> Dest: %s </td>
> >>> </tr>
> >>> """ % \
> >>> (t.getAttribute('name'), dest)
> >>>
> >>> def print_heading(self, sh):
> >>>
> >>> print '<table class="heading">'
> >>> print '<tr><td>'
> >>> print sh
> >>> print '</td></tr>'
> >>> print '</table>'
> >>>
> >>> def print_subheading(self, sh, comment=''):
> >>>
> >>> print '<table>'
> >>> print '<tr><td>'
> >>>
> >>> print '<table class="subheading">'
> >>> print '<tr><td>'
> >>> print sh
> >>> print '</td></tr>'
> >>> print '</table>'
> >>>
> >>> print '</td></tr>'
> >>>
> >>> print '<tr>'
> >>> print '<td>'
> >>> print '<div class="subindented">'
> >>> self.print_comment(comment)
> >>> print '</div>'
> >>> print '</td>'
> >>> print '</tr>'
> >>>
> >>> print '</table>'
> >>>
> >>>
> >>> def decode_svc_group_members(self, i):
> >>>
> >>> print '<table class="tabledataindent">'
> >>> for a in i:
> >>> print '<tr class="tablerow" valign="top">'
> >>> print """
> >>> <td> %s </td>
> >>> """ % self.descriptions[a]
> >>> print '</tr>'
> >>> print '</table>'
> >>>
> >>> def decode_svc_grp(self, h):
> >>> self.descriptions[h.getAttribute('id')] =
> >>> h.getAttribute('name')
> >>> self.print_subheading("Service Group: %s" %
> >>> h.getAttribute('name'),
> >>> h.getAttribute('comment'))
> >>> print '<div class="indented">'
> >>> l = []
> >>> for n in h.getElementsByTagName('ServiceRef'):
> >>> l.append(n.getAttribute('ref'))
> >>> self.decode_svc_group_members(l)
> >>> print '</div>'
> >>>
> >>> def decode_service_groups(self, o):
> >>>
> >>> ts = o.getElementsByTagName('ServiceGroup')
> >>> self.print_subheading("Service Groups")
> >>> print '<div class="subindented">'
> >>> for t in ts:
> >>> n = t.getAttribute('name')
> >>> if n == 'Groups':
> >>> for g in
> >>> t.getElementsByTagName('ServiceGroup'):
> >>> self.decode_svc_grp(g)
> >>> print '</div>'
> >>>
> >>> def decode_services(self, o):
> >>>
> >>> ts = o.getElementsByTagName('UDPService')
> >>> self.print_subheading("UDP Services")
> >>> print '<table class="tabledataindent">'
> >>> for t in ts:
> >>> self.decode_svc_tcp(t)
> >>> print '</table>'
> >>>
> >>> ts = o.getElementsByTagName('TCPService')
> >>> self.print_subheading("TCP Services")
> >>> print '<table class="tabledataindent">'
> >>> for t in ts:
> >>> self.decode_svc_tcp(t)
> >>> print '</table>'
> >>>
> >>> ts = o.getElementsByTagName('ICMPService')
> >>> self.print_subheading("ICMP Services")
> >>> print '<table class="tabledataindent">'
> >>> for t in ts:
> >>> self.decode_svc_icmp(t)
> >>> print '</table>'
> >>>
> >>> def get_srvref(self, c, ref):
> >>> r = c.getElementsByTagName(ref)
> >>> ans = []
> >>> for n in r[0].getElementsByTagName('ServiceRef'):
> >>> ans.append(n.getAttribute('ref'))
> >>> return ans
> >>>
> >>> def get_ref(self, c, ref):
> >>> r = c.getElementsByTagName(ref)
> >>> ans = []
> >>> for n in r[0].getElementsByTagName('ObjectRef'):
> >>> ans.append(n.getAttribute('ref'))
> >>> return ans
> >>>
> >>> def decode_policyrule(self, nr):
> >>>
> >>> print '<tr class="tablerow" valign="top">'
> >>>
> >>> print '<td> %s </td>' % nr.getAttribute('action')
> >>>
> >>> comment = nr.getAttribute('comment')
> >>> print '<td>'
> >>> self.print_comment(comment)
> >>> print '</td>'
> >>>
> >>> src = self.get_ref(nr, 'Src')
> >>> dst = self.get_ref(nr, 'Dst')
> >>> srv = self.get_srvref(nr, 'Srv')
> >>>
> >>> print """<td>
> >>>
> >>> <table class="tabledata">
> >>> <tr class="tablerow" valign="top"> <td> Src:
> >>> </td> <td> %s </td> </tr>
> >>> <tr class="tablerow" valign="top"> <td>
> >>> Dest: </td> <td> %s </td> </tr>
> >>> <tr class="tablerow" valign="top"> <td>
> >>> Service: </td> <td> %s </td> </tr>
> >>> </table>
> >>> </td>
> >>> """ % \
> >>> (self.get_desc(src),
> >>> self.get_desc(dst),
> >>> self.get_desc(srv))
> >>>
> >>> print '</tr>'
> >>>
> >>> def decode_natrule(self, nr):
> >>>
> >>> print '<tr class="tablerow" valign="top">'
> >>>
> >>> comment = nr.getAttribute('comment')
> >>> print '<td>'
> >>> self.print_comment(comment)
> >>> print '</td>'
> >>>
> >>> osrc = self.get_ref(nr, 'OSrc')
> >>> odst = self.get_ref(nr, 'ODst')
> >>> osrv = self.get_srvref(nr, 'OSrv')
> >>> tsrc = self.get_ref(nr, 'TSrc')
> >>> tdst = self.get_ref(nr, 'TDst')
> >>> tsrv = self.get_srvref(nr, 'TSrv')
> >>>
> >>> print """
> >>> <td>
> >>> <table class="tabledata">
> >>> <tr class="tablerow" valign="top"> <td> Original
> >>> Src: </td> <td> %s </td> </tr>
> >>> <tr class="tablerow" valign="top"> <td> Original
> >>> Dest: </td> <td> %s </td> </tr>
> >>> <tr class="tablerow" valign="top"> <td> Original
> >>> Service: </td> <td> %s </td> </tr>
> >>> </table>
> >>> </td>
> >>> """ % \
> >>> (self.get_desc(osrc),
> >>> self.get_desc(odst),
> >>> self.get_desc(osrv))
> >>>
> >>> print """
> >>> <td>
> >>>
> >>> <table class="tabledata">
> >>> <tr class="tablerow" valign="top"> <td> Target Src:
> >>> </td> <td> %s </td> </tr>
> >>> <tr class="tablerow" valign="top"> <td> Target Dest:
> >>> </td> <td> %s </td> </tr>
> >>> <tr class="tablerow" valign="top"> <td> Target
> >>> Service: </td> <td> %s </td> </tr>
> >>> </table>
> >>> </td>
> >>> """ % \
> >>> (self.get_desc(tsrc),
> >>> self.get_desc(tdst),
> >>> self.get_desc(tsrv))
> >>>
> >>> print '</tr>'
> >>>
> >>> def decode_fw_interface(self, n):
> >>> self.print_subheading("Interface: %s" %
> >>> n.getAttribute('name'),
> >>> n.getAttribute('comment'))
> >>>
> >>> print '<table class="tabledataindent">'
> >>> for pr in n.getElementsByTagName('PolicyRule'):
> >>> self.decode_policyrule(pr)
> >>> print '</table>'
> >>>
> >>> def decode_policy(self, n):
> >>> self.print_subheading("Policy:")
> >>> print '<table class="tabledataindent">'
> >>> for nr in n.getElementsByTagName('PolicyRule'):
> >>> self.decode_policyrule(nr)
> >>> print '</table>'
> >>>
> >>> def decode_nat(self, n):
> >>> self.print_subheading("NAT:")
> >>> print '<table class="tabledataindent">'
> >>> for nr in n.getElementsByTagName('NATRule'):
> >>> self.decode_natrule(nr)
> >>> print '</table>'
> >>>
> >>> def decode_group_members(self, i):
> >>>
> >>> print '<table class="tabledataindent">'
> >>> for a in i:
> >>> print '<tr class="tablerow" valign="top">'
> >>> print """
> >>> <td> %s </td>
> >>> """ % self.descriptions[a]
> >>> print '</tr>'
> >>> print '</table>'
> >>>
> >>> def decode_group(self, h):
> >>> self.descriptions[h.getAttribute('id')] =
> >>> h.getAttribute('name')
> >>> self.print_subheading("Group: %s" % h.getAttribute('name'),
> >>> h.getAttribute('comment'))
> >>> print '<div class="indented">'
> >>> l = []
> >>> for n in h.getElementsByTagName('ObjectRef'):
> >>> l.append(n.getAttribute('ref'))
> >>> self.decode_group_members(l)
> >>> print '</div>'
> >>>
> >>> def decode_groups(self, h):
> >>> print '<div class="indented">'
> >>> for n in h.getElementsByTagName('ObjectGroup'):
> >>> self.decode_group(n)
> >>> print '</div>'
> >>>
> >>> def decode_firewall(self, h):
> >>> self.print_subheading("Firewall: %s" %
> >>> h.getAttribute('name'))
> >>> print '<div class="indented">'
> >>> for n in h.getElementsByTagName('Interface'):
> >>> self.decode_interface(n)
> >>> for n in h.getElementsByTagName('Policy'):
> >>> self.decode_policy(n)
> >>> for n in h.getElementsByTagName('NAT'):
> >>> self.decode_nat(n)
> >>> for n in h.getElementsByTagName('Interface'):
> >>> self.decode_fw_interface(n)
> >>> print '</div>'
> >>>
> >>> def decode_firewalls(self, o):
> >>>
> >>> hl = o.getElementsByTagName('Firewall')
> >>> for fw in hl:
> >>> self.decode_firewall(fw)
> >>>
> >>>if __name__ == '__main__':
> >>>
> >>> from sys import argv
> >>>
> >>> fd = open(argv[1], "r")
> >>> doc = parse(fd)
> >>>
> >>> f = fw()
> >>>
> >>> print "<html>"
> >>> print """
> >>><style type="text/css">
> >>>.tabledataindent
> >>>{
> >>> color: #000000;
> >>> background: #aaffaa;
> >>> border-color: #000000 #999999 #999999 #000000;
> >>> border-style: solid;
> >>> border-top-width: 1px;
> >>> border-right-width: 1px;
> >>> border-bottom-width: 1px;
> >>> border-left-width: 1px;
> >>> margin-left: 40px;
> >>>}
> >>>.tablerow
> >>>{
> >>> color: #000000;
> >>> background: #ccffcc;
> >>> border-color: #000000 #999999 #999999 #000000;
> >>> border-style: solid;
> >>> border-top-width: 1px;
> >>> border-right-width: 1px;
> >>> border-bottom-width: 1px;
> >>> border-left-width: 1px;
> >>>}
> >>>.tabledata
> >>>{
> >>> color: #000000;
> >>> background: #ccffcc;
> >>>}
> >>>.heading
> >>>{
> >>> font-size: 20;
> >>> font-family: Verdana, Arial, Helvetica, sans-serif;
> >>> color: #000000;
> >>> background: #aaaaff;
> >>> margin-top: 40px;
> >>> margin-bottom: 10px;
> >>> border-style: solid;
> >>> border-top-width: 1px;
> >>> border-right-width: 1px;
> >>> border-bottom-width: 1px;
> >>> border-left-width: 1px;
> >>>}
> >>>.subheading
> >>>{
> >>> font-size: 15;
> >>> font-family: Verdana, Arial, Helvetica, sans-serif;
> >>> color: #000000;
> >>> background: #ccccff;
> >>> margin-top: 15px;
> >>> margin-left: 20px;
> >>> margin-right: 20px;
> >>> border-style: solid;
> >>> border-top-width: 1px;
> >>> border-right-width: 1px;
> >>> border-bottom-width: 1px;
> >>> border-left-width: 1px;
> >>>}
> >>>.indented
> >>>{
> >>> margin-left: 40px;
> >>>}
> >>>.subindented
> >>>{
> >>> margin-left: 20px;
> >>> margin-bottom: 10px;
> >>>}
> >>></style>
> >>> """
> >>> print "<body>"
> >>>
> >>> lib = doc.getElementsByTagName('Library')
> >>> f.descriptions['sysid0'] = 'Any Network'
> >>> f.descriptions['sysid1'] = 'Any IP Service'
> >>>
> >>> svcs = doc.getElementsByTagName('ServiceGroup')
> >>>
> >>> for o in svcs:
> >>> n = o.getAttribute('name')
> >>> if n == 'Services':
> >>> f.print_heading(n)
> >>> f.decode_services(o)
> >>>
> >>> for o in svcs:
> >>> n = o.getAttribute('name')
> >>> if n == 'Services':
> >>> f.decode_service_groups(o)
> >>>
> >>> objs = doc.getElementsByTagName('ObjectGroup')
> >>>
> >>> for o in objs:
> >>> n = o.getAttribute('name')
> >>>
> >>> if n == 'Hosts':
> >>> f.print_heading(n)
> >>> f.decode_hosts(o)
> >>>
> >>> if n == 'Address Ranges':
> >>> f.print_heading(n)
> >>>
> >>> f.decode_address_ranges(o.getElementsByTagName('AddressRange'))
> >>>
> >>> if n == 'Addresses':
> >>> f.print_heading(n)
> >>> f.decode_ipv4(o.getElementsByTagName('IPv4'))
> >>> print
> >>>
> >>> for o in objs:
> >>> n = o.getAttribute('name')
> >>> if n == 'Groups':
> >>> f.print_heading(n)
> >>> f.decode_groups(o)
> >>> print
> >>>
> >>> for o in objs:
> >>> n = o.getAttribute('name')
> >>> if n == 'Firewalls':
> >>> f.print_heading(n)
> >>> f.decode_firewalls(o)
> >>> print
> >>>
> >>> print "</body>"
> >>> print "</html>"
> >>>-- System Information:
> >>>Debian Release: testing/unstable
> >>>Architecture: i386
> >>>Kernel: Linux highfield 2.6.11-1-686 #1 Fri May 20 07:34:54 UTC 2005 i686
> >>>Locale: LANG=C, LC_CTYPE=C
> >>>
> >>>Versions of packages fwbuilder depends on:
> >>>ii fwbuilder-common 2.0.3-2 Firewall administration tool
> >>>GUI (
> >>>ii fwbuilder-linux [fwbuild 2.0.3-2 Firewall Builder policy
> >>>compiler(s
> >>>ii libc6 2.3.2.ds1-21 GNU C Library: Shared
> >>>libraries an
> >>>ii libfwbuilder6 2.0.3-1 Firewall Builder API library
> >>>ii libgcc1 1:3.5-0pre1 GCC support library
> >>>ii libqt3c102-mt 3:3.3.4-3 Qt GUI Library (Threaded
> >>>runtime v
> >>>ii libsnmp5 5.1.2-6 NET SNMP (Simple Network
> >>>Managemen
> >>>ii libssl0.9.7 0.9.7c-5 SSL shared libraries
> >>>ii libstdc++5 1:3.3.4-11 The GNU Standard C++ Library
> >>>v3
> >>>ii libwrap0 7.6-ipv6.1-3 Wietse Venema's TCP wrappers
> >>>libra
> >>>ii libx11-6 4.3.0.dfsg.1-6 X Window System protocol
> >>>client li
> >>>ii libxext6 4.3.0.dfsg.1-6 X Window System miscellaneous
> >>>exte
> >>>ii libxml2 2.6.16-7 GNOME XML library
> >>>ii libxslt1.1 1.1.12-8 XSLT processing library -
> >>>runtime ii xlibs 4.3.0.dfsg.1-11 X Keyboard Extension
> >>>(XKB) configu
> >>>ii zlib1g 1:1.2.1-3 compression library - runtime
> >>>
> >>>-- no debconf information
> >>>
> >>>
> >>>
> >>>
> >
> >
--
--
<a href="http://lkcl.net">http://lkcl.net</a>
--
--
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]