From d4115cb65f50f43e355145f2193df46fc962d9c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20V=C3=A9zina?= <5130500+morpheus65535@users.noreply.github.com> Date: Sat, 26 Oct 2019 14:52:22 -0400 Subject: [PATCH] WIP --- bazarr/database.py | 24 ++++++++++++++++++--- bazarr/get_series.py | 35 +++++++++++++++--------------- bazarr/get_subtitle.py | 18 +++++++++------- bazarr/list_subtitles.py | 40 +++++++++++++++++----------------- bazarr/main.py | 44 +++++++++++++++++++++++--------------- libs/sqlite3worker.py | 18 ++++++++++------ views/episodes.tpl | 46 ++++++++++++++++++++-------------------- views/menu.tpl | 36 +++++++++++++------------------ views/series.tpl | 28 ++++++++++++------------ 9 files changed, 158 insertions(+), 131 deletions(-) diff --git a/bazarr/database.py b/bazarr/database.py index eaaf4caa8..89e305096 100644 --- a/bazarr/database.py +++ b/bazarr/database.py @@ -9,18 +9,20 @@ database = Sqlite3Worker(os.path.join(args.config_dir, 'db', 'bazarr.db'), max_q class SqliteDictConverter: def __init__(self): + pass + + def convert(self, values_dict): self.keys = str() self.values = str() self.items = str() - def convert(self, values_dict): if type(values_dict) is dict: for key, value in values_dict.items(): self.keys += key + ", " - if type(value) is not str: + if type(value) not in [str, unicode]: value = str(value) else: - value = "'" + value + "'" + value = "\"" + value + "\"" self.values += value + ", " self.items += key + "=" + value + ", " self.keys = self.keys.rstrip(", ") @@ -32,3 +34,19 @@ class SqliteDictConverter: dict_converter = SqliteDictConverter() + + +class SqliteDictPathMapper: + def __init__(self): + pass + + def path_replace(self, values_dict): + for item in values_dict: + item['path'] = path_replace(item['path']) + + def path_replace_movie(self, values_dict): + for item in values_dict: + item['path'] = path_replace_movie(item['path']) + + +dict_mapper = SqliteDictPathMapper() \ No newline at end of file diff --git a/bazarr/get_series.py b/bazarr/get_series.py index 63aaf8258..5a37da8a7 100644 --- a/bazarr/get_series.py +++ b/bazarr/get_series.py @@ -49,7 +49,7 @@ def update_series(): # Get current shows in DB current_shows_db = database.execute("SELECT tvdbId FROM table_shows") - current_shows_db_list = [x.tvdb_id for x in current_shows_db] + current_shows_db_list = [x['tvdbId'] for x in current_shows_db] current_shows_sonarr = [] series_to_update = [] series_to_add = [] @@ -83,43 +83,43 @@ def update_series(): if show['tvdbId'] in current_shows_db_list: series_to_update.append({'title': unicode(show["title"]), 'path': unicode(show["path"]), - 'tvdb_id': int(show["tvdbId"]), - 'sonarr_series_id': int(show["id"]), + 'tvdbId': int(show["tvdbId"]), + 'sonarrSeriesId': int(show["id"]), 'overview': unicode(overview), 'poster': unicode(poster), 'fanart': unicode(fanart), 'audio_language': unicode(profile_id_to_language((show['qualityProfileId'] if sonarr_version.startswith('2') else show['languageProfileId']), audio_profiles)), - 'sort_title': unicode(show['sortTitle']), + 'sortTitle': unicode(show['sortTitle']), 'year': unicode(show['year']), - 'alternate_titles': unicode(alternateTitles)}) + 'alternateTitles': unicode(alternateTitles)}) else: if serie_default_enabled is True: series_to_add.append({'title': show["title"], 'path': show["path"], - 'tvdb_id': show["tvdbId"], + 'tvdbId': show["tvdbId"], 'languages': serie_default_language, 'hearing_impaired': serie_default_hi, - 'sonarr_series_id': show["id"], + 'sonarrSeriesId': show["id"], 'overview': overview, 'poster': poster, 'fanart': fanart, 'audio_language': profile_id_to_language((show['qualityProfileId'] if sonarr_version.startswith('2') else show['languageProfileId']), audio_profiles), - 'sort_title': show['sortTitle'], + 'sortTitle': show['sortTitle'], 'year': show['year'], - 'alternate_titles': alternateTitles, + 'alternateTitles': alternateTitles, 'forced': serie_default_forced}) else: series_to_add.append({'title': show["title"], 'path': show["path"], - 'tvdb_id': show["tvdbId"], - 'sonarr_series_id': show["id"], + 'tvdbId': show["tvdbId"], + 'sonarrSeriesId': show["id"], 'overview': overview, 'poster': poster, 'fanart': fanart, 'audio_language': profile_id_to_language((show['qualityProfileId'] if sonarr_version.startswith('2') else show['languageProfileId']), audio_profiles), - 'sort_title': show['sortTitle'], + 'sortTitle': show['sortTitle'], 'year': show['year'], - 'alternate_titles': alternateTitles}) + 'alternateTitles': alternateTitles}) # Update existing series in DB series_in_db_list = [] @@ -133,15 +133,14 @@ def update_series(): for updated_series in series_to_update_list: query = dict_converter.convert(updated_series) - database.execute("UPDATE table_shows SET ? WHERE sonarrSeriesId=?", - (query.items, updated_series['sonarr_series_id'])) + database.execute("""UPDATE table_shows SET {0} WHERE sonarrSeriesId=?""".format(query.items), + (updated_series['sonarrSeriesId'],)) # Insert new series in DB for added_series in series_to_add: query = dict_converter.convert(added_series) - database.execute("INSERT OR IGNORE INTO table_shows(?) VALUES(?)", - (query.keys, query.values)) - list_missing_subtitles(no=added_series['sonarr_series_id']) + database.execute("""INSERT OR IGNORE INTO table_shows({0}) VALUES({1})""".format(query.keys, query.values)) + list_missing_subtitles(no=added_series['sonarrSeriesId']) # Remove old series from DB removed_series = list(set(current_shows_db_list) - set(current_shows_sonarr)) diff --git a/bazarr/get_subtitle.py b/bazarr/get_subtitle.py index a146de772..4a65434f7 100644 --- a/bazarr/get_subtitle.py +++ b/bazarr/get_subtitle.py @@ -33,7 +33,7 @@ from get_providers import get_providers, get_providers_auth, provider_throttle, from get_args import args from queueconfig import notifications from pyprobe.pyprobe import VideoFileParser -from database import database +from database import database, dict_mapper from analytics import track_event @@ -816,9 +816,10 @@ def wanted_search_missing_subtitles(): else: monitored_only_query_string_sonarr = "" - # path_replace episodes = database.execute("SELECT path FROM table_episodes WHERE missing_subtitles != '[]'" + monitored_only_query_string_sonarr) + # path_replace + dict_mapper.path_replace(episodes) count_episodes = len(episodes) for i, episode in enumerate(episodes, 1): @@ -836,9 +837,10 @@ def wanted_search_missing_subtitles(): else: monitored_only_query_string_radarr = "" - # path_replace_movie movies = database.execute("SELECT path FROM table_movies WHERE missing_subtitles != '[]'" + monitored_only_query_string_radarr) + # path_replace + dict_mapper.path_replace_movie(movies) count_movies = len(movies) for i, movie in enumerate(movies, 1): @@ -883,17 +885,17 @@ def refine_from_db(path, video): "table_episodes.video_codec, table_episodes.audio_codec, table_episodes.path " "FROM table_episodes INNER JOIN table_shows on " "table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId " - "WHERE table_episodes.path = ?", (unicode(path_replace_reverse(path)),)) + "WHERE table_episodes.path = ?", (unicode(path_replace_reverse(path)),))[0] if data: video.series, year, country = series_re.match(data['seriesTitle']).groups() video.season = int(data['season']) video.episode = int(data['episode']) video.title = data['episodeTitle'] - if data.year: + if data['year']: if int(data['year']) > 0: video.year = int(data['year']) - video.series_tvdb_id = int(data['tvdb_id']) - video.alternative_series = ast.literal_eval(data['alternate_titles']) + video.series_tvdb_id = int(data['tvdbId']) + video.alternative_series = ast.literal_eval(data['alternateTitles']) if not video.format: video.format = str(data['format']) if not video.resolution: @@ -908,7 +910,7 @@ def refine_from_db(path, video): if data: video.title = re.sub(r'(\(\d\d\d\d\))', '', data['title']) - if data.year: + if data['year']: if int(data['year']) > 0: video.year = int(data['year']) if data['imdb_id']: video.imdb_id = data['imdb_id'] video.alternative_titles = ast.literal_eval(data['alternative_titles']) diff --git a/bazarr/list_subtitles.py b/bazarr/list_subtitles.py index b668ec30a..7fa336cc5 100644 --- a/bazarr/list_subtitles.py +++ b/bazarr/list_subtitles.py @@ -218,9 +218,9 @@ def store_subtitles_movie(file): def list_missing_subtitles(no=None, epno=None): if no is not None: - episodes_subtitles_clause = " WHERE sonarrSeriesId=no" + episodes_subtitles_clause = " WHERE table_episodes.sonarrSeriesId=" + str(no) elif epno is not None: - episodes_subtitles_clause = " WHERE sonarrEpisodeId=no" + episodes_subtitles_clause = " WHERE table_episodes.sonarrEpisodeId=" + str(epno) else: episodes_subtitles_clause = "" episodes_subtitles = database.execute("SELECT table_shows.sonarrSeriesId, table_episodes.sonarrEpisodeId, " @@ -237,27 +237,27 @@ def list_missing_subtitles(no=None, epno=None): actual_subtitles = [] desired_subtitles = [] missing_subtitles = [] - if episode_subtitles.subtitles is not None: + if episode_subtitles['subtitles'] is not None: if use_embedded_subs: - actual_subtitles = ast.literal_eval(episode_subtitles.subtitles) + actual_subtitles = ast.literal_eval(episode_subtitles['subtitles']) else: - actual_subtitles_temp = ast.literal_eval(episode_subtitles.subtitles) + actual_subtitles_temp = ast.literal_eval(episode_subtitles['subtitles']) for subtitle in actual_subtitles_temp: if subtitle[1] is not None: actual_subtitles.append(subtitle) - if episode_subtitles.languages is not None: - desired_subtitles = ast.literal_eval(episode_subtitles.languages) - if episode_subtitles.forced == "True" and desired_subtitles is not None: + if episode_subtitles['languages'] is not None: + desired_subtitles = ast.literal_eval(episode_subtitles['languages']) + if episode_subtitles['forced'] == "True" and desired_subtitles is not None: for i, desired_subtitle in enumerate(desired_subtitles): desired_subtitles[i] = desired_subtitle + ":forced" - elif episode_subtitles.forced == "Both" and desired_subtitles is not None: + elif episode_subtitles['forced'] == "Both" and desired_subtitles is not None: for desired_subtitle in desired_subtitles: desired_subtitles_temp.append(desired_subtitle) desired_subtitles_temp.append(desired_subtitle + ":forced") desired_subtitles = desired_subtitles_temp actual_subtitles_list = [] if desired_subtitles is None: - missing_subtitles_global.append(tuple(['[]', episode_subtitles.sonarr_episode_id])) + missing_subtitles_global.append(tuple(['[]', episode_subtitles['sonarrEpisodeId']])) else: for item in actual_subtitles: if item[0] == "pt-BR": @@ -267,7 +267,7 @@ def list_missing_subtitles(no=None, epno=None): else: actual_subtitles_list.append(item[0]) missing_subtitles = list(set(desired_subtitles) - set(actual_subtitles_list)) - missing_subtitles_global.append(tuple([str(missing_subtitles), episode_subtitles.sonarr_episode_id])) + missing_subtitles_global.append(tuple([str(missing_subtitles), episode_subtitles['sonarrEpisodeId']])) for missing_subtitles_item in missing_subtitles_global: database.execute("UPDATE table_episodes SET missing_subtitles=? WHERE sonarrEpisodeId=?", @@ -291,27 +291,27 @@ def list_missing_subtitles_movies(no=None): actual_subtitles = [] desired_subtitles = [] missing_subtitles = [] - if movie_subtitles.subtitles is not None: + if movie_subtitles['subtitles'] is not None: if use_embedded_subs: - actual_subtitles = ast.literal_eval(movie_subtitles.subtitles) + actual_subtitles = ast.literal_eval(movie_subtitles['subtitles']) else: - actual_subtitles_temp = ast.literal_eval(movie_subtitles.subtitles) + actual_subtitles_temp = ast.literal_eval(movie_subtitles['subtitles']) for subtitle in actual_subtitles_temp: if subtitle[1] is not None: actual_subtitles.append(subtitle) - if movie_subtitles.languages is not None: - desired_subtitles = ast.literal_eval(movie_subtitles.languages) - if movie_subtitles.forced == "True" and desired_subtitles is not None: + if movie_subtitles['languages'] is not None: + desired_subtitles = ast.literal_eval(movie_subtitles['languages']) + if movie_subtitles['forced'] == "True" and desired_subtitles is not None: for i, desired_subtitle in enumerate(desired_subtitles): desired_subtitles[i] = desired_subtitle + ":forced" - elif movie_subtitles.forced == "Both" and desired_subtitles is not None: + elif movie_subtitles['forced'] == "Both" and desired_subtitles is not None: for desired_subtitle in desired_subtitles: desired_subtitles_temp.append(desired_subtitle) desired_subtitles_temp.append(desired_subtitle + ":forced") desired_subtitles = desired_subtitles_temp actual_subtitles_list = [] if desired_subtitles is None: - missing_subtitles_global.append(tuple(['[]', movie_subtitles.radarr_id])) + missing_subtitles_global.append(tuple(['[]', movie_subtitles['radarrId']])) else: for item in actual_subtitles: if item[0] == "pt-BR": @@ -321,7 +321,7 @@ def list_missing_subtitles_movies(no=None): else: actual_subtitles_list.append(item[0]) missing_subtitles = list(set(desired_subtitles) - set(actual_subtitles_list)) - missing_subtitles_global.append(tuple([str(missing_subtitles), movie_subtitles.radarr_id])) + missing_subtitles_global.append(tuple([str(missing_subtitles), movie_subtitles['radarrId']])) for missing_subtitles_item in missing_subtitles_global: database.execute("UPDATE table_movies SET missing_subtitles=? WHERE radarrIr=?", diff --git a/bazarr/main.py b/bazarr/main.py index 2553ea8a1..7ed397987 100644 --- a/bazarr/main.py +++ b/bazarr/main.py @@ -22,7 +22,7 @@ from calendar import day_name from get_args import args from init import * -from database import database +from database import database, dict_mapper from notifier import update_notifier from logger import configure_logging, empty_log @@ -517,19 +517,20 @@ def redirect_root(): def series(): authorize() - missing_count = database.execute("SELECT COUNT(*) FROM table_shows") + series_count = len(database.execute("SELECT COUNT(*) FROM table_shows")) page = request.GET.page if page == "": page = "1" page_size = int(settings.general.page_size) offset = (int(page) - 1) * page_size - max_page = int(math.ceil(missing_count / (page_size + 0.0))) + max_page = int(math.ceil(series_count / (page_size + 0.0))) # Get list of series - # path_replace data = database.execute("SELECT tvdbId, title, path, languages, hearing_impaired, sonarrSeriesId, poster, " "audio_language, forced FROM table_shows ORDER BY sortTitle ASC LIMIT ? OFFSET ?", (page_size, offset)) + # path_replace + dict_mapper.path_replace(data) # Get languages list languages = database.execute("SELECT code2, name FROM table_settings_languages WHERE enabled=1") @@ -542,7 +543,7 @@ def series(): # Get missing subtitles count by series missing_subtitles_list = database.execute("SELECT table_shows.sonarrSeriesId, " - "COUNT(table_episodes.missing_subtitles) FROM table_shows LEFT JOIN " + "COUNT(table_episodes.missing_subtitles) as missing_subtitles FROM table_shows LEFT JOIN " "table_episodes ON table_shows.sonarrSeriesId=" "table_episodes.sonarrSeriesId WHERE table_shows.languages IS NOT 'None' " "AND table_episodes.missing_subtitles IS NOT '[]'" + @@ -556,13 +557,13 @@ def series(): # Get total subtitles count by series total_subtitles_list = database.execute("SELECT table_shows.sonarrSeriesId, " - "COUNT(table_episodes.missing_subtitles) FROM table_shows LEFT JOIN " + "COUNT(table_episodes.missing_subtitles) as missing_subtitles FROM table_shows LEFT JOIN " "table_episodes ON table_shows.sonarrSeriesId=" "table_episodes.sonarrSeriesId WHERE table_shows.languages IS NOT 'None'" + total_subtitles_clause + " GROUP BY table_shows.sonarrSeriesId") return template('series', bazarr_version=bazarr_version, rows=data, missing_subtitles_list=missing_subtitles_list, - total_subtitles_list=total_subtitles_list, languages=languages, missing_count=missing_count, + total_subtitles_list=total_subtitles_list, languages=languages, missing_count=series_count, page=page, max_page=max_page, base_url=base_url, single_language=settings.general.getboolean('single_language'), page_size=page_size, current_port=settings.general.port) @@ -577,9 +578,10 @@ def serieseditor(): missing_count = database.execute("SELECT COUNT(*) FROM table_shows") # Get series list - # path_replace data = database.execute("SELECT tvdbId, title, path, languages, hearing_impaired, sonarrSeriesId, poster, " "audio_language, forced FROM table_shows ORDER BY sortTitle ASC") + # path_replace + dict_mapper.path_replace(data) # Get languages list languages = database.execute("SELECT code2, name FROM table_settings_languages WHERE enabled=1") @@ -690,26 +692,29 @@ def edit_serieseditor(): def episodes(no): authorize() - # path_replace series_details = database.execute("SELECT title, overview, poster, fanart, hearing_impaired, tvdbId, " "audio_language, languages, path, forced FROM table_shows WHERE " "sonarrSeriesId=?", (no,)) + # path_replace + dict_mapper.path_replace(series_details) + for series in series_details: - tvdbid = series.tvdb_id + tvdbid = series['tvdbId'] series_details = series break - # path_replace episodes = database.execute("SELECT title, path, season, episode, subtitles, sonarrSeriesId, missing_subtitles, " "sonarrEpisodeId, scene_name, monitored, failedAttempts FROM table_episodes WHERE " "sonarrSeriesId=? ORDER BY season DESC, episode DESC", (no,)) + # path_replace + dict_mapper.path_replace(episodes) number = len(episodes) languages = database.execute("SELECT code2, name FROM table_settings_languages WHERE enabled=1") seasons_list = [] - for key, season in itertools.groupby(episodes.dicts(), lambda x: x['season']): + for key, season in itertools.groupby(episodes, lambda x: x['season']): seasons_list.append(list(season)) return template('episodes', bazarr_version=bazarr_version, no=no, details=series_details, @@ -730,10 +735,11 @@ def movies(): offset = (int(page) - 1) * page_size max_page = int(math.ceil(missing_count / (page_size + 0.0))) - # path_replace_movie data = database.execute("SELECT tmdbId, title, path, languages, hearing_impaired, radarrId, poster, " "audio_language, monitored, scenename, forced FROM table_movies ORDER BY sortTitle ASC " "LIMIT ? OFFSET ?", (page_size, offset)) + # path_replace + dict_mapper.path_replace_movie(data) languages = database.execute("SELECT code2, name FROM table_settings_languages WHERE enabled=1") @@ -750,9 +756,10 @@ def movieseditor(): missing_count = database.execute("SELECT COUNT(*) FORM table_movies") - # path_replace_movie data = database.execute("SELECT tmdbId, title, path, languages, hearing_impaired, radarrId, poster, " "audio_language, forced FROM table_movies ORDER BY sortTitle ASC") + # path_replace + dict_mapper.path_replace_movie(data) languages = database.execute("SELECT code2, name FROM table_settings_languages WHERE enabled=1") @@ -834,11 +841,12 @@ def edit_movie(no): def movie(no): authorize() - # path_replace_movie movies_details = database.execute("SELECT title, overview, poster, fanart, hearing_impaired, tmdbId, " "audio_language, languages, path, subtitles, radarrId, missing_subtitles, " "scenename, monitored, failedAttempts, forced FROM table_movies " "WHERE radarrId=?", (no,)) + # path_replace + dict_mapper.path_replace(movies_details) for movie_details in movies_details: movies_details = movie_details @@ -1085,7 +1093,6 @@ def wantedseries(): offset = (int(page) - 1) * page_size max_page = int(math.ceil(missing_count / (page_size + 0.0))) - # path_replace data = database.execute("SELECT table_shows.title, table_episodes.season || 'x' || table_episodes.episode, " "table_episodes.title, table_episodes.missing_subtitles, table_episodes.sonarrSeriesId, " "table_episodes.path, table_shows.hearing_impaired, table_episodes.sonarrEpisodeId, " @@ -1093,6 +1100,8 @@ def wantedseries(): "INNER JOIN table_shows on table_shows.sonarrSeriesId = table_episodes.sonarrSeriesId " "WHERE table_episodes.missing_subtitles != '[]'" + monitored_only_query_string + " ORDER BY table_episodes._rowid_ DESC LIMIT ? OFFSET ?", (page_size, offset)) + # path_replace + dict_mapper.path_replace(data) return template('wantedseries', bazarr_version=bazarr_version, rows=data, missing_count=missing_count, page=page, max_page=max_page, base_url=base_url, page_size=page_size, current_port=settings.general.port) @@ -1117,11 +1126,12 @@ def wantedmovies(): offset = (int(page) - 1) * page_size max_page = int(math.ceil(missing_count / (page_size + 0.0))) - # path_replace_movie data = database.execute("SELECT title, missing_subtitles, radarrId, path, hearing_impaired, sceneName, " "failedAttempts FROM table_movies WHERE missing_subtitles != '[]'" + monitored_only_query_string + " ORDER BY _rowid_ DESC LIMIT ? OFFSET ?", (page_size, offset)) + # path_replace + dict_mapper.path_replace_movie(data) return template('wantedmovies', bazarr_version=bazarr_version, rows=data, missing_count=missing_count, page=page, max_page=max_page, base_url=base_url, page_size=page_size, diff --git a/libs/sqlite3worker.py b/libs/sqlite3worker.py index 29ba2821a..2247f7adb 100644 --- a/libs/sqlite3worker.py +++ b/libs/sqlite3worker.py @@ -58,6 +58,7 @@ class Sqlite3Worker(threading.Thread): Args: file_name: The name of the file. max_queue_size: The max queries that will be queued. + as_dict: Return result as a dictionary. """ threading.Thread.__init__(self) self.daemon = True @@ -89,11 +90,11 @@ class Sqlite3Worker(threading.Thread): """ LOGGER.debug("run: Thread started") execute_count = 0 - for token, query, values in iter(self.sql_queue.get, None): + for token, query, values, only_one in iter(self.sql_queue.get, None): LOGGER.debug("sql_queue: %s", self.sql_queue.qsize()) if token != self.exit_token: LOGGER.debug("run: %s", query) - self.run_query(token, query, values) + self.run_query(token, query, values, only_one) execute_count += 1 # Let the executes build up a little before committing to disk # to speed things up. @@ -111,7 +112,7 @@ class Sqlite3Worker(threading.Thread): self.thread_running = False return - def run_query(self, token, query, values): + def run_query(self, token, query, values, only_one): """Run a query. Args: @@ -122,7 +123,10 @@ class Sqlite3Worker(threading.Thread): if query.lower().strip().startswith("select"): try: self.sqlite3_cursor.execute(query, values) - self.results[token] = self.sqlite3_cursor.fetchall() + if only_one: + self.results[token] = self.sqlite3_cursor.fetchone() + else: + self.results[token] = self.sqlite3_cursor.fetchall() except sqlite3.Error as err: # Put the error into the output queue since a response # is required. @@ -173,7 +177,7 @@ class Sqlite3Worker(threading.Thread): if delay < 8: delay += delay - def execute(self, query, values=None): + def execute(self, query, values=None, only_one=False): """Execute a query. Args: @@ -193,10 +197,10 @@ class Sqlite3Worker(threading.Thread): # If it's a select we queue it up with a token to mark the results # into the output queue so we know what results are ours. if query.lower().strip().startswith("select"): - self.sql_queue.put((token, query, values), timeout=5) + self.sql_queue.put((token, query, values, only_one), timeout=5) return self.query_results(token) else: - self.sql_queue.put((token, query, values), timeout=5) + self.sql_queue.put((token, query, values, only_one), timeout=5) def dict_factory(cursor, row): diff --git a/views/episodes.tpl b/views/episodes.tpl index 3f6da85dc..6cdf3294b 100644 --- a/views/episodes.tpl +++ b/views/episodes.tpl @@ -19,11 +19,11 @@ -