Replace g.gettext by iwla._

Add createCurTitle() to factorize code
This commit is contained in:
Grégory Soutadé 2014-12-17 20:31:59 +01:00
parent c278ff30f0
commit ccab40b4e1
9 changed files with 68 additions and 84 deletions

View File

@ -27,6 +27,5 @@ max_downloads_displayed = 100
compress_output_files = ['html', 'css', 'js']
# locale = 'fr'
locale = 'fr_FR'
locale = 'fr'
# locale = 'fr_FR.utf8'

View File

@ -348,3 +348,8 @@ def generateHTMLLink(url, name=None, max_length=100, prefix=u'http'):
if not name: name = unicode(url)
if not url.startswith(prefix): url = u'%s://%s' % (prefix, url)
return u'<a href="%s">%s</a>' % (url, name[:max_length])
def createCurTitle(iwla, title):
title = iwla._(title) + time.strftime(u' - %B %Y', iwla.getCurTime())
return title

44
iwla.py
View File

@ -10,7 +10,7 @@ import gzip
import importlib
import argparse
import logging
import gettext as g
import gettext
from calendar import monthrange
from datetime import date
@ -131,19 +131,13 @@ class IWLA(object):
logging.basicConfig(format='%(name)s %(message)s', level=logLevel)
self.logger = logging.getLogger(self.__class__.__name__)
self.logger.info('==> Start')
# print conf.locales_path
# print conf.locale
#print g.find('iwla', localedir=conf.locales_path, all=False)
# print g.find('iwla', localedir=conf.locales_path, languages=[conf.locale], all=True)
#g.install('iwla', localedir=conf.locales_path)
t = g.translation('iwla', localedir=conf.locales_path, languages=[conf.locale])
self._ = t.gettext
#t.install()
# g.install('iwla', localedir=conf.locales_path, names=conf.locale)
print(self._('Statistics'))
# print(_('Statistics'))
try:
t = gettext.translation('iwla', localedir=conf.locales_path, languages=[conf.locale], codeset='utf8')
self.logger.info('\tUsing locale %s' % (conf.locale))
except IOError:
t = gettext.NullTranslations()
self.logger.info('\tUsing default locale en_EN')
self._ = t.ugettext
def getVersion(self):
return IWLA.IWLA_VERSION
@ -353,13 +347,13 @@ class IWLA(object):
def _generateDisplayDaysStats(self):
cur_time = self.meta_infos['last_time']
title = '%s %d/%02d' % (g.gettext('Statistics'), cur_time.tm_year, cur_time.tm_mon)
title = '%s %d/%02d' % (self._('Statistics'), cur_time.tm_year, cur_time.tm_mon)
filename = self.getCurDisplayPath('index.html')
self.logger.info('==> Generate display (%s)' % (filename))
page = self.display.createPage(title, filename, conf.css_path)
_, nb_month_days = monthrange(cur_time.tm_year, cur_time.tm_mon)
days = self.display.createBlock(DisplayHTMLBlockTableWithGraph, g.gettext('By day'), [g.gettext('Day'), g.gettext('Visits'), g.gettext('Pages'), g.gettext('Hits'), g.gettext('Bandwidth'), g.gettext('Not viewed Bandwidth')], None, nb_month_days, range(1,6))
days = self.display.createBlock(DisplayHTMLBlockTableWithGraph, self._('By day'), [self._('Day'), self._('Visits'), self._('Pages'), self._('Hits'), self._('Bandwidth'), self._('Not viewed Bandwidth')], None, nb_month_days, range(1,6))
days.setColsCSSClass(['', 'iwla_visit', 'iwla_page', 'iwla_hit', 'iwla_bandwidth', 'iwla_bandwidth'])
nb_visits = 0
nb_days = 0
@ -396,12 +390,12 @@ class IWLA(object):
else:
average_row = map(lambda(v): 0, row)
average_row[0] = g.gettext('Average')
average_row[0] = self._('Average')
average_row[4] = bytesToStr(average_row[4])
average_row[5] = bytesToStr(average_row[5])
days.appendRow(average_row)
row[0] = g.gettext('Total')
row[0] = self._('Total')
row[4] = bytesToStr(row[4])
row[5] = bytesToStr(row[5])
days.appendRow(row)
@ -410,9 +404,9 @@ class IWLA(object):
def _generateDisplayMonthStats(self, page, year, month_stats):
cur_time = time.localtime()
months_name = ['', g.gettext('Jan'), g.gettext('Feb'), g.gettext('Mar'), g.gettext('Apr'), g.gettext('May'), g.gettext('June'), g.gettext('July'), g.gettext('Aug'), g.gettext('Sep'), g.gettext('Oct'), g.gettext('Nov'), g.gettext('Dec')]
title = '%s %d' % (g.gettext('Summary'), year)
cols = [g.gettext('Month'), g.gettext('Visitors'), g.gettext('Visits'), g.gettext('Pages'), g.gettext('Hits'), g.gettext('Bandwidth'), g.gettext('Not viewed Bandwidth'), g.gettext('Details')]
months_name = ['', self._('Jan'), self._('Feb'), self._('Mar'), self._('Apr'), self._('May'), self._('June'), self._('July'), self._('Aug'), self._('Sep'), self._('Oct'), self._('Nov'), self._('Dec')]
title = '%s %d' % (self._('Summary'), year)
cols = [self._('Month'), self._('Visitors'), self._('Visits'), self._('Pages'), self._('Hits'), self._('Bandwidth'), self._('Not viewed Bandwidth'), self._('Details')]
graph_cols=range(1,7)
months = self.display.createBlock(DisplayHTMLBlockTableWithGraph, title, cols, None, 12, graph_cols)
months.setColsCSSClass(['', 'iwla_visitor', 'iwla_visit', 'iwla_page', 'iwla_hit', 'iwla_bandwidth', 'iwla_bandwidth', ''])
@ -422,7 +416,7 @@ class IWLA(object):
full_month = '%s %d' % (months_name[i], year)
if i in month_stats.keys():
stats = month_stats[i]
link = '<a href="%d/%02d/index.html">%s</a>' % (year, i, g.gettext('Details'))
link = '<a href="%d/%02d/index.html">%s</a>' % (year, i, self._('Details'))
row = [full_month, stats['nb_visitors'], stats['nb_visits'], stats['viewed_pages'], stats['viewed_hits'],
stats['viewed_bandwidth'], stats['not_viewed_bandwidth'], link]
for j in graph_cols:
@ -439,21 +433,21 @@ class IWLA(object):
else: css = 'iwla_curday'
months.setCellCSSClass(i-1, 0, css)
total[0] = g.gettext('Total')
total[0] = self._('Total')
total[5] = bytesToStr(total[5])
total[6] = bytesToStr(total[6])
months.appendRow(total)
page.appendBlock(months)
def _generateDisplayWholeMonthStats(self):
title = '%s %s' % (g.gettext('Statistics for'), conf.domain_name)
title = '%s %s' % (self._('Statistics for'), conf.domain_name)
filename = 'index.html'
self.logger.info('==> Generate main page (%s)' % (filename))
page = self.display.createPage(title, filename, conf.css_path)
last_update = '<b>%s</b> %s<br />' % (g.gettext('Last update'), time.strftime('%02d %b %Y %H:%M', time.localtime()))
last_update = '<b>%s</b> %s<br />' % (self._('Last update'), time.strftime('%02d %b %Y %H:%M', time.localtime()))
page.appendBlock(self.display.createBlock(DisplayHTMLRaw, last_update))
for year in sorted(self.meta_infos['stats'].keys(), reverse=True):

View File

@ -1,5 +1,4 @@
import time
import gettext as g
from iwla import IWLA
from iplugin import IPlugin
@ -42,13 +41,13 @@ class IWLADisplayAllVisits(IPlugin):
last_access = sorted(hits.values(), key=lambda t: t['last_access'], reverse=True)
title = time.strftime(g.gettext('All visits') + ' - %B %Y', self.iwla.getCurTime())
title = time.strftime(self.iwla._(u'All visits') + u' - %B %Y', self.iwla.getCurTime())
filename = 'all_visits.html'
path = self.iwla.getCurDisplayPath(filename)
page = display.createPage(title, path, self.iwla.getConfValue('css_path', []))
table = display.createBlock(DisplayHTMLBlockTable, g.gettext('Last seen'), [g.gettext('Host'), g.gettext('Pages'), g.gettext('Hits'), g.gettext('Bandwidth'), g.gettext('Last seen')])
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'Last seen'), [self.iwla._(u'Host'), self.iwla._(u'Pages'), self.iwla._(u'Hits'), self.iwla._(u'Bandwidth'), self.iwla._(u'Last seen')])
table.setColsCSSClass(['', 'iwla_page', 'iwla_hit', 'iwla_bandwidth', ''])
for super_hit in last_access:
@ -70,8 +69,8 @@ class IWLADisplayAllVisits(IPlugin):
display.addPage(page)
index = self.iwla.getDisplayIndex()
link = '<a href=\'%s\'>%s</a>' % (g.gettext('All visits'), filename)
block = index.getBlock(g.gettext('Top visitors'))
link = '<a href=\'%s\'>%s</a>' % (filename, self.iwla._(u'All visits'))
block = index.getBlock(self.iwla._(u'Top visitors'))
if block:
block.setTitle('%s - %s' % (block.getTitle(), link))
else:

View File

@ -1,6 +1,3 @@
import time
import gettext as g
from iwla import IWLA
from iplugin import IPlugin
from display import *
@ -69,17 +66,17 @@ class IWLADisplayReferers(IPlugin):
# All referers in a file
if self.create_all_referers:
title = time.strftime(g.gettext('Connexion from') + ' - %B %Y', cur_time)
title = createCurTitle(self.iwla, u'Connexion from')
filename = 'referers.html'
path = self.iwla.getCurDisplayPath(filename)
page = display.createPage(title, path, self.iwla.getConfValue('css_path', []))
table = display.createBlock(DisplayHTMLBlockTable, g.gettext('Connexion from'), [g.gettext('Origin'), g.gettext('Pages'), g.gettext('Hits')])
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'Connexion from'), [self.iwla._(u'Origin'), self.iwla._(u'Pages'), self.iwla._(u'Hits')])
table.setColsCSSClass(['', 'iwla_page', 'iwla_hit'])
total_search = [0]*3
table.appendRow(['<b>%s</b>' % (g.gettext('Search Engine')), '', ''])
table.appendRow(['<b>%s</b>' % (self.iwla._(u'Search Engine')), '', ''])
new_list = self.max_referers and top_search_engine_referers[:self.max_referers] or top_search_engine_referers
for r,_ in new_list:
row = [r, search_engine_referers[r]['pages'], search_engine_referers[r]['hits']]
@ -88,7 +85,7 @@ class IWLADisplayReferers(IPlugin):
table.appendRow(row)
total_external = [0]*3
table.appendRow(['<b>%s</b>' % (g.gettext('External URL')), '', ''])
table.appendRow(['<b>%s</b>' % (self.iwla._(u'External URL')), '', ''])
new_list = self.max_referers and top_referers[:self.max_referers] or top_referers
for r,_ in new_list:
row = [generateHTMLLink(r), referers[r]['pages'], referers[r]['hits']]
@ -97,7 +94,7 @@ class IWLADisplayReferers(IPlugin):
table.appendRow(row)
total_robot = [0]*3
table.appendRow(['<b>%s</b>' % (g.gettext('External URL (robot)')), '', ''])
table.appendRow(['<b>%s</b>' % (self.iwla._(u'External URL (robot)')), '', ''])
new_list = self.max_referers and top_robots_referers[:self.max_referers] or top_robots_referers
for r,_ in new_list:
row = [generateHTMLLink(r), robots_referers[r]['pages'], robots_referers[r]['hits']]
@ -109,45 +106,45 @@ class IWLADisplayReferers(IPlugin):
display.addPage(page)
title = g.gettext('Top Referers')
title = self.iwla._(u'Top Referers')
if self.create_all_referers:
link = '<a href=\'%s\'>%s</a>' % (filename, g.gettext('All Referers'))
link = '<a href=\'%s\'>%s</a>' % (filename, self.iwla._(u'All Referers'))
title = '%s - %s' % (title, link)
# Top referers in index
table = display.createBlock(DisplayHTMLBlockTable, title, [g.gettext('Origin'), g.gettext('Pages'), g.gettext('Hits')])
table = display.createBlock(DisplayHTMLBlockTable, title, [self.iwla._(u'Origin'), self.iwla._(u'Pages'), self.iwla._(u'Hits')])
table.setColsCSSClass(['', 'iwla_page', 'iwla_hit'])
table.appendRow(['<b>%s</b>' % (g.gettext('Search Engine')), '', ''])
table.appendRow(['<b>%s</b>' % (self.iwla._(u'Search Engine')), '', ''])
for r,_ in top_search_engine_referers[:10]:
row = [r, search_engine_referers[r]['pages'], search_engine_referers[r]['hits']]
total_search[1] -= search_engine_referers[r]['pages']
total_search[2] -= search_engine_referers[r]['hits']
table.appendRow(row)
if total_search[1] or total_search[2]:
total_search[0] = g.gettext('Others')
total_search[0] = self.iwla._(u'Others')
table.appendRow(total_search)
table.setCellCSSClass(table.getNbRows()-1, 0, 'iwla_others')
table.appendRow(['<b>%s</b>' % (g.gettext('External URL')), '', ''])
table.appendRow(['<b>%s</b>' % (self.iwla._(u'External URL')), '', ''])
for r,_ in top_referers[:10]:
row = [generateHTMLLink(r), referers[r]['pages'], referers[r]['hits']]
total_external[1] -= referers[r]['pages']
total_external[2] -= referers[r]['hits']
table.appendRow(row)
if total_external[1] or total_external[2]:
total_external[0] = g.gettext('Others')
total_external[0] = self.iwla._(u'Others')
table.appendRow(total_external)
table.setCellCSSClass(table.getNbRows()-1, 0, 'iwla_others')
table.appendRow(['<b>%s</b>' % (g.gettext('External URL (robot)')), '', ''])
table.appendRow(['<b>%s</b>' % (self.iwla._(u'External URL (robot)')), '', ''])
for r,_ in top_robots_referers[:10]:
row = [generateHTMLLink(r), robots_referers[r]['pages'], robots_referers[r]['hits']]
total_robot[1] -= robots_referers[r]['pages']
total_robot[2] -= robots_referers[r]['hits']
table.appendRow(row)
if total_robot[1] or total_robot[2]:
total_robot[0] = g.gettext('Others')
total_robot[0] = self.iwla._(u'Others')
table.appendRow(total_robot)
table.setCellCSSClass(table.getNbRows()-1, 0, 'iwla_others')
@ -155,14 +152,14 @@ class IWLADisplayReferers(IPlugin):
# All key phrases in a file
if self.create_all_key_phrases:
title = time.strftime(g.gettext('Key Phrases') + ' - %B %Y', cur_time)
title = createCurTitle(self.iwla, u'Key Phrases')
filename = 'key_phrases.html'
path = self.iwla.getCurDisplayPath(filename)
total_search = [0]*2
page = display.createPage(title, path, self.iwla.getConfValue('css_path', []))
table = display.createBlock(DisplayHTMLBlockTable, g.gettext('Top key phrases'), [g.gettext('Key phrase'), g.gettext('Search')])
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'Top key phrases'), [self.iwla._(u'Key phrase'), self.iwla._(u'Search')])
table.setColsCSSClass(['', 'iwla_search'])
new_list = self.max_key_phrases and top_key_phrases[:self.max_key_phrases] or top_key_phrases
for phrase in new_list:
@ -172,19 +169,19 @@ class IWLADisplayReferers(IPlugin):
display.addPage(page)
title = g.gettext('Top key phrases')
title = self.iwla._(u'Top key phrases')
if self.create_all_key_phrases:
link = '<a href=\'%s\'>%s</a>' % (filename, g.gettext('All key phrases'))
link = '<a href=\'%s\'>%s</a>' % (filename, self.iwla._(u'All key phrases'))
title = '%s - %s' % (title, link)
# Top key phrases in index
table = display.createBlock(DisplayHTMLBlockTable, title, [g.gettext('Key phrase'), g.gettext('Search')])
table = display.createBlock(DisplayHTMLBlockTable, title, [self.iwla._(u'Key phrase'), self.iwla._(u'Search')])
table.setColsCSSClass(['', 'iwla_search'])
for phrase in top_key_phrases[:10]:
table.appendRow([phrase[0], phrase[1]])
total_search[1] -= phrase[1]
if total_search[1]:
total_search[0] = g.gettext('Others')
total_search[0] = self.iwla._(u'Others')
table.appendRow(total_search)
table.setCellCSSClass(table.getNbRows()-1, 0, 'iwla_others')
index.appendBlock(table)

View File

@ -1,6 +1,3 @@
import time
import gettext as g
from iwla import IWLA
from iplugin import IPlugin
from display import *
@ -48,10 +45,10 @@ class IWLADisplayTopDownloads(IPlugin):
if self.create_all_downloads:
filename = 'top_downloads.html'
path = self.iwla.getCurDisplayPath(filename)
title = time.strftime(g.gettext('All Downloads') + ' - %B %Y', self.iwla.getCurTime())
title = createCurTitle(self.iwla, u'All Downloads')
page = display.createPage(title, path, self.iwla.getConfValue('css_path', []))
table = display.createBlock(DisplayHTMLBlockTable, g.gettext('All Downloads'), [g.gettext('URI'), g.gettext('Hit')])
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'All Downloads'), [self.iwla._(u'URI'), self.iwla._(u'Hit')])
table.setColsCSSClass(['', 'iwla_hit'])
total_entrance = [0]*2
@ -63,21 +60,21 @@ class IWLADisplayTopDownloads(IPlugin):
display.addPage(page)
title = g.gettext('Top Downloads')
title = self.iwla._(u'Top Downloads')
if self.create_all_downloads:
link = '<a href=\'%s\'>%s</a>' % (filename, g.gettext('All Downloads'))
link = '<a href=\'%s\'>%s</a>' % (filename, self.iwla._(u'All Downloads'))
title = '%s - %s' % (title, link)
# Top in index
index = self.iwla.getDisplayIndex()
table = display.createBlock(DisplayHTMLBlockTable, title, [g.gettext('URI'), g.gettext('Hits')])
table = display.createBlock(DisplayHTMLBlockTable, title, [self.iwla._(u'URI'), self.iwla._(u'Hits')])
table.setColsCSSClass(['', 'iwla_hit'])
for (uri, entrance) in top_downloads[:10]:
table.appendRow([generateHTMLLink(uri), entrance])
total_entrance[1] -= entrance
if total_entrance[1]:
total_entrance[0] = g.gettext('Others')
total_entrance[0] = self.iwla._(u'Others')
table.appendRow(total_entrance)
table.setCellCSSClass(table.getNbRows()-1, 0, 'iwla_others')
index.appendBlock(table)

View File

@ -1,6 +1,3 @@
import time
import gettext as g
from iwla import IWLA
from iplugin import IPlugin
from display import *
@ -46,12 +43,12 @@ class IWLADisplayTopHits(IPlugin):
# All in a file
if self.create_all_hits:
title = time.strftime(g.gettext('All Hits') + ' - %B %Y', self.iwla.getCurTime())
title = createCurTitle(self.iwla, u'All Hits')
filename = 'top_hits.html'
path = self.iwla.getCurDisplayPath(filename)
page = display.createPage(title, path, self.iwla.getConfValue('css_path', []))
table = display.createBlock(DisplayHTMLBlockTable, g.gettext('All Hits'), [g.gettext('URI'), g.gettext('Entrance')])
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'All Hits'), [self.iwla._(u'URI'), self.iwla._(u'Entrance')])
table.setColsCSSClass(['', 'iwla_hit'])
total_hits = [0]*2
new_list = self.max_hits and top_hits[:self.max_hits] or top_hits
@ -64,19 +61,19 @@ class IWLADisplayTopHits(IPlugin):
title = 'Top Hits'
if self.create_all_hits:
link = '<a href=\'%s\'>%s</a>' % (filename, g.gettext('All Hits'))
link = '<a href=\'%s\'>%s</a>' % (filename, self.iwla._(u'All Hits'))
title = '%s - %s' % (title, link)
# Top in index
index = self.iwla.getDisplayIndex()
table = display.createBlock(DisplayHTMLBlockTable, title, [g.gettext('URI'), g.gettext('Entrance')])
table = display.createBlock(DisplayHTMLBlockTable, title, [self.iwla._(u'URI'), self.iwla._(u'Entrance')])
table.setColsCSSClass(['', 'iwla_hit'])
for (uri, entrance) in top_hits[:10]:
table.appendRow([generateHTMLLink(uri), entrance])
total_hits[1] -= entrance
if total_hits[1]:
total_hits[0] = g.gettext('Others')
total_hits[0] = self.iwla._(u'Others')
table.appendRow(total_hits)
table.setCellCSSClass(table.getNbRows()-1, 0, 'iwla_others')
index.appendBlock(table)

View File

@ -1,6 +1,3 @@
import time
import gettext as g
from iwla import IWLA
from iplugin import IPlugin
from display import *
@ -46,12 +43,12 @@ class IWLADisplayTopPages(IPlugin):
# All in a page
if self.create_all_pages:
title = time.strftime(g.gettext('All Pages') + ' - %B %Y', self.iwla.getCurTime())
title = createCurTitle(self.iwla, u'All Pages')
filename = 'top_pages.html'
path = self.iwla.getCurDisplayPath(filename)
page = display.createPage(title, path, self.iwla.getConfValue('css_path', []))
table = display.createBlock(DisplayHTMLBlockTable, g.gettext('All Pages'), [g.gettext('URI'), g.gettext('Entrance')])
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'All Pages'), [self.iwla._(u'URI'), self.iwla._(u'Entrance')])
table.setColsCSSClass(['', 'iwla_hit'])
total_hits = [0]*2
new_list = self.max_pages and top_pages[:self.max_pages] or top_pages
@ -62,21 +59,21 @@ class IWLADisplayTopPages(IPlugin):
display.addPage(page)
title = g.gettext('Top Pages')
title = self.iwla._(u'Top Pages')
if self.create_all_pages:
link = '<a href=\'%s\'>%s</a>' % (filename, g.gettext('All Pages'))
link = '<a href=\'%s\'>%s</a>' % (filename, self.iwla._(u'All Pages'))
title = '%s - %s' % (title, link)
# Top in index
index = self.iwla.getDisplayIndex()
table = display.createBlock(DisplayHTMLBlockTable, title, [g.gettext('URI'), g.gettext('Entrance')])
table = display.createBlock(DisplayHTMLBlockTable, title, [self.iwla._(u'URI'), self.iwla._(u'Entrance')])
table.setColsCSSClass(['', 'iwla_hit'])
for (uri, entrance) in top_pages[:10]:
table.appendRow([generateHTMLLink(uri), entrance])
total_hits[1] -= entrance
if total_hits[1]:
total_hits[0] = g.gettext('Others')
total_hits[0] = self.iwla._(u'Others')
table.appendRow(total_hits)
table.setCellCSSClass(table.getNbRows()-1, 0, 'iwla_others')
index.appendBlock(table)

View File

@ -1,5 +1,4 @@
import time
import gettext as g
from iwla import IWLA
from iplugin import IPlugin
@ -50,7 +49,7 @@ class IWLADisplayTopVisitors(IPlugin):
top_visitors = [hits[h[0]] for h in top_bandwidth[:10]]
index = self.iwla.getDisplayIndex()
table = display.createBlock(DisplayHTMLBlockTable, g.gettext('Top visitors'), [g.gettext('Host'), g.gettext('Pages'), g.gettext('Hits'), g.gettext('Bandwidth'), g.gettext('Last seen')])
table = display.createBlock(DisplayHTMLBlockTable, self.iwla._(u'Top visitors'), [self.iwla._(u'Host'), self.iwla._(u'Pages'), self.iwla._(u'Hits'), self.iwla._(u'Bandwidth'), self.iwla._(u'Last seen')])
table.setColsCSSClass(['', 'iwla_page', 'iwla_hit', 'iwla_bandwidth', ''])
for super_hit in top_visitors:
address = super_hit['remote_addr']
@ -70,7 +69,7 @@ class IWLADisplayTopVisitors(IPlugin):
total[3] -= super_hit['bandwidth']
table.appendRow(row)
if total[1] or total[2] or total[3]:
total[0] = g.gettext('Others')
total[0] = self.iwla._(u'Others')
total[3] = bytesToStr(total[3])
total[4] = ''
table.appendRow(total)