Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge remote-tracking branch 'origin/2.3' #3801

Merged
merged 64 commits into from
Jun 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
f558560
Remove unwanted moves
sbrunner May 24, 2018
18c35c0
Spell on more files
sbrunner May 7, 2018
80d11fe
Add a spell correction
sbrunner May 7, 2018
975ed12
Merge pull request #3726 from camptocamp/spell
sbrunner May 24, 2018
c49379f
Fix the redirects
sbrunner May 25, 2018
2330be8
Little fix for Docker upgrade
sbrunner May 25, 2018
ee230ca
Revert "Prevent caching of admin pages (#3760)"
sbrunner May 28, 2018
b804dd4
Fix the travis in the project
sbrunner May 28, 2018
43d0a13
Setup a global front
May 28, 2018
eac1df8
Merge pull request #3771 from camptocamp/fix-redirect
sbrunner May 29, 2018
2c2d017
Cleanup
sbrunner May 29, 2018
a52e9b9
Update c2cgeoform
sbrunner May 28, 2018
709456d
Merge pull request #3773 from camptocamp/travis
sbrunner May 29, 2018
c09f9a2
Merge pull request #3769 from camptocamp/upgrade-fix
sbrunner May 29, 2018
9cbdc80
Merge pull request #3774 from camptocamp/cache-control
sbrunner May 29, 2018
9345094
Merge pull request #3772 from camptocamp/global_front
sbrunner May 29, 2018
965e9f1
Merge pull request #3777 from camptocamp/docker-upgrade
sbrunner May 29, 2018
22aa382
Then old node_modules_bak should allways be removed
sbrunner May 30, 2018
dcb332a
Fix Jenkins stages
sbrunner May 29, 2018
a5e078f
Merge pull request #3780 from camptocamp/jenkins-fix
sbrunner May 30, 2018
0d36de8
Merge pull request #3779 from camptocamp/fix
sbrunner May 30, 2018
e52da4b
Add all interfaces theme
sbrunner May 30, 2018
fc29569
Merge pull request #3781 from camptocamp/fix-23
sbrunner May 30, 2018
84c2e6e
Fix the tiles entry point
sbrunner May 29, 2018
eeac505
Fix TileCloud-chain container
sbrunner May 29, 2018
ab997c2
Change datetime fields to datetime with timezone
arnaud-morvan May 29, 2018
4c2a4b4
Add template interpretation in config
sbrunner May 29, 2018
e0dc449
Refactor
sbrunner May 31, 2018
79feadc
Merge pull request #3782 from camptocamp/template-config
sbrunner Jun 1, 2018
3f3422d
Fix raster web service
sbrunner May 28, 2018
a6bf31a
Fix webpack entry points
sbrunner May 28, 2018
25face6
Merge pull request #3778 from camptocamp/timezones
arnaud-morvan Jun 1, 2018
f01a5fa
Merge pull request #3784 from camptocamp/docker-webpack
sbrunner Jun 4, 2018
b588817
Add move components changelog message
sbrunner Jun 1, 2018
0f5c549
Be able to use dev mode without dev server
sbrunner Jun 1, 2018
e15f08d
Add project alias
sbrunner Jun 1, 2018
dcf0c69
Some fix for Windows
sbrunner Jun 1, 2018
7ed4685
Add custom requirements
sbrunner Jun 1, 2018
bb48d08
Hide and ignore compile errors
sbrunner Jun 1, 2018
99a40b2
Add missing googshift required for the migration
sbrunner Jun 1, 2018
7999f19
Unused dependency
sbrunner Jun 1, 2018
a9e3a74
Add npm prefix to avoid conflict
sbrunner Jun 1, 2018
ac3c2e9
Disabe flippering test
sbrunner Jun 4, 2018
c72d98d
Merge pull request #3785 from camptocamp/windows
sbrunner Jun 4, 2018
4882aab
Fix the pip publishing
sbrunner Jun 4, 2018
65628b7
Merge pull request #3786 from camptocamp/fix-pip
sbrunner Jun 4, 2018
d325234
Fix mapserver for Docker compose environment
sbrunner Jun 5, 2018
4b24a26
Fix some typo
sbrunner Jun 5, 2018
ec88b93
Add Docker debuging tips
sbrunner Jun 5, 2018
dda51d8
Merge pull request #3787 from camptocamp/mapserver-docker
sbrunner Jun 5, 2018
c879c62
Be able to access to the admin interface without ending slash
sbrunner Jun 5, 2018
c6ebd7a
Merge pull request #3792 from camptocamp/admin-no-slash
sbrunner Jun 5, 2018
8748085
Merge pull request #3790 from camptocamp/typo-docker
sbrunner Jun 5, 2018
7d93b9d
Merge pull request #3789 from camptocamp/debug-docker
sbrunner Jun 5, 2018
18813b9
Return a better message
sbrunner Jun 6, 2018
41dd695
Fix signal send for Gunicorn instead of for Apache
sbrunner Jun 6, 2018
dff837c
Merge pull request #3795 from camptocamp/fix-notfound
sbrunner Jun 6, 2018
6598f24
Fix the print for the Docker compose environment
sbrunner Jun 5, 2018
bf1ad1c
Merge pull request #3794 from camptocamp/fix-debugginf
sbrunner Jun 6, 2018
752b8fa
Merge pull request #3788 from camptocamp/print-docker
sbrunner Jun 6, 2018
fe581ff
Merge remote-tracking branch 'origin/2.3'
sbrunner Jun 7, 2018
f34e530
No spell on package-lock.json
sbrunner Jun 7, 2018
f5ce4bf
Fix spell
sbrunner Jun 7, 2018
38e622b
Fix upgrade
sbrunner Jun 7, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ To check before create a new issue:
* I am using the latest minor version of the major version (`x.y.last`).
* I create one issue per subject (do not put more than one thing in the same issue).

For commiters:
For committers:

* I have assigned a green label.
* I have assigned a milestone.
Expand Down
8 changes: 1 addition & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
/npm-packages
/Dockerfile
/commons/tests.yaml
/commons/.build/
/commons/c2cgeoportal_commons.egg-info/
/geoportal/package.json
/geoportal/tests/functional/test.ini
Expand All @@ -18,17 +17,12 @@
/geoportal/c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/locale/
/geoportal/c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static-ngeo/images/
/geoportal/c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static-ngeo/js/apps/
/geoportal/c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static-ngeo/components/
/geoportal/c2cgeoportal_geoportal/scaffolds/update/CONST_Makefile_tmpl.mk
/geoportal/c2cgeoportal_geoportal/scaffolds/update/CONST_create_template/
/geoportal/c2cgeoportal_geoportal/scaffolds/nondockercreate/geoportal/+package+_geoportal/static-ngeo/js/apps/
/geoportal/c2cgeoportal_geoportal/scaffolds/nondockerupdate/CONST_create_template/
/geoportal/c2cgeoportal_geoportal.egg-info/
/admin/tests.ini
/admin/.build/
/admin/.pytest_cache/
/admin/package-lock.json
/admin/package.json
/admin/node_modules/
/admin/npm-packages
/admin/c2cgeoportal_admin/locale/
/admin/c2cgeoportal_admin.egg-info/
Expand Down
25 changes: 13 additions & 12 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dockerBuild {
sh 'docker run --name geomapfish-db --env=POSTGRES_USER=www-data --env=POSTGRES_PASSWORD=www-data --env=POSTGRES_DB=geomapfish --publish=5432:5432 --detach camptocamp/geomapfish-test-db'
sh 'travis/test-upgrade-convert.sh init ${HOME}/workspace'
}
stage('Test') {
stage('Tests') {
checkout scm
parallel 'Lint and test c2cgeoportal': {
sh './docker-run travis/status.sh'
Expand Down Expand Up @@ -99,23 +99,24 @@ dockerBuild {
sh 'cat ${HOME}/workspace/testgeomapfish/testdb/*.sql'
sh 'cat ${HOME}/workspace/testgeomapfish/geoportal/config.yaml'
withCredentials([[
$class : 'UsernamePasswordMultiBinding',
credentialsId : 'dockerhub',
usernameVariable: 'USERNAME',
passwordVariable: 'PASSWORD'
]]) {
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'dockerhub',
usernameVariable: 'USERNAME',
passwordVariable: 'PASSWORD'
]]) {
try {
sh 'docker login -u "$USERNAME" -p "$PASSWORD"'
sh '(cd ${HOME}/workspace/testgeomapfish/; docker-compose up --force-recreate -d)'
sh '(cd ${HOME}/workspace/testgeomapfish/; docker-compose exec -T geoportal wait-for-db)'
sh './docker-run travis/waitwsgi http://`netstat --route --numeric|grep ^0.0.0.0|awk \'{print($2)}\'`:8080/'
for (path in [
'c2c/health_check',
'c2c/health_check?max_level=9',
'c2c/health_check?checks=check_collector',
'layers/test/values/type enum',
'admin/layertree',
'admin/layertree/children'
'c2c/health_check',
'c2c/health_check?max_level=9',
'c2c/health_check?checks=check_collector',
// TODO: activate gunicon logs to debug this test
// 'layers/test/values/type enum',
'admin/layertree',
'admin/layertree/children'
]) {
def start_lines = [:]
['db', 'external-db', 'print', 'mapserver', 'geoportal'].each { service ->
Expand Down
22 changes: 16 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ ADMIN_SRC_FILES = $(shell ls -1 commons/c2cgeoportal_commons/models/*.py) \
$(shell find admin/c2cgeoportal_admin/templates/widgets -name "*.pt" -print)

APPS += desktop mobile
APPS_PACKAGE_PATH_NONDOCKER = geoportal/c2cgeoportal_geoportal/scaffolds/nondockercreate/geoportal/+package+_geoportal
APPS_HTML_FILES = $(addprefix $(APPS_PACKAGE_PATH_NONDOCKER)/static-ngeo/js/apps/, $(addsuffix .html.ejs_tmpl, $(APPS)))
APPS_PACKAGE_PATH = geoportal/c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal
APPS_HTML_FILES = $(addprefix $(APPS_PACKAGE_PATH)/static-ngeo/js/apps/, $(addsuffix .html.ejs_tmpl, $(APPS)))
APPS_HTML_FILES += $(addprefix $(APPS_PACKAGE_PATH)/static-ngeo/js/apps/, $(addsuffix .html.ejs_tmpl, $(APPS)))
APPS_JS_FILES = $(addprefix $(APPS_PACKAGE_PATH)/static-ngeo/js/apps/Controller, $(addsuffix .js_tmpl, $(APPS)))
APPS_ALT += desktop_alt mobile_alt oeedit oeview
APPS_PACKAGE_PATH_ALT = geoportal/c2cgeoportal_geoportal/scaffolds/update/CONST_create_template/geoportal/+package+_geoportal/
Expand Down Expand Up @@ -251,12 +253,14 @@ quote:

.PHONY: spell
spell:
codespell --ignore-words=spell-ignore-words.txt geoportal/setup.py \
$(shell find commons/c2cgeoportal_commons -name '*.py' -print) \
$(shell find geoportal/c2cgeoportal_geoportal -name static -prune -or -name '*.py' -print) \
$(shell find admin/c2cgeoportal_admin -name '*.py' -print)
codespell --quiet-level=2 --check-filenames --ignore-words=spell-ignore-words.txt \
$(shell find -name node_modules -prune -or -name .build -prune -or -name .git -prune -or -name ngeo -prune \
-or -name '__pycache__' -prune -or -name _build -prune \
-or \( -type f -and -not -name '*.png' -and -not -name '*.mo' -and -not -name '*.po*' \
-and -not -name 'CONST_Makefile_tmpl' \) -print)

YAML_FILES ?= $(shell find -name node_modules -prune -or -name .build -prune -or -name ngeo -prune -or -name functional -prune -or \( -name "*.yml" -or -name "*.yaml" \) -print)

YAML_FILES ?= $(shell find -name ngeo -prune -or -name functional -prune -or \( -name "*.yml" -or -name "*.yaml" \) -print)
.PHONY: yamllint
yamllint:
yamllint --strict --config-file=yamllint.yaml -s $(YAML_FILES)
Expand Down Expand Up @@ -334,6 +338,11 @@ $(APPS_PACKAGE_PATH)/static-ngeo/js/apps/%.html.ejs_tmpl: ngeo/contribs/gmf/apps
mkdir --parent $(dir $@)
import-ngeo-apps --html $* $< $@

$(APPS_PACKAGE_PATH_NONDOCKER)/static-ngeo/js/apps/%.html.ejs_tmpl: ngeo/contribs/gmf/apps/%/index.html.ejs
$(PRERULE_CMD)
mkdir --parent $(dir $@)
import-ngeo-apps --html --non-docker $* $< $@

$(APPS_PACKAGE_PATH)/static-ngeo/js/apps/Controller%.js_tmpl: ngeo/contribs/gmf/apps/%/Controller.js
$(PRERULE_CMD)
mkdir --parent $(dir $@)
Expand Down Expand Up @@ -369,6 +378,7 @@ npm-packages: ngeo package.json
coveralls gaze jasmine-core jsdoc jsdom karma karma-chrome-launcher karma-coverage \
karma-jasmine karma-sourcemap-loader karma-webpack \
--src=ngeo/package.json --src=package.json --dst=$@
echo googshift eslint-plugin-googshift >> $@

admin/npm-packages: ngeo package.json
$(PRERULE_CMD)
Expand Down
6 changes: 0 additions & 6 deletions admin/c2cgeoportal_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ def main(_, **settings):
config.add_subscriber(add_renderer_globals, BeforeRender)
config.add_subscriber(add_localizer, NewRequest)

config.add_tween('c2cgeoportal_admin.cache_tween.CacheTween')

generate_mappers()

health_check = HealthCheck(config)
Expand Down Expand Up @@ -93,9 +91,5 @@ def includeme(config: Configurator):
config.include('pyramid_tm')
config.add_translation_dirs('c2cgeoportal_admin:locale')

import c2cgeoportal_admin.cache_tween
c2cgeoportal_admin.cache_tween.route_prefix = config.route_prefix
config.add_tween('c2cgeoportal_admin.cache_tween.CacheTween')

with PermissionSetter(config):
config.scan()
2 changes: 2 additions & 0 deletions admin/c2cgeoportal_admin/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ def includeme(config):
'{}:node_modules'.format(config.root_package.__name__))
path = None
for path_ in [
os.path.join(os.path.dirname(__file__), '..', '..', 'admin', 'node_modules'),
os.path.join(os.path.dirname(__file__), '..', '..', 'node_modules'),
os.path.join(os.path.dirname(__file__), '..', 'admin', 'node_modules'),
os.path.join(os.path.dirname(__file__), '..', 'node_modules'),
'/usr/lib/node_modules/',
]:
Expand Down
2 changes: 1 addition & 1 deletion admin/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
c2cgeoform==2.0.dev20180527
c2cgeoform
#c2cgeoportal-commons # pip -> Could not find a version that satisfies the requirement c2cgeoportal-commons
c2cwsgiutils
colander
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2011-2018, Camptocamp SA
# Copyright (c) 2017-2018, Camptocamp SA
# All rights reserved.

# Redistribution and use in source and binary forms, with or without
Expand All @@ -27,19 +27,40 @@
# of the authors and should not be interpreted as representing official policies,
# either expressed or implied, of the FreeBSD Project.

route_prefix = None
"""Add timezone on datetime fields

Revision ID: 53d671b17b20
Revises: 1857owc78a07
Create Date: 2018-05-29 08:44:17.675988
"""

class CacheTween:
from alembic import op
from c2cgeoportal_commons.config import config

def __init__(self, handler, registry):
del registry
self.handler = handler
# revision identifiers, used by Alembic.
revision = '53d671b17b20'
down_revision = '1857owc78a07'
branch_labels = None
depends_on = None

def __call__(self, request):
# Never cache admin pages
response = self.handler(request)
if route_prefix is None or request.path_info.startswith('/' + route_prefix):
response.cache_control.no_cache = True
response.cache_control.max_age = 0
return response

def upgrade():
staticschema = config['schema_static']

op.execute("""
SET TIME ZONE 'UTC';
ALTER TABLE {staticschema}.user ALTER COLUMN last_login TYPE timestamp with time zone;
SET TIME ZONE LOCAL;
ALTER TABLE {staticschema}.user ALTER COLUMN expire_on TYPE timestamp with time zone;
""".format(staticschema=staticschema))


def downgrade():
staticschema = config['schema_static']

op.execute("""
SET TIME ZONE 'UTC';
ALTER TABLE {staticschema}.user ALTER COLUMN last_login TYPE timestamp without time zone;
SET TIME ZONE LOCAL;
ALTER TABLE {staticschema}.user ALTER COLUMN expire_on TYPE timestamp without time zone;
""".format(staticschema=staticschema))
5 changes: 3 additions & 2 deletions commons/c2cgeoportal_commons/models/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import logging
from datetime import datetime
from hashlib import sha1
import pytz
from typing import Optional

from sqlalchemy import Column
Expand Down Expand Up @@ -198,10 +199,10 @@ def validate_password(self, passwd: str) -> bool:
return False

def expired(self) -> bool:
return self.expire_on is not None and self.expire_on < datetime.utcnow()
return self.expire_on is not None and self.expire_on < datetime.now(pytz.utc)

def update_last_login(self) -> None:
self.last_login = datetime.utcnow()
self.last_login = datetime.now(pytz.utc)

def __unicode__(self) -> str:
return self.username or '' # pragma: no cover
Expand Down
38 changes: 32 additions & 6 deletions doc/developer/debugging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Sometime more information are available by using this command:
You may also activate MapServer's debug mode and set environment variable of the MapServer container
``MS_DEBUGLEVEL`` to ``5`` (most verbose level, default is 0).

`More informations <http://mapserver.org/optimization/debugging.html?highlight=debug#debug-levels>`_
`More information <http://mapserver.org/optimization/debugging.html?highlight=debug#debug-levels>`_

PostgreSQL
----------
Expand All @@ -67,19 +67,45 @@ Logs are available in the ``/var/log/postgresql/postgresql-9.*-main.log`` file.
Makefile
--------

You can run `DEBUG=TRUE make ...` to have some debug message.
To obtain additional debug messages, you can rebuild your project as follows:

.. prompt:: bash

DEBUG=TRUE make ...

Actually we display the running rule and why she is running (dependence update).

Docker
------

Edit a file in a running apache WSGI container
Run gunicorn to reload on modifications of Python files
.......................................................

Add the following environment variable to the geoportal container:

``GUNICORN_PARAMS="-b :80 --worker-class gthread --threads 1 --workers 1 --reload"``

Do a graceful restart of the running geoportal container
........................................................

.. prompt:: bash

docker exec -ti <package>_wsgi_1 bash
vi ...
kill -s USR1 1 # graceful
docker-compose exec geoportal bash
kill -s HUP `ps aux|grep gunicorn|head --lines=1|awk '{print $2}'` # graceful

Mount c2cgeoportal in the container
...................................

Add in the ``docker-compose.yaml`` file, in the ``geoportal`` service the following lines:

.. code:: yaml

services:
geoportal:
volumes:
- <c2cgeoportal_git_root>/geoportal/c2cgeoportal_commons:/opt/c2cgeoportal_geoportal/c2cgeoportal_commons
- <c2cgeoportal_git_root>/geoportal/c2cgeoportal_geoportal:/opt/c2cgeoportal_geoportal/c2cgeoportal_geoportal
- <c2cgeoportal_git_root>/geoportal/c2cgeoportal_admin:/opt/c2cgeoportal_geoportal/c2cgeoportal_admin


Performance or network error
Expand Down
8 changes: 4 additions & 4 deletions doc/developer/webservices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -240,18 +240,18 @@ Result HTTP code:
* 200 Success: Success.
* 400 Bad request: When something wrong.

User informations
-----------------
User information
----------------

Used to get the user informations.
Used to get the user information.

URL: ``.../loginuser``

Result HTTP code:

* 200 Success: Success.

Annoymous JSON result
Anonymous JSON result
~~~~~~~~~~~~~~~~~~~~~

.. code:: json
Expand Down
2 changes: 1 addition & 1 deletion doc/integrator/fulltext_search.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Also make sure that the db user can ``SELECT`` in the ``tsearch`` table:

sudo -u postgres psql -c 'GRANT SELECT ON TABLE <schema_name>.tsearch TO "<db_user>";' <db_name>

with ``<db_user>``, and ``<db_name>`` substituded as appropriately.
with ``<db_user>``, and ``<db_name>`` substituted as appropriately.

Populate the full-text search table
-----------------------------------
Expand Down
6 changes: 3 additions & 3 deletions doc/integrator/security.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ Services:
- login
- error

Authorized referers
-------------------
Authorized referrers
--------------------

To mitigate `CSRF <https://en.wikipedia.org/wiki/Cross-site_request_forgery>`_
attacks, the server validates the referer against a list of authorized referers.
attacks, the server validates the referer against a list of authorized referrers.

By default, only the pages coming from the server are allowed. You can change
that list by adding an ``authorized_referers`` list in your
Expand Down
8 changes: 8 additions & 0 deletions docker/build/bin/eval-templates
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash -e

find /app/ -name '*.tmpl' -print | while read file
do
envsubst < ${file} > ${file%.tmpl}
done

exec "$@"
5 changes: 4 additions & 1 deletion docker/build/bin/import-ngeo-apps
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def main():

parser.add_argument('--html', action="store_true", help="Import the html template")
parser.add_argument('--js', action="store_true", help="Import the javascript controller")
parser.add_argument('--non-docker', action="store_false", dest="docker", help="Import for non Docker")
parser.add_argument('interface', metavar='INTERFACE', help="The interface we import")
parser.add_argument('src', metavar='SRC', help="The ngeo source file")
parser.add_argument('dst', metavar='DST', help="The destination file")
Expand Down Expand Up @@ -116,7 +117,9 @@ def main():
data = _sub(
re.escape('<script src="https://geomapfish-demo.camptocamp.com/2.') + '[0-9]' +
re.escape('/wsgi/dynamic.js?interface={}"></script>'.format(args.interface)),
'<script src="dynamic.js?interface={interface}"></script>'.format(interface=args.interface),
'<script src="{entry_point}dynamic.js?interface={interface}"></script>'.format(
entry_point='${htmlWebpackPlugin.options.vars.entry_point}' if args.docker else '',
interface=args.interface),
data
)

Expand Down
Loading