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

v2.0.0 - ampycloud article release #133

Merged
merged 62 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
a155343
AMAROC-768 add heigh cloud flag and allow NSC
regDaniel Apr 8, 2024
2e2e2b0
AMAROC-768 formatting (easy fixes)
regDaniel Apr 9, 2024
4ffcc62
AMAROC-768 update copyright years
regDaniel Apr 9, 2024
cdbb945
AMAROC-768 update changelog
regDaniel Apr 9, 2024
8b18066
AMAROC-768 fix f-string
regDaniel Apr 9, 2024
fa4db2a
AMAROC-768 NSC if sligrolay in buffer
regDaniel Apr 9, 2024
798f5b7
AMAROC-768 Restrict python versions for pylinter
regDaniel Apr 9, 2024
745a50a
AMAROC-768 install setuptools for pylinter
regDaniel Apr 9, 2024
c22cd99
AMAROC-768 add comments
regDaniel Apr 10, 2024
17930a5
AMAROC-765 Add mypy to the setup
Apr 10, 2024
ba885da
AMAROC-768 drop attrs, add CeiloChunk attribute
regDaniel Apr 10, 2024
5aa7fae
AMAROC-768 remove unused import
regDaniel Apr 10, 2024
456dbf5
AMAROC-768 add NSC warning to scope.rst
regDaniel Apr 10, 2024
d09d1f5
AMAROC-768 improve message in CHANGELOG
regDaniel Apr 10, 2024
c2e5d23
Merge pull request #114 from MeteoSwiss/feature/AMAROC-768-nsc-flag
regDaniel Apr 10, 2024
804015d
Set mock exemple to be 900s long
fpavogt Mar 23, 2024
281be4e
Use 'height' in 'ft aal' throughout
fpavogt Mar 26, 2024
6108174
As of Python 3.12, setuptools needs to be explicitely requested as an…
fpavogt Apr 8, 2024
c4d9847
Bump version to reflect the breaking API changes
fpavogt Apr 9, 2024
c732f2b
AMAROC-768 remove explicit build of setuptools
regDaniel Apr 10, 2024
f73ce81
Merge pull request #113 from MeteoSwiss/develop_vof
regDaniel Apr 10, 2024
cc35cfd
AMAROC-765 Remove not necessary converting data
Apr 17, 2024
39908d0
AMAROC-765 Correct easy type issues
Apr 17, 2024
1e48c69
AMAROC-765 solve issue in texify and add test
Apr 22, 2024
cf87c4b
AMAROC-765 fix arraylike type issue
Apr 22, 2024
c2d65fe
AMAROC-765 fix mixing type issues
Apr 22, 2024
2b780ca
Merge branch 'develop' into bugfix/AMAROC-765-fixMypyIssues
Apr 22, 2024
19d3f25
AMAROC-765 fix leftover issues after merge
Apr 22, 2024
9b28aec
AMAROC-765 fix conf.py
Apr 22, 2024
65e9ce0
AMAROC-765 fix np.array in mocker.py
Apr 22, 2024
9bef3f8
AMAROC-765 review suggestions applied
Apr 23, 2024
7f002fa
AMAROC-765 temporary skip test macos python 3.9
Apr 23, 2024
c1ad831
AMAROC-765 temporary skip test macos python 3.9
Apr 23, 2024
0e14055
AMAROC-765 temporary skip test macos python 3.9
Apr 23, 2024
c33405f
AMAROC-765 eclude conda
Apr 23, 2024
3ccbd80
AMAROC-784 update setup-python in pytest workflow (#122)
regDaniel Apr 23, 2024
e344261
Fix #116
fpavogt Apr 16, 2024
903bc72
Update docs
fpavogt Apr 16, 2024
7bd4b28
Add additional test case following review
fpavogt Apr 23, 2024
c4d7240
Fix #119
fpavogt Apr 17, 2024
4d05ff4
Minor code cleanup
fpavogt Apr 17, 2024
ab0fbca
Merge pull request #118 from MeteoSwiss/develop_vof
fpavogt Apr 23, 2024
7bbd67d
Merge branch 'develop' into bugfix/AMAROC-765-fixMypyIssues
srethore Apr 23, 2024
68ba86c
Merge pull request #121 from MeteoSwiss/bugfix/AMAROC-765-fixMypyIssues
srethore Apr 23, 2024
79413f1
Fix #123
fpavogt Apr 25, 2024
14025a4
Merge pull request #125 from MeteoSwiss/fix_123
fpavogt Apr 25, 2024
5f433e3
Add one rogue point to the mock example
fpavogt Apr 28, 2024
991c626
Correct col type
fpavogt Apr 28, 2024
9aafcb8
Swap instead of add rogue hit
fpavogt Apr 28, 2024
1ab73ce
Merge pull request #126 from MeteoSwiss/develop_vof
fpavogt Apr 29, 2024
0674d3e
Add support for numpy >2.0
fpavogt Jun 25, 2024
8a2b05b
Update docs
fpavogt Jun 25, 2024
8c3c3a2
Update docs
fpavogt Jun 25, 2024
00bfab6
Merge pull request #129 from MeteoSwiss/develop_vof
fpavogt Jun 26, 2024
3bf417c
Allow to trigger the weekly tests manually
fpavogt Jun 26, 2024
9e52f4d
Update CHANGELOG
fpavogt Jun 26, 2024
880a9f2
Merge pull request #130 from MeteoSwiss/develop_vof
fpavogt Jun 26, 2024
5843bb7
Fix manual trigger of automated tests (#131)
fpavogt Jun 26, 2024
4d9ca27
Update CONTRIBUTING.md
fpavogt Jun 28, 2024
0c8e618
Merge pull request #132 from MeteoSwiss/fpavogt-patch-1
fpavogt Jun 28, 2024
cb70e14
Update CONTRIBUTING.md
fpavogt Jul 2, 2024
6818b2f
Update CONTRIBUTING.md
fpavogt Jul 2, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/CI_check_version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
steps:

- name: Checkout current repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.11'

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/CI_docs_build_and_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ jobs:
steps:
# Checkout our repository
- name: Checkout current repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Set up Python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/CI_docs_build_and_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ jobs:
steps:
# Checkout our repository
- name: Checkout current repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Also check out the live docs, placing it into a pseudo "build" folder for the docs
- name: Checkout live docs
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: MeteoSwiss/ampycloud
ref: gh-pages
Expand All @@ -51,7 +51,7 @@ jobs:

# Set up Python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/CI_pylinter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ jobs:
steps:
# Checkout our repository
- name: Checkout current repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Set up Python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

# Install any dependency we require
- name: Install dependancies
- name: Install dependencies
run: |
python -m pip install --upgrade pip
shell: bash
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/CI_pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:
steps:

- name: Checkout current repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.11'

Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/CI_pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.9', '3.10', '3.11']
exclude:
- os: macos-latest
python-version: '3.9'

steps:
# Checkout the repository
- name: Checkout current repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Setup python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand All @@ -42,13 +45,11 @@ jobs:
if: matrix.os == 'windows-latest'
run: |
Get-Command python | Select-Object -ExpandProperty Definition
echo $CONDA

- name: Check the setup (II)
if: matrix.os != 'windows-latest'
run: |
which python
which conda

# Install all the dependencies we require
- name: Install dependencies
Expand Down
17 changes: 13 additions & 4 deletions .github/workflows/CI_pytest_weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
name: CI_pytest_weekly

on:
workflow_dispatch: # Allow to trigger the weekly tests manually
schedule:
- cron: '43 21 * * 1,4' # Run at 21:43 UTC every Monday and Thursday

Expand All @@ -22,18 +23,26 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]

steps:
# Checkout the master branch from the repository
# Checkout the master branch if this is a scheduled test
# The idea for this Action is to spot issues with new dependency versions as soon as they
# are released (and not when we decide to update ampycloud).
- name: Checkout current repository
uses: actions/checkout@v3
- name: Checkout current repository (master branch)
if: ${{ github.event_name == 'schedule' }}
uses: actions/checkout@v4
with:
repository: MeteoSwiss/ampycloud
ref: master

# Alternatively, checkout whichever branch was selected by the user upon the manual trigger.
- name: Checkout current repository (custom branch)
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: actions/checkout@v4
with:
repository: MeteoSwiss/ampycloud

# Setup python
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.x'

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/CI_speed_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ jobs:
steps:
# Checkout our repository
- name: Checkout current repository
uses: actions/checkout@v3
uses: actions/checkout@v4

# Set up Python
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

Expand Down
32 changes: 25 additions & 7 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,33 @@ All notable changes to ampycloud will be documented in this file.
The format is inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v2.0.0]
### Added:
- [fpavogt, 2024-06-26] Add ability to trigger weekly tests manually.
- [fpavogt, 2024-04-16] Improve input data consistency check (fix #116).
- [regDaniel, 2024-04-09] Add flag for clouds above (MSA + MSA_HIT_BUFFER) and allow for NSC in METAR message.
- [fpavogt, 2024-03-26] Add option to reset only a single parameter.
### Fixed:
- [srethore, 2024-04-23] Fix static types issues.
- [regDaniel, 2024-04-23] Fix deprecated github actions worklflow file
- [fpavogt, 2024-04-17] Fix #119
- [regDaniel, 2024-04-09] Minor adaptions to better comply with PEP standards.
- [fpavogt, 2024-03-26] Use "height" in "ft aal" throughout.
### Changed:
- [fpavogt, 2024-06-25] Add support for numpy >2.0
- [fpavogt, 2024-04-28] Add a rogue point to the mock example.
- [fpavogt, 2024-03-25] Set the fluffiness boost to 2 (fixes #123).
- [fpavogt, 2024-03-23] Changed default mock dataset to be 900s long (instead of 2400s).

## [v1.0.0]
### Added
- [regDaniel, 2023-11-09] Add minimum separation condition for grouping step
### Fixed
- [regDaniel, 2023-11-09] Fix #107 (no more reporting of two layers at same height)
### Changed
### Added:
- [regDaniel, 2023-11-09] Add minimum separation condition for grouping step.
### Fixed:
- [regDaniel, 2023-11-09] Fix #107 (no more reporting of two layers at same height).
### Changed:
- [fpavogt, 2023-11-05] Updated version to 1.0.0 for first full release, incl. misc documentation changes.
- [regDaniel, 2023-11-09] Changed min sep in layering from layer mean to layer base altitude
- [regDaniel, 2023-11-10] Refactoring (modularization) of metarize method
- [regDaniel, 2023-11-09] Changed min sep in layering from layer mean to layer base altitude.
- [regDaniel, 2023-11-10] Refactoring (modularization) of metarize method.

## [v0.6.0.dev0]
### Added:
Expand Down
28 changes: 15 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

If you:

* :boom: want to **report a bug** with ampycloud: [jump here.](https://github.com/MeteoSwiss/ampycloud/issues)
* :question: have a **question** about ampycloud: [jump here instead.](https://github.com/MeteoSwiss/ampycloud/discussions)
* :construction_worker: want to **contribute** to ampycloud (:heart_eyes: :tada:): read on !
* :boom: want to **report a bug** with ampycloud: [jump here.](https://github.com/MeteoSwiss/ampycloud/issues)
* :question: have a **question** about ampycloud: [jump here instead.](https://github.com/MeteoSwiss/ampycloud/discussions)
* :construction_worker: want to **contribute** to ampycloud, read on !


## Table of contents

- [Code of conduct](#code-of-conduct)
- [Scope of ampycloud](#scope-of-ampycloud)
- [Scope](#scope)
- [Essential things to know about ampycloud for dev work](#essential-things-to-know-about-ampycloud-for-dev-work)
- [Branching model](#branching-model)
- [Installing from source](#installing-from-source)
Expand All @@ -23,18 +23,17 @@ If you:
- [Documentation](#documentation)
- [Testing](#testing)
- [Plotting](#plotting)
- [Release mechanisms](#release-mechanisms)
- [Release mechanism](#release-mechanism)
- [Less-Essential things to know about ampycloud for dev work](#less-essential-things-to-know-about-ampycloud-for-dev-work)
- [Updating the copyright years](#updating-the-copyright-years)


## Code of conduct

This project and everyone participating in it is governed by the [ampycloud Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
Please report unacceptable behavior to [[email protected]](mailto:[email protected]) and/or [[email protected]](mailto:[email protected]).
Please report unacceptable behavior to [[email protected]](mailto:[email protected]).


## Scope of ampycloud
## Scope

Please be sure to read (and understand the implications) of the
[scope of ampycloud](https://meteoswiss.github.io/ampycloud/index.html#scope-of-ampycloud).
Expand Down Expand Up @@ -86,9 +85,11 @@ Automated CI/CD checks are triggered upon Pull Requests being issued towards the
* automatic publication of the Sphinx docs (for a PR to `master` only)
* check that the code version was incremented (for PR to `master` only)

To test the code with the latest Python developments, a `pytest-weeklz` workflow runs the
To test the latest release of the code with the latest Python developments, a `pytest-weekly` workflow runs the
ampycloud tests twice a week using the latest version of Python and of the ampycloud dependencies.

:warning: This test is being run from the `master` branch. Pushing a bug fix to `develop` will not be sufficient to make it turn green - a new code release is necessary !

There is another Github action responsible for publishing the code onto pypi, that gets triggered
upon a new release or pre-release being published. See the ampycloud
[release mechanisms](#release-mechanisms) for details.
Expand Down Expand Up @@ -293,7 +294,7 @@ def some_plot_function(...):
With this decorator, all functions will automatically deploy the effects associated to the value of `dynamic.AMPYCLOUD_PRMS['MPL_STYLE']` which can take one of the following values:
`['base', 'latex', 'metsymb']`.

### Release mechanisms
### Release mechanism

When changes merged in the `develop` branch are stable and deemed *worthy*, follow these steps to
create a new release of ampycloud:
Expand Down Expand Up @@ -325,13 +326,14 @@ create a new release of ampycloud:
- on the [release page](https://github.com/MeteoSwiss/ampycloud/releases),
- in the [README](https://github.com/MeteoSwiss/ampycloud/blob/develop/README.md) tags,
- on [testpypi](https://test.pypi.org/project/ampycloud/) and [pypi](https://pypi.org/project/ampycloud/),
- on the [`gh-pages` branch](https://github.com/MeteoSwiss/ampycloud/tree/gh-pages), and
- in the [live documentation](https://MeteoSwiss.github.io/ampycloud).
- on the [`gh-pages` branch](https://github.com/MeteoSwiss/ampycloud/tree/gh-pages),
- in the [live documentation](https://MeteoSwiss.github.io/ampycloud), and
- on [Zenodo](https://zenodo.org/doi/10.5281/zenodo.8399683) (for which the connection to this repo is enabled from Zenodo itself, by the admins of the MeteoSwiss organization on Github).

## Less-Essential things to know about ampycloud for dev work

### Updating the copyright years
The ampycloud copyright years may need to be updated if the development goes on beyond 2022. If so,
The ampycloud copyright years may need to be updated if the development goes on beyond 2022 (which it already has 😉). If so,
the copyright years will need to be manually updated in the following locations:

* `docs/source/substitutions.rst` (the copyright tag)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ For the full documentation, installation instructions, etc ..., go to: https://m

### License & Copyright

ampycloud is released under the terms of **the 3-Clause BSD license**. The copyright (2021-2023) belongs to MeteoSwiss.
ampycloud is released under the terms of **the 3-Clause BSD license**. The copyright (2021-2024) belongs to MeteoSwiss.

### Contributing to ampycloud

Expand Down
5 changes: 3 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#

from pathlib import Path
from typing import Any

# Define
file_absolute_path = Path(__file__).absolute()
Expand All @@ -28,7 +29,7 @@
# -- Project information -----------------------------------------------------

project = 'ampycloud'
copyright = '2021-2023, MeteoSwiss'
copyright = '2021-2024, MeteoSwiss'
author = 'Frédéric P.A. Vogt'
version = vers

Expand Down Expand Up @@ -63,7 +64,7 @@
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
exclude_patterns: list[Any] = []

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
Expand Down
13 changes: 11 additions & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,19 @@ Welcome to the ampycloud documentation
--------------------------------------

* **What:** ampycloud refers to both a **Python package** and the **algorithm** at its core, designed
to characterize cloud layers (i.e. height and sky coverage fraction) using ceilometer measurements
(i.e. automatic cloud base *hits*), and derive a corresponding METAR-like message.
to characterize cloud layers (i.e. sky coverage fraction and base height) using ceilometer measurements
(i.e. cloud base *hits*), and derive a corresponding METAR-like message.
A visual illustration of the algorithm is visible in :numref:`fig-demo`.

.. note::
At the moment, ampycloud **cannot** use backscatter profiles to derive cloud base hits independantly.

.. note::
ampycloud does not challenge the quality/nature of the cloud base hits that it is being provided.
It trusts them all fully and equally. The capacity of the algorithm to provide an accurate
assessment of cloud layers above an aerodrome is thus directly limited by the ability of
ceilometers to report clouds up to the aerodrome's Minimum Sector Altitude in the first place.

* **Where:** ampycloud lives in `a dedicated repository <https://github.com/MeteoSwiss/ampycloud>`_
under the `MeteoSwiss organization <https://github.com/MeteoSwiss>`_ on Github, where you can
submit all your `questions <https://github.com/MeteoSwiss/ampycloud/discussions>`_ and
Expand Down
6 changes: 3 additions & 3 deletions docs/source/running.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ A no-words example for those that want to get started quickly
# Your data should have *exactly* this structure
mock_data = mocker.canonical_demo_data()

# Run the ampycloud algorithm on it, setting the MSA to 10'000 ft
# Run the ampycloud algorithm on it, setting the MSA to 10'000 ft aal
chunk = ampycloud.run(mock_data, prms={'MSA': 10000},
geoloc='Mock data', ref_dt=datetime.now())

Expand All @@ -36,8 +36,8 @@ A no-words example for those that want to get started quickly
The input data
--------------

The ampycloud algorithm is meant to process cloud base *hits* from ceilometer observations. A given
set of hits to be processed by the ampycloud package must be stored inside a
The ampycloud algorithm is meant to process cloud base *hits* derived from ceilometer observations.
A given set of hits to be processed by the ampycloud package must be stored inside a
:py:class:`pandas.DataFrame` with a specific set of characteristics outlined below. Users can use
the following utility function to check whether a given :py:class:`pandas.DataFrame` meets all the
requirements of ampycloud.
Expand Down
20 changes: 15 additions & 5 deletions docs/source/scope.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@ which requires all its dependencies to be robust and stable.

This has the following implications for ampycloud:

* The scope of ampycloud will remain limited to the **automatic processing of ceilometer
hits**. In particular, ampycloud does not process Vertical Visibility (VV) measurements.
Depending on the ceilometer type, the user will need to decide how to treat VV hits *before*
passing them to ampycloud, e.g. by removing them or by converting them to cloud base
heights.
* The scope of ampycloud will remain limited to the **automatic processing of cloud base
hits derived using ceilometers**. Furthermore, ampycloud does not process
Vertical Visibility (VV) measurements. Depending on the ceilometer type, the user will need
to decide how to treat VV hits *before* passing them to ampycloud, e.g. by removing them or
by converting them to cloud base heights.

* Note that regulation says that "if there are no clouds of operational significance
and no restriction on vertical visibility and the abbreviation 'CAVOK' is not
appropriate, the abbreviation 'NSC' should be used" (AMC1 MET.TR.205(e)(1)).
ampycloud cannot decide whether a 'CAVOK' is appropriate, and will therefore
always return 'NSC' if no clouds of operational significance are found. If no clouds
are detected at all by the ceilometers, ampycloud will return 'NCD'. Importantly,
users should bear in mind that ampycloud cannot handle CB and TCU cases,
such that any 'NCD'/'NSC' codes issued may need to be overwritten by the user in
certain situations.

* ampycloud can evidently be used for R&D work, but the code itself should not be
seen as an R&D platform.
Expand Down
Loading
Loading