diff --git a/scripttease/lib/snippets/__init__.py b/scripttease/lib/snippets/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/scripttease/lib/snippets/centos.py b/scripttease/lib/snippets/centos.py deleted file mode 100644 index c55a4b2..0000000 --- a/scripttease/lib/snippets/centos.py +++ /dev/null @@ -1,32 +0,0 @@ -centos = { - 'apache': { - 'reload': "apachectl -k reload", - 'restart': "apachectl -k restart", - 'start': "apachectl -k start", - 'stop': "apachectl -k stop", - 'test': "apachectl configtest", - }, - 'install': "yum install -y {{ args[0] }}", - 'reload': "systemctl reload {{ args[0] }}", - 'restart': "systemctl restart {{ args[0] }}", - 'run': "{{ args[0] }}", - 'start': "systemctl start {{ args[0] }}", - 'stop': "systemctl stop {{ args[0] }}", - 'system': { - 'reboot': "reboot", - 'update': "yum check-update", - 'upgrade': "yum update -y", - }, - 'uninstall': "yum remove -y {{ args[0] }}", - 'upgrade': "yum upgrade -y {{ args[0] }}", - 'user': { - 'add': [ - "adduser {{ args[0] }}", - "{% if home %}--home {{ home }}{% endif %}", - "{% if login %}--shell {{ login }}{% endif %}", - "{% if system %}--system{% endif %}", - "{% if groups %}&& {% for group in groups %}gpasswd -a {{ args[0] }} {{ group }};{% endfor %}{% endif %}" - ], - 'remove': "userdel -r {{ args[0] }}", - } -} diff --git a/scripttease/lib/snippets/django.py b/scripttease/lib/snippets/django.py deleted file mode 100644 index 3d2ae8f..0000000 --- a/scripttease/lib/snippets/django.py +++ /dev/null @@ -1,109 +0,0 @@ -from commonkit import parse_jinja_string -from ...constants import EXCLUDED_KWARGS - - -def django_command_parser(snippet, args=None, excluded_kwargs=None): - - _excluded_kwargs = excluded_kwargs or EXCLUDED_KWARGS - - # We need to remove the common options so any remaining keyword arguments are converted to switches for the - # management command. - _kwargs = snippet.kwargs.copy() - for name in _excluded_kwargs: - _kwargs.pop(name, None) - - # We need to remove some parameters for dumpdata and loaddata. Otherwise they end up as switches. - if snippet.name in ("django.dumpdata", "django.loaddata"): - app_name = _kwargs.pop("app", None) - model_name = _kwargs.pop("model", None) - - default_path = "fixtures/%s/initial.json" % app_name - if model_name: - default_path = "fixtures/%s/%s.json" % (app_name, model_name.lower()) - - path = _kwargs.pop("path", default_path) - if 'path' not in snippet.kwargs: - snippet.kwargs['path'] = path - - a = list() - command_name = None - for key, value in _kwargs.items(): - if key == "_name": - command_name = value - continue - - key = key.replace("_", "-") - if type(value) is bool: - if value is True: - a.append("--%s" % key) - else: - a.append("--%s=%s" % (key, value)) - - context = snippet.context.copy() - context['args'] = args or snippet.args - context['command_name'] = command_name - context['switches'] = " ".join(a) - context.update(snippet.kwargs) - - if type(snippet.content) is list: - b = list() - for i in snippet.content: - b.append(parse_jinja_string(i, context)) - - return " ".join(b) - - return parse_jinja_string(snippet.content, context) - - -# def django_command_builder(tokens, *args, **kwargs): -# a = list() -# -# command_name = tokens.pop(0) -# if command_name == "command": -# command_name = tokens.pop(0) -# -# params = django_convert_params(*args, **kwargs) -# -# a.append("./manage.py %s" % command_name) -# if len(list(params)) > 0: -# a.append(" ".join(list(params))) -# -# return a -# -# -# def django_convert_params(*args, **kwargs): -# a = list() -# for key, value in kwargs.items(): -# key = key.replace("_", "-") -# if type(value) is bool: -# if value is True: -# a.append("--%s" % key) -# else: -# a.append("--%s=%s" % (key, value)) -# -# return " ".join(list(args)), " ".join(a) - - -django = { - 'django': { - 'check': "./manage.py check {{ switches }}", - 'command': "./manage.py {{ command_name }} {% if args %}{{ ' '.join(args) }}{% endif %} {{ switches }}", - 'dumpdata': [ - "./manage.py dumpdata {{ app }}{% if model %}.{{ model }}{% endif %}", - # "--indent=4", - "{{ switches }}", - '> {{ path }}', - ], - 'loaddata': [ - "./manage.py loaddata", - "{{ switches }}" - '{{ path }}', - ], - 'migrate': "./manage.py migrate {{ switches }}", - 'static': "./manage.py collectstatic {{ switches }}", - '_default': "command", - '_parser': django_command_parser, - '_prefix': "source {{ virtualenv }}/bin/activate", - '_register': ["check", "migrate"] - } -} diff --git a/scripttease/lib/snippets/mappings.py b/scripttease/lib/snippets/mappings.py deleted file mode 100644 index 338ee58..0000000 --- a/scripttease/lib/snippets/mappings.py +++ /dev/null @@ -1,62 +0,0 @@ -# Imports - -from .centos import centos -from .django import django -from .messages import messages -from .mysql import mysql -from .pgsql import pgsql -from .php import php -from .posix import posix -from .python import python -from .ubuntu import ubuntu - -# Exports - -__all__ = ( - "MAPPINGS", - "merge", - "merge_dictionaries", -) - -# Functions - - -def merge(first: dict, *others) -> dict: - """Merge all other dictionaries into the first. - - :param first: The first dictionary. - :type first: dict - - :param others: A list of other dictionaries to be merged. - - """ - for d in others: - first = merge_dictionaries(first, d) - - return first - - -def merge_dictionaries(first: dict, second: dict) -> dict: - """Merge the second dictionary into the first. - - :param first: The first dictionary. - :type first: dict - - :param second: The second dictionary. - :type second: dict - - :rtype: dict - - """ - for key, values in second.items(): - first[key] = values - - return first - -# Mappings - - -MAPPINGS = { - 'centos': merge(centos, django, messages, mysql, pgsql, php, posix, python), - 'ubuntu': merge(ubuntu, django, messages, mysql, pgsql, php, posix, python), -} diff --git a/scripttease/lib/snippets/messages.py b/scripttease/lib/snippets/messages.py deleted file mode 100644 index 0e15c08..0000000 --- a/scripttease/lib/snippets/messages.py +++ /dev/null @@ -1,22 +0,0 @@ -messages = { - 'dialog': [ - "dialog", - "--clear", - '--backtitle "{{ title|default("Message") }}', - '--msgbox "{{ args[0] }}" {{ height|default("15") }} {{ width|default("100") }};' - 'clear;' - ], - 'echo': 'echo "{{ args[0] }}"', - 'explain': "{{ args[0] }}", # not used, but supports is_valid - 'screenshot': "{{ args[0] }}", # not used, but supports is_valid - 'slack': [ - "curl -X POST -H 'Content-type: application/json' --data", - '{"text": "{{ args[0] }}"}', - "{{ url }}", - ], - 'twist': [ - "curl -X POST -H 'Content-type: application/json' --data", - '{"content": "{{ args[0] }}", "title": "{{ title|default("Notice") }}"}', - "{{ url }}", - ], -} \ No newline at end of file diff --git a/scripttease/lib/snippets/mysql.py b/scripttease/lib/snippets/mysql.py deleted file mode 100644 index eda4fd1..0000000 --- a/scripttease/lib/snippets/mysql.py +++ /dev/null @@ -1,87 +0,0 @@ -mysql = { - 'mysql': { - 'create': [ - "mysqladmin create", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - "{{ args[0] }}", - '{% if owner %}&& mysql --user {{ admin_user|default("root") }} ' - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %} ' - '--host={{ host|default("localhost") }} ' - '--port={{ port|default("3306") }} ' - '--execute="GRANT ALL ON {{ args[0] }}.* TO \'{{ owner }}\'@\'{{ host|default("localhost") }}\'"' - '{% endif %}' - ], - 'drop': [ - "mysqladmin drop", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - "{{ args[0] }}", - ], - 'dump': [ - "mysqldump", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - '--complete-inserts', - '{{ args[0] }} > {{ path|default("dump.sql") }}', - ], - 'exec': [ - "mysql", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - '--execute="{{ args[0] }}"', - '{{ database|default("default") }}', - ], - 'exists': [ - "mysql", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - '--execute="SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \'{{ args[0] }}\'"', - ], - 'grant': [ - "mysql", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - '--execute="GRANT {{ args[0] }} ON {{ database|default("default") }}.* TO \'{{ user }}\'@\'{{ host|default("localhost") }}\'"' - ], - 'user': { - 'create': [ - "mysql", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - '--execute="CREATE USER IF NOT EXISTS \'{{ args[0] }}\'@\'{{ host|default("localhost") }}\'" ' - '{% if password %}IDENTIFIED BY PASSWORD(\'{{ password }}\'{% endif %}' - ], - 'drop': [ - "mysql", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - '--execute="DROP USER IF EXISTS \'{{ args[0] }}\'@\'{{ host|default("localhost") }}\'"' - ], - 'exists': [ - "mysql", - '--user={{ admin_user|default("root") }}', - '{% if admin_pass %}--password="{{ admin_pass }}"{% endif %}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("3306") }}', - '--execute="SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = \'{{ args[0] }}\')"' - ], - }, - } -} diff --git a/scripttease/lib/snippets/pgsql.py b/scripttease/lib/snippets/pgsql.py deleted file mode 100644 index 7da25e2..0000000 --- a/scripttease/lib/snippets/pgsql.py +++ /dev/null @@ -1,115 +0,0 @@ -from commonkit import parse_jinja_string - - -def pgsql_command_parser(snippet, args=None): - a = list() - - if snippet.admin_pass: - a.append('export PGPASSWORD="%s" &&' % snippet.admin_pass) - - if snippet.admin_user: - a.append("-U %s" % snippet.admin_user) - - if snippet.host: - a.append("--host=%s" % snippet.host) - - if snippet.port: - a.append("--port=%s" % snippet.port) - - context = snippet.context.copy() - context['args'] = args or snippet.args - context.update(snippet.kwargs) - - if type(snippet.content) is list: - b = list() - for i in snippet.content: - b.append(parse_jinja_string(i, context)) - - return " ".join(b) - - return parse_jinja_string(snippet.content, context) - - -pgsql = { - 'pgsql': { - 'create': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "createdb", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - "{% if owner %}--owner={{ owner }}{% endif %}", - "{% if template %}--template={{ template }}{% endif %}", - "{{ args[0] }}", - ], - 'drop': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "dropdb", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - "{{ args[0] }}", - ], - 'dump': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "pd_dump", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - "--column-inserts", - '--file={{ path|default("dump.sql") }}', - "{{ args[0] }}" - ], - 'exec': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "psql", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - "--dbname={{ database }}", - '-c "{{ args[0] }}"', - ], - 'exists': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "psql", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - r"-lqt | cut -d \| -f 1 | grep -qw {{ args[0] }}", - ], - 'user': { - 'create': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "createuser", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - "-DRS {{ args[0] }}", # no create db or roles, and not a superuser - '{% if password %}&& psql -U {{ admin_user|default("postgres") }} ' - '--host={{ host|default("localhost") }} ' - '--port={{ port|default("5432") }} ' - ' -c "ALTER USER {{ args[0] }} WITH ENCRYPTED PASSWORD \'{{ password }}\';"' - '{% endif %}', - ], - 'drop': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "dropuser", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - "{{ args[0] }}" - ], - 'exists': [ - '{% if admin_pass %}export PGPASSWORD="{{ admin_pass }}" &&{% endif %}', - "psql", - '-U {{ admin_user|default("postgres") }}', - '--host={{ host|default("localhost") }}', - '--port={{ port|default("5432") }}', - '-c "SELECT 1 FROM pgsql_roles WHERE rolnamme={{ args[0] }};"' - ], - }, - # '_parser': pgsql_command_parser, - '_register': ["exists", 'user.exists'], - } -} - diff --git a/scripttease/lib/snippets/php.py b/scripttease/lib/snippets/php.py deleted file mode 100644 index 26409b6..0000000 --- a/scripttease/lib/snippets/php.py +++ /dev/null @@ -1,5 +0,0 @@ -php = { - 'php': { - 'module': "phpenmod {{ args[0] }}", - }, -} diff --git a/scripttease/lib/snippets/posix.py b/scripttease/lib/snippets/posix.py deleted file mode 100644 index 678c866..0000000 --- a/scripttease/lib/snippets/posix.py +++ /dev/null @@ -1,125 +0,0 @@ -posix = { - 'append': 'echo "{{ content }}" >> {{ args[0] }}', - 'archive': [ - "tar -cz", - "{% if absolute %}-P{% endif %}", - "{% if view %}-v{% endif %}", - "{% if exclude %}--exclude {{ exclude }}{% endif %}", - "{% if strip %}--strip-components {{ strip }}{% endif %}", - "-f {{ args[0] }} {{ to }}", - ], - 'copy': [ - "cp", - "{% if not overwrite %}-n{% endif %}", - "{% if recursive %}-R{% endif %}", - "{{ args[0] }} {{ args[1] }}" - ], - 'dir': [ - "mkdir", - "{% if recursive %}-p{% endif %}", - "{% if mode %}-m {{ mode }}{% endif %}", - "{{ args[0] }}", - "{% if group %}&& chgrp -R {{ group }} {{ args[0] }}{% endif %}", - "{% if owner %}&& chown -R {{ owner }} {{ args[0] }}{% endif %}" - ], - 'extract': [ - "tar", - "-xz", - "{% if absolute %}-P{% endif %}", - "{% if view %}-v{% endif %}", - "{% if exclude %}--exclude {{ exclude }}{% endif %}", - "{% if strip %}--script-components {{ strip }}{% endif %}", - '-f {{ args[0] }} {{ to|default("./") }}', - ], - 'file': [ - "{% if content %}cat > {{ args[0] }} << EOF\n{{ content }}\nEOF{% else %}touch {{ args[0] }}{% endif %}", - "{% if mode %}&& chmod {{ mode }} {{ args[0] }}{% endif %}", - "{% if group %}&& chgrp {{ group }} {{ args[0] }}{% endif %}", - "{% if owner %}&& chown {{ owner }} {{ args[0] }}{% endif %}" - ], - 'link': [ - "ln -s", - "{% if force %}-f{% endif %}", - '{{ args[0] }} {{ args[1] }}', - ], - 'mkdir': [ - "mkdir", - "{% if recursive %}-p{% endif %}", - "{% if mode %}-m {{ mode }}{% endif %}", - "{{ args[0] }}", - "{% if group %}&& chgrp -R {{ group }} {{ args[0] }}{% endif %}", - "{% if owner %}&& chown -R {{ owner }} {{ args[0] }}{% endif %}" - ], - 'move': "mv {{ args[0] }} {{ args[1] }}", - 'perms': [ - "{% if group %}chgrp {% if recursive %}-R {% endif %}{{ group }} {{ args[0] }};{% endif %}", - "{% if mode %}chmod {% if recursive %}-R {% endif %}{{ mode }} {{ args[0] }};{% endif %}", - "{% if owner %}chown {% if recursive %}-R {% endif %}{{ owner }} {{ args[0] }}{% endif %}", - ], - 'push': [ - "rsync", - "--csv-exclude", - "--checksum", - "--compress", - "{% if delete %}--delete{% endif %}", - "{% if links %}--copy-links{% endif %}", - "{% if exclude %}--exclude-from={{ exclude }}{% endif %}", - # --partial and --progress - "-P", - "{% if recursive %}--recursive{% endif %}", - "{{ args[0] }}", - '-e "ssh -i {{ key_file }} -p {{ port|default("22") }}', - "{{ user }}@{{ host }}:{{ args[1] }}", - ], - 'remove': [ - "rm", - "{% if force %}-f{% endif %}", - "{% if recursive %}-r{% endif %}", - "{{ args[0] }}" - ], - 'rename': "mv {{ args[0] }} {{ args[1] }}", - 'replace': [ - 'sed -i {{ backup|default(".b") }}', - '"s{{ delimiter|default("/") }}{{ find }}{{ delimiter|default("/") }}{{ sub }}{{ delimiter|default("/") }}g"', - "{{ args[0] }}" - ], - 'scopy': [ - "scp", - "{% if key_file %}-i {{ key_file }}{% endif %}", - '-P {{ port|default("22") }}', - "{{ args[0] }}", - "{{ user }}@{{ host }}:{{ args[1] }}" - ], - 'ssl': [ - "certbot certonly", - "--agree-tos", - '--email {{ email|default("webmaster@" + args[0]) }}', - "-n --webroot", - '-w {{ webroot|default("/var/www/maint/www") }}', - "-d {{ args[0] }}" - ], - 'sync': [ - "rsync", - "--csv-exclude", - "--checksum", - "--compress", - "{% if delete %}--delete{% endif %}", - "{% if links %}--copy-links{% endif %}", - "{% if exclude %}--exclude-from={{ exclude }}{% endif %}", - # --partial and --progress - "-P", - "{% if recursive %}--rescursive{% endif %}", - "{{ args[0] }}" - "{{ args[1] }}" - ], - 'touch': "touch {{ args[0] }}", - 'wait': "sleep {{ args[0] }}", - # 'write': [ - # "cat > {{ args[0] }} << EOF", - # "\n", - # "{{ content }}", - # "\n", - # "EOF" - # ], - 'write': "cat > {{ args[0] }} << EOF\n{{ content }}\nEOF", -} \ No newline at end of file diff --git a/scripttease/lib/snippets/python.py b/scripttease/lib/snippets/python.py deleted file mode 100644 index 55768eb..0000000 --- a/scripttease/lib/snippets/python.py +++ /dev/null @@ -1,33 +0,0 @@ -python = { - 'pip': [ - "{% if venv %}source {{ venv }}/bin/activate &&{%- endif %}", - "pip{% if version %}{{ version }}{% endif %}", - '{{ op|default("install") }}', - '{% if op == "upgrade" %}--upgrade{% endif %}', - "{{ args[0] }}", - ], - 'pip3': [ - "{% if venv %}source {{ venv }}/bin/activate &&{%- endif %}", - 'pip3 {{ op|default("install") }}', - '{% if op == "upgrade"%}--upgrade{% endif %}', - "{{ args[0] }}", - ], - # 'pip': { - # 'install': [ - # "{% if venv %}source {{ venv }} &&{% endif %}", - # "{% if version %}pip{{ version }}{% else %}pip{% endif %}", - # "install {{ args[0] }}", - # ], - # 'remove': [ - # "{% if version %}pip{{ version }}{% else %}pip{% endif %}", - # "uninstall {{ args[0] }}", - # ], - # 'upgrade': [ - # "{% if version %}pip{{ version }}{% else %}pip{% endif %}", - # "install --upgrade {{ args[0] }}", - # ], - # '_default': "install", - # '_dotted': True, - # }, - 'virtualenv': "virtualenv {{ args[0] }}", -} \ No newline at end of file diff --git a/scripttease/lib/snippets/ubuntu.py b/scripttease/lib/snippets/ubuntu.py deleted file mode 100644 index 9679320..0000000 --- a/scripttease/lib/snippets/ubuntu.py +++ /dev/null @@ -1,41 +0,0 @@ -ubuntu = { - 'apache': { - # 'disable': '{% if args[0].startswith("mod_") %}a2dismod{% else %}a2dissite{% endif %} {{ args[0] }}', - 'disable_module': "a2dismod {{ args[0] }}", - 'disable_site': "a2dissite {{ args[0] }}", - # 'enable': '{% if args[0].startswith("mod_") %}a2enmod{% else %}a2ensite{% endif %} {{ args[0] }}', - 'enable_module': "a2enmod {{ args[0] }}", - 'enable_site': "a2ensite {{ args[0] }}", - 'reload': "service apache2 reload", - 'restart': "service apache2 restart", - 'start': "service apache2 start", - 'stop': "service apache2 stop", - 'test': "apachectl configtest", - }, - 'install': "apt install -y {{ args[0] }}", - 'reload': "service {{ args[0] }} reload", - 'restart': "service {{ args[0] }} restart", - 'run': "{{ args[0] }}", - 'start': "service {{ args[0] }} start", - 'stop': "service {{ args[0] }} stop", - 'system': { - 'reboot': "reboot", - 'update': "apt-get update -y", - 'upgrade': "apt-get upgrade -y", - }, - 'uninstall': "apt-get uninstall -y {{ args[0] }}", - 'upgrade': "apt-get install -y --only-upgrade {{ args[0] }}", - 'user': { - # The gecos switch eliminates the prompts. - # TODO: Deal with user password when creating a user in ubuntu. - 'add': [ - "adduser {{ args[0] }} --gecos --disabled-password", - "{% if home %}--home {{ home }}{% endif %}", - "{% if login %}--shell {{ login }}{% endif %}", - "{% if system %}--system{% endif %}", - "{% if groups %}&& {% for group in groups %}adduser {{ args[0] }} {{ group }};{% endfor %}{% endif %}" - - ], - 'remove': "deluser {{ args[0] }}", - }, -}