aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/sabre/vobject
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sabre/vobject')
-rw-r--r--vendor/sabre/vobject/.gitignore17
-rw-r--r--vendor/sabre/vobject/.travis.yml23
-rw-r--r--vendor/sabre/vobject/CHANGELOG.md739
-rw-r--r--vendor/sabre/vobject/ChangeLog88
-rw-r--r--vendor/sabre/vobject/LICENSE2
-rw-r--r--vendor/sabre/vobject/README.md375
-rwxr-xr-xvendor/sabre/vobject/bin/bench.php4
-rw-r--r--vendor/sabre/vobject/bin/bench_freebusygenerator.php62
-rw-r--r--vendor/sabre/vobject/bin/bench_manipulatevcard.php69
-rwxr-xr-xvendor/sabre/vobject/bin/fetch_windows_zones.php51
-rwxr-xr-xvendor/sabre/vobject/bin/generate_vcards241
-rwxr-xr-xvendor/sabre/vobject/bin/generateicalendardata.php41
-rwxr-xr-xvendor/sabre/vobject/bin/mergeduplicates.php184
-rw-r--r--vendor/sabre/vobject/bin/rrulebench.php32
-rwxr-xr-xvendor/sabre/vobject/bin/vobject27
-rwxr-xr-xvendor/sabre/vobject/bin/vobjectvalidate.php139
-rw-r--r--vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php191
-rw-r--r--vendor/sabre/vobject/lib/Cli.php771
-rw-r--r--vendor/sabre/vobject/lib/Component.php700
-rw-r--r--vendor/sabre/vobject/lib/Component/Available.php126
-rw-r--r--vendor/sabre/vobject/lib/Component/VAlarm.php (renamed from vendor/sabre/vobject/lib/Sabre/VObject/Component/VAlarm.php)76
-rw-r--r--vendor/sabre/vobject/lib/Component/VAvailability.php156
-rw-r--r--vendor/sabre/vobject/lib/Component/VCalendar.php561
-rw-r--r--vendor/sabre/vobject/lib/Component/VCard.php553
-rw-r--r--vendor/sabre/vobject/lib/Component/VEvent.php153
-rw-r--r--vendor/sabre/vobject/lib/Component/VFreeBusy.php102
-rw-r--r--vendor/sabre/vobject/lib/Component/VJournal.php107
-rw-r--r--vendor/sabre/vobject/lib/Component/VTimeZone.php67
-rw-r--r--vendor/sabre/vobject/lib/Component/VTodo.php193
-rw-r--r--vendor/sabre/vobject/lib/DateTimeParser.php571
-rw-r--r--vendor/sabre/vobject/lib/Document.php270
-rw-r--r--vendor/sabre/vobject/lib/ElementList.php54
-rw-r--r--vendor/sabre/vobject/lib/EofException.php15
-rw-r--r--vendor/sabre/vobject/lib/FreeBusyData.php193
-rw-r--r--vendor/sabre/vobject/lib/FreeBusyGenerator.php604
-rw-r--r--vendor/sabre/vobject/lib/ITip/Broker.php989
-rw-r--r--vendor/sabre/vobject/lib/ITip/ITipException.php15
-rw-r--r--vendor/sabre/vobject/lib/ITip/Message.php141
-rw-r--r--vendor/sabre/vobject/lib/ITip/SameOrganizerForAllComponentsException.php18
-rw-r--r--vendor/sabre/vobject/lib/InvalidDataException.php14
-rw-r--r--vendor/sabre/vobject/lib/Node.php265
-rw-r--r--vendor/sabre/vobject/lib/PHPUnitAssertions.php82
-rw-r--r--vendor/sabre/vobject/lib/Parameter.php394
-rw-r--r--vendor/sabre/vobject/lib/ParseException.php13
-rw-r--r--vendor/sabre/vobject/lib/Parser/Json.php197
-rw-r--r--vendor/sabre/vobject/lib/Parser/MimeDir.php696
-rw-r--r--vendor/sabre/vobject/lib/Parser/Parser.php80
-rw-r--r--vendor/sabre/vobject/lib/Parser/XML.php428
-rw-r--r--vendor/sabre/vobject/lib/Parser/XML/Element/KeyValue.php70
-rw-r--r--vendor/sabre/vobject/lib/Property.php662
-rw-r--r--vendor/sabre/vobject/lib/Property/Binary.php128
-rw-r--r--vendor/sabre/vobject/lib/Property/Boolean.php84
-rw-r--r--vendor/sabre/vobject/lib/Property/FlatText.php50
-rw-r--r--vendor/sabre/vobject/lib/Property/FloatValue.php142
-rw-r--r--vendor/sabre/vobject/lib/Property/ICalendar/CalAddress.php61
-rw-r--r--vendor/sabre/vobject/lib/Property/ICalendar/Date.php18
-rw-r--r--vendor/sabre/vobject/lib/Property/ICalendar/DateTime.php404
-rw-r--r--vendor/sabre/vobject/lib/Property/ICalendar/Duration.php85
-rw-r--r--vendor/sabre/vobject/lib/Property/ICalendar/Period.php155
-rw-r--r--vendor/sabre/vobject/lib/Property/ICalendar/Recur.php293
-rw-r--r--vendor/sabre/vobject/lib/Property/IntegerValue.php88
-rw-r--r--vendor/sabre/vobject/lib/Property/Text.php413
-rw-r--r--vendor/sabre/vobject/lib/Property/Time.php144
-rw-r--r--vendor/sabre/vobject/lib/Property/Unknown.php44
-rw-r--r--vendor/sabre/vobject/lib/Property/Uri.php122
-rw-r--r--vendor/sabre/vobject/lib/Property/UtcOffset.php77
-rw-r--r--vendor/sabre/vobject/lib/Property/VCard/Date.php43
-rw-r--r--vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php405
-rw-r--r--vendor/sabre/vobject/lib/Property/VCard/DateTime.php30
-rw-r--r--vendor/sabre/vobject/lib/Property/VCard/LanguageTag.php60
-rw-r--r--vendor/sabre/vobject/lib/Property/VCard/TimeStamp.php86
-rw-r--r--vendor/sabre/vobject/lib/Reader.php98
-rw-r--r--vendor/sabre/vobject/lib/Recur/EventIterator.php507
-rw-r--r--vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php16
-rw-r--r--vendor/sabre/vobject/lib/Recur/NoInstancesException.php18
-rw-r--r--vendor/sabre/vobject/lib/Recur/RDateIterator.php182
-rw-r--r--vendor/sabre/vobject/lib/Recur/RRuleIterator.php921
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Component.php405
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Component/VCalendar.php244
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Component/VCard.php107
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Component/VEvent.php70
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Component/VFreeBusy.php68
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Component/VJournal.php46
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Component/VTodo.php68
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/DateTimeParser.php181
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Document.php109
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/ElementList.php172
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/FreeBusyGenerator.php322
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Node.php187
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Parameter.php104
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/ParseException.php12
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Property.php444
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Property/Compound.php125
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Property/DateTime.php245
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Property/MultiDateTime.php180
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Reader.php223
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/RecurrenceIterator.php1144
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/StringUtil.php61
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/TimeZoneUtil.php527
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/Version.php24
-rw-r--r--vendor/sabre/vobject/lib/Sabre/VObject/includes.php41
-rw-r--r--vendor/sabre/vobject/lib/Settings.php56
-rw-r--r--vendor/sabre/vobject/lib/Splitter/ICalendar.php (renamed from vendor/sabre/vobject/lib/Sabre/VObject/Splitter/ICalendar.php)50
-rw-r--r--vendor/sabre/vobject/lib/Splitter/SplitterInterface.php (renamed from vendor/sabre/vobject/lib/Sabre/VObject/Splitter/SplitterInterface.php)10
-rw-r--r--vendor/sabre/vobject/lib/Splitter/VCard.php (renamed from vendor/sabre/vobject/lib/Sabre/VObject/Splitter/VCard.php)46
-rw-r--r--vendor/sabre/vobject/lib/StringUtil.php66
-rw-r--r--vendor/sabre/vobject/lib/TimeZoneUtil.php266
-rw-r--r--vendor/sabre/vobject/lib/UUIDUtil.php69
-rw-r--r--vendor/sabre/vobject/lib/VCardConverter.php467
-rw-r--r--vendor/sabre/vobject/lib/Version.php19
-rw-r--r--vendor/sabre/vobject/lib/Writer.php81
-rw-r--r--vendor/sabre/vobject/lib/timezonedata/exchangezones.php93
-rw-r--r--vendor/sabre/vobject/lib/timezonedata/lotuszones.php101
-rw-r--r--vendor/sabre/vobject/lib/timezonedata/php-bc.php154
-rw-r--r--vendor/sabre/vobject/lib/timezonedata/php-workaround.php46
-rw-r--r--vendor/sabre/vobject/lib/timezonedata/windowszones.php119
-rw-r--r--vendor/sabre/vobject/resources/schema/xcal.rng1192
-rw-r--r--vendor/sabre/vobject/resources/schema/xcard.rng388
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Component/VAlarmTest.php175
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Component/VCalendarTest.php244
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Component/VCardTest.php100
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Component/VEventTest.php74
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Component/VFreeBusyTest.php39
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Component/VJournalTest.php41
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Component/VTodoTest.php67
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/ComponentTest.php413
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/DateTimeParserTest.php153
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/DocumentTest.php26
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/ElementListTest.php32
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/EmClientTest.php55
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/FreeBusyGeneratorTest.php246
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Issue153Test.php14
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Issue154Test.php29
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Issue48Test.php47
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Issue50Test.php128
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/ParameterTest.php44
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Property/CompoundTest.php59
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Property/DateTimeTest.php240
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Property/MultiDateTimeTest.php208
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/PropertyTest.php324
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/ReaderTest.php367
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorFifthTuesdayProblemTest.php44
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorIncorrectExpandTest.php62
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorInfiniteLoopProblemTest.php91
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMinusOneProblemTest.php30
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMissingOverriddenTest.php63
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorTest.php1425
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/SlashRTest.php19
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Splitter/ICalendarTest.php283
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/Splitter/VCardTest.php138
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/StringUtilTest.php59
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/TimeZoneUtilTest.php306
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/VersionTest.php17
-rw-r--r--vendor/sabre/vobject/tests/Sabre/VObject/issue153.vcf352
-rw-r--r--vendor/sabre/vobject/tests/bootstrap.php18
-rw-r--r--vendor/sabre/vobject/tests/phpunit.xml14
156 files changed, 18858 insertions, 11815 deletions
diff --git a/vendor/sabre/vobject/.gitignore b/vendor/sabre/vobject/.gitignore
index a46b19e2a..95935f798 100644
--- a/vendor/sabre/vobject/.gitignore
+++ b/vendor/sabre/vobject/.gitignore
@@ -2,3 +2,20 @@
vendor/
composer.lock
tests/cov/
+tests/temp
+
+#vim
+.*.swp
+
+#binaries
+bin/phpunit
+bin/phpcs
+bin/php-cs-fixer
+bin/sabre-cs-fixer
+bin/hoa
+
+# Development stuff
+testdata/
+
+# OS X
+.DS_Store
diff --git a/vendor/sabre/vobject/.travis.yml b/vendor/sabre/vobject/.travis.yml
index 5bd15086d..06bbdf8a0 100644
--- a/vendor/sabre/vobject/.travis.yml
+++ b/vendor/sabre/vobject/.travis.yml
@@ -1,17 +1,24 @@
language: php
php:
- - 5.3
- - 5.4
- 5.5
- - 5.5.9
- - 5.5.10
- 5.6
+ - 7
+ - hhvm
+
+sudo: false
matrix:
allow_failures:
- - php: 5.5.10
- - php: 5.6
+ - php: hhvm
+
+script:
+ - phpunit --configuration tests/phpunit.xml
+ - ./bin/sabre-cs-fixer fix . --dry-run --diff
-script: phpunit --configuration tests/phpunit.xml
+before_script:
+ - phpenv config-rm xdebug.ini; true
+ - composer install
-before_script: composer install
+cache:
+ directories:
+ - $HOME/.composer/cache
diff --git a/vendor/sabre/vobject/CHANGELOG.md b/vendor/sabre/vobject/CHANGELOG.md
new file mode 100644
index 000000000..0bd7d53bd
--- /dev/null
+++ b/vendor/sabre/vobject/CHANGELOG.md
@@ -0,0 +1,739 @@
+ChangeLog
+=========
+
+
+4.1.0 (2016-04-06)
+------------------
+
+* #309: When expanding recurring events, the first event should also have a
+ `RECURRENCE-ID` property.
+* #306: iTip REPLYs to the first instance of a recurring event was not handled
+ correctly.
+* Slightly better error message during validation of `N` and `ADR` properties.
+* #312: Correctly extracing timezone in the iTip broker, even when we don't
+ have a master event. (@vkomrakov-sugar).
+* When validating a component's property that must appear once and which could
+ automatically be repaired, make sure we report the change as 'repaired'.
+* Added a PHPUnitAssertions trait. This trait makes it easy to compare two
+ vcards or iCalendar objects semantically.
+* Better error message when parsing objects with an invalid `VALUE` parameter.
+
+
+4.0.3 (2016-03-12)
+------------------
+
+* #300: Added `VCard::getByType()` to quickly get a property with a specific
+ `TYPE` parameter. (@kbond)
+* #302: `UNTIL` was not encoded correctly when converting to jCal.
+ (@GrahamLinagora)
+* #303: `COUNT` is now encoded as an int in jCal instead of a string. (@strokyl)
+* #295: `RRULE` now has more validation and repair rules.
+
+
+4.0.2 (2016-01-11)
+------------------
+
+* #288: Only decode `CHARSET` if we're reading vCard 2.1. If it appears
+ in any other document, we must ignore it.
+
+
+4.0.1 (2016-01-04)
+------------------
+
+* #284: When generating `CANCEL` iTip messages, we now include `DTEND`.
+ (@kewisch)
+
+
+4.0.0 (2015-12-11)
+------------------
+
+* #274: When creating new vCards, the default vCard version is now 4.0.
+* #275: `VEVENT`, `VTODO` and `VCARD` now automatically get a `UID` and
+ `DTSTAMP` property if this was not already specified.
+* `ParseException` now extends `\Exception`.
+* `Sabre\VObject\Reader::read` now has a `$charset` argument.
+* #272: `Sabre\VObject\Recur\EventIterator::$maxInstances` is now
+ `Sabre\VObject\Settings::$maxRecurrences` and is also honored by the
+ FreeBusyGenerator.
+* #278: `expand()` did not work correctly on events with sub-components.
+
+
+4.0.0-beta1 (2015-12-02)
+------------------------
+
+* #258: Support for expanding events that use `RDATE`. (@jabdoa2)
+* #258: Correctly support TZID for events that use `RDATE`. (@jabdoa2)
+* #240: `Component\VCalendar::expand()` now returns a new expanded `VCalendar`
+ object, instead of editing the existing `VCalendar` in-place. This is a BC
+ break.
+* #265: Using the new `InvalidDataException` in place of
+ `InvalidArgumentException` and `LogicException` in all places where we fail
+ because there was something wrong with input data.
+* #227: Always add `VALUE=URI` to `PHOTO` properties.
+* #235: Always add `VALUE=URI` to `URL` properties.
+* It's now possible to override which class is used instead of
+ `Component\VCalendar` or `Component\VCard` during parsing.
+* #263: Lots of small cleanups. (@jakobsack)
+* #220: Automatically stop recurring after 3500 recurrences.
+* #41: Allow user to set different encoding than UTF-8 when decoding vCards.
+* #41: Support the `ENCODING` parameter from vCard 2.1.
+ Both ISO-8859-1 and Windows-1252 are currently supported.
+* #185: Fix encoding/decoding of `TIME` values in jCal/jCard.
+
+
+4.0.0-alpha2 (2015-09-04)
+-------------------------
+
+* Updated windows timezone file to support new mexican timezone.
+* #239: Added a `BirthdayCalendarGenerator`. (@DominikTo)
+* #250: `isInTimeRange()` now considers the timezone for floating dates and
+ times. (@armin-hackmann)
+* Added a duplicate vcard merging tool for the command line.
+* #253: `isInTimeRange()` now correctly handles events that throw the
+ `NoInstancesException` exception. (@migrax, @DominikTo)
+* #254: The parser threw an `E_NOTICE` for certain invalid objects. It now
+ correctly throws a `ParseException`.
+
+
+4.0.0-alpha1 (2015-07-17)
+-------------------------
+
+* sabre/vobject now requires PHP 5.5.
+* #244: PHP7 support.
+* Lots of speedups and reduced memory usage!
+* #160: Support for xCal a.k.a. RFC6321! (@Hywan)
+* #192: Support for xCard a.k.a. RFC6351! (@Hywan)
+* #139: We now accept `DateTimeInterface` wherever it accepted `DateTime`
+ before in arguments. This means that either `DateTime` or
+ `DateTimeImmutable` may be used everywhere.
+* #242: Full support for the `VAVAILABILITY` component, and calculating
+ `VFREEBUSY` based on `VAVAILABILITY` data.
+* #186: Fixing conversion of `UTC-OFFSET` properties when going back and
+ forward between jCal and iCalendar.
+* Properties, Components and Parameters now implement PHP's `JsonSerializable`
+ interface.
+* #139: We now _always_ return `DateTimeImmutable` from any method. This could
+ potentially have big implications if you manipulate Date objects anywhere.
+* #161: Simplified `ElementList` by extending `ArrayIterator`.
+* Removed `RecurrenceIterator` (use Recur\EventIterator instead).
+* Now using php-cs-fixer to automatically enforce and correct CS.
+* #233: The `+00:00` timezone is now recognized as UTC. (@c960657)
+* #237: Added a `destroy()` method to all documents. This method breaks any
+ circular references, allowing PHP to free up memory.
+* #197: Made accessing properties and objects by their name a lot faster. This
+ especially helps objects that have a lot of sub-components or properties,
+ such as large iCalendar objects.
+* #197: The `$children` property on components has been changed from `public`
+ to `protected`. Use the `children()` method instead to get a flat list of
+ objects.
+* #244: The `Float` and `Integer` classes have been renamed to `FloatValue`
+ and `IntegerValue` to allow PHP 7 compatibility.
+
+
+3.5.1 (2016-04-06)
+------------------
+
+* #309: When expanding recurring events, the first event should also have a
+ `RECURRENCE-ID` property.
+* #306: iTip REPLYs to the first instance of a recurring event was not handled
+ correctly.
+
+
+3.5.0 (2016-01-11)
+------------------
+
+* This release supports PHP 7, contrary to 3.4.x versions.
+* BC Break: `Sabre\VObject\Property\Float` has been renamed to
+ `Sabre\VObject\Property\FloatValue`.
+* BC Break: `Sabre\VObject\Property\Integer` has been renamed to
+ `Sabre\VObject\Property\IntegerValue`.
+
+
+3.4.9 (2016-01-11)
+------------------
+
+* This package now specifies in composer.json that it does not support PHP 7.
+ For PHP 7, use version 3.5.x or 4.x.
+
+
+3.4.8 (2016-01-04)
+------------------
+
+* #284: When generating `CANCEL` iTip messages, we now include `DTEND`.
+ (@kewisch).
+
+
+3.4.7 (2015-09-05)
+------------------
+
+* #253: Handle `isInTimeRange` for recurring events that have 0 valid
+ instances. (@DominikTo, @migrax).
+
+
+3.4.6 (2015-08-06)
+------------------
+
+* #250: Recurring all-day events are incorrectly included in time range
+ requests when not using UTC in the time range. (@armin-hackmann)
+
+
+3.4.5 (2015-06-02)
+------------------
+
+* #229: Converting vcards from 3.0 to 4.0 that contained a `LANG` property
+ would throw an error.
+
+
+3.4.4 (2015-05-27)
+------------------
+
+* #228: Fixed a 'party crasher' bug in the iTip broker. This would break
+ scheduling in some cases.
+
+
+3.4.3 (2015-05-19)
+------------------
+
+* #219: Corrected validation of `EXDATE` properties with more than one value.
+* #212: `BYSETPOS` with values below `-1` was broken and could cause infinite
+ loops.
+* #211: Fix `BYDAY=-5TH` in recurrence iterator. (@lindquist)
+* #216: `ENCODING` parameter is now validated for all document types.
+* #217: Initializing vCard `DATE` objects with a PHP DateTime object will now
+ work correctly. (@thomascube)
+
+
+3.4.2 (2015-02-25)
+------------------
+
+* #210: iTip: Replying to an event without a master event was broken.
+
+
+3.4.1 (2015-02-24)
+------------------
+
+* A minor change to ensure that unittests work correctly in the sabre/dav
+ test-suite.
+
+
+3.4.0 (2015-02-23)
+------------------
+
+* #196: Made parsing recurrence rules a lot faster on big calendars.
+* Updated windows timezone mappings to latest unicode version.
+* #202: Support for parsing and validating `VAVAILABILITY` components. (@Hywan)
+* #195: PHP 5.3 compatibility in 'generatevcards' script. (@rickdenhaan)
+* #205: Improving handling of multiple `EXDATE` when processing iTip changes.
+ (@armin-hackmann)
+* #187: Fixed validator rules for `LAST-MODIFIED` properties.
+* #188: Retain floating times when generating instances using
+ `Recur\EventIterator`.
+* #203: Skip tests for timezones that are not supported on older PHP versions,
+ instead of a hard fail.
+* #204: Dealing a bit better with vCard date-time values that contained
+ milliseconds. (which is normally invalid). (@armin-hackmann)
+
+
+3.3.5 (2015-01-09)
+------------------
+
+* #168: Expanding calendars now removes objects with recurrence rules that
+ don't have a valid recurrence instance.
+* #177: SCHEDULE-STATUS should not contain a reason phrase, only a status
+ code.
+* #175: Parser can now read and skip the UTF-8 BOM.
+* #179: Added `isFloating` to `DATE-TIME` properties.
+* #179: Fixed jCal serialization of floating `DATE-TIME` properties.
+* #173: vCard converter failed for `X-ABDATE` properties that had no
+ `X-ABLABEL`.
+* #180: Added `PROFILE_CALDAV` and `PROFILE_CARDDAV` to enable validation rules
+ specific for CalDAV/CardDAV servers.
+* #176: A missing `UID` is no longer an error, but a warning for the vCard
+ validator, unless `PROFILE_CARDDAV` is specified.
+
+
+3.3.4 (2014-11-19)
+------------------
+
+* #154: Converting `ANNIVERSARY` to `X-ANNIVERSARY` and `X-ABDATE` and
+ vice-versa when converting to/from vCard 4.
+* #154: It's now possible to easily select all vCard properties belonging to
+ a single group with `$vcard->{'ITEM1.'}` syntax. (@armin-hackmann)
+* #156: Simpler way to check if a string is UTF-8. (@Hywan)
+* Unittest improvements.
+* #159: The recurrence iterator, freebusy generator and iCalendar DATE and
+ DATE-TIME properties can now all accept a reference timezone when working
+ floating times or all-day events.
+* #159: Master events will no longer get a `RECURRENCE-ID` when expanding.
+* #159: `RECURRENCE-ID` for all-day events will now be correct when expanding.
+* #163: Added a `getTimeZone()` method to `VTIMEZONE` components.
+
+
+3.3.3 (2014-10-09)
+------------------
+
+* #142: `CANCEL` and `REPLY` messages now include the `DTSTART` from the
+ original event.
+* #143: `SCHEDULE-AGENT` on the `ORGANIZER` property is respected.
+* #144: `PARTSTAT=NEEDS-ACTION` is now set for new invites, if no `PARTSTAT` is
+ set to support the inbox feature of iOS.
+* #147: Bugs related to scheduling all-day events.
+* #148: Ignore events that have attendees but no organizer.
+* #149: Avoiding logging errors during timezone detection. This is a workaround
+ for a PHP bug.
+* Support for "Line Islands Standard Time" windows timezone.
+* #154: Correctly work around vCard parameters that have a value but no name.
+
+
+3.3.2 (2014-09-19)
+------------------
+
+* Changed: iTip broker now sets RSVP status to false when replies are received.
+* #118: iTip Message now has a `getScheduleStatus()` method.
+* #119: Support for detecting 'significant changes'.
+* #120: Support for `SCHEDULE-FORCE-SEND`.
+* #121: iCal demands parameters containing the + sign to be quoted.
+* #122: Don't generate REPLY messages for events that have been cancelled.
+* #123: Added `SUMMARY` to iTip messages.
+* #130: Incorrect validation rules for `RELATED` (should be `RELATED-TO`).
+* #128: `ATTACH` in iCalendar is `URI` by default, not `BINARY`.
+* #131: RRULE that doesn't provide a single valid instance now throws an
+ exception.
+* #136: Validator rejects *all* control characters. We were missing a few.
+* #133: Splitter objects will throw exceptions when receiving incompatible
+ objects.
+* #127: Attendees who delete recurring event instances events they had already
+ declined earlier will no longer generate another reply.
+* #125: Send CANCEL messages when ORGANIZER property gets deleted.
+
+
+3.3.1 (2014-08-18)
+------------------
+
+* Changed: It's now possible to pass DateTime objects when using the magic
+ setters on properties. (`$event->DTSTART = new DateTime('now')`).
+* #111: iTip Broker does not process attendee adding events to EXDATE.
+* #112: EventIterator now sets TZID on RECURRENCE-ID.
+* #113: Timezone support during creation of iTip REPLY messages.
+* #114: VTIMEZONE is retained when generating new REQUEST objects.
+* #114: Support for 'MAILTO:' style email addresses (in uppercase) in the iTip
+ broker. This improves evolution support.
+* #115: Using REQUEST-STATUS from REPLY messages and now propegating that into
+ SCHEDULE-STATUS.
+
+
+3.3.0 (2014-08-07)
+------------------
+
+* We now use PSR-4 for the directory structure. This means that everything
+ that was used to be in the `lib/Sabre/VObject` directory is now moved to
+ `lib/`. If you use composer to load this library, you shouldn't have to do
+ anything about that though.
+* VEVENT now get populated with a DTSTAMP and UID property by default.
+* BC Break: Removed the 'includes.php' file. Use composer instead.
+* #103: Added support for processing [iTip][iTip] messages. This allows a user
+ to parse incoming iTip messages and apply the result on existing calendars,
+ or automatically generate invites/replies/cancellations based on changes that
+ a user made on objects.
+* #75, #58, #18: Fixes related to overriding the first event in recurrences.
+* Added: VCalendar::getBaseComponent to find the 'master' component in a
+ calendar.
+* #51: Support for iterating RDATE properties.
+* Fixed: Issue #101: RecurrenceIterator::nextMonthly() shows events that are
+ excluded events with wrong time
+
+
+3.2.4 (2014-07-14)
+------------------
+
+* Added: Issue #98. The VCardConverter now takes `X-APPLE-OMIT-YEAR` into
+ consideration when converting between vCard 3 and 4.
+* Fixed: Issue #96. Some support for Yahoo's broken vcards.
+* Fixed: PHP 5.3 support was broken in the cli tool.
+
+
+3.2.3 (2014-06-12)
+------------------
+
+* Validator now checks if DUE and DTSTART are of the same type in VTODO, and
+ ensures that DUE is always after DTSTART.
+* Removed documentation from source repository, to http://sabre.io/vobject/
+* Expanded the vobject cli tool validation output to make it easier to find
+ issues.
+* Fixed: vobject repair. It was not working for iCalendar objects.
+
+
+3.2.2 (2014-05-07)
+------------------
+
+* Minor tweak in unittests to make it run on PHP 5.5.12. Json-prettifying
+ slightly changed which caused the test to fail.
+
+
+3.2.1 (2014-05-03)
+------------------
+
+* Minor tweak to make the unittests run with the latest hhvm on travis.
+* Updated timezone definitions.
+* Updated copyright links to point to http://sabre.io/
+
+
+3.2.0 (2014-04-02)
+------------------
+
+* Now hhvm compatible!
+* The validator can now detect a _lot_ more problems. Many rules for both
+ iCalendar and vCard were added.
+* Added: bin/generate_vcards, a utility to generate random vcards for testing
+ purposes. Patches are welcome to add more data.
+* Updated: Windows timezone mapping to latest version from unicode.org
+* Changed: The timezone maps are now loaded in from external files, in
+ lib/Sabre/VObject/timezonedata.
+* Added: Fixing badly encoded URL's from google contacts vcards.
+* Fixed: Issue #68. Couldn't decode properties ending in a colon.
+* Fixed: Issue #72. RecurrenceIterator should respect timezone in the UNTIL
+ clause.
+* Fixed: Issue #67. BYMONTH limit on DAILY recurrences.
+* Fixed: Issue #26. Return a more descriptive error when coming across broken
+ BYDAY rules.
+* Fixed: Issue #28. Incorrect timezone detection for some timezones.
+* Fixed: Issue #70. Casting a parameter with a null value to string would fail.
+* Added: Support for rfc6715 and rfc6474.
+* Added: Support for DateTime objects in the VCard DATE-AND-OR-TIME property.
+* Added: UUIDUtil, for easily creating unique identifiers.
+* Fixed: Issue #83. Creating new VALUE=DATE objects using php's DateTime.
+* Fixed: Issue #86. Don't go into an infinite loop when php errors are
+ disabled and an invalid file is read.
+
+
+3.1.4 (2014-03-30)
+------------------
+
+* Fixed: Issue #87: Several compatibility fixes related to timezone handling
+ changes in PHP 5.5.10.
+
+
+3.1.3 (2013-10-02)
+------------------
+
+* Fixed: Support from properties from draft-daboo-valarm-extensions-04. Issue
+ #56.
+* Fixed: Issue #54. Parsing a stream of multiple vcards separated by more than
+ one newline. Thanks @Vedmak for the patch.
+* Fixed: Serializing vcard 2.1 parameters with no name caused a literal '1' to
+ be inserted.
+* Added: VCardConverter removed properties that are no longer supported in vCard
+ 4.0.
+* Added: vCards with a minimum number of values (such as N), but don't have that
+ many, are now automatically padded with empty components.
+* Added: The vCard validator now also checks for a minimum number of components,
+ and has the ability to repair these.
+* Added: Some support for vCard 2.1 in the VCard converter, to upgrade to vCard
+ 3.0 or 4.0.
+* Fixed: Issue 60 Use Document::$componentMap when instantiating the top-level
+ VCalendar and VCard components.
+* Fixed: Issue 62: Parsing iCalendar parameters with no value.
+* Added: --forgiving option to vobject utility.
+* Fixed: Compound properties such as ADR were not correctly split up in vCard
+ 2.1 quoted printable-encoded properties.
+* Fixed: Issue 64: Encoding of binary properties of converted vCards. Thanks
+ @DominikTo for the patch.
+
+
+3.1.2 (2013-08-13)
+------------------
+
+* Fixed: Setting correct property group on VCard conversion
+
+
+3.1.1 (2013-08-02)
+------------------
+
+* Fixed: Issue #53. A regression in RecurrenceIterator.
+
+
+3.1.0 (2013-07-27)
+------------------
+
+* Added: bad-ass new cli debugging utility (in bin/vobject).
+* Added: jCal and jCard parser.
+* Fixed: URI properties should not escape ; and ,.
+* Fixed: VCard 4 documents now correctly use URI as a default value-type for
+ PHOTO and others. BINARY no longer exists in vCard 4.
+* Added: Utility to convert between 2.1, 3.0 and 4.0 vCards.
+* Added: You can now add() multiple parameters to a property in one call.
+* Added: Parameter::has() for easily checking if a parameter value exists.
+* Added: VCard::preferred() to find a preferred email, phone number, etc for a
+ contact.
+* Changed: All $duration properties are now public.
+* Added: A few validators for iCalendar documents.
+* Fixed: Issue #50. RecurrenceIterator gives incorrect result when exception
+ events are out of order in the iCalendar file.
+* Fixed: Issue #48. Overridden events in the recurrence iterator that were past
+ the UNTIL date were ignored.
+* Added: getDuration for DURATION values such as TRIGGER. Thanks to
+ @SimonSimCity.
+* Fixed: Issue #52. vCard 2.1 parameters with no name may lose values if there's
+ more than 1. Thanks to @Vedmak.
+
+
+3.0.0 (2013-06-21)
+------------------
+
+* Fixed: includes.php file was still broken. Our tool to generate it had some
+ bugs.
+
+
+3.0.0-beta4 (2013-06-21)
+------------------------
+
+* Fixed: includes.php was no longer up to date.
+
+
+3.0.0-beta3 (2013-06-17)
+------------------------
+
+* Added: OPTION_FORGIVING now also allows slashes in property names.
+* Fixed: DateTimeParser no longer fails on dates with years < 1000 & > 4999
+* Fixed: Issue 36: Workaround for the recurrenceiterator and caldav events with
+ a missing base event.
+* Fixed: jCard encoding of TIME properties.
+* Fixed: jCal encoding of REQUEST-STATUS, GEO and PERIOD values.
+
+
+3.0.0-beta2 (2013-06-10)
+------------------------
+
+* Fixed: Corrected includes.php file.
+* Fixed: vCard date-time parser supported extended-format dates as well.
+* Changed: Properties have been moved to an ICalendar or VCard directory.
+* Fixed: Couldn't parse vCard 3 extended format dates and times.
+* Fixed: Couldn't export jCard DATE values correctly.
+* Fixed: Recursive loop in ICalendar\DateTime property.
+
+
+3.0.0-beta1 (2013-06-07)
+------------------------
+
+* Added: jsonSerialize() for creating jCal and jCard documents.
+* Added: helper method to parse vCard dates and times.
+* Added: Specialized classes for FLOAT, LANGUAGE-TAG, TIME, TIMESTAMP,
+ DATE-AND-OR-TIME, CAL-ADDRESS, UNKNOWN and UTC-OFFSET properties.
+* Removed: CommaSeparatedText property. Now included into Text.
+* Fixed: Multiple parameters with the same name are now correctly encoded.
+* Fixed: Parameter values containing a comma are now enclosed in double-quotes.
+* Fixed: Iterating parameter values should now fully work as expected.
+* Fixed: Support for vCard 2.1 nameless parameters.
+* Changed: $valueMap, $componentMap and $propertyMap now all use fully-qualified
+ class names, so they are actually overridable.
+* Fixed: Updating DATE-TIME to DATE values now behaves like expected.
+
+
+3.0.0-alpha4 (2013-05-31)
+-------------------------
+
+* Added: It's now possible to send parser options to the splitter classes.
+* Added: A few tweaks to improve component and property creation.
+
+
+3.0.0-alpha3 (2013-05-13)
+-------------------------
+
+* Changed: propertyMap, valueMap and componentMap are now static properties.
+* Changed: Component::remove() will throw an exception when trying to a node
+ that's not a child of said component.
+* Added: Splitter objects are now faster, line numbers are accurately reported
+ and use less memory.
+* Added: MimeDir parser can now continue parsing with the same stream buffer.
+* Fixed: vobjectvalidate.php is operational again.
+* Fixed: \r is properly stripped in text values.
+* Fixed: QUOTED-PRINTABLE is now correctly encoded as well as encoded, for
+ vCards 2.1.
+* Fixed: Parser assumes vCard 2.1, if no version was supplied.
+
+
+3.0.0-alpha2 (2013-05-22)
+-------------------------
+
+* Fixed: vCard URL properties were referencing a non-existant class.
+
+
+3.0.0-alpha1 (2013-05-21)
+-------------------------
+
+* Fixed: Now correctly dealing with escaping of properties. This solves the
+ problem with double-backslashes where they don't belong.
+* Added: Easy support for properties with more than one value, using setParts
+ and getParts.
+* Added: Support for broken 2.1 vCards produced by microsoft.
+* Added: Automatically decoding quoted-printable values.
+* Added: Automatically decoding base64 values.
+* Added: Decoding RFC6868 parameter values (uses ^ as an escape character).
+* Added: Fancy new MimeDir parser that can also parse streams.
+* Added: Automatically mapping many, many properties to a property-class with
+ specialized API's.
+* Added: remove() method for easily removing properties and sub-components
+ components.
+* Changed: Components, Properties and Parameters can no longer be created with
+ Component::create, Property::create and Parameter::create. They must instead
+ be created through the root component. (A VCalendar or VCard object).
+* Changed: API for DateTime properties has slightly changed.
+* Changed: the ->value property is now protected everywhere. Use getParts() and
+ getValue() instead.
+* BC Break: No support for mac newlines (\r). Never came across these anyway.
+* Added: add() method to the Property class.
+* Added: It's now possible to easy set multi-value properties as arrays.
+* Added: When setting date-time properties you can just pass PHP's DateTime
+ object.
+* Added: New components automatically get a bunch of default properties, such as
+ VERSION and CALSCALE.
+* Added: You can add new sub-components much quicker with the magic setters, and
+ add() method.
+
+
+2.1.7 (2015-01-21)
+------------------
+
+* Fixed: Issue #94, a workaround for bad escaping of ; and , in compound
+ properties. It's not a full solution, but it's an improvement for those
+ stuck in the 2.1 versions.
+
+
+2.1.6 (2014-12-10)
+------------------
+
+* Fixed: Minor change to make sure that unittests succeed on every PHP version.
+
+
+2.1.5 (2014-06-03)
+------------------
+
+* Fixed: #94: Better parameter escaping.
+* Changed: Documentation cleanups.
+
+
+2.1.4 (2014-03-30)
+------------------
+
+* Fixed: Issue #87: Several compatibility fixes related to timezone handling
+ changes in PHP 5.5.10.
+
+
+2.1.3 (2013-10-02)
+------------------
+
+* Fixed: Issue #55. \r must be stripped from property values.
+* Fixed: Issue #65. Putting quotes around parameter values that contain a colon.
+
+
+2.1.2 (2013-08-02)
+------------------
+
+* Fixed: Issue #53. A regression in RecurrenceIterator.
+
+
+2.1.1 (2013-07-27)
+------------------
+
+* Fixed: Issue #50. RecurrenceIterator gives incorrect result when exception
+ events are out of order in the iCalendar file.
+* Fixed: Issue #48. Overridden events in the recurrence iterator that were past
+ the UNTIL date were ignored.
+
+
+2.1.0 (2013-06-17)
+------------------
+
+* This version is fully backwards compatible with 2.0.\*. However, it contains a
+ few new API's that mimic the VObject 3 API. This allows it to be used a
+ 'bridge' version. Specifically, this new version exists so SabreDAV 1.7 and
+ 1.8 can run with both the 2 and 3 versions of this library.
+* Added: Property\DateTime::hasTime().
+* Added: Property\MultiDateTime::hasTime().
+* Added: Property::getValue().
+* Added: Document class.
+* Added: Document::createComponent and Document::createProperty.
+* Added: Parameter::getValue().
+
+
+2.0.7 (2013-03-05)
+------------------
+
+* Fixed: Microsoft re-uses their magic numbers for different timezones,
+ specifically id 2 for both Sarajevo and Lisbon). A workaround was added to
+ deal with this.
+
+
+2.0.6 (2013-02-17)
+------------------
+
+* Fixed: The reader now properly parses parameters without a value.
+
+
+2.0.5 (2012-11-05)
+------------------
+
+* Fixed: The FreeBusyGenerator is now properly using the factory methods for
+ creation of components and properties.
+
+
+2.0.4 (2012-11-02)
+------------------
+
+* Added: Known Lotus Notes / Domino timezone id's.
+
+
+2.0.3 (2012-10-29)
+------------------
+
+* Added: Support for 'GMT+????' format in TZID's.
+* Added: Support for formats like SystemV/EST5EDT in TZID's.
+* Fixed: RecurrenceIterator now repairs recurrence rules where UNTIL < DTSTART.
+* Added: Support for BYHOUR in FREQ=DAILY (@hollodk).
+* Added: Support for BYHOUR and BYDAY in FREQ=WEEKLY.
+
+
+2.0.2 (2012-10-06)
+------------------
+
+* Added: includes.php file, to load the entire library in one go.
+* Fixed: A problem with determining alarm triggers for TODO's.
+
+
+2.0.1 (2012-09-22)
+------------------
+
+* Removed: Element class. It wasn't used.
+* Added: Basic validation and repair methods for broken input data.
+* Fixed: RecurrenceIterator could infinitely loop when an INTERVAL of 0 was
+ specified.
+* Added: A cli script that can validate and automatically repair vcards and
+ iCalendar objects.
+* Added: A new 'Compound' property, that can automatically split up parts for
+ properties such as N, ADR, ORG and CATEGORIES.
+* Added: Splitter classes, that can split up large objects (such as exports)
+ into individual objects (thanks @DominikTo and @armin-hackmann).
+* Added: VFREEBUSY component, which allows easily checking wether timeslots are
+ available.
+* Added: The Reader class now has a 'FORGIVING' option, which allows it to parse
+ properties with incorrect characters in the name (at this time, it just allows
+ underscores).
+* Added: Also added the 'IGNORE_INVALID_LINES' option, to completely disregard
+ any invalid lines.
+* Fixed: A bug in Windows timezone-id mappings for times created in Greenlands
+ timezone (sorry Greenlanders! I do care!).
+* Fixed: DTEND was not generated correctly for VFREEBUSY reports.
+* Fixed: Parser is at least 25% faster with real-world data.
+
+
+2.0.0 (2012-08-08)
+------------------
+
+* VObject is now a separate project from SabreDAV. See the SabreDAV changelog
+ for version information before 2.0.
+* New: VObject library now uses PHP 5.3 namespaces.
+* New: It's possible to specify lists of parameters when constructing
+ properties.
+* New: made it easier to construct the FreeBusyGenerator.
+
+[iTip]: http://tools.ietf.org/html/rfc5546
diff --git a/vendor/sabre/vobject/ChangeLog b/vendor/sabre/vobject/ChangeLog
deleted file mode 100644
index 96e1fb669..000000000
--- a/vendor/sabre/vobject/ChangeLog
+++ /dev/null
@@ -1,88 +0,0 @@
-2.1.4-stable (2014-03-30)
- * Fixed: Issue #87: Several compatibility fixes related to timezone
- handling changes in PHP 5.5.10.
-
-2.1.3-stable (2013-10-02)
- * Fixed: Issue #55. \r must be stripped from property values.
- * Fixed: Issue #65. Putting quotes around parameter values that contain a
- colon.
-
-2.1.2-stable (2013-08-02)
- * Fixed: Issue #53. A regression in RecurrenceIterator.
-
-2.1.1-stable (2013-07-27)
- * Fixed: Issue #50. RecurrenceIterator gives incorrect result when
- exception events are out of order in the iCalendar file.
- * Fixed: Issue #48. Overridden events in the recurrence iterator that were
- past the UNTIL date were ignored.
-
-2.1.0-stable (2013-06-17)
- * This version is fully backwards compatible with 2.0.*. However, it
- contains a few new API's that mimic the VObject 3 API. This allows it to
- be used a 'bridge' version.
- Specifically, this new version exists so SabreDAV 1.7 and 1.8 can run with
- both the 2 and 3 versions of this library.
- * Added: Property\DateTime::hasTime().
- * Added: Property\MultiDateTime::hasTime().
- * Added: Property::getValue().
- * Added: Document class.
- * Added: Document::createComponent and Document::createProperty.
- * Added: Parameter::getValue().
-
-
-2.0.7-stable (2013-03-05)
- * Fixed: Microsoft re-uses their magic numbers for different timezones,
- specifically id 2 for both Sarajevo and Lisbon). A workaround was added
- to deal with this.
-
-2.0.6-stable (2013-02-17)
- * Fixed: The reader now properly parses parameters without a value.
-
-2.0.5-stable (2012-11-05)
- * Fixed: The FreeBusyGenerator is now properly using the factory methods
- for creation of components and properties.
-
-2.0.4-stable (2012-11-02)
- * Added: Known Lotus Notes / Domino timezone id's.
-
-2.0.3-stable (2012-10-29)
- * Added: Support for 'GMT+????' format in TZID's.
- * Added: Support for formats like SystemV/EST5EDT in TZID's.
- * Fixed: RecurrenceIterator now repairs recurrence rules where UNTIL < DTSTART.
- * Added: Support for BYHOUR in FREQ=DAILY (@hollodk).
- * Added: Support for BYHOUR and BYDAY in FREQ=WEEKLY.
-
-2.0.2-stable (2012-10-06)
- * Added: includes.php file, to load the entire library in one go.
- * Fixed: A problem with determining alarm triggers for TODO's.
-
-2.0.1-stable (2012-09-22)
- * Removed: Element class. It wasn't used.
- * Added: Basic validation and repair methods for broken input data.
- * Fixed: RecurrenceIterator could infinitely loop when an INTERVAL of 0
- was specified.
- * Added: A cli script that can validate and automatically repair vcards
- and iCalendar objects.
- * Added: A new 'Compound' property, that can automatically split up parts
- for properties such as N, ADR, ORG and CATEGORIES.
- * Added: Splitter classes, that can split up large objects (such as exports)
- into individual objects (thanks @DominikTO and @armin-hackmann).
- * Added: VFREEBUSY component, which allows easily checking wether
- timeslots are available.
- * Added: The Reader class now has a 'FORGIVING' option, which allows it to
- parse properties with incorrect characters in the name (at this time, it
- just allows underscores).
- * Added: Also added the 'IGNORE_INVALID_LINES' option, to completely
- disregard any invalid lines.
- * Fixed: A bug in Windows timezone-id mappings for times created in
- Greenlands timezone (sorry Greenlanders! I do care!).
- * Fixed: DTEND was not generated correctly for VFREEBUSY reports.
- * Fixed: Parser is at least 25% faster with real-world data.
-
-2.0.0-stable (2012-08-08)
- * VObject is now a separate project from SabreDAV. See the SabreDAV
- changelog for version information before 2.0.
- * New: VObject library now uses PHP 5.3 namespaces.
- * New: It's possible to specify lists of parameters when constructing
- properties.
- * New: made it easier to construct the FreeBusyGenerator.
diff --git a/vendor/sabre/vobject/LICENSE b/vendor/sabre/vobject/LICENSE
index 628c60c78..a99c8da19 100644
--- a/vendor/sabre/vobject/LICENSE
+++ b/vendor/sabre/vobject/LICENSE
@@ -1,4 +1,4 @@
-Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/)
+Copyright (C) 2011-2016 fruux GmbH (https://fruux.com/)
All rights reserved.
diff --git a/vendor/sabre/vobject/README.md b/vendor/sabre/vobject/README.md
index c7541eaca..0e37f1388 100644
--- a/vendor/sabre/vobject/README.md
+++ b/vendor/sabre/vobject/README.md
@@ -1,377 +1,46 @@
-SabreTooth VObject library
-==========================
-
-[![Build Status](https://secure.travis-ci.org/fruux/sabre-vobject.png?branch=master)](http://travis-ci.org/fruux/sabre-vobject)
+sabre/vobject
+=============
The VObject library allows you to easily parse and manipulate [iCalendar](https://tools.ietf.org/html/rfc5545)
and [vCard](https://tools.ietf.org/html/rfc6350) objects using PHP.
+
The goal of the VObject library is to create a very complete library, with an easy to use API.
-This project is a spin-off from [SabreDAV](http://code.google.com/p/sabredav/), where it has
-been used for several years. The VObject library has 100% unittest coverage.
Installation
------------
-VObject requires PHP 5.3, and should be installed using composer.
-The general composer instructions can be found on the [composer website](http://getcomposer.org/doc/00-intro.md composer website).
-
-After that, just declare the vobject dependency as follows:
-
-```
-"require" : {
- "sabre/vobject" : "2.0.*"
-}
-```
-
-Then, run `composer.phar update` and you should be good.
-
-Usage
------
-
-### Parsing
-
-For our example, we will be using the following vcard:
-
-```
-BEGIN:VCARD
-VERSION:3.0
-PRODID:-//Sabre//Sabre VObject 2.0//EN
-N:Planck;Max;;;
-FN:Max Planck
-EMAIL;TYPE=WORK:mplanck@example.org
-item1.TEL;TYPE=CELL:(+49)3144435678
-item1.X-ABLabel:Private cell
-item2.TEL;TYPE=WORK:(+49)5554564744
-item2.X-ABLabel:Work
-END:VCARD
-```
-
-
-If we want to just print out Max' full name, you can just use property access:
-
-
-```php
-use Sabre\VObject;
-
-$card = VObject\Reader::read($data);
-echo $card->FN;
-```
-
-### Changing properties
-
-Creating properties is pretty similar. If we like to add his birthday, we just
-set the property:
-
-```php
-$card->BDAY = '1858-04-23';
-```
-
-Note that in the previous example, we're actually updating any existing BDAY that
-may already exist. If we want to add a new property, without overwriting the previous
-we can do this with the `add` method.
-
-```php
-$card->add('EMAIL','max@example.org');
-```
-
-### Parameters
-
-If we want to also specify that this is max' home email addresses, we can do this with
-a third parameter:
-
-```
-$card->add('EMAIL', 'max@example'org', array('type' => 'HOME'));
-```
-
-If we want to read out all the email addresses and their type, this would look something
-like this:
-
-```
-foreach($card->EMAIL as $email) {
-
- echo $email['TYPE'], ' - ', $email;
-
-}
-```
-
-### Groups
-
-In our example, you can see that the TEL properties are prefixed. These are 'groups' and
-allow you to group multiple related properties together. The group can be any user-defined
-name.
-
-This particular example as generated by the OS X addressbook, which uses the `X-ABLabel`
-to allow the user to specify custom labels for properties. OS X addressbook uses groups
-to tie the label to the property.
-
-The VObject library simply ignores the group if you don't specify it, so this will work:
-
-```php
-foreach($card->TEL as $tel) {
- echo $tel, "\n";
-}
-```
-
-But if you would like to target a specific group + property, this is possible too:
-
-```php
-echo $card->{'ITEM1.TEL'};
-```
-
-So if you would like to show all the phone numbers, along with their custom label, the
-following syntax is used:
-
-```php
-foreach($card->TEL as $tel) {
-
- echo $card->{$tel->group . '.X-ABLABEL'}, ": ";
- echo $tel, "\n";
-
-}
-```
-
-### Serializing / Saving
-
-If you want to generate your updated VObject, you can simply call the serialize() method.
-
-```php
-echo $card->serialize();
-```
+Make sure you have [Composer][1] installed, and then run:
-### Components
+ composer require sabre/vobject "^4.0"
-iCalendar, unlike vCards always have sub-components. Where vCards are often just a flat
-list, iCalendar objects tend to have a tree-like structure. For the following paragraphs,
-we will use the following object as the example:
+This package requires PHP 5.5. If you need the PHP 5.3/5.4 version of this package instead, use:
-```
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Sabre//Sabre VObject 2.0//EN
-BEGIN:VEVENT
-SUMMARY:Curiosity landing
-DTSTART:20120806T051439Z
-LOCATION:Mars
-END:VEVENT
-END:VCALENDAR
-```
-Since events, tasks and journals are always in a sub component, this is also how we
-access them.
+ composer require sabre/vobject "^3.4"
-```php
-use Sabre\VObject;
-$calendar = VObject\Reader::read($data);
-echo $calendar->VEVENT->SUMMARY;
-```
-
-Adding components to a calendar is done with a factory method:
-
-```php
-$event = VObject\Component::create('VEVENT');
-$calendar->add($event);
-
-$event->SUMMARY = 'Curiosity launch';
-$event->DTSTART = '20111126T150202Z';
-$event->LOCATION = 'Cape Carnival';
-```
-
-By the way.. cloning also works as expected, as the entire structure is cloned along with it:
-
-```php
-$clonedEvent = clone $calendar->VEVENT[0];
-$calendar->add($clonedEvent);
-```
-
-### Date and time handling
-
-If you ever had to deal with iCalendar timezones, you know it can be complicated.
-The way timezones are specified is flawed, which is something I may write an essay about some
-day. VObject does its best to determine the correct timezone. Many standard formats
-have been tested and verified, and special code has been implemented for special-casing
-microsoft generated timezone information, and others.
-
-To get a real php `DateTime` object, you can request this as follows:
-
-```php
-$event = $calendar->VEVENT;
-$start = $event->DTSTART->getDateTime();
-echo $start->format(\DateTime::W3C);
-```
-
-To set the property with a DateTime object, you can use the following syntax:
-
-```php
-$dateTime = new \DateTime('2012-08-07 23:53:00', new DateTimeZone('Europe/Amsterdam'));
-$event->DTSTART->setDateTime($dateTime, VObject\Property\DateTime::DATE);
-```
-
-The second argument specifies the type of date you're setting. The following three
-options exist:
-
-1. `LOCAL` This is a floating time, with no timezone information. This basically specifies that the event happens in whatever the timezone's currently in. This would be encoded as `DTSTART;VALUE=DATE-TIME:20120807235300`
-2. `UTC` This specifies that the time should be encoded as a UTC time. This is encoded as `DTSTART;VALUE=DATE-TIME:20120807205300Z`. Note the extra Z and the fact that it's two hours 'earlier'.
-3. `LOCALTZ` specifies that it's supposed to be encoded in its local timezone. For example `DTSTART;VALUE=DATE-TIME;TZID=Europe/Amsterdam:20120807235300`.
-4. `DATE` This is a date-only, and does not contain the time. In this case this would be encoded as `DTSTART;VALUE=DATE:20120807`.
-
-A few important notes:
-
-* When a `TZID` is specified, there should also be a matching `VTIMEZONE` object with all the timezone information. VObject cannot currently automatically embed this. However, in reality other clients seem to do fine without this information. Yet, for completeness, this will be added in the future.
-* As mentioned, the timezone-determination process may sometimes fail. Report any issues you find, and I'll be quick to add workarounds!
-
-### Recurrence rules
-
-Recurrence rules allow events to recur, for example for a weekly meeting, or an anniversary.
-This is done with the `RRULE` property. The `RRULE` property allows for a LOT of different
-rules. VObject only implements the ones that actually appear in calendar software.
-
-To read more about `RRULE` and all the options, check out [RFC5545](https://tools.ietf.org/html/rfc5545#section-3.8.5).
-VObject supports the following options:
-
-1. `UNTIL` for an end date.
-2. `INTERVAL` for for example "every 2 days".
-3. `COUNT` to stop recurring after x items.
-4. `FREQ=DAILY` to recur every day, and `BYDAY` to limit it to certain days.
-5. `FREQ=WEEKLY` to recur every week, `BYDAY` to expand this to multiple weekdays in every week and `WKST` to specify on which day the week starts.
-6. `FREQ=MONTHLY` to recur every month, `BYMONTHDAY` to expand this to certain days in a month, `BYDAY` to expand it to certain weekdays occuring in a month, and `BYSETPOS` to limit the last two expansions.
-7. `FREQ=YEARLY` to recur every year, `BYMONTH` to expand that to certain months in a year, and `BYDAY` and `BYWEEKDAY` to expand the `BYMONTH` rule even further.
-
-VObject supports the `EXDATE` property for exclusions, but not yet the `RDATE` and `EXRULE`
-properties. If you're interested in this, please file a github issue, as this will put it
-on my radar.
-
-This is a bit of a complex subject to go in excruciating detail. The
-[RFC](https://tools.ietf.org/html/rfc5545#section-3.8.5) has a lot of examples though.
-
-The hard part is not to write the RRULE, it is to expand them. The most complex and
-hard-to-read code is hidden in this component. Dragons be here.
-
-So, if we have a meeting every 2nd monday of the month, this would be specified as such:
-
-```
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Sabre//Sabre VObject 2.0//EN
-BEGIN:VEVENT
-UID:1102c450-e0d7-11e1-9b23-0800200c9a66
-DTSTART:20120109T140000Z
-RRULE:FREQ=MONTHLY;BYDAY=MO;BYSETPOS=2
-END:VEVENT
-END:VCALENDAR
-```
-
-Note that normally it's not allowed to indent the object like this, but it does make
-it easier to read. This is also the first time I added in a UID, which is required
-for all VEVENT, VTODO and VJOURNAL objects!
-
-To figure out all the meetings for this year, we can use the following syntax:
-
-```php
-use Sabre\VObject;
-
-$calendar = VObject\Reader::read($data);
-$calendar->expand(new DateTime('2012-01-01'), new DateTime('2012-12-31'));
-```
-
-What the expand method does, is look at its inner events, and expand the recurring
-rule. Our calendar now contains 12 events. The first will have its RRULE stripped,
-and every subsequent VEVENT has the correct meeting date and a `RECURRENCE-ID` set.
-
-This results in something like this:
-
-```
-BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Sabre//Sabre VObject 2.0//EN
- BEGIN:VEVENT
- UID:1102c450-e0d7-11e1-9b23-0800200c9a66
- DTSTART:20120109T140000Z
- END:VEVENT
- BEGIN:VEVENT
- UID:1102c450-e0d7-11e1-9b23-0800200c9a66
- RECURRENCE-ID:20120213T140000Z
- DTSTART:20120213T140000Z
- END:VEVENT
- BEGIN:VEVENT
- UID:1102c450-e0d7-11e1-9b23-0800200c9a66
- RECURRENCE-ID:20120312T140000Z
- DTSTART:20120312T140000Z
- END:VEVENT
- ..etc..
-END:VCALENDAR
-```
-
-To show the list of dates, we would do this as such:
-
-```php
-foreach($calendar->VEVENT as $event) {
- echo $event->DTSTART->getDateTime()->format(\DateTime::ATOM);
-}
-```
-
-In a recurring event, single instances can also be overriden. VObject also takes these
-into consideration. The reason we needed to specify a start and end-date, is because
-some recurrence rules can be 'never ending'.
-
-You should make sure you pick a sane date-range. Because if you pick a 50 year
-time-range, for a daily recurring event; this would result in over 18K objects.
-
-Free-busy report generation
----------------------------
-
-Some calendaring software can make use of FREEBUSY reports to show when people are
-available.
+Usage
+-----
-You can automatically generate these reports from calendars using the `FreeBusyGenerator`.
+* [Working with vCards](http://sabre.io/vobject/vcard/)
+* [Working with iCalendar](http://sabre.io/vobject/icalendar/)
-Example based on our last event:
-```php
-// We're giving it the calendar object. It's also possible to specify multiple objects,
-// by setting them as an array.
-//
-// We must also specify a start and end date, because recurring events are expanded.
-$fbGenerator = new VObject\FreeBusyGenerator(
- new DateTime('2012-01-01'),
- new DateTime('2012-12-31'),
- $calendar
-);
-// Grabbing the report
-$freebusy = $fbGenerator->result();
+Build status
+------------
-// The freebusy report is another VCALENDAR object, so we can serialize it as usual:
-echo $freebusy->serialize();
-```
+| branch | status |
+| ------ | ------ |
+| master | [![Build Status](https://travis-ci.org/fruux/sabre-vobject.svg?branch=master)](https://travis-ci.org/fruux/sabre-vobject) |
+| 3.5 | [![Build Status](https://travis-ci.org/fruux/sabre-vobject.svg?branch=3.5)](https://travis-ci.org/fruux/sabre-vobject) |
+| 3.4 | [![Build Status](https://travis-ci.org/fruux/sabre-vobject.svg?branch=3.4)](https://travis-ci.org/fruux/sabre-vobject) |
+| 3.1 | [![Build Status](https://travis-ci.org/fruux/sabre-vobject.svg?branch=3.1)](https://travis-ci.org/fruux/sabre-vobject) |
+| 2.1 | [![Build Status](https://travis-ci.org/fruux/sabre-vobject.svg?branch=2.1)](https://travis-ci.org/fruux/sabre-vobject) |
+| 2.0 | [![Build Status](https://travis-ci.org/fruux/sabre-vobject.svg?branch=2.0)](https://travis-ci.org/fruux/sabre-vobject) |
-The output of this script will look like this:
-```
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Sabre//Sabre VObject 2.0//EN
-CALSCALE:GREGORIAN
-BEGIN:VFREEBUSY
-DTSTART;VALUE=DATE-TIME:20111231T230000Z
-DTEND;VALUE=DATE-TIME:20111231T230000Z
-DTSTAMP;VALUE=DATE-TIME:20120808T131628Z
-FREEBUSY;FBTYPE=BUSY:20120109T140000Z/20120109T140000Z
-FREEBUSY;FBTYPE=BUSY:20120213T140000Z/20120213T140000Z
-FREEBUSY;FBTYPE=BUSY:20120312T140000Z/20120312T140000Z
-FREEBUSY;FBTYPE=BUSY:20120409T140000Z/20120409T140000Z
-FREEBUSY;FBTYPE=BUSY:20120514T140000Z/20120514T140000Z
-FREEBUSY;FBTYPE=BUSY:20120611T140000Z/20120611T140000Z
-FREEBUSY;FBTYPE=BUSY:20120709T140000Z/20120709T140000Z
-FREEBUSY;FBTYPE=BUSY:20120813T140000Z/20120813T140000Z
-FREEBUSY;FBTYPE=BUSY:20120910T140000Z/20120910T140000Z
-FREEBUSY;FBTYPE=BUSY:20121008T140000Z/20121008T140000Z
-FREEBUSY;FBTYPE=BUSY:20121112T140000Z/20121112T140000Z
-FREEBUSY;FBTYPE=BUSY:20121210T140000Z/20121210T140000Z
-END:VFREEBUSY
-END:VCALENDAR
-```
Support
-------
@@ -382,3 +51,5 @@ Made at fruux
-------------
This library is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support.
+
+[1]: https://getcomposer.org/
diff --git a/vendor/sabre/vobject/bin/bench.php b/vendor/sabre/vobject/bin/bench.php
index b949c8ea4..807b40777 100755
--- a/vendor/sabre/vobject/bin/bench.php
+++ b/vendor/sabre/vobject/bin/bench.php
@@ -5,8 +5,8 @@ include __DIR__ . '/../vendor/autoload.php';
$data = stream_get_contents(STDIN);
-$start = microtime(true);
+$start = microtime(true);
$lol = Sabre\VObject\Reader::read($data);
-echo "time: " . (microtime(true)-$start) . "\n";
+echo "time: " . (microtime(true) - $start) . "\n";
diff --git a/vendor/sabre/vobject/bin/bench_freebusygenerator.php b/vendor/sabre/vobject/bin/bench_freebusygenerator.php
new file mode 100644
index 000000000..2c51b2a32
--- /dev/null
+++ b/vendor/sabre/vobject/bin/bench_freebusygenerator.php
@@ -0,0 +1,62 @@
+<?php
+
+include __DIR__ . '/../vendor/autoload.php';
+
+if ($argc < 2) {
+ echo "sabre/vobject ", Sabre\VObject\Version::VERSION, " freebusy benchmark\n";
+ echo "\n";
+ echo "This script can be used to measure the speed of generating a\n";
+ echo "free-busy report based on a calendar.\n";
+ echo "\n";
+ echo "The process will be repeated 100 times to get accurate stats\n";
+ echo "\n";
+ echo "Usage: " . $argv[0] . " inputfile.ics\n";
+ die();
+}
+
+list(, $inputFile) = $argv;
+
+$bench = new Hoa\Bench\Bench();
+$bench->parse->start();
+
+$vcal = Sabre\VObject\Reader::read(fopen($inputFile, 'r'));
+
+$bench->parse->stop();
+
+$repeat = 100;
+$start = new \DateTime('2000-01-01');
+$end = new \DateTime('2020-01-01');
+$timeZone = new \DateTimeZone('America/Toronto');
+
+$bench->fb->start();
+
+for ($i = 0; $i < $repeat; $i++) {
+
+ $fb = new Sabre\VObject\FreeBusyGenerator($start, $end, $vcal, $timeZone);
+ $results = $fb->getResult();
+
+}
+$bench->fb->stop();
+
+
+
+echo $bench,"\n";
+
+function formatMemory($input) {
+
+ if (strlen($input) > 6) {
+
+ return round($input / (1024 * 1024)) . 'M';
+
+ } elseif (strlen($input) > 3) {
+
+ return round($input / 1024) . 'K';
+
+ }
+
+}
+
+unset($input, $splitter);
+
+echo "peak memory usage: " . formatMemory(memory_get_peak_usage()), "\n";
+echo "current memory usage: " . formatMemory(memory_get_usage()), "\n";
diff --git a/vendor/sabre/vobject/bin/bench_manipulatevcard.php b/vendor/sabre/vobject/bin/bench_manipulatevcard.php
new file mode 100644
index 000000000..adc198e9b
--- /dev/null
+++ b/vendor/sabre/vobject/bin/bench_manipulatevcard.php
@@ -0,0 +1,69 @@
+<?php
+
+include __DIR__ . '/../vendor/autoload.php';
+
+if ($argc < 2) {
+ echo "sabre/vobject ", Sabre\VObject\Version::VERSION, " manipulation benchmark\n";
+ echo "\n";
+ echo "This script can be used to measure the speed of opening a large amount of\n";
+ echo "vcards, making a few alterations and serializing them again.\n";
+ echo "system.";
+ echo "\n";
+ echo "Usage: " . $argv[0] . " inputfile.vcf\n";
+ die();
+}
+
+list(, $inputFile) = $argv;
+
+$input = file_get_contents($inputFile);
+
+$splitter = new Sabre\VObject\Splitter\VCard($input);
+
+$bench = new Hoa\Bench\Bench();
+
+while (true) {
+
+ $bench->parse->start();
+ $vcard = $splitter->getNext();
+ $bench->parse->pause();
+
+ if (!$vcard) break;
+
+ $bench->manipulate->start();
+ $vcard->{'X-FOO'} = 'Random new value!';
+ $emails = [];
+ if (isset($vcard->EMAIL)) foreach ($vcard->EMAIL as $email) {
+ $emails[] = (string)$email;
+ }
+ $bench->manipulate->pause();
+
+ $bench->serialize->start();
+ $vcard2 = $vcard->serialize();
+ $bench->serialize->pause();
+
+ $vcard->destroy();
+
+}
+
+
+
+echo $bench,"\n";
+
+function formatMemory($input) {
+
+ if (strlen($input) > 6) {
+
+ return round($input / (1024 * 1024)) . 'M';
+
+ } elseif (strlen($input) > 3) {
+
+ return round($input / 1024) . 'K';
+
+ }
+
+}
+
+unset($input, $splitter);
+
+echo "peak memory usage: " . formatMemory(memory_get_peak_usage()), "\n";
+echo "current memory usage: " . formatMemory(memory_get_usage()), "\n";
diff --git a/vendor/sabre/vobject/bin/fetch_windows_zones.php b/vendor/sabre/vobject/bin/fetch_windows_zones.php
new file mode 100755
index 000000000..1b1fdc37c
--- /dev/null
+++ b/vendor/sabre/vobject/bin/fetch_windows_zones.php
@@ -0,0 +1,51 @@
+#!/usr/bin/env php
+<?php
+
+$windowsZonesUrl = 'http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml';
+$outputFile = __DIR__ . '/../lib/timezonedata/windowszones.php';
+
+echo "Fetching timezone map from: " . $windowsZonesUrl, "\n";
+
+$data = file_get_contents($windowsZonesUrl);
+
+$xml = simplexml_load_string($data);
+
+$map = [];
+
+foreach ($xml->xpath('//mapZone') as $mapZone) {
+
+ $from = (string)$mapZone['other'];
+ $to = (string)$mapZone['type'];
+
+ list($to) = explode(' ', $to, 2);
+
+ if (!isset($map[$from])) {
+ $map[$from] = $to;
+ }
+
+}
+
+ksort($map);
+echo "Writing to: $outputFile\n";
+
+$f = fopen($outputFile, 'w');
+fwrite($f, "<?php\n\n");
+fwrite($f, "/**\n");
+fwrite($f, " * Automatically generated timezone file\n");
+fwrite($f, " *\n");
+fwrite($f, " * Last update: " . date(DATE_W3C) . "\n");
+fwrite($f, " * Source: " . $windowsZonesUrl . "\n");
+fwrite($f, " *\n");
+fwrite($f, " * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).\n");
+fwrite($f, " * @license http://sabre.io/license/ Modified BSD License\n");
+fwrite($f, " */\n");
+fwrite($f, "\n");
+fwrite($f, "return ");
+fwrite($f, var_export($map, true) . ';');
+fclose($f);
+
+echo "Formatting\n";
+
+exec(__DIR__ . '/sabre-cs-fixer fix ' . escapeshellarg($outputFile));
+
+echo "Done\n";
diff --git a/vendor/sabre/vobject/bin/generate_vcards b/vendor/sabre/vobject/bin/generate_vcards
new file mode 100755
index 000000000..4663c3c16
--- /dev/null
+++ b/vendor/sabre/vobject/bin/generate_vcards
@@ -0,0 +1,241 @@
+#!/usr/bin/env php
+<?php
+
+namespace Sabre\VObject;
+
+// This sucks.. we have to try to find the composer autoloader. But chances
+// are, we can't find it this way. So we'll do our bestest
+$paths = [
+ __DIR__ . '/../vendor/autoload.php', // In case vobject is cloned directly
+ __DIR__ . '/../../../autoload.php', // In case vobject is a composer dependency.
+];
+
+foreach($paths as $path) {
+ if (file_exists($path)) {
+ include $path;
+ break;
+ }
+}
+
+if (!class_exists('Sabre\\VObject\\Version')) {
+ fwrite(STDERR, "Composer autoloader could not be properly loaded.\n");
+ die(1);
+}
+
+if ($argc < 2) {
+
+ $version = Version::VERSION;
+
+ $help = <<<HI
+sabre/vobject $version
+Usage:
+ generate_vcards [count]
+
+Options:
+ count The number of random vcards to generate
+
+Examples:
+ generate_vcards 1000 > testdata.vcf
+
+HI;
+
+ fwrite(STDERR, $help);
+ exit(2);
+}
+
+$count = (int)$argv[1];
+if ($count < 1) {
+ fwrite(STDERR, "Count must be at least 1\n");
+ exit(2);
+}
+
+fwrite(STDERR, "sabre/vobject " . Version::VERSION . "\n");
+fwrite(STDERR, "Generating " . $count . " vcards in vCard 4.0 format\n");
+
+/**
+ * The following list is just some random data we compiled from various
+ * sources online.
+ *
+ * Very little thought went into compiling this list, and certainly nothing
+ * political or ethical.
+ *
+ * We would _love_ more additions to this to add more variation to this list.
+ *
+ * Send us PR's and don't be shy adding your own first and last name for fun.
+ */
+
+$sets = array(
+ "nl" => array(
+ "country" => "Netherlands",
+ "boys" => array(
+ "Anno",
+ "Bram",
+ "Daan",
+ "Evert",
+ "Finn",
+ "Jayden",
+ "Jens",
+ "Jesse",
+ "Levi",
+ "Lucas",
+ "Luuk",
+ "Milan",
+ "René",
+ "Sem",
+ "Sibrand",
+ "Willem",
+ ),
+ "girls" => array(
+ "Celia",
+ "Emma",
+ "Fenna",
+ "Geke",
+ "Inge",
+ "Julia",
+ "Lisa",
+ "Lotte",
+ "Mila",
+ "Sara",
+ "Sophie",
+ "Tess",
+ "Zoë",
+ ),
+ "last" => array(
+ "Bakker",
+ "Bos",
+ "De Boer",
+ "De Groot",
+ "De Jong",
+ "De Vries",
+ "Jansen",
+ "Janssen",
+ "Meyer",
+ "Mulder",
+ "Peters",
+ "Smit",
+ "Van Dijk",
+ "Van den Berg",
+ "Visser",
+ "Vos",
+ ),
+ ),
+ "us" => array(
+ "country" => "United States",
+ "boys" => array(
+ "Aiden",
+ "Alexander",
+ "Charles",
+ "David",
+ "Ethan",
+ "Jacob",
+ "James",
+ "Jayden",
+ "John",
+ "Joseph",
+ "Liam",
+ "Mason",
+ "Michael",
+ "Noah",
+ "Richard",
+ "Robert",
+ "Thomas",
+ "William",
+ ),
+ "girls" => array(
+ "Ava",
+ "Barbara",
+ "Chloe",
+ "Dorothy",
+ "Elizabeth",
+ "Emily",
+ "Emma",
+ "Isabella",
+ "Jennifer",
+ "Lily",
+ "Linda",
+ "Margaret",
+ "Maria",
+ "Mary",
+ "Mia",
+ "Olivia",
+ "Patricia",
+ "Roxy",
+ "Sophia",
+ "Susan",
+ "Zoe",
+ ),
+ "last" => array(
+ "Smith",
+ "Johnson",
+ "Williams",
+ "Jones",
+ "Brown",
+ "Davis",
+ "Miller",
+ "Wilson",
+ "Moore",
+ "Taylor",
+ "Anderson",
+ "Thomas",
+ "Jackson",
+ "White",
+ "Harris",
+ "Martin",
+ "Thompson",
+ "Garcia",
+ "Martinez",
+ "Robinson",
+ ),
+ ),
+);
+
+$current = 0;
+
+$r = function($arr) {
+
+ return $arr[mt_rand(0,count($arr)-1)];
+
+};
+
+$bdayStart = strtotime('-85 years');
+$bdayEnd = strtotime('-20 years');
+
+while($current < $count) {
+
+ $current++;
+ fwrite(STDERR, "\033[100D$current/$count");
+
+ $country = array_rand($sets);
+ $gender = mt_rand(0,1)?'girls':'boys';
+
+ $vcard = new Component\VCard(array(
+ 'VERSION' => '4.0',
+ 'FN' => $r($sets[$country][$gender]) . ' ' . $r($sets[$country]['last']),
+ 'UID' => UUIDUtil::getUUID(),
+ ));
+
+ $bdayRatio = mt_rand(0,9);
+
+ if($bdayRatio < 2) {
+ // 20% has a birthday property with a full date
+ $dt = new \DateTime('@' . mt_rand($bdayStart, $bdayEnd));
+ $vcard->add('BDAY', $dt->format('Ymd'));
+
+ } elseif ($bdayRatio < 3) {
+ // 10% we only know the month and date of
+ $dt = new \DateTime('@' . mt_rand($bdayStart, $bdayEnd));
+ $vcard->add('BDAY', '--' . $dt->format('md'));
+ }
+ if ($result = $vcard->validate()) {
+ ob_start();
+ echo "\nWe produced an invalid vcard somehow!\n";
+ foreach($result as $message) {
+ echo " " . $message['message'] . "\n";
+ }
+ fwrite(STDERR, ob_get_clean());
+ }
+ echo $vcard->serialize();
+
+}
+
+fwrite(STDERR,"\nDone.\n");
diff --git a/vendor/sabre/vobject/bin/generateicalendardata.php b/vendor/sabre/vobject/bin/generateicalendardata.php
index 92c8c106d..dfcf18780 100755
--- a/vendor/sabre/vobject/bin/generateicalendardata.php
+++ b/vendor/sabre/vobject/bin/generateicalendardata.php
@@ -3,7 +3,7 @@
use Sabre\VObject;
-if ($argc<2) {
+if ($argc < 2) {
$cmd = $argv[0];
fwrite(STDERR, <<<HI
Fruux test data generator
@@ -29,49 +29,47 @@ include __DIR__ . '/../vendor/autoload.php';
fwrite(STDERR, "Generating " . $events . " events\n");
-$currentDate = new DateTime('-' . round($events/2) . ' days');
+$currentDate = new DateTime('-' . round($events / 2) . ' days');
-$calendar = VObject\Component::create('VCALENDAR');
-$calendar->version = '2.0';
-$calendar->calscale = 'GREGORIAN';
+$calendar = new VObject\Component\VCalendar();
-$ii=0;
+$ii = 0;
-while($ii < $events) {
+while ($ii < $events) {
$ii++;
- $event = VObject\Component::create('VEVENT');
+ $event = $calendar->add('VEVENT');
$event->DTSTART = 'bla';
$event->SUMMARY = 'Event #' . $ii;
$event->UID = md5(microtime(true));
- $doctorRandom = mt_rand(1,1000);
+ $doctorRandom = mt_rand(1, 1000);
- switch($doctorRandom) {
+ switch ($doctorRandom) {
// All-day event
- case 1 :
+ case 1 :
$event->DTEND = 'bla';
$dtStart = clone $currentDate;
$dtEnd = clone $currentDate;
- $dtEnd->modify('+' . mt_rand(1,3) . ' days');
- $event->DTSTART->setDateTime($dtStart, VObject\Property\DateTime::DATE);
- $event->DTEND->setDateTime($dtEnd, VObject\Property\DateTime::DATE);
+ $dtEnd->modify('+' . mt_rand(1, 3) . ' days');
+ $event->DTSTART->setDateTime($dtStart);
+ $event->DTSTART['VALUE'] = 'DATE';
+ $event->DTEND->setDateTime($dtEnd);
break;
case 2 :
- $event->RRULE = 'FREQ=DAILY;COUNT=' . mt_rand(1,10);
+ $event->RRULE = 'FREQ=DAILY;COUNT=' . mt_rand(1, 10);
// No break intentional
default :
$dtStart = clone $currentDate;
- $dtStart->setTime(mt_rand(1,23), mt_rand(0,59), mt_rand(0,59));
- $event->DTSTART->setDateTime($dtStart, VObject\Property\DateTime::UTC);
- $event->DURATION = 'PT'.mt_rand(1,3).'H';
+ $dtStart->setTime(mt_rand(1, 23), mt_rand(0, 59), mt_rand(0, 59));
+ $event->DTSTART->setDateTime($dtStart);
+ $event->DURATION = 'PT' . mt_rand(1, 3) . 'H';
break;
}
- $calendar->add($event);
- $currentDate->modify('+ ' . mt_rand(0,3) . ' days');
+ $currentDate->modify('+ ' . mt_rand(0, 3) . ' days');
}
fwrite(STDERR, "Validating\n");
@@ -79,7 +77,7 @@ fwrite(STDERR, "Validating\n");
$result = $calendar->validate();
if ($result) {
fwrite(STDERR, "Errors!\n");
- fwrite(STDERR, print_r($result,true));
+ fwrite(STDERR, print_r($result, true));
die(-1);
}
@@ -88,4 +86,3 @@ fwrite(STDERR, "Serializing this beast\n");
echo $calendar->serialize();
fwrite(STDERR, "done.\n");
-
diff --git a/vendor/sabre/vobject/bin/mergeduplicates.php b/vendor/sabre/vobject/bin/mergeduplicates.php
new file mode 100755
index 000000000..1662e7bf3
--- /dev/null
+++ b/vendor/sabre/vobject/bin/mergeduplicates.php
@@ -0,0 +1,184 @@
+#!/usr/bin/env php
+<?php
+
+namespace Sabre\VObject;
+
+// This sucks.. we have to try to find the composer autoloader. But chances
+// are, we can't find it this way. So we'll do our bestest
+$paths = [
+ __DIR__ . '/../vendor/autoload.php', // In case vobject is cloned directly
+ __DIR__ . '/../../../autoload.php', // In case vobject is a composer dependency.
+];
+
+foreach ($paths as $path) {
+ if (file_exists($path)) {
+ include $path;
+ break;
+ }
+}
+
+if (!class_exists('Sabre\\VObject\\Version')) {
+ fwrite(STDERR, "Composer autoloader could not be loaded.\n");
+ die(1);
+}
+
+echo "sabre/vobject ", Version::VERSION, " duplicate contact merge tool\n";
+
+if ($argc < 3) {
+
+ echo "\n";
+ echo "Usage: ", $argv[0], " input.vcf output.vcf [debug.log]\n";
+ die(1);
+
+}
+
+$input = fopen($argv[1], 'r');
+$output = fopen($argv[2], 'w');
+$debug = isset($argv[3]) ? fopen($argv[3], 'w') : null;
+
+$splitter = new Splitter\VCard($input);
+
+// The following properties are ignored. If they appear in some vcards
+// but not in others, we don't consider them for the sake of finding
+// differences.
+$ignoredProperties = [
+ "PRODID",
+ "VERSION",
+ "REV",
+ "UID",
+ "X-ABLABEL",
+];
+
+
+$collectedNames = [];
+
+$stats = [
+ "Total vcards" => 0,
+ "No FN property" => 0,
+ "Ignored duplicates" => 0,
+ "Merged values" => 0,
+ "Error" => 0,
+ "Unique cards" => 0,
+ "Total written" => 0,
+];
+
+function writeStats() {
+
+ global $stats;
+ foreach ($stats as $name => $value) {
+ echo str_pad($name, 23, " ", STR_PAD_RIGHT), str_pad($value, 6, " ", STR_PAD_LEFT), "\n";
+ }
+ // Moving cursor back a few lines.
+ echo "\033[" . count($stats) . "A";
+
+}
+
+function write($vcard) {
+
+ global $stats, $output;
+
+ $stats["Total written"]++;
+ fwrite($output, $vcard->serialize() . "\n");
+
+}
+
+while ($vcard = $splitter->getNext()) {
+
+ $stats["Total vcards"]++;
+ writeStats();
+
+ $fn = isset($vcard->FN) ? (string)$vcard->FN : null;
+
+ if (empty($fn)) {
+
+ // Immediately write this vcard, we don't compare it.
+ $stats["No FN property"]++;
+ $stats['Unique cards']++;
+ write($vcard);
+ $vcard->destroy();
+ continue;
+
+ }
+
+ if (!isset($collectedNames[$fn])) {
+
+ $collectedNames[$fn] = $vcard;
+ $stats['Unique cards']++;
+ continue;
+
+ } else {
+
+ // Starting comparison for all properties. We only check if properties
+ // in the current vcard exactly appear in the earlier vcard as well.
+ foreach ($vcard->children() as $newProp) {
+
+ if (in_array($newProp->name, $ignoredProperties)) {
+ // We don't care about properties such as UID and REV.
+ continue;
+ }
+ $ok = false;
+ foreach ($collectedNames[$fn]->select($newProp->name) as $compareProp) {
+
+ if ($compareProp->serialize() === $newProp->serialize()) {
+ $ok = true;
+ break;
+ }
+ }
+
+ if (!$ok) {
+
+ if ($newProp->name === 'EMAIL' || $newProp->name === 'TEL') {
+
+ // We're going to make another attempt to find this
+ // property, this time just by value. If we find it, we
+ // consider it a success.
+ foreach ($collectedNames[$fn]->select($newProp->name) as $compareProp) {
+
+ if ($compareProp->getValue() === $newProp->getValue()) {
+ $ok = true;
+ break;
+ }
+ }
+
+ if (!$ok) {
+
+ // Merging the new value in the old vcard.
+ $collectedNames[$fn]->add(clone $newProp);
+ $ok = true;
+ $stats['Merged values']++;
+
+ }
+
+ }
+
+ }
+
+ if (!$ok) {
+
+ // echo $newProp->serialize() . " does not appear in earlier vcard!\n";
+ $stats['Error']++;
+ if ($debug) fwrite($debug, "Missing '" . $newProp->name . "' property in duplicate. Earlier vcard:\n" . $collectedNames[$fn]->serialize() . "\n\nLater:\n" . $vcard->serialize() . "\n\n");
+
+ $vcard->destroy();
+ continue 2;
+ }
+
+ }
+
+ }
+
+ $vcard->destroy();
+ $stats['Ignored duplicates']++;
+
+}
+
+foreach ($collectedNames as $vcard) {
+
+ // Overwriting any old PRODID
+ $vcard->PRODID = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN';
+ write($vcard);
+ writeStats();
+
+}
+
+echo str_repeat("\n", count($stats)), "\nDone.\n";
diff --git a/vendor/sabre/vobject/bin/rrulebench.php b/vendor/sabre/vobject/bin/rrulebench.php
new file mode 100644
index 000000000..af26b4765
--- /dev/null
+++ b/vendor/sabre/vobject/bin/rrulebench.php
@@ -0,0 +1,32 @@
+<?php
+
+include __DIR__ . '/../vendor/autoload.php';
+
+if ($argc < 4) {
+ echo "sabre/vobject ", Sabre\VObject\Version::VERSION, " RRULE benchmark\n";
+ echo "\n";
+ echo "This script can be used to measure the speed of the 'recurrence expansion'\n";
+ echo "system.";
+ echo "\n";
+ echo "Usage: " . $argv[0] . " inputfile.ics startdate enddate\n";
+ die();
+}
+
+list(, $inputFile, $startDate, $endDate) = $argv;
+
+$bench = new Hoa\Bench\Bench();
+$bench->parse->start();
+
+echo "Parsing.\n";
+$vobj = Sabre\VObject\Reader::read(fopen($inputFile, 'r'));
+
+$bench->parse->stop();
+
+echo "Expanding.\n";
+$bench->expand->start();
+
+$vobj->expand(new DateTime($startDate), new DateTime($endDate));
+
+$bench->expand->stop();
+
+echo $bench,"\n";
diff --git a/vendor/sabre/vobject/bin/vobject b/vendor/sabre/vobject/bin/vobject
new file mode 100755
index 000000000..2aca7e729
--- /dev/null
+++ b/vendor/sabre/vobject/bin/vobject
@@ -0,0 +1,27 @@
+#!/usr/bin/env php
+<?php
+
+namespace Sabre\VObject;
+
+// This sucks.. we have to try to find the composer autoloader. But chances
+// are, we can't find it this way. So we'll do our bestest
+$paths = [
+ __DIR__ . '/../vendor/autoload.php', // In case vobject is cloned directly
+ __DIR__ . '/../../../autoload.php', // In case vobject is a composer dependency.
+];
+
+foreach($paths as $path) {
+ if (file_exists($path)) {
+ include $path;
+ break;
+ }
+}
+
+if (!class_exists('Sabre\\VObject\\Version')) {
+ fwrite(STDERR, "Composer autoloader could not be loaded.\n");
+ die(1);
+}
+
+$cli = new Cli();
+exit($cli->main($argv));
+
diff --git a/vendor/sabre/vobject/bin/vobjectvalidate.php b/vendor/sabre/vobject/bin/vobjectvalidate.php
deleted file mode 100755
index e0b2a479f..000000000
--- a/vendor/sabre/vobject/bin/vobjectvalidate.php
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/usr/bin/env php
-<?php
-
-namespace Sabre\VObject;
-
-// This sucks.. we have to try to find the composer autoloader. But chances
-// are, we can't find it this way. So we'll do our bestest
-$paths = array(
- __DIR__ . '/../vendor/autoload.php', // In case vobject is cloned directly
- __DIR__ . '/../../../autoload.php', // In case vobject is a composer dependency.
-);
-
-foreach($paths as $path) {
- if (file_exists($path)) {
- include $path;
- break;
- }
-}
-
-if (!class_exists('Sabre\\VObject\\Version')) {
- fwrite(STDERR, "Composer autoloader could not be properly loaded.\n");
- die(1);
-}
-
-fwrite(STDERR, "SabreTooth VObject validator " . Version::VERSION . "\n");
-
-
-$repair = false;
-$posArgs = array();
-
-// Argument parsing:
-foreach($argv as $k=>$v) {
-
- if ($k===0) {
- continue;
- }
- if (substr($v,0,2)==='--') {
- switch($v) {
- case '--repair' :
- $repair = true;
- break;
- default :
- throw new InvalidArgumentException('Unknown option: ' . $v);
- break;
- }
- continue;
- }
- $posArgs[] = $v;
-
-}
-
-function help() {
-
- global $argv;
-
- fwrite(STDERR, <<<HELP
-Usage instructions:
-
- {$argv[0]} [--repair] inputfile [outputfile]
-
- inputfile Input .vcf or .ics file.
- outputfile Output .vcf or .ics file. This is only used with --repair.
- --repair Attempt to automatically repair broken files.
-
-For both the output- and inputfile "-" can be specified, to use STDIN and STDOUT
-respectively.
-
-All other output from this script is sent to STDERR.
-
-https://github.com/fruux/sabre-vobject
-
-HELP
-);
-
-}
-
-if (count($posArgs) < 1) {
- help();
- die();
-}
-
-if ($posArgs[0]!=='-') {
- $input = fopen($posArgs[0],'r');
-} else {
- $input = STDIN;
-}
-
-if (isset($posArgs[1]) && $posArgs[1]!=='-') {
- $output = fopen($posArgs[1],'w');
-} else {
- $output = STDOUT;
-}
-
-// This is a bit of a hack to easily support multiple objects in a single file.
-$inputStr = "BEGIN:X-SABRE-WRAPPER\r\n" . stream_get_contents($input);
-
-$inputStr = rtrim($inputStr, "\r\n") . "\r\nEND:X-SABRE-WRAPPER\r\n";
-
-// Now the actual work.
-$vObj = Reader::read($inputStr);
-
-$objects = $vObj->children();
-
-foreach($objects as $child) {
-
- switch($child->name) {
- case 'VCALENDAR' :
- fwrite(STDERR, "iCalendar: " . (string)$child->VERSION . "\n");
- break;
- case 'VCARD' :
- fwrite(STDERR, "vCard: " . (string)$child->VERSION . "\n");
- break;
- default :
- fwrite(STDERR, "This was an unknown object, but it did parse. It's likely that validation will give you unexpected results.\n");
- break;
- }
-
- $options = 0;
- if ($repair) $options |= Node::REPAIR;
-
- $warnings = $child->validate($options);
-
- if (!count($warnings)) {
- fwrite(STDERR, "[GOOD NEWS] No warnings!\n");
- } else {
- foreach($warnings as $warn) {
-
- fwrite(STDERR, $warn['message'] . "\n");
-
- }
-
- }
-
- if ($repair) {
- fwrite($output, $child->serialize());
- }
-
-}
-
diff --git a/vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php b/vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php
new file mode 100644
index 000000000..afa41ab1c
--- /dev/null
+++ b/vendor/sabre/vobject/lib/BirthdayCalendarGenerator.php
@@ -0,0 +1,191 @@
+<?php
+
+namespace Sabre\VObject;
+
+use Sabre\VObject\Component\VCalendar;
+
+/**
+ * This class generates birthday calendars.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Dominik Tobschall (http://tobschall.de/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class BirthdayCalendarGenerator {
+
+ /**
+ * Input objects.
+ *
+ * @var array
+ */
+ protected $objects = [];
+
+ /**
+ * Default year.
+ * Used for dates without a year.
+ */
+ const DEFAULT_YEAR = 2000;
+
+ /**
+ * Output format for the SUMMARY.
+ *
+ * @var string
+ */
+ protected $format = '%1$s\'s Birthday';
+
+ /**
+ * Creates the generator.
+ *
+ * Check the setTimeRange and setObjects methods for details about the
+ * arguments.
+ *
+ * @param mixed $objects
+ */
+ function __construct($objects = null) {
+
+ if ($objects) {
+ $this->setObjects($objects);
+ }
+
+ }
+
+ /**
+ * Sets the input objects.
+ *
+ * You must either supply a vCard as a string or as a Component/VCard object.
+ * It's also possible to supply an array of strings or objects.
+ *
+ * @param mixed $objects
+ *
+ * @return void
+ */
+ function setObjects($objects) {
+
+ if (!is_array($objects)) {
+ $objects = [$objects];
+ }
+
+ $this->objects = [];
+ foreach ($objects as $object) {
+
+ if (is_string($object)) {
+
+ $vObj = Reader::read($object);
+ if (!$vObj instanceof Component\VCard) {
+ throw new \InvalidArgumentException('String could not be parsed as \\Sabre\\VObject\\Component\\VCard by setObjects');
+ }
+
+ $this->objects[] = $vObj;
+
+ } elseif ($object instanceof Component\VCard) {
+
+ $this->objects[] = $object;
+
+ } else {
+
+ throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component\\VCard arguments to setObjects');
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Sets the output format for the SUMMARY
+ *
+ * @param string $format
+ *
+ * @return void
+ */
+ function setFormat($format) {
+
+ $this->format = $format;
+
+ }
+
+ /**
+ * Parses the input data and returns a VCALENDAR.
+ *
+ * @return Component/VCalendar
+ */
+ function getResult() {
+
+ $calendar = new VCalendar();
+
+ foreach ($this->objects as $object) {
+
+ // Skip if there is no BDAY property.
+ if (!$object->select('BDAY')) {
+ continue;
+ }
+
+ // We've seen clients (ez-vcard) putting "BDAY:" properties
+ // without a value into vCards. If we come across those, we'll
+ // skip them.
+ if (empty($object->BDAY->getValue())) {
+ continue;
+ }
+
+ // We're always converting to vCard 4.0 so we can rely on the
+ // VCardConverter handling the X-APPLE-OMIT-YEAR property for us.
+ $object = $object->convert(Document::VCARD40);
+
+ // Skip if the card has no FN property.
+ if (!isset($object->FN)) {
+ continue;
+ }
+
+ // Skip if the BDAY property is not of the right type.
+ if (!$object->BDAY instanceof Property\VCard\DateAndOrTime) {
+ continue;
+ }
+
+ // Skip if we can't parse the BDAY value.
+ try {
+ $dateParts = DateTimeParser::parseVCardDateTime($object->BDAY->getValue());
+ } catch (InvalidDataException $e) {
+ continue;
+ }
+
+ // Set a year if it's not set.
+ $unknownYear = false;
+
+ if (!$dateParts['year']) {
+ $object->BDAY = self::DEFAULT_YEAR . '-' . $dateParts['month'] . '-' . $dateParts['date'];
+
+ $unknownYear = true;
+ }
+
+ // Create event.
+ $event = $calendar->add('VEVENT', [
+ 'SUMMARY' => sprintf($this->format, $object->FN->getValue()),
+ 'DTSTART' => new \DateTime($object->BDAY->getValue()),
+ 'RRULE' => 'FREQ=YEARLY',
+ 'TRANSP' => 'TRANSPARENT',
+ ]);
+
+ // add VALUE=date
+ $event->DTSTART['VALUE'] = 'DATE';
+
+ // Add X-SABRE-BDAY property.
+ if ($unknownYear) {
+ $event->add('X-SABRE-BDAY', 'BDAY', [
+ 'X-SABRE-VCARD-UID' => $object->UID->getValue(),
+ 'X-SABRE-VCARD-FN' => $object->FN->getValue(),
+ 'X-SABRE-OMIT-YEAR' => self::DEFAULT_YEAR,
+ ]);
+ } else {
+ $event->add('X-SABRE-BDAY', 'BDAY', [
+ 'X-SABRE-VCARD-UID' => $object->UID->getValue(),
+ 'X-SABRE-VCARD-FN' => $object->FN->getValue(),
+ ]);
+ }
+
+ }
+
+ return $calendar;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Cli.php b/vendor/sabre/vobject/lib/Cli.php
new file mode 100644
index 000000000..df7ac22f3
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Cli.php
@@ -0,0 +1,771 @@
+<?php
+
+namespace Sabre\VObject;
+
+use
+ InvalidArgumentException;
+
+/**
+ * This is the CLI interface for sabre-vobject.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Cli {
+
+ /**
+ * No output.
+ *
+ * @var bool
+ */
+ protected $quiet = false;
+
+ /**
+ * Help display.
+ *
+ * @var bool
+ */
+ protected $showHelp = false;
+
+ /**
+ * Wether to spit out 'mimedir' or 'json' format.
+ *
+ * @var string
+ */
+ protected $format;
+
+ /**
+ * JSON pretty print.
+ *
+ * @var bool
+ */
+ protected $pretty;
+
+ /**
+ * Source file.
+ *
+ * @var string
+ */
+ protected $inputPath;
+
+ /**
+ * Destination file.
+ *
+ * @var string
+ */
+ protected $outputPath;
+
+ /**
+ * output stream.
+ *
+ * @var resource
+ */
+ protected $stdout;
+
+ /**
+ * stdin.
+ *
+ * @var resource
+ */
+ protected $stdin;
+
+ /**
+ * stderr.
+ *
+ * @var resource
+ */
+ protected $stderr;
+
+ /**
+ * Input format (one of json or mimedir).
+ *
+ * @var string
+ */
+ protected $inputFormat;
+
+ /**
+ * Makes the parser less strict.
+ *
+ * @var bool
+ */
+ protected $forgiving = false;
+
+ /**
+ * Main function.
+ *
+ * @return int
+ */
+ function main(array $argv) {
+
+ // @codeCoverageIgnoreStart
+ // We cannot easily test this, so we'll skip it. Pretty basic anyway.
+
+ if (!$this->stderr) {
+ $this->stderr = fopen('php://stderr', 'w');
+ }
+ if (!$this->stdout) {
+ $this->stdout = fopen('php://stdout', 'w');
+ }
+ if (!$this->stdin) {
+ $this->stdin = fopen('php://stdin', 'r');
+ }
+
+ // @codeCoverageIgnoreEnd
+
+
+ try {
+
+ list($options, $positional) = $this->parseArguments($argv);
+
+ if (isset($options['q'])) {
+ $this->quiet = true;
+ }
+ $this->log($this->colorize('green', "sabre/vobject ") . $this->colorize('yellow', Version::VERSION));
+
+ foreach ($options as $name => $value) {
+
+ switch ($name) {
+
+ case 'q' :
+ // Already handled earlier.
+ break;
+ case 'h' :
+ case 'help' :
+ $this->showHelp();
+ return 0;
+ break;
+ case 'format' :
+ switch ($value) {
+
+ // jcard/jcal documents
+ case 'jcard' :
+ case 'jcal' :
+
+ // specific document versions
+ case 'vcard21' :
+ case 'vcard30' :
+ case 'vcard40' :
+ case 'icalendar20' :
+
+ // specific formats
+ case 'json' :
+ case 'mimedir' :
+
+ // icalendar/vcad
+ case 'icalendar' :
+ case 'vcard' :
+ $this->format = $value;
+ break;
+
+ default :
+ throw new InvalidArgumentException('Unknown format: ' . $value);
+
+ }
+ break;
+ case 'pretty' :
+ if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
+ $this->pretty = true;
+ }
+ break;
+ case 'forgiving' :
+ $this->forgiving = true;
+ break;
+ case 'inputformat' :
+ switch ($value) {
+ // json formats
+ case 'jcard' :
+ case 'jcal' :
+ case 'json' :
+ $this->inputFormat = 'json';
+ break;
+
+ // mimedir formats
+ case 'mimedir' :
+ case 'icalendar' :
+ case 'vcard' :
+ case 'vcard21' :
+ case 'vcard30' :
+ case 'vcard40' :
+ case 'icalendar20' :
+
+ $this->inputFormat = 'mimedir';
+ break;
+
+ default :
+ throw new InvalidArgumentException('Unknown format: ' . $value);
+
+ }
+ break;
+ default :
+ throw new InvalidArgumentException('Unknown option: ' . $name);
+
+ }
+
+ }
+
+ if (count($positional) === 0) {
+ $this->showHelp();
+ return 1;
+ }
+
+ if (count($positional) === 1) {
+ throw new InvalidArgumentException('Inputfile is a required argument');
+ }
+
+ if (count($positional) > 3) {
+ throw new InvalidArgumentException('Too many arguments');
+ }
+
+ if (!in_array($positional[0], ['validate', 'repair', 'convert', 'color'])) {
+ throw new InvalidArgumentException('Uknown command: ' . $positional[0]);
+ }
+
+ } catch (InvalidArgumentException $e) {
+ $this->showHelp();
+ $this->log('Error: ' . $e->getMessage(), 'red');
+ return 1;
+ }
+
+ $command = $positional[0];
+
+ $this->inputPath = $positional[1];
+ $this->outputPath = isset($positional[2]) ? $positional[2] : '-';
+
+ if ($this->outputPath !== '-') {
+ $this->stdout = fopen($this->outputPath, 'w');
+ }
+
+ if (!$this->inputFormat) {
+ if (substr($this->inputPath, -5) === '.json') {
+ $this->inputFormat = 'json';
+ } else {
+ $this->inputFormat = 'mimedir';
+ }
+ }
+ if (!$this->format) {
+ if (substr($this->outputPath, -5) === '.json') {
+ $this->format = 'json';
+ } else {
+ $this->format = 'mimedir';
+ }
+ }
+
+
+ $realCode = 0;
+
+ try {
+
+ while ($input = $this->readInput()) {
+
+ $returnCode = $this->$command($input);
+ if ($returnCode !== 0) $realCode = $returnCode;
+
+ }
+
+ } catch (EofException $e) {
+ // end of file
+ } catch (\Exception $e) {
+ $this->log('Error: ' . $e->getMessage(), 'red');
+ return 2;
+ }
+
+ return $realCode;
+
+ }
+
+ /**
+ * Shows the help message.
+ *
+ * @return void
+ */
+ protected function showHelp() {
+
+ $this->log('Usage:', 'yellow');
+ $this->log(" vobject [options] command [arguments]");
+ $this->log('');
+ $this->log('Options:', 'yellow');
+ $this->log($this->colorize('green', ' -q ') . "Don't output anything.");
+ $this->log($this->colorize('green', ' -help -h ') . "Display this help message.");
+ $this->log($this->colorize('green', ' --format ') . "Convert to a specific format. Must be one of: vcard, vcard21,");
+ $this->log($this->colorize('green', ' --forgiving ') . "Makes the parser less strict.");
+ $this->log(" vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.");
+ $this->log($this->colorize('green', ' --inputformat ') . "If the input format cannot be guessed from the extension, it");
+ $this->log(" must be specified here.");
+ // Only PHP 5.4 and up
+ if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
+ $this->log($this->colorize('green', ' --pretty ') . "json pretty-print.");
+ }
+ $this->log('');
+ $this->log('Commands:', 'yellow');
+ $this->log($this->colorize('green', ' validate') . ' source_file Validates a file for correctness.');
+ $this->log($this->colorize('green', ' repair') . ' source_file [output_file] Repairs a file.');
+ $this->log($this->colorize('green', ' convert') . ' source_file [output_file] Converts a file.');
+ $this->log($this->colorize('green', ' color') . ' source_file Colorize a file, useful for debbugging.');
+ $this->log(
+ <<<HELP
+
+If source_file is set as '-', STDIN will be used.
+If output_file is omitted, STDOUT will be used.
+All other output is sent to STDERR.
+
+HELP
+ );
+
+ $this->log('Examples:', 'yellow');
+ $this->log(' vobject convert contact.vcf contact.json');
+ $this->log(' vobject convert --format=vcard40 old.vcf new.vcf');
+ $this->log(' vobject convert --inputformat=json --format=mimedir - -');
+ $this->log(' vobject color calendar.ics');
+ $this->log('');
+ $this->log('https://github.com/fruux/sabre-vobject', 'purple');
+
+ }
+
+ /**
+ * Validates a VObject file.
+ *
+ * @param Component $vObj
+ *
+ * @return int
+ */
+ protected function validate(Component $vObj) {
+
+ $returnCode = 0;
+
+ switch ($vObj->name) {
+ case 'VCALENDAR' :
+ $this->log("iCalendar: " . (string)$vObj->VERSION);
+ break;
+ case 'VCARD' :
+ $this->log("vCard: " . (string)$vObj->VERSION);
+ break;
+ }
+
+ $warnings = $vObj->validate();
+ if (!count($warnings)) {
+ $this->log(" No warnings!");
+ } else {
+
+ $levels = [
+ 1 => 'REPAIRED',
+ 2 => 'WARNING',
+ 3 => 'ERROR',
+ ];
+ $returnCode = 2;
+ foreach ($warnings as $warn) {
+
+ $extra = '';
+ if ($warn['node'] instanceof Property) {
+ $extra = ' (property: "' . $warn['node']->name . '")';
+ }
+ $this->log(" [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
+
+ }
+
+ }
+
+ return $returnCode;
+
+ }
+
+ /**
+ * Repairs a VObject file.
+ *
+ * @param Component $vObj
+ *
+ * @return int
+ */
+ protected function repair(Component $vObj) {
+
+ $returnCode = 0;
+
+ switch ($vObj->name) {
+ case 'VCALENDAR' :
+ $this->log("iCalendar: " . (string)$vObj->VERSION);
+ break;
+ case 'VCARD' :
+ $this->log("vCard: " . (string)$vObj->VERSION);
+ break;
+ }
+
+ $warnings = $vObj->validate(Node::REPAIR);
+ if (!count($warnings)) {
+ $this->log(" No warnings!");
+ } else {
+
+ $levels = [
+ 1 => 'REPAIRED',
+ 2 => 'WARNING',
+ 3 => 'ERROR',
+ ];
+ $returnCode = 2;
+ foreach ($warnings as $warn) {
+
+ $extra = '';
+ if ($warn['node'] instanceof Property) {
+ $extra = ' (property: "' . $warn['node']->name . '")';
+ }
+ $this->log(" [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
+
+ }
+
+ }
+ fwrite($this->stdout, $vObj->serialize());
+
+ return $returnCode;
+
+ }
+
+ /**
+ * Converts a vObject file to a new format.
+ *
+ * @param Component $vObj
+ *
+ * @return int
+ */
+ protected function convert($vObj) {
+
+ $json = false;
+ $convertVersion = null;
+ $forceInput = null;
+
+ switch ($this->format) {
+ case 'json' :
+ $json = true;
+ if ($vObj->name === 'VCARD') {
+ $convertVersion = Document::VCARD40;
+ }
+ break;
+ case 'jcard' :
+ $json = true;
+ $forceInput = 'VCARD';
+ $convertVersion = Document::VCARD40;
+ break;
+ case 'jcal' :
+ $json = true;
+ $forceInput = 'VCALENDAR';
+ break;
+ case 'mimedir' :
+ case 'icalendar' :
+ case 'icalendar20' :
+ case 'vcard' :
+ break;
+ case 'vcard21' :
+ $convertVersion = Document::VCARD21;
+ break;
+ case 'vcard30' :
+ $convertVersion = Document::VCARD30;
+ break;
+ case 'vcard40' :
+ $convertVersion = Document::VCARD40;
+ break;
+
+ }
+
+ if ($forceInput && $vObj->name !== $forceInput) {
+ throw new \Exception('You cannot convert a ' . strtolower($vObj->name) . ' to ' . $this->format);
+ }
+ if ($convertVersion) {
+ $vObj = $vObj->convert($convertVersion);
+ }
+ if ($json) {
+ $jsonOptions = 0;
+ if ($this->pretty) {
+ $jsonOptions = JSON_PRETTY_PRINT;
+ }
+ fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
+ } else {
+ fwrite($this->stdout, $vObj->serialize());
+ }
+
+ return 0;
+
+ }
+
+ /**
+ * Colorizes a file.
+ *
+ * @param Component $vObj
+ *
+ * @return int
+ */
+ protected function color($vObj) {
+
+ fwrite($this->stdout, $this->serializeComponent($vObj));
+
+ }
+
+ /**
+ * Returns an ansi color string for a color name.
+ *
+ * @param string $color
+ *
+ * @return string
+ */
+ protected function colorize($color, $str, $resetTo = 'default') {
+
+ $colors = [
+ 'cyan' => '1;36',
+ 'red' => '1;31',
+ 'yellow' => '1;33',
+ 'blue' => '0;34',
+ 'green' => '0;32',
+ 'default' => '0',
+ 'purple' => '0;35',
+ ];
+ return "\033[" . $colors[$color] . 'm' . $str . "\033[" . $colors[$resetTo] . "m";
+
+ }
+
+ /**
+ * Writes out a string in specific color.
+ *
+ * @param string $color
+ * @param string $str
+ *
+ * @return void
+ */
+ protected function cWrite($color, $str) {
+
+ fwrite($this->stdout, $this->colorize($color, $str));
+
+ }
+
+ protected function serializeComponent(Component $vObj) {
+
+ $this->cWrite('cyan', 'BEGIN');
+ $this->cWrite('red', ':');
+ $this->cWrite('yellow', $vObj->name . "\n");
+
+ /**
+ * Gives a component a 'score' for sorting purposes.
+ *
+ * This is solely used by the childrenSort method.
+ *
+ * A higher score means the item will be lower in the list.
+ * To avoid score collisions, each "score category" has a reasonable
+ * space to accomodate elements. The $key is added to the $score to
+ * preserve the original relative order of elements.
+ *
+ * @param int $key
+ * @param array $array
+ *
+ * @return int
+ */
+ $sortScore = function($key, $array) {
+
+ if ($array[$key] instanceof Component) {
+
+ // We want to encode VTIMEZONE first, this is a personal
+ // preference.
+ if ($array[$key]->name === 'VTIMEZONE') {
+ $score = 300000000;
+ return $score + $key;
+ } else {
+ $score = 400000000;
+ return $score + $key;
+ }
+ } else {
+ // Properties get encoded first
+ // VCARD version 4.0 wants the VERSION property to appear first
+ if ($array[$key] instanceof Property) {
+ if ($array[$key]->name === 'VERSION') {
+ $score = 100000000;
+ return $score + $key;
+ } else {
+ // All other properties
+ $score = 200000000;
+ return $score + $key;
+ }
+ }
+ }
+
+ };
+
+ $children = $vObj->children();
+ $tmp = $children;
+ uksort(
+ $children,
+ function($a, $b) use ($sortScore, $tmp) {
+
+ $sA = $sortScore($a, $tmp);
+ $sB = $sortScore($b, $tmp);
+
+ return $sA - $sB;
+
+ }
+ );
+
+ foreach ($children as $child) {
+ if ($child instanceof Component) {
+ $this->serializeComponent($child);
+ } else {
+ $this->serializeProperty($child);
+ }
+ }
+
+ $this->cWrite('cyan', 'END');
+ $this->cWrite('red', ':');
+ $this->cWrite('yellow', $vObj->name . "\n");
+
+ }
+
+ /**
+ * Colorizes a property.
+ *
+ * @param Property $property
+ *
+ * @return void
+ */
+ protected function serializeProperty(Property $property) {
+
+ if ($property->group) {
+ $this->cWrite('default', $property->group);
+ $this->cWrite('red', '.');
+ }
+
+ $this->cWrite('yellow', $property->name);
+
+ foreach ($property->parameters as $param) {
+
+ $this->cWrite('red', ';');
+ $this->cWrite('blue', $param->serialize());
+
+ }
+ $this->cWrite('red', ':');
+
+ if ($property instanceof Property\Binary) {
+
+ $this->cWrite('default', 'embedded binary stripped. (' . strlen($property->getValue()) . ' bytes)');
+
+ } else {
+
+ $parts = $property->getParts();
+ $first1 = true;
+ // Looping through property values
+ foreach ($parts as $part) {
+ if ($first1) {
+ $first1 = false;
+ } else {
+ $this->cWrite('red', $property->delimiter);
+ }
+ $first2 = true;
+ // Looping through property sub-values
+ foreach ((array)$part as $subPart) {
+ if ($first2) {
+ $first2 = false;
+ } else {
+ // The sub-value delimiter is always comma
+ $this->cWrite('red', ',');
+ }
+
+ $subPart = strtr(
+ $subPart,
+ [
+ '\\' => $this->colorize('purple', '\\\\', 'green'),
+ ';' => $this->colorize('purple', '\;', 'green'),
+ ',' => $this->colorize('purple', '\,', 'green'),
+ "\n" => $this->colorize('purple', "\\n\n\t", 'green'),
+ "\r" => "",
+ ]
+ );
+
+ $this->cWrite('green', $subPart);
+ }
+ }
+
+ }
+ $this->cWrite("default", "\n");
+
+ }
+
+ /**
+ * Parses the list of arguments.
+ *
+ * @param array $argv
+ *
+ * @return void
+ */
+ protected function parseArguments(array $argv) {
+
+ $positional = [];
+ $options = [];
+
+ for ($ii = 0; $ii < count($argv); $ii++) {
+
+ // Skipping the first argument.
+ if ($ii === 0) continue;
+
+ $v = $argv[$ii];
+
+ if (substr($v, 0, 2) === '--') {
+ // This is a long-form option.
+ $optionName = substr($v, 2);
+ $optionValue = true;
+ if (strpos($optionName, '=')) {
+ list($optionName, $optionValue) = explode('=', $optionName);
+ }
+ $options[$optionName] = $optionValue;
+ } elseif (substr($v, 0, 1) === '-' && strlen($v) > 1) {
+ // This is a short-form option.
+ foreach (str_split(substr($v, 1)) as $option) {
+ $options[$option] = true;
+ }
+
+ } else {
+
+ $positional[] = $v;
+
+ }
+
+ }
+
+ return [$options, $positional];
+
+ }
+
+ protected $parser;
+
+ /**
+ * Reads the input file.
+ *
+ * @return Component
+ */
+ protected function readInput() {
+
+ if (!$this->parser) {
+ if ($this->inputPath !== '-') {
+ $this->stdin = fopen($this->inputPath, 'r');
+ }
+
+ if ($this->inputFormat === 'mimedir') {
+ $this->parser = new Parser\MimeDir($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
+ } else {
+ $this->parser = new Parser\Json($this->stdin, ($this->forgiving ? Reader::OPTION_FORGIVING : 0));
+ }
+ }
+
+ return $this->parser->parse();
+
+ }
+
+ /**
+ * Sends a message to STDERR.
+ *
+ * @param string $msg
+ *
+ * @return void
+ */
+ protected function log($msg, $color = 'default') {
+
+ if (!$this->quiet) {
+ if ($color !== 'default') {
+ $msg = $this->colorize($color, $msg);
+ }
+ fwrite($this->stderr, $msg . "\n");
+ }
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Component.php b/vendor/sabre/vobject/lib/Component.php
new file mode 100644
index 000000000..9a10ed3f8
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component.php
@@ -0,0 +1,700 @@
+<?php
+
+namespace Sabre\VObject;
+
+use Sabre\Xml;
+
+/**
+ * Component.
+ *
+ * A component represents a group of properties, such as VCALENDAR, VEVENT, or
+ * VCARD.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Component extends Node {
+
+ /**
+ * Component name.
+ *
+ * This will contain a string such as VEVENT, VTODO, VCALENDAR, VCARD.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * A list of properties and/or sub-components.
+ *
+ * @var array
+ */
+ protected $children = [];
+
+ /**
+ * Creates a new component.
+ *
+ * You can specify the children either in key=>value syntax, in which case
+ * properties will automatically be created, or you can just pass a list of
+ * Component and Property object.
+ *
+ * By default, a set of sensible values will be added to the component. For
+ * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
+ * ensure that this does not happen, set $defaults to false.
+ *
+ * @param Document $root
+ * @param string $name such as VCALENDAR, VEVENT.
+ * @param array $children
+ * @param bool $defaults
+ *
+ * @return void
+ */
+ function __construct(Document $root, $name, array $children = [], $defaults = true) {
+
+ $this->name = strtoupper($name);
+ $this->root = $root;
+
+ if ($defaults) {
+ // This is a terribly convoluted way to do this, but this ensures
+ // that the order of properties as they are specified in both
+ // defaults and the childrens list, are inserted in the object in a
+ // natural way.
+ $list = $this->getDefaults();
+ $nodes = [];
+ foreach ($children as $key => $value) {
+ if ($value instanceof Node) {
+ if (isset($list[$value->name])) {
+ unset($list[$value->name]);
+ }
+ $nodes[] = $value;
+ } else {
+ $list[$key] = $value;
+ }
+ }
+ foreach ($list as $key => $value) {
+ $this->add($key, $value);
+ }
+ foreach ($nodes as $node) {
+ $this->add($node);
+ }
+ } else {
+ foreach ($children as $k => $child) {
+ if ($child instanceof Node) {
+ // Component or Property
+ $this->add($child);
+ } else {
+
+ // Property key=>value
+ $this->add($k, $child);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Adds a new property or component, and returns the new item.
+ *
+ * This method has 3 possible signatures:
+ *
+ * add(Component $comp) // Adds a new component
+ * add(Property $prop) // Adds a new property
+ * add($name, $value, array $parameters = []) // Adds a new property
+ * add($name, array $children = []) // Adds a new component
+ * by name.
+ *
+ * @return Node
+ */
+ function add() {
+
+ $arguments = func_get_args();
+
+ if ($arguments[0] instanceof Node) {
+ if (isset($arguments[1])) {
+ throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject Node');
+ }
+ $arguments[0]->parent = $this;
+ $newNode = $arguments[0];
+
+ } elseif (is_string($arguments[0])) {
+
+ $newNode = call_user_func_array([$this->root, 'create'], $arguments);
+
+ } else {
+
+ throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Node or a string');
+
+ }
+
+ $name = $newNode->name;
+ if (isset($this->children[$name])) {
+ $this->children[$name][] = $newNode;
+ } else {
+ $this->children[$name] = [$newNode];
+ }
+ return $newNode;
+
+ }
+
+ /**
+ * This method removes a component or property from this component.
+ *
+ * You can either specify the item by name (like DTSTART), in which case
+ * all properties/components with that name will be removed, or you can
+ * pass an instance of a property or component, in which case only that
+ * exact item will be removed.
+ *
+ * @param string|Property|Component $item
+ * @return void
+ */
+ function remove($item) {
+
+ if (is_string($item)) {
+ // If there's no dot in the name, it's an exact property name and
+ // we can just wipe out all those properties.
+ //
+ if (strpos($item, '.') === false) {
+ unset($this->children[strtoupper($item)]);
+ return;
+ }
+ // If there was a dot, we need to ask select() to help us out and
+ // then we just call remove recursively.
+ foreach ($this->select($item) as $child) {
+
+ $this->remove($child);
+
+ }
+ } else {
+ foreach ($this->select($item->name) as $k => $child) {
+ if ($child === $item) {
+ unset($this->children[$item->name][$k]);
+ return;
+ }
+ }
+ }
+
+ throw new \InvalidArgumentException('The item you passed to remove() was not a child of this component');
+
+ }
+
+ /**
+ * Returns a flat list of all the properties and components in this
+ * component.
+ *
+ * @return array
+ */
+ function children() {
+
+ $result = [];
+ foreach ($this->children as $childGroup) {
+ $result = array_merge($result, $childGroup);
+ }
+ return $result;
+
+ }
+
+ /**
+ * This method only returns a list of sub-components. Properties are
+ * ignored.
+ *
+ * @return array
+ */
+ function getComponents() {
+
+ $result = [];
+
+ foreach ($this->children as $childGroup) {
+ foreach ($childGroup as $child) {
+ if ($child instanceof self) {
+ $result[] = $child;
+ }
+ }
+ }
+ return $result;
+
+ }
+
+ /**
+ * Returns an array with elements that match the specified name.
+ *
+ * This function is also aware of MIME-Directory groups (as they appear in
+ * vcards). This means that if a property is grouped as "HOME.EMAIL", it
+ * will also be returned when searching for just "EMAIL". If you want to
+ * search for a property in a specific group, you can select on the entire
+ * string ("HOME.EMAIL"). If you want to search on a specific property that
+ * has not been assigned a group, specify ".EMAIL".
+ *
+ * @param string $name
+ * @return array
+ */
+ function select($name) {
+
+ $group = null;
+ $name = strtoupper($name);
+ if (strpos($name, '.') !== false) {
+ list($group, $name) = explode('.', $name, 2);
+ }
+ if ($name === '') $name = null;
+
+ if (!is_null($name)) {
+
+ $result = isset($this->children[$name]) ? $this->children[$name] : [];
+
+ if (is_null($group)) {
+ return $result;
+ } else {
+ // If we have a group filter as well, we need to narrow it down
+ // more.
+ return array_filter(
+ $result,
+ function($child) use ($group) {
+
+ return $child instanceof Property && strtoupper($child->group) === $group;
+
+ }
+ );
+ }
+
+ }
+
+ // If we got to this point, it means there was no 'name' specified for
+ // searching, implying that this is a group-only search.
+ $result = [];
+ foreach ($this->children as $childGroup) {
+
+ foreach ($childGroup as $child) {
+
+ if ($child instanceof Property && strtoupper($child->group) === $group) {
+ $result[] = $child;
+ }
+
+ }
+
+ }
+ return $result;
+
+ }
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ function serialize() {
+
+ $str = "BEGIN:" . $this->name . "\r\n";
+
+ /**
+ * Gives a component a 'score' for sorting purposes.
+ *
+ * This is solely used by the childrenSort method.
+ *
+ * A higher score means the item will be lower in the list.
+ * To avoid score collisions, each "score category" has a reasonable
+ * space to accomodate elements. The $key is added to the $score to
+ * preserve the original relative order of elements.
+ *
+ * @param int $key
+ * @param array $array
+ *
+ * @return int
+ */
+ $sortScore = function($key, $array) {
+
+ if ($array[$key] instanceof Component) {
+
+ // We want to encode VTIMEZONE first, this is a personal
+ // preference.
+ if ($array[$key]->name === 'VTIMEZONE') {
+ $score = 300000000;
+ return $score + $key;
+ } else {
+ $score = 400000000;
+ return $score + $key;
+ }
+ } else {
+ // Properties get encoded first
+ // VCARD version 4.0 wants the VERSION property to appear first
+ if ($array[$key] instanceof Property) {
+ if ($array[$key]->name === 'VERSION') {
+ $score = 100000000;
+ return $score + $key;
+ } else {
+ // All other properties
+ $score = 200000000;
+ return $score + $key;
+ }
+ }
+ }
+
+ };
+
+ $children = $this->children();
+ $tmp = $children;
+ uksort(
+ $children,
+ function($a, $b) use ($sortScore, $tmp) {
+
+ $sA = $sortScore($a, $tmp);
+ $sB = $sortScore($b, $tmp);
+
+ return $sA - $sB;
+
+ }
+ );
+
+ foreach ($children as $child) $str .= $child->serialize();
+ $str .= "END:" . $this->name . "\r\n";
+
+ return $str;
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in JSON. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ function jsonSerialize() {
+
+ $components = [];
+ $properties = [];
+
+ foreach ($this->children as $childGroup) {
+ foreach ($childGroup as $child) {
+ if ($child instanceof self) {
+ $components[] = $child->jsonSerialize();
+ } else {
+ $properties[] = $child->jsonSerialize();
+ }
+ }
+ }
+
+ return [
+ strtolower($this->name),
+ $properties,
+ $components
+ ];
+
+ }
+
+ /**
+ * This method serializes the data into XML. This is used to create xCard or
+ * xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ function xmlSerialize(Xml\Writer $writer) {
+
+ $components = [];
+ $properties = [];
+
+ foreach ($this->children as $childGroup) {
+ foreach ($childGroup as $child) {
+ if ($child instanceof self) {
+ $components[] = $child;
+ } else {
+ $properties[] = $child;
+ }
+ }
+ }
+
+ $writer->startElement(strtolower($this->name));
+
+ if (!empty($properties)) {
+
+ $writer->startElement('properties');
+
+ foreach ($properties as $property) {
+ $property->xmlSerialize($writer);
+ }
+
+ $writer->endElement();
+
+ }
+
+ if (!empty($components)) {
+
+ $writer->startElement('components');
+
+ foreach ($components as $component) {
+ $component->xmlSerialize($writer);
+ }
+
+ $writer->endElement();
+ }
+
+ $writer->endElement();
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return [];
+
+ }
+
+ /* Magic property accessors {{{ */
+
+ /**
+ * Using 'get' you will either get a property or component.
+ *
+ * If there were no child-elements found with the specified name,
+ * null is returned.
+ *
+ * To use this, this may look something like this:
+ *
+ * $event = $calendar->VEVENT;
+ *
+ * @param string $name
+ *
+ * @return Property
+ */
+ function __get($name) {
+
+ if ($name === 'children') {
+
+ throw new \RuntimeException('Starting sabre/vobject 4.0 the children property is now protected. You should use the children() method instead');
+
+ }
+
+ $matches = $this->select($name);
+ if (count($matches) === 0) {
+ return;
+ } else {
+ $firstMatch = current($matches);
+ /** @var $firstMatch Property */
+ $firstMatch->setIterator(new ElementList(array_values($matches)));
+ return $firstMatch;
+ }
+
+ }
+
+ /**
+ * This method checks if a sub-element with the specified name exists.
+ *
+ * @param string $name
+ *
+ * @return bool
+ */
+ function __isset($name) {
+
+ $matches = $this->select($name);
+ return count($matches) > 0;
+
+ }
+
+ /**
+ * Using the setter method you can add properties or subcomponents.
+ *
+ * You can either pass a Component, Property
+ * object, or a string to automatically create a Property.
+ *
+ * If the item already exists, it will be removed. If you want to add
+ * a new item with the same name, always use the add() method.
+ *
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return void
+ */
+ function __set($name, $value) {
+
+ $name = strtoupper($name);
+ $this->remove($name);
+ if ($value instanceof self || $value instanceof Property) {
+ $this->add($value);
+ } else {
+ $this->add($name, $value);
+ }
+ }
+
+ /**
+ * Removes all properties and components within this component with the
+ * specified name.
+ *
+ * @param string $name
+ *
+ * @return void
+ */
+ function __unset($name) {
+
+ $this->remove($name);
+
+ }
+
+ /* }}} */
+
+ /**
+ * This method is automatically called when the object is cloned.
+ * Specifically, this will ensure all child elements are also cloned.
+ *
+ * @return void
+ */
+ function __clone() {
+
+ foreach ($this->children as $childName => $childGroup) {
+ foreach ($childGroup as $key => $child) {
+ $clonedChild = clone $child;
+ $clonedChild->parent = $this;
+ $clonedChild->root = $this->root;
+ $this->children[$childName][$key] = $clonedChild;
+ }
+ }
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * It is also possible to specify defaults and severity levels for
+ * violating the rule.
+ *
+ * See the VEVENT implementation for getValidationRules for a more complex
+ * example.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [];
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ * Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
+ * Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on).
+ * 2 - A warning.
+ * 3 - An error.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $rules = $this->getValidationRules();
+ $defaults = $this->getDefaults();
+
+ $propertyCounters = [];
+
+ $messages = [];
+
+ foreach ($this->children() as $child) {
+ $name = strtoupper($child->name);
+ if (!isset($propertyCounters[$name])) {
+ $propertyCounters[$name] = 1;
+ } else {
+ $propertyCounters[$name]++;
+ }
+ $messages = array_merge($messages, $child->validate($options));
+ }
+
+ foreach ($rules as $propName => $rule) {
+
+ switch ($rule) {
+ case '0' :
+ if (isset($propertyCounters[$propName])) {
+ $messages[] = [
+ 'level' => 3,
+ 'message' => $propName . ' MUST NOT appear in a ' . $this->name . ' component',
+ 'node' => $this,
+ ];
+ }
+ break;
+ case '1' :
+ if (!isset($propertyCounters[$propName]) || $propertyCounters[$propName] !== 1) {
+ $repaired = false;
+ if ($options & self::REPAIR && isset($defaults[$propName])) {
+ $this->add($propName, $defaults[$propName]);
+ $repaired = true;
+ }
+ $messages[] = [
+ 'level' => $repaired ? 1 : 3,
+ 'message' => $propName . ' MUST appear exactly once in a ' . $this->name . ' component',
+ 'node' => $this,
+ ];
+ }
+ break;
+ case '+' :
+ if (!isset($propertyCounters[$propName]) || $propertyCounters[$propName] < 1) {
+ $messages[] = [
+ 'level' => 3,
+ 'message' => $propName . ' MUST appear at least once in a ' . $this->name . ' component',
+ 'node' => $this,
+ ];
+ }
+ break;
+ case '*' :
+ break;
+ case '?' :
+ if (isset($propertyCounters[$propName]) && $propertyCounters[$propName] > 1) {
+ $messages[] = [
+ 'level' => 3,
+ 'message' => $propName . ' MUST NOT appear more than once in a ' . $this->name . ' component',
+ 'node' => $this,
+ ];
+ }
+ break;
+
+ }
+
+ }
+ return $messages;
+
+ }
+
+ /**
+ * Call this method on a document if you're done using it.
+ *
+ * It's intended to remove all circular references, so PHP can easily clean
+ * it up.
+ *
+ * @return void
+ */
+ function destroy() {
+
+ parent::destroy();
+ foreach ($this->children as $childGroup) {
+ foreach ($childGroup as $child) {
+ $child->destroy();
+ }
+ }
+ $this->children = [];
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Component/Available.php b/vendor/sabre/vobject/lib/Component/Available.php
new file mode 100644
index 000000000..b3aaf08af
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/Available.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use Sabre\VObject;
+
+/**
+ * The Available sub-component.
+ *
+ * This component adds functionality to a component, specific for AVAILABLE
+ * components.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Ivan Enderlin
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Available extends VObject\Component {
+
+ /**
+ * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
+ * component.
+ *
+ * We use the DTSTART and DTEND or DURATION to determine this.
+ *
+ * The returned value is an array containing DateTimeImmutable instances.
+ * If either the start or end is 'unbounded' its value will be null
+ * instead.
+ *
+ * @return array
+ */
+ function getEffectiveStartEnd() {
+
+ $effectiveStart = $this->DTSTART->getDateTime();
+ if (isset($this->DTEND)) {
+ $effectiveEnd = $this->DTEND->getDateTime();
+ } else {
+ $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
+ }
+
+ return [$effectiveStart, $effectiveEnd];
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'UID' => 1,
+ 'DTSTART' => 1,
+ 'DTSTAMP' => 1,
+
+ 'DTEND' => '?',
+ 'DURATION' => '?',
+
+ 'CREATED' => '?',
+ 'DESCRIPTION' => '?',
+ 'LAST-MODIFIED' => '?',
+ 'RECURRENCE-ID' => '?',
+ 'RRULE' => '?',
+ 'SUMMARY' => '?',
+
+ 'CATEGORIES' => '*',
+ 'COMMENT' => '*',
+ 'CONTACT' => '*',
+ 'EXDATE' => '*',
+ 'RDATE' => '*',
+
+ 'AVAILABLE' => '*',
+ ];
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ * Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
+ * Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on).
+ * 2 - A warning.
+ * 3 - An error.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $result = parent::validate($options);
+
+ if (isset($this->DTEND) && isset($this->DURATION)) {
+ $result[] = [
+ 'level' => 3,
+ 'message' => 'DTEND and DURATION cannot both be present',
+ 'node' => $this
+ ];
+ }
+
+ return $result;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VAlarm.php b/vendor/sabre/vobject/lib/Component/VAlarm.php
index 2f86c44fd..8cbd572e6 100644
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VAlarm.php
+++ b/vendor/sabre/vobject/lib/Component/VAlarm.php
@@ -1,16 +1,20 @@
<?php
namespace Sabre\VObject\Component;
+
use Sabre\VObject;
+use Sabre\VObject\InvalidDataException;
+use DateTimeInterface;
+use DateTimeImmutable;
/**
- * VAlarm component
+ * VAlarm component.
*
* This component contains some additional functionality specific for VALARMs.
*
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
* @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ * @license http://sabre.io/license/ Modified BSD License
*/
class VAlarm extends VObject\Component {
@@ -19,12 +23,12 @@ class VAlarm extends VObject\Component {
*
* This ignores repeated alarm, only the first trigger is returned.
*
- * @return DateTime
+ * @return DateTimeImmutable
*/
- public function getEffectiveTriggerTime() {
+ function getEffectiveTriggerTime() {
$trigger = $this->TRIGGER;
- if(!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') {
+ if (!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') {
$triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER);
$related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START';
@@ -37,28 +41,28 @@ class VAlarm extends VObject\Component {
$propName = 'DTSTART';
}
- $effectiveTrigger = clone $parentComponent->$propName->getDateTime();
- $effectiveTrigger->add($triggerDuration);
+ $effectiveTrigger = $parentComponent->$propName->getDateTime();
+ $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
} else {
if ($parentComponent->name === 'VTODO') {
$endProp = 'DUE';
} elseif ($parentComponent->name === 'VEVENT') {
$endProp = 'DTEND';
} else {
- throw new \LogicException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT');
+ throw new InvalidDataException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT');
}
if (isset($parentComponent->$endProp)) {
- $effectiveTrigger = clone $parentComponent->$endProp->getDateTime();
- $effectiveTrigger->add($triggerDuration);
+ $effectiveTrigger = $parentComponent->$endProp->getDateTime();
+ $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
} elseif (isset($parentComponent->DURATION)) {
- $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime();
+ $effectiveTrigger = $parentComponent->DTSTART->getDateTime();
$duration = VObject\DateTimeParser::parseDuration($parentComponent->DURATION);
- $effectiveTrigger->add($duration);
- $effectiveTrigger->add($triggerDuration);
+ $effectiveTrigger = $effectiveTrigger->add($duration);
+ $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
} else {
- $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime();
- $effectiveTrigger->add($triggerDuration);
+ $effectiveTrigger = $parentComponent->DTSTART->getDateTime();
+ $effectiveTrigger = $effectiveTrigger->add($triggerDuration);
}
}
} else {
@@ -75,24 +79,25 @@ class VAlarm extends VObject\Component {
* The rules used to determine if an event falls within the specified
* time-range is based on the CalDAV specification.
*
- * @param \DateTime $start
- * @param \DateTime $end
+ * @param DateTime $start
+ * @param DateTime $end
+ *
* @return bool
*/
- public function isInTimeRange(\DateTime $start, \DateTime $end) {
+ function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
$effectiveTrigger = $this->getEffectiveTriggerTime();
if (isset($this->DURATION)) {
$duration = VObject\DateTimeParser::parseDuration($this->DURATION);
- $repeat = (string)$this->repeat;
+ $repeat = (string)$this->REPEAT;
if (!$repeat) {
$repeat = 1;
}
$period = new \DatePeriod($effectiveTrigger, $duration, (int)$repeat);
- foreach($period as $occurrence) {
+ foreach ($period as $occurrence) {
if ($start <= $occurrence && $end > $occurrence) {
return true;
@@ -105,4 +110,33 @@ class VAlarm extends VObject\Component {
}
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'ACTION' => 1,
+ 'TRIGGER' => 1,
+
+ 'DURATION' => '?',
+ 'REPEAT' => '?',
+
+ 'ATTACH' => '?',
+ ];
+
+ }
+
}
diff --git a/vendor/sabre/vobject/lib/Component/VAvailability.php b/vendor/sabre/vobject/lib/Component/VAvailability.php
new file mode 100644
index 000000000..66b3310c5
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VAvailability.php
@@ -0,0 +1,156 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use DateTimeInterface;
+use Sabre\VObject;
+
+/**
+ * The VAvailability component.
+ *
+ * This component adds functionality to a component, specific for VAVAILABILITY
+ * components.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Ivan Enderlin
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VAvailability extends VObject\Component {
+
+ /**
+ * Returns true or false depending on if the event falls in the specified
+ * time-range. This is used for filtering purposes.
+ *
+ * The rules used to determine if an event falls within the specified
+ * time-range is based on:
+ *
+ * https://tools.ietf.org/html/draft-daboo-calendar-availability-05#section-3.1
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ *
+ * @return bool
+ */
+ function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
+
+ list($effectiveStart, $effectiveEnd) = $this->getEffectiveStartEnd();
+ return (
+ (is_null($effectiveStart) || $start < $effectiveEnd) &&
+ (is_null($effectiveEnd) || $end > $effectiveStart)
+ );
+
+ }
+
+ /**
+ * Returns the 'effective start' and 'effective end' of this VAVAILABILITY
+ * component.
+ *
+ * We use the DTSTART and DTEND or DURATION to determine this.
+ *
+ * The returned value is an array containing DateTimeImmutable instances.
+ * If either the start or end is 'unbounded' its value will be null
+ * instead.
+ *
+ * @return array
+ */
+ function getEffectiveStartEnd() {
+
+ $effectiveStart = null;
+ $effectiveEnd = null;
+
+ if (isset($this->DTSTART)) {
+ $effectiveStart = $this->DTSTART->getDateTime();
+ }
+ if (isset($this->DTEND)) {
+ $effectiveEnd = $this->DTEND->getDateTime();
+ } elseif ($effectiveStart && isset($this->DURATION)) {
+ $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
+ }
+
+ return [$effectiveStart, $effectiveEnd];
+
+ }
+
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'UID' => 1,
+ 'DTSTAMP' => 1,
+
+ 'BUSYTYPE' => '?',
+ 'CLASS' => '?',
+ 'CREATED' => '?',
+ 'DESCRIPTION' => '?',
+ 'DTSTART' => '?',
+ 'LAST-MODIFIED' => '?',
+ 'ORGANIZER' => '?',
+ 'PRIORITY' => '?',
+ 'SEQUENCE' => '?',
+ 'SUMMARY' => '?',
+ 'URL' => '?',
+ 'DTEND' => '?',
+ 'DURATION' => '?',
+
+ 'CATEGORIES' => '*',
+ 'COMMENT' => '*',
+ 'CONTACT' => '*',
+ ];
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ * Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
+ * Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on).
+ * 2 - A warning.
+ * 3 - An error.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $result = parent::validate($options);
+
+ if (isset($this->DTEND) && isset($this->DURATION)) {
+ $result[] = [
+ 'level' => 3,
+ 'message' => 'DTEND and DURATION cannot both be present',
+ 'node' => $this
+ ];
+ }
+
+ return $result;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Component/VCalendar.php b/vendor/sabre/vobject/lib/Component/VCalendar.php
new file mode 100644
index 000000000..988db9dc2
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VCalendar.php
@@ -0,0 +1,561 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use DateTimeInterface;
+use DateTimeZone;
+use Sabre\VObject;
+use Sabre\VObject\Component;
+use Sabre\VObject\Property;
+use Sabre\VObject\Recur\EventIterator;
+use Sabre\VObject\Recur\NoInstancesException;
+use Sabre\VObject\InvalidDataException;
+
+/**
+ * The VCalendar component.
+ *
+ * This component adds functionality to a component, specific for a VCALENDAR.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VCalendar extends VObject\Document {
+
+ /**
+ * The default name for this component.
+ *
+ * This should be 'VCALENDAR' or 'VCARD'.
+ *
+ * @var string
+ */
+ static $defaultName = 'VCALENDAR';
+
+ /**
+ * This is a list of components, and which classes they should map to.
+ *
+ * @var array
+ */
+ static $componentMap = [
+ 'VCALENDAR' => 'Sabre\\VObject\\Component\\VCalendar',
+ 'VALARM' => 'Sabre\\VObject\\Component\\VAlarm',
+ 'VEVENT' => 'Sabre\\VObject\\Component\\VEvent',
+ 'VFREEBUSY' => 'Sabre\\VObject\\Component\\VFreeBusy',
+ 'VAVAILABILITY' => 'Sabre\\VObject\\Component\\VAvailability',
+ 'AVAILABLE' => 'Sabre\\VObject\\Component\\Available',
+ 'VJOURNAL' => 'Sabre\\VObject\\Component\\VJournal',
+ 'VTIMEZONE' => 'Sabre\\VObject\\Component\\VTimeZone',
+ 'VTODO' => 'Sabre\\VObject\\Component\\VTodo',
+ ];
+
+ /**
+ * List of value-types, and which classes they map to.
+ *
+ * @var array
+ */
+ static $valueMap = [
+ 'BINARY' => 'Sabre\\VObject\\Property\\Binary',
+ 'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean',
+ 'CAL-ADDRESS' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
+ 'DATE' => 'Sabre\\VObject\\Property\\ICalendar\\Date',
+ 'DATE-TIME' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
+ 'FLOAT' => 'Sabre\\VObject\\Property\\FloatValue',
+ 'INTEGER' => 'Sabre\\VObject\\Property\\IntegerValue',
+ 'PERIOD' => 'Sabre\\VObject\\Property\\ICalendar\\Period',
+ 'RECUR' => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
+ 'TEXT' => 'Sabre\\VObject\\Property\\Text',
+ 'TIME' => 'Sabre\\VObject\\Property\\Time',
+ 'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
+ 'URI' => 'Sabre\\VObject\\Property\\Uri',
+ 'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset',
+ ];
+
+ /**
+ * List of properties, and which classes they map to.
+ *
+ * @var array
+ */
+ static $propertyMap = [
+ // Calendar properties
+ 'CALSCALE' => 'Sabre\\VObject\\Property\\FlatText',
+ 'METHOD' => 'Sabre\\VObject\\Property\\FlatText',
+ 'PRODID' => 'Sabre\\VObject\\Property\\FlatText',
+ 'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
+
+ // Component properties
+ 'ATTACH' => 'Sabre\\VObject\\Property\\Uri',
+ 'CATEGORIES' => 'Sabre\\VObject\\Property\\Text',
+ 'CLASS' => 'Sabre\\VObject\\Property\\FlatText',
+ 'COMMENT' => 'Sabre\\VObject\\Property\\FlatText',
+ 'DESCRIPTION' => 'Sabre\\VObject\\Property\\FlatText',
+ 'GEO' => 'Sabre\\VObject\\Property\\FloatValue',
+ 'LOCATION' => 'Sabre\\VObject\\Property\\FlatText',
+ 'PERCENT-COMPLETE' => 'Sabre\\VObject\\Property\\IntegerValue',
+ 'PRIORITY' => 'Sabre\\VObject\\Property\\IntegerValue',
+ 'RESOURCES' => 'Sabre\\VObject\\Property\\Text',
+ 'STATUS' => 'Sabre\\VObject\\Property\\FlatText',
+ 'SUMMARY' => 'Sabre\\VObject\\Property\\FlatText',
+
+ // Date and Time Component Properties
+ 'COMPLETED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'DTEND' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'DUE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'DTSTART' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'DURATION' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
+ 'FREEBUSY' => 'Sabre\\VObject\\Property\\ICalendar\\Period',
+ 'TRANSP' => 'Sabre\\VObject\\Property\\FlatText',
+
+ // Time Zone Component Properties
+ 'TZID' => 'Sabre\\VObject\\Property\\FlatText',
+ 'TZNAME' => 'Sabre\\VObject\\Property\\FlatText',
+ 'TZOFFSETFROM' => 'Sabre\\VObject\\Property\\UtcOffset',
+ 'TZOFFSETTO' => 'Sabre\\VObject\\Property\\UtcOffset',
+ 'TZURL' => 'Sabre\\VObject\\Property\\Uri',
+
+ // Relationship Component Properties
+ 'ATTENDEE' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
+ 'CONTACT' => 'Sabre\\VObject\\Property\\FlatText',
+ 'ORGANIZER' => 'Sabre\\VObject\\Property\\ICalendar\\CalAddress',
+ 'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'RELATED-TO' => 'Sabre\\VObject\\Property\\FlatText',
+ 'URL' => 'Sabre\\VObject\\Property\\Uri',
+ 'UID' => 'Sabre\\VObject\\Property\\FlatText',
+
+ // Recurrence Component Properties
+ 'EXDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'RDATE' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'RRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur',
+ 'EXRULE' => 'Sabre\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545
+
+ // Alarm Component Properties
+ 'ACTION' => 'Sabre\\VObject\\Property\\FlatText',
+ 'REPEAT' => 'Sabre\\VObject\\Property\\IntegerValue',
+ 'TRIGGER' => 'Sabre\\VObject\\Property\\ICalendar\\Duration',
+
+ // Change Management Component Properties
+ 'CREATED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'DTSTAMP' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'SEQUENCE' => 'Sabre\\VObject\\Property\\IntegerValue',
+
+ // Request Status
+ 'REQUEST-STATUS' => 'Sabre\\VObject\\Property\\Text',
+
+ // Additions from draft-daboo-valarm-extensions-04
+ 'ALARM-AGENT' => 'Sabre\\VObject\\Property\\Text',
+ 'ACKNOWLEDGED' => 'Sabre\\VObject\\Property\\ICalendar\\DateTime',
+ 'PROXIMITY' => 'Sabre\\VObject\\Property\\Text',
+ 'DEFAULT-ALARM' => 'Sabre\\VObject\\Property\\Boolean',
+
+ // Additions from draft-daboo-calendar-availability-05
+ 'BUSYTYPE' => 'Sabre\\VObject\\Property\\Text',
+
+ ];
+
+ /**
+ * Returns the current document type.
+ *
+ * @return int
+ */
+ function getDocumentType() {
+
+ return self::ICALENDAR20;
+
+ }
+
+ /**
+ * Returns a list of all 'base components'. For instance, if an Event has
+ * a recurrence rule, and one instance is overridden, the overridden event
+ * will have the same UID, but will be excluded from this list.
+ *
+ * VTIMEZONE components will always be excluded.
+ *
+ * @param string $componentName filter by component name
+ *
+ * @return VObject\Component[]
+ */
+ function getBaseComponents($componentName = null) {
+
+ $isBaseComponent = function($component) {
+
+ if (!$component instanceof VObject\Component) {
+ return false;
+ }
+ if ($component->name === 'VTIMEZONE') {
+ return false;
+ }
+ if (isset($component->{'RECURRENCE-ID'})) {
+ return false;
+ }
+ return true;
+
+ };
+
+ if ($componentName) {
+ // Early exit
+ return array_filter(
+ $this->select($componentName),
+ $isBaseComponent
+ );
+ }
+
+ $components = [];
+ foreach ($this->children as $childGroup) {
+
+ foreach ($childGroup as $child) {
+
+ if (!$child instanceof Component) {
+ // If one child is not a component, they all are so we skip
+ // the entire group.
+ continue 2;
+ }
+ if ($isBaseComponent($child)) {
+ $components[] = $child;
+ }
+
+ }
+
+ }
+ return $components;
+
+ }
+
+ /**
+ * Returns the first component that is not a VTIMEZONE, and does not have
+ * an RECURRENCE-ID.
+ *
+ * If there is no such component, null will be returned.
+ *
+ * @param string $componentName filter by component name
+ *
+ * @return VObject\Component|null
+ */
+ function getBaseComponent($componentName = null) {
+
+ $isBaseComponent = function($component) {
+
+ if (!$component instanceof VObject\Component) {
+ return false;
+ }
+ if ($component->name === 'VTIMEZONE') {
+ return false;
+ }
+ if (isset($component->{'RECURRENCE-ID'})) {
+ return false;
+ }
+ return true;
+
+ };
+
+ if ($componentName) {
+ foreach ($this->select($componentName) as $child) {
+ if ($isBaseComponent($child)) {
+ return $child;
+ }
+ }
+ return null;
+ }
+
+ // Searching all components
+ foreach ($this->children as $childGroup) {
+ foreach ($childGroup as $child) {
+ if ($isBaseComponent($child)) {
+ return $child;
+ }
+ }
+
+ }
+ return null;
+
+ }
+
+ /**
+ * Expand all events in this VCalendar object and return a new VCalendar
+ * with the expanded events.
+ *
+ * If this calendar object, has events with recurrence rules, this method
+ * can be used to expand the event into multiple sub-events.
+ *
+ * Each event will be stripped from it's recurrence information, and only
+ * the instances of the event in the specified timerange will be left
+ * alone.
+ *
+ * In addition, this method will cause timezone information to be stripped,
+ * and normalized to UTC.
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ * @param DateTimeZone $timeZone reference timezone for floating dates and
+ * times.
+ * @return VCalendar
+ */
+ function expand(DateTimeInterface $start, DateTimeInterface $end, DateTimeZone $timeZone = null) {
+
+ $newChildren = [];
+ $recurringEvents = [];
+
+ if (!$timeZone) {
+ $timeZone = new DateTimeZone('UTC');
+ }
+
+ $stripTimezones = function(Component $component) use ($timeZone, &$stripTimezones) {
+
+ foreach ($component->children() as $componentChild) {
+ if ($componentChild instanceof Property\ICalendar\DateTime && $componentChild->hasTime()) {
+
+ $dt = $componentChild->getDateTimes($timeZone);
+ // We only need to update the first timezone, because
+ // setDateTimes will match all other timezones to the
+ // first.
+ $dt[0] = $dt[0]->setTimeZone(new DateTimeZone('UTC'));
+ $componentChild->setDateTimes($dt);
+ } elseif ($componentChild instanceof Component) {
+ $stripTimezones($componentChild);
+ }
+
+ }
+ return $component;
+
+ };
+
+ foreach ($this->children() as $child) {
+
+ if ($child instanceof Property && $child->name !== 'PRODID') {
+ // We explictly want to ignore PRODID, because we want to
+ // overwrite it with our own.
+ $newChildren[] = clone $child;
+ } elseif ($child instanceof Component && $child->name !== 'VTIMEZONE') {
+
+ // We're also stripping all VTIMEZONE objects because we're
+ // converting everything to UTC.
+ if ($child->name === 'VEVENT' && (isset($child->{'RECURRENCE-ID'}) || isset($child->RRULE) || isset($child->RDATE))) {
+ // Handle these a bit later.
+ $uid = (string)$child->UID;
+ if (!$uid) {
+ throw new InvalidDataException('Every VEVENT object must have a UID property');
+ }
+ if (isset($recurringEvents[$uid])) {
+ $recurringEvents[$uid][] = clone $child;
+ } else {
+ $recurringEvents[$uid] = [clone $child];
+ }
+ } elseif ($child->name === 'VEVENT' && $child->isInTimeRange($start, $end)) {
+ $newChildren[] = $stripTimezones(clone $child);
+ }
+
+ }
+
+ }
+
+ foreach ($recurringEvents as $events) {
+
+ try {
+ $it = new EventIterator($events, $timeZone);
+
+ } catch (NoInstancesException $e) {
+ // This event is recurring, but it doesn't have a single
+ // instance. We are skipping this event from the output
+ // entirely.
+ continue;
+ }
+ $it->fastForward($start);
+
+ while ($it->valid() && $it->getDTStart() < $end) {
+
+ if ($it->getDTEnd() > $start) {
+
+ $newChildren[] = $stripTimezones($it->getEventObject());
+
+ }
+ $it->next();
+
+ }
+
+ }
+
+ return new self($newChildren);
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return [
+ 'VERSION' => '2.0',
+ 'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
+ 'CALSCALE' => 'GREGORIAN',
+ ];
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'PRODID' => 1,
+ 'VERSION' => 1,
+
+ 'CALSCALE' => '?',
+ 'METHOD' => '?',
+ ];
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ * Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
+ * Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on).
+ * 2 - A warning.
+ * 3 - An error.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $warnings = parent::validate($options);
+
+ if ($ver = $this->VERSION) {
+ if ((string)$ver !== '2.0') {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
+ 'node' => $this,
+ ];
+ }
+
+ }
+
+ $uidList = [];
+ $componentsFound = 0;
+ $componentTypes = [];
+
+ foreach ($this->children() as $child) {
+ if ($child instanceof Component) {
+ $componentsFound++;
+
+ if (!in_array($child->name, ['VEVENT', 'VTODO', 'VJOURNAL'])) {
+ continue;
+ }
+ $componentTypes[] = $child->name;
+
+ $uid = (string)$child->UID;
+ $isMaster = isset($child->{'RECURRENCE-ID'}) ? 0 : 1;
+ if (isset($uidList[$uid])) {
+ $uidList[$uid]['count']++;
+ if ($isMaster && $uidList[$uid]['hasMaster']) {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'More than one master object was found for the object with UID ' . $uid,
+ 'node' => $this,
+ ];
+ }
+ $uidList[$uid]['hasMaster'] += $isMaster;
+ } else {
+ $uidList[$uid] = [
+ 'count' => 1,
+ 'hasMaster' => $isMaster,
+ ];
+ }
+
+ }
+ }
+
+ if ($componentsFound === 0) {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'An iCalendar object must have at least 1 component.',
+ 'node' => $this,
+ ];
+ }
+
+ if ($options & self::PROFILE_CALDAV) {
+ if (count($uidList) > 1) {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'A calendar object on a CalDAV server may only have components with the same UID.',
+ 'node' => $this,
+ ];
+ }
+ if (count($componentTypes) === 0) {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'A calendar object on a CalDAV server must have at least 1 component (VTODO, VEVENT, VJOURNAL).',
+ 'node' => $this,
+ ];
+ }
+ if (count(array_unique($componentTypes)) > 1) {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'A calendar object on a CalDAV server may only have 1 type of component (VEVENT, VTODO or VJOURNAL).',
+ 'node' => $this,
+ ];
+ }
+
+ if (isset($this->METHOD)) {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'A calendar object on a CalDAV server MUST NOT have a METHOD property.',
+ 'node' => $this,
+ ];
+ }
+ }
+
+ return $warnings;
+
+ }
+
+ /**
+ * Returns all components with a specific UID value.
+ *
+ * @return array
+ */
+ function getByUID($uid) {
+
+ return array_filter($this->getComponents(), function($item) use ($uid) {
+
+ if (!$itemUid = $item->select('UID')) {
+ return false;
+ }
+ $itemUid = current($itemUid)->getValue();
+ return $uid === $itemUid;
+
+ });
+
+ }
+
+
+}
diff --git a/vendor/sabre/vobject/lib/Component/VCard.php b/vendor/sabre/vobject/lib/Component/VCard.php
new file mode 100644
index 000000000..3c05191a9
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VCard.php
@@ -0,0 +1,553 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use Sabre\VObject;
+use Sabre\Xml;
+
+/**
+ * The VCard component.
+ *
+ * This component represents the BEGIN:VCARD and END:VCARD found in every
+ * vcard.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VCard extends VObject\Document {
+
+ /**
+ * The default name for this component.
+ *
+ * This should be 'VCALENDAR' or 'VCARD'.
+ *
+ * @var string
+ */
+ static $defaultName = 'VCARD';
+
+ /**
+ * Caching the version number.
+ *
+ * @var int
+ */
+ private $version = null;
+
+ /**
+ * This is a list of components, and which classes they should map to.
+ *
+ * @var array
+ */
+ static $componentMap = [
+ 'VCARD' => 'Sabre\\VObject\\Component\\VCard',
+ ];
+
+ /**
+ * List of value-types, and which classes they map to.
+ *
+ * @var array
+ */
+ static $valueMap = [
+ 'BINARY' => 'Sabre\\VObject\\Property\\Binary',
+ 'BOOLEAN' => 'Sabre\\VObject\\Property\\Boolean',
+ 'CONTENT-ID' => 'Sabre\\VObject\\Property\\FlatText', // vCard 2.1 only
+ 'DATE' => 'Sabre\\VObject\\Property\\VCard\\Date',
+ 'DATE-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateTime',
+ 'DATE-AND-OR-TIME' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime', // vCard only
+ 'FLOAT' => 'Sabre\\VObject\\Property\\FloatValue',
+ 'INTEGER' => 'Sabre\\VObject\\Property\\IntegerValue',
+ 'LANGUAGE-TAG' => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
+ 'TIMESTAMP' => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
+ 'TEXT' => 'Sabre\\VObject\\Property\\Text',
+ 'TIME' => 'Sabre\\VObject\\Property\\Time',
+ 'UNKNOWN' => 'Sabre\\VObject\\Property\\Unknown', // jCard / jCal-only.
+ 'URI' => 'Sabre\\VObject\\Property\\Uri',
+ 'URL' => 'Sabre\\VObject\\Property\\Uri', // vCard 2.1 only
+ 'UTC-OFFSET' => 'Sabre\\VObject\\Property\\UtcOffset',
+ ];
+
+ /**
+ * List of properties, and which classes they map to.
+ *
+ * @var array
+ */
+ static $propertyMap = [
+
+ // vCard 2.1 properties and up
+ 'N' => 'Sabre\\VObject\\Property\\Text',
+ 'FN' => 'Sabre\\VObject\\Property\\FlatText',
+ 'PHOTO' => 'Sabre\\VObject\\Property\\Binary',
+ 'BDAY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
+ 'ADR' => 'Sabre\\VObject\\Property\\Text',
+ 'LABEL' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+ 'TEL' => 'Sabre\\VObject\\Property\\FlatText',
+ 'EMAIL' => 'Sabre\\VObject\\Property\\FlatText',
+ 'MAILER' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+ 'GEO' => 'Sabre\\VObject\\Property\\FlatText',
+ 'TITLE' => 'Sabre\\VObject\\Property\\FlatText',
+ 'ROLE' => 'Sabre\\VObject\\Property\\FlatText',
+ 'LOGO' => 'Sabre\\VObject\\Property\\Binary',
+ // 'AGENT' => 'Sabre\\VObject\\Property\\', // Todo: is an embedded vCard. Probably rare, so
+ // not supported at the moment
+ 'ORG' => 'Sabre\\VObject\\Property\\Text',
+ 'NOTE' => 'Sabre\\VObject\\Property\\FlatText',
+ 'REV' => 'Sabre\\VObject\\Property\\VCard\\TimeStamp',
+ 'SOUND' => 'Sabre\\VObject\\Property\\FlatText',
+ 'URL' => 'Sabre\\VObject\\Property\\Uri',
+ 'UID' => 'Sabre\\VObject\\Property\\FlatText',
+ 'VERSION' => 'Sabre\\VObject\\Property\\FlatText',
+ 'KEY' => 'Sabre\\VObject\\Property\\FlatText',
+ 'TZ' => 'Sabre\\VObject\\Property\\Text',
+
+ // vCard 3.0 properties
+ 'CATEGORIES' => 'Sabre\\VObject\\Property\\Text',
+ 'SORT-STRING' => 'Sabre\\VObject\\Property\\FlatText',
+ 'PRODID' => 'Sabre\\VObject\\Property\\FlatText',
+ 'NICKNAME' => 'Sabre\\VObject\\Property\\Text',
+ 'CLASS' => 'Sabre\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+
+ // rfc2739 properties
+ 'FBURL' => 'Sabre\\VObject\\Property\\Uri',
+ 'CAPURI' => 'Sabre\\VObject\\Property\\Uri',
+ 'CALURI' => 'Sabre\\VObject\\Property\\Uri',
+ 'CALADRURI' => 'Sabre\\VObject\\Property\\Uri',
+
+ // rfc4770 properties
+ 'IMPP' => 'Sabre\\VObject\\Property\\Uri',
+
+ // vCard 4.0 properties
+ 'SOURCE' => 'Sabre\\VObject\\Property\\Uri',
+ 'XML' => 'Sabre\\VObject\\Property\\FlatText',
+ 'ANNIVERSARY' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
+ 'CLIENTPIDMAP' => 'Sabre\\VObject\\Property\\Text',
+ 'LANG' => 'Sabre\\VObject\\Property\\VCard\\LanguageTag',
+ 'GENDER' => 'Sabre\\VObject\\Property\\Text',
+ 'KIND' => 'Sabre\\VObject\\Property\\FlatText',
+ 'MEMBER' => 'Sabre\\VObject\\Property\\Uri',
+ 'RELATED' => 'Sabre\\VObject\\Property\\Uri',
+
+ // rfc6474 properties
+ 'BIRTHPLACE' => 'Sabre\\VObject\\Property\\FlatText',
+ 'DEATHPLACE' => 'Sabre\\VObject\\Property\\FlatText',
+ 'DEATHDATE' => 'Sabre\\VObject\\Property\\VCard\\DateAndOrTime',
+
+ // rfc6715 properties
+ 'EXPERTISE' => 'Sabre\\VObject\\Property\\FlatText',
+ 'HOBBY' => 'Sabre\\VObject\\Property\\FlatText',
+ 'INTEREST' => 'Sabre\\VObject\\Property\\FlatText',
+ 'ORG-DIRECTORY' => 'Sabre\\VObject\\Property\\FlatText',
+
+ ];
+
+ /**
+ * Returns the current document type.
+ *
+ * @return int
+ */
+ function getDocumentType() {
+
+ if (!$this->version) {
+
+ $version = (string)$this->VERSION;
+
+ switch ($version) {
+ case '2.1' :
+ $this->version = self::VCARD21;
+ break;
+ case '3.0' :
+ $this->version = self::VCARD30;
+ break;
+ case '4.0' :
+ $this->version = self::VCARD40;
+ break;
+ default :
+ // We don't want to cache the version if it's unknown,
+ // because we might get a version property in a bit.
+ return self::UNKNOWN;
+ }
+ }
+
+ return $this->version;
+
+ }
+
+ /**
+ * Converts the document to a different vcard version.
+ *
+ * Use one of the VCARD constants for the target. This method will return
+ * a copy of the vcard in the new version.
+ *
+ * At the moment the only supported conversion is from 3.0 to 4.0.
+ *
+ * If input and output version are identical, a clone is returned.
+ *
+ * @param int $target
+ *
+ * @return VCard
+ */
+ function convert($target) {
+
+ $converter = new VObject\VCardConverter();
+ return $converter->convert($this, $target);
+
+ }
+
+ /**
+ * VCards with version 2.1, 3.0 and 4.0 are found.
+ *
+ * If the VCARD doesn't know its version, 2.1 is assumed.
+ */
+ const DEFAULT_VERSION = self::VCARD21;
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on)
+ * 2 - An inconsequential issue
+ * 3 - A severe issue.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $warnings = [];
+
+ $versionMap = [
+ self::VCARD21 => '2.1',
+ self::VCARD30 => '3.0',
+ self::VCARD40 => '4.0',
+ ];
+
+ $version = $this->select('VERSION');
+ if (count($version) === 1) {
+ $version = (string)$this->VERSION;
+ if ($version !== '2.1' && $version !== '3.0' && $version !== '4.0') {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
+ 'node' => $this,
+ ];
+ if ($options & self::REPAIR) {
+ $this->VERSION = $versionMap[self::DEFAULT_VERSION];
+ }
+ }
+ if ($version === '2.1' && ($options & self::PROFILE_CARDDAV)) {
+ $warnings[] = [
+ 'level' => 3,
+ 'message' => 'CardDAV servers are not allowed to accept vCard 2.1.',
+ 'node' => $this,
+ ];
+ }
+
+ }
+ $uid = $this->select('UID');
+ if (count($uid) === 0) {
+ if ($options & self::PROFILE_CARDDAV) {
+ // Required for CardDAV
+ $warningLevel = 3;
+ $message = 'vCards on CardDAV servers MUST have a UID property.';
+ } else {
+ // Not required for regular vcards
+ $warningLevel = 2;
+ $message = 'Adding a UID to a vCard property is recommended.';
+ }
+ if ($options & self::REPAIR) {
+ $this->UID = VObject\UUIDUtil::getUUID();
+ $warningLevel = 1;
+ }
+ $warnings[] = [
+ 'level' => $warningLevel,
+ 'message' => $message,
+ 'node' => $this,
+ ];
+ }
+
+ $fn = $this->select('FN');
+ if (count($fn) !== 1) {
+
+ $repaired = false;
+ if (($options & self::REPAIR) && count($fn) === 0) {
+ // We're going to try to see if we can use the contents of the
+ // N property.
+ if (isset($this->N)) {
+ $value = explode(';', (string)$this->N);
+ if (isset($value[1]) && $value[1]) {
+ $this->FN = $value[1] . ' ' . $value[0];
+ } else {
+ $this->FN = $value[0];
+ }
+ $repaired = true;
+
+ // Otherwise, the ORG property may work
+ } elseif (isset($this->ORG)) {
+ $this->FN = (string)$this->ORG;
+ $repaired = true;
+ }
+
+ }
+ $warnings[] = [
+ 'level' => $repaired ? 1 : 3,
+ 'message' => 'The FN property must appear in the VCARD component exactly 1 time',
+ 'node' => $this,
+ ];
+ }
+
+ return array_merge(
+ parent::validate($options),
+ $warnings
+ );
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'ADR' => '*',
+ 'ANNIVERSARY' => '?',
+ 'BDAY' => '?',
+ 'CALADRURI' => '*',
+ 'CALURI' => '*',
+ 'CATEGORIES' => '*',
+ 'CLIENTPIDMAP' => '*',
+ 'EMAIL' => '*',
+ 'FBURL' => '*',
+ 'IMPP' => '*',
+ 'GENDER' => '?',
+ 'GEO' => '*',
+ 'KEY' => '*',
+ 'KIND' => '?',
+ 'LANG' => '*',
+ 'LOGO' => '*',
+ 'MEMBER' => '*',
+ 'N' => '?',
+ 'NICKNAME' => '*',
+ 'NOTE' => '*',
+ 'ORG' => '*',
+ 'PHOTO' => '*',
+ 'PRODID' => '?',
+ 'RELATED' => '*',
+ 'REV' => '?',
+ 'ROLE' => '*',
+ 'SOUND' => '*',
+ 'SOURCE' => '*',
+ 'TEL' => '*',
+ 'TITLE' => '*',
+ 'TZ' => '*',
+ 'URL' => '*',
+ 'VERSION' => '1',
+ 'XML' => '*',
+
+ // FN is commented out, because it's already handled by the
+ // validate function, which may also try to repair it.
+ // 'FN' => '+',
+ 'UID' => '?',
+ ];
+
+ }
+
+ /**
+ * Returns a preferred field.
+ *
+ * VCards can indicate wether a field such as ADR, TEL or EMAIL is
+ * preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
+ * being a number between 1 and 100).
+ *
+ * If neither of those parameters are specified, the first is returned, if
+ * a field with that name does not exist, null is returned.
+ *
+ * @param string $fieldName
+ *
+ * @return VObject\Property|null
+ */
+ function preferred($propertyName) {
+
+ $preferred = null;
+ $lastPref = 101;
+ foreach ($this->select($propertyName) as $field) {
+
+ $pref = 101;
+ if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
+ $pref = 1;
+ } elseif (isset($field['PREF'])) {
+ $pref = $field['PREF']->getValue();
+ }
+
+ if ($pref < $lastPref || is_null($preferred)) {
+ $preferred = $field;
+ $lastPref = $pref;
+ }
+
+ }
+ return $preferred;
+
+ }
+
+ /**
+ * Returns a property with a specific TYPE value (ADR, TEL, or EMAIL).
+ *
+ * This function will return null if the property does not exist. If there are
+ * multiple properties with the same TYPE value, only one will be returned.
+ *
+ * @param string $propertyName
+ * @param string $type
+ *
+ * @return VObject\Property|null
+ */
+ function getByType($propertyName, $type) {
+ foreach ($this->select($propertyName) as $field) {
+ if (isset($field['TYPE']) && $field['TYPE']->has($type)) {
+ return $field;
+ }
+ }
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return [
+ 'VERSION' => '4.0',
+ 'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
+ 'UID' => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
+ ];
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in json. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ function jsonSerialize() {
+
+ // A vcard does not have sub-components, so we're overriding this
+ // method to remove that array element.
+ $properties = [];
+
+ foreach ($this->children() as $child) {
+ $properties[] = $child->jsonSerialize();
+ }
+
+ return [
+ strtolower($this->name),
+ $properties,
+ ];
+
+ }
+
+ /**
+ * This method serializes the data into XML. This is used to create xCard or
+ * xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ function xmlSerialize(Xml\Writer $writer) {
+
+ $propertiesByGroup = [];
+
+ foreach ($this->children() as $property) {
+
+ $group = $property->group;
+
+ if (!isset($propertiesByGroup[$group])) {
+ $propertiesByGroup[$group] = [];
+ }
+
+ $propertiesByGroup[$group][] = $property;
+
+ }
+
+ $writer->startElement(strtolower($this->name));
+
+ foreach ($propertiesByGroup as $group => $properties) {
+
+ if (!empty($group)) {
+
+ $writer->startElement('group');
+ $writer->writeAttribute('name', strtolower($group));
+
+ }
+
+ foreach ($properties as $property) {
+ switch ($property->name) {
+
+ case 'VERSION':
+ continue;
+
+ case 'XML':
+ $value = $property->getParts();
+ $fragment = new Xml\Element\XmlFragment($value[0]);
+ $writer->write($fragment);
+ break;
+
+ default:
+ $property->xmlSerialize($writer);
+ break;
+
+ }
+ }
+
+ if (!empty($group)) {
+ $writer->endElement();
+ }
+
+ }
+
+ $writer->endElement();
+
+ }
+
+ /**
+ * Returns the default class for a property name.
+ *
+ * @param string $propertyName
+ *
+ * @return string
+ */
+ function getClassNameForPropertyName($propertyName) {
+
+ $className = parent::getClassNameForPropertyName($propertyName);
+
+ // In vCard 4, BINARY no longer exists, and we need URI instead.
+ if ($className == 'Sabre\\VObject\\Property\\Binary' && $this->getDocumentType() === self::VCARD40) {
+ return 'Sabre\\VObject\\Property\\Uri';
+ }
+ return $className;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Component/VEvent.php b/vendor/sabre/vobject/lib/Component/VEvent.php
new file mode 100644
index 000000000..7f6861190
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VEvent.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use DateTimeInterface;
+use Sabre\VObject;
+use Sabre\VObject\Recur\EventIterator;
+use Sabre\VObject\Recur\NoInstancesException;
+
+/**
+ * VEvent component.
+ *
+ * This component contains some additional functionality specific for VEVENT's.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VEvent extends VObject\Component {
+
+ /**
+ * Returns true or false depending on if the event falls in the specified
+ * time-range. This is used for filtering purposes.
+ *
+ * The rules used to determine if an event falls within the specified
+ * time-range is based on the CalDAV specification.
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ *
+ * @return bool
+ */
+ function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
+
+ if ($this->RRULE) {
+
+ try {
+
+ $it = new EventIterator($this, null, $start->getTimezone());
+
+ } catch (NoInstancesException $e) {
+
+ // If we've catched this exception, there are no instances
+ // for the event that fall into the specified time-range.
+ return false;
+
+ }
+
+ $it->fastForward($start);
+
+ // We fast-forwarded to a spot where the end-time of the
+ // recurrence instance exceeded the start of the requested
+ // time-range.
+ //
+ // If the starttime of the recurrence did not exceed the
+ // end of the time range as well, we have a match.
+ return ($it->getDTStart() < $end && $it->getDTEnd() > $start);
+
+ }
+
+ $effectiveStart = $this->DTSTART->getDateTime($start->getTimezone());
+ if (isset($this->DTEND)) {
+
+ // The DTEND property is considered non inclusive. So for a 3 day
+ // event in july, dtstart and dtend would have to be July 1st and
+ // July 4th respectively.
+ //
+ // See:
+ // http://tools.ietf.org/html/rfc5545#page-54
+ $effectiveEnd = $this->DTEND->getDateTime($end->getTimezone());
+
+ } elseif (isset($this->DURATION)) {
+ $effectiveEnd = $effectiveStart->add(VObject\DateTimeParser::parseDuration($this->DURATION));
+ } elseif (!$this->DTSTART->hasTime()) {
+ $effectiveEnd = $effectiveStart->modify('+1 day');
+ } else {
+ $effectiveEnd = $effectiveStart;
+ }
+ return (
+ ($start < $effectiveEnd) && ($end > $effectiveStart)
+ );
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return [
+ 'UID' => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
+ 'DTSTAMP' => date('Ymd\\THis\\Z'),
+ ];
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ $hasMethod = isset($this->parent->METHOD);
+ return [
+ 'UID' => 1,
+ 'DTSTAMP' => 1,
+ 'DTSTART' => $hasMethod ? '?' : '1',
+ 'CLASS' => '?',
+ 'CREATED' => '?',
+ 'DESCRIPTION' => '?',
+ 'GEO' => '?',
+ 'LAST-MODIFIED' => '?',
+ 'LOCATION' => '?',
+ 'ORGANIZER' => '?',
+ 'PRIORITY' => '?',
+ 'SEQUENCE' => '?',
+ 'STATUS' => '?',
+ 'SUMMARY' => '?',
+ 'TRANSP' => '?',
+ 'URL' => '?',
+ 'RECURRENCE-ID' => '?',
+ 'RRULE' => '?',
+ 'DTEND' => '?',
+ 'DURATION' => '?',
+
+ 'ATTACH' => '*',
+ 'ATTENDEE' => '*',
+ 'CATEGORIES' => '*',
+ 'COMMENT' => '*',
+ 'CONTACT' => '*',
+ 'EXDATE' => '*',
+ 'REQUEST-STATUS' => '*',
+ 'RELATED-TO' => '*',
+ 'RESOURCES' => '*',
+ 'RDATE' => '*',
+ ];
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Component/VFreeBusy.php b/vendor/sabre/vobject/lib/Component/VFreeBusy.php
new file mode 100644
index 000000000..72294cc9f
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VFreeBusy.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use DateTimeInterface;
+use Sabre\VObject;
+
+/**
+ * The VFreeBusy component.
+ *
+ * This component adds functionality to a component, specific for VFREEBUSY
+ * components.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VFreeBusy extends VObject\Component {
+
+ /**
+ * Checks based on the contained FREEBUSY information, if a timeslot is
+ * available.
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ *
+ * @return bool
+ */
+ function isFree(DateTimeInterface $start, DatetimeInterface $end) {
+
+ foreach ($this->select('FREEBUSY') as $freebusy) {
+
+ // We are only interested in FBTYPE=BUSY (the default),
+ // FBTYPE=BUSY-TENTATIVE or FBTYPE=BUSY-UNAVAILABLE.
+ if (isset($freebusy['FBTYPE']) && strtoupper(substr((string)$freebusy['FBTYPE'], 0, 4)) !== 'BUSY') {
+ continue;
+ }
+
+ // The freebusy component can hold more than 1 value, separated by
+ // commas.
+ $periods = explode(',', (string)$freebusy);
+
+ foreach ($periods as $period) {
+ // Every period is formatted as [start]/[end]. The start is an
+ // absolute UTC time, the end may be an absolute UTC time, or
+ // duration (relative) value.
+ list($busyStart, $busyEnd) = explode('/', $period);
+
+ $busyStart = VObject\DateTimeParser::parse($busyStart);
+ $busyEnd = VObject\DateTimeParser::parse($busyEnd);
+ if ($busyEnd instanceof \DateInterval) {
+ $busyEnd = $busyStart->add($busyEnd);
+ }
+
+ if ($start < $busyEnd && $end > $busyStart) {
+ return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'UID' => 1,
+ 'DTSTAMP' => 1,
+
+ 'CONTACT' => '?',
+ 'DTSTART' => '?',
+ 'DTEND' => '?',
+ 'ORGANIZER' => '?',
+ 'URL' => '?',
+
+ 'ATTENDEE' => '*',
+ 'COMMENT' => '*',
+ 'FREEBUSY' => '*',
+ 'REQUEST-STATUS' => '*',
+ ];
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Component/VJournal.php b/vendor/sabre/vobject/lib/Component/VJournal.php
new file mode 100644
index 000000000..a1b1a863d
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VJournal.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use DateTimeInterface;
+use Sabre\VObject;
+
+/**
+ * VJournal component.
+ *
+ * This component contains some additional functionality specific for VJOURNALs.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VJournal extends VObject\Component {
+
+ /**
+ * Returns true or false depending on if the event falls in the specified
+ * time-range. This is used for filtering purposes.
+ *
+ * The rules used to determine if an event falls within the specified
+ * time-range is based on the CalDAV specification.
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ *
+ * @return bool
+ */
+ function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
+
+ $dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
+ if ($dtstart) {
+ $effectiveEnd = $dtstart;
+ if (!$this->DTSTART->hasTime()) {
+ $effectiveEnd = $effectiveEnd->modify('+1 day');
+ }
+
+ return ($start <= $effectiveEnd && $end > $dtstart);
+
+ }
+ return false;
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'UID' => 1,
+ 'DTSTAMP' => 1,
+
+ 'CLASS' => '?',
+ 'CREATED' => '?',
+ 'DTSTART' => '?',
+ 'LAST-MODIFIED' => '?',
+ 'ORGANIZER' => '?',
+ 'RECURRENCE-ID' => '?',
+ 'SEQUENCE' => '?',
+ 'STATUS' => '?',
+ 'SUMMARY' => '?',
+ 'URL' => '?',
+
+ 'RRULE' => '?',
+
+ 'ATTACH' => '*',
+ 'ATTENDEE' => '*',
+ 'CATEGORIES' => '*',
+ 'COMMENT' => '*',
+ 'CONTACT' => '*',
+ 'DESCRIPTION' => '*',
+ 'EXDATE' => '*',
+ 'RELATED-TO' => '*',
+ 'RDATE' => '*',
+ ];
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return [
+ 'UID' => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
+ 'DTSTAMP' => date('Ymd\\THis\\Z'),
+ ];
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Component/VTimeZone.php b/vendor/sabre/vobject/lib/Component/VTimeZone.php
new file mode 100644
index 000000000..d5d886947
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VTimeZone.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use Sabre\VObject;
+
+/**
+ * The VTimeZone component.
+ *
+ * This component adds functionality to a component, specific for VTIMEZONE
+ * components.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VTimeZone extends VObject\Component {
+
+ /**
+ * Returns the PHP DateTimeZone for this VTIMEZONE component.
+ *
+ * If we can't accurately determine the timezone, this method will return
+ * UTC.
+ *
+ * @return \DateTimeZone
+ */
+ function getTimeZone() {
+
+ return VObject\TimeZoneUtil::getTimeZone((string)$this->TZID, $this->root);
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'TZID' => 1,
+
+ 'LAST-MODIFIED' => '?',
+ 'TZURL' => '?',
+
+ // At least 1 STANDARD or DAYLIGHT must appear, or more. But both
+ // cannot appear in the same VTIMEZONE.
+ //
+ // The validator is not specific yet to pick this up, so these
+ // rules are too loose.
+ 'STANDARD' => '*',
+ 'DAYLIGHT' => '*',
+ ];
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Component/VTodo.php b/vendor/sabre/vobject/lib/Component/VTodo.php
new file mode 100644
index 000000000..144ced694
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Component/VTodo.php
@@ -0,0 +1,193 @@
+<?php
+
+namespace Sabre\VObject\Component;
+
+use DateTimeInterface;
+use Sabre\VObject;
+
+/**
+ * VTodo component.
+ *
+ * This component contains some additional functionality specific for VTODOs.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VTodo extends VObject\Component {
+
+ /**
+ * Returns true or false depending on if the event falls in the specified
+ * time-range. This is used for filtering purposes.
+ *
+ * The rules used to determine if an event falls within the specified
+ * time-range is based on the CalDAV specification.
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ *
+ * @return bool
+ */
+ function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end) {
+
+ $dtstart = isset($this->DTSTART) ? $this->DTSTART->getDateTime() : null;
+ $duration = isset($this->DURATION) ? VObject\DateTimeParser::parseDuration($this->DURATION) : null;
+ $due = isset($this->DUE) ? $this->DUE->getDateTime() : null;
+ $completed = isset($this->COMPLETED) ? $this->COMPLETED->getDateTime() : null;
+ $created = isset($this->CREATED) ? $this->CREATED->getDateTime() : null;
+
+ if ($dtstart) {
+ if ($duration) {
+ $effectiveEnd = $dtstart->add($duration);
+ return $start <= $effectiveEnd && $end > $dtstart;
+ } elseif ($due) {
+ return
+ ($start < $due || $start <= $dtstart) &&
+ ($end > $dtstart || $end >= $due);
+ } else {
+ return $start <= $dtstart && $end > $dtstart;
+ }
+ }
+ if ($due) {
+ return ($start < $due && $end >= $due);
+ }
+ if ($completed && $created) {
+ return
+ ($start <= $created || $start <= $completed) &&
+ ($end >= $created || $end >= $completed);
+ }
+ if ($completed) {
+ return ($start <= $completed && $end >= $completed);
+ }
+ if ($created) {
+ return ($end > $created);
+ }
+ return true;
+
+ }
+
+ /**
+ * A simple list of validation rules.
+ *
+ * This is simply a list of properties, and how many times they either
+ * must or must not appear.
+ *
+ * Possible values per property:
+ * * 0 - Must not appear.
+ * * 1 - Must appear exactly once.
+ * * + - Must appear at least once.
+ * * * - Can appear any number of times.
+ * * ? - May appear, but not more than once.
+ *
+ * @var array
+ */
+ function getValidationRules() {
+
+ return [
+ 'UID' => 1,
+ 'DTSTAMP' => 1,
+
+ 'CLASS' => '?',
+ 'COMPLETED' => '?',
+ 'CREATED' => '?',
+ 'DESCRIPTION' => '?',
+ 'DTSTART' => '?',
+ 'GEO' => '?',
+ 'LAST-MODIFIED' => '?',
+ 'LOCATION' => '?',
+ 'ORGANIZER' => '?',
+ 'PERCENT' => '?',
+ 'PRIORITY' => '?',
+ 'RECURRENCE-ID' => '?',
+ 'SEQUENCE' => '?',
+ 'STATUS' => '?',
+ 'SUMMARY' => '?',
+ 'URL' => '?',
+
+ 'RRULE' => '?',
+ 'DUE' => '?',
+ 'DURATION' => '?',
+
+ 'ATTACH' => '*',
+ 'ATTENDEE' => '*',
+ 'CATEGORIES' => '*',
+ 'COMMENT' => '*',
+ 'CONTACT' => '*',
+ 'EXDATE' => '*',
+ 'REQUEST-STATUS' => '*',
+ 'RELATED-TO' => '*',
+ 'RESOURCES' => '*',
+ 'RDATE' => '*',
+ ];
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on)
+ * 2 - An inconsequential issue
+ * 3 - A severe issue.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $result = parent::validate($options);
+ if (isset($this->DUE) && isset($this->DTSTART)) {
+
+ $due = $this->DUE;
+ $dtStart = $this->DTSTART;
+
+ if ($due->getValueType() !== $dtStart->getValueType()) {
+
+ $result[] = [
+ 'level' => 3,
+ 'message' => 'The value type (DATE or DATE-TIME) must be identical for DUE and DTSTART',
+ 'node' => $due,
+ ];
+
+ } elseif ($due->getDateTime() < $dtStart->getDateTime()) {
+
+ $result[] = [
+ 'level' => 3,
+ 'message' => 'DUE must occur after DTSTART',
+ 'node' => $due,
+ ];
+
+ }
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return [
+ 'UID' => 'sabre-vobject-' . VObject\UUIDUtil::getUUID(),
+ 'DTSTAMP' => date('Ymd\\THis\\Z'),
+ ];
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/DateTimeParser.php b/vendor/sabre/vobject/lib/DateTimeParser.php
new file mode 100644
index 000000000..fc568abb0
--- /dev/null
+++ b/vendor/sabre/vobject/lib/DateTimeParser.php
@@ -0,0 +1,571 @@
+<?php
+
+namespace Sabre\VObject;
+
+use DateTimeImmutable;
+use DateTimeZone;
+use DateInterval;
+
+/**
+ * DateTimeParser.
+ *
+ * This class is responsible for parsing the several different date and time
+ * formats iCalendar and vCards have.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class DateTimeParser {
+
+ /**
+ * Parses an iCalendar (rfc5545) formatted datetime and returns a
+ * DateTimeImmutable object.
+ *
+ * Specifying a reference timezone is optional. It will only be used
+ * if the non-UTC format is used. The argument is used as a reference, the
+ * returned DateTimeImmutable object will still be in the UTC timezone.
+ *
+ * @param string $dt
+ * @param DateTimeZone $tz
+ *
+ * @return DateTimeImmutable
+ */
+ static function parseDateTime($dt, DateTimeZone $tz = null) {
+
+ // Format is YYYYMMDD + "T" + hhmmss
+ $result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/', $dt, $matches);
+
+ if (!$result) {
+ throw new InvalidDataException('The supplied iCalendar datetime value is incorrect: ' . $dt);
+ }
+
+ if ($matches[7] === 'Z' || is_null($tz)) {
+ $tz = new DateTimeZone('UTC');
+ }
+ $date = new DateTimeImmutable($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] . ':' . $matches[6], $tz);
+
+ return $date;
+
+ }
+
+ /**
+ * Parses an iCalendar (rfc5545) formatted date and returns a DateTimeImmutable object.
+ *
+ * @param string $date
+ * @param DateTimeZone $tz
+ *
+ * @return DateTimeImmutable
+ */
+ static function parseDate($date, DateTimeZone $tz = null) {
+
+ // Format is YYYYMMDD
+ $result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])$/', $date, $matches);
+
+ if (!$result) {
+ throw new InvalidDataException('The supplied iCalendar date value is incorrect: ' . $date);
+ }
+
+ if (is_null($tz)) {
+ $tz = new DateTimeZone('UTC');
+ }
+
+ $date = new DateTimeImmutable($matches[1] . '-' . $matches[2] . '-' . $matches[3], $tz);
+
+ return $date;
+
+ }
+
+ /**
+ * Parses an iCalendar (RFC5545) formatted duration value.
+ *
+ * This method will either return a DateTimeInterval object, or a string
+ * suitable for strtotime or DateTime::modify.
+ *
+ * @param string $duration
+ * @param bool $asString
+ *
+ * @return DateInterval|string
+ */
+ static function parseDuration($duration, $asString = false) {
+
+ $result = preg_match('/^(?<plusminus>\+|-)?P((?<week>\d+)W)?((?<day>\d+)D)?(T((?<hour>\d+)H)?((?<minute>\d+)M)?((?<second>\d+)S)?)?$/', $duration, $matches);
+ if (!$result) {
+ throw new InvalidDataException('The supplied iCalendar duration value is incorrect: ' . $duration);
+ }
+
+ if (!$asString) {
+
+ $invert = false;
+
+ if ($matches['plusminus'] === '-') {
+ $invert = true;
+ }
+
+ $parts = [
+ 'week',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ ];
+
+ foreach ($parts as $part) {
+ $matches[$part] = isset($matches[$part]) && $matches[$part] ? (int)$matches[$part] : 0;
+ }
+
+ // We need to re-construct the $duration string, because weeks and
+ // days are not supported by DateInterval in the same string.
+ $duration = 'P';
+ $days = $matches['day'];
+
+ if ($matches['week']) {
+ $days += $matches['week'] * 7;
+ }
+
+ if ($days) {
+ $duration .= $days . 'D';
+ }
+
+ if ($matches['minute'] || $matches['second'] || $matches['hour']) {
+
+ $duration .= 'T';
+
+ if ($matches['hour']) {
+ $duration .= $matches['hour'] . 'H';
+ }
+
+ if ($matches['minute']) {
+ $duration .= $matches['minute'] . 'M';
+ }
+
+ if ($matches['second']) {
+ $duration .= $matches['second'] . 'S';
+ }
+
+ }
+
+ if ($duration === 'P') {
+ $duration = 'PT0S';
+ }
+
+ $iv = new DateInterval($duration);
+
+ if ($invert) {
+ $iv->invert = true;
+ }
+
+ return $iv;
+
+ }
+
+ $parts = [
+ 'week',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ ];
+
+ $newDur = '';
+
+ foreach ($parts as $part) {
+ if (isset($matches[$part]) && $matches[$part]) {
+ $newDur .= ' ' . $matches[$part] . ' ' . $part . 's';
+ }
+ }
+
+ $newDur = ($matches['plusminus'] === '-' ? '-' : '+') . trim($newDur);
+
+ if ($newDur === '+') {
+ $newDur = '+0 seconds';
+ };
+
+ return $newDur;
+
+ }
+
+ /**
+ * Parses either a Date or DateTime, or Duration value.
+ *
+ * @param string $date
+ * @param DateTimeZone|string $referenceTz
+ *
+ * @return DateTimeImmutable|DateInterval
+ */
+ static function parse($date, $referenceTz = null) {
+
+ if ($date[0] === 'P' || ($date[0] === '-' && $date[1] === 'P')) {
+ return self::parseDuration($date);
+ } elseif (strlen($date) === 8) {
+ return self::parseDate($date, $referenceTz);
+ } else {
+ return self::parseDateTime($date, $referenceTz);
+ }
+
+ }
+
+ /**
+ * This method parses a vCard date and or time value.
+ *
+ * This can be used for the DATE, DATE-TIME, TIMESTAMP and
+ * DATE-AND-OR-TIME value.
+ *
+ * This method returns an array, not a DateTime value.
+ *
+ * The elements in the array are in the following order:
+ * year, month, date, hour, minute, second, timezone
+ *
+ * Almost any part of the string may be omitted. It's for example legal to
+ * just specify seconds, leave out the year, etc.
+ *
+ * Timezone is either returned as 'Z' or as '+0800'
+ *
+ * For any non-specified values null is returned.
+ *
+ * List of date formats that are supported:
+ * YYYY
+ * YYYY-MM
+ * YYYYMMDD
+ * --MMDD
+ * ---DD
+ *
+ * YYYY-MM-DD
+ * --MM-DD
+ * ---DD
+ *
+ * List of supported time formats:
+ *
+ * HH
+ * HHMM
+ * HHMMSS
+ * -MMSS
+ * --SS
+ *
+ * HH
+ * HH:MM
+ * HH:MM:SS
+ * -MM:SS
+ * --SS
+ *
+ * A full basic-format date-time string looks like :
+ * 20130603T133901
+ *
+ * A full extended-format date-time string looks like :
+ * 2013-06-03T13:39:01
+ *
+ * Times may be postfixed by a timezone offset. This can be either 'Z' for
+ * UTC, or a string like -0500 or +1100.
+ *
+ * @param string $date
+ *
+ * @return array
+ */
+ static function parseVCardDateTime($date) {
+
+ $regex = '/^
+ (?: # date part
+ (?:
+ (?: (?<year> [0-9]{4}) (?: -)?| --)
+ (?<month> [0-9]{2})?
+ |---)
+ (?<date> [0-9]{2})?
+ )?
+ (?:T # time part
+ (?<hour> [0-9]{2} | -)
+ (?<minute> [0-9]{2} | -)?
+ (?<second> [0-9]{2})?
+
+ (?: \.[0-9]{3})? # milliseconds
+ (?P<timezone> # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{4})
+
+ )?
+
+ )?
+ $/x';
+
+ if (!preg_match($regex, $date, $matches)) {
+
+ // Attempting to parse the extended format.
+ $regex = '/^
+ (?: # date part
+ (?: (?<year> [0-9]{4}) - | -- )
+ (?<month> [0-9]{2}) -
+ (?<date> [0-9]{2})
+ )?
+ (?:T # time part
+
+ (?: (?<hour> [0-9]{2}) : | -)
+ (?: (?<minute> [0-9]{2}) : | -)?
+ (?<second> [0-9]{2})?
+
+ (?: \.[0-9]{3})? # milliseconds
+ (?P<timezone> # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
+
+ )?
+
+ )?
+ $/x';
+
+ if (!preg_match($regex, $date, $matches)) {
+ throw new InvalidDataException('Invalid vCard date-time string: ' . $date);
+ }
+
+ }
+ $parts = [
+ 'year',
+ 'month',
+ 'date',
+ 'hour',
+ 'minute',
+ 'second',
+ 'timezone'
+ ];
+
+ $result = [];
+ foreach ($parts as $part) {
+
+ if (empty($matches[$part])) {
+ $result[$part] = null;
+ } elseif ($matches[$part] === '-' || $matches[$part] === '--') {
+ $result[$part] = null;
+ } else {
+ $result[$part] = $matches[$part];
+ }
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * This method parses a vCard TIME value.
+ *
+ * This method returns an array, not a DateTime value.
+ *
+ * The elements in the array are in the following order:
+ * hour, minute, second, timezone
+ *
+ * Almost any part of the string may be omitted. It's for example legal to
+ * just specify seconds, leave out the hour etc.
+ *
+ * Timezone is either returned as 'Z' or as '+08:00'
+ *
+ * For any non-specified values null is returned.
+ *
+ * List of supported time formats:
+ *
+ * HH
+ * HHMM
+ * HHMMSS
+ * -MMSS
+ * --SS
+ *
+ * HH
+ * HH:MM
+ * HH:MM:SS
+ * -MM:SS
+ * --SS
+ *
+ * A full basic-format time string looks like :
+ * 133901
+ *
+ * A full extended-format time string looks like :
+ * 13:39:01
+ *
+ * Times may be postfixed by a timezone offset. This can be either 'Z' for
+ * UTC, or a string like -0500 or +11:00.
+ *
+ * @param string $date
+ *
+ * @return array
+ */
+ static function parseVCardTime($date) {
+
+ $regex = '/^
+ (?<hour> [0-9]{2} | -)
+ (?<minute> [0-9]{2} | -)?
+ (?<second> [0-9]{2})?
+
+ (?: \.[0-9]{3})? # milliseconds
+ (?P<timezone> # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{4})
+
+ )?
+ $/x';
+
+
+ if (!preg_match($regex, $date, $matches)) {
+
+ // Attempting to parse the extended format.
+ $regex = '/^
+ (?: (?<hour> [0-9]{2}) : | -)
+ (?: (?<minute> [0-9]{2}) : | -)?
+ (?<second> [0-9]{2})?
+
+ (?: \.[0-9]{3})? # milliseconds
+ (?P<timezone> # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
+
+ )?
+ $/x';
+
+ if (!preg_match($regex, $date, $matches)) {
+ throw new InvalidDataException('Invalid vCard time string: ' . $date);
+ }
+
+ }
+ $parts = [
+ 'hour',
+ 'minute',
+ 'second',
+ 'timezone'
+ ];
+
+ $result = [];
+ foreach ($parts as $part) {
+
+ if (empty($matches[$part])) {
+ $result[$part] = null;
+ } elseif ($matches[$part] === '-') {
+ $result[$part] = null;
+ } else {
+ $result[$part] = $matches[$part];
+ }
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * This method parses a vCard date and or time value.
+ *
+ * This can be used for the DATE, DATE-TIME and
+ * DATE-AND-OR-TIME value.
+ *
+ * This method returns an array, not a DateTime value.
+ * The elements in the array are in the following order:
+ * year, month, date, hour, minute, second, timezone
+ * Almost any part of the string may be omitted. It's for example legal to
+ * just specify seconds, leave out the year, etc.
+ *
+ * Timezone is either returned as 'Z' or as '+0800'
+ *
+ * For any non-specified values null is returned.
+ *
+ * List of date formats that are supported:
+ * 20150128
+ * 2015-01
+ * --01
+ * --0128
+ * ---28
+ *
+ * List of supported time formats:
+ * 13
+ * 1353
+ * 135301
+ * -53
+ * -5301
+ * --01 (unreachable, see the tests)
+ * --01Z
+ * --01+1234
+ *
+ * List of supported date-time formats:
+ * 20150128T13
+ * --0128T13
+ * ---28T13
+ * ---28T1353
+ * ---28T135301
+ * ---28T13Z
+ * ---28T13+1234
+ *
+ * See the regular expressions for all the possible patterns.
+ *
+ * Times may be postfixed by a timezone offset. This can be either 'Z' for
+ * UTC, or a string like -0500 or +1100.
+ *
+ * @param string $date
+ *
+ * @return array
+ */
+ static function parseVCardDateAndOrTime($date) {
+
+ // \d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d
+ $valueDate = '/^(?J)(?:' .
+ '(?<year>\d{4})(?<month>\d\d)(?<date>\d\d)' .
+ '|(?<year>\d{4})-(?<month>\d\d)' .
+ '|--(?<month>\d\d)(?<date>\d\d)?' .
+ '|---(?<date>\d\d)' .
+ ')$/';
+
+ // (\d\d(\d\d(\d\d)?)?|-\d\d(\d\d)?|--\d\d)(Z|[+\-]\d\d(\d\d)?)?
+ $valueTime = '/^(?J)(?:' .
+ '((?<hour>\d\d)((?<minute>\d\d)(?<second>\d\d)?)?' .
+ '|-(?<minute>\d\d)(?<second>\d\d)?' .
+ '|--(?<second>\d\d))' .
+ '(?<timezone>(Z|[+\-]\d\d(\d\d)?))?' .
+ ')$/';
+
+ // (\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?(Z|[+\-]\d\d(\d\d?)?
+ $valueDateTime = '/^(?:' .
+ '((?<year0>\d{4})(?<month0>\d\d)(?<date0>\d\d)' .
+ '|--(?<month1>\d\d)(?<date1>\d\d)' .
+ '|---(?<date2>\d\d))' .
+ 'T' .
+ '(?<hour>\d\d)((?<minute>\d\d)(?<second>\d\d)?)?' .
+ '(?<timezone>(Z|[+\-]\d\d(\d\d?)))?' .
+ ')$/';
+
+ // date-and-or-time is date | date-time | time
+ // in this strict order.
+
+ if (0 === preg_match($valueDate, $date, $matches)
+ && 0 === preg_match($valueDateTime, $date, $matches)
+ && 0 === preg_match($valueTime, $date, $matches)) {
+ throw new InvalidDataException('Invalid vCard date-time string: ' . $date);
+ }
+
+ $parts = [
+ 'year' => null,
+ 'month' => null,
+ 'date' => null,
+ 'hour' => null,
+ 'minute' => null,
+ 'second' => null,
+ 'timezone' => null
+ ];
+
+ // The $valueDateTime expression has a bug with (?J) so we simulate it.
+ $parts['date0'] = &$parts['date'];
+ $parts['date1'] = &$parts['date'];
+ $parts['date2'] = &$parts['date'];
+ $parts['month0'] = &$parts['month'];
+ $parts['month1'] = &$parts['month'];
+ $parts['year0'] = &$parts['year'];
+
+ foreach ($parts as $part => &$value) {
+ if (!empty($matches[$part])) {
+ $value = $matches[$part];
+ }
+ }
+
+ unset($parts['date0']);
+ unset($parts['date1']);
+ unset($parts['date2']);
+ unset($parts['month0']);
+ unset($parts['month1']);
+ unset($parts['year0']);
+
+ return $parts;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Document.php b/vendor/sabre/vobject/lib/Document.php
new file mode 100644
index 000000000..03252ab06
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Document.php
@@ -0,0 +1,270 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * Document.
+ *
+ * A document is just like a component, except that it's also the top level
+ * element.
+ *
+ * Both a VCALENDAR and a VCARD are considered documents.
+ *
+ * This class also provides a registry for document types.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+abstract class Document extends Component {
+
+ /**
+ * Unknown document type.
+ */
+ const UNKNOWN = 1;
+
+ /**
+ * vCalendar 1.0.
+ */
+ const VCALENDAR10 = 2;
+
+ /**
+ * iCalendar 2.0.
+ */
+ const ICALENDAR20 = 3;
+
+ /**
+ * vCard 2.1.
+ */
+ const VCARD21 = 4;
+
+ /**
+ * vCard 3.0.
+ */
+ const VCARD30 = 5;
+
+ /**
+ * vCard 4.0.
+ */
+ const VCARD40 = 6;
+
+ /**
+ * The default name for this component.
+ *
+ * This should be 'VCALENDAR' or 'VCARD'.
+ *
+ * @var string
+ */
+ static $defaultName;
+
+ /**
+ * List of properties, and which classes they map to.
+ *
+ * @var array
+ */
+ static $propertyMap = [];
+
+ /**
+ * List of components, along with which classes they map to.
+ *
+ * @var array
+ */
+ static $componentMap = [];
+
+ /**
+ * List of value-types, and which classes they map to.
+ *
+ * @var array
+ */
+ static $valueMap = [];
+
+ /**
+ * Creates a new document.
+ *
+ * We're changing the default behavior slightly here. First, we don't want
+ * to have to specify a name (we already know it), and we want to allow
+ * children to be specified in the first argument.
+ *
+ * But, the default behavior also works.
+ *
+ * So the two sigs:
+ *
+ * new Document(array $children = [], $defaults = true);
+ * new Document(string $name, array $children = [], $defaults = true)
+ *
+ * @return void
+ */
+ function __construct() {
+
+ $args = func_get_args();
+ if (count($args) === 0 || is_array($args[0])) {
+ array_unshift($args, $this, static::$defaultName);
+ call_user_func_array(['parent', '__construct'], $args);
+ } else {
+ array_unshift($args, $this);
+ call_user_func_array(['parent', '__construct'], $args);
+ }
+
+ }
+
+ /**
+ * Returns the current document type.
+ *
+ * @return int
+ */
+ function getDocumentType() {
+
+ return self::UNKNOWN;
+
+ }
+
+ /**
+ * Creates a new component or property.
+ *
+ * If it's a known component, we will automatically call createComponent.
+ * otherwise, we'll assume it's a property and call createProperty instead.
+ *
+ * @param string $name
+ * @param string $arg1,... Unlimited number of args
+ *
+ * @return mixed
+ */
+ function create($name) {
+
+ if (isset(static::$componentMap[strtoupper($name)])) {
+
+ return call_user_func_array([$this, 'createComponent'], func_get_args());
+
+ } else {
+
+ return call_user_func_array([$this, 'createProperty'], func_get_args());
+
+ }
+
+ }
+
+ /**
+ * Creates a new component.
+ *
+ * This method automatically searches for the correct component class, based
+ * on its name.
+ *
+ * You can specify the children either in key=>value syntax, in which case
+ * properties will automatically be created, or you can just pass a list of
+ * Component and Property object.
+ *
+ * By default, a set of sensible values will be added to the component. For
+ * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
+ * ensure that this does not happen, set $defaults to false.
+ *
+ * @param string $name
+ * @param array $children
+ * @param bool $defaults
+ *
+ * @return Component
+ */
+ function createComponent($name, array $children = null, $defaults = true) {
+
+ $name = strtoupper($name);
+ $class = 'Sabre\\VObject\\Component';
+
+ if (isset(static::$componentMap[$name])) {
+ $class = static::$componentMap[$name];
+ }
+ if (is_null($children)) $children = [];
+ return new $class($this, $name, $children, $defaults);
+
+ }
+
+ /**
+ * Factory method for creating new properties.
+ *
+ * This method automatically searches for the correct property class, based
+ * on its name.
+ *
+ * You can specify the parameters either in key=>value syntax, in which case
+ * parameters will automatically be created, or you can just pass a list of
+ * Parameter objects.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @param array $parameters
+ * @param string $valueType Force a specific valuetype, such as URI or TEXT
+ *
+ * @return Property
+ */
+ function createProperty($name, $value = null, array $parameters = null, $valueType = null) {
+
+ // If there's a . in the name, it means it's prefixed by a groupname.
+ if (($i = strpos($name, '.')) !== false) {
+ $group = substr($name, 0, $i);
+ $name = strtoupper(substr($name, $i + 1));
+ } else {
+ $name = strtoupper($name);
+ $group = null;
+ }
+
+ $class = null;
+
+ if ($valueType) {
+ // The valueType argument comes first to figure out the correct
+ // class.
+ $class = $this->getClassNameForPropertyValue($valueType);
+ }
+
+ if (is_null($class)) {
+ // If a VALUE parameter is supplied, we should use that.
+ if (isset($parameters['VALUE'])) {
+ $class = $this->getClassNameForPropertyValue($parameters['VALUE']);
+ if (is_null($class)) {
+ throw new InvalidDataException('Unsupported VALUE parameter for ' . $name . ' property. You supplied "' . $parameters['VALUE'] . '"');
+ }
+ }
+ else {
+ $class = $this->getClassNameForPropertyName($name);
+ }
+ }
+ if (is_null($parameters)) $parameters = [];
+
+ return new $class($this, $name, $value, $parameters, $group);
+
+ }
+
+ /**
+ * This method returns a full class-name for a value parameter.
+ *
+ * For instance, DTSTART may have VALUE=DATE. In that case we will look in
+ * our valueMap table and return the appropriate class name.
+ *
+ * This method returns null if we don't have a specialized class.
+ *
+ * @param string $valueParam
+ * @return string|null
+ */
+ function getClassNameForPropertyValue($valueParam) {
+
+ $valueParam = strtoupper($valueParam);
+ if (isset(static::$valueMap[$valueParam])) {
+ return static::$valueMap[$valueParam];
+ }
+
+ }
+
+ /**
+ * Returns the default class for a property name.
+ *
+ * @param string $propertyName
+ *
+ * @return string
+ */
+ function getClassNameForPropertyName($propertyName) {
+
+ if (isset(static::$propertyMap[$propertyName])) {
+ return static::$propertyMap[$propertyName];
+ } else {
+ return 'Sabre\\VObject\\Property\\Unknown';
+ }
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/ElementList.php b/vendor/sabre/vobject/lib/ElementList.php
new file mode 100644
index 000000000..959249247
--- /dev/null
+++ b/vendor/sabre/vobject/lib/ElementList.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Sabre\VObject;
+
+use ArrayIterator;
+use LogicException;
+
+/**
+ * VObject ElementList.
+ *
+ * This class represents a list of elements. Lists are the result of queries,
+ * such as doing $vcalendar->vevent where there's multiple VEVENT objects.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class ElementList extends ArrayIterator {
+
+
+ /* {{{ ArrayAccess Interface */
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * @param int $offset
+ * @param mixed $value
+ *
+ * @return void
+ */
+ function offsetSet($offset, $value) {
+
+ throw new LogicException('You can not add new objects to an ElementList');
+
+ }
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ *
+ * @return void
+ */
+ function offsetUnset($offset) {
+
+ throw new LogicException('You can not remove objects from an ElementList');
+
+ }
+
+ /* }}} */
+
+}
diff --git a/vendor/sabre/vobject/lib/EofException.php b/vendor/sabre/vobject/lib/EofException.php
new file mode 100644
index 000000000..e9bd55878
--- /dev/null
+++ b/vendor/sabre/vobject/lib/EofException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * Exception thrown by parser when the end of the stream has been reached,
+ * before this was expected.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class EofException extends ParseException {
+
+}
diff --git a/vendor/sabre/vobject/lib/FreeBusyData.php b/vendor/sabre/vobject/lib/FreeBusyData.php
new file mode 100644
index 000000000..0a6c72bb2
--- /dev/null
+++ b/vendor/sabre/vobject/lib/FreeBusyData.php
@@ -0,0 +1,193 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * FreeBusyData is a helper class that manages freebusy information.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class FreeBusyData {
+
+ /**
+ * Start timestamp
+ *
+ * @var int
+ */
+ protected $start;
+
+ /**
+ * End timestamp
+ *
+ * @var int
+ */
+ protected $end;
+
+ /**
+ * A list of free-busy times.
+ *
+ * @var array
+ */
+ protected $data;
+
+ function __construct($start, $end) {
+
+ $this->start = $start;
+ $this->end = $end;
+ $this->data = [];
+
+ $this->data[] = [
+ 'start' => $this->start,
+ 'end' => $this->end,
+ 'type' => 'FREE',
+ ];
+
+ }
+
+ /**
+ * Adds free or busytime to the data.
+ *
+ * @param int $start
+ * @param int $end
+ * @param string $type FREE, BUSY, BUSY-UNAVAILABLE or BUSY-TENTATIVE
+ * @return void
+ */
+ function add($start, $end, $type) {
+
+ if ($start > $this->end || $end < $this->start) {
+
+ // This new data is outside our timerange.
+ return;
+
+ }
+
+ if ($start < $this->start) {
+ // The item starts before our requested time range
+ $start = $this->start;
+ }
+ if ($end > $this->end) {
+ // The item ends after our requested time range
+ $end = $this->end;
+ }
+
+ // Finding out where we need to insert the new item.
+ $currentIndex = 0;
+ while ($start > $this->data[$currentIndex]['end']) {
+ $currentIndex++;
+ }
+
+ // The standard insertion point will be one _after_ the first
+ // overlapping item.
+ $insertStartIndex = $currentIndex + 1;
+
+ $newItem = [
+ 'start' => $start,
+ 'end' => $end,
+ 'type' => $type,
+ ];
+
+ $preceedingItem = $this->data[$insertStartIndex - 1];
+ if ($this->data[$insertStartIndex - 1]['start'] === $start) {
+ // The old item starts at the exact same point as the new item.
+ $insertStartIndex--;
+ }
+
+ // Now we know where to insert the item, we need to know where it
+ // starts overlapping with items on the tail end. We need to start
+ // looking one item before the insertStartIndex, because it's possible
+ // that the new item 'sits inside' the previous old item.
+ if ($insertStartIndex > 0) {
+ $currentIndex = $insertStartIndex - 1;
+ } else {
+ $currentIndex = 0;
+ }
+
+ while ($end > $this->data[$currentIndex]['end']) {
+
+ $currentIndex++;
+
+ }
+
+ // What we are about to insert into the array
+ $newItems = [
+ $newItem
+ ];
+
+ // This is the amount of items that are completely overwritten by the
+ // new item.
+ $itemsToDelete = $currentIndex - $insertStartIndex;
+ if ($this->data[$currentIndex]['end'] <= $end) $itemsToDelete++;
+
+ // If itemsToDelete was -1, it means that the newly inserted item is
+ // actually sitting inside an existing one. This means we need to split
+ // the item at the current position in two and insert the new item in
+ // between.
+ if ($itemsToDelete === -1) {
+ $itemsToDelete = 0;
+ if ($newItem['end'] < $preceedingItem['end']) {
+ $newItems[] = [
+ 'start' => $newItem['end'] + 1,
+ 'end' => $preceedingItem['end'],
+ 'type' => $preceedingItem['type']
+ ];
+ }
+ }
+
+ array_splice(
+ $this->data,
+ $insertStartIndex,
+ $itemsToDelete,
+ $newItems
+ );
+
+ $doMerge = false;
+ $mergeOffset = $insertStartIndex;
+ $mergeItem = $newItem;
+ $mergeDelete = 1;
+
+ if (isset($this->data[$insertStartIndex - 1])) {
+ // Updating the start time of the previous item.
+ $this->data[$insertStartIndex - 1]['end'] = $start;
+
+ // If the previous and the current are of the same type, we can
+ // merge them into one item.
+ if ($this->data[$insertStartIndex - 1]['type'] === $this->data[$insertStartIndex]['type']) {
+ $doMerge = true;
+ $mergeOffset--;
+ $mergeDelete++;
+ $mergeItem['start'] = $this->data[$insertStartIndex - 1]['start'];
+ }
+ }
+ if (isset($this->data[$insertStartIndex + 1])) {
+ // Updating the start time of the next item.
+ $this->data[$insertStartIndex + 1]['start'] = $end;
+
+ // If the next and the current are of the same type, we can
+ // merge them into one item.
+ if ($this->data[$insertStartIndex + 1]['type'] === $this->data[$insertStartIndex]['type']) {
+ $doMerge = true;
+ $mergeDelete++;
+ $mergeItem['end'] = $this->data[$insertStartIndex + 1]['end'];
+ }
+
+ }
+ if ($doMerge) {
+ array_splice(
+ $this->data,
+ $mergeOffset,
+ $mergeDelete,
+ [$mergeItem]
+ );
+ }
+
+ }
+
+ function getData() {
+
+ return $this->data;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/FreeBusyGenerator.php b/vendor/sabre/vobject/lib/FreeBusyGenerator.php
new file mode 100644
index 000000000..e33621090
--- /dev/null
+++ b/vendor/sabre/vobject/lib/FreeBusyGenerator.php
@@ -0,0 +1,604 @@
+<?php
+
+namespace Sabre\VObject;
+
+use DateTimeInterface;
+use DateTimeImmutable;
+use DateTimeZone;
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\Recur\EventIterator;
+use Sabre\VObject\Recur\NoInstancesException;
+
+/**
+ * This class helps with generating FREEBUSY reports based on existing sets of
+ * objects.
+ *
+ * It only looks at VEVENT and VFREEBUSY objects from the sourcedata, and
+ * generates a single VFREEBUSY object.
+ *
+ * VFREEBUSY components are described in RFC5545, The rules for what should
+ * go in a single freebusy report is taken from RFC4791, section 7.10.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class FreeBusyGenerator {
+
+ /**
+ * Input objects.
+ *
+ * @var array
+ */
+ protected $objects = [];
+
+ /**
+ * Start of range.
+ *
+ * @var DateTimeInterface|null
+ */
+ protected $start;
+
+ /**
+ * End of range.
+ *
+ * @var DateTimeInterface|null
+ */
+ protected $end;
+
+ /**
+ * VCALENDAR object.
+ *
+ * @var Document
+ */
+ protected $baseObject;
+
+ /**
+ * Reference timezone.
+ *
+ * When we are calculating busy times, and we come across so-called
+ * floating times (times without a timezone), we use the reference timezone
+ * instead.
+ *
+ * This is also used for all-day events.
+ *
+ * This defaults to UTC.
+ *
+ * @var DateTimeZone
+ */
+ protected $timeZone;
+
+ /**
+ * A VAVAILABILITY document.
+ *
+ * If this is set, it's information will be included when calculating
+ * freebusy time.
+ *
+ * @var Document
+ */
+ protected $vavailability;
+
+ /**
+ * Creates the generator.
+ *
+ * Check the setTimeRange and setObjects methods for details about the
+ * arguments.
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ * @param mixed $objects
+ * @param DateTimeZone $timeZone
+ */
+ function __construct(DateTimeInterface $start = null, DateTimeInterface $end = null, $objects = null, DateTimeZone $timeZone = null) {
+
+ $this->setTimeRange($start, $end);
+
+ if ($objects) {
+ $this->setObjects($objects);
+ }
+ if (is_null($timeZone)) {
+ $timeZone = new DateTimeZone('UTC');
+ }
+ $this->setTimeZone($timeZone);
+
+ }
+
+ /**
+ * Sets the VCALENDAR object.
+ *
+ * If this is set, it will not be generated for you. You are responsible
+ * for setting things like the METHOD, CALSCALE, VERSION, etc..
+ *
+ * The VFREEBUSY object will be automatically added though.
+ *
+ * @param Document $vcalendar
+ * @return void
+ */
+ function setBaseObject(Document $vcalendar) {
+
+ $this->baseObject = $vcalendar;
+
+ }
+
+ /**
+ * Sets a VAVAILABILITY document.
+ *
+ * @param Document $vcalendar
+ * @return void
+ */
+ function setVAvailability(Document $vcalendar) {
+
+ $this->vavailability = $vcalendar;
+
+ }
+
+ /**
+ * Sets the input objects.
+ *
+ * You must either specify a valendar object as a string, or as the parse
+ * Component.
+ * It's also possible to specify multiple objects as an array.
+ *
+ * @param mixed $objects
+ *
+ * @return void
+ */
+ function setObjects($objects) {
+
+ if (!is_array($objects)) {
+ $objects = [$objects];
+ }
+
+ $this->objects = [];
+ foreach ($objects as $object) {
+
+ if (is_string($object)) {
+ $this->objects[] = Reader::read($object);
+ } elseif ($object instanceof Component) {
+ $this->objects[] = $object;
+ } else {
+ throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component arguments to setObjects');
+ }
+
+ }
+
+ }
+
+ /**
+ * Sets the time range.
+ *
+ * Any freebusy object falling outside of this time range will be ignored.
+ *
+ * @param DateTimeInterface $start
+ * @param DateTimeInterface $end
+ *
+ * @return void
+ */
+ function setTimeRange(DateTimeInterface $start = null, DateTimeInterface $end = null) {
+
+ if (!$start) {
+ $start = new DateTimeImmutable(Settings::$minDate);
+ }
+ if (!$end) {
+ $end = new DateTimeImmutable(Settings::$maxDate);
+ }
+ $this->start = $start;
+ $this->end = $end;
+
+ }
+
+ /**
+ * Sets the reference timezone for floating times.
+ *
+ * @param DateTimeZone $timeZone
+ *
+ * @return void
+ */
+ function setTimeZone(DateTimeZone $timeZone) {
+
+ $this->timeZone = $timeZone;
+
+ }
+
+ /**
+ * Parses the input data and returns a correct VFREEBUSY object, wrapped in
+ * a VCALENDAR.
+ *
+ * @return Component
+ */
+ function getResult() {
+
+ $fbData = new FreeBusyData(
+ $this->start->getTimeStamp(),
+ $this->end->getTimeStamp()
+ );
+ if ($this->vavailability) {
+
+ $this->calculateAvailability($fbData, $this->vavailability);
+
+ }
+
+ $this->calculateBusy($fbData, $this->objects);
+
+ return $this->generateFreeBusyCalendar($fbData);
+
+
+ }
+
+ /**
+ * This method takes a VAVAILABILITY component and figures out all the
+ * available times.
+ *
+ * @param FreeBusyData $fbData
+ * @param VCalendar $vavailability
+ * @return void
+ */
+ protected function calculateAvailability(FreeBusyData $fbData, VCalendar $vavailability) {
+
+ $vavailComps = iterator_to_array($vavailability->VAVAILABILITY);
+ usort(
+ $vavailComps,
+ function($a, $b) {
+
+ // We need to order the components by priority. Priority 1
+ // comes first, up until priority 9. Priority 0 comes after
+ // priority 9. No priority implies priority 0.
+ //
+ // Yes, I'm serious.
+ $priorityA = isset($a->PRIORITY) ? (int)$a->PRIORITY->getValue() : 0;
+ $priorityB = isset($b->PRIORITY) ? (int)$b->PRIORITY->getValue() : 0;
+
+ if ($priorityA === 0) $priorityA = 10;
+ if ($priorityB === 0) $priorityB = 10;
+
+ return $priorityA - $priorityB;
+
+ }
+ );
+
+ // Now we go over all the VAVAILABILITY components and figure if
+ // there's any we don't need to consider.
+ //
+ // This is can be because of one of two reasons: either the
+ // VAVAILABILITY component falls outside the time we are interested in,
+ // or a different VAVAILABILITY component with a higher priority has
+ // already completely covered the time-range.
+ $old = $vavailComps;
+ $new = [];
+
+ foreach ($old as $vavail) {
+
+ list($compStart, $compEnd) = $vavail->getEffectiveStartEnd();
+
+ // We don't care about datetimes that are earlier or later than the
+ // start and end of the freebusy report, so this gets normalized
+ // first.
+ if (is_null($compStart) || $compStart < $this->start) {
+ $compStart = $this->start;
+ }
+ if (is_null($compEnd) || $compEnd > $this->end) {
+ $compEnd = $this->end;
+ }
+
+ // If the item fell out of the timerange, we can just skip it.
+ if ($compStart > $this->end || $compEnd < $this->start) {
+ continue;
+ }
+
+ // Going through our existing list of components to see if there's
+ // a higher priority component that already fully covers this one.
+ foreach ($new as $higherVavail) {
+
+ list($higherStart, $higherEnd) = $higherVavail->getEffectiveStartEnd();
+ if (
+ (is_null($higherStart) || $higherStart < $compStart) &&
+ (is_null($higherEnd) || $higherEnd > $compEnd)
+ ) {
+
+ // Component is fully covered by a higher priority
+ // component. We can skip this component.
+ continue 2;
+
+ }
+
+ }
+
+ // We're keeping it!
+ $new[] = $vavail;
+
+ }
+
+ // Lastly, we need to traverse the remaining components and fill in the
+ // freebusydata slots.
+ //
+ // We traverse the components in reverse, because we want the higher
+ // priority components to override the lower ones.
+ foreach (array_reverse($new) as $vavail) {
+
+ $busyType = isset($vavail->BUSYTYPE) ? strtoupper($vavail->BUSYTYPE) : 'BUSY-UNAVAILABLE';
+ list($vavailStart, $vavailEnd) = $vavail->getEffectiveStartEnd();
+
+ // Making the component size no larger than the requested free-busy
+ // report range.
+ if (!$vavailStart || $vavailStart < $this->start) {
+ $vavailStart = $this->start;
+ }
+ if (!$vavailEnd || $vavailEnd > $this->end) {
+ $vavailEnd = $this->end;
+ }
+
+ // Marking the entire time range of the VAVAILABILITY component as
+ // busy.
+ $fbData->add(
+ $vavailStart->getTimeStamp(),
+ $vavailEnd->getTimeStamp(),
+ $busyType
+ );
+
+ // Looping over the AVAILABLE components.
+ if (isset($vavail->AVAILABLE)) foreach ($vavail->AVAILABLE as $available) {
+
+ list($availStart, $availEnd) = $available->getEffectiveStartEnd();
+ $fbData->add(
+ $availStart->getTimeStamp(),
+ $availEnd->getTimeStamp(),
+ 'FREE'
+ );
+
+ if ($available->RRULE) {
+ // Our favourite thing: recurrence!!
+
+ $rruleIterator = new Recur\RRuleIterator(
+ $available->RRULE->getValue(),
+ $availStart
+ );
+ $rruleIterator->fastForward($vavailStart);
+
+ $startEndDiff = $availStart->diff($availEnd);
+
+ while ($rruleIterator->valid()) {
+
+ $recurStart = $rruleIterator->current();
+ $recurEnd = $recurStart->add($startEndDiff);
+
+ if ($recurStart > $vavailEnd) {
+ // We're beyond the legal timerange.
+ break;
+ }
+
+ if ($recurEnd > $vavailEnd) {
+ // Truncating the end if it exceeds the
+ // VAVAILABILITY end.
+ $recurEnd = $vavailEnd;
+ }
+
+ $fbData->add(
+ $recurStart->getTimeStamp(),
+ $recurEnd->getTimeStamp(),
+ 'FREE'
+ );
+
+ $rruleIterator->next();
+
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * This method takes an array of iCalendar objects and applies its busy
+ * times on fbData.
+ *
+ * @param FreeBusyData $fbData
+ * @param VCalendar[] $objects
+ */
+ protected function calculateBusy(FreeBusyData $fbData, array $objects) {
+
+ foreach ($objects as $key => $object) {
+
+ foreach ($object->getBaseComponents() as $component) {
+
+ switch ($component->name) {
+
+ case 'VEVENT' :
+
+ $FBTYPE = 'BUSY';
+ if (isset($component->TRANSP) && (strtoupper($component->TRANSP) === 'TRANSPARENT')) {
+ break;
+ }
+ if (isset($component->STATUS)) {
+ $status = strtoupper($component->STATUS);
+ if ($status === 'CANCELLED') {
+ break;
+ }
+ if ($status === 'TENTATIVE') {
+ $FBTYPE = 'BUSY-TENTATIVE';
+ }
+ }
+
+ $times = [];
+
+ if ($component->RRULE) {
+ try {
+ $iterator = new EventIterator($object, (string)$component->UID, $this->timeZone);
+ } catch (NoInstancesException $e) {
+ // This event is recurring, but it doesn't have a single
+ // instance. We are skipping this event from the output
+ // entirely.
+ unset($this->objects[$key]);
+ continue;
+ }
+
+ if ($this->start) {
+ $iterator->fastForward($this->start);
+ }
+
+ $maxRecurrences = Settings::$maxRecurrences;
+
+ while ($iterator->valid() && --$maxRecurrences) {
+
+ $startTime = $iterator->getDTStart();
+ if ($this->end && $startTime > $this->end) {
+ break;
+ }
+ $times[] = [
+ $iterator->getDTStart(),
+ $iterator->getDTEnd(),
+ ];
+
+ $iterator->next();
+
+ }
+
+ } else {
+
+ $startTime = $component->DTSTART->getDateTime($this->timeZone);
+ if ($this->end && $startTime > $this->end) {
+ break;
+ }
+ $endTime = null;
+ if (isset($component->DTEND)) {
+ $endTime = $component->DTEND->getDateTime($this->timeZone);
+ } elseif (isset($component->DURATION)) {
+ $duration = DateTimeParser::parseDuration((string)$component->DURATION);
+ $endTime = clone $startTime;
+ $endTime = $endTime->add($duration);
+ } elseif (!$component->DTSTART->hasTime()) {
+ $endTime = clone $startTime;
+ $endTime = $endTime->modify('+1 day');
+ } else {
+ // The event had no duration (0 seconds)
+ break;
+ }
+
+ $times[] = [$startTime, $endTime];
+
+ }
+
+ foreach ($times as $time) {
+
+ if ($this->end && $time[0] > $this->end) break;
+ if ($this->start && $time[1] < $this->start) break;
+
+ $fbData->add(
+ $time[0]->getTimeStamp(),
+ $time[1]->getTimeStamp(),
+ $FBTYPE
+ );
+ }
+ break;
+
+ case 'VFREEBUSY' :
+ foreach ($component->FREEBUSY as $freebusy) {
+
+ $fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY';
+
+ // Skipping intervals marked as 'free'
+ if ($fbType === 'FREE')
+ continue;
+
+ $values = explode(',', $freebusy);
+ foreach ($values as $value) {
+ list($startTime, $endTime) = explode('/', $value);
+ $startTime = DateTimeParser::parseDateTime($startTime);
+
+ if (substr($endTime, 0, 1) === 'P' || substr($endTime, 0, 2) === '-P') {
+ $duration = DateTimeParser::parseDuration($endTime);
+ $endTime = clone $startTime;
+ $endTime = $endTime->add($duration);
+ } else {
+ $endTime = DateTimeParser::parseDateTime($endTime);
+ }
+
+ if ($this->start && $this->start > $endTime) continue;
+ if ($this->end && $this->end < $startTime) continue;
+ $fbData->add(
+ $startTime->getTimeStamp(),
+ $endTime->getTimeStamp(),
+ $fbType
+ );
+
+ }
+
+
+ }
+ break;
+
+ }
+
+
+ }
+
+ }
+
+ }
+
+ /**
+ * This method takes a FreeBusyData object and generates the VCALENDAR
+ * object associated with it.
+ *
+ * @return VCalendar
+ */
+ protected function generateFreeBusyCalendar(FreeBusyData $fbData) {
+
+ if ($this->baseObject) {
+ $calendar = $this->baseObject;
+ } else {
+ $calendar = new VCalendar();
+ }
+
+ $vfreebusy = $calendar->createComponent('VFREEBUSY');
+ $calendar->add($vfreebusy);
+
+ if ($this->start) {
+ $dtstart = $calendar->createProperty('DTSTART');
+ $dtstart->setDateTime($this->start);
+ $vfreebusy->add($dtstart);
+ }
+ if ($this->end) {
+ $dtend = $calendar->createProperty('DTEND');
+ $dtend->setDateTime($this->end);
+ $vfreebusy->add($dtend);
+ }
+
+ $tz = new \DateTimeZone('UTC');
+ $dtstamp = $calendar->createProperty('DTSTAMP');
+ $dtstamp->setDateTime(new DateTimeImmutable('now', $tz));
+ $vfreebusy->add($dtstamp);
+
+ foreach ($fbData->getData() as $busyTime) {
+
+ $busyType = strtoupper($busyTime['type']);
+
+ // Ignoring all the FREE parts, because those are already assumed.
+ if ($busyType === 'FREE') {
+ continue;
+ }
+
+ $busyTime[0] = new \DateTimeImmutable('@' . $busyTime['start'], $tz);
+ $busyTime[1] = new \DateTimeImmutable('@' . $busyTime['end'], $tz);
+
+ $prop = $calendar->createProperty(
+ 'FREEBUSY',
+ $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
+ );
+
+ // Only setting FBTYPE if it's not BUSY, because BUSY is the
+ // default anyway.
+ if ($busyType !== 'BUSY') {
+ $prop['FBTYPE'] = $busyType;
+ }
+ $vfreebusy->add($prop);
+
+ }
+
+ return $calendar;
+
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/ITip/Broker.php b/vendor/sabre/vobject/lib/ITip/Broker.php
new file mode 100644
index 000000000..effa74317
--- /dev/null
+++ b/vendor/sabre/vobject/lib/ITip/Broker.php
@@ -0,0 +1,989 @@
+<?php
+
+namespace Sabre\VObject\ITip;
+
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\DateTimeParser;
+use Sabre\VObject\Reader;
+use Sabre\VObject\Recur\EventIterator;
+
+/**
+ * The ITip\Broker class is a utility class that helps with processing
+ * so-called iTip messages.
+ *
+ * iTip is defined in rfc5546, stands for iCalendar Transport-Independent
+ * Interoperability Protocol, and describes the underlying mechanism for
+ * using iCalendar for scheduling for for example through email (also known as
+ * IMip) and CalDAV Scheduling.
+ *
+ * This class helps by:
+ *
+ * 1. Creating individual invites based on an iCalendar event for each
+ * attendee.
+ * 2. Generating invite updates based on an iCalendar update. This may result
+ * in new invites, updates and cancellations for attendees, if that list
+ * changed.
+ * 3. On the receiving end, it can create a local iCalendar event based on
+ * a received invite.
+ * 4. It can also process an invite update on a local event, ensuring that any
+ * overridden properties from attendees are retained.
+ * 5. It can create a accepted or declined iTip reply based on an invite.
+ * 6. It can process a reply from an invite and update an events attendee
+ * status based on a reply.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Broker {
+
+ /**
+ * This setting determines whether the rules for the SCHEDULE-AGENT
+ * parameter should be followed.
+ *
+ * This is a parameter defined on ATTENDEE properties, introduced by RFC
+ * 6638. This parameter allows a caldav client to tell the server 'Don't do
+ * any scheduling operations'.
+ *
+ * If this setting is turned on, any attendees with SCHEDULE-AGENT set to
+ * CLIENT will be ignored. This is the desired behavior for a CalDAV
+ * server, but if you're writing an iTip application that doesn't deal with
+ * CalDAV, you may want to ignore this parameter.
+ *
+ * @var bool
+ */
+ public $scheduleAgentServerRules = true;
+
+ /**
+ * The broker will try during 'parseEvent' figure out whether the change
+ * was significant.
+ *
+ * It uses a few different ways to do this. One of these ways is seeing if
+ * certain properties changed values. This list of specified here.
+ *
+ * This list is taken from:
+ * * http://tools.ietf.org/html/rfc5546#section-2.1.4
+ *
+ * @var string[]
+ */
+ public $significantChangeProperties = [
+ 'DTSTART',
+ 'DTEND',
+ 'DURATION',
+ 'DUE',
+ 'RRULE',
+ 'RDATE',
+ 'EXDATE',
+ 'STATUS',
+ ];
+
+ /**
+ * This method is used to process an incoming itip message.
+ *
+ * Examples:
+ *
+ * 1. A user is an attendee to an event. The organizer sends an updated
+ * meeting using a new iTip message with METHOD:REQUEST. This function
+ * will process the message and update the attendee's event accordingly.
+ *
+ * 2. The organizer cancelled the event using METHOD:CANCEL. We will update
+ * the users event to state STATUS:CANCELLED.
+ *
+ * 3. An attendee sent a reply to an invite using METHOD:REPLY. We can
+ * update the organizers event to update the ATTENDEE with its correct
+ * PARTSTAT.
+ *
+ * The $existingObject is updated in-place. If there is no existing object
+ * (because it's a new invite for example) a new object will be created.
+ *
+ * If an existing object does not exist, and the method was CANCEL or
+ * REPLY, the message effectively gets ignored, and no 'existingObject'
+ * will be created.
+ *
+ * The updated $existingObject is also returned from this function.
+ *
+ * If the iTip message was not supported, we will always return false.
+ *
+ * @param Message $itipMessage
+ * @param VCalendar $existingObject
+ *
+ * @return VCalendar|null
+ */
+ function processMessage(Message $itipMessage, VCalendar $existingObject = null) {
+
+ // We only support events at the moment.
+ if ($itipMessage->component !== 'VEVENT') {
+ return false;
+ }
+
+ switch ($itipMessage->method) {
+
+ case 'REQUEST' :
+ return $this->processMessageRequest($itipMessage, $existingObject);
+
+ case 'CANCEL' :
+ return $this->processMessageCancel($itipMessage, $existingObject);
+
+ case 'REPLY' :
+ return $this->processMessageReply($itipMessage, $existingObject);
+
+ default :
+ // Unsupported iTip message
+ return;
+
+ }
+
+ return $existingObject;
+
+ }
+
+ /**
+ * This function parses a VCALENDAR object and figure out if any messages
+ * need to be sent.
+ *
+ * A VCALENDAR object will be created from the perspective of either an
+ * attendee, or an organizer. You must pass a string identifying the
+ * current user, so we can figure out who in the list of attendees or the
+ * organizer we are sending this message on behalf of.
+ *
+ * It's possible to specify the current user as an array, in case the user
+ * has more than one identifying href (such as multiple emails).
+ *
+ * It $oldCalendar is specified, it is assumed that the operation is
+ * updating an existing event, which means that we need to look at the
+ * differences between events, and potentially send old attendees
+ * cancellations, and current attendees updates.
+ *
+ * If $calendar is null, but $oldCalendar is specified, we treat the
+ * operation as if the user has deleted an event. If the user was an
+ * organizer, this means that we need to send cancellation notices to
+ * people. If the user was an attendee, we need to make sure that the
+ * organizer gets the 'declined' message.
+ *
+ * @param VCalendar|string $calendar
+ * @param string|array $userHref
+ * @param VCalendar|string $oldCalendar
+ *
+ * @return array
+ */
+ function parseEvent($calendar = null, $userHref, $oldCalendar = null) {
+
+ if ($oldCalendar) {
+ if (is_string($oldCalendar)) {
+ $oldCalendar = Reader::read($oldCalendar);
+ }
+ if (!isset($oldCalendar->VEVENT)) {
+ // We only support events at the moment
+ return [];
+ }
+
+ $oldEventInfo = $this->parseEventInfo($oldCalendar);
+ } else {
+ $oldEventInfo = [
+ 'organizer' => null,
+ 'significantChangeHash' => '',
+ 'attendees' => [],
+ ];
+ }
+
+ $userHref = (array)$userHref;
+
+ if (!is_null($calendar)) {
+
+ if (is_string($calendar)) {
+ $calendar = Reader::read($calendar);
+ }
+ if (!isset($calendar->VEVENT)) {
+ // We only support events at the moment
+ return [];
+ }
+ $eventInfo = $this->parseEventInfo($calendar);
+ if (!$eventInfo['attendees'] && !$oldEventInfo['attendees']) {
+ // If there were no attendees on either side of the equation,
+ // we don't need to do anything.
+ return [];
+ }
+ if (!$eventInfo['organizer'] && !$oldEventInfo['organizer']) {
+ // There was no organizer before or after the change.
+ return [];
+ }
+
+ $baseCalendar = $calendar;
+
+ // If the new object didn't have an organizer, the organizer
+ // changed the object from a scheduling object to a non-scheduling
+ // object. We just copy the info from the old object.
+ if (!$eventInfo['organizer'] && $oldEventInfo['organizer']) {
+ $eventInfo['organizer'] = $oldEventInfo['organizer'];
+ $eventInfo['organizerName'] = $oldEventInfo['organizerName'];
+ }
+
+ } else {
+ // The calendar object got deleted, we need to process this as a
+ // cancellation / decline.
+ if (!$oldCalendar) {
+ // No old and no new calendar, there's no thing to do.
+ return [];
+ }
+
+ $eventInfo = $oldEventInfo;
+
+ if (in_array($eventInfo['organizer'], $userHref)) {
+ // This is an organizer deleting the event.
+ $eventInfo['attendees'] = [];
+ // Increasing the sequence, but only if the organizer deleted
+ // the event.
+ $eventInfo['sequence']++;
+ } else {
+ // This is an attendee deleting the event.
+ foreach ($eventInfo['attendees'] as $key => $attendee) {
+ if (in_array($attendee['href'], $userHref)) {
+ $eventInfo['attendees'][$key]['instances'] = ['master' =>
+ ['id' => 'master', 'partstat' => 'DECLINED']
+ ];
+ }
+ }
+ }
+ $baseCalendar = $oldCalendar;
+
+ }
+
+ if (in_array($eventInfo['organizer'], $userHref)) {
+ return $this->parseEventForOrganizer($baseCalendar, $eventInfo, $oldEventInfo);
+ } elseif ($oldCalendar) {
+ // We need to figure out if the user is an attendee, but we're only
+ // doing so if there's an oldCalendar, because we only want to
+ // process updates, not creation of new events.
+ foreach ($eventInfo['attendees'] as $attendee) {
+ if (in_array($attendee['href'], $userHref)) {
+ return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
+ }
+ }
+ }
+ return [];
+
+ }
+
+ /**
+ * Processes incoming REQUEST messages.
+ *
+ * This is message from an organizer, and is either a new event
+ * invite, or an update to an existing one.
+ *
+ *
+ * @param Message $itipMessage
+ * @param VCalendar $existingObject
+ *
+ * @return VCalendar|null
+ */
+ protected function processMessageRequest(Message $itipMessage, VCalendar $existingObject = null) {
+
+ if (!$existingObject) {
+ // This is a new invite, and we're just going to copy over
+ // all the components from the invite.
+ $existingObject = new VCalendar();
+ foreach ($itipMessage->message->getComponents() as $component) {
+ $existingObject->add(clone $component);
+ }
+ } else {
+ // We need to update an existing object with all the new
+ // information. We can just remove all existing components
+ // and create new ones.
+ foreach ($existingObject->getComponents() as $component) {
+ $existingObject->remove($component);
+ }
+ foreach ($itipMessage->message->getComponents() as $component) {
+ $existingObject->add(clone $component);
+ }
+ }
+ return $existingObject;
+
+ }
+
+ /**
+ * Processes incoming CANCEL messages.
+ *
+ * This is a message from an organizer, and means that either an
+ * attendee got removed from an event, or an event got cancelled
+ * altogether.
+ *
+ * @param Message $itipMessage
+ * @param VCalendar $existingObject
+ *
+ * @return VCalendar|null
+ */
+ protected function processMessageCancel(Message $itipMessage, VCalendar $existingObject = null) {
+
+ if (!$existingObject) {
+ // The event didn't exist in the first place, so we're just
+ // ignoring this message.
+ } else {
+ foreach ($existingObject->VEVENT as $vevent) {
+ $vevent->STATUS = 'CANCELLED';
+ $vevent->SEQUENCE = $itipMessage->sequence;
+ }
+ }
+ return $existingObject;
+
+ }
+
+ /**
+ * Processes incoming REPLY messages.
+ *
+ * The message is a reply. This is for example an attendee telling
+ * an organizer he accepted the invite, or declined it.
+ *
+ * @param Message $itipMessage
+ * @param VCalendar $existingObject
+ *
+ * @return VCalendar|null
+ */
+ protected function processMessageReply(Message $itipMessage, VCalendar $existingObject = null) {
+
+ // A reply can only be processed based on an existing object.
+ // If the object is not available, the reply is ignored.
+ if (!$existingObject) {
+ return;
+ }
+ $instances = [];
+ $requestStatus = '2.0';
+
+ // Finding all the instances the attendee replied to.
+ foreach ($itipMessage->message->VEVENT as $vevent) {
+ $recurId = isset($vevent->{'RECURRENCE-ID'}) ? $vevent->{'RECURRENCE-ID'}->getValue() : 'master';
+ $attendee = $vevent->ATTENDEE;
+ $instances[$recurId] = $attendee['PARTSTAT']->getValue();
+ if (isset($vevent->{'REQUEST-STATUS'})) {
+ $requestStatus = $vevent->{'REQUEST-STATUS'}->getValue();
+ list($requestStatus) = explode(';', $requestStatus);
+ }
+ }
+
+ // Now we need to loop through the original organizer event, to find
+ // all the instances where we have a reply for.
+ $masterObject = null;
+ foreach ($existingObject->VEVENT as $vevent) {
+ $recurId = isset($vevent->{'RECURRENCE-ID'}) ? $vevent->{'RECURRENCE-ID'}->getValue() : 'master';
+ if ($recurId === 'master') {
+ $masterObject = $vevent;
+ }
+ if (isset($instances[$recurId])) {
+ $attendeeFound = false;
+ if (isset($vevent->ATTENDEE)) {
+ foreach ($vevent->ATTENDEE as $attendee) {
+ if ($attendee->getValue() === $itipMessage->sender) {
+ $attendeeFound = true;
+ $attendee['PARTSTAT'] = $instances[$recurId];
+ $attendee['SCHEDULE-STATUS'] = $requestStatus;
+ // Un-setting the RSVP status, because we now know
+ // that the attendee already replied.
+ unset($attendee['RSVP']);
+ break;
+ }
+ }
+ }
+ if (!$attendeeFound) {
+ // Adding a new attendee. The iTip documentation calls this
+ // a party crasher.
+ $attendee = $vevent->add('ATTENDEE', $itipMessage->sender, [
+ 'PARTSTAT' => $instances[$recurId]
+ ]);
+ if ($itipMessage->senderName) $attendee['CN'] = $itipMessage->senderName;
+ }
+ unset($instances[$recurId]);
+ }
+ }
+
+ if (!$masterObject) {
+ // No master object, we can't add new instances.
+ return;
+ }
+ // If we got replies to instances that did not exist in the
+ // original list, it means that new exceptions must be created.
+ foreach ($instances as $recurId => $partstat) {
+
+ $recurrenceIterator = new EventIterator($existingObject, $itipMessage->uid);
+ $found = false;
+ $iterations = 1000;
+ do {
+
+ $newObject = $recurrenceIterator->getEventObject();
+ $recurrenceIterator->next();
+
+ if (isset($newObject->{'RECURRENCE-ID'}) && $newObject->{'RECURRENCE-ID'}->getValue() === $recurId) {
+ $found = true;
+ }
+ $iterations--;
+
+ } while ($recurrenceIterator->valid() && !$found && $iterations);
+
+ // Invalid recurrence id. Skipping this object.
+ if (!$found) continue;
+
+ unset(
+ $newObject->RRULE,
+ $newObject->EXDATE,
+ $newObject->RDATE
+ );
+ $attendeeFound = false;
+ if (isset($newObject->ATTENDEE)) {
+ foreach ($newObject->ATTENDEE as $attendee) {
+ if ($attendee->getValue() === $itipMessage->sender) {
+ $attendeeFound = true;
+ $attendee['PARTSTAT'] = $partstat;
+ break;
+ }
+ }
+ }
+ if (!$attendeeFound) {
+ // Adding a new attendee
+ $attendee = $newObject->add('ATTENDEE', $itipMessage->sender, [
+ 'PARTSTAT' => $partstat
+ ]);
+ if ($itipMessage->senderName) {
+ $attendee['CN'] = $itipMessage->senderName;
+ }
+ }
+ $existingObject->add($newObject);
+
+ }
+ return $existingObject;
+
+ }
+
+ /**
+ * This method is used in cases where an event got updated, and we
+ * potentially need to send emails to attendees to let them know of updates
+ * in the events.
+ *
+ * We will detect which attendees got added, which got removed and create
+ * specific messages for these situations.
+ *
+ * @param VCalendar $calendar
+ * @param array $eventInfo
+ * @param array $oldEventInfo
+ *
+ * @return array
+ */
+ protected function parseEventForOrganizer(VCalendar $calendar, array $eventInfo, array $oldEventInfo) {
+
+ // Merging attendee lists.
+ $attendees = [];
+ foreach ($oldEventInfo['attendees'] as $attendee) {
+ $attendees[$attendee['href']] = [
+ 'href' => $attendee['href'],
+ 'oldInstances' => $attendee['instances'],
+ 'newInstances' => [],
+ 'name' => $attendee['name'],
+ 'forceSend' => null,
+ ];
+ }
+ foreach ($eventInfo['attendees'] as $attendee) {
+ if (isset($attendees[$attendee['href']])) {
+ $attendees[$attendee['href']]['name'] = $attendee['name'];
+ $attendees[$attendee['href']]['newInstances'] = $attendee['instances'];
+ $attendees[$attendee['href']]['forceSend'] = $attendee['forceSend'];
+ } else {
+ $attendees[$attendee['href']] = [
+ 'href' => $attendee['href'],
+ 'oldInstances' => [],
+ 'newInstances' => $attendee['instances'],
+ 'name' => $attendee['name'],
+ 'forceSend' => $attendee['forceSend'],
+ ];
+ }
+ }
+
+ $messages = [];
+
+ foreach ($attendees as $attendee) {
+
+ // An organizer can also be an attendee. We should not generate any
+ // messages for those.
+ if ($attendee['href'] === $eventInfo['organizer']) {
+ continue;
+ }
+
+ $message = new Message();
+ $message->uid = $eventInfo['uid'];
+ $message->component = 'VEVENT';
+ $message->sequence = $eventInfo['sequence'];
+ $message->sender = $eventInfo['organizer'];
+ $message->senderName = $eventInfo['organizerName'];
+ $message->recipient = $attendee['href'];
+ $message->recipientName = $attendee['name'];
+
+ if (!$attendee['newInstances']) {
+
+ // If there are no instances the attendee is a part of, it
+ // means the attendee was removed and we need to send him a
+ // CANCEL.
+ $message->method = 'CANCEL';
+
+ // Creating the new iCalendar body.
+ $icalMsg = new VCalendar();
+ $icalMsg->METHOD = $message->method;
+ $event = $icalMsg->add('VEVENT', [
+ 'UID' => $message->uid,
+ 'SEQUENCE' => $message->sequence,
+ ]);
+ if (isset($calendar->VEVENT->SUMMARY)) {
+ $event->add('SUMMARY', $calendar->VEVENT->SUMMARY->getValue());
+ }
+ $event->add(clone $calendar->VEVENT->DTSTART);
+ if (isset($calendar->VEVENT->DTEND)) {
+ $event->add(clone $calendar->VEVENT->DTEND);
+ } elseif (isset($calendar->VEVENT->DURATION)) {
+ $event->add(clone $calendar->VEVENT->DURATION);
+ }
+ $org = $event->add('ORGANIZER', $eventInfo['organizer']);
+ if ($eventInfo['organizerName']) $org['CN'] = $eventInfo['organizerName'];
+ $event->add('ATTENDEE', $attendee['href'], [
+ 'CN' => $attendee['name'],
+ ]);
+ $message->significantChange = true;
+
+ } else {
+
+ // The attendee gets the updated event body
+ $message->method = 'REQUEST';
+
+ // Creating the new iCalendar body.
+ $icalMsg = new VCalendar();
+ $icalMsg->METHOD = $message->method;
+
+ foreach ($calendar->select('VTIMEZONE') as $timezone) {
+ $icalMsg->add(clone $timezone);
+ }
+
+ // We need to find out that this change is significant. If it's
+ // not, systems may opt to not send messages.
+ //
+ // We do this based on the 'significantChangeHash' which is
+ // some value that changes if there's a certain set of
+ // properties changed in the event, or simply if there's a
+ // difference in instances that the attendee is invited to.
+
+ $message->significantChange =
+ $attendee['forceSend'] === 'REQUEST' ||
+ array_keys($attendee['oldInstances']) != array_keys($attendee['newInstances']) ||
+ $oldEventInfo['significantChangeHash'] !== $eventInfo['significantChangeHash'];
+
+ foreach ($attendee['newInstances'] as $instanceId => $instanceInfo) {
+
+ $currentEvent = clone $eventInfo['instances'][$instanceId];
+ if ($instanceId === 'master') {
+
+ // We need to find a list of events that the attendee
+ // is not a part of to add to the list of exceptions.
+ $exceptions = [];
+ foreach ($eventInfo['instances'] as $instanceId => $vevent) {
+ if (!isset($attendee['newInstances'][$instanceId])) {
+ $exceptions[] = $instanceId;
+ }
+ }
+
+ // If there were exceptions, we need to add it to an
+ // existing EXDATE property, if it exists.
+ if ($exceptions) {
+ if (isset($currentEvent->EXDATE)) {
+ $currentEvent->EXDATE->setParts(array_merge(
+ $currentEvent->EXDATE->getParts(),
+ $exceptions
+ ));
+ } else {
+ $currentEvent->EXDATE = $exceptions;
+ }
+ }
+
+ // Cleaning up any scheduling information that
+ // shouldn't be sent along.
+ unset($currentEvent->ORGANIZER['SCHEDULE-FORCE-SEND']);
+ unset($currentEvent->ORGANIZER['SCHEDULE-STATUS']);
+
+ foreach ($currentEvent->ATTENDEE as $attendee) {
+ unset($attendee['SCHEDULE-FORCE-SEND']);
+ unset($attendee['SCHEDULE-STATUS']);
+
+ // We're adding PARTSTAT=NEEDS-ACTION to ensure that
+ // iOS shows an "Inbox Item"
+ if (!isset($attendee['PARTSTAT'])) {
+ $attendee['PARTSTAT'] = 'NEEDS-ACTION';
+ }
+
+ }
+
+ }
+
+ $icalMsg->add($currentEvent);
+
+ }
+
+ }
+
+ $message->message = $icalMsg;
+ $messages[] = $message;
+
+ }
+
+ return $messages;
+
+ }
+
+ /**
+ * Parse an event update for an attendee.
+ *
+ * This function figures out if we need to send a reply to an organizer.
+ *
+ * @param VCalendar $calendar
+ * @param array $eventInfo
+ * @param array $oldEventInfo
+ * @param string $attendee
+ *
+ * @return Message[]
+ */
+ protected function parseEventForAttendee(VCalendar $calendar, array $eventInfo, array $oldEventInfo, $attendee) {
+
+ if ($this->scheduleAgentServerRules && $eventInfo['organizerScheduleAgent'] === 'CLIENT') {
+ return [];
+ }
+
+ // Don't bother generating messages for events that have already been
+ // cancelled.
+ if ($eventInfo['status'] === 'CANCELLED') {
+ return [];
+ }
+
+ $oldInstances = !empty($oldEventInfo['attendees'][$attendee]['instances']) ?
+ $oldEventInfo['attendees'][$attendee]['instances'] :
+ [];
+
+ $instances = [];
+ foreach ($oldInstances as $instance) {
+
+ $instances[$instance['id']] = [
+ 'id' => $instance['id'],
+ 'oldstatus' => $instance['partstat'],
+ 'newstatus' => null,
+ ];
+
+ }
+ foreach ($eventInfo['attendees'][$attendee]['instances'] as $instance) {
+
+ if (isset($instances[$instance['id']])) {
+ $instances[$instance['id']]['newstatus'] = $instance['partstat'];
+ } else {
+ $instances[$instance['id']] = [
+ 'id' => $instance['id'],
+ 'oldstatus' => null,
+ 'newstatus' => $instance['partstat'],
+ ];
+ }
+
+ }
+
+ // We need to also look for differences in EXDATE. If there are new
+ // items in EXDATE, it means that an attendee deleted instances of an
+ // event, which means we need to send DECLINED specifically for those
+ // instances.
+ // We only need to do that though, if the master event is not declined.
+ if (isset($instances['master']) && $instances['master']['newstatus'] !== 'DECLINED') {
+ foreach ($eventInfo['exdate'] as $exDate) {
+
+ if (!in_array($exDate, $oldEventInfo['exdate'])) {
+ if (isset($instances[$exDate])) {
+ $instances[$exDate]['newstatus'] = 'DECLINED';
+ } else {
+ $instances[$exDate] = [
+ 'id' => $exDate,
+ 'oldstatus' => null,
+ 'newstatus' => 'DECLINED',
+ ];
+ }
+ }
+
+ }
+ }
+
+ // Gathering a few extra properties for each instance.
+ foreach ($instances as $recurId => $instanceInfo) {
+
+ if (isset($eventInfo['instances'][$recurId])) {
+ $instances[$recurId]['dtstart'] = clone $eventInfo['instances'][$recurId]->DTSTART;
+ } else {
+ $instances[$recurId]['dtstart'] = $recurId;
+ }
+
+ }
+
+ $message = new Message();
+ $message->uid = $eventInfo['uid'];
+ $message->method = 'REPLY';
+ $message->component = 'VEVENT';
+ $message->sequence = $eventInfo['sequence'];
+ $message->sender = $attendee;
+ $message->senderName = $eventInfo['attendees'][$attendee]['name'];
+ $message->recipient = $eventInfo['organizer'];
+ $message->recipientName = $eventInfo['organizerName'];
+
+ $icalMsg = new VCalendar();
+ $icalMsg->METHOD = 'REPLY';
+
+ $hasReply = false;
+
+ foreach ($instances as $instance) {
+
+ if ($instance['oldstatus'] == $instance['newstatus'] && $eventInfo['organizerForceSend'] !== 'REPLY') {
+ // Skip
+ continue;
+ }
+
+ $event = $icalMsg->add('VEVENT', [
+ 'UID' => $message->uid,
+ 'SEQUENCE' => $message->sequence,
+ ]);
+ $summary = isset($calendar->VEVENT->SUMMARY) ? $calendar->VEVENT->SUMMARY->getValue() : '';
+ // Adding properties from the correct source instance
+ if (isset($eventInfo['instances'][$instance['id']])) {
+ $instanceObj = $eventInfo['instances'][$instance['id']];
+ $event->add(clone $instanceObj->DTSTART);
+ if (isset($instanceObj->DTEND)) {
+ $event->add(clone $instanceObj->DTEND);
+ } elseif (isset($instanceObj->DURATION)) {
+ $event->add(clone $instanceObj->DURATION);
+ }
+ if (isset($instanceObj->SUMMARY)) {
+ $event->add('SUMMARY', $instanceObj->SUMMARY->getValue());
+ } elseif ($summary) {
+ $event->add('SUMMARY', $summary);
+ }
+ } else {
+ // This branch of the code is reached, when a reply is
+ // generated for an instance of a recurring event, through the
+ // fact that the instance has disappeared by showing up in
+ // EXDATE
+ $dt = DateTimeParser::parse($instance['id'], $eventInfo['timezone']);
+ // Treat is as a DATE field
+ if (strlen($instance['id']) <= 8) {
+ $event->add('DTSTART', $dt, ['VALUE' => 'DATE']);
+ } else {
+ $event->add('DTSTART', $dt);
+ }
+ if ($summary) {
+ $event->add('SUMMARY', $summary);
+ }
+ }
+ if ($instance['id'] !== 'master') {
+ $dt = DateTimeParser::parse($instance['id'], $eventInfo['timezone']);
+ // Treat is as a DATE field
+ if (strlen($instance['id']) <= 8) {
+ $event->add('RECURRENCE-ID', $dt, ['VALUE' => 'DATE']);
+ } else {
+ $event->add('RECURRENCE-ID', $dt);
+ }
+ }
+ $organizer = $event->add('ORGANIZER', $message->recipient);
+ if ($message->recipientName) {
+ $organizer['CN'] = $message->recipientName;
+ }
+ $attendee = $event->add('ATTENDEE', $message->sender, [
+ 'PARTSTAT' => $instance['newstatus']
+ ]);
+ if ($message->senderName) {
+ $attendee['CN'] = $message->senderName;
+ }
+ $hasReply = true;
+
+ }
+
+ if ($hasReply) {
+ $message->message = $icalMsg;
+ return [$message];
+ } else {
+ return [];
+ }
+
+ }
+
+ /**
+ * Returns attendee information and information about instances of an
+ * event.
+ *
+ * Returns an array with the following keys:
+ *
+ * 1. uid
+ * 2. organizer
+ * 3. organizerName
+ * 4. organizerScheduleAgent
+ * 5. organizerForceSend
+ * 6. instances
+ * 7. attendees
+ * 8. sequence
+ * 9. exdate
+ * 10. timezone - strictly the timezone on which the recurrence rule is
+ * based on.
+ * 11. significantChangeHash
+ * 12. status
+ * @param VCalendar $calendar
+ *
+ * @return array
+ */
+ protected function parseEventInfo(VCalendar $calendar = null) {
+
+ $uid = null;
+ $organizer = null;
+ $organizerName = null;
+ $organizerForceSend = null;
+ $sequence = null;
+ $timezone = null;
+ $status = null;
+ $organizerScheduleAgent = 'SERVER';
+
+ $significantChangeHash = '';
+
+ // Now we need to collect a list of attendees, and which instances they
+ // are a part of.
+ $attendees = [];
+
+ $instances = [];
+ $exdate = [];
+
+ foreach ($calendar->VEVENT as $vevent) {
+
+ if (is_null($uid)) {
+ $uid = $vevent->UID->getValue();
+ } else {
+ if ($uid !== $vevent->UID->getValue()) {
+ throw new ITipException('If a calendar contained more than one event, they must have the same UID.');
+ }
+ }
+
+ if (!isset($vevent->DTSTART)) {
+ throw new ITipException('An event MUST have a DTSTART property.');
+ }
+
+ if (isset($vevent->ORGANIZER)) {
+ if (is_null($organizer)) {
+ $organizer = $vevent->ORGANIZER->getNormalizedValue();
+ $organizerName = isset($vevent->ORGANIZER['CN']) ? $vevent->ORGANIZER['CN'] : null;
+ } else {
+ if ($organizer !== $vevent->ORGANIZER->getNormalizedValue()) {
+ throw new SameOrganizerForAllComponentsException('Every instance of the event must have the same organizer.');
+ }
+ }
+ $organizerForceSend =
+ isset($vevent->ORGANIZER['SCHEDULE-FORCE-SEND']) ?
+ strtoupper($vevent->ORGANIZER['SCHEDULE-FORCE-SEND']) :
+ null;
+ $organizerScheduleAgent =
+ isset($vevent->ORGANIZER['SCHEDULE-AGENT']) ?
+ strtoupper((string)$vevent->ORGANIZER['SCHEDULE-AGENT']) :
+ 'SERVER';
+ }
+ if (is_null($sequence) && isset($vevent->SEQUENCE)) {
+ $sequence = $vevent->SEQUENCE->getValue();
+ }
+ if (isset($vevent->EXDATE)) {
+ foreach ($vevent->select('EXDATE') as $val) {
+ $exdate = array_merge($exdate, $val->getParts());
+ }
+ sort($exdate);
+ }
+ if (isset($vevent->STATUS)) {
+ $status = strtoupper($vevent->STATUS->getValue());
+ }
+
+ $recurId = isset($vevent->{'RECURRENCE-ID'}) ? $vevent->{'RECURRENCE-ID'}->getValue() : 'master';
+ if (is_null($timezone)) {
+ if ($recurId === 'master') {
+ $timezone = $vevent->DTSTART->getDateTime()->getTimeZone();
+ } else {
+ $timezone = $vevent->{'RECURRENCE-ID'}->getDateTime()->getTimeZone();
+ }
+ }
+ if (isset($vevent->ATTENDEE)) {
+ foreach ($vevent->ATTENDEE as $attendee) {
+
+ if ($this->scheduleAgentServerRules &&
+ isset($attendee['SCHEDULE-AGENT']) &&
+ strtoupper($attendee['SCHEDULE-AGENT']->getValue()) === 'CLIENT'
+ ) {
+ continue;
+ }
+ $partStat =
+ isset($attendee['PARTSTAT']) ?
+ strtoupper($attendee['PARTSTAT']) :
+ 'NEEDS-ACTION';
+
+ $forceSend =
+ isset($attendee['SCHEDULE-FORCE-SEND']) ?
+ strtoupper($attendee['SCHEDULE-FORCE-SEND']) :
+ null;
+
+
+ if (isset($attendees[$attendee->getNormalizedValue()])) {
+ $attendees[$attendee->getNormalizedValue()]['instances'][$recurId] = [
+ 'id' => $recurId,
+ 'partstat' => $partStat,
+ 'force-send' => $forceSend,
+ ];
+ } else {
+ $attendees[$attendee->getNormalizedValue()] = [
+ 'href' => $attendee->getNormalizedValue(),
+ 'instances' => [
+ $recurId => [
+ 'id' => $recurId,
+ 'partstat' => $partStat,
+ ],
+ ],
+ 'name' => isset($attendee['CN']) ? (string)$attendee['CN'] : null,
+ 'forceSend' => $forceSend,
+ ];
+ }
+
+ }
+ $instances[$recurId] = $vevent;
+
+ }
+
+ foreach ($this->significantChangeProperties as $prop) {
+ if (isset($vevent->$prop)) {
+ $propertyValues = $vevent->select($prop);
+
+ $significantChangeHash .= $prop . ':';
+
+ if ($prop === 'EXDATE') {
+
+ $significantChangeHash .= implode(',', $exdate) . ';';
+
+ } else {
+
+ foreach ($propertyValues as $val) {
+ $significantChangeHash .= $val->getValue() . ';';
+ }
+
+ }
+ }
+ }
+
+ }
+ $significantChangeHash = md5($significantChangeHash);
+
+ return compact(
+ 'uid',
+ 'organizer',
+ 'organizerName',
+ 'organizerScheduleAgent',
+ 'organizerForceSend',
+ 'instances',
+ 'attendees',
+ 'sequence',
+ 'exdate',
+ 'timezone',
+ 'significantChangeHash',
+ 'status'
+ );
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/ITip/ITipException.php b/vendor/sabre/vobject/lib/ITip/ITipException.php
new file mode 100644
index 000000000..ad5e53ab4
--- /dev/null
+++ b/vendor/sabre/vobject/lib/ITip/ITipException.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Sabre\VObject\ITip;
+
+use Exception;
+
+/**
+ * This message is emitted in case of serious problems with iTip messages.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class ITipException extends Exception {
+}
diff --git a/vendor/sabre/vobject/lib/ITip/Message.php b/vendor/sabre/vobject/lib/ITip/Message.php
new file mode 100644
index 000000000..bebe2e4fc
--- /dev/null
+++ b/vendor/sabre/vobject/lib/ITip/Message.php
@@ -0,0 +1,141 @@
+<?php
+
+namespace Sabre\VObject\ITip;
+
+/**
+ * This class represents an iTip message.
+ *
+ * A message holds all the information relevant to the message, including the
+ * object itself.
+ *
+ * It should for the most part be treated as immutable.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Message {
+
+ /**
+ * The object's UID.
+ *
+ * @var string
+ */
+ public $uid;
+
+ /**
+ * The component type, such as VEVENT.
+ *
+ * @var string
+ */
+ public $component;
+
+ /**
+ * Contains the ITip method, which is something like REQUEST, REPLY or
+ * CANCEL.
+ *
+ * @var string
+ */
+ public $method;
+
+ /**
+ * The current sequence number for the event.
+ *
+ * @var int
+ */
+ public $sequence;
+
+ /**
+ * The senders' email address.
+ *
+ * Note that this does not imply that this has to be used in a From: field
+ * if the message is sent by email. It may also be populated in Reply-To:
+ * or not at all.
+ *
+ * @var string
+ */
+ public $sender;
+
+ /**
+ * The name of the sender. This is often populated from a CN parameter from
+ * either the ORGANIZER or ATTENDEE, depending on the message.
+ *
+ * @var string|null
+ */
+ public $senderName;
+
+ /**
+ * The recipient's email address.
+ *
+ * @var string
+ */
+ public $recipient;
+
+ /**
+ * The name of the recipient. This is usually populated with the CN
+ * parameter from the ATTENDEE or ORGANIZER property, if it's available.
+ *
+ * @var string|null
+ */
+ public $recipientName;
+
+ /**
+ * After the message has been delivered, this should contain a string such
+ * as : 1.1;Sent or 1.2;Delivered.
+ *
+ * In case of a failure, this will hold the error status code.
+ *
+ * See:
+ * http://tools.ietf.org/html/rfc6638#section-7.3
+ *
+ * @var string
+ */
+ public $scheduleStatus;
+
+ /**
+ * The iCalendar / iTip body.
+ *
+ * @var \Sabre\VObject\Component\VCalendar
+ */
+ public $message;
+
+ /**
+ * This will be set to true, if the iTip broker considers the change
+ * 'significant'.
+ *
+ * In practice, this means that we'll only mark it true, if for instance
+ * DTSTART changed. This allows systems to only send iTip messages when
+ * significant changes happened. This is especially useful for iMip, as
+ * normally a ton of messages may be generated for normal calendar use.
+ *
+ * To see the list of properties that are considered 'significant', check
+ * out Sabre\VObject\ITip\Broker::$significantChangeProperties.
+ *
+ * @var bool
+ */
+ public $significantChange = true;
+
+ /**
+ * Returns the schedule status as a string.
+ *
+ * For example:
+ * 1.2
+ *
+ * @return mixed bool|string
+ */
+ function getScheduleStatus() {
+
+ if (!$this->scheduleStatus) {
+
+ return false;
+
+ } else {
+
+ list($scheduleStatus) = explode(';', $this->scheduleStatus);
+ return $scheduleStatus;
+
+ }
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/ITip/SameOrganizerForAllComponentsException.php b/vendor/sabre/vobject/lib/ITip/SameOrganizerForAllComponentsException.php
new file mode 100644
index 000000000..423b39831
--- /dev/null
+++ b/vendor/sabre/vobject/lib/ITip/SameOrganizerForAllComponentsException.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Sabre\VObject\ITip;
+
+/**
+ * SameOrganizerForAllComponentsException.
+ *
+ * This exception is emitted when an event is encountered with more than one
+ * component (e.g.: exceptions), but the organizer is not identical in every
+ * component.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class SameOrganizerForAllComponentsException extends ITipException {
+
+}
diff --git a/vendor/sabre/vobject/lib/InvalidDataException.php b/vendor/sabre/vobject/lib/InvalidDataException.php
new file mode 100644
index 000000000..50ebc0f49
--- /dev/null
+++ b/vendor/sabre/vobject/lib/InvalidDataException.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * This exception is thrown whenever an invalid value is found anywhere in a
+ * iCalendar or vCard object.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class InvalidDataException extends \Exception {
+}
diff --git a/vendor/sabre/vobject/lib/Node.php b/vendor/sabre/vobject/lib/Node.php
new file mode 100644
index 000000000..e2845da75
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Node.php
@@ -0,0 +1,265 @@
+<?php
+
+namespace Sabre\VObject;
+
+use Sabre\Xml;
+
+/**
+ * A node is the root class for every element in an iCalendar of vCard object.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+abstract class Node
+ implements \IteratorAggregate,
+ \ArrayAccess,
+ \Countable,
+ \JsonSerializable,
+ Xml\XmlSerializable {
+
+ /**
+ * The following constants are used by the validate() method.
+ *
+ * If REPAIR is set, the validator will attempt to repair any broken data
+ * (if possible).
+ */
+ const REPAIR = 1;
+
+ /**
+ * If this option is set, the validator will operate on the vcards on the
+ * assumption that the vcards need to be valid for CardDAV.
+ *
+ * This means for example that the UID is required, whereas it is not for
+ * regular vcards.
+ */
+ const PROFILE_CARDDAV = 2;
+
+ /**
+ * If this option is set, the validator will operate on iCalendar objects
+ * on the assumption that the vcards need to be valid for CalDAV.
+ *
+ * This means for example that calendars can only contain objects with
+ * identical component types and UIDs.
+ */
+ const PROFILE_CALDAV = 4;
+
+ /**
+ * Reference to the parent object, if this is not the top object.
+ *
+ * @var Node
+ */
+ public $parent;
+
+ /**
+ * Iterator override.
+ *
+ * @var ElementList
+ */
+ protected $iterator = null;
+
+ /**
+ * The root document.
+ *
+ * @var Component
+ */
+ protected $root;
+
+ /**
+ * Serializes the node into a mimedir format.
+ *
+ * @return string
+ */
+ abstract function serialize();
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in JSON. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ abstract function jsonSerialize();
+
+ /**
+ * This method serializes the data into XML. This is used to create xCard or
+ * xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ abstract function xmlSerialize(Xml\Writer $writer);
+
+ /**
+ * Call this method on a document if you're done using it.
+ *
+ * It's intended to remove all circular references, so PHP can easily clean
+ * it up.
+ *
+ * @return void
+ */
+ function destroy() {
+
+ $this->parent = null;
+ $this->root = null;
+
+ }
+
+ /* {{{ IteratorAggregator interface */
+
+ /**
+ * Returns the iterator for this object.
+ *
+ * @return ElementList
+ */
+ function getIterator() {
+
+ if (!is_null($this->iterator)) {
+ return $this->iterator;
+ }
+
+ return new ElementList([$this]);
+
+ }
+
+ /**
+ * Sets the overridden iterator.
+ *
+ * Note that this is not actually part of the iterator interface
+ *
+ * @param ElementList $iterator
+ *
+ * @return void
+ */
+ function setIterator(ElementList $iterator) {
+
+ $this->iterator = $iterator;
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on)
+ * 2 - An inconsequential issue
+ * 3 - A severe issue.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ return [];
+
+ }
+
+ /* }}} */
+
+ /* {{{ Countable interface */
+
+ /**
+ * Returns the number of elements.
+ *
+ * @return int
+ */
+ function count() {
+
+ $it = $this->getIterator();
+ return $it->count();
+
+ }
+
+ /* }}} */
+
+ /* {{{ ArrayAccess Interface */
+
+
+ /**
+ * Checks if an item exists through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ *
+ * @return bool
+ */
+ function offsetExists($offset) {
+
+ $iterator = $this->getIterator();
+ return $iterator->offsetExists($offset);
+
+ }
+
+ /**
+ * Gets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ *
+ * @return mixed
+ */
+ function offsetGet($offset) {
+
+ $iterator = $this->getIterator();
+ return $iterator->offsetGet($offset);
+
+ }
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ * @param mixed $value
+ *
+ * @return void
+ */
+ function offsetSet($offset, $value) {
+
+ $iterator = $this->getIterator();
+ $iterator->offsetSet($offset, $value);
+
+ // @codeCoverageIgnoreStart
+ //
+ // This method always throws an exception, so we ignore the closing
+ // brace
+ }
+ // @codeCoverageIgnoreEnd
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ *
+ * @return void
+ */
+ function offsetUnset($offset) {
+
+ $iterator = $this->getIterator();
+ $iterator->offsetUnset($offset);
+
+ // @codeCoverageIgnoreStart
+ //
+ // This method always throws an exception, so we ignore the closing
+ // brace
+ }
+ // @codeCoverageIgnoreEnd
+
+ /* }}} */
+}
diff --git a/vendor/sabre/vobject/lib/PHPUnitAssertions.php b/vendor/sabre/vobject/lib/PHPUnitAssertions.php
new file mode 100644
index 000000000..87ec75e8f
--- /dev/null
+++ b/vendor/sabre/vobject/lib/PHPUnitAssertions.php
@@ -0,0 +1,82 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * PHPUnit Assertions
+ *
+ * This trait can be added to your unittest to make it easier to test iCalendar
+ * and/or vCards.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+trait PHPUnitAssertions {
+
+ /**
+ * This method tests wether two vcards or icalendar objects are
+ * semantically identical.
+ *
+ * It supports objects being supplied as strings, streams or
+ * Sabre\VObject\Component instances.
+ *
+ * PRODID is removed from both objects as this is often changes and would
+ * just get in the way.
+ *
+ * CALSCALE will automatically get removed if it's set to GREGORIAN.
+ *
+ * Any property that has the value **ANY** will be treated as a wildcard.
+ *
+ * @param resource|string|Component $expected
+ * @param resource|string|Component $actual
+ * @param string $message
+ */
+ function assertVObjectEqualsVObject($expected, $actual, $message = '') {
+
+ $self = $this;
+ $getObj = function($input) use ($self) {
+
+ if (is_resource($input)) {
+ $input = stream_get_contents($input);
+ }
+ if (is_string($input)) {
+ $input = Reader::read($input);
+ }
+ if (!$input instanceof Component) {
+ $this->fail('Input must be a string, stream or VObject component');
+ }
+ unset($input->PRODID);
+ if ($input instanceof Component\VCalendar && (string)$input->CALSCALE === 'GREGORIAN') {
+ unset($input->CALSCALE);
+ }
+ return $input;
+
+ };
+
+ $expected = $getObj($expected)->serialize();
+ $actual = $getObj($actual)->serialize();
+
+ // Finding wildcards in expected.
+ preg_match_all('|^([A-Z]+):\\*\\*ANY\\*\\*\r$|m', $expected, $matches, PREG_SET_ORDER);
+
+ foreach ($matches as $match) {
+
+ $actual = preg_replace(
+ '|^' . preg_quote($match[1], '|') . ':(.*)\r$|m',
+ $match[1] . ':**ANY**' . "\r",
+ $actual
+ );
+
+ }
+
+ $this->assertEquals(
+ $expected,
+ $actual,
+ $message
+ );
+
+ }
+
+
+}
diff --git a/vendor/sabre/vobject/lib/Parameter.php b/vendor/sabre/vobject/lib/Parameter.php
new file mode 100644
index 000000000..270643eab
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Parameter.php
@@ -0,0 +1,394 @@
+<?php
+
+namespace Sabre\VObject;
+
+use Sabre\Xml;
+use ArrayIterator;
+
+/**
+ * VObject Parameter.
+ *
+ * This class represents a parameter. A parameter is always tied to a property.
+ * In the case of:
+ * DTSTART;VALUE=DATE:20101108
+ * VALUE=DATE would be the parameter name and value.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Parameter extends Node {
+
+ /**
+ * Parameter name.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * vCard 2.1 allows parameters to be encoded without a name.
+ *
+ * We can deduce the parameter name based on it's value.
+ *
+ * @var bool
+ */
+ public $noName = false;
+
+ /**
+ * Parameter value.
+ *
+ * @var string
+ */
+ protected $value;
+
+ /**
+ * Sets up the object.
+ *
+ * It's recommended to use the create:: factory method instead.
+ *
+ * @param string $name
+ * @param string $value
+ */
+ function __construct(Document $root, $name, $value = null) {
+
+ $this->name = strtoupper($name);
+ $this->root = $root;
+ if (is_null($name)) {
+ $this->noName = true;
+ $this->name = static::guessParameterNameByValue($value);
+ }
+
+ // If guessParameterNameByValue() returns an empty string
+ // above, we're actually dealing with a parameter that has no value.
+ // In that case we have to move the value to the name.
+ if ($this->name === '') {
+ $this->noName = false;
+ $this->name = strtoupper($value);
+ } else {
+ $this->setValue($value);
+ }
+
+ }
+
+ /**
+ * Try to guess property name by value, can be used for vCard 2.1 nameless parameters.
+ *
+ * Figuring out what the name should have been. Note that a ton of
+ * these are rather silly in 2014 and would probably rarely be
+ * used, but we like to be complete.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ static function guessParameterNameByValue($value) {
+ switch (strtoupper($value)) {
+
+ // Encodings
+ case '7-BIT' :
+ case 'QUOTED-PRINTABLE' :
+ case 'BASE64' :
+ $name = 'ENCODING';
+ break;
+
+ // Common types
+ case 'WORK' :
+ case 'HOME' :
+ case 'PREF' :
+
+ // Delivery Label Type
+ case 'DOM' :
+ case 'INTL' :
+ case 'POSTAL' :
+ case 'PARCEL' :
+
+ // Telephone types
+ case 'VOICE' :
+ case 'FAX' :
+ case 'MSG' :
+ case 'CELL' :
+ case 'PAGER' :
+ case 'BBS' :
+ case 'MODEM' :
+ case 'CAR' :
+ case 'ISDN' :
+ case 'VIDEO' :
+
+ // EMAIL types (lol)
+ case 'AOL' :
+ case 'APPLELINK' :
+ case 'ATTMAIL' :
+ case 'CIS' :
+ case 'EWORLD' :
+ case 'INTERNET' :
+ case 'IBMMAIL' :
+ case 'MCIMAIL' :
+ case 'POWERSHARE' :
+ case 'PRODIGY' :
+ case 'TLX' :
+ case 'X400' :
+
+ // Photo / Logo format types
+ case 'GIF' :
+ case 'CGM' :
+ case 'WMF' :
+ case 'BMP' :
+ case 'DIB' :
+ case 'PICT' :
+ case 'TIFF' :
+ case 'PDF' :
+ case 'PS' :
+ case 'JPEG' :
+ case 'MPEG' :
+ case 'MPEG2' :
+ case 'AVI' :
+ case 'QTIME' :
+
+ // Sound Digital Audio Type
+ case 'WAVE' :
+ case 'PCM' :
+ case 'AIFF' :
+
+ // Key types
+ case 'X509' :
+ case 'PGP' :
+ $name = 'TYPE';
+ break;
+
+ // Value types
+ case 'INLINE' :
+ case 'URL' :
+ case 'CONTENT-ID' :
+ case 'CID' :
+ $name = 'VALUE';
+ break;
+
+ default:
+ $name = '';
+ }
+
+ return $name;
+ }
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * @param string|array $value
+ *
+ * @return void
+ */
+ function setValue($value) {
+
+ $this->value = $value;
+
+ }
+
+ /**
+ * Returns the current value.
+ *
+ * This method will always return a string, or null. If there were multiple
+ * values, it will automatically concatenate them (separated by comma).
+ *
+ * @return string|null
+ */
+ function getValue() {
+
+ if (is_array($this->value)) {
+ return implode(',', $this->value);
+ } else {
+ return $this->value;
+ }
+
+ }
+
+ /**
+ * Sets multiple values for this parameter.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setParts(array $value) {
+
+ $this->value = $value;
+
+ }
+
+ /**
+ * Returns all values for this parameter.
+ *
+ * If there were no values, an empty array will be returned.
+ *
+ * @return array
+ */
+ function getParts() {
+
+ if (is_array($this->value)) {
+ return $this->value;
+ } elseif (is_null($this->value)) {
+ return [];
+ } else {
+ return [$this->value];
+ }
+
+ }
+
+ /**
+ * Adds a value to this parameter.
+ *
+ * If the argument is specified as an array, all items will be added to the
+ * parameter value list.
+ *
+ * @param string|array $part
+ *
+ * @return void
+ */
+ function addValue($part) {
+
+ if (is_null($this->value)) {
+ $this->value = $part;
+ } else {
+ $this->value = array_merge((array)$this->value, (array)$part);
+ }
+
+ }
+
+ /**
+ * Checks if this parameter contains the specified value.
+ *
+ * This is a case-insensitive match. It makes sense to call this for for
+ * instance the TYPE parameter, to see if it contains a keyword such as
+ * 'WORK' or 'FAX'.
+ *
+ * @param string $value
+ *
+ * @return bool
+ */
+ function has($value) {
+
+ return in_array(
+ strtolower($value),
+ array_map('strtolower', (array)$this->value)
+ );
+
+ }
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ function serialize() {
+
+ $value = $this->getParts();
+
+ if (count($value) === 0) {
+ return $this->name . '=';
+ }
+
+ if ($this->root->getDocumentType() === Document::VCARD21 && $this->noName) {
+
+ return implode(';', $value);
+
+ }
+
+ return $this->name . '=' . array_reduce(
+ $value,
+ function($out, $item) {
+
+ if (!is_null($out)) $out .= ',';
+
+ // If there's no special characters in the string, we'll use the simple
+ // format.
+ //
+ // The list of special characters is defined as:
+ //
+ // Any character except CONTROL, DQUOTE, ";", ":", ","
+ //
+ // by the iCalendar spec:
+ // https://tools.ietf.org/html/rfc5545#section-3.1
+ //
+ // And we add ^ to that because of:
+ // https://tools.ietf.org/html/rfc6868
+ //
+ // But we've found that iCal (7.0, shipped with OSX 10.9)
+ // severaly trips on + characters not being quoted, so we
+ // added + as well.
+ if (!preg_match('#(?: [\n":;\^,\+] )#x', $item)) {
+ return $out . $item;
+ } else {
+ // Enclosing in double-quotes, and using RFC6868 for encoding any
+ // special characters
+ $out .= '"' . strtr(
+ $item,
+ [
+ '^' => '^^',
+ "\n" => '^n',
+ '"' => '^\'',
+ ]
+ ) . '"';
+ return $out;
+ }
+
+ }
+ );
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in JSON. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ function jsonSerialize() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * This method serializes the data into XML. This is used to create xCard or
+ * xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ function xmlSerialize(Xml\Writer $writer) {
+
+ foreach (explode(',', $this->value) as $value) {
+ $writer->writeElement('text', $value);
+ }
+
+ }
+
+ /**
+ * Called when this object is being cast to a string.
+ *
+ * @return string
+ */
+ function __toString() {
+
+ return (string)$this->getValue();
+
+ }
+
+ /**
+ * Returns the iterator for this object.
+ *
+ * @return ElementList
+ */
+ function getIterator() {
+
+ if (!is_null($this->iterator))
+ return $this->iterator;
+
+ return $this->iterator = new ArrayIterator((array)$this->value);
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/ParseException.php b/vendor/sabre/vobject/lib/ParseException.php
new file mode 100644
index 000000000..d96d20720
--- /dev/null
+++ b/vendor/sabre/vobject/lib/ParseException.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * Exception thrown by Reader if an invalid object was attempted to be parsed.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class ParseException extends \Exception {
+}
diff --git a/vendor/sabre/vobject/lib/Parser/Json.php b/vendor/sabre/vobject/lib/Parser/Json.php
new file mode 100644
index 000000000..370c981a8
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Parser/Json.php
@@ -0,0 +1,197 @@
+<?php
+
+namespace Sabre\VObject\Parser;
+
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\ParseException;
+use Sabre\VObject\EofException;
+
+/**
+ * Json Parser.
+ *
+ * This parser parses both the jCal and jCard formats.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Json extends Parser {
+
+ /**
+ * The input data.
+ *
+ * @var array
+ */
+ protected $input;
+
+ /**
+ * Root component.
+ *
+ * @var Document
+ */
+ protected $root;
+
+ /**
+ * This method starts the parsing process.
+ *
+ * If the input was not supplied during construction, it's possible to pass
+ * it here instead.
+ *
+ * If either input or options are not supplied, the defaults will be used.
+ *
+ * @param resource|string|array|null $input
+ * @param int $options
+ *
+ * @return Sabre\VObject\Document
+ */
+ function parse($input = null, $options = 0) {
+
+ if (!is_null($input)) {
+ $this->setInput($input);
+ }
+ if (is_null($this->input)) {
+ throw new EofException('End of input stream, or no input supplied');
+ }
+
+ if (0 !== $options) {
+ $this->options = $options;
+ }
+
+ switch ($this->input[0]) {
+ case 'vcalendar' :
+ $this->root = new VCalendar([], false);
+ break;
+ case 'vcard' :
+ $this->root = new VCard([], false);
+ break;
+ default :
+ throw new ParseException('The root component must either be a vcalendar, or a vcard');
+
+ }
+ foreach ($this->input[1] as $prop) {
+ $this->root->add($this->parseProperty($prop));
+ }
+ if (isset($this->input[2])) foreach ($this->input[2] as $comp) {
+ $this->root->add($this->parseComponent($comp));
+ }
+
+ // Resetting the input so we can throw an feof exception the next time.
+ $this->input = null;
+
+ return $this->root;
+
+ }
+
+ /**
+ * Parses a component.
+ *
+ * @param array $jComp
+ *
+ * @return \Sabre\VObject\Component
+ */
+ function parseComponent(array $jComp) {
+
+ // We can remove $self from PHP 5.4 onward.
+ $self = $this;
+
+ $properties = array_map(
+ function($jProp) use ($self) {
+ return $self->parseProperty($jProp);
+ },
+ $jComp[1]
+ );
+
+ if (isset($jComp[2])) {
+
+ $components = array_map(
+ function($jComp) use ($self) {
+ return $self->parseComponent($jComp);
+ },
+ $jComp[2]
+ );
+
+ } else $components = [];
+
+ return $this->root->createComponent(
+ $jComp[0],
+ array_merge($properties, $components),
+ $defaults = false
+ );
+
+ }
+
+ /**
+ * Parses properties.
+ *
+ * @param array $jProp
+ *
+ * @return \Sabre\VObject\Property
+ */
+ function parseProperty(array $jProp) {
+
+ list(
+ $propertyName,
+ $parameters,
+ $valueType
+ ) = $jProp;
+
+ $propertyName = strtoupper($propertyName);
+
+ // This is the default class we would be using if we didn't know the
+ // value type. We're using this value later in this function.
+ $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
+
+ $parameters = (array)$parameters;
+
+ $value = array_slice($jProp, 3);
+
+ $valueType = strtoupper($valueType);
+
+ if (isset($parameters['group'])) {
+ $propertyName = $parameters['group'] . '.' . $propertyName;
+ unset($parameters['group']);
+ }
+
+ $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
+ $prop->setJsonValue($value);
+
+ // We have to do something awkward here. FlatText as well as Text
+ // represents TEXT values. We have to normalize these here. In the
+ // future we can get rid of FlatText once we're allowed to break BC
+ // again.
+ if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') {
+ $defaultPropertyClass = 'Sabre\VObject\Property\Text';
+ }
+
+ // If the value type we received (e.g.: TEXT) was not the default value
+ // type for the given property (e.g.: BDAY), we need to add a VALUE=
+ // parameter.
+ if ($defaultPropertyClass !== get_class($prop)) {
+ $prop["VALUE"] = $valueType;
+ }
+
+ return $prop;
+
+ }
+
+ /**
+ * Sets the input data.
+ *
+ * @param resource|string|array $input
+ *
+ * @return void
+ */
+ function setInput($input) {
+
+ if (is_resource($input)) {
+ $input = stream_get_contents($input);
+ }
+ if (is_string($input)) {
+ $input = json_decode($input);
+ }
+ $this->input = $input;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Parser/MimeDir.php b/vendor/sabre/vobject/lib/Parser/MimeDir.php
new file mode 100644
index 000000000..6a7f9317b
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Parser/MimeDir.php
@@ -0,0 +1,696 @@
+<?php
+
+namespace Sabre\VObject\Parser;
+
+use Sabre\VObject\ParseException;
+use Sabre\VObject\EofException;
+use Sabre\VObject\Component;
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\Document;
+
+/**
+ * MimeDir parser.
+ *
+ * This class parses iCalendar 2.0 and vCard 2.1, 3.0 and 4.0 files. This
+ * parser will return one of the following two objects from the parse method:
+ *
+ * Sabre\VObject\Component\VCalendar
+ * Sabre\VObject\Component\VCard
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class MimeDir extends Parser {
+
+ /**
+ * The input stream.
+ *
+ * @var resource
+ */
+ protected $input;
+
+ /**
+ * Root component.
+ *
+ * @var Component
+ */
+ protected $root;
+
+ /**
+ * By default all input will be assumed to be UTF-8.
+ *
+ * However, both iCalendar and vCard might be encoded using different
+ * character sets. The character set is usually set in the mime-type.
+ *
+ * If this is the case, use setEncoding to specify that a different
+ * encoding will be used. If this is set, the parser will automatically
+ * convert all incoming data to UTF-8.
+ *
+ * @var string
+ */
+ protected $charset = 'UTF-8';
+
+ /**
+ * The list of character sets we support when decoding.
+ *
+ * This would be a const expression but for now we need to support PHP 5.5
+ */
+ protected static $SUPPORTED_CHARSETS = [
+ 'UTF-8',
+ 'ISO-8859-1',
+ 'Windows-1252',
+ ];
+
+ /**
+ * Parses an iCalendar or vCard file.
+ *
+ * Pass a stream or a string. If null is parsed, the existing buffer is
+ * used.
+ *
+ * @param string|resource|null $input
+ * @param int $options
+ *
+ * @return Sabre\VObject\Document
+ */
+ function parse($input = null, $options = 0) {
+
+ $this->root = null;
+
+ if (!is_null($input)) {
+ $this->setInput($input);
+ }
+
+ if (0 !== $options) {
+ $this->options = $options;
+ }
+
+ $this->parseDocument();
+
+ return $this->root;
+
+ }
+
+ /**
+ * By default all input will be assumed to be UTF-8.
+ *
+ * However, both iCalendar and vCard might be encoded using different
+ * character sets. The character set is usually set in the mime-type.
+ *
+ * If this is the case, use setEncoding to specify that a different
+ * encoding will be used. If this is set, the parser will automatically
+ * convert all incoming data to UTF-8.
+ *
+ * @param string $charset
+ */
+ function setCharset($charset) {
+
+ if (!in_array($charset, self::$SUPPORTED_CHARSETS)) {
+ throw new \InvalidArgumentException('Unsupported encoding. (Supported encodings: ' . implode(', ', self::$SUPPORTED_CHARSETS) . ')');
+ }
+ $this->charset = $charset;
+
+ }
+
+ /**
+ * Sets the input buffer. Must be a string or stream.
+ *
+ * @param resource|string $input
+ *
+ * @return void
+ */
+ function setInput($input) {
+
+ // Resetting the parser
+ $this->lineIndex = 0;
+ $this->startLine = 0;
+
+ if (is_string($input)) {
+ // Convering to a stream.
+ $stream = fopen('php://temp', 'r+');
+ fwrite($stream, $input);
+ rewind($stream);
+ $this->input = $stream;
+ } elseif (is_resource($input)) {
+ $this->input = $input;
+ } else {
+ throw new \InvalidArgumentException('This parser can only read from strings or streams.');
+ }
+
+ }
+
+ /**
+ * Parses an entire document.
+ *
+ * @return void
+ */
+ protected function parseDocument() {
+
+ $line = $this->readLine();
+
+ // BOM is ZERO WIDTH NO-BREAK SPACE (U+FEFF).
+ // It's 0xEF 0xBB 0xBF in UTF-8 hex.
+ if (3 <= strlen($line)
+ && ord($line[0]) === 0xef
+ && ord($line[1]) === 0xbb
+ && ord($line[2]) === 0xbf) {
+ $line = substr($line, 3);
+ }
+
+ switch (strtoupper($line)) {
+ case 'BEGIN:VCALENDAR' :
+ $class = VCalendar::$componentMap['VCALENDAR'];
+ break;
+ case 'BEGIN:VCARD' :
+ $class = VCard::$componentMap['VCARD'];
+ break;
+ default :
+ throw new ParseException('This parser only supports VCARD and VCALENDAR files');
+ }
+
+ $this->root = new $class([], false);
+
+ while (true) {
+
+ // Reading until we hit END:
+ $line = $this->readLine();
+ if (strtoupper(substr($line, 0, 4)) === 'END:') {
+ break;
+ }
+ $result = $this->parseLine($line);
+ if ($result) {
+ $this->root->add($result);
+ }
+
+ }
+
+ $name = strtoupper(substr($line, 4));
+ if ($name !== $this->root->name) {
+ throw new ParseException('Invalid MimeDir file. expected: "END:' . $this->root->name . '" got: "END:' . $name . '"');
+ }
+
+ }
+
+ /**
+ * Parses a line, and if it hits a component, it will also attempt to parse
+ * the entire component.
+ *
+ * @param string $line Unfolded line
+ *
+ * @return Node
+ */
+ protected function parseLine($line) {
+
+ // Start of a new component
+ if (strtoupper(substr($line, 0, 6)) === 'BEGIN:') {
+
+ $component = $this->root->createComponent(substr($line, 6), [], false);
+
+ while (true) {
+
+ // Reading until we hit END:
+ $line = $this->readLine();
+ if (strtoupper(substr($line, 0, 4)) === 'END:') {
+ break;
+ }
+ $result = $this->parseLine($line);
+ if ($result) {
+ $component->add($result);
+ }
+
+ }
+
+ $name = strtoupper(substr($line, 4));
+ if ($name !== $component->name) {
+ throw new ParseException('Invalid MimeDir file. expected: "END:' . $component->name . '" got: "END:' . $name . '"');
+ }
+
+ return $component;
+
+ } else {
+
+ // Property reader
+ $property = $this->readProperty($line);
+ if (!$property) {
+ // Ignored line
+ return false;
+ }
+ return $property;
+
+ }
+
+ }
+
+ /**
+ * We need to look ahead 1 line every time to see if we need to 'unfold'
+ * the next line.
+ *
+ * If that was not the case, we store it here.
+ *
+ * @var null|string
+ */
+ protected $lineBuffer;
+
+ /**
+ * The real current line number.
+ */
+ protected $lineIndex = 0;
+
+ /**
+ * In the case of unfolded lines, this property holds the line number for
+ * the start of the line.
+ *
+ * @var int
+ */
+ protected $startLine = 0;
+
+ /**
+ * Contains a 'raw' representation of the current line.
+ *
+ * @var string
+ */
+ protected $rawLine;
+
+ /**
+ * Reads a single line from the buffer.
+ *
+ * This method strips any newlines and also takes care of unfolding.
+ *
+ * @throws \Sabre\VObject\EofException
+ *
+ * @return string
+ */
+ protected function readLine() {
+
+ if (!is_null($this->lineBuffer)) {
+ $rawLine = $this->lineBuffer;
+ $this->lineBuffer = null;
+ } else {
+ do {
+ $eof = feof($this->input);
+
+ $rawLine = fgets($this->input);
+
+ if ($eof || (feof($this->input) && $rawLine === false)) {
+ throw new EofException('End of document reached prematurely');
+ }
+ if ($rawLine === false) {
+ throw new ParseException('Error reading from input stream');
+ }
+ $rawLine = rtrim($rawLine, "\r\n");
+ } while ($rawLine === ''); // Skipping empty lines
+ $this->lineIndex++;
+ }
+ $line = $rawLine;
+
+ $this->startLine = $this->lineIndex;
+
+ // Looking ahead for folded lines.
+ while (true) {
+
+ $nextLine = rtrim(fgets($this->input), "\r\n");
+ $this->lineIndex++;
+ if (!$nextLine) {
+ break;
+ }
+ if ($nextLine[0] === "\t" || $nextLine[0] === " ") {
+ $line .= substr($nextLine, 1);
+ $rawLine .= "\n " . substr($nextLine, 1);
+ } else {
+ $this->lineBuffer = $nextLine;
+ break;
+ }
+
+ }
+ $this->rawLine = $rawLine;
+ return $line;
+
+ }
+
+ /**
+ * Reads a property or component from a line.
+ *
+ * @return void
+ */
+ protected function readProperty($line) {
+
+ if ($this->options & self::OPTION_FORGIVING) {
+ $propNameToken = 'A-Z0-9\-\._\\/';
+ } else {
+ $propNameToken = 'A-Z0-9\-\.';
+ }
+
+ $paramNameToken = 'A-Z0-9\-';
+ $safeChar = '^";:,';
+ $qSafeChar = '^"';
+
+ $regex = "/
+ ^(?P<name> [$propNameToken]+ ) (?=[;:]) # property name
+ |
+ (?<=:)(?P<propValue> .+)$ # property value
+ |
+ ;(?P<paramName> [$paramNameToken]+) (?=[=;:]) # parameter name
+ |
+ (=|,)(?P<paramValue> # parameter value
+ (?: [$safeChar]*) |
+ \"(?: [$qSafeChar]+)\"
+ ) (?=[;:,])
+ /xi";
+
+ //echo $regex, "\n"; die();
+ preg_match_all($regex, $line, $matches, PREG_SET_ORDER);
+
+ $property = [
+ 'name' => null,
+ 'parameters' => [],
+ 'value' => null
+ ];
+
+ $lastParam = null;
+
+ /**
+ * Looping through all the tokens.
+ *
+ * Note that we are looping through them in reverse order, because if a
+ * sub-pattern matched, the subsequent named patterns will not show up
+ * in the result.
+ */
+ foreach ($matches as $match) {
+
+ if (isset($match['paramValue'])) {
+ if ($match['paramValue'] && $match['paramValue'][0] === '"') {
+ $value = substr($match['paramValue'], 1, -1);
+ } else {
+ $value = $match['paramValue'];
+ }
+
+ $value = $this->unescapeParam($value);
+
+ if (is_null($lastParam)) {
+ throw new ParseException('Invalid Mimedir file. Line starting at ' . $this->startLine . ' did not follow iCalendar/vCard conventions');
+ }
+ if (is_null($property['parameters'][$lastParam])) {
+ $property['parameters'][$lastParam] = $value;
+ } elseif (is_array($property['parameters'][$lastParam])) {
+ $property['parameters'][$lastParam][] = $value;
+ } else {
+ $property['parameters'][$lastParam] = [
+ $property['parameters'][$lastParam],
+ $value
+ ];
+ }
+ continue;
+ }
+ if (isset($match['paramName'])) {
+ $lastParam = strtoupper($match['paramName']);
+ if (!isset($property['parameters'][$lastParam])) {
+ $property['parameters'][$lastParam] = null;
+ }
+ continue;
+ }
+ if (isset($match['propValue'])) {
+ $property['value'] = $match['propValue'];
+ continue;
+ }
+ if (isset($match['name']) && $match['name']) {
+ $property['name'] = strtoupper($match['name']);
+ continue;
+ }
+
+ // @codeCoverageIgnoreStart
+ throw new \LogicException('This code should not be reachable');
+ // @codeCoverageIgnoreEnd
+
+ }
+
+ if (is_null($property['value'])) {
+ $property['value'] = '';
+ }
+ if (!$property['name']) {
+ if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
+ return false;
+ }
+ throw new ParseException('Invalid Mimedir file. Line starting at ' . $this->startLine . ' did not follow iCalendar/vCard conventions');
+ }
+
+ // vCard 2.1 states that parameters may appear without a name, and only
+ // a value. We can deduce the value based on it's name.
+ //
+ // Our parser will get those as parameters without a value instead, so
+ // we're filtering these parameters out first.
+ $namedParameters = [];
+ $namelessParameters = [];
+
+ foreach ($property['parameters'] as $name => $value) {
+ if (!is_null($value)) {
+ $namedParameters[$name] = $value;
+ } else {
+ $namelessParameters[] = $name;
+ }
+ }
+
+ $propObj = $this->root->createProperty($property['name'], null, $namedParameters);
+
+ foreach ($namelessParameters as $namelessParameter) {
+ $propObj->add(null, $namelessParameter);
+ }
+
+ if (strtoupper($propObj['ENCODING']) === 'QUOTED-PRINTABLE') {
+ $propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
+ } else {
+ $charset = $this->charset;
+ if ($this->root->getDocumentType() === Document::VCARD21 && isset($propObj['CHARSET'])) {
+ // vCard 2.1 allows the character set to be specified per property.
+ $charset = (string)$propObj['CHARSET'];
+ }
+ switch ($charset) {
+ case 'UTF-8' :
+ break;
+ case 'ISO-8859-1' :
+ $property['value'] = utf8_encode($property['value']);
+ break;
+ case 'Windows-1252' :
+ $property['value'] = mb_convert_encoding($property['value'], 'UTF-8', $charset);
+ break;
+ default :
+ throw new ParseException('Unsupported CHARSET: ' . $propObj['CHARSET']);
+ }
+ $propObj->setRawMimeDirValue($property['value']);
+ }
+
+ return $propObj;
+
+ }
+
+ /**
+ * Unescapes a property value.
+ *
+ * vCard 2.1 says:
+ * * Semi-colons must be escaped in some property values, specifically
+ * ADR, ORG and N.
+ * * Semi-colons must be escaped in parameter values, because semi-colons
+ * are also use to separate values.
+ * * No mention of escaping backslashes with another backslash.
+ * * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
+ * span values over more than 1 line.
+ *
+ * vCard 3.0 says:
+ * * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
+ * escaped, all time time.
+ * * Comma's are used for delimeters in multiple values
+ * * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
+ * as in some properties semi-colon is used for separators.
+ * * Properties using semi-colons: N, ADR, GEO, ORG
+ * * Both ADR and N's individual parts may be broken up further with a
+ * comma.
+ * * Properties using commas: NICKNAME, CATEGORIES
+ *
+ * vCard 4.0 (rfc6350) says:
+ * * Commas must be escaped.
+ * * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
+ * delimiter, depending on the property.
+ * * Backslashes must be escaped
+ * * Newlines must be escaped as either \N or \n.
+ * * Some compound properties may contain multiple parts themselves, so a
+ * comma within a semi-colon delimited property may also be unescaped
+ * to denote multiple parts _within_ the compound property.
+ * * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
+ * * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
+ *
+ * Even though the spec says that commas must always be escaped, the
+ * example for GEO in Section 6.5.2 seems to violate this.
+ *
+ * iCalendar 2.0 (rfc5545) says:
+ * * Commas or semi-colons may be used as delimiters, depending on the
+ * property.
+ * * Commas, semi-colons, backslashes, newline (\N or \n) are always
+ * escaped, unless they are delimiters.
+ * * Colons shall not be escaped.
+ * * Commas can be considered the 'default delimiter' and is described as
+ * the delimiter in cases where the order of the multiple values is
+ * insignificant.
+ * * Semi-colons are described as the delimiter for 'structured values'.
+ * They are specifically used in Semi-colons are used as a delimiter in
+ * REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
+ *
+ * Now for the parameters
+ *
+ * If delimiter is not set (null) this method will just return a string.
+ * If it's a comma or a semi-colon the string will be split on those
+ * characters, and always return an array.
+ *
+ * @param string $input
+ * @param string $delimiter
+ *
+ * @return string|string[]
+ */
+ static function unescapeValue($input, $delimiter = ';') {
+
+ $regex = '# (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
+ if ($delimiter) {
+ $regex .= ' | (' . $delimiter . ')';
+ }
+ $regex .= ') #x';
+
+ $matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+
+ $resultArray = [];
+ $result = '';
+
+ foreach ($matches as $match) {
+
+ switch ($match) {
+ case '\\\\' :
+ $result .= '\\';
+ break;
+ case '\N' :
+ case '\n' :
+ $result .= "\n";
+ break;
+ case '\;' :
+ $result .= ';';
+ break;
+ case '\,' :
+ $result .= ',';
+ break;
+ case $delimiter :
+ $resultArray[] = $result;
+ $result = '';
+ break;
+ default :
+ $result .= $match;
+ break;
+
+ }
+
+ }
+
+ $resultArray[] = $result;
+ return $delimiter ? $resultArray : $result;
+
+ }
+
+ /**
+ * Unescapes a parameter value.
+ *
+ * vCard 2.1:
+ * * Does not mention a mechanism for this. In addition, double quotes
+ * are never used to wrap values.
+ * * This means that parameters can simply not contain colons or
+ * semi-colons.
+ *
+ * vCard 3.0 (rfc2425, rfc2426):
+ * * Parameters _may_ be surrounded by double quotes.
+ * * If this is not the case, semi-colon, colon and comma may simply not
+ * occur (the comma used for multiple parameter values though).
+ * * If it is surrounded by double-quotes, it may simply not contain
+ * double-quotes.
+ * * This means that a parameter can in no case encode double-quotes, or
+ * newlines.
+ *
+ * vCard 4.0 (rfc6350)
+ * * Behavior seems to be identical to vCard 3.0
+ *
+ * iCalendar 2.0 (rfc5545)
+ * * Behavior seems to be identical to vCard 3.0
+ *
+ * Parameter escaping mechanism (rfc6868) :
+ * * This rfc describes a new way to escape parameter values.
+ * * New-line is encoded as ^n
+ * * ^ is encoded as ^^.
+ * * " is encoded as ^'
+ *
+ * @param string $input
+ *
+ * @return void
+ */
+ private function unescapeParam($input) {
+
+ return
+ preg_replace_callback(
+ '#(\^(\^|n|\'))#',
+ function($matches) {
+ switch ($matches[2]) {
+ case 'n' :
+ return "\n";
+ case '^' :
+ return '^';
+ case '\'' :
+ return '"';
+
+ // @codeCoverageIgnoreStart
+ }
+ // @codeCoverageIgnoreEnd
+ },
+ $input
+ );
+ }
+
+ /**
+ * Gets the full quoted printable value.
+ *
+ * We need a special method for this, because newlines have both a meaning
+ * in vCards, and in QuotedPrintable.
+ *
+ * This method does not do any decoding.
+ *
+ * @return string
+ */
+ private function extractQuotedPrintableValue() {
+
+ // We need to parse the raw line again to get the start of the value.
+ //
+ // We are basically looking for the first colon (:), but we need to
+ // skip over the parameters first, as they may contain one.
+ $regex = '/^
+ (?: [^:])+ # Anything but a colon
+ (?: "[^"]")* # A parameter in double quotes
+ : # start of the value we really care about
+ (.*)$
+ /xs';
+
+ preg_match($regex, $this->rawLine, $matches);
+
+ $value = $matches[1];
+ // Removing the first whitespace character from every line. Kind of
+ // like unfolding, but we keep the newline.
+ $value = str_replace("\n ", "\n", $value);
+
+ // Microsoft products don't always correctly fold lines, they may be
+ // missing a whitespace. So if 'forgiving' is turned on, we will take
+ // those as well.
+ if ($this->options & self::OPTION_FORGIVING) {
+ while (substr($value, -1) === '=') {
+ // Reading the line
+ $this->readLine();
+ // Grabbing the raw form
+ $value .= "\n" . $this->rawLine;
+ }
+ }
+
+ return $value;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Parser/Parser.php b/vendor/sabre/vobject/lib/Parser/Parser.php
new file mode 100644
index 000000000..ca8bc0add
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Parser/Parser.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Sabre\VObject\Parser;
+
+/**
+ * Abstract parser.
+ *
+ * This class serves as a base-class for the different parsers.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+abstract class Parser {
+
+ /**
+ * Turning on this option makes the parser more forgiving.
+ *
+ * In the case of the MimeDir parser, this means that the parser will
+ * accept slashes and underscores in property names, and it will also
+ * attempt to fix Microsoft vCard 2.1's broken line folding.
+ */
+ const OPTION_FORGIVING = 1;
+
+ /**
+ * If this option is turned on, any lines we cannot parse will be ignored
+ * by the reader.
+ */
+ const OPTION_IGNORE_INVALID_LINES = 2;
+
+ /**
+ * Bitmask of parser options.
+ *
+ * @var int
+ */
+ protected $options;
+
+ /**
+ * Creates the parser.
+ *
+ * Optionally, it's possible to parse the input stream here.
+ *
+ * @param mixed $input
+ * @param int $options Any parser options (OPTION constants).
+ *
+ * @return void
+ */
+ function __construct($input = null, $options = 0) {
+
+ if (!is_null($input)) {
+ $this->setInput($input);
+ }
+ $this->options = $options;
+ }
+
+ /**
+ * This method starts the parsing process.
+ *
+ * If the input was not supplied during construction, it's possible to pass
+ * it here instead.
+ *
+ * If either input or options are not supplied, the defaults will be used.
+ *
+ * @param mixed $input
+ * @param int $options
+ *
+ * @return array
+ */
+ abstract function parse($input = null, $options = 0);
+
+ /**
+ * Sets the input data.
+ *
+ * @param mixed $input
+ *
+ * @return void
+ */
+ abstract function setInput($input);
+
+}
diff --git a/vendor/sabre/vobject/lib/Parser/XML.php b/vendor/sabre/vobject/lib/Parser/XML.php
new file mode 100644
index 000000000..060a7fe2e
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Parser/XML.php
@@ -0,0 +1,428 @@
+<?php
+
+namespace Sabre\VObject\Parser;
+
+use Sabre\VObject\Component;
+use Sabre\VObject\Component\VCalendar;
+use Sabre\VObject\Component\VCard;
+use Sabre\VObject\EofException;
+use Sabre\VObject\ParseException;
+use Sabre\Xml as SabreXml;
+
+/**
+ * XML Parser.
+ *
+ * This parser parses both the xCal and xCard formats.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Ivan Enderlin
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class XML extends Parser {
+
+ const XCAL_NAMESPACE = 'urn:ietf:params:xml:ns:icalendar-2.0';
+ const XCARD_NAMESPACE = 'urn:ietf:params:xml:ns:vcard-4.0';
+
+ /**
+ * The input data.
+ *
+ * @var array
+ */
+ protected $input;
+
+ /**
+ * A pointer/reference to the input.
+ *
+ * @var array
+ */
+ private $pointer;
+
+ /**
+ * Document, root component.
+ *
+ * @var Sabre\VObject\Document
+ */
+ protected $root;
+
+ /**
+ * Creates the parser.
+ *
+ * Optionally, it's possible to parse the input stream here.
+ *
+ * @param mixed $input
+ * @param int $options Any parser options (OPTION constants).
+ *
+ * @return void
+ */
+ function __construct($input = null, $options = 0) {
+
+ if (0 === $options) {
+ $options = parent::OPTION_FORGIVING;
+ }
+
+ parent::__construct($input, $options);
+
+ }
+
+ /**
+ * Parse xCal or xCard.
+ *
+ * @param resource|string $input
+ * @param int $options
+ *
+ * @throws \Exception
+ *
+ * @return Sabre\VObject\Document
+ */
+ function parse($input = null, $options = 0) {
+
+ if (!is_null($input)) {
+ $this->setInput($input);
+ }
+
+ if (0 !== $options) {
+ $this->options = $options;
+ }
+
+ if (is_null($this->input)) {
+ throw new EofException('End of input stream, or no input supplied');
+ }
+
+ switch ($this->input['name']) {
+
+ case '{' . self::XCAL_NAMESPACE . '}icalendar':
+ $this->root = new VCalendar([], false);
+ $this->pointer = &$this->input['value'][0];
+ $this->parseVCalendarComponents($this->root);
+ break;
+
+ case '{' . self::XCARD_NAMESPACE . '}vcards':
+ foreach ($this->input['value'] as &$vCard) {
+
+ $this->root = new VCard(['version' => '4.0'], false);
+ $this->pointer = &$vCard;
+ $this->parseVCardComponents($this->root);
+
+ // We just parse the first <vcard /> element.
+ break;
+
+ }
+ break;
+
+ default:
+ throw new ParseException('Unsupported XML standard');
+
+ }
+
+ return $this->root;
+ }
+
+ /**
+ * Parse a xCalendar component.
+ *
+ * @param Component $parentComponent
+ *
+ * @return void
+ */
+ protected function parseVCalendarComponents(Component $parentComponent) {
+
+ foreach ($this->pointer['value'] ?: [] as $children) {
+
+ switch (static::getTagName($children['name'])) {
+
+ case 'properties':
+ $this->pointer = &$children['value'];
+ $this->parseProperties($parentComponent);
+ break;
+
+ case 'components':
+ $this->pointer = &$children;
+ $this->parseComponent($parentComponent);
+ break;
+ }
+ }
+
+ }
+
+ /**
+ * Parse a xCard component.
+ *
+ * @param Component $parentComponent
+ *
+ * @return void
+ */
+ protected function parseVCardComponents(Component $parentComponent) {
+
+ $this->pointer = &$this->pointer['value'];
+ $this->parseProperties($parentComponent);
+
+ }
+
+ /**
+ * Parse xCalendar and xCard properties.
+ *
+ * @param Component $parentComponent
+ * @param string $propertyNamePrefix
+ *
+ * @return void
+ */
+ protected function parseProperties(Component $parentComponent, $propertyNamePrefix = '') {
+
+ foreach ($this->pointer ?: [] as $xmlProperty) {
+
+ list($namespace, $tagName) = SabreXml\Service::parseClarkNotation($xmlProperty['name']);
+
+ $propertyName = $tagName;
+ $propertyValue = [];
+ $propertyParameters = [];
+ $propertyType = 'text';
+
+ // A property which is not part of the standard.
+ if ($namespace !== self::XCAL_NAMESPACE
+ && $namespace !== self::XCARD_NAMESPACE) {
+
+ $propertyName = 'xml';
+ $value = '<' . $tagName . ' xmlns="' . $namespace . '"';
+
+ foreach ($xmlProperty['attributes'] as $attributeName => $attributeValue) {
+ $value .= ' ' . $attributeName . '="' . str_replace('"', '\"', $attributeValue) . '"';
+ }
+
+ $value .= '>' . $xmlProperty['value'] . '</' . $tagName . '>';
+
+ $propertyValue = [$value];
+
+ $this->createProperty(
+ $parentComponent,
+ $propertyName,
+ $propertyParameters,
+ $propertyType,
+ $propertyValue
+ );
+
+ continue;
+ }
+
+ // xCard group.
+ if ($propertyName === 'group') {
+
+ if (!isset($xmlProperty['attributes']['name'])) {
+ continue;
+ }
+
+ $this->pointer = &$xmlProperty['value'];
+ $this->parseProperties(
+ $parentComponent,
+ strtoupper($xmlProperty['attributes']['name']) . '.'
+ );
+
+ continue;
+
+ }
+
+ // Collect parameters.
+ foreach ($xmlProperty['value'] as $i => $xmlPropertyChild) {
+
+ if (!is_array($xmlPropertyChild)
+ || 'parameters' !== static::getTagName($xmlPropertyChild['name']))
+ continue;
+
+ $xmlParameters = $xmlPropertyChild['value'];
+
+ foreach ($xmlParameters as $xmlParameter) {
+
+ $propertyParameterValues = [];
+
+ foreach ($xmlParameter['value'] as $xmlParameterValues) {
+ $propertyParameterValues[] = $xmlParameterValues['value'];
+ }
+
+ $propertyParameters[static::getTagName($xmlParameter['name'])]
+ = implode(',', $propertyParameterValues);
+
+ }
+
+ array_splice($xmlProperty['value'], $i, 1);
+
+ }
+
+ $propertyNameExtended = ($this->root instanceof VCalendar
+ ? 'xcal'
+ : 'xcard') . ':' . $propertyName;
+
+ switch ($propertyNameExtended) {
+
+ case 'xcal:geo':
+ $propertyType = 'float';
+ $propertyValue['latitude'] = 0;
+ $propertyValue['longitude'] = 0;
+
+ foreach ($xmlProperty['value'] as $xmlRequestChild) {
+ $propertyValue[static::getTagName($xmlRequestChild['name'])]
+ = $xmlRequestChild['value'];
+ }
+ break;
+
+ case 'xcal:request-status':
+ $propertyType = 'text';
+
+ foreach ($xmlProperty['value'] as $xmlRequestChild) {
+ $propertyValue[static::getTagName($xmlRequestChild['name'])]
+ = $xmlRequestChild['value'];
+ }
+ break;
+
+ case 'xcal:freebusy':
+ $propertyType = 'freebusy';
+ // We don't break because we only want to set
+ // another property type.
+
+ case 'xcal:categories':
+ case 'xcal:resources':
+ case 'xcal:exdate':
+ foreach ($xmlProperty['value'] as $specialChild) {
+ $propertyValue[static::getTagName($specialChild['name'])]
+ = $specialChild['value'];
+ }
+ break;
+
+ case 'xcal:rdate':
+ $propertyType = 'date-time';
+
+ foreach ($xmlProperty['value'] as $specialChild) {
+
+ $tagName = static::getTagName($specialChild['name']);
+
+ if ('period' === $tagName) {
+
+ $propertyParameters['value'] = 'PERIOD';
+ $propertyValue[] = implode('/', $specialChild['value']);
+
+ }
+ else {
+ $propertyValue[] = $specialChild['value'];
+ }
+ }
+ break;
+
+ default:
+ $propertyType = static::getTagName($xmlProperty['value'][0]['name']);
+
+ foreach ($xmlProperty['value'] as $value) {
+ $propertyValue[] = $value['value'];
+ }
+
+ if ('date' === $propertyType) {
+ $propertyParameters['value'] = 'DATE';
+ }
+ break;
+ }
+
+ $this->createProperty(
+ $parentComponent,
+ $propertyNamePrefix . $propertyName,
+ $propertyParameters,
+ $propertyType,
+ $propertyValue
+ );
+
+ }
+
+ }
+
+ /**
+ * Parse a component.
+ *
+ * @param Component $parentComponent
+ *
+ * @return void
+ */
+ protected function parseComponent(Component $parentComponent) {
+
+ $components = $this->pointer['value'] ?: [];
+
+ foreach ($components as $component) {
+
+ $componentName = static::getTagName($component['name']);
+ $currentComponent = $this->root->createComponent(
+ $componentName,
+ null,
+ false
+ );
+
+ $this->pointer = &$component;
+ $this->parseVCalendarComponents($currentComponent);
+
+ $parentComponent->add($currentComponent);
+
+ }
+
+ }
+
+ /**
+ * Create a property.
+ *
+ * @param Component $parentComponent
+ * @param string $name
+ * @param array $parameters
+ * @param string $type
+ * @param mixed $value
+ *
+ * @return void
+ */
+ protected function createProperty(Component $parentComponent, $name, $parameters, $type, $value) {
+
+ $property = $this->root->createProperty(
+ $name,
+ null,
+ $parameters,
+ $type
+ );
+ $parentComponent->add($property);
+ $property->setXmlValue($value);
+
+ }
+
+ /**
+ * Sets the input data.
+ *
+ * @param resource|string $input
+ *
+ * @return void
+ */
+ function setInput($input) {
+
+ if (is_resource($input)) {
+ $input = stream_get_contents($input);
+ }
+
+ if (is_string($input)) {
+
+ $reader = new SabreXml\Reader();
+ $reader->elementMap['{' . self::XCAL_NAMESPACE . '}period']
+ = 'Sabre\VObject\Parser\XML\Element\KeyValue';
+ $reader->elementMap['{' . self::XCAL_NAMESPACE . '}recur']
+ = 'Sabre\VObject\Parser\XML\Element\KeyValue';
+ $reader->xml($input);
+ $input = $reader->parse();
+
+ }
+
+ $this->input = $input;
+
+ }
+
+ /**
+ * Get tag name from a Clark notation.
+ *
+ * @param string $clarkedTagName
+ *
+ * @return string
+ */
+ protected static function getTagName($clarkedTagName) {
+
+ list(, $tagName) = SabreXml\Service::parseClarkNotation($clarkedTagName);
+ return $tagName;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Parser/XML/Element/KeyValue.php b/vendor/sabre/vobject/lib/Parser/XML/Element/KeyValue.php
new file mode 100644
index 000000000..14d798433
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Parser/XML/Element/KeyValue.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace Sabre\VObject\Parser\XML\Element;
+
+use Sabre\Xml as SabreXml;
+
+/**
+ * Our own sabre/xml key-value element.
+ *
+ * It just removes the clark notation.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Ivan Enderlin
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class KeyValue extends SabreXml\Element\KeyValue {
+
+ /**
+ * The deserialize method is called during xml parsing.
+ *
+ * This method is called staticly, this is because in theory this method
+ * may be used as a type of constructor, or factory method.
+ *
+ * Often you want to return an instance of the current class, but you are
+ * free to return other data as well.
+ *
+ * Important note 2: You are responsible for advancing the reader to the
+ * next element. Not doing anything will result in a never-ending loop.
+ *
+ * If you just want to skip parsing for this element altogether, you can
+ * just call $reader->next();
+ *
+ * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
+ * the next element.
+ *
+ * @param XML\Reader $reader
+ *
+ * @return mixed
+ */
+ static function xmlDeserialize(SabreXml\Reader $reader) {
+
+ // If there's no children, we don't do anything.
+ if ($reader->isEmptyElement) {
+ $reader->next();
+ return [];
+ }
+
+ $values = [];
+ $reader->read();
+
+ do {
+
+ if ($reader->nodeType === SabreXml\Reader::ELEMENT) {
+
+ $name = $reader->localName;
+ $values[$name] = $reader->parseCurrentElement()['value'];
+
+ } else {
+ $reader->read();
+ }
+
+ } while ($reader->nodeType !== SabreXml\Reader::END_ELEMENT);
+
+ $reader->read();
+
+ return $values;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property.php b/vendor/sabre/vobject/lib/Property.php
new file mode 100644
index 000000000..112775131
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property.php
@@ -0,0 +1,662 @@
+<?php
+
+namespace Sabre\VObject;
+
+use Sabre\Xml;
+
+/**
+ * Property.
+ *
+ * A property is always in a KEY:VALUE structure, and may optionally contain
+ * parameters.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+abstract class Property extends Node {
+
+ /**
+ * Property name.
+ *
+ * This will contain a string such as DTSTART, SUMMARY, FN.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Property group.
+ *
+ * This is only used in vcards
+ *
+ * @var string
+ */
+ public $group;
+
+ /**
+ * List of parameters.
+ *
+ * @var array
+ */
+ public $parameters = [];
+
+ /**
+ * Current value.
+ *
+ * @var mixed
+ */
+ protected $value;
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = ';';
+
+ /**
+ * Creates the generic property.
+ *
+ * Parameters must be specified in key=>value syntax.
+ *
+ * @param Component $root The root document
+ * @param string $name
+ * @param string|array|null $value
+ * @param array $parameters List of parameters
+ * @param string $group The vcard property group
+ *
+ * @return void
+ */
+ function __construct(Component $root, $name, $value = null, array $parameters = [], $group = null) {
+
+ $this->name = $name;
+ $this->group = $group;
+
+ $this->root = $root;
+
+ foreach ($parameters as $k => $v) {
+ $this->add($k, $v);
+ }
+
+ if (!is_null($value)) {
+ $this->setValue($value);
+ }
+
+ }
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * @param string|array $value
+ *
+ * @return void
+ */
+ function setValue($value) {
+
+ $this->value = $value;
+
+ }
+
+ /**
+ * Returns the current value.
+ *
+ * This method will always return a singular value. If this was a
+ * multi-value object, some decision will be made first on how to represent
+ * it as a string.
+ *
+ * To get the correct multi-value version, use getParts.
+ *
+ * @return string
+ */
+ function getValue() {
+
+ if (is_array($this->value)) {
+ if (count($this->value) == 0) {
+ return;
+ } elseif (count($this->value) === 1) {
+ return $this->value[0];
+ } else {
+ return $this->getRawMimeDirValue();
+ }
+ } else {
+ return $this->value;
+ }
+
+ }
+
+ /**
+ * Sets a multi-valued property.
+ *
+ * @param array $parts
+ *
+ * @return void
+ */
+ function setParts(array $parts) {
+
+ $this->value = $parts;
+
+ }
+
+ /**
+ * Returns a multi-valued property.
+ *
+ * This method always returns an array, if there was only a single value,
+ * it will still be wrapped in an array.
+ *
+ * @return array
+ */
+ function getParts() {
+
+ if (is_null($this->value)) {
+ return [];
+ } elseif (is_array($this->value)) {
+ return $this->value;
+ } else {
+ return [$this->value];
+ }
+
+ }
+
+ /**
+ * Adds a new parameter.
+ *
+ * If a parameter with same name already existed, the values will be
+ * combined.
+ * If nameless parameter is added, we try to guess it's name.
+ *
+ * @param string $name
+ * @param string|null|array $value
+ */
+ function add($name, $value = null) {
+ $noName = false;
+ if ($name === null) {
+ $name = Parameter::guessParameterNameByValue($value);
+ $noName = true;
+ }
+
+ if (isset($this->parameters[strtoupper($name)])) {
+ $this->parameters[strtoupper($name)]->addValue($value);
+ }
+ else {
+ $param = new Parameter($this->root, $name, $value);
+ $param->noName = $noName;
+ $this->parameters[$param->name] = $param;
+ }
+ }
+
+ /**
+ * Returns an iterable list of children.
+ *
+ * @return array
+ */
+ function parameters() {
+
+ return $this->parameters;
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ abstract function getValueType();
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ abstract function setRawMimeDirValue($val);
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ abstract function getRawMimeDirValue();
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ function serialize() {
+
+ $str = $this->name;
+ if ($this->group) $str = $this->group . '.' . $this->name;
+
+ foreach ($this->parameters() as $param) {
+
+ $str .= ';' . $param->serialize();
+
+ }
+
+ $str .= ':' . $this->getRawMimeDirValue();
+
+ $out = '';
+ while (strlen($str) > 0) {
+ if (strlen($str) > 75) {
+ $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
+ $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
+ } else {
+ $out .= $str . "\r\n";
+ $str = '';
+ break;
+ }
+ }
+
+ return $out;
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for JSON.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ return $this->getParts();
+
+ }
+
+ /**
+ * Sets the JSON value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setJsonValue(array $value) {
+
+ if (count($value) === 1) {
+ $this->setValue(reset($value));
+ } else {
+ $this->setValue($value);
+ }
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in JSON. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ function jsonSerialize() {
+
+ $parameters = [];
+
+ foreach ($this->parameters as $parameter) {
+ if ($parameter->name === 'VALUE') {
+ continue;
+ }
+ $parameters[strtolower($parameter->name)] = $parameter->jsonSerialize();
+ }
+ // In jCard, we need to encode the property-group as a separate 'group'
+ // parameter.
+ if ($this->group) {
+ $parameters['group'] = $this->group;
+ }
+
+ return array_merge(
+ [
+ strtolower($this->name),
+ (object)$parameters,
+ strtolower($this->getValueType()),
+ ],
+ $this->getJsonValue()
+ );
+ }
+
+ /**
+ * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
+ * object.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setXmlValue(array $value) {
+
+ $this->setJsonValue($value);
+
+ }
+
+ /**
+ * This method serializes the data into XML. This is used to create xCard or
+ * xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ function xmlSerialize(Xml\Writer $writer) {
+
+ $parameters = [];
+
+ foreach ($this->parameters as $parameter) {
+
+ if ($parameter->name === 'VALUE') {
+ continue;
+ }
+
+ $parameters[] = $parameter;
+
+ }
+
+ $writer->startElement(strtolower($this->name));
+
+ if (!empty($parameters)) {
+
+ $writer->startElement('parameters');
+
+ foreach ($parameters as $parameter) {
+
+ $writer->startElement(strtolower($parameter->name));
+ $writer->write($parameter);
+ $writer->endElement();
+
+ }
+
+ $writer->endElement();
+
+ }
+
+ $this->xmlSerializeValue($writer);
+ $writer->endElement();
+
+ }
+
+ /**
+ * This method serializes only the value of a property. This is used to
+ * create xCard or xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ protected function xmlSerializeValue(Xml\Writer $writer) {
+
+ $valueType = strtolower($this->getValueType());
+
+ foreach ($this->getJsonValue() as $values) {
+ foreach ((array)$values as $value) {
+ $writer->writeElement($valueType, $value);
+ }
+ }
+
+ }
+
+ /**
+ * Called when this object is being cast to a string.
+ *
+ * If the property only had a single value, you will get just that. In the
+ * case the property had multiple values, the contents will be escaped and
+ * combined with ,.
+ *
+ * @return string
+ */
+ function __toString() {
+
+ return (string)$this->getValue();
+
+ }
+
+ /* ArrayAccess interface {{{ */
+
+ /**
+ * Checks if an array element exists.
+ *
+ * @param mixed $name
+ *
+ * @return bool
+ */
+ function offsetExists($name) {
+
+ if (is_int($name)) return parent::offsetExists($name);
+
+ $name = strtoupper($name);
+
+ foreach ($this->parameters as $parameter) {
+ if ($parameter->name == $name) return true;
+ }
+ return false;
+
+ }
+
+ /**
+ * Returns a parameter.
+ *
+ * If the parameter does not exist, null is returned.
+ *
+ * @param string $name
+ *
+ * @return Node
+ */
+ function offsetGet($name) {
+
+ if (is_int($name)) return parent::offsetGet($name);
+ $name = strtoupper($name);
+
+ if (!isset($this->parameters[$name])) {
+ return;
+ }
+
+ return $this->parameters[$name];
+
+ }
+
+ /**
+ * Creates a new parameter.
+ *
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return void
+ */
+ function offsetSet($name, $value) {
+
+ if (is_int($name)) {
+ parent::offsetSet($name, $value);
+ // @codeCoverageIgnoreStart
+ // This will never be reached, because an exception is always
+ // thrown.
+ return;
+ // @codeCoverageIgnoreEnd
+ }
+
+ $param = new Parameter($this->root, $name, $value);
+ $this->parameters[$param->name] = $param;
+
+ }
+
+ /**
+ * Removes one or more parameters with the specified name.
+ *
+ * @param string $name
+ *
+ * @return void
+ */
+ function offsetUnset($name) {
+
+ if (is_int($name)) {
+ parent::offsetUnset($name);
+ // @codeCoverageIgnoreStart
+ // This will never be reached, because an exception is always
+ // thrown.
+ return;
+ // @codeCoverageIgnoreEnd
+ }
+
+ unset($this->parameters[strtoupper($name)]);
+
+ }
+ /* }}} */
+
+ /**
+ * This method is automatically called when the object is cloned.
+ * Specifically, this will ensure all child elements are also cloned.
+ *
+ * @return void
+ */
+ function __clone() {
+
+ foreach ($this->parameters as $key => $child) {
+ $this->parameters[$key] = clone $child;
+ $this->parameters[$key]->parent = $this;
+ }
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * - Node::REPAIR - If something is broken, and automatic repair may
+ * be attempted.
+ *
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $warnings = [];
+
+ // Checking if our value is UTF-8
+ if (!StringUtil::isUTF8($this->getRawMimeDirValue())) {
+
+ $oldValue = $this->getRawMimeDirValue();
+ $level = 3;
+ if ($options & self::REPAIR) {
+ $newValue = StringUtil::convertToUTF8($oldValue);
+ if (true || StringUtil::isUTF8($newValue)) {
+ $this->setRawMimeDirValue($newValue);
+ $level = 1;
+ }
+
+ }
+
+
+ if (preg_match('%([\x00-\x08\x0B-\x0C\x0E-\x1F\x7F])%', $oldValue, $matches)) {
+ $message = 'Property contained a control character (0x' . bin2hex($matches[1]) . ')';
+ } else {
+ $message = 'Property is not valid UTF-8! ' . $oldValue;
+ }
+
+ $warnings[] = [
+ 'level' => $level,
+ 'message' => $message,
+ 'node' => $this,
+ ];
+ }
+
+ // Checking if the propertyname does not contain any invalid bytes.
+ if (!preg_match('/^([A-Z0-9-]+)$/', $this->name)) {
+ $warnings[] = [
+ 'level' => 1,
+ 'message' => 'The propertyname: ' . $this->name . ' contains invalid characters. Only A-Z, 0-9 and - are allowed',
+ 'node' => $this,
+ ];
+ if ($options & self::REPAIR) {
+ // Uppercasing and converting underscores to dashes.
+ $this->name = strtoupper(
+ str_replace('_', '-', $this->name)
+ );
+ // Removing every other invalid character
+ $this->name = preg_replace('/([^A-Z0-9-])/u', '', $this->name);
+
+ }
+
+ }
+
+ if ($encoding = $this->offsetGet('ENCODING')) {
+
+ if ($this->root->getDocumentType() === Document::VCARD40) {
+ $warnings[] = [
+ 'level' => 1,
+ 'message' => 'ENCODING parameter is not valid in vCard 4.',
+ 'node' => $this
+ ];
+ } else {
+
+ $encoding = (string)$encoding;
+
+ $allowedEncoding = [];
+
+ switch ($this->root->getDocumentType()) {
+ case Document::ICALENDAR20 :
+ $allowedEncoding = ['8BIT', 'BASE64'];
+ break;
+ case Document::VCARD21 :
+ $allowedEncoding = ['QUOTED-PRINTABLE', 'BASE64', '8BIT'];
+ break;
+ case Document::VCARD30 :
+ $allowedEncoding = ['B'];
+ break;
+
+ }
+ if ($allowedEncoding && !in_array(strtoupper($encoding), $allowedEncoding)) {
+ $warnings[] = [
+ 'level' => 1,
+ 'message' => 'ENCODING=' . strtoupper($encoding) . ' is not valid for this document type.',
+ 'node' => $this
+ ];
+ }
+ }
+
+ }
+
+ // Validating inner parameters
+ foreach ($this->parameters as $param) {
+ $warnings = array_merge($warnings, $param->validate($options));
+ }
+
+ return $warnings;
+
+ }
+
+ /**
+ * Call this method on a document if you're done using it.
+ *
+ * It's intended to remove all circular references, so PHP can easily clean
+ * it up.
+ *
+ * @return void
+ */
+ function destroy() {
+
+ parent::destroy();
+ foreach ($this->parameters as $param) {
+ $param->destroy();
+ }
+ $this->parameters = [];
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/Binary.php b/vendor/sabre/vobject/lib/Property/Binary.php
new file mode 100644
index 000000000..d54cae25d
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/Binary.php
@@ -0,0 +1,128 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+use Sabre\VObject\Property;
+
+/**
+ * BINARY property.
+ *
+ * This object represents BINARY values.
+ *
+ * Binary values are most commonly used by the iCalendar ATTACH property, and
+ * the vCard PHOTO property.
+ *
+ * This property will transparently encode and decode to base64.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Binary extends Property {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = null;
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * @param string|array $value
+ *
+ * @return void
+ */
+ function setValue($value) {
+
+ if (is_array($value)) {
+
+ if (count($value) === 1) {
+ $this->value = $value[0];
+ } else {
+ throw new \InvalidArgumentException('The argument must either be a string or an array with only one child');
+ }
+
+ } else {
+
+ $this->value = $value;
+
+ }
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->value = base64_decode($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return base64_encode($this->value);
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'BINARY';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ return [base64_encode($this->getValue())];
+
+ }
+
+ /**
+ * Sets the json value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setJsonValue(array $value) {
+
+ $value = array_map('base64_decode', $value);
+ parent::setJsonValue($value);
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/Boolean.php b/vendor/sabre/vobject/lib/Property/Boolean.php
new file mode 100644
index 000000000..6f5887e25
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/Boolean.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+use
+ Sabre\VObject\Property;
+
+/**
+ * Boolean property.
+ *
+ * This object represents BOOLEAN values. These are always the case-insenstive
+ * string TRUE or FALSE.
+ *
+ * Automatic conversion to PHP's true and false are done.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Boolean extends Property {
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $val = strtoupper($val) === 'TRUE' ? true : false;
+ $this->setValue($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return $this->value ? 'TRUE' : 'FALSE';
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'BOOLEAN';
+
+ }
+
+ /**
+ * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
+ * object.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setXmlValue(array $value) {
+
+ $value = array_map(
+ function($value) {
+ return 'true' === $value;
+ },
+ $value
+ );
+ parent::setXmlValue($value);
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/FlatText.php b/vendor/sabre/vobject/lib/Property/FlatText.php
new file mode 100644
index 000000000..2c7b43c29
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/FlatText.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+/**
+ * FlatText property.
+ *
+ * This object represents certain TEXT values.
+ *
+ * Specifically, this property is used for text values where there is only 1
+ * part. Semi-colons and colons will be de-escaped when deserializing, but if
+ * any semi-colons or commas appear without a backslash, we will not assume
+ * that they are delimiters.
+ *
+ * vCard 2.1 specifically has a whole bunch of properties where this may
+ * happen, as it only defines a delimiter for a few properties.
+ *
+ * vCard 4.0 states something similar. An unescaped semi-colon _may_ be a
+ * delimiter, depending on the property.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class FlatText extends Text {
+
+ /**
+ * Field separator.
+ *
+ * @var string
+ */
+ public $delimiter = ',';
+
+ /**
+ * Sets the value as a quoted-printable encoded string.
+ *
+ * Overriding this so we're not splitting on a ; delimiter.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setQuotedPrintableValue($val) {
+
+ $val = quoted_printable_decode($val);
+ $this->setValue($val);
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/FloatValue.php b/vendor/sabre/vobject/lib/Property/FloatValue.php
new file mode 100644
index 000000000..15b119549
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/FloatValue.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+use Sabre\VObject\Property;
+use Sabre\Xml;
+
+/**
+ * Float property.
+ *
+ * This object represents FLOAT values. These can be 1 or more floating-point
+ * numbers.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class FloatValue extends Property {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = ';';
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $val = explode($this->delimiter, $val);
+ foreach ($val as &$item) {
+ $item = (float)$item;
+ }
+ $this->setParts($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return implode(
+ $this->delimiter,
+ $this->getParts()
+ );
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'FLOAT';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for JSON.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ $val = array_map('floatval', $this->getParts());
+
+ // Special-casing the GEO property.
+ //
+ // See:
+ // http://tools.ietf.org/html/draft-ietf-jcardcal-jcal-04#section-3.4.1.2
+ if ($this->name === 'GEO') {
+ return [$val];
+ }
+
+ return $val;
+
+ }
+
+ /**
+ * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
+ * object.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setXmlValue(array $value) {
+
+ $value = array_map('floatval', $value);
+ parent::setXmlValue($value);
+
+ }
+
+ /**
+ * This method serializes only the value of a property. This is used to
+ * create xCard or xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ protected function xmlSerializeValue(Xml\Writer $writer) {
+
+ // Special-casing the GEO property.
+ //
+ // See:
+ // http://tools.ietf.org/html/rfc6321#section-3.4.1.2
+ if ($this->name === 'GEO') {
+
+ $value = array_map('floatval', $this->getParts());
+
+ $writer->writeElement('latitude', $value[0]);
+ $writer->writeElement('longitude', $value[1]);
+
+ }
+ else {
+ parent::xmlSerializeValue($writer);
+ }
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/CalAddress.php b/vendor/sabre/vobject/lib/Property/ICalendar/CalAddress.php
new file mode 100644
index 000000000..a0c4a9b9a
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/ICalendar/CalAddress.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Sabre\VObject\Property\ICalendar;
+
+use
+ Sabre\VObject\Property\Text;
+
+/**
+ * CalAddress property.
+ *
+ * This object encodes CAL-ADDRESS values, as defined in rfc5545
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class CalAddress extends Text {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = null;
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'CAL-ADDRESS';
+
+ }
+
+ /**
+ * This returns a normalized form of the value.
+ *
+ * This is primarily used right now to turn mixed-cased schemes in user
+ * uris to lower-case.
+ *
+ * Evolution in particular tends to encode mailto: as MAILTO:.
+ *
+ * @return string
+ */
+ function getNormalizedValue() {
+
+ $input = $this->getValue();
+ if (!strpos($input, ':')) {
+ return $input;
+ }
+ list($schema, $everythingElse) = explode(':', $input, 2);
+ return strtolower($schema) . ':' . $everythingElse;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/Date.php b/vendor/sabre/vobject/lib/Property/ICalendar/Date.php
new file mode 100644
index 000000000..378a0d60a
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/ICalendar/Date.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Sabre\VObject\Property\ICalendar;
+
+/**
+ * DateTime property.
+ *
+ * This object represents DATE values, as defined here:
+ *
+ * http://tools.ietf.org/html/rfc5545#section-3.3.5
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Date extends DateTime {
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/DateTime.php b/vendor/sabre/vobject/lib/Property/ICalendar/DateTime.php
new file mode 100644
index 000000000..d580d4f68
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/ICalendar/DateTime.php
@@ -0,0 +1,404 @@
+<?php
+
+namespace Sabre\VObject\Property\ICalendar;
+
+use DateTimeInterface;
+use DateTimeZone;
+use Sabre\VObject\DateTimeParser;
+use Sabre\VObject\InvalidDataException;
+use Sabre\VObject\Property;
+use Sabre\VObject\TimeZoneUtil;
+
+/**
+ * DateTime property.
+ *
+ * This object represents DATE-TIME values, as defined here:
+ *
+ * http://tools.ietf.org/html/rfc5545#section-3.3.4
+ *
+ * This particular object has a bit of hackish magic that it may also in some
+ * cases represent a DATE value. This is because it's a common usecase to be
+ * able to change a DATE-TIME into a DATE.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class DateTime extends Property {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = ',';
+
+ /**
+ * Sets a multi-valued property.
+ *
+ * You may also specify DateTime objects here.
+ *
+ * @param array $parts
+ *
+ * @return void
+ */
+ function setParts(array $parts) {
+
+ if (isset($parts[0]) && $parts[0] instanceof DateTimeInterface) {
+ $this->setDateTimes($parts);
+ } else {
+ parent::setParts($parts);
+ }
+
+ }
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * Instead of strings, you may also use DateTime here.
+ *
+ * @param string|array|DateTimeInterface $value
+ *
+ * @return void
+ */
+ function setValue($value) {
+
+ if (is_array($value) && isset($value[0]) && $value[0] instanceof DateTimeInterface) {
+ $this->setDateTimes($value);
+ } elseif ($value instanceof DateTimeInterface) {
+ $this->setDateTimes([$value]);
+ } else {
+ parent::setValue($value);
+ }
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue(explode($this->delimiter, $val));
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return implode($this->delimiter, $this->getParts());
+
+ }
+
+ /**
+ * Returns true if this is a DATE-TIME value, false if it's a DATE.
+ *
+ * @return bool
+ */
+ function hasTime() {
+
+ return strtoupper((string)$this['VALUE']) !== 'DATE';
+
+ }
+
+ /**
+ * Returns true if this is a floating DATE or DATE-TIME.
+ *
+ * Note that DATE is always floating.
+ */
+ function isFloating() {
+
+ return
+ !$this->hasTime() ||
+ (
+ !isset($this['TZID']) &&
+ strpos($this->getValue(), 'Z') === false
+ );
+
+ }
+
+ /**
+ * Returns a date-time value.
+ *
+ * Note that if this property contained more than 1 date-time, only the
+ * first will be returned. To get an array with multiple values, call
+ * getDateTimes.
+ *
+ * If no timezone information is known, because it's either an all-day
+ * property or floating time, we will use the DateTimeZone argument to
+ * figure out the exact date.
+ *
+ * @param DateTimeZone $timeZone
+ *
+ * @return DateTimeImmutable
+ */
+ function getDateTime(DateTimeZone $timeZone = null) {
+
+ $dt = $this->getDateTimes($timeZone);
+ if (!$dt) return;
+
+ return $dt[0];
+
+ }
+
+ /**
+ * Returns multiple date-time values.
+ *
+ * If no timezone information is known, because it's either an all-day
+ * property or floating time, we will use the DateTimeZone argument to
+ * figure out the exact date.
+ *
+ * @param DateTimeZone $timeZone
+ *
+ * @return DateTimeImmutable[]
+ * @return \DateTime[]
+ */
+ function getDateTimes(DateTimeZone $timeZone = null) {
+
+ // Does the property have a TZID?
+ $tzid = $this['TZID'];
+
+ if ($tzid) {
+ $timeZone = TimeZoneUtil::getTimeZone((string)$tzid, $this->root);
+ }
+
+ $dts = [];
+ foreach ($this->getParts() as $part) {
+ $dts[] = DateTimeParser::parse($part, $timeZone);
+ }
+ return $dts;
+
+ }
+
+ /**
+ * Sets the property as a DateTime object.
+ *
+ * @param DateTimeInterface $dt
+ * @param bool isFloating If set to true, timezones will be ignored.
+ *
+ * @return void
+ */
+ function setDateTime(DateTimeInterface $dt, $isFloating = false) {
+
+ $this->setDateTimes([$dt], $isFloating);
+
+ }
+
+ /**
+ * Sets the property as multiple date-time objects.
+ *
+ * The first value will be used as a reference for the timezones, and all
+ * the otehr values will be adjusted for that timezone
+ *
+ * @param DateTimeInterface[] $dt
+ * @param bool isFloating If set to true, timezones will be ignored.
+ *
+ * @return void
+ */
+ function setDateTimes(array $dt, $isFloating = false) {
+
+ $values = [];
+
+ if ($this->hasTime()) {
+
+ $tz = null;
+ $isUtc = false;
+
+ foreach ($dt as $d) {
+
+ if ($isFloating) {
+ $values[] = $d->format('Ymd\\THis');
+ continue;
+ }
+ if (is_null($tz)) {
+ $tz = $d->getTimeZone();
+ $isUtc = in_array($tz->getName(), ['UTC', 'GMT', 'Z', '+00:00']);
+ if (!$isUtc) {
+ $this->offsetSet('TZID', $tz->getName());
+ }
+ } else {
+ $d = $d->setTimeZone($tz);
+ }
+
+ if ($isUtc) {
+ $values[] = $d->format('Ymd\\THis\\Z');
+ } else {
+ $values[] = $d->format('Ymd\\THis');
+ }
+
+ }
+ if ($isUtc || $isFloating) {
+ $this->offsetUnset('TZID');
+ }
+
+ } else {
+
+ foreach ($dt as $d) {
+
+ $values[] = $d->format('Ymd');
+
+ }
+ $this->offsetUnset('TZID');
+
+ }
+
+ $this->value = $values;
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return $this->hasTime() ? 'DATE-TIME' : 'DATE';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for JSON.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ $dts = $this->getDateTimes();
+ $hasTime = $this->hasTime();
+ $isFloating = $this->isFloating();
+
+ $tz = $dts[0]->getTimeZone();
+ $isUtc = $isFloating ? false : in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
+
+ return array_map(
+ function(DateTimeInterface $dt) use ($hasTime, $isUtc) {
+
+ if ($hasTime) {
+ return $dt->format('Y-m-d\\TH:i:s') . ($isUtc ? 'Z' : '');
+ } else {
+ return $dt->format('Y-m-d');
+ }
+
+ },
+ $dts
+ );
+
+ }
+
+ /**
+ * Sets the json value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setJsonValue(array $value) {
+
+ // dates and times in jCal have one difference to dates and times in
+ // iCalendar. In jCal date-parts are separated by dashes, and
+ // time-parts are separated by colons. It makes sense to just remove
+ // those.
+ $this->setValue(
+ array_map(
+ function($item) {
+
+ return strtr($item, [':' => '', '-' => '']);
+
+ },
+ $value
+ )
+ );
+
+ }
+
+ /**
+ * We need to intercept offsetSet, because it may be used to alter the
+ * VALUE from DATE-TIME to DATE or vice-versa.
+ *
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return void
+ */
+ function offsetSet($name, $value) {
+
+ parent::offsetSet($name, $value);
+ if (strtoupper($name) !== 'VALUE') {
+ return;
+ }
+
+ // This will ensure that dates are correctly encoded.
+ $this->setDateTimes($this->getDateTimes());
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on)
+ * 2 - An inconsequential issue
+ * 3 - A severe issue.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $messages = parent::validate($options);
+ $valueType = $this->getValueType();
+ $values = $this->getParts();
+ try {
+ foreach ($values as $value) {
+ switch ($valueType) {
+ case 'DATE' :
+ DateTimeParser::parseDate($value);
+ break;
+ case 'DATE-TIME' :
+ DateTimeParser::parseDateTime($value);
+ break;
+ }
+ }
+ } catch (InvalidDataException $e) {
+ $messages[] = [
+ 'level' => 3,
+ 'message' => 'The supplied value (' . $value . ') is not a correct ' . $valueType,
+ 'node' => $this,
+ ];
+ }
+ return $messages;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/Duration.php b/vendor/sabre/vobject/lib/Property/ICalendar/Duration.php
new file mode 100644
index 000000000..66d366960
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/ICalendar/Duration.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Sabre\VObject\Property\ICalendar;
+
+use Sabre\VObject\Property;
+use Sabre\VObject\DateTimeParser;
+
+/**
+ * Duration property.
+ *
+ * This object represents DURATION values, as defined here:
+ *
+ * http://tools.ietf.org/html/rfc5545#section-3.3.6
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Duration extends Property {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = ',';
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue(explode($this->delimiter, $val));
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return implode($this->delimiter, $this->getParts());
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'DURATION';
+
+ }
+
+ /**
+ * Returns a DateInterval representation of the Duration property.
+ *
+ * If the property has more than one value, only the first is returned.
+ *
+ * @return \DateInterval
+ */
+ function getDateInterval() {
+
+ $parts = $this->getParts();
+ $value = $parts[0];
+ return DateTimeParser::parseDuration($value);
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/Period.php b/vendor/sabre/vobject/lib/Property/ICalendar/Period.php
new file mode 100644
index 000000000..a4561d929
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/ICalendar/Period.php
@@ -0,0 +1,155 @@
+<?php
+
+namespace Sabre\VObject\Property\ICalendar;
+
+use Sabre\VObject\Property;
+use Sabre\VObject\DateTimeParser;
+use Sabre\Xml;
+
+/**
+ * Period property.
+ *
+ * This object represents PERIOD values, as defined here:
+ *
+ * http://tools.ietf.org/html/rfc5545#section-3.8.2.6
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Period extends Property {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = ',';
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue(explode($this->delimiter, $val));
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return implode($this->delimiter, $this->getParts());
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'PERIOD';
+
+ }
+
+ /**
+ * Sets the json value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setJsonValue(array $value) {
+
+ $value = array_map(
+ function($item) {
+
+ return strtr(implode('/', $item), [':' => '', '-' => '']);
+
+ },
+ $value
+ );
+ parent::setJsonValue($value);
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ $return = [];
+ foreach ($this->getParts() as $item) {
+
+ list($start, $end) = explode('/', $item, 2);
+
+ $start = DateTimeParser::parseDateTime($start);
+
+ // This is a duration value.
+ if ($end[0] === 'P') {
+ $return[] = [
+ $start->format('Y-m-d\\TH:i:s'),
+ $end
+ ];
+ } else {
+ $end = DateTimeParser::parseDateTime($end);
+ $return[] = [
+ $start->format('Y-m-d\\TH:i:s'),
+ $end->format('Y-m-d\\TH:i:s'),
+ ];
+ }
+
+ }
+
+ return $return;
+
+ }
+
+ /**
+ * This method serializes only the value of a property. This is used to
+ * create xCard or xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ protected function xmlSerializeValue(Xml\Writer $writer) {
+
+ $writer->startElement(strtolower($this->getValueType()));
+ $value = $this->getJsonValue();
+ $writer->writeElement('start', $value[0][0]);
+
+ if ($value[0][1][0] === 'P') {
+ $writer->writeElement('duration', $value[0][1]);
+ }
+ else {
+ $writer->writeElement('end', $value[0][1]);
+ }
+
+ $writer->endElement();
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/ICalendar/Recur.php b/vendor/sabre/vobject/lib/Property/ICalendar/Recur.php
new file mode 100644
index 000000000..a3c36dc64
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/ICalendar/Recur.php
@@ -0,0 +1,293 @@
+<?php
+
+namespace Sabre\VObject\Property\ICalendar;
+
+use Sabre\VObject\Property;
+use Sabre\Xml;
+
+/**
+ * Recur property.
+ *
+ * This object represents RECUR properties.
+ * These values are just used for RRULE and the now deprecated EXRULE.
+ *
+ * The RRULE property may look something like this:
+ *
+ * RRULE:FREQ=MONTHLY;BYDAY=1,2,3;BYHOUR=5.
+ *
+ * This property exposes this as a key=>value array that is accessible using
+ * getParts, and may be set using setParts.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Recur extends Property {
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * @param string|array $value
+ *
+ * @return void
+ */
+ function setValue($value) {
+
+ // If we're getting the data from json, we'll be receiving an object
+ if ($value instanceof \StdClass) {
+ $value = (array)$value;
+ }
+
+ if (is_array($value)) {
+ $newVal = [];
+ foreach ($value as $k => $v) {
+
+ if (is_string($v)) {
+ $v = strtoupper($v);
+
+ // The value had multiple sub-values
+ if (strpos($v, ',') !== false) {
+ $v = explode(',', $v);
+ }
+ if (strcmp($k, 'until') === 0) {
+ $v = strtr($v, [':' => '', '-' => '']);
+ }
+ } elseif (is_array($v)) {
+ $v = array_map('strtoupper', $v);
+ }
+
+ $newVal[strtoupper($k)] = $v;
+ }
+ $this->value = $newVal;
+ } elseif (is_string($value)) {
+ $this->value = self::stringToArray($value);
+ } else {
+ throw new \InvalidArgumentException('You must either pass a string, or a key=>value array');
+ }
+
+ }
+
+ /**
+ * Returns the current value.
+ *
+ * This method will always return a singular value. If this was a
+ * multi-value object, some decision will be made first on how to represent
+ * it as a string.
+ *
+ * To get the correct multi-value version, use getParts.
+ *
+ * @return string
+ */
+ function getValue() {
+
+ $out = [];
+ foreach ($this->value as $key => $value) {
+ $out[] = $key . '=' . (is_array($value) ? implode(',', $value) : $value);
+ }
+ return strtoupper(implode(';', $out));
+
+ }
+
+ /**
+ * Sets a multi-valued property.
+ *
+ * @param array $parts
+ * @return void
+ */
+ function setParts(array $parts) {
+
+ $this->setValue($parts);
+
+ }
+
+ /**
+ * Returns a multi-valued property.
+ *
+ * This method always returns an array, if there was only a single value,
+ * it will still be wrapped in an array.
+ *
+ * @return array
+ */
+ function getParts() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return $this->getValue();
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'RECUR';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ $values = [];
+ foreach ($this->getParts() as $k => $v) {
+ if (strcmp($k, 'UNTIL') === 0) {
+ $date = new DateTime($this->root, null, $v);
+ $values[strtolower($k)] = $date->getJsonValue()[0];
+ } elseif (strcmp($k, 'COUNT') === 0) {
+ $values[strtolower($k)] = intval($v);
+ } else {
+ $values[strtolower($k)] = $v;
+ }
+ }
+ return [$values];
+
+ }
+
+ /**
+ * This method serializes only the value of a property. This is used to
+ * create xCard or xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ protected function xmlSerializeValue(Xml\Writer $writer) {
+
+ $valueType = strtolower($this->getValueType());
+
+ foreach ($this->getJsonValue() as $value) {
+ $writer->writeElement($valueType, $value);
+ }
+
+ }
+
+ /**
+ * Parses an RRULE value string, and turns it into a struct-ish array.
+ *
+ * @param string $value
+ *
+ * @return array
+ */
+ static function stringToArray($value) {
+
+ $value = strtoupper($value);
+ $newValue = [];
+ foreach (explode(';', $value) as $part) {
+
+ // Skipping empty parts.
+ if (empty($part)) {
+ continue;
+ }
+ list($partName, $partValue) = explode('=', $part);
+
+ // The value itself had multiple values..
+ if (strpos($partValue, ',') !== false) {
+ $partValue = explode(',', $partValue);
+ }
+ $newValue[$partName] = $partValue;
+
+ }
+
+ return $newValue;
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on)
+ * 2 - An inconsequential issue
+ * 3 - A severe issue.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $repair = ($options & self::REPAIR);
+
+ $warnings = parent::validate($options);
+ $values = $this->getParts();
+
+ foreach ($values as $key => $value) {
+
+ if (empty($value)) {
+ $warnings[] = [
+ 'level' => $repair ? 3 : 1,
+ 'message' => 'Invalid value for ' . $key . ' in ' . $this->name,
+ 'node' => $this
+ ];
+ if ($repair) {
+ unset($values[$key]);
+ }
+ }
+
+ }
+ if (!isset($values['FREQ'])) {
+ $warnings[] = [
+ 'level' => $repair ? 3 : 1,
+ 'message' => 'FREQ is required in ' . $this->name,
+ 'node' => $this
+ ];
+ if ($repair) {
+ $this->parent->remove($this);
+ }
+ }
+ if ($repair) {
+ $this->setValue($values);
+ }
+
+ return $warnings;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/IntegerValue.php b/vendor/sabre/vobject/lib/Property/IntegerValue.php
new file mode 100644
index 000000000..5bd1887fa
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/IntegerValue.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+use
+ Sabre\VObject\Property;
+
+/**
+ * Integer property.
+ *
+ * This object represents INTEGER values. These are always a single integer.
+ * They may be preceeded by either + or -.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class IntegerValue extends Property {
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue((int)$val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'INTEGER';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ return [(int)$this->getValue()];
+
+ }
+
+ /**
+ * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
+ * object.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setXmlValue(array $value) {
+
+ $value = array_map('intval', $value);
+ parent::setXmlValue($value);
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Property/Text.php b/vendor/sabre/vobject/lib/Property/Text.php
new file mode 100644
index 000000000..2e16ac534
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/Text.php
@@ -0,0 +1,413 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+use Sabre\VObject\Property;
+use Sabre\VObject\Component;
+use Sabre\VObject\Parser\MimeDir;
+use Sabre\VObject\Document;
+use Sabre\Xml;
+
+/**
+ * Text property.
+ *
+ * This object represents TEXT values.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Text extends Property {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string
+ */
+ public $delimiter = ',';
+
+ /**
+ * List of properties that are considered 'structured'.
+ *
+ * @var array
+ */
+ protected $structuredValues = [
+ // vCard
+ 'N',
+ 'ADR',
+ 'ORG',
+ 'GENDER',
+ 'CLIENTPIDMAP',
+
+ // iCalendar
+ 'REQUEST-STATUS',
+ ];
+
+ /**
+ * Some text components have a minimum number of components.
+ *
+ * N must for instance be represented as 5 components, separated by ;, even
+ * if the last few components are unused.
+ *
+ * @var array
+ */
+ protected $minimumPropertyValues = [
+ 'N' => 5,
+ 'ADR' => 7,
+ ];
+
+ /**
+ * Creates the property.
+ *
+ * You can specify the parameters either in key=>value syntax, in which case
+ * parameters will automatically be created, or you can just pass a list of
+ * Parameter objects.
+ *
+ * @param Component $root The root document
+ * @param string $name
+ * @param string|array|null $value
+ * @param array $parameters List of parameters
+ * @param string $group The vcard property group
+ *
+ * @return void
+ */
+ function __construct(Component $root, $name, $value = null, array $parameters = [], $group = null) {
+
+ // There's two types of multi-valued text properties:
+ // 1. multivalue properties.
+ // 2. structured value properties
+ //
+ // The former is always separated by a comma, the latter by semi-colon.
+ if (in_array($name, $this->structuredValues)) {
+ $this->delimiter = ';';
+ }
+
+ parent::__construct($root, $name, $value, $parameters, $group);
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue(MimeDir::unescapeValue($val, $this->delimiter));
+
+ }
+
+ /**
+ * Sets the value as a quoted-printable encoded string.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setQuotedPrintableValue($val) {
+
+ $val = quoted_printable_decode($val);
+
+ // Quoted printable only appears in vCard 2.1, and the only character
+ // that may be escaped there is ;. So we are simply splitting on just
+ // that.
+ //
+ // We also don't have to unescape \\, so all we need to look for is a ;
+ // that's not preceeded with a \.
+ $regex = '# (?<!\\\\) ; #x';
+ $matches = preg_split($regex, $val);
+ $this->setValue($matches);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ $val = $this->getParts();
+
+ if (isset($this->minimumPropertyValues[$this->name])) {
+ $val = array_pad($val, $this->minimumPropertyValues[$this->name], '');
+ }
+
+ foreach ($val as &$item) {
+
+ if (!is_array($item)) {
+ $item = [$item];
+ }
+
+ foreach ($item as &$subItem) {
+ $subItem = strtr(
+ $subItem,
+ [
+ '\\' => '\\\\',
+ ';' => '\;',
+ ',' => '\,',
+ "\n" => '\n',
+ "\r" => "",
+ ]
+ );
+ }
+ $item = implode(',', $item);
+
+ }
+
+ return implode($this->delimiter, $val);
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ // Structured text values should always be returned as a single
+ // array-item. Multi-value text should be returned as multiple items in
+ // the top-array.
+ if (in_array($this->name, $this->structuredValues)) {
+ return [$this->getParts()];
+ }
+ return $this->getParts();
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'TEXT';
+
+ }
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ function serialize() {
+
+ // We need to kick in a special type of encoding, if it's a 2.1 vcard.
+ if ($this->root->getDocumentType() !== Document::VCARD21) {
+ return parent::serialize();
+ }
+
+ $val = $this->getParts();
+
+ if (isset($this->minimumPropertyValues[$this->name])) {
+ $val = array_pad($val, $this->minimumPropertyValues[$this->name], '');
+ }
+
+ // Imploding multiple parts into a single value, and splitting the
+ // values with ;.
+ if (count($val) > 1) {
+ foreach ($val as $k => $v) {
+ $val[$k] = str_replace(';', '\;', $v);
+ }
+ $val = implode(';', $val);
+ } else {
+ $val = $val[0];
+ }
+
+ $str = $this->name;
+ if ($this->group) $str = $this->group . '.' . $this->name;
+ foreach ($this->parameters as $param) {
+
+ if ($param->getValue() === 'QUOTED-PRINTABLE') {
+ continue;
+ }
+ $str .= ';' . $param->serialize();
+
+ }
+
+
+
+ // If the resulting value contains a \n, we must encode it as
+ // quoted-printable.
+ if (strpos($val, "\n") !== false) {
+
+ $str .= ';ENCODING=QUOTED-PRINTABLE:';
+ $lastLine = $str;
+ $out = null;
+
+ // The PHP built-in quoted-printable-encode does not correctly
+ // encode newlines for us. Specifically, the \r\n sequence must in
+ // vcards be encoded as =0D=OA and we must insert soft-newlines
+ // every 75 bytes.
+ for ($ii = 0;$ii < strlen($val);$ii++) {
+ $ord = ord($val[$ii]);
+ // These characters are encoded as themselves.
+ if ($ord >= 32 && $ord <= 126) {
+ $lastLine .= $val[$ii];
+ } else {
+ $lastLine .= '=' . strtoupper(bin2hex($val[$ii]));
+ }
+ if (strlen($lastLine) >= 75) {
+ // Soft line break
+ $out .= $lastLine . "=\r\n ";
+ $lastLine = null;
+ }
+
+ }
+ if (!is_null($lastLine)) $out .= $lastLine . "\r\n";
+ return $out;
+
+ } else {
+ $str .= ':' . $val;
+ $out = '';
+ while (strlen($str) > 0) {
+ if (strlen($str) > 75) {
+ $out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
+ $str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
+ } else {
+ $out .= $str . "\r\n";
+ $str = '';
+ break;
+ }
+ }
+
+ return $out;
+
+ }
+
+ }
+
+ /**
+ * This method serializes only the value of a property. This is used to
+ * create xCard or xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ protected function xmlSerializeValue(Xml\Writer $writer) {
+
+ $values = $this->getParts();
+
+ $map = function($items) use ($values, $writer) {
+ foreach ($items as $i => $item) {
+ $writer->writeElement(
+ $item,
+ !empty($values[$i]) ? $values[$i] : null
+ );
+ }
+ };
+
+ switch ($this->name) {
+
+ // Special-casing the REQUEST-STATUS property.
+ //
+ // See:
+ // http://tools.ietf.org/html/rfc6321#section-3.4.1.3
+ case 'REQUEST-STATUS':
+ $writer->writeElement('code', $values[0]);
+ $writer->writeElement('description', $values[1]);
+
+ if (isset($values[2])) {
+ $writer->writeElement('data', $values[2]);
+ }
+ break;
+
+ case 'N':
+ $map([
+ 'surname',
+ 'given',
+ 'additional',
+ 'prefix',
+ 'suffix'
+ ]);
+ break;
+
+ case 'GENDER':
+ $map([
+ 'sex',
+ 'text'
+ ]);
+ break;
+
+ case 'ADR':
+ $map([
+ 'pobox',
+ 'ext',
+ 'street',
+ 'locality',
+ 'region',
+ 'code',
+ 'country'
+ ]);
+ break;
+
+ case 'CLIENTPIDMAP':
+ $map([
+ 'sourceid',
+ 'uri'
+ ]);
+ break;
+
+ default:
+ parent::xmlSerializeValue($writer);
+ }
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * - Node::REPAIR - If something is broken, and automatic repair may
+ * be attempted.
+ *
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $warnings = parent::validate($options);
+
+ if (isset($this->minimumPropertyValues[$this->name])) {
+
+ $minimum = $this->minimumPropertyValues[$this->name];
+ $parts = $this->getParts();
+ if (count($parts) < $minimum) {
+ $warnings[] = [
+ 'level' => $options & self::REPAIR ? 1 : 3,
+ 'message' => 'The ' . $this->name . ' property must have at least ' . $minimum . ' values. It only has ' . count($parts),
+ 'node' => $this,
+ ];
+ if ($options & self::REPAIR) {
+ $parts = array_pad($parts, $minimum, '');
+ $this->setParts($parts);
+ }
+ }
+
+ }
+ return $warnings;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Property/Time.php b/vendor/sabre/vobject/lib/Property/Time.php
new file mode 100644
index 000000000..dbafc3b85
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/Time.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+use Sabre\VObject\DateTimeParser;
+
+/**
+ * Time property.
+ *
+ * This object encodes TIME values.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Time extends Text {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = null;
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'TIME';
+
+ }
+
+ /**
+ * Sets the JSON value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setJsonValue(array $value) {
+
+ // Removing colons from value.
+ $value = str_replace(
+ ':',
+ '',
+ $value
+ );
+
+ if (count($value) === 1) {
+ $this->setValue(reset($value));
+ } else {
+ $this->setValue($value);
+ }
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ $parts = DateTimeParser::parseVCardTime($this->getValue());
+ $timeStr = '';
+
+ // Hour
+ if (!is_null($parts['hour'])) {
+ $timeStr .= $parts['hour'];
+
+ if (!is_null($parts['minute'])) {
+ $timeStr .= ':';
+ }
+ } else {
+ // We know either minute or second _must_ be set, so we insert a
+ // dash for an empty value.
+ $timeStr .= '-';
+ }
+
+ // Minute
+ if (!is_null($parts['minute'])) {
+ $timeStr .= $parts['minute'];
+
+ if (!is_null($parts['second'])) {
+ $timeStr .= ':';
+ }
+ } else {
+ if (isset($parts['second'])) {
+ // Dash for empty minute
+ $timeStr .= '-';
+ }
+ }
+
+ // Second
+ if (!is_null($parts['second'])) {
+ $timeStr .= $parts['second'];
+ }
+
+ // Timezone
+ if (!is_null($parts['timezone'])) {
+ if ($parts['timezone'] === 'Z') {
+ $timeStr .= 'Z';
+ } else {
+ $timeStr .=
+ preg_replace('/([0-9]{2})([0-9]{2})$/', '$1:$2', $parts['timezone']);
+ }
+ }
+
+ return [$timeStr];
+
+ }
+
+ /**
+ * Hydrate data from a XML subtree, as it would appear in a xCard or xCal
+ * object.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setXmlValue(array $value) {
+
+ $value = array_map(
+ function($value) {
+ return str_replace(':', '', $value);
+ },
+ $value
+ );
+ parent::setXmlValue($value);
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/Unknown.php b/vendor/sabre/vobject/lib/Property/Unknown.php
new file mode 100644
index 000000000..7a3373868
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/Unknown.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+/**
+ * Unknown property.
+ *
+ * This object represents any properties not recognized by the parser.
+ * This type of value has been introduced by the jCal, jCard specs.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Unknown extends Text {
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ return [$this->getRawMimeDirValue()];
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'UNKNOWN';
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/Uri.php b/vendor/sabre/vobject/lib/Property/Uri.php
new file mode 100644
index 000000000..58e676e60
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/Uri.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+use Sabre\VObject\Property;
+use Sabre\VObject\Parameter;
+
+/**
+ * URI property.
+ *
+ * This object encodes URI values. vCard 2.1 calls these URL.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Uri extends Text {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = null;
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'URI';
+
+ }
+
+ /**
+ * Returns an iterable list of children.
+ *
+ * @return array
+ */
+ function parameters() {
+
+ $parameters = parent::parameters();
+ if (!isset($parameters['VALUE']) && in_array($this->name, ['URL', 'PHOTO'])) {
+ // If we are encoding a URI value, and this URI value has no
+ // VALUE=URI parameter, we add it anyway.
+ //
+ // This is not required by any spec, but both Apple iCal and Apple
+ // AddressBook (at least in version 10.8) will trip over this if
+ // this is not set, and so it improves compatibility.
+ //
+ // See Issue #227 and #235
+ $parameters['VALUE'] = new Parameter($this->root, 'VALUE', 'URI');
+ }
+ return $parameters;
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ // Normally we don't need to do any type of unescaping for these
+ // properties, however.. we've noticed that Google Contacts
+ // specifically escapes the colon (:) with a blackslash. While I have
+ // no clue why they thought that was a good idea, I'm unescaping it
+ // anyway.
+ //
+ // Good thing backslashes are not allowed in urls. Makes it easy to
+ // assume that a backslash is always intended as an escape character.
+ if ($this->name === 'URL') {
+ $regex = '# (?: (\\\\ (?: \\\\ | : ) ) ) #x';
+ $matches = preg_split($regex, $val, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $newVal = '';
+ foreach ($matches as $match) {
+ switch ($match) {
+ case '\:' :
+ $newVal .= ':';
+ break;
+ default :
+ $newVal .= $match;
+ break;
+ }
+ }
+ $this->value = $newVal;
+ } else {
+ $this->value = strtr($val, ['\,' => ',']);
+ }
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ if (is_array($this->value)) {
+ $value = $this->value[0];
+ } else {
+ $value = $this->value;
+ }
+
+ return strtr($value, [',' => '\,']);
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/UtcOffset.php b/vendor/sabre/vobject/lib/Property/UtcOffset.php
new file mode 100644
index 000000000..61895c48e
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/UtcOffset.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Sabre\VObject\Property;
+
+/**
+ * UtcOffset property.
+ *
+ * This object encodes UTC-OFFSET values.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class UtcOffset extends Text {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = null;
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'UTC-OFFSET';
+
+ }
+
+ /**
+ * Sets the JSON value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ *
+ * @return void
+ */
+ function setJsonValue(array $value) {
+
+ $value = array_map(
+ function($value) {
+ return str_replace(':', '', $value);
+ },
+ $value
+ );
+ parent::setJsonValue($value);
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for JSON.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ return array_map(
+ function($value) {
+ return substr($value, 0, -2) . ':' .
+ substr($value, -2);
+ },
+ parent::getJsonValue()
+ );
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Property/VCard/Date.php b/vendor/sabre/vobject/lib/Property/VCard/Date.php
new file mode 100644
index 000000000..1ef6dff34
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/VCard/Date.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Sabre\VObject\Property\VCard;
+
+/**
+ * Date property.
+ *
+ * This object encodes vCard DATE values.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Date extends DateAndOrTime {
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'DATE';
+
+ }
+
+ /**
+ * Sets the property as a DateTime object.
+ *
+ * @param \DateTimeInterface $dt
+ *
+ * @return void
+ */
+ function setDateTime(\DateTimeInterface $dt) {
+
+ $this->value = $dt->format('Ymd');
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php b/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php
new file mode 100644
index 000000000..650e19cbf
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/VCard/DateAndOrTime.php
@@ -0,0 +1,405 @@
+<?php
+
+namespace Sabre\VObject\Property\VCard;
+
+use DateTimeInterface;
+use DateTimeImmutable;
+use DateTime;
+use Sabre\VObject\DateTimeParser;
+use Sabre\VObject\InvalidDataException;
+use Sabre\VObject\Property;
+use Sabre\Xml;
+
+/**
+ * DateAndOrTime property.
+ *
+ * This object encodes DATE-AND-OR-TIME values.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class DateAndOrTime extends Property {
+
+ /**
+ * Field separator.
+ *
+ * @var null|string
+ */
+ public $delimiter = null;
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'DATE-AND-OR-TIME';
+
+ }
+
+ /**
+ * Sets a multi-valued property.
+ *
+ * You may also specify DateTime objects here.
+ *
+ * @param array $parts
+ *
+ * @return void
+ */
+ function setParts(array $parts) {
+
+ if (count($parts) > 1) {
+ throw new \InvalidArgumentException('Only one value allowed');
+ }
+ if (isset($parts[0]) && $parts[0] instanceof \DateTime) {
+ $this->setDateTime($parts[0]);
+ } else {
+ parent::setParts($parts);
+ }
+
+ }
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * Instead of strings, you may also use DateTime here.
+ *
+ * @param string|array|\DateTime $value
+ *
+ * @return void
+ */
+ function setValue($value) {
+
+ if ($value instanceof \DateTime) {
+ $this->setDateTime($value);
+ } else {
+ parent::setValue($value);
+ }
+
+ }
+
+ /**
+ * Sets the property as a DateTime object.
+ *
+ * @param DateTimeInterface $dt
+ *
+ * @return void
+ */
+ function setDateTime(DateTimeInterface $dt) {
+
+ $tz = $dt->getTimeZone();
+ $isUtc = in_array($tz->getName(), ['UTC', 'GMT', 'Z']);
+
+ if ($isUtc) {
+ $value = $dt->format('Ymd\\THis\\Z');
+ } else {
+ // Calculating the offset.
+ $value = $dt->format('Ymd\\THisO');
+ }
+
+ $this->value = $value;
+
+ }
+
+ /**
+ * Returns a date-time value.
+ *
+ * Note that if this property contained more than 1 date-time, only the
+ * first will be returned. To get an array with multiple values, call
+ * getDateTimes.
+ *
+ * If no time was specified, we will always use midnight (in the default
+ * timezone) as the time.
+ *
+ * If parts of the date were omitted, such as the year, we will grab the
+ * current values for those. So at the time of writing, if the year was
+ * omitted, we would have filled in 2014.
+ *
+ * @return DateTimeImmutable
+ */
+ function getDateTime() {
+
+ $now = new DateTime();
+
+ $tzFormat = $now->getTimezone()->getOffset($now) === 0 ? '\\Z' : 'O';
+ $nowParts = DateTimeParser::parseVCardDateTime($now->format('Ymd\\This' . $tzFormat));
+
+ $dateParts = DateTimeParser::parseVCardDateTime($this->getValue());
+
+ // This sets all the missing parts to the current date/time.
+ // So if the year was missing for a birthday, we're making it 'this
+ // year'.
+ foreach ($dateParts as $k => $v) {
+ if (is_null($v)) {
+ $dateParts[$k] = $nowParts[$k];
+ }
+ }
+ return new DateTimeImmutable("$dateParts[year]-$dateParts[month]-$dateParts[date] $dateParts[hour]:$dateParts[minute]:$dateParts[second] $dateParts[timezone]");
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ $parts = DateTimeParser::parseVCardDateTime($this->getValue());
+
+ $dateStr = '';
+
+ // Year
+ if (!is_null($parts['year'])) {
+
+ $dateStr .= $parts['year'];
+
+ if (!is_null($parts['month'])) {
+ // If a year and a month is set, we need to insert a separator
+ // dash.
+ $dateStr .= '-';
+ }
+
+ } else {
+
+ if (!is_null($parts['month']) || !is_null($parts['date'])) {
+ // Inserting two dashes
+ $dateStr .= '--';
+ }
+
+ }
+
+ // Month
+ if (!is_null($parts['month'])) {
+
+ $dateStr .= $parts['month'];
+
+ if (isset($parts['date'])) {
+ // If month and date are set, we need the separator dash.
+ $dateStr .= '-';
+ }
+
+ } elseif (isset($parts['date'])) {
+ // If the month is empty, and a date is set, we need a 'empty
+ // dash'
+ $dateStr .= '-';
+ }
+
+ // Date
+ if (!is_null($parts['date'])) {
+ $dateStr .= $parts['date'];
+ }
+
+
+ // Early exit if we don't have a time string.
+ if (is_null($parts['hour']) && is_null($parts['minute']) && is_null($parts['second'])) {
+ return [$dateStr];
+ }
+
+ $dateStr .= 'T';
+
+ // Hour
+ if (!is_null($parts['hour'])) {
+
+ $dateStr .= $parts['hour'];
+
+ if (!is_null($parts['minute'])) {
+ $dateStr .= ':';
+ }
+
+ } else {
+ // We know either minute or second _must_ be set, so we insert a
+ // dash for an empty value.
+ $dateStr .= '-';
+ }
+
+ // Minute
+ if (!is_null($parts['minute'])) {
+
+ $dateStr .= $parts['minute'];
+
+ if (!is_null($parts['second'])) {
+ $dateStr .= ':';
+ }
+
+ } elseif (isset($parts['second'])) {
+ // Dash for empty minute
+ $dateStr .= '-';
+ }
+
+ // Second
+ if (!is_null($parts['second'])) {
+ $dateStr .= $parts['second'];
+ }
+
+ // Timezone
+ if (!is_null($parts['timezone'])) {
+ $dateStr .= $parts['timezone'];
+ }
+
+ return [$dateStr];
+
+ }
+
+ /**
+ * This method serializes only the value of a property. This is used to
+ * create xCard or xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ protected function xmlSerializeValue(Xml\Writer $writer) {
+
+ $valueType = strtolower($this->getValueType());
+ $parts = DateTimeParser::parseVCardDateAndOrTime($this->getValue());
+ $value = '';
+
+ // $d = defined
+ $d = function($part) use ($parts) {
+ return !is_null($parts[$part]);
+ };
+
+ // $r = read
+ $r = function($part) use ($parts) {
+ return $parts[$part];
+ };
+
+ // From the Relax NG Schema.
+ //
+ // # 4.3.1
+ // value-date = element date {
+ // xsd:string { pattern = "\d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d" }
+ // }
+ if (($d('year') || $d('month') || $d('date'))
+ && (!$d('hour') && !$d('minute') && !$d('second') && !$d('timezone'))) {
+
+ if ($d('year') && $d('month') && $d('date')) {
+ $value .= $r('year') . $r('month') . $r('date');
+ } elseif ($d('year') && $d('month') && !$d('date')) {
+ $value .= $r('year') . '-' . $r('month');
+ } elseif (!$d('year') && $d('month')) {
+ $value .= '--' . $r('month') . $r('date');
+ } elseif (!$d('year') && !$d('month') && $d('date')) {
+ $value .= '---' . $r('date');
+ }
+
+ // # 4.3.2
+ // value-time = element time {
+ // xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d?)|--\d\d)"
+ // ~ "(Z|[+\-]\d\d(\d\d)?)?" }
+ // }
+ } elseif ((!$d('year') && !$d('month') && !$d('date'))
+ && ($d('hour') || $d('minute') || $d('second'))) {
+
+ if ($d('hour')) {
+ $value .= $r('hour') . $r('minute') . $r('second');
+ } elseif ($d('minute')) {
+ $value .= '-' . $r('minute') . $r('second');
+ } elseif ($d('second')) {
+ $value .= '--' . $r('second');
+ }
+
+ $value .= $r('timezone');
+
+ // # 4.3.3
+ // value-date-time = element date-time {
+ // xsd:string { pattern = "(\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?"
+ // ~ "(Z|[+\-]\d\d(\d\d)?)?" }
+ // }
+ } elseif ($d('date') && $d('hour')) {
+
+ if ($d('year') && $d('month') && $d('date')) {
+ $value .= $r('year') . $r('month') . $r('date');
+ } elseif (!$d('year') && $d('month') && $d('date')) {
+ $value .= '--' . $r('month') . $r('date');
+ } elseif (!$d('year') && !$d('month') && $d('date')) {
+ $value .= '---' . $r('date');
+ }
+
+ $value .= 'T' . $r('hour') . $r('minute') . $r('second') .
+ $r('timezone');
+
+ }
+
+ $writer->writeElement($valueType, $value);
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return implode($this->delimiter, $this->getParts());
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * Node::REPAIR - May attempt to automatically repair the problem.
+ *
+ * This method returns an array with detected problems.
+ * Every element has the following properties:
+ *
+ * * level - problem level.
+ * * message - A human-readable string describing the issue.
+ * * node - A reference to the problematic node.
+ *
+ * The level means:
+ * 1 - The issue was repaired (only happens if REPAIR was turned on)
+ * 2 - An inconsequential issue
+ * 3 - A severe issue.
+ *
+ * @param int $options
+ *
+ * @return array
+ */
+ function validate($options = 0) {
+
+ $messages = parent::validate($options);
+ $value = $this->getValue();
+
+ try {
+ DateTimeParser::parseVCardDateTime($value);
+ } catch (InvalidDataException $e) {
+ $messages[] = [
+ 'level' => 3,
+ 'message' => 'The supplied value (' . $value . ') is not a correct DATE-AND-OR-TIME property',
+ 'node' => $this,
+ ];
+ }
+
+ return $messages;
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Property/VCard/DateTime.php b/vendor/sabre/vobject/lib/Property/VCard/DateTime.php
new file mode 100644
index 000000000..e7c804ca7
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/VCard/DateTime.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Sabre\VObject\Property\VCard;
+
+/**
+ * DateTime property.
+ *
+ * This object encodes DATE-TIME values for vCards.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class DateTime extends DateAndOrTime {
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'DATE-TIME';
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/VCard/LanguageTag.php b/vendor/sabre/vobject/lib/Property/VCard/LanguageTag.php
new file mode 100644
index 000000000..aa7e9178d
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/VCard/LanguageTag.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Sabre\VObject\Property\VCard;
+
+use
+ Sabre\VObject\Property;
+
+/**
+ * LanguageTag property.
+ *
+ * This object represents LANGUAGE-TAG values as used in vCards.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class LanguageTag extends Property {
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ *
+ * @return void
+ */
+ function setRawMimeDirValue($val) {
+
+ $this->setValue($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ function getRawMimeDirValue() {
+
+ return $this->getValue();
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'LANGUAGE-TAG';
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Property/VCard/TimeStamp.php b/vendor/sabre/vobject/lib/Property/VCard/TimeStamp.php
new file mode 100644
index 000000000..9d311f99d
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Property/VCard/TimeStamp.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Sabre\VObject\Property\VCard;
+
+use Sabre\VObject\DateTimeParser;
+use Sabre\VObject\Property\Text;
+use Sabre\Xml;
+
+/**
+ * TimeStamp property.
+ *
+ * This object encodes TIMESTAMP values.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class TimeStamp extends Text {
+
+ /**
+ * In case this is a multi-value property. This string will be used as a
+ * delimiter.
+ *
+ * @var string|null
+ */
+ public $delimiter = null;
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ function getValueType() {
+
+ return 'TIMESTAMP';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ function getJsonValue() {
+
+ $parts = DateTimeParser::parseVCardDateTime($this->getValue());
+
+ $dateStr =
+ $parts['year'] . '-' .
+ $parts['month'] . '-' .
+ $parts['date'] . 'T' .
+ $parts['hour'] . ':' .
+ $parts['minute'] . ':' .
+ $parts['second'];
+
+ // Timezone
+ if (!is_null($parts['timezone'])) {
+ $dateStr .= $parts['timezone'];
+ }
+
+ return [$dateStr];
+
+ }
+
+ /**
+ * This method serializes only the value of a property. This is used to
+ * create xCard or xCal documents.
+ *
+ * @param Xml\Writer $writer XML writer.
+ *
+ * @return void
+ */
+ protected function xmlSerializeValue(Xml\Writer $writer) {
+
+ // xCard is the only XML and JSON format that has the same date and time
+ // format than vCard.
+ $valueType = strtolower($this->getValueType());
+ $writer->writeElement($valueType, $this->getValue());
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Reader.php b/vendor/sabre/vobject/lib/Reader.php
new file mode 100644
index 000000000..709929337
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Reader.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * iCalendar/vCard/jCal/jCard/xCal/xCard reader object.
+ *
+ * This object provides a few (static) convenience methods to quickly access
+ * the parsers.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Reader {
+
+ /**
+ * If this option is passed to the reader, it will be less strict about the
+ * validity of the lines.
+ */
+ const OPTION_FORGIVING = 1;
+
+ /**
+ * If this option is turned on, any lines we cannot parse will be ignored
+ * by the reader.
+ */
+ const OPTION_IGNORE_INVALID_LINES = 2;
+
+ /**
+ * Parses a vCard or iCalendar object, and returns the top component.
+ *
+ * The options argument is a bitfield. Pass any of the OPTIONS constant to
+ * alter the parsers' behaviour.
+ *
+ * You can either supply a string, or a readable stream for input.
+ *
+ * @param string|resource $data
+ * @param int $options
+ * @param string $charset
+ * @return Document
+ */
+ static function read($data, $options = 0, $charset = 'UTF-8') {
+
+ $parser = new Parser\MimeDir();
+ $parser->setCharset($charset);
+ $result = $parser->parse($data, $options);
+
+ return $result;
+
+ }
+
+ /**
+ * Parses a jCard or jCal object, and returns the top component.
+ *
+ * The options argument is a bitfield. Pass any of the OPTIONS constant to
+ * alter the parsers' behaviour.
+ *
+ * You can either a string, a readable stream, or an array for it's input.
+ * Specifying the array is useful if json_decode was already called on the
+ * input.
+ *
+ * @param string|resource|array $data
+ * @param int $options
+ *
+ * @return Document
+ */
+ static function readJson($data, $options = 0) {
+
+ $parser = new Parser\Json();
+ $result = $parser->parse($data, $options);
+
+ return $result;
+
+ }
+
+ /**
+ * Parses a xCard or xCal object, and returns the top component.
+ *
+ * The options argument is a bitfield. Pass any of the OPTIONS constant to
+ * alter the parsers' behaviour.
+ *
+ * You can either supply a string, or a readable stream for input.
+ *
+ * @param string|resource $data
+ * @param int $options
+ *
+ * @return Document
+ */
+ static function readXML($data, $options = 0) {
+
+ $parser = new Parser\XML();
+ $result = $parser->parse($data, $options);
+
+ return $result;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/Recur/EventIterator.php b/vendor/sabre/vobject/lib/Recur/EventIterator.php
new file mode 100644
index 000000000..86c996aec
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Recur/EventIterator.php
@@ -0,0 +1,507 @@
+<?php
+
+namespace Sabre\VObject\Recur;
+
+use DateTimeZone;
+use DateTimeImmutable;
+use DateTimeInterface;
+use InvalidArgumentException;
+use Sabre\VObject\Component;
+use Sabre\VObject\Component\VEvent;
+use Sabre\VObject\Settings;
+
+/**
+ * This class is used to determine new for a recurring event, when the next
+ * events occur.
+ *
+ * This iterator may loop infinitely in the future, therefore it is important
+ * that if you use this class, you set hard limits for the amount of iterations
+ * you want to handle.
+ *
+ * Note that currently there is not full support for the entire iCalendar
+ * specification, as it's very complex and contains a lot of permutations
+ * that's not yet used very often in software.
+ *
+ * For the focus has been on features as they actually appear in Calendaring
+ * software, but this may well get expanded as needed / on demand
+ *
+ * The following RRULE properties are supported
+ * * UNTIL
+ * * INTERVAL
+ * * COUNT
+ * * FREQ=DAILY
+ * * BYDAY
+ * * BYHOUR
+ * * BYMONTH
+ * * FREQ=WEEKLY
+ * * BYDAY
+ * * BYHOUR
+ * * WKST
+ * * FREQ=MONTHLY
+ * * BYMONTHDAY
+ * * BYDAY
+ * * BYSETPOS
+ * * FREQ=YEARLY
+ * * BYMONTH
+ * * BYMONTHDAY (only if BYMONTH is also set)
+ * * BYDAY (only if BYMONTH is also set)
+ *
+ * Anything beyond this is 'undefined', which means that it may get ignored, or
+ * you may get unexpected results. The effect is that in some applications the
+ * specified recurrence may look incorrect, or is missing.
+ *
+ * The recurrence iterator also does not yet support THISANDFUTURE.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class EventIterator implements \Iterator {
+
+ /**
+ * Reference timeZone for floating dates and times.
+ *
+ * @var DateTimeZone
+ */
+ protected $timeZone;
+
+ /**
+ * True if we're iterating an all-day event.
+ *
+ * @var bool
+ */
+ protected $allDay = false;
+
+ /**
+ * Creates the iterator.
+ *
+ * There's three ways to set up the iterator.
+ *
+ * 1. You can pass a VCALENDAR component and a UID.
+ * 2. You can pass an array of VEVENTs (all UIDS should match).
+ * 3. You can pass a single VEVENT component.
+ *
+ * Only the second method is recomended. The other 1 and 3 will be removed
+ * at some point in the future.
+ *
+ * The $uid parameter is only required for the first method.
+ *
+ * @param Component|array $input
+ * @param string|null $uid
+ * @param DateTimeZone $timeZone Reference timezone for floating dates and
+ * times.
+ */
+ function __construct($input, $uid = null, DateTimeZone $timeZone = null) {
+
+ if (is_null($timeZone)) {
+ $timeZone = new DateTimeZone('UTC');
+ }
+ $this->timeZone = $timeZone;
+
+ if (is_array($input)) {
+ $events = $input;
+ } elseif ($input instanceof VEvent) {
+ // Single instance mode.
+ $events = [$input];
+ } else {
+ // Calendar + UID mode.
+ $uid = (string)$uid;
+ if (!$uid) {
+ throw new InvalidArgumentException('The UID argument is required when a VCALENDAR is passed to this constructor');
+ }
+ if (!isset($input->VEVENT)) {
+ throw new InvalidArgumentException('No events found in this calendar');
+ }
+ $events = $input->getByUID($uid);
+
+ }
+
+ foreach ($events as $vevent) {
+
+ if (!isset($vevent->{'RECURRENCE-ID'})) {
+
+ $this->masterEvent = $vevent;
+
+ } else {
+
+ $this->exceptions[
+ $vevent->{'RECURRENCE-ID'}->getDateTime($this->timeZone)->getTimeStamp()
+ ] = true;
+ $this->overriddenEvents[] = $vevent;
+
+ }
+
+ }
+
+ if (!$this->masterEvent) {
+ // No base event was found. CalDAV does allow cases where only
+ // overridden instances are stored.
+ //
+ // In this particular case, we're just going to grab the first
+ // event and use that instead. This may not always give the
+ // desired result.
+ if (!count($this->overriddenEvents)) {
+ throw new InvalidArgumentException('This VCALENDAR did not have an event with UID: ' . $uid);
+ }
+ $this->masterEvent = array_shift($this->overriddenEvents);
+ }
+
+ $this->startDate = $this->masterEvent->DTSTART->getDateTime($this->timeZone);
+ $this->allDay = !$this->masterEvent->DTSTART->hasTime();
+
+ if (isset($this->masterEvent->EXDATE)) {
+
+ foreach ($this->masterEvent->EXDATE as $exDate) {
+
+ foreach ($exDate->getDateTimes($this->timeZone) as $dt) {
+ $this->exceptions[$dt->getTimeStamp()] = true;
+ }
+
+ }
+
+ }
+
+ if (isset($this->masterEvent->DTEND)) {
+ $this->eventDuration =
+ $this->masterEvent->DTEND->getDateTime($this->timeZone)->getTimeStamp() -
+ $this->startDate->getTimeStamp();
+ } elseif (isset($this->masterEvent->DURATION)) {
+ $duration = $this->masterEvent->DURATION->getDateInterval();
+ $end = clone $this->startDate;
+ $end = $end->add($duration);
+ $this->eventDuration = $end->getTimeStamp() - $this->startDate->getTimeStamp();
+ } elseif ($this->allDay) {
+ $this->eventDuration = 3600 * 24;
+ } else {
+ $this->eventDuration = 0;
+ }
+
+ if (isset($this->masterEvent->RDATE)) {
+ $this->recurIterator = new RDateIterator(
+ $this->masterEvent->RDATE->getParts(),
+ $this->startDate
+ );
+ } elseif (isset($this->masterEvent->RRULE)) {
+ $this->recurIterator = new RRuleIterator(
+ $this->masterEvent->RRULE->getParts(),
+ $this->startDate
+ );
+ } else {
+ $this->recurIterator = new RRuleIterator(
+ [
+ 'FREQ' => 'DAILY',
+ 'COUNT' => 1,
+ ],
+ $this->startDate
+ );
+ }
+
+ $this->rewind();
+ if (!$this->valid()) {
+ throw new NoInstancesException('This recurrence rule does not generate any valid instances');
+ }
+
+ }
+
+ /**
+ * Returns the date for the current position of the iterator.
+ *
+ * @return DateTimeImmutable
+ */
+ function current() {
+
+ if ($this->currentDate) {
+ return clone $this->currentDate;
+ }
+
+ }
+
+ /**
+ * This method returns the start date for the current iteration of the
+ * event.
+ *
+ * @return DateTimeImmutable
+ */
+ function getDtStart() {
+
+ if ($this->currentDate) {
+ return clone $this->currentDate;
+ }
+
+ }
+
+ /**
+ * This method returns the end date for the current iteration of the
+ * event.
+ *
+ * @return DateTimeImmutable
+ */
+ function getDtEnd() {
+
+ if (!$this->valid()) {
+ return;
+ }
+ $end = clone $this->currentDate;
+ return $end->modify('+' . $this->eventDuration . ' seconds');
+
+ }
+
+ /**
+ * Returns a VEVENT for the current iterations of the event.
+ *
+ * This VEVENT will have a recurrence id, and it's DTSTART and DTEND
+ * altered.
+ *
+ * @return VEvent
+ */
+ function getEventObject() {
+
+ if ($this->currentOverriddenEvent) {
+ return $this->currentOverriddenEvent;
+ }
+
+ $event = clone $this->masterEvent;
+
+ // Ignoring the following block, because PHPUnit's code coverage
+ // ignores most of these lines, and this messes with our stats.
+ //
+ // @codeCoverageIgnoreStart
+ unset(
+ $event->RRULE,
+ $event->EXDATE,
+ $event->RDATE,
+ $event->EXRULE,
+ $event->{'RECURRENCE-ID'}
+ );
+ // @codeCoverageIgnoreEnd
+
+ $event->DTSTART->setDateTime($this->getDtStart(), $event->DTSTART->isFloating());
+ if (isset($event->DTEND)) {
+ $event->DTEND->setDateTime($this->getDtEnd(), $event->DTEND->isFloating());
+ }
+ $recurid = clone $event->DTSTART;
+ $recurid->name = 'RECURRENCE-ID';
+ $event->add($recurid);
+ return $event;
+
+ }
+
+ /**
+ * Returns the current position of the iterator.
+ *
+ * This is for us simply a 0-based index.
+ *
+ * @return int
+ */
+ function key() {
+
+ // The counter is always 1 ahead.
+ return $this->counter - 1;
+
+ }
+
+ /**
+ * This is called after next, to see if the iterator is still at a valid
+ * position, or if it's at the end.
+ *
+ * @return bool
+ */
+ function valid() {
+
+ if ($this->counter > Settings::$maxRecurrences && Settings::$maxRecurrences !== -1) {
+ throw new MaxInstancesExceededException('Recurring events are only allowed to generate ' . Settings::$maxRecurrences);
+ }
+ return !!$this->currentDate;
+
+ }
+
+ /**
+ * Sets the iterator back to the starting point.
+ */
+ function rewind() {
+
+ $this->recurIterator->rewind();
+ // re-creating overridden event index.
+ $index = [];
+ foreach ($this->overriddenEvents as $key => $event) {
+ $stamp = $event->DTSTART->getDateTime($this->timeZone)->getTimeStamp();
+ $index[$stamp] = $key;
+ }
+ krsort($index);
+ $this->counter = 0;
+ $this->overriddenEventsIndex = $index;
+ $this->currentOverriddenEvent = null;
+
+ $this->nextDate = null;
+ $this->currentDate = clone $this->startDate;
+
+ $this->next();
+
+ }
+
+ /**
+ * Advances the iterator with one step.
+ *
+ * @return void
+ */
+ function next() {
+
+ $this->currentOverriddenEvent = null;
+ $this->counter++;
+ if ($this->nextDate) {
+ // We had a stored value.
+ $nextDate = $this->nextDate;
+ $this->nextDate = null;
+ } else {
+ // We need to ask rruleparser for the next date.
+ // We need to do this until we find a date that's not in the
+ // exception list.
+ do {
+ if (!$this->recurIterator->valid()) {
+ $nextDate = null;
+ break;
+ }
+ $nextDate = $this->recurIterator->current();
+ $this->recurIterator->next();
+ } while (isset($this->exceptions[$nextDate->getTimeStamp()]));
+
+ }
+
+
+ // $nextDate now contains what rrule thinks is the next one, but an
+ // overridden event may cut ahead.
+ if ($this->overriddenEventsIndex) {
+
+ $offset = end($this->overriddenEventsIndex);
+ $timestamp = key($this->overriddenEventsIndex);
+ if (!$nextDate || $timestamp < $nextDate->getTimeStamp()) {
+ // Overridden event comes first.
+ $this->currentOverriddenEvent = $this->overriddenEvents[$offset];
+
+ // Putting the rrule next date aside.
+ $this->nextDate = $nextDate;
+ $this->currentDate = $this->currentOverriddenEvent->DTSTART->getDateTime($this->timeZone);
+
+ // Ensuring that this item will only be used once.
+ array_pop($this->overriddenEventsIndex);
+
+ // Exit point!
+ return;
+
+ }
+
+ }
+
+ $this->currentDate = $nextDate;
+
+ }
+
+ /**
+ * Quickly jump to a date in the future.
+ *
+ * @param DateTimeInterface $dateTime
+ */
+ function fastForward(DateTimeInterface $dateTime) {
+
+ while ($this->valid() && $this->getDtEnd() < $dateTime) {
+ $this->next();
+ }
+
+ }
+
+ /**
+ * Returns true if this recurring event never ends.
+ *
+ * @return bool
+ */
+ function isInfinite() {
+
+ return $this->recurIterator->isInfinite();
+
+ }
+
+ /**
+ * RRULE parser.
+ *
+ * @var RRuleIterator
+ */
+ protected $recurIterator;
+
+ /**
+ * The duration, in seconds, of the master event.
+ *
+ * We use this to calculate the DTEND for subsequent events.
+ */
+ protected $eventDuration;
+
+ /**
+ * A reference to the main (master) event.
+ *
+ * @var VEVENT
+ */
+ protected $masterEvent;
+
+ /**
+ * List of overridden events.
+ *
+ * @var array
+ */
+ protected $overriddenEvents = [];
+
+ /**
+ * Overridden event index.
+ *
+ * Key is timestamp, value is the index of the item in the $overriddenEvent
+ * property.
+ *
+ * @var array
+ */
+ protected $overriddenEventsIndex;
+
+ /**
+ * A list of recurrence-id's that are either part of EXDATE, or are
+ * overridden.
+ *
+ * @var array
+ */
+ protected $exceptions = [];
+
+ /**
+ * Internal event counter.
+ *
+ * @var int
+ */
+ protected $counter;
+
+ /**
+ * The very start of the iteration process.
+ *
+ * @var DateTimeImmutable
+ */
+ protected $startDate;
+
+ /**
+ * Where we are currently in the iteration process.
+ *
+ * @var DateTimeImmutable
+ */
+ protected $currentDate;
+
+ /**
+ * The next date from the rrule parser.
+ *
+ * Sometimes we need to temporary store the next date, because an
+ * overridden event came before.
+ *
+ * @var DateTimeImmutable
+ */
+ protected $nextDate;
+
+ /**
+ * The event that overwrites the current iteration
+ *
+ * @var VEVENT
+ */
+ protected $currentOverriddenEvent;
+
+}
diff --git a/vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php b/vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php
new file mode 100644
index 000000000..264df7d2b
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Sabre\VObject\Recur;
+
+use Exception;
+
+/**
+ * This exception will get thrown when a recurrence rule generated more than
+ * the maximum number of instances.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class MaxInstancesExceededException extends Exception {
+}
diff --git a/vendor/sabre/vobject/lib/Recur/NoInstancesException.php b/vendor/sabre/vobject/lib/Recur/NoInstancesException.php
new file mode 100644
index 000000000..8f8bb472b
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Recur/NoInstancesException.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Sabre\VObject\Recur;
+
+use Exception;
+
+/**
+ * This exception gets thrown when a recurrence iterator produces 0 instances.
+ *
+ * This may happen when every occurence in a rrule is also in EXDATE.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class NoInstancesException extends Exception {
+
+}
diff --git a/vendor/sabre/vobject/lib/Recur/RDateIterator.php b/vendor/sabre/vobject/lib/Recur/RDateIterator.php
new file mode 100644
index 000000000..f44960e12
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Recur/RDateIterator.php
@@ -0,0 +1,182 @@
+<?php
+
+namespace Sabre\VObject\Recur;
+
+use DateTimeInterface;
+use Iterator;
+use Sabre\VObject\DateTimeParser;
+
+/**
+ * RRuleParser.
+ *
+ * This class receives an RRULE string, and allows you to iterate to get a list
+ * of dates in that recurrence.
+ *
+ * For instance, passing: FREQ=DAILY;LIMIT=5 will cause the iterator to contain
+ * 5 items, one for each day.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class RDateIterator implements Iterator {
+
+ /**
+ * Creates the Iterator.
+ *
+ * @param string|array $rrule
+ * @param DateTimeInterface $start
+ */
+ function __construct($rrule, DateTimeInterface $start) {
+
+ $this->startDate = $start;
+ $this->parseRDate($rrule);
+ $this->currentDate = clone $this->startDate;
+
+ }
+
+ /* Implementation of the Iterator interface {{{ */
+
+ function current() {
+
+ if (!$this->valid()) return;
+ return clone $this->currentDate;
+
+ }
+
+ /**
+ * Returns the current item number.
+ *
+ * @return int
+ */
+ function key() {
+
+ return $this->counter;
+
+ }
+
+ /**
+ * Returns whether the current item is a valid item for the recurrence
+ * iterator.
+ *
+ * @return bool
+ */
+ function valid() {
+
+ return ($this->counter <= count($this->dates));
+
+ }
+
+ /**
+ * Resets the iterator.
+ *
+ * @return void
+ */
+ function rewind() {
+
+ $this->currentDate = clone $this->startDate;
+ $this->counter = 0;
+
+ }
+
+ /**
+ * Goes on to the next iteration.
+ *
+ * @return void
+ */
+ function next() {
+
+ $this->counter++;
+ if (!$this->valid()) return;
+
+ $this->currentDate =
+ DateTimeParser::parse(
+ $this->dates[$this->counter - 1],
+ $this->startDate->getTimezone()
+ );
+
+ }
+
+ /* End of Iterator implementation }}} */
+
+ /**
+ * Returns true if this recurring event never ends.
+ *
+ * @return bool
+ */
+ function isInfinite() {
+
+ return false;
+
+ }
+
+ /**
+ * This method allows you to quickly go to the next occurrence after the
+ * specified date.
+ *
+ * @param DateTimeInterface $dt
+ *
+ * @return void
+ */
+ function fastForward(DateTimeInterface $dt) {
+
+ while ($this->valid() && $this->currentDate < $dt) {
+ $this->next();
+ }
+
+ }
+
+ /**
+ * The reference start date/time for the rrule.
+ *
+ * All calculations are based on this initial date.
+ *
+ * @var DateTimeInterface
+ */
+ protected $startDate;
+
+ /**
+ * The date of the current iteration. You can get this by calling
+ * ->current().
+ *
+ * @var DateTimeInterface
+ */
+ protected $currentDate;
+
+ /**
+ * The current item in the list.
+ *
+ * You can get this number with the key() method.
+ *
+ * @var int
+ */
+ protected $counter = 0;
+
+ /* }}} */
+
+ /**
+ * This method receives a string from an RRULE property, and populates this
+ * class with all the values.
+ *
+ * @param string|array $rrule
+ *
+ * @return void
+ */
+ protected function parseRDate($rdate) {
+
+ if (is_string($rdate)) {
+ $rdate = explode(',', $rdate);
+ }
+
+ $this->dates = $rdate;
+
+ }
+
+ /**
+ * Array with the RRULE dates
+ *
+ * @var array
+ */
+ protected $dates = [];
+
+}
diff --git a/vendor/sabre/vobject/lib/Recur/RRuleIterator.php b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php
new file mode 100644
index 000000000..402e2de83
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php
@@ -0,0 +1,921 @@
+<?php
+
+namespace Sabre\VObject\Recur;
+
+use DateTimeInterface;
+use DateTimeImmutable;
+use Iterator;
+use Sabre\VObject\DateTimeParser;
+use Sabre\VObject\InvalidDataException;
+use Sabre\VObject\Property;
+
+/**
+ * RRuleParser.
+ *
+ * This class receives an RRULE string, and allows you to iterate to get a list
+ * of dates in that recurrence.
+ *
+ * For instance, passing: FREQ=DAILY;LIMIT=5 will cause the iterator to contain
+ * 5 items, one for each day.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class RRuleIterator implements Iterator {
+
+ /**
+ * Creates the Iterator.
+ *
+ * @param string|array $rrule
+ * @param DateTimeInterface $start
+ */
+ function __construct($rrule, DateTimeInterface $start) {
+
+ $this->startDate = $start;
+ $this->parseRRule($rrule);
+ $this->currentDate = clone $this->startDate;
+
+ }
+
+ /* Implementation of the Iterator interface {{{ */
+
+ function current() {
+
+ if (!$this->valid()) return;
+ return clone $this->currentDate;
+
+ }
+
+ /**
+ * Returns the current item number.
+ *
+ * @return int
+ */
+ function key() {
+
+ return $this->counter;
+
+ }
+
+ /**
+ * Returns whether the current item is a valid item for the recurrence
+ * iterator. This will return false if we've gone beyond the UNTIL or COUNT
+ * statements.
+ *
+ * @return bool
+ */
+ function valid() {
+
+ if (!is_null($this->count)) {
+ return $this->counter < $this->count;
+ }
+ return is_null($this->until) || $this->currentDate <= $this->until;
+
+ }
+
+ /**
+ * Resets the iterator.
+ *
+ * @return void
+ */
+ function rewind() {
+
+ $this->currentDate = clone $this->startDate;
+ $this->counter = 0;
+
+ }
+
+ /**
+ * Goes on to the next iteration.
+ *
+ * @return void
+ */
+ function next() {
+
+ // Otherwise, we find the next event in the normal RRULE
+ // sequence.
+ switch ($this->frequency) {
+
+ case 'hourly' :
+ $this->nextHourly();
+ break;
+
+ case 'daily' :
+ $this->nextDaily();
+ break;
+
+ case 'weekly' :
+ $this->nextWeekly();
+ break;
+
+ case 'monthly' :
+ $this->nextMonthly();
+ break;
+
+ case 'yearly' :
+ $this->nextYearly();
+ break;
+
+ }
+ $this->counter++;
+
+ }
+
+ /* End of Iterator implementation }}} */
+
+ /**
+ * Returns true if this recurring event never ends.
+ *
+ * @return bool
+ */
+ function isInfinite() {
+
+ return !$this->count && !$this->until;
+
+ }
+
+ /**
+ * This method allows you to quickly go to the next occurrence after the
+ * specified date.
+ *
+ * @param DateTimeInterface $dt
+ *
+ * @return void
+ */
+ function fastForward(DateTimeInterface $dt) {
+
+ while ($this->valid() && $this->currentDate < $dt) {
+ $this->next();
+ }
+
+ }
+
+ /**
+ * The reference start date/time for the rrule.
+ *
+ * All calculations are based on this initial date.
+ *
+ * @var DateTimeInterface
+ */
+ protected $startDate;
+
+ /**
+ * The date of the current iteration. You can get this by calling
+ * ->current().
+ *
+ * @var DateTimeInterface
+ */
+ protected $currentDate;
+
+ /**
+ * Frequency is one of: secondly, minutely, hourly, daily, weekly, monthly,
+ * yearly.
+ *
+ * @var string
+ */
+ protected $frequency;
+
+ /**
+ * The number of recurrences, or 'null' if infinitely recurring.
+ *
+ * @var int
+ */
+ protected $count;
+
+ /**
+ * The interval.
+ *
+ * If for example frequency is set to daily, interval = 2 would mean every
+ * 2 days.
+ *
+ * @var int
+ */
+ protected $interval = 1;
+
+ /**
+ * The last instance of this recurrence, inclusively.
+ *
+ * @var DateTimeInterface|null
+ */
+ protected $until;
+
+ /**
+ * Which seconds to recur.
+ *
+ * This is an array of integers (between 0 and 60)
+ *
+ * @var array
+ */
+ protected $bySecond;
+
+ /**
+ * Which minutes to recur.
+ *
+ * This is an array of integers (between 0 and 59)
+ *
+ * @var array
+ */
+ protected $byMinute;
+
+ /**
+ * Which hours to recur.
+ *
+ * This is an array of integers (between 0 and 23)
+ *
+ * @var array
+ */
+ protected $byHour;
+
+ /**
+ * The current item in the list.
+ *
+ * You can get this number with the key() method.
+ *
+ * @var int
+ */
+ protected $counter = 0;
+
+ /**
+ * Which weekdays to recur.
+ *
+ * This is an array of weekdays
+ *
+ * This may also be preceeded by a positive or negative integer. If present,
+ * this indicates the nth occurrence of a specific day within the monthly or
+ * yearly rrule. For instance, -2TU indicates the second-last tuesday of
+ * the month, or year.
+ *
+ * @var array
+ */
+ protected $byDay;
+
+ /**
+ * Which days of the month to recur.
+ *
+ * This is an array of days of the months (1-31). The value can also be
+ * negative. -5 for instance means the 5th last day of the month.
+ *
+ * @var array
+ */
+ protected $byMonthDay;
+
+ /**
+ * Which days of the year to recur.
+ *
+ * This is an array with days of the year (1 to 366). The values can also
+ * be negative. For instance, -1 will always represent the last day of the
+ * year. (December 31st).
+ *
+ * @var array
+ */
+ protected $byYearDay;
+
+ /**
+ * Which week numbers to recur.
+ *
+ * This is an array of integers from 1 to 53. The values can also be
+ * negative. -1 will always refer to the last week of the year.
+ *
+ * @var array
+ */
+ protected $byWeekNo;
+
+ /**
+ * Which months to recur.
+ *
+ * This is an array of integers from 1 to 12.
+ *
+ * @var array
+ */
+ protected $byMonth;
+
+ /**
+ * Which items in an existing st to recur.
+ *
+ * These numbers work together with an existing by* rule. It specifies
+ * exactly which items of the existing by-rule to filter.
+ *
+ * Valid values are 1 to 366 and -1 to -366. As an example, this can be
+ * used to recur the last workday of the month.
+ *
+ * This would be done by setting frequency to 'monthly', byDay to
+ * 'MO,TU,WE,TH,FR' and bySetPos to -1.
+ *
+ * @var array
+ */
+ protected $bySetPos;
+
+ /**
+ * When the week starts.
+ *
+ * @var string
+ */
+ protected $weekStart = 'MO';
+
+ /* Functions that advance the iterator {{{ */
+
+ /**
+ * Does the processing for advancing the iterator for hourly frequency.
+ *
+ * @return void
+ */
+ protected function nextHourly() {
+
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' hours');
+
+ }
+
+ /**
+ * Does the processing for advancing the iterator for daily frequency.
+ *
+ * @return void
+ */
+ protected function nextDaily() {
+
+ if (!$this->byHour && !$this->byDay) {
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' days');
+ return;
+ }
+
+ if (!empty($this->byHour)) {
+ $recurrenceHours = $this->getHours();
+ }
+
+ if (!empty($this->byDay)) {
+ $recurrenceDays = $this->getDays();
+ }
+
+ if (!empty($this->byMonth)) {
+ $recurrenceMonths = $this->getMonths();
+ }
+
+ do {
+ if ($this->byHour) {
+ if ($this->currentDate->format('G') == '23') {
+ // to obey the interval rule
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval - 1 . ' days');
+ }
+
+ $this->currentDate = $this->currentDate->modify('+1 hours');
+
+ } else {
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' days');
+
+ }
+
+ // Current month of the year
+ $currentMonth = $this->currentDate->format('n');
+
+ // Current day of the week
+ $currentDay = $this->currentDate->format('w');
+
+ // Current hour of the day
+ $currentHour = $this->currentDate->format('G');
+
+ } while (
+ ($this->byDay && !in_array($currentDay, $recurrenceDays)) ||
+ ($this->byHour && !in_array($currentHour, $recurrenceHours)) ||
+ ($this->byMonth && !in_array($currentMonth, $recurrenceMonths))
+ );
+
+ }
+
+ /**
+ * Does the processing for advancing the iterator for weekly frequency.
+ *
+ * @return void
+ */
+ protected function nextWeekly() {
+
+ if (!$this->byHour && !$this->byDay) {
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' weeks');
+ return;
+ }
+
+ if ($this->byHour) {
+ $recurrenceHours = $this->getHours();
+ }
+
+ if ($this->byDay) {
+ $recurrenceDays = $this->getDays();
+ }
+
+ // First day of the week:
+ $firstDay = $this->dayMap[$this->weekStart];
+
+ do {
+
+ if ($this->byHour) {
+ $this->currentDate = $this->currentDate->modify('+1 hours');
+ } else {
+ $this->currentDate = $this->currentDate->modify('+1 days');
+ }
+
+ // Current day of the week
+ $currentDay = (int)$this->currentDate->format('w');
+
+ // Current hour of the day
+ $currentHour = (int)$this->currentDate->format('G');
+
+ // We need to roll over to the next week
+ if ($currentDay === $firstDay && (!$this->byHour || $currentHour == '0')) {
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval - 1 . ' weeks');
+
+ // We need to go to the first day of this week, but only if we
+ // are not already on this first day of this week.
+ if ($this->currentDate->format('w') != $firstDay) {
+ $this->currentDate = $this->currentDate->modify('last ' . $this->dayNames[$this->dayMap[$this->weekStart]]);
+ }
+ }
+
+ // We have a match
+ } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)));
+ }
+
+ /**
+ * Does the processing for advancing the iterator for monthly frequency.
+ *
+ * @return void
+ */
+ protected function nextMonthly() {
+
+ $currentDayOfMonth = $this->currentDate->format('j');
+ if (!$this->byMonthDay && !$this->byDay) {
+
+ // If the current day is higher than the 28th, rollover can
+ // occur to the next month. We Must skip these invalid
+ // entries.
+ if ($currentDayOfMonth < 29) {
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' months');
+ } else {
+ $increase = 0;
+ do {
+ $increase++;
+ $tempDate = clone $this->currentDate;
+ $tempDate = $tempDate->modify('+ ' . ($this->interval * $increase) . ' months');
+ } while ($tempDate->format('j') != $currentDayOfMonth);
+ $this->currentDate = $tempDate;
+ }
+ return;
+ }
+
+ while (true) {
+
+ $occurrences = $this->getMonthlyOccurrences();
+
+ foreach ($occurrences as $occurrence) {
+
+ // The first occurrence thats higher than the current
+ // day of the month wins.
+ if ($occurrence > $currentDayOfMonth) {
+ break 2;
+ }
+
+ }
+
+ // If we made it all the way here, it means there were no
+ // valid occurrences, and we need to advance to the next
+ // month.
+ //
+ // This line does not currently work in hhvm. Temporary workaround
+ // follows:
+ // $this->currentDate->modify('first day of this month');
+ $this->currentDate = new DateTimeImmutable($this->currentDate->format('Y-m-1 H:i:s'), $this->currentDate->getTimezone());
+ // end of workaround
+ $this->currentDate = $this->currentDate->modify('+ ' . $this->interval . ' months');
+
+ // This goes to 0 because we need to start counting at the
+ // beginning.
+ $currentDayOfMonth = 0;
+
+ }
+
+ $this->currentDate = $this->currentDate->setDate(
+ (int)$this->currentDate->format('Y'),
+ (int)$this->currentDate->format('n'),
+ (int)$occurrence
+ );
+
+ }
+
+ /**
+ * Does the processing for advancing the iterator for yearly frequency.
+ *
+ * @return void
+ */
+ protected function nextYearly() {
+
+ $currentMonth = $this->currentDate->format('n');
+ $currentYear = $this->currentDate->format('Y');
+ $currentDayOfMonth = $this->currentDate->format('j');
+
+ // No sub-rules, so we just advance by year
+ if (empty($this->byMonth)) {
+
+ // Unless it was a leap day!
+ if ($currentMonth == 2 && $currentDayOfMonth == 29) {
+
+ $counter = 0;
+ do {
+ $counter++;
+ // Here we increase the year count by the interval, until
+ // we hit a date that's also in a leap year.
+ //
+ // We could just find the next interval that's dividable by
+ // 4, but that would ignore the rule that there's no leap
+ // year every year that's dividable by a 100, but not by
+ // 400. (1800, 1900, 2100). So we just rely on the datetime
+ // functions instead.
+ $nextDate = clone $this->currentDate;
+ $nextDate = $nextDate->modify('+ ' . ($this->interval * $counter) . ' years');
+ } while ($nextDate->format('n') != 2);
+
+ $this->currentDate = $nextDate;
+
+ return;
+
+ }
+
+ // The easiest form
+ $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' years');
+ return;
+
+ }
+
+ $currentMonth = $this->currentDate->format('n');
+ $currentYear = $this->currentDate->format('Y');
+ $currentDayOfMonth = $this->currentDate->format('j');
+
+ $advancedToNewMonth = false;
+
+ // If we got a byDay or getMonthDay filter, we must first expand
+ // further.
+ if ($this->byDay || $this->byMonthDay) {
+
+ while (true) {
+
+ $occurrences = $this->getMonthlyOccurrences();
+
+ foreach ($occurrences as $occurrence) {
+
+ // The first occurrence that's higher than the current
+ // day of the month wins.
+ // If we advanced to the next month or year, the first
+ // occurrence is always correct.
+ if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) {
+ break 2;
+ }
+
+ }
+
+ // If we made it here, it means we need to advance to
+ // the next month or year.
+ $currentDayOfMonth = 1;
+ $advancedToNewMonth = true;
+ do {
+
+ $currentMonth++;
+ if ($currentMonth > 12) {
+ $currentYear += $this->interval;
+ $currentMonth = 1;
+ }
+ } while (!in_array($currentMonth, $this->byMonth));
+
+ $this->currentDate = $this->currentDate->setDate(
+ (int)$currentYear,
+ (int)$currentMonth,
+ (int)$currentDayOfMonth
+ );
+
+ }
+
+ // If we made it here, it means we got a valid occurrence
+ $this->currentDate = $this->currentDate->setDate(
+ (int)$currentYear,
+ (int)$currentMonth,
+ (int)$occurrence
+ );
+ return;
+
+ } else {
+
+ // These are the 'byMonth' rules, if there are no byDay or
+ // byMonthDay sub-rules.
+ do {
+
+ $currentMonth++;
+ if ($currentMonth > 12) {
+ $currentYear += $this->interval;
+ $currentMonth = 1;
+ }
+ } while (!in_array($currentMonth, $this->byMonth));
+ $this->currentDate = $this->currentDate->setDate(
+ (int)$currentYear,
+ (int)$currentMonth,
+ (int)$currentDayOfMonth
+ );
+
+ return;
+
+ }
+
+ }
+
+ /* }}} */
+
+ /**
+ * This method receives a string from an RRULE property, and populates this
+ * class with all the values.
+ *
+ * @param string|array $rrule
+ *
+ * @return void
+ */
+ protected function parseRRule($rrule) {
+
+ if (is_string($rrule)) {
+ $rrule = Property\ICalendar\Recur::stringToArray($rrule);
+ }
+
+ foreach ($rrule as $key => $value) {
+
+ $key = strtoupper($key);
+ switch ($key) {
+
+ case 'FREQ' :
+ $value = strtolower($value);
+ if (!in_array(
+ $value,
+ ['secondly', 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly']
+ )) {
+ throw new InvalidDataException('Unknown value for FREQ=' . strtoupper($value));
+ }
+ $this->frequency = $value;
+ break;
+
+ case 'UNTIL' :
+ $this->until = DateTimeParser::parse($value, $this->startDate->getTimezone());
+
+ // In some cases events are generated with an UNTIL=
+ // parameter before the actual start of the event.
+ //
+ // Not sure why this is happening. We assume that the
+ // intention was that the event only recurs once.
+ //
+ // So we are modifying the parameter so our code doesn't
+ // break.
+ if ($this->until < $this->startDate) {
+ $this->until = $this->startDate;
+ }
+ break;
+
+ case 'INTERVAL' :
+ // No break
+
+ case 'COUNT' :
+ $val = (int)$value;
+ if ($val < 1) {
+ throw new InvalidDataException(strtoupper($key) . ' in RRULE must be a positive integer!');
+ }
+ $key = strtolower($key);
+ $this->$key = $val;
+ break;
+
+ case 'BYSECOND' :
+ $this->bySecond = (array)$value;
+ break;
+
+ case 'BYMINUTE' :
+ $this->byMinute = (array)$value;
+ break;
+
+ case 'BYHOUR' :
+ $this->byHour = (array)$value;
+ break;
+
+ case 'BYDAY' :
+ $value = (array)$value;
+ foreach ($value as $part) {
+ if (!preg_match('#^ (-|\+)? ([1-5])? (MO|TU|WE|TH|FR|SA|SU) $# xi', $part)) {
+ throw new InvalidDataException('Invalid part in BYDAY clause: ' . $part);
+ }
+ }
+ $this->byDay = $value;
+ break;
+
+ case 'BYMONTHDAY' :
+ $this->byMonthDay = (array)$value;
+ break;
+
+ case 'BYYEARDAY' :
+ $this->byYearDay = (array)$value;
+ break;
+
+ case 'BYWEEKNO' :
+ $this->byWeekNo = (array)$value;
+ break;
+
+ case 'BYMONTH' :
+ $this->byMonth = (array)$value;
+ break;
+
+ case 'BYSETPOS' :
+ $this->bySetPos = (array)$value;
+ break;
+
+ case 'WKST' :
+ $this->weekStart = strtoupper($value);
+ break;
+
+ default:
+ throw new InvalidDataException('Not supported: ' . strtoupper($key));
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Mappings between the day number and english day name.
+ *
+ * @var array
+ */
+ protected $dayNames = [
+ 0 => 'Sunday',
+ 1 => 'Monday',
+ 2 => 'Tuesday',
+ 3 => 'Wednesday',
+ 4 => 'Thursday',
+ 5 => 'Friday',
+ 6 => 'Saturday',
+ ];
+
+ /**
+ * Returns all the occurrences for a monthly frequency with a 'byDay' or
+ * 'byMonthDay' expansion for the current month.
+ *
+ * The returned list is an array of integers with the day of month (1-31).
+ *
+ * @return array
+ */
+ protected function getMonthlyOccurrences() {
+
+ $startDate = clone $this->currentDate;
+
+ $byDayResults = [];
+
+ // Our strategy is to simply go through the byDays, advance the date to
+ // that point and add it to the results.
+ if ($this->byDay) foreach ($this->byDay as $day) {
+
+ $dayName = $this->dayNames[$this->dayMap[substr($day, -2)]];
+
+
+ // Dayname will be something like 'wednesday'. Now we need to find
+ // all wednesdays in this month.
+ $dayHits = [];
+
+ // workaround for missing 'first day of the month' support in hhvm
+ $checkDate = new \DateTime($startDate->format('Y-m-1'));
+ // workaround modify always advancing the date even if the current day is a $dayName in hhvm
+ if ($checkDate->format('l') !== $dayName) {
+ $checkDate = $checkDate->modify($dayName);
+ }
+
+ do {
+ $dayHits[] = $checkDate->format('j');
+ $checkDate = $checkDate->modify('next ' . $dayName);
+ } while ($checkDate->format('n') === $startDate->format('n'));
+
+ // So now we have 'all wednesdays' for month. It is however
+ // possible that the user only really wanted the 1st, 2nd or last
+ // wednesday.
+ if (strlen($day) > 2) {
+ $offset = (int)substr($day, 0, -2);
+
+ if ($offset > 0) {
+ // It is possible that the day does not exist, such as a
+ // 5th or 6th wednesday of the month.
+ if (isset($dayHits[$offset - 1])) {
+ $byDayResults[] = $dayHits[$offset - 1];
+ }
+ } else {
+
+ // if it was negative we count from the end of the array
+ // might not exist, fx. -5th tuesday
+ if (isset($dayHits[count($dayHits) + $offset])) {
+ $byDayResults[] = $dayHits[count($dayHits) + $offset];
+ }
+ }
+ } else {
+ // There was no counter (first, second, last wednesdays), so we
+ // just need to add the all to the list).
+ $byDayResults = array_merge($byDayResults, $dayHits);
+
+ }
+
+ }
+
+ $byMonthDayResults = [];
+ if ($this->byMonthDay) foreach ($this->byMonthDay as $monthDay) {
+
+ // Removing values that are out of range for this month
+ if ($monthDay > $startDate->format('t') ||
+ $monthDay < 0 - $startDate->format('t')) {
+ continue;
+ }
+ if ($monthDay > 0) {
+ $byMonthDayResults[] = $monthDay;
+ } else {
+ // Negative values
+ $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay;
+ }
+ }
+
+ // If there was just byDay or just byMonthDay, they just specify our
+ // (almost) final list. If both were provided, then byDay limits the
+ // list.
+ if ($this->byMonthDay && $this->byDay) {
+ $result = array_intersect($byMonthDayResults, $byDayResults);
+ } elseif ($this->byMonthDay) {
+ $result = $byMonthDayResults;
+ } else {
+ $result = $byDayResults;
+ }
+ $result = array_unique($result);
+ sort($result, SORT_NUMERIC);
+
+ // The last thing that needs checking is the BYSETPOS. If it's set, it
+ // means only certain items in the set survive the filter.
+ if (!$this->bySetPos) {
+ return $result;
+ }
+
+ $filteredResult = [];
+ foreach ($this->bySetPos as $setPos) {
+
+ if ($setPos < 0) {
+ $setPos = count($result) + ($setPos + 1);
+ }
+ if (isset($result[$setPos - 1])) {
+ $filteredResult[] = $result[$setPos - 1];
+ }
+ }
+
+ sort($filteredResult, SORT_NUMERIC);
+ return $filteredResult;
+
+ }
+
+ /**
+ * Simple mapping from iCalendar day names to day numbers.
+ *
+ * @var array
+ */
+ protected $dayMap = [
+ 'SU' => 0,
+ 'MO' => 1,
+ 'TU' => 2,
+ 'WE' => 3,
+ 'TH' => 4,
+ 'FR' => 5,
+ 'SA' => 6,
+ ];
+
+ protected function getHours() {
+
+ $recurrenceHours = [];
+ foreach ($this->byHour as $byHour) {
+ $recurrenceHours[] = $byHour;
+ }
+
+ return $recurrenceHours;
+ }
+
+ protected function getDays() {
+
+ $recurrenceDays = [];
+ foreach ($this->byDay as $byDay) {
+
+ // The day may be preceeded with a positive (+n) or
+ // negative (-n) integer. However, this does not make
+ // sense in 'weekly' so we ignore it here.
+ $recurrenceDays[] = $this->dayMap[substr($byDay, -2)];
+
+ }
+
+ return $recurrenceDays;
+ }
+
+ protected function getMonths() {
+
+ $recurrenceMonths = [];
+ foreach ($this->byMonth as $byMonth) {
+ $recurrenceMonths[] = $byMonth;
+ }
+
+ return $recurrenceMonths;
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component.php b/vendor/sabre/vobject/lib/Sabre/VObject/Component.php
deleted file mode 100644
index 1c1d92444..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component.php
+++ /dev/null
@@ -1,405 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * VObject Component
- *
- * This class represents a VCALENDAR/VCARD component. A component is for example
- * VEVENT, VTODO and also VCALENDAR. It starts with BEGIN:COMPONENTNAME and
- * ends with END:COMPONENTNAME
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class Component extends Node {
-
- /**
- * Name, for example VEVENT
- *
- * @var string
- */
- public $name;
-
- /**
- * Children properties and components
- *
- * @var array
- */
- public $children = array();
-
- /**
- * If components are added to this map, they will be automatically mapped
- * to their respective classes, if parsed by the reader or constructed with
- * the 'create' method.
- *
- * @var array
- */
- static public $classMap = array(
- 'VALARM' => 'Sabre\\VObject\\Component\\VAlarm',
- 'VCALENDAR' => 'Sabre\\VObject\\Component\\VCalendar',
- 'VCARD' => 'Sabre\\VObject\\Component\\VCard',
- 'VEVENT' => 'Sabre\\VObject\\Component\\VEvent',
- 'VJOURNAL' => 'Sabre\\VObject\\Component\\VJournal',
- 'VTODO' => 'Sabre\\VObject\\Component\\VTodo',
- 'VFREEBUSY' => 'Sabre\\VObject\\Component\\VFreeBusy',
- );
-
- /**
- * Creates the new component by name, but in addition will also see if
- * there's a class mapped to the property name.
- *
- * @param string $name
- * @param string $value
- * @return Component
- */
- static public function create($name, $value = null) {
-
- $name = strtoupper($name);
-
- if (isset(self::$classMap[$name])) {
- return new self::$classMap[$name]($name, $value);
- } else {
- return new self($name, $value);
- }
-
- }
-
- /**
- * Creates a new component.
- *
- * By default this object will iterate over its own children, but this can
- * be overridden with the iterator argument
- *
- * @param string $name
- * @param ElementList $iterator
- */
- public function __construct($name, ElementList $iterator = null) {
-
- $this->name = strtoupper($name);
- if (!is_null($iterator)) $this->iterator = $iterator;
-
- }
-
- /**
- * Turns the object back into a serialized blob.
- *
- * @return string
- */
- public function serialize() {
-
- $str = "BEGIN:" . $this->name . "\r\n";
-
- /**
- * Gives a component a 'score' for sorting purposes.
- *
- * This is solely used by the childrenSort method.
- *
- * A higher score means the item will be lower in the list.
- * To avoid score collisions, each "score category" has a reasonable
- * space to accomodate elements. The $key is added to the $score to
- * preserve the original relative order of elements.
- *
- * @param int $key
- * @param array $array
- * @return int
- */
- $sortScore = function($key, $array) {
-
- if ($array[$key] instanceof Component) {
-
- // We want to encode VTIMEZONE first, this is a personal
- // preference.
- if ($array[$key]->name === 'VTIMEZONE') {
- $score=300000000;
- return $score+$key;
- } else {
- $score=400000000;
- return $score+$key;
- }
- } else {
- // Properties get encoded first
- // VCARD version 4.0 wants the VERSION property to appear first
- if ($array[$key] instanceof Property) {
- if ($array[$key]->name === 'VERSION') {
- $score=100000000;
- return $score+$key;
- } else {
- // All other properties
- $score=200000000;
- return $score+$key;
- }
- }
- }
-
- };
-
- $tmp = $this->children;
- uksort($this->children, function($a, $b) use ($sortScore, $tmp) {
-
- $sA = $sortScore($a, $tmp);
- $sB = $sortScore($b, $tmp);
-
- if ($sA === $sB) return 0;
-
- return ($sA < $sB) ? -1 : 1;
-
- });
-
- foreach($this->children as $child) $str.=$child->serialize();
- $str.= "END:" . $this->name . "\r\n";
-
- return $str;
-
- }
-
- /**
- * Adds a new component or element
- *
- * You can call this method with the following syntaxes:
- *
- * add(Node $node)
- * add(string $name, $value, array $parameters = array())
- *
- * The first version adds an Element
- * The second adds a property as a string.
- *
- * @param mixed $item
- * @param mixed $itemValue
- * @return void
- */
- public function add($item, $itemValue = null, array $parameters = array()) {
-
- if ($item instanceof Node) {
- if (!is_null($itemValue)) {
- throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject Node');
- }
- $item->parent = $this;
- $this->children[] = $item;
- } elseif(is_string($item)) {
-
- $item = Property::create($item,$itemValue, $parameters);
- $item->parent = $this;
- $this->children[] = $item;
-
- } else {
-
- throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Node or a string');
-
- }
-
- }
-
- /**
- * Returns an iterable list of children
- *
- * @return ElementList
- */
- public function children() {
-
- return new ElementList($this->children);
-
- }
-
- /**
- * Returns an array with elements that match the specified name.
- *
- * This function is also aware of MIME-Directory groups (as they appear in
- * vcards). This means that if a property is grouped as "HOME.EMAIL", it
- * will also be returned when searching for just "EMAIL". If you want to
- * search for a property in a specific group, you can select on the entire
- * string ("HOME.EMAIL"). If you want to search on a specific property that
- * has not been assigned a group, specify ".EMAIL".
- *
- * Keys are retained from the 'children' array, which may be confusing in
- * certain cases.
- *
- * @param string $name
- * @return array
- */
- public function select($name) {
-
- $group = null;
- $name = strtoupper($name);
- if (strpos($name,'.')!==false) {
- list($group,$name) = explode('.', $name, 2);
- }
-
- $result = array();
- foreach($this->children as $key=>$child) {
-
- if (
- strtoupper($child->name) === $name &&
- (is_null($group) || ( $child instanceof Property && strtoupper($child->group) === $group))
- ) {
-
- $result[$key] = $child;
-
- }
- }
-
- reset($result);
- return $result;
-
- }
-
- /**
- * This method only returns a list of sub-components. Properties are
- * ignored.
- *
- * @return array
- */
- public function getComponents() {
-
- $result = array();
- foreach($this->children as $child) {
- if ($child instanceof Component) {
- $result[] = $child;
- }
- }
-
- return $result;
-
- }
-
- /**
- * Validates the node for correctness.
- *
- * The following options are supported:
- * - Node::REPAIR - If something is broken, and automatic repair may
- * be attempted.
- *
- * An array is returned with warnings.
- *
- * Every item in the array has the following properties:
- * * level - (number between 1 and 3 with severity information)
- * * message - (human readable message)
- * * node - (reference to the offending node)
- *
- * @param int $options
- * @return array
- */
- public function validate($options = 0) {
-
- $result = array();
- foreach($this->children as $child) {
- $result = array_merge($result, $child->validate($options));
- }
- return $result;
-
- }
-
- /* Magic property accessors {{{ */
-
- /**
- * Using 'get' you will either get a property or component,
- *
- * If there were no child-elements found with the specified name,
- * null is returned.
- *
- * @param string $name
- * @return Property
- */
- public function __get($name) {
-
- $matches = $this->select($name);
- if (count($matches)===0) {
- return null;
- } else {
- $firstMatch = current($matches);
- /** @var $firstMatch Property */
- $firstMatch->setIterator(new ElementList(array_values($matches)));
- return $firstMatch;
- }
-
- }
-
- /**
- * This method checks if a sub-element with the specified name exists.
- *
- * @param string $name
- * @return bool
- */
- public function __isset($name) {
-
- $matches = $this->select($name);
- return count($matches)>0;
-
- }
-
- /**
- * Using the setter method you can add properties or subcomponents
- *
- * You can either pass a Component, Property
- * object, or a string to automatically create a Property.
- *
- * If the item already exists, it will be removed. If you want to add
- * a new item with the same name, always use the add() method.
- *
- * @param string $name
- * @param mixed $value
- * @return void
- */
- public function __set($name, $value) {
-
- $matches = $this->select($name);
- $overWrite = count($matches)?key($matches):null;
-
- if ($value instanceof Component || $value instanceof Property) {
- $value->parent = $this;
- if (!is_null($overWrite)) {
- $this->children[$overWrite] = $value;
- } else {
- $this->children[] = $value;
- }
- } elseif (is_scalar($value)) {
- $property = Property::create($name,$value);
- $property->parent = $this;
- if (!is_null($overWrite)) {
- $this->children[$overWrite] = $property;
- } else {
- $this->children[] = $property;
- }
- } else {
- throw new \InvalidArgumentException('You must pass a \\Sabre\\VObject\\Component, \\Sabre\\VObject\\Property or scalar type');
- }
-
- }
-
- /**
- * Removes all properties and components within this component.
- *
- * @param string $name
- * @return void
- */
- public function __unset($name) {
-
- $matches = $this->select($name);
- foreach($matches as $k=>$child) {
-
- unset($this->children[$k]);
- $child->parent = null;
-
- }
-
- }
-
- /* }}} */
-
- /**
- * This method is automatically called when the object is cloned.
- * Specifically, this will ensure all child elements are also cloned.
- *
- * @return void
- */
- public function __clone() {
-
- foreach($this->children as $key=>$child) {
- $this->children[$key] = clone $child;
- $this->children[$key]->parent = $this;
- }
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCalendar.php b/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCalendar.php
deleted file mode 100644
index 9de67982e..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCalendar.php
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-/**
- * The VCalendar component
- *
- * This component adds functionality to a component, specific for a VCALENDAR.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class VCalendar extends VObject\Document {
-
- static $defaultName = 'VCALENDAR';
-
- /**
- * Returns a list of all 'base components'. For instance, if an Event has
- * a recurrence rule, and one instance is overridden, the overridden event
- * will have the same UID, but will be excluded from this list.
- *
- * VTIMEZONE components will always be excluded.
- *
- * @param string $componentName filter by component name
- * @return array
- */
- public function getBaseComponents($componentName = null) {
-
- $components = array();
- foreach($this->children as $component) {
-
- if (!$component instanceof VObject\Component)
- continue;
-
- if (isset($component->{'RECURRENCE-ID'}))
- continue;
-
- if ($componentName && $component->name !== strtoupper($componentName))
- continue;
-
- if ($component->name === 'VTIMEZONE')
- continue;
-
- $components[] = $component;
-
- }
-
- return $components;
-
- }
-
- /**
- * If this calendar object, has events with recurrence rules, this method
- * can be used to expand the event into multiple sub-events.
- *
- * Each event will be stripped from it's recurrence information, and only
- * the instances of the event in the specified timerange will be left
- * alone.
- *
- * In addition, this method will cause timezone information to be stripped,
- * and normalized to UTC.
- *
- * This method will alter the VCalendar. This cannot be reversed.
- *
- * This functionality is specifically used by the CalDAV standard. It is
- * possible for clients to request expand events, if they are rather simple
- * clients and do not have the possibility to calculate recurrences.
- *
- * @param DateTime $start
- * @param DateTime $end
- * @return void
- */
- public function expand(\DateTime $start, \DateTime $end) {
-
- $newEvents = array();
-
- foreach($this->select('VEVENT') as $key=>$vevent) {
-
- if (isset($vevent->{'RECURRENCE-ID'})) {
- unset($this->children[$key]);
- continue;
- }
-
-
- if (!$vevent->rrule) {
- unset($this->children[$key]);
- if ($vevent->isInTimeRange($start, $end)) {
- $newEvents[] = $vevent;
- }
- continue;
- }
-
- $uid = (string)$vevent->uid;
- if (!$uid) {
- throw new \LogicException('Event did not have a UID!');
- }
-
- $it = new VObject\RecurrenceIterator($this, $vevent->uid);
- $it->fastForward($start);
-
- while($it->valid() && $it->getDTStart() < $end) {
-
- if ($it->getDTEnd() > $start) {
-
- $newEvents[] = $it->getEventObject();
-
- }
- $it->next();
-
- }
- unset($this->children[$key]);
-
- }
-
- foreach($newEvents as $newEvent) {
-
- foreach($newEvent->children as $child) {
- if ($child instanceof VObject\Property\DateTime &&
- $child->getDateType() == VObject\Property\DateTime::LOCALTZ) {
- $child->setDateTime($child->getDateTime(),VObject\Property\DateTime::UTC);
- }
- }
-
- $this->add($newEvent);
-
- }
-
- // Removing all VTIMEZONE components
- unset($this->VTIMEZONE);
-
- }
-
- /**
- * Validates the node for correctness.
- * An array is returned with warnings.
- *
- * Every item in the array has the following properties:
- * * level - (number between 1 and 3 with severity information)
- * * message - (human readable message)
- * * node - (reference to the offending node)
- *
- * @return array
- */
- /*
- public function validate() {
-
- $warnings = array();
-
- $version = $this->select('VERSION');
- if (count($version)!==1) {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
- 'node' => $this,
- );
- } else {
- if ((string)$this->VERSION !== '2.0') {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
- 'node' => $this,
- );
- }
- }
- $version = $this->select('PRODID');
- if (count($version)!==1) {
- $warnings[] = array(
- 'level' => 2,
- 'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
- 'node' => $this,
- );
- }
- if (count($this->CALSCALE) > 1) {
- $warnings[] = array(
- 'level' => 2,
- 'message' => 'The CALSCALE property must not be specified more than once.',
- 'node' => $this,
- );
- }
- if (count($this->METHOD) > 1) {
- $warnings[] = array(
- 'level' => 2,
- 'message' => 'The METHOD property must not be specified more than once.',
- 'node' => $this,
- );
- }
-
- $allowedComponents = array(
- 'VEVENT',
- 'VTODO',
- 'VJOURNAL',
- 'VFREEBUSY',
- 'VTIMEZONE',
- );
- $allowedProperties = array(
- 'PRODID',
- 'VERSION',
- 'CALSCALE',
- 'METHOD',
- );
- $componentsFound = 0;
- foreach($this->children as $child) {
- if($child instanceof Component) {
- $componentsFound++;
- if (!in_array($child->name, $allowedComponents)) {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
- 'node' => $this,
- );
- }
- }
- if ($child instanceof Property) {
- if (!in_array($child->name, $allowedProperties)) {
- $warnings[] = array(
- 'level' => 2,
- 'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
- 'node' => $this,
- );
- }
- }
- }
-
- if ($componentsFound===0) {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'An iCalendar object must have at least 1 component.',
- 'node' => $this,
- );
- }
-
- return array_merge(
- $warnings,
- parent::validate()
- );
-
- }
- */
-
-}
-
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCard.php b/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCard.php
deleted file mode 100644
index 0fc8b7020..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCard.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-/**
- * The VCard component
- *
- * This component represents the BEGIN:VCARD and END:VCARD found in every
- * vcard.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class VCard extends VObject\Component {
-
- static $defaultName = 'VCARD';
-
- /**
- * VCards with version 2.1, 3.0 and 4.0 are found.
- *
- * If the VCARD doesn't know its version, 4.0 is assumed.
- */
- const DEFAULT_VERSION = '4.0';
-
- /**
- * Validates the node for correctness.
- *
- * The following options are supported:
- * - Node::REPAIR - If something is broken, and automatic repair may
- * be attempted.
- *
- * An array is returned with warnings.
- *
- * Every item in the array has the following properties:
- * * level - (number between 1 and 3 with severity information)
- * * message - (human readable message)
- * * node - (reference to the offending node)
- *
- * @param int $options
- * @return array
- */
- public function validate($options = 0) {
-
- $warnings = array();
-
- $version = $this->select('VERSION');
- if (count($version)!==1) {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'The VERSION property must appear in the VCARD component exactly 1 time',
- 'node' => $this,
- );
- if ($options & self::REPAIR) {
- $this->VERSION = self::DEFAULT_VERSION;
- }
- } else {
- $version = (string)$this->VERSION;
- if ($version!=='2.1' && $version!=='3.0' && $version!=='4.0') {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
- 'node' => $this,
- );
- if ($options & self::REPAIR) {
- $this->VERSION = '4.0';
- }
- }
-
- }
- $fn = $this->select('FN');
- if (count($fn)!==1) {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'The FN property must appear in the VCARD component exactly 1 time',
- 'node' => $this,
- );
- if (($options & self::REPAIR) && count($fn) === 0) {
- // We're going to try to see if we can use the contents of the
- // N property.
- if (isset($this->N)) {
- $value = explode(';', (string)$this->N);
- if (isset($value[1]) && $value[1]) {
- $this->FN = $value[1] . ' ' . $value[0];
- } else {
- $this->FN = $value[0];
- }
-
- // Otherwise, the ORG property may work
- } elseif (isset($this->ORG)) {
- $this->FN = (string)$this->ORG;
- }
-
- }
- }
-
- return array_merge(
- parent::validate($options),
- $warnings
- );
-
- }
-
-}
-
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VEvent.php b/vendor/sabre/vobject/lib/Sabre/VObject/Component/VEvent.php
deleted file mode 100644
index 2375c5317..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VEvent.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-use Sabre\VObject;
-
-/**
- * VEvent component
- *
- * This component contains some additional functionality specific for VEVENT's.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class VEvent extends VObject\Component {
-
- /**
- * Returns true or false depending on if the event falls in the specified
- * time-range. This is used for filtering purposes.
- *
- * The rules used to determine if an event falls within the specified
- * time-range is based on the CalDAV specification.
- *
- * @param \DateTime $start
- * @param \DateTime $end
- * @return bool
- */
- public function isInTimeRange(\DateTime $start, \DateTime $end) {
-
- if ($this->RRULE) {
- $it = new VObject\RecurrenceIterator($this);
- $it->fastForward($start);
-
- // We fast-forwarded to a spot where the end-time of the
- // recurrence instance exceeded the start of the requested
- // time-range.
- //
- // If the starttime of the recurrence did not exceed the
- // end of the time range as well, we have a match.
- return ($it->getDTStart() < $end && $it->getDTEnd() > $start);
-
- }
-
- $effectiveStart = $this->DTSTART->getDateTime();
- if (isset($this->DTEND)) {
-
- // The DTEND property is considered non inclusive. So for a 3 day
- // event in july, dtstart and dtend would have to be July 1st and
- // July 4th respectively.
- //
- // See:
- // http://tools.ietf.org/html/rfc5545#page-54
- $effectiveEnd = $this->DTEND->getDateTime();
-
- } elseif (isset($this->DURATION)) {
- $effectiveEnd = clone $effectiveStart;
- $effectiveEnd->add( VObject\DateTimeParser::parseDuration($this->DURATION) );
- } elseif ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) {
- $effectiveEnd = clone $effectiveStart;
- $effectiveEnd->modify('+1 day');
- } else {
- $effectiveEnd = clone $effectiveStart;
- }
- return (
- ($start <= $effectiveEnd) && ($end > $effectiveStart)
- );
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VFreeBusy.php b/vendor/sabre/vobject/lib/Sabre/VObject/Component/VFreeBusy.php
deleted file mode 100644
index 7afe9fdb3..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VFreeBusy.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-/**
- * The VFreeBusy component
- *
- * This component adds functionality to a component, specific for VFREEBUSY
- * components.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class VFreeBusy extends VObject\Component {
-
- /**
- * Checks based on the contained FREEBUSY information, if a timeslot is
- * available.
- *
- * @param DateTime $start
- * @param Datetime $end
- * @return bool
- */
- public function isFree(\DateTime $start, \Datetime $end) {
-
- foreach($this->select('FREEBUSY') as $freebusy) {
-
- // We are only interested in FBTYPE=BUSY (the default),
- // FBTYPE=BUSY-TENTATIVE or FBTYPE=BUSY-UNAVAILABLE.
- if (isset($freebusy['FBTYPE']) && strtoupper(substr((string)$freebusy['FBTYPE'],0,4))!=='BUSY') {
- continue;
- }
-
- // The freebusy component can hold more than 1 value, separated by
- // commas.
- $periods = explode(',', (string)$freebusy);
-
- foreach($periods as $period) {
- // Every period is formatted as [start]/[end]. The start is an
- // absolute UTC time, the end may be an absolute UTC time, or
- // duration (relative) value.
- list($busyStart, $busyEnd) = explode('/', $period);
-
- $busyStart = VObject\DateTimeParser::parse($busyStart);
- $busyEnd = VObject\DateTimeParser::parse($busyEnd);
- if ($busyEnd instanceof \DateInterval) {
- $tmp = clone $busyStart;
- $tmp->add($busyEnd);
- $busyEnd = $tmp;
- }
-
- if($start < $busyEnd && $end > $busyStart) {
- return false;
- }
-
- }
-
- }
-
- return true;
-
- }
-
-}
-
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VJournal.php b/vendor/sabre/vobject/lib/Sabre/VObject/Component/VJournal.php
deleted file mode 100644
index 232887879..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VJournal.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-/**
- * VJournal component
- *
- * This component contains some additional functionality specific for VJOURNALs.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class VJournal extends VObject\Component {
-
- /**
- * Returns true or false depending on if the event falls in the specified
- * time-range. This is used for filtering purposes.
- *
- * The rules used to determine if an event falls within the specified
- * time-range is based on the CalDAV specification.
- *
- * @param DateTime $start
- * @param DateTime $end
- * @return bool
- */
- public function isInTimeRange(\DateTime $start, \DateTime $end) {
-
- $dtstart = isset($this->DTSTART)?$this->DTSTART->getDateTime():null;
- if ($dtstart) {
- $effectiveEnd = clone $dtstart;
- if ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) {
- $effectiveEnd->modify('+1 day');
- }
-
- return ($start <= $effectiveEnd && $end > $dtstart);
-
- }
- return false;
-
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VTodo.php b/vendor/sabre/vobject/lib/Sabre/VObject/Component/VTodo.php
deleted file mode 100644
index b1579cf74..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Component/VTodo.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-/**
- * VTodo component
- *
- * This component contains some additional functionality specific for VTODOs.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class VTodo extends VObject\Component {
-
- /**
- * Returns true or false depending on if the event falls in the specified
- * time-range. This is used for filtering purposes.
- *
- * The rules used to determine if an event falls within the specified
- * time-range is based on the CalDAV specification.
- *
- * @param DateTime $start
- * @param DateTime $end
- * @return bool
- */
- public function isInTimeRange(\DateTime $start, \DateTime $end) {
-
- $dtstart = isset($this->DTSTART)?$this->DTSTART->getDateTime():null;
- $duration = isset($this->DURATION)?VObject\DateTimeParser::parseDuration($this->DURATION):null;
- $due = isset($this->DUE)?$this->DUE->getDateTime():null;
- $completed = isset($this->COMPLETED)?$this->COMPLETED->getDateTime():null;
- $created = isset($this->CREATED)?$this->CREATED->getDateTime():null;
-
- if ($dtstart) {
- if ($duration) {
- $effectiveEnd = clone $dtstart;
- $effectiveEnd->add($duration);
- return $start <= $effectiveEnd && $end > $dtstart;
- } elseif ($due) {
- return
- ($start < $due || $start <= $dtstart) &&
- ($end > $dtstart || $end >= $due);
- } else {
- return $start <= $dtstart && $end > $dtstart;
- }
- }
- if ($due) {
- return ($start < $due && $end >= $due);
- }
- if ($completed && $created) {
- return
- ($start <= $created || $start <= $completed) &&
- ($end >= $created || $end >= $completed);
- }
- if ($completed) {
- return ($start <= $completed && $end >= $completed);
- }
- if ($created) {
- return ($end > $created);
- }
- return true;
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/DateTimeParser.php b/vendor/sabre/vobject/lib/Sabre/VObject/DateTimeParser.php
deleted file mode 100644
index 03600506d..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/DateTimeParser.php
+++ /dev/null
@@ -1,181 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * DateTimeParser
- *
- * This class is responsible for parsing the several different date and time
- * formats iCalendar and vCards have.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class DateTimeParser {
-
- /**
- * Parses an iCalendar (rfc5545) formatted datetime and returns a DateTime object
- *
- * Specifying a reference timezone is optional. It will only be used
- * if the non-UTC format is used. The argument is used as a reference, the
- * returned DateTime object will still be in the UTC timezone.
- *
- * @param string $dt
- * @param DateTimeZone $tz
- * @return DateTime
- */
- static public function parseDateTime($dt,\DateTimeZone $tz = null) {
-
- // Format is YYYYMMDD + "T" + hhmmss
- $result = preg_match('/^([1-4][0-9]{3})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/',$dt,$matches);
-
- if (!$result) {
- throw new \LogicException('The supplied iCalendar datetime value is incorrect: ' . $dt);
- }
-
- if ($matches[7]==='Z' || is_null($tz)) {
- $tz = new \DateTimeZone('UTC');
- }
- $date = new \DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] .':' . $matches[6], $tz);
-
- // Still resetting the timezone, to normalize everything to UTC
- $date->setTimeZone(new \DateTimeZone('UTC'));
- return $date;
-
- }
-
- /**
- * Parses an iCalendar (rfc5545) formatted date and returns a DateTime object
- *
- * @param string $date
- * @return DateTime
- */
- static public function parseDate($date) {
-
- // Format is YYYYMMDD
- $result = preg_match('/^([1-4][0-9]{3})([0-1][0-9])([0-3][0-9])$/',$date,$matches);
-
- if (!$result) {
- throw new \LogicException('The supplied iCalendar date value is incorrect: ' . $date);
- }
-
- $date = new \DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3], new \DateTimeZone('UTC'));
- return $date;
-
- }
-
- /**
- * Parses an iCalendar (RFC5545) formatted duration value.
- *
- * This method will either return a DateTimeInterval object, or a string
- * suitable for strtotime or DateTime::modify.
- *
- * @param string $duration
- * @param bool $asString
- * @return DateInterval|string
- */
- static public function parseDuration($duration, $asString = false) {
-
- $result = preg_match('/^(?P<plusminus>\+|-)?P((?P<week>\d+)W)?((?P<day>\d+)D)?(T((?P<hour>\d+)H)?((?P<minute>\d+)M)?((?P<second>\d+)S)?)?$/', $duration, $matches);
- if (!$result) {
- throw new \LogicException('The supplied iCalendar duration value is incorrect: ' . $duration);
- }
-
- if (!$asString) {
- $invert = false;
- if ($matches['plusminus']==='-') {
- $invert = true;
- }
-
-
- $parts = array(
- 'week',
- 'day',
- 'hour',
- 'minute',
- 'second',
- );
- foreach($parts as $part) {
- $matches[$part] = isset($matches[$part])&&$matches[$part]?(int)$matches[$part]:0;
- }
-
-
- // We need to re-construct the $duration string, because weeks and
- // days are not supported by DateInterval in the same string.
- $duration = 'P';
- $days = $matches['day'];
- if ($matches['week']) {
- $days+=$matches['week']*7;
- }
- if ($days)
- $duration.=$days . 'D';
-
- if ($matches['minute'] || $matches['second'] || $matches['hour']) {
- $duration.='T';
-
- if ($matches['hour'])
- $duration.=$matches['hour'].'H';
-
- if ($matches['minute'])
- $duration.=$matches['minute'].'M';
-
- if ($matches['second'])
- $duration.=$matches['second'].'S';
-
- }
-
- if ($duration==='P') {
- $duration = 'PT0S';
- }
- $iv = new \DateInterval($duration);
- if ($invert) $iv->invert = true;
-
- return $iv;
-
- }
-
-
-
- $parts = array(
- 'week',
- 'day',
- 'hour',
- 'minute',
- 'second',
- );
-
- $newDur = '';
- foreach($parts as $part) {
- if (isset($matches[$part]) && $matches[$part]) {
- $newDur.=' '.$matches[$part] . ' ' . $part . 's';
- }
- }
-
- $newDur = ($matches['plusminus']==='-'?'-':'+') . trim($newDur);
- if ($newDur === '+') { $newDur = '+0 seconds'; };
- return $newDur;
-
- }
-
- /**
- * Parses either a Date or DateTime, or Duration value.
- *
- * @param string $date
- * @param DateTimeZone|string $referenceTZ
- * @return DateTime|DateInterval
- */
- static public function parse($date, $referenceTZ = null) {
-
- if ($date[0]==='P' || ($date[0]==='-' && $date[1]==='P')) {
- return self::parseDuration($date);
- } elseif (strlen($date)===8) {
- return self::parseDate($date);
- } else {
- return self::parseDateTime($date, $referenceTZ);
- }
-
- }
-
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Document.php b/vendor/sabre/vobject/lib/Sabre/VObject/Document.php
deleted file mode 100644
index 50a662ee9..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Document.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * Document
- *
- * A document is just like a component, except that it's also the top level
- * element.
- *
- * Both a VCALENDAR and a VCARD are considered documents.
- *
- * This class also provides a registry for document types.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-abstract class Document extends Component {
-
- /**
- * The default name for this component.
- *
- * This should be 'VCALENDAR' or 'VCARD'.
- *
- * @var string
- */
- static $defaultName;
-
- /**
- * Creates a new document.
- *
- * We're changing the default behavior slightly here. First, we don't want
- * to have to specify a name (we already know it), and we want to allow
- * children to be specified in the first argument.
- *
- * But, the default behavior also works.
- *
- * So the two sigs:
- *
- * new Document(array $children = array());
- * new Document(string $name, array $children = array())
- *
- * @return void
- */
- public function __construct() {
-
- $args = func_get_args();
- if (count($args)===0 || is_array($args[0])) {
- array_unshift($args, static::$defaultName);
- call_user_func_array(array('parent', '__construct'), $args);
- } else {
- call_user_func_array(array('parent', '__construct'), $args);
- }
-
- }
-
- /**
- * Creates a new component
- *
- * This method automatically searches for the correct component class, based
- * on its name.
- *
- * You can specify the children either in key=>value syntax, in which case
- * properties will automatically be created, or you can just pass a list of
- * Component and Property object.
- *
- * @param string $name
- * @param array $children
- * @return Component
- */
- public function createComponent($name, array $children = array()) {
-
- $component = Component::create($name);
- foreach($children as $k=>$v) {
-
- if ($v instanceof Node) {
- $component->add($v);
- } else {
- $component->add($k, $v);
- }
-
- }
- return $component;
-
- }
-
- /**
- * Factory method for creating new properties
- *
- * This method automatically searches for the correct property class, based
- * on its name.
- *
- * You can specify the parameters either in key=>value syntax, in which case
- * parameters will automatically be created, or you can just pass a list of
- * Parameter objects.
- *
- * @param string $name
- * @param mixed $value
- * @param array $parameters
- * @return Property
- */
- public function createProperty($name, $value = null, array $parameters = array()) {
-
- return Property::create($name, $value, $parameters);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/ElementList.php b/vendor/sabre/vobject/lib/Sabre/VObject/ElementList.php
deleted file mode 100644
index 1c203708e..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/ElementList.php
+++ /dev/null
@@ -1,172 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * VObject ElementList
- *
- * This class represents a list of elements. Lists are the result of queries,
- * such as doing $vcalendar->vevent where there's multiple VEVENT objects.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class ElementList implements \Iterator, \Countable, \ArrayAccess {
-
- /**
- * Inner elements
- *
- * @var array
- */
- protected $elements = array();
-
- /**
- * Creates the element list.
- *
- * @param array $elements
- */
- public function __construct(array $elements) {
-
- $this->elements = $elements;
-
- }
-
- /* {{{ Iterator interface */
-
- /**
- * Current position
- *
- * @var int
- */
- private $key = 0;
-
- /**
- * Returns current item in iteration
- *
- * @return Element
- */
- public function current() {
-
- return $this->elements[$this->key];
-
- }
-
- /**
- * To the next item in the iterator
- *
- * @return void
- */
- public function next() {
-
- $this->key++;
-
- }
-
- /**
- * Returns the current iterator key
- *
- * @return int
- */
- public function key() {
-
- return $this->key;
-
- }
-
- /**
- * Returns true if the current position in the iterator is a valid one
- *
- * @return bool
- */
- public function valid() {
-
- return isset($this->elements[$this->key]);
-
- }
-
- /**
- * Rewinds the iterator
- *
- * @return void
- */
- public function rewind() {
-
- $this->key = 0;
-
- }
-
- /* }}} */
-
- /* {{{ Countable interface */
-
- /**
- * Returns the number of elements
- *
- * @return int
- */
- public function count() {
-
- return count($this->elements);
-
- }
-
- /* }}} */
-
- /* {{{ ArrayAccess Interface */
-
-
- /**
- * Checks if an item exists through ArrayAccess.
- *
- * @param int $offset
- * @return bool
- */
- public function offsetExists($offset) {
-
- return isset($this->elements[$offset]);
-
- }
-
- /**
- * Gets an item through ArrayAccess.
- *
- * @param int $offset
- * @return mixed
- */
- public function offsetGet($offset) {
-
- return $this->elements[$offset];
-
- }
-
- /**
- * Sets an item through ArrayAccess.
- *
- * @param int $offset
- * @param mixed $value
- * @return void
- */
- public function offsetSet($offset,$value) {
-
- throw new \LogicException('You can not add new objects to an ElementList');
-
- }
-
- /**
- * Sets an item through ArrayAccess.
- *
- * This method just forwards the request to the inner iterator
- *
- * @param int $offset
- * @return void
- */
- public function offsetUnset($offset) {
-
- throw new \LogicException('You can not remove objects from an ElementList');
-
- }
-
- /* }}} */
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/FreeBusyGenerator.php b/vendor/sabre/vobject/lib/Sabre/VObject/FreeBusyGenerator.php
deleted file mode 100644
index 96d0be5ac..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/FreeBusyGenerator.php
+++ /dev/null
@@ -1,322 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * This class helps with generating FREEBUSY reports based on existing sets of
- * objects.
- *
- * It only looks at VEVENT and VFREEBUSY objects from the sourcedata, and
- * generates a single VFREEBUSY object.
- *
- * VFREEBUSY components are described in RFC5545, The rules for what should
- * go in a single freebusy report is taken from RFC4791, section 7.10.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class FreeBusyGenerator {
-
- /**
- * Input objects
- *
- * @var array
- */
- protected $objects;
-
- /**
- * Start of range
- *
- * @var DateTime|null
- */
- protected $start;
-
- /**
- * End of range
- *
- * @var DateTime|null
- */
- protected $end;
-
- /**
- * VCALENDAR object
- *
- * @var Component
- */
- protected $baseObject;
-
- /**
- * Creates the generator.
- *
- * Check the setTimeRange and setObjects methods for details about the
- * arguments.
- *
- * @param DateTime $start
- * @param DateTime $end
- * @param mixed $objects
- * @return void
- */
- public function __construct(\DateTime $start = null, \DateTime $end = null, $objects = null) {
-
- if ($start && $end) {
- $this->setTimeRange($start, $end);
- }
-
- if ($objects) {
- $this->setObjects($objects);
- }
-
- }
-
- /**
- * Sets the VCALENDAR object.
- *
- * If this is set, it will not be generated for you. You are responsible
- * for setting things like the METHOD, CALSCALE, VERSION, etc..
- *
- * The VFREEBUSY object will be automatically added though.
- *
- * @param Component $vcalendar
- * @return void
- */
- public function setBaseObject(Component $vcalendar) {
-
- $this->baseObject = $vcalendar;
-
- }
-
- /**
- * Sets the input objects
- *
- * You must either specify a valendar object as a strong, or as the parse
- * Component.
- * It's also possible to specify multiple objects as an array.
- *
- * @param mixed $objects
- * @return void
- */
- public function setObjects($objects) {
-
- if (!is_array($objects)) {
- $objects = array($objects);
- }
-
- $this->objects = array();
- foreach($objects as $object) {
-
- if (is_string($object)) {
- $this->objects[] = Reader::read($object);
- } elseif ($object instanceof Component) {
- $this->objects[] = $object;
- } else {
- throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component arguments to setObjects');
- }
-
- }
-
- }
-
- /**
- * Sets the time range
- *
- * Any freebusy object falling outside of this time range will be ignored.
- *
- * @param DateTime $start
- * @param DateTime $end
- * @return void
- */
- public function setTimeRange(\DateTime $start = null, \DateTime $end = null) {
-
- $this->start = $start;
- $this->end = $end;
-
- }
-
- /**
- * Parses the input data and returns a correct VFREEBUSY object, wrapped in
- * a VCALENDAR.
- *
- * @return Component
- */
- public function getResult() {
-
- $busyTimes = array();
-
- foreach($this->objects as $object) {
-
- foreach($object->getBaseComponents() as $component) {
-
- switch($component->name) {
-
- case 'VEVENT' :
-
- $FBTYPE = 'BUSY';
- if (isset($component->TRANSP) && (strtoupper($component->TRANSP) === 'TRANSPARENT')) {
- break;
- }
- if (isset($component->STATUS)) {
- $status = strtoupper($component->STATUS);
- if ($status==='CANCELLED') {
- break;
- }
- if ($status==='TENTATIVE') {
- $FBTYPE = 'BUSY-TENTATIVE';
- }
- }
-
- $times = array();
-
- if ($component->RRULE) {
-
- $iterator = new RecurrenceIterator($object, (string)$component->uid);
- if ($this->start) {
- $iterator->fastForward($this->start);
- }
-
- $maxRecurrences = 200;
-
- while($iterator->valid() && --$maxRecurrences) {
-
- $startTime = $iterator->getDTStart();
- if ($this->end && $startTime > $this->end) {
- break;
- }
- $times[] = array(
- $iterator->getDTStart(),
- $iterator->getDTEnd(),
- );
-
- $iterator->next();
-
- }
-
- } else {
-
- $startTime = $component->DTSTART->getDateTime();
- if ($this->end && $startTime > $this->end) {
- break;
- }
- $endTime = null;
- if (isset($component->DTEND)) {
- $endTime = $component->DTEND->getDateTime();
- } elseif (isset($component->DURATION)) {
- $duration = DateTimeParser::parseDuration((string)$component->DURATION);
- $endTime = clone $startTime;
- $endTime->add($duration);
- } elseif ($component->DTSTART->getDateType() === Property\DateTime::DATE) {
- $endTime = clone $startTime;
- $endTime->modify('+1 day');
- } else {
- // The event had no duration (0 seconds)
- break;
- }
-
- $times[] = array($startTime, $endTime);
-
- }
-
- foreach($times as $time) {
-
- if ($this->end && $time[0] > $this->end) break;
- if ($this->start && $time[1] < $this->start) break;
-
- $busyTimes[] = array(
- $time[0],
- $time[1],
- $FBTYPE,
- );
- }
- break;
-
- case 'VFREEBUSY' :
- foreach($component->FREEBUSY as $freebusy) {
-
- $fbType = isset($freebusy['FBTYPE'])?strtoupper($freebusy['FBTYPE']):'BUSY';
-
- // Skipping intervals marked as 'free'
- if ($fbType==='FREE')
- continue;
-
- $values = explode(',', $freebusy);
- foreach($values as $value) {
- list($startTime, $endTime) = explode('/', $value);
- $startTime = DateTimeParser::parseDateTime($startTime);
-
- if (substr($endTime,0,1)==='P' || substr($endTime,0,2)==='-P') {
- $duration = DateTimeParser::parseDuration($endTime);
- $endTime = clone $startTime;
- $endTime->add($duration);
- } else {
- $endTime = DateTimeParser::parseDateTime($endTime);
- }
-
- if($this->start && $this->start > $endTime) continue;
- if($this->end && $this->end < $startTime) continue;
- $busyTimes[] = array(
- $startTime,
- $endTime,
- $fbType
- );
-
- }
-
-
- }
- break;
-
-
-
- }
-
-
- }
-
- }
-
- if ($this->baseObject) {
- $calendar = $this->baseObject;
- } else {
- $calendar = Component::create('VCALENDAR');
- $calendar->version = '2.0';
- $calendar->prodid = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN';
- $calendar->calscale = 'GREGORIAN';
- }
-
- $vfreebusy = Component::create('VFREEBUSY');
- $calendar->add($vfreebusy);
-
- if ($this->start) {
- $dtstart = Property::create('DTSTART');
- $dtstart->setDateTime($this->start,Property\DateTime::UTC);
- $vfreebusy->add($dtstart);
- }
- if ($this->end) {
- $dtend = Property::create('DTEND');
- $dtend->setDateTime($this->end,Property\DateTime::UTC);
- $vfreebusy->add($dtend);
- }
- $dtstamp = Property::create('DTSTAMP');
- $dtstamp->setDateTime(new \DateTime('now'), Property\DateTime::UTC);
- $vfreebusy->add($dtstamp);
-
- foreach($busyTimes as $busyTime) {
-
- $busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
- $busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
-
- $prop = Property::create(
- 'FREEBUSY',
- $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
- );
- $prop['FBTYPE'] = $busyTime[2];
- $vfreebusy->add($prop);
-
- }
-
- return $calendar;
-
- }
-
-}
-
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Node.php b/vendor/sabre/vobject/lib/Sabre/VObject/Node.php
deleted file mode 100644
index bee68ec2a..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Node.php
+++ /dev/null
@@ -1,187 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * Base class for all nodes
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-abstract class Node implements \IteratorAggregate, \ArrayAccess, \Countable {
-
- /**
- * The following constants are used by the validate() method.
- */
- const REPAIR = 1;
-
- /**
- * Turns the object back into a serialized blob.
- *
- * @return string
- */
- abstract function serialize();
-
- /**
- * Iterator override
- *
- * @var ElementList
- */
- protected $iterator = null;
-
- /**
- * A link to the parent node
- *
- * @var Node
- */
- public $parent = null;
-
- /**
- * Validates the node for correctness.
- *
- * The following options are supported:
- * - Node::REPAIR - If something is broken, and automatic repair may
- * be attempted.
- *
- * An array is returned with warnings.
- *
- * Every item in the array has the following properties:
- * * level - (number between 1 and 3 with severity information)
- * * message - (human readable message)
- * * node - (reference to the offending node)
- *
- * @param int $options
- * @return array
- */
- public function validate($options = 0) {
-
- return array();
-
- }
-
- /* {{{ IteratorAggregator interface */
-
- /**
- * Returns the iterator for this object
- *
- * @return ElementList
- */
- public function getIterator() {
-
- if (!is_null($this->iterator))
- return $this->iterator;
-
- return new ElementList(array($this));
-
- }
-
- /**
- * Sets the overridden iterator
- *
- * Note that this is not actually part of the iterator interface
- *
- * @param ElementList $iterator
- * @return void
- */
- public function setIterator(ElementList $iterator) {
-
- $this->iterator = $iterator;
-
- }
-
- /* }}} */
-
- /* {{{ Countable interface */
-
- /**
- * Returns the number of elements
- *
- * @return int
- */
- public function count() {
-
- $it = $this->getIterator();
- return $it->count();
-
- }
-
- /* }}} */
-
- /* {{{ ArrayAccess Interface */
-
-
- /**
- * Checks if an item exists through ArrayAccess.
- *
- * This method just forwards the request to the inner iterator
- *
- * @param int $offset
- * @return bool
- */
- public function offsetExists($offset) {
-
- $iterator = $this->getIterator();
- return $iterator->offsetExists($offset);
-
- }
-
- /**
- * Gets an item through ArrayAccess.
- *
- * This method just forwards the request to the inner iterator
- *
- * @param int $offset
- * @return mixed
- */
- public function offsetGet($offset) {
-
- $iterator = $this->getIterator();
- return $iterator->offsetGet($offset);
-
- }
-
- /**
- * Sets an item through ArrayAccess.
- *
- * This method just forwards the request to the inner iterator
- *
- * @param int $offset
- * @param mixed $value
- * @return void
- */
- public function offsetSet($offset,$value) {
-
- $iterator = $this->getIterator();
- $iterator->offsetSet($offset,$value);
-
- // @codeCoverageIgnoreStart
- //
- // This method always throws an exception, so we ignore the closing
- // brace
- }
- // @codeCoverageIgnoreEnd
-
- /**
- * Sets an item through ArrayAccess.
- *
- * This method just forwards the request to the inner iterator
- *
- * @param int $offset
- * @return void
- */
- public function offsetUnset($offset) {
-
- $iterator = $this->getIterator();
- $iterator->offsetUnset($offset);
-
- // @codeCoverageIgnoreStart
- //
- // This method always throws an exception, so we ignore the closing
- // brace
- }
- // @codeCoverageIgnoreEnd
-
- /* }}} */
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Parameter.php b/vendor/sabre/vobject/lib/Sabre/VObject/Parameter.php
deleted file mode 100644
index 72bf03b47..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Parameter.php
+++ /dev/null
@@ -1,104 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * VObject Parameter
- *
- * This class represents a parameter. A parameter is always tied to a property.
- * In the case of:
- * DTSTART;VALUE=DATE:20101108
- * VALUE=DATE would be the parameter name and value.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class Parameter extends Node {
-
- /**
- * Parameter name
- *
- * @var string
- */
- public $name;
-
- /**
- * Parameter value
- *
- * @var string
- */
- public $value;
-
- /**
- * Sets up the object
- *
- * @param string $name
- * @param string $value
- */
- public function __construct($name, $value = null) {
-
- if (!is_scalar($value) && !is_null($value)) {
- throw new \InvalidArgumentException('The value argument must be a scalar value or null');
- }
-
- $this->name = strtoupper($name);
- $this->value = $value;
-
- }
-
- /**
- * Returns the parameter's internal value.
- *
- * @return string
- */
- public function getValue() {
-
- return $this->value;
-
- }
-
-
- /**
- * Turns the object back into a serialized blob.
- *
- * @return string
- */
- public function serialize() {
-
- if (is_null($this->value)) {
- return $this->name;
- }
- $src = array(
- '\\',
- "\n",
- ';',
- ',',
- );
- $out = array(
- '\\\\',
- '\n',
- '\;',
- '\,',
- );
-
- $value = str_replace($src, $out, $this->value);
- if (strpos($value,":")!==false) {
- $value = '"' . $value . '"';
- }
- return $this->name . '=' . $value;
-
- }
-
- /**
- * Called when this object is being cast to a string
- *
- * @return string
- */
- public function __toString() {
-
- return $this->value;
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/ParseException.php b/vendor/sabre/vobject/lib/Sabre/VObject/ParseException.php
deleted file mode 100644
index 66b49c606..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/ParseException.php
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * Exception thrown by Reader if an invalid object was attempted to be parsed.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class ParseException extends \Exception { }
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Property.php b/vendor/sabre/vobject/lib/Sabre/VObject/Property.php
deleted file mode 100644
index 63ae64574..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Property.php
+++ /dev/null
@@ -1,444 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * VObject Property
- *
- * A property in VObject is usually in the form PARAMNAME:paramValue.
- * An example is : SUMMARY:Weekly meeting
- *
- * Properties can also have parameters:
- * SUMMARY;LANG=en:Weekly meeting.
- *
- * Parameters can be accessed using the ArrayAccess interface.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class Property extends Node {
-
- /**
- * Propertyname
- *
- * @var string
- */
- public $name;
-
- /**
- * Group name
- *
- * This may be something like 'HOME' for vcards.
- *
- * @var string
- */
- public $group;
-
- /**
- * Property parameters
- *
- * @var array
- */
- public $parameters = array();
-
- /**
- * Property value
- *
- * @var string
- */
- public $value;
-
- /**
- * If properties are added to this map, they will be automatically mapped
- * to their respective classes, if parsed by the reader or constructed with
- * the 'create' method.
- *
- * @var array
- */
- static public $classMap = array(
- 'COMPLETED' => 'Sabre\\VObject\\Property\\DateTime',
- 'CREATED' => 'Sabre\\VObject\\Property\\DateTime',
- 'DTEND' => 'Sabre\\VObject\\Property\\DateTime',
- 'DTSTAMP' => 'Sabre\\VObject\\Property\\DateTime',
- 'DTSTART' => 'Sabre\\VObject\\Property\\DateTime',
- 'DUE' => 'Sabre\\VObject\\Property\\DateTime',
- 'EXDATE' => 'Sabre\\VObject\\Property\\MultiDateTime',
- 'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\DateTime',
- 'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\DateTime',
- 'TRIGGER' => 'Sabre\\VObject\\Property\\DateTime',
- 'N' => 'Sabre\\VObject\\Property\\Compound',
- 'ORG' => 'Sabre\\VObject\\Property\\Compound',
- 'ADR' => 'Sabre\\VObject\\Property\\Compound',
- 'CATEGORIES' => 'Sabre\\VObject\\Property\\Compound',
- );
-
- /**
- * Creates the new property by name, but in addition will also see if
- * there's a class mapped to the property name.
- *
- * Parameters can be specified with the optional third argument. Parameters
- * must be a key->value map of the parameter name, and value. If the value
- * is specified as an array, it is assumed that multiple parameters with
- * the same name should be added.
- *
- * @param string $name
- * @param string $value
- * @param array $parameters
- * @return Property
- */
- static public function create($name, $value = null, array $parameters = array()) {
-
- $name = strtoupper($name);
- $shortName = $name;
- $group = null;
- if (strpos($shortName,'.')!==false) {
- list($group, $shortName) = explode('.', $shortName);
- }
-
- if (isset(self::$classMap[$shortName])) {
- return new self::$classMap[$shortName]($name, $value, $parameters);
- } else {
- return new self($name, $value, $parameters);
- }
-
- }
-
- /**
- * Creates a new property object
- *
- * Parameters can be specified with the optional third argument. Parameters
- * must be a key->value map of the parameter name, and value. If the value
- * is specified as an array, it is assumed that multiple parameters with
- * the same name should be added.
- *
- * @param string $name
- * @param string $value
- * @param array $parameters
- */
- public function __construct($name, $value = null, array $parameters = array()) {
-
- if (!is_scalar($value) && !is_null($value)) {
- throw new \InvalidArgumentException('The value argument must be scalar or null');
- }
-
- $name = strtoupper($name);
- $group = null;
- if (strpos($name,'.')!==false) {
- list($group, $name) = explode('.', $name);
- }
- $this->name = $name;
- $this->group = $group;
- $this->setValue($value);
-
- foreach($parameters as $paramName => $paramValues) {
-
- if (!is_array($paramValues)) {
- $paramValues = array($paramValues);
- }
-
- foreach($paramValues as $paramValue) {
- $this->add($paramName, $paramValue);
- }
-
- }
-
- }
-
- /**
- * Updates the internal value
- *
- * @param string $value
- * @return void
- */
- public function setValue($value) {
-
- $this->value = $value;
-
- }
-
- /**
- * Returns the internal value
- *
- * @param string $value
- * @return string
- */
- public function getValue() {
-
- return $this->value;
-
- }
-
- /**
- * Turns the object back into a serialized blob.
- *
- * @return string
- */
- public function serialize() {
-
- $str = $this->name;
- if ($this->group) $str = $this->group . '.' . $this->name;
-
- foreach($this->parameters as $param) {
-
- $str.=';' . $param->serialize();
-
- }
-
- $src = array(
- '\\',
- "\n",
- "\r",
- );
- $out = array(
- '\\\\',
- '\n',
- '',
- );
- $str.=':' . str_replace($src, $out, $this->value);
-
- $out = '';
- while(strlen($str)>0) {
- if (strlen($str)>75) {
- $out.= mb_strcut($str,0,75,'utf-8') . "\r\n";
- $str = ' ' . mb_strcut($str,75,strlen($str),'utf-8');
- } else {
- $out.=$str . "\r\n";
- $str='';
- break;
- }
- }
-
- return $out;
-
- }
-
- /**
- * Adds a new componenten or element
- *
- * You can call this method with the following syntaxes:
- *
- * add(Parameter $element)
- * add(string $name, $value)
- *
- * The first version adds an Parameter
- * The second adds a property as a string.
- *
- * @param mixed $item
- * @param mixed $itemValue
- * @return void
- */
- public function add($item, $itemValue = null) {
-
- if ($item instanceof Parameter) {
- if (!is_null($itemValue)) {
- throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject');
- }
- $item->parent = $this;
- $this->parameters[] = $item;
- } elseif(is_string($item)) {
-
- $parameter = new Parameter($item,$itemValue);
- $parameter->parent = $this;
- $this->parameters[] = $parameter;
-
- } else {
-
- throw new \InvalidArgumentException('The first argument must either be a Node a string');
-
- }
-
- }
-
- /* ArrayAccess interface {{{ */
-
- /**
- * Checks if an array element exists
- *
- * @param mixed $name
- * @return bool
- */
- public function offsetExists($name) {
-
- if (is_int($name)) return parent::offsetExists($name);
-
- $name = strtoupper($name);
-
- foreach($this->parameters as $parameter) {
- if ($parameter->name == $name) return true;
- }
- return false;
-
- }
-
- /**
- * Returns a parameter, or parameter list.
- *
- * @param string $name
- * @return Node
- */
- public function offsetGet($name) {
-
- if (is_int($name)) return parent::offsetGet($name);
- $name = strtoupper($name);
-
- $result = array();
- foreach($this->parameters as $parameter) {
- if ($parameter->name == $name)
- $result[] = $parameter;
- }
-
- if (count($result)===0) {
- return null;
- } elseif (count($result)===1) {
- return $result[0];
- } else {
- $result[0]->setIterator(new ElementList($result));
- return $result[0];
- }
-
- }
-
- /**
- * Creates a new parameter
- *
- * @param string $name
- * @param mixed $value
- * @return void
- */
- public function offsetSet($name, $value) {
-
- if (is_int($name)) parent::offsetSet($name, $value);
-
- if (is_scalar($value)) {
- if (!is_string($name))
- throw new \InvalidArgumentException('A parameter name must be specified. This means you cannot use the $array[]="string" to add parameters.');
-
- $this->offsetUnset($name);
- $parameter = new Parameter($name, $value);
- $parameter->parent = $this;
- $this->parameters[] = $parameter;
-
- } elseif ($value instanceof Parameter) {
- if (!is_null($name))
- throw new \InvalidArgumentException('Don\'t specify a parameter name if you\'re passing a \\Sabre\\VObject\\Parameter. Add using $array[]=$parameterObject.');
-
- $value->parent = $this;
- $this->parameters[] = $value;
- } else {
- throw new \InvalidArgumentException('You can only add parameters to the property object');
- }
-
- }
-
- /**
- * Removes one or more parameters with the specified name
- *
- * @param string $name
- * @return void
- */
- public function offsetUnset($name) {
-
- if (is_int($name)) parent::offsetUnset($name);
- $name = strtoupper($name);
-
- foreach($this->parameters as $key=>$parameter) {
- if ($parameter->name == $name) {
- $parameter->parent = null;
- unset($this->parameters[$key]);
- }
-
- }
-
- }
-
- /* }}} */
-
- /**
- * Called when this object is being cast to a string
- *
- * @return string
- */
- public function __toString() {
-
- return (string)$this->value;
-
- }
-
- /**
- * This method is automatically called when the object is cloned.
- * Specifically, this will ensure all child elements are also cloned.
- *
- * @return void
- */
- public function __clone() {
-
- foreach($this->parameters as $key=>$child) {
- $this->parameters[$key] = clone $child;
- $this->parameters[$key]->parent = $this;
- }
-
- }
-
- /**
- * Validates the node for correctness.
- *
- * The following options are supported:
- * - Node::REPAIR - If something is broken, and automatic repair may
- * be attempted.
- *
- * An array is returned with warnings.
- *
- * Every item in the array has the following properties:
- * * level - (number between 1 and 3 with severity information)
- * * message - (human readable message)
- * * node - (reference to the offending node)
- *
- * @param int $options
- * @return array
- */
- public function validate($options = 0) {
-
- $warnings = array();
-
- // Checking if our value is UTF-8
- if (!StringUtil::isUTF8($this->value)) {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'Property is not valid UTF-8!',
- 'node' => $this,
- );
- if ($options & self::REPAIR) {
- $this->value = StringUtil::convertToUTF8($this->value);
- }
- }
-
- // Checking if the propertyname does not contain any invalid bytes.
- if (!preg_match('/^([A-Z0-9-]+)$/', $this->name)) {
- $warnings[] = array(
- 'level' => 1,
- 'message' => 'The propertyname: ' . $this->name . ' contains invalid characters. Only A-Z, 0-9 and - are allowed',
- 'node' => $this,
- );
- if ($options & self::REPAIR) {
- // Uppercasing and converting underscores to dashes.
- $this->name = strtoupper(
- str_replace('_', '-', $this->name)
- );
- // Removing every other invalid character
- $this->name = preg_replace('/([^A-Z0-9-])/u', '', $this->name);
-
- }
-
- }
-
- // Validating inner parameters
- foreach($this->parameters as $param) {
- $warnings = array_merge($warnings, $param->validate($options));
- }
-
- return $warnings;
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Property/Compound.php b/vendor/sabre/vobject/lib/Sabre/VObject/Property/Compound.php
deleted file mode 100644
index 26f090069..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Property/Compound.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Property;
-
-use Sabre\VObject;
-
-/**
- * Compound property.
- *
- * This class adds (de)serialization of compound properties to/from arrays.
- *
- * Currently the following properties from RFC 6350 are mapped to use this
- * class:
- *
- * N: Section 6.2.2
- * ADR: Section 6.3.1
- * ORG: Section 6.6.4
- * CATEGORIES: Section 6.7.1
- *
- * In order to use this correctly, you must call setParts and getParts to
- * retrieve and modify dates respectively.
- *
- * @author Thomas Tanghus (http://tanghus.net/)
- * @author Lars Kneschke
- * @author Evert Pot (http://evertpot.com/)
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class Compound extends VObject\Property {
-
- /**
- * If property names are added to this map, they will be (de)serialised as arrays
- * using the getParts() and setParts() methods.
- * The keys are the property names, values are delimiter chars.
- *
- * @var array
- */
- static public $delimiterMap = array(
- 'N' => ';',
- 'ADR' => ';',
- 'ORG' => ';',
- 'CATEGORIES' => ',',
- );
-
- /**
- * The currently used delimiter.
- *
- * @var string
- */
- protected $delimiter = null;
-
- /**
- * Get a compound value as an array.
- *
- * @param $name string
- * @return array
- */
- public function getParts() {
-
- if (is_null($this->value)) {
- return array();
- }
-
- $delimiter = $this->getDelimiter();
-
- // split by any $delimiter which is NOT prefixed by a slash.
- // Note that this is not a a perfect solution. If a value is prefixed
- // by two slashes, it should actually be split anyway.
- //
- // Hopefully we can fix this better in a future version, where we can
- // break compatibility a bit.
- $compoundValues = preg_split("/(?<!\\\)$delimiter/", $this->value);
-
- // remove slashes from any semicolon and comma left escaped in the single values
- $compoundValues = array_map(
- function($val) {
- return strtr($val, array('\,' => ',', '\;' => ';'));
- }, $compoundValues);
-
- return $compoundValues;
-
- }
-
- /**
- * Returns the delimiter for this property.
- *
- * @return string
- */
- public function getDelimiter() {
-
- if (!$this->delimiter) {
- if (isset(self::$delimiterMap[$this->name])) {
- $this->delimiter = self::$delimiterMap[$this->name];
- } else {
- // To be a bit future proof, we are going to default the
- // delimiter to ;
- $this->delimiter = ';';
- }
- }
- return $this->delimiter;
-
- }
-
- /**
- * Set a compound value as an array.
- *
- *
- * @param $name string
- * @return array
- */
- public function setParts(array $values) {
-
- // add slashes to all semicolons and commas in the single values
- $values = array_map(
- function($val) {
- return strtr($val, array(',' => '\,', ';' => '\;'));
- }, $values);
-
- $this->setValue(
- implode($this->getDelimiter(), $values)
- );
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Property/DateTime.php b/vendor/sabre/vobject/lib/Sabre/VObject/Property/DateTime.php
deleted file mode 100644
index 95e9b0209..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Property/DateTime.php
+++ /dev/null
@@ -1,245 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Property;
-
-use Sabre\VObject;
-
-/**
- * DateTime property
- *
- * This element is used for iCalendar properties such as the DTSTART property.
- * It basically provides a few helper functions that make it easier to deal
- * with these. It supports both DATE-TIME and DATE values.
- *
- * In order to use this correctly, you must call setDateTime and getDateTime to
- * retrieve and modify dates respectively.
- *
- * If you use the 'value' or properties directly, this object does not keep
- * reference and results might appear incorrectly.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class DateTime extends VObject\Property {
-
- /**
- * Local 'floating' time
- */
- const LOCAL = 1;
-
- /**
- * UTC-based time
- */
- const UTC = 2;
-
- /**
- * Local time plus timezone
- */
- const LOCALTZ = 3;
-
- /**
- * Only a date, time is ignored
- */
- const DATE = 4;
-
- /**
- * DateTime representation
- *
- * @var \DateTime
- */
- protected $dateTime;
-
- /**
- * dateType
- *
- * @var int
- */
- protected $dateType;
-
- /**
- * Updates the Date and Time.
- *
- * @param \DateTime $dt
- * @param int $dateType
- * @return void
- */
- public function setDateTime(\DateTime $dt, $dateType = self::LOCALTZ) {
-
- switch($dateType) {
-
- case self::LOCAL :
- $this->setValue($dt->format('Ymd\\THis'));
- $this->offsetUnset('VALUE');
- $this->offsetUnset('TZID');
- $this->offsetSet('VALUE','DATE-TIME');
- break;
- case self::UTC :
- $dt->setTimeZone(new \DateTimeZone('UTC'));
- $this->setValue($dt->format('Ymd\\THis\\Z'));
- $this->offsetUnset('VALUE');
- $this->offsetUnset('TZID');
- $this->offsetSet('VALUE','DATE-TIME');
- break;
- case self::LOCALTZ :
- $this->setValue($dt->format('Ymd\\THis'));
- $this->offsetUnset('VALUE');
- $this->offsetUnset('TZID');
- $this->offsetSet('VALUE','DATE-TIME');
- $this->offsetSet('TZID', $dt->getTimeZone()->getName());
- break;
- case self::DATE :
- $this->setValue($dt->format('Ymd'));
- $this->offsetUnset('VALUE');
- $this->offsetUnset('TZID');
- $this->offsetSet('VALUE','DATE');
- break;
- default :
- throw new \InvalidArgumentException('You must pass a valid dateType constant');
-
- }
- $this->dateTime = $dt;
- $this->dateType = $dateType;
-
- }
-
- /**
- * Returns the current DateTime value.
- *
- * If no value was set, this method returns null.
- *
- * @return \DateTime|null
- */
- public function getDateTime() {
-
- if ($this->dateTime)
- return $this->dateTime;
-
- list(
- $this->dateType,
- $this->dateTime
- ) = self::parseData($this->value, $this);
- return $this->dateTime;
-
- }
-
- /**
- * Returns the type of Date format.
- *
- * This method returns one of the format constants. If no date was set,
- * this method will return null.
- *
- * @return int|null
- */
- public function getDateType() {
-
- if ($this->dateType)
- return $this->dateType;
-
- list(
- $this->dateType,
- $this->dateTime,
- ) = self::parseData($this->value, $this);
- return $this->dateType;
-
- }
-
- /**
- * This method will return true, if the property had a date and a time, as
- * opposed to only a date.
- *
- * @return bool
- */
- public function hasTime() {
-
- return $this->getDateType()!==self::DATE;
-
- }
-
- /**
- * Parses the internal data structure to figure out what the current date
- * and time is.
- *
- * The returned array contains two elements:
- * 1. A 'DateType' constant (as defined on this class), or null.
- * 2. A DateTime object (or null)
- *
- * @param string|null $propertyValue The string to parse (yymmdd or
- * ymmddThhmmss, etc..)
- * @param \Sabre\VObject\Property|null $property The instance of the
- * property we're parsing.
- * @return array
- */
- static public function parseData($propertyValue, VObject\Property $property = null) {
-
- if (is_null($propertyValue)) {
- return array(null, null);
- }
-
- $date = '(?P<year>[1-2][0-9]{3})(?P<month>[0-1][0-9])(?P<date>[0-3][0-9])';
- $time = '(?P<hour>[0-2][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9])';
- $regex = "/^$date(T$time(?P<isutc>Z)?)?$/";
-
- if (!preg_match($regex, $propertyValue, $matches)) {
- throw new \InvalidArgumentException($propertyValue . ' is not a valid \DateTime or Date string');
- }
-
- if (!isset($matches['hour'])) {
- // Date-only
- return array(
- self::DATE,
- new \DateTime($matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' 00:00:00', new \DateTimeZone('UTC')),
- );
- }
-
- $dateStr =
- $matches['year'] .'-' .
- $matches['month'] . '-' .
- $matches['date'] . ' ' .
- $matches['hour'] . ':' .
- $matches['minute'] . ':' .
- $matches['second'];
-
- if (isset($matches['isutc'])) {
- $dt = new \DateTime($dateStr,new \DateTimeZone('UTC'));
- $dt->setTimeZone(new \DateTimeZone('UTC'));
- return array(
- self::UTC,
- $dt
- );
- }
-
- // Finding the timezone.
- $tzid = $property['TZID'];
- if (!$tzid) {
- // This was a floating time string. This implies we use the
- // timezone from date_default_timezone_set / date.timezone ini
- // setting.
- return array(
- self::LOCAL,
- new \DateTime($dateStr)
- );
- }
-
- // To look up the timezone, we must first find the VCALENDAR component.
- $root = $property;
- while($root->parent) {
- $root = $root->parent;
- }
- if ($root->name === 'VCALENDAR') {
- $tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid, $root);
- } else {
- $tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid);
- }
-
- $dt = new \DateTime($dateStr, $tz);
- $dt->setTimeZone($tz);
-
- return array(
- self::LOCALTZ,
- $dt
- );
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Property/MultiDateTime.php b/vendor/sabre/vobject/lib/Sabre/VObject/Property/MultiDateTime.php
deleted file mode 100644
index f01491b66..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Property/MultiDateTime.php
+++ /dev/null
@@ -1,180 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Property;
-
-use Sabre\VObject;
-
-/**
- * Multi-DateTime property
- *
- * This element is used for iCalendar properties such as the EXDATE property.
- * It basically provides a few helper functions that make it easier to deal
- * with these. It supports both DATE-TIME and DATE values.
- *
- * In order to use this correctly, you must call setDateTimes and getDateTimes
- * to retrieve and modify dates respectively.
- *
- * If you use the 'value' or properties directly, this object does not keep
- * reference and results might appear incorrectly.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class MultiDateTime extends VObject\Property {
-
- /**
- * DateTime representation
- *
- * @var DateTime[]
- */
- protected $dateTimes;
-
- /**
- * dateType
- *
- * This is one of the Sabre\VObject\Property\DateTime constants.
- *
- * @var int
- */
- protected $dateType;
-
- /**
- * Updates the value
- *
- * @param array $dt Must be an array of DateTime objects.
- * @param int $dateType
- * @return void
- */
- public function setDateTimes(array $dt, $dateType = VObject\Property\DateTime::LOCALTZ) {
-
- foreach($dt as $i)
- if (!$i instanceof \DateTime)
- throw new \InvalidArgumentException('You must pass an array of DateTime objects');
-
- $this->offsetUnset('VALUE');
- $this->offsetUnset('TZID');
- switch($dateType) {
-
- case DateTime::LOCAL :
- $val = array();
- foreach($dt as $i) {
- $val[] = $i->format('Ymd\\THis');
- }
- $this->setValue(implode(',',$val));
- $this->offsetSet('VALUE','DATE-TIME');
- break;
- case DateTime::UTC :
- $val = array();
- foreach($dt as $i) {
- $i->setTimeZone(new \DateTimeZone('UTC'));
- $val[] = $i->format('Ymd\\THis\\Z');
- }
- $this->setValue(implode(',',$val));
- $this->offsetSet('VALUE','DATE-TIME');
- break;
- case DateTime::LOCALTZ :
- $val = array();
- foreach($dt as $i) {
- $val[] = $i->format('Ymd\\THis');
- }
- $this->setValue(implode(',',$val));
- $this->offsetSet('VALUE','DATE-TIME');
- $this->offsetSet('TZID', $dt[0]->getTimeZone()->getName());
- break;
- case DateTime::DATE :
- $val = array();
- foreach($dt as $i) {
- $val[] = $i->format('Ymd');
- }
- $this->setValue(implode(',',$val));
- $this->offsetSet('VALUE','DATE');
- break;
- default :
- throw new \InvalidArgumentException('You must pass a valid dateType constant');
-
- }
- $this->dateTimes = $dt;
- $this->dateType = $dateType;
-
- }
-
- /**
- * Returns the current DateTime value.
- *
- * If no value was set, this method returns null.
- *
- * @return array|null
- */
- public function getDateTimes() {
-
- if ($this->dateTimes)
- return $this->dateTimes;
-
- $dts = array();
-
- if (!$this->value) {
- $this->dateTimes = null;
- $this->dateType = null;
- return null;
- }
-
- foreach(explode(',',$this->value) as $val) {
- list(
- $type,
- $dt
- ) = DateTime::parseData($val, $this);
- $dts[] = $dt;
- $this->dateType = $type;
- }
- $this->dateTimes = $dts;
- return $this->dateTimes;
-
- }
-
- /**
- * Returns the type of Date format.
- *
- * This method returns one of the format constants. If no date was set,
- * this method will return null.
- *
- * @return int|null
- */
- public function getDateType() {
-
- if ($this->dateType)
- return $this->dateType;
-
- if (!$this->value) {
- $this->dateTimes = null;
- $this->dateType = null;
- return null;
- }
-
- $dts = array();
- foreach(explode(',',$this->value) as $val) {
- list(
- $type,
- $dt
- ) = DateTime::parseData($val, $this);
- $dts[] = $dt;
- $this->dateType = $type;
- }
- $this->dateTimes = $dts;
- return $this->dateType;
-
- }
-
- /**
- * This method will return true, if the property had a date and a time, as
- * opposed to only a date.
- *
- * @return bool
- */
- public function hasTime() {
-
- return $this->getDateType()!==DateTime::DATE;
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Reader.php b/vendor/sabre/vobject/lib/Sabre/VObject/Reader.php
deleted file mode 100644
index a001b2bf1..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Reader.php
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * VCALENDAR/VCARD reader
- *
- * This class reads the vobject file, and returns a full element tree.
- *
- * TODO: this class currently completely works 'statically'. This is pointless,
- * and defeats OOP principals. Needs refactoring in a future version.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class Reader {
-
- /**
- * If this option is passed to the reader, it will be less strict about the
- * validity of the lines.
- *
- * Currently using this option just means, that it will accept underscores
- * in property names.
- */
- const OPTION_FORGIVING = 1;
-
- /**
- * If this option is turned on, any lines we cannot parse will be ignored
- * by the reader.
- */
- const OPTION_IGNORE_INVALID_LINES = 2;
-
- /**
- * Parses the file and returns the top component
- *
- * The options argument is a bitfield. Pass any of the OPTIONS constant to
- * alter the parsers' behaviour.
- *
- * @param string $data
- * @param int $options
- * @return Node
- */
- static function read($data, $options = 0) {
-
- // Normalizing newlines
- $data = str_replace(array("\r","\n\n"), array("\n","\n"), $data);
-
- $lines = explode("\n", $data);
-
- // Unfolding lines
- $lines2 = array();
- foreach($lines as $line) {
-
- // Skipping empty lines
- if (!$line) continue;
-
- if ($line[0]===" " || $line[0]==="\t") {
- $lines2[count($lines2)-1].=substr($line,1);
- } else {
- $lines2[] = $line;
- }
-
- }
-
- unset($lines);
-
- reset($lines2);
-
- return self::readLine($lines2, $options);
-
- }
-
- /**
- * Reads and parses a single line.
- *
- * This method receives the full array of lines. The array pointer is used
- * to traverse.
- *
- * This method returns null if an invalid line was encountered, and the
- * IGNORE_INVALID_LINES option was turned on.
- *
- * @param array $lines
- * @param int $options See the OPTIONS constants.
- * @return Node
- */
- static private function readLine(&$lines, $options = 0) {
-
- $line = current($lines);
- $lineNr = key($lines);
- next($lines);
-
- // Components
- if (strtoupper(substr($line,0,6)) === "BEGIN:") {
-
- $componentName = strtoupper(substr($line,6));
- $obj = Component::create($componentName);
-
- $nextLine = current($lines);
-
- while(strtoupper(substr($nextLine,0,4))!=="END:") {
-
- $parsedLine = self::readLine($lines, $options);
- $nextLine = current($lines);
-
- if (is_null($parsedLine)) {
- continue;
- }
- $obj->add($parsedLine);
-
- if ($nextLine===false)
- throw new ParseException('Invalid VObject. Document ended prematurely.');
-
- }
-
- // Checking component name of the 'END:' line.
- if (substr($nextLine,4)!==$obj->name) {
- throw new ParseException('Invalid VObject, expected: "END:' . $obj->name . '" got: "' . $nextLine . '"');
- }
- next($lines);
-
- return $obj;
-
- }
-
- // Properties
- //$result = preg_match('/(?P<name>[A-Z0-9-]+)(?:;(?P<parameters>^(?<!:):))(.*)$/',$line,$matches);
-
- if ($options & self::OPTION_FORGIVING) {
- $token = '[A-Z0-9-\._]+';
- } else {
- $token = '[A-Z0-9-\.]+';
- }
- $parameters = "(?:;(?P<parameters>([^:^\"]|\"([^\"]*)\")*))?";
- $regex = "/^(?P<name>$token)$parameters:(?P<value>.*)$/i";
-
- $result = preg_match($regex,$line,$matches);
-
- if (!$result) {
- if ($options & self::OPTION_IGNORE_INVALID_LINES) {
- return null;
- } else {
- throw new ParseException('Invalid VObject, line ' . ($lineNr+1) . ' did not follow the icalendar/vcard format');
- }
- }
-
- $propertyName = strtoupper($matches['name']);
- $propertyValue = preg_replace_callback('#(\\\\(\\\\|N|n))#',function($matches) {
- if ($matches[2]==='n' || $matches[2]==='N') {
- return "\n";
- } else {
- return $matches[2];
- }
- }, $matches['value']);
-
- $obj = Property::create($propertyName, $propertyValue);
-
- if ($matches['parameters']) {
-
- foreach(self::readParameters($matches['parameters']) as $param) {
- $obj->add($param);
- }
-
- }
-
- return $obj;
-
-
- }
-
- /**
- * Reads a parameter list from a property
- *
- * This method returns an array of Parameter
- *
- * @param string $parameters
- * @return array
- */
- static private function readParameters($parameters) {
-
- $token = '[A-Z0-9-]+';
-
- $paramValue = '(?P<paramValue>[^\"^;]*|"[^"]*")';
-
- $regex = "/(?<=^|;)(?P<paramName>$token)(=$paramValue(?=$|;))?/i";
- preg_match_all($regex, $parameters, $matches, PREG_SET_ORDER);
-
- $params = array();
- foreach($matches as $match) {
-
- if (!isset($match['paramValue'])) {
-
- $value = null;
-
- } else {
-
- $value = $match['paramValue'];
-
- if (isset($value[0]) && $value[0]==='"') {
- // Stripping quotes, if needed
- $value = substr($value,1,strlen($value)-2);
- }
-
- $value = preg_replace_callback('#(\\\\(\\\\|N|n|;|,))#',function($matches) {
- if ($matches[2]==='n' || $matches[2]==='N') {
- return "\n";
- } else {
- return $matches[2];
- }
- }, $value);
-
- }
-
- $params[] = new Parameter($match['paramName'], $value);
-
- }
-
- return $params;
-
- }
-
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/RecurrenceIterator.php b/vendor/sabre/vobject/lib/Sabre/VObject/RecurrenceIterator.php
deleted file mode 100644
index 8bd4ed224..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/RecurrenceIterator.php
+++ /dev/null
@@ -1,1144 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * This class is used to determine new for a recurring event, when the next
- * events occur.
- *
- * This iterator may loop infinitely in the future, therefore it is important
- * that if you use this class, you set hard limits for the amount of iterations
- * you want to handle.
- *
- * Note that currently there is not full support for the entire iCalendar
- * specification, as it's very complex and contains a lot of permutations
- * that's not yet used very often in software.
- *
- * For the focus has been on features as they actually appear in Calendaring
- * software, but this may well get expanded as needed / on demand
- *
- * The following RRULE properties are supported
- * * UNTIL
- * * INTERVAL
- * * COUNT
- * * FREQ=DAILY
- * * BYDAY
- * * BYHOUR
- * * FREQ=WEEKLY
- * * BYDAY
- * * BYHOUR
- * * WKST
- * * FREQ=MONTHLY
- * * BYMONTHDAY
- * * BYDAY
- * * BYSETPOS
- * * FREQ=YEARLY
- * * BYMONTH
- * * BYMONTHDAY (only if BYMONTH is also set)
- * * BYDAY (only if BYMONTH is also set)
- *
- * Anything beyond this is 'undefined', which means that it may get ignored, or
- * you may get unexpected results. The effect is that in some applications the
- * specified recurrence may look incorrect, or is missing.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class RecurrenceIterator implements \Iterator {
-
- /**
- * The initial event date
- *
- * @var DateTime
- */
- public $startDate;
-
- /**
- * The end-date of the initial event
- *
- * @var DateTime
- */
- public $endDate;
-
- /**
- * The 'current' recurrence.
- *
- * This will be increased for every iteration.
- *
- * @var DateTime
- */
- public $currentDate;
-
-
- /**
- * List of dates that are excluded from the rules.
- *
- * This list contains the items that have been overriden by the EXDATE
- * property.
- *
- * @var array
- */
- public $exceptionDates = array();
-
- /**
- * Base event
- *
- * @var Component\VEvent
- */
- public $baseEvent;
-
- /**
- * List of dates that are overridden by other events.
- * Similar to $overriddenEvents, but this just contains the original dates.
- *
- * @var array
- */
- public $overriddenDates = array();
-
- /**
- * list of events that are 'overridden'.
- *
- * This is an array of Component\VEvent objects.
- *
- * @var array
- */
- public $overriddenEvents = array();
-
- /**
- * Frequency is one of: secondly, minutely, hourly, daily, weekly, monthly,
- * yearly.
- *
- * @var string
- */
- public $frequency;
-
- /**
- * The last instance of this recurrence, inclusively
- *
- * @var DateTime|null
- */
- public $until;
-
- /**
- * The number of recurrences, or 'null' if infinitely recurring.
- *
- * @var int
- */
- public $count;
-
- /**
- * The interval.
- *
- * If for example frequency is set to daily, interval = 2 would mean every
- * 2 days.
- *
- * @var int
- */
- public $interval = 1;
-
- /**
- * Which seconds to recur.
- *
- * This is an array of integers (between 0 and 60)
- *
- * @var array
- */
- public $bySecond;
-
- /**
- * Which minutes to recur
- *
- * This is an array of integers (between 0 and 59)
- *
- * @var array
- */
- public $byMinute;
-
- /**
- * Which hours to recur
- *
- * This is an array of integers (between 0 and 23)
- *
- * @var array
- */
- public $byHour;
-
- /**
- * Which weekdays to recur.
- *
- * This is an array of weekdays
- *
- * This may also be preceeded by a positive or negative integer. If present,
- * this indicates the nth occurrence of a specific day within the monthly or
- * yearly rrule. For instance, -2TU indicates the second-last tuesday of
- * the month, or year.
- *
- * @var array
- */
- public $byDay;
-
- /**
- * Which days of the month to recur
- *
- * This is an array of days of the months (1-31). The value can also be
- * negative. -5 for instance means the 5th last day of the month.
- *
- * @var array
- */
- public $byMonthDay;
-
- /**
- * Which days of the year to recur.
- *
- * This is an array with days of the year (1 to 366). The values can also
- * be negative. For instance, -1 will always represent the last day of the
- * year. (December 31st).
- *
- * @var array
- */
- public $byYearDay;
-
- /**
- * Which week numbers to recur.
- *
- * This is an array of integers from 1 to 53. The values can also be
- * negative. -1 will always refer to the last week of the year.
- *
- * @var array
- */
- public $byWeekNo;
-
- /**
- * Which months to recur
- *
- * This is an array of integers from 1 to 12.
- *
- * @var array
- */
- public $byMonth;
-
- /**
- * Which items in an existing st to recur.
- *
- * These numbers work together with an existing by* rule. It specifies
- * exactly which items of the existing by-rule to filter.
- *
- * Valid values are 1 to 366 and -1 to -366. As an example, this can be
- * used to recur the last workday of the month.
- *
- * This would be done by setting frequency to 'monthly', byDay to
- * 'MO,TU,WE,TH,FR' and bySetPos to -1.
- *
- * @var array
- */
- public $bySetPos;
-
- /**
- * When a week starts
- *
- * @var string
- */
- public $weekStart = 'MO';
-
- /**
- * The current item in the list
- *
- * @var int
- */
- public $counter = 0;
-
- /**
- * Simple mapping from iCalendar day names to day numbers
- *
- * @var array
- */
- private $dayMap = array(
- 'SU' => 0,
- 'MO' => 1,
- 'TU' => 2,
- 'WE' => 3,
- 'TH' => 4,
- 'FR' => 5,
- 'SA' => 6,
- );
-
- /**
- * Mappings between the day number and english day name.
- *
- * @var array
- */
- private $dayNames = array(
- 0 => 'Sunday',
- 1 => 'Monday',
- 2 => 'Tuesday',
- 3 => 'Wednesday',
- 4 => 'Thursday',
- 5 => 'Friday',
- 6 => 'Saturday',
- );
-
- /**
- * If the current iteration of the event is an overriden event, this
- * property will hold the VObject
- *
- * @var Component
- */
- private $currentOverriddenEvent;
-
- /**
- * This property may contain the date of the next not-overridden event.
- * This date is calculated sometimes a bit early, before overridden events
- * are evaluated.
- *
- * @var DateTime
- */
- private $nextDate;
-
- /**
- * This counts the number of overridden events we've handled so far
- *
- * @var int
- */
- private $handledOverridden = 0;
-
- /**
- * Creates the iterator
- *
- * You should pass a VCALENDAR component, as well as the UID of the event
- * we're going to traverse.
- *
- * @param Component $vcal
- * @param string|null $uid
- */
- public function __construct(Component $vcal, $uid=null) {
-
- if (is_null($uid)) {
- if ($vcal->name === 'VCALENDAR') {
- throw new \InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well');
- }
- $components = array($vcal);
- $uid = (string)$vcal->uid;
- } else {
- $components = $vcal->select('VEVENT');
- }
- foreach($components as $component) {
- if ((string)$component->uid == $uid) {
- if (isset($component->{'RECURRENCE-ID'})) {
- $this->overriddenEvents[$component->DTSTART->getDateTime()->getTimeStamp()] = $component;
- $this->overriddenDates[] = $component->{'RECURRENCE-ID'}->getDateTime();
- } else {
- $this->baseEvent = $component;
- }
- }
- }
-
- ksort($this->overriddenEvents);
-
- if (!$this->baseEvent) {
- throw new \InvalidArgumentException('Could not find a base event with uid: ' . $uid);
- }
-
- $this->startDate = clone $this->baseEvent->DTSTART->getDateTime();
-
- $this->endDate = null;
- if (isset($this->baseEvent->DTEND)) {
- $this->endDate = clone $this->baseEvent->DTEND->getDateTime();
- } else {
- $this->endDate = clone $this->startDate;
- if (isset($this->baseEvent->DURATION)) {
- $this->endDate->add(DateTimeParser::parse($this->baseEvent->DURATION->value));
- } elseif ($this->baseEvent->DTSTART->getDateType()===Property\DateTime::DATE) {
- $this->endDate->modify('+1 day');
- }
- }
- $this->currentDate = clone $this->startDate;
-
- $rrule = (string)$this->baseEvent->RRULE;
-
- $parts = explode(';', $rrule);
-
- // If no rrule was specified, we create a default setting
- if (!$rrule) {
- $this->frequency = 'daily';
- $this->count = 1;
- } else foreach($parts as $part) {
-
- list($key, $value) = explode('=', $part, 2);
-
- switch(strtoupper($key)) {
-
- case 'FREQ' :
- if (!in_array(
- strtolower($value),
- array('secondly','minutely','hourly','daily','weekly','monthly','yearly')
- )) {
- throw new \InvalidArgumentException('Unknown value for FREQ=' . strtoupper($value));
-
- }
- $this->frequency = strtolower($value);
- break;
-
- case 'UNTIL' :
- $this->until = DateTimeParser::parse($value);
-
- // In some cases events are generated with an UNTIL=
- // parameter before the actual start of the event.
- //
- // Not sure why this is happening. We assume that the
- // intention was that the event only recurs once.
- //
- // So we are modifying the parameter so our code doesn't
- // break.
- if($this->until < $this->baseEvent->DTSTART->getDateTime()) {
- $this->until = $this->baseEvent->DTSTART->getDateTime();
- }
- break;
-
- case 'COUNT' :
- $this->count = (int)$value;
- break;
-
- case 'INTERVAL' :
- $this->interval = (int)$value;
- if ($this->interval < 1) {
- throw new \InvalidArgumentException('INTERVAL in RRULE must be a positive integer!');
- }
- break;
-
- case 'BYSECOND' :
- $this->bySecond = explode(',', $value);
- break;
-
- case 'BYMINUTE' :
- $this->byMinute = explode(',', $value);
- break;
-
- case 'BYHOUR' :
- $this->byHour = explode(',', $value);
- break;
-
- case 'BYDAY' :
- $this->byDay = explode(',', strtoupper($value));
- break;
-
- case 'BYMONTHDAY' :
- $this->byMonthDay = explode(',', $value);
- break;
-
- case 'BYYEARDAY' :
- $this->byYearDay = explode(',', $value);
- break;
-
- case 'BYWEEKNO' :
- $this->byWeekNo = explode(',', $value);
- break;
-
- case 'BYMONTH' :
- $this->byMonth = explode(',', $value);
- break;
-
- case 'BYSETPOS' :
- $this->bySetPos = explode(',', $value);
- break;
-
- case 'WKST' :
- $this->weekStart = strtoupper($value);
- break;
-
- }
-
- }
-
- // Parsing exception dates
- if (isset($this->baseEvent->EXDATE)) {
- foreach($this->baseEvent->EXDATE as $exDate) {
-
- foreach(explode(',', (string)$exDate) as $exceptionDate) {
-
- $this->exceptionDates[] =
- DateTimeParser::parse($exceptionDate, $this->startDate->getTimeZone());
-
- }
-
- }
-
- }
-
- }
-
- /**
- * Returns the current item in the list
- *
- * @return DateTime
- */
- public function current() {
-
- if (!$this->valid()) return null;
- return clone $this->currentDate;
-
- }
-
- /**
- * This method returns the startdate for the current iteration of the
- * event.
- *
- * @return DateTime
- */
- public function getDtStart() {
-
- if (!$this->valid()) return null;
- return clone $this->currentDate;
-
- }
-
- /**
- * This method returns the enddate for the current iteration of the
- * event.
- *
- * @return DateTime
- */
- public function getDtEnd() {
-
- if (!$this->valid()) return null;
- $dtEnd = clone $this->currentDate;
- $dtEnd->add( $this->startDate->diff( $this->endDate ) );
- return clone $dtEnd;
-
- }
-
- /**
- * Returns a VEVENT object with the updated start and end date.
- *
- * Any recurrence information is removed, and this function may return an
- * 'overridden' event instead.
- *
- * This method always returns a cloned instance.
- *
- * @return Component\VEvent
- */
- public function getEventObject() {
-
- if ($this->currentOverriddenEvent) {
- return clone $this->currentOverriddenEvent;
- }
- $event = clone $this->baseEvent;
- unset($event->RRULE);
- unset($event->EXDATE);
- unset($event->RDATE);
- unset($event->EXRULE);
-
- $event->DTSTART->setDateTime($this->getDTStart(), $event->DTSTART->getDateType());
- if (isset($event->DTEND)) {
- $event->DTEND->setDateTime($this->getDtEnd(), $event->DTSTART->getDateType());
- }
- if ($this->counter > 0) {
- $event->{'RECURRENCE-ID'} = (string)$event->DTSTART;
- }
-
- return $event;
-
- }
-
- /**
- * Returns the current item number
- *
- * @return int
- */
- public function key() {
-
- return $this->counter;
-
- }
-
- /**
- * Whether or not there is a 'next item'
- *
- * @return bool
- */
- public function valid() {
-
- if (!is_null($this->count)) {
- return $this->counter < $this->count;
- }
- if (!is_null($this->until) && $this->currentDate > $this->until) {
-
- // Need to make sure there's no overridden events past the
- // until date.
- foreach($this->overriddenEvents as $overriddenEvent) {
-
- if ($overriddenEvent->DTSTART->getDateTime() >= $this->currentDate) {
-
- return true;
- }
- }
- return false;
- }
- return true;
-
- }
-
- /**
- * Resets the iterator
- *
- * @return void
- */
- public function rewind() {
-
- $this->currentDate = clone $this->startDate;
- $this->counter = 0;
-
- }
-
- /**
- * This method allows you to quickly go to the next occurrence after the
- * specified date.
- *
- * Note that this checks the current 'endDate', not the 'stardDate'. This
- * means that if you forward to January 1st, the iterator will stop at the
- * first event that ends *after* January 1st.
- *
- * @param DateTime $dt
- * @return void
- */
- public function fastForward(\DateTime $dt) {
-
- while($this->valid() && $this->getDTEnd() <= $dt) {
- $this->next();
- }
-
- }
-
- /**
- * Returns true if this recurring event never ends.
- *
- * @return bool
- */
- public function isInfinite() {
-
- return !$this->count && !$this->until;
-
- }
-
- /**
- * Goes on to the next iteration
- *
- * @return void
- */
- public function next() {
-
- $previousStamp = $this->currentDate->getTimeStamp();
-
- // Finding the next overridden event in line, and storing that for
- // later use.
- $overriddenEvent = null;
- $overriddenDate = null;
- $this->currentOverriddenEvent = null;
-
- foreach($this->overriddenEvents as $index=>$event) {
- if ($index > $previousStamp) {
- $overriddenEvent = $event;
- $overriddenDate = clone $event->DTSTART->getDateTime();
- break;
- }
- }
-
- // If we have a stored 'next date', we will use that.
- if ($this->nextDate) {
- if (!$overriddenDate || $this->nextDate < $overriddenDate) {
- $this->currentDate = $this->nextDate;
- $currentStamp = $this->currentDate->getTimeStamp();
- $this->nextDate = null;
- } else {
- $this->currentDate = clone $overriddenDate;
- $this->currentOverriddenEvent = $overriddenEvent;
- }
- $this->counter++;
- return;
- }
-
- while(true) {
-
- // Otherwise, we find the next event in the normal RRULE
- // sequence.
- switch($this->frequency) {
-
- case 'hourly' :
- $this->nextHourly();
- break;
-
- case 'daily' :
- $this->nextDaily();
- break;
-
- case 'weekly' :
- $this->nextWeekly();
- break;
-
- case 'monthly' :
- $this->nextMonthly();
- break;
-
- case 'yearly' :
- $this->nextYearly();
- break;
-
- }
- $currentStamp = $this->currentDate->getTimeStamp();
-
-
- // Checking exception dates
- foreach($this->exceptionDates as $exceptionDate) {
- if ($this->currentDate == $exceptionDate) {
- $this->counter++;
- continue 2;
- }
- }
- foreach($this->overriddenDates as $check) {
- if ($this->currentDate == $check) {
- continue 2;
- }
- }
- break;
-
- }
-
-
-
- // Is the date we have actually higher than the next overiddenEvent?
- if ($overriddenDate && $this->currentDate > $overriddenDate) {
- $this->nextDate = clone $this->currentDate;
- $this->currentDate = clone $overriddenDate;
- $this->currentOverriddenEvent = $overriddenEvent;
- $this->handledOverridden++;
- }
- $this->counter++;
-
-
- /*
- * If we have overridden events left in the queue, but our counter is
- * running out, we should grab one of those.
- */
- if (!is_null($overriddenEvent) && !is_null($this->count) && count($this->overriddenEvents) - $this->handledOverridden >= ($this->count - $this->counter)) {
-
- $this->currentOverriddenEvent = $overriddenEvent;
- $this->currentDate = clone $overriddenDate;
- $this->handledOverridden++;
-
- }
-
- }
-
- /**
- * Does the processing for advancing the iterator for hourly frequency.
- *
- * @return void
- */
- protected function nextHourly() {
-
- if (!$this->byHour) {
- $this->currentDate->modify('+' . $this->interval . ' hours');
- return;
- }
- }
-
- /**
- * Does the processing for advancing the iterator for daily frequency.
- *
- * @return void
- */
- protected function nextDaily() {
-
- if (!$this->byHour && !$this->byDay) {
- $this->currentDate->modify('+' . $this->interval . ' days');
- return;
- }
-
- if (isset($this->byHour)) {
- $recurrenceHours = $this->getHours();
- }
-
- if (isset($this->byDay)) {
- $recurrenceDays = $this->getDays();
- }
-
- do {
-
- if ($this->byHour) {
- if ($this->currentDate->format('G') == '23') {
- // to obey the interval rule
- $this->currentDate->modify('+' . $this->interval-1 . ' days');
- }
-
- $this->currentDate->modify('+1 hours');
-
- } else {
- $this->currentDate->modify('+' . $this->interval . ' days');
-
- }
-
- // Current day of the week
- $currentDay = $this->currentDate->format('w');
-
- // Current hour of the day
- $currentHour = $this->currentDate->format('G');
-
- } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)));
-
- }
-
- /**
- * Does the processing for advancing the iterator for weekly frequency.
- *
- * @return void
- */
- protected function nextWeekly() {
-
- if (!$this->byHour && !$this->byDay) {
- $this->currentDate->modify('+' . $this->interval . ' weeks');
- return;
- }
-
- if ($this->byHour) {
- $recurrenceHours = $this->getHours();
- }
-
- if ($this->byDay) {
- $recurrenceDays = $this->getDays();
- }
-
- // First day of the week:
- $firstDay = $this->dayMap[$this->weekStart];
-
- do {
-
- if ($this->byHour) {
- $this->currentDate->modify('+1 hours');
- } else {
- $this->currentDate->modify('+1 days');
- }
-
- // Current day of the week
- $currentDay = (int) $this->currentDate->format('w');
-
- // Current hour of the day
- $currentHour = (int) $this->currentDate->format('G');
-
- // We need to roll over to the next week
- if ($currentDay === $firstDay && (!$this->byHour || $currentHour == '0')) {
- $this->currentDate->modify('+' . $this->interval-1 . ' weeks');
-
- // We need to go to the first day of this week, but only if we
- // are not already on this first day of this week.
- if($this->currentDate->format('w') != $firstDay) {
- $this->currentDate->modify('last ' . $this->dayNames[$this->dayMap[$this->weekStart]]);
- }
- }
-
- // We have a match
- } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)));
- }
-
- /**
- * Does the processing for advancing the iterator for monthly frequency.
- *
- * @return void
- */
- protected function nextMonthly() {
-
- $currentDayOfMonth = $this->currentDate->format('j');
- if (!$this->byMonthDay && !$this->byDay) {
-
- // If the current day is higher than the 28th, rollover can
- // occur to the next month. We Must skip these invalid
- // entries.
- if ($currentDayOfMonth < 29) {
- $this->currentDate->modify('+' . $this->interval . ' months');
- } else {
- $increase = 0;
- do {
- $increase++;
- $tempDate = clone $this->currentDate;
- $tempDate->modify('+ ' . ($this->interval*$increase) . ' months');
- } while ($tempDate->format('j') != $currentDayOfMonth);
- $this->currentDate = $tempDate;
- }
- return;
- }
-
- while(true) {
-
- $occurrences = $this->getMonthlyOccurrences();
-
- foreach($occurrences as $occurrence) {
-
- // The first occurrence thats higher than the current
- // day of the month wins.
- if ($occurrence > $currentDayOfMonth) {
- break 2;
- }
-
- }
-
- // If we made it all the way here, it means there were no
- // valid occurrences, and we need to advance to the next
- // month.
- $this->currentDate->modify('first day of this month');
- $this->currentDate->modify('+ ' . $this->interval . ' months');
-
- // This goes to 0 because we need to start counting at hte
- // beginning.
- $currentDayOfMonth = 0;
-
- }
-
- $this->currentDate->setDate($this->currentDate->format('Y'), $this->currentDate->format('n'), $occurrence);
-
- }
-
- /**
- * Does the processing for advancing the iterator for yearly frequency.
- *
- * @return void
- */
- protected function nextYearly() {
-
- $currentMonth = $this->currentDate->format('n');
- $currentYear = $this->currentDate->format('Y');
- $currentDayOfMonth = $this->currentDate->format('j');
-
- // No sub-rules, so we just advance by year
- if (!$this->byMonth) {
-
- // Unless it was a leap day!
- if ($currentMonth==2 && $currentDayOfMonth==29) {
-
- $counter = 0;
- do {
- $counter++;
- // Here we increase the year count by the interval, until
- // we hit a date that's also in a leap year.
- //
- // We could just find the next interval that's dividable by
- // 4, but that would ignore the rule that there's no leap
- // year every year that's dividable by a 100, but not by
- // 400. (1800, 1900, 2100). So we just rely on the datetime
- // functions instead.
- $nextDate = clone $this->currentDate;
- $nextDate->modify('+ ' . ($this->interval*$counter) . ' years');
- } while ($nextDate->format('n')!=2);
- $this->currentDate = $nextDate;
-
- return;
-
- }
-
- // The easiest form
- $this->currentDate->modify('+' . $this->interval . ' years');
- return;
-
- }
-
- $currentMonth = $this->currentDate->format('n');
- $currentYear = $this->currentDate->format('Y');
- $currentDayOfMonth = $this->currentDate->format('j');
-
- $advancedToNewMonth = false;
-
- // If we got a byDay or getMonthDay filter, we must first expand
- // further.
- if ($this->byDay || $this->byMonthDay) {
-
- while(true) {
-
- $occurrences = $this->getMonthlyOccurrences();
-
- foreach($occurrences as $occurrence) {
-
- // The first occurrence that's higher than the current
- // day of the month wins.
- // If we advanced to the next month or year, the first
- // occurrence is always correct.
- if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) {
- break 2;
- }
-
- }
-
- // If we made it here, it means we need to advance to
- // the next month or year.
- $currentDayOfMonth = 1;
- $advancedToNewMonth = true;
- do {
-
- $currentMonth++;
- if ($currentMonth>12) {
- $currentYear+=$this->interval;
- $currentMonth = 1;
- }
- } while (!in_array($currentMonth, $this->byMonth));
-
- $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth);
-
- }
-
- // If we made it here, it means we got a valid occurrence
- $this->currentDate->setDate($currentYear, $currentMonth, $occurrence);
- return;
-
- } else {
-
- // These are the 'byMonth' rules, if there are no byDay or
- // byMonthDay sub-rules.
- do {
-
- $currentMonth++;
- if ($currentMonth>12) {
- $currentYear+=$this->interval;
- $currentMonth = 1;
- }
- } while (!in_array($currentMonth, $this->byMonth));
- $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth);
-
- return;
-
- }
-
- }
-
- /**
- * Returns all the occurrences for a monthly frequency with a 'byDay' or
- * 'byMonthDay' expansion for the current month.
- *
- * The returned list is an array of integers with the day of month (1-31).
- *
- * @return array
- */
- protected function getMonthlyOccurrences() {
-
- $startDate = clone $this->currentDate;
-
- $byDayResults = array();
-
- // Our strategy is to simply go through the byDays, advance the date to
- // that point and add it to the results.
- if ($this->byDay) foreach($this->byDay as $day) {
-
- $dayName = $this->dayNames[$this->dayMap[substr($day,-2)]];
-
- // Dayname will be something like 'wednesday'. Now we need to find
- // all wednesdays in this month.
- $dayHits = array();
-
- $checkDate = clone $startDate;
- $checkDate->modify('first day of this month');
- $checkDate->modify($dayName);
-
- do {
- $dayHits[] = $checkDate->format('j');
- $checkDate->modify('next ' . $dayName);
- } while ($checkDate->format('n') === $startDate->format('n'));
-
- // So now we have 'all wednesdays' for month. It is however
- // possible that the user only really wanted the 1st, 2nd or last
- // wednesday.
- if (strlen($day)>2) {
- $offset = (int)substr($day,0,-2);
-
- if ($offset>0) {
- // It is possible that the day does not exist, such as a
- // 5th or 6th wednesday of the month.
- if (isset($dayHits[$offset-1])) {
- $byDayResults[] = $dayHits[$offset-1];
- }
- } else {
-
- // if it was negative we count from the end of the array
- $byDayResults[] = $dayHits[count($dayHits) + $offset];
- }
- } else {
- // There was no counter (first, second, last wednesdays), so we
- // just need to add the all to the list).
- $byDayResults = array_merge($byDayResults, $dayHits);
-
- }
-
- }
-
- $byMonthDayResults = array();
- if ($this->byMonthDay) foreach($this->byMonthDay as $monthDay) {
-
- // Removing values that are out of range for this month
- if ($monthDay > $startDate->format('t') ||
- $monthDay < 0-$startDate->format('t')) {
- continue;
- }
- if ($monthDay>0) {
- $byMonthDayResults[] = $monthDay;
- } else {
- // Negative values
- $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay;
- }
- }
-
- // If there was just byDay or just byMonthDay, they just specify our
- // (almost) final list. If both were provided, then byDay limits the
- // list.
- if ($this->byMonthDay && $this->byDay) {
- $result = array_intersect($byMonthDayResults, $byDayResults);
- } elseif ($this->byMonthDay) {
- $result = $byMonthDayResults;
- } else {
- $result = $byDayResults;
- }
- $result = array_unique($result);
- sort($result, SORT_NUMERIC);
-
- // The last thing that needs checking is the BYSETPOS. If it's set, it
- // means only certain items in the set survive the filter.
- if (!$this->bySetPos) {
- return $result;
- }
-
- $filteredResult = array();
- foreach($this->bySetPos as $setPos) {
-
- if ($setPos<0) {
- $setPos = count($result)-($setPos+1);
- }
- if (isset($result[$setPos-1])) {
- $filteredResult[] = $result[$setPos-1];
- }
- }
-
- sort($filteredResult, SORT_NUMERIC);
- return $filteredResult;
-
- }
-
- protected function getHours()
- {
- $recurrenceHours = array();
- foreach($this->byHour as $byHour) {
- $recurrenceHours[] = $byHour;
- }
-
- return $recurrenceHours;
- }
-
- protected function getDays()
- {
- $recurrenceDays = array();
- foreach($this->byDay as $byDay) {
-
- // The day may be preceeded with a positive (+n) or
- // negative (-n) integer. However, this does not make
- // sense in 'weekly' so we ignore it here.
- $recurrenceDays[] = $this->dayMap[substr($byDay,-2)];
-
- }
-
- return $recurrenceDays;
- }
-}
-
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/StringUtil.php b/vendor/sabre/vobject/lib/Sabre/VObject/StringUtil.php
deleted file mode 100644
index ea88e1e86..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/StringUtil.php
+++ /dev/null
@@ -1,61 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * Useful utilities for working with various strings.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class StringUtil {
-
- /**
- * Returns true or false depending on if a string is valid UTF-8
- *
- * @param string $str
- * @return bool
- */
- static function isUTF8($str) {
-
- // First check.. mb_check_encoding
- if (!mb_check_encoding($str, 'UTF-8')) {
- return false;
- }
-
- // Control characters
- if (preg_match('%(?:[\x00-\x08\x0B-\x0C\x0E\x0F])%', $str)) {
- return false;
- }
-
- return true;
-
- }
-
- /**
- * This method tries its best to convert the input string to UTF-8.
- *
- * Currently only ISO-5991-1 input and UTF-8 input is supported, but this
- * may be expanded upon if we receive other examples.
- *
- * @param string $str
- * @return string
- */
- static function convertToUTF8($str) {
-
- $encoding = mb_detect_encoding($str , array('UTF-8','ISO-8859-1'), true);
-
- if ($encoding === 'ISO-8859-1') {
- $newStr = utf8_encode($str);
- } else {
- $newStr = $str;
- }
-
- // Removing any control characters
- return (preg_replace('%(?:[\x00-\x08\x0B-\x0C\x0E\x0F])%', '', $newStr));
-
- }
-
-}
-
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/TimeZoneUtil.php b/vendor/sabre/vobject/lib/Sabre/VObject/TimeZoneUtil.php
deleted file mode 100644
index c009a6af0..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/TimeZoneUtil.php
+++ /dev/null
@@ -1,527 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * Time zone name translation
- *
- * This file translates well-known time zone names into "Olson database" time zone names.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Frank Edelhaeuser (fedel@users.sourceforge.net)
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class TimeZoneUtil {
-
- public static $map = array(
-
- // from http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html
- // snapshot taken on 2012/01/16
-
- // windows
- 'AUS Central Standard Time'=>'Australia/Darwin',
- 'AUS Eastern Standard Time'=>'Australia/Sydney',
- 'Afghanistan Standard Time'=>'Asia/Kabul',
- 'Alaskan Standard Time'=>'America/Anchorage',
- 'Arab Standard Time'=>'Asia/Riyadh',
- 'Arabian Standard Time'=>'Asia/Dubai',
- 'Arabic Standard Time'=>'Asia/Baghdad',
- 'Argentina Standard Time'=>'America/Buenos_Aires',
- 'Armenian Standard Time'=>'Asia/Yerevan',
- 'Atlantic Standard Time'=>'America/Halifax',
- 'Azerbaijan Standard Time'=>'Asia/Baku',
- 'Azores Standard Time'=>'Atlantic/Azores',
- 'Bangladesh Standard Time'=>'Asia/Dhaka',
- 'Canada Central Standard Time'=>'America/Regina',
- 'Cape Verde Standard Time'=>'Atlantic/Cape_Verde',
- 'Caucasus Standard Time'=>'Asia/Yerevan',
- 'Cen. Australia Standard Time'=>'Australia/Adelaide',
- 'Central America Standard Time'=>'America/Guatemala',
- 'Central Asia Standard Time'=>'Asia/Almaty',
- 'Central Brazilian Standard Time'=>'America/Cuiaba',
- 'Central Europe Standard Time'=>'Europe/Budapest',
- 'Central European Standard Time'=>'Europe/Warsaw',
- 'Central Pacific Standard Time'=>'Pacific/Guadalcanal',
- 'Central Standard Time'=>'America/Chicago',
- 'Central Standard Time (Mexico)'=>'America/Mexico_City',
- 'China Standard Time'=>'Asia/Shanghai',
- 'Dateline Standard Time'=>'Etc/GMT+12',
- 'E. Africa Standard Time'=>'Africa/Nairobi',
- 'E. Australia Standard Time'=>'Australia/Brisbane',
- 'E. Europe Standard Time'=>'Europe/Minsk',
- 'E. South America Standard Time'=>'America/Sao_Paulo',
- 'Eastern Standard Time'=>'America/New_York',
- 'Egypt Standard Time'=>'Africa/Cairo',
- 'Ekaterinburg Standard Time'=>'Asia/Yekaterinburg',
- 'FLE Standard Time'=>'Europe/Kiev',
- 'Fiji Standard Time'=>'Pacific/Fiji',
- 'GMT Standard Time'=>'Europe/London',
- 'GTB Standard Time'=>'Europe/Istanbul',
- 'Georgian Standard Time'=>'Asia/Tbilisi',
- 'Greenland Standard Time'=>'America/Godthab',
- 'Greenwich Standard Time'=>'Atlantic/Reykjavik',
- 'Hawaiian Standard Time'=>'Pacific/Honolulu',
- 'India Standard Time'=>'Asia/Calcutta',
- 'Iran Standard Time'=>'Asia/Tehran',
- 'Israel Standard Time'=>'Asia/Jerusalem',
- 'Jordan Standard Time'=>'Asia/Amman',
- 'Kamchatka Standard Time'=>'Asia/Kamchatka',
- 'Korea Standard Time'=>'Asia/Seoul',
- 'Magadan Standard Time'=>'Asia/Magadan',
- 'Mauritius Standard Time'=>'Indian/Mauritius',
- 'Mexico Standard Time'=>'America/Mexico_City',
- 'Mexico Standard Time 2'=>'America/Chihuahua',
- 'Mid-Atlantic Standard Time'=>'Etc/GMT-2',
- 'Middle East Standard Time'=>'Asia/Beirut',
- 'Montevideo Standard Time'=>'America/Montevideo',
- 'Morocco Standard Time'=>'Africa/Casablanca',
- 'Mountain Standard Time'=>'America/Denver',
- 'Mountain Standard Time (Mexico)'=>'America/Chihuahua',
- 'Myanmar Standard Time'=>'Asia/Rangoon',
- 'N. Central Asia Standard Time'=>'Asia/Novosibirsk',
- 'Namibia Standard Time'=>'Africa/Windhoek',
- 'Nepal Standard Time'=>'Asia/Katmandu',
- 'New Zealand Standard Time'=>'Pacific/Auckland',
- 'Newfoundland Standard Time'=>'America/St_Johns',
- 'North Asia East Standard Time'=>'Asia/Irkutsk',
- 'North Asia Standard Time'=>'Asia/Krasnoyarsk',
- 'Pacific SA Standard Time'=>'America/Santiago',
- 'Pacific Standard Time'=>'America/Los_Angeles',
- 'Pacific Standard Time (Mexico)'=>'America/Santa_Isabel',
- 'Pakistan Standard Time'=>'Asia/Karachi',
- 'Paraguay Standard Time'=>'America/Asuncion',
- 'Romance Standard Time'=>'Europe/Paris',
- 'Russian Standard Time'=>'Europe/Moscow',
- 'SA Eastern Standard Time'=>'America/Cayenne',
- 'SA Pacific Standard Time'=>'America/Bogota',
- 'SA Western Standard Time'=>'America/La_Paz',
- 'SE Asia Standard Time'=>'Asia/Bangkok',
- 'Samoa Standard Time'=>'Pacific/Apia',
- 'Singapore Standard Time'=>'Asia/Singapore',
- 'South Africa Standard Time'=>'Africa/Johannesburg',
- 'Sri Lanka Standard Time'=>'Asia/Colombo',
- 'Syria Standard Time'=>'Asia/Damascus',
- 'Taipei Standard Time'=>'Asia/Taipei',
- 'Tasmania Standard Time'=>'Australia/Hobart',
- 'Tokyo Standard Time'=>'Asia/Tokyo',
- 'Tonga Standard Time'=>'Pacific/Tongatapu',
- 'US Eastern Standard Time'=>'America/Indianapolis',
- 'US Mountain Standard Time'=>'America/Phoenix',
- 'UTC+12'=>'Etc/GMT-12',
- 'UTC-02'=>'Etc/GMT+2',
- 'UTC-11'=>'Etc/GMT+11',
- 'Ulaanbaatar Standard Time'=>'Asia/Ulaanbaatar',
- 'Venezuela Standard Time'=>'America/Caracas',
- 'Vladivostok Standard Time'=>'Asia/Vladivostok',
- 'W. Australia Standard Time'=>'Australia/Perth',
- 'W. Central Africa Standard Time'=>'Africa/Lagos',
- 'W. Europe Standard Time'=>'Europe/Berlin',
- 'West Asia Standard Time'=>'Asia/Tashkent',
- 'West Pacific Standard Time'=>'Pacific/Port_Moresby',
- 'Yakutsk Standard Time'=>'Asia/Yakutsk',
-
- // Microsoft exchange timezones
- // Source:
- // http://msdn.microsoft.com/en-us/library/ms988620%28v=exchg.65%29.aspx
- //
- // Correct timezones deduced with help from:
- // http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
- 'Universal Coordinated Time' => 'UTC',
- 'Casablanca, Monrovia' => 'Africa/Casablanca',
- 'Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London' => 'Europe/Lisbon',
- 'Greenwich Mean Time; Dublin, Edinburgh, London' => 'Europe/London',
- 'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin',
- 'Belgrade, Pozsony, Budapest, Ljubljana, Prague' => 'Europe/Prague',
- 'Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris',
- 'Paris, Madrid, Brussels, Copenhagen' => 'Europe/Paris',
- 'Prague, Central Europe' => 'Europe/Prague',
- 'Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb' => 'Europe/Sarajevo',
- 'West Central Africa' => 'Africa/Luanda', // This was a best guess
- 'Athens, Istanbul, Minsk' => 'Europe/Athens',
- 'Bucharest' => 'Europe/Bucharest',
- 'Cairo' => 'Africa/Cairo',
- 'Harare, Pretoria' => 'Africa/Harare',
- 'Helsinki, Riga, Tallinn' => 'Europe/Helsinki',
- 'Israel, Jerusalem Standard Time' => 'Asia/Jerusalem',
- 'Baghdad' => 'Asia/Baghdad',
- 'Arab, Kuwait, Riyadh' => 'Asia/Kuwait',
- 'Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow',
- 'East Africa, Nairobi' => 'Africa/Nairobi',
- 'Tehran' => 'Asia/Tehran',
- 'Abu Dhabi, Muscat' => 'Asia/Muscat', // Best guess
- 'Baku, Tbilisi, Yerevan' => 'Asia/Baku',
- 'Kabul' => 'Asia/Kabul',
- 'Ekaterinburg' => 'Asia/Yekaterinburg',
- 'Islamabad, Karachi, Tashkent' => 'Asia/Karachi',
- 'Kolkata, Chennai, Mumbai, New Delhi, India Standard Time' => 'Asia/Calcutta',
- 'Kathmandu, Nepal' => 'Asia/Kathmandu',
- 'Almaty, Novosibirsk, North Central Asia' => 'Asia/Almaty',
- 'Astana, Dhaka' => 'Asia/Dhaka',
- 'Sri Jayawardenepura, Sri Lanka' => 'Asia/Colombo',
- 'Rangoon' => 'Asia/Rangoon',
- 'Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok',
- 'Krasnoyarsk' => 'Asia/Krasnoyarsk',
- 'Beijing, Chongqing, Hong Kong SAR, Urumqi' => 'Asia/Shanghai',
- 'Irkutsk, Ulaan Bataar' => 'Asia/Irkutsk',
- 'Kuala Lumpur, Singapore' => 'Asia/Singapore',
- 'Perth, Western Australia' => 'Australia/Perth',
- 'Taipei' => 'Asia/Taipei',
- 'Osaka, Sapporo, Tokyo' => 'Asia/Tokyo',
- 'Seoul, Korea Standard time' => 'Asia/Seoul',
- 'Yakutsk' => 'Asia/Yakutsk',
- 'Adelaide, Central Australia' => 'Australia/Adelaide',
- 'Darwin' => 'Australia/Darwin',
- 'Brisbane, East Australia' => 'Australia/Brisbane',
- 'Canberra, Melbourne, Sydney, Hobart (year 2000 only)' => 'Australia/Sydney',
- 'Guam, Port Moresby' => 'Pacific/Guam',
- 'Hobart, Tasmania' => 'Australia/Hobart',
- 'Vladivostok' => 'Asia/Vladivostok',
- 'Magadan, Solomon Is., New Caledonia' => 'Asia/Magadan',
- 'Auckland, Wellington' => 'Pacific/Auckland',
- 'Fiji Islands, Kamchatka, Marshall Is.' => 'Pacific/Fiji',
- 'Nuku\'alofa, Tonga' => 'Pacific/Tongatapu',
- 'Azores' => 'Atlantic/Azores',
- 'Cape Verde Is.' => 'Atlantic/Cape_Verde',
- 'Mid-Atlantic' => 'America/Noronha',
- 'Brasilia' => 'America/Sao_Paulo', // Best guess
- 'Buenos Aires' => 'America/Argentina/Buenos_Aires',
- 'Greenland' => 'America/Godthab',
- 'Newfoundland' => 'America/St_Johns',
- 'Atlantic Time (Canada)' => 'America/Halifax',
- 'Caracas, La Paz' => 'America/Caracas',
- 'Santiago' => 'America/Santiago',
- 'Bogota, Lima, Quito' => 'America/Bogota',
- 'Eastern Time (US & Canada)' => 'America/New_York',
- 'Indiana (East)' => 'America/Indiana/Indianapolis',
- 'Central America' => 'America/Guatemala',
- 'Central Time (US & Canada)' => 'America/Chicago',
- 'Mexico City, Tegucigalpa' => 'America/Mexico_City',
- 'Saskatchewan' => 'America/Edmonton',
- 'Arizona' => 'America/Phoenix',
- 'Mountain Time (US & Canada)' => 'America/Denver', // Best guess
- 'Pacific Time (US & Canada); Tijuana' => 'America/Los_Angeles', // Best guess
- 'Alaska' => 'America/Anchorage',
- 'Hawaii' => 'Pacific/Honolulu',
- 'Midway Island, Samoa' => 'Pacific/Midway',
- 'Eniwetok, Kwajalein, Dateline Time' => 'Pacific/Kwajalein',
-
- // The following list are timezone names that could be generated by
- // Lotus / Domino
- 'Dateline' => 'Etc/GMT-12',
- 'Samoa' => 'Pacific/Apia',
- 'Hawaiian' => 'Pacific/Honolulu',
- 'Alaskan' => 'America/Anchorage',
- 'Pacific' => 'America/Los_Angeles',
- 'Pacific Standard Time' => 'America/Los_Angeles',
- 'Mexico Standard Time 2' => 'America/Chihuahua',
- 'Mountain' => 'America/Denver',
- 'Mountain Standard Time' => 'America/Chihuahua',
- 'US Mountain' => 'America/Phoenix',
- 'Canada Central' => 'America/Edmonton',
- 'Central America' => 'America/Guatemala',
- 'Central' => 'America/Chicago',
- 'Central Standard Time' => 'America/Mexico_City',
- 'Mexico' => 'America/Mexico_City',
- 'Eastern' => 'America/New_York',
- 'SA Pacific' => 'America/Bogota',
- 'US Eastern' => 'America/Indiana/Indianapolis',
- 'Venezuela' => 'America/Caracas',
- 'Atlantic' => 'America/Halifax',
- 'Central Brazilian' => 'America/Manaus',
- 'Pacific SA' => 'America/Santiago',
- 'SA Western' => 'America/La_Paz',
- 'Newfoundland' => 'America/St_Johns',
- 'Argentina' => 'America/Argentina/Buenos_Aires',
- 'E. South America' => 'America/Belem',
- 'Greenland' => 'America/Godthab',
- 'Montevideo' => 'America/Montevideo',
- 'SA Eastern' => 'America/Belem',
- 'Mid-Atlantic' => 'Etc/GMT-2',
- 'Azores' => 'Atlantic/Azores',
- 'Cape Verde' => 'Atlantic/Cape_Verde',
- 'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious.. Greenwich is not GMT.
- 'Morocco' => 'Africa/Casablanca',
- 'Central Europe' => 'Europe/Prague',
- 'Central European' => 'Europe/Sarajevo',
- 'Romance' => 'Europe/Paris',
- 'W. Central Africa' => 'Africa/Lagos', // Best guess
- 'W. Europe' => 'Europe/Amsterdam',
- 'E. Europe' => 'Europe/Minsk',
- 'Egypt' => 'Africa/Cairo',
- 'FLE' => 'Europe/Helsinki',
- 'GTB' => 'Europe/Athens',
- 'Israel' => 'Asia/Jerusalem',
- 'Jordan' => 'Asia/Amman',
- 'Middle East' => 'Asia/Beirut',
- 'Namibia' => 'Africa/Windhoek',
- 'South Africa' => 'Africa/Harare',
- 'Arab' => 'Asia/Kuwait',
- 'Arabic' => 'Asia/Baghdad',
- 'E. Africa' => 'Africa/Nairobi',
- 'Georgian' => 'Asia/Tbilisi',
- 'Russian' => 'Europe/Moscow',
- 'Iran' => 'Asia/Tehran',
- 'Arabian' => 'Asia/Muscat',
- 'Armenian' => 'Asia/Yerevan',
- 'Azerbijan' => 'Asia/Baku',
- 'Caucasus' => 'Asia/Yerevan',
- 'Mauritius' => 'Indian/Mauritius',
- 'Afghanistan' => 'Asia/Kabul',
- 'Ekaterinburg' => 'Asia/Yekaterinburg',
- 'Pakistan' => 'Asia/Karachi',
- 'West Asia' => 'Asia/Tashkent',
- 'India' => 'Asia/Calcutta',
- 'Sri Lanka' => 'Asia/Colombo',
- 'Nepal' => 'Asia/Kathmandu',
- 'Central Asia' => 'Asia/Dhaka',
- 'N. Central Asia' => 'Asia/Almaty',
- 'Myanmar' => 'Asia/Rangoon',
- 'North Asia' => 'Asia/Krasnoyarsk',
- 'SE Asia' => 'Asia/Bangkok',
- 'China' => 'Asia/Shanghai',
- 'North Asia East' => 'Asia/Irkutsk',
- 'Singapore' => 'Asia/Singapore',
- 'Taipei' => 'Asia/Taipei',
- 'W. Australia' => 'Australia/Perth',
- 'Korea' => 'Asia/Seoul',
- 'Tokyo' => 'Asia/Tokyo',
- 'Yakutsk' => 'Asia/Yakutsk',
- 'AUS Central' => 'Australia/Darwin',
- 'Cen. Australia' => 'Australia/Adelaide',
- 'AUS Eastern' => 'Australia/Sydney',
- 'E. Australia' => 'Australia/Brisbane',
- 'Tasmania' => 'Australia/Hobart',
- 'Vladivostok' => 'Asia/Vladivostok',
- 'West Pacific' => 'Pacific/Guam',
- 'Central Pacific' => 'Asia/Magadan',
- 'Fiji' => 'Pacific/Fiji',
- 'New Zealand' => 'Pacific/Auckland',
- 'Tonga' => 'Pacific/Tongatapu',
-
- // PHP 5.5.10 failed on a few timezones that were valid before. We're
- // normalizing them here.
- 'CST6CDT' => 'America/Chicago',
- 'Cuba' => 'America/Havana',
- 'Egypt' => 'Africa/Cairo',
- 'Eire' => 'Europe/Dublin',
- 'EST5EDT' => 'America/New_York',
- 'Factory' => 'UTC',
- 'GB-Eire' => 'Europe/London',
- 'GMT0' => 'UTC',
- 'Greenwich' => 'UTC',
- 'Hongkong' => 'Asia/Hong_Kong',
- 'Iceland' => 'Atlantic/Reykjavik',
- 'Iran' => 'Asia/Tehran',
- 'Israel' => 'Asia/Jerusalem',
- 'Jamaica' => 'America/Jamaica',
- 'Japan' => 'Asia/Tokyo',
- 'Kwajalein' => 'Pacific/Kwajalein',
- 'Libya' => 'Africa/Tripoli',
- 'MST7MDT' => 'America/Denver',
- 'Navajo' => 'America/Denver',
- 'NZ-CHAT' => 'Pacific/Chatham',
- 'Poland' => 'Europe/Warsaw',
- 'Portugal' => 'Europe/Lisbon',
- 'PST8PDT' => 'America/Los_Angeles',
- 'Singapore' => 'Asia/Singapore',
- 'Turkey' => 'Europe/Istanbul',
- 'Universal' => 'UTC',
- 'W-SU' => 'Europe/Moscow',
- );
-
- /**
- * List of microsoft exchange timezone ids.
- *
- * Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx
- */
- public static $microsoftExchangeMap = array(
- 0 => 'UTC',
- 31 => 'Africa/Casablanca',
-
- // Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo.
- // I'm not even kidding.. We handle this special case in the
- // getTimeZone method.
- 2 => 'Europe/Lisbon',
- 1 => 'Europe/London',
- 4 => 'Europe/Berlin',
- 6 => 'Europe/Prague',
- 3 => 'Europe/Paris',
- 69 => 'Africa/Luanda', // This was a best guess
- 7 => 'Europe/Athens',
- 5 => 'Europe/Bucharest',
- 49 => 'Africa/Cairo',
- 50 => 'Africa/Harare',
- 59 => 'Europe/Helsinki',
- 27 => 'Asia/Jerusalem',
- 26 => 'Asia/Baghdad',
- 74 => 'Asia/Kuwait',
- 51 => 'Europe/Moscow',
- 56 => 'Africa/Nairobi',
- 25 => 'Asia/Tehran',
- 24 => 'Asia/Muscat', // Best guess
- 54 => 'Asia/Baku',
- 48 => 'Asia/Kabul',
- 58 => 'Asia/Yekaterinburg',
- 47 => 'Asia/Karachi',
- 23 => 'Asia/Calcutta',
- 62 => 'Asia/Kathmandu',
- 46 => 'Asia/Almaty',
- 71 => 'Asia/Dhaka',
- 66 => 'Asia/Colombo',
- 61 => 'Asia/Rangoon',
- 22 => 'Asia/Bangkok',
- 64 => 'Asia/Krasnoyarsk',
- 45 => 'Asia/Shanghai',
- 63 => 'Asia/Irkutsk',
- 21 => 'Asia/Singapore',
- 73 => 'Australia/Perth',
- 75 => 'Asia/Taipei',
- 20 => 'Asia/Tokyo',
- 72 => 'Asia/Seoul',
- 70 => 'Asia/Yakutsk',
- 19 => 'Australia/Adelaide',
- 44 => 'Australia/Darwin',
- 18 => 'Australia/Brisbane',
- 76 => 'Australia/Sydney',
- 43 => 'Pacific/Guam',
- 42 => 'Australia/Hobart',
- 68 => 'Asia/Vladivostok',
- 41 => 'Asia/Magadan',
- 17 => 'Pacific/Auckland',
- 40 => 'Pacific/Fiji',
- 67 => 'Pacific/Tongatapu',
- 29 => 'Atlantic/Azores',
- 53 => 'Atlantic/Cape_Verde',
- 30 => 'America/Noronha',
- 8 => 'America/Sao_Paulo', // Best guess
- 32 => 'America/Argentina/Buenos_Aires',
- 60 => 'America/Godthab',
- 28 => 'America/St_Johns',
- 9 => 'America/Halifax',
- 33 => 'America/Caracas',
- 65 => 'America/Santiago',
- 35 => 'America/Bogota',
- 10 => 'America/New_York',
- 34 => 'America/Indiana/Indianapolis',
- 55 => 'America/Guatemala',
- 11 => 'America/Chicago',
- 37 => 'America/Mexico_City',
- 36 => 'America/Edmonton',
- 38 => 'America/Phoenix',
- 12 => 'America/Denver', // Best guess
- 13 => 'America/Los_Angeles', // Best guess
- 14 => 'America/Anchorage',
- 15 => 'Pacific/Honolulu',
- 16 => 'Pacific/Midway',
- 39 => 'Pacific/Kwajalein',
- );
-
- /**
- * This method will try to find out the correct timezone for an iCalendar
- * date-time value.
- *
- * You must pass the contents of the TZID parameter, as well as the full
- * calendar.
- *
- * If the lookup fails, this method will return the default PHP timezone
- * (as configured using date_default_timezone_set, or the date.timezone ini
- * setting).
- *
- * Alternatively, if $failIfUncertain is set to true, it will throw an
- * exception if we cannot accurately determine the timezone.
- *
- * @param string $tzid
- * @param Sabre\VObject\Component $vcalendar
- * @return DateTimeZone
- */
- static public function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false) {
-
- // First we will just see if the tzid is a support timezone identifier.
- //
- // The only exception is if the timezone starts with (. This is to
- // handle cases where certain microsoft products generate timezone
- // identifiers that for instance look like:
- //
- // (GMT+01.00) Sarajevo/Warsaw/Zagreb
- //
- // Since PHP 5.5.10, the first bit will be used as the timezone and
- // this method will return just GMT+01:00. This is wrong, because it
- // doesn't take DST into account.
- if ($tzid[0]!=='(') {
- try {
- return new \DateTimeZone($tzid);
- } catch (\Exception $e) {
- }
- }
-
- // Next, we check if the tzid is somewhere in our tzid map.
- if (isset(self::$map[$tzid])) {
- return new \DateTimeZone(self::$map[$tzid]);
- }
-
- // Maybe the author was hyper-lazy and just included an offset. We
- // support it, but we aren't happy about it.
- //
- // Note that the path in the source will never be taken from PHP 5.5.10
- // onwards. PHP 5.5.10 supports the "GMT+0100" style of format, so it
- // already gets returned early in this function. Once we drop support
- // for versions under PHP 5.5.10, this bit can be taken out of the
- // source.
- if (preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)) {
- return new \DateTimeZone('Etc/GMT' . $matches[1] . ltrim(substr($matches[2],0,2),'0'));
- }
-
- if ($vcalendar) {
-
- // If that didn't work, we will scan VTIMEZONE objects
- foreach($vcalendar->select('VTIMEZONE') as $vtimezone) {
-
- if ((string)$vtimezone->TZID === $tzid) {
-
- // Some clients add 'X-LIC-LOCATION' with the olson name.
- if (isset($vtimezone->{'X-LIC-LOCATION'})) {
-
- $lic = (string)$vtimezone->{'X-LIC-LOCATION'};
-
- // Libical generators may specify strings like
- // "SystemV/EST5EDT". For those we must remove the
- // SystemV part.
- if (substr($lic,0,8)==='SystemV/') {
- $lic = substr($lic,8);
- }
-
- return self::getTimeZone($lic, null, $failIfUncertain);
-
- }
- // Microsoft may add a magic number, which we also have an
- // answer for.
- if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
- $cdoId = (int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value;
-
- // 2 can mean both Europe/Lisbon and Europe/Sarajevo.
- if ($cdoId===2 && strpos((string)$vtimezone->TZID, 'Sarajevo')!==false) {
- return new \DateTimeZone('Europe/Sarajevo');
- }
-
- if (isset(self::$microsoftExchangeMap[$cdoId])) {
- return new \DateTimeZone(self::$microsoftExchangeMap[$cdoId]);
- }
- }
-
- }
-
- }
-
- }
-
- if ($failIfUncertain) {
- throw new \InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: ' . $tzid);
- }
-
- // If we got all the way here, we default to UTC.
- return new \DateTimeZone(date_default_timezone_get());
-
- }
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Version.php b/vendor/sabre/vobject/lib/Sabre/VObject/Version.php
deleted file mode 100644
index 5b04d0b7a..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Version.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * This class contains the version number for the VObject package
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-class Version {
-
- /**
- * Full version number
- */
- const VERSION = '2.1.4';
-
- /**
- * Stability : alpha, beta, stable
- */
- const STABILITY = 'stable';
-
-}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/includes.php b/vendor/sabre/vobject/lib/Sabre/VObject/includes.php
deleted file mode 100644
index d15329a6a..000000000
--- a/vendor/sabre/vobject/lib/Sabre/VObject/includes.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-/**
- * Includes file
- *
- * This file includes the entire VObject library in one go.
- * The benefit is that an autoloader is not needed, which is often faster.
- *
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Evert Pot (http://evertpot.com/)
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
- */
-
-// Begin includes
-include __DIR__ . '/DateTimeParser.php';
-include __DIR__ . '/ElementList.php';
-include __DIR__ . '/FreeBusyGenerator.php';
-include __DIR__ . '/Node.php';
-include __DIR__ . '/Parameter.php';
-include __DIR__ . '/ParseException.php';
-include __DIR__ . '/Property.php';
-include __DIR__ . '/Reader.php';
-include __DIR__ . '/RecurrenceIterator.php';
-include __DIR__ . '/Splitter/SplitterInterface.php';
-include __DIR__ . '/StringUtil.php';
-include __DIR__ . '/TimeZoneUtil.php';
-include __DIR__ . '/Version.php';
-include __DIR__ . '/Splitter/VCard.php';
-include __DIR__ . '/Component.php';
-include __DIR__ . '/Document.php';
-include __DIR__ . '/Property/Compound.php';
-include __DIR__ . '/Property/DateTime.php';
-include __DIR__ . '/Property/MultiDateTime.php';
-include __DIR__ . '/Splitter/ICalendar.php';
-include __DIR__ . '/Component/VAlarm.php';
-include __DIR__ . '/Component/VCalendar.php';
-include __DIR__ . '/Component/VEvent.php';
-include __DIR__ . '/Component/VFreeBusy.php';
-include __DIR__ . '/Component/VJournal.php';
-include __DIR__ . '/Component/VTodo.php';
-// End includes
diff --git a/vendor/sabre/vobject/lib/Settings.php b/vendor/sabre/vobject/lib/Settings.php
new file mode 100644
index 000000000..3f274ba8e
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Settings.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * This class provides a list of global defaults for vobject.
+ *
+ * Some of these started to appear in various classes, so it made a bit more
+ * sense to centralize them, so it's easier for user to find and change these.
+ *
+ * The global nature of them does mean that changing the settings for one
+ * instance has a global influence.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Settings {
+
+ /**
+ * The minimum date we accept for various calculations with dates, such as
+ * recurrences.
+ *
+ * The choice of 1900 is pretty arbitrary, but it covers most common
+ * use-cases. In particular, it covers birthdates for virtually everyone
+ * alive on earth, which is less than 5 people at the time of writing.
+ */
+ static $minDate = '1900-01-01';
+
+ /**
+ * The maximum date we accept for various calculations with dates, such as
+ * recurrences.
+ *
+ * The choice of 2100 is pretty arbitrary, but should cover most
+ * appointments made for many years to come.
+ */
+ static $maxDate = '2100-01-01';
+
+ /**
+ * The maximum number of recurrences that will be generated.
+ *
+ * This setting limits the maximum of recurring events that this library
+ * generates in its recurrence iterators.
+ *
+ * This is a security measure. Without this, it would be possible to craft
+ * specific events that recur many, many times, potentially DDOSing the
+ * server.
+ *
+ * The default (3500) allows creation of a dialy event that goes on for 10
+ * years, which is hopefully long enough for most.
+ *
+ * Set this value to -1 to disable this control altogether.
+ */
+ static $maxRecurrences = 3500;
+
+}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/ICalendar.php b/vendor/sabre/vobject/lib/Splitter/ICalendar.php
index 657cfb810..c0007ba01 100644
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/ICalendar.php
+++ b/vendor/sabre/vobject/lib/Splitter/ICalendar.php
@@ -3,9 +3,10 @@
namespace Sabre\VObject\Splitter;
use Sabre\VObject;
+use Sabre\VObject\Component\VCalendar;
/**
- * Splitter
+ * Splitter.
*
* This class is responsible for splitting up iCalendar objects.
*
@@ -13,41 +14,44 @@ use Sabre\VObject;
* calendar-objects inside. Objects with identical UID's will be combined into
* a single object.
*
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Dominik Tobschall
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Dominik Tobschall (http://tobschall.de/)
* @author Armin Hackmann
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ * @license http://sabre.io/license/ Modified BSD License
*/
class ICalendar implements SplitterInterface {
/**
- * Timezones
+ * Timezones.
*
* @var array
*/
- protected $vtimezones = array();
+ protected $vtimezones = [];
/**
- * iCalendar objects
+ * iCalendar objects.
*
* @var array
*/
- protected $objects = array();
+ protected $objects = [];
/**
- * Constructor
+ * Constructor.
*
* The splitter should receive an readable file stream as it's input.
*
* @param resource $input
+ * @param int $options Parser options, see the OPTIONS constants.
*/
- public function __construct($input) {
+ function __construct($input, $options = 0) {
- $data = VObject\Reader::read(stream_get_contents($input));
- $vtimezones = array();
- $components = array();
+ $data = VObject\Reader::read($input, $options);
- foreach($data->children as $component) {
+ if (!$data instanceof VObject\Component\VCalendar) {
+ throw new VObject\ParseException('Supplied input could not be parsed as VCALENDAR.');
+ }
+
+ foreach ($data->children() as $component) {
if (!$component instanceof VObject\Component) {
continue;
}
@@ -59,16 +63,14 @@ class ICalendar implements SplitterInterface {
}
// Get component UID for recurring Events search
- if($component->UID) {
- $uid = (string)$component->UID;
- } else {
- // Generating a random UID
- $uid = sha1(microtime()) . '-vobjectimport';
+ if (!$component->UID) {
+ $component->UID = sha1(microtime()) . '-vobjectimport';
}
+ $uid = (string)$component->UID;
// Take care of recurring events
if (!array_key_exists($uid, $this->objects)) {
- $this->objects[$uid] = VObject\Component::create('VCALENDAR');
+ $this->objects[$uid] = new VCalendar();
}
$this->objects[$uid]->add(clone $component);
@@ -84,9 +86,9 @@ class ICalendar implements SplitterInterface {
*
* @return Sabre\VObject\Component|null
*/
- public function getNext() {
+ function getNext() {
- if($object=array_shift($this->objects)) {
+ if ($object = array_shift($this->objects)) {
// create our baseobject
$object->version = '2.0';
@@ -102,10 +104,10 @@ class ICalendar implements SplitterInterface {
} else {
- return null;
+ return;
}
- }
+ }
}
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/SplitterInterface.php b/vendor/sabre/vobject/lib/Splitter/SplitterInterface.php
index c0126883a..8f827cc4b 100644
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/SplitterInterface.php
+++ b/vendor/sabre/vobject/lib/Splitter/SplitterInterface.php
@@ -3,7 +3,7 @@
namespace Sabre\VObject\Splitter;
/**
- * VObject splitter
+ * VObject splitter.
*
* The splitter is responsible for reading a large vCard or iCalendar object,
* and splitting it into multiple objects.
@@ -11,14 +11,14 @@ namespace Sabre\VObject\Splitter;
* This is for example for Card and CalDAV, which require every event and vcard
* to exist in their own objects, instead of one large one.
*
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Dominik Tobschall
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Dominik Tobschall (http://tobschall.de/)
+ * @license http://sabre.io/license/ Modified BSD License
*/
interface SplitterInterface {
/**
- * Constructor
+ * Constructor.
*
* The splitter should receive an readable file stream as it's input.
*
diff --git a/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/VCard.php b/vendor/sabre/vobject/lib/Splitter/VCard.php
index 7a8718c00..0bb82abe9 100644
--- a/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/VCard.php
+++ b/vendor/sabre/vobject/lib/Splitter/VCard.php
@@ -3,9 +3,10 @@
namespace Sabre\VObject\Splitter;
use Sabre\VObject;
+use Sabre\VObject\Parser\MimeDir;
/**
- * Splitter
+ * Splitter.
*
* This class is responsible for splitting up VCard objects.
*
@@ -13,30 +14,39 @@ use Sabre\VObject;
* class checks for BEGIN:VCARD and END:VCARD and parses each encountered
* component individually.
*
- * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
- * @author Dominik Tobschall
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Dominik Tobschall (http://tobschall.de/)
* @author Armin Hackmann
- * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ * @license http://sabre.io/license/ Modified BSD License
*/
class VCard implements SplitterInterface {
/**
- * File handle
+ * File handle.
*
* @var resource
*/
protected $input;
/**
- * Constructor
+ * Persistent parser.
+ *
+ * @var MimeDir
+ */
+ protected $parser;
+
+ /**
+ * Constructor.
*
* The splitter should receive an readable file stream as it's input.
*
* @param resource $input
+ * @param int $options Parser options, see the OPTIONS constants.
*/
- public function __construct($input) {
+ function __construct($input, $options = 0) {
$this->input = $input;
+ $this->parser = new MimeDir($input, $options);
}
@@ -48,25 +58,17 @@ class VCard implements SplitterInterface {
*
* @return Sabre\VObject\Component|null
*/
- public function getNext() {
+ function getNext() {
- $vcard = '';
+ try {
+ $object = $this->parser->parse();
- do {
-
- if (feof($this->input)) {
- return false;
+ if (!$object instanceof VObject\Component\VCard) {
+ throw new VObject\ParseException('The supplied input contained non-VCARD data.');
}
- $line = fgets($this->input);
- $vcard .= $line;
-
- } while(strtoupper(substr($line,0,4))!=="END:");
-
- $object = VObject\Reader::read($vcard);
-
- if($object->name !== 'VCARD') {
- throw new \InvalidArgumentException("Thats no vCard!", 1);
+ } catch (VObject\EofException $e) {
+ return;
}
return $object;
diff --git a/vendor/sabre/vobject/lib/StringUtil.php b/vendor/sabre/vobject/lib/StringUtil.php
new file mode 100644
index 000000000..b8615f2ba
--- /dev/null
+++ b/vendor/sabre/vobject/lib/StringUtil.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * Useful utilities for working with various strings.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class StringUtil {
+
+ /**
+ * Returns true or false depending on if a string is valid UTF-8.
+ *
+ * @param string $str
+ *
+ * @return bool
+ */
+ static function isUTF8($str) {
+
+ // Control characters
+ if (preg_match('%[\x00-\x08\x0B-\x0C\x0E\x0F]%', $str)) {
+ return false;
+ }
+
+ return (bool)preg_match('%%u', $str);
+
+ }
+
+ /**
+ * This method tries its best to convert the input string to UTF-8.
+ *
+ * Currently only ISO-5991-1 input and UTF-8 input is supported, but this
+ * may be expanded upon if we receive other examples.
+ *
+ * @param string $str
+ *
+ * @return string
+ */
+ static function convertToUTF8($str) {
+
+ $encoding = mb_detect_encoding($str, ['UTF-8', 'ISO-8859-1', 'WINDOWS-1252'], true);
+
+ switch ($encoding) {
+ case 'ISO-8859-1' :
+ $newStr = utf8_encode($str);
+ break;
+ /* Unreachable code. Not sure yet how we can improve this
+ * situation.
+ case 'WINDOWS-1252' :
+ $newStr = iconv('cp1252', 'UTF-8', $str);
+ break;
+ */
+ default :
+ $newStr = $str;
+
+ }
+
+ // Removing any control characters
+ return (preg_replace('%(?:[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F])%', '', $newStr));
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/TimeZoneUtil.php b/vendor/sabre/vobject/lib/TimeZoneUtil.php
new file mode 100644
index 000000000..4873daf92
--- /dev/null
+++ b/vendor/sabre/vobject/lib/TimeZoneUtil.php
@@ -0,0 +1,266 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * Time zone name translation.
+ *
+ * This file translates well-known time zone names into "Olson database" time zone names.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Frank Edelhaeuser (fedel@users.sourceforge.net)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class TimeZoneUtil {
+
+ static $map = null;
+
+ /**
+ * List of microsoft exchange timezone ids.
+ *
+ * Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx
+ */
+ static $microsoftExchangeMap = [
+ 0 => 'UTC',
+ 31 => 'Africa/Casablanca',
+
+ // Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo.
+ // I'm not even kidding.. We handle this special case in the
+ // getTimeZone method.
+ 2 => 'Europe/Lisbon',
+ 1 => 'Europe/London',
+ 4 => 'Europe/Berlin',
+ 6 => 'Europe/Prague',
+ 3 => 'Europe/Paris',
+ 69 => 'Africa/Luanda', // This was a best guess
+ 7 => 'Europe/Athens',
+ 5 => 'Europe/Bucharest',
+ 49 => 'Africa/Cairo',
+ 50 => 'Africa/Harare',
+ 59 => 'Europe/Helsinki',
+ 27 => 'Asia/Jerusalem',
+ 26 => 'Asia/Baghdad',
+ 74 => 'Asia/Kuwait',
+ 51 => 'Europe/Moscow',
+ 56 => 'Africa/Nairobi',
+ 25 => 'Asia/Tehran',
+ 24 => 'Asia/Muscat', // Best guess
+ 54 => 'Asia/Baku',
+ 48 => 'Asia/Kabul',
+ 58 => 'Asia/Yekaterinburg',
+ 47 => 'Asia/Karachi',
+ 23 => 'Asia/Calcutta',
+ 62 => 'Asia/Kathmandu',
+ 46 => 'Asia/Almaty',
+ 71 => 'Asia/Dhaka',
+ 66 => 'Asia/Colombo',
+ 61 => 'Asia/Rangoon',
+ 22 => 'Asia/Bangkok',
+ 64 => 'Asia/Krasnoyarsk',
+ 45 => 'Asia/Shanghai',
+ 63 => 'Asia/Irkutsk',
+ 21 => 'Asia/Singapore',
+ 73 => 'Australia/Perth',
+ 75 => 'Asia/Taipei',
+ 20 => 'Asia/Tokyo',
+ 72 => 'Asia/Seoul',
+ 70 => 'Asia/Yakutsk',
+ 19 => 'Australia/Adelaide',
+ 44 => 'Australia/Darwin',
+ 18 => 'Australia/Brisbane',
+ 76 => 'Australia/Sydney',
+ 43 => 'Pacific/Guam',
+ 42 => 'Australia/Hobart',
+ 68 => 'Asia/Vladivostok',
+ 41 => 'Asia/Magadan',
+ 17 => 'Pacific/Auckland',
+ 40 => 'Pacific/Fiji',
+ 67 => 'Pacific/Tongatapu',
+ 29 => 'Atlantic/Azores',
+ 53 => 'Atlantic/Cape_Verde',
+ 30 => 'America/Noronha',
+ 8 => 'America/Sao_Paulo', // Best guess
+ 32 => 'America/Argentina/Buenos_Aires',
+ 60 => 'America/Godthab',
+ 28 => 'America/St_Johns',
+ 9 => 'America/Halifax',
+ 33 => 'America/Caracas',
+ 65 => 'America/Santiago',
+ 35 => 'America/Bogota',
+ 10 => 'America/New_York',
+ 34 => 'America/Indiana/Indianapolis',
+ 55 => 'America/Guatemala',
+ 11 => 'America/Chicago',
+ 37 => 'America/Mexico_City',
+ 36 => 'America/Edmonton',
+ 38 => 'America/Phoenix',
+ 12 => 'America/Denver', // Best guess
+ 13 => 'America/Los_Angeles', // Best guess
+ 14 => 'America/Anchorage',
+ 15 => 'Pacific/Honolulu',
+ 16 => 'Pacific/Midway',
+ 39 => 'Pacific/Kwajalein',
+ ];
+
+ /**
+ * This method will try to find out the correct timezone for an iCalendar
+ * date-time value.
+ *
+ * You must pass the contents of the TZID parameter, as well as the full
+ * calendar.
+ *
+ * If the lookup fails, this method will return the default PHP timezone
+ * (as configured using date_default_timezone_set, or the date.timezone ini
+ * setting).
+ *
+ * Alternatively, if $failIfUncertain is set to true, it will throw an
+ * exception if we cannot accurately determine the timezone.
+ *
+ * @param string $tzid
+ * @param Sabre\VObject\Component $vcalendar
+ *
+ * @return DateTimeZone
+ */
+ static function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false) {
+
+ // First we will just see if the tzid is a support timezone identifier.
+ //
+ // The only exception is if the timezone starts with (. This is to
+ // handle cases where certain microsoft products generate timezone
+ // identifiers that for instance look like:
+ //
+ // (GMT+01.00) Sarajevo/Warsaw/Zagreb
+ //
+ // Since PHP 5.5.10, the first bit will be used as the timezone and
+ // this method will return just GMT+01:00. This is wrong, because it
+ // doesn't take DST into account.
+ if ($tzid[0] !== '(') {
+
+ // PHP has a bug that logs PHP warnings even it shouldn't:
+ // https://bugs.php.net/bug.php?id=67881
+ //
+ // That's why we're checking if we'll be able to successfull instantiate
+ // \DateTimeZone() before doing so. Otherwise we could simply instantiate
+ // and catch the exception.
+ $tzIdentifiers = \DateTimeZone::listIdentifiers();
+
+ try {
+ if (
+ (in_array($tzid, $tzIdentifiers)) ||
+ (preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)) ||
+ (in_array($tzid, self::getIdentifiersBC()))
+ ) {
+ return new \DateTimeZone($tzid);
+ }
+ } catch (\Exception $e) {
+ }
+
+ }
+
+ self::loadTzMaps();
+
+ // Next, we check if the tzid is somewhere in our tzid map.
+ if (isset(self::$map[$tzid])) {
+ return new \DateTimeZone(self::$map[$tzid]);
+ }
+
+ // Maybe the author was hyper-lazy and just included an offset. We
+ // support it, but we aren't happy about it.
+ if (preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)) {
+
+ // Note that the path in the source will never be taken from PHP 5.5.10
+ // onwards. PHP 5.5.10 supports the "GMT+0100" style of format, so it
+ // already gets returned early in this function. Once we drop support
+ // for versions under PHP 5.5.10, this bit can be taken out of the
+ // source.
+ // @codeCoverageIgnoreStart
+ return new \DateTimeZone('Etc/GMT' . $matches[1] . ltrim(substr($matches[2], 0, 2), '0'));
+ // @codeCoverageIgnoreEnd
+ }
+
+ if ($vcalendar) {
+
+ // If that didn't work, we will scan VTIMEZONE objects
+ foreach ($vcalendar->select('VTIMEZONE') as $vtimezone) {
+
+ if ((string)$vtimezone->TZID === $tzid) {
+
+ // Some clients add 'X-LIC-LOCATION' with the olson name.
+ if (isset($vtimezone->{'X-LIC-LOCATION'})) {
+
+ $lic = (string)$vtimezone->{'X-LIC-LOCATION'};
+
+ // Libical generators may specify strings like
+ // "SystemV/EST5EDT". For those we must remove the
+ // SystemV part.
+ if (substr($lic, 0, 8) === 'SystemV/') {
+ $lic = substr($lic, 8);
+ }
+
+ return self::getTimeZone($lic, null, $failIfUncertain);
+
+ }
+ // Microsoft may add a magic number, which we also have an
+ // answer for.
+ if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
+ $cdoId = (int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->getValue();
+
+ // 2 can mean both Europe/Lisbon and Europe/Sarajevo.
+ if ($cdoId === 2 && strpos((string)$vtimezone->TZID, 'Sarajevo') !== false) {
+ return new \DateTimeZone('Europe/Sarajevo');
+ }
+
+ if (isset(self::$microsoftExchangeMap[$cdoId])) {
+ return new \DateTimeZone(self::$microsoftExchangeMap[$cdoId]);
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+ if ($failIfUncertain) {
+ throw new \InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: ' . $tzid);
+ }
+
+ // If we got all the way here, we default to UTC.
+ return new \DateTimeZone(date_default_timezone_get());
+
+ }
+
+ /**
+ * This method will load in all the tz mapping information, if it's not yet
+ * done.
+ */
+ static function loadTzMaps() {
+
+ if (!is_null(self::$map)) return;
+
+ self::$map = array_merge(
+ include __DIR__ . '/timezonedata/windowszones.php',
+ include __DIR__ . '/timezonedata/lotuszones.php',
+ include __DIR__ . '/timezonedata/exchangezones.php',
+ include __DIR__ . '/timezonedata/php-workaround.php'
+ );
+
+ }
+
+ /**
+ * This method returns an array of timezone identifiers, that are supported
+ * by DateTimeZone(), but not returned by DateTimeZone::listIdentifiers().
+ *
+ * We're not using DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC) because:
+ * - It's not supported by some PHP versions as well as HHVM.
+ * - It also returns identifiers, that are invalid values for new DateTimeZone() on some PHP versions.
+ * (See timezonedata/php-bc.php and timezonedata php-workaround.php)
+ *
+ * @return array
+ */
+ static function getIdentifiersBC() {
+ return include __DIR__ . '/timezonedata/php-bc.php';
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/UUIDUtil.php b/vendor/sabre/vobject/lib/UUIDUtil.php
new file mode 100644
index 000000000..24ebe3cf8
--- /dev/null
+++ b/vendor/sabre/vobject/lib/UUIDUtil.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * UUID Utility.
+ *
+ * This class has static methods to generate and validate UUID's.
+ * UUIDs are used a decent amount within various *DAV standards, so it made
+ * sense to include it.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class UUIDUtil {
+
+ /**
+ * Returns a pseudo-random v4 UUID.
+ *
+ * This function is based on a comment by Andrew Moore on php.net
+ *
+ * @see http://www.php.net/manual/en/function.uniqid.php#94959
+ *
+ * @return string
+ */
+ static function getUUID() {
+
+ return sprintf(
+
+ '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
+
+ // 32 bits for "time_low"
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff),
+
+ // 16 bits for "time_mid"
+ mt_rand(0, 0xffff),
+
+ // 16 bits for "time_hi_and_version",
+ // four most significant bits holds version number 4
+ mt_rand(0, 0x0fff) | 0x4000,
+
+ // 16 bits, 8 bits for "clk_seq_hi_res",
+ // 8 bits for "clk_seq_low",
+ // two most significant bits holds zero and one for variant DCE1.1
+ mt_rand(0, 0x3fff) | 0x8000,
+
+ // 48 bits for "node"
+ mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
+ );
+ }
+
+ /**
+ * Checks if a string is a valid UUID.
+ *
+ * @param string $uuid
+ *
+ * @return bool
+ */
+ static function validateUUID($uuid) {
+
+ return preg_match(
+ '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i',
+ $uuid
+ ) !== 0;
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/VCardConverter.php b/vendor/sabre/vobject/lib/VCardConverter.php
new file mode 100644
index 000000000..1f6d016f1
--- /dev/null
+++ b/vendor/sabre/vobject/lib/VCardConverter.php
@@ -0,0 +1,467 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * This utility converts vcards from one version to another.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class VCardConverter {
+
+ /**
+ * Converts a vCard object to a new version.
+ *
+ * targetVersion must be one of:
+ * Document::VCARD21
+ * Document::VCARD30
+ * Document::VCARD40
+ *
+ * Currently only 3.0 and 4.0 as input and output versions.
+ *
+ * 2.1 has some minor support for the input version, it's incomplete at the
+ * moment though.
+ *
+ * If input and output version are identical, a clone is returned.
+ *
+ * @param Component\VCard $input
+ * @param int $targetVersion
+ */
+ function convert(Component\VCard $input, $targetVersion) {
+
+ $inputVersion = $input->getDocumentType();
+ if ($inputVersion === $targetVersion) {
+ return clone $input;
+ }
+
+ if (!in_array($inputVersion, [Document::VCARD21, Document::VCARD30, Document::VCARD40])) {
+ throw new \InvalidArgumentException('Only vCard 2.1, 3.0 and 4.0 are supported for the input data');
+ }
+ if (!in_array($targetVersion, [Document::VCARD30, Document::VCARD40])) {
+ throw new \InvalidArgumentException('You can only use vCard 3.0 or 4.0 for the target version');
+ }
+
+ $newVersion = $targetVersion === Document::VCARD40 ? '4.0' : '3.0';
+
+ $output = new Component\VCard([
+ 'VERSION' => $newVersion,
+ ]);
+
+ // We might have generated a default UID. Remove it!
+ unset($output->UID);
+
+ foreach ($input->children() as $property) {
+
+ $this->convertProperty($input, $output, $property, $targetVersion);
+
+ }
+
+ return $output;
+
+ }
+
+ /**
+ * Handles conversion of a single property.
+ *
+ * @param Component\VCard $input
+ * @param Component\VCard $output
+ * @param Property $property
+ * @param int $targetVersion
+ *
+ * @return void
+ */
+ protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion) {
+
+ // Skipping these, those are automatically added.
+ if (in_array($property->name, ['VERSION', 'PRODID'])) {
+ return;
+ }
+
+ $parameters = $property->parameters();
+ $valueType = null;
+ if (isset($parameters['VALUE'])) {
+ $valueType = $parameters['VALUE']->getValue();
+ unset($parameters['VALUE']);
+ }
+ if (!$valueType) {
+ $valueType = $property->getValueType();
+ }
+ $newProperty = $output->createProperty(
+ $property->name,
+ $property->getParts(),
+ [], // parameters will get added a bit later.
+ $valueType
+ );
+
+
+ if ($targetVersion === Document::VCARD30) {
+
+ if ($property instanceof Property\Uri && in_array($property->name, ['PHOTO', 'LOGO', 'SOUND'])) {
+
+ $newProperty = $this->convertUriToBinary($output, $newProperty);
+
+ } elseif ($property instanceof Property\VCard\DateAndOrTime) {
+
+ // In vCard 4, the birth year may be optional. This is not the
+ // case for vCard 3. Apple has a workaround for this that
+ // allows applications that support Apple's extension still
+ // omit birthyears in vCard 3, but applications that do not
+ // support this, will just use a random birthyear. We're
+ // choosing 1604 for the birthyear, because that's what apple
+ // uses.
+ $parts = DateTimeParser::parseVCardDateTime($property->getValue());
+ if (is_null($parts['year'])) {
+ $newValue = '1604-' . $parts['month'] . '-' . $parts['date'];
+ $newProperty->setValue($newValue);
+ $newProperty['X-APPLE-OMIT-YEAR'] = '1604';
+ }
+
+ if ($newProperty->name == 'ANNIVERSARY') {
+ // Microsoft non-standard anniversary
+ $newProperty->name = 'X-ANNIVERSARY';
+
+ // We also need to add a new apple property for the same
+ // purpose. This apple property needs a 'label' in the same
+ // group, so we first need to find a groupname that doesn't
+ // exist yet.
+ $x = 1;
+ while ($output->select('ITEM' . $x . '.')) {
+ $x++;
+ }
+ $output->add('ITEM' . $x . '.X-ABDATE', $newProperty->getValue(), ['VALUE' => 'DATE-AND-OR-TIME']);
+ $output->add('ITEM' . $x . '.X-ABLABEL', '_$!<Anniversary>!$_');
+ }
+
+ } elseif ($property->name === 'KIND') {
+
+ switch (strtolower($property->getValue())) {
+ case 'org' :
+ // vCard 3.0 does not have an equivalent to KIND:ORG,
+ // but apple has an extension that means the same
+ // thing.
+ $newProperty = $output->createProperty('X-ABSHOWAS', 'COMPANY');
+ break;
+
+ case 'individual' :
+ // Individual is implicit, so we skip it.
+ return;
+
+ case 'group' :
+ // OS X addressbook property
+ $newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND', 'GROUP');
+ break;
+ }
+
+
+ }
+
+ } elseif ($targetVersion === Document::VCARD40) {
+
+ // These properties were removed in vCard 4.0
+ if (in_array($property->name, ['NAME', 'MAILER', 'LABEL', 'CLASS'])) {
+ return;
+ }
+
+ if ($property instanceof Property\Binary) {
+
+ $newProperty = $this->convertBinaryToUri($output, $newProperty, $parameters);
+
+ } elseif ($property instanceof Property\VCard\DateAndOrTime && isset($parameters['X-APPLE-OMIT-YEAR'])) {
+
+ // If a property such as BDAY contained 'X-APPLE-OMIT-YEAR',
+ // then we're stripping the year from the vcard 4 value.
+ $parts = DateTimeParser::parseVCardDateTime($property->getValue());
+ if ($parts['year'] === $property['X-APPLE-OMIT-YEAR']->getValue()) {
+ $newValue = '--' . $parts['month'] . '-' . $parts['date'];
+ $newProperty->setValue($newValue);
+ }
+
+ // Regardless if the year matched or not, we do need to strip
+ // X-APPLE-OMIT-YEAR.
+ unset($parameters['X-APPLE-OMIT-YEAR']);
+
+ }
+ switch ($property->name) {
+ case 'X-ABSHOWAS' :
+ if (strtoupper($property->getValue()) === 'COMPANY') {
+ $newProperty = $output->createProperty('KIND', 'ORG');
+ }
+ break;
+ case 'X-ADDRESSBOOKSERVER-KIND' :
+ if (strtoupper($property->getValue()) === 'GROUP') {
+ $newProperty = $output->createProperty('KIND', 'GROUP');
+ }
+ break;
+ case 'X-ANNIVERSARY' :
+ $newProperty->name = 'ANNIVERSARY';
+ // If we already have an anniversary property with the same
+ // value, ignore.
+ foreach ($output->select('ANNIVERSARY') as $anniversary) {
+ if ($anniversary->getValue() === $newProperty->getValue()) {
+ return;
+ }
+ }
+ break;
+ case 'X-ABDATE' :
+ // Find out what the label was, if it exists.
+ if (!$property->group) {
+ break;
+ }
+ $label = $input->{$property->group . '.X-ABLABEL'};
+
+ // We only support converting anniversaries.
+ if (!$label || $label->getValue() !== '_$!<Anniversary>!$_') {
+ break;
+ }
+
+ // If we already have an anniversary property with the same
+ // value, ignore.
+ foreach ($output->select('ANNIVERSARY') as $anniversary) {
+ if ($anniversary->getValue() === $newProperty->getValue()) {
+ return;
+ }
+ }
+ $newProperty->name = 'ANNIVERSARY';
+ break;
+ // Apple's per-property label system.
+ case 'X-ABLABEL' :
+ if ($newProperty->getValue() === '_$!<Anniversary>!$_') {
+ // We can safely remove these, as they are converted to
+ // ANNIVERSARY properties.
+ return;
+ }
+ break;
+
+ }
+
+ }
+
+ // set property group
+ $newProperty->group = $property->group;
+
+ if ($targetVersion === Document::VCARD40) {
+ $this->convertParameters40($newProperty, $parameters);
+ } else {
+ $this->convertParameters30($newProperty, $parameters);
+ }
+
+ // Lastly, we need to see if there's a need for a VALUE parameter.
+ //
+ // We can do that by instantating a empty property with that name, and
+ // seeing if the default valueType is identical to the current one.
+ $tempProperty = $output->createProperty($newProperty->name);
+ if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
+ $newProperty['VALUE'] = $newProperty->getValueType();
+ }
+
+ $output->add($newProperty);
+
+
+ }
+
+ /**
+ * Converts a BINARY property to a URI property.
+ *
+ * vCard 4.0 no longer supports BINARY properties.
+ *
+ * @param Component\VCard $output
+ * @param Property\Uri $property The input property.
+ * @param $parameters List of parameters that will eventually be added to
+ * the new property.
+ *
+ * @return Property\Uri
+ */
+ protected function convertBinaryToUri(Component\VCard $output, Property\Binary $newProperty, array &$parameters) {
+
+ $value = $newProperty->getValue();
+ $newProperty = $output->createProperty(
+ $newProperty->name,
+ null, // no value
+ [], // no parameters yet
+ 'URI' // Forcing the BINARY type
+ );
+
+ $mimeType = 'application/octet-stream';
+
+ // See if we can find a better mimetype.
+ if (isset($parameters['TYPE'])) {
+
+ $newTypes = [];
+ foreach ($parameters['TYPE']->getParts() as $typePart) {
+ if (in_array(
+ strtoupper($typePart),
+ ['JPEG', 'PNG', 'GIF']
+ )) {
+ $mimeType = 'image/' . strtolower($typePart);
+ } else {
+ $newTypes[] = $typePart;
+ }
+ }
+
+ // If there were any parameters we're not converting to a
+ // mime-type, we need to keep them.
+ if ($newTypes) {
+ $parameters['TYPE']->setParts($newTypes);
+ } else {
+ unset($parameters['TYPE']);
+ }
+
+ }
+
+ $newProperty->setValue('data:' . $mimeType . ';base64,' . base64_encode($value));
+ return $newProperty;
+
+ }
+
+ /**
+ * Converts a URI property to a BINARY property.
+ *
+ * In vCard 4.0 attachments are encoded as data: uri. Even though these may
+ * be valid in vCard 3.0 as well, we should convert those to BINARY if
+ * possible, to improve compatibility.
+ *
+ * @param Component\VCard $output
+ * @param Property\Uri $property The input property.
+ *
+ * @return Property\Binary|null
+ */
+ protected function convertUriToBinary(Component\VCard $output, Property\Uri $newProperty) {
+
+ $value = $newProperty->getValue();
+
+ // Only converting data: uris
+ if (substr($value, 0, 5) !== 'data:') {
+ return $newProperty;
+ }
+
+ $newProperty = $output->createProperty(
+ $newProperty->name,
+ null, // no value
+ [], // no parameters yet
+ 'BINARY'
+ );
+
+ $mimeType = substr($value, 5, strpos($value, ',') - 5);
+ if (strpos($mimeType, ';')) {
+ $mimeType = substr($mimeType, 0, strpos($mimeType, ';'));
+ $newProperty->setValue(base64_decode(substr($value, strpos($value, ',') + 1)));
+ } else {
+ $newProperty->setValue(substr($value, strpos($value, ',') + 1));
+ }
+ unset($value);
+
+ $newProperty['ENCODING'] = 'b';
+ switch ($mimeType) {
+
+ case 'image/jpeg' :
+ $newProperty['TYPE'] = 'JPEG';
+ break;
+ case 'image/png' :
+ $newProperty['TYPE'] = 'PNG';
+ break;
+ case 'image/gif' :
+ $newProperty['TYPE'] = 'GIF';
+ break;
+
+ }
+
+
+ return $newProperty;
+
+ }
+
+ /**
+ * Adds parameters to a new property for vCard 4.0.
+ *
+ * @param Property $newProperty
+ * @param array $parameters
+ *
+ * @return void
+ */
+ protected function convertParameters40(Property $newProperty, array $parameters) {
+
+ // Adding all parameters.
+ foreach ($parameters as $param) {
+
+ // vCard 2.1 allowed parameters with no name
+ if ($param->noName) $param->noName = false;
+
+ switch ($param->name) {
+
+ // We need to see if there's any TYPE=PREF, because in vCard 4
+ // that's now PREF=1.
+ case 'TYPE' :
+ foreach ($param->getParts() as $paramPart) {
+
+ if (strtoupper($paramPart) === 'PREF') {
+ $newProperty->add('PREF', '1');
+ } else {
+ $newProperty->add($param->name, $paramPart);
+ }
+
+ }
+ break;
+ // These no longer exist in vCard 4
+ case 'ENCODING' :
+ case 'CHARSET' :
+ break;
+
+ default :
+ $newProperty->add($param->name, $param->getParts());
+ break;
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Adds parameters to a new property for vCard 3.0.
+ *
+ * @param Property $newProperty
+ * @param array $parameters
+ *
+ * @return void
+ */
+ protected function convertParameters30(Property $newProperty, array $parameters) {
+
+ // Adding all parameters.
+ foreach ($parameters as $param) {
+
+ // vCard 2.1 allowed parameters with no name
+ if ($param->noName) $param->noName = false;
+
+ switch ($param->name) {
+
+ case 'ENCODING' :
+ // This value only existed in vCard 2.1, and should be
+ // removed for anything else.
+ if (strtoupper($param->getValue()) !== 'QUOTED-PRINTABLE') {
+ $newProperty->add($param->name, $param->getParts());
+ }
+ break;
+
+ /*
+ * Converting PREF=1 to TYPE=PREF.
+ *
+ * Any other PREF numbers we'll drop.
+ */
+ case 'PREF' :
+ if ($param->getValue() == '1') {
+ $newProperty->add('TYPE', 'PREF');
+ }
+ break;
+
+ default :
+ $newProperty->add($param->name, $param->getParts());
+ break;
+
+ }
+
+ }
+
+ }
+}
diff --git a/vendor/sabre/vobject/lib/Version.php b/vendor/sabre/vobject/lib/Version.php
new file mode 100644
index 000000000..0b0e16c03
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Version.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Sabre\VObject;
+
+/**
+ * This class contains the version number for the VObject package.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Version {
+
+ /**
+ * Full version number.
+ */
+ const VERSION = '4.1.0';
+
+}
diff --git a/vendor/sabre/vobject/lib/Writer.php b/vendor/sabre/vobject/lib/Writer.php
new file mode 100644
index 000000000..f8a58758d
--- /dev/null
+++ b/vendor/sabre/vobject/lib/Writer.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Sabre\VObject;
+
+use Sabre\Xml;
+
+/**
+ * iCalendar/vCard/jCal/jCard/xCal/xCard writer object.
+ *
+ * This object provides a few (static) convenience methods to quickly access
+ * the serializers.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @author Ivan Enderlin
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+class Writer {
+
+ /**
+ * Serializes a vCard or iCalendar object.
+ *
+ * @param Component $component
+ *
+ * @return string
+ */
+ static function write(Component $component) {
+
+ return $component->serialize();
+
+ }
+
+ /**
+ * Serializes a jCal or jCard object.
+ *
+ * @param Component $component
+ * @param int $options
+ *
+ * @return string
+ */
+ static function writeJson(Component $component, $options = 0) {
+
+ return json_encode($component, $options);
+
+ }
+
+ /**
+ * Serializes a xCal or xCard object.
+ *
+ * @param Component $component
+ *
+ * @return string
+ */
+ static function writeXml(Component $component) {
+
+ $writer = new Xml\Writer();
+ $writer->openMemory();
+ $writer->setIndent(true);
+
+ $writer->startDocument('1.0', 'utf-8');
+
+ if ($component instanceof Component\VCalendar) {
+
+ $writer->startElement('icalendar');
+ $writer->writeAttribute('xmlns', Parser\Xml::XCAL_NAMESPACE);
+
+ } else {
+
+ $writer->startElement('vcards');
+ $writer->writeAttribute('xmlns', Parser\Xml::XCARD_NAMESPACE);
+
+ }
+
+ $component->xmlSerialize($writer);
+
+ $writer->endElement();
+
+ return $writer->outputMemory();
+
+ }
+
+}
diff --git a/vendor/sabre/vobject/lib/timezonedata/exchangezones.php b/vendor/sabre/vobject/lib/timezonedata/exchangezones.php
new file mode 100644
index 000000000..38138354a
--- /dev/null
+++ b/vendor/sabre/vobject/lib/timezonedata/exchangezones.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * Microsoft exchange timezones
+ * Source:
+ * http://msdn.microsoft.com/en-us/library/ms988620%28v=exchg.65%29.aspx.
+ *
+ * Correct timezones deduced with help from:
+ * http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+return [
+ 'Universal Coordinated Time' => 'UTC',
+ 'Casablanca, Monrovia' => 'Africa/Casablanca',
+ 'Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London' => 'Europe/Lisbon',
+ 'Greenwich Mean Time; Dublin, Edinburgh, London' => 'Europe/London',
+ 'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin',
+ 'Belgrade, Pozsony, Budapest, Ljubljana, Prague' => 'Europe/Prague',
+ 'Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris',
+ 'Paris, Madrid, Brussels, Copenhagen' => 'Europe/Paris',
+ 'Prague, Central Europe' => 'Europe/Prague',
+ 'Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb' => 'Europe/Sarajevo',
+ 'West Central Africa' => 'Africa/Luanda', // This was a best guess
+ 'Athens, Istanbul, Minsk' => 'Europe/Athens',
+ 'Bucharest' => 'Europe/Bucharest',
+ 'Cairo' => 'Africa/Cairo',
+ 'Harare, Pretoria' => 'Africa/Harare',
+ 'Helsinki, Riga, Tallinn' => 'Europe/Helsinki',
+ 'Israel, Jerusalem Standard Time' => 'Asia/Jerusalem',
+ 'Baghdad' => 'Asia/Baghdad',
+ 'Arab, Kuwait, Riyadh' => 'Asia/Kuwait',
+ 'Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow',
+ 'East Africa, Nairobi' => 'Africa/Nairobi',
+ 'Tehran' => 'Asia/Tehran',
+ 'Abu Dhabi, Muscat' => 'Asia/Muscat', // Best guess
+ 'Baku, Tbilisi, Yerevan' => 'Asia/Baku',
+ 'Kabul' => 'Asia/Kabul',
+ 'Ekaterinburg' => 'Asia/Yekaterinburg',
+ 'Islamabad, Karachi, Tashkent' => 'Asia/Karachi',
+ 'Kolkata, Chennai, Mumbai, New Delhi, India Standard Time' => 'Asia/Calcutta',
+ 'Kathmandu, Nepal' => 'Asia/Kathmandu',
+ 'Almaty, Novosibirsk, North Central Asia' => 'Asia/Almaty',
+ 'Astana, Dhaka' => 'Asia/Dhaka',
+ 'Sri Jayawardenepura, Sri Lanka' => 'Asia/Colombo',
+ 'Rangoon' => 'Asia/Rangoon',
+ 'Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok',
+ 'Krasnoyarsk' => 'Asia/Krasnoyarsk',
+ 'Beijing, Chongqing, Hong Kong SAR, Urumqi' => 'Asia/Shanghai',
+ 'Irkutsk, Ulaan Bataar' => 'Asia/Irkutsk',
+ 'Kuala Lumpur, Singapore' => 'Asia/Singapore',
+ 'Perth, Western Australia' => 'Australia/Perth',
+ 'Taipei' => 'Asia/Taipei',
+ 'Osaka, Sapporo, Tokyo' => 'Asia/Tokyo',
+ 'Seoul, Korea Standard time' => 'Asia/Seoul',
+ 'Yakutsk' => 'Asia/Yakutsk',
+ 'Adelaide, Central Australia' => 'Australia/Adelaide',
+ 'Darwin' => 'Australia/Darwin',
+ 'Brisbane, East Australia' => 'Australia/Brisbane',
+ 'Canberra, Melbourne, Sydney, Hobart (year 2000 only)' => 'Australia/Sydney',
+ 'Guam, Port Moresby' => 'Pacific/Guam',
+ 'Hobart, Tasmania' => 'Australia/Hobart',
+ 'Vladivostok' => 'Asia/Vladivostok',
+ 'Magadan, Solomon Is., New Caledonia' => 'Asia/Magadan',
+ 'Auckland, Wellington' => 'Pacific/Auckland',
+ 'Fiji Islands, Kamchatka, Marshall Is.' => 'Pacific/Fiji',
+ 'Nuku\'alofa, Tonga' => 'Pacific/Tongatapu',
+ 'Azores' => 'Atlantic/Azores',
+ 'Cape Verde Is.' => 'Atlantic/Cape_Verde',
+ 'Mid-Atlantic' => 'America/Noronha',
+ 'Brasilia' => 'America/Sao_Paulo', // Best guess
+ 'Buenos Aires' => 'America/Argentina/Buenos_Aires',
+ 'Greenland' => 'America/Godthab',
+ 'Newfoundland' => 'America/St_Johns',
+ 'Atlantic Time (Canada)' => 'America/Halifax',
+ 'Caracas, La Paz' => 'America/Caracas',
+ 'Santiago' => 'America/Santiago',
+ 'Bogota, Lima, Quito' => 'America/Bogota',
+ 'Eastern Time (US & Canada)' => 'America/New_York',
+ 'Indiana (East)' => 'America/Indiana/Indianapolis',
+ 'Central America' => 'America/Guatemala',
+ 'Central Time (US & Canada)' => 'America/Chicago',
+ 'Mexico City, Tegucigalpa' => 'America/Mexico_City',
+ 'Saskatchewan' => 'America/Edmonton',
+ 'Arizona' => 'America/Phoenix',
+ 'Mountain Time (US & Canada)' => 'America/Denver', // Best guess
+ 'Pacific Time (US & Canada); Tijuana' => 'America/Los_Angeles', // Best guess
+ 'Alaska' => 'America/Anchorage',
+ 'Hawaii' => 'Pacific/Honolulu',
+ 'Midway Island, Samoa' => 'Pacific/Midway',
+ 'Eniwetok, Kwajalein, Dateline Time' => 'Pacific/Kwajalein',
+];
diff --git a/vendor/sabre/vobject/lib/timezonedata/lotuszones.php b/vendor/sabre/vobject/lib/timezonedata/lotuszones.php
new file mode 100644
index 000000000..7d0785f04
--- /dev/null
+++ b/vendor/sabre/vobject/lib/timezonedata/lotuszones.php
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * The following list are timezone names that could be generated by
+ * Lotus / Domino.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+return [
+ 'Dateline' => 'Etc/GMT-12',
+ 'Samoa' => 'Pacific/Apia',
+ 'Hawaiian' => 'Pacific/Honolulu',
+ 'Alaskan' => 'America/Anchorage',
+ 'Pacific' => 'America/Los_Angeles',
+ 'Pacific Standard Time' => 'America/Los_Angeles',
+ 'Mexico Standard Time 2' => 'America/Chihuahua',
+ 'Mountain' => 'America/Denver',
+ // 'Mountain Standard Time' => 'America/Chihuahua', // conflict with windows timezones.
+ 'US Mountain' => 'America/Phoenix',
+ 'Canada Central' => 'America/Edmonton',
+ 'Central America' => 'America/Guatemala',
+ 'Central' => 'America/Chicago',
+ // 'Central Standard Time' => 'America/Mexico_City', // conflict with windows timezones.
+ 'Mexico' => 'America/Mexico_City',
+ 'Eastern' => 'America/New_York',
+ 'SA Pacific' => 'America/Bogota',
+ 'US Eastern' => 'America/Indiana/Indianapolis',
+ 'Venezuela' => 'America/Caracas',
+ 'Atlantic' => 'America/Halifax',
+ 'Central Brazilian' => 'America/Manaus',
+ 'Pacific SA' => 'America/Santiago',
+ 'SA Western' => 'America/La_Paz',
+ 'Newfoundland' => 'America/St_Johns',
+ 'Argentina' => 'America/Argentina/Buenos_Aires',
+ 'E. South America' => 'America/Belem',
+ 'Greenland' => 'America/Godthab',
+ 'Montevideo' => 'America/Montevideo',
+ 'SA Eastern' => 'America/Belem',
+ // 'Mid-Atlantic' => 'Etc/GMT-2', // conflict with windows timezones.
+ 'Azores' => 'Atlantic/Azores',
+ 'Cape Verde' => 'Atlantic/Cape_Verde',
+ 'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious.. Greenwich is not GMT.
+ 'Morocco' => 'Africa/Casablanca',
+ 'Central Europe' => 'Europe/Prague',
+ 'Central European' => 'Europe/Sarajevo',
+ 'Romance' => 'Europe/Paris',
+ 'W. Central Africa' => 'Africa/Lagos', // Best guess
+ 'W. Europe' => 'Europe/Amsterdam',
+ 'E. Europe' => 'Europe/Minsk',
+ 'Egypt' => 'Africa/Cairo',
+ 'FLE' => 'Europe/Helsinki',
+ 'GTB' => 'Europe/Athens',
+ 'Israel' => 'Asia/Jerusalem',
+ 'Jordan' => 'Asia/Amman',
+ 'Middle East' => 'Asia/Beirut',
+ 'Namibia' => 'Africa/Windhoek',
+ 'South Africa' => 'Africa/Harare',
+ 'Arab' => 'Asia/Kuwait',
+ 'Arabic' => 'Asia/Baghdad',
+ 'E. Africa' => 'Africa/Nairobi',
+ 'Georgian' => 'Asia/Tbilisi',
+ 'Russian' => 'Europe/Moscow',
+ 'Iran' => 'Asia/Tehran',
+ 'Arabian' => 'Asia/Muscat',
+ 'Armenian' => 'Asia/Yerevan',
+ 'Azerbijan' => 'Asia/Baku',
+ 'Caucasus' => 'Asia/Yerevan',
+ 'Mauritius' => 'Indian/Mauritius',
+ 'Afghanistan' => 'Asia/Kabul',
+ 'Ekaterinburg' => 'Asia/Yekaterinburg',
+ 'Pakistan' => 'Asia/Karachi',
+ 'West Asia' => 'Asia/Tashkent',
+ 'India' => 'Asia/Calcutta',
+ 'Sri Lanka' => 'Asia/Colombo',
+ 'Nepal' => 'Asia/Kathmandu',
+ 'Central Asia' => 'Asia/Dhaka',
+ 'N. Central Asia' => 'Asia/Almaty',
+ 'Myanmar' => 'Asia/Rangoon',
+ 'North Asia' => 'Asia/Krasnoyarsk',
+ 'SE Asia' => 'Asia/Bangkok',
+ 'China' => 'Asia/Shanghai',
+ 'North Asia East' => 'Asia/Irkutsk',
+ 'Singapore' => 'Asia/Singapore',
+ 'Taipei' => 'Asia/Taipei',
+ 'W. Australia' => 'Australia/Perth',
+ 'Korea' => 'Asia/Seoul',
+ 'Tokyo' => 'Asia/Tokyo',
+ 'Yakutsk' => 'Asia/Yakutsk',
+ 'AUS Central' => 'Australia/Darwin',
+ 'Cen. Australia' => 'Australia/Adelaide',
+ 'AUS Eastern' => 'Australia/Sydney',
+ 'E. Australia' => 'Australia/Brisbane',
+ 'Tasmania' => 'Australia/Hobart',
+ 'Vladivostok' => 'Asia/Vladivostok',
+ 'West Pacific' => 'Pacific/Guam',
+ 'Central Pacific' => 'Asia/Magadan',
+ 'Fiji' => 'Pacific/Fiji',
+ 'New Zealand' => 'Pacific/Auckland',
+ 'Tonga' => 'Pacific/Tongatapu',
+];
diff --git a/vendor/sabre/vobject/lib/timezonedata/php-bc.php b/vendor/sabre/vobject/lib/timezonedata/php-bc.php
new file mode 100644
index 000000000..906ccb0e4
--- /dev/null
+++ b/vendor/sabre/vobject/lib/timezonedata/php-bc.php
@@ -0,0 +1,154 @@
+<?php
+
+/**
+ * A list of additional PHP timezones that are returned by
+ * DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC)
+ * valid for new DateTimeZone().
+ *
+ * This list does not include those timezone identifiers that we have to map to
+ * a different identifier for some PHP versions (see php-workaround.php).
+ *
+ * Instead of using DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC)
+ * directly, we use this file because DateTimeZone::ALL_WITH_BC is not properly
+ * supported by all PHP version and HHVM.
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+return [
+ 'Africa/Asmera',
+ 'Africa/Timbuktu',
+ 'America/Argentina/ComodRivadavia',
+ 'America/Atka',
+ 'America/Buenos_Aires',
+ 'America/Catamarca',
+ 'America/Coral_Harbour',
+ 'America/Cordoba',
+ 'America/Ensenada',
+ 'America/Fort_Wayne',
+ 'America/Indianapolis',
+ 'America/Jujuy',
+ 'America/Knox_IN',
+ 'America/Louisville',
+ 'America/Mendoza',
+ 'America/Montreal',
+ 'America/Porto_Acre',
+ 'America/Rosario',
+ 'America/Shiprock',
+ 'America/Virgin',
+ 'Antarctica/South_Pole',
+ 'Asia/Ashkhabad',
+ 'Asia/Calcutta',
+ 'Asia/Chungking',
+ 'Asia/Dacca',
+ 'Asia/Istanbul',
+ 'Asia/Katmandu',
+ 'Asia/Macao',
+ 'Asia/Saigon',
+ 'Asia/Tel_Aviv',
+ 'Asia/Thimbu',
+ 'Asia/Ujung_Pandang',
+ 'Asia/Ulan_Bator',
+ 'Atlantic/Faeroe',
+ 'Atlantic/Jan_Mayen',
+ 'Australia/ACT',
+ 'Australia/Canberra',
+ 'Australia/LHI',
+ 'Australia/North',
+ 'Australia/NSW',
+ 'Australia/Queensland',
+ 'Australia/South',
+ 'Australia/Tasmania',
+ 'Australia/Victoria',
+ 'Australia/West',
+ 'Australia/Yancowinna',
+ 'Brazil/Acre',
+ 'Brazil/DeNoronha',
+ 'Brazil/East',
+ 'Brazil/West',
+ 'Canada/Atlantic',
+ 'Canada/Central',
+ 'Canada/East-Saskatchewan',
+ 'Canada/Eastern',
+ 'Canada/Mountain',
+ 'Canada/Newfoundland',
+ 'Canada/Pacific',
+ 'Canada/Saskatchewan',
+ 'Canada/Yukon',
+ 'CET',
+ 'Chile/Continental',
+ 'Chile/EasterIsland',
+ 'EET',
+ 'EST',
+ 'Etc/GMT',
+ 'Etc/GMT+0',
+ 'Etc/GMT+1',
+ 'Etc/GMT+10',
+ 'Etc/GMT+11',
+ 'Etc/GMT+12',
+ 'Etc/GMT+2',
+ 'Etc/GMT+3',
+ 'Etc/GMT+4',
+ 'Etc/GMT+5',
+ 'Etc/GMT+6',
+ 'Etc/GMT+7',
+ 'Etc/GMT+8',
+ 'Etc/GMT+9',
+ 'Etc/GMT-0',
+ 'Etc/GMT-1',
+ 'Etc/GMT-10',
+ 'Etc/GMT-11',
+ 'Etc/GMT-12',
+ 'Etc/GMT-13',
+ 'Etc/GMT-14',
+ 'Etc/GMT-2',
+ 'Etc/GMT-3',
+ 'Etc/GMT-4',
+ 'Etc/GMT-5',
+ 'Etc/GMT-6',
+ 'Etc/GMT-7',
+ 'Etc/GMT-8',
+ 'Etc/GMT-9',
+ 'Etc/GMT0',
+ 'Etc/Greenwich',
+ 'Etc/UCT',
+ 'Etc/Universal',
+ 'Etc/UTC',
+ 'Etc/Zulu',
+ 'Europe/Belfast',
+ 'Europe/Nicosia',
+ 'Europe/Tiraspol',
+ 'GB',
+ 'GMT',
+ 'GMT+0',
+ 'GMT-0',
+ 'HST',
+ 'MET',
+ 'Mexico/BajaNorte',
+ 'Mexico/BajaSur',
+ 'Mexico/General',
+ 'MST',
+ 'NZ',
+ 'Pacific/Ponape',
+ 'Pacific/Samoa',
+ 'Pacific/Truk',
+ 'Pacific/Yap',
+ 'PRC',
+ 'ROC',
+ 'ROK',
+ 'UCT',
+ 'US/Alaska',
+ 'US/Aleutian',
+ 'US/Arizona',
+ 'US/Central',
+ 'US/East-Indiana',
+ 'US/Eastern',
+ 'US/Hawaii',
+ 'US/Indiana-Starke',
+ 'US/Michigan',
+ 'US/Mountain',
+ 'US/Pacific',
+ 'US/Pacific-New',
+ 'US/Samoa',
+ 'WET',
+];
diff --git a/vendor/sabre/vobject/lib/timezonedata/php-workaround.php b/vendor/sabre/vobject/lib/timezonedata/php-workaround.php
new file mode 100644
index 000000000..6b9cb6ef7
--- /dev/null
+++ b/vendor/sabre/vobject/lib/timezonedata/php-workaround.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * A list of PHP timezones that were supported until 5.5.9, removed in
+ * PHP 5.5.10 and re-introduced in PHP 5.5.17.
+ *
+ * DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC) returns them,
+ * but they are invalid for new DateTimeZone(). Fixed in PHP 5.5.17.
+ * https://bugs.php.net/bug.php?id=66985
+ *
+ * Some more info here:
+ * http://evertpot.com/php-5-5-10-timezone-changes/
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+return [
+ 'CST6CDT' => 'America/Chicago',
+ 'Cuba' => 'America/Havana',
+ 'Egypt' => 'Africa/Cairo',
+ 'Eire' => 'Europe/Dublin',
+ 'EST5EDT' => 'America/New_York',
+ 'Factory' => 'UTC',
+ 'GB-Eire' => 'Europe/London',
+ 'GMT0' => 'UTC',
+ 'Greenwich' => 'UTC',
+ 'Hongkong' => 'Asia/Hong_Kong',
+ 'Iceland' => 'Atlantic/Reykjavik',
+ 'Iran' => 'Asia/Tehran',
+ 'Israel' => 'Asia/Jerusalem',
+ 'Jamaica' => 'America/Jamaica',
+ 'Japan' => 'Asia/Tokyo',
+ 'Kwajalein' => 'Pacific/Kwajalein',
+ 'Libya' => 'Africa/Tripoli',
+ 'MST7MDT' => 'America/Denver',
+ 'Navajo' => 'America/Denver',
+ 'NZ-CHAT' => 'Pacific/Chatham',
+ 'Poland' => 'Europe/Warsaw',
+ 'Portugal' => 'Europe/Lisbon',
+ 'PST8PDT' => 'America/Los_Angeles',
+ 'Singapore' => 'Asia/Singapore',
+ 'Turkey' => 'Europe/Istanbul',
+ 'Universal' => 'UTC',
+ 'W-SU' => 'Europe/Moscow',
+ 'Zulu' => 'UTC',
+];
diff --git a/vendor/sabre/vobject/lib/timezonedata/windowszones.php b/vendor/sabre/vobject/lib/timezonedata/windowszones.php
new file mode 100644
index 000000000..ac69847cc
--- /dev/null
+++ b/vendor/sabre/vobject/lib/timezonedata/windowszones.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * Automatically generated timezone file
+ *
+ * Last update: 2015-07-27T16:56:36-04:00
+ * Source: http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
+ *
+ * @copyright Copyright (C) fruux GmbH (https://fruux.com/)
+ * @license http://sabre.io/license/ Modified BSD License
+ */
+
+return [
+ 'AUS Central Standard Time' => 'Australia/Darwin',
+ 'AUS Eastern Standard Time' => 'Australia/Sydney',
+ 'Afghanistan Standard Time' => 'Asia/Kabul',
+ 'Alaskan Standard Time' => 'America/Anchorage',
+ 'Arab Standard Time' => 'Asia/Riyadh',
+ 'Arabian Standard Time' => 'Asia/Dubai',
+ 'Arabic Standard Time' => 'Asia/Baghdad',
+ 'Argentina Standard Time' => 'America/Buenos_Aires',
+ 'Atlantic Standard Time' => 'America/Halifax',
+ 'Azerbaijan Standard Time' => 'Asia/Baku',
+ 'Azores Standard Time' => 'Atlantic/Azores',
+ 'Bahia Standard Time' => 'America/Bahia',
+ 'Bangladesh Standard Time' => 'Asia/Dhaka',
+ 'Belarus Standard Time' => 'Europe/Minsk',
+ 'Canada Central Standard Time' => 'America/Regina',
+ 'Cape Verde Standard Time' => 'Atlantic/Cape_Verde',
+ 'Caucasus Standard Time' => 'Asia/Yerevan',
+ 'Cen. Australia Standard Time' => 'Australia/Adelaide',
+ 'Central America Standard Time' => 'America/Guatemala',
+ 'Central Asia Standard Time' => 'Asia/Almaty',
+ 'Central Brazilian Standard Time' => 'America/Cuiaba',
+ 'Central Europe Standard Time' => 'Europe/Budapest',
+ 'Central European Standard Time' => 'Europe/Warsaw',
+ 'Central Pacific Standard Time' => 'Pacific/Guadalcanal',
+ 'Central Standard Time' => 'America/Chicago',
+ 'Central Standard Time (Mexico)' => 'America/Mexico_City',
+ 'China Standard Time' => 'Asia/Shanghai',
+ 'Dateline Standard Time' => 'Etc/GMT+12',
+ 'E. Africa Standard Time' => 'Africa/Nairobi',
+ 'E. Australia Standard Time' => 'Australia/Brisbane',
+ 'E. South America Standard Time' => 'America/Sao_Paulo',
+ 'Eastern Standard Time' => 'America/New_York',
+ 'Eastern Standard Time (Mexico)' => 'America/Cancun',
+ 'Egypt Standard Time' => 'Africa/Cairo',
+ 'Ekaterinburg Standard Time' => 'Asia/Yekaterinburg',
+ 'FLE Standard Time' => 'Europe/Kiev',
+ 'Fiji Standard Time' => 'Pacific/Fiji',
+ 'GMT Standard Time' => 'Europe/London',
+ 'GTB Standard Time' => 'Europe/Bucharest',
+ 'Georgian Standard Time' => 'Asia/Tbilisi',
+ 'Greenland Standard Time' => 'America/Godthab',
+ 'Greenwich Standard Time' => 'Atlantic/Reykjavik',
+ 'Hawaiian Standard Time' => 'Pacific/Honolulu',
+ 'India Standard Time' => 'Asia/Calcutta',
+ 'Iran Standard Time' => 'Asia/Tehran',
+ 'Israel Standard Time' => 'Asia/Jerusalem',
+ 'Jordan Standard Time' => 'Asia/Amman',
+ 'Kaliningrad Standard Time' => 'Europe/Kaliningrad',
+ 'Korea Standard Time' => 'Asia/Seoul',
+ 'Libya Standard Time' => 'Africa/Tripoli',
+ 'Line Islands Standard Time' => 'Pacific/Kiritimati',
+ 'Magadan Standard Time' => 'Asia/Magadan',
+ 'Mauritius Standard Time' => 'Indian/Mauritius',
+ 'Middle East Standard Time' => 'Asia/Beirut',
+ 'Montevideo Standard Time' => 'America/Montevideo',
+ 'Morocco Standard Time' => 'Africa/Casablanca',
+ 'Mountain Standard Time' => 'America/Denver',
+ 'Mountain Standard Time (Mexico)' => 'America/Chihuahua',
+ 'Myanmar Standard Time' => 'Asia/Rangoon',
+ 'N. Central Asia Standard Time' => 'Asia/Novosibirsk',
+ 'Namibia Standard Time' => 'Africa/Windhoek',
+ 'Nepal Standard Time' => 'Asia/Katmandu',
+ 'New Zealand Standard Time' => 'Pacific/Auckland',
+ 'Newfoundland Standard Time' => 'America/St_Johns',
+ 'North Asia East Standard Time' => 'Asia/Irkutsk',
+ 'North Asia Standard Time' => 'Asia/Krasnoyarsk',
+ 'Pacific SA Standard Time' => 'America/Santiago',
+ 'Pacific Standard Time' => 'America/Los_Angeles',
+ 'Pacific Standard Time (Mexico)' => 'America/Santa_Isabel',
+ 'Pakistan Standard Time' => 'Asia/Karachi',
+ 'Paraguay Standard Time' => 'America/Asuncion',
+ 'Romance Standard Time' => 'Europe/Paris',
+ 'Russia Time Zone 10' => 'Asia/Srednekolymsk',
+ 'Russia Time Zone 11' => 'Asia/Kamchatka',
+ 'Russia Time Zone 3' => 'Europe/Samara',
+ 'Russian Standard Time' => 'Europe/Moscow',
+ 'SA Eastern Standard Time' => 'America/Cayenne',
+ 'SA Pacific Standard Time' => 'America/Bogota',
+ 'SA Western Standard Time' => 'America/La_Paz',
+ 'SE Asia Standard Time' => 'Asia/Bangkok',
+ 'Samoa Standard Time' => 'Pacific/Apia',
+ 'Singapore Standard Time' => 'Asia/Singapore',
+ 'South Africa Standard Time' => 'Africa/Johannesburg',
+ 'Sri Lanka Standard Time' => 'Asia/Colombo',
+ 'Syria Standard Time' => 'Asia/Damascus',
+ 'Taipei Standard Time' => 'Asia/Taipei',
+ 'Tasmania Standard Time' => 'Australia/Hobart',
+ 'Tokyo Standard Time' => 'Asia/Tokyo',
+ 'Tonga Standard Time' => 'Pacific/Tongatapu',
+ 'Turkey Standard Time' => 'Europe/Istanbul',
+ 'US Eastern Standard Time' => 'America/Indianapolis',
+ 'US Mountain Standard Time' => 'America/Phoenix',
+ 'UTC' => 'Etc/GMT',
+ 'UTC+12' => 'Etc/GMT-12',
+ 'UTC-02' => 'Etc/GMT+2',
+ 'UTC-11' => 'Etc/GMT+11',
+ 'Ulaanbaatar Standard Time' => 'Asia/Ulaanbaatar',
+ 'Venezuela Standard Time' => 'America/Caracas',
+ 'Vladivostok Standard Time' => 'Asia/Vladivostok',
+ 'W. Australia Standard Time' => 'Australia/Perth',
+ 'W. Central Africa Standard Time' => 'Africa/Lagos',
+ 'W. Europe Standard Time' => 'Europe/Berlin',
+ 'West Asia Standard Time' => 'Asia/Tashkent',
+ 'West Pacific Standard Time' => 'Pacific/Port_Moresby',
+ 'Yakutsk Standard Time' => 'Asia/Yakutsk',
+];
diff --git a/vendor/sabre/vobject/resources/schema/xcal.rng b/vendor/sabre/vobject/resources/schema/xcal.rng
new file mode 100644
index 000000000..4a51460e7
--- /dev/null
+++ b/vendor/sabre/vobject/resources/schema/xcal.rng
@@ -0,0 +1,1192 @@
+# RELAX NG Schema for iCalendar in XML
+# Extract from RFC6321.
+# Erratum 3042 applied.
+# Erratum 3050 applied.
+# Erratum 3314 applied.
+
+default namespace = "urn:ietf:params:xml:ns:icalendar-2.0"
+
+# 3.2 Property Parameters
+
+# 3.2.1 Alternate Text Representation
+
+altrepparam = element altrep {
+ value-uri
+}
+
+# 3.2.2 Common Name
+
+cnparam = element cn {
+ value-text
+}
+
+# 3.2.3 Calendar User Type
+
+cutypeparam = element cutype {
+ element text {
+ "INDIVIDUAL" |
+ "GROUP" |
+ "RESOURCE" |
+ "ROOM" |
+ "UNKNOWN"
+ }
+}
+
+# 3.2.4 Delegators
+
+delfromparam = element delegated-from {
+ value-cal-address+
+}
+
+# 3.2.5 Delegatees
+
+deltoparam = element delegated-to {
+ value-cal-address+
+}
+
+# 3.2.6 Directory Entry Reference
+
+dirparam = element dir {
+ value-uri
+}
+
+# 3.2.7 Inline Encoding
+
+encodingparam = element encoding {
+ element text {
+ "8BIT" |
+ "BASE64"
+ }
+}
+
+# 3.2.8 Format Type
+
+fmttypeparam = element fmttype {
+ value-text
+}
+
+# 3.2.9 Free/Busy Time Type
+
+fbtypeparam = element fbtype {
+ element text {
+ "FREE" |
+ "BUSY" |
+ "BUSY-UNAVAILABLE" |
+ "BUSY-TENTATIVE"
+ }
+}
+
+# 3.2.10 Language
+
+languageparam = element language {
+ value-text
+}
+
+# 3.2.11 Group or List Membership
+
+memberparam = element member {
+ value-cal-address+
+}
+
+# 3.2.12 Participation Status
+
+partstatparam = element partstat {
+ type-partstat-event |
+ type-partstat-todo |
+ type-partstat-jour
+}
+
+type-partstat-event = (
+ element text {
+ "NEEDS-ACTION" |
+ "ACCEPTED" |
+ "DECLINED" |
+ "TENTATIVE" |
+ "DELEGATED"
+ }
+)
+
+type-partstat-todo = (
+ element text {
+ "NEEDS-ACTION" |
+ "ACCEPTED" |
+ "DECLINED" |
+ "TENTATIVE" |
+ "DELEGATED" |
+ "COMPLETED" |
+ "IN-PROCESS"
+ }
+)
+
+type-partstat-jour = (
+ element text {
+ "NEEDS-ACTION" |
+ "ACCEPTED" |
+ "DECLINED"
+ }
+)
+
+# 3.2.13 Recurrence Identifier Range
+
+rangeparam = element range {
+ element text {
+ "THISANDFUTURE"
+ }
+}
+
+# 3.2.14 Alarm Trigger Relationship
+
+trigrelparam = element related {
+ element text {
+ "START" |
+ "END"
+ }
+}
+
+# 3.2.15 Relationship Type
+
+reltypeparam = element reltype {
+ element text {
+ "PARENT" |
+ "CHILD" |
+ "SIBLING"
+ }
+}
+
+# 3.2.16 Participation Role
+
+roleparam = element role {
+ element text {
+ "CHAIR" |
+ "REQ-PARTICIPANT" |
+ "OPT-PARTICIPANT" |
+ "NON-PARTICIPANT"
+ }
+}
+
+# 3.2.17 RSVP Expectation
+
+rsvpparam = element rsvp {
+ value-boolean
+}
+
+# 3.2.18 Sent By
+
+sentbyparam = element sent-by {
+ value-cal-address
+}
+
+# 3.2.19 Time Zone Identifier
+
+tzidparam = element tzid {
+ value-text
+}
+
+# 3.3 Property Value Data Types
+
+# 3.3.1 BINARY
+
+value-binary = element binary {
+ xsd:string
+}
+
+# 3.3.2 BOOLEAN
+
+value-boolean = element boolean {
+ xsd:boolean
+}
+
+# 3.3.3 CAL-ADDRESS
+
+value-cal-address = element cal-address {
+ xsd:anyURI
+}
+
+# 3.3.4 DATE
+
+pattern-date = xsd:string {
+ pattern = "\d\d\d\d-\d\d-\d\d"
+}
+
+value-date = element date {
+ pattern-date
+}
+
+# 3.3.5 DATE-TIME
+
+pattern-date-time = xsd:string {
+ pattern = "\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ?"
+}
+
+value-date-time = element date-time {
+ pattern-date-time
+}
+
+# 3.3.6 DURATION
+
+pattern-duration = xsd:string {
+ pattern = "(+|-)?P(\d+W)|(\d+D)?"
+ ~ "(T(\d+H(\d+M)?(\d+S)?)|"
+ ~ "(\d+M(\d+S)?)|"
+ ~ "(\d+S))?"
+}
+
+value-duration = element duration {
+ pattern-duration
+}
+
+# 3.3.7 FLOAT
+
+value-float = element float {
+ xsd:float
+}
+
+# 3.3.8 INTEGER
+
+value-integer = element integer {
+ xsd:integer
+}
+
+# 3.3.9 PERIOD
+
+value-period = element period {
+ element start {
+ pattern-date-time
+ },
+ (
+ element end {
+ pattern-date-time
+ } |
+ element duration {
+ pattern-duration
+ }
+ )
+}
+
+# 3.3.10 RECUR
+
+value-recur = element recur {
+ type-freq,
+ (type-until | type-count)?,
+ element interval {
+ xsd:positiveInteger
+ }?,
+ type-bysecond*,
+ type-byminute*,
+ type-byhour*,
+ type-byday*,
+ type-bymonthday*,
+ type-byyearday*,
+ type-byweekno*,
+ type-bymonth*,
+ type-bysetpos*,
+ element wkst { type-weekday }?
+}
+
+type-freq = element freq {
+ "SECONDLY" |
+ "MINUTELY" |
+ "HOURLY" |
+ "DAILY" |
+ "WEEKLY" |
+ "MONTHLY" |
+ "YEARLY"
+}
+
+type-until = element until {
+ type-date |
+ type-date-time
+}
+
+type-count = element count {
+ xsd:positiveInteger
+}
+
+type-bysecond = element bysecond {
+ xsd:nonNegativeInteger
+}
+
+type-byminute = element byminute {
+ xsd:nonNegativeInteger
+}
+
+type-byhour = element byhour {
+ xsd:nonNegativeInteger
+}
+
+type-weekday = (
+ "SU" |
+ "MO" |
+ "TU" |
+ "WE" |
+ "TH" |
+ "FR" |
+ "SA"
+)
+
+type-byday = element byday {
+ xsd:integer?,
+ type-weekday
+}
+
+type-bymonthday = element bymonthday {
+ xsd:integer
+}
+
+type-byyearday = element byyearday {
+ xsd:integer
+}
+
+type-byweekno = element byweekno {
+ xsd:integer
+}
+
+type-bymonth = element bymonth {
+ xsd:positiveInteger
+}
+
+type-bysetpos = element bysetpos {
+ xsd:integer
+}
+
+# 3.3.11 TEXT
+
+value-text = element text {
+ xsd:string
+}
+
+# 3.3.12 TIME
+
+pattern-time = xsd:string {
+ pattern = "\d\d:\d\d:\d\dZ?"
+}
+
+value-time = element time {
+ pattern-time
+}
+
+# 3.3.13 URI
+
+value-uri = element uri {
+ xsd:anyURI
+}
+
+# 3.3.14 UTC-OFFSET
+
+value-utc-offset = element utc-offset {
+ xsd:string { pattern = "(+|-)\d\d:\d\d(:\d\d)?" }
+}
+
+# UNKNOWN
+
+value-unknown = element unknown {
+ xsd:string
+}
+
+# 3.4 iCalendar Stream
+
+start = element icalendar {
+ vcalendar+
+}
+
+# 3.6 Calendar Components
+
+vcalendar = element vcalendar {
+ type-calprops,
+ type-component
+}
+
+type-calprops = element properties {
+ property-prodid &
+ property-version &
+ property-calscale? &
+ property-method?
+}
+
+type-component = element components {
+ (
+ component-vevent |
+ component-vtodo |
+ component-vjournal |
+ component-vfreebusy |
+ component-vtimezone
+ )*
+}
+
+# 3.6.1 Event Component
+
+component-vevent = element vevent {
+ type-eventprop,
+ element components {
+ component-valarm+
+ }?
+}
+
+type-eventprop = element properties {
+ property-dtstamp &
+ property-dtstart &
+ property-uid &
+
+ property-class? &
+ property-created? &
+ property-description? &
+ property-geo? &
+ property-last-mod? &
+ property-location? &
+ property-organizer? &
+ property-priority? &
+ property-seq? &
+ property-status-event? &
+ property-summary? &
+ property-transp? &
+ property-url? &
+ property-recurid? &
+
+ property-rrule? &
+
+ (property-dtend | property-duration)? &
+
+ property-attach* &
+ property-attendee* &
+ property-categories* &
+ property-comment* &
+ property-contact* &
+ property-exdate* &
+ property-rstatus* &
+ property-related* &
+ property-resources* &
+ property-rdate*
+}
+
+# 3.6.2 To-do Component
+
+component-vtodo = element vtodo {
+ type-todoprop,
+ element components {
+ component-valarm+
+ }?
+}
+
+type-todoprop = element properties {
+ property-dtstamp &
+ property-uid &
+
+ property-class? &
+ property-completed? &
+ property-created? &
+ property-description? &
+ property-geo? &
+ property-last-mod? &
+ property-location? &
+ property-organizer? &
+ property-percent? &
+ property-priority? &
+ property-recurid? &
+ property-seq? &
+ property-status-todo? &
+ property-summary? &
+ property-url? &
+
+ property-rrule? &
+
+ (
+ (property-dtstart?, property-dtend? ) |
+ (property-dtstart, property-duration)?
+ ) &
+
+ property-attach* &
+ property-attendee* &
+ property-categories* &
+ property-comment* &
+ property-contact* &
+ property-exdate* &
+ property-rstatus* &
+ property-related* &
+ property-resources* &
+ property-rdate*
+}
+
+# 3.6.3 Journal Component
+
+component-vjournal = element vjournal {
+ type-jourprop
+}
+
+type-jourprop = element properties {
+ property-dtstamp &
+ property-uid &
+
+ property-class? &
+ property-created? &
+ property-dtstart? &
+ property-last-mod? &
+ property-organizer? &
+ property-recurid? &
+ property-seq? &
+ property-status-jour? &
+ property-summary? &
+ property-url? &
+
+ property-rrule? &
+
+ property-attach* &
+ property-attendee* &
+ property-categories* &
+ property-comment* &
+ property-contact* &
+ property-description? &
+ property-exdate* &
+ property-related* &
+ property-rdate* &
+ property-rstatus*
+}
+
+# 3.6.4 Free/Busy Component
+
+component-vfreebusy = element vfreebusy {
+ type-fbprop
+}
+
+type-fbprop = element properties {
+ property-dtstamp &
+ property-uid &
+
+ property-contact? &
+ property-dtstart? &
+ property-dtend? &
+ property-duration? &
+ property-organizer? &
+ property-url? &
+
+ property-attendee* &
+ property-comment* &
+ property-freebusy* &
+ property-rstatus*
+}
+
+# 3.6.5 Time Zone Component
+
+component-vtimezone = element vtimezone {
+ element properties {
+ property-tzid &
+
+ property-last-mod? &
+ property-tzurl?
+ },
+ element components {
+ (component-standard | component-daylight) &
+ component-standard* &
+ component-daylight*
+ }
+}
+
+component-standard = element standard {
+ type-tzprop
+}
+
+component-daylight = element daylight {
+ type-tzprop
+}
+
+type-tzprop = element properties {
+ property-dtstart &
+ property-tzoffsetto &
+ property-tzoffsetfrom &
+
+ property-rrule? &
+
+ property-comment* &
+ property-rdate* &
+ property-tzname*
+}
+
+# 3.6.6 Alarm Component
+
+component-valarm = element valarm {
+ type-audioprop | type-dispprop | type-emailprop
+}
+
+type-audioprop = element properties {
+ property-action &
+
+ property-trigger &
+
+ (property-duration, property-repeat)? &
+
+ property-attach?
+}
+
+type-emailprop = element properties {
+ property-action &
+ property-description &
+ property-trigger &
+ property-summary &
+
+ property-attendee+ &
+
+ (property-duration, property-repeat)? &
+
+ property-attach*
+}
+
+type-dispprop = element properties {
+ property-action &
+ property-description &
+ property-trigger &
+
+ (property-duration, property-repeat)?
+}
+
+# 3.7 Calendar Properties
+
+# 3.7.1 Calendar Scale
+
+property-calscale = element calscale {
+
+ element parameters { empty }?,
+
+ element text { "GREGORIAN" }
+}
+
+# 3.7.2 Method
+
+property-method = element method {
+
+ element parameters { empty }?,
+
+ value-text
+}
+
+# 3.7.3 Product Identifier
+
+property-prodid = element prodid {
+
+ element parameters { empty }?,
+
+ value-text
+}
+
+# 3.7.4 Version
+
+property-version = element version {
+
+ element parameters { empty }?,
+
+ element text { "2.0" }
+}
+
+# 3.8 Component Properties
+
+# 3.8.1 Descriptive Component Properties
+
+# 3.8.1.1 Attachment
+
+property-attach = element attach {
+
+ element parameters {
+ fmttypeparam? &
+ encodingparam?
+ }?,
+
+ value-uri | value-binary
+}
+
+# 3.8.1.2 Categories
+
+property-categories = element categories {
+
+ element parameters {
+ languageparam? &
+ }?,
+
+ value-text+
+}
+
+# 3.8.1.3 Classification
+
+property-class = element class {
+
+ element parameters { empty }?,
+
+ element text {
+ "PUBLIC" |
+ "PRIVATE" |
+ "CONFIDENTIAL"
+ }
+}
+
+# 3.8.1.4 Comment
+
+property-comment = element comment {
+
+ element parameters {
+ altrepparam? &
+ languageparam?
+ }?,
+
+ value-text
+}
+
+# 3.8.1.5 Description
+
+property-description = element description {
+
+ element parameters {
+ altrepparam? &
+ languageparam?
+ }?,
+
+ value-text
+}
+
+# 3.8.1.6 Geographic Position
+
+property-geo = element geo {
+
+ element parameters { empty }?,
+
+ element latitude { xsd:float },
+ element longitude { xsd:float }
+}
+
+# 3.8.1.7 Location
+
+property-location = element location {
+
+ element parameters {
+
+ altrepparam? &
+ languageparam?
+ }?,
+
+ value-text
+}
+
+# 3.8.1.8 Percent Complete
+
+property-percent = element percent-complete {
+
+ element parameters { empty }?,
+
+ value-integer
+}
+
+# 3.8.1.9 Priority
+
+property-priority = element priority {
+
+ element parameters { empty }?,
+
+ value-integer
+}
+
+# 3.8.1.10 Resources
+
+property-resources = element resources {
+
+ element parameters {
+ altrepparam? &
+ languageparam?
+ }?,
+
+ value-text+
+}
+
+# 3.8.1.11 Status
+
+property-status-event = element status {
+
+ element parameters { empty }?,
+
+ element text {
+ "TENTATIVE" |
+ "CONFIRMED" |
+ "CANCELLED"
+ }
+}
+
+property-status-todo = element status {
+
+ element parameters { empty }?,
+
+ element text {
+ "NEEDS-ACTION" |
+ "COMPLETED" |
+ "IN-PROCESS" |
+ "CANCELLED"
+ }
+}
+
+property-status-jour = element status {
+
+ element parameters { empty }?,
+
+ element text {
+ "DRAFT" |
+ "FINAL" |
+ "CANCELLED"
+ }
+}
+
+# 3.8.1.12 Summary
+
+property-summary = element summary {
+
+ element parameters {
+ altrepparam? &
+ languageparam?
+ }?,
+
+ value-text
+}
+
+# 3.8.2 Date and Time Component Properties
+
+# 3.8.2.1 Date/Time Completed
+
+property-completed = element completed {
+
+ element parameters { empty }?,
+
+ value-date-time
+}
+
+# 3.8.2.2 Date/Time End
+
+property-dtend = element dtend {
+
+ element parameters {
+ tzidparam?
+ }?,
+
+ value-date-time |
+ value-date
+}
+
+# 3.8.2.3 Date/Time Due
+
+property-due = element due {
+
+ element parameters {
+ tzidparam?
+ }?,
+
+ value-date-time |
+ value-date
+}
+
+# 3.8.2.4 Date/Time Start
+
+property-dtstart = element dtstart {
+
+ element parameters {
+ tzidparam?
+ }?,
+
+ value-date-time |
+ value-date
+}
+
+# 3.8.2.5 Duration
+
+property-duration = element duration {
+
+ element parameters { empty }?,
+
+ value-duration
+}
+
+# 3.8.2.6 Free/Busy Time
+
+property-freebusy = element freebusy {
+
+ element parameters {
+ fbtypeparam?
+ }?,
+
+
+ value-period+
+}
+
+# 3.8.2.7 Time Transparency
+
+property-transp = element transp {
+
+ element parameters { empty }?,
+
+ element text {
+ "OPAQUE" |
+ "TRANSPARENT"
+ }
+}
+
+# 3.8.3 Time Zone Component Properties
+
+# 3.8.3.1 Time Zone Identifier
+
+property-tzid = element tzid {
+
+ element parameters { empty }?,
+
+ value-text
+}
+
+# 3.8.3.2 Time Zone Name
+
+property-tzname = element tzname {
+
+ element parameters {
+ languageparam?
+ }?,
+
+ value-text
+}
+
+# 3.8.3.3 Time Zone Offset From
+
+property-tzoffsetfrom = element tzoffsetfrom {
+
+ element parameters { empty }?,
+
+ value-utc-offset
+}
+
+# 3.8.3.4 Time Zone Offset To
+
+property-tzoffsetto = element tzoffsetto {
+
+ element parameters { empty }?,
+
+ value-utc-offset
+}
+
+# 3.8.3.5 Time Zone URL
+
+property-tzurl = element tzurl {
+
+ element parameters { empty }?,
+
+ value-uri
+}
+
+# 3.8.4 Relationship Component Properties
+
+# 3.8.4.1 Attendee
+
+property-attendee = element attendee {
+
+ element parameters {
+ cutypeparam? &
+ memberparam? &
+ roleparam? &
+ partstatparam? &
+ rsvpparam? &
+ deltoparam? &
+ delfromparam? &
+ sentbyparam? &
+ cnparam? &
+ dirparam? &
+ languageparam?
+ }?,
+
+ value-cal-address
+}
+
+# 3.8.4.2 Contact
+
+property-contact = element contact {
+
+ element parameters {
+ altrepparam? &
+ languageparam?
+ }?,
+
+ value-text
+}
+
+# 3.8.4.3 Organizer
+
+property-organizer = element organizer {
+
+ element parameters {
+ cnparam? &
+ dirparam? &
+ sentbyparam? &
+ languageparam?
+ }?,
+
+ value-cal-address
+}
+
+# 3.8.4.4 Recurrence ID
+
+property-recurid = element recurrence-id {
+
+ element parameters {
+ tzidparam? &
+ rangeparam?
+ }?,
+
+ value-date-time |
+ value-date
+}
+
+# 3.8.4.5 Related-To
+
+property-related = element related-to {
+
+ element parameters {
+ reltypeparam?
+ }?,
+
+ value-text
+}
+
+# 3.8.4.6 Uniform Resource Locator
+
+property-url = element url {
+
+ element parameters { empty }?,
+
+ value-uri
+}
+
+# 3.8.4.7 Unique Identifier
+
+property-uid = element uid {
+
+ element parameters { empty }?,
+
+ value-text
+}
+
+# 3.8.5 Recurrence Component Properties
+
+# 3.8.5.1 Exception Date/Times
+
+property-exdate = element exdate {
+
+ element parameters {
+ tzidparam?
+ }?,
+
+ value-date-time+ |
+ value-date+
+}
+
+# 3.8.5.2 Recurrence Date/Times
+
+property-rdate = element rdate {
+
+ element parameters {
+ tzidparam?
+ }?,
+
+ value-date-time+ |
+ value-date+ |
+ value-period+
+}
+
+# 3.8.5.3 Recurrence Rule
+
+property-rrule = element rrule {
+
+ element parameters { empty }?,
+
+ value-recur
+}
+
+# 3.8.6 Alarm Component Properties
+
+# 3.8.6.1 Action
+
+property-action = element action {
+
+ element parameters { empty }?,
+
+ element text {
+ "AUDIO" |
+ "DISPLAY" |
+ "EMAIL"
+ }
+}
+
+# 3.8.6.2 Repeat Count
+
+property-repeat = element repeat {
+
+ element parameters { empty }?,
+
+ value-integer
+}
+
+# 3.8.6.3 Trigger
+
+property-trigger = element trigger {
+
+ (
+ element parameters {
+ trigrelparam?
+ }?,
+
+ value-duration
+ ) |
+ (
+ element parameters { empty }?,
+
+ value-date-time
+ )
+}
+
+# 3.8.7 Change Management Component Properties
+
+# 3.8.7.1 Date/Time Created
+
+property-created = element created {
+
+ element parameters { empty }?,
+
+ value-date-time
+}
+
+# 3.8.7.2 Date/Time Stamp
+
+property-dtstamp = element dtstamp {
+
+ element parameters { empty }?,
+
+ value-date-time
+}
+
+# 3.8.7.3 Last Modified
+
+property-last-mod = element last-modified {
+
+ element parameters { empty }?,
+
+ value-date-time
+}
+
+# 3.8.7.4 Sequence Number
+
+property-seq = element sequence {
+
+ element parameters { empty }?,
+
+ value-integer
+}
+
+# 3.8.8 Miscellaneous Component Properties
+
+# 3.8.8.3 Request Status
+
+property-rstatus = element request-status {
+
+ element parameters {
+ languageparam?
+ }?,
+
+ element code { xsd:string },
+ element description { xsd:string },
+ element data { xsd:string }?
+}
diff --git a/vendor/sabre/vobject/resources/schema/xcard.rng b/vendor/sabre/vobject/resources/schema/xcard.rng
new file mode 100644
index 000000000..c0b7cfb35
--- /dev/null
+++ b/vendor/sabre/vobject/resources/schema/xcard.rng
@@ -0,0 +1,388 @@
+# RELAX NG Schema for vCard in XML
+# Extract from RFC6351.
+# Erratum 2994 applied.
+# Erratum 3047 applied.
+# Erratum 3008 applied.
+# Erratum 4247 applied.
+
+default namespace = "urn:ietf:params:xml:ns:vcard-4.0"
+
+### Section 3.3: vCard Format Specification
+#
+# 3.3
+iana-token = xsd:string { pattern = "[a-zA-Z0-9\-]+" }
+x-name = xsd:string { pattern = "x-[a-zA-Z0-9\-]+" }
+
+### Section 4: Value types
+#
+# 4.1
+value-text = element text { text }
+value-text-list = value-text+
+
+# 4.2
+value-uri = element uri { xsd:anyURI }
+
+# 4.3.1
+value-date = element date {
+ xsd:string { pattern = "\d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d" }
+ }
+
+# 4.3.2
+value-time = element time {
+ xsd:string { pattern = "(\d\d(\d\d(\d\d)?)?|-\d\d(\d\d)?|--\d\d)"
+ ~ "(Z|[+\-]\d\d(\d\d)?)?" }
+ }
+
+# 4.3.3
+value-date-time = element date-time {
+ xsd:string { pattern = "(\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?"
+ ~ "(Z|[+\-]\d\d(\d\d)?)?" }
+ }
+
+# 4.3.4
+value-date-and-or-time = value-date | value-date-time | value-time
+
+# 4.3.5
+value-timestamp = element timestamp {
+ xsd:string { pattern = "\d{8}T\d{6}(Z|[+\-]\d\d(\d\d)?)?" }
+ }
+
+# 4.4
+value-boolean = element boolean { xsd:boolean }
+
+# 4.5
+value-integer = element integer { xsd:integer }
+
+# 4.6
+value-float = element float { xsd:float }
+
+# 4.7
+value-utc-offset = element utc-offset {
+ xsd:string { pattern = "[+\-]\d\d(\d\d)?" }
+ }
+
+# 4.8
+value-language-tag = element language-tag {
+ xsd:string { pattern = "([a-z]{2,3}((-[a-z]{3}){0,3})?|[a-z]{4,8})"
+ ~ "(-[a-z]{4})?(-([a-z]{2}|\d{3}))?"
+ ~ "(-([0-9a-z]{5,8}|\d[0-9a-z]{3}))*"
+ ~ "(-[0-9a-wyz](-[0-9a-z]{2,8})+)*"
+ ~ "(-x(-[0-9a-z]{1,8})+)?|x(-[0-9a-z]{1,8})+|"
+ ~ "[a-z]{1,3}(-[0-9a-z]{2,8}){1,2}" }
+ }
+
+### Section 5: Parameters
+#
+# 5.1
+param-language = element language { value-language-tag }?
+
+# 5.2
+param-pref = element pref {
+ element integer {
+ xsd:integer { minInclusive = "1" maxInclusive = "100" }
+ }
+ }?
+
+# 5.4
+param-altid = element altid { value-text }?
+
+# 5.5
+param-pid = element pid {
+ element text { xsd:string { pattern = "\d+(\.\d+)?" } }+
+ }?
+
+# 5.6
+param-type = element type { element text { "work" | "home" }+ }?
+
+# 5.7
+param-mediatype = element mediatype { value-text }?
+
+# 5.8
+param-calscale = element calscale { element text { "gregorian" } }?
+
+# 5.9
+param-sort-as = element sort-as { value-text+ }?
+
+# 5.10
+param-geo = element geo { value-uri }?
+
+# 5.11
+param-tz = element tz { value-text | value-uri }?
+
+### Section 6: Properties
+#
+# 6.1.3
+property-source = element source {
+ element parameters { param-altid, param-pid, param-pref,
+ param-mediatype }?,
+ value-uri
+ }
+
+# 6.1.4
+property-kind = element kind {
+ element text { "individual" | "group" | "org" | "location" |
+ x-name | iana-token }*
+ }
+
+# 6.2.1
+property-fn = element fn {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type }?,
+ value-text
+ }
+
+# 6.2.2
+property-n = element n {
+ element parameters { param-language, param-sort-as, param-altid }?,
+ element surname { text }+,
+ element given { text }+,
+ element additional { text }+,
+ element prefix { text }+,
+ element suffix { text }+
+ }
+
+# 6.2.3
+property-nickname = element nickname {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type }?,
+ value-text-list
+ }
+
+# 6.2.4
+property-photo = element photo {
+ element parameters { param-altid, param-pid, param-pref, param-type,
+ param-mediatype }?,
+ value-uri
+ }
+
+# 6.2.5
+property-bday = element bday {
+ element parameters { param-altid, param-calscale }?,
+ (value-date-and-or-time | value-text)
+ }
+
+# 6.2.6
+property-anniversary = element anniversary {
+ element parameters { param-altid, param-calscale }?,
+ (value-date-and-or-time | value-text)
+ }
+
+# 6.2.7
+property-gender = element gender {
+ element sex { "" | "M" | "F" | "O" | "N" | "U" },
+ element identity { text }?
+ }
+
+# 6.3.1
+param-label = element label { value-text }?
+property-adr = element adr {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type, param-geo, param-tz,
+ param-label }?,
+ element pobox { text }+,
+ element ext { text }+,
+ element street { text }+,
+ element locality { text }+,
+ element region { text }+,
+ element code { text }+,
+ element country { text }+
+ }
+
+# 6.4.1
+property-tel = element tel {
+ element parameters {
+ param-altid,
+ param-pid,
+ param-pref,
+ element type {
+ element text { "work" | "home" | "text" | "voice"
+ | "fax" | "cell" | "video" | "pager"
+ | "textphone" | x-name | iana-token }+
+ }?,
+ param-mediatype
+ }?,
+ (value-text | value-uri)
+ }
+
+# 6.4.2
+property-email = element email {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type }?,
+ value-text
+ }
+
+# 6.4.3
+property-impp = element impp {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ value-uri
+ }
+
+# 6.4.4
+property-lang = element lang {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type }?,
+ value-language-tag
+ }
+
+# 6.5.1
+property-tz = element tz {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ (value-text | value-uri | value-utc-offset)
+ }
+
+# 6.5.2
+property-geo = element geo {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ value-uri
+ }
+
+# 6.6.1
+property-title = element title {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type }?,
+ value-text
+ }
+
+# 6.6.2
+property-role = element role {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type }?,
+ value-text
+ }
+
+# 6.6.3
+property-logo = element logo {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type, param-mediatype }?,
+ value-uri
+ }
+
+# 6.6.4
+property-org = element org {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type, param-sort-as }?,
+ value-text-list
+ }
+
+# 6.6.5
+property-member = element member {
+ element parameters { param-altid, param-pid, param-pref,
+ param-mediatype }?,
+ value-uri
+ }
+
+# 6.6.6
+property-related = element related {
+ element parameters {
+ param-altid,
+ param-pid,
+ param-pref,
+ element type {
+ element text {
+ "work" | "home" | "contact" | "acquaintance" |
+ "friend" | "met" | "co-worker" | "colleague" | "co-resident" |
+ "neighbor" | "child" | "parent" | "sibling" | "spouse" |
+ "kin" | "muse" | "crush" | "date" | "sweetheart" | "me" |
+ "agent" | "emergency"
+ }+
+ }?,
+ param-mediatype
+ }?,
+ (value-uri | value-text)
+ }
+
+# 6.7.1
+property-categories = element categories {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type }?,
+ value-text-list
+ }
+
+# 6.7.2
+property-note = element note {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type }?,
+ value-text
+ }
+
+# 6.7.3
+property-prodid = element prodid { value-text }
+
+# 6.7.4
+property-rev = element rev { value-timestamp }
+
+# 6.7.5
+property-sound = element sound {
+ element parameters { param-language, param-altid, param-pid,
+ param-pref, param-type, param-mediatype }?,
+ value-uri
+ }
+
+# 6.7.6
+property-uid = element uid { value-uri }
+
+# 6.7.7
+property-clientpidmap = element clientpidmap {
+ element sourceid { xsd:positiveInteger },
+ value-uri
+ }
+
+# 6.7.8
+property-url = element url {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ value-uri
+ }
+
+# 6.8.1
+property-key = element key {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ (value-uri | value-text)
+ }
+
+# 6.9.1
+property-fburl = element fburl {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ value-uri
+ }
+
+# 6.9.2
+property-caladruri = element caladruri {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ value-uri
+ }
+
+# 6.9.3
+property-caluri = element caluri {
+ element parameters { param-altid, param-pid, param-pref,
+ param-type, param-mediatype }?,
+ value-uri
+ }
+
+# Top-level grammar
+property = property-adr | property-anniversary | property-bday
+ | property-caladruri | property-caluri | property-categories
+ | property-clientpidmap | property-email | property-fburl
+ | property-fn | property-geo | property-impp | property-key
+ | property-kind | property-lang | property-logo
+ | property-member | property-n | property-nickname
+ | property-note | property-org | property-photo
+ | property-prodid | property-related | property-rev
+ | property-role | property-gender | property-sound
+ | property-source | property-tel | property-title
+ | property-tz | property-uid | property-url
+start = element vcards {
+ element vcard {
+ (property
+ | element group {
+ attribute name { text },
+ property*
+ })+
+ }+
+ }
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VAlarmTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Component/VAlarmTest.php
deleted file mode 100644
index d57be7aa5..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VAlarmTest.php
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject\Component;
-use DateTime;
-use Sabre\VObject\Reader;
-
-class VAlarmTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * @dataProvider timeRangeTestData
- */
- public function testInTimeRange(VAlarm $valarm,$start,$end,$outcome) {
-
- $this->assertEquals($outcome, $valarm->isInTimeRange($start, $end));
-
- }
-
- public function timeRangeTestData() {
-
- $tests = array();
-
- // Hard date and time
- $valarm1 = Component::create('VALARM');
- $valarm1->TRIGGER = '20120312T130000Z';
- $valarm1->TRIGGER['VALUE'] = 'DATE-TIME';
-
- $tests[] = array($valarm1, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true);
- $tests[] = array($valarm1, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false);
-
- // Relation to start time of event
- $valarm2 = Component::create('VALARM');
- $valarm2->TRIGGER = '-P1D';
- $valarm2->TRIGGER['VALUE'] = 'DURATION';
-
- $vevent2 = Component::create('VEVENT');
- $vevent2->DTSTART = '20120313T130000Z';
- $vevent2->add($valarm2);
-
- $tests[] = array($valarm2, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true);
- $tests[] = array($valarm2, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false);
-
- // Relation to end time of event
- $valarm3 = Component::create('VALARM');
- $valarm3->TRIGGER = '-P1D';
- $valarm3->TRIGGER['VALUE'] = 'DURATION';
- $valarm3->TRIGGER['RELATED']= 'END';
-
- $vevent3 = Component::create('VEVENT');
- $vevent3->DTSTART = '20120301T130000Z';
- $vevent3->DTEND = '20120401T130000Z';
- $vevent3->add($valarm3);
-
- $tests[] = array($valarm3, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false);
- $tests[] = array($valarm3, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true);
-
- // Relation to end time of todo
- $valarm4 = Component::create('VALARM');
- $valarm4->TRIGGER = '-P1D';
- $valarm4->TRIGGER['VALUE'] = 'DURATION';
- $valarm4->TRIGGER['RELATED']= 'END';
-
- $vtodo4 = Component::create('VTODO');
- $vtodo4->DTSTART = '20120301T130000Z';
- $vtodo4->DUE = '20120401T130000Z';
- $vtodo4->add($valarm4);
-
- $tests[] = array($valarm4, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false);
- $tests[] = array($valarm4, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true);
-
- // Relation to start time of event + repeat
- $valarm5 = Component::create('VALARM');
- $valarm5->TRIGGER = '-P1D';
- $valarm5->TRIGGER['VALUE'] = 'DURATION';
- $valarm5->REPEAT = 10;
- $valarm5->DURATION = 'P1D';
-
- $vevent5 = Component::create('VEVENT');
- $vevent5->DTSTART = '20120301T130000Z';
- $vevent5->add($valarm5);
-
- $tests[] = array($valarm5, new DateTime('2012-03-09 01:00:00'), new DateTime('2012-03-10 01:00:00'), true);
-
- // Relation to start time of event + duration, but no repeat
- $valarm6 = Component::create('VALARM');
- $valarm6->TRIGGER = '-P1D';
- $valarm6->TRIGGER['VALUE'] = 'DURATION';
- $valarm6->DURATION = 'P1D';
-
- $vevent6 = Component::create('VEVENT');
- $vevent6->DTSTART = '20120313T130000Z';
- $vevent6->add($valarm6);
-
- $tests[] = array($valarm6, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true);
- $tests[] = array($valarm6, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false);
-
-
- // Relation to end time of event (DURATION instead of DTEND)
- $valarm7 = Component::create('VALARM');
- $valarm7->TRIGGER = '-P1D';
- $valarm7->TRIGGER['VALUE'] = 'DURATION';
- $valarm7->TRIGGER['RELATED']= 'END';
-
- $vevent7 = Component::create('VEVENT');
- $vevent7->DTSTART = '20120301T130000Z';
- $vevent7->DURATION = 'P30D';
- $vevent7->add($valarm7);
-
- $tests[] = array($valarm7, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false);
- $tests[] = array($valarm7, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true);
-
- // Relation to end time of event (No DTEND or DURATION)
- $valarm7 = Component::create('VALARM');
- $valarm7->TRIGGER = '-P1D';
- $valarm7->TRIGGER['VALUE'] = 'DURATION';
- $valarm7->TRIGGER['RELATED']= 'END';
-
- $vevent7 = Component::create('VEVENT');
- $vevent7->DTSTART = '20120301T130000Z';
- $vevent7->add($valarm7);
-
- $tests[] = array($valarm7, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), true);
- $tests[] = array($valarm7, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), false);
-
-
- return $tests;
- }
-
- /**
- * @expectedException LogicException
- */
- public function testInTimeRangeInvalidComponent() {
-
- $valarm = Component::create('VALARM');
- $valarm->TRIGGER = '-P1D';
- $valarm->TRIGGER['RELATED'] = 'END';
-
- $vjournal = Component::create('VJOURNAL');
- $vjournal->add($valarm);
-
- $valarm->isInTimeRange(new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'));
-
- }
-
- /**
- * This bug was found and reported on the mailing list.
- */
- public function testInTimeRangeBuggy() {
-
-$input = <<<BLA
-BEGIN:VCALENDAR
-BEGIN:VTODO
-DTSTAMP:20121003T064931Z
-UID:b848cb9a7bb16e464a06c222ca1f8102@examle.com
-STATUS:NEEDS-ACTION
-DUE:20121005T000000Z
-SUMMARY:Task 1
-CATEGORIES:AlarmCategory
-BEGIN:VALARM
-TRIGGER:-PT10M
-ACTION:DISPLAY
-DESCRIPTION:Task 1
-END:VALARM
-END:VTODO
-END:VCALENDAR
-BLA;
-
- $vobj = Reader::read($input);
-
- $this->assertTrue($vobj->VTODO->VALARM->isInTimeRange(new \DateTime('2012-10-01 00:00:00'), new \DateTime('2012-11-01 00:00:00')));
-
- }
-}
-
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCalendarTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCalendarTest.php
deleted file mode 100644
index 1d7e0c603..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCalendarTest.php
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-class VCalendarTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * @dataProvider expandData
- */
- public function testExpand($input, $output) {
-
- $vcal = VObject\Reader::read($input);
- $vcal->expand(
- new \DateTime('2011-12-01'),
- new \DateTime('2011-12-31')
- );
-
- // This will normalize the output
- $output = VObject\Reader::read($output)->serialize();
-
- $this->assertEquals($output, $vcal->serialize());
-
- }
-
- public function expandData() {
-
- $tests = array();
-
- // No data
- $input = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-END:VCALENDAR
-';
-
- $output = $input;
- $tests[] = array($input,$output);
-
-
- // Simple events
- $input = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-UID:bla
-SUMMARY:InExpand
-DTSTART;VALUE=DATE:20111202
-END:VEVENT
-BEGIN:VEVENT
-UID:bla2
-SUMMARY:NotInExpand
-DTSTART;VALUE=DATE:20120101
-END:VEVENT
-END:VCALENDAR
-';
-
- $output = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-UID:bla
-SUMMARY:InExpand
-DTSTART;VALUE=DATE:20111202
-END:VEVENT
-END:VCALENDAR
-';
-
- $tests[] = array($input, $output);
-
- // Removing timezone info
- $input = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:Europe/Paris
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:bla4
-SUMMARY:RemoveTZ info
-DTSTART;TZID=Europe/Paris:20111203T130102
-END:VEVENT
-END:VCALENDAR
-';
-
- $output = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-UID:bla4
-SUMMARY:RemoveTZ info
-DTSTART;VALUE=DATE-TIME:20111203T120102Z
-END:VEVENT
-END:VCALENDAR
-';
-
- $tests[] = array($input, $output);
-
- // Recurrence rule
- $input = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule
-DTSTART:20111125T120000Z
-DTEND:20111125T130000Z
-RRULE:FREQ=WEEKLY
-END:VEVENT
-END:VCALENDAR
-';
-
- $output = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule
-DTSTART;VALUE=DATE-TIME:20111202T120000Z
-DTEND;VALUE=DATE-TIME:20111202T130000Z
-RECURRENCE-ID:20111202T120000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule
-DTSTART;VALUE=DATE-TIME:20111209T120000Z
-DTEND;VALUE=DATE-TIME:20111209T130000Z
-RECURRENCE-ID:20111209T120000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule
-DTSTART;VALUE=DATE-TIME:20111216T120000Z
-DTEND;VALUE=DATE-TIME:20111216T130000Z
-RECURRENCE-ID:20111216T120000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule
-DTSTART;VALUE=DATE-TIME:20111223T120000Z
-DTEND;VALUE=DATE-TIME:20111223T130000Z
-RECURRENCE-ID:20111223T120000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule
-DTSTART;VALUE=DATE-TIME:20111230T120000Z
-DTEND;VALUE=DATE-TIME:20111230T130000Z
-RECURRENCE-ID:20111230T120000Z
-END:VEVENT
-END:VCALENDAR
-';
-
- // Recurrence rule + override
- $input = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule2
-DTSTART:20111125T120000Z
-DTEND:20111125T130000Z
-RRULE:FREQ=WEEKLY
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-RECURRENCE-ID:20111209T120000Z
-DTSTART:20111209T140000Z
-DTEND:20111209T150000Z
-SUMMARY:Override!
-END:VEVENT
-END:VCALENDAR
-';
-
- $output = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule2
-DTSTART;VALUE=DATE-TIME:20111202T120000Z
-DTEND;VALUE=DATE-TIME:20111202T130000Z
-RECURRENCE-ID:20111202T120000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-RECURRENCE-ID:20111209T120000Z
-DTSTART:20111209T140000Z
-DTEND:20111209T150000Z
-SUMMARY:Override!
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule2
-DTSTART;VALUE=DATE-TIME:20111216T120000Z
-DTEND;VALUE=DATE-TIME:20111216T130000Z
-RECURRENCE-ID:20111216T120000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule2
-DTSTART;VALUE=DATE-TIME:20111223T120000Z
-DTEND;VALUE=DATE-TIME:20111223T130000Z
-RECURRENCE-ID:20111223T120000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:bla6
-SUMMARY:Testing RRule2
-DTSTART;VALUE=DATE-TIME:20111230T120000Z
-DTEND;VALUE=DATE-TIME:20111230T130000Z
-RECURRENCE-ID:20111230T120000Z
-END:VEVENT
-END:VCALENDAR
-';
-
- $tests[] = array($input, $output);
- return $tests;
-
- }
-
- /**
- * @expectedException LogicException
- */
- public function testBrokenEventExpand() {
-
- $input = 'BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-VERSION:2.0
-BEGIN:VEVENT
-RRULE:FREQ=WEEKLY
-DTSTART;VALUE=DATE:20111202
-END:VEVENT
-END:VCALENDAR
-';
- $vcal = VObject\Reader::read($input);
- $vcal->expand(
- new \DateTime('2011-12-01'),
- new \DateTime('2011-12-31')
- );
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCardTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCardTest.php
deleted file mode 100644
index 584a007d9..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCardTest.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-class VCardTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * @dataProvider validateData
- */
- function testValidate($input, $expectedWarnings, $expectedRepairedOutput) {
-
- $vcard = VObject\Reader::read($input);
-
- $warnings = $vcard->validate();
-
- $warnMsg = array();
- foreach($warnings as $warning) {
- $warnMsg[] = $warning['message'];
- }
-
- $this->assertEquals($expectedWarnings, $warnMsg);
-
- $vcard->validate(VObject\Component::REPAIR);
-
- $this->assertEquals(
- $expectedRepairedOutput,
- $vcard->serialize()
- );
-
- }
-
- public function validateData() {
-
- $tests = array();
-
- // Correct
- $tests[] = array(
- "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n",
- array(),
- "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n",
- );
-
- // No VERSION
- $tests[] = array(
- "BEGIN:VCARD\r\nFN:John Doe\r\nEND:VCARD\r\n",
- array(
- 'The VERSION property must appear in the VCARD component exactly 1 time',
- ),
- "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n",
- );
-
- // Unknown version
- $tests[] = array(
- "BEGIN:VCARD\r\nVERSION:2.2\r\nFN:John Doe\r\nEND:VCARD\r\n",
- array(
- 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
- ),
- "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n",
- );
-
- // No FN
- $tests[] = array(
- "BEGIN:VCARD\r\nVERSION:4.0\r\nEND:VCARD\r\n",
- array(
- 'The FN property must appear in the VCARD component exactly 1 time',
- ),
- "BEGIN:VCARD\r\nVERSION:4.0\r\nEND:VCARD\r\n",
- );
- // No FN, N fallback
- $tests[] = array(
- "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;John;;;;;\r\nEND:VCARD\r\n",
- array(
- 'The FN property must appear in the VCARD component exactly 1 time',
- ),
- "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;John;;;;;\r\nFN:John Doe\r\nEND:VCARD\r\n",
- );
- // No FN, N fallback, no first name
- $tests[] = array(
- "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;;;;;;\r\nEND:VCARD\r\n",
- array(
- 'The FN property must appear in the VCARD component exactly 1 time',
- ),
- "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;;;;;;\r\nFN:Doe\r\nEND:VCARD\r\n",
- );
-
- // No FN, ORG fallback
- $tests[] = array(
- "BEGIN:VCARD\r\nVERSION:4.0\r\nORG:Acme Co.\r\nEND:VCARD\r\n",
- array(
- 'The FN property must appear in the VCARD component exactly 1 time',
- ),
- "BEGIN:VCARD\r\nVERSION:4.0\r\nORG:Acme Co.\r\nFN:Acme Co.\r\nEND:VCARD\r\n",
- );
- return $tests;
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VEventTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Component/VEventTest.php
deleted file mode 100644
index 616da4ac7..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VEventTest.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject;
-
-class VEventTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * @dataProvider timeRangeTestData
- */
- public function testInTimeRange(VEvent $vevent,$start,$end,$outcome) {
-
- $this->assertEquals($outcome, $vevent->isInTimeRange($start, $end));
-
- }
-
- public function timeRangeTestData() {
-
- $tests = array();
-
- $vevent = new VEvent('VEVENT');
- $vevent->DTSTART = '20111223T120000Z';
- $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vevent2 = clone $vevent;
- $vevent2->DTEND = '20111225T120000Z';
- $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vevent3 = clone $vevent;
- $vevent3->DURATION = 'P1D';
- $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vevent4 = clone $vevent;
- $vevent4->DTSTART = '20111225';
- $vevent4->DTSTART['VALUE'] = 'DATE';
- $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
- // Event with no end date should be treated as lasting the entire day.
- $tests[] = array($vevent4, new \DateTime('2011-12-25 16:00:00'), new \DateTime('2011-12-25 17:00:00'), true);
-
-
- $vevent5 = clone $vevent;
- $vevent5->DURATION = 'P1D';
- $vevent5->RRULE = 'FREQ=YEARLY';
- $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
- $tests[] = array($vevent5, new \DateTime('2013-12-01'), new \DateTime('2013-12-31'), true);
-
- $vevent6 = clone $vevent;
- $vevent6->DTSTART = '20111225';
- $vevent6->DTSTART['VALUE'] = 'DATE';
- $vevent6->DTEND = '20111225';
- $vevent6->DTEND['VALUE'] = 'DATE';
-
- $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- // Added this test to ensure that recurrence rules with no DTEND also
- // get checked for the entire day.
- $vevent7 = clone $vevent;
- $vevent7->DTSTART = '20120101';
- $vevent7->DTSTART['VALUE'] = 'DATE';
- $vevent7->RRULE = 'FREQ=MONTHLY';
- $tests[] = array($vevent7, new \DateTime('2012-02-01 15:00:00'), new \DateTime('2012-02-02'), true);
- return $tests;
-
- }
-
-}
-
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VFreeBusyTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Component/VFreeBusyTest.php
deleted file mode 100644
index 031c3c684..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VFreeBusyTest.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-use Sabre\VObject;
-
-class VFreeBusyTest extends \PHPUnit_Framework_TestCase {
-
- function testIsFree() {
-
- $input = <<<BLA
-BEGIN:VCALENDAR
-BEGIN:VFREEBUSY
-FREEBUSY;FBTYPE=FREE:20120912T000500Z/PT1H
-FREEBUSY;FBTYPE=BUSY:20120912T010000Z/20120912T020000Z
-FREEBUSY;FBTYPE=BUSY-TENTATIVE:20120912T020000Z/20120912T030000Z
-FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20120912T030000Z/20120912T040000Z
-FREEBUSY;FBTYPE=BUSY:20120912T050000Z/20120912T060000Z,20120912T080000Z/20120912T090000Z
-FREEBUSY;FBTYPE=BUSY:20120912T100000Z/PT1H
-END:VFREEBUSY
-END:VCALENDAR
-BLA;
-
- $obj = VObject\Reader::read($input);
- $vfb = $obj->VFREEBUSY;
-
- $tz = new \DateTimeZone('UTC');
-
- $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 01:15:00', $tz), new \DateTime('2012-09-12 01:45:00', $tz)));
- $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 08:05:00', $tz), new \DateTime('2012-09-12 08:10:00', $tz)));
- $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 10:15:00', $tz), new \DateTime('2012-09-12 10:45:00', $tz)));
-
- // Checking whether the end time is treated as non-inclusive
- $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 09:00:00', $tz), new \DateTime('2012-09-12 09:15:00', $tz)));
- $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 09:45:00', $tz), new \DateTime('2012-09-12 10:00:00', $tz)));
- $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 11:00:00', $tz), new \DateTime('2012-09-12 12:00:00', $tz)));
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VJournalTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Component/VJournalTest.php
deleted file mode 100644
index 46ecb992b..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VJournalTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject\Component;
-
-class VJournalTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * @dataProvider timeRangeTestData
- */
- public function testInTimeRange(VJournal $vtodo,$start,$end,$outcome) {
-
- $this->assertEquals($outcome, $vtodo->isInTimeRange($start, $end));
-
- }
-
- public function timeRangeTestData() {
-
- $tests = array();
-
- $vjournal = Component::create('VJOURNAL');
- $vjournal->DTSTART = '20111223T120000Z';
- $tests[] = array($vjournal, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vjournal, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vjournal2 = Component::create('VJOURNAL');
- $vjournal2->DTSTART = '20111223';
- $vjournal2->DTSTART['VALUE'] = 'DATE';
- $tests[] = array($vjournal2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vjournal2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vjournal3 = Component::create('VJOURNAL');
- $tests[] = array($vjournal3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), false);
- $tests[] = array($vjournal3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- return $tests;
- }
-
-}
-
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VTodoTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Component/VTodoTest.php
deleted file mode 100644
index a84da5cdf..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Component/VTodoTest.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Component;
-
-use Sabre\VObject\Component;
-
-class VTodoTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * @dataProvider timeRangeTestData
- */
- public function testInTimeRange(VTodo $vtodo,$start,$end,$outcome) {
-
- $this->assertEquals($outcome, $vtodo->isInTimeRange($start, $end));
-
- }
-
- public function timeRangeTestData() {
-
- $tests = array();
-
- $vtodo = Component::create('VTODO');
- $vtodo->DTSTART = '20111223T120000Z';
- $tests[] = array($vtodo, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vtodo2 = clone $vtodo;
- $vtodo2->DURATION = 'P1D';
- $tests[] = array($vtodo2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vtodo3 = clone $vtodo;
- $vtodo3->DUE = '20111225';
- $tests[] = array($vtodo3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vtodo4 = Component::create('VTODO');
- $vtodo4->DUE = '20111225';
- $tests[] = array($vtodo4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vtodo5 = Component::create('VTODO');
- $vtodo5->COMPLETED = '20111225';
- $tests[] = array($vtodo5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vtodo6 = Component::create('VTODO');
- $vtodo6->CREATED = '20111225';
- $tests[] = array($vtodo6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vtodo7 = Component::create('VTODO');
- $vtodo7->CREATED = '20111225';
- $vtodo7->COMPLETED = '20111226';
- $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false);
-
- $vtodo7 = Component::create('VTODO');
- $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true);
- $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), true);
-
- return $tests;
-
- }
-
-}
-
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/ComponentTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/ComponentTest.php
deleted file mode 100644
index 07000bda0..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/ComponentTest.php
+++ /dev/null
@@ -1,413 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class ComponentTest extends \PHPUnit_Framework_TestCase {
-
- function testIterate() {
-
- $comp = new Component('VCALENDAR');
-
- $sub = new Component('VEVENT');
- $comp->children[] = $sub;
-
- $sub = new Component('VTODO');
- $comp->children[] = $sub;
-
- $count = 0;
- foreach($comp->children() as $key=>$subcomponent) {
-
- $count++;
- $this->assertInstanceOf('Sabre\\VObject\\Component',$subcomponent);
-
- }
- $this->assertEquals(2,$count);
- $this->assertEquals(1,$key);
-
- }
-
- function testMagicGet() {
-
- $comp = new Component('VCALENDAR');
-
- $sub = new Component('VEVENT');
- $comp->children[] = $sub;
-
- $sub = new Component('VTODO');
- $comp->children[] = $sub;
-
- $event = $comp->vevent;
- $this->assertInstanceOf('Sabre\\VObject\\Component', $event);
- $this->assertEquals('VEVENT', $event->name);
-
- $this->assertInternalType('null', $comp->vjournal);
-
- }
-
- function testMagicGetGroups() {
-
- $comp = new Component('VCARD');
-
- $sub = new Property('GROUP1.EMAIL','1@1.com');
- $comp->children[] = $sub;
-
- $sub = new Property('GROUP2.EMAIL','2@2.com');
- $comp->children[] = $sub;
-
- $sub = new Property('EMAIL','3@3.com');
- $comp->children[] = $sub;
-
- $emails = $comp->email;
- $this->assertEquals(3, count($emails));
-
- $email1 = $comp->{"group1.email"};
- $this->assertEquals('EMAIL', $email1[0]->name);
- $this->assertEquals('GROUP1', $email1[0]->group);
-
- $email3 = $comp->{".email"};
- $this->assertEquals('EMAIL', $email3[0]->name);
- $this->assertEquals(null, $email3[0]->group);
-
- }
-
- function testMagicIsset() {
-
- $comp = new Component('VCALENDAR');
-
- $sub = new Component('VEVENT');
- $comp->children[] = $sub;
-
- $sub = new Component('VTODO');
- $comp->children[] = $sub;
-
- $this->assertTrue(isset($comp->vevent));
- $this->assertTrue(isset($comp->vtodo));
- $this->assertFalse(isset($comp->vjournal));
-
- }
-
- function testMagicSetScalar() {
-
- $comp = new Component('VCALENDAR');
- $comp->myProp = 'myValue';
-
- $this->assertInstanceOf('Sabre\\VObject\\Property',$comp->MYPROP);
- $this->assertEquals('myValue',$comp->MYPROP->value);
-
-
- }
-
- function testMagicSetScalarTwice() {
-
- $comp = new Component('VCALENDAR');
- $comp->myProp = 'myValue';
- $comp->myProp = 'myValue';
-
- $this->assertEquals(1,count($comp->children));
- $this->assertInstanceOf('Sabre\\VObject\\Property',$comp->MYPROP);
- $this->assertEquals('myValue',$comp->MYPROP->value);
-
- }
-
- function testMagicSetComponent() {
-
- $comp = new Component('VCALENDAR');
-
- // Note that 'myProp' is ignored here.
- $comp->myProp = new Component('VEVENT');
-
- $this->assertEquals(1, count($comp->children));
-
- $this->assertEquals('VEVENT',$comp->VEVENT->name);
-
- }
-
- function testMagicSetTwice() {
-
- $comp = new Component('VCALENDAR');
-
- $comp->VEVENT = new Component('VEVENT');
- $comp->VEVENT = new Component('VEVENT');
-
- $this->assertEquals(1, count($comp->children));
-
- $this->assertEquals('VEVENT',$comp->VEVENT->name);
-
- }
-
- function testArrayAccessGet() {
-
- $comp = new Component('VCALENDAR');
-
- $event = new Component('VEVENT');
- $event->summary = 'Event 1';
-
- $comp->add($event);
-
- $event2 = clone $event;
- $event2->summary = 'Event 2';
-
- $comp->add($event2);
-
- $this->assertEquals(2,count($comp->children()));
- $this->assertTrue($comp->vevent[1] instanceof Component);
- $this->assertEquals('Event 2', (string)$comp->vevent[1]->summary);
-
- }
-
- function testArrayAccessExists() {
-
- $comp = new Component('VCALENDAR');
-
- $event = new Component('VEVENT');
- $event->summary = 'Event 1';
-
- $comp->add($event);
-
- $event2 = clone $event;
- $event2->summary = 'Event 2';
-
- $comp->add($event2);
-
- $this->assertTrue(isset($comp->vevent[0]));
- $this->assertTrue(isset($comp->vevent[1]));
-
- }
-
- /**
- * @expectedException LogicException
- */
- function testArrayAccessSet() {
-
- $comp = new Component('VCALENDAR');
- $comp['hey'] = 'hi there';
-
- }
- /**
- * @expectedException LogicException
- */
- function testArrayAccessUnset() {
-
- $comp = new Component('VCALENDAR');
- unset($comp[0]);
-
- }
-
- function testAddScalar() {
-
- $comp = new Component('VCALENDAR');
-
- $comp->add('myprop','value');
-
- $this->assertEquals(1, count($comp->children));
-
- $this->assertTrue($comp->children[0] instanceof Property);
- $this->assertEquals('MYPROP',$comp->children[0]->name);
- $this->assertEquals('value',$comp->children[0]->value);
-
- }
-
- function testAddScalarParams() {
-
- $comp = Component::create('VCALENDAR');
-
- $comp->add('myprop','value',array('param1'=>'value1'));
-
- $this->assertEquals(1, count($comp->children));
-
- $this->assertTrue($comp->children[0] instanceof Property);
- $this->assertEquals('MYPROP',$comp->children[0]->name);
- $this->assertEquals('value',$comp->children[0]->value);
-
- $this->assertEquals(1, count($comp->children[0]->parameters));
-
- $this->assertTrue($comp->children[0]->parameters[0] instanceof Parameter);
- $this->assertEquals('PARAM1',$comp->children[0]->parameters[0]->name);
- $this->assertEquals('value1',$comp->children[0]->parameters[0]->value);
-
- }
-
-
- function testAddComponent() {
-
- $comp = new Component('VCALENDAR');
-
- $comp->add(new Component('VEVENT'));
-
- $this->assertEquals(1, count($comp->children));
-
- $this->assertEquals('VEVENT',$comp->VEVENT->name);
-
- }
-
- function testAddComponentTwice() {
-
- $comp = new Component('VCALENDAR');
-
- $comp->add(new Component('VEVENT'));
- $comp->add(new Component('VEVENT'));
-
- $this->assertEquals(2, count($comp->children));
-
- $this->assertEquals('VEVENT',$comp->VEVENT->name);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testAddArgFail() {
-
- $comp = new Component('VCALENDAR');
- $comp->add(new Component('VEVENT'),'hello');
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testAddArgFail2() {
-
- $comp = new Component('VCALENDAR');
- $comp->add(array());
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testAddArgFail3() {
-
- $comp = new Component('VCALENDAR');
- $comp->add('hello',array());
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testMagicSetInvalid() {
-
- $comp = new Component('VCALENDAR');
-
- // Note that 'myProp' is ignored here.
- $comp->myProp = new \StdClass();
-
- $this->assertEquals(1, count($comp->children));
-
- $this->assertEquals('VEVENT',$comp->VEVENT->name);
-
- }
-
- function testMagicUnset() {
-
- $comp = new Component('VCALENDAR');
- $comp->add(new Component('VEVENT'));
-
- unset($comp->vevent);
-
- $this->assertEquals(array(), $comp->children);
-
- }
-
-
- function testCount() {
-
- $comp = new Component('VCALENDAR');
- $this->assertEquals(1,$comp->count());
-
- }
-
- function testChildren() {
-
- $comp = new Component('VCALENDAR');
-
- // Note that 'myProp' is ignored here.
- $comp->children = array(
- new Component('VEVENT'),
- new Component('VTODO')
- );
-
- $r = $comp->children();
- $this->assertTrue($r instanceof ElementList);
- $this->assertEquals(2,count($r));
- }
-
- function testGetComponents() {
-
- $comp = new Component('VCALENDAR');
-
- // Note that 'myProp' is ignored here.
- $comp->children = array(
- new Property('FOO','BAR'),
- new Component('VTODO')
- );
-
- $r = $comp->getComponents();
- $this->assertInternalType('array', $r);
- $this->assertEquals(1, count($r));
- $this->assertEquals('VTODO', $r[0]->name);
- }
-
- function testSerialize() {
-
- $comp = new Component('VCALENDAR');
- $this->assertEquals("BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n", $comp->serialize());
-
- }
-
- function testSerializeChildren() {
-
- $comp = new Component('VCALENDAR');
- $comp->children = array(
- new Component('VEVENT'),
- new Component('VTODO')
- );
-
- $str = $comp->serialize();
-
- $this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", $str);
-
- }
-
- function testSerializeOrderCompAndProp() {
-
- $comp = new Component('VCALENDAR');
- $comp->add(new Component('VEVENT'));
- $comp->add('PROP1','BLABLA');
- $comp->add('VERSION','2.0');
- $comp->add(new Component('VTIMEZONE'));
-
- $str = $comp->serialize();
-
- $this->assertEquals("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPROP1:BLABLA\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $str);
-
- }
-
- function testAnotherSerializeOrderProp() {
-
- $prop4s=array('1', '2', '3', '4', '5', '6', '7', '8', '9', '10');
-
- $comp = new Component('VCARD');
- $comp->__set('SOMEPROP','FOO');
- $comp->__set('ANOTHERPROP','FOO');
- $comp->__set('THIRDPROP','FOO');
- foreach ($prop4s as $prop4) {
- $comp->add('PROP4', 'FOO '.$prop4);
- }
- $comp->__set('PROPNUMBERFIVE', 'FOO');
- $comp->__set('PROPNUMBERSIX', 'FOO');
- $comp->__set('PROPNUMBERSEVEN', 'FOO');
- $comp->__set('PROPNUMBEREIGHT', 'FOO');
- $comp->__set('PROPNUMBERNINE', 'FOO');
- $comp->__set('PROPNUMBERTEN', 'FOO');
- $comp->__set('VERSION','2.0');
- $comp->__set('UID', 'FOO');
-
- $str = $comp->serialize();
-
- $this->assertEquals("BEGIN:VCARD\r\nVERSION:2.0\r\nSOMEPROP:FOO\r\nANOTHERPROP:FOO\r\nTHIRDPROP:FOO\r\nPROP4:FOO 1\r\nPROP4:FOO 2\r\nPROP4:FOO 3\r\nPROP4:FOO 4\r\nPROP4:FOO 5\r\nPROP4:FOO 6\r\nPROP4:FOO 7\r\nPROP4:FOO 8\r\nPROP4:FOO 9\r\nPROP4:FOO 10\r\nPROPNUMBERFIVE:FOO\r\nPROPNUMBERSIX:FOO\r\nPROPNUMBERSEVEN:FOO\r\nPROPNUMBEREIGHT:FOO\r\nPROPNUMBERNINE:FOO\r\nPROPNUMBERTEN:FOO\r\nUID:FOO\r\nEND:VCARD\r\n", $str);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/DateTimeParserTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/DateTimeParserTest.php
deleted file mode 100644
index 6ea2faed9..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/DateTimeParserTest.php
+++ /dev/null
@@ -1,153 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-use DateTime;
-use DateTimeZone;
-use DateInterval;
-
-class DateTimeParserTest extends \PHPUnit_Framework_TestCase {
-
- function testParseICalendarDuration() {
-
- $this->assertEquals('+1 weeks', DateTimeParser::parseDuration('P1W',true));
- $this->assertEquals('+5 days', DateTimeParser::parseDuration('P5D',true));
- $this->assertEquals('+5 days 3 hours 50 minutes 12 seconds', DateTimeParser::parseDuration('P5DT3H50M12S',true));
- $this->assertEquals('-1 weeks 50 minutes', DateTimeParser::parseDuration('-P1WT50M',true));
- $this->assertEquals('+50 days 3 hours 2 seconds', DateTimeParser::parseDuration('+P50DT3H2S',true));
- $this->assertEquals(new DateInterval('PT0S'), DateTimeParser::parseDuration('PT0S'));
-
- }
-
- function testParseICalendarDurationDateInterval() {
-
- $expected = new DateInterval('P7D');
- $this->assertEquals($expected, DateTimeParser::parseDuration('P1W'));
- $this->assertEquals($expected, DateTimeParser::parse('P1W'));
-
- $expected = new DateInterval('PT3M');
- $expected->invert = true;
- $this->assertEquals($expected, DateTimeParser::parseDuration('-PT3M'));
-
- }
-
- /**
- * @expectedException LogicException
- */
- function testParseICalendarDurationFail() {
-
- DateTimeParser::parseDuration('P1X',true);
-
- }
-
- function testParseICalendarDateTime() {
-
- $dateTime = DateTimeParser::parseDateTime('20100316T141405');
-
- $compare = new DateTime('2010-03-16 14:14:05',new DateTimeZone('UTC'));
-
- $this->assertEquals($compare, $dateTime);
-
- }
-
- /**
- * @depends testParseICalendarDateTime
- * @expectedException LogicException
- */
- function testParseICalendarDateTimeBadFormat() {
-
- $dateTime = DateTimeParser::parseDateTime('20100316T141405 ');
-
- }
-
- /**
- * @depends testParseICalendarDateTime
- */
- function testParseICalendarDateTimeUTC() {
-
- $dateTime = DateTimeParser::parseDateTime('20100316T141405Z');
-
- $compare = new DateTime('2010-03-16 14:14:05',new DateTimeZone('UTC'));
- $this->assertEquals($compare, $dateTime);
-
- }
-
- /**
- * @depends testParseICalendarDateTime
- */
- function testParseICalendarDateTimeUTC2() {
-
- $dateTime = DateTimeParser::parseDateTime('20101211T160000Z');
-
- $compare = new DateTime('2010-12-11 16:00:00',new DateTimeZone('UTC'));
- $this->assertEquals($compare, $dateTime);
-
- }
-
- /**
- * @depends testParseICalendarDateTime
- */
- function testParseICalendarDateTimeCustomTimeZone() {
-
- $dateTime = DateTimeParser::parseDateTime('20100316T141405', new DateTimeZone('Europe/Amsterdam'));
-
- $compare = new DateTime('2010-03-16 13:14:05',new DateTimeZone('UTC'));
- $this->assertEquals($compare, $dateTime);
-
- }
-
- function testParseICalendarDate() {
-
- $dateTime = DateTimeParser::parseDate('20100316');
-
- $expected = new DateTime('2010-03-16 00:00:00',new DateTimeZone('UTC'));
-
- $this->assertEquals($expected, $dateTime);
-
- $dateTime = DateTimeParser::parse('20100316');
- $this->assertEquals($expected, $dateTime);
-
- }
-
- /**
- * TCheck if a date with year > 4000 will not throw an exception. iOS seems to use 45001231 in yearly recurring events
- */
- function testParseICalendarDateGreaterThan4000() {
-
- $dateTime = DateTimeParser::parseDate('45001231');
-
- $expected = new DateTime('4500-12-31 00:00:00',new DateTimeZone('UTC'));
-
- $this->assertEquals($expected, $dateTime);
-
- $dateTime = DateTimeParser::parse('45001231');
- $this->assertEquals($expected, $dateTime);
-
- }
-
- /**
- * Check if a datetime with year > 4000 will not throw an exception. iOS seems to use 45001231T235959 in yearly recurring events
- */
- function testParseICalendarDateTimeGreaterThan4000() {
-
- $dateTime = DateTimeParser::parseDateTime('45001231T235959');
-
- $expected = new DateTime('4500-12-31 23:59:59',new DateTimeZone('UTC'));
-
- $this->assertEquals($expected, $dateTime);
-
- $dateTime = DateTimeParser::parse('45001231T235959');
- $this->assertEquals($expected, $dateTime);
-
- }
-
- /**
- * @depends testParseICalendarDate
- * @expectedException LogicException
- */
- function testParseICalendarDateBadFormat() {
-
- $dateTime = DateTimeParser::parseDate('20100316T141405');
-
- }
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/DocumentTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/DocumentTest.php
deleted file mode 100644
index 5fd2a2a78..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/DocumentTest.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class DocumentTest extends \PHPUnit_Framework_TestCase {
-
- function testCreateComponent() {
-
- $vcal = new Component\VCalendar();
-
- $event = $vcal->createComponent('VEVENT');
-
- $this->assertInstanceOf('Sabre\VObject\Component\VEvent', $event);
- $vcal->add($event);
-
- $prop = $vcal->createProperty('X-PROP','1234256',array('X-PARAM' => '3'));
- $this->assertInstanceOf('Sabre\VObject\Property', $prop);
-
- $event->add($prop);
-
- $out = $vcal->serialize();
- $this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nX-PROP;X-PARAM=3:1234256\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $out);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/ElementListTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/ElementListTest.php
deleted file mode 100644
index 84e1bcbe9..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/ElementListTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class ElementListTest extends \PHPUnit_Framework_TestCase {
-
- function testIterate() {
-
- $sub = new Component('VEVENT');
-
- $elems = array(
- $sub,
- clone $sub,
- clone $sub
- );
-
- $elemList = new ElementList($elems);
-
- $count = 0;
- foreach($elemList as $key=>$subcomponent) {
-
- $count++;
- $this->assertInstanceOf('Sabre\\VObject\\Component',$subcomponent);
-
- }
- $this->assertEquals(3,$count);
- $this->assertEquals(2,$key);
-
- }
-
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/EmClientTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/EmClientTest.php
deleted file mode 100644
index 69d410fe7..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/EmClientTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class EmClientTest extends \PHPUnit_Framework_TestCase {
-
- function testParseTz() {
-
- $str = 'BEGIN:VCALENDAR
-X-WR-CALNAME:Blackhawks Schedule 2011-12
-X-APPLE-CALENDAR-COLOR:#E51717
-X-WR-TIMEZONE:America/Chicago
-CALSCALE:GREGORIAN
-PRODID:-//eM Client/4.0.13961.0
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:America/Chicago
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0600
-RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
-DTSTART:20070311T020000
-TZNAME:CDT
-TZOFFSETTO:-0500
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0500
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
-DTSTART:20071104T020000
-TZNAME:CST
-TZOFFSETTO:-0600
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-CREATED:20110624T181236Z
-UID:be3bbfff-96e8-4c66-9908-ab791a62231d
-DTEND;TZID="America/Chicago":20111008T223000
-TRANSP:OPAQUE
-SUMMARY:Stars @ Blackhawks (Home Opener)
-DTSTART;TZID="America/Chicago":20111008T193000
-DTSTAMP:20120330T013232Z
-SEQUENCE:2
-X-MICROSOFT-CDO-BUSYSTATUS:BUSY
-LAST-MODIFIED:20120330T013237Z
-CLASS:PUBLIC
-END:VEVENT
-END:VCALENDAR';
-
- $vObject = Reader::read($str);
- $dt = $vObject->VEVENT->DTSTART->getDateTime();
- $this->assertEquals(new \DateTime('2011-10-08 19:30:00', new \DateTimeZone('America/Chicago')), $dt);
-
- }
-
-}
-
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/FreeBusyGeneratorTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/FreeBusyGeneratorTest.php
deleted file mode 100644
index 1f79e0a47..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/FreeBusyGeneratorTest.php
+++ /dev/null
@@ -1,246 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class FreeBusyGeneratorTest extends \PHPUnit_Framework_TestCase {
-
- function getInput() {
-
- // shows up
-$blob1 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20110101T120000Z
-DTEND:20110101T130000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // opaque, shows up
-$blob2 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-TRANSP:OPAQUE
-DTSTART:20110101T130000Z
-DTEND:20110101T140000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // transparent, hidden
-$blob3 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-TRANSP:TRANSPARENT
-DTSTART:20110101T140000Z
-DTEND:20110101T150000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // cancelled, hidden
-$blob4 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-STATUS:CANCELLED
-DTSTART:20110101T160000Z
-DTEND:20110101T170000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // tentative, shows up
-$blob5 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-STATUS:TENTATIVE
-DTSTART:20110101T180000Z
-DTEND:20110101T190000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // outside of time-range, hidden
-$blob6 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20110101T090000Z
-DTEND:20110101T100000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // outside of time-range, hidden
-$blob7 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20110104T090000Z
-DTEND:20110104T100000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // using duration, shows up
-$blob8 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20110101T190000Z
-DURATION:PT1H
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- // Day-long event, shows up
-$blob9 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART;TYPE=DATE:20110102
-END:VEVENT
-END:VCALENDAR
-ICS;
-
-// No duration, does not show up
-$blob10 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20110101T200000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
-// encoded as object, shows up
-$blob11 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20110101T210000Z
-DURATION:PT1H
-END:VEVENT
-END:VCALENDAR
-ICS;
-
-// Freebusy. Some parts show up
-$blob12 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VFREEBUSY
-FREEBUSY:20110103T010000Z/20110103T020000Z
-FREEBUSY;FBTYPE=FREE:20110103T020000Z/20110103T030000Z
-FREEBUSY:20110103T030000Z/20110103T040000Z,20110103T040000Z/20110103T050000Z
-FREEBUSY:20120101T000000Z/20120101T010000Z
-FREEBUSY:20110103T050000Z/PT1H
-END:VFREEBUSY
-END:VCALENDAR
-ICS;
-
-// Yearly recurrence rule, shows up
-$blob13 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20100101T220000Z
-DTEND:20100101T230000Z
-RRULE:FREQ=YEARLY
-END:VEVENT
-END:VCALENDAR
-ICS;
-
-// Yearly recurrence rule + duration, shows up
-$blob14 = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTART:20100101T230000Z
-DURATION:PT1H
-RRULE:FREQ=YEARLY
-END:VEVENT
-END:VCALENDAR
-ICS;
-
-
- return array(
- $blob1,
- $blob2,
- $blob3,
- $blob4,
- $blob5,
- $blob6,
- $blob7,
- $blob8,
- $blob9,
- $blob10,
- Reader::read($blob11),
- $blob12,
- $blob13,
- $blob14,
- );
-
- }
-
- function testGenerator() {
-
- $gen = new FreeBusyGenerator(
- new \DateTime('20110101T110000Z', new \DateTimeZone('UTC')),
- new \DateTime('20110103T110000Z', new \DateTimeZone('UTC')),
- $this->getInput()
- );
-
- $result = $gen->getResult();
-
- $expected = array(
- '20110101T120000Z/20110101T130000Z',
- '20110101T130000Z/20110101T140000Z',
- '20110101T180000Z/20110101T190000Z',
- '20110101T190000Z/20110101T200000Z',
- '20110102T000000Z/20110103T000000Z',
- '20110101T210000Z/20110101T220000Z',
-
- '20110103T010000Z/20110103T020000Z',
- '20110103T030000Z/20110103T040000Z',
- '20110103T040000Z/20110103T050000Z',
- '20110103T050000Z/20110103T060000Z',
-
- '20110101T220000Z/20110101T230000Z',
- '20110101T230000Z/20110102T000000Z',
- );
-
- foreach($result->VFREEBUSY->FREEBUSY as $fb) {
-
- $this->assertContains((string)$fb, $expected);
-
- $k = array_search((string)$fb, $expected);
- unset($expected[$k]);
-
- }
- if (count($expected)>0) {
- $this->fail('There were elements in the expected array that were not found in the output: ' . "\n" . print_r($expected,true) . "\n" . $result->serialize());
-
- }
-
- }
-
- function testGeneratorBaseObject() {
-
- $obj = new Component('VCALENDAR');
- $obj->METHOD = 'PUBLISH';
-
- $gen = new FreeBusyGenerator();
- $gen->setObjects(array());
- $gen->setBaseObject($obj);
-
- $result = $gen->getResult();
-
- $this->assertEquals('PUBLISH', $result->METHOD->value);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testInvalidArg() {
-
- $gen = new FreeBusyGenerator(
- new \DateTime('2012-01-01'),
- new \DateTime('2012-12-31'),
- new \StdClass()
- );
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Issue153Test.php b/vendor/sabre/vobject/tests/Sabre/VObject/Issue153Test.php
deleted file mode 100644
index 1cc14c161..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Issue153Test.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class Issue153Test extends \PHPUnit_Framework_TestCase {
-
- function testRead() {
-
- $obj = Reader::read(file_get_contents(dirname(__FILE__) . '/issue153.vcf'));
- $this->assertEquals('Test Benutzer', (string)$obj->fn);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Issue154Test.php b/vendor/sabre/vobject/tests/Sabre/VObject/Issue154Test.php
deleted file mode 100644
index ed9c7c3f4..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Issue154Test.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class Issue154Test extends \PHPUnit_Framework_TestCase {
-
- function testStuff() {
-
- $vcard = new Component('VCARD');
- $vcard->VERSION = '3.0';
- $vcard->PHOTO = base64_encode('random_stuff');
- $vcard->PHOTO->add('BASE64',null);
- $vcard->UID = 'foo-bar';
-
- $result = $vcard->serialize();
- $expected = array(
- "BEGIN:VCARD",
- "VERSION:3.0",
- "PHOTO;BASE64:" . base64_encode('random_stuff'),
- "UID:foo-bar",
- "END:VCARD",
- "",
- );
-
- $this->assertEquals(implode("\r\n", $expected), $result);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Issue48Test.php b/vendor/sabre/vobject/tests/Sabre/VObject/Issue48Test.php
deleted file mode 100644
index 980d432b9..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Issue48Test.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-use
- DateTime,
- DateTimeZone;
-
-class Issue48Test extends \PHPUnit_Framework_TestCase {
-
- function testExpand() {
-
- $input = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-UID:foo
-DTEND;TZID=Europe/Moscow:20130710T120000
-DTSTART;TZID=Europe/Moscow:20130710T110000
-RRULE:FREQ=DAILY;UNTIL=20130712T195959Z
-END:VEVENT
-BEGIN:VEVENT
-UID:foo
-DTEND;TZID=Europe/Moscow:20130713T120000
-DTSTART;TZID=Europe/Moscow:20130713T110000
-RECURRENCE-ID;TZID=Europe/Moscow:20130711T110000
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- $vcal = Reader::read($input);
- $this->assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal);
-
- $it = new RecurrenceIterator($vcal, 'foo');
-
- $result = iterator_to_array($it);
-
- $tz = new DateTimeZone('Europe/Moscow');
-
- $this->assertEquals(array(
- new DateTime('2013-07-10 11:00:00', $tz),
- new DateTime('2013-07-12 11:00:00', $tz),
- new DateTime('2013-07-13 11:00:00', $tz),
- ), $result);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Issue50Test.php b/vendor/sabre/vobject/tests/Sabre/VObject/Issue50Test.php
deleted file mode 100644
index fdb012ba2..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Issue50Test.php
+++ /dev/null
@@ -1,128 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-use
- DateTime,
- DateTimeZone;
-
-class Issue50Test extends \PHPUnit_Framework_TestCase {
-
- function testExpand() {
-
- $input = <<<ICS
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
-BEGIN:VTIMEZONE
-TZID:Europe/Brussels
-X-LIC-LOCATION:Europe/Brussels
-BEGIN:DAYLIGHT
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-TZNAME:CEST
-DTSTART:19700329T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-TZNAME:CET
-DTSTART:19701025T030000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-CREATED:20130705T142510Z
-LAST-MODIFIED:20130715T132556Z
-DTSTAMP:20130715T132556Z
-UID:1aef0b27-3d92-4581-829a-11999dd36724
-SUMMARY:Werken
-RRULE:FREQ=DAILY;COUNT=5
-DTSTART;TZID=Europe/Brussels:20130715T090000
-DTEND;TZID=Europe/Brussels:20130715T170000
-LOCATION:Job
-DESCRIPTION:Vrij
-X-MOZ-GENERATION:9
-END:VEVENT
-BEGIN:VEVENT
-CREATED:20130715T081654Z
-LAST-MODIFIED:20130715T110931Z
-DTSTAMP:20130715T110931Z
-UID:1aef0b27-3d92-4581-829a-11999dd36724
-SUMMARY:Werken
-RECURRENCE-ID;TZID=Europe/Brussels:20130719T090000
-DTSTART;TZID=Europe/Brussels:20130719T070000
-DTEND;TZID=Europe/Brussels:20130719T150000
-SEQUENCE:1
-LOCATION:Job
-DESCRIPTION:Vrij
-X-MOZ-GENERATION:1
-END:VEVENT
-BEGIN:VEVENT
-CREATED:20130715T111654Z
-LAST-MODIFIED:20130715T132556Z
-DTSTAMP:20130715T132556Z
-UID:1aef0b27-3d92-4581-829a-11999dd36724
-SUMMARY:Werken
-RECURRENCE-ID;TZID=Europe/Brussels:20130716T090000
-DTSTART;TZID=Europe/Brussels:20130716T070000
-DTEND;TZID=Europe/Brussels:20130716T150000
-SEQUENCE:1
-LOCATION:Job
-X-MOZ-GENERATION:2
-END:VEVENT
-BEGIN:VEVENT
-CREATED:20130715T125942Z
-LAST-MODIFIED:20130715T130023Z
-DTSTAMP:20130715T130023Z
-UID:1aef0b27-3d92-4581-829a-11999dd36724
-SUMMARY:Werken
-RECURRENCE-ID;TZID=Europe/Brussels:20130717T090000
-DTSTART;TZID=Europe/Brussels:20130717T070000
-DTEND;TZID=Europe/Brussels:20130717T150000
-SEQUENCE:1
-LOCATION:Job
-X-MOZ-GENERATION:3
-END:VEVENT
-BEGIN:VEVENT
-CREATED:20130715T130024Z
-LAST-MODIFIED:20130715T130034Z
-DTSTAMP:20130715T130034Z
-UID:1aef0b27-3d92-4581-829a-11999dd36724
-SUMMARY:Werken
-RECURRENCE-ID;TZID=Europe/Brussels:20130718T090000
-DTSTART;TZID=Europe/Brussels:20130718T090000
-DTEND;TZID=Europe/Brussels:20130718T170000
-LOCATION:Job
-X-MOZ-GENERATION:5
-DESCRIPTION:Vrij
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- $vcal = Reader::read($input);
- $this->assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal);
-
- $it = new RecurrenceIterator($vcal, '1aef0b27-3d92-4581-829a-11999dd36724');
-
- $result = array();
- foreach($it as $instance) {
-
- $result[] = $instance;
-
- }
-
- $tz = new DateTimeZone('Europe/Brussels');
-
- $this->assertEquals(array(
- new DateTime('2013-07-15 09:00:00', $tz),
- new DateTime('2013-07-16 07:00:00', $tz),
- new DateTime('2013-07-17 07:00:00', $tz),
- new DateTime('2013-07-18 09:00:00', $tz),
- new DateTime('2013-07-19 07:00:00', $tz),
- ), $result);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/ParameterTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/ParameterTest.php
deleted file mode 100644
index 90eb5d2aa..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/ParameterTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class ParameterTest extends \PHPUnit_Framework_TestCase {
-
- function testSetup() {
-
- $param = new Parameter('name','value');
- $this->assertEquals('NAME',$param->name);
- $this->assertEquals('value',$param->value);
- $this->assertEquals('value',$param->getValue());
-
- }
-
- function testCastToString() {
-
- $param = new Parameter('name','value');
- $this->assertEquals('value',$param->__toString());
- $this->assertEquals('value',(string)$param);
-
- }
-
- function testSerialize() {
-
- $param = new Parameter('name','value');
- $this->assertEquals('NAME=value',$param->serialize());
-
- }
-
- function testSerializeEmpty() {
-
- $param = new Parameter('name',null);
- $this->assertEquals('NAME',$param->serialize());
-
- }
-
- function testSerializeColon() {
-
- $param = new Parameter('name','va:lue');
- $this->assertEquals('NAME="va:lue"',$param->serialize());
-
- }
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Property/CompoundTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Property/CompoundTest.php
deleted file mode 100644
index 5d8cdaabb..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Property/CompoundTest.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Property;
-use Sabre\VObject\Component;
-
-class CompoundTest extends \PHPUnit_Framework_TestCase {
-
- function testSetParts() {
-
- $arr = array(
- 'ABC, Inc.',
- 'North American Division',
- 'Marketing;Sales',
- );
-
- $elem = new Compound('ORG');
- $elem->setParts($arr);
-
- $this->assertEquals('ABC\, Inc.;North American Division;Marketing\;Sales', $elem->value);
- $this->assertEquals(3, count($elem->getParts()));
- $parts = $elem->getParts();
- $this->assertEquals('Marketing;Sales', $parts[2]);
-
- }
-
- function testGetParts() {
-
- $str = 'ABC\, Inc.;North American Division;Marketing\;Sales';
-
- $elem = new Compound('ORG', $str);
-
- $this->assertEquals(3, count($elem->getParts()));
- $parts = $elem->getParts();
- $this->assertEquals('Marketing;Sales', $parts[2]);
- }
-
- function testGetPartsDefaultDelimiter() {
-
- $str = 'Hi!;Hello!';
-
- $elem = new Compound('X-FOO', $str);
-
- $this->assertEquals(array(
- 'Hi!',
- 'Hello!',
- ), $elem->getParts());
-
- }
-
- function testGetPartsNull() {
-
- $str = 'ABC\, Inc.;North American Division;Marketing\;Sales';
-
- $elem = new Compound('ORG', null);
-
- $this->assertEquals(0, count($elem->getParts()));
-
- }
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Property/DateTimeTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Property/DateTimeTest.php
deleted file mode 100644
index b5b522e7d..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Property/DateTimeTest.php
+++ /dev/null
@@ -1,240 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Property;
-use Sabre\VObject\Component;
-
-class DateTimeTest extends \PHPUnit_Framework_TestCase {
-
- function testSetDateTime() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new DateTime('DTSTART');
- $elem->setDateTime($dt);
-
- $this->assertEquals('19850704T013000', $elem->value);
- $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
-
- }
-
- function testSetDateTimeLOCAL() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new DateTime('DTSTART');
- $elem->setDateTime($dt, DateTime::LOCAL);
-
- $this->assertEquals('19850704T013000', $elem->value);
- $this->assertNull($elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
- }
-
- function testSetDateTimeUTC() {
-
- $tz = new \DateTimeZone('GMT');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new DateTime('DTSTART');
- $elem->setDateTime($dt, DateTime::UTC);
-
- $this->assertEquals('19850704T013000Z', $elem->value);
- $this->assertNull($elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
- }
-
- function testSetDateTimeLOCALTZ() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new DateTime('DTSTART');
- $elem->setDateTime($dt, DateTime::LOCALTZ);
-
- $this->assertEquals('19850704T013000', $elem->value);
- $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
- }
-
- function testSetDateTimeDATE() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new DateTime('DTSTART');
- $elem->setDateTime($dt, DateTime::DATE);
-
- $this->assertEquals('19850704', $elem->value);
- $this->assertNull($elem['TZID']);
- $this->assertEquals('DATE', (string)$elem['VALUE']);
-
- $this->assertFalse($elem->hasTime());
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testSetDateTimeInvalid() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new DateTime('DTSTART');
- $elem->setDateTime($dt, 7);
-
- }
-
- function testGetDateTimeCached() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new DateTime('DTSTART');
- $elem->setDateTime($dt);
-
- $this->assertEquals($elem->getDateTime(), $dt);
-
- }
-
- function testGetDateTimeDateNULL() {
-
- $elem = new DateTime('DTSTART');
- $dt = $elem->getDateTime();
-
- $this->assertNull($dt);
- $this->assertNull($elem->getDateType());
-
- }
-
- function testGetDateTimeDateDATE() {
-
- $elem = new DateTime('DTSTART','19850704');
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 00:00:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals(DateTime::DATE, $elem->getDateType());
-
- }
-
-
- function testGetDateTimeDateLOCAL() {
-
- $elem = new DateTime('DTSTART','19850704T013000');
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals(DateTime::LOCAL, $elem->getDateType());
-
- }
-
- function testGetDateTimeDateUTC() {
-
- $elem = new DateTime('DTSTART','19850704T013000Z');
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals('UTC', $dt->getTimeZone()->getName());
- $this->assertEquals(DateTime::UTC, $elem->getDateType());
-
- }
-
- function testGetDateTimeDateLOCALTZ() {
-
- $elem = new DateTime('DTSTART','19850704T013000');
- $elem['TZID'] = 'Europe/Amsterdam';
-
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName());
- $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType());
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testGetDateTimeDateInvalid() {
-
- $elem = new DateTime('DTSTART','bla');
- $dt = $elem->getDateTime();
-
- }
-
- function testGetDateTimeWeirdTZ() {
-
- $elem = new DateTime('DTSTART','19850704T013000');
- $elem['TZID'] = '/freeassociation.sourceforge.net/Tzfile/Europe/Amsterdam';
-
-
- $event = new Component('VEVENT');
- $event->add($elem);
-
- $timezone = new Component('VTIMEZONE');
- $timezone->TZID = '/freeassociation.sourceforge.net/Tzfile/Europe/Amsterdam';
- $timezone->{'X-LIC-LOCATION'} = 'Europe/Amsterdam';
-
- $calendar = new Component('VCALENDAR');
- $calendar->add($event);
- $calendar->add($timezone);
-
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName());
- $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType());
-
- }
-
- function testGetDateTimeBadTimeZone() {
-
- $default = date_default_timezone_get();
- date_default_timezone_set('Canada/Eastern');
-
- $elem = new DateTime('DTSTART','19850704T013000');
- $elem['TZID'] = 'Moon';
-
-
- $event = new Component('VEVENT');
- $event->add($elem);
-
- $timezone = new Component('VTIMEZONE');
- $timezone->TZID = 'Moon';
- $timezone->{'X-LIC-LOCATION'} = 'Moon';
-
- $calendar = new Component('VCALENDAR');
- $calendar->add($event);
- $calendar->add($timezone);
-
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals('Canada/Eastern', $dt->getTimeZone()->getName());
- $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType());
- date_default_timezone_set($default);
-
- }
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Property/MultiDateTimeTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Property/MultiDateTimeTest.php
deleted file mode 100644
index 177616652..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Property/MultiDateTimeTest.php
+++ /dev/null
@@ -1,208 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Property;
-
-class MultiDateTimeTest extends \PHPUnit_Framework_TestCase {
-
- function testSetDateTime() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt1 = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt2 = new \DateTime('1986-07-04 01:30:00', $tz);
- $dt1->setTimeZone($tz);
- $dt2->setTimeZone($tz);
-
- $elem = new MultiDateTime('DTSTART');
- $elem->setDateTimes(array($dt1,$dt2));
-
- $this->assertEquals('19850704T013000,19860704T013000', $elem->value);
- $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
-
- }
-
- function testSetDateTimeLOCAL() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt1 = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt2 = new \DateTime('1986-07-04 01:30:00', $tz);
- $dt1->setTimeZone($tz);
- $dt2->setTimeZone($tz);
-
- $elem = new MultiDateTime('DTSTART');
- $elem->setDateTimes(array($dt1,$dt2), DateTime::LOCAL);
-
- $this->assertEquals('19850704T013000,19860704T013000', $elem->value);
- $this->assertNull($elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
- }
-
- function testSetDateTimeUTC() {
-
- $tz = new \DateTimeZone('GMT');
- $dt1 = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt2 = new \DateTime('1986-07-04 01:30:00', $tz);
- $dt1->setTimeZone($tz);
- $dt2->setTimeZone($tz);
-
- $elem = new MultiDateTime('DTSTART');
- $elem->setDateTimes(array($dt1,$dt2), DateTime::UTC);
-
- $this->assertEquals('19850704T013000Z,19860704T013000Z', $elem->value);
- $this->assertNull($elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
- }
-
- function testSetDateTimeLOCALTZ() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt1 = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt2 = new \DateTime('1986-07-04 01:30:00', $tz);
- $dt1->setTimeZone($tz);
- $dt2->setTimeZone($tz);
-
- $elem = new MultiDateTime('DTSTART');
- $elem->setDateTimes(array($dt1,$dt2), DateTime::LOCALTZ);
-
- $this->assertEquals('19850704T013000,19860704T013000', $elem->value);
- $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']);
- $this->assertEquals('DATE-TIME', (string)$elem['VALUE']);
-
- $this->assertTrue($elem->hasTime());
- }
-
- function testSetDateTimeDATE() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt1 = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt2 = new \DateTime('1986-07-04 01:30:00', $tz);
- $dt1->settimezone($tz);
- $dt2->settimezone($tz);
-
- $elem = new MultiDateTime('DTSTART');
- $elem->setDateTimes(array($dt1,$dt2), DateTime::DATE);
-
- $this->assertEquals('19850704,19860704', $elem->value);
- $this->assertNull($elem['TZID']);
- $this->assertEquals('DATE', (string)$elem['VALUE']);
-
- $this->assertFalse($elem->hasTime());
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testSetDateTimeInvalid() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt->setTimeZone($tz);
-
- $elem = new MultiDateTime('DTSTART');
- $elem->setDateTimes(array($dt), 7);
-
- }
-
- function testGetDateTimeCached() {
-
- $tz = new \DateTimeZone('Europe/Amsterdam');
- $dt1 = new \DateTime('1985-07-04 01:30:00', $tz);
- $dt2 = new \DateTime('1986-07-04 01:30:00', $tz);
- $dt1->settimezone($tz);
- $dt2->settimezone($tz);
-
- $elem = new MultiDateTime('DTSTART');
- $elem->setDateTimes(array($dt1,$dt2));
-
- $this->assertEquals($elem->getDateTimes(), array($dt1,$dt2));
-
- }
-
- function testGetDateTimeDateNULL() {
-
- $elem = new MultiDateTime('DTSTART');
- $dt = $elem->getDateTimes();
-
- $this->assertNull($dt);
- $this->assertNull($elem->getDateType());
-
- }
-
- function testGetDateTimeDateDATE() {
-
- $elem = new MultiDateTime('DTSTART','19850704,19860704');
- $dt = $elem->getDateTimes();
-
- $this->assertEquals('1985-07-04 00:00:00', $dt[0]->format('Y-m-d H:i:s'));
- $this->assertEquals('1986-07-04 00:00:00', $dt[1]->format('Y-m-d H:i:s'));
- $this->assertEquals(DateTime::DATE, $elem->getDateType());
-
- }
-
- function testGetDateTimeDateDATEReverse() {
-
- $elem = new MultiDateTime('DTSTART','19850704,19860704');
-
- $this->assertEquals(DateTime::DATE, $elem->getDateType());
-
- $dt = $elem->getDateTimes();
- $this->assertEquals('1985-07-04 00:00:00', $dt[0]->format('Y-m-d H:i:s'));
- $this->assertEquals('1986-07-04 00:00:00', $dt[1]->format('Y-m-d H:i:s'));
-
- }
-
-
- function testGetDateTimeDateLOCAL() {
-
- $elem = new DateTime('DTSTART','19850704T013000');
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals(DateTime::LOCAL, $elem->getDateType());
-
- }
-
- function testGetDateTimeDateUTC() {
-
- $elem = new DateTime('DTSTART','19850704T013000Z');
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals('UTC', $dt->getTimeZone()->getName());
- $this->assertEquals(DateTime::UTC, $elem->getDateType());
-
- }
-
- function testGetDateTimeDateLOCALTZ() {
-
- $elem = new DateTime('DTSTART','19850704T013000');
- $elem['TZID'] = 'Europe/Amsterdam';
-
- $dt = $elem->getDateTime();
-
- $this->assertInstanceOf('DateTime', $dt);
- $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s'));
- $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName());
- $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType());
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testGetDateTimeDateInvalid() {
-
- $elem = new DateTime('DTSTART','bla');
- $dt = $elem->getDateTime();
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/PropertyTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/PropertyTest.php
deleted file mode 100644
index 3bb289567..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/PropertyTest.php
+++ /dev/null
@@ -1,324 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class PropertyTest extends \PHPUnit_Framework_TestCase {
-
- public function testToString() {
-
- $property = new Property('propname','propvalue');
- $this->assertEquals('PROPNAME', $property->name);
- $this->assertEquals('propvalue', $property->value);
- $this->assertEquals('propvalue', $property->__toString());
- $this->assertEquals('propvalue', (string)$property);
- $this->assertEquals('propvalue', $property->getValue());
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- public function testCreateNonScalar() {
-
- $property = new Property('propname',array());
-
- }
-
- public function testParameterExists() {
-
- $property = new Property('propname','propvalue');
- $property->parameters[] = new Parameter('paramname','paramvalue');
-
- $this->assertTrue(isset($property['PARAMNAME']));
- $this->assertTrue(isset($property['paramname']));
- $this->assertFalse(isset($property['foo']));
-
- }
-
- public function testParameterGet() {
-
- $property = new Property('propname','propvalue');
- $property->parameters[] = new Parameter('paramname','paramvalue');
-
- $this->assertInstanceOf('Sabre\\VObject\\Parameter',$property['paramname']);
-
- }
-
- public function testParameterNotExists() {
-
- $property = new Property('propname','propvalue');
- $property->parameters[] = new Parameter('paramname','paramvalue');
-
- $this->assertInternalType('null',$property['foo']);
-
- }
-
- public function testParameterMultiple() {
-
- $property = new Property('propname','propvalue');
- $property->parameters[] = new Parameter('paramname','paramvalue');
- $property->parameters[] = new Parameter('paramname','paramvalue');
-
- $this->assertInstanceOf('Sabre\\VObject\\Parameter',$property['paramname']);
- $this->assertEquals(2,count($property['paramname']));
-
- }
-
- public function testSetParameterAsString() {
-
- $property = new Property('propname','propvalue');
- $property['paramname'] = 'paramvalue';
-
- $this->assertEquals(1,count($property->parameters));
- $this->assertInstanceOf('Sabre\\VObject\\Parameter', $property->parameters[0]);
- $this->assertEquals('PARAMNAME',$property->parameters[0]->name);
- $this->assertEquals('paramvalue',$property->parameters[0]->value);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- public function testSetParameterAsStringNoKey() {
-
- $property = new Property('propname','propvalue');
- $property[] = 'paramvalue';
-
- }
-
- public function testSetParameterObject() {
-
- $property = new Property('propname','propvalue');
- $param = new Parameter('paramname','paramvalue');
-
- $property[] = $param;
-
- $this->assertEquals(1,count($property->parameters));
- $this->assertEquals($param, $property->parameters[0]);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- public function testSetParameterObjectWithKey() {
-
- $property = new Property('propname','propvalue');
- $param = new Parameter('paramname','paramvalue');
-
- $property['key'] = $param;
-
- }
-
-
- /**
- * @expectedException InvalidArgumentException
- */
- public function testSetParameterObjectRandomObject() {
-
- $property = new Property('propname','propvalue');
- $property[] = new \StdClass();
-
- }
-
- public function testUnsetParameter() {
-
- $property = new Property('propname','propvalue');
- $param = new Parameter('paramname','paramvalue');
- $property->parameters[] = $param;
-
- unset($property['PARAMNAME']);
- $this->assertEquals(0,count($property->parameters));
-
- }
-
- public function testParamCount() {
-
- $property = new Property('propname','propvalue');
- $param = new Parameter('paramname','paramvalue');
- $property->parameters[] = $param;
- $property->parameters[] = clone $param;
-
- $this->assertEquals(2,count($property->parameters));
-
- }
-
- public function testSerialize() {
-
- $property = new Property('propname','propvalue');
-
- $this->assertEquals("PROPNAME:propvalue\r\n",$property->serialize());
-
- }
-
- public function testSerializeParam() {
-
- $property = new Property('propname','propvalue');
- $property->parameters[] = new Parameter('paramname','paramvalue');
- $property->parameters[] = new Parameter('paramname2','paramvalue2');
-
- $this->assertEquals("PROPNAME;PARAMNAME=paramvalue;PARAMNAME2=paramvalue2:propvalue\r\n",$property->serialize());
-
- }
-
- public function testSerializeNewLine() {
-
- $property = new Property('propname',"line1\nline2");
-
- $this->assertEquals("PROPNAME:line1\\nline2\r\n",$property->serialize());
-
- }
-
- public function testSerializeLongLine() {
-
- $value = str_repeat('!',200);
- $property = new Property('propname',$value);
-
- $expected = "PROPNAME:" . str_repeat('!',66) . "\r\n " . str_repeat('!',74) . "\r\n " . str_repeat('!',60) . "\r\n";
-
- $this->assertEquals($expected,$property->serialize());
-
- }
-
- public function testSerializeUTF8LineFold() {
-
- $value = str_repeat('!',65) . "\xc3\xa4bla"; // inserted umlaut-a
- $property = new Property('propname', $value);
- $expected = "PROPNAME:" . str_repeat('!',65) . "\r\n \xc3\xa4bla\r\n";
- $this->assertEquals($expected, $property->serialize());
-
- }
-
- public function testGetIterator() {
-
- $it = new ElementList(array());
- $property = new Property('propname','propvalue');
- $property->setIterator($it);
- $this->assertEquals($it,$property->getIterator());
-
- }
-
-
- public function testGetIteratorDefault() {
-
- $property = new Property('propname','propvalue');
- $it = $property->getIterator();
- $this->assertTrue($it instanceof ElementList);
- $this->assertEquals(1,count($it));
-
- }
-
- function testAddScalar() {
-
- $property = new Property('EMAIL');
-
- $property->add('myparam','value');
-
- $this->assertEquals(1, count($property->parameters));
-
- $this->assertTrue($property->parameters[0] instanceof Parameter);
- $this->assertEquals('MYPARAM',$property->parameters[0]->name);
- $this->assertEquals('value',$property->parameters[0]->value);
-
- }
-
- function testAddParameter() {
-
- $prop = new Property('EMAIL');
-
- $prop->add(new Parameter('MYPARAM','value'));
-
- $this->assertEquals(1, count($prop->parameters));
- $this->assertEquals('MYPARAM',$prop['myparam']->name);
-
- }
-
- function testAddParameterTwice() {
-
- $prop = new Property('EMAIL');
-
- $prop->add(new Parameter('MYPARAM', 'value1'));
- $prop->add(new Parameter('MYPARAM', 'value2'));
-
- $this->assertEquals(2, count($prop->parameters));
-
- $this->assertEquals('MYPARAM',$prop['MYPARAM']->name);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testAddArgFail() {
-
- $prop = new Property('EMAIL');
- $prop->add(new Parameter('MPARAM'),'hello');
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testAddArgFail2() {
-
- $property = new Property('EMAIL','value');
- $property->add(array());
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testAddArgFail3() {
-
- $property = new Property('EMAIL','value');
- $property->add('hello',array());
-
- }
-
- function testClone() {
-
- $property = new Property('EMAIL','value');
- $property['FOO'] = 'BAR';
-
- $property2 = clone $property;
-
- $property['FOO'] = 'BAZ';
- $this->assertEquals('BAR', (string)$property2['FOO']);
-
- }
-
- function testCreateParams() {
-
- $property = Property::create('X-PROP', 'value', array(
- 'param1' => 'value1',
- 'param2' => array('value2', 'value3')
- ));
-
- $this->assertEquals(1, count($property['PARAM1']));
- $this->assertEquals(2, count($property['PARAM2']));
-
- }
-
- function testValidateNonUTF8() {
-
- $property = Property::create('X-PROP', "Bla\x00");
- $result = $property->validate(Property::REPAIR);
-
- $this->assertEquals('Property is not valid UTF-8!', $result[0]['message']);
- $this->assertEquals('Bla', $property->value);
-
- }
-
-
- function testValidateBadPropertyName() {
-
- $property = Property::create("X_*&PROP*", "Bla");
- $result = $property->validate(Property::REPAIR);
-
- $this->assertEquals($result[0]['message'], 'The propertyname: X_*&PROP* contains invalid characters. Only A-Z, 0-9 and - are allowed');
- $this->assertEquals('X-PROP', $property->name);
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/ReaderTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/ReaderTest.php
deleted file mode 100644
index 0969c6e52..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/ReaderTest.php
+++ /dev/null
@@ -1,367 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class ReaderTest extends \PHPUnit_Framework_TestCase {
-
- function testReadComponent() {
-
- $data = "BEGIN:VCALENDAR\r\nEND:VCALENDAR";
-
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result);
- $this->assertEquals('VCALENDAR', $result->name);
- $this->assertEquals(0, count($result->children));
-
- }
-
- function testReadComponentUnixNewLine() {
-
- $data = "BEGIN:VCALENDAR\nEND:VCALENDAR";
-
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result);
- $this->assertEquals('VCALENDAR', $result->name);
- $this->assertEquals(0, count($result->children));
-
- }
-
- function testReadComponentMacNewLine() {
-
- $data = "BEGIN:VCALENDAR\rEND:VCALENDAR";
-
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result);
- $this->assertEquals('VCALENDAR', $result->name);
- $this->assertEquals(0, count($result->children));
-
- }
-
- function testReadComponentLineFold() {
-
- $data = "BEGIN:\r\n\tVCALENDAR\r\nE\r\n ND:VCALENDAR";
-
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result);
- $this->assertEquals('VCALENDAR', $result->name);
- $this->assertEquals(0, count($result->children));
-
- }
-
- /**
- * @expectedException Sabre\VObject\ParseException
- */
- function testReadCorruptComponent() {
-
- $data = "BEGIN:VCALENDAR\r\nEND:FOO";
-
- $result = Reader::read($data);
-
- }
-
- function testReadProperty() {
-
- $data = "PROPNAME:propValue";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue', $result->value);
-
- }
-
- function testReadPropertyWithNewLine() {
-
- $data = 'PROPNAME:Line1\\nLine2\\NLine3\\\\Not the 4th line!';
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals("Line1\nLine2\nLine3\\Not the 4th line!", $result->value);
-
- }
-
- function testReadMappedProperty() {
-
- $data = "DTSTART:20110529";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property\\DateTime', $result);
- $this->assertEquals('DTSTART', $result->name);
- $this->assertEquals('20110529', $result->value);
-
- }
-
- function testReadMappedPropertyGrouped() {
-
- $data = "foo.DTSTART:20110529";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property\\DateTime', $result);
- $this->assertEquals('DTSTART', $result->name);
- $this->assertEquals('20110529', $result->value);
-
- }
-
-
- /**
- * @expectedException Sabre\VObject\ParseException
- */
- function testReadBrokenLine() {
-
- $data = "PROPNAME;propValue";
- $result = Reader::read($data);
-
- }
-
- function testReadPropertyInComponent() {
-
- $data = array(
- "BEGIN:VCALENDAR",
- "PROPNAME:propValue",
- "END:VCALENDAR"
- );
-
- $result = Reader::read(implode("\r\n",$data));
-
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result);
- $this->assertEquals('VCALENDAR', $result->name);
- $this->assertEquals(1, count($result->children));
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result->children[0]);
- $this->assertEquals('PROPNAME', $result->children[0]->name);
- $this->assertEquals('propValue', $result->children[0]->value);
-
- }
- function testReadNestedComponent() {
-
- $data = array(
- "BEGIN:VCALENDAR",
- "BEGIN:VTIMEZONE",
- "BEGIN:DAYLIGHT",
- "END:DAYLIGHT",
- "END:VTIMEZONE",
- "END:VCALENDAR"
- );
-
- $result = Reader::read(implode("\r\n",$data));
-
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result);
- $this->assertEquals('VCALENDAR', $result->name);
- $this->assertEquals(1, count($result->children));
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result->children[0]);
- $this->assertEquals('VTIMEZONE', $result->children[0]->name);
- $this->assertEquals(1, count($result->children[0]->children));
- $this->assertInstanceOf('Sabre\\VObject\\Component', $result->children[0]->children[0]);
- $this->assertEquals('DAYLIGHT', $result->children[0]->children[0]->name);
-
-
- }
-
- function testReadPropertyParameter() {
-
- $data = "PROPNAME;PARAMNAME=paramvalue:propValue";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue', $result->value);
- $this->assertEquals(1, count($result->parameters));
- $this->assertEquals('PARAMNAME', $result->parameters[0]->name);
- $this->assertEquals('paramvalue', $result->parameters[0]->value);
-
- }
-
- function testReadPropertyNoValue() {
-
- $data = "PROPNAME;PARAMNAME:propValue";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue', $result->value);
- $this->assertEquals(1, count($result->parameters));
- $this->assertEquals('PARAMNAME', $result->parameters[0]->name);
-
- $this->assertNull($result->parameters[0]->value);
-
- }
-
- function testReadPropertyParameterExtraColon() {
-
- $data = "PROPNAME;PARAMNAME=paramvalue:propValue:anotherrandomstring";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue:anotherrandomstring', $result->value);
- $this->assertEquals(1, count($result->parameters));
- $this->assertEquals('PARAMNAME', $result->parameters[0]->name);
- $this->assertEquals('paramvalue', $result->parameters[0]->value);
-
- }
-
- function testReadProperty2Parameters() {
-
- $data = "PROPNAME;PARAMNAME=paramvalue;PARAMNAME2=paramvalue2:propValue";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue', $result->value);
- $this->assertEquals(2, count($result->parameters));
- $this->assertEquals('PARAMNAME', $result->parameters[0]->name);
- $this->assertEquals('paramvalue', $result->parameters[0]->value);
- $this->assertEquals('PARAMNAME2', $result->parameters[1]->name);
- $this->assertEquals('paramvalue2', $result->parameters[1]->value);
-
- }
-
- function testReadPropertyParameterQuoted() {
-
- $data = "PROPNAME;PARAMNAME=\"paramvalue\":propValue";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue', $result->value);
- $this->assertEquals(1, count($result->parameters));
- $this->assertEquals('PARAMNAME', $result->parameters[0]->name);
- $this->assertEquals('paramvalue', $result->parameters[0]->value);
-
- }
- function testReadPropertyParameterNewLines() {
-
- $data = "PROPNAME;PARAMNAME=paramvalue1\\nvalue2\\\\nvalue3:propValue";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue', $result->value);
-
- $this->assertEquals(1, count($result->parameters));
- $this->assertEquals('PARAMNAME', $result->parameters[0]->name);
- $this->assertEquals("paramvalue1\nvalue2\\nvalue3", $result->parameters[0]->value);
-
- }
-
- function testReadPropertyParameterQuotedColon() {
-
- $data = "PROPNAME;PARAMNAME=\"param:value\":propValue";
- $result = Reader::read($data);
-
- $this->assertInstanceOf('Sabre\\VObject\\Property', $result);
- $this->assertEquals('PROPNAME', $result->name);
- $this->assertEquals('propValue', $result->value);
- $this->assertEquals(1, count($result->parameters));
- $this->assertEquals('PARAMNAME', $result->parameters[0]->name);
- $this->assertEquals('param:value', $result->parameters[0]->value);
-
- }
-
- function testReadForgiving() {
-
- $data = array(
- "BEGIN:VCALENDAR",
- "X_PROP:propValue",
- "END:VCALENDAR"
- );
-
- $caught = false;
- try {
- $result = Reader::read(implode("\r\n",$data));
- } catch (ParseException $e) {
- $caught = true;
- }
-
- $this->assertEquals(true, $caught);
-
- $result = Reader::read(implode("\r\n",$data), Reader::OPTION_FORGIVING);
-
- $expected = implode("\r\n", array(
- "BEGIN:VCALENDAR",
- "X_PROP:propValue",
- "END:VCALENDAR",
- ""
- ));
-
- $this->assertEquals($expected, $result->serialize());
-
-
- }
-
- function testReadWithInvalidLine() {
-
- $data = array(
- "BEGIN:VCALENDAR",
- "DESCRIPTION:propValue",
- "Yes, we've actually seen a file with non-idented property values on multiple lines",
- "END:VCALENDAR"
- );
-
- $caught = false;
- try {
- $result = Reader::read(implode("\r\n",$data));
- } catch (ParseException $e) {
- $caught = true;
- }
-
- $this->assertEquals(true, $caught);
-
- $result = Reader::read(implode("\r\n",$data), Reader::OPTION_IGNORE_INVALID_LINES);
-
- $expected = implode("\r\n", array(
- "BEGIN:VCALENDAR",
- "DESCRIPTION:propValue",
- "END:VCALENDAR",
- ""
- ));
-
- $this->assertEquals($expected, $result->serialize());
-
-
- }
-
- /**
- * Reported as Issue 32.
- *
- * @expectedException \Sabre\VObject\ParseException
- */
- function testReadIncompleteFile() {
-
- $input = <<<ICS
-BEGIN:VCALENDAR
-VERSION:1.0
-BEGIN:VEVENT
-X-FUNAMBOL-FOLDER:DEFAULT_FOLDER
-X-FUNAMBOL-ALLDAY:0
-DTSTART:20111017T110000Z
-DTEND:20111017T123000Z
-X-MICROSOFT-CDO-BUSYSTATUS:BUSY
-CATEGORIES:
-LOCATION;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:Netviewer Meeting
-PRIORITY:1
-STATUS:3
-X-MICROSOFT-CDO-REPLYTIME:20111017T064200Z
-SUMMARY;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:Kopieren: test
-CLASS:PUBLIC
-AALARM:
-RRULE:
-X-FUNAMBOL-BILLINGINFO:
-X-FUNAMBOL-COMPANIES:
-X-FUNAMBOL-MILEAGE:
-X-FUNAMBOL-NOAGING:0
-ATTENDEE;STATUS=NEEDS ACTION;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:'Heino' heino@test.com
-ATTENDEE;STATUS=NEEDS ACTION;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:'Markus' test@test.com
-ATTENDEE;STATUS=NEEDS AC
-ICS;
-
- Reader::read($input);
-
- }
-
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorFifthTuesdayProblemTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorFifthTuesdayProblemTest.php
deleted file mode 100644
index 069832a0f..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorFifthTuesdayProblemTest.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class RecurrenceIteratorFifthTuesdayProblemTest extends \PHPUnit_Framework_TestCase {
-
- function testGetDTEnd() {
-
- $ics = <<<ICS
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.4//EN
-CALSCALE:GREGORIAN
-BEGIN:VEVENT
-TRANSP:OPAQUE
-DTEND;TZID=America/New_York:20070925T170000
-UID:uuid
-DTSTAMP:19700101T000000Z
-LOCATION:
-DESCRIPTION:
-STATUS:CONFIRMED
-SEQUENCE:18
-SUMMARY:Stuff
-DTSTART;TZID=America/New_York:20070925T160000
-CREATED:20071004T144642Z
-RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=20071030T035959Z;BYDAY=5TU
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- $vObject = Reader::read($ics);
- $it = new RecurrenceIterator($vObject, (string)$vObject->VEVENT->UID);
-
- while($it->valid()) {
- $it->next();
- }
-
- // If we got here, it means we were successful. The bug that was in the
- // system before would fail on the 5th tuesday of the month, if the 5th
- // tuesday did not exist.
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorIncorrectExpandTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorIncorrectExpandTest.php
deleted file mode 100644
index 9adc8537f..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorIncorrectExpandTest.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-use
- DateTime,
- DateTimeZone;
-
-/**
- * This is a unittest for Issue #53.
- */
-class RecurrenceIteratorIncorrectExpandTest extends \PHPUnit_Framework_TestCase {
-
- function testExpand() {
-
- $input = <<<ICS
-BEGIN:VCALENDAR
-VERSION:2.0
-BEGIN:VEVENT
-UID:foo
-DTSTART:20130711T050000Z
-DTEND:20130711T053000Z
-RRULE:FREQ=DAILY;INTERVAL=1;COUNT=2
-END:VEVENT
-BEGIN:VEVENT
-UID:foo
-DTSTART:20130719T050000Z
-DTEND:20130719T053000Z
-RECURRENCE-ID:20130712T050000Z
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- $vcal = Reader::read($input);
- $this->assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal);
-
- $vcal->expand(new DateTime('2011-01-01'), new DateTime('2014-01-01'));
-
- $result = $vcal->serialize();
-
- $output = <<<ICS
-BEGIN:VCALENDAR
-VERSION:2.0
-BEGIN:VEVENT
-UID:foo
-DTSTART;VALUE=DATE-TIME:20130711T050000Z
-DTEND;VALUE=DATE-TIME:20130711T053000Z
-END:VEVENT
-BEGIN:VEVENT
-UID:foo
-DTSTART:20130719T050000Z
-DTEND:20130719T053000Z
-RECURRENCE-ID:20130712T050000Z
-END:VEVENT
-END:VCALENDAR
-
-ICS;
- $this->assertEquals($output, str_replace("\r", "", $result));
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorInfiniteLoopProblemTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorInfiniteLoopProblemTest.php
deleted file mode 100644
index 670c39bae..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorInfiniteLoopProblemTest.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-use DateTime;
-use DateTimeZone;
-
-class RecurrenceIteratorInfiniteLoopProblemTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * This bug came from a Fruux customer. This would result in a never-ending
- * request.
- */
- function testFastForwardTooFar() {
-
- $ev = Component::create('VEVENT');
- $ev->DTSTART = '20090420T180000Z';
- $ev->RRULE = 'FREQ=WEEKLY;BYDAY=MO;UNTIL=20090704T205959Z;INTERVAL=1';
-
- $this->assertFalse($ev->isInTimeRange(new DateTime('2012-01-01 12:00:00'),new DateTime('3000-01-01 00:00:00')));
-
- }
-
- /**
- * Different bug, also likely an infinite loop.
- */
- function testYearlyByMonthLoop() {
-
- $ev = Component::create('VEVENT');
- $ev->UID = 'uuid';
- $ev->DTSTART = '20120101T154500';
- $ev->DTSTART['TZID'] = 'Europe/Berlin';
- $ev->RRULE = 'FREQ=YEARLY;INTERVAL=1;UNTIL=20120203T225959Z;BYMONTH=2;BYSETPOS=1;BYDAY=SU,MO,TU,WE,TH,FR,SA';
- $ev->DTEND = '20120101T164500';
- $ev->DTEND['TZID'] = 'Europe/Berlin';
-
- // This recurrence rule by itself is a yearly rule that should happen
- // every february.
- //
- // The BYDAY part expands this to every day of the month, but the
- // BYSETPOS limits this to only the 1st day of the month. Very crazy
- // way to specify this, and could have certainly been a lot easier.
- $cal = Component::create('VCALENDAR');
- $cal->add($ev);
-
- $it = new RecurrenceIterator($cal,'uuid');
- $it->fastForward(new DateTime('2012-01-29 23:00:00', new DateTimeZone('UTC')));
-
- $collect = array();
-
- while($it->valid()) {
- $collect[] = $it->getDTSTART();
- if ($it->getDTSTART() > new DateTime('2013-02-05 22:59:59', new DateTimeZone('UTC'))) {
- break;
- }
- $it->next();
-
- }
-
- $this->assertEquals(
- array(new DateTime('2012-02-01 15:45:00', new DateTimeZone('Europe/Berlin'))),
- $collect
- );
-
- }
-
- /**
- * Something, somewhere produced an ics with an interval set to 0. Because
- * this means we increase the current day (or week, month) by 0, this also
- * results in an infinite loop.
- *
- * @expectedException InvalidArgumentException
- * @return void
- */
- function testZeroInterval() {
-
- $ev = Component::create('VEVENT');
- $ev->UID = 'uuid';
- $ev->DTSTART = '20120824T145700Z';
- $ev->RRULE = 'FREQ=YEARLY;INTERVAL=0';
- $cal = Component::create('VCALENDAR');
- $cal->add($ev);
-
- $it = new RecurrenceIterator($cal,'uuid');
- $it->fastForward(new DateTime('2013-01-01 23:00:00', new DateTimeZone('UTC')));
-
- // if we got this far.. it means we are no longer infinitely looping
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMinusOneProblemTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMinusOneProblemTest.php
deleted file mode 100644
index 2c17f9f6b..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMinusOneProblemTest.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class RecurrenceIteratorMinusOneProblemTest extends \PHPUnit_Framework_TestCase {
-
- function testMinusOne() {
-
- $ics = <<<ICS
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-DTSTAMP:20120314T203127Z
-UID:foo
-SUMMARY:foo
-RRULE:FREQ=YEARLY;UNTIL=20120314
-DTSTART;VALUE=DATE:20120315
-DTEND;VALUE=DATE:20120316
-SEQUENCE:1
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- $vObject = Reader::read($ics);
- $it = new RecurrenceIterator($vObject, (string)$vObject->VEVENT->UID);
-
- $this->assertTrue($it->valid());
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMissingOverriddenTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMissingOverriddenTest.php
deleted file mode 100644
index f311329db..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMissingOverriddenTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-use
- DateTime,
- DateTimeZone;
-
-class RecurrenceIteratorMissingOverriddenTest extends \PHPUnit_Framework_TestCase {
-
- function testExpand() {
-
- $input = <<<ICS
-BEGIN:VCALENDAR
-VERSION:2.0
-BEGIN:VEVENT
-UID:foo
-DTSTART:20130727T120000Z
-DURATION:PT1H
-RRULE:FREQ=DAILY;COUNT=2
-SUMMARY:A
-END:VEVENT
-BEGIN:VEVENT
-RECURRENCE-ID:20130728T120000Z
-UID:foo
-DTSTART:20140101T120000Z
-DURATION:PT1H
-SUMMARY:B
-END:VEVENT
-END:VCALENDAR
-ICS;
-
- $vcal = Reader::read($input);
- $this->assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal);
-
- $vcal->expand(new DateTime('2011-01-01'), new DateTime('2015-01-01'));
-
- $result = $vcal->serialize();
-
- $output = <<<ICS
-BEGIN:VCALENDAR
-VERSION:2.0
-BEGIN:VEVENT
-UID:foo
-DTSTART;VALUE=DATE-TIME:20130727T120000Z
-DURATION:PT1H
-SUMMARY:A
-END:VEVENT
-BEGIN:VEVENT
-RECURRENCE-ID:20130728T120000Z
-UID:foo
-DTSTART:20140101T120000Z
-DURATION:PT1H
-SUMMARY:B
-END:VEVENT
-END:VCALENDAR
-
-ICS;
- $this->assertEquals($output, str_replace("\r","",$result));
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorTest.php
deleted file mode 100644
index 5988f16e2..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorTest.php
+++ /dev/null
@@ -1,1425 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-use DateTime;
-use DateTimeZone;
-
-class RecurrenceIteratorTest extends \PHPUnit_Framework_TestCase {
-
- function testValues() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=DAILY;BYHOUR=10;BYMINUTE=5;BYSECOND=16;BYWEEKNO=32;BYYEARDAY=100,200';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07'),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertTrue($it->isInfinite());
- $this->assertEquals(array(10), $it->byHour);
- $this->assertEquals(array(5), $it->byMinute);
- $this->assertEquals(array(16), $it->bySecond);
- $this->assertEquals(array(32), $it->byWeekNo);
- $this->assertEquals(array(100,200), $it->byYearDay);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- * @depends testValues
- */
- function testInvalidFreq() {
-
- $ev = new Component('VEVENT');
- $ev->RRULE = 'FREQ=SMONTHLY;INTERVAL=3;UNTIL=20111025T000000Z';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07'),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testVCalendarNoUID() {
-
- $vcal = new Component('VCALENDAR');
- $it = new RecurrenceIterator($vcal);
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testVCalendarInvalidUID() {
-
- $vcal = new Component('VCALENDAR');
- $it = new RecurrenceIterator($vcal,'foo');
-
- }
-
- /**
- * @depends testValues
- */
- function testHourly() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=HOURLY;INTERVAL=3;UNTIL=20111025T000000Z';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07 12:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,$ev->uid);
-
- $this->assertEquals('hourly', $it->frequency);
- $this->assertEquals(3, $it->interval);
- $this->assertEquals(new DateTime('2011-10-25', new DateTimeZone('UTC')), $it->until);
-
- // Max is to prevent overflow
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07 12:00:00', $tz),
- new DateTime('2011-10-07 15:00:00', $tz),
- new DateTime('2011-10-07 18:00:00', $tz),
- new DateTime('2011-10-07 21:00:00', $tz),
- new DateTime('2011-10-08 00:00:00', $tz),
- new DateTime('2011-10-08 03:00:00', $tz),
- new DateTime('2011-10-08 06:00:00', $tz),
- new DateTime('2011-10-08 09:00:00', $tz),
- new DateTime('2011-10-08 12:00:00', $tz),
- new DateTime('2011-10-08 15:00:00', $tz),
- new DateTime('2011-10-08 18:00:00', $tz),
- new DateTime('2011-10-08 21:00:00', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testDaily() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=DAILY;INTERVAL=3;UNTIL=20111025T000000Z';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,$ev->uid);
-
- $this->assertEquals('daily', $it->frequency);
- $this->assertEquals(3, $it->interval);
- $this->assertEquals(new DateTime('2011-10-25', new DateTimeZone('UTC')), $it->until);
-
- // Max is to prevent overflow
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07', $tz),
- new DateTime('2011-10-10', $tz),
- new DateTime('2011-10-13', $tz),
- new DateTime('2011-10-16', $tz),
- new DateTime('2011-10-19', $tz),
- new DateTime('2011-10-22', $tz),
- new DateTime('2011-10-25', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testNoRRULE() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,$ev->uid);
-
- $this->assertEquals('daily', $it->frequency);
- $this->assertEquals(1, $it->interval);
-
- // Max is to prevent overflow
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testDailyByDayByHour() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=DAILY;BYDAY=SA,SU;BYHOUR=6,7';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-08 06:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('daily', $it->frequency);
- $this->assertEquals(1, $it->interval);
- $this->assertEquals(array('6','7'), $it->byHour);
- $this->assertEquals(array('SA','SU'), $it->byDay);
-
- // Grabbing the next 12 items
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new datetime('2011-10-08 06:00:00', $tz),
- new datetime('2011-10-08 07:00:00', $tz),
- new datetime('2011-10-09 06:00:00', $tz),
- new datetime('2011-10-09 07:00:00', $tz),
- new datetime('2011-10-15 06:00:00', $tz),
- new datetime('2011-10-15 07:00:00', $tz),
- new datetime('2011-10-16 06:00:00', $tz),
- new datetime('2011-10-16 07:00:00', $tz),
- new datetime('2011-10-22 06:00:00', $tz),
- new datetime('2011-10-22 07:00:00', $tz),
- new datetime('2011-10-23 06:00:00', $tz),
- new datetime('2011-10-23 07:00:00', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testDailyByHour() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYHOUR=10,11,12,13,14,15';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2012-10-11 12:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('daily', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(array('10','11','12','13','14','15'), $it->byHour);
-
- // Grabbing the next 12 items
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new datetime('2012-10-11 12:00:00', $tz),
- new datetime('2012-10-11 13:00:00', $tz),
- new datetime('2012-10-11 14:00:00', $tz),
- new datetime('2012-10-11 15:00:00', $tz),
- new datetime('2012-10-13 10:00:00', $tz),
- new datetime('2012-10-13 11:00:00', $tz),
- new datetime('2012-10-13 12:00:00', $tz),
- new datetime('2012-10-13 13:00:00', $tz),
- new datetime('2012-10-13 14:00:00', $tz),
- new datetime('2012-10-13 15:00:00', $tz),
- new datetime('2012-10-15 10:00:00', $tz),
- new datetime('2012-10-15 11:00:00', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testDailyByDay() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYDAY=TU,WE,FR';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('daily', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(array('TU','WE','FR'), $it->byDay);
-
- // Grabbing the next 12 items
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07', $tz),
- new DateTime('2011-10-11', $tz),
- new DateTime('2011-10-19', $tz),
- new DateTime('2011-10-21', $tz),
- new DateTime('2011-10-25', $tz),
- new DateTime('2011-11-02', $tz),
- new DateTime('2011-11-04', $tz),
- new DateTime('2011-11-08', $tz),
- new DateTime('2011-11-16', $tz),
- new DateTime('2011-11-18', $tz),
- new DateTime('2011-11-22', $tz),
- new DateTime('2011-11-30', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testWeekly() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;COUNT=10';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('weekly', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(10, $it->count);
-
- // Max is to prevent overflow
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07', $tz),
- new DateTime('2011-10-21', $tz),
- new DateTime('2011-11-04', $tz),
- new DateTime('2011-11-18', $tz),
- new DateTime('2011-12-02', $tz),
- new DateTime('2011-12-16', $tz),
- new DateTime('2011-12-30', $tz),
- new DateTime('2012-01-13', $tz),
- new DateTime('2012-01-27', $tz),
- new DateTime('2012-02-10', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testWeeklyByDayByHour() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=MO;BYHOUR=8,9,10';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07 08:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('weekly', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(array('TU','WE','FR'), $it->byDay);
- $this->assertEquals(array('8','9','10'), $it->byHour);
- $this->assertEquals('MO', $it->weekStart);
-
- // Grabbing the next 12 items
- $max = 15;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07 08:00:00', $tz),
- new DateTime('2011-10-07 09:00:00', $tz),
- new DateTime('2011-10-07 10:00:00', $tz),
- new DateTime('2011-10-18 08:00:00', $tz),
- new DateTime('2011-10-18 09:00:00', $tz),
- new DateTime('2011-10-18 10:00:00', $tz),
- new DateTime('2011-10-19 08:00:00', $tz),
- new DateTime('2011-10-19 09:00:00', $tz),
- new DateTime('2011-10-19 10:00:00', $tz),
- new DateTime('2011-10-21 08:00:00', $tz),
- new DateTime('2011-10-21 09:00:00', $tz),
- new DateTime('2011-10-21 10:00:00', $tz),
- new DateTime('2011-11-01 08:00:00', $tz),
- new DateTime('2011-11-01 09:00:00', $tz),
- new DateTime('2011-11-01 10:00:00', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testWeeklyByDaySpecificHour() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07 18:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('weekly', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(array('TU','WE','FR'), $it->byDay);
- $this->assertEquals('SU', $it->weekStart);
-
- // Grabbing the next 12 items
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07 18:00:00', $tz),
- new DateTime('2011-10-18 18:00:00', $tz),
- new DateTime('2011-10-19 18:00:00', $tz),
- new DateTime('2011-10-21 18:00:00', $tz),
- new DateTime('2011-11-01 18:00:00', $tz),
- new DateTime('2011-11-02 18:00:00', $tz),
- new DateTime('2011-11-04 18:00:00', $tz),
- new DateTime('2011-11-15 18:00:00', $tz),
- new DateTime('2011-11-16 18:00:00', $tz),
- new DateTime('2011-11-18 18:00:00', $tz),
- new DateTime('2011-11-29 18:00:00', $tz),
- new DateTime('2011-11-30 18:00:00', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testWeeklyByDay() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('weekly', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(array('TU','WE','FR'), $it->byDay);
- $this->assertEquals('SU', $it->weekStart);
-
- // Grabbing the next 12 items
- $max = 12;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-10-07', $tz),
- new DateTime('2011-10-18', $tz),
- new DateTime('2011-10-19', $tz),
- new DateTime('2011-10-21', $tz),
- new DateTime('2011-11-01', $tz),
- new DateTime('2011-11-02', $tz),
- new DateTime('2011-11-04', $tz),
- new DateTime('2011-11-15', $tz),
- new DateTime('2011-11-16', $tz),
- new DateTime('2011-11-18', $tz),
- new DateTime('2011-11-29', $tz),
- new DateTime('2011-11-30', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testMonthly() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=3;COUNT=5';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-12-05', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('monthly', $it->frequency);
- $this->assertEquals(3, $it->interval);
- $this->assertEquals(5, $it->count);
-
- $max = 14;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-12-05', $tz),
- new DateTime('2012-03-05', $tz),
- new DateTime('2012-06-05', $tz),
- new DateTime('2012-09-05', $tz),
- new DateTime('2012-12-05', $tz),
- ),
- $result
- );
-
-
- }
-
- /**
- * @depends testValues
- */
- function testMonthlyEndOfMonth() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=12';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-12-31', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('monthly', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(12, $it->count);
-
- $max = 14;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-12-31', $tz),
- new DateTime('2012-08-31', $tz),
- new DateTime('2012-10-31', $tz),
- new DateTime('2012-12-31', $tz),
- new DateTime('2013-08-31', $tz),
- new DateTime('2013-10-31', $tz),
- new DateTime('2013-12-31', $tz),
- new DateTime('2014-08-31', $tz),
- new DateTime('2014-10-31', $tz),
- new DateTime('2014-12-31', $tz),
- new DateTime('2015-08-31', $tz),
- new DateTime('2015-10-31', $tz),
- ),
- $result
- );
-
-
- }
-
- /**
- * @depends testValues
- */
- function testMonthlyByMonthDay() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=5;COUNT=9;BYMONTHDAY=1,31,-7';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-01-01', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('monthly', $it->frequency);
- $this->assertEquals(5, $it->interval);
- $this->assertEquals(9, $it->count);
- $this->assertEquals(array(1, 31, -7), $it->byMonthDay);
-
- $max = 14;
- $result = array();
- foreach($it as $item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-01-01', $tz),
- new DateTime('2011-01-25', $tz),
- new DateTime('2011-01-31', $tz),
- new DateTime('2011-06-01', $tz),
- new DateTime('2011-06-24', $tz),
- new DateTime('2011-11-01', $tz),
- new DateTime('2011-11-24', $tz),
- new DateTime('2012-04-01', $tz),
- new DateTime('2012-04-24', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testMonthlyByDay() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=16;BYDAY=MO,-2TU,+1WE,3TH';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-01-03', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('monthly', $it->frequency);
- $this->assertEquals(2, $it->interval);
- $this->assertEquals(16, $it->count);
- $this->assertEquals(array('MO','-2TU','+1WE','3TH'), $it->byDay);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-01-03', $tz),
- new DateTime('2011-01-05', $tz),
- new DateTime('2011-01-10', $tz),
- new DateTime('2011-01-17', $tz),
- new DateTime('2011-01-18', $tz),
- new DateTime('2011-01-20', $tz),
- new DateTime('2011-01-24', $tz),
- new DateTime('2011-01-31', $tz),
- new DateTime('2011-03-02', $tz),
- new DateTime('2011-03-07', $tz),
- new DateTime('2011-03-14', $tz),
- new DateTime('2011-03-17', $tz),
- new DateTime('2011-03-21', $tz),
- new DateTime('2011-03-22', $tz),
- new DateTime('2011-03-28', $tz),
- new DateTime('2011-05-02', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testMonthlyByDayByMonthDay() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO;BYMONTHDAY=1';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-08-01', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('monthly', $it->frequency);
- $this->assertEquals(1, $it->interval);
- $this->assertEquals(10, $it->count);
- $this->assertEquals(array('MO'), $it->byDay);
- $this->assertEquals(array(1), $it->byMonthDay);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-08-01', $tz),
- new DateTime('2012-10-01', $tz),
- new DateTime('2013-04-01', $tz),
- new DateTime('2013-07-01', $tz),
- new DateTime('2014-09-01', $tz),
- new DateTime('2014-12-01', $tz),
- new DateTime('2015-06-01', $tz),
- new DateTime('2016-02-01', $tz),
- new DateTime('2016-08-01', $tz),
- new DateTime('2017-05-01', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testMonthlyByDayBySetPos() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1,-1';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-01-03', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('monthly', $it->frequency);
- $this->assertEquals(1, $it->interval);
- $this->assertEquals(10, $it->count);
- $this->assertEquals(array('MO','TU','WE','TH','FR'), $it->byDay);
- $this->assertEquals(array(1,-1), $it->bySetPos);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-01-03', $tz),
- new DateTime('2011-01-31', $tz),
- new DateTime('2011-02-01', $tz),
- new DateTime('2011-02-28', $tz),
- new DateTime('2011-03-01', $tz),
- new DateTime('2011-03-31', $tz),
- new DateTime('2011-04-01', $tz),
- new DateTime('2011-04-29', $tz),
- new DateTime('2011-05-02', $tz),
- new DateTime('2011-05-31', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testYearly() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=YEARLY;COUNT=10;INTERVAL=3';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-01-01', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('yearly', $it->frequency);
- $this->assertEquals(3, $it->interval);
- $this->assertEquals(10, $it->count);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-01-01', $tz),
- new DateTime('2014-01-01', $tz),
- new DateTime('2017-01-01', $tz),
- new DateTime('2020-01-01', $tz),
- new DateTime('2023-01-01', $tz),
- new DateTime('2026-01-01', $tz),
- new DateTime('2029-01-01', $tz),
- new DateTime('2032-01-01', $tz),
- new DateTime('2035-01-01', $tz),
- new DateTime('2038-01-01', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testYearlyLeapYear() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=YEARLY;COUNT=3';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2012-02-29', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('yearly', $it->frequency);
- $this->assertEquals(3, $it->count);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2012-02-29', $tz),
- new DateTime('2016-02-29', $tz),
- new DateTime('2020-02-29', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testYearlyByMonth() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYMONTH=4,10';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-04-07', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('yearly', $it->frequency);
- $this->assertEquals(4, $it->interval);
- $this->assertEquals(8, $it->count);
- $this->assertEquals(array(4,10), $it->byMonth);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-04-07', $tz),
- new DateTime('2011-10-07', $tz),
- new DateTime('2015-04-07', $tz),
- new DateTime('2015-10-07', $tz),
- new DateTime('2019-04-07', $tz),
- new DateTime('2019-10-07', $tz),
- new DateTime('2023-04-07', $tz),
- new DateTime('2023-10-07', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testYearlyByMonthByDay() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-04-04', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('yearly', $it->frequency);
- $this->assertEquals(5, $it->interval);
- $this->assertEquals(8, $it->count);
- $this->assertEquals(array(4,10), $it->byMonth);
- $this->assertEquals(array('1MO','-1SU'), $it->byDay);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $tz = new DateTimeZone('UTC');
-
- $this->assertEquals(
- array(
- new DateTime('2011-04-04', $tz),
- new DateTime('2011-04-24', $tz),
- new DateTime('2011-10-03', $tz),
- new DateTime('2011-10-30', $tz),
- new DateTime('2016-04-04', $tz),
- new DateTime('2016-04-24', $tz),
- new DateTime('2016-10-03', $tz),
- new DateTime('2016-10-30', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testFastForward() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU';
- $dtStart = new Property\DateTime('DTSTART');
- $dtStart->setDateTime(new DateTime('2011-04-04', new DateTimeZone('UTC')),Property\DateTime::UTC);
-
- $ev->add($dtStart);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- // The idea is that we're fast-forwarding too far in the future, so
- // there will be no results left.
- $it->fastForward(new DateTime('2020-05-05', new DateTimeZone('UTC')));
-
- $max = 20;
- $result = array();
- while($item = $it->current()) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
- $it->next();
-
- }
-
- $tz = new DateTimeZone('UTC');
- $this->assertEquals(array(), $result);
-
- }
-
- /**
- * @depends testValues
- */
- function testComplexExclusions() {
-
- $ev = new Component('VEVENT');
- $ev->UID = 'bla';
- $ev->RRULE = 'FREQ=YEARLY;COUNT=10';
- $dtStart = new Property\DateTime('DTSTART');
-
- $tz = new DateTimeZone('Canada/Eastern');
- $dtStart->setDateTime(new DateTime('2011-01-01 13:50:20', $tz),Property\DateTime::LOCALTZ);
-
- $exDate1 = new Property\MultiDateTime('EXDATE');
- $exDate1->setDateTimes(array(new DateTime('2012-01-01 13:50:20', $tz), new DateTime('2014-01-01 13:50:20', $tz)), Property\DateTime::LOCALTZ);
- $exDate2 = new Property\MultiDateTime('EXDATE');
- $exDate2->setDateTimes(array(new DateTime('2016-01-01 13:50:20', $tz)), Property\DateTime::LOCALTZ);
-
- $ev->add($dtStart);
- $ev->add($exDate1);
- $ev->add($exDate2);
-
- $vcal = Component::create('VCALENDAR');
- $vcal->add($ev);
-
- $it = new RecurrenceIterator($vcal,(string)$ev->uid);
-
- $this->assertEquals('yearly', $it->frequency);
- $this->assertEquals(1, $it->interval);
- $this->assertEquals(10, $it->count);
-
- $max = 20;
- $result = array();
- foreach($it as $k=>$item) {
-
- $result[] = $item;
- $max--;
-
- if (!$max) break;
-
- }
-
- $this->assertEquals(
- array(
- new DateTime('2011-01-01 13:50:20', $tz),
- new DateTime('2013-01-01 13:50:20', $tz),
- new DateTime('2015-01-01 13:50:20', $tz),
- new DateTime('2017-01-01 13:50:20', $tz),
- new DateTime('2018-01-01 13:50:20', $tz),
- new DateTime('2019-01-01 13:50:20', $tz),
- new DateTime('2020-01-01 13:50:20', $tz),
- ),
- $result
- );
-
- }
-
- /**
- * @depends testValues
- */
- function testOverridenEvent() {
-
- $vcal = Component::create('VCALENDAR');
-
- $ev1 = Component::create('VEVENT');
- $ev1->UID = 'overridden';
- $ev1->RRULE = 'FREQ=DAILY;COUNT=10';
- $ev1->DTSTART = '20120107T120000Z';
- $ev1->SUMMARY = 'baseEvent';
-
- $vcal->add($ev1);
-
- // ev2 overrides an event, and puts it on 2pm instead.
- $ev2 = Component::create('VEVENT');
- $ev2->UID = 'overridden';
- $ev2->{'RECURRENCE-ID'} = '20120110T120000Z';
- $ev2->DTSTART = '20120110T140000Z';
- $ev2->SUMMARY = 'Event 2';
-
- $vcal->add($ev2);
-
- // ev3 overrides an event, and puts it 2 days and 2 hours later
- $ev3 = Component::create('VEVENT');
- $ev3->UID = 'overridden';
- $ev3->{'RECURRENCE-ID'} = '20120113T120000Z';
- $ev3->DTSTART = '20120115T140000Z';
- $ev3->SUMMARY = 'Event 3';
-
- $vcal->add($ev3);
-
- $it = new RecurrenceIterator($vcal,'overridden');
-
- $dates = array();
- $summaries = array();
- while($it->valid()) {
-
- $dates[] = $it->getDTStart();
- $summaries[] = (string)$it->getEventObject()->SUMMARY;
- $it->next();
-
- }
-
- $tz = new DateTimeZone('UTC');
- $this->assertEquals(array(
- new DateTime('2012-01-07 12:00:00',$tz),
- new DateTime('2012-01-08 12:00:00',$tz),
- new DateTime('2012-01-09 12:00:00',$tz),
- new DateTime('2012-01-10 14:00:00',$tz),
- new DateTime('2012-01-11 12:00:00',$tz),
- new DateTime('2012-01-12 12:00:00',$tz),
- new DateTime('2012-01-14 12:00:00',$tz),
- new DateTime('2012-01-15 12:00:00',$tz),
- new DateTime('2012-01-15 14:00:00',$tz),
- new DateTime('2012-01-16 12:00:00',$tz),
- ), $dates);
-
- $this->assertEquals(array(
- 'baseEvent',
- 'baseEvent',
- 'baseEvent',
- 'Event 2',
- 'baseEvent',
- 'baseEvent',
- 'baseEvent',
- 'baseEvent',
- 'Event 3',
- 'baseEvent',
- ), $summaries);
-
- }
-
- /**
- * @depends testValues
- */
- function testOverridenEvent2() {
-
- $vcal = Component::create('VCALENDAR');
-
- $ev1 = Component::create('VEVENT');
- $ev1->UID = 'overridden';
- $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3';
- $ev1->DTSTART = '20120112T120000Z';
- $ev1->SUMMARY = 'baseEvent';
-
- $vcal->add($ev1);
-
- // ev2 overrides an event, and puts it 6 days earlier instead.
- $ev2 = Component::create('VEVENT');
- $ev2->UID = 'overridden';
- $ev2->{'RECURRENCE-ID'} = '20120119T120000Z';
- $ev2->DTSTART = '20120113T120000Z';
- $ev2->SUMMARY = 'Override!';
-
- $vcal->add($ev2);
-
- $it = new RecurrenceIterator($vcal,'overridden');
-
- $dates = array();
- $summaries = array();
- while($it->valid()) {
-
- $dates[] = $it->getDTStart();
- $summaries[] = (string)$it->getEventObject()->SUMMARY;
- $it->next();
-
- }
-
- $tz = new DateTimeZone('UTC');
- $this->assertEquals(array(
- new DateTime('2012-01-12 12:00:00',$tz),
- new DateTime('2012-01-13 12:00:00',$tz),
- new DateTime('2012-01-26 12:00:00',$tz),
-
- ), $dates);
-
- $this->assertEquals(array(
- 'baseEvent',
- 'Override!',
- 'baseEvent',
- ), $summaries);
-
- }
-
- /**
- * @depends testValues
- */
- function testOverridenEventNoValuesExpected() {
-
- $vcal = Component::create('VCALENDAR');
-
- $ev1 = Component::create('VEVENT');
- $ev1->UID = 'overridden';
- $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3';
- $ev1->DTSTART = '20120124T120000Z';
- $ev1->SUMMARY = 'baseEvent';
-
- $vcal->add($ev1);
-
- // ev2 overrides an event, and puts it 6 days earlier instead.
- $ev2 = Component::create('VEVENT');
- $ev2->UID = 'overridden';
- $ev2->{'RECURRENCE-ID'} = '20120131T120000Z';
- $ev2->DTSTART = '20120125T120000Z';
- $ev2->SUMMARY = 'Override!';
-
- $vcal->add($ev2);
-
- $it = new RecurrenceIterator($vcal,'overridden');
-
- $dates = array();
- $summaries = array();
-
- // The reported problem was specifically related to the VCALENDAR
- // expansion. In this parcitular case, we had to forward to the 28th of
- // january.
- $it->fastForward(new DateTime('2012-01-28 23:00:00'));
-
- // We stop the loop when it hits the 6th of februari. Normally this
- // iterator would hit 24, 25 (overriden from 31) and 7 feb but because
- // we 'filter' from the 28th till the 6th, we should get 0 results.
- while($it->valid() && $it->getDTSTart() < new DateTime('2012-02-06 23:00:00')) {
-
- $dates[] = $it->getDTStart();
- $summaries[] = (string)$it->getEventObject()->SUMMARY;
- $it->next();
-
- }
-
- $this->assertEquals(array(), $dates);
- $this->assertEquals(array(), $summaries);
-
- }
-}
-
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/SlashRTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/SlashRTest.php
deleted file mode 100644
index ebbfb04a7..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/SlashRTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-/**
- * This issue was pointed out in Issue 55. \r should be stripped completely
- * when encoding property values.
- */
-class SlashRTest extends \PHPUnit_Framework_TestCase {
-
- function testEncode() {
-
- $prop = new \Sabre\VObject\Property('test', "abc\r\ndef");
- $this->assertEquals("TEST:abc\\ndef\r\n", $prop->serialize());
-
- }
-
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/ICalendarTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/ICalendarTest.php
deleted file mode 100644
index 43613350f..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/ICalendarTest.php
+++ /dev/null
@@ -1,283 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Splitter;
-
-use Sabre\VObject;
-
-class ICalendarSplitterTest extends \PHPUnit_Framework_TestCase {
-
- protected $version;
-
- function setup() {
- $this->version = VObject\Version::VERSION;
- }
-
- function createStream($data) {
-
- $stream = fopen('php://memory','r+');
- fwrite($stream, $data);
- rewind($stream);
- return $stream;
-
- }
-
- function testICalendarImportValidEvent() {
-
- $data = <<<EOT
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-UID:foo
-END:VEVENT
-END:VCALENDAR
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new ICalendar($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
- $this->assertEquals(array(), VObject\Reader::read($return)->validate());
- }
-
- function testICalendarImportEndOfData() {
- $data = <<<EOT
-BEGIN:VCALENDAR
-BEGIN:VEVENT
-UID:foo
-END:VEVENT
-END:VCALENDAR
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new ICalendar($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
- $this->assertNull($object=$objects->getNext());
- }
-
- /**
- * @expectedException Sabre\VObject\ParseException
- */
- function testICalendarImportInvalidEvent() {
- $data = <<<EOT
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new ICalendar($tempFile);
- }
-
- function testICalendarImportMultipleValidEvents() {
-
- $event[] = <<<EOT
-BEGIN:VEVENT
-UID:foo1
-END:VEVENT
-EOT;
-
-$event[] = <<<EOT
-BEGIN:VEVENT
-UID:foo2
-END:VEVENT
-EOT;
-
- $data = <<<EOT
-BEGIN:VCALENDAR
-$event[0]
-$event[1]
-END:VCALENDAR
-
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new ICalendar($tempFile);
-
- $return = "";
- $i = 0;
- while($object=$objects->getNext()) {
-
- $expected = <<<EOT
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Sabre//Sabre VObject $this->version//EN
-CALSCALE:GREGORIAN
-$event[$i]
-END:VCALENDAR
-
-EOT;
-
- $return .= $object->serialize();
- $expected = str_replace("\n", "\r\n", $expected);
- $this->assertEquals($expected, $object->serialize());
- $i++;
- }
- $this->assertEquals(array(), VObject\Reader::read($return)->validate());
- }
-
- function testICalendarImportEventWithoutUID() {
-
- $data = <<<EOT
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Sabre//Sabre VObject $this->version//EN
-CALSCALE:GREGORIAN
-BEGIN:VEVENT
-END:VEVENT
-END:VCALENDAR
-
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new ICalendar($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $expected = str_replace("\n", "\r\n", $data);
- $this->assertEquals($expected, $object->serialize());
- $return .= $object->serialize();
- }
-
- $this->assertEquals(array(), VObject\Reader::read($return)->validate());
- }
-
- function testICalendarImportMultipleVTIMEZONESAndMultipleValidEvents() {
-
- $timezones = <<<EOT
-BEGIN:VTIMEZONE
-TZID:Europe/Berlin
-BEGIN:DAYLIGHT
-TZOFFSETFROM:+0100
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
-DTSTART:19810329T020000
-TZNAME:MESZ
-TZOFFSETTO:+0200
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:+0200
-RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
-DTSTART:19961027T030000
-TZNAME:MEZ
-TZOFFSETTO:+0100
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VTIMEZONE
-TZID:Europe/London
-BEGIN:DAYLIGHT
-TZOFFSETFROM:+0000
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
-DTSTART:19810329T010000
-TZNAME:GMT+01:00
-TZOFFSETTO:+0100
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:+0100
-RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
-DTSTART:19961027T020000
-TZNAME:GMT
-TZOFFSETTO:+0000
-END:STANDARD
-END:VTIMEZONE
-EOT;
-
- $event[] = <<<EOT
-BEGIN:VEVENT
-UID:foo1
-END:VEVENT
-EOT;
-
- $event[] = <<<EOT
-BEGIN:VEVENT
-UID:foo2
-END:VEVENT
-EOT;
-
- $event[] = <<<EOT
-BEGIN:VEVENT
-UID:foo3
-END:VEVENT
-EOT;
-
- $data = <<<EOT
-BEGIN:VCALENDAR
-$timezones
-$event[0]
-$event[1]
-$event[2]
-END:VCALENDAR
-
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new ICalendar($tempFile);
-
- $return = "";
- $i = 0;
- while($object=$objects->getNext()) {
-
- $expected = <<<EOT
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Sabre//Sabre VObject $this->version//EN
-CALSCALE:GREGORIAN
-$timezones
-$event[$i]
-END:VCALENDAR
-
-EOT;
- $expected = str_replace("\n", "\r\n", $expected);
-
- $this->assertEquals($expected, $object->serialize());
- $return .= $object->serialize();
- $i++;
-
- }
-
- $this->assertEquals(array(), VObject\Reader::read($return)->validate());
- $this->assertEquals(array(), VObject\Reader::read($return)->validate());
- }
-
- function testICalendarImportWithOutVTIMEZONES() {
-
- $data = <<<EOT
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//Mac OS X 10.8//EN
-CALSCALE:GREGORIAN
-BEGIN:VEVENT
-CREATED:20120605T072109Z
-UID:D6716295-C10F-4B20-82F9-E1A3026C7DCF
-DTEND;VALUE=DATE:20120717
-TRANSP:TRANSPARENT
-SUMMARY:Start Vorbereitung
-DTSTART;VALUE=DATE:20120716
-DTSTAMP:20120605T072115Z
-SEQUENCE:2
-BEGIN:VALARM
-X-WR-ALARMUID:A99EDA6A-35EB-4446-B8BC-CDA3C60C627D
-UID:A99EDA6A-35EB-4446-B8BC-CDA3C60C627D
-TRIGGER:-PT15H
-X-APPLE-DEFAULT-ALARM:TRUE
-ATTACH;VALUE=URI:Basso
-ACTION:AUDIO
-END:VALARM
-END:VEVENT
-END:VCALENDAR
-
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new ICalendar($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
-
- $this->assertEquals(array(), VObject\Reader::read($return)->validate());
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/VCardTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/VCardTest.php
deleted file mode 100644
index b6b41925f..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/VCardTest.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-
-namespace Sabre\VObject\Splitter;
-
-use Sabre\VObject;
-
-class VCardSplitterTest extends \PHPUnit_Framework_TestCase {
-
- function createStream($data) {
-
- $stream = fopen('php://memory','r+');
- fwrite($stream, $data);
- rewind($stream);
- return $stream;
-
- }
-
- function testVCardImportValidVCard() {
- $data = <<<EOT
-BEGIN:VCARD
-UID:foo
-END:VCARD
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new VCard($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
-
- VObject\Reader::read($return);
- }
-
- function testVCardImportValidVCardsWithCategories() {
- $data = <<<EOT
-BEGIN:VCARD
-UID:card-in-foo1-and-foo2
-CATEGORIES:foo1\,foo2
-END:VCARD
-BEGIN:VCARD
-UID:card-in-foo1
-CATEGORIES:foo1
-END:VCARD
-BEGIN:VCARD
-UID:card-in-foo3
-CATEGORIES:foo3
-END:VCARD
-BEGIN:VCARD
-UID:card-in-foo1-and-foo3
-CATEGORIES:foo1\,foo3
-END:VCARD
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new VCard($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
-
- VObject\Reader::read($return);
- }
-
- function testVCardImportEndOfData() {
- $data = <<<EOT
-BEGIN:VCARD
-UID:foo
-END:VCARD
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new VCard($tempFile);
- $object=$objects->getNext();
-
- $this->assertFalse($object=$objects->getNext());
-
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testVCardImportCheckInvalidArgumentException() {
- $data = <<<EOT
-BEGIN:FOO
-END:FOO
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new VCard($tempFile);
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
-
- }
-
- function testVCardImportMultipleValidVCards() {
- $data = <<<EOT
-BEGIN:VCARD
-UID:foo
-END:VCARD
-BEGIN:VCARD
-UID:foo
-END:VCARD
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new VCard($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
-
- VObject\Reader::read($return);
- }
-
- function testVCardImportVCardWithoutUID() {
- $data = <<<EOT
-BEGIN:VCARD
-END:VCARD
-EOT;
- $tempFile = $this->createStream($data);
-
- $objects = new VCard($tempFile);
-
- $return = "";
- while($object=$objects->getNext()) {
- $return .= $object->serialize();
- }
-
- VObject\Reader::read($return);
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/StringUtilTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/StringUtilTest.php
deleted file mode 100644
index 59a83d294..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/StringUtilTest.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class StringUtilTest extends \PHPUnit_Framework_TestCase {
-
- function testNonUTF8() {
-
- $string = StringUtil::isUTF8(chr('0xbf'));
-
- $this->assertEquals(false, $string);
-
- }
-
- function testIsUTF8() {
-
- $string = StringUtil::isUTF8('I 💚 SabreDAV');
-
- $this->assertEquals(true, $string);
-
- }
-
- function testUTF8ControlChar() {
-
- $string = StringUtil::isUTF8(chr('0x00'));
-
- $this->assertEquals(false, $string);
-
- }
-
- function testConvertToUTF8nonUTF8() {
-
- $string = StringUtil::convertToUTF8(chr('0xbf'));
-
- $this->assertEquals(utf8_encode(chr('0xbf')), $string);
-
- }
-
- function testConvertToUTF8IsUTF8() {
-
- $string = StringUtil::convertToUTF8('I 💚 SabreDAV');
-
- $this->assertEquals('I 💚 SabreDAV', $string);
-
- }
-
- function testConvertToUTF8ControlChar() {
-
- $string = StringUtil::convertToUTF8(chr(0x00));
-
- $this->assertEquals('', $string);
-
- }
-
-
-
-
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/TimeZoneUtilTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/TimeZoneUtilTest.php
deleted file mode 100644
index b898e8d26..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/TimeZoneUtilTest.php
+++ /dev/null
@@ -1,306 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class TimezoneUtilTest extends \PHPUnit_Framework_TestCase {
-
- /**
- * @dataProvider getMapping
- */
- function testCorrectTZ($timezoneName) {
-
- $tz = new \DateTimeZone($timezoneName);
-
- }
-
- function getMapping() {
-
- // PHPUNit requires an array of arrays
- return array_map(
- function($value) {
- return array($value);
- },
- TimeZoneUtil::$map
- );
-
- }
-
- function testExchangeMap() {
-
- $vobj = <<<HI
-BEGIN:VCALENDAR
-METHOD:REQUEST
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:foo
-X-MICROSOFT-CDO-TZID:2
-BEGIN:STANDARD
-DTSTART:16010101T030000
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:16010101T020000
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-DTSTAMP:20120416T092149Z
-DTSTART;TZID="foo":20120418T1
- 00000
-SUMMARY:Begin Unterhaltsreinigung
-UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
- 0100000008FECD2E607780649BE5A4C9EE6418CBC
- 000
-END:VEVENT
-END:VCALENDAR
-HI;
-
- $tz = TimeZoneUtil::getTimeZone('foo', Reader::read($vobj));
- $ex = new \DateTimeZone('Europe/Lisbon');
-
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
- function testWetherMicrosoftIsStillInsane() {
-
- $vobj = <<<HI
-BEGIN:VCALENDAR
-METHOD:REQUEST
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:(GMT+01.00) Sarajevo/Warsaw/Zagreb
-X-MICROSOFT-CDO-TZID:2
-BEGIN:STANDARD
-DTSTART:16010101T030000
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
-END:STANDARD
-END:VTIMEZONE
-END:VCALENDAR
-HI;
-
- $tz = TimeZoneUtil::getTimeZone('(GMT+01.00) Sarajevo/Warsaw/Zagreb', Reader::read($vobj));
- $ex = new \DateTimeZone('Europe/Sarajevo');
-
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
- function testUnknownExchangeId() {
-
- $vobj = <<<HI
-BEGIN:VCALENDAR
-METHOD:REQUEST
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:foo
-X-MICROSOFT-CDO-TZID:2000
-BEGIN:STANDARD
-DTSTART:16010101T030000
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:16010101T020000
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-DTSTAMP:20120416T092149Z
-DTSTART;TZID="foo":20120418T1
- 00000
-SUMMARY:Begin Unterhaltsreinigung
-UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
- 0100000008FECD2E607780649BE5A4C9EE6418CBC
-DTEND;TZID="Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb":20120418T103
- 000
-END:VEVENT
-END:VCALENDAR
-HI;
-
- $tz = TimeZoneUtil::getTimeZone('foo', Reader::read($vobj));
- $ex = new \DateTimeZone(date_default_timezone_get());
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
- function testWindowsTimeZone() {
-
- $tz = TimeZoneUtil::getTimeZone('Eastern Standard Time');
- $ex = new \DateTimeZone('America/New_York');
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
- function testTimezoneOffset() {
-
- $tz = TimeZoneUtil::getTimeZone('GMT-0400', null, true);
-
- if (version_compare(PHP_VERSION, '5.5.10', '>=')) {
- $ex = new \DateTimeZone('-04:00');
- } else {
- $ex = new \DateTimeZone('Etc/GMT-4');
- }
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
- /**
- * @expectedException InvalidArgumentException
- */
- function testTimezoneFail() {
-
- $tz = TimeZoneUtil::getTimeZone('FooBar',null,true);
-
- }
-
- function testFallBack() {
-
- $vobj = <<<HI
-BEGIN:VCALENDAR
-METHOD:REQUEST
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:foo
-BEGIN:STANDARD
-DTSTART:16010101T030000
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:16010101T020000
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-DTSTAMP:20120416T092149Z
-DTSTART;TZID="foo":20120418T1
- 00000
-SUMMARY:Begin Unterhaltsreinigung
-UID:040000008200E00074C5B7101A82E0080000000010DA091DC31BCD01000000000000000
- 0100000008FECD2E607780649BE5A4C9EE6418CBC
- 000
-END:VEVENT
-END:VCALENDAR
-HI;
-
- $tz = TimeZoneUtil::getTimeZone('foo', Reader::read($vobj));
- $ex = new \DateTimeZone(date_default_timezone_get());
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
- function testLjubljanaBug() {
-
- $vobj = <<<HI
-BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-PRODID:-//Ximian//NONSGML Evolution Calendar//EN
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:/freeassociation.sourceforge.net/Tzfile/Europe/Ljubljana
-X-LIC-LOCATION:Europe/Ljubljana
-BEGIN:STANDARD
-TZNAME:CET
-DTSTART:19701028T030000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-END:STANDARD
-BEGIN:DAYLIGHT
-TZNAME:CEST
-DTSTART:19700325T020000
-RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:foo
-DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/Europe/Ljubljana:
- 20121003T080000
-DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/Europe/Ljubljana:
- 20121003T083000
-TRANSP:OPAQUE
-SEQUENCE:2
-SUMMARY:testing
-CREATED:20121002T172613Z
-LAST-MODIFIED:20121002T172613Z
-END:VEVENT
-END:VCALENDAR
-
-HI;
-
-
- $tz = TimeZoneUtil::getTimeZone('/freeassociation.sourceforge.net/Tzfile/Europe/Ljubljana', Reader::read($vobj));
- $ex = new \DateTimeZone('Europe/Ljubljana');
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
- function testWeirdSystemVLICs() {
-
-$vobj = <<<HI
-BEGIN:VCALENDAR
-CALSCALE:GREGORIAN
-PRODID:-//Ximian//NONSGML Evolution Calendar//EN
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:/freeassociation.sourceforge.net/Tzfile/SystemV/EST5EDT
-X-LIC-LOCATION:SystemV/EST5EDT
-BEGIN:STANDARD
-TZNAME:EST
-DTSTART:19701104T020000
-RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
-TZOFFSETFROM:-0400
-TZOFFSETTO:-0500
-END:STANDARD
-BEGIN:DAYLIGHT
-TZNAME:EDT
-DTSTART:19700311T020000
-RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
-TZOFFSETFROM:-0500
-TZOFFSETTO:-0400
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-UID:20121026T021107Z-6301-1000-1-0@chAir
-DTSTAMP:20120905T172126Z
-DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/SystemV/EST5EDT:
- 20121026T153000
-DTEND;TZID=/freeassociation.sourceforge.net/Tzfile/SystemV/EST5EDT:
- 20121026T160000
-TRANSP:OPAQUE
-SEQUENCE:5
-SUMMARY:pick up Ibby
-CLASS:PUBLIC
-CREATED:20121026T021108Z
-LAST-MODIFIED:20121026T021118Z
-X-EVOLUTION-MOVE-CALENDAR:1
-END:VEVENT
-END:VCALENDAR
-HI;
-
- $tz = TimeZoneUtil::getTimeZone('/freeassociation.sourceforge.net/Tzfile/SystemV/EST5EDT', Reader::read($vobj), true);
- if (version_compare(PHP_VERSION, '5.5.10', '>=')) {
- $ex = new \DateTimeZone('America/New_York');
- } else {
- $ex = new \DateTimeZone('EST5EDT');
- }
- $this->assertEquals($ex->getName(), $tz->getName());
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/VersionTest.php b/vendor/sabre/vobject/tests/Sabre/VObject/VersionTest.php
deleted file mode 100644
index ae6855e85..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/VersionTest.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-namespace Sabre\VObject;
-
-class VersionTest extends \PHPUnit_Framework_TestCase {
-
- function testString() {
-
- $v = Version::VERSION;
- $this->assertEquals(-1, version_compare('0.9.0',$v));
-
- $s = Version::STABILITY;
- $this->assertTrue($s == 'alpha' || $s == 'beta' || $s =='stable');
-
- }
-
-}
diff --git a/vendor/sabre/vobject/tests/Sabre/VObject/issue153.vcf b/vendor/sabre/vobject/tests/Sabre/VObject/issue153.vcf
deleted file mode 100644
index 5fb0fa297..000000000
--- a/vendor/sabre/vobject/tests/Sabre/VObject/issue153.vcf
+++ /dev/null
@@ -1,352 +0,0 @@
-BEGIN:VCARD
-VERSION:3.0
-N:Benutzer;Test;;;
-FN:Test Benutzer
-PHOTO;BASE64:
- /9j/4AAQSkZJRgABAQAAAQABAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQA
- AAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABQKADAAQAAAABAAABQAAAAAD/2wBD
- AAIBAQIBAQICAQICAgICAwUDAwMDAwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ0JCgsLDAwMBwkN
- Dg0MDgsMDAv/2wBDAQICAgMCAwUDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL
- CwsLCwsLCwsLCwsLCwsLCwsLCwv/wAARCAFAAUADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAA
- AAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKB
- kaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZn
- aGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT
- 1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI
- CQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV
- YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6
- goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk
- 5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8J7JbO8tYo1tIFCDLOVG5qfdaVZRwmSOFWzyA
- F4H1rLt5WViMhdp6HgmtKK8O3B+4Rhx6fSgBI9FtjaNN5aErwRjilSys7lFAt41xyTtqc2yJCVlY
- 7eqgGqv2jyLcebjZnGPWncdzT0+w0u5eQXtrGiBcIyoPmNMXwpb/AGMTSRRbH6YAyPwqK21GKdfL
- BAVfu+1SQX4jnjKFsp03dPypCKN9oEaKSkC7R0bGKpnSlSPdHErZOORXV3Ouy337sCLB6kpx+FY0
- t+VfyrgcbuCB1oAfoMemrcImq2sZX+I7ATXS618PdK1DRlvvDEaMq5LoV2nisx4LVrUfu5BOePau
- m8EQS6PY3HmFXjljKhTzjOf1oA4mz8OxvMrLbW5RD8wbByKg1LRrRriRYY408w/KAMba1pRaWt/H
- a6a7CVm2u7N8lUPEujzaRekzSK6tgqVNAGNBZJauY5Yon92GTRJp0ROY0Un0A4q3c2odkaYOMjii
- KL7NIDGcj1NDAZBplmmWv1xnoFHStfS/DFpewqYoYm3DutZ8lv8AapdyOqk8EVteEbSe3KBSrDrQ
- BT8S+HbawiiWGCAPjsuMnPesqHS4JSFlSMP7DitbXbvfrkkM2eGw3p+FMfTh5X+hr8w7t3oAhOhW
- u8MkMZUY3fL0Heo9UsrN5FFrbxKmMBgoG41fWFra0Acjpzg9aoXjtgRoo29vagCoun27kbY059qn
- bwykskYjRArdTT7GEl2UqMr2q/JtVU27iR15NADdK8DC/wBPle2iicxNg5ALH6Umm6FZ/a3ttQt4
- g2Cqnb0PbJ+tamn3j6ZCW0nILfeBORWVfO4dhLw7fMW7560AZuqeHf7MuTFcRpv6qVGVx70q2Eci
- QwyW0SsPvOqjJrUtb6S9tHQKGeMZYuM8VUs7gRxbrncy9mWgB1x4QtTHvsQWkHJVhhax3tkhugHh
- UkfeAXIFdPZ3v2uxkQ9G4jI6/j+tYun3r2Fy6yxeb2Py5IoAqXenJ5xaGNNvXH/1qcLSGeBdkSg9
- CcdaswC3be0pfexOMnpn2qaS1KQkQASKoydvLCgDNi09RKTNCuO2BxVjSobc6gqXMERQHkleDUsc
- u9VADbG6qOWAp11bLbptkjlCkZRsde9AFi5sbO3kKfZYTnkHaOlVbuO2F5thtYcADjaKXUpHj8ku
- Co2VDFL5wLeg696YFwQ2z7Qtlb8HJO0c1Zsr7T7a9kL6XazZ4CmMFRWfHdkEgjGRjPpU9raP5LSP
- j5h2pAWdQ0+z1KdG+y21qvcRqBn8qXSvC+iTu63ssqyE/IAuR+NQwSrGm1g+c8E9qiSQW9wPNYYP
- OR2oAW68GNa28k3lwGNHwvzDJGfSqM9nHBgm3j59QMVdmma4zIjsUBHy5OKp6o8s2BJjZjjAoAro
- /nysbgYY9zWmLPCR+WQQwyaz4k2F/Pbft/GtKxvUeFN+B2x+NAEptsWpZSdo9etZe8su2X7pPFdU
- LeOazKqVwevNYt7pw5EA5HIxQBQA8tAIeGz1NWIJvJlhW5OQBzjrUMR/eN9pwoXjB4qQ3ERJeYcy
- 9P8AZoA0jf8AmybVxsHAFS6jp63ixmwjIwOfrWfaou12GcDpmt/w5qJhXc6hh2GM0AZkHiRpblVl
- G0RjGMdxXQ+H/E0Rm+bjdw1crqEHm3EksY4Y9PTmq0cskc42qUOfpmgDovHOhLBOZ9O+aEnIUdRW
- QZft1sgum/1Ywua3fDfiFDL5WoEPEwxzzirPizwTFPZC60kYUjcAp4NAHPSq91EoRS3061DHD9nb
- 94Mkfw020v57GbcCRt4IIqzNcedIH2jc3JyOaAIYrRZmJxtNdB4fkGn2hluBgBR+NZ2n2X9ozAQD
- 5qvaxGbKIRXkuFU4C96AMDxBKZdQkuEUkStuUegpNM1eWScAkqpHTHNPlwbjMzExZ4Pal1PS/s6+
- dY/6vuwPSgC9G8c0A+1xEknrnpUVxaeXNm2dVUfjVazvEZAEkMrccZzV1YYyBIhJP8SZ6fhQBSmV
- 4JfMVT+96UJdSQdcMO4A6fjVmTUoJiqTOMJ/q+elRyQs0TtaxF0PVhzmgCzpd55r7YI2HHPTmrV0
- sDTF7gnJXGO4OKyNKgn80NbFhjoBzWjqdg6SISPmIBOaAKVnI1leyhsMJOD7CqOqRtZqotjiFulW
- rhsSMshKH1ogsZbmF475TKifdf0oApabevHIAhCYOdxp0t59luS0I+995uxqpdRyWsrqmXGeCR/K
- rVlZfaogqv8AvD/CaAIY42kV3K5zzn1p9jNLp6u/A80YPNWWsJNPAVpC4JAZT2HfFWJoVmVVjhVk
- HTPrQBPoi2wsoo4APtBHL+tP1mS5uVEFxgJGNqH15plp5WmyBriMRsowM8UybXTNdbrpd6A/KKAD
- xbJAGs44FIPlnd9c/wD16ynt/LiDW2SR2qa5vP7RnMs6BNuQMd6jhkAUb2K8+tADYp0fhj8w6itC
- yQ3CFYeAOoqi8Uew+UMuf4u9T2NwIW+UgMetO4FmS6RJ1ik6HqxHAqC+gimUiA8DvjrU0kcE8ieY
- itu+8c0+bShaWxksSZoM4b0SkBTgha0cq33Cuc1SvrrLFV6jpWqbuGe1HnnDdAKy7i3WSY7OT2NN
- AMulWSV8ZDNzxV7SlbaFjClx69Kpww7W3ct7jpUtnNJHd5UjZnt1NIDdt7h7NQ7qGfpt7VR1XVEh
- dhEpP94/4VpafexTy7ZlbBGDVHxFbQh1j04HaOTkdKAM5ZVlYso3E+tVp4w8gx0Bqd7QxNu+6D6V
- DIoVySxAx2NAFyNmli2pjYBz61paW3lWrFS3BwP8/hWJbTBFJy2D6HgfWtiTWPsqxraBHyOeBg0A
- RSoLSTdIepzz0606exTWyQGMXljORTNT1B7+ECZR5fHzDqapfbHjbFkTsIwSTQA43ptyyS44Paun
- 8N64Z7Bre4YlZBtU5+7XLTQbjwN4Pb+IfWn2lw9uyrIw2Z5HpQBv3GirHc7LxWVZOVI71FNp7WDg
- QYlIIGD6VvaPdi+tljb5yeAzcn8DT9YtbPSpVhDM87jJ3Htjnn6UAUIrJreD7Si7MDoKhv8AUxqt
- pGt5GqIOr9zRfLM8ZFgZGtex2nGe4zWKN8rsDhYx2JpJ3Atx+HxcRSzWcpcL/CRwaj0zW1sQy3cS
- nsFPSoYJpbIl7dm8tT8wzV7+0hqEO1Y4lQ9cqMn9KoCp9kW7kaaxU+Yx+5j5etWrb/RGxfr5bkdu
- lW7KFILpfspDbVyc1fjNnrLtHqOYWP8AFjGfxpAc/e6Ql/GzW4AfqBWfpupS6Xer5vPlHmMjg10V
- 5pp0u4JhYNGvAYHrUn2WLWrVo41AvSMRZAC/8CPr1oAvafdWOuNG+lqDekY+zg8MPXPX/wDXWZrF
- tcWNw0erKElB4Rf4R6c1BpqyaBdbrnEcwyAc4x06H0rQS9a9jUTgOXPzMwycexoAw7u1jYb3zkU3
- Srtgdk54PFamv2C2pDQbWjcfKCeSa56aJld23YA6ZOKFqBrXGjjULuOKxKuZOTn+H/OKwr/ztOvs
- uCrg7RgVLYapPbXAEW4EkHJNdBNBH4gtgyhFmXuw60AVpbT7VpiPJ94jLetQWsDRSIYz8mec1c0+
- 1nexdrw7GjJXk/epsFtDPG0bOdw+b5SaAKWsXA+14Y71FQi5S4RvlAC8A0y5hHmHarhvQ9BVGSQx
- sUXPHX3oAmDCJ8rzgHg96gQ+ZGWbg9vahNRG7EnalkkF6hEXyD270MCWF3aEhdue1OsmNnMAih/r
- VaBgAUY8561PaubdnMxJXseuKANhIY5Assp2v12itZtAgubEi2nb5xuKYHWubstQaO6SVzujTqpP
- X8K2rXWLRF8xZJPMfjAzgUAcxcNiaRSpUocc96sW+yNgZCMVF4lvJdRvTOYkj52jbgZ98D6VWmlY
- 2qCUnJOKaVwCzviibANwYc8Utkdl7tbKhjxmpUspvm8tgn16ipigSEG4G4pxu9TSA27GeFbRlGGm
- P3cdhUN8GEP2hV3JjafrWfpU/wBmuAcZLA4/Sr1trkarJHcRmSEZO3uTQBmrcbZCLoDZ2x1qOHSi
- yebJIAPQipp4kmbzI1EQJ6GtCxsoHP8Ap91GB2yDQBlSWO+M/ZsBHHzZ71XkfMIWNgGU9vSt3U9N
- t9m21uonz0Iz/hVCfRkjg82FhtHDGgCuZ8EMjDZjBzSZ8pAwU7XbGT0pWtEjjAZgV4PFOml2QKqk
- OoOcU1qBNYRSrdkrhw3BIrah8KwXoV/m3PyVzyDWNp999kccgZq/ea7PFAGgZlJ6EUgN23thpdi4
- V1Eucr7ev9K53V/ER1a/MkuWdBtG04zioLrXJ5wDK2XAxmqVqmZ2YPtHJ/GgDsvC3i0ppr2d2ish
- yFAHIz706bRLNdOPnErKw4y3NcvZ3pjA8o4kB61o3OpSX9nbx3QIkU/MwoAj/sGaPzFjlWSJjk46
- ioYYwqssjIHHAHpWm4ESN9nYDIFZV+I7uVI1wrY5b1oAtafcvb3W4MM9Nx6U/VZpNRys54ToU4zW
- KXaDKrJuC8cVdtpi1gzs43HNAD9N195bdYtRIUR4wD1NX2KuA9uThuSQelcsZwzq9xyzfezV/SdX
- e3m8pXJhkPKkUAdYZk8RywjVVJES7U2cE/WtA+HDHohuY3Uxg7RF/GeaPBlxaawMW6rHKnAU9SOO
- lX/FFv8A2bpzTQk+cpAAz93nrQBx+r4c5CODEOA3Y+wrKu5V1C1GFKznkk9K6Wzv49fs8Xf7y7DY
- MhGNgrmtX0s2t66WknnKvUp0/WgCnbrJFdot0NwJxkDFdDYp86oMjjIArJivxbR7LuMyEjKitS21
- MW8auuW44H93/PFAG15aXdr5Uv7uULkA/wCFc+Yvstw0at8+eoq/p+rm6vRJMNwIx9KranYySXSy
- WEZZHOCw7UARXFyj5STAk7ntWVf2gALLyfUVoataLbfLO2SO/Ws2c+VwhLK3QDpQBmz2xAyCG56d
- 6uWPlnCkFcjoTzUBkMc/3cZpwn8oZkDFs8HsKALN1apDIHOeaiLkRkMOtSXE6yxAsRUcdxldswIJ
- HANMCuJW8xQgOP51oacWPPGAeRUUOIZQzDhecd6mbIcbPusM0gLmq6bHPohlhDeZuH4c1zzF1+Rs
- HByDXTae0s0IhjjZg3GPWqOs+HpLCTbNGyb+cHrQBZitjPEzW/LL97vinw2v2m2aORec9AKXQbsw
- ygBBiX72TWxfaS8kiGFQAwz8vWkncDlbqNraT5cjb/n+lMGckx8kjOa1tU2TxkPkMpxyKyrhJ4Wa
- KIDbTAkgvIp7URzgBwe/BpZYrd4vmZWNZ81x5cgBXDdzVlIvtUOGIBHpQA2aEROpR8DsB2q3bvG9
- iySzEsTkLnrVMqViCZzt7nrT7GBVuQRnODQA6Q+Sx80A4HApEJB3BAR9K19EmhkvCJ0ZsKe3tUc8
- Mc1yy7cpn6YoAzoUiclnYYY8AHpUl8zRxqpPy9qtC2tULgSMAvQ460lzIl9b7YiDt4GaAKMMQlJ5
- z9Kj8gIW5yKnS3Crlzhh6d6k0mbyZT565Q5z60ANtrRpPmhzWhbwy7DJcDhhwMdKlt7aK+gb+z33
- yKdxVuMCqaz5cqGYfWgB6yu8rBB8o6Gs/UpjGQXBGPTvVmSfyImyepqrqjbIw3WgCDz1ib9yOTg4
- NbVlNBJYvlVBHt1rBaPzQWU4IHSn2FwRJslJxQA6e3M0O4oAzdB6VXR2iKGQENGOK0ms1eAkFjF/
- BjrVGaAo371smgC7pety2kwl06Vo5AOWXmuwm+Itv4g8Ota30aWlySAJQfmkP/1zXIeG4Y5SVBB3
- evamXGly2tydwG0nKkHpQBZ86fRbpBLI252y4PGRWhO8Ml1IbJhHn+BTnNU9O1oRwvDqqhB2lHJP
- 4U6awb+z4JdKbzdh5ZurDHtQBat5LaRHiaOP7QejEZKD/Oauy+FI7W3Bsroyhxkq3QH8q5a7ujM8
- nWOQnBqTR9burCT98xdR60AbbaHc6ZG3ymJsZC/3hVnw/fNIXt7hygHzZp2oeIBqCxzqfmCgEe3+
- RVdrmLVAEtf3bxfOW/ve36UAV7+7DXMu5Q4/Os2e3eRWkiAGOijtWrPodxfQmeNVAPOPWsppJIpi
- JxsKcY9aAMwRyTSbpflx68VOYvOXb97OKtXAiZdzkqT0AGc037BIIRLHjsR60AVprZrZwGj4qTY0
- xyRj3PUVMJDduFfqvFRzxJCzrCzEr60ALEu+YI53c4qeGB7lGCnBU4FUopTBLvfk1at9R2sAMjNA
- GtaXsnhy2FzPHvC46jgnNQ33imTXrkz3oVFAwo9Kfrtq03hAzEfJ5gyc81hWM5hhKrhgT0NPcByS
- P5g2uVI98Vp6X4uuNGlyzCQIQR0bI7/1rNQxqW+05J7Y4qK5ZYUP2ZCW9TSA7SR9M8V30X9nMFZw
- WfcNi5qPWPDtjo0pE7O03U/Mf055rmtFmN9E0DEox+atPWbiW7lSO8Ja4jQbcDC4A9PXFADYtM0+
- 6nc3u7aOm3IP6Vnak9tYt/xL/M445zTIbieOdmWNsE46cip42EkyC4hYx469KAFsrT7XEJgFPOT6
- 1s+H9PD3XlzxnL/MDtqn9pghgb7GjL/eJORWqfEnmrA9oFRoxjJ5BoAp6NqDW2pzRXtuyIAw3FMf
- rVS4iF08pydmeCDxWvqeuC+Ro9qglcMw71mwReXD5aAlFJPPU0AZ0cEsbkSZKH15FD2xJJiJVj6c
- VfnzLGEXAA71PFpDPaebE6/KOh60AYVws8TBgrFe57CmHUG25RVJA7AVozzSLbNvX5T1AHNY/m/Z
- nPlqwDetAEtvqzJNu3FZBwQBjI96vPqkd3mRtokH31UYx+VZqWruxaFl+frkZxT1tvs1ujJgEH5m
- PR/pQAXl2S371XAHI+Wkaf7VD8hGR2arKySylRccQ98DmiS0jifdsdgeODQBQd9x3IBx1xTYlBm3
- En86sXUAwPswKg9QeaBErIEj6nrQC0NHRtUjt0K3AHzDABGcVW1fTzJL51jyOpz0NVooispebBI4
- wK2YFEthk8qR07igDAgJil+TKtnnHFaP2h5yI3ZsgdSfaqd2P3im3BGM9aktsjmRgCOaAJZrMwR7
- 3A5PT0pdMvZtOning+byzuVDyh/A8VHczSzDPy7RwOKgiuHEewjKeoFAzp7TUNM8XXEw8RhYNQmP
- 7ny18uNeOM7cCtMfDiS8uY0tDEYghyynjPbn864htP8ANhLIehzWzovxDvtFsDB9+PI4I/rQI0r3
- wNc6DO0N2VaQqW2q24YxmqFhYRgE/vkkDfMGBBP4GrSeJ7tZd6SxvIfmK4yQP84p0XiyC71gS65G
- 00zAKGX5Qv4UAbFpd28WnIsBLsDzmub1+AXt1LJEoQqfu4xu+lbWsWgs4/NsCXjPIbqK5+5kklmE
- rDD54BFAGb5cjybCrAnnB6ipEvXil2sM4GMVpFY7m4UNmNyOWJ4qteaM0BISVZe+RQBFHC2/zISg
- B69KlIVhIHA3HuR70lqotlBulY5P4Vcls44k3u6N5oyoHb60wM6O1SRir5LemOKv2vhuW4iLg7VA
- 6k4FTR2ax4aaVIwR3HWqGua5PcQm1WRBH6jqaQFzWbE2nhzynuIi+8HaHyKweJSEQEN6jpVcKyOw
- cMVznOeKmtZvOPDKuOKAJbi0JYFf4eue9IW8sncfvdqnlvVFyFyu09abI0bysMZx0oArC4eCTcgb
- juK2dNvE1N1M0ohljGQzc5A7cfSs6aweWAk7kTuapQysIT9mOSvG49aAOkvzLMxk06QNuG1l7j3r
- PlnnJAuGJij+nNQ6XqT7wEYqyn5v9utLULaW7j321uiEjLqMkKKAIotbghb/AI8hKGPIBHNXLG6t
- 7uzk3RLbKG/iP+Fc+8f2d1eFztzyD2q5p2oCFWRoxOX52nPFAGgLyC2lyZFKdB70r69buxRJBHjr
- nvWVdeXLE7xE8fwnoPpVKZUnQPkBhwRmgDq7a9tLyARWiiWYngL1qG4gurJ28+NowO2a5a3v3smD
- aa5WUd1HNbC6zI0KSX13JO7D5lbHFAE4V7pi0b5x1GazdUtXSM7v4iPw5rQ0/XrcXX75FgUdxzuq
- /qFrp+sWRe3uDkc4BFAHLRDY42ycd6uPOXiiV+RGPlWnXOg3IQvEmIB/Ft6/jUUEZmMcgydvzECg
- C1G2+Ly3YAvyM9qY88kaFcmmp807uwPJ4FS3do+Fzn5ulAFVrjbgS8Z4yah2C03SMffNWZdPknVA
- iluQOnHWmX9pILvyY13HHK46UAVre7LSyOCTmtjSiy7VijLeZ0IqO08OzPIUiTI74Ga6bRP7O01F
- h1KYJOv3V4BoA4zU1lExMrkbOAvpVcSifhjgrzmtjxPp7pO7SggOcqfUViy25hG5fSgC8rrLAojb
- d7d6SexlEgwpRfTNV7e5LFBbKAwPNWHeX7TguxI7GmBPBExhaNVIJ6egqOVknO1fkx1J61aj1gLC
- UEKlk4LVWvozC67kCFxkD1pAQ24e3uDLC3z9CR3H/wCqrczJdOGiOxvYc5/CocMYhtUBj3xU8Qjk
- XbKPIZOjqclvzoAu2HiO60xPKvd7wY/1fGBWnJo8WuW6y6XIPMYZEAzuH9KxISonAuzuRzgk9qtR
- 79KmMuhTt5cRyxznFADLzS2tMw6pAY5OoDEZ/Sm20TQQ74YwVQckGtMatB4kUpqreVIRw5+8aqXF
- jc6bAsbD9yThWz94UAOmmjvrRCMJjOQRVS0sD9pLyABM5Of6Vdtrdn+RUGcZqO6uRBG0MuFI79KA
- MfV7r7ZqDI7kohAVT6U2eJNimJQOuTnpSXFussrMvBz1pJov3YUsR9O9ABblRncQ3bAqY2EUwIiA
- Vqr20ojfYqZx3q9bSKAGcYJPIoAoq7OCEQBffrRDGEcleM8nNPjuGkhHmbB74ApvmxltsuTnuDQA
- +SFEjDwu5buD0qpLL5vMg2kEdOlXECMAyZGOMMePyprQRI5N0rt3BXO326UAV4b0Wt0pC5HrXS2W
- qq9zE7jcO+OhFc81kbg7iMqeAFHSpLa8eymaNOUIwD6UAavjPQYYybq1bBmXcF9O39Kw4iXdDKcE
- DAxW3q7NdWELISdiYIz71kz6ZNZNHI0cjqQfujIFAEtzAtu/7vODzmqlyzNyAo9vWp7uWSWJd+AM
- jjGGqOWCSWRVVW2+uKAKskpWU5TP0p8c+ExsPPNTmCVD+5U/QrzRJHJGymeOQc45HFAFczh497KR
- jirWlEsAudvII9znitEeBp7yAPZvEVPJUsP5ZqCO3j0yYDUNwliI6dOPpQBt/wDCR3Wj6eHFujvI
- do3DIX9KoHXoL6J11CJYZAONlaWueIYtY8Nwx6ZHu2MdxVeTXKG0eaXKRuCeuBQB0mn+HRe2Yeze
- MqRkFmwfyra0rwsIrRmvZICcgDLVw7xXFuFd2uEQfeAJAxUkkjSxh4J7gjPAErf40Abvjq1i0y4S
- KByCdrfL+FUI7SR4Wc+WzMOCW5qhf3Mt9cCV2ZiihRk5qpdTSBgRI+R2DnFAFw2k6AqJZMjuD1qn
- cxzyyAkPuiP3ieT/AJzV+01R7a2RpMZPVmGQ1WVuTqLDCptcfMBwRQBEkst/YMCSTH8vJqtJaoYQ
- JPv1o+ZDZKAo+UnBpmrCBpRNp4/0crgZ9f8A9dAzCdGgkOynxSus2xjkj+L1qW5/fxYj+8D+NRWz
- R4fzCd2O9Ai0lzI6mPaMOcZqW4uI7rbtJ3IMc1XScKqncQT0olPlKWfBz6UATKjSDcmdoFWtPCyR
- kzckHiqUV0623lKVIPzHHWp7Ic/vSRz0zQBcCqdyT4J7YqC3uZdKv1a2UupO7B6H2NMglMUsmcnd
- 0Lc4q3BmaMBiDjr60AWJRBfyb9P2RueWJ6KfQVLHqMdtcEysxJXayN0x0yKyWihWQBdwTOSdxHNb
- zWEF5ErXhX7QQAMNge2f0oAnhs4rq2kksHwirkg9SfauXnJnmL3AbL9jXSRWh0N28x1cEfMqtnA/
- Cs+70+O9/fWRIb+76fhSTuBimbyyyKDgnipLk7AML1pZbCWO7Hnjn26U6ZykRL+veqAryuvm/Jwf
- Sk3mo2AyHyCT6Ux5pLU5Gwg88gGkBPNAILUO3KmooyjL8ueegzTvPMsRjG4qBwKrW1sxJZzsIPGa
- AJbmfp5q7MZx71NZawEi8qZSyHg4NRGLzCPtB3eme1R3Nutocodyd8UAaVtqEUDlI8/N3PaqV2Ht
- X2x4lIOSwHFSWkEFyo+cD1BpbmNbNdkh20AMh1UiJ1c9RzWj/wAJa1vYiK1RmRvvetY5gDENxgnp
- UlhN5TiI4O4845oAmu51lXzFDGQ8jnpTra4uJkBAOQavXvhG8tIhPawvJAfmY9gKE1COwgIiAZiO
- 3rQBV866T52Qsw6YrXguZNTs0WSJ8IPnHr9KwZNamNumZSpPU4pbPxBeRy/uJjtXqfWgDodMtnXK
- QjYeo3VnalpiXjMzXMKS9O9VV1ydCXkmLY/SorWwTVJTmQEt81AHTeCY49Mik+0SJKmOg71W1bxH
- HLdgaXaSRNnjdzWapGlBBG2ec4GKtQ6yZD5hjLMvbIzQBfutWC2ajV4ywwN2OM/Sql/JY2kKGzU/
- McnBBqlf3Lam5e8lKMv3Yz2FU4VjgzsGQ3WgDa0ya0u7kxzgqCCcn1q43hizkEjRkOoXcAOua5Ka
- 6Mc3ygEVb0nW57ac/ZC4Xuo5zQBBeZjcwuMxRn5fUUmnySx6kv2cgg98deK1LjT31pTLpymSVuWi
- Xqv17U2GzFgFBUCVOo7igCTT7cnTp/ty5ZnyCvGOKz2uwimOY7geQB0FWY7tzu8xiqk8A96qOvmy
- MSowOc0AVpkkgk3uAiP39KkjtonYtnO4cKOP1q1Z3K+X5V2N6OeM8gfWiewaxiKhDsAyJB2oAk0u
- 1juAwniYshwoB61FLZfaJDv/AHWexpulXRNwpjkP7s8nu1Wd4uC7zfezxQBTjxZTHzlMigbdy8Up
- YXEv7nPvk1aNqbhDhgARnFZMCvbzuWZgc/nQBo2l6qs63AJA6VIsiG4DI4jXP8XeqcbrK5JH3xkH
- 0pWhWVR52CF6UAa8kUd7H8rD5f1p5txHAfNPasWRCjgh8D0BrV0a+DgCdfM3DaB9RigCml/JFPyB
- 159xV+C/wfNHAbtUN9orxO3k5dhycfw1XmT7JarIjb1k6U2BcuNSVGDSAPu6be1QTXcO0CVSwbPA
- 7VRtpftEmxW2Mx6HvUv2V1J2jkdaQBFJB5jBVYemetRyW6SqTKCfTFNllCHBX5vWkLBPvk4NADTG
- 0ePKB5qdLN5NjycqvNQIpZAFVj71LsaJQBuGaAH3aCVwycKODUMsZgJjxv8AXIzUs0DpHhmBycjm
- gOd37wdRjNAFETeTcARAbSeTViApfrhjufHXNJNCsUu18Z61Xit3Q5JxQBdW0MYKyn5hSf2BPIjS
- 24I29T6f5xUMMrs5HOF71ooVmtMyu3ynAAzQBqeCfG7aaPsmuYkiYFG3HseKq67YQW2rSNpLCS0l
- GQ5GSh74xWZc2SyxK4OZl5x7d/0rV0K+j+xPFOu4Pwpx0oAo3OnFreM7AR9Kp/2eYpxtyCx6VoXd
- g2nSlQzMh6UxJdjqSpKgfN6mgCOLSZGkKyYw/wCn+c1YltRodoWA+Y8Z+taPhWz866DQqxLdmq34
- x0ZbS23yY3NgkUAcZcSyrjcc7zw3YU62meOeTazdOhrZ07TYLkYvSFVfmqveQWkDj7CW9zg0AZs9
- 8wbO3L8ZpvmGRsyZQDsO9WLu0EwZojwMc1DJCrsA5we1AFmGVZLc7Y1bA6nvU1gIyNzgxtnoKr7I
- NgHO8dx0pJ3AYG3UnHegDRS+NpL5lsxh3dQverj38OtL/pKCKSPhWU/f+tYEt98xMnC9qgludrrJ
- GzFl7DvQBq6pYNGdzHGO3aqS33kEBhlSME0+01z7OcXGXRupJ5H0q5fafFqNuJLLnofmGDRsBmJe
- DzMEZGevpW7o8sN/bzLqTBML8oB71k/2YYh83FQRqbdtr7sDv60AX7jSo4ZsiVo067hj9anuNHey
- jVizMj8gkdaqQyi+UxjO7O0A96tXDz6rEFucp5HygUANGEQKjDJGaqzWbzgyn5QOPY1p2xZtOaGN
- VMo5BPoKqxa1NHHtmij+Q4xkUAUraZFiYScMOgNMf76CIZHf2q5KRq8arEjK4OTsGaki0oKwAEhP
- uDmgCohEsqq/O6rrMNMj3AEdgfQmn3tqUgEcaYz1JFMtLdn0wpFGxYHhjQBa026M0XM2WQ/NnHzU
- 6Yw6tCPt6rbpH0CdvzrPtrZ45ceU4cHk9qtzW6XLOjqwY9+1AEa+HWun8zR28xU5LAZx+VLaGSV9
- jrkr145amvEY4hGkjKMg5XoPY/571vaHFDr95HHqDMkoU4C9G+uKAOevoo5iSBjBxVYwLdRkL1Xt
- XSeK/CdzpkjRMqyJ95SjbsD3rmJbUwoeuGOCfSgC9eWc9rcbbdA0KHPmhcq39Ka8e9DkBS5zk1X0
- /wAR3dvEtuTm3AwVzW/D4w0xIEivbOaSTAVWBAH40AYMu6CZDkFcHcTz6UrtkYlwVHIwOtb91olr
- qtuRZSL5h5EX8VY97pc1jKAqZ2jB/wA/nQBRJhubjE4YOOnNMC+S+DzmrMkIA819wPTbjmqwfzcM
- 4w3vQA9mbYwgIz/ENvSm2t+6jZsYKeTkVYjn/eqwGAOp9aeW+2sdkgVf5UAQLKY5MHGferNv+6IM
- XT07CmyaeZIS1vtmkUdQKbZ+akOZoyqMe45oAvRzjUJPLLgSds8/zqyPDzwETagy4U8YwARWMbcw
- NuDDePenPrbXEfkTn5hwrdqAO709LPSbbzlZdvqD0Ncnr/iufX793uWQrGdmFGBjpmstdQeFRHKx
- 2Nn5f73+f61E7iLCxDnrjvQBaubtNypAxyRzg0q263DMsJIzzyc1mwyDeSD82e9XIGUIrSyBNw+X
- 2+tAD3tSpcFvufrVZbdL2XbnDdjnGKnhs2nkYtcIEJ6461HMiJIApBVe5HWgB8mmtpzDzSrrkZYU
- 65mRGYoBgirEkCStiJlC7c5IqjLNsYhtu0d6AKkshbAZcAdc81Gdwb5SD6cVZjYy5WXBVu/pWppn
- h63urfdLdxR47MDk0AYjnhehxntVq11OVANuTj8q2/8AhBZ7mwkm00CYKQBtHXrWe+kTWS7J4zE+
- OQ1ACQX/ANrkC3DD0wODV280KQwM0jxheueKdZWcCrvkjYYHUHvRe6jFLapHtLKeDjg0AVrDQ5xd
- xuhIUEMHx8pH1roZtH+2W+dPIbHDMOcms+81YNoqWltlFKhQD1HNP0e5udHsHFkcyMRkDoaALUPh
- aa1n8yUgqRgjPOO/eq+reDkvHzoQYIB85JzzW5HBLqWmCSWQJM3UEdB3/Sk0S3uNPmIkBlgJyXAw
- o/Ci4EHh3QYfDsfm3mHklGGLdFqS91HSYpvMw0jjkhTx/KqXjLUg8hihYiMn746H6Vg+QYxuV9vH
- 1oA3xrem38TNe28rqp+VUyD+gpbTU7O6ylvEYoEBPzjDAjp2HeuUk1aeyfNqMH+8BTrvVhqEAMuP
- O7n1oA3X1Q3U0klp5S7OGHFZt7rj4DwxlTJ6riqMTiDZsHTn6/WpbfU5EP8AxMVMqdFIOMfWgCZb
- lpEO/GDgn9K6bwZpktjcC7lUsAMYPvj/AArBi0lrpc2sqbZsHbjkV20SvDp8UUZBcDp60AY+ueIZ
- dIu3Frh0lbD+YNxAPXBPSqLrpuunyNPBSSM7mZyQpJ/KtWQ2uqvNDcjypQjAFjnJx0rhNYhntbvy
- 7jcucgIe9AEUMOy5ImYgg4xViVVa4UFSoToc9a6DxZoEdqv2rTsHzDlx/dFcujFpG27vlPGe9AEi
- anPpV359o7b143jqo/yP0rWs/FSavF9l1JltlB3tOerd+axl3XGfMXC9896iu7UbtyYIxg0AdTc2
- Vrqe3+zZxIF4Uj+I1S1Hwpexu0kts8aL7Vg2t9JZ8REjJ+UD+Guh0TxjeaW3/EwAuFAxh260AY8y
- ujfLkBOCOuabHcqgCxYAbrz0rsbSysfHdzks1rO33Y0AwTWd4h+D2r6M5mmt0ER5D85P1oAxLfWZ
- LSYrbnAb5eKnudVnyELFkHOcCqUmjzRzBWyD9K6W38JtLo6TtkLzmgDHtryGZiZUDZqDU1Vl3wp8
- g+9jsf8AOKmGnw2cpE8jFR1I7VdGjRXMQa0kdoSPmHrQBn6bYnWz5NydjgZVgORWeztBK8ZBJQld
- x6nFdZ4ZtoNI1QPI7O+OB7VX8faO9rdC7ESrC4BJHqaAOcgUTtuORiraW0M9yiXLAIeoPc+1RWar
- u6Haxq7e6ekEZkBGzGVz1ptgVprUw3ku3iJDgDPUYFEzAwZRN2CDgUw3JEkezD7+xolvytwn2pVV
- RkADv060gLVlMk4aLIDHp7+1Vbu1+yzgThiHOOelElyIZl8v5CDkVtxWkGtaYs0bMblCcr/KgDCe
- 3LzsN20L2HepUQJnHI9KsX+gT29pHKCd79qWw0u4aPcwU4796AL+meIr2G1aDSbiWHOMhR1qxZXz
- xXBl1n/iYBBlg/FR6VZW1nciS9mdJADgYGO1Q3pIOOu5hz60AO1vxLDqluP7Pt47eJSQ2KzvtiSg
- eWuPpU89gsfzH5cc+1ZaSpbXRZT8tAGjjz237gNuPwrc0O48uUPOM4GBXORXC3HmJD1bB/QVZivZ
- fLwp+71oA6fVfEiwXC+UBGjfKTj14qZbi7gtJWjkY2zx5C9s4rnbCRdZiaOUkFQTke3P9KbYa1c6
- XcBARLEWxhzwBU2AotqzH5Ls5YdFPOKmiu1KgxfvCOqHrXTL4EXxLbl9MO6bGRkYzXPal4TuNLu2
- ju/3csfUD9KoDO19yChhO3OcqO1VoZEUbHVckZL9x3q09s8a5uDkZxUDWX2i4OzgHvQBLCwkwyEF
- c4z6VNDZm7utkROCfwqCzAhuGRhhV/WtR5okjjkQ7ST2oAlSRtMdUjHzR1p2OuOI2Ly4kHQViS3K
- iYBMsW5zSNF9klEjPnPSgC1dzm4uVKSMZd4JP41oeJPD8+r6ZHLbwmW5H3yCMqvr/Os6xu/tDfvU
- CqSOfWuj0yf7OxLO2CAG9x6UAZs6vcIqSiVw3GQMisR7RVvpFkGFU46e1dN4c1hYmCXm0quDIO9c
- 54quVl16drdDHGzZX6UAV5bTzWIi4Ws6/DQEoQSpI5q9BfywxkS7WU9OOlMa3F8hG7bj5sn86AKc
- ErggKVA96lFwLcYHX3NQPAHnYD5e26pAnluA/JoAu6JevFqsEqs4YN0HQV39p8aL+CJVnWKWOP5c
- OAf6VwCzrbxAIMMefpT48zEFD9RQB6hZ+PNE8YqsfiJFt5GOC0abcH6ioPF+i2/hiGK50xmuLOQ4
- AjO9s/T8a8wlzLIdxKkHIwcc1s6R43vdJi2xurxsdriQbto9RnpQBal1C1urtzcIVjfqu3FRMNM8
- zbpplViehyAKnuU0/X4N+ixtFdR/67e2fN+g4xzWPcWzWFyDL8gP3Qw+9+NAGhqulSWzpJHt/wBn
- Bzj2NejeHLG28f8Ahox6/HsmA2DHBGO9eTrrksUTKSOD0Par+n/EnVdMRVsZYgpHIK9u9KwEvjn4
- eTeF9UY2Jie3HI+bJFc6b6eMkt909j2rsrTxpYa7bGHWYpXlc8Ord/yrOu/B8gEjQul3Ao6RjLL9
- cGhaAcu0skr7mK8HtTjEAcMMk881Zm0l7JXxg7uQBywqqzysygDBPr1qgHSWqzANL6UunXjWBOxW
- KsaZcggbu4HSlindrf5ANxNIDqblPteiWrESNC2fujJ7Vd0bRY7KLfZswWYZYSdT2/pWJ4Q8ST21
- 1b2krIYj8pBFdd4k024ht0nsdpjA4AHNAHO6npkSs2SwPase6ieJcSYdenB+atGbWykgF9G2cHvi
- qGqMxiWW0GFyCSRnFAFeSN4yGiLE9we1QXYEhzMo+bnAqaC9YzbpSGY8CoL/ACwDQ80AV1mxdJwQ
- q9h1qd71WHU/QdqgDO0gJAyevFE4WI8dW60AafhzUHt5v3ZAzxVzXNFku/38Odg9KwbK4ELA4z+N
- ddourgQKJsMv92gCr4Y8Qy6VGUmkdLcDjn5/8a6vS5tM8SWTG3kkaZeP3xIyfxrmPEuk/ZXF9akG
- CY/LHj7tZy38tvcxSwnYw7DpQB0viLwrIigwhcHqAeKxDpbmcgJtKjOfStXRPHgjlEeuAzZ6bf4e
- lajX+navE4gZIyQcFmxQBxd5ZPG+9iuDxmqitHGR5oO09M+tdDqmjNsDl90YPBHSsJ4N7uH7dOOt
- MByxj+EkE/d5qwYGkUNu+VetUgxVz6gVNAryx7Y84J5PpSAeZWjG8A/Lg1sabqn2hF8wnniqPkK6
- qk/z/TilaEWo/cgqKANPSbRba8zM6MXGDzVPxHYPPOzOOVPy471R03XmSRXlQEHv6VstqaakgJKh
- h0X1oA5jBjYrP8uTkA9TQ0qoxLHqPyrQ1+z6TMu104x65/8A1ViSsVc5GdwoAseWbkDyQWC01QVv
- S+5WGcbe9OguTFZqIjhxnPHWnWTCO6LyKjPnpQBDfs4n3sMc8Y7VPBKWT922498U7X0RCjRnJmAL
- KP4aq2rtA/ycBu5HXFAGkYg0GT8rY5J5qIw5jyMORxU28zwAou5jxj1pnktAzCUlT1xQBHFP/Z8w
- dpNsg6ccj8a6jQPFNjqdqbfxJbvPM/yxTE/LF9c1zsNsJ1U3EYIP8VPe1iicCORsnnHTBoAtat4Z
- mS92Wn79WBK7aw0ia3uXW4jdChxkjvW/Z+KLjTZFd4hKwyAc44qy+nwazpxEOPNdvMdx1UdTQBzb
- AbSNyqGPf+lWvDPiW58IXDtZzOIpRiVVON4qS/0ePcG04/aYV4Z8YwaoPGJrgq2AqnAPY0AdVdww
- eJLX7XoxSKfbnyRwzn61zGooyMzsreYpwQTyn+P/ANap9NvX0S4DQtzu7dhW/rel2viWzWfRiPtC
- L88a/wAfuaAOQEvyDepIOOamtbFJZWKzrH7Gpk02QRBLgYYHkDtSTaf5LBgM7u1AEVxbS2aiSNfm
- xw3St7RfiTLFZi2vUe4VRt44xWJDczTzoLoFgvO096bMomlkaJfI5ztFAG7Jqdlrcm2WNYHA+82C
- KidbiCAoVLWzfKoHOawo1dyGO4bQcc9frWppOvSwQLDcDzQSOvbmgCjcWBQsqDYwOTmo44BdAZfG
- OeuK1NYdZLjzCdu8dAKzpLYQt+6OKAK88ciXREQ3AY5/Ckmt3dlMoznPSrMU2zJxgD2zSSRmX5kY
- gdiO9AFWO3KSDgqMjrXQ6fYuUAjG3HO7rWRawNeSDLYKnHPeunVG0bR4ruTnc20g96AHxn7ZbNA7
- qzgcVzup2s2mzOl0CAT8jYzvrb1TxpZ3tgr6fBFFL/EUqpp+pJqpxeqJAPulucfSgDDfcjgxAqSP
- mB60xXXlZFBPXpV2+tms5W2oTnpk1nht0uZCAfTFAG9oOvCJBb6jueJj8qj+Grer6XFCqvHMvHTA
- zmuajlMUmWHznoKvQ6tLDEPtKeZnsT0oAkaBVLGX7x54qOG6NvkEEA/rV2dYLi08y3fMhH3e4rMR
- mkDLOMkHg9KALcN7vXI4Iq9ZyG5jw7An1rFuWMWMAopxTzqMkIxZAuOpINAD7ZAcg9F6VqaXdRFg
- pX5h92sPzRbfKQdvr61c0+4MjDyxsYHkkUAdA2lvdQ+ZcDIPGOuawNY0wWNywjwVbocdK2E1ubTF
- +T5gw5yM1Lc2kOqaX5kXMxG4nPT8KAOSUSKu5VGM03aZmRo22k9Tird26Fgp+6hwcVAZfNmCnBVu
- mKAJp7N71FDcuOI8d6pJlLlt+d44PoK0dTZLKCI2HmCZQCd33c+1R6iqXKpJBu34+bPQGmBNpzND
- bgH7zHjPapLiXMhEvzMRwarQXG+ILcfMP7w7VZjdHj+QgMOmaQCRF7AsVBZO2am2G5t2kIAJ9O1V
- 2vzM21l+UU9Cjj5M8eh4NAAIXjUeRl8/pUa6k1hGFtWyG6n+lWYX25Y8dsUs9t5tkVkK7Tz7+tAE
- 9l4hAj8q/RUf+Db0P1qZ/DUWrTO0paK9cfLGg+Qn61zc0SeYc53DgVr+HNfk0u623LgwSDaxHLY9
- QaYFa80a60G58vU1VmbqF5AFWdC1k6PqaTW6qyEbSD+FdRJd2s8IikZJbO46MTmRB7nr2/WsrxD4
- QjtohLo+9kHXPb0pAd6uh6Lrekm6hkkQSRgNtQfK/p+dc1f/AAsuGUnSWSVScgynbisHQfGFxpki
- RKw8tRyD0z/nNWPFHji/1lFihkCxKMAocUAaNt8NNSt3bzYrYsnT5xTLvwZYQTIuqzlLh/vqigqP
- xrk/7QuIwRHcXG4jnMpP9ary3kzhvtUkrSH7p3E0AdXqPgvT1vI47K4kfcCcYAx0/wAar2ngu2uW
- ZIJX3pnjHFc3DqUikfPIGHU5PFb2ka3PDe7dPZGGzGW7/wCc0AX7LRLSzcxb3eXrhhxVG78JeVcA
- bvvcVfEgudqaoyrOrbiV9Pwpmo311pMnmWmySH3w1AGRrXh6TRfLMq8yfcHGPxqxZ6fpmnmNddml
- jlk5+RQRx/8ArqO51ptT3vMwWU9iOF/CsOZHnkIkYu3YnmgDo7qPTtPszcWTu5LcAr1ycVl6p4hk
- 1BRbsCEXkCqEGqz20wEWGEZGAeRxVy+vRqV2JpUVJiACQMAUAZ0+mvaNuuz88hwAOmaktbt7C4Ub
- c8jvW5rGkp/YUEsRM0nLSf7PFYogSWEF/lJ6CgDWcjXyuMhwOAO9Y09hLbSyKy9+pqzpM9xo90Jr
- co2OMMM5ropr2PxBYGK7VVXBbIXG4jnrQByUI8xSADs6HPWpPLIjGxssvr3pxQmcqx+VGwFHenJI
- gOF5oAW0jZB5nQnnH6Usnzjrg0rW2/8AeISD1x2pWR5VySNo60AQBX2EzHIXpSQJ5kjOOFpLgrtI
- iLFvWi2Y3CFYuoNAEt4myTBBQ46Gq6OyHKjGTzSyyyXUm+/cnHc0+PY42RtuDcDigDS03UzdQlHG
- WHFSw3/2CX99lo+hA64NUorOeyG9FJA68VJFaLqNu0hkIlXkgelAF3VtEjvNMF1pKOctyPTFc/bw
- tGVeMfMRzW54f119M8yJ2IjlGzk9B/k1p6f4fsmi2xXsUmeP88U7gYV5Et3aQlWCsox+NR2eUnWG
- 7bdvrZ1TRY7FXjuQsatzHJ7VkyeXbxnz38xl6NmkBFfiXR3MDKQjHI9xUMV0ijMnNdBZWbeJbUcC
- SZU+U454rFu/DF7byNJcW0qxqeeOtAE0EcbI+4nax49qnKNY7CCG46Vjw3DRHO1gtaNrqPnBRKu1
- R0Y80AXYDHPAzlPmzzTWG2Evn8KafMMWIsFfamKxcAyjAHbNAFSeRJpOBg0xrXykVjyp6VLqFv5b
- AqwTI6dal02ZZ5VjuMNGentQBJZxXFtFuUZDcitDSPFrwOYrkFkfj6Vl30l7p87RpKRDn92eoIqG
- 31gRxk3qMzqRnmgC/wCJtIa2uzLYfMjgEj2rNs70woyIMjPLHtW7Y3y38gkUnGBke1R6p4dS/mNx
- obeZgfvIVH3Pf3oAz7W3EmGzgrSSRqszF13+4/hqOOLdGSrk5HO0d6WCUxYaUMYhw4HegCM6TLcy
- Ztkd0wckd6jtZZbPiI+aqnlem2tTStXNvcbYZyiSA4QcdMf41Y8Taf8A2dZieGMR7sAkc7s8H+dA
- GVJqTT3AKtjIxtrStNVy/kyLuUj1rAlhG4NtKqOc/wB+l+2SpP8AcKMn3s07gdJdeHPtLRS2zpCr
- csD171laro72bGSFWZRwzHpQdUe8hTDEMg5xU0N7Pcx7GVpIf4lzSAwlk2yAoevUDpWpa2hvYeTg
- 0mo2UM8w8lPs4HUDvRpsFz9oYW6NKB07U0BbjvptGhkgJDRMu01VLRyyIYQSgA3HstVdVMiSlZyx
- bPKiksbyS1hdWUmKQ5K0gJpt8UgAw69iKn0/UyJdrdOmKIPIvW/cyLEqj7p4zUEUIEr+blHXJBx1
- oAk1O28q6VoSFVhk1GbZQ25TzUlvcfakIucKAcAnqaWK1cyFkQlB70AJvJdNq5I4+tBcbCnCjv71
- LIVcAowVhxj0qO2t9zkXHKt0bsKAIpbPIHlKWUjk06wgaNiqIBzViF/kKKwBHA9aguI5oX3REk9j
- TQErWypGPOGc/pTLTy47gMFyob5fetB7EmcG3G6N8hSTjNWRpgsws/y7ouWB70gKd5dGSRcfKnIP
- HFXrHSYL61e4kfyVVcYA61lC7OrxurAKxbIHtUtxfC2sTDA/A49KAEazRmkEw+TqG9as+H7YSTeX
- bvu7ccYrIt7qRdobPLc59K6jw9pf2KUXcJBVjuI/z9aALF88MsJh1AiRoPl54Iqt5GmXUG3ABx1x
- 0/WneMbGfTryO8VB5d2N6qfTJHP5VBoNtFqUb/b28uU/d2d6AJLPV4dGtP8AQyokHGKgu/Fwu9wl
- PXgj0pmpaSmnOxmYEdu5rOht2knZ4FX3oAimiju3AtlAznrVWSAW7OC2HQ/d7VdNjLaMjurbSeMC
- s+4WS41BjyEB5zQBcgnk2ARnJbqKZcydmZt3fFVxB+9DRkjHfNWLh/KKGTp/6FQBGLg3C5PzFeBT
- LeT5yEzlB0p1zb7wGtzt9RTNhWVQOHPWgDc0iUajbPbTgM5GE9aydTtPKk8sKcDrk9adZX5+0FLc
- FZM/K1dPpmgReJLR2nOyZDhQT1z60AYWgXYtrvy5cFXBXA9+OtGpLceH9YIsZ3BwGI4+YHsaNR09
- 9C1ERTFTMjBgE6YyO9S+IoDqHlag5++RGPfGKALelpb+IbtA+Ldk+ZkXofxqHxFpn2Vpv7OXdGOW
- 56Vk3GpCBQB8pB429a0bHXN8kX2gKY1ILju1AGakfmFfJXLN0/z+VdZYQG503yda5xyPp/8AqqXw
- 2LKJJvsqbjIdwDL936Viarq8u9nhA8sNg88/TFAGrdeFbeWBHscSL/AM9DWRqnhObyS7KUYdfetH
- wkx1Gdnm3rECAB6Vu674psYbIRxeZuHBJHWgDzZw2nybQMluDVnT9T2PsJK56Ve1OS1vJ/OhOfXj
- pWVdWctu/mJhgTxQBeYrOS0xAxTojJHKHspCQ3GPSqaXCTuqpnf+lTQIJ5XRXwy0AaN7YxzWzT3I
- /fSHp6VnS2LI8Yt13kj5ucAU17me4hYbvkHXJ5qvJfDMYDNlevqeaAJTAVJGBuHPFSWuoMN32iNW
- UgjOelVo5vNUvg8HGKVollOIG4HNAGhb6dHewhrVy8gPK4qaFTZZRssT1GKzLWd7C5zDlS1a9rq5
- vU2uFAIznuaAK93po2GSIEjqefu1C8QZApc+uBxWnbQpeyCG1OB1cnjmi5sUuTlxgpTQFBAYCWEQ
- bjrmmsHvDypH0qYqYGPlk56DPSnWFuz3BN2MCkB0niGK10bw/ExCyMxwhVskH8K5O98SPfWixqPm
- AxkjBNEkkz2iQSzgqn3U54rPm4RkY4YEfhQBd0gPBMGnwc8fSpvElpFBIGU5Y4Ix0qjcanIkKBG5
- 7VGzPdIHvF3P9aAHpGtymc4Ira0fU5YYUG7KA5P0rAEgjOFjfHtVqzndD8ilFkGKAPTri4h1fRrW
- DVAojmjwjdwPY/XNcJK6aTfubdjhDgc9a19PnbUYLW2upsRJ8o61S8WeH1sryKJ2AeRSUb1oApTX
- TXpaQMWJGcdal8PSf6UTcj5WOKz5YW0zgTKZG44Bq4THLpSqj7LhWJdsdfSgDo9e16OGFba0ji3p
- wZCBzXOoYZp2N2u0Mecd6Zp12cIbkfIBzTbwRG53W4wp5oAbeWVmgY2ZYeuTVC4SWFAzjdGO5qws
- HmK28jaTVi1vhaR+XfRGeJhtVR69jz6dfwpgZEcrPcAp92pl2IzMxLuRwamfSJZCXtnRhnLgcFR6
- VWc7J9mNpbtikAW9w0MheQj5ea3NG1Y2sPmWhCvjuf5Vk7UadY48RseW960rDS11C3b7EMzL3oAt
- 6hpn9pZu4GzGq7djH5g2PzpPDsMV/Y3Fveg/uVZl+vNJYRy2KhXfcB972q5aRw310/2eZLbcuCWH
- X8qaA4yTeT845B4qaEqjZlVtzflV+80qY31z/Z8T3ENqMs8ZAAGcd6zoZMncEwH6H0pAdDpusLZQ
- 7Rjc3ApkFoZJHmY4iAPXpms8R7oh/Gc5HtXQaALbUtGMN6ApPHrzQA/TvEdsdOWD92rRk8gcmud8
- QXkl1cZzlfapr3QP7NujGjfKTlSKzr2Jmdgx/wBX096AIkn8ucBQQjdat/bWMLZKOOnOOKzdjL0P
- BoiXe2Cu7vQBpxC0KAyK2488Hiql3LskbaDtbpjrV+3tlubYC2TExGBVe+tJNOAF4PmHNAFO0meG
- R1bI9jU0iK23zcbsdagWYO+xOH7mrkMWYcNgkUAQwKGA4JC5pzyFmPlEADt61asYIgSJWA3dOKv6
- zosFpdxPaBGVlG445BwKAMwuWADAbqs6eI/3hl++Pu1cj8NFyrRncAdxb0psElpY37NMhljD4YKe
- poAsWmm/aIjKknlsvUnoalhtHLcbiueucA1Uu9UMs8wt4SsOfkUnkCrOmXcotj9rkV0HSLnmgDoD
- 4JSXSzPNNFJhdwCkZX9a5+K9gD+XPgDdjNTpez6ZZywwPskcZbk/KK5qZ2llPmvvYnrQATr8zE5D
- N1zxRbou7951anhZNYuUVFw7dvSp59IltXdZ1IZKAGvpLNGfLAfufaqDCSKUEkgdMkVd07VWs7oG
- XLL0x60+7ePUjyCpByMUAV3bBGxsk1ZikV4gAMkHOKpzW5SUmN849qjjnlil3KODxj0oA6KykW7t
- yJW8pk4BFdxrGhwax4TS5JWWaEBEY9QDn/CvNrPUfJmBcZDHLV0s2vsfDMwt2ZYy4z7cGgDHv9NK
- yjfD+8bgYFUNRtTps4S6HlkjIBPU/wCcVeN86xKZmJlyMc5p/ifU5L/RYVmto9wJUyZ5oAy01Dfb
- qZV2xnoKbfX6NEv2ZcHHWmPLFJYQx2ZLTL1U1EIJA+2bAJ6Y5oAIboyDb0PU1c8xLkBJLna4Hy44
- 5x06VAbZbdcyZ3elNBXeCRjnOaAG2808N5syYmJ7fx+5q7tW5QCZQso/iqsULT7rXLr6k4xVi0dX
- +9kmgBlxpbI7SxqZAoGWz0p+i3txZ3AezJAHXjrWlZ26mFyzEnPC+vStzTLO3vZ1M8Yjwp6Hr0oA
- 5/xFqyrIggQKrLlsdc96xpQZ5wySbu2DVnVYQ9/MJCSitxVOQFW4G1aAOm+H3iGPSbie1upBDBqC
- CKRugwOfwrI8VWsenazNHZtvs0fEb/3h6j171Elg02N65x6Gt200i18VwwwXcjQ3Fou2NQMiTvye
- 3WgDn4riKEhkfKf3h6+9aFlGLeyS8eT5DIMoDnv3FXZ9I0iwhJFxJLMpwY2ACg1TvvISzMs77S5w
- EUcUAW9dH9qW6y6ZKBgcgdawoNOu7iWMmNiWOMDtT4Jxb5e1bKuMEHsfWpNM1ZrG4WWFmct0BHSg
- CprWivp0u193mMeR6VHa2jmQbVH0zV3WNRkv5mkn5YnjFRJGBMjRMScdKANvR7OO1u4pS+SGGV68
- d61/GnhSHUYReQyqsZXiPI64rK0S5hRNzfePXvWr5w1KIwwucAccUAefW1q8kqiT+WK0RpdzFFuE
- bFT0bHBqxrFj/Z87LjDZ/Km2ctw7Kgk3KO3SgDPQPuHmqNynv2rRs7hrhjDIcDqD6VPeafDfWbbC
- UnUjav8AeHfn8qsaL4bl2pLcYWJT85PYdzQBq6dfjRtKX7QnmC4JQH07f1rIl0SztbsSrcoQnJQH
- qaseJ7mBVT7PIXtDwrYwQ3esOO4RrxvLZmjI+90P5UAXrm881T9lHOeAOareXPH+8BKOB19Kb9rF
- pcq0ILDPc8mp7m+S6k3fdKj7vWgB8Gtj7Oq3AZ3fCs7DmorqxQTbl+oAqJJlu4gJMKwIxT3kNq+H
- G5/7o7D1zTA7Pwpd6NBrk5vQwMv3Pl+7UnjAwwXX7tFe3l5UjBbHvXP3GnCOxhuo2IL1G+qPcFYX
- cknoT/n2pbgVZtGFxZvNbH5VOBk+vt+FZ8lrPakrcqyHGcEYzWidWS3lCxAlVPUdDWxf6pa6nLH/
- AGlH99QoI4wTwKbA45pHEirjk1asbxYZCsoDYH1rV17wyumSKVbeGG4Y6gVk/wBn7UdgCpPc0gLw
- aEwtLKMDtWhoNykVwHdd8JGCjDIrDkSW1g2zOhVhkVLo+puSVlKlccYoA6Dxf4PbSLRb21wto7DG
- W7ntj61mpKdXtxaOQvlfMCSBuJrqLfWIfEvhg2muKzQoN4CnBJHT9cVyU5hEjNbB0CHABPNAGTPa
- fZriQONjqcZ6flUtqqB1SRmMr/dJzWlDaLrEUh1Qbnx+628ZNZE1s9nfctxEccjpQBO9tLcy7Zjw
- vfNQ31q9oee3A75qe2Yyzby5OKiutRMsjKQDg4FG4EVvEyfM5xnsD1q5bbzKHBAB9KrCJN4YMd3p
- V+wt8szRZUCnYDXsWSGPz7jGI+SMVVuvErXKEWuRk9QMYqXVyLXTUyRmRcmsSC4EAO8D2pAXxbma
- IMR8w7+tVdRtkUAT9ew71as7wsF2nFGsKodDOMzHo/YU0rgULe7j098qW545Gaki1FIbwzeYyzfw
- EdvyqkyGSfaw+bvRcQLayqyEnAyaQHR6gi6/pXnBER0IGFHzN15rnmlXyTGRuQHByeQau2GrS20G
- 9OhO3H1//VWhf6RprXbXmnrMtuYsOjNk78DkfiDQBi2rpHIVQjb1otHPnBZAMAdRVUQiW6Bgyis2
- Buq29q2nXJjn/eDsycUAOLCG8yg9zkcVCzeVIZY+cenekN0LqYRSHAHA9aLMCOTy5BlTyPegCxa6
- ltkL2+ORzxjFWbTXpLSV3Y84+XFVJvLilKjgVFMpAyBxQBq6prEF7bQSzA+ZJ97jpVRGjDbUJAB+
- U+tUywlJUdE6VteHLK3kuoDqQZ0zyAcYFAG3feVo+io90u2d13R/LyR35rm77VZNSmzC5SEj5hnH
- 14/Otu+hv/FN3gTWywW4KRqQM4/OsUeFZp5miaVAc9R0oAaXWa0EUWCIjuA9PeqEMbCYM3G77oAr
- bi8Gz2YDmeLc3ygev61X1CxnnuTE8TvPb9fKXigDMuIJFlBdtzHnAPSrEF0IwDCm5hw2VNRzxTWt
- 0BeKVMnTIxj8KZ/ahtgY49uT7UAX7VH1K63oERVOTxiuu0ex0nS7L7chJkm+R1kwwyPQZrh4JJDw
- zbVbk4/OrNpefLsnyyg5UUAf/9k=
-END:VCARD
diff --git a/vendor/sabre/vobject/tests/bootstrap.php b/vendor/sabre/vobject/tests/bootstrap.php
index 3608abec1..14281e218 100644
--- a/vendor/sabre/vobject/tests/bootstrap.php
+++ b/vendor/sabre/vobject/tests/bootstrap.php
@@ -2,14 +2,24 @@
date_default_timezone_set('UTC');
-$try = array(
+$try = [
__DIR__ . '/../vendor/autoload.php',
__DIR__ . '/../../../autoload.php',
-);
+];
-foreach($try as $path) {
+foreach ($try as $path) {
if (file_exists($path)) {
- include $path;
+ $autoLoader = include $path;
break;
}
}
+
+$autoLoader->addPsr4('Sabre\\VObject\\', __DIR__ . '/VObject');
+
+if (!defined('SABRE_TEMPDIR')) {
+ define('SABRE_TEMPDIR', __DIR__ . '/temp/');
+}
+
+if (!file_exists(SABRE_TEMPDIR)) {
+ mkdir(SABRE_TEMPDIR);
+}
diff --git a/vendor/sabre/vobject/tests/phpunit.xml b/vendor/sabre/vobject/tests/phpunit.xml
index 8aeb65aa0..46dad6a3d 100644
--- a/vendor/sabre/vobject/tests/phpunit.xml
+++ b/vendor/sabre/vobject/tests/phpunit.xml
@@ -4,14 +4,20 @@
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
+ beStrictAboutTestsThatDoNotTestAnything="true"
+ beStrictAboutOutputDuringTests="true"
+ beStrictAboutTestSize="true"
>
- <testsuite name="Sabre_VObject">
- <directory>Sabre/</directory>
+ <testsuite name="Sabre\VObject">
+ <directory>VObject/</directory>
</testsuite>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
- <directory suffix=".php">../lib/</directory>
- </whitelist>
+ <directory suffix=".php">../lib/</directory>
+ <exclude>
+ <file>../lib/Sabre/VObject/includes.php</file>
+ </exclude>
+ </whitelist>
</filter>
</phpunit>