From 70351adae6433737b2536105697f7eb8163b14b2 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 17:16:13 +0100 Subject: [PATCH 01/14] Use single render context in all places --- md_pdf/build/__init__.py | 2 +- md_pdf/build/content.py | 4 +++- md_pdf/build/context.py | 14 ++++++++++++++ md_pdf/build/templates.py | 13 ++++--------- 4 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 md_pdf/build/context.py diff --git a/md_pdf/build/__init__.py b/md_pdf/build/__init__.py index 29a47d8..27075f1 100644 --- a/md_pdf/build/__init__.py +++ b/md_pdf/build/__init__.py @@ -20,7 +20,7 @@ def build(config): if 'html' in config['output_formats']: output_html(parsed_template, os.path.abspath(config['output_dir'])) if 'pdf' in config['output_formats']: - render_templates(config) + render_templates(config, parsed_template) render_css() export_pdf(parsed_template, config) logger.info('Output completed in {:.2f} seconds.'.format(time.time() - start_time)) diff --git a/md_pdf/build/content.py b/md_pdf/build/content.py index 2d89308..27e03a3 100644 --- a/md_pdf/build/content.py +++ b/md_pdf/build/content.py @@ -2,6 +2,7 @@ from jinja2 import Template from bs4 import BeautifulSoup import os import logging +from md_pdf.build.context import get_context logger = logging.getLogger(__file__) @@ -38,7 +39,8 @@ def add_body_class(doc, config): def render_template(html, config): logger.debug("Rendering Template...") template = Template(html) - return template.render(config) + context = get_context(config, html) + return template.render(context) def parse_template(doc, config): diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py new file mode 100644 index 0000000..84102d2 --- /dev/null +++ b/md_pdf/build/context.py @@ -0,0 +1,14 @@ +from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR + + +EXTRA_CONTEXT = { + 'templates_dir': TEMPLATES_DIR, + 'static_dir': STATIC_DIR +} + + +def get_context(config, content): + context = config['context'].copy() + context['title'] = config['title'] + context = dict(context, **EXTRA_CONTEXT) + return context diff --git a/md_pdf/build/templates.py b/md_pdf/build/templates.py index 3c8c4ef..e593f5c 100644 --- a/md_pdf/build/templates.py +++ b/md_pdf/build/templates.py @@ -1,14 +1,11 @@ from jinja2 import Template -from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR +from md_pdf.consts import TEMPLATES_DIR +from md_pdf.build.context import get_context import os import logging logger = logging.getLogger(__file__) -EXTRA_CONFIG = { - 'templates_dir': TEMPLATES_DIR, - 'static_dir': STATIC_DIR -} FILE_NAME_FORMAT = os.path.join(TEMPLATES_DIR, "{}.html") TEMPLATE_FORMAT = os.path.join(TEMPLATES_DIR, "{}-template.html") @@ -24,10 +21,8 @@ def render_page(input_file, output_file, context): return cover -def render_templates(config): - context = config['context'].copy() - context['title'] = config['title'] - context = dict(context, **EXTRA_CONFIG) +def render_templates(config, content): + context = get_context(config, content) for template in [ 'cover', 'header', From 805ddbcadbd77369db4308346c8c3030020cc525 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 17:42:36 +0100 Subject: [PATCH 02/14] Add wordcount --- md_pdf/build/context.py | 2 ++ setup.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index 84102d2..0d14468 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -1,4 +1,5 @@ from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR +from word_count import word_count EXTRA_CONTEXT = { @@ -11,4 +12,5 @@ def get_context(config, content): context = config['context'].copy() context['title'] = config['title'] context = dict(context, **EXTRA_CONTEXT) + context['word_count'] = word_count(content) return context diff --git a/setup.py b/setup.py index a099a3a..6094970 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,8 @@ setup( "progressbar2==3.16.0", "pypandoc==1.3.3", "pyscss==1.3.5", - "PyYAML==3.12" + "PyYAML==3.12", + "word-count==0.1.0" ], setup_requires=['setuptools_scm'], packages=find_packages(), From 243ccc46411a727ec4e20e787ccf6f4fae32bb71 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 20:07:38 +0100 Subject: [PATCH 03/14] Add wordcount to footer --- md_pdf/assets/static/style.scss | 1 + md_pdf/assets/templates/footer-template.html | 4 ++++ md_pdf/assets/templates/header-template.html | 7 +++++++ md_pdf/build/context.py | 5 +++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/md_pdf/assets/static/style.scss b/md_pdf/assets/static/style.scss index 522df91..ddfdefe 100644 --- a/md_pdf/assets/static/style.scss +++ b/md_pdf/assets/static/style.scss @@ -55,6 +55,7 @@ body.footer, body.header { td { text-align: center; + width: 33%; } } } diff --git a/md_pdf/assets/templates/footer-template.html b/md_pdf/assets/templates/footer-template.html index fdf7715..ceabfa5 100644 --- a/md_pdf/assets/templates/footer-template.html +++ b/md_pdf/assets/templates/footer-template.html @@ -6,9 +6,13 @@ + +
Page of + Total Words: {{ word_count }} +
diff --git a/md_pdf/assets/templates/header-template.html b/md_pdf/assets/templates/header-template.html index 91e760b..3f8c9a8 100644 --- a/md_pdf/assets/templates/header-template.html +++ b/md_pdf/assets/templates/header-template.html @@ -4,6 +4,13 @@ + + + + + + +
diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index 0d14468..e380d42 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -11,6 +11,7 @@ EXTRA_CONTEXT = { def get_context(config, content): context = config['context'].copy() context['title'] = config['title'] - context = dict(context, **EXTRA_CONTEXT) - context['word_count'] = word_count(content) + context = dict(context, **EXTRA_CONTEXT, **{ + 'word_count': word_count(content) + }) return context From 6f8aa6ee09accbb46db6927dac0e61ca64b7d143 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 20:34:41 +0100 Subject: [PATCH 04/14] Calculate wordcount better and make togglable --- md_pdf/assets/templates/footer-template.html | 4 +++- md_pdf/build/context.py | 4 +++- md_pdf/config/validate.py | 10 +++++++++- md_pdf/utils.py | 12 ++++++++++++ test-files/mdp.yml | 1 + 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/md_pdf/assets/templates/footer-template.html b/md_pdf/assets/templates/footer-template.html index ceabfa5..2ea9fde 100644 --- a/md_pdf/assets/templates/footer-template.html +++ b/md_pdf/assets/templates/footer-template.html @@ -11,7 +11,9 @@ Page of - Total Words: {{ word_count }} + {% if word_count %} + Total Words: {{ word_count }} + {% endif %} diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index e380d42..0a6d127 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -1,5 +1,6 @@ from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR from word_count import word_count +from md_pdf.utils import get_plain_text EXTRA_CONTEXT = { @@ -12,6 +13,7 @@ def get_context(config, content): context = config['context'].copy() context['title'] = config['title'] context = dict(context, **EXTRA_CONTEXT, **{ - 'word_count': word_count(content) }) + if config.get('show_word_count'): + context['word_count'] = word_count(get_plain_text(content)) return context diff --git a/md_pdf/config/validate.py b/md_pdf/config/validate.py index d7e0199..c8dc41e 100644 --- a/md_pdf/config/validate.py +++ b/md_pdf/config/validate.py @@ -76,6 +76,13 @@ def validate_toc(config): raise ConfigValidationException("Table of contents key should be either true or false") +def validate_wordcount(config): + if 'show_word_count' not in config: + return + if type(config['show_word_count']) != bool: + raise ConfigValidationException("Show word count key should be either true or false") + + def validate_config(config): logger.debug("Validating Config...") for validator in [ @@ -84,7 +91,8 @@ def validate_config(config): test_output, validate_bibliography, validate_context, - validate_toc + validate_toc, + validate_wordcount ]: validator(config) logger.debug("Config Ok!") diff --git a/md_pdf/utils.py b/md_pdf/utils.py index 69a0e0b..101e639 100644 --- a/md_pdf/utils.py +++ b/md_pdf/utils.py @@ -1,6 +1,7 @@ import shutil import os import logging +from bs4 import BeautifulSoup logger = logging.getLogger(__file__) @@ -19,3 +20,14 @@ def safe_list_get(l, idx, default): return l[idx] except IndexError: return default + + +def get_plain_text(content): + soup = BeautifulSoup(content, 'html.parser') + body = soup.find('body') + try: + body.find('h1', class_='references-title').extract() + body.find('div', class_='references').extract() + except AttributeError: + pass + return body.text diff --git a/test-files/mdp.yml b/test-files/mdp.yml index 661ce22..538845b 100644 --- a/test-files/mdp.yml +++ b/test-files/mdp.yml @@ -13,3 +13,4 @@ context: turnitin_number: 789123 title: test title toc: true +show_word_count: true From b242657df763cc63b79df109eccf91f276c8bb93 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 20:36:23 +0100 Subject: [PATCH 05/14] Add render date to context --- md_pdf/build/context.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index 0a6d127..36ad500 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -1,11 +1,13 @@ from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR from word_count import word_count from md_pdf.utils import get_plain_text +from datetime import datetime EXTRA_CONTEXT = { 'templates_dir': TEMPLATES_DIR, - 'static_dir': STATIC_DIR + 'static_dir': STATIC_DIR, + 'date': datetime.now() } From a8a228cb23460f9cd70b4a5b2c2be11b4c7b6807 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 20:39:24 +0100 Subject: [PATCH 06/14] add all of config to context --- md_pdf/build/context.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index 36ad500..8978051 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -12,10 +12,17 @@ EXTRA_CONTEXT = { def get_context(config, content): + config = config.copy() context = config['context'].copy() - context['title'] = config['title'] - context = dict(context, **EXTRA_CONTEXT, **{ - }) + del config['context'] + context = dict( + config, + **context, + **EXTRA_CONTEXT, + **{ + + } + ) if config.get('show_word_count'): context['word_count'] = word_count(get_plain_text(content)) return context From 1c937e91884be06e3ae98bda51053cdf25b10179 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 21:33:18 +0100 Subject: [PATCH 07/14] Render submission date --- md_pdf/assets/templates/cover-template.html | 4 ++++ md_pdf/assets/templates/header-template.html | 6 +++++- md_pdf/build/context.py | 15 ++++++++++++--- md_pdf/config/validate.py | 18 ++++++++++++++++-- md_pdf/consts.py | 4 ++++ setup.py | 1 + test-files/mdp.yml | 1 + 7 files changed, 43 insertions(+), 6 deletions(-) diff --git a/md_pdf/assets/templates/cover-template.html b/md_pdf/assets/templates/cover-template.html index 53f95a4..cac7519 100644 --- a/md_pdf/assets/templates/cover-template.html +++ b/md_pdf/assets/templates/cover-template.html @@ -16,5 +16,9 @@ {% if turnitin_number %}

TurnItIn Number: {{ turnitin_number }}

{% endif %} + + {% if submission_date %} +

Submission Date: {{ submission_date }}

+ {% endif %} diff --git a/md_pdf/assets/templates/header-template.html b/md_pdf/assets/templates/header-template.html index 3f8c9a8..24b1048 100644 --- a/md_pdf/assets/templates/header-template.html +++ b/md_pdf/assets/templates/header-template.html @@ -8,7 +8,11 @@ - + + {% if submission_date %} + Date: {{ submission_date }} + {% endif %} + diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index 8978051..28be8b4 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -1,13 +1,16 @@ -from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR +from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR, DATE_FORMAT, TIME_FORMAT, DATETIME_FORMAT from word_count import word_count from md_pdf.utils import get_plain_text -from datetime import datetime +from dateutil import parser +import datetime EXTRA_CONTEXT = { 'templates_dir': TEMPLATES_DIR, 'static_dir': STATIC_DIR, - 'date': datetime.now() + 'date': datetime.datetime.now().strftime(DATE_FORMAT), + 'time': datetime.datetime.now().strftime(TIME_FORMAT), + 'datetime': datetime.datetime.now().strftime(DATETIME_FORMAT) } @@ -25,4 +28,10 @@ def get_context(config, content): ) if config.get('show_word_count'): context['word_count'] = word_count(get_plain_text(content)) + if config.get('submission_date'): + if type(config['submission_date']) in [datetime.date, datetime.datetime, datetime.time]: + submission_date = config['submission_date'] + else: + submission_date = parser.parse(config['submission_date']) + context['submission_date'] = submission_date.strftime(DATE_FORMAT) return context diff --git a/md_pdf/config/validate.py b/md_pdf/config/validate.py index c8dc41e..5eaf687 100644 --- a/md_pdf/config/validate.py +++ b/md_pdf/config/validate.py @@ -3,7 +3,8 @@ from md_pdf.consts import CSL_DIR import glob import os import logging - +from dateutil import parser +import datetime logger = logging.getLogger(__file__) @@ -83,6 +84,18 @@ def validate_wordcount(config): raise ConfigValidationException("Show word count key should be either true or false") +def validate_submission_date(config): + if 'submission_date' not in config: + return + if type(config['submission_date']) in [datetime.date, datetime.datetime, datetime.time]: + return + try: + parser.parse(config['submission_date']) + except ValueError: + raise ConfigValidationException("Invalid Submission Date format") + + + def validate_config(config): logger.debug("Validating Config...") for validator in [ @@ -92,7 +105,8 @@ def validate_config(config): validate_bibliography, validate_context, validate_toc, - validate_wordcount + validate_wordcount, + validate_submission_date ]: validator(config) logger.debug("Config Ok!") diff --git a/md_pdf/consts.py b/md_pdf/consts.py index a0aadb9..7e3620e 100644 --- a/md_pdf/consts.py +++ b/md_pdf/consts.py @@ -11,3 +11,7 @@ STATIC_DIR = os.path.join(ASSET_DIR, 'static') CONFIG_FILE = os.path.join(WORKING_DIR, 'mdp.yml') CSL_DOWNLOAD_LINK = "https://github.com/citation-style-language/styles/archive/master.zip" + +DATE_FORMAT = "%d %B %Y" +TIME_FORMAT = "%H:%M" +DATETIME_FORMAT = "{} {}".format(DATE_FORMAT, TIME_FORMAT) diff --git a/setup.py b/setup.py index 6094970..5a59877 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ setup( "progressbar2==3.16.0", "pypandoc==1.3.3", "pyscss==1.3.5", + "python-dateutil==2.6.0", "PyYAML==3.12", "word-count==0.1.0" ], diff --git a/test-files/mdp.yml b/test-files/mdp.yml index 538845b..bfd54ef 100644 --- a/test-files/mdp.yml +++ b/test-files/mdp.yml @@ -14,3 +14,4 @@ context: title: test title toc: true show_word_count: true +submission_date: 2017-01-01 From 85f7d4671dc410f1ec5c9df6957bf01c5157f964 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 21:42:28 +0100 Subject: [PATCH 08/14] Update wkhtml download link --- scripts/before_script.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/before_script.sh b/scripts/before_script.sh index 1d1adaa..f69210d 100644 --- a/scripts/before_script.sh +++ b/scripts/before_script.sh @@ -5,8 +5,8 @@ set -e sudo apt-get install -y openssl build-essential xorg libssl-dev -wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz -tar -xJf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz +wget https://downloads.wkhtmltopdf.org/0.12/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz +tar -xJf wkhtmltox-0.12.4_linux-generic-amd64.tar.xz cd wkhtmltox sudo chown root:root bin/wkhtmltopdf sudo cp -r * /usr/ From e70839eeafcc1f139e6c53f03340abd394cd409a Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 21:48:03 +0100 Subject: [PATCH 09/14] Reorder css styles --- md_pdf/assets/static/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/md_pdf/assets/static/style.scss b/md_pdf/assets/static/style.scss index ddfdefe..15af1d8 100644 --- a/md_pdf/assets/static/style.scss +++ b/md_pdf/assets/static/style.scss @@ -54,8 +54,8 @@ body.footer, body.header { width: 100%; td { - text-align: center; width: 33%; + text-align: center; } } } From dd7ec2952643e5147a53a310b3cddbc553e7ddfc Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Thu, 25 May 2017 21:50:02 +0100 Subject: [PATCH 10/14] Remove empty line --- md_pdf/config/validate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/md_pdf/config/validate.py b/md_pdf/config/validate.py index 5eaf687..e90f5ba 100644 --- a/md_pdf/config/validate.py +++ b/md_pdf/config/validate.py @@ -95,7 +95,6 @@ def validate_submission_date(config): raise ConfigValidationException("Invalid Submission Date format") - def validate_config(config): logger.debug("Validating Config...") for validator in [ From fc46e085593d313c846fdb5c61b365a8a7a67750 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sat, 27 May 2017 11:51:00 +0100 Subject: [PATCH 11/14] Add title to header --- md_pdf/assets/templates/header-template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/md_pdf/assets/templates/header-template.html b/md_pdf/assets/templates/header-template.html index 24b1048..579edb0 100644 --- a/md_pdf/assets/templates/header-template.html +++ b/md_pdf/assets/templates/header-template.html @@ -6,7 +6,7 @@ - +
{{ title }} {% if submission_date %} From 67020eb8c56b0d93cba88e97aa97f3b516179227 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sat, 27 May 2017 14:12:31 +0100 Subject: [PATCH 12/14] Add output dir to context --- md_pdf/build/context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index 28be8b4..7919d79 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -3,6 +3,7 @@ from word_count import word_count from md_pdf.utils import get_plain_text from dateutil import parser import datetime +import os EXTRA_CONTEXT = { @@ -23,7 +24,7 @@ def get_context(config, content): **context, **EXTRA_CONTEXT, **{ - + 'output_dir': os.path.abspath(config['output_dir']), } ) if config.get('show_word_count'): From ecc0b174cb19ca621c07660a2526c913e8279bc5 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sat, 27 May 2017 14:20:39 +0100 Subject: [PATCH 13/14] Add program version to context --- md_pdf/__init__.py | 1 + md_pdf/args.py | 2 ++ md_pdf/build/context.py | 4 +++- setup.py | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/md_pdf/__init__.py b/md_pdf/__init__.py index e69de29..7e49527 100644 --- a/md_pdf/__init__.py +++ b/md_pdf/__init__.py @@ -0,0 +1 @@ +__version__ = '1.0' diff --git a/md_pdf/args.py b/md_pdf/args.py index bf5ac06..3b42416 100644 --- a/md_pdf/args.py +++ b/md_pdf/args.py @@ -1,9 +1,11 @@ import argparse +from md_pdf import __version__ def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("-v", "--verbose", help="Set verbosity level (repeat argument)", action="count", default=0) parser.add_argument("--update-csl", help="Update CSL files", action="store_true") + parser.add_argument("--version", action="version", version="%(prog)s {}".format(__version__)) parser.add_help = True return parser.parse_args() diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index 7919d79..f486b5c 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -1,6 +1,7 @@ from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR, DATE_FORMAT, TIME_FORMAT, DATETIME_FORMAT from word_count import word_count from md_pdf.utils import get_plain_text +from md_pdf import __version__ from dateutil import parser import datetime import os @@ -11,7 +12,8 @@ EXTRA_CONTEXT = { 'static_dir': STATIC_DIR, 'date': datetime.datetime.now().strftime(DATE_FORMAT), 'time': datetime.datetime.now().strftime(TIME_FORMAT), - 'datetime': datetime.datetime.now().strftime(DATETIME_FORMAT) + 'datetime': datetime.datetime.now().strftime(DATETIME_FORMAT), + 'mdp_version': __version__ } diff --git a/setup.py b/setup.py index 5a59877..f0d671a 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ from setuptools import setup, find_packages - +from md_pdf import __version__ setup( name="md-pdf", - version="1.0", + version=__version__, use_scm_version=True, install_requires=[ "beautifulsoup4==4.5.3", From 6042019c0c2bdae52ef955fa05f6d0a494d8e840 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sat, 27 May 2017 14:35:28 +0100 Subject: [PATCH 14/14] Allow context to override builtins --- md_pdf/build/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/md_pdf/build/context.py b/md_pdf/build/context.py index f486b5c..1d43af8 100644 --- a/md_pdf/build/context.py +++ b/md_pdf/build/context.py @@ -23,8 +23,8 @@ def get_context(config, content): del config['context'] context = dict( config, - **context, **EXTRA_CONTEXT, + **context, **{ 'output_dir': os.path.abspath(config['output_dir']), }