diff --git a/.coveragerc b/.coveragerc index fc0969a..51243ad 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,33 +1,13 @@ -# .coveragerc to control coverage.py [run] branch = True -omit = - # omit tests - */test/* - # omit test runner - test.py - # omit example runner - main.py +source = icalevents [report] -# Regexes for lines to exclude from consideration exclude_lines = - # Have to re-enable the standard pragma + if self.debug: pragma: no cover - - # Don't complain about missing debug-only code: - def __repr__ - if self\.debug - - # Don't complain if tests don't hit defensive assertion code: - raise AssertionError raise NotImplementedError - - # Don't complain if non-runnable code isn't run: - if 0: if __name__ == .__main__.: - ignore_errors = True - -[html] -directory = coverage_html_report \ No newline at end of file +omit = + tests/* diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..c2fdddc --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-complexity = 10 +select = E9,F63,F7,F82 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..4e20212 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,37 @@ +name: Release + +on: + push: + tags: + - '*' + +jobs: + deploy: + if: github.repository == 'jazzband/icalevents' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install poetry==1.1.11 + + - name: Build package + run: poetry build + + - name: Upload packages to Jazzband + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + uses: pypa/gh-action-pypi-publish@master + with: + user: jazzband + password: ${{ secrets.JAZZBAND_RELEASE_KEY }} + repository_url: https://jazzband.co/projects/icalevents/upload diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..8d09d89 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,34 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: Run pytest + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.9 + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install poetry==1.1.11 + poetry install + - name: Test with pytest + run: | + poetry run coverage run test.py + poetry run coverage xml + - name: 'Upload coverage to Codecov' + uses: codecov/codecov-action@v2 + with: + fail_ci_if_error: true diff --git a/.gitignore b/.gitignore index 0280133..e126df8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ dist/* MANIFEST icalevents.egg-info/* /build + +docs/_build/** +coverage.xml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ca341d0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/psf/black + rev: 21.10b0 + hooks: + - id: black + - repo: https://github.com/PyCQA/flake8 + rev: 4.0.1 + hooks: + - id: flake8 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..e0d5efa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Code of Conduct + +As contributors and maintainers of the Jazzband projects, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in the Jazzband a harassment-free experience +for everyone, regardless of the level of experience, gender, gender identity and +expression, sexual orientation, disability, personal appearance, body size, race, +ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery +- Personal attacks +- Trolling or insulting/derogatory comments +- Public or private harassment +- Publishing other's private information, such as physical or electronic addresses, + without explicit permission +- Other unethical or unprofessional conduct + +The Jazzband roadies have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are not +aligned to this Code of Conduct, or to ban temporarily or permanently any contributor +for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, the roadies commit themselves to fairly and +consistently applying these principles to every aspect of managing the jazzband +projects. Roadies who do not follow or enforce the Code of Conduct may be permanently +removed from the Jazzband roadies. + +This code of conduct applies both within project spaces and in public spaces when an +individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by +contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and appropriate to +the circumstances. Roadies are obligated to maintain confidentiality with regard to the +reporter of an incident. + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version +1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version] + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/3/0/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ad78220 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +[![Jazzband](https://jazzband.co/static/img/jazzband.svg)](https://jazzband.co/) + +This is a [Jazzband](https://jazzband.co/) project. By contributing you agree to abide by the [Contributor Code of Conduct](https://jazzband.co/about/conduct) and follow the [guidelines](https://jazzband.co/about/guidelines). diff --git a/README.md b/README.md index 5203540..5b0816a 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,17 @@ Simple Python 3 library to download, parse and query iCal sources. +[![Jazzband](https://jazzband.co/static/img/badge.svg)](https://jazzband.co/) + ## Build info -[![Build Status](https://travis-ci.org/irgangla/icalevents.svg?branch=master)](https://travis-ci.org/irgangla/icalevents) +last push: ![run pytest](https://github.com/jazzband/icalevents/actions/workflows/python-test.yml/badge.svg) -https://travis-ci.org/irgangla/icalevents +master: [![Run pytest](https://github.com/jazzband/icalevents/actions/workflows/python-test.yml/badge.svg?branch=master)](https://github.com/jazzband/icalevents/actions/workflows/python-test.yml) -[![codecov](https://codecov.io/gh/irgangla/icalevents/branch/master/graph/badge.svg)](https://codecov.io/gh/irgangla/icalevents) +## Documentation -https://codecov.io/gh/irgangla/icalevents +https://icalevents.readthedocs.io/en/latest/ ## Usage @@ -31,3 +33,13 @@ from icalevents.icalevents import events es = events() ``` + +# Contributing + +You will need [poetry](https://github.com/python-poetry/poetry) and [pre-commit](https://pre-commit.com/index.html) installed and than run. + +```bash +pre-commit install +``` + +Happy contributing! diff --git a/Makefile b/docs/Makefile similarity index 68% rename from Makefile rename to docs/Makefile index 0ef7755..d4bb2cb 100644 --- a/Makefile +++ b/docs/Makefile @@ -1,12 +1,12 @@ # Minimal makefile for Sphinx documentation # -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = python -msphinx -SPHINXPROJ = iCalEvents -SOURCEDIR = source -BUILDDIR = build +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @@ -17,4 +17,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..032a499 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,60 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys + +sys.path.insert(0, os.path.abspath("..")) + + +# -- Project information ----------------------------------------------------- + +project = "iCalEvents" +copyright = "2021, Thomas Irgang" +author = "Thomas Irgang" + +# The full version, including alpha/beta/rc tags +release = "0.1.25" + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ["sphinx.ext.autodoc"] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# 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 = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "alabaster" + +html_theme_options = { + # Disable showing the sidebar. Defaults to 'false' + "nosidebar": True, +} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..e9ad1ef --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,120 @@ +.. iCalEvents documentation master file, created by + sphinx-quickstart on Wed Sep 8 21:48:51 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to iCalEvents's documentation! +====================================== + +Simple Python 3 library to download, parse and query iCal sources. + + +Usage +===== + +iCloud: +------- + +.. code:: python + + from icalevents.icalevents import events + + es = events(, fix_apple=True) + +Google: +------- + +.. code:: python + + from icalevents.icalevents import events + + es = events() + + +Example +======= + +see main.py + +.. code:: python + + from icalevents.icalevents import events_async, latest_events, all_done + from time import sleep + + if __name__ == '__main__': + keys = [] + + with open('calendars.txt', mode='r', encoding='utf-8') as f: + counter = 1 + + while True: + line = f.readline() + if not line: + break + + name, url = line.split(maxsplit=1) + name = name.strip() + url = url.strip() + + fix_apple = False + if name == 'icloud': + fix_apple = True + + key = "req_%d" % counter + counter += 1 + keys.append(key) + events_async(key, url, fix_apple=fix_apple) + + while keys: + print("%d request running." % len(keys)) + + for k in keys[:]: + if all_done(k): + print("Request %s finished." % k) + keys.remove(k) + + es = latest_events(k) + + for e in es: + print(e) + + sleep(2) + + +API +=== + +Module contents +--------------- + +.. automodule:: icalevents + :members: + :undoc-members: + :show-inheritance: + +Submodules +---------- + +icalevents.icaldownload module +------------------------------ + +.. automodule:: icalevents.icaldownload + :members: + :undoc-members: + :show-inheritance: + +icalevents.icalevents module +---------------------------- + +.. automodule:: icalevents.icalevents + :members: + :undoc-members: + :show-inheritance: + +icalevents.icalparser module +---------------------------- + +.. automodule:: icalevents.icalparser + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..2119f51 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/icalevents/icaldownload.py b/icalevents/icaldownload.py index a7fe21f..6aadedd 100644 --- a/icalevents/icaldownload.py +++ b/icalevents/icaldownload.py @@ -12,7 +12,7 @@ def apple_data_fix(content): :param content: content to fix :return: fixed content """ - return content.replace('TZOFFSETFROM:+5328', 'TZOFFSETFROM:+0053') + return content.replace("TZOFFSETFROM:+5328", "TZOFFSETFROM:+0053") def apple_url_fix(url): @@ -23,7 +23,7 @@ def apple_url_fix(url): :return: fixed URL """ if url.startswith("webcal://"): - url = url.replace('webcal://', 'http://', 1) + url = url.replace("webcal://", "http://", 1) return url @@ -31,17 +31,22 @@ class ICalDownload: """ Downloads or reads and decodes iCal sources. """ - def __init__(self, http=None, encoding='utf-8'): + + def __init__(self, http=None, encoding="utf-8"): # Get logger logger = logging.getLogger() # default http connection to use if http is None: try: - http = Http('.cache') + http = Http(".cache") except (PermissionError, OSError) as e: # Cache disabled if no write permission in working directory - logger.warning(("Caching is disabled due to a read-only working directory: {}").format(e)) + logger.warning( + ( + "Caching is disabled due to a read-only working directory: {}" + ).format(e) + ) http = Http() self.http = http @@ -61,7 +66,7 @@ def data_from_url(self, url, apple_fix=False): _, content = self.http.request(url) if not content: - raise ConnectionError('Could not get data from %s!' % url) + raise ConnectionError("Could not get data from %s!" % url) return self.decode(content, apple_fix=apple_fix) @@ -73,11 +78,11 @@ def data_from_file(self, file, apple_fix=False): :param apple_fix: fix wrong Apple tzdata in iCal :return: decoded (and fixed) iCal data """ - with open(file, mode='rb') as f: + with open(file, mode="rb") as f: content = f.read() if not content: - raise IOError("File %f is not readable or is empty!" % file) + raise IOError("File %s is not readable or is empty!" % file) return self.decode(content, apple_fix=apple_fix) @@ -96,7 +101,7 @@ def decode(self, content, apple_fix=False): :return: decoded (and fixed) content """ content = content.decode(self.encoding) - content = content.replace('\r', '') + content = content.replace("\r", "") if apple_fix: content = apple_data_fix(content) diff --git a/icalevents/icalevents.py b/icalevents/icalevents.py index f0d8d8f..bf6082d 100644 --- a/icalevents/icalevents.py +++ b/icalevents/icalevents.py @@ -44,8 +44,7 @@ def events( content = ical_download.data_from_file(file, apple_fix=fix_apple) if not content and string_content: - content = ical_download.data_from_string( - string_content, apple_fix=fix_apple) + content = ical_download.data_from_string(string_content, apple_fix=fix_apple) found_events += parse_events(content, start=start, end=end) @@ -67,15 +66,22 @@ def request_data(key, url, file, string_content, start, end, fix_apple): data = [] try: - data += events(url=url, file=file, string_content=string_content, - start=start, end=end, fix_apple=fix_apple) + data += events( + url=url, + file=file, + string_content=string_content, + start=start, + end=end, + fix_apple=fix_apple, + ) finally: update_events(key, data) request_finished(key) -def events_async(key, url=None, file=None, start=None, string_content=None, - end=None, fix_apple=False): +def events_async( + key, url=None, file=None, start=None, string_content=None, end=None, fix_apple=False +): """ Trigger an asynchronous data request. @@ -87,7 +93,10 @@ def events_async(key, url=None, file=None, start=None, string_content=None, :param end: end date :param fix_apple: fix known Apple iCal issues """ - t = Thread(target=request_data, args=(key, url, file, string_content, start, end, fix_apple)) + t = Thread( + target=request_data, + args=(key, url, file, string_content, start, end, fix_apple), + ) with event_lock: if key not in threads: diff --git a/icalevents/icalparser.py b/icalevents/icalparser.py index 46bcd79..bb63661 100644 --- a/icalevents/icalparser.py +++ b/icalevents/icalparser.py @@ -11,6 +11,7 @@ from dateutil.tz import UTC, gettz from icalendar import Calendar +from icalendar.windows_to_olson import WINDOWS_TO_OLSON from icalendar.prop import vDDDLists, vText from pytz import timezone @@ -39,6 +40,7 @@ def __init__(self): self.start = None self.end = None self.all_day = True + self.transparent = False self.recurring = False self.location = None self.private = False @@ -48,6 +50,8 @@ def __init__(self): self.attendee = None self.organizer = None self.categories = None + self.status = None + self.url = None def time_left(self, time=None): """ @@ -66,7 +70,9 @@ def __lt__(self, other): :return: True if start of this event is smaller than other """ if not other or not isinstance(other, Event): - raise ValueError('Only events can be compared with each other! Other is %s' % type(other)) + raise ValueError( + "Only events can be compared with each other! Other is %s" % type(other) + ) else: return self.start < other.start @@ -124,7 +130,7 @@ def copy_to(self, new_start=None, uid=None): if self.end: duration = self.end - self.start - ne.end = (new_start + duration) + ne.end = new_start + duration ne.all_day = self.all_day ne.recurring = self.recurring @@ -132,10 +138,14 @@ def copy_to(self, new_start=None, uid=None): ne.attendee = self.attendee ne.organizer = self.organizer ne.private = self.private + ne.transparent = self.transparent ne.uid = uid ne.created = self.created ne.last_modified = self.last_modified ne.categories = self.categories + ne.status = self.status + ne.url = self.url + ne.sequence = self.sequence return ne @@ -146,7 +156,7 @@ def encode(value: Optional[vText]) -> Optional[str]: try: return str(value) except UnicodeEncodeError: - return str(value.encode('utf-8')) + return str(value.encode("utf-8")) def create_event(component, tz=UTC): @@ -160,56 +170,60 @@ def create_event(component, tz=UTC): event = Event() - event.start = normalize(component.get('dtstart').dt, tz=tz) + event.start = normalize(component.get("dtstart").dt, tz=tz) - if component.get('dtend'): - event.end = normalize(component.get('dtend').dt, tz=tz) - elif component.get('duration'): # compute implicit end as start + duration - event.end = event.start + component.get('duration').dt - else: # compute implicit end as start + 0 + if component.get("dtend"): + event.end = normalize(component.get("dtend").dt, tz=tz) + elif component.get("duration"): # compute implicit end as start + duration + event.end = event.start + component.get("duration").dt + else: # compute implicit end as start + 0 event.end = event.start - event.summary = encode(component.get('summary')) - event.description = encode(component.get('description')) - event.all_day = type(component.get('dtstart').dt) is date - if component.get('rrule'): + event.summary = encode(component.get("summary")) + event.description = encode(component.get("description")) + event.all_day = type(component.get("dtstart").dt) is date + if component.get("rrule"): event.recurring = True - event.location = encode(component.get('location')) + event.location = encode(component.get("location")) - if component.get('attendee'): - event.attendee = component.get('attendee') + if component.get("attendee"): + event.attendee = component.get("attendee") if type(event.attendee) is list: temp = [] for a in event.attendee: - temp.append(a.encode('utf-8').decode('ascii')) + temp.append(a.encode("utf-8").decode("ascii")) event.attendee = temp else: - event.attendee = event.attendee.encode('utf-8').decode('ascii') + event.attendee = event.attendee.encode("utf-8").decode("ascii") else: event.attendee = str(None) - if component.get('uid'): - event.uid = component.get('uid').encode('utf-8').decode('ascii') + if component.get("uid"): + event.uid = component.get("uid").encode("utf-8").decode("ascii") - if component.get('organizer'): - event.organizer = component.get('organizer').encode('utf-8').decode('ascii') + if component.get("organizer"): + event.organizer = component.get("organizer").encode("utf-8").decode("ascii") else: event.organizer = str(None) - if component.get('class'): - event_class = component.get('class') - event.private = event_class == 'PRIVATE' or event_class == 'CONFIDENTIAL' + if component.get("class"): + event_class = component.get("class") + event.private = event_class == "PRIVATE" or event_class == "CONFIDENTIAL" - if component.get('created'): - event.created = normalize(component.get('created').dt, tz) + if component.get("class"): + event.transparent = component.get("transp") == "TRANSPARENT" - if component.get('last-modified'): - event.last_modified = normalize(component.get('last-modified').dt, tz) + if component.get("created"): + event.created = normalize(component.get("created").dt, tz) + + if component.get("last-modified"): + event.last_modified = normalize(component.get("last-modified").dt, tz) elif event.created: event.last_modified = event.created - if component.get('sequence'): - event.sequence = component.get('sequence') + # sequence can be 0 - test for None instead + if not component.get("sequence") is None: + event.sequence = component.get("sequence") if component.get("categories"): categories = component.get("categories").cats @@ -218,6 +232,12 @@ def create_event(component, tz=UTC): encoded_categories.append(encode(category)) event.categories = encoded_categories + if component.get("status"): + event.status = encode(component.get("status")) + + if component.get("url"): + event.url = encode(component.get("url")) + return event @@ -244,6 +264,34 @@ def normalize(dt, tz=UTC): return dt +def get_timezone(tz_name): + if tz_name in WINDOWS_TO_OLSON: + return gettz(WINDOWS_TO_OLSON[tz_name]) + else: + return gettz(tz_name) + + +def adjust_timezone(component, dates, tz=None): + # Remove timezone if none is present in component + if ( + isinstance(component["dtstart"].dt, date) + or component["dtstart"].dt.tzinfo is None + ): + dates = [ + date.replace(tzinfo=None) if type(date) is datetime else date + for date in dates + ] + + # Add timezone if one is present in component + if ( + isinstance(component["dtstart"].dt, datetime) + and not component["dtstart"].dt.tzinfo is None + ): + dates = [normalize(date) for date in dates] + + return dates + + def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): """ Query the events occurring in a given time range. @@ -261,14 +309,20 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): end = start + default_span if not content: - raise ValueError('Content is invalid!') + raise ValueError("Content is invalid!") calendar = Calendar.from_ical(content) # Keep track of the timezones defined in the calendar timezones = {} - for c in calendar.walk('VTIMEZONE'): - name = str(c['TZID']) + + # Parse non standard timezone name + if "X-WR-TIMEZONE" in calendar: + x_wr_timezone = str(calendar["X-WR-TIMEZONE"]) + timezones[x_wr_timezone] = get_timezone(x_wr_timezone) + + for c in calendar.walk("VTIMEZONE"): + name = str(c["TZID"]) try: timezones[name] = c.to_tz() except IndexError: @@ -278,10 +332,10 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): # value from the name as a fallback. timezones[name] = timezone(name) - # If there's exactly one timezone in the file, + # If there's at least one timezone in the file, # assume it applies globally, otherwise UTC - if len(timezones) == 1: - cal_tz = gettz(list(timezones)[0]) + if len(timezones): + cal_tz = get_timezone(list(timezones)[0]) else: cal_tz = UTC @@ -289,24 +343,16 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): end = normalize(end, cal_tz) found = [] + recurrence_ids = [] - # Skip dates that are stored as exceptions. - exceptions = {} for component in calendar.walk(): if component.name == "VEVENT": e = create_event(component, cal_tz) - if 'EXDATE' in component: - # Deal with the fact that sometimes it's a list and - # sometimes it's a singleton - exlist = [] - if isinstance(component['EXDATE'], list): - exlist = component['EXDATE'] - else: - exlist.append(component['EXDATE']) - for ex in exlist: - exdate = ex.to_ical().decode("UTF-8") - exceptions[exdate[0:8]] = exdate + if "RECURRENCE-ID" in component: + recurrence_ids.append( + (e.uid, component["RECURRENCE-ID"].dt, e.sequence) + ) # Attempt to work out what timezone is used for the start # and end times. If the timezone is defined in the calendar, @@ -314,40 +360,17 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): start_tz = None end_tz = None - if e.all_day: - # Start and end times for all day events must not have - # a timezone because the specification forbids the - # RRULE UNTIL from having a timezone. On the other - # hand, they must be datetime values (not just dates) - # because RRULE UNTIL will do a comparison against a - # timezone naive datetime. So we coerce start and end - # times for all day events into timezone naive - # datetime values. - e.start = datetime.combine(e.start.date(), datetime.min.time()) - e.end = datetime.combine(e.end.date(), datetime.min.time()) - start = datetime.combine(start, datetime.min.time()) - end = datetime.combine(end, datetime.min.time()) - else: - # Work out the staring and ending timezone. We don't do - # this for all-day appointments because they aren't really - # in a timezone. - if e.start.tzinfo != UTC: - if str(e.start.tzinfo) in timezones: - start_tz = timezones[str(e.start.tzinfo)] - else: - try: - start_tz = timezone(str(e.start.tzinfo)) - except: - pass - - if e.end.tzinfo != UTC: - if str(e.end.tzinfo) in timezones: - end_tz = timezones[str(e.end.tzinfo)] - else: - try: - end_tz = timezone(str(e.end.tzinfo)) - except: - pass + if e.start.tzinfo != UTC: + if str(e.start.tzinfo) in timezones: + start_tz = timezones[str(e.start.tzinfo)] + else: + start_tz = e.start.tzinfo + + if e.end.tzinfo != UTC: + if str(e.end.tzinfo) in timezones: + end_tz = timezones[str(e.end.tzinfo)] + else: + end_tz = e.end.tzinfo # If we've been passed or constructed start/end values # that are timezone naive, but the actual appointment @@ -364,8 +387,8 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): if e.recurring: # Unfold recurring events according to their rrule rule = parse_rrule(component, cal_tz) - dur = e.end - e.start - after = start - dur + [after] = adjust_timezone(component, [start - duration], start_tz) + [end] = adjust_timezone(component, [end], start_tz) for dt in rule.between(after, end, inc=True): if start_tz is None: @@ -375,8 +398,10 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): # Recompute the start time in the current timezone *on* the # date of *this* occurrence. This handles the case where the # recurrence has crossed over the daylight savings time boundary. - naive = datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second) - dtstart = start_tz.localize(naive) + naive = datetime( + dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second + ) + dtstart = normalize(naive, tz=start_tz) ecopy = e.copy_to(dtstart, e.uid) @@ -387,14 +412,36 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): # timezone from the start time, we'll have lost that. ecopy.end = dtstart + duration - exdate = "%04d%02d%02d" % (ecopy.start.year, ecopy.start.month, ecopy.start.day) - if exdate not in exceptions: - found.append(ecopy) + found.append(ecopy) elif e.end >= start and e.start <= end: - exdate = "%04d%02d%02d" % (e.start.year, e.start.month, e.start.day) - if exdate not in exceptions: - found.append(e) - return found + found.append(e) + + # Filter out all events that are moved as indicated by the recurrence-id prop + return [ + event for event in found + if not is_replaced_by_recurrence_id_instance(event, recurrence_ids) + ] + + +def is_replaced_by_recurrence_id_instance(event, recurrence_ids): + # calendars that use RECURRENCE-ID also use sequences + if event.sequence is None: + return False + + # only recurring events can be replaced by instances + if not event.recurring: + return False + + # check if the recurring event has a RECURRENCE-ID instance that replaces it + for uid, start, sequence in recurrence_ids: + if uid == event.uid and start == event.start: + # If the recurrence event's sequence is less than the original rrule event + # we ignore it + if sequence >= event.sequence: + return True + else: + return False + return False def parse_rrule(component, tz=UTC): @@ -407,22 +454,28 @@ def parse_rrule(component, tz=UTC): :param tz: timezone for DST handling :return: extracted rrule or rruleset """ - if component.get('rrule'): + if component.get("rrule"): # component['rrule'] can be both a scalar and a list - rrules = component['rrule'] + rrules = component["rrule"] if not isinstance(rrules, list): rrules = [rrules] # If dtstart is a datetime, make sure it's in a timezone. - rdtstart = component['dtstart'].dt + rdtstart = component["dtstart"].dt if type(rdtstart) is datetime: rdtstart = normalize(rdtstart, tz=tz) + # Remove/add timezone to rrule until dates depending on component + for index, rru in enumerate(rrules): + if "UNTIL" in rru: + rrules[index]["UNTIL"] = adjust_timezone(component, rru["UNTIL"], tz) + # Parse the rrules, might return a rruleset instance, instead of rrule - rule = rrulestr('\n'.join(x.to_ical().decode() for x in rrules), - dtstart=rdtstart) + rule = rrulestr( + "\n".join(x.to_ical().decode() for x in rrules), dtstart=rdtstart + ) - if component.get('exdate'): + if component.get("exdate"): # Make sure, to work with a rruleset if isinstance(rule, rrule): rules = rruleset() @@ -438,7 +491,7 @@ def parse_rrule(component, tz=UTC): # You really want an rrule for a component without rrule? Here you are. else: rule = rruleset() - rule.rdate(normalize(component['dtstart'].dt, tz=tz)) + rule.rdate(normalize(component["dtstart"].dt, tz=tz)) return rule @@ -452,12 +505,12 @@ def extract_exdates(component): """ dates = [] - exd_prop = component.get('exdate') + exd_prop = component.get("exdate") if exd_prop: - if isinstance(exd_prop, list): # In case there is more than one exdate property + if isinstance(exd_prop, list): # In case there is more than one exdate property for exd_list in exd_prop: dates.extend(normalize(exd.dt) for exd in exd_list.dts) elif isinstance(exd_prop, vDDDLists): dates.extend(normalize(exd.dt) for exd in exd_prop.dts) - return dates + return adjust_timezone(component, dates) diff --git a/main.py b/main.py index 26c9bd3..50099d7 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,10 @@ from icalevents.icalevents import events_async, latest_events, all_done from time import sleep -if __name__ == '__main__': +if __name__ == "__main__": keys = [] - with open('calendars.txt', mode='r', encoding='utf-8') as f: + with open("calendars.txt", mode="r", encoding="utf-8") as f: counter = 1 while True: @@ -17,7 +17,7 @@ url = url.strip() fix_apple = False - if name == 'icloud': + if name == "icloud": fix_apple = True key = "req_%d" % counter diff --git a/make.bat b/make.bat deleted file mode 100644 index 16288c8..0000000 --- a/make.bat +++ /dev/null @@ -1,36 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=python -msphinx -) -set SOURCEDIR=source -set BUILDDIR=build -set SPHINXPROJ=iCalEvents - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The Sphinx module was not found. Make sure you have Sphinx installed, - echo.then set the SPHINXBUILD environment variable to point to the full - echo.path of the 'sphinx-build' executable. Alternatively you may add the - echo.Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..4d42c1a --- /dev/null +++ b/poetry.lock @@ -0,0 +1,660 @@ +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] + +[[package]] +name = "black" +version = "21.9b0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0,<1" +platformdirs = ">=2" +regex = ">=2020.1.8" +tomli = ">=0.2.6,<2.0.0" +typing-extensions = [ + {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, + {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, +] + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +python2 = ["typed-ast (>=1.4.2)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.6" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "dev" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "click" +version = "8.0.3" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "codecov" +version = "2.1.12" +description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +coverage = "*" +requests = ">=2.7.9" + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "coverage" +version = "6.0.1" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "datetime" +version = "4.3" +description = "This package provides a DateTime data type, as known from Zope. Unless you need to communicate with Zope APIs, you're probably better off using Python's built-in datetime module." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pytz = "*" +"zope.interface" = "*" + +[[package]] +name = "flake8" +version = "4.0.1" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +mccabe = ">=0.6.0,<0.7.0" +pycodestyle = ">=2.8.0,<2.9.0" +pyflakes = ">=2.4.0,<2.5.0" + +[[package]] +name = "httplib2" +version = "0.20.1" +description = "A comprehensive HTTP client library." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +pyparsing = ">=2.4.2,<3" + +[[package]] +name = "icalendar" +version = "4.0.8" +description = "iCalendar parser/generator" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.dependencies] +python-dateutil = "*" +pytz = "*" + +[[package]] +name = "idna" +version = "3.2" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] +name = "platformdirs" +version = "2.4.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pycodestyle" +version = "2.8.0" +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "pyflakes" +version = "2.4.0" +description = "passive checker of Python programs" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "pytest" +version = "6.2.5" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +toml = "*" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2021.3" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "regex" +version = "2021.10.8" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tomli" +version = "1.2.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "typing-extensions" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "urllib3" +version = "1.26.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "zope.interface" +version = "5.4.0" +description = "Interfaces for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +docs = ["sphinx", "repoze.sphinx.autointerface"] +test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] +testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.9" +content-hash = "df78c6613912c3547a62e5c37d8cfa6c5e4e0866437dd117b6747ed71ea678e2" + +[metadata.files] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] +black = [ + {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, + {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, +] +certifi = [ + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.6.tar.gz", hash = "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"}, + {file = "charset_normalizer-2.0.6-py3-none-any.whl", hash = "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6"}, +] +click = [ + {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, + {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, +] +codecov = [ + {file = "codecov-2.1.12-py2.py3-none-any.whl", hash = "sha256:585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47"}, + {file = "codecov-2.1.12-py3.8.egg", hash = "sha256:782a8e5352f22593cbc5427a35320b99490eb24d9dcfa2155fd99d2b75cfb635"}, + {file = "codecov-2.1.12.tar.gz", hash = "sha256:a0da46bb5025426da895af90938def8ee12d37fcbcbbbc15b6dc64cf7ebc51c1"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +coverage = [ + {file = "coverage-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:abe8207dfb8a61ded9cd830d26c1073c8218fc0ae17eb899cfe8ec0fafae6e22"}, + {file = "coverage-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83faa3692e8306b20293889714fdf573d10ef5efc5843bd7c7aea6971487bd6a"}, + {file = "coverage-6.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f82a17f2a77958f3eef40ad385fc82d4c6ba9a77a51a174efe03ce75daebbc16"}, + {file = "coverage-6.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b06f4f1729e2963281d9cd6e65e6976bf27b44d4c07ac5b47223ce45f822cec"}, + {file = "coverage-6.0.1-cp310-cp310-win32.whl", hash = "sha256:7600fac458f74c68b097379f76f3a6e3a630493fc7fc94b6508fedd9d498c194"}, + {file = "coverage-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:2c5f39d1556e75fc3c4fb071f9e7cfa618895a999a0de763a541d730775d0d5f"}, + {file = "coverage-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3edbb3ec580c73e5a264f5d04f30245bc98eff1a26765d46c5c65134f0a0e2f7"}, + {file = "coverage-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea452a2d83964d08232ade470091015e7ab9b8f53acbec10f2210fbab4ce7e43"}, + {file = "coverage-6.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1770d24f45f1f2daeae34cfa3b33fcb29702153544cd2ad40d58399dd4ff53b5"}, + {file = "coverage-6.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ad7182a82843f9f85487f44567c8c688f16c906bdb8d0e44ae462aed61cb8f1b"}, + {file = "coverage-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:9d242a2434801ef5125330deddb4cddba8990c9a49b3dec99dca17dd7eefba5a"}, + {file = "coverage-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e66c50f0ab445fec920a9f084914ea1776a809e3016c3738519048195f851bbb"}, + {file = "coverage-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5b1ceacb86e0a9558061dcc6baae865ed25933ea57effea644f21657cdce19bc"}, + {file = "coverage-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e15ab5afbee34abf716fece80ea33ea09a82e7450512f022723b1a82ec9a4e"}, + {file = "coverage-6.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6873f3f954d3e3ab8b1881f4e5307cc19f70c9f931c41048d9f7e6fd946eabe7"}, + {file = "coverage-6.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0898d6948b31df13391cd40568de8f35fa5901bc922c5ae05cf070587cb9c666"}, + {file = "coverage-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9c416ba03844608f45661a5b48dc59c6b5e89956efe388564dd138ca8caf540b"}, + {file = "coverage-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:66fe33e9e0df58675e08e83fe257f89e7f625e7633ea93d0872154e09cce2724"}, + {file = "coverage-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:353a50f123f0185cdb7a1e1e3e2cfb9d1fd7e293cfaf68eedaf5bd8e02e3ec32"}, + {file = "coverage-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b81a4e667c45b13658b84f9b8f1d32ef86d5405fabcbd181b76b9e51d295f397"}, + {file = "coverage-6.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:17426808e8e0824f864876312d41961223bf5e503bf8f1f846735279a60ea345"}, + {file = "coverage-6.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e11cca9eb5c9b3eaad899728ee2ce916138399ee8cbbccaadc1871fecb750827"}, + {file = "coverage-6.0.1-cp38-cp38-win32.whl", hash = "sha256:0a7e55cc9f7efa22d5cc9966276ec7a40a8803676f6ccbfdc06a486fba9aa9ee"}, + {file = "coverage-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:4eb9cd910ca8e243f930243a9940ea1a522e32435d15668445753d087c30ee12"}, + {file = "coverage-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:83682b73785d2e078e0b5f63410b8125b122e1a22422640c57edd4011c950f3e"}, + {file = "coverage-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b45f89a8ef65c29195f8f28dbe215f44ccb29d934f3e862d2a5c12e38698a793"}, + {file = "coverage-6.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:73880a80fad0597eca43e213e5e1711bf6c0fcdb7eb6b01b3b17841ebe5a7f8d"}, + {file = "coverage-6.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f398d38e6ebc2637863db1d7be3d4f9c5174e7d24bb3b0716cdb1f204669cbcf"}, + {file = "coverage-6.0.1-cp39-cp39-win32.whl", hash = "sha256:1864bdf9b2ccb43e724051bc23a1c558daf101ad4488ede1945f2a8be1facdad"}, + {file = "coverage-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:c9c413c4397d4cdc7ca89286158d240ce524f9667b52c9a64dd7e13d16cf8815"}, + {file = "coverage-6.0.1-pp36-none-any.whl", hash = "sha256:65da6e3e8325291f012921bbf71fea0a97824e1c573981871096aac6e2cf0ec5"}, + {file = "coverage-6.0.1-pp37-none-any.whl", hash = "sha256:07efe1fbd72e67df026ad5109bcd216acbbd4a29d5208b3dab61779bae6b7b26"}, + {file = "coverage-6.0.1.tar.gz", hash = "sha256:3490ff6dbf3f7accf0750136ed60ae1f487bccc1f097740e3b21262bc9c89854"}, +] +datetime = [ + {file = "DateTime-4.3-py2.py3-none-any.whl", hash = "sha256:371dba07417b929a4fa685c2f7a3eaa6a62d60c02947831f97d4df9a9e70dfd0"}, + {file = "DateTime-4.3.tar.gz", hash = "sha256:5cef605bab8259ff61281762cdf3290e459fbf0b4719951d5fab967d5f2ea0ea"}, +] +flake8 = [ + {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, + {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, +] +httplib2 = [ + {file = "httplib2-0.20.1-py3-none-any.whl", hash = "sha256:8fa4dbf2fbf839b71f8c7837a831e00fcdc860feca99b8bda58ceae4bc53d185"}, + {file = "httplib2-0.20.1.tar.gz", hash = "sha256:0efbcb8bfbfbc11578130d87d8afcc65c2274c6eb446e59fc674e4d7c972d327"}, +] +icalendar = [ + {file = "icalendar-4.0.8-py2.py3-none-any.whl", hash = "sha256:825209edeb8f3067cf31f0712b0fc9507b1ded270165f98f3176d6b50e8c7b78"}, + {file = "icalendar-4.0.8.tar.gz", hash = "sha256:7508a92b4e36049777640b0ae393e7219a16488d852841a0e57b44fe51d9f848"}, +] +idna = [ + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] +pathspec = [ + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] +platformdirs = [ + {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, + {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, +] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +py = [ + {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, + {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +] +pycodestyle = [ + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, +] +pyflakes = [ + {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, + {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pytest = [ + {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, + {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pytz = [ + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, +] +regex = [ + {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981c786293a3115bc14c103086ae54e5ee50ca57f4c02ce7cf1b60318d1e8072"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51feefd58ac38eb91a21921b047da8644155e5678e9066af7bcb30ee0dca7361"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8de658d7db5987b11097445f2b1f134400e2232cb40e614e5f7b6f5428710e"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1ce02f420a7ec3b2480fe6746d756530f69769292eca363218c2291d0b116a01"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39079ebf54156be6e6902f5c70c078f453350616cfe7bfd2dd15bdb3eac20ccc"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ff24897f6b2001c38a805d53b6ae72267025878d35ea225aa24675fbff2dba7f"}, + {file = "regex-2021.10.8-cp310-cp310-win32.whl", hash = "sha256:c6569ba7b948c3d61d27f04e2b08ebee24fec9ff8e9ea154d8d1e975b175bfa7"}, + {file = "regex-2021.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:45cb0f7ff782ef51bc79e227a87e4e8f24bc68192f8de4f18aae60b1d60bc152"}, + {file = "regex-2021.10.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fab3ab8aedfb443abb36729410403f0fe7f60ad860c19a979d47fb3eb98ef820"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e55f8d66f1b41d44bc44c891bcf2c7fad252f8f323ee86fba99d71fd1ad5e3"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d52c5e089edbdb6083391faffbe70329b804652a53c2fdca3533e99ab0580d9"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1abbd95cbe9e2467cac65c77b6abd9223df717c7ae91a628502de67c73bf6838"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b5c215f3870aa9b011c00daeb7be7e1ae4ecd628e9beb6d7e6107e07d81287"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f540f153c4f5617bc4ba6433534f8916d96366a08797cbbe4132c37b70403e92"}, + {file = "regex-2021.10.8-cp36-cp36m-win32.whl", hash = "sha256:1f51926db492440e66c89cd2be042f2396cf91e5b05383acd7372b8cb7da373f"}, + {file = "regex-2021.10.8-cp36-cp36m-win_amd64.whl", hash = "sha256:5f55c4804797ef7381518e683249310f7f9646da271b71cb6b3552416c7894ee"}, + {file = "regex-2021.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb2baff66b7d2267e07ef71e17d01283b55b3cc51a81b54cc385e721ae172ba4"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e527ab1c4c7cf2643d93406c04e1d289a9d12966529381ce8163c4d2abe4faf"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c98b013273e9da5790ff6002ab326e3f81072b4616fd95f06c8fa733d2745f"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:55ef044899706c10bc0aa052f2fc2e58551e2510694d6aae13f37c50f3f6ff61"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0ab3530a279a3b7f50f852f1bab41bc304f098350b03e30a3876b7dd89840e"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a37305eb3199d8f0d8125ec2fb143ba94ff6d6d92554c4b8d4a8435795a6eccd"}, + {file = "regex-2021.10.8-cp37-cp37m-win32.whl", hash = "sha256:2efd47704bbb016136fe34dfb74c805b1ef5c7313aef3ce6dcb5ff844299f432"}, + {file = "regex-2021.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:924079d5590979c0e961681507eb1773a142553564ccae18d36f1de7324e71ca"}, + {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b09d3904bf312d11308d9a2867427479d277365b1617e48ad09696fa7dfcdf59"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f125fce0a0ae4fd5c3388d369d7a7d78f185f904c90dd235f7ecf8fe13fa741"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f199419a81c1016e0560c39773c12f0bd924c37715bffc64b97140d2c314354"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:09e1031e2059abd91177c302da392a7b6859ceda038be9e015b522a182c89e4f"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c070d5895ac6aeb665bd3cd79f673775caf8d33a0b569e98ac434617ecea57d"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:176796cb7f82a7098b0c436d6daac82f57b9101bb17b8e8119c36eecf06a60a3"}, + {file = "regex-2021.10.8-cp38-cp38-win32.whl", hash = "sha256:5e5796d2f36d3c48875514c5cd9e4325a1ca172fc6c78b469faa8ddd3d770593"}, + {file = "regex-2021.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:e4204708fa116dd03436a337e8e84261bc8051d058221ec63535c9403a1582a1"}, + {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b6ee6555b6fbae578f1468b3f685cdfe7940a65675611365a7ea1f8d724991"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973499dac63625a5ef9dfa4c791aa33a502ddb7615d992bdc89cf2cc2285daa3"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88dc3c1acd3f0ecfde5f95c32fcb9beda709dbdf5012acdcf66acbc4794468eb"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4786dae85c1f0624ac77cb3813ed99267c9adb72e59fdc7297e1cf4d6036d493"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe6ce4f3d3c48f9f402da1ceb571548133d3322003ce01b20d960a82251695d2"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9e3e2cea8f1993f476a6833ef157f5d9e8c75a59a8d8b0395a9a6887a097243b"}, + {file = "regex-2021.10.8-cp39-cp39-win32.whl", hash = "sha256:82cfb97a36b1a53de32b642482c6c46b6ce80803854445e19bc49993655ebf3b"}, + {file = "regex-2021.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:b04e512eb628ea82ed86eb31c0f7fc6842b46bf2601b66b1356a7008327f7700"}, + {file = "regex-2021.10.8.tar.gz", hash = "sha256:26895d7c9bbda5c52b3635ce5991caa90fbb1ddfac9c9ff1c7ce505e2282fb2a"}, +] +requests = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +tomli = [ + {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"}, + {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, +] +typing-extensions = [ + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, +] +urllib3 = [ + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, +] +"zope.interface" = [ + {file = "zope.interface-5.4.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7df1e1c05304f26faa49fa752a8c690126cf98b40b91d54e6e9cc3b7d6ffe8b7"}, + {file = "zope.interface-5.4.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c98384b254b37ce50eddd55db8d381a5c53b4c10ee66e1e7fe749824f894021"}, + {file = "zope.interface-5.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:08f9636e99a9d5410181ba0729e0408d3d8748026ea938f3b970a0249daa8192"}, + {file = "zope.interface-5.4.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0ea1d73b7c9dcbc5080bb8aaffb776f1c68e807767069b9ccdd06f27a161914a"}, + {file = "zope.interface-5.4.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:273f158fabc5ea33cbc936da0ab3d4ba80ede5351babc4f577d768e057651531"}, + {file = "zope.interface-5.4.0-cp27-cp27m-win32.whl", hash = "sha256:a1e6e96217a0f72e2b8629e271e1b280c6fa3fe6e59fa8f6701bec14e3354325"}, + {file = "zope.interface-5.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:877473e675fdcc113c138813a5dd440da0769a2d81f4d86614e5d62b69497155"}, + {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f7ee479e96f7ee350db1cf24afa5685a5899e2b34992fb99e1f7c1b0b758d263"}, + {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:b0297b1e05fd128d26cc2460c810d42e205d16d76799526dfa8c8ccd50e74959"}, + {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:af310ec8335016b5e52cae60cda4a4f2a60a788cbb949a4fbea13d441aa5a09e"}, + {file = "zope.interface-5.4.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9a9845c4c6bb56e508651f005c4aeb0404e518c6f000d5a1123ab077ab769f5c"}, + {file = "zope.interface-5.4.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0b465ae0962d49c68aa9733ba92a001b2a0933c317780435f00be7ecb959c702"}, + {file = "zope.interface-5.4.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5dd9ca406499444f4c8299f803d4a14edf7890ecc595c8b1c7115c2342cadc5f"}, + {file = "zope.interface-5.4.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:469e2407e0fe9880ac690a3666f03eb4c3c444411a5a5fddfdabc5d184a79f05"}, + {file = "zope.interface-5.4.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:52de7fc6c21b419078008f697fd4103dbc763288b1406b4562554bd47514c004"}, + {file = "zope.interface-5.4.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:3dd4952748521205697bc2802e4afac5ed4b02909bb799ba1fe239f77fd4e117"}, + {file = "zope.interface-5.4.0-cp35-cp35m-win32.whl", hash = "sha256:dd93ea5c0c7f3e25335ab7d22a507b1dc43976e1345508f845efc573d3d779d8"}, + {file = "zope.interface-5.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:3748fac0d0f6a304e674955ab1365d515993b3a0a865e16a11ec9d86fb307f63"}, + {file = "zope.interface-5.4.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:66c0061c91b3b9cf542131148ef7ecbecb2690d48d1612ec386de9d36766058f"}, + {file = "zope.interface-5.4.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:d0c1bc2fa9a7285719e5678584f6b92572a5b639d0e471bb8d4b650a1a910920"}, + {file = "zope.interface-5.4.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2876246527c91e101184f63ccd1d716ec9c46519cc5f3d5375a3351c46467c46"}, + {file = "zope.interface-5.4.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:334701327f37c47fa628fc8b8d28c7d7730ce7daaf4bda1efb741679c2b087fc"}, + {file = "zope.interface-5.4.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:71aace0c42d53abe6fc7f726c5d3b60d90f3c5c055a447950ad6ea9cec2e37d9"}, + {file = "zope.interface-5.4.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5bb3489b4558e49ad2c5118137cfeaf59434f9737fa9c5deefc72d22c23822e2"}, + {file = "zope.interface-5.4.0-cp36-cp36m-win32.whl", hash = "sha256:1c0e316c9add0db48a5b703833881351444398b04111188069a26a61cfb4df78"}, + {file = "zope.interface-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f0c02cbb9691b7c91d5009108f975f8ffeab5dff8f26d62e21c493060eff2a1"}, + {file = "zope.interface-5.4.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:7d97a4306898b05404a0dcdc32d9709b7d8832c0c542b861d9a826301719794e"}, + {file = "zope.interface-5.4.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:867a5ad16892bf20e6c4ea2aab1971f45645ff3102ad29bd84c86027fa99997b"}, + {file = "zope.interface-5.4.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5f931a1c21dfa7a9c573ec1f50a31135ccce84e32507c54e1ea404894c5eb96f"}, + {file = "zope.interface-5.4.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:194d0bcb1374ac3e1e023961610dc8f2c78a0f5f634d0c737691e215569e640d"}, + {file = "zope.interface-5.4.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8270252effc60b9642b423189a2fe90eb6b59e87cbee54549db3f5562ff8d1b8"}, + {file = "zope.interface-5.4.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:15e7d1f7a6ee16572e21e3576d2012b2778cbacf75eb4b7400be37455f5ca8bf"}, + {file = "zope.interface-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:8892f89999ffd992208754851e5a052f6b5db70a1e3f7d54b17c5211e37a98c7"}, + {file = "zope.interface-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2e5a26f16503be6c826abca904e45f1a44ff275fdb7e9d1b75c10671c26f8b94"}, + {file = "zope.interface-5.4.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:0f91b5b948686659a8e28b728ff5e74b1be6bf40cb04704453617e5f1e945ef3"}, + {file = "zope.interface-5.4.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4de4bc9b6d35c5af65b454d3e9bc98c50eb3960d5a3762c9438df57427134b8e"}, + {file = "zope.interface-5.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bf68f4b2b6683e52bec69273562df15af352e5ed25d1b6641e7efddc5951d1a7"}, + {file = "zope.interface-5.4.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:63b82bb63de7c821428d513607e84c6d97d58afd1fe2eb645030bdc185440120"}, + {file = "zope.interface-5.4.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:db1fa631737dab9fa0b37f3979d8d2631e348c3b4e8325d6873c2541d0ae5a48"}, + {file = "zope.interface-5.4.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f44e517131a98f7a76696a7b21b164bcb85291cee106a23beccce454e1f433a4"}, + {file = "zope.interface-5.4.0-cp38-cp38-win32.whl", hash = "sha256:a9506a7e80bcf6eacfff7f804c0ad5350c8c95b9010e4356a4b36f5322f09abb"}, + {file = "zope.interface-5.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:3c02411a3b62668200910090a0dff17c0b25aaa36145082a5a6adf08fa281e54"}, + {file = "zope.interface-5.4.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0cee5187b60ed26d56eb2960136288ce91bcf61e2a9405660d271d1f122a69a4"}, + {file = "zope.interface-5.4.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:a8156e6a7f5e2a0ff0c5b21d6bcb45145efece1909efcbbbf48c56f8da68221d"}, + {file = "zope.interface-5.4.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:205e40ccde0f37496904572035deea747390a8b7dc65146d30b96e2dd1359a83"}, + {file = "zope.interface-5.4.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3f24df7124c323fceb53ff6168da70dbfbae1442b4f3da439cd441681f54fe25"}, + {file = "zope.interface-5.4.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:5208ebd5152e040640518a77827bdfcc73773a15a33d6644015b763b9c9febc1"}, + {file = "zope.interface-5.4.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:17776ecd3a1fdd2b2cd5373e5ef8b307162f581c693575ec62e7c5399d80794c"}, + {file = "zope.interface-5.4.0-cp39-cp39-win32.whl", hash = "sha256:d4d9d6c1a455d4babd320203b918ccc7fcbefe308615c521062bc2ba1aa4d26e"}, + {file = "zope.interface-5.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:0cba8477e300d64a11a9789ed40ee8932b59f9ee05f85276dbb4b59acee5dd09"}, + {file = "zope.interface-5.4.0.tar.gz", hash = "sha256:5dba5f530fec3f0988d83b78cc591b58c0b6eb8431a85edd1569a0539a8a5a0e"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dec433f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[tool.poetry] +name = "icalevents" +version = "0.1.26" +description = "Simple Python 3 library to download, parse and query iCal sources." +authors = ["Martin Eigenmann ", "Thomas Irgang ", "Alexander Hultnér "] +license = "MIT Licence" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.9" +httplib2 = "==0.20.1" +icalendar = "==4.0.8" +python-dateutil = "==2.8.2" +pytz = "==2021.3" +DateTime = "==4.3" + +[tool.poetry.dev-dependencies] +coverage = "==6.0.1" +codecov = "==2.1.12" +pytest = "==6.2.5" +black = "===21.9b0" +flake8 = "===3.7.9" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a09d117..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -httplib2 -icalendar -python-dateutil >= 2.7.0 -pytz -datetime -coverage -codecov diff --git a/setup.cfg b/setup.cfg index b88034e..08aedd7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,2 @@ [metadata] -description-file = README.md +description_file = README.md diff --git a/setup.py b/setup.py index b0f9b7b..93e2422 100755 --- a/setup.py +++ b/setup.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 from setuptools import setup -version = '0.1.25' +version = "0.1.26" setup( - name = 'icalevents', - packages = ['icalevents'], + name="icalevents", + packages=["icalevents"], install_requires=[ "httplib2", "icalendar", @@ -13,27 +13,29 @@ "datetime", ], version=version, - description = 'iCal downloader and parser', - author = 'Thomas Irgang', - author_email = 'thomas@irgang-la.de', - url = 'https://github.com/irgangla/icalevents', - download_url = 'https://github.com/irgangla/icalevents/archive/v' + version + '.tar.gz', - keywords = ['iCal'], - classifiers = [ - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Development Status :: 4 - Beta', - 'Environment :: Other Environment', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Operating System :: OS Independent', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - long_description = """\ + description="iCal downloader and parser", + author="Thomas Irgang", + author_email="thomas@irgang-la.de", + url="https://github.com/jazzband/icalevents", + download_url="https://github.com/jazzband/icalevents/archive/v" + + version + + ".tar.gz", + keywords=["iCal"], + classifiers=[ + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Development Status :: 4 - Beta", + "Environment :: Other Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Operating System :: OS Independent", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + long_description="""\ iCal download, parse and query tool ------------------------------------- @@ -44,5 +46,5 @@ This version requires Python 3 or later. -""" +""", ) diff --git a/source/conf.py b/source/conf.py deleted file mode 100644 index 0eafcd5..0000000 --- a/source/conf.py +++ /dev/null @@ -1,180 +0,0 @@ -# -*- coding: utf-8 -*- -# -# iCalEvents documentation build configuration file, created by -# sphinx-quickstart on Wed Jul 19 16:55:32 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.imgmath', - 'sphinx.ext.ifconfig'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'iCalEvents' -copyright = u'2017, Thomas Irgang' -author = u'Thomas Irgang' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = u'0.0.1' -# The full version, including alpha/beta/rc tags. -release = u'0.0.1' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = [] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'about.html', - 'navigation.html', - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - 'donate.html', - ] -} - - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'iCalEventsdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'iCalEvents.tex', u'iCalEvents Documentation', - u'Thomas Irgang', 'manual'), -] - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'icalevents', u'iCalEvents Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'iCalEvents', u'iCalEvents Documentation', - author, 'iCalEvents', 'One line description of project.', - 'Miscellaneous'), -] - - - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/source/index.rst b/source/index.rst deleted file mode 100644 index 25bd50e..0000000 --- a/source/index.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. iCalEvents documentation master file, created by - sphinx-quickstart on Wed Jul 19 16:55:32 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to iCalEvents's documentation! -====================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - -* :ref:`genindex` -* :ref:`modindex` - -icalevents -========== - -.. automodule:: icalevents.icalevents - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -icaldownload -============ - -.. automodule:: icalevents.icaldownload - :members: - :undoc-members: - :inherited-members: - :show-inheritance: - -icalparser -========== - -.. automodule:: icalevents.icalparser - :members: - :undoc-members: - :inherited-members: - :show-inheritance: diff --git a/test/test_data/categories_test.ics b/test/test_data/categories_test.ics index 756d8f6..c1e2e76 100644 --- a/test/test_data/categories_test.ics +++ b/test/test_data/categories_test.ics @@ -24,4 +24,4 @@ DTSTART:20201118T021500Z DTEND:20201118T041500Z CATEGORIES:In19-S04-IT2406,In19-S04-IT2405 END:VEVENT -END:VCALENDAR \ No newline at end of file +END:VCALENDAR diff --git a/test/test_data/cest.ics b/test/test_data/cest.ics new file mode 100644 index 0000000..8c07e39 --- /dev/null +++ b/test/test_data/cest.ics @@ -0,0 +1,2262 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +X-WR-CALNAME:Calendar +BEGIN:VTIMEZONE +TZID:W. Europe Standard Time +BEGIN:STANDARD +DTSTART:16010101T030000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20200521T220000Z;INTERVAL=1;BYDAY=MO,FR;WKST=MO +UID:040000008200E00074C5B7101A82E008000000001075617F3BE6D501000000000000000 + 0100000007B29D30C240193429FF8C08553783419 +SUMMARY:Away +DTSTART;VALUE=DATE:20200508 +DTEND;VALUE=DATE:20200509 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000B05AD42D8A27D601000000000000000 + 01000000030BB2D39F818C747A760BA7929ED3981 +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20200512T090000 +DTEND;TZID=W. Europe Standard Time:20200512T093000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20200520T140000Z;INTERVAL=1;BYDAY=WE;WKST=MO +UID:040000008200E00074C5B7101A82E00800000000D0B7C0A43BE6D501000000000000000 + 0100000000C1F72E9A45C5D4ABC1F1AC4E9461313 +SUMMARY:Away +DTSTART;TZID=W. Europe Standard Time:20200513T160000 +DTEND;TZID=W. Europe Standard Time:20200513T220000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:DE298210-0417-46D3-B2B2-4038AA905649 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200526T090000 +DTEND;TZID=W. Europe Standard Time:20200526T093000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:B5E946AC-2F29-4F13-8922-5686D24E8187 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200526T114500 +DTEND;TZID=W. Europe Standard Time:20200526T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:EAE44C91-F256-4212-A477-6B5215AA8BC7 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200527T090000 +DTEND;TZID=W. Europe Standard Time:20200527T094500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000C01BF415203BD601000000000000000 + 0100000006B678962A55F6842977AD405D4ECAA8B +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200608T154500 +DTEND;TZID=W. Europe Standard Time:20200608T161500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:BF60522B-2482-4734-A552-14F8C39011CA +SUMMARY:Free +DTSTART;TZID=W. Europe Standard Time:20200701T090000 +DTEND;TZID=W. Europe Standard Time:20200701T110000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:TRANSPARENT +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:FREE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:AE5B3952-8663-432D-84C2-87D34E9C753F +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200706T090000 +DTEND;TZID=W. Europe Standard Time:20200706T093000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:8839D7E0-115A-4E61-B5B3-AE6307DAD3D4 +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20200706T093000 +DTEND;TZID=W. Europe Standard Time:20200706T100000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:733C582E-47E9-405A-A365-D476589C803C +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200706T130000 +DTEND;TZID=W. Europe Standard Time:20200706T133000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:A3A5B2A9-6D72-4541-8F24-E77EA1BEFC3F +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200708T103000 +DTEND;TZID=W. Europe Standard Time:20200708T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:2 +X-MICROSOFT-CDO-APPT-SEQUENCE:2 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:55B4C453-E46F-4C59-80F0-86795757EA54 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200713T153000 +DTEND;TZID=W. Europe Standard Time:20200713T160000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:2 +X-MICROSOFT-CDO-APPT-SEQUENCE:2 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000908294864A50D601000000000000000 + 010000000B11AD25C8FAC044AA4B213C41795F969 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200716T120000 +DTEND;TZID=W. Europe Standard Time:20200716T130000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:4 +X-MICROSOFT-CDO-APPT-SEQUENCE:4 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:997EAA7F-3875-48A7-9F2C-625A9DA4C74B +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200716T143000 +DTEND;TZID=W. Europe Standard Time:20200716T150000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000DC9F44E10C5AD601000000000000000 + 0100000000F865D0942EDAE45AD168FD5AE0085DD +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200717T130000 +DTEND;TZID=W. Europe Standard Time:20200717T133000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000400D2869775ED601000000000000000 + 010000000712CF41D5BDC7B47AC67478991311A12 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200720T103000 +DTEND;TZID=W. Europe Standard Time:20200720T104500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000004C7923C4D522D601000000000000000 + 010000000A106A7E501F8324795D06DEA44182073 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200727T070000 +DTEND;TZID=W. Europe Standard Time:20200727T073000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:D03C22DA-13B7-49AE-9087-7CC1183EE7AA +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200727T134500 +DTEND;TZID=W. Europe Standard Time:20200727T154500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000005ABFDC9E1F64D601000000000000000 + 010000000A86E35E32541A043AF90A3B032210D57 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200730T133000 +DTEND;TZID=W. Europe Standard Time:20200730T140000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000503CA7354B50D601000000000000000 + 0100000000FEB7774C50048408D5F919D19319CAF +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200813T120000 +DTEND;TZID=W. Europe Standard Time:20200813T130000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:3 +X-MICROSOFT-CDO-APPT-SEQUENCE:3 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:171F5E53-F03C-4FD6-A92A-CCC3AEC9099B +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200826T103000 +DTEND;TZID=W. Europe Standard Time:20200826T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:34CC9FCD-AFBB-4DF1-B1B7-9E2FC79139B1 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200904T160000 +DTEND;TZID=W. Europe Standard Time:20200904T164500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:4E3984EFA34448D68E97183D8EAF5FB80 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200907T130000 +DTEND;TZID=W. Europe Standard Time:20200907T140000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:2 +X-MICROSOFT-CDO-APPT-SEQUENCE:2 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20201216T080000Z;INTERVAL=1;BYDAY=WE;WKST=SU +UID:1F6F1A4B-A70F-45DA-8F31-A47AAE02F7AC +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200909T090000 +DTEND;TZID=W. Europe Standard Time:20200909T103000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:5 +X-MICROSOFT-CDO-APPT-SEQUENCE:5 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:DF3704CE-4336-42E3-9BBE-F4AB1AE33E36 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200911T160000 +DTEND;TZID=W. Europe Standard Time:20200911T210000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20201221T230000Z;INTERVAL=1;BYDAY=TU;WKST=MO +UID:040000008200E00074C5B7101A82E0080000000016888E6CBF86D601000000000000000 + 010000000448FF2FAF3F0424A89B6DC5D1FD02484 +SUMMARY:Away +DTSTART;VALUE=DATE:20200915 +DTEND;VALUE=DATE:20200916 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20201224T110000Z;INTERVAL=1;BYDAY=TH;WKST=MO +UID:040000008200E00074C5B7101A82E00800000000A429EDD6C086D601000000000000000 + 0100000009CEB2D590EF69D4F9F4A5CBEEB46C471 +SUMMARY:Away +DTSTART;TZID=W. Europe Standard Time:20200917T120000 +DTEND;TZID=W. Europe Standard Time:20200917T173000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:98E77A12-F595-4DFA-AAA4-70655A64AD22 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200918T110000 +DTEND;TZID=W. Europe Standard Time:20200918T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20201225T110000Z;INTERVAL=1;BYDAY=FR;WKST=MO +UID:040000008200E00074C5B7101A82E008000000003E664513C186D601000000000000000 + 01000000026A83D65744F3C4C80410BE9CFA1B03C +SUMMARY:Away +DTSTART;TZID=W. Europe Standard Time:20200918T120000 +DTEND;TZID=W. Europe Standard Time:20200918T170000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:91B8081F-4764-4108-97A9-E4C0AF6E33C3 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200924T093000 +DTEND;TZID=W. Europe Standard Time:20200924T113000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000103FADEF4C71D601000000000000000 + 010000000F08C89F594F6A645A59D42928F69DF4B +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200924T120000 +DTEND;TZID=W. Europe Standard Time:20200924T130000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:F9B8DF47-0F86-4845-BDED-646A38D03B0A +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20200930T101500 +DTEND;TZID=W. Europe Standard Time:20200930T103000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000349C10C11797D601000000000000000 + 010000000927A2F068F5FCA40829F0F35BA04ACFC +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201001T090000 +DTEND;TZID=W. Europe Standard Time:20201001T093000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000BB812ABD0A97D601000000000000000 + 010000000F4E98D4229BFFA49871BE9A4252B77BA +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201001T093000 +DTEND;TZID=W. Europe Standard Time:20201001T100000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000F152D604BB91D601000000000000000 + 010000000B062F09E1083D94E801010FDFBB3C179 +SUMMARY:Free +DTSTART;TZID=W. Europe Standard Time:20201002T080000 +DTEND;TZID=W. Europe Standard Time:20201002T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:TRANSPARENT +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:FREE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000000F12AF14197D601000000000000000 + 010000000B2F69E4E61595740A288CD8FF9191DC1 +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20201002T090000 +DTEND;TZID=W. Europe Standard Time:20201002T094500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000002DCD218DF6A1D601000000000000000 + 0100000008C2B77CC1D0C8E4F9F75A410E5FB5170 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201016T090000 +DTEND;TZID=W. Europe Standard Time:20201016T094500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000E30226C965A1D601000000000000000 + 0100000000248855A551E4F409F1C134AB8B1E8F5 +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20201016T130000 +DTEND;TZID=W. Europe Standard Time:20201016T133000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000B773F8E965A1D601000000000000000 + 0100000005AF82035561A6D438E87A4558E721B4D +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201016T160000 +DTEND;TZID=W. Europe Standard Time:20201016T170000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000006043B50DC4A7D601000000000000000 + 010000000504B9DE85AC0434BB1E1152DEC546CBC +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201022T090000 +DTEND;TZID=W. Europe Standard Time:20201022T100000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000050FC3101C4A7D601000000000000000 + 010000000886DDB26E9F8EF448AE0C6FBF58F9A50 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201022T100000 +DTEND;TZID=W. Europe Standard Time:20201022T103000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000803A2CD475ABD601000000000000000 + 010000000E8B2F7397211794A9A0039A9A547ECB6 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201026T150000 +DTEND;TZID=W. Europe Standard Time:20201026T160000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000A0AC4F364D71D601000000000000000 + 010000000598606CD1DBC3F458327B7940CCC0E4F +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201029T120000 +DTEND;TZID=W. Europe Standard Time:20201029T130000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000007D3D53B664ACD601000000000000000 + 010000000F8C3CFB29FA20B4FAC6AB54B9F985EFF +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201030T090000 +DTEND;TZID=W. Europe Standard Time:20201030T093000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000F0E7713464B3D601000000000000000 + 010000000F20CCD9063386848B1E6C38D56348A3A +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201105T113000 +DTEND;TZID=W. Europe Standard Time:20201105T114500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000B003167078B6D601000000000000000 + 0100000009566D0821DFAB444A78B69525A1F61A2 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201109T150000 +DTEND;TZID=W. Europe Standard Time:20201109T153000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000772606315EB6D601000000000000000 + 0100000001CCF2EBE9FEFE0439A7C3D07F4FE4883 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201113T090000 +DTEND;TZID=W. Europe Standard Time:20201113T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000008C9C524993B9D601000000000000000 + 0100000009EAAC0689CB0C1498DDA7C183750D6A2 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201113T110000 +DTEND;TZID=W. Europe Standard Time:20201113T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000198EAB2DE8BBD601000000000000000 + 0100000004B3E4AC2F61161469205D3DD9BF15047 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201118T090000 +DTEND;TZID=W. Europe Standard Time:20201118T100000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000007D0934885EB6D601000000000000000 + 0100000005D8D3D05DA30FF4AA18FC1A9BC69270C +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201119T110000 +DTEND;TZID=W. Europe Standard Time:20201119T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000021FE26DABEBDD601000000000000000 + 010000000A61457CDF929E84B9E540355583BECC6 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201120T090000 +DTEND;TZID=W. Europe Standard Time:20201120T093000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000591198E55EB6D601000000000000000 + 010000000CC7B25FF48720A42932E5EF20335F073 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201123T130000 +DTEND;TZID=W. Europe Standard Time:20201123T140000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000002FD322CF0EC3D601000000000000000 + 0100000002879E7E16395374FA08EA9A114429811 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201125T130000 +DTEND;TZID=W. Europe Standard Time:20201125T134500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000089F581662EC3D601000000000000000 + 0100000004D75E5BEC145564D9A55BBE5A1ED1800 +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20201127T091500 +DTEND;TZID=W. Europe Standard Time:20201127T100000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000005F8D2ADC1BC7D601000000000000000 + 010000000DEF2117458876E41BCF3BA06CFCCA592 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201202T093000 +DTEND;TZID=W. Europe Standard Time:20201202T103000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000006CC4F013A9C4D601000000000000000 + 010000000F149D1D4B39A914CACE58508268387AD +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20201204T091500 +DTEND;TZID=W. Europe Standard Time:20201204T100000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000007BB741DEAFC8D601000000000000000 + 0100000001684F5DC2799904BA0520074A8841886 +SUMMARY:Free +DTSTART;VALUE=DATE:20201207 +DTEND;VALUE=DATE:20201208 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:TRANSPARENT +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:FREE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000002099F7108FCCD601000000000000000 + 01000000092773DDAACCD5343A8B16FCFEB67D040 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20201207T130000 +DTEND;TZID=W. Europe Standard Time:20201207T133000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000001F0DAC8B99C8D601000000000000000 + 010000000DAE6A8429A0E224BBEFA1ECD2FD61D5C +SUMMARY:Away +DTSTART;VALUE=DATE:20201214 +DTEND;VALUE=DATE:20210103 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000007D187AF9CAE4D601000000000000000 + 010000000FE63728EA079484EAD5DC5A25B5E16A7 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210107T094500 +DTEND;TZID=W. Europe Standard Time:20210107T103000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20210125T230000Z;INTERVAL=1;BYDAY=MO,TU;WKST=SU +UID:040000008200E00074C5B7101A82E008000000002B891E7C27E4D601000000000000000 + 0100000006DE03E881A143B45AD0DCE35DAE22EAE +SUMMARY:Away +DTSTART;VALUE=DATE:20210111 +DTEND;VALUE=DATE:20210112 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000009CBE5D424AEAD601000000000000000 + 01000000022A6E26556835141B9E5E95142C40DEF +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210114T100000 +DTEND;TZID=W. Europe Standard Time:20210114T110000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000884B9DBFC7E9D601000000000000000 + 010000000A30A5DF8B2B46D488F11D6B274B544D6 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210121T110000 +DTEND;TZID=W. Europe Standard Time:20210121T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000060DBEE5200F0D601000000000000000 + 01000000023B33A24482A7D46B9B37405A78E3366 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210121T160000 +DTEND;TZID=W. Europe Standard Time:20210121T170000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000020F5C57016CFD601000000000000000 + 0100000007BB1D7474520E348A825D6909AA899FE +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210128T123000 +DTEND;TZID=W. Europe Standard Time:20210128T131500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000440773E767F5D601000000000000000 + 0100000009966933D911E7E42B6AB82C6BD6B4F32 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210129T143000 +DTEND;TZID=W. Europe Standard Time:20210129T151500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000000EEC6AE56EFDD601000000000000000 + 010000000A13DB89C59332647B6810D2CAF3934BE +SUMMARY:Away +DTSTART;TZID=W. Europe Standard Time:20210208T123000 +DTEND;TZID=W. Europe Standard Time:20210208T153000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000376247EB6EFDD601000000000000000 + 010000000D8E5E8A206338C4093D0A8D898092505 +SUMMARY:Away +DTSTART;TZID=W. Europe Standard Time:20210209T100000 +DTEND;TZID=W. Europe Standard Time:20210209T110000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000063A58C56C8FED601000000000000000 + 0100000000CA0BC7BC5659B4CADDDFC4178FB5E91 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210209T150000 +DTEND;TZID=W. Europe Standard Time:20210209T154500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20210701T220000Z;INTERVAL=1;BYDAY=WE,FR;WKST=SU +EXDATE;TZID=W. Europe Standard Time:20210409T000000 +UID:040000008200E00074C5B7101A82E0080000000062FD14411601D701000000000000000 + 01000000052EAF66D5C3BC6458198F47BAE50996F +SUMMARY:Away +DTSTART;VALUE=DATE:20210210 +DTEND;VALUE=DATE:20210211 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000303073B75600D701000000000000000 + 010000000AE5A210A3F9BEE44B9B75195D0FAB846 +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20210211T102000 +DTEND;TZID=W. Europe Standard Time:20210211T105000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000001033B0755900D701000000000000000 + 010000000F21D5BA0A102E44FA1349F57C83524E9 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210212T100000 +DTEND;TZID=W. Europe Standard Time:20210212T103000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000009A51E42C8500D701000000000000000 + 01000000026D978CECD0ED94ABAE1820E59EBDACD +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210212T140000 +DTEND;TZID=W. Europe Standard Time:20210212T144500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000919F8FC44601D701000000000000000 + 010000000C69F0D73D52D9644856FB428C86A0058 +SUMMARY:Away +DTSTART;VALUE=DATE:20210215 +DTEND;VALUE=DATE:20210220 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000053199367C4FED601000000000000000 + 0100000007A757D6743D6AC45B928616252EEFD13 +SUMMARY:Away +DTSTART;TZID=W. Europe Standard Time:20210215T133000 +DTEND;TZID=W. Europe Standard Time:20210215T150000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000001A5783F69306D701000000000000000 + 01000000091231B1A616E6E4C83C33C02741BCCB2 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210222T111500 +DTEND;TZID=W. Europe Standard Time:20210222T114500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20210614T140000Z;INTERVAL=1;BYDAY=MO;WKST=SU +UID:040000008200E00074C5B7101A82E0080000000032F6CC7BC4FED601000000000000000 + 01000000059A4AC935178BE498342C66FCD96605B +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210222T160000 +DTEND;TZID=W. Europe Standard Time:20210222T170000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000005A6368804A0BD701000000000000000 + 010000000282C19D7AAC16D42A5AE2A4BA42C666D +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210225T140000 +DTEND;TZID=W. Europe Standard Time:20210225T144500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000D0AABD9383F5D601000000000000000 + 0100000000A8335BCAA31684BA1520DCE5D660873 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210304T120000 +DTEND;TZID=W. Europe Standard Time:20210304T130000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000415891C7D211D701000000000000000 + 0100000005DECAE2F4DBDE242B2CCFD09A74DBABA +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210308T133000 +DTEND;TZID=W. Europe Standard Time:20210308T140000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000AF393EB98015D701000000000000000 + 010000000763A658A5A46CD44BE873E1C3015A606 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210311T110000 +DTEND;TZID=W. Europe Standard Time:20210311T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000005B85AB63FA14D701000000000000000 + 01000000004B8755F6F487641B55BB9603E985222 +SUMMARY:Free +DTSTART;TZID=W. Europe Standard Time:20210311T130000 +DTEND;TZID=W. Europe Standard Time:20210311T133000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:TRANSPARENT +STATUS:CONFIRMED +X-MICROSOFT-CDO-BUSYSTATUS:FREE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20210527T130000Z;INTERVAL=1;BYDAY=TH;WKST=MO +UID:040000008200E00074C5B7101A82E00800000000E9C052427816D701000000000000000 + 0100000008F01F7E13E614043AD1987096D963151 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210311T150000 +DTEND;TZID=W. Europe Standard Time:20210311T153000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000502B3C36A30ED701000000000000000 + 010000000EAF014D5A35FB14B93C6395A458BF29A +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210315T100000 +DTEND;TZID=W. Europe Standard Time:20210315T103000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000F4592894950ED701000000000000000 + 010000000A7CBC87DBBCA6943AAA7201F572B2A11 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210316T100000 +DTEND;TZID=W. Europe Standard Time:20210316T110000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000020BBAF412A17D701000000000000000 + 01000000015C7B7FD9D3C704D8A71EA1095C4144C +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210316T133000 +DTEND;TZID=W. Europe Standard Time:20210316T143000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000EAB7100F3E1BD701000000000000000 + 01000000039AC9904FB7B574CACB169DCA9A308C5 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210318T110000 +DTEND;TZID=W. Europe Standard Time:20210318T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:3 +X-MICROSOFT-CDO-APPT-SEQUENCE:3 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000056708658D41BD701000000000000000 + 010000000288A95567748874395EB3C35488488C4 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210318T140000 +DTEND;TZID=W. Europe Standard Time:20210318T144500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000047612D687716D701000000000000000 + 010000000C64ADB397B7B5F46A00A2569EC5EA967 +RECURRENCE-ID;TZID=W. Europe Standard Time:20210325T110000 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210325T110000 +DTEND;TZID=W. Europe Standard Time:20210325T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:3 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20210520T090000Z;INTERVAL=2;BYDAY=TH;WKST=MO +UID:040000008200E00074C5B7101A82E0080000000047612D687716D701000000000000000 + 010000000C64ADB397B7B5F46A00A2569EC5EA967 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210325T110000 +DTEND;TZID=W. Europe Standard Time:20210325T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000E438F64A7D1AD701000000000000000 + 0100000006865BBCD6ADF3C498266727498DA68B8 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210325T130000 +DTEND;TZID=W. Europe Standard Time:20210325T134500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000009000BFC0C820D701000000000000000 + 01000000019AB21D3295D4041B98C981AF2630F56 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210325T140000 +DTEND;TZID=W. Europe Standard Time:20210325T150000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000004025612F8D21D701000000000000000 + 010000000EB5CE5C94A6D8D4DBFFEAE51936A4B0B +SUMMARY:Tentative +DTSTART;TZID=W. Europe Standard Time:20210326T203000 +DTEND;TZID=W. Europe Standard Time:20210326T213000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000E9C052427816D701000000000000000 + 0100000008F01F7E13E614043AD1987096D963151 +RECURRENCE-ID;TZID=W. Europe Standard Time:20210401T150000 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210401T140000 +DTEND;TZID=W. Europe Standard Time:20210401T143000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:2 +X-MICROSOFT-CDO-APPT-SEQUENCE:2 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:3 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000011605C2ACD26D701000000000000000 + 010000000F798EE164A5A0649A59CE9127B6CFC1B +SUMMARY:Away +DTSTART;TZID=W. Europe Standard Time:20210401T153000 +DTEND;TZID=W. Europe Standard Time:20210401T170000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000047612D687716D701000000000000000 + 010000000C64ADB397B7B5F46A00A2569EC5EA967 +RECURRENCE-ID;TZID=W. Europe Standard Time:20210408T110000 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210408T110000 +DTEND;TZID=W. Europe Standard Time:20210408T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:3 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000FD7292805F2CD701000000000000000 + 01000000084E6928FD699C3428C99D6027BA86275 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210408T143000 +DTEND;TZID=W. Europe Standard Time:20210408T150000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000F610DC2BDE24D701000000000000000 + 010000000F0F7E5A9202B5C4DAF526C900716D097 +SUMMARY:Away +DTSTART;VALUE=DATE:20210409 +DTEND;VALUE=DATE:20210410 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000D05779292F2DD701000000000000000 + 010000000D150442AD591AE4B86FD598B7840020D +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210412T110000 +DTEND;TZID=W. Europe Standard Time:20210412T113000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000605EA78DFF10D701000000000000000 + 010000000EAE226447A402443AF0B8B003E0E015D +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210415T120000 +DTEND;TZID=W. Europe Standard Time:20210415T130000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000047612D687716D701000000000000000 + 010000000C64ADB397B7B5F46A00A2569EC5EA967 +RECURRENCE-ID;TZID=W. Europe Standard Time:20210422T110000 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210422T110000 +DTEND;TZID=W. Europe Standard Time:20210422T120000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:3 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000E9C052427816D701000000000000000 + 0100000008F01F7E13E614043AD1987096D963151 +RECURRENCE-ID;TZID=W. Europe Standard Time:20210422T150000 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210422T144500 +DTEND;TZID=W. Europe Standard Time:20210422T151500 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:3 +X-MICROSOFT-CDO-APPT-SEQUENCE:3 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:3 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000A0167C30CF35D701000000000000000 + 010000000EFA0066ABD2B1B418293BD97F9CDBA8C +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210429T090000 +DTEND;TZID=W. Europe Standard Time:20210429T110000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:1 +X-MICROSOFT-CDO-APPT-SEQUENCE:1 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000532394E1CC3CD701000000000000000 + 0100000007DD8BEF5B4F8184EA8CEA7032E7534D7 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210429T110000 +DTEND;TZID=W. Europe Standard Time:20210429T113000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000A7CA7204D73CD701000000000000000 + 010000000BF412F30A119224B9A77AA835DF602C4 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210429T141500 +DTEND;TZID=W. Europe Standard Time:20210429T150000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000B0B38DC8F431D701000000000000000 + 01000000051CF385F745B294C895769D9C4C29FA1 +SUMMARY:Busy +DTSTART;TZID=W. Europe Standard Time:20210520T120000 +DTEND;TZID=W. Europe Standard Time:20210520T130000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210508T112140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/empty.ics b/test/test_data/empty.ics new file mode 100644 index 0000000..e69de29 diff --git a/test/test_data/google_tz.ics b/test/test_data/google_tz.ics new file mode 100644 index 0000000..405f842 --- /dev/null +++ b/test/test_data/google_tz.ics @@ -0,0 +1,17 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:test +X-WR-TIMEZONE:Europe/Zurich +BEGIN:VEVENT +DTSTART;VALUE=DATE:20210324 +DTEND;VALUE=DATE:20210327 +DTSTAMP:20210328T094322Z +UID:1gn1mvk5325euprb9fcf7ndpdn@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +SUMMARY:Busy +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/icloud.ics b/test/test_data/icloud.ics index 1679376..5075ce3 100644 --- a/test/test_data/icloud.ics +++ b/test/test_data/icloud.ics @@ -246,12 +246,12 @@ DTEND;TZID=Europe/Berlin:20161103T183000 DTSTAMP:20161026T154649Z DTSTART;TZID=Europe/Berlin:20161103T180000 LAST-MODIFIED:20161026T154648Z -LOCATION:Naturpark Altmühltal\nKanalstraße 5\n91757 +LOCATION:Naturpark Altmühltal\nKanalstraße 5\n91757 Treuchtlingen\nDeutschland SEQUENCE:0 SUMMARY:Friseur UID:003AFB7E-BA60-481A-A087-23024D956074 -X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS=Kanalstraße 5\\n91757 +X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS=Kanalstraße 5\\n91757 Treuchtlingen\\nDeutschland;X-APPLE-RADIUS=100;X-APPLE-REFERENCEFRAME=1; X-TITLE=Naturpark Altmühltal:geo:48.954682,10.909644 END:VEVENT diff --git a/test/test_data/icloud_content.txt b/test/test_data/icloud_content.txt index aeb9bc1..bed4f1b 100644 --- a/test/test_data/icloud_content.txt +++ b/test/test_data/icloud_content.txt @@ -246,12 +246,12 @@ DTEND;TZID=Europe/Berlin:20161103T183000 DTSTAMP:20161026T154649Z DTSTART;TZID=Europe/Berlin:20161103T180000 LAST-MODIFIED:20161026T154648Z -LOCATION:Naturpark Altmühltal\nKanalstraße 5\n91757 +LOCATION:Naturpark Altmühltal\nKanalstraße 5\n91757 Treuchtlingen\nDeutschland SEQUENCE:0 SUMMARY:Friseur UID:003AFB7E-BA60-481A-A087-23024D956074 -X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS=Kanalstraße 5\\n91757 +X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-ADDRESS=Kanalstraße 5\\n91757 Treuchtlingen\\nDeutschland;X-APPLE-RADIUS=100;X-APPLE-REFERENCEFRAME=1; X-TITLE=Naturpark Altmühltal:geo:48.954682,10.909644 END:VEVENT diff --git a/test/test_data/ms_tz.ics b/test/test_data/ms_tz.ics new file mode 100644 index 0000000..ab5f861 --- /dev/null +++ b/test/test_data/ms_tz.ics @@ -0,0 +1,42 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +X-WR-CALNAME:test +BEGIN:VTIMEZONE +TZID:W. Europe Standard Time +BEGIN:STANDARD +DTSTART:16010101T030000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000007E56CFC7E1DD701000000000000000 + 01000000068B41E0ADF04374687B1104CB913D622 +SUMMARY:Busy +DTSTART;VALUE=DATE:20210324 +DTEND;VALUE=DATE:20210327 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210328T104140Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/recurrenceid_google.ics b/test/test_data/recurrenceid_google.ics new file mode 100644 index 0000000..41d0722 --- /dev/null +++ b/test/test_data/recurrenceid_google.ics @@ -0,0 +1,48 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:test +X-WR-TIMEZONE:Europe/Zurich +BEGIN:VEVENT +DTSTART:20210327T110000Z +DTEND:20210327T120000Z +DTSTAMP:20210320T113243Z +UID:5kml9evtgr3lffqh2lc2lu86kp@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +RECURRENCE-ID:20210327T110000Z +SUMMARY:Busy +END:VEVENT +BEGIN:VEVENT +DTSTART:20210326T110000Z +DTEND:20210326T120000Z +DTSTAMP:20210320T113243Z +UID:5kml9evtgr3lffqh2lc2lu86kp@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +RECURRENCE-ID:20210326T110000Z +SUMMARY:Busy +END:VEVENT +BEGIN:VEVENT +DTSTART:20210325T110000Z +DTEND:20210325T120000Z +DTSTAMP:20210320T113243Z +UID:5kml9evtgr3lffqh2lc2lu86kp@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +RECURRENCE-ID:20210325T110000Z +SUMMARY:Busy +END:VEVENT +BEGIN:VEVENT +DTSTART:20210324T110000Z +DTEND:20210324T120000Z +DTSTAMP:20210320T113243Z +UID:5kml9evtgr3lffqh2lc2lu86kp@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +RECURRENCE-ID:20210324T110000Z +SUMMARY:Busy +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/recurrenceid_ms.ics b/test/test_data/recurrenceid_ms.ics new file mode 100644 index 0000000..6b599c4 --- /dev/null +++ b/test/test_data/recurrenceid_ms.ics @@ -0,0 +1,65 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +X-WR-CALNAME:Calendar +BEGIN:VTIMEZONE +TZID:W. Europe Standard Time +BEGIN:STANDARD +DTSTART:16010101T030000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20210701T220000Z;INTERVAL=1;BYDAY=WE,FR;WKST=SU +UID:040000008200E00074C5B7101A82E0080000000062FD14411601D701000000000000000 + 01000000052EAF66D5C3BC6458198F47BAE50996F +SUMMARY:Away +DTSTART;VALUE=DATE:20210210 +DTEND;VALUE=DATE:20210211 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210329T195704Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E0080000000062FD14411601D701000000000000000 + 01000000052EAF66D5C3BC6458198F47BAE50996F +RECURRENCE-ID;TZID=W. Europe Standard Time:20210409T000000 +SUMMARY:Away +DTSTART;VALUE=DATE:20210410 +DTEND;VALUE=DATE:20210411 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210329T195704Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:OOF +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:3 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/rrule_until_all_day_google.ics b/test/test_data/rrule_until_all_day_google.ics new file mode 100644 index 0000000..9ce3845 --- /dev/null +++ b/test/test_data/rrule_until_all_day_google.ics @@ -0,0 +1,38 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:test +X-WR-TIMEZONE:Europe/Zurich +BEGIN:VEVENT +DTSTART;VALUE=DATE:20210407 +DTEND;VALUE=DATE:20210410 +DTSTAMP:20210328T184235Z +UID:1gn1mvk5325euprb9fcf7ndpdn@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +RECURRENCE-ID;VALUE=DATE:20210407 +SUMMARY:Busy +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20210331 +DTEND;VALUE=DATE:20210403 +DTSTAMP:20210328T184235Z +UID:1gn1mvk5325euprb9fcf7ndpdn@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +RECURRENCE-ID;VALUE=DATE:20210331 +SUMMARY:Busy +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20210324 +DTEND;VALUE=DATE:20210327 +DTSTAMP:20210328T184235Z +UID:1gn1mvk5325euprb9fcf7ndpdn@google.com +ATTENDEE;X-NUM-GUESTS=0:mailto:hst9ma4s2h5hf2iafmrqffki9o@group.calendar.go + ogle.com +RECURRENCE-ID;VALUE=DATE:20210324 +SUMMARY:Busy +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/rrule_until_all_day_ms.ics b/test/test_data/rrule_until_all_day_ms.ics new file mode 100644 index 0000000..6bb938c --- /dev/null +++ b/test/test_data/rrule_until_all_day_ms.ics @@ -0,0 +1,36 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +X-WR-CALNAME:Kalender +BEGIN:VTIMEZONE +TZID:W. Europe Standard Time +BEGIN:STANDARD +DTSTART:16010101T030000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +RRULE:FREQ=WEEKLY;UNTIL=20210502T220000Z;INTERVAL=1;BYDAY=FR;WKST=MO +EXDATE;TZID=W. Europe Standard Time:20210430T000000 +UID:040000008200E00074C5B7101A82E00800000000D0A3F2C7C4E8D601000000000000000 + 0100000006C7ACDDE7E4A5E47ACD97CBB31A1438C +SUMMARY:Away +DTSTART;VALUE=DATE:20210319 +DTEND;VALUE=DATE:20210321 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210326T082505Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/rrule_until_only_date.ics b/test/test_data/rrule_until_only_date.ics new file mode 100644 index 0000000..a7a831c --- /dev/null +++ b/test/test_data/rrule_until_only_date.ics @@ -0,0 +1,43 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:NotYourCalendar +X-WR-TIMEZONE:America/Boise +BEGIN:VTIMEZONE +TZID:America/Boise +X-LIC-LOCATION:America/Boise +BEGIN:DAYLIGHT +TZOFFSETFROM:-0700 +TZOFFSETTO:-0600 +TZNAME:MDT +DTSTART:19700308T020000 +RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:-0600 +TZOFFSETTO:-0700 +TZNAME:MST +DTSTART:19701101T020000 +RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=America/Boise:20210929T130000 +DTEND;TZID=America/Boise:20210929T135000 +RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20211020;BYDAY=MO,TH,WE +EXDATE;TZID=America/Boise:20211013T130000 +DTSTAMP:20211029T011330Z +UID:9cntado4fkl7simv3loh94ua1m@google.com +CREATED:20210811T153934Z +DESCRIPTION: +LAST-MODIFIED:20210927T184338Z +LOCATION: +SEQUENCE:3 +STATUS:CONFIRMED +SUMMARY:LUNCH +TRANSP:OPAQUE +X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:AUTOMATIC +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/status_and_url.ics b/test/test_data/status_and_url.ics new file mode 100644 index 0000000..be26ade --- /dev/null +++ b/test/test_data/status_and_url.ics @@ -0,0 +1,41 @@ +BEGIN:VCALENDAR +BEGIN:VTIMEZONE +TZID:Europe/Berlin +END:VTIMEZONE +BEGIN:VEVENT +DESCRIPTION:Event with Status and URL +SUMMARY:Tentative Event w/ Recurrance to test copy +STATUS:TENTATIVE +DTSTART;VALUE=DATE:20181030 +DTEND;VALUE=DATE:20181031 +RRULE:FREQ=WEEKLY;BYDAY=TU +END:VEVENT +BEGIN:VEVENT +DESCRIPTION:Event with Status and URL +SUMMARY:Confirmed Event +STATUS:CONFIRMED +URL:https://example.com/ +DTSTART;VALUE=DATE:20181030 +DTEND;VALUE=DATE:20181031 +END:VEVENT +BEGIN:VEVENT +DESCRIPTION:Event with Status +SUMMARY:Cancelled Event +STATUS:CANCELLED +DTSTART;VALUE=DATE:20181030 +DTEND;VALUE=DATE:20181031 +END:VEVENT +BEGIN:VEVENT +DESCRIPTION:Event with Status +SUMMARY:XPARAM Event +STATUS;X-SOMETHING=IGNOREME:CANCELLED +DTSTART;VALUE=DATE:20181030 +DTEND;VALUE=DATE:20181031 +END:VEVENT +BEGIN:VEVENT +DESCRIPTION:Event without Status +SUMMARY:Event +DTSTART;VALUE=DATE:20181030 +DTEND;VALUE=DATE:20181031 +END:VEVENT +END:VCALENDAR diff --git a/test/test_data/transparent.ics b/test/test_data/transparent.ics new file mode 100644 index 0000000..b9b66d0 --- /dev/null +++ b/test/test_data/transparent.ics @@ -0,0 +1,63 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +X-WR-CALNAME:Kalender +BEGIN:VTIMEZONE +TZID:Central European Standard Time +BEGIN:STANDARD +DTSTART:16010101T030000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E008000000007BFBACB1614AD701000000000000000 + 0100000004A699A72684F7646A814017A9F145FE8 +SUMMARY:Free +DTSTART;VALUE=DATE:20210520 +DTEND;VALUE=DATE:20210521 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210516T144840Z +TRANSP:TRANSPARENT +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:FREE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:TRUE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +BEGIN:VEVENT +UID:040000008200E00074C5B7101A82E00800000000F7B85AB6614AD701000000000000000 + 01000000005576067F6247C45A572F9B9E56ABB32 +SUMMARY:Busy +DTSTART;TZID=Central European Standard Time:20210521T070000 +DTEND;TZID=Central European Standard Time:20210521T223000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20210516T144840Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +END:VCALENDAR diff --git a/test/test_icaldownload.py b/test/test_icaldownload.py index adbe8f8..09dbc9c 100644 --- a/test/test_icaldownload.py +++ b/test/test_icaldownload.py @@ -6,7 +6,6 @@ class ICalDownloadTests(unittest.TestCase): - def test_apple_data_fix(self): data = """ DTSTART:18831118T120702 @@ -50,7 +49,7 @@ def test_data_from_file_google(self): expected = None - with open(result, mode='r', encoding='utf-8') as f: + with open(result, mode="r", encoding="utf-8") as f: expected = f.read() content = icalevents.icaldownload.ICalDownload().data_from_file(file) @@ -63,10 +62,12 @@ def test_data_from_file_apple(self): expected = None - with open(result, mode='r', encoding='utf-8') as f: + with open(result, mode="r", encoding="utf-8") as f: expected = f.read() - content = icalevents.icaldownload.ICalDownload().data_from_file(file, apple_fix=True) + content = icalevents.icaldownload.ICalDownload().data_from_file( + file, apple_fix=True + ) self.assertEqual(expected, content, "content form iCal file, google format") @@ -93,3 +94,13 @@ def test_read_only_directory(self): os.chdir("..") shutil.rmtree("tmp") + def test_empty_file(self): + empty_ical = "test/test_data/empty.ics" + + with self.assertRaises(IOError) as cm: + icalevents.icaldownload.ICalDownload().data_from_file(empty_ical) + + self.assertEqual( + str(cm.exception), + "File test/test_data/empty.ics is not readable or is empty!", + ) diff --git a/test/test_icalevents.py b/test/test_icalevents.py index 0561271..d54f8b2 100644 --- a/test/test_icalevents.py +++ b/test/test_icalevents.py @@ -3,13 +3,13 @@ from datetime import date, timedelta, datetime from time import sleep from dateutil.relativedelta import relativedelta -from dateutil.tz import UTC +from dateutil.tz import UTC, gettz from re import search class ICalEventsTests(unittest.TestCase): def test_events_url(self): - url = "https://raw.githubusercontent.com/irgangla/icalevents/master/test/test_data/basic.ics" + url = "https://raw.githubusercontent.com/jazzband/icalevents/master/test/test_data/basic.ics" start = date(2017, 5, 18) end = date(2017, 5, 19) @@ -62,11 +62,19 @@ def test_events_recurring(self): e1 = evs[1] self.assertEqual(e1.start.hour, 10, "check time with DST") - self.assertEqual(e1.start.tzinfo.utcoffset(e1.start), timedelta(seconds=7200), "check UTC offset with DST") + self.assertEqual( + e1.start.tzinfo.utcoffset(e1.start), + timedelta(seconds=7200), + "check UTC offset with DST", + ) e2 = evs[2] self.assertEqual(e2.start.hour, 10, "check time without DST") - self.assertEqual(e2.start.tzinfo.utcoffset(e2.start), timedelta(seconds=3600), "check UTC offset without DST") + self.assertEqual( + e2.start.tzinfo.utcoffset(e2.start), + timedelta(seconds=3600), + "check UTC offset without DST", + ) self.assertEqual(e2.start.day, 5, "Check observance of exdate.") @@ -94,18 +102,74 @@ def test_events_all_day_recurring(self): self.assertEqual(len(event_set), 1) self.assertEqual(ev.summary, "Recurring All-day Event") self.assertEqual(ev.description, "All-day event recurring on tuesday each week") - self.assertTrue(ev.all_day, "Recurring All-day Event's first instance is an all-day event") + self.assertTrue( + ev.all_day, "Recurring All-day Event's first instance is an all-day event" + ) start_2nd_instance = date(2018, 11, 6) end_2nd_instance = date(2018, 11, 7) - event_set2 = icalevents.events(url=None, file=ical, start=start_2nd_instance, end=end_2nd_instance) + event_set2 = icalevents.events( + url=None, file=ical, start=start_2nd_instance, end=end_2nd_instance + ) ev_2 = event_set2[0] self.assertEqual(len(event_set2), 1) self.assertEqual(ev_2.summary, "Recurring All-day Event") - self.assertEqual(ev_2.description, "All-day event recurring on tuesday each week") - self.assertTrue(ev_2.all_day, "Recurring All-day Event's second instance is an all-day event") + self.assertEqual( + ev_2.description, "All-day event recurring on tuesday each week" + ) + self.assertTrue( + ev_2.all_day, + "Recurring All-day Event's second instance is an all-day event", + ) + + def test_events_rrule_until_all_day_ms(self): + ical = "test/test_data/rrule_until_all_day_ms.ics" + start = date(2021, 1, 1) + end = date(2022, 1, 1) + + evs = icalevents.events(file=ical, start=start, end=end) + ev_0 = evs[0] + + self.assertEqual( + len(evs), 6, "Seven events and one is excluded" + ) # rrule_until_all_day_ms has one exdate (EXDATE;TZID=W. Europe Standard Time:20210430T000000) + self.assertEqual( + ev_0.start, datetime(2021, 3, 19, 00, 0, 0, tzinfo=gettz("Europe/Berlin")) + ) + self.assertEqual(ev_0.recurring, True, "Recurring all day event") + self.assertEqual(ev_0.summary, "Away") + + def test_events_rrule_until_all_day_google(self): + ical = "test/test_data/rrule_until_all_day_google.ics" + start = date(2021, 1, 1) + end = date(2022, 1, 1) + + evs = icalevents.events(file=ical, start=start, end=end) + ev_2 = evs[2] + + self.assertEqual(len(evs), 3) + self.assertEqual( + ev_2.start, datetime(2021, 3, 24, 00, 0, 0, tzinfo=gettz("Europe/Zurich")) + ) + self.assertEqual(ev_2.all_day, True, "All day event") + self.assertEqual(ev_2.summary, "Busy") + + def test_events_rrule_until_only_date(self): + ical = "test/test_data/rrule_until_only_date.ics" + start = date(2021, 9, 29) + end = date(2021, 10, 19) + evs = icalevents.events(file=ical, start=start, end=end) + self.assertEqual(len(evs), 8) + self.assertEqual( + evs[0].start, + datetime(2021, 9, 29, 13, 0, 0, 0, tzinfo=gettz("America/Boise")), + ) + self.assertEqual( + evs[-1].start, + datetime(2021, 10, 18, 13, 0, 0, 0, tzinfo=gettz("America/Boise")), + ) def test_events_rrule_until(self): ical = "test/test_data/rrule_until.ics" @@ -137,7 +201,9 @@ def test_event_recurring_attribute(self): end = date(2017, 7, 13) ev = icalevents.events(url=None, file=ical, start=start, end=end)[0] - self.assertEqual(ev.recurring, False, "check recurring=False for non recurring event") + self.assertEqual( + ev.recurring, False, "check recurring=False for non recurring event" + ) ical = "test/test_data/recurring.ics" start = date(2018, 10, 15) @@ -147,11 +213,15 @@ def test_event_recurring_attribute(self): e1 = evs[1] e2 = evs[2] - self.assertEqual(e1.recurring, True, "check recurring=True for recurring event (1)") - self.assertEqual(e2.recurring, True, "check recurring=True for recurring event (2)") + self.assertEqual( + e1.recurring, True, "check recurring=True for recurring event (1)" + ) + self.assertEqual( + e2.recurring, True, "check recurring=True for recurring event (2)" + ) def test_events_async_url(self): - url = "https://raw.githubusercontent.com/irgangla/icalevents/master/test/test_data/basic.ics" + url = "https://raw.githubusercontent.com/jazzband/icalevents/master/test/test_data/basic.ics" start = date(2017, 5, 18) end = date(2017, 5, 19) key = "basic" @@ -182,7 +252,15 @@ def test_request_data(self): end = date(2017, 5, 19) key = "basic" - icalevents.request_data(key, url=None, file=ical, string_content=None, start=start, end=end, fix_apple=False) + icalevents.request_data( + key, + url=None, + file=ical, + string_content=None, + start=start, + end=end, + fix_apple=False, + ) self.assertTrue(icalevents.all_done(key), "request is finished") self.assertEqual(len(icalevents.latest_events(key)), 2, "two events are found") @@ -190,15 +268,22 @@ def test_request_data(self): def test_string_data(self): ical = "test/test_data/basic.ics" - with open(ical, mode='rb') as f: + with open(ical, mode="rb") as f: string_content = f.read() start = date(2017, 5, 18) end = date(2017, 5, 19) key = "basic" - icalevents.request_data(key, url=None, file=None, string_content=string_content, start=start, end=end, - fix_apple=False) + icalevents.request_data( + key, + url=None, + file=None, + string_content=string_content, + start=start, + end=end, + fix_apple=False, + ) self.assertTrue(icalevents.all_done(key), "request is finished") self.assertEqual(len(icalevents.latest_events(key)), 2, "two events are found") @@ -213,18 +298,36 @@ def test_event_str(self): evs = icalevents.events(file=ical, start=start, end=end) e1 = evs[0] - self.assertIsNotNone(search(r"ended", str(e1.copy_to(n - relativedelta(days=5) + m))), "stringify past event") - self.assertIsNotNone(search(r"today", str(e1.copy_to(n - relativedelta(days=1) + m))), - "stringify ongoing event") - self.assertIsNotNone(search(r"days left", str(e1.copy_to(n + relativedelta(days=3) + m))), - "stringify future event") + self.assertIsNotNone( + search(r"ended", str(e1.copy_to(n - relativedelta(days=5) + m))), + "stringify past event", + ) + self.assertIsNotNone( + search(r"today", str(e1.copy_to(n - relativedelta(days=1) + m))), + "stringify ongoing event", + ) + self.assertIsNotNone( + search(r"days left", str(e1.copy_to(n + relativedelta(days=3) + m))), + "stringify future event", + ) e2 = evs[1] - self.assertIsNotNone(search(r"ended", str(e2.copy_to(n - relativedelta(hours=5)))), "stringify past event") - self.assertIsNotNone(search(r"now", str(e2.copy_to(n - relativedelta(hours=1)))), "stringify ongoing event") - self.assertIsNotNone(search(r"hours left", str(e2.copy_to(n + relativedelta(hours=3)))), - "stringify future event") - self.assertIsNotNone(search(r"days left", str(e2.copy_to(n + relativedelta(days=3)))), "stringify future event") + self.assertIsNotNone( + search(r"ended", str(e2.copy_to(n - relativedelta(hours=5)))), + "stringify past event", + ) + self.assertIsNotNone( + search(r"now", str(e2.copy_to(n - relativedelta(hours=1)))), + "stringify ongoing event", + ) + self.assertIsNotNone( + search(r"hours left", str(e2.copy_to(n + relativedelta(hours=3)))), + "stringify future event", + ) + self.assertIsNotNone( + search(r"days left", str(e2.copy_to(n + relativedelta(days=3)))), + "stringify future event", + ) def test_events_no_description(self): ical = "test/test_data/no_description.ics" @@ -245,10 +348,14 @@ def test_event_created_last_modified(self): events = icalevents.events(url=None, file=ical, start=start, end=end) self.assertEqual(events[0].created, datetime(2017, 1, 3, 7, 4, 1, tzinfo=UTC)) - self.assertEqual(events[0].last_modified, datetime(2017, 7, 11, 14, 0, 50, tzinfo=UTC)) + self.assertEqual( + events[0].last_modified, datetime(2017, 7, 11, 14, 0, 50, tzinfo=UTC) + ) self.assertEqual(events[1].created, datetime(2017, 1, 4, 8, 4, 1, tzinfo=UTC)) - self.assertEqual(events[1].last_modified, datetime(2017, 1, 4, 8, 4, 1, tzinfo=UTC)) + self.assertEqual( + events[1].last_modified, datetime(2017, 1, 4, 8, 4, 1, tzinfo=UTC) + ) self.assertEqual(events[2].created, None) self.assertEqual(events[2].last_modified, None) @@ -258,5 +365,88 @@ def test_event_categories(self): start = date(2020, 11, 10) end = date(2020, 11, 19) events = icalevents.events(url=None, file=ical, start=start, end=end) - self.assertEqual(events[0].categories, ["In19-S04-IT2403"], "event 1 is not equal") - self.assertEqual(events[1].categories, ["In19-S04-IT2406", "In19-S04-IT2405"], "event 2 is not equal") + self.assertEqual( + events[0].categories, ["In19-S04-IT2403"], "event 1 is not equal" + ) + self.assertEqual( + events[1].categories, + ["In19-S04-IT2406", "In19-S04-IT2405"], + "event 2 is not equal", + ) + + def test_google_timezone(self): + ical = "test/test_data/google_tz.ics" + start = date(2021, 1, 1) + end = date(2021, 12, 31) + + evs = icalevents.events(file=ical, start=start, end=end) + + e1 = evs[0] + self.assertEqual(e1.start.hour, 0, "check start of the day") + self.assertEqual( + e1.start.tzinfo, gettz("Europe/Zurich"), "check tz as specified in calendar" + ) + + def test_ms_timezone(self): + ical = "test/test_data/ms_tz.ics" + start = date(2021, 1, 1) + end = date(2021, 12, 31) + + evs = icalevents.events(file=ical, start=start, end=end) + + e1 = evs[0] + self.assertEqual(e1.start.hour, 0, "check start of the day") + self.assertEqual( + e1.start.tzinfo, gettz("Europe/Berlin"), "check tz as specified in calendar" + ) + + def test_recurence_id_ms(self): + ical = "test/test_data/recurrenceid_ms.ics" + start = date(2021, 1, 1) + end = date(2021, 12, 31) + + evs = icalevents.events(file=ical, start=start, end=end) + + self.assertEqual(len(evs), 41, "41 events in total - one was moved") + + def test_recurence_id_google(self): + ical = "test/test_data/recurrenceid_google.ics" + start = date(2021, 1, 1) + end = date(2021, 12, 31) + + evs = icalevents.events(file=ical, start=start, end=end) + + self.assertEqual(len(evs), 4, "4 events in total") + + def test_cest(self): + ical = "test/test_data/cest.ics" + start = date(2021, 1, 1) + end = date(2021, 12, 31) + + evs = icalevents.events(file=ical, start=start, end=end) + + self.assertEqual(len(evs), 115, "4 events in total") + + def test_transparent(self): + ical = "test/test_data/transparent.ics" + start = date(2021, 1, 1) + end = date(2021, 12, 31) + + [e1, e2] = icalevents.events(file=ical, start=start, end=end) + + self.assertEqual(e1.transparent, True, "respect transparency") + self.assertEqual(e2.transparent, False, "respect opaqueness") + + def test_status_and_url(self): + ical = "test/test_data/status_and_url.ics" + start = date(2018, 10, 30) + end = date(2018, 10, 31) + + [ev1, ev2, ev3, ev4, ev5] = icalevents.events(file=ical, start=start, end=end) + self.assertEqual(ev1.status, "TENTATIVE") + self.assertEqual(ev1.url, None) + self.assertEqual(ev2.status, "CONFIRMED") + self.assertEqual(ev2.url, "https://example.com/") + self.assertEqual(ev3.status, "CANCELLED") + self.assertEqual(ev4.status, "CANCELLED") + self.assertEqual(ev5.status, None) diff --git a/test/test_icalparser.py b/test/test_icalparser.py index fba9710..16ca87f 100644 --- a/test/test_icalparser.py +++ b/test/test_icalparser.py @@ -5,12 +5,15 @@ class ICalParserTests(unittest.TestCase): - def setUp(self): self.eventA = icalevents.icalparser.Event() self.eventA.uid = 1234 - self.eventA.start = datetime(year=2017, month=2, day=3, hour=12, minute=5, tzinfo=UTC) - self.eventA.end = datetime(year=2017, month=2, day=3, hour=15, minute=5, tzinfo=UTC) + self.eventA.start = datetime( + year=2017, month=2, day=3, hour=12, minute=5, tzinfo=UTC + ) + self.eventA.end = datetime( + year=2017, month=2, day=3, hour=15, minute=5, tzinfo=UTC + ) self.eventA.all_day = False self.eventA.summary = "Event A" self.eventA.attendee = "name@example.com" @@ -18,15 +21,19 @@ def setUp(self): self.eventB = icalevents.icalparser.Event() self.eventB.uid = 1234 - self.eventB.start = datetime(year=2017, month=2, day=1, hour=15, minute=5, tzinfo=UTC) - self.eventB.end = datetime(year=2017, month=2, day=1, hour=16, minute=5, tzinfo=UTC) + self.eventB.start = datetime( + year=2017, month=2, day=1, hour=15, minute=5, tzinfo=UTC + ) + self.eventB.end = datetime( + year=2017, month=2, day=1, hour=16, minute=5, tzinfo=UTC + ) self.eventB.all_day = False self.eventB.summary = "Event B" self.eventB.attendee = ["name@example.com", "another@example.com"] self.eventB.organizer = "name@example.com" self.dtA = datetime(2018, 6, 21, 12) - self.dtB = datetime(2018, 6, 21, 12, tzinfo=gettz('Europe/Berlin')) + self.dtB = datetime(2018, 6, 21, 12, tzinfo=gettz("Europe/Berlin")) def test_now(self): n = icalevents.icalparser.now() @@ -47,16 +54,24 @@ def test_event_copy_to(self): self.assertNotEqual(eventC.uid, self.eventA.uid, "new event has new UID") self.assertEqual(eventC.start, new_start, "new event has new start") - self.assertEqual(eventC.end - eventC.start, self.eventA.end - self.eventA.start, "new event has same duration") + self.assertEqual( + eventC.end - eventC.start, + self.eventA.end - self.eventA.start, + "new event has same duration", + ) self.assertEqual(eventC.all_day, False, "new event is no all day event") self.assertEqual(eventC.summary, self.eventA.summary, "copy to: summary") - self.assertEqual(eventC.description, self.eventA.description, "copy to: description") + self.assertEqual( + eventC.description, self.eventA.description, "copy to: description" + ) eventD = eventC.copy_to(uid=new_uid) self.assertEqual(eventD.uid, new_uid, "new event has specified UID") self.assertEqual(eventD.start, eventC.start, "new event has same start") self.assertEqual(eventD.end, eventC.end, "new event has same end") - self.assertEqual(eventD.all_day, eventC.all_day, "new event is no all day event") + self.assertEqual( + eventD.all_day, eventC.all_day, "new event is no all day event" + ) self.assertEqual(eventD.summary, eventC.summary, "copy to: summary") self.assertEqual(eventD.description, eventC.description, "copy to: description") @@ -100,8 +115,8 @@ def test_attendee(self): def test_organizer(self): self.assertIsInstance(self.eventA.organizer, str) self.assertIsInstance(self.eventB.organizer, str) - + def test_str(self): self.eventA.start = datetime(year=2017, month=2, day=3, hour=12, minute=5) self.eventA.end = datetime(year=2017, month=2, day=3, hour=15, minute=5) - self.assertEqual('2017-02-03 12:05:00+00:00: Event A (ended)', str(self.eventA)) + self.assertEqual("2017-02-03 12:05:00+00:00: Event A (ended)", str(self.eventA))