Merge pull request #2048 from rejas/issue_1926

Updated ical library to latest version
This commit is contained in:
Michael Teeuw 2020-06-22 18:19:18 +02:00 committed by GitHub
commit 3b442d4bfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 749 additions and 4689 deletions

View File

@ -38,6 +38,7 @@ _This release is scheduled to be released on 2020-07-01._
- Fix the use of "maxNumberOfDays" in the module "weatherforecast" [#2018](https://github.com/MichMich/MagicMirror/issues/2018)
- Throw error when check_config fails [#1928](https://github.com/MichMich/MagicMirror/issues/1928)
- Bug fix related to 'maxEntries' not displaying Calendar events. [#2050](https://github.com/MichMich/MagicMirror/issues/2050)
- Updated ical library to latest version [#1926](https://github.com/MichMich/MagicMirror/issues/1926)
## [2.11.0] - 2020-04-01

View File

@ -5,27 +5,28 @@
* MIT Licensed.
*/
const Log = require("../../../js/logger.js");
const ical = require("./vendor/ical.js");
const ical = require("ical");
const moment = require("moment");
const request = require("request");
var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumberOfDays, auth, includePastEvents) {
var self = this;
const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumberOfDays, auth, includePastEvents) {
const self = this;
var reloadTimer = null;
var events = [];
let reloadTimer = null;
let events = [];
var fetchFailedCallback = function () {};
var eventsReceivedCallback = function () {};
let fetchFailedCallback = function () {};
let eventsReceivedCallback = function () {};
/* fetchCalendar()
* Initiates calendar fetch.
*/
var fetchCalendar = function () {
const fetchCalendar = function () {
clearTimeout(reloadTimer);
reloadTimer = null;
var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
var opts = {
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
const opts = {
headers: {
"User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)"
},
@ -40,41 +41,40 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
} else {
opts.auth = {
user: auth.user,
pass: auth.pass
pass: auth.pass,
sendImmediately: auth.method !== "digest"
};
if (auth.method === "digest") {
opts.auth.sendImmediately = false;
} else {
opts.auth.sendImmediately = true;
}
}
}
ical.fromURL(url, opts, function (err, data) {
request(url, opts, function (err, r, requestData) {
if (err) {
fetchFailedCallback(self, err);
scheduleTimer();
return;
} else if (r.statusCode !== 200) {
fetchFailedCallback(self, r.statusCode + ": " + r.statusMessage);
scheduleTimer();
return;
}
var newEvents = [];
const data = ical.parseICS(requestData);
const newEvents = [];
// limitFunction doesn't do much limiting, see comment re: the dates array in rrule section below as to why we need to do the filtering ourselves
var limitFunction = function (date, i) {
const limitFunction = function (date, i) {
return true;
};
var eventDate = function (event, time) {
const eventDate = function (event, time) {
return event[time].length === 8 ? moment(event[time], "YYYYMMDD") : moment(new Date(event[time]));
};
for (var e in data) {
var event = data[e];
var now = new Date();
var today = moment().startOf("day").toDate();
var future = moment().startOf("day").add(maximumNumberOfDays, "days").subtract(1, "seconds").toDate(); // Subtract 1 second so that events that start on the middle of the night will not repeat.
var past = today;
Object.entries(data).forEach(([key, event]) => {
const now = new Date();
const today = moment().startOf("day").toDate();
const future = moment().startOf("day").add(maximumNumberOfDays, "days").subtract(1, "seconds").toDate(); // Subtract 1 second so that events that start on the middle of the night will not repeat.
let past = today;
if (includePastEvents) {
past = moment().startOf("day").subtract(maximumNumberOfDays, "days").toDate();
@ -82,7 +82,7 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
// FIXME: Ugly fix to solve the facebook birthday issue.
// Otherwise, the recurring events only show the birthday for next year.
var isFacebookBirthday = false;
let isFacebookBirthday = false;
if (typeof event.uid !== "undefined") {
if (event.uid.indexOf("@facebook.com") !== -1) {
isFacebookBirthday = true;
@ -90,13 +90,13 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
}
if (event.type === "VEVENT") {
var startDate = eventDate(event, "start");
var endDate;
let startDate = eventDate(event, "start");
let endDate;
if (typeof event.end !== "undefined") {
endDate = eventDate(event, "end");
} else if (typeof event.duration !== "undefined") {
var dur = moment.duration(event.duration);
endDate = startDate.clone().add(dur);
endDate = startDate.clone().add(moment.duration(event.duration));
} else {
if (!isFacebookBirthday) {
endDate = startDate;
@ -105,20 +105,20 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
}
}
// calculate the duration f the event for use with recurring events.
var duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));
// calculate the duration of the event for use with recurring events.
let duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));
if (event.start.length === 8) {
startDate = startDate.startOf("day");
}
var title = getTitleFromEvent(event);
const title = getTitleFromEvent(event);
var excluded = false,
let excluded = false,
dateFilter = null;
for (var f in excludedEvents) {
var filter = excludedEvents[f],
for (let f in excludedEvents) {
let filter = excludedEvents[f],
testTitle = title.toLowerCase(),
until = null,
useRegex = false,
@ -161,16 +161,19 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
}
if (excluded) {
continue;
return;
}
var location = event.location || false;
var geo = event.geo || false;
var description = event.description || false;
const location = event.location || false;
const geo = event.geo || false;
const description = event.description || false;
if (typeof event.rrule !== "undefined" && event.rrule !== null && !isFacebookBirthday) {
var rule = event.rrule;
var addedEvents = 0;
const rule = event.rrule;
let addedEvents = 0;
const pastMoment = moment(past);
const futureMoment = moment(future);
// can cause problems with e.g. birthdays before 1900
if ((rule.options && rule.origOptions && rule.origOptions.dtstart && rule.origOptions.dtstart.getFullYear() < 1900) || (rule.options && rule.options.dtstart && rule.options.dtstart.getFullYear() < 1900)) {
@ -179,28 +182,24 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
}
// For recurring events, get the set of start dates that fall within the range
// of dates we"re looking for.
// of dates we're looking for.
// kblankenship1989 - to fix issue #1798, converting all dates to locale time first, then converting back to UTC time
var pastLocal = moment(past).subtract(past.getTimezoneOffset(), "minutes").toDate();
var futureLocal = moment(future).subtract(future.getTimezoneOffset(), "minutes").toDate();
var datesLocal = rule.between(pastLocal, futureLocal, true, limitFunction);
var dates = datesLocal.map(function (dateLocal) {
var date = moment(dateLocal).add(dateLocal.getTimezoneOffset(), "minutes").toDate();
return date;
const pastLocal = pastMoment.subtract(past.getTimezoneOffset(), "minutes").toDate();
const futureLocal = futureMoment.subtract(future.getTimezoneOffset(), "minutes").toDate();
const datesLocal = rule.between(pastLocal, futureLocal, true, limitFunction);
const dates = datesLocal.map(function (dateLocal) {
return moment(dateLocal).add(dateLocal.getTimezoneOffset(), "minutes").toDate();
});
// The "dates" array contains the set of dates within our desired date range range that are valid
// for the recurrence rule. *However*, it"s possible for us to have a specific recurrence that
// for the recurrence rule. *However*, it's possible for us to have a specific recurrence that
// had its date changed from outside the range to inside the range. For the time being,
// we"ll handle this by adding *all* recurrence entries into the set of dates that we check,
// because the logic below will filter out any recurrences that don"t actually belong within
// we'll handle this by adding *all* recurrence entries into the set of dates that we check,
// because the logic below will filter out any recurrences that don't actually belong within
// our display range.
// Would be great if there was a better way to handle this.
if (event.recurrences !== undefined) {
var pastMoment = moment(past);
var futureMoment = moment(future);
for (var r in event.recurrences) {
for (let r in event.recurrences) {
// Only add dates that weren't already in the range we added from the rrule so that
// we don"t double-add those events.
if (moment(new Date(r)).isBetween(pastMoment, futureMoment) !== true) {
@ -210,25 +209,25 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
}
// Loop through the set of date entries to see which recurrences should be added to our event list.
for (var d in dates) {
var date = dates[d];
for (let d in dates) {
const date = dates[d];
// ical.js started returning recurrences and exdates as ISOStrings without time information.
// .toISOString().substring(0,10) is the method they use to calculate keys, so we'll do the same
// (see https://github.com/peterbraden/ical.js/pull/84 )
var dateKey = date.toISOString().substring(0, 10);
var curEvent = event;
var showRecurrence = true;
const dateKey = date.toISOString().substring(0, 10);
let curEvent = event;
let showRecurrence = true;
startDate = moment(date);
// For each date that we"re checking, it"s possible that there is a recurrence override for that one day.
// For each date that we're checking, it's possible that there is a recurrence override for that one day.
if (curEvent.recurrences !== undefined && curEvent.recurrences[dateKey] !== undefined) {
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
curEvent = curEvent.recurrences[dateKey];
startDate = moment(curEvent.start);
duration = parseInt(moment(curEvent.end).format("x")) - parseInt(startDate.format("x"));
}
// If there"s no recurrence override, check for an exception date. Exception dates represent exceptions to the rule.
// If there's no recurrence override, check for an exception date. Exception dates represent exceptions to the rule.
else if (curEvent.exdate !== undefined && curEvent.exdate[dateKey] !== undefined) {
// This date is an exception date, which means we should skip it in the recurrence pattern.
showRecurrence = false;
@ -239,7 +238,7 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
endDate = endDate.endOf("day");
}
var recurrenceTitle = getTitleFromEvent(curEvent);
const recurrenceTitle = getTitleFromEvent(curEvent);
// If this recurrence ends before the start of the date range, or starts after the end of the date range, don"t add
// it to the event list.
@ -269,32 +268,32 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
// end recurring event parsing
} else {
// Single event.
var fullDayEvent = isFacebookBirthday ? true : isFullDayEvent(event);
const fullDayEvent = isFacebookBirthday ? true : isFullDayEvent(event);
if (includePastEvents) {
// Past event is too far in the past, so skip.
if (endDate < past) {
continue;
return;
}
} else {
// It's not a fullday event, and it is in the past, so skip.
if (!fullDayEvent && endDate < new Date()) {
continue;
return;
}
// It's a fullday event, and it is before today, So skip.
if (fullDayEvent && endDate <= today) {
continue;
return;
}
}
// It exceeds the maximumNumberOfDays limit, so skip.
if (startDate > future) {
continue;
return;
}
if (timeFilterApplies(now, endDate, dateFilter)) {
continue;
return;
}
// Adjust start date so multiple day events will be displayed as happening today even though they started some days ago already
@ -315,7 +314,7 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
});
}
}
}
});
newEvents.sort(function (a, b) {
return a.startDate - b.startDate;
@ -331,7 +330,7 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
/* scheduleTimer()
* Schedule the timer for the next update.
*/
var scheduleTimer = function () {
const scheduleTimer = function () {
clearTimeout(reloadTimer);
reloadTimer = setTimeout(function () {
fetchCalendar();
@ -345,14 +344,14 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
*
* return bool - The event is a fullday event.
*/
var isFullDayEvent = function (event) {
const isFullDayEvent = function (event) {
if (event.start.length === 8 || event.start.dateOnly) {
return true;
}
var start = event.start || 0;
var startDate = new Date(start);
var end = event.end || 0;
const start = event.start || 0;
const startDate = new Date(start);
const end = event.end || 0;
if ((end - start) % (24 * 60 * 60 * 1000) === 0 && startDate.getHours() === 0 && startDate.getMinutes() === 0) {
// Is 24 hours, and starts on the middle of the night.
return true;
@ -370,11 +369,11 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
*
* return bool - The event should be filtered out
*/
var timeFilterApplies = function (now, endDate, filter) {
const timeFilterApplies = function (now, endDate, filter) {
if (filter) {
var until = filter.split(" "),
const until = filter.split(" "),
value = parseInt(until[0]),
increment = until[1].slice("-1") === "s" ? until[1] : until[1] + "s", // Massage the data for moment js
increment = until[1].slice(-1) === "s" ? until[1] : until[1] + "s", // Massage the data for moment js
filterUntil = moment(endDate.format()).subtract(value, increment);
return now < filterUntil.format("x");
@ -390,8 +389,8 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
*
* return string - The title of the event, or "Event" if no title is found.
*/
var getTitleFromEvent = function (event) {
var title = "Event";
const getTitleFromEvent = function (event) {
let title = "Event";
if (event.summary) {
title = typeof event.summary.val !== "undefined" ? event.summary.val : event.summary;
} else if (event.description) {
@ -401,7 +400,7 @@ var CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumNumb
return title;
};
var testTitleByFilter = function (title, filter, useRegex, regexFlags) {
const testTitleByFilter = function (title, filter, useRegex, regexFlags) {
if (useRegex) {
// Assume if leading slash, there is also trailing slash
if (filter[0] === "/") {

View File

@ -5,24 +5,23 @@
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const CalendarFetcher = require("./calendarfetcher.js");
var CalendarFetcher = require("./calendarfetcher.js");
var url = "https://calendar.google.com/calendar/ical/pkm1t2uedjbp0uvq1o7oj1jouo%40group.calendar.google.com/private-08ba559f89eec70dd74bbd887d0a3598/basic.ics"; // Standard test URL
// var url = "https://www.googleapis.com/calendar/v3/calendars/primary/events/"; // URL for Bearer auth (must be configured in Google OAuth2 first)
var fetchInterval = 60 * 60 * 1000;
var maximumEntries = 10;
var maximumNumberOfDays = 365;
var user = "magicmirror";
var pass = "MyStrongPass";
var auth = {
const url = "https://calendar.google.com/calendar/ical/pkm1t2uedjbp0uvq1o7oj1jouo%40group.calendar.google.com/private-08ba559f89eec70dd74bbd887d0a3598/basic.ics"; // Standard test URL
//const url = "https://www.googleapis.com/calendar/v3/calendars/primary/events/"; // URL for Bearer auth (must be configured in Google OAuth2 first)
const fetchInterval = 60 * 60 * 1000;
const maximumEntries = 10;
const maximumNumberOfDays = 365;
const user = "magicmirror";
const pass = "MyStrongPass";
const auth = {
user: user,
pass: pass
};
console.log("Create fetcher ...");
var fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maximumNumberOfDays, auth);
const fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maximumNumberOfDays, auth);
fetcher.onReceive(function (fetcher) {
console.log(fetcher.events());

View File

@ -1,4 +0,0 @@
language: node_js
node_js:
- "8.9"
install: npm install

View File

@ -1,178 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -1,13 +0,0 @@
Copyright 2012 Peter Braden
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,16 +0,0 @@
'use strict';
const ical = require('ical');
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function (err, data) {
for (let k in data) {
if (data.hasOwnProperty(k)) {
var ev = data[k];
if (data[k].type == 'VEVENT') {
console.log(`${ev.summary} is in ${ev.location} on the ${ev.start.getDate()} of ${months[ev.start.getMonth()]} at ${ev.start.toLocaleTimeString('en-GB')}`);
}
}
}
});

View File

@ -1,118 +0,0 @@
var ical = require('./node-ical')
var moment = require('moment')
var data = ical.parseFile('./examples/example_rrule.ics');
// Complicated example demonstrating how to handle recurrence rules and exceptions.
for (var k in data) {
// When dealing with calendar recurrences, you need a range of dates to query against,
// because otherwise you can get an infinite number of calendar events.
var rangeStart = moment("2017-01-01");
var rangeEnd = moment("2017-12-31");
var event = data[k]
if (event.type === 'VEVENT') {
var title = event.summary;
var startDate = moment(event.start);
var endDate = moment(event.end);
// Calculate the duration of the event for use with recurring events.
var duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));
// Simple case - no recurrences, just print out the calendar event.
if (typeof event.rrule === 'undefined')
{
console.log('title:' + title);
console.log('startDate:' + startDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('endDate:' + endDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('duration:' + moment.duration(duration).humanize());
console.log();
}
// Complicated case - if an RRULE exists, handle multiple recurrences of the event.
else if (typeof event.rrule !== 'undefined')
{
// For recurring events, get the set of event start dates that fall within the range
// of dates we're looking for.
var dates = event.rrule.between(
rangeStart.toDate(),
rangeEnd.toDate(),
true,
function(date, i) {return true;}
)
// The "dates" array contains the set of dates within our desired date range range that are valid
// for the recurrence rule. *However*, it's possible for us to have a specific recurrence that
// had its date changed from outside the range to inside the range. One way to handle this is
// to add *all* recurrence override entries into the set of dates that we check, and then later
// filter out any recurrences that don't actually belong within our range.
if (event.recurrences != undefined)
{
for (var r in event.recurrences)
{
// Only add dates that weren't already in the range we added from the rrule so that
// we don't double-add those events.
if (moment(new Date(r)).isBetween(rangeStart, rangeEnd) != true)
{
dates.push(new Date(r));
}
}
}
// Loop through the set of date entries to see which recurrences should be printed.
for(var i in dates) {
var date = dates[i];
var curEvent = event;
var showRecurrence = true;
var curDuration = duration;
startDate = moment(date);
// Use just the date of the recurrence to look up overrides and exceptions (i.e. chop off time information)
var dateLookupKey = date.toISOString().substring(0, 10);
// For each date that we're checking, it's possible that there is a recurrence override for that one day.
if ((curEvent.recurrences != undefined) && (curEvent.recurrences[dateLookupKey] != undefined))
{
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
curEvent = curEvent.recurrences[dateLookupKey];
startDate = moment(curEvent.start);
curDuration = parseInt(moment(curEvent.end).format("x")) - parseInt(startDate.format("x"));
}
// If there's no recurrence override, check for an exception date. Exception dates represent exceptions to the rule.
else if ((curEvent.exdate != undefined) && (curEvent.exdate[dateLookupKey] != undefined))
{
// This date is an exception date, which means we should skip it in the recurrence pattern.
showRecurrence = false;
}
// Set the the title and the end date from either the regular event or the recurrence override.
var recurrenceTitle = curEvent.summary;
endDate = moment(parseInt(startDate.format("x")) + curDuration, 'x');
// If this recurrence ends before the start of the date range, or starts after the end of the date range,
// don't process it.
if (endDate.isBefore(rangeStart) || startDate.isAfter(rangeEnd)) {
showRecurrence = false;
}
if (showRecurrence === true) {
console.log('title:' + recurrenceTitle);
console.log('startDate:' + startDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('endDate:' + endDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('duration:' + moment.duration(curDuration).humanize());
console.log();
}
}
}
}
}

View File

@ -1,40 +0,0 @@
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:ical
X-WR-TIMEZONE:US/Central
X-WR-CALDESC:
BEGIN:VEVENT
UID:98765432-ABCD-DCBB-999A-987765432123
DTSTART;TZID=US/Central:20170601T090000
DTEND;TZID=US/Central:20170601T170000
DTSTAMP:20170727T044436Z
EXDATE;TZID=US/Central:20170706T090000,20170713T090000,20170720T090000,20
170803T090000
LAST-MODIFIED:20170727T044435Z
RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20170814T045959Z;BYDAY=TH
SEQUENCE:0
SUMMARY:Recurring weekly meeting from June 1 - Aug 14 (except July 6, July 13, July 20, Aug 3)
END:VEVENT
BEGIN:VEVENT
UID:98765432-ABCD-DCBB-999A-987765432123
RECURRENCE-ID;TZID=US/Central:20170629T090000
DTSTART;TZID=US/Central:20170703T090000
DTEND;TZID=US/Central:20170703T120000
DTSTAMP:20170727T044436Z
LAST-MODIFIED:20170216T143445Z
SEQUENCE:0
SUMMARY:Last meeting in June moved to Monday July 3 and shortened to half day
END:VEVENT
BEGIN:VEVENT
UID:12354454-ABCD-DCBB-999A-2349872354897
DTSTART;TZID=US/Central:20171201T130000
DTEND;TZID=US/Central:20171201T150000
DTSTAMP:20170727T044436Z
LAST-MODIFIED:20170727T044435Z
SEQUENCE:0
SUMMARY:Single event on Dec 1
END:VEVENT
END:VCALENDAR

View File

@ -1,452 +0,0 @@
(function(name, definition) {
/****************
* A tolerant, minimal icalendar parser
* (http://tools.ietf.org/html/rfc5545)
*
* <peterbraden@peterbraden.co.uk>
* **************/
if (typeof module !== 'undefined') {
module.exports = definition();
} else if (typeof define === 'function' && typeof define.amd === 'object'){
define(definition);
} else {
this[name] = definition();
}
}('ical', function(){
// Unescape Text re RFC 4.3.11
var text = function(t){
t = t || "";
return (t
.replace(/\\\,/g, ',')
.replace(/\\\;/g, ';')
.replace(/\\[nN]/g, '\n')
.replace(/\\\\/g, '\\')
)
}
var parseParams = function(p){
var out = {}
for (var i = 0; i<p.length; i++){
if (p[i].indexOf('=') > -1){
var segs = p[i].split('=');
out[segs[0]] = parseValue(segs.slice(1).join('='));
}
}
return out || sp
}
var parseValue = function(val){
if ('TRUE' === val)
return true;
if ('FALSE' === val)
return false;
var number = Number(val);
if (!isNaN(number))
return number;
return val;
}
var storeValParam = function (name) {
return function (val, curr) {
var current = curr[name];
if (Array.isArray(current)) {
current.push(val);
return curr;
}
if (current != null) {
curr[name] = [current, val];
return curr;
}
curr[name] = val;
return curr
}
}
var storeParam = function (name) {
return function (val, params, curr) {
var data;
if (params && params.length && !(params.length == 1 && params[0] === 'CHARSET=utf-8')) {
data = { params: parseParams(params), val: text(val) }
}
else
data = text(val)
return storeValParam(name)(data, curr);
}
}
var addTZ = function (dt, params) {
var p = parseParams(params);
if (params && p){
dt.tz = p.TZID
}
return dt
}
var dateParam = function(name){
return function (val, params, curr) {
var newDate = text(val);
if (params && params[0] === "VALUE=DATE") {
// Just Date
var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(val);
if (comps !== null) {
// No TZ info - assume same timezone as this computer
newDate = new Date(
comps[1],
parseInt(comps[2], 10)-1,
comps[3]
);
newDate = addTZ(newDate, params);
newDate.dateOnly = true;
// Store as string - worst case scenario
return storeValParam(name)(newDate, curr)
}
}
//typical RFC date-time format
var comps = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z)?$/.exec(val);
if (comps !== null) {
if (comps[7] == 'Z'){ // GMT
newDate = new Date(Date.UTC(
parseInt(comps[1], 10),
parseInt(comps[2], 10)-1,
parseInt(comps[3], 10),
parseInt(comps[4], 10),
parseInt(comps[5], 10),
parseInt(comps[6], 10 )
));
// TODO add tz
} else {
newDate = new Date(
parseInt(comps[1], 10),
parseInt(comps[2], 10)-1,
parseInt(comps[3], 10),
parseInt(comps[4], 10),
parseInt(comps[5], 10),
parseInt(comps[6], 10)
);
}
newDate = addTZ(newDate, params);
}
// Store as string - worst case scenario
return storeValParam(name)(newDate, curr)
}
}
var geoParam = function(name){
return function(val, params, curr){
storeParam(val, params, curr)
var parts = val.split(';');
curr[name] = {lat:Number(parts[0]), lon:Number(parts[1])};
return curr
}
}
var categoriesParam = function (name) {
var separatorPattern = /\s*,\s*/g;
return function (val, params, curr) {
storeParam(val, params, curr)
if (curr[name] === undefined)
curr[name] = val ? val.split(separatorPattern) : []
else
if (val)
curr[name] = curr[name].concat(val.split(separatorPattern))
return curr
}
}
// EXDATE is an entry that represents exceptions to a recurrence rule (ex: "repeat every day except on 7/4").
// The EXDATE entry itself can also contain a comma-separated list, so we make sure to parse each date out separately.
// There can also be more than one EXDATE entries in a calendar record.
// Since there can be multiple dates, we create an array of them. The index into the array is the ISO string of the date itself, for ease of use.
// i.e. You can check if ((curr.exdate != undefined) && (curr.exdate[date iso string] != undefined)) to see if a date is an exception.
// NOTE: This specifically uses date only, and not time. This is to avoid a few problems:
// 1. The ISO string with time wouldn't work for "floating dates" (dates without timezones).
// ex: "20171225T060000" - this is supposed to mean 6 AM in whatever timezone you're currently in
// 2. Daylight savings time potentially affects the time you would need to look up
// 3. Some EXDATE entries in the wild seem to have times different from the recurrence rule, but are still excluded by calendar programs. Not sure how or why.
// These would fail any sort of sane time lookup, because the time literally doesn't match the event. So we'll ignore time and just use date.
// ex: DTSTART:20170814T140000Z
// RRULE:FREQ=WEEKLY;WKST=SU;INTERVAL=2;BYDAY=MO,TU
// EXDATE:20171219T060000
// Even though "T060000" doesn't match or overlap "T1400000Z", it's still supposed to be excluded? Odd. :(
// TODO: See if this causes any problems with events that recur multiple times a day.
var exdateParam = function (name) {
return function (val, params, curr) {
var separatorPattern = /\s*,\s*/g;
curr[name] = curr[name] || [];
var dates = val ? val.split(separatorPattern) : [];
dates.forEach(function (entry) {
var exdate = new Array();
dateParam(name)(entry, params, exdate);
if (exdate[name])
{
if (typeof exdate[name].toISOString === 'function') {
curr[name][exdate[name].toISOString().substring(0, 10)] = exdate[name];
} else {
console.error("No toISOString function in exdate[name]", exdate[name]);
}
}
}
)
return curr;
}
}
// RECURRENCE-ID is the ID of a specific recurrence within a recurrence rule.
// TODO: It's also possible for it to have a range, like "THISANDPRIOR", "THISANDFUTURE". This isn't currently handled.
var recurrenceParam = function (name) {
return dateParam(name);
}
var addFBType = function (fb, params) {
var p = parseParams(params);
if (params && p){
fb.type = p.FBTYPE || "BUSY"
}
return fb;
}
var freebusyParam = function (name) {
return function(val, params, curr){
var fb = addFBType({}, params);
curr[name] = curr[name] || []
curr[name].push(fb);
storeParam(val, params, fb);
var parts = val.split('/');
['start', 'end'].forEach(function (name, index) {
dateParam(name)(parts[index], params, fb);
});
return curr;
}
}
return {
objectHandlers : {
'BEGIN' : function(component, params, curr, stack){
stack.push(curr)
return {type:component, params:params}
}
, 'END' : function(component, params, curr, stack){
// prevents the need to search the root of the tree for the VCALENDAR object
if (component === "VCALENDAR") {
//scan all high level object in curr and drop all strings
var key,
obj;
for (key in curr) {
if(curr.hasOwnProperty(key)) {
obj = curr[key];
if (typeof obj === 'string') {
delete curr[key];
}
}
}
return curr
}
var par = stack.pop()
if (curr.uid)
{
// If this is the first time we run into this UID, just save it.
if (par[curr.uid] === undefined)
{
par[curr.uid] = curr;
}
else
{
// If we have multiple ical entries with the same UID, it's either going to be a
// modification to a recurrence (RECURRENCE-ID), and/or a significant modification
// to the entry (SEQUENCE).
// TODO: Look into proper sequence logic.
if (curr.recurrenceid === undefined)
{
// If we have the same UID as an existing record, and it *isn't* a specific recurrence ID,
// not quite sure what the correct behaviour should be. For now, just take the new information
// and merge it with the old record by overwriting only the fields that appear in the new record.
var key;
for (key in curr) {
par[curr.uid][key] = curr[key];
}
}
}
// If we have recurrence-id entries, list them as an array of recurrences keyed off of recurrence-id.
// To use - as you're running through the dates of an rrule, you can try looking it up in the recurrences
// array. If it exists, then use the data from the calendar object in the recurrence instead of the parent
// for that day.
// NOTE: Sometimes the RECURRENCE-ID record will show up *before* the record with the RRULE entry. In that
// case, what happens is that the RECURRENCE-ID record ends up becoming both the parent record and an entry
// in the recurrences array, and then when we process the RRULE entry later it overwrites the appropriate
// fields in the parent record.
if (curr.recurrenceid != null)
{
// TODO: Is there ever a case where we have to worry about overwriting an existing entry here?
// Create a copy of the current object to save in our recurrences array. (We *could* just do par = curr,
// except for the case that we get the RECURRENCE-ID record before the RRULE record. In that case, we
// would end up with a shared reference that would cause us to overwrite *both* records at the point
// that we try and fix up the parent record.)
var recurrenceObj = new Object();
var key;
for (key in curr) {
recurrenceObj[key] = curr[key];
}
if (recurrenceObj.recurrences != undefined) {
delete recurrenceObj.recurrences;
}
// If we don't have an array to store recurrences in yet, create it.
if (par[curr.uid].recurrences === undefined) {
par[curr.uid].recurrences = new Array();
}
// Save off our cloned recurrence object into the array, keyed by date but not time.
// We key by date only to avoid timezone and "floating time" problems (where the time isn't associated with a timezone).
// TODO: See if this causes a problem with events that have multiple recurrences per day.
if (typeof curr.recurrenceid.toISOString === 'function') {
par[curr.uid].recurrences[curr.recurrenceid.toISOString().substring(0,10)] = recurrenceObj;
} else {
console.error("No toISOString function in curr.recurrenceid", curr.recurrenceid);
}
}
// One more specific fix - in the case that an RRULE entry shows up after a RECURRENCE-ID entry,
// let's make sure to clear the recurrenceid off the parent field.
if ((par[curr.uid].rrule != undefined) && (par[curr.uid].recurrenceid != undefined))
{
delete par[curr.uid].recurrenceid;
}
}
else
par[Math.random()*100000] = curr // Randomly assign ID : TODO - use true GUID
return par
}
, 'SUMMARY' : storeParam('summary')
, 'DESCRIPTION' : storeParam('description')
, 'URL' : storeParam('url')
, 'UID' : storeParam('uid')
, 'LOCATION' : storeParam('location')
, 'DTSTART' : dateParam('start')
, 'DTEND' : dateParam('end')
, 'EXDATE' : exdateParam('exdate')
,' CLASS' : storeParam('class')
, 'TRANSP' : storeParam('transparency')
, 'GEO' : geoParam('geo')
, 'PERCENT-COMPLETE': storeParam('completion')
, 'COMPLETED': dateParam('completed')
, 'CATEGORIES': categoriesParam('categories')
, 'FREEBUSY': freebusyParam('freebusy')
, 'DTSTAMP': dateParam('dtstamp')
, 'CREATED': dateParam('created')
, 'LAST-MODIFIED': dateParam('lastmodified')
, 'RECURRENCE-ID': recurrenceParam('recurrenceid')
},
handleObject : function(name, val, params, ctx, stack, line){
var self = this
if(self.objectHandlers[name])
return self.objectHandlers[name](val, params, ctx, stack, line)
//handling custom properties
if(name.match(/X\-[\w\-]+/) && stack.length > 0) {
//trimming the leading and perform storeParam
name = name.substring(2);
return (storeParam(name))(val, params, ctx, stack, line);
}
return storeParam(name.toLowerCase())(val, params, ctx);
},
parseICS : function(str){
var self = this
var lines = str.split(/\r?\n/)
var ctx = {}
var stack = []
for (var i = 0, ii = lines.length, l = lines[0]; i<ii; i++, l=lines[i]){
//Unfold : RFC#3.1
while (lines[i+1] && /[ \t]/.test(lines[i+1][0])) {
l += lines[i+1].slice(1)
i += 1
}
var kv = l.split(":")
if (kv.length < 2){
// Invalid line - must have k&v
continue;
}
// Although the spec says that vals with colons should be quote wrapped
// in practise nobody does, so we assume further colons are part of the
// val
var value = kv.slice(1).join(":")
, kp = kv[0].split(";")
, name = kp[0]
, params = kp.slice(1)
ctx = self.handleObject(name, value, params, ctx, stack, l) || {}
}
// type and params are added to the list of items, get rid of them.
delete ctx.type
delete ctx.params
return ctx
}
}
}))

View File

@ -1,8 +0,0 @@
module.exports = require('./ical')
var node = require('./node-ical')
// Copy node functions across to exports
for (var i in node){
module.exports[i] = node[i]
}

View File

@ -1,77 +0,0 @@
var ical = require('./ical')
, request = require('request')
, fs = require('fs')
exports.fromURL = function(url, opts, cb){
if (!cb)
return;
request(url, opts, function(err, r, data){
if (err)
{
return cb(err, null);
}
else if (r.statusCode != 200)
{
return cb(r.statusCode + ": " + r.statusMessage, null);
}
cb(undefined, ical.parseICS(data));
})
}
exports.parseFile = function(filename){
return ical.parseICS(fs.readFileSync(filename, 'utf8'))
}
var rrule = require('rrule').RRule
function getLocaleISOString(date) {
var year = date.getFullYear().toString(10).padStart(4,'0');
var month = (date.getMonth() + 1).toString(10).padStart(2,'0');
var day = date.getDate().toString(10).padStart(2,'0');
var hour = date.getHours().toString(10).padStart(2,'0');
var minute = date.getMinutes().toString(10).padStart(2,'0');
var second = date.getSeconds().toString(10).padStart(2,'0');
return `${year}${month}${day}T${hour}${minute}${second}Z`;
}
ical.objectHandlers['RRULE'] = function(val, params, curr, stack, line){
curr.rrule = line;
return curr
}
var originalEnd = ical.objectHandlers['END'];
ical.objectHandlers['END'] = function (val, params, curr, stack) {
// Recurrence rules are only valid for VEVENT, VTODO, and VJOURNAL.
// More specifically, we need to filter the VCALENDAR type because we might end up with a defined rrule
// due to the subtypes.
if ((val === "VEVENT") || (val === "VTODO") || (val === "VJOURNAL")) {
if (curr.rrule) {
var rule = curr.rrule.replace('RRULE:', '');
if (rule.indexOf('DTSTART') === -1) {
if (curr.start.length === 8) {
var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(curr.start);
if (comps) {
curr.start = new Date(comps[1], comps[2] - 1, comps[3]);
}
}
if (typeof curr.start.toISOString === 'function') {
try {
// kblankenship1989 - to fix issue #1798, converting all dates to locale time first, then converting back to UTC time
rule += ';DTSTART=' + getLocaleISOString(curr.start);
} catch (error) {
console.error("ERROR when trying to convert to ISOString", error);
}
} else {
console.error("No toISOString function in curr.start", curr.start);
}
}
curr.rrule = rrule.fromString(rule);
}
}
return originalEnd.call(this, val, params, curr, stack);
}

View File

@ -1,29 +0,0 @@
{
"name": "ical",
"version": "0.5.0",
"main": "index.js",
"description": "A tolerant, minimal icalendar parser",
"keywords": [
"ical",
"ics",
"calendar"
],
"homepage": "https://github.com/peterbraden/ical.js",
"author": "Peter Braden <peterbraden@peterbraden.co.uk> (peterbraden.co.uk)",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "git://github.com/peterbraden/ical.js.git"
},
"dependencies": {
"request": "^2.88.0",
"rrule": "2.4.1"
},
"devDependencies": {
"vows": "0.8.2",
"underscore": "1.9.1"
},
"scripts": {
"test": "./node_modules/vows/bin/vows ./test/test.js"
}
}

View File

@ -1,62 +0,0 @@
# ical.js #
(Formerly node-ical)
[![Build Status](https://travis-ci.org/peterbraden/ical.js.png)](https://travis-ci.org/peterbraden/ical.js)
A tolerant, minimal icalendar parser for javascript/node
(http://tools.ietf.org/html/rfc5545)
## Install - Node.js ##
ical.js is availble on npm:
npm install ical
## API ##
ical.parseICS(str)
Parses a string with an ICS File
var data = ical.parseFile(filename)
Reads in the specified iCal file, parses it and returns the parsed data
ical.fromURL(url, options, function(err, data) {} )
Use the request library to fetch the specified URL (```opts``` gets passed on to the ```request()``` call), and call the function with the result (either an error or the data).
## Example 1 - Print list of upcoming node conferences (see example.js)
```javascript
'use strict';
const ical = require('ical');
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function (err, data) {
for (let k in data) {
if (data.hasOwnProperty(k)) {
var ev = data[k];
if (data[k].type == 'VEVENT') {
console.log(`${ev.summary} is in ${ev.location} on the ${ev.start.getDate()} of ${months[ev.start.getMonth()]} at ${ev.start.toLocaleTimeString('en-GB')}`);
}
}
}
});
```
## Recurrences and Exceptions ##
Calendar events with recurrence rules can be significantly more complicated to handle correctly. There are three parts to handling them:
1. rrule - the recurrence rule specifying the pattern of recurring dates and times for the event.
2. recurrences - an optional array of event data that can override specific occurrences of the event.
3. exdate - an optional array of dates that should be excluded from the recurrence pattern.
See example_rrule.js for an example of handling recurring calendar events.

View File

@ -1,500 +0,0 @@
/****
* Tests
*
*
***/
process.env.TZ = 'America/San_Francisco';
var ical = require('../index')
var vows = require('vows')
, assert = require('assert')
, _ = require('underscore')
vows.describe('node-ical').addBatch({
'when parsing test1.ics (node conferences schedule from lanyrd.com, modified)': {
topic: function () {
return ical.parseFile('./test/test1.ics')
}
,'we get 9 events': function (topic) {
var events = _.select(_.values(topic), function(x){ return x.type==='VEVENT'})
assert.equal (events.length, 9);
}
,'event 47f6e' : {
topic: function(events){
return _.select(_.values(events),
function(x){
return x.uid ==='47f6ea3f28af2986a2192fa39a91fa7d60d26b76'})[0]
}
,'is in fort lauderdale' : function(topic){
assert.equal(topic.location, "Fort Lauderdale, United States")
}
,'starts Tue, 29 Nov 2011' : function(topic){
assert.equal(topic.start.toDateString(), new Date(2011,10,29).toDateString())
}
}
, 'event 480a' : {
topic: function(events){
return _.select(_.values(events),
function(x){
return x.uid ==='480a3ad48af5ed8965241f14920f90524f533c18'})[0]
}
, 'has a summary (invalid colon handling tolerance)' : function(topic){
assert.equal(topic.summary, '[Async]: Everything Express')
}
, 'has a date only start datetime' : function(topic){
assert.equal(topic.start.dateOnly, true)
}
, 'has a date only end datetime' : function(topic){
assert.equal(topic.end.dateOnly, true)
}
}
, 'event d4c8' :{
topic : function(events){
return _.select(_.values(events),
function(x){
return x.uid === 'd4c826dfb701f611416d69b4df81caf9ff80b03a'})[0]
}
, 'has a start datetime' : function(topic){
assert.equal(topic.start.toDateString(), new Date(Date.UTC(2011, 2, 12, 20, 0, 0)).toDateString())
}
}
, 'event sdfkf09fsd0 (Invalid Date)' :{
topic : function(events){
return _.select(_.values(events),
function(x){
return x.uid === 'sdfkf09fsd0'})[0]
}
, 'has a start datetime' : function(topic){
assert.equal(topic.start, "Next Year")
}
}
}
, 'with test2.ics (testing ical features)' : {
topic: function () {
return ical.parseFile('./test/test2.ics')
}
, 'todo item uid4@host1.com' : {
topic : function(items){
return items['uid4@host1.com']
}
, 'is a VTODO' : function(topic){
assert.equal(topic.type, 'VTODO')
}
}
, 'vfreebusy' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.type === 'VFREEBUSY';
})[0];
}
, 'has a URL' : function(topic) {
assert.equal(topic.url, 'http://www.host.com/calendar/busytime/jsmith.ifb');
}
}
, 'vfreebusy first freebusy' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.type === 'VFREEBUSY';
})[0].freebusy[0];
}
, 'has undefined type defaulting to busy' : function(topic) {
assert.equal(topic.type, "BUSY");
}
, 'has an start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 1998);
assert.equal(topic.start.getUTCMonth(), 2);
assert.equal(topic.start.getUTCDate(), 14);
assert.equal(topic.start.getUTCHours(), 23);
assert.equal(topic.start.getUTCMinutes(), 30);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 1998);
assert.equal(topic.end.getUTCMonth(), 2);
assert.equal(topic.end.getUTCDate(), 15);
assert.equal(topic.end.getUTCHours(), 00);
assert.equal(topic.end.getUTCMinutes(), 30);
}
}
}
, 'with test3.ics (testing tvcountdown.com)' : {
topic: function() {
return ical.parseFile('./test/test3.ics');
}
, 'event -83' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.uid === '20110505T220000Z-83@tvcountdown.com';
})[0];
}
, 'has a start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2011);
assert.equal(topic.start.getMonth(), 4);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 2011);
assert.equal(topic.end.getMonth(), 4);
}
}
}
, 'with test4.ics (testing tripit.com)' : {
topic: function() {
return ical.parseFile('./test/test4.ics');
}
, 'event c32a5...' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.uid === 'c32a5eaba2354bb29e012ec18da827db90550a3b@tripit.com';
})[0];
}
, 'has a start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2011);
assert.equal(topic.start.getMonth(), 09);
assert.equal(topic.start.getDate(), 11);
}
, 'has a summary' : function(topic){
// escaped commas and semicolons should be replaced
assert.equal(topic.summary, 'South San Francisco, CA, October 2011;')
}
, 'has a description' : function(topic){
var desired = 'John Doe is in South San Francisco, CA from Oct 11 ' +
'to Oct 13, 2011\nView and/or edit details in TripIt : http://www.tripit.c' +
'om/trip/show/id/23710889\nTripIt - organize your travel at http://www.trip' +
'it.com\n'
assert.equal(topic.description, desired)
}
, 'has a geolocation' : function(topic){
assert.ok(topic.geo, 'no geo param')
assert.equal(topic.geo.lat, 37.654656)
assert.equal(topic.geo.lon, -122.40775)
}
, 'has transparency' : function(topic){
assert.equal(topic.transparency, 'TRANSPARENT')
}
}
}
, 'with test5.ics (testing meetup.com)' : {
topic: function () {
return ical.parseFile('./test/test5.ics')
}
, 'event nsmxnyppbfc@meetup.com' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.uid === 'event_nsmxnyppbfc@meetup.com';
})[0];
}
, 'has a start' : function(topic){
assert.equal(topic.start.tz, 'America/Phoenix')
assert.equal(topic.start.toISOString(), new Date(2011, 10, 09, 19, 0,0).toISOString())
}
}
}
, 'with test6.ics (testing assembly.org)': {
topic: function () {
return ical.parseFile('./test/test6.ics')
}
, 'event with no ID' : {
topic: function(events) {
return _.select(_.values(events), function(x) {
return x.summary === 'foobar Summer 2011 starts!';
})[0];
}
, 'has a start' : function(topic){
assert.equal(topic.start.toISOString(), new Date(2011, 07, 04, 12, 0,0).toISOString())
}
}
, 'event with rrule' :{
topic: function(events){
return _.select(_.values(events), function(x){
return x.summary === "foobarTV broadcast starts"
})[0];
}
, "Has an RRULE": function(topic){
assert.notEqual(topic.rrule, undefined);
}
, "RRule text": function(topic){
assert.equal(topic.rrule.toText(), "every 5 weeks on Monday, Friday until January 30, 2013")
}
}
}
, 'with test7.ics (testing dtstart of rrule)' :{
topic: function() {
return ical.parseFile('./test/test7.ics');
},
'recurring yearly event (14 july)': {
topic: function(events){
var ev = _.values(events)[0];
return ev.rrule.between(new Date(2013, 0, 1), new Date(2014, 0, 1));
},
'dt start well set': function(topic) {
assert.equal(topic[0].toDateString(), new Date(2013, 6, 14).toDateString());
}
}
}
, "with test 8.ics (VTODO completion)": {
topic: function() {
return ical.parseFile('./test/test8.ics');
},
'grabbing VTODO task': {
topic: function(topic) {
return _.values(topic)[0];
},
'task completed': function(task){
assert.equal(task.completion, 100);
assert.equal(task.completed.toISOString(), new Date(2013, 06, 16, 10, 57, 45).toISOString());
}
}
}
, "with test 9.ics (VEVENT with VALARM)": {
topic: function() {
return ical.parseFile('./test/test9.ics');
},
'grabbing VEVENT task': {
topic: function(topic) {
return _.values(topic)[0];
},
'task completed': function(task){
assert.equal(task.summary, "Event with an alarm");
}
}
}
, 'with test 11.ics (VEVENT with custom properties)': {
topic: function() {
return ical.parseFile('./test10.ics');
},
'grabbing custom properties': {
topic: function(topic) {
}
}
},
'with test10.ics': {
topic: function () {
return ical.parseFile('./test/test10.ics');
},
'when categories present': {
topic: function (t) {return _.values(t)[0]},
'should be a list': function (e) {
assert(e.categories instanceof [].constructor);
},
'should contain individual category values': function (e) {
assert.deepEqual(e.categories, ['cat1', 'cat2', 'cat3']);
}
},
'when categories present with trailing whitespace': {
topic: function (t) {return _.values(t)[1]},
'should contain individual category values without whitespace': function (e) {
assert.deepEqual(e.categories, ['cat1', 'cat2', 'cat3']);
}
},
'when categories present but empty': {
topic: function (t) {return _.values(t)[2]},
'should be an empty list': function (e) {
assert.deepEqual(e.categories, []);
}
},
'when categories present but singular': {
topic: function (t) {return _.values(t)[3]},
'should be a list of single item': function (e) {
assert.deepEqual(e.categories, ['lonely-cat']);
}
},
'when categories present on multiple lines': {
topic: function (t) {return _.values(t)[4]},
'should contain the category values in an array': function (e) {
assert.deepEqual(e.categories, ['cat1', 'cat2', 'cat3']);
}
}
},
'with test11.ics (testing zimbra freebusy)': {
topic: function () {
return ical.parseFile('./test/test11.ics');
},
'freebusy params' : {
topic: function(events) {
return _.values(events)[0];
}
, 'has a URL' : function(topic) {
assert.equal(topic.url, 'http://mail.example.com/yvr-2a@example.com/20140416');
}
, 'has an ORGANIZER' : function(topic) {
assert.equal(topic.organizer, 'mailto:yvr-2a@example.com');
}
, 'has an start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2014);
assert.equal(topic.start.getMonth(), 3);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 2014);
assert.equal(topic.end.getMonth(), 6);
}
}
, 'freebusy busy events' : {
topic: function(events) {
return _.select(_.values(events)[0].freebusy, function(x) {
return x.type === 'BUSY';
})[0];
}
, 'has an start datetime' : function(topic) {
assert.equal(topic.start.getFullYear(), 2014);
assert.equal(topic.start.getMonth(), 3);
assert.equal(topic.start.getUTCHours(), 15);
assert.equal(topic.start.getUTCMinutes(), 15);
}
, 'has an end datetime' : function(topic) {
assert.equal(topic.end.getFullYear(), 2014);
assert.equal(topic.end.getMonth(), 3);
assert.equal(topic.end.getUTCHours(), 19);
assert.equal(topic.end.getUTCMinutes(), 00);
}
}
}
, 'with test12.ics (testing recurrences and exdates)': {
topic: function () {
return ical.parseFile('./test/test12.ics')
}
, 'event with rrule': {
topic: function (events) {
return _.select(_.values(events), function (x) {
return x.uid === '0000001';
})[0];
}
, "Has an RRULE": function (topic) {
assert.notEqual(topic.rrule, undefined);
}
, "Has summary Treasure Hunting": function (topic) {
assert.equal(topic.summary, 'Treasure Hunting');
}
, "Has two EXDATES": function (topic) {
assert.notEqual(topic.exdate, undefined);
assert.notEqual(topic.exdate[new Date(2015, 06, 08, 12, 0, 0).toISOString().substring(0, 10)], undefined);
assert.notEqual(topic.exdate[new Date(2015, 06, 10, 12, 0, 0).toISOString().substring(0, 10)], undefined);
}
, "Has a RECURRENCE-ID override": function (topic) {
assert.notEqual(topic.recurrences, undefined);
assert.notEqual(topic.recurrences[new Date(2015, 06, 07, 12, 0, 0).toISOString().substring(0, 10)], undefined);
assert.equal(topic.recurrences[new Date(2015, 06, 07, 12, 0, 0).toISOString().substring(0, 10)].summary, 'More Treasure Hunting');
}
}
}
, 'with test13.ics (testing recurrence-id before rrule)': {
topic: function () {
return ical.parseFile('./test/test13.ics')
}
, 'event with rrule': {
topic: function (events) {
return _.select(_.values(events), function (x) {
return x.uid === '6m2q7kb2l02798oagemrcgm6pk@google.com';
})[0];
}
, "Has an RRULE": function (topic) {
assert.notEqual(topic.rrule, undefined);
}
, "Has summary 'repeated'": function (topic) {
assert.equal(topic.summary, 'repeated');
}
, "Has a RECURRENCE-ID override": function (topic) {
assert.notEqual(topic.recurrences, undefined);
assert.notEqual(topic.recurrences[new Date(2016, 7, 26, 14, 0, 0).toISOString().substring(0, 10)], undefined);
assert.equal(topic.recurrences[new Date(2016, 7, 26, 14, 0, 0).toISOString().substring(0, 10)].summary, 'bla bla');
}
}
}
, 'with test14.ics (testing comma-separated exdates)': {
topic: function () {
return ical.parseFile('./test/test14.ics')
}
, 'event with comma-separated exdate': {
topic: function (events) {
return _.select(_.values(events), function (x) {
return x.uid === '98765432-ABCD-DCBB-999A-987765432123';
})[0];
}
, "Has summary 'Example of comma-separated exdates'": function (topic) {
assert.equal(topic.summary, 'Example of comma-separated exdates');
}
, "Has four comma-separated EXDATES": function (topic) {
assert.notEqual(topic.exdate, undefined);
// Verify the four comma-separated EXDATES are there
assert.notEqual(topic.exdate[new Date(2017, 6, 6, 12, 0, 0).toISOString().substring(0, 10)], undefined);
assert.notEqual(topic.exdate[new Date(2017, 6, 17, 12, 0, 0).toISOString().substring(0, 10)], undefined);
assert.notEqual(topic.exdate[new Date(2017, 6, 20, 12, 0, 0).toISOString().substring(0, 10)], undefined);
assert.notEqual(topic.exdate[new Date(2017, 7, 3, 12, 0, 0).toISOString().substring(0, 10)], undefined);
// Verify an arbitrary date isn't there
assert.equal(topic.exdate[new Date(2017, 4, 5, 12, 0, 0).toISOString().substring(0, 10)], undefined);
}
}
}
, 'with test14.ics (testing exdates with bad times)': {
topic: function () {
return ical.parseFile('./test/test14.ics')
}
, 'event with exdates with bad times': {
topic: function (events) {
return _.select(_.values(events), function (x) {
return x.uid === '1234567-ABCD-ABCD-ABCD-123456789012';
})[0];
}
, "Has summary 'Example of exdate with bad times'": function (topic) {
assert.equal(topic.summary, 'Example of exdate with bad times');
}
, "Has two EXDATES even though they have bad times": function (topic) {
assert.notEqual(topic.exdate, undefined);
// Verify the two EXDATES are there, even though they have bad times
assert.notEqual(topic.exdate[new Date(2017, 11, 18, 12, 0, 0).toISOString().substring(0, 10)], undefined);
assert.notEqual(topic.exdate[new Date(2017, 11, 19, 12, 0, 0).toISOString().substring(0, 10)], undefined);
}
}
}
, 'url request errors': {
topic : function () {
ical.fromURL('http://255.255.255.255/', {}, this.callback);
}
, 'are passed back to the callback' : function (err, result) {
assert.instanceOf(err, Error);
if (!err){
console.log(">E:", err, result)
}
}
}
}).export(module)
//ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics',
// {},
// function(err, data){
// console.log("OUT:", data)
// })

View File

@ -1,78 +0,0 @@
BEGIN:VCALENDAR
PRODID:-//lanyrd.com//Lanyrd//EN
X-ORIGINAL-URL:http://lanyrd.com/topics/nodejs/nodejs.ics
X-WR-CALNAME;CHARSET=utf-8:Node.js conferences
VERSION:2.0
METHOD:PUBLISH
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Dyncon 2011
LOCATION;CHARSET=utf-8:Stockholm, Sweden
URL:http://lanyrd.com/2011/dyncon/
UID:d4c826dfb701f611416d69b4df81caf9ff80b03a
DTSTART:20110312T200000Z
DTEND;VALUE=DATE:20110314
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:[Async]: Everything Express
LOCATION;CHARSET=utf-8:Brighton, United Kingdom
URL:http://lanyrd.com/2011/asyncjs-express/
UID:480a3ad48af5ed8965241f14920f90524f533c18
DTSTART;VALUE=DATE:20110324
DTEND;VALUE=DATE:20110325
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:JSConf US 2011
LOCATION;CHARSET=utf-8:Portland, United States
URL:http://lanyrd.com/2011/jsconf/
UID:ed334cc85db5ebdff5ff5a630a7a48631a677dbe
DTSTART;VALUE=DATE:20110502
DTEND;VALUE=DATE:20110504
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:NodeConf 2011
LOCATION;CHARSET=utf-8:Portland, United States
URL:http://lanyrd.com/2011/nodeconf/
UID:25169a7b1ba5c248278f47120a40878055dc8c15
DTSTART;VALUE=DATE:20110505
DTEND;VALUE=DATE:20110506
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:BrazilJS
LOCATION;CHARSET=utf-8:Fortaleza, Brazil
URL:http://lanyrd.com/2011/braziljs/
UID:dafee3be83624f3388c5635662229ff11766bb9c
DTSTART;VALUE=DATE:20110513
DTEND;VALUE=DATE:20110515
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Falsy Values
LOCATION;CHARSET=utf-8:Warsaw, Poland
URL:http://lanyrd.com/2011/falsy-values/
UID:73cad6a09ac4e7310979c6130f871d17d990b5ad
DTSTART;VALUE=DATE:20110518
DTEND;VALUE=DATE:20110521
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:nodecamp.eu
LOCATION;CHARSET=utf-8:Cologne, Germany
URL:http://lanyrd.com/2011/nodecampde/
UID:b728a5fdb5f292b6293e4a2fd97a1ccfc69e9d6f
DTSTART;VALUE=DATE:20110611
DTEND;VALUE=DATE:20110613
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Rich Web Experience 2011
LOCATION;CHARSET=utf-8:Fort Lauderdale, United States
URL:http://lanyrd.com/2011/rich-web-experience/
UID:47f6ea3f28af2986a2192fa39a91fa7d60d26b76
DTSTART;VALUE=DATE:20111129
DTEND;VALUE=DATE:20111203
END:VEVENT
BEGIN:VEVENT
SUMMARY;CHARSET=utf-8:Foobar
UID:sdfkf09fsd0
DTSTART;VALUE=DATE:Next Year
DTEND;VALUE=DATE:20111203
END:VEVENT
END:VCALENDAR

View File

@ -1,34 +0,0 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:1
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:cat1,cat2,cat3
END:VEVENT
BEGIN:VEVENT
UID:2
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:cat1 , cat2, cat3
END:VEVENT
BEGIN:VEVENT
UID:3
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:
END:VEVENT
BEGIN:VEVENT
UID:4
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:lonely-cat
END:VEVENT
BEGIN:VEVENT
UID:5
SUMMARY:Event with a category
DESCRIPTION:Details for an event with a category
CATEGORIES:cat1
CATEGORIES:cat2
CATEGORIES:cat3
END:VEVENT
END:VCALENDAR

View File

@ -1,41 +0,0 @@
BEGIN:VCALENDAR
PRODID:Zimbra-Calendar-Provider
VERSION:2.0
METHOD:PUBLISH
BEGIN:VFREEBUSY
ORGANIZER:mailto:yvr-2a@example.com
DTSTAMP:20140516T235436Z
DTSTART:20140415T235436Z
DTEND:20140717T235436Z
URL:http://mail.example.com/yvr-2a@example.com/20140416
FREEBUSY;FBTYPE=BUSY:20140416T151500Z/20140416T190000Z
FREEBUSY;FBTYPE=BUSY:20140416T195500Z/20140416T231500Z
FREEBUSY;FBTYPE=BUSY:20140417T193000Z/20140417T203000Z
FREEBUSY;FBTYPE=BUSY:20140421T210000Z/20140421T213000Z
FREEBUSY;FBTYPE=BUSY:20140423T180000Z/20140423T190000Z
FREEBUSY;FBTYPE=BUSY:20140423T200000Z/20140423T210000Z
FREEBUSY;FBTYPE=BUSY:20140423T223500Z/20140423T231500Z
FREEBUSY;FBTYPE=BUSY:20140424T155000Z/20140424T165500Z
FREEBUSY;FBTYPE=BUSY:20140424T170000Z/20140424T183000Z
FREEBUSY;FBTYPE=BUSY:20140424T195000Z/20140424T230000Z
FREEBUSY;FBTYPE=BUSY:20140425T144500Z/20140425T161500Z
FREEBUSY;FBTYPE=BUSY:20140425T180000Z/20140425T194500Z
FREEBUSY;FBTYPE=BUSY:20140425T223000Z/20140425T230000Z
FREEBUSY;FBTYPE=BUSY:20140428T151500Z/20140428T163000Z
FREEBUSY;FBTYPE=BUSY:20140428T170000Z/20140428T173000Z
FREEBUSY;FBTYPE=BUSY:20140428T195500Z/20140428T213000Z
FREEBUSY;FBTYPE=BUSY:20140428T231000Z/20140428T234000Z
FREEBUSY;FBTYPE=BUSY:20140429T152500Z/20140429T170000Z
FREEBUSY;FBTYPE=BUSY:20140429T180000Z/20140429T183000Z
FREEBUSY;FBTYPE=BUSY:20140429T201500Z/20140429T230000Z
FREEBUSY;FBTYPE=BUSY:20140430T162500Z/20140430T165500Z
FREEBUSY;FBTYPE=BUSY:20140430T180000Z/20140430T190000Z
FREEBUSY;FBTYPE=BUSY:20140501T170000Z/20140501T173000Z
FREEBUSY;FBTYPE=BUSY:20140501T175000Z/20140501T190000Z
FREEBUSY;FBTYPE=BUSY:20140501T232000Z/20140501T235000Z
FREEBUSY;FBTYPE=BUSY:20140502T163500Z/20140502T173000Z
FREEBUSY;FBTYPE=BUSY:20140505T165500Z/20140505T173000Z
FREEBUSY;FBTYPE=BUSY:20140505T201500Z/20140505T203000Z
FREEBUSY;FBTYPE=BUSY:20140505T210000Z/20140505T213000Z
END:VFREEBUSY
END:VCALENDAR

View File

@ -1,19 +0,0 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:0000001
SUMMARY:Treasure Hunting
DTSTART;TZID=America/Los_Angeles:20150706T120000
DTEND;TZID=America/Los_Angeles:20150706T130000
RRULE:FREQ=DAILY;COUNT=10
EXDATE;TZID=America/Los_Angeles:20150708T120000
EXDATE;TZID=America/Los_Angeles:20150710T120000
END:VEVENT
BEGIN:VEVENT
UID:0000001
SUMMARY:More Treasure Hunting
LOCATION:The other island
DTSTART;TZID=America/Los_Angeles:20150709T150000
DTEND;TZID=America/Los_Angeles:20150707T160000
RECURRENCE-ID;TZID=America/Los_Angeles:20150707T120000
END:VEVENT
END:VCALENDAR

View File

@ -1,57 +0,0 @@
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:ical
X-WR-TIMEZONE:Europe/Kiev
X-WR-CALDESC:
BEGIN:VTIMEZONE
TZID:Europe/Kiev
X-LIC-LOCATION:Europe/Kiev
BEGIN:DAYLIGHT
TZOFFSETFROM:+0200
TZOFFSETTO:+0300
TZNAME:EEST
DTSTART:19700329T030000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
TZNAME:EET
DTSTART:19701025T040000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=Europe/Kiev:20160826T140000
DTEND;TZID=Europe/Kiev:20160826T150000
DTSTAMP:20160825T061505Z
UID:6m2q7kb2l02798oagemrcgm6pk@google.com
RECURRENCE-ID;TZID=Europe/Kiev:20160826T140000
CREATED:20160823T125221Z
DESCRIPTION:
LAST-MODIFIED:20160823T130320Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:bla bla
TRANSP:OPAQUE
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=Europe/Kiev:20160825T140000
DTEND;TZID=Europe/Kiev:20160825T150000
RRULE:FREQ=DAILY;UNTIL=20160828T110000Z
DTSTAMP:20160825T061505Z
UID:6m2q7kb2l02798oagemrcgm6pk@google.com
CREATED:20160823T125221Z
DESCRIPTION:
LAST-MODIFIED:20160823T125221Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:repeated
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR

View File

@ -1,33 +0,0 @@
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:ical
X-WR-TIMEZONE:Europe/Kiev
X-WR-CALDESC:
BEGIN:VEVENT
UID:98765432-ABCD-DCBB-999A-987765432123
DTSTART;TZID=US/Central:20170216T090000
DTEND;TZID=US/Central:20170216T190000
DTSTAMP:20170727T044436Z
EXDATE;TZID=US/Central:20170706T090000,20170717T090000,20170720T090000,20
170803T090000
LAST-MODIFIED:20170727T044435Z
RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20170814T045959Z;INTERVAL=2;BYDAY=MO,TH
SEQUENCE:0
SUMMARY:Example of comma-separated exdates
END:VEVENT
BEGIN:VEVENT
UID:1234567-ABCD-ABCD-ABCD-123456789012
DTSTART:20170814T140000Z
DTEND:20170815T000000Z
DTSTAMP:20171204T134925Z
EXDATE:20171219T060000
EXDATE:20171218T060000
LAST-MODIFIED:20171024T140004Z
RRULE:FREQ=WEEKLY;WKST=SU;INTERVAL=2;BYDAY=MO,TU
SEQUENCE:0
SUMMARY:Example of exdate with bad times
END:VEVENT
END:VCALENDAR

View File

@ -1,83 +0,0 @@
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
X-WR-TIMEZONE;VALUE=TEXT:US/Pacific
METHOD:PUBLISH
PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
X-WR-CALNAME;VALUE=TEXT:Example
VERSION:2.0
BEGIN:VEVENT
SEQUENCE:5
DTSTART;TZID=US/Pacific:20021028T140000
DTSTAMP:20021028T011706Z
SUMMARY:Coffee with Jason
UID:EC9439B1-FF65-11D6-9973-003065F99D04
DTEND;TZID=US/Pacific:20021028T150000
END:VEVENT
BEGIN:VALARM
TRIGGER;VALUE=DURATION:-P1D
ACTION:DISPLAY
DESCRIPTION:Event reminder
END:VALARM
BEGIN:VEVENT
SEQUENCE:1
DTSTAMP:20021128T012034Z
SUMMARY:Code Review
UID:EC944331-FF65-11D6-9973-003065F99D04
DTSTART;TZID=US/Pacific:20021127T120000
DURATION:PT1H
END:VEVENT
BEGIN:VEVENT
SEQUENCE:1
DTSTAMP:20021028T012034Z
SUMMARY:Dinner with T
UID:EC944CFA-FF65-11D6-9973-003065F99D04
DTSTART;TZID=US/Pacific:20021216T200000
DURATION:PT1H
END:VEVENT
BEGIN:VTODO
DTSTAMP:19980130T134500Z
SEQUENCE:2
UID:uid4@host1.com
ORGANIZER:MAILTO:unclesam@us.gov
ATTENDEE;PARTSTAT=ACCEPTED:MAILTO:jqpublic@host.com
DUE:19980415T235959
STATUS:NEEDS-ACTION
SUMMARY:Submit Income Taxes
END:VTODO
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:19980403T120000
ATTACH;FMTTYPE=audio/basic:http://host.com/pub/audio-
files/ssbanner.aud
REPEAT:4
DURATION:PT1H
END:VALARM
BEGIN:VJOURNAL
DTSTAMP:19970324T120000Z
UID:uid5@host1.com
ORGANIZER:MAILTO:jsmith@host.com
STATUS:DRAFT
CLASS:PUBLIC
CATEGORY:Project Report, XYZ, Weekly Meeting
DESCRIPTION:Project xyz Review Meeting Minutes\n
Agenda\n1. Review of project version 1.0 requirements.\n2.
Definition
of project processes.\n3. Review of project schedule.\n
Participants: John Smith, Jane Doe, Jim Dandy\n-It was
decided that the requirements need to be signed off by
product marketing.\n-Project processes were accepted.\n
-Project schedule needs to account for scheduled holidays
and employee vacation time. Check with HR for specific
dates.\n-New schedule will be distributed by Friday.\n-
Next weeks meeting is cancelled. No meeting until 3/23.
END:VJOURNAL
BEGIN:VFREEBUSY
ORGANIZER:MAILTO:jsmith@host.com
DTSTART:19980313T141711Z
DTEND:19980410T141711Z
FREEBUSY:19980314T233000Z/19980315T003000Z
FREEBUSY:19980316T153000Z/19980316T163000Z
FREEBUSY:19980318T030000Z/19980318T040000Z
URL:http://www.host.com/calendar/busytime/jsmith.ifb
END:VFREEBUSY
END:VCALENDAR

View File

@ -1,226 +0,0 @@
BEGIN:VCALENDAR
CALSCALE:GREGORIAN
PRODID:tvcountdown.com
X-WR-CALNAME:tvcountdown.com
VERSION:2.0
METHOD:PUBLISH
X-WR-TIMEZONE:US/Eastern
X-WR-CALNAME;VALUE=TEXT:tvcountdown.com
X-WR-CALDESC:
BEGIN:VEVENT
UID:20110519T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110519T200000
DTEND;VALUE=DATE-TIME:20110519T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E24 - The Roomate Transmogrfication
END:VEVENT
BEGIN:VEVENT
UID:20110512T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110512T200000
DTEND;VALUE=DATE-TIME:20110512T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E23 - The Engagement Reaction
END:VEVENT
BEGIN:VEVENT
UID:20110505T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110505T220000
DTEND;VALUE=DATE-TIME:20110505T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E23 - Respawn
END:VEVENT
BEGIN:VEVENT
UID:20110505T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110505T200000
DTEND;VALUE=DATE-TIME:20110505T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E22 - The Wildebeest Implementation
END:VEVENT
BEGIN:VEVENT
UID:20110504T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110504T230000
DTEND;VALUE=DATE-TIME:20110504T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E59 - David Barton
END:VEVENT
BEGIN:VEVENT
UID:20110503T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110503T230000
DTEND;VALUE=DATE-TIME:20110503T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E58 - Rachel Maddow
END:VEVENT
BEGIN:VEVENT
UID:20110502T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110502T230000
DTEND;VALUE=DATE-TIME:20110502T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E57 - Philip K. Howard
END:VEVENT
BEGIN:VEVENT
UID:20110428T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110428T230000
DTEND;VALUE=DATE-TIME:20110428T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E56 - William Cohan
END:VEVENT
BEGIN:VEVENT
UID:20110428T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110428T220000
DTEND;VALUE=DATE-TIME:20110428T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E22 - Everything Sunny All the Time Always
END:VEVENT
BEGIN:VEVENT
UID:20110428T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110428T200000
DTEND;VALUE=DATE-TIME:20110428T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E21 - The Agreement Dissection
END:VEVENT
BEGIN:VEVENT
UID:20110427T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110427T230000
DTEND;VALUE=DATE-TIME:20110427T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E55 - Sen. Bernie Sanders
END:VEVENT
BEGIN:VEVENT
UID:20110426T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110426T230000
DTEND;VALUE=DATE-TIME:20110426T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E54 - Elizabeth Warren
END:VEVENT
BEGIN:VEVENT
UID:20110425T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110425T230000
DTEND;VALUE=DATE-TIME:20110425T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E53 - Gigi Ibrahim
END:VEVENT
BEGIN:VEVENT
UID:20110421T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110421T220000
DTEND;VALUE=DATE-TIME:20110421T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E21 - 100th Episode Part 2 of 2
END:VEVENT
BEGIN:VEVENT
UID:20110421T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110421T220000
DTEND;VALUE=DATE-TIME:20110421T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E20 - 100th Episode Part 1 of 2
END:VEVENT
BEGIN:VEVENT
UID:20110414T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110414T230000
DTEND;VALUE=DATE-TIME:20110414T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E52 - Ricky Gervais
END:VEVENT
BEGIN:VEVENT
UID:20110414T220000Z-83@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110414T220000
DTEND;VALUE=DATE-TIME:20110414T223000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:30 Rock - S05E19 - I Heart Connecticut
END:VEVENT
BEGIN:VEVENT
UID:20110413T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110413T230000
DTEND;VALUE=DATE-TIME:20110413T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E51 - Tracy Morgan
END:VEVENT
BEGIN:VEVENT
UID:20110412T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110412T230000
DTEND;VALUE=DATE-TIME:20110412T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E50 - Gov. Deval Patrick
END:VEVENT
BEGIN:VEVENT
UID:20110411T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110411T230000
DTEND;VALUE=DATE-TIME:20110411T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E49 - Foo Fighters
END:VEVENT
BEGIN:VEVENT
UID:20110407T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110407T230000
DTEND;VALUE=DATE-TIME:20110407T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E48 - Jamie Oliver
END:VEVENT
BEGIN:VEVENT
UID:20110407T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110407T200000
DTEND;VALUE=DATE-TIME:20110407T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E20 - The Herb Garden Germination
END:VEVENT
BEGIN:VEVENT
UID:20110406T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110406T230000
DTEND;VALUE=DATE-TIME:20110406T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E47 - Mike Huckabee
END:VEVENT
BEGIN:VEVENT
UID:20110405T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110405T230000
DTEND;VALUE=DATE-TIME:20110405T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E46 - Colin Quinn
END:VEVENT
BEGIN:VEVENT
UID:20110404T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110404T230000
DTEND;VALUE=DATE-TIME:20110404T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E45 - Billy Crystal
END:VEVENT
BEGIN:VEVENT
UID:20110331T230000Z-289@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110331T230000
DTEND;VALUE=DATE-TIME:20110331T233000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Daily Show - S16E44 - Norm MacDonald
END:VEVENT
BEGIN:VEVENT
UID:20110331T200000Z-79@tvcountdown.com
DTSTART;VALUE=DATE-TIME:20110331T200000
DTEND;VALUE=DATE-TIME:20110331T203000
DTSTAMP:20110430T192946Z
URL;VALUE=URI:
SUMMARY:The Big Bang Theory - S04E19 - The Zarnecki Incursion
END:VEVENT
END:VCALENDAR

View File

@ -1,747 +0,0 @@
BEGIN:VCALENDAR
X-WR-CALNAME:John Doe (TripIt)
X-WR-CALDESC:TripIt Calendar
X-PUBLISHED-TTL:PT15M
PRODID:-//John Doe/NONSGML Bennu 0.1//EN
VERSION:2.0
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:c32a5eaba2354bb29e012ec18da827db90550a3b@tripit.com
DTSTART;VALUE=DATE:20111011
DTEND;VALUE=DATE:20111014
SUMMARY:South San Francisco\, CA\, October 2011\;
LOCATION:South San Francisco\, CA
GEO:37.654656;-122.40775
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in South San Francisco\, CA from Oct 11
to Oct 13\, 2011\nView and/or edit details in TripIt : http://www.tripit.c
om/trip/show/id/23710889\nTripIt - organize your travel at http://www.trip
it.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
TRANSP:TRANSPARENT
UID:item-ee275ccffa83f492d9eb63b01953b39f18d4f944@tripit.com
DTSTART:20111011T100500
DTEND:20111011T110500
SUMMARY:Directions from SFO to Embassy Suites San Francisco Airport - Sout
h San Francisco
LOCATION:250 GATEWAY BLVD\, South San Francisco\, CA\, 94080
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/1234\n \n[Directions] 10/11/2011 10:05am - Directions from S
FO to Embassy Suites San Francisco Airport - South San Francisco \nfrom: S
FO \nto: 250 GATEWAY BLVD\, South San Francisco\, CA\, 94080 \nView direct
ions here: http://maps.google.com/maps?output=mobile&saddr=SFO&daddr=250+G
ATEWAY+BLVD%2C+South+San+Francisco%2C+CA%2C+94080 \n \n \n\nTripIt - organ
ize your travel at http://www.tripit.com
GEO:37.655634;-122.401273
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111011T165500Z
SUMMARY:US403 PHX to SFO
LOCATION:Phoenix (PHX)
UID:item-c576afd397cf1f90578b4ba35e781b61ba8897db@tripit.com
DTSTART:20111011T144500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/1234\n \n[Flight] 10/11/2011 US Airways(US) #403 dep PHX 7:4
5am MST arr SFO 9:55am PDT\; John Doe\; seat(s) 8B\; conf #DXH9K
Z\, BXQ9WH \nBooked on http://www.americanexpress-travel.com/\; Reference
#: 4127 8626 9715\; http://www.americanexpress-travel.com/\; US:1-800-297-
2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at htt
p://www.tripit.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-e99a90ee1c7e4f5b68a4e551009e5bb6c475940c@tripit.com
DTSTART:20111011T172500Z
DTEND:20111011T182500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/1234\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #R9508361 \np
ickup 10/11/2011 10:25am\; dropoff 10/13/2011 6:49pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4127 8626 9715\; ht
tp://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582
-2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Embassy Suites San Francisco Airport - South San Francis
co
TRANSP:TRANSPARENT
UID:item-7f3288d418bed063cc82b4512e792fbb5d8ae761@tripit.com
DTSTART:20111011T185500Z
DTEND:20111011T195500Z
LOCATION:250 GATEWAY BLVD\, South San Francisco\, CA\, 94080
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Lodging] Embassy Suites San Francisco Airport - So
uth San Francisco\; primary guest John Doe\; conf #R9508361 \n25
0 GATEWAY BLVD\, South San Francisco\, CA\, 94080\; tel 1.650.589.3400 \na
rrive 10/11/2011\; depart 10/13/2011\; rooms: 1 \nBooked on http://www.ame
ricanexpress-travel.com/\; Reference #: 4127 8626 9715\; http://www.americ
anexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n \n \n\
nTripIt - organize your travel at http://www.tripit.com
GEO:37.655634;-122.401273
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Embassy Suites San Francisco Airport - South San Franci
sco
TRANSP:TRANSPARENT
UID:item-5eb4cb5fc25c55b0423921e18336e57f8c34598d@tripit.com
DTSTART:20111014T011900Z
DTEND:20111014T021900Z
LOCATION:250 GATEWAY BLVD\, South San Francisco\, CA\, 94080
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Lodging] Embassy Suites San Francisco Airport - So
uth San Francisco\; primary guest John Doe\; conf #R9508361 \n25
0 GATEWAY BLVD\, South San Francisco\, CA\, 94080\; tel 1.650.589.3400 \na
rrive 10/11/2011\; depart 10/13/2011\; rooms: 1 \nBooked on http://www.ame
ricanexpress-travel.com/\; Reference #: 4127 8626 9715\; http://www.americ
anexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n \n \n\
nTripIt - organize your travel at http://www.tripit.com
GEO:37.655634;-122.401273
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-11fdbf5d02e84646025716d9f9c7a4158e1fb025@tripit.com
DTSTART:20111014T014900Z
DTEND:20111014T024900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #R9508361 \np
ickup 10/11/2011 10:25am\; dropoff 10/13/2011 6:49pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4127 8626 9715\; ht
tp://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582
-2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111014T051900Z
SUMMARY:CO6256 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-cb485a571a01972d6bdc74c2b829905d6e3786bf@tripit.com
DTSTART:20111014T031900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/23710889\n \n[Flight] 10/13/2011 Continental Airlines(CO) #6256
dep SFO 8:19pm PDT arr PHX 10:19pm MST\; John Doe\; conf #DXH9KZ
\, BXQ9WH(Operated by United Airlines flight 6256) \nBooked on http://www.
americanexpress-travel.com/\; Reference #: 4127 8626 9715\; http://www.ame
ricanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n \n
\n\nTripIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:c7b133db1e7be2713a4a63b75dcbad209690cab5@tripit.com
DTSTART;VALUE=DATE:20111023
DTEND;VALUE=DATE:20111028
SUMMARY:Santa Barbara\, CA\, October 2011
LOCATION:Santa Barbara\, CA
GEO:34.420831;-119.69819
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in Santa Barbara\, CA from Oct 23 to Oct
27\, 2011\nView and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\nTripIt - organize your travel at http://www.tripit.com
\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111023T191200Z
SUMMARY:US2719 PHX to SBA
LOCATION:Phoenix (PHX)
UID:item-c4375369e9070fcc04df39ed18c4d93087577591@tripit.com
DTSTART:20111023T173500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Flight] 10/23/2011 US Airways(US) #2719 dep PHX 10
:35am MST arr SBA 12:12pm PDT\; John Doe Ticket #0378717202638\;
conf #A44XS5\, PRX98G\, FYYJZ4 \nBooked on http://www.americanexpress-tra
vel.com/\; Reference #: 7128 8086 8504\; http://www.americanexpress-travel
.com/\; US:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $699.99 \n
\n \n\nTripIt - organize your travel at http://www.tripit.com
GEO:34.427778;-119.839444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
TRANSP:TRANSPARENT
UID:item-962e4f045d12149319d1837ec096bf43770abd6e@tripit.com
DTSTART:20111025T094000
DTEND:20111025T104000
SUMMARY:Directions from Hertz to Sofitel San Francisco Bay
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Directions] 10/25/2011 9:40am - Directions from He
rtz to Sofitel San Francisco Bay \nfrom: 780 McDonnell Road\, San Francisc
o\, CA\, 94128 \nto: 223 Twin Dolphin Drive\, Redwood City\, CA\, 94065 \n
View directions here: http://maps.google.com/maps?output=mobile&saddr=780+
McDonnell+Road%2C+San+Francisco%2C+CA%2C+94128&daddr=223+Twin+Dolphin+Driv
e%2C+Redwood+City%2C+CA%2C+94065 \n \n \n\nTripIt - organize your travel a
t http://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111025T162600Z
SUMMARY:UA5304 SBA to SFO
LOCATION:Santa Barbara (SBA)
UID:item-ae300a6934c3820974dba2c9c5b8fae843c67693@tripit.com
DTSTART:20111025T150900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Flight] 10/25/2011 United Airlines(UA) #5304 dep S
BA 8:09am PDT arr SFO 9:26am PDT\; John Doe Ticket #037871720263
8\; seat(s) 11B\; conf #A44XS5\, PRX98G\, FYYJZ4 \nBooked on http://www.am
ericanexpress-travel.com/\; Reference #: 7128 8086 8504\; http://www.ameri
canexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716\; Total
Cost: $699.99 \n \n \n\nTripIt - organize your travel at http://www.tripit
.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Hertz
TRANSP:TRANSPARENT
UID:item-2a9fd5a57a4cdda4677fc6ce23738e1954fdbe2a@tripit.com
DTSTART:20111025T163000Z
DTEND:20111025T173000Z
LOCATION:780 McDonnell Road\, San Francisco\, CA\, 94128
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Car Rental] Hertz\; San Francisco International Ai
rport\; primary driver John Doe\; conf #F2633064194 \n780 McDonn
ell Road\, San Francisco\, CA\, 94128 \npickup 10/25/2011 9:30am\; dropoff
10/27/2011 7:00pm \nToyota Corolla or similar\; 84.57 USD \nBooked on htt
p://www.hertz.com/\; Reference #: F2633064194\; http://www.hertz.com/\; 80
0-654-3131\; Booking Rate: 84.57 USD\; Total Cost: 333.76 USD \n \n \n\nTr
ipIt - organize your travel at http://www.tripit.com
GEO:37.6297569;-122.4000351
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
TRANSP:TRANSPARENT
UID:item-98dfcb0bcfdcffcce9c58a84947212ed67cadda6@tripit.com
DTSTART:20111025T163600Z
DTEND:20111025T173600Z
SUMMARY:Directions from SFO to Sofitel San Francisco Bay
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Directions] 10/25/2011 9:36am - Directions from SF
O to Sofitel San Francisco Bay \nfrom: SFO \nto: 223 Twin Dolphin Drive\,
Redwood City\, CA\, 94065 \nView directions here: http://maps.google.com/m
aps?output=mobile&saddr=SFO&daddr=223+Twin+Dolphin+Drive%2C+Redwood+City%2
C+CA%2C+94065 \n \n \n\nTripIt - organize your travel at http://www.tripit
.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-8de3937b336c333faf2d55ad0a41c5ca6cc02393@tripit.com
DTSTART:20111025T220000Z
DTEND:20111025T230000Z
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #F80-0GMW \n223 Twin Dolphin Drive\, Redwood Ci
ty\, CA\, 94065\; tel (+1)650/598-9000 \narrive 10/25/2011\; depart 10/27/
2011\; rooms: 1 \nBooked on http://www.sofitel.com/\; http://www.sofitel.c
om/\; Total Cost: 564.00 USD \n \n \n\nTripIt - organize your travel at ht
tp://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-f3ade58646964bde101616a6d26ea7784a1a81e8@tripit.com
DTSTART:20111027T190000Z
DTEND:20111027T200000Z
LOCATION:223 Twin Dolphin Drive\, Redwood City\, CA\, 94065
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #F80-0GMW \n223 Twin Dolphin Drive\, Redwood Ci
ty\, CA\, 94065\; tel (+1)650/598-9000 \narrive 10/25/2011\; depart 10/27/
2011\; rooms: 1 \nBooked on http://www.sofitel.com/\; http://www.sofitel.c
om/\; Total Cost: 564.00 USD \n \n \n\nTripIt - organize your travel at ht
tp://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Hertz
TRANSP:TRANSPARENT
UID:item-50620273fea0614d37775649034d5e1de92ae361@tripit.com
DTSTART:20111028T020000Z
DTEND:20111028T030000Z
LOCATION:780 McDonnell Road\, San Francisco\, CA\, 94128
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Car Rental] Hertz\; San Francisco International Ai
rport\; primary driver John Doe\; conf #F2633064194 \n780 McDonn
ell Road\, San Francisco\, CA\, 94128 \npickup 10/25/2011 9:30am\; dropoff
10/27/2011 7:00pm \nToyota Corolla or similar\; 84.57 USD \nBooked on htt
p://www.hertz.com/\; Reference #: F2633064194\; http://www.hertz.com/\; 80
0-654-3131\; Booking Rate: 84.57 USD\; Total Cost: 333.76 USD \n \n \n\nTr
ipIt - organize your travel at http://www.tripit.com
GEO:37.6297569;-122.4000351
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111028T051900Z
SUMMARY:CO6256 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-71d327f30d8beeaf7bf50c8fa63ce16005b9b0df@tripit.com
DTSTART:20111028T031900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24259445\n \n[Flight] 10/27/2011 Continental Airlines(CO) #6256
dep SFO 8:19pm PDT arr PHX 10:19pm MST\; John Doe Ticket #037871
7202638\; seat(s) 17D\; conf #A44XS5\, PRX98G\, FYYJZ4(Operated by United
Airlines flight 6256) \nBooked on http://www.americanexpress-travel.com/\;
Reference #: 7128 8086 8504\; http://www.americanexpress-travel.com/\; US
:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $699.99 \n \n \n\nTri
pIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:2d4b446e63a94ade7dab0f0e9546b2d1965f011c@tripit.com
DTSTART;VALUE=DATE:20111108
DTEND;VALUE=DATE:20111111
SUMMARY:Redwood City\, CA\, November 2011
LOCATION:Redwood City\, CA
GEO:37.485215;-122.236355
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in Redwood City\, CA from Nov 8 to Nov 1
0\, 2011\nView and/or edit details in TripIt : http://www.tripit.com/trip/
show/id/24913749\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111108T175700Z
SUMMARY:US403 PHX to SFO
LOCATION:Phoenix (PHX)
UID:item-7de7d829b2f95991de6d01c3d68f24b84770168c@tripit.com
DTSTART:20111108T154500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Flight] 11/8/2011 US Airways(US) #403 dep PHX 8:45
am MST arr SFO 9:57am PST\; John Doe\; seat(s) 21C\; conf #FJDX0
J\, I2W8HW \nBooked on http://www.americanexpress-travel.com/\; Reference
#: 4129 9623 4732\; http://www.americanexpress-travel.com/\; US:1-800-297-
2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at htt
p://www.tripit.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-1ac6982fefdd79bc5ea849785f415a6291c450b1@tripit.com
DTSTART:20111108T182700Z
DTEND:20111108T192700Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #Q0058133 \np
ickup 11/8/2011 10:27am\; dropoff 11/10/2011 6:25pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4129 9623 4732\; htt
p://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-
2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-126e584ffbefbec32a15ca503f0bdf8d3f9cc2f4@tripit.com
DTSTART:20111108T195700Z
DTEND:20111108T205700Z
LOCATION:223 TWIN DOLPHIN DR\, Redwood City\, CA\, 94065-1514
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #Q0058133 \n223 TWIN DOLPHIN DR\, Redwood City\
, CA\, 94065-1514\; tel 1.650.598.9000 \narrive 11/8/2011\; depart 11/10/2
011\; rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Refere
nce #: 4129 9623 4732\; http://www.americanexpress-travel.com/\; US:1-800-
297-2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at
http://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Sofitel San Francisco Bay
TRANSP:TRANSPARENT
UID:item-ff48c502022356ccaa862ebb61761a0de08a1ce9@tripit.com
DTSTART:20111111T015500Z
DTEND:20111111T025500Z
LOCATION:223 TWIN DOLPHIN DR\, Redwood City\, CA\, 94065-1514
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Lodging] Sofitel San Francisco Bay\; primary guest
John Doe\; conf #Q0058133 \n223 TWIN DOLPHIN DR\, Redwood City\
, CA\, 94065-1514\; tel 1.650.598.9000 \narrive 11/8/2011\; depart 11/10/2
011\; rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Refere
nce #: 4129 9623 4732\; http://www.americanexpress-travel.com/\; US:1-800-
297-2977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at
http://www.tripit.com
GEO:37.5232475;-122.261296
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Dollar Rent A Car
TRANSP:TRANSPARENT
UID:item-c0273c03ddbb68a9b05d5d43a489bc318136ca42@tripit.com
DTSTART:20111111T022500Z
DTEND:20111111T032500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Car Rental] Dollar Rent A Car\; San Francisco Inte
rnational Airport\; primary driver John Doe\; conf #Q0058133 \np
ickup 11/8/2011 10:27am\; dropoff 11/10/2011 6:25pm \nEconomy \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4129 9623 4732\; htt
p://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-
2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111111T055400Z
SUMMARY:CO496 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-3473cf9275326ac393b37859df3b04306b4849aa@tripit.com
DTSTART:20111111T035500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/24913749\n \n[Flight] 11/10/2011 Continental Airlines(CO) #496 d
ep SFO 7:55pm PST arr PHX 10:54pm MST\; John Doe\; seat(s) 26B\;
conf #FJDX0J\, I2W8HW(Operated by United Airlines flight 496) \nBooked on
http://www.americanexpress-travel.com/\; Reference #: 4129 9623 4732\; ht
tp://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582
-2716 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:4ee5ded058432990e3d8808f48ca851e04923b6d@tripit.com
DTSTART;VALUE=DATE:20111129
DTEND;VALUE=DATE:20111202
SUMMARY:Milpitas\, CA\, November 2011
LOCATION:Milpitas\, CA
GEO:37.428272;-121.906624
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in Milpitas\, CA from Nov 29 to Dec 1\,
2011\nView and/or edit details in TripIt : http://www.tripit.com/trip/show
/id/25671681\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111129T172400Z
SUMMARY:US282 PHX to SJC
LOCATION:Phoenix (PHX)
UID:item-644d5973b50d521d50e475ccf5321605d54bd0d5@tripit.com
DTSTART:20111129T152500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Flight] 11/29/2011 US Airways(US) #282 dep PHX 8:2
5am MST arr SJC 9:24am PST\; John Doe\; seat(s) 17C\; conf #DQKD
GY \nBooked on http://www.americanexpress-travel.com/\; Reference #: 4131
3301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2977\, O
utside:210-582-2716 \n \n \n\nTripIt - organize your travel at http://www.
tripit.com
GEO:37.361111;-121.925556
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-10368bbdbc9b6f26f83098500633cc4eb604c751@tripit.com
DTSTART:20111129T175400Z
DTEND:20111129T185400Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Car Rental] Alamo\; San Jose International Airport
\; primary driver John Doe\; conf #372828149COUNT \npickup 11/29
/2011 9:54am\; dropoff 12/1/2011 5:45pm \nIntermediate \nBooked on http://
www.americanexpress-travel.com/\; Reference #: 4131 3301 9911\; http://www
.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n
\n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: The Beverly Heritage Hotel
TRANSP:TRANSPARENT
UID:item-98d8638d3f1c011d03cb8f58b3a14a0f1203339b@tripit.com
DTSTART:20111129T192400Z
DTEND:20111129T202400Z
LOCATION:1820 Barber Lane\, Milpitas\, CA\, 95035
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Lodging] The Beverly Heritage Hotel\; primary gues
t John Doe\; conf #372828149COUNT \n1820 Barber Lane\, Milpitas\
, CA\, 95035\; tel 1.408.943.9080 \narrive 11/29/2011\; depart 12/1/2011\;
rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Reference #
: 4131 3301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2
977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at http
://www.tripit.com
GEO:37.4010467;-121.9116284
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111201T194400Z
SUMMARY:US273 SJC to PHX
LOCATION:San Jose (SJC)
UID:item-7b9ee9bb4edfe69743e32b33f9be55753956a883@tripit.com
DTSTART:20111201T175900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Flight] 12/1/2011 US Airways(US) #273 dep SJC 9:59
am PST arr PHX 12:44pm MST\; John Doe Ticket #0378727451156\; co
nf #EMF71T \nBooked on http://www.americanexpress-travel.com/\; Reference
#: 5133 5264 1627\; http://www.americanexpress-travel.com/\; US:1-800-297-
2977\, Outside:210-582-2716\; Total Cost: $316.69 \n \n \n\nTripIt - organ
ize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: The Beverly Heritage Hotel
TRANSP:TRANSPARENT
UID:item-f79f203072002b8f06598dcb2be0e36af17b625b@tripit.com
DTSTART:20111202T011500Z
DTEND:20111202T021500Z
LOCATION:1820 Barber Lane\, Milpitas\, CA\, 95035
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Lodging] The Beverly Heritage Hotel\; primary gues
t John Doe\; conf #372828149COUNT \n1820 Barber Lane\, Milpitas\
, CA\, 95035\; tel 1.408.943.9080 \narrive 11/29/2011\; depart 12/1/2011\;
rooms: 1 \nBooked on http://www.americanexpress-travel.com/\; Reference #
: 4131 3301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2
977\, Outside:210-582-2716 \n \n \n\nTripIt - organize your travel at http
://www.tripit.com
GEO:37.4010467;-121.9116284
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-69f526ad49fa8ca0a74486f4fc77cc3f9d23a72f@tripit.com
DTSTART:20111202T014500Z
DTEND:20111202T024500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Car Rental] Alamo\; San Jose International Airport
\; primary driver John Doe\; conf #372828149COUNT \npickup 11/29
/2011 9:54am\; dropoff 12/1/2011 5:45pm \nIntermediate \nBooked on http://
www.americanexpress-travel.com/\; Reference #: 4131 3301 9911\; http://www
.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:210-582-2716 \n
\n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111202T045900Z
SUMMARY:US288 SJC to PHX
LOCATION:San Jose (SJC)
UID:item-dab68a87c8dd49064ab0ba1dec5ba75ba46ff1d3@tripit.com
DTSTART:20111202T031500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/25671681\n \n[Flight] 12/1/2011 US Airways(US) #288 dep SJC 7:15
pm PST arr PHX 9:59pm MST\; John Doe\; seat(s) 13C\; conf #DQKDG
Y \nBooked on http://www.americanexpress-travel.com/\; Reference #: 4131 3
301 9911\; http://www.americanexpress-travel.com/\; US:1-800-297-2977\, Ou
tside:210-582-2716 \n \n \n\nTripIt - organize your travel at http://www.t
ripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:67d48ddde166a2e9bbac2cf7d93fe493b0860008@tripit.com
DTSTART;VALUE=DATE:20111213
DTEND;VALUE=DATE:20111216
SUMMARY:San Jose\, CA\, December 2011
LOCATION:San Jose\, CA
GEO:37.339386;-121.894955
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in San Jose\, CA from Dec 13 to Dec 15\,
2011\nView and/or edit details in TripIt : http://www.tripit.com/trip/sho
w/id/27037117\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111213T172400Z
SUMMARY:US282 PHX to SJC
LOCATION:Phoenix (PHX)
UID:item-2b1b9021be548a87dd335f190b60ab78c33b619d@tripit.com
DTSTART:20111213T152500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Flight] 12/13/2011 US Airways(US) #282 dep PHX 8:2
5am MST arr SJC 9:24am PST\; John Doe Ticket #0378728465928\; se
at(s) 15C\; conf #GGNV29 \nBooked on http://www.americanexpress-travel.com
/\; Reference #: 3134 0525 5102\; http://www.americanexpress-travel.com/\;
US:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $406.39 \n \n \n\n
TripIt - organize your travel at http://www.tripit.com
GEO:37.361111;-121.925556
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Advantage
TRANSP:TRANSPARENT
UID:item-619d345bb08aaef68e8767b672277243697f5bff@tripit.com
DTSTART:20111213T180000Z
DTEND:20111213T190000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Car Rental] Advantage\; San Jose International Air
port\; primary driver John Doe\; conf #F31539020E7 \npickup 12/1
3/2011 10:00am\; dropoff 12/15/2011 7:00pm \nStandard Convertible \nRefere
nce #: 3134 0526 3890 \n \n \n\nTripIt - organize your travel at http://ww
w.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Crestview Hotel:
TRANSP:TRANSPARENT
UID:item-fbe6c08e7523c82fac69b40ad1d0899f3d8d5982@tripit.com
DTSTART:20111213T192400Z
DTEND:20111213T202400Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Lodging] Crestview Hotel:\; conf #CR31342159 \ntel
650-966-8848 \narrive 12/13/2011\; depart 12/15/2011 \nBooking Rate: 153.
30 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Crestview Hotel:
TRANSP:TRANSPARENT
UID:item-7ed8b84628e650a6b37161c7825bac9e72add49f@tripit.com
DTSTART:20111216T011500Z
DTEND:20111216T021500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Lodging] Crestview Hotel:\; conf #CR31342159 \ntel
650-966-8848 \narrive 12/13/2011\; depart 12/15/2011 \nBooking Rate: 153.
30 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Advantage
TRANSP:TRANSPARENT
UID:item-623b54ebe07ffd48845f1a120a86940ce79c698b@tripit.com
DTSTART:20111216T030000Z
DTEND:20111216T040000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Car Rental] Advantage\; San Jose International Air
port\; primary driver John Doe\; conf #F31539020E7 \npickup 12/1
3/2011 10:00am\; dropoff 12/15/2011 7:00pm \nStandard Convertible \nRefere
nce #: 3134 0526 3890 \n \n \n\nTripIt - organize your travel at http://ww
w.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20111216T045900Z
SUMMARY:US288 SJC to PHX
LOCATION:San Jose (SJC)
UID:item-52481e672972d2e88d5eaa5cf49bb801562c6014@tripit.com
DTSTART:20111216T031500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27037117\n \n[Flight] 12/15/2011 US Airways(US) #288 dep SJC 7:1
5pm PST arr PHX 9:59pm MST\; John Doe Ticket #0378728465928\; se
at(s) 7B\; conf #GGNV29 \nBooked on http://www.americanexpress-travel.com/
\; Reference #: 3134 0525 5102\; http://www.americanexpress-travel.com/\;
US:1-800-297-2977\, Outside:210-582-2716\; Total Cost: $406.39 \n \n \n\nT
ripIt - organize your travel at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
UID:7299ff29daed7d5c3e2ed4acc74deec5b7942bd5@tripit.com
DTSTART;VALUE=DATE:20120103
DTEND;VALUE=DATE:20120106
SUMMARY:San Francisco\, CA\, January 2012
LOCATION:San Francisco\, CA
GEO:37.774929;-122.419415
TRANSP:TRANSPARENT
DESCRIPTION:John Doe is in San Francisco\, CA from Jan 3 to Jan
5\, 2012\nView and/or edit details in TripIt : http://www.tripit.com/trip/
show/id/27863159\nTripIt - organize your travel at http://www.tripit.com\n
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20120103T175700Z
SUMMARY:US403 PHX to SFO
LOCATION:Phoenix (PHX)
UID:item-f099e76114bf43ef3b122432579d8b40995412a7@tripit.com
DTSTART:20120103T154500Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Flight] 1/3/2012 US Airways(US) #403 dep PHX 8:45a
m MST arr SFO 9:57am PST\; John Doe Ticket #0378731791515\; conf
#FH9B72\, L4F9M5 \nBooked on http://www.americanexpress-travel.com/\; Ref
erence #: 6135 7391 6119\; http://www.americanexpress-travel.com/\; US:1-8
00-297-2977\, Outside:210-582-2716\; Total Cost: $668.39 \n \n \n\nTripIt
- organize your travel at http://www.tripit.com
GEO:37.618889;-122.375
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Pick-up Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-fae4b4b07b66fc87df125238e0aaf645106cf4f3@tripit.com
DTSTART:20120103T180000Z
DTEND:20120103T190000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Car Rental] Alamo\; San Francisco International Ai
rport\; primary driver John Doe\; conf #373525981COUNT \npickup
1/3/2012 10:00am\; dropoff 1/5/2012 6:00pm \nCompact \nReference #: 6135 7
391 6898 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-in: Grand Hotel Sunnyvale
TRANSP:TRANSPARENT
UID:item-d89a856eb9da9dfdcb4da46f42e49af3a838fcbb@tripit.com
DTSTART:20120103T195700Z
DTEND:20120103T205700Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Lodging] Grand Hotel Sunnyvale\; conf #22084SY0361
18 \ntel 1-408-7208500 \narrive 1/3/2012\; depart 1/5/2012 \nBooking Rate:
USD 169.00 \nPolicies: Guarantee to valid form of payment is required at
time of booking\; Cancel 1 day prior to arrival date to avoid penalty of 1
Nights Room Charge. Change fee may apply for early departures and changes
made to confirmed reservations.\; \n \n \n\nTripIt - organize your travel
at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Check-out: Grand Hotel Sunnyvale
TRANSP:TRANSPARENT
UID:item-6edc82f6411fd0b66f2f7f6baafa41623a8623a9@tripit.com
DTSTART:20120106T010900Z
DTEND:20120106T020900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Lodging] Grand Hotel Sunnyvale\; conf #22084SY0361
18 \ntel 1-408-7208500 \narrive 1/3/2012\; depart 1/5/2012 \nBooking Rate:
USD 169.00 \nPolicies: Guarantee to valid form of payment is required at
time of booking\; Cancel 1 day prior to arrival date to avoid penalty of 1
Nights Room Charge. Change fee may apply for early departures and changes
made to confirmed reservations.\; \n \n \n\nTripIt - organize your travel
at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
SUMMARY:Drop-off Rental Car: Alamo
TRANSP:TRANSPARENT
UID:item-58a31b96066ffd09b800af49de59a84f7b7a3a06@tripit.com
DTSTART:20120106T020000Z
DTEND:20120106T030000Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Car Rental] Alamo\; San Francisco International Ai
rport\; primary driver John Doe\; conf #373525981COUNT \npickup
1/3/2012 10:00am\; dropoff 1/5/2012 6:00pm \nCompact \nReference #: 6135 7
391 6898 \n \n \n\nTripIt - organize your travel at http://www.tripit.com
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20120101T215311Z
DTEND:20120106T050500Z
SUMMARY:CO496 SFO to PHX
LOCATION:San Francisco (SFO)
UID:item-7884351ce42d503b90ccc48c33c7c30bd4f44767@tripit.com
DTSTART:20120106T030900Z
DESCRIPTION:View and/or edit details in TripIt : http://www.tripit.com/tri
p/show/id/27863159\n \n[Flight] 1/5/2012 Continental Airlines(CO) #496 dep
SFO 7:09pm PST arr PHX 10:05pm MST\; John Doe Ticket #037873179
1515\; conf #FH9B72\, L4F9M5(Operated by United Airlines flight 496) \nBoo
ked on http://www.americanexpress-travel.com/\; Reference #: 6135 7391 611
9\; http://www.americanexpress-travel.com/\; US:1-800-297-2977\, Outside:2
10-582-2716\; Total Cost: $668.39 \n \n \n\nTripIt - organize your travel
at http://www.tripit.com
GEO:33.436111;-112.009444
END:VEVENT
END:VCALENDAR

View File

@ -1,41 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Meetup//RemoteApi//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-ORIGINAL-URL:http://www.meetup.com/events/ical/8333638/dfdba2e469216075
3404f737feace78d526ff0ce/going
X-WR-CALNAME:My Meetups
X-MS-OLK-FORCEINSPECTOROPEN:TRUE
BEGIN:VTIMEZONE
TZID:America/Phoenix
TZURL:http://tzurl.org/zoneinfo-outlook/America/Phoenix
X-LIC-LOCATION:America/Phoenix
BEGIN:STANDARD
TZOFFSETFROM:-0700
TZOFFSETTO:-0700
TZNAME:MST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20111106T155927Z
DTSTART;TZID=America/Phoenix:20111109T190000
DTEND;TZID=America/Phoenix:20111109T210000
STATUS:CONFIRMED
SUMMARY:Phoenix Drupal User Group Monthly Meetup
DESCRIPTION:Phoenix Drupal User Group\nWednesday\, November 9 at 7:00 PM\
n\nCustomizing node display with template pages in Drupal 6\n\n Jon Shee
han and Matthew Berry of the Office of Knowledge Enterprise Development
(OKED) Knowledge...\n\nDetails: http://www.meetup.com/Phoenix-Drupal-Use
r-Group/events/33627272/
CLASS:PUBLIC
CREATED:20100630T083023Z
GEO:33.56;-111.90
LOCATION:Open Source Project Tempe (1415 E University Dr. #103A\, Tempe\,
AZ 85281)
URL:http://www.meetup.com/Phoenix-Drupal-User-Group/events/33627272/
LAST-MODIFIED:20111102T213309Z
UID:event_nsmxnyppbfc@meetup.com
END:VEVENT
END:VCALENDAR

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:ownCloud Calendar 0.6.3
X-WR-CALNAME:Fête Nationale - Férié
BEGIN:VEVENT
CREATED:20090502T140513Z
DTSTAMP:20111106T124709Z
UID:FA9831E7-C238-4FEC-95E5-CD46BD466421
SUMMARY:Fête Nationale - Férié
RRULE:FREQ=YEARLY
DTSTART;VALUE=DATE:20120714
DTEND;VALUE=DATE:20120715
TRANSP:OPAQUE
SEQUENCE:5
END:VEVENT
END:VCALENDAR

View File

@ -1,23 +0,0 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:ownCloud Calendar 0.6.3
X-WR-CALNAME:Default calendar
BEGIN:VTODO
CREATED;VALUE=DATE-TIME:20130714T092804Z
UID:0aa462f13c
LAST-MODIFIED;VALUE=DATE-TIME:20130714T092804Z
DTSTAMP;VALUE=DATE-TIME:20130714T092804Z
CATEGORIES:Projets
SUMMARY:Migrer le blog
PERCENT-COMPLETE:100
COMPLETED;VALUE=DATE-TIME;TZID=Europe/Monaco:20130716T105745
END:VTODO
BEGIN:VTODO
CREATED;VALUE=DATE-TIME:20130714T092912Z
UID:5e05bbcf34
LAST-MODIFIED;VALUE=DATE-TIME:20130714T092912Z
DTSTAMP;VALUE=DATE-TIME:20130714T092912Z
SUMMARY:Créer test unitaire erreur ical
CATEGORIES:Projets
END:VTODO
END:VCALENDAR

View File

@ -1,21 +0,0 @@
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:eb9e1bd2-ceba-499f-be77-f02773954c72
SUMMARY:Event with an alarm
DESCRIPTION:This is an event with an alarm.
ORGANIZER="mailto:stomlinson@mozilla.com"
DTSTART;TZID="America/Los_Angeles":20130418T110000
DTEND;TZID="America/Los_Angeles":20130418T120000
STATUS:CONFIRMED
CLASS:PUBLIC
TRANSP:OPAQUE
LAST-MODIFIED:20130418T175632Z
DTSTAMP:20130418T175632Z
SEQUENCE:3
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;RELATED=START:-PT5M
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR

1151
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@
"test:prettier": "prettier --check **/*.{js,css,json,md,yml}",
"test:js": "eslint *.js js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --quiet",
"test:css": "stylelint css/main.css modules/default/**/*.css --config .stylelintrc.json",
"test:calendar": "node ./modules/default/calendar/debug.js",
"config:check": "node js/check_config.js",
"lint:prettier": "prettier --write **/*.{js,css,json,md,yml}",
"lint:js": "eslint *.js js/**/*.js modules/default/**/*.js clientonly/*.js serveronly/*.js translations/*.js vendor/*.js tests/**/*.js config/* --config .eslintrc.json --fix",
@ -46,7 +47,7 @@
"current-week-number": "^1.0.7",
"danger": "^3.1.3",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-prettier": "^3.1.4",
"http-auth": "^3.2.3",
"husky": "^4.2.5",
"jsdom": "^11.6.2",
@ -56,8 +57,8 @@
"prettier": "^2.0.5",
"pretty-quick": "^2.0.1",
"spectron": "^8.0.0",
"stylelint": "^13.3.3",
"stylelint-config-prettier": "^8.0.1",
"stylelint": "^13.6.1",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-standard": "^20.0.0",
"stylelint-prettier": "^1.1.2"
},
@ -67,16 +68,17 @@
"dependencies": {
"colors": "^1.1.2",
"console-stamp": "^0.2.9",
"eslint": "^6.8.0",
"eslint": "^7.3.0",
"express": "^4.16.2",
"express-ipfilter": "^1.0.1",
"feedme": "latest",
"helmet": "^3.21.2",
"ical": "^0.8.0",
"iconv-lite": "latest",
"lodash": "^4.17.15",
"module-alias": "^2.2.2",
"moment": "latest",
"request": "^2.88.0",
"request": "^2.88.2",
"rrule": "^2.6.2",
"rrule-alt": "^2.2.8",
"simple-git": "^1.85.0",