You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@any23.apache.org by ha...@apache.org on 2018/08/27 17:14:15 UTC

[1/3] any23 git commit: ANY23-390 implement ICal, JCal, and XCal extractors

Repository: any23
Updated Branches:
  refs/heads/master f3e66003a -> 19d85f2fc


ANY23-390 implement ICal, JCal, and XCal extractors


Project: http://git-wip-us.apache.org/repos/asf/any23/repo
Commit: http://git-wip-us.apache.org/repos/asf/any23/commit/54a92960
Tree: http://git-wip-us.apache.org/repos/asf/any23/tree/54a92960
Diff: http://git-wip-us.apache.org/repos/asf/any23/diff/54a92960

Branch: refs/heads/master
Commit: 54a92960ac2fda9510041b6886eb7259a9b1220b
Parents: f3e6600
Author: Hans <fi...@gmail.com>
Authored: Tue Aug 21 11:37:35 2018 -0500
Committer: Hans <fi...@gmail.com>
Committed: Tue Aug 21 11:37:35 2018 -0500

----------------------------------------------------------------------
 core/pom.xml                                    |   5 +
 .../calendar/BaseCalendarExtractor.java         | 222 +++++++++++++++++++
 .../any23/extractor/calendar/ICalExtractor.java |  41 ++++
 .../calendar/ICalExtractorFactory.java          |  47 ++++
 .../any23/extractor/calendar/JCalExtractor.java |  40 ++++
 .../calendar/JCalExtractorFactory.java          |  48 ++++
 .../any23/extractor/calendar/XCalExtractor.java |  41 ++++
 .../calendar/XCalExtractorFactory.java          |  47 ++++
 .../any23/extractor/calendar/package-info.java  |  21 ++
 pom.xml                                         |   5 +
 10 files changed, 517 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 49a1bfc..0fb5b28 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -93,6 +93,11 @@
     </dependency>
     <!-- END: httpcomponents -->
 
+    <dependency>
+      <groupId>net.sf.biweekly</groupId>
+      <artifactId>biweekly</artifactId>
+    </dependency>
+
     <!-- BEGIN: Tika -->
     <dependency>
       <groupId>org.apache.tika</groupId>

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java b/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java
new file mode 100644
index 0000000..74c3e10
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import biweekly.ICalDataType;
+import biweekly.ICalVersion;
+import biweekly.ICalendar;
+import biweekly.component.ICalComponent;
+import biweekly.io.ParseWarning;
+import biweekly.io.SkipMeException;
+import biweekly.io.StreamReader;
+import biweekly.io.TimezoneInfo;
+import biweekly.io.WriteContext;
+import biweekly.io.scribe.ScribeIndex;
+import biweekly.io.scribe.component.ICalComponentScribe;
+import biweekly.io.scribe.property.ICalPropertyScribe;
+import biweekly.property.ICalProperty;
+import com.github.mangstadt.vinnie.io.VObjectPropertyValues;
+import org.apache.any23.extractor.ExtractionContext;
+import org.apache.any23.extractor.ExtractionException;
+import org.apache.any23.extractor.ExtractionParameters;
+import org.apache.any23.extractor.ExtractionResult;
+import org.apache.any23.extractor.Extractor;
+import org.apache.any23.extractor.IssueReport;
+import org.apache.any23.vocab.ICAL;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.IRI;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.model.vocabulary.RDF;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * @author Hans Brende (hansbrende@apache.org)
+ */
+abstract class BaseCalendarExtractor implements Extractor.ContentExtractor {
+
+    @Override
+    public void setStopAtFirstError(boolean b) {
+        //unsupported
+    }
+
+    private static final ValueFactory f = SimpleValueFactory.getInstance();
+    private static final ICAL vICAL = ICAL.getInstance();
+
+    abstract StreamReader reader(InputStream inputStream);
+
+    @Override
+    public final void run(ExtractionParameters extractionParameters, ExtractionContext extractionContext, InputStream inputStream,
+                          ExtractionResult extractionResult) throws IOException, ExtractionException {
+        ScribeIndex index = new ScribeIndex();
+        try (StreamReader reader = reader(inputStream)) {
+            ICalendar cal;
+            while ((cal = reader.readNext()) != null) {
+                for (ParseWarning warning : reader.getWarnings()) {
+                    String message = warning.getMessage();
+                    Integer lineNumber = warning.getLineNumber();
+                    if (lineNumber == null) {
+                        extractionResult.notifyIssue(IssueReport.IssueLevel.WARNING, message, -1, -1);
+                    } else {
+                        extractionResult.notifyIssue(IssueReport.IssueLevel.WARNING, message, lineNumber, -1);
+                    }
+                }
+
+                BNode calNode = f.createBNode();
+                extractionResult.writeTriple(calNode, RDF.TYPE, vICAL.Vcalendar);
+                extract(index, cal.getTimezoneInfo(), calNode, cal, extractionResult);
+            }
+        } catch (Exception e) {
+            extractionResult.notifyIssue(IssueReport.IssueLevel.FATAL, toString(e), -1, -1);
+        }
+    }
+
+    private static String toString(Throwable th) {
+        StringWriter writer = new StringWriter();
+        try (PrintWriter pw = new PrintWriter(writer)) {
+            th.printStackTrace(pw);
+        }
+        String string = writer.toString();
+        if (string.length() > 200) {
+            return string.substring(0, 197) + "...";
+        }
+        return string;
+    }
+
+
+    private static String localNameOfType(String typeName) {
+        if (typeName.isEmpty()) {
+            return "";
+        }
+        int ind = Character.charCount(typeName.codePointAt(0));
+        return typeName.substring(0, ind).toUpperCase(Locale.ENGLISH) + typeName.substring(ind);
+    }
+
+    private static String localNameOfProperty(String propertyName) {
+        String[] nameComponents = propertyName.split("-");
+        StringBuilder sb = new StringBuilder(propertyName.length());
+        sb.append(nameComponents[0]);
+        for (int i = 1, len = nameComponents.length; i < len; i++) {
+            sb.append(localNameOfType(nameComponents[i]));
+        }
+        return sb.toString();
+    }
+
+    private static IRI type(ICalComponentScribe<?> scribe, ExtractionResult result) {
+        if (scribe == null) {
+            return null;
+        }
+        String originalName = scribe.getComponentName();
+        String name = originalName.toLowerCase(Locale.ENGLISH);
+
+        if (name.startsWith("x-")) {
+            //non-standard class
+            return f.createIRI(ICAL.NS, "X-" + localNameOfType(name.substring(2)));
+        }
+
+        name = localNameOfType(name);
+
+        try {
+            return Objects.requireNonNull(vICAL.getClass(name));
+        } catch (RuntimeException e) {
+            IRI iri = f.createIRI(ICAL.NS, name);
+            result.notifyIssue(IssueReport.IssueLevel.ERROR,
+                    "class " + iri + " (" + originalName + ") not defined in " + ICAL.class.getName(),
+                    -1, -1);
+            return iri;
+        }
+    }
+
+    private static IRI predicate(ICalPropertyScribe<?> scribe, ExtractionResult result) {
+        if (scribe == null) {
+            return null;
+        }
+        String originalName = scribe.getPropertyName(ICalVersion.V2_0);
+        String name = originalName.toLowerCase(Locale.ENGLISH);
+        if (name.startsWith("x-")) {
+            //non-standard property
+            return f.createIRI(ICAL.NS, "x-" + localNameOfProperty(name.substring(2)));
+        }
+
+        name = localNameOfProperty(name);
+
+        try {
+            return Objects.requireNonNull(vICAL.getProperty(name));
+        } catch (RuntimeException e) {
+            IRI iri = f.createIRI(ICAL.NS, name);
+            result.notifyIssue(IssueReport.IssueLevel.ERROR,
+                    "property " + iri + " (" + originalName + ") not defined in " + ICAL.class.getName(),
+                    -1, -1);
+            return iri;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends ICalProperty> Value value(ICalPropertyScribe<T> scribe, ICalProperty property, TimezoneInfo info) {
+        try {
+            T prop = (T)property;
+            String text = scribe.writeText(prop, new WriteContext(ICalVersion.V2_0, info, null));
+            if (text == null) {
+                return null;
+            }
+            text = VObjectPropertyValues.unescape(text);
+            ICalDataType dataType = scribe.dataType(prop, ICalVersion.V2_0);
+            if (ICalDataType.URI.equals(dataType) || ICalDataType.URL.equals(dataType)) {
+                try {
+                    return f.createIRI(text.trim());
+                } catch (IllegalArgumentException e) {
+                    //ignore
+                }
+            }
+            return f.createLiteral(text);
+        } catch (SkipMeException e) {
+            return null;
+        }
+    }
+
+    private static void extract(ScribeIndex index, TimezoneInfo info, BNode node, ICalComponent component, ExtractionResult extractionResult) {
+        for (ICalProperty property : component.getProperties().values()) {
+            ICalPropertyScribe<?> scribe = index.getPropertyScribe(property);
+            IRI predicate = predicate(scribe, extractionResult);
+            if (predicate != null) {
+                Value value = value(scribe, property, info);
+                if (value != null) {
+                    extractionResult.writeTriple(node, predicate, value);
+                }
+            }
+        }
+        for (ICalComponent child : component.getComponents().values()) {
+            BNode childNode = f.createBNode();
+            extractionResult.writeTriple(node, vICAL.component, childNode);
+            IRI childType = type(index.getComponentScribe(child), extractionResult);
+            if (childType != null) {
+                extractionResult.writeTriple(childNode, RDF.TYPE, childType);
+            }
+            extract(index, info, childNode, child, extractionResult);
+        }
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractor.java b/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractor.java
new file mode 100644
index 0000000..adb2d7d
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractor.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import biweekly.io.StreamReader;
+import biweekly.io.text.ICalReader;
+import org.apache.any23.extractor.ExtractorDescription;
+
+import java.io.InputStream;
+
+/**
+ * @author Hans Brende (hansbrende@apache.org)
+ */
+public class ICalExtractor extends BaseCalendarExtractor {
+
+    @Override
+    StreamReader reader(InputStream inputStream) {
+        return new ICalReader(inputStream);
+    }
+
+    @Override
+    public ExtractorDescription getDescription() {
+        return ICalExtractorFactory.getDescriptionInstance();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractorFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractorFactory.java b/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractorFactory.java
new file mode 100644
index 0000000..8a25dcb
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/ICalExtractorFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import org.apache.any23.extractor.ExtractorDescription;
+import org.apache.any23.extractor.SimpleExtractorFactory;
+import org.apache.any23.rdf.Prefixes;
+
+import java.util.Collections;
+
+/**
+ * @author Hans Brende (hansbrende@apache.org)
+ */
+public class ICalExtractorFactory extends SimpleExtractorFactory<ICalExtractor> {
+
+    private static final String NAME = "ical";
+    private static final Prefixes PREFIXES = null;
+    private static final ExtractorDescription descriptionInstance = new ICalExtractorFactory();
+
+    public ICalExtractorFactory() {
+        super(NAME, PREFIXES, Collections.singletonList("text/calendar"), null);
+    }
+
+    public static ExtractorDescription getDescriptionInstance() {
+        return descriptionInstance;
+    }
+
+    @Override
+    public ICalExtractor createExtractor() {
+        return new ICalExtractor();
+    }
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractor.java b/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractor.java
new file mode 100644
index 0000000..32dc73b
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractor.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import biweekly.io.StreamReader;
+import biweekly.io.json.JCalReader;
+import org.apache.any23.extractor.ExtractorDescription;
+
+import java.io.InputStream;
+
+/**
+ * @author Hans Brende (hansbrende@apache.org)
+ */
+public class JCalExtractor extends BaseCalendarExtractor {
+
+    @Override
+    StreamReader reader(InputStream inputStream) {
+        return new JCalReader(inputStream);
+    }
+
+    @Override
+    public ExtractorDescription getDescription() {
+        return JCalExtractorFactory.getDescriptionInstance();
+    }
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractorFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractorFactory.java b/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractorFactory.java
new file mode 100644
index 0000000..2344bab
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/JCalExtractorFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import org.apache.any23.extractor.ExtractorDescription;
+import org.apache.any23.extractor.SimpleExtractorFactory;
+import org.apache.any23.rdf.Prefixes;
+
+import java.util.Collections;
+
+/**
+ * @author Hans Brende (hansbrende@apache.org)
+ */
+public class JCalExtractorFactory extends SimpleExtractorFactory<JCalExtractor> {
+
+    private static final String NAME = "jcal";
+    private static final Prefixes PREFIXES = null;
+    private static final ExtractorDescription descriptionInstance = new JCalExtractorFactory();
+
+    public JCalExtractorFactory() {
+        super(NAME, PREFIXES, Collections.singletonList("application/calendar+json"), null);
+    }
+
+    public static ExtractorDescription getDescriptionInstance() {
+        return descriptionInstance;
+    }
+
+    @Override
+    public JCalExtractor createExtractor() {
+        return new JCalExtractor();
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractor.java b/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractor.java
new file mode 100644
index 0000000..555b4f7
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractor.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import biweekly.io.StreamReader;
+import biweekly.io.xml.XCalReader;
+import org.apache.any23.extractor.ExtractorDescription;
+
+import java.io.InputStream;
+
+/**
+ * @author Hans Brende (hansbrende@apache.org)
+ */
+public class XCalExtractor extends BaseCalendarExtractor {
+
+    @Override
+    StreamReader reader(InputStream inputStream) {
+        return new XCalReader(inputStream);
+    }
+
+    @Override
+    public ExtractorDescription getDescription() {
+        return XCalExtractorFactory.getDescriptionInstance();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractorFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractorFactory.java b/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractorFactory.java
new file mode 100644
index 0000000..6519b1f
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/XCalExtractorFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import org.apache.any23.extractor.ExtractorDescription;
+import org.apache.any23.extractor.SimpleExtractorFactory;
+import org.apache.any23.rdf.Prefixes;
+
+import java.util.Collections;
+
+/**
+ * @author Hans Brende (hansbrende@apache.org)
+ */
+public class XCalExtractorFactory extends SimpleExtractorFactory<XCalExtractor> {
+
+    private static final String NAME = "xcal";
+    private static final Prefixes PREFIXES = null;
+    private static final ExtractorDescription descriptionInstance = new XCalExtractorFactory();
+
+    public XCalExtractorFactory() {
+        super(NAME, PREFIXES, Collections.singletonList("application/calendar+xml"), null);
+    }
+
+    public static ExtractorDescription getDescriptionInstance() {
+        return descriptionInstance;
+    }
+
+    @Override
+    public XCalExtractor createExtractor() {
+        return new XCalExtractor();
+    }
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/core/src/main/java/org/apache/any23/extractor/calendar/package-info.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/package-info.java b/core/src/main/java/org/apache/any23/extractor/calendar/package-info.java
new file mode 100644
index 0000000..50d731a
--- /dev/null
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/**
+ * This package contains extractors for various calendar serialization formats.
+ */
+package org.apache.any23.extractor.calendar;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/any23/blob/54a92960/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index ce2ee5d..2aa6278 100644
--- a/pom.xml
+++ b/pom.xml
@@ -372,6 +372,11 @@
         <artifactId>jsoup</artifactId>
         <version>1.11.3</version>
       </dependency>
+      <dependency>
+        <groupId>net.sf.biweekly</groupId>
+        <artifactId>biweekly</artifactId>
+        <version>0.6.2</version>
+      </dependency>
 
       <!-- BEGIN: Tika -->
       <dependency>


[2/3] any23 git commit: ANY23-390 ical tests, support for params, datatypes, & structured values

Posted by ha...@apache.org.
http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.xml/rfc6321-example1-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.xml/rfc6321-example1-expected.nquads b/test-resources/src/test/resources/calendar.xml/rfc6321-example1-expected.nquads
new file mode 100644
index 0000000..779b6de
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.xml/rfc6321-example1-expected.nquads
@@ -0,0 +1,26 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu4bdubx2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu4bdubx2 <http://www.w3.org/2002/12/cal/icaltzd#calscale> "GREGORIAN" <http://bob.example.com/> .
+_:node1clu4bdubx2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//Example Inc.//Example Calendar//EN" <http://bob.example.com/> .
+_:node1clu4bdubx2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu4bdubx3 <http://bob.example.com/> .
+_:node1clu4bdubx3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu4bdubx3 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "2008-02-05T19:12:24Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4bdubx3 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2008-10-06"^^<http://www.w3.org/2001/XMLSchema#date> <http://bob.example.com/> .
+_:node1clu4bdubx3 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Planning meeting" <http://bob.example.com/> .
+_:node1clu4bdubx3 <http://www.w3.org/2002/12/cal/icaltzd#uid> "4088E990AD89CB3DBB484909" <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.xml/rfc6321-example1.xml
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.xml/rfc6321-example1.xml b/test-resources/src/test/resources/calendar.xml/rfc6321-example1.xml
new file mode 100755
index 0000000..2c1f069
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.xml/rfc6321-example1.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
+	<vcalendar>
+		<properties>
+			<calscale>
+				<text>GREGORIAN</text>
+			</calscale>
+			<prodid>
+				<text>-//Example Inc.//Example Calendar//EN</text>
+			</prodid>
+			<version>
+				<text>2.0</text>
+			</version>
+		</properties>
+		<components>
+			<vevent>
+				<properties>
+					<dtstamp>
+						<date-time>2008-02-05T19:12:24Z</date-time>
+					</dtstamp>
+					<dtstart>
+						<date>2008-10-06</date>
+					</dtstart>
+					<summary>
+						<text>Planning meeting</text>
+					</summary>
+					<uid>
+						<text>4088E990AD89CB3DBB484909</text>
+					</uid>
+				</properties>
+			</vevent>
+		</components>
+	</vcalendar>
+</icalendar>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.xml/rfc6321-example2-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.xml/rfc6321-example2-expected.nquads b/test-resources/src/test/resources/calendar.xml/rfc6321-example2-expected.nquads
new file mode 100644
index 0000000..70ebe15
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.xml/rfc6321-example2-expected.nquads
@@ -0,0 +1,75 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu4e12ox2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu4e12ox2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//Example Inc.//Example Client//EN" <http://bob.example.com/> .
+_:node1clu4e12ox2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu4e12ox3 <http://bob.example.com/> .
+_:node1clu4e12ox3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vtimezone> <http://bob.example.com/> .
+_:node1clu4e12ox3 <http://www.w3.org/2002/12/cal/icaltzd#lastModified> "2004-01-10T03:28:45Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox3 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu4e12ox3 <http://www.w3.org/2002/12/cal/icaltzd#daylight> _:node1clu4e12ox4 <http://bob.example.com/> .
+_:node1clu4e12ox4 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2000-04-04T02:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox4 <http://www.w3.org/2002/12/cal/icaltzd#rrule> _:node1clu4e12ox5 <http://bob.example.com/> .
+_:node1clu4e12ox5 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_RECUR> <http://bob.example.com/> .
+_:node1clu4e12ox5 <http://www.w3.org/2002/12/cal/icaltzd#freq> "YEARLY" <http://bob.example.com/> .
+_:node1clu4e12ox5 <http://www.w3.org/2002/12/cal/icaltzd#byday> "1SU" <http://bob.example.com/> .
+_:node1clu4e12ox5 <http://www.w3.org/2002/12/cal/icaltzd#bymonth> "4"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu4e12ox4 <http://www.w3.org/2002/12/cal/icaltzd#tzname> "EDT" <http://bob.example.com/> .
+_:node1clu4e12ox4 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetfrom> "-05:00" <http://bob.example.com/> .
+_:node1clu4e12ox4 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetto> "-04:00" <http://bob.example.com/> .
+_:node1clu4e12ox3 <http://www.w3.org/2002/12/cal/icaltzd#standard> _:node1clu4e12ox6 <http://bob.example.com/> .
+_:node1clu4e12ox6 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2000-10-26T02:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox6 <http://www.w3.org/2002/12/cal/icaltzd#rrule> _:node1clu4e12ox7 <http://bob.example.com/> .
+_:node1clu4e12ox7 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_RECUR> <http://bob.example.com/> .
+_:node1clu4e12ox7 <http://www.w3.org/2002/12/cal/icaltzd#freq> "YEARLY" <http://bob.example.com/> .
+_:node1clu4e12ox7 <http://www.w3.org/2002/12/cal/icaltzd#byday> "-1SU" <http://bob.example.com/> .
+_:node1clu4e12ox7 <http://www.w3.org/2002/12/cal/icaltzd#bymonth> "10"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu4e12ox6 <http://www.w3.org/2002/12/cal/icaltzd#tzname> "EST" <http://bob.example.com/> .
+_:node1clu4e12ox6 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetfrom> "-04:00" <http://bob.example.com/> .
+_:node1clu4e12ox6 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetto> "-05:00" <http://bob.example.com/> .
+_:node1clu4e12ox2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu4e12ox8 <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "2006-02-06T00:11:21Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> _:node1clu4e12ox9 <http://bob.example.com/> .
+_:node1clu4e12ox9 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu4e12ox9 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2006-01-02T12:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#duration> "PT1H"^^<http://www.w3.org/2001/XMLSchema#duration> <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#rrule> _:node1clu4e12ox10 <http://bob.example.com/> .
+_:node1clu4e12ox10 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_RECUR> <http://bob.example.com/> .
+_:node1clu4e12ox10 <http://www.w3.org/2002/12/cal/icaltzd#freq> "DAILY" <http://bob.example.com/> .
+_:node1clu4e12ox10 <http://www.w3.org/2002/12/cal/icaltzd#count> "5"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#rdate> _:node1clu4e12ox11 <http://bob.example.com/> .
+_:node1clu4e12ox11 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu4e12ox11 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:node1clu4e12ox12 <http://bob.example.com/> .
+_:node1clu4e12ox12 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_PERIOD> <http://bob.example.com/> .
+_:node1clu4e12ox12 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2006-01-02T15:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox12 <http://www.w3.org/2002/12/cal/icaltzd#duration> "PT2H"^^<http://www.w3.org/2001/XMLSchema#duration> <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Event #2" <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#description> "We are having a meeting all this week at 12pm for one hour, with an additional meeting on the first day 2 hours long.\nPlease bring your own lunch for the 12 pm meetings." <http://bob.example.com/> .
+_:node1clu4e12ox8 <http://www.w3.org/2002/12/cal/icaltzd#uid> "00959BC664CA650E933C892C@example.com" <http://bob.example.com/> .
+_:node1clu4e12ox2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu4e12ox13 <http://bob.example.com/> .
+_:node1clu4e12ox13 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu4e12ox13 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "2006-02-06T00:11:21Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox13 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> _:node1clu4e12ox14 <http://bob.example.com/> .
+_:node1clu4e12ox14 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu4e12ox14 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2006-01-04T14:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox13 <http://www.w3.org/2002/12/cal/icaltzd#duration> "PT1H"^^<http://www.w3.org/2001/XMLSchema#duration> <http://bob.example.com/> .
+_:node1clu4e12ox13 <http://www.w3.org/2002/12/cal/icaltzd#recurrenceId> _:node1clu4e12ox15 <http://bob.example.com/> .
+_:node1clu4e12ox15 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu4e12ox15 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2006-01-04T12:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu4e12ox13 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Event #2 bis" <http://bob.example.com/> .
+_:node1clu4e12ox13 <http://www.w3.org/2002/12/cal/icaltzd#uid> "00959BC664CA650E933C892C@example.com" <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.xml/rfc6321-example2.xml
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.xml/rfc6321-example2.xml b/test-resources/src/test/resources/calendar.xml/rfc6321-example2.xml
new file mode 100755
index 0000000..adcc49e
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.xml/rfc6321-example2.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<icalendar xmlns="urn:ietf:params:xml:ns:icalendar-2.0">
+	<vcalendar>
+		<properties>
+			<prodid>
+				<text>-//Example Inc.//Example Client//EN</text>
+			</prodid>
+			<version>
+				<text>2.0</text>
+			</version>
+		</properties>
+		<components>
+			<vevent>
+				<properties>
+					<dtstamp>
+						<date-time>2006-02-06T00:11:21Z</date-time>
+					</dtstamp>
+					<dtstart>
+						<parameters>
+							<tzid>
+								<text>US/Eastern</text>
+							</tzid>
+						</parameters>
+						<date-time>2006-01-02T12:00:00</date-time>
+					</dtstart>
+					<duration>
+						<duration>PT1H</duration>
+					</duration>
+					<rrule>
+						<recur>
+							<freq>DAILY</freq>
+							<count>5</count>
+						</recur>
+					</rrule>
+					<rdate>
+						<parameters>
+							<tzid>
+								<text>US/Eastern</text>
+							</tzid>
+						</parameters>
+						<period>
+							<start>2006-01-02T15:00:00</start>
+							<duration>PT2H</duration>
+						</period>
+					</rdate>
+					<summary>
+						<text>Event #2</text>
+					</summary>
+					<description>
+						<text>We are having a meeting all this week at 12pm for one hour, with an additional meeting on the first day 2 hours long.&#x0a;Please bring your own lunch for the 12 pm meetings.</text>
+					</description>
+					<uid>
+						<text>00959BC664CA650E933C892C@example.com</text>
+					</uid>
+				</properties>
+			</vevent>
+			<vevent>
+				<properties>
+					<dtstamp>
+						<date-time>2006-02-06T00:11:21Z</date-time>
+					</dtstamp>
+					<dtstart>
+						<parameters>
+							<tzid>
+								<text>US/Eastern</text>
+							</tzid>
+						</parameters>
+						<date-time>2006-01-04T14:00:00</date-time>
+					</dtstart>
+					<duration>
+						<duration>PT1H</duration>
+					</duration>
+					<recurrence-id>
+						<parameters>
+							<tzid>
+								<text>US/Eastern</text>
+							</tzid>
+						</parameters>
+						<date-time>2006-01-04T12:00:00</date-time>
+					</recurrence-id>
+					<summary>
+						<text>Event #2 bis</text>
+					</summary>
+					<uid>
+						<text>00959BC664CA650E933C892C@example.com</text>
+					</uid>
+				</properties>
+			</vevent>
+			<vtimezone>
+				<properties>
+					<last-modified>
+						<date-time>2004-01-10T03:28:45Z</date-time>
+					</last-modified>
+					<tzid>
+						<text>US/Eastern</text>
+					</tzid>
+				</properties>
+				<components>
+					<daylight>
+						<properties>
+							<dtstart>
+								<date-time>2000-04-04T02:00:00</date-time>
+							</dtstart>
+							<rrule>
+								<recur>
+									<freq>YEARLY</freq>
+									<byday>1SU</byday>
+									<bymonth>4</bymonth>
+								</recur>
+							</rrule>
+							<tzname>
+								<text>EDT</text>
+							</tzname>
+							<tzoffsetfrom>
+								<utc-offset>-05:00</utc-offset>
+							</tzoffsetfrom>
+							<tzoffsetto>
+								<utc-offset>-04:00</utc-offset>
+							</tzoffsetto>
+						</properties>
+					</daylight>
+					<standard>
+						<properties>
+							<dtstart>
+								<date-time>2000-10-26T02:00:00</date-time>
+							</dtstart>
+							<rrule>
+								<recur>
+									<freq>YEARLY</freq>
+									<byday>-1SU</byday>
+									<bymonth>10</bymonth>
+								</recur>
+							</rrule>
+							<tzname>
+								<text>EST</text>
+							</tzname>
+							<tzoffsetfrom>
+								<utc-offset>-04:00</utc-offset>
+							</tzoffsetfrom>
+							<tzoffsetto>
+								<utc-offset>-05:00</utc-offset>
+							</tzoffsetto>
+						</properties>
+					</standard>
+				</components>
+			</vtimezone>
+		</components>
+	</vcalendar>
+</icalendar>
\ No newline at end of file


[3/3] any23 git commit: ANY23-390 ical tests, support for params, datatypes, & structured values

Posted by ha...@apache.org.
ANY23-390 ical tests, support for params, datatypes, & structured values


Project: http://git-wip-us.apache.org/repos/asf/any23/repo
Commit: http://git-wip-us.apache.org/repos/asf/any23/commit/19d85f2f
Tree: http://git-wip-us.apache.org/repos/asf/any23/tree/19d85f2f
Diff: http://git-wip-us.apache.org/repos/asf/any23/diff/19d85f2f

Branch: refs/heads/master
Commit: 19d85f2fc84b4431228b4978c0b1419b758aa203
Parents: 54a9296
Author: Hans <fi...@gmail.com>
Authored: Mon Aug 27 11:59:24 2018 -0500
Committer: Hans <fi...@gmail.com>
Committed: Mon Aug 27 12:06:50 2018 -0500

----------------------------------------------------------------------
 .../main/java/org/apache/any23/vocab/ICAL.java  |   9 +
 .../calendar/BaseCalendarExtractor.java         | 420 ++++++++++++++++---
 .../calendar/BaseCalendarExtractorTest.java     |  98 +++++
 .../extractor/calendar/ICalExtractorTest.java   |  67 +++
 .../extractor/calendar/JCalExtractorTest.java   |  46 ++
 .../extractor/calendar/XCalExtractorTest.java   |  46 ++
 .../apache/any23/vocab/RDFSchemaUtilsTest.java  |   4 +-
 .../rfc7265-example1-expected.nquads            |  26 ++
 .../calendar.json/rfc7265-example1.json         |  18 +
 .../rfc7265-example2-expected.nquads            |  75 ++++
 .../calendar.json/rfc7265-example2.json         |  96 +++++
 .../rfc5545-example1-expected.nquads            |  30 ++
 .../calendar.text/rfc5545-example1.ics          |  17 +
 .../rfc5545-example2-expected.nquads            |  55 +++
 .../calendar.text/rfc5545-example2.ics          |  34 ++
 .../rfc5545-example3-expected.nquads            |  40 ++
 .../calendar.text/rfc5545-example3.ics          |  22 +
 .../rfc5545-example4-expected.nquads            |  40 ++
 .../calendar.text/rfc5545-example4.ics          |  22 +
 .../rfc5545-example5-expected.nquads            |  30 ++
 .../calendar.text/rfc5545-example5.ics          |  23 +
 .../rfc5545-example6-expected.nquads            |  37 ++
 .../calendar.text/rfc5545-example6.ics          |  13 +
 .../rfc6321-example1-expected.nquads            |  26 ++
 .../resources/calendar.xml/rfc6321-example1.xml |  34 ++
 .../rfc6321-example2-expected.nquads            |  75 ++++
 .../resources/calendar.xml/rfc6321-example2.xml | 149 +++++++
 27 files changed, 1488 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/api/src/main/java/org/apache/any23/vocab/ICAL.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/any23/vocab/ICAL.java b/api/src/main/java/org/apache/any23/vocab/ICAL.java
index 783d668..81bae3f 100644
--- a/api/src/main/java/org/apache/any23/vocab/ICAL.java
+++ b/api/src/main/java/org/apache/any23/vocab/ICAL.java
@@ -29,6 +29,11 @@ public class ICAL extends Vocabulary {
      */
     public static final String NS = "http://www.w3.org/2002/12/cal/icaltzd#";
 
+    /**
+     * Recommended prefix for the ICAL namespace
+     */
+    public static final String PREFIX = "ical";
+
     private static final class InstanceHolder {
         private static final ICAL instance = new ICAL();
     }
@@ -54,6 +59,8 @@ public class ICAL extends Vocabulary {
 
     public final IRI Value_DATE        = createClass("Value_DATE");
 
+    public final IRI Value_DATE_TIME   = createClass("Value_DATE-TIME");
+
     public final IRI Value_DURATION    = createClass("Value_DURATION");
 
     public final IRI Value_PERIOD      = createClass("Value_PERIOD");
@@ -191,6 +198,8 @@ public class ICAL extends Vocabulary {
 
     public final IRI byyearday = createProperty("byyearday");
 
+    public final IRI wkst = createProperty("wkst");
+
     /**
      * value type: TEXTThis IRI defines the calendar scale used for the calendar
      * information specified in the iCalendar object..

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java b/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java
index 74c3e10..258006f 100644
--- a/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java
+++ b/core/src/main/java/org/apache/any23/extractor/calendar/BaseCalendarExtractor.java
@@ -21,16 +21,23 @@ import biweekly.ICalDataType;
 import biweekly.ICalVersion;
 import biweekly.ICalendar;
 import biweekly.component.ICalComponent;
+import biweekly.component.VTimezone;
 import biweekly.io.ParseWarning;
 import biweekly.io.SkipMeException;
 import biweekly.io.StreamReader;
+import biweekly.io.TimezoneAssignment;
 import biweekly.io.TimezoneInfo;
 import biweekly.io.WriteContext;
+import biweekly.io.json.JCalValue;
+import biweekly.io.json.JsonValue;
 import biweekly.io.scribe.ScribeIndex;
-import biweekly.io.scribe.component.ICalComponentScribe;
 import biweekly.io.scribe.property.ICalPropertyScribe;
+import biweekly.parameter.Encoding;
+import biweekly.parameter.ICalParameters;
+import biweekly.property.Geo;
 import biweekly.property.ICalProperty;
-import com.github.mangstadt.vinnie.io.VObjectPropertyValues;
+import biweekly.util.DateTimeComponents;
+import biweekly.util.ICalDateFormat;
 import org.apache.any23.extractor.ExtractionContext;
 import org.apache.any23.extractor.ExtractionException;
 import org.apache.any23.extractor.ExtractionParameters;
@@ -38,19 +45,34 @@ import org.apache.any23.extractor.ExtractionResult;
 import org.apache.any23.extractor.Extractor;
 import org.apache.any23.extractor.IssueReport;
 import org.apache.any23.vocab.ICAL;
+import org.apache.commons.lang.StringUtils;
 import org.eclipse.rdf4j.model.BNode;
 import org.eclipse.rdf4j.model.IRI;
 import org.eclipse.rdf4j.model.Value;
 import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.datatypes.XMLDatatypeUtil;
 import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
 import org.eclipse.rdf4j.model.vocabulary.RDF;
+import org.eclipse.rdf4j.model.vocabulary.XMLSchema;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.ZoneOffset;
+import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @author Hans Brende (hansbrende@apache.org)
@@ -69,7 +91,11 @@ abstract class BaseCalendarExtractor implements Extractor.ContentExtractor {
 
     @Override
     public final void run(ExtractionParameters extractionParameters, ExtractionContext extractionContext, InputStream inputStream,
-                          ExtractionResult extractionResult) throws IOException, ExtractionException {
+                          ExtractionResult result) throws IOException, ExtractionException {
+        result.writeNamespace(RDF.PREFIX, RDF.NAMESPACE);
+        result.writeNamespace(ICAL.PREFIX, ICAL.NS);
+        result.writeNamespace(XMLSchema.PREFIX, XMLSchema.NAMESPACE);
+
         ScribeIndex index = new ScribeIndex();
         try (StreamReader reader = reader(inputStream)) {
             ICalendar cal;
@@ -78,18 +104,19 @@ abstract class BaseCalendarExtractor implements Extractor.ContentExtractor {
                     String message = warning.getMessage();
                     Integer lineNumber = warning.getLineNumber();
                     if (lineNumber == null) {
-                        extractionResult.notifyIssue(IssueReport.IssueLevel.WARNING, message, -1, -1);
+                        result.notifyIssue(IssueReport.IssueLevel.WARNING, message, -1, -1);
                     } else {
-                        extractionResult.notifyIssue(IssueReport.IssueLevel.WARNING, message, lineNumber, -1);
+                        result.notifyIssue(IssueReport.IssueLevel.WARNING, message, lineNumber, -1);
                     }
                 }
 
                 BNode calNode = f.createBNode();
-                extractionResult.writeTriple(calNode, RDF.TYPE, vICAL.Vcalendar);
-                extract(index, cal.getTimezoneInfo(), calNode, cal, extractionResult);
+                result.writeTriple(calNode, RDF.TYPE, vICAL.Vcalendar);
+                WriteContext ctx = new WriteContext(ICalVersion.V2_0, cal.getTimezoneInfo(), null);
+                extract(index, ctx, calNode, cal, result, true);
             }
         } catch (Exception e) {
-            extractionResult.notifyIssue(IssueReport.IssueLevel.FATAL, toString(e), -1, -1);
+            result.notifyIssue(IssueReport.IssueLevel.FATAL, toString(e), -1, -1);
         }
     }
 
@@ -111,56 +138,42 @@ abstract class BaseCalendarExtractor implements Extractor.ContentExtractor {
             return "";
         }
         int ind = Character.charCount(typeName.codePointAt(0));
-        return typeName.substring(0, ind).toUpperCase(Locale.ENGLISH) + typeName.substring(ind);
+        return typeName.substring(0, ind).toUpperCase(Locale.ENGLISH)
+                + typeName.substring(ind).toLowerCase(Locale.ENGLISH);
     }
 
     private static String localNameOfProperty(String propertyName) {
         String[] nameComponents = propertyName.split("-");
         StringBuilder sb = new StringBuilder(propertyName.length());
-        sb.append(nameComponents[0]);
+        sb.append(nameComponents[0].toLowerCase(Locale.ENGLISH));
         for (int i = 1, len = nameComponents.length; i < len; i++) {
             sb.append(localNameOfType(nameComponents[i]));
         }
         return sb.toString();
     }
 
-    private static IRI type(ICalComponentScribe<?> scribe, ExtractionResult result) {
-        if (scribe == null) {
-            return null;
-        }
-        String originalName = scribe.getComponentName();
-        String name = originalName.toLowerCase(Locale.ENGLISH);
-
-        if (name.startsWith("x-")) {
+    private static IRI type(String originalName) {
+        if (originalName.regionMatches(true, 0, "X-", 0, 2)) {
             //non-standard class
-            return f.createIRI(ICAL.NS, "X-" + localNameOfType(name.substring(2)));
+            return f.createIRI(ICAL.NS, "X-" + localNameOfType(originalName.substring(2)));
         }
 
-        name = localNameOfType(name);
+        String name = localNameOfType(originalName);
 
         try {
             return Objects.requireNonNull(vICAL.getClass(name));
         } catch (RuntimeException e) {
-            IRI iri = f.createIRI(ICAL.NS, name);
-            result.notifyIssue(IssueReport.IssueLevel.ERROR,
-                    "class " + iri + " (" + originalName + ") not defined in " + ICAL.class.getName(),
-                    -1, -1);
-            return iri;
+            return null;
         }
     }
 
-    private static IRI predicate(ICalPropertyScribe<?> scribe, ExtractionResult result) {
-        if (scribe == null) {
-            return null;
-        }
-        String originalName = scribe.getPropertyName(ICalVersion.V2_0);
-        String name = originalName.toLowerCase(Locale.ENGLISH);
-        if (name.startsWith("x-")) {
+    private static IRI predicate(String originalName, ExtractionResult result) {
+        if (originalName.regionMatches(true, 0, "X-", 0, 2)) {
             //non-standard property
-            return f.createIRI(ICAL.NS, "x-" + localNameOfProperty(name.substring(2)));
+            return f.createIRI(ICAL.NS, "x-" + localNameOfProperty(originalName.substring(2)));
         }
 
-        name = localNameOfProperty(name);
+        String name = localNameOfProperty(originalName);
 
         try {
             return Objects.requireNonNull(vICAL.getProperty(name));
@@ -173,49 +186,332 @@ abstract class BaseCalendarExtractor implements Extractor.ContentExtractor {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    private static <T extends ICalProperty> Value value(ICalPropertyScribe<T> scribe, ICalProperty property, TimezoneInfo info) {
-        try {
-            T prop = (T)property;
-            String text = scribe.writeText(prop, new WriteContext(ICalVersion.V2_0, info, null));
-            if (text == null) {
-                return null;
+    private static final String NaN = Double.toString(Double.NaN);
+    private static String str(Double d) {
+        return d == null ? NaN : d.toString();
+    }
+
+    private static void writeParams(BNode subject, ICalParameters params, ExtractionResult result) {
+        for (Map.Entry<String, List<String>> entry : params.getMap().entrySet()) {
+            List<String> strings = entry.getValue();
+            if (strings != null && !strings.isEmpty()) {
+                IRI predicate = predicate(entry.getKey(), result);
+                for (String v : strings) {
+                    result.writeTriple(subject, predicate, f.createLiteral(v));
+                }
             }
-            text = VObjectPropertyValues.unescape(text);
-            ICalDataType dataType = scribe.dataType(prop, ICalVersion.V2_0);
-            if (ICalDataType.URI.equals(dataType) || ICalDataType.URL.equals(dataType)) {
+        }
+    }
+
+
+    private static IRI dataType(ICalDataType dataType) {
+        if (dataType == null || ICalDataType.TEXT.equals(dataType)) {
+            return XMLSchema.STRING;
+        } else if (ICalDataType.BOOLEAN.equals(dataType)) {
+            return XMLSchema.BOOLEAN;
+        } else if (ICalDataType.INTEGER.equals(dataType)) {
+            return XMLSchema.INTEGER;
+        } else if (ICalDataType.FLOAT.equals(dataType)) {
+            return XMLSchema.FLOAT;
+        } else if (ICalDataType.BINARY.equals(dataType)) {
+            return XMLSchema.BASE64BINARY;
+        } else if (ICalDataType.URI.equals(dataType)
+                || ICalDataType.URL.equals(dataType)
+                || ICalDataType.CONTENT_ID.equals(dataType)
+                || ICalDataType.CAL_ADDRESS.equals(dataType)) {
+            return XMLSchema.ANYURI;
+        } else if (ICalDataType.DATE_TIME.equals(dataType)) {
+            return XMLSchema.DATETIME;
+        } else if (ICalDataType.DATE.equals(dataType)) {
+            return XMLSchema.DATE;
+        } else if (ICalDataType.TIME.equals(dataType)) {
+            return XMLSchema.TIME;
+        } else if (ICalDataType.DURATION.equals(dataType)) {
+            return XMLSchema.DURATION;
+        } else if (ICalDataType.PERIOD.equals(dataType)) {
+            return vICAL.Value_PERIOD;
+        } else if (ICalDataType.RECUR.equals(dataType)) {
+            return vICAL.Value_RECUR;
+        } else {
+            return XMLSchema.STRING;
+        }
+    }
+
+
+    private static final Pattern durationWeeksPattern = Pattern.compile("(-?P)(\\d+)W");
+
+    private static String normalizeAndReportIfInvalid(String s, IRI dataType, TimeZone zone, ExtractionResult result) {
+        if (dataType == null) {
+            return s;
+        }
+        try {
+            if (XMLSchema.DURATION.equals(dataType)) {
+                Matcher m = durationWeeksPattern.matcher(s);
+                if (m.matches()) {
+                    long days = Long.parseLong(m.group(2)) * 7;
+                    return m.group(1) + days + "D";
+                }
+            } else if (vICAL.Value_PERIOD.equals(dataType)) {
+                if (s.indexOf('/') == -1) {
+                    throw new IllegalArgumentException();
+                }
+            } else if (zone != null && XMLSchema.DATETIME.equals(dataType)) {
                 try {
-                    return f.createIRI(text.trim());
+                    DateTimeComponents dt = DateTimeComponents.parse(s);
+                    if (!dt.isUtc()) {
+                        s = ICalDateFormat.DATE_TIME_EXTENDED.format(dt.toDate(zone), zone);
+                    }
                 } catch (IllegalArgumentException e) {
                     //ignore
                 }
+            } else {
+                s = XMLDatatypeUtil.normalize(s, dataType);
             }
-            return f.createLiteral(text);
-        } catch (SkipMeException e) {
+
+            if (!XMLDatatypeUtil.isValidValue(s, dataType)) {
+                throw new IllegalArgumentException();
+            }
+        } catch (IllegalArgumentException e) {
+            String m = e.getMessage();
+            if (StringUtils.isBlank(m)) {
+                m = "Not a valid " + dataType + " value: " + s;
+            }
+            result.notifyIssue(IssueReport.IssueLevel.ERROR, m, -1, -1);
+        }
+        return s;
+    }
+
+    private static boolean writeValue(BNode subject, IRI predicate, JsonValue jsonValue, String lang, IRI dataType, TimeZone zone, ExtractionResult result) {
+        if (jsonValue == null || jsonValue.isNull()) {
+            return false;
+        }
+        Object val = jsonValue.getValue();
+        if (val != null) {
+            Value v;
+            if (val instanceof Byte) {
+                v = f.createLiteral((byte)val);
+            } else if (val instanceof Short) {
+                v = f.createLiteral((short)val);
+            } else if (val instanceof Integer) {
+                v = f.createLiteral((int)val);
+            } else if (val instanceof Long) {
+                v = f.createLiteral((long)val);
+            } else if (val instanceof Float) {
+                v = f.createLiteral((float)val);
+            } else if (val instanceof Double) {
+                v = f.createLiteral((double)val);
+            } else if (val instanceof Boolean) {
+                v = f.createLiteral((boolean)val);
+            } else if (val instanceof BigInteger) {
+                v = f.createLiteral((BigInteger)val);
+            } else if (val instanceof BigDecimal) {
+                v = f.createLiteral((BigDecimal)val);
+            } else {
+                String str = normalizeAndReportIfInvalid(val.toString(), dataType, zone, result);
+
+                if (XMLSchema.STRING.equals(dataType)) {
+                    if (lang == null) {
+                        v = f.createLiteral(str);
+                    } else {
+                        v = f.createLiteral(str, lang);
+                    }
+                } else if (XMLSchema.ANYURI.equals(dataType)) {
+                    try {
+                        v = f.createIRI(str);
+                    } catch (IllegalArgumentException e) {
+                        v = f.createLiteral(str, dataType);
+                    }
+                } else if (vICAL.Value_PERIOD.equals(dataType)) {
+                    String[] strs = str.split("/");
+                    if (strs.length != 2) {
+                        v = f.createLiteral(str);
+                    } else {
+                        BNode bNode = f.createBNode();
+                        result.writeTriple(subject, predicate, bNode);
+                        result.writeTriple(bNode, RDF.TYPE, dataType);
+
+                        String start = normalizeAndReportIfInvalid(strs[0], XMLSchema.DATETIME, zone, result);
+                        result.writeTriple(bNode, vICAL.dtstart, f.createLiteral(start, XMLSchema.DATETIME));
+                        String str1 = strs[1];
+                        if (str1.indexOf('P') != -1) { //duration
+                            String duration = normalizeAndReportIfInvalid(str1, XMLSchema.DURATION, zone, result);
+                            result.writeTriple(bNode, vICAL.duration, f.createLiteral(duration, XMLSchema.DURATION));
+                        } else {
+                            String end = normalizeAndReportIfInvalid(str1, XMLSchema.DATETIME, zone, result);
+                            result.writeTriple(bNode, vICAL.dtend, f.createLiteral(end, XMLSchema.DATETIME));
+                        }
+                        return true;
+                    }
+                } else if (dataType != null) {
+                    v = f.createLiteral(str, dataType);
+                } else {
+                    v = f.createLiteral(str);
+                }
+
+            }
+            result.writeTriple(subject, predicate, v);
+            return true;
+        }
+
+        List<JsonValue> array = jsonValue.getArray();
+        if (array != null && !array.isEmpty()) {
+            if (array.size() == 1) {
+                return writeValue(subject, predicate, array.get(0), lang, dataType, zone, result);
+            } else {
+                BNode bNode = f.createBNode();
+                result.writeTriple(subject, predicate, bNode);
+                for (JsonValue value : array) {
+                    writeValue(bNode, RDF.VALUE, value, lang, dataType, zone, result);
+                }
+                return true;
+            }
+        }
+
+        Map<String, JsonValue> object = jsonValue.getObject();
+        if (object != null) {
+            BNode bNode = f.createBNode();
+            result.writeTriple(subject, predicate, bNode);
+            if (dataType != null && ICAL.NS.equals(dataType.getNamespace())) {
+                result.writeTriple(bNode, RDF.TYPE, dataType);
+            }
+            for (Map.Entry<String, JsonValue> entry : object.entrySet()) {
+                writeValue(bNode, predicate(entry.getKey(), result), entry.getValue(), lang, XMLSchema.STRING, zone, result);
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    private static TimeZone getTimeZone(ICalProperty prop, TimezoneInfo info) {
+        if (info.isFloating(prop)) {
             return null;
         }
+        TimezoneAssignment assignment = info.getTimezoneToWriteIn(prop);
+        if (assignment == null) {
+            return TimeZone.getTimeZone(ZoneOffset.UTC);
+        } else {
+            return assignment.getTimeZone();
+        }
     }
 
-    private static void extract(ScribeIndex index, TimezoneInfo info, BNode node, ICalComponent component, ExtractionResult extractionResult) {
-        for (ICalProperty property : component.getProperties().values()) {
-            ICalPropertyScribe<?> scribe = index.getPropertyScribe(property);
-            IRI predicate = predicate(scribe, extractionResult);
-            if (predicate != null) {
-                Value value = value(scribe, property, info);
-                if (value != null) {
-                    extractionResult.writeTriple(node, predicate, value);
+    @SuppressWarnings("unchecked")
+    private static <T extends ICalProperty> void writeProperty(BNode subject, ICalPropertyScribe<T> scribe, ICalProperty property, WriteContext ctx, ExtractionResult result) {
+        try {
+            T prop = (T)property;
+
+            ICalVersion version = ctx.getVersion();
+
+            ICalDataType dataType = scribe.dataType(prop, version);
+
+            ICalParameters params = scribe.prepareParameters(prop, ctx);
+
+            String lang = params.getLanguage();
+            params.removeAll(ICalParameters.LANGUAGE);
+
+            Encoding encoding = params.getEncoding();
+
+            if (dataType == null) {
+                dataType = params.getValue();
+                if (dataType == null && Encoding.BASE64.equals(encoding)) {
+                    dataType = ICalDataType.BINARY;
+                }
+            }
+            params.removeAll(ICalParameters.VALUE);
+
+            if (ICalDataType.BINARY.equals(dataType)) {
+                // RFC 5545 s. 3.2.7.
+                // If the value type parameter is ";VALUE=BINARY", then the inline
+                // encoding parameter MUST be specified with the value
+                // ";ENCODING=BASE64"
+                if (encoding != null && !Encoding.BASE64.equals(encoding)) {
+                    result.notifyIssue(IssueReport.IssueLevel.ERROR,
+                            "Invalid encoding " + encoding + " specified for BINARY value", -1, -1);
+                    dataType = null;
                 }
+                params.removeAll(ICalParameters.ENCODING);
             }
+
+            if (Encoding._8BIT.equals(encoding)) {
+                // RFC 5545 s. 3.2.7.
+                // The default encoding is "8BIT",
+                // corresponding to a property value consisting of text.
+                params.removeAll(ICalParameters.ENCODING);
+            }
+
+            // RFC 5545 s. 3.1.4.
+            // There is not a property parameter to declare the charset used in a
+            //   property value.  The default charset for an iCalendar stream is UTF-8
+            //   as defined in [RFC3629].
+            params.removeAll(ICalParameters.CHARSET);
+
+            IRI predicate = predicate(scribe.getPropertyName(version), result);
+
+            if (!params.isEmpty()) {
+                BNode bNode = f.createBNode();
+                result.writeTriple(subject, predicate, bNode);
+                writeParams(bNode, params, result);
+
+                subject = bNode;
+                predicate = RDF.VALUE;
+            }
+
+            if (prop instanceof Geo) {
+                // RFC 5870
+                Geo g = (Geo)prop;
+                IRI value = f.createIRI("geo:" + str(g.getLatitude()) + "," + str(g.getLongitude()));
+                result.writeTriple(subject, predicate, value);
+            } else {
+                TimeZone timeZone = getTimeZone(prop, ctx.getTimezoneInfo());
+                IRI dataTypeIRI = dataType(dataType);
+
+                JCalValue jsonVal = scribe.writeJson(prop, ctx);
+                List<JsonValue> jsonVals = jsonVal.getValues();
+
+                boolean mod = false;
+                for (JsonValue value : jsonVals) {
+                    mod |= writeValue(subject, predicate, value, lang, dataTypeIRI, timeZone, result);
+                }
+                if (!mod) {
+                    result.writeTriple(subject, predicate, f.createLiteral(jsonVal.asSingle()));
+                }
+            }
+        } catch (SkipMeException e) {
+            //ignore
+        }
+    }
+
+    private static void extract(ScribeIndex index, WriteContext ctx, BNode node, ICalComponent component, ExtractionResult result, boolean writeTimezones) {
+        for (ICalProperty property : component.getProperties().values()) {
+            ctx.setParent(component);
+            writeProperty(node, index.getPropertyScribe(property), property, ctx, result);
         }
-        for (ICalComponent child : component.getComponents().values()) {
+
+        Stream<ICalComponent> components = component.getComponents().values().stream();
+
+        if (writeTimezones) {
+            Collection<VTimezone> tzs = ctx.getTimezoneInfo().getComponents();
+            Set<String> tzIds = tzs.stream()
+                    .map(tz -> tz.getTimezoneId().getValue())
+                    .collect(Collectors.toSet());
+            components = Stream.concat(tzs.stream(), components.filter(c ->
+                    !(c instanceof VTimezone && tzIds.contains(((VTimezone) c).getTimezoneId().getValue())))
+            );
+        }
+
+        components.forEachOrdered(child -> {
             BNode childNode = f.createBNode();
-            extractionResult.writeTriple(node, vICAL.component, childNode);
-            IRI childType = type(index.getComponentScribe(child), extractionResult);
-            if (childType != null) {
-                extractionResult.writeTriple(childNode, RDF.TYPE, childType);
+            String componentName = index.getComponentScribe(child).getComponentName();
+            IRI childType = type(componentName);
+
+            if (childType == null) {
+                result.writeTriple(node, predicate(componentName, result), childNode);
+            } else {
+                result.writeTriple(node, vICAL.component, childNode);
+                result.writeTriple(childNode, RDF.TYPE, childType);
             }
-            extract(index, info, childNode, child, extractionResult);
-        }
+            extract(index, ctx, childNode, child, result, false);
+        });
     }
 
 }

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/core/src/test/java/org/apache/any23/extractor/calendar/BaseCalendarExtractorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/any23/extractor/calendar/BaseCalendarExtractorTest.java b/core/src/test/java/org/apache/any23/extractor/calendar/BaseCalendarExtractorTest.java
new file mode 100644
index 0000000..701b9ad
--- /dev/null
+++ b/core/src/test/java/org/apache/any23/extractor/calendar/BaseCalendarExtractorTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import org.apache.any23.extractor.html.AbstractExtractorTestCase;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.RepositoryException;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.RDFParseException;
+import org.eclipse.rdf4j.rio.RDFParser;
+import org.eclipse.rdf4j.rio.Rio;
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+abstract class BaseCalendarExtractorTest extends AbstractExtractorTestCase {
+
+    abstract String filePrefix();
+
+    protected void extractAndVerifyAgainstNQuads(String actual, String expected)
+            throws RepositoryException, RDFHandlerException, IOException, RDFParseException {
+        String filePrefix = filePrefix();
+        assertExtract(filePrefix + actual);
+        assertModelNotEmpty();
+        List<Statement> expectedStatements = loadResultStatement(filePrefix + expected);
+        int actualStmtSize = getStatementsSize(null, null, null);
+        Assert.assertEquals(expectedStatements.size(), actualStmtSize);
+        for (Statement statement : expectedStatements) {
+            assertContains(
+                    statement.getSubject() instanceof BNode ? null : statement.getSubject(),
+                    statement.getPredicate(),
+                    statement.getObject() instanceof BNode ? null : statement.getObject()
+            );
+        }
+    }
+
+    private List<Statement> loadResultStatement(String resultFilePath)
+            throws RDFHandlerException, IOException, RDFParseException {
+        RDFParser nQuadsParser = Rio.createParser(RDFFormat.NQUADS);
+        TestRDFHandler rdfHandler = new TestRDFHandler();
+        nQuadsParser.setRDFHandler(rdfHandler);
+        File file = copyResourceToTempFile(resultFilePath);
+        nQuadsParser.parse(
+                new FileReader(file),
+                baseIRI.toString()
+        );
+        return rdfHandler.getStatements();
+    }
+
+    private static class TestRDFHandler implements RDFHandler {
+
+        private final List<Statement> statements = new ArrayList<Statement>();
+
+        protected List<Statement> getStatements() {
+            return statements;
+        }
+
+        public void startRDF() throws RDFHandlerException {
+        }
+
+        public void endRDF() throws RDFHandlerException {
+        }
+
+        public void handleNamespace(String s, String s1) throws RDFHandlerException {
+            throw new UnsupportedOperationException();
+        }
+
+        public void handleStatement(Statement statement) throws RDFHandlerException {
+            statements.add(statement);
+        }
+
+        public void handleComment(String s) throws RDFHandlerException {
+            throw new UnsupportedOperationException();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/core/src/test/java/org/apache/any23/extractor/calendar/ICalExtractorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/any23/extractor/calendar/ICalExtractorTest.java b/core/src/test/java/org/apache/any23/extractor/calendar/ICalExtractorTest.java
new file mode 100644
index 0000000..9000d64
--- /dev/null
+++ b/core/src/test/java/org/apache/any23/extractor/calendar/ICalExtractorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import org.apache.any23.extractor.ExtractorFactory;
+import org.junit.Test;
+
+import java.io.IOException;
+
+
+public class ICalExtractorTest extends BaseCalendarExtractorTest {
+    @Override
+    protected ExtractorFactory<?> getExtractorFactory() {
+        return new ICalExtractorFactory();
+    }
+
+    @Override
+    String filePrefix() {
+        return "/calendar.text/";
+    }
+
+    @Test
+    public void testRFC5545example1() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc5545-example1.ics", "rfc5545-example1-expected.nquads");
+    }
+
+    @Test
+    public void testRFC5545example2() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc5545-example2.ics", "rfc5545-example2-expected.nquads");
+    }
+
+    @Test
+    public void testRFC5545example3() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc5545-example3.ics", "rfc5545-example3-expected.nquads");
+    }
+
+    @Test
+    public void testRFC5545example4() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc5545-example4.ics", "rfc5545-example4-expected.nquads");
+    }
+
+    @Test
+    public void testRFC5545example5() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc5545-example5.ics", "rfc5545-example5-expected.nquads");
+    }
+
+    @Test
+    public void testRFC5545example6() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc5545-example6.ics", "rfc5545-example6-expected.nquads");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/core/src/test/java/org/apache/any23/extractor/calendar/JCalExtractorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/any23/extractor/calendar/JCalExtractorTest.java b/core/src/test/java/org/apache/any23/extractor/calendar/JCalExtractorTest.java
new file mode 100644
index 0000000..bbe633b
--- /dev/null
+++ b/core/src/test/java/org/apache/any23/extractor/calendar/JCalExtractorTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import org.apache.any23.extractor.ExtractorFactory;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class JCalExtractorTest extends BaseCalendarExtractorTest {
+
+    @Override
+    String filePrefix() {
+        return "/calendar.json/";
+    }
+
+    @Override
+    protected ExtractorFactory<?> getExtractorFactory() {
+        return new JCalExtractorFactory();
+    }
+
+    @Test
+    public void testRFC7265example1() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc7265-example1.json", "rfc7265-example1-expected.nquads");
+    }
+
+    @Test
+    public void testRFC7265example2() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc7265-example2.json", "rfc7265-example2-expected.nquads");
+    }
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/core/src/test/java/org/apache/any23/extractor/calendar/XCalExtractorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/any23/extractor/calendar/XCalExtractorTest.java b/core/src/test/java/org/apache/any23/extractor/calendar/XCalExtractorTest.java
new file mode 100644
index 0000000..c063179
--- /dev/null
+++ b/core/src/test/java/org/apache/any23/extractor/calendar/XCalExtractorTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package org.apache.any23.extractor.calendar;
+
+import org.apache.any23.extractor.ExtractorFactory;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class XCalExtractorTest extends BaseCalendarExtractorTest {
+
+    @Override
+    String filePrefix() {
+        return "/calendar.xml/";
+    }
+
+    @Override
+    protected ExtractorFactory<?> getExtractorFactory() {
+        return new XCalExtractorFactory();
+    }
+
+    @Test
+    public void testRFC6321example1() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc6321-example1.xml", "rfc6321-example1-expected.nquads");
+    }
+
+    @Test
+    public void testRFC6321example2() throws IOException {
+        extractAndVerifyAgainstNQuads("rfc6321-example2.xml", "rfc6321-example2-expected.nquads");
+    }
+}

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/core/src/test/java/org/apache/any23/vocab/RDFSchemaUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/any23/vocab/RDFSchemaUtilsTest.java b/core/src/test/java/org/apache/any23/vocab/RDFSchemaUtilsTest.java
index d8fd8d5..83917bf 100644
--- a/core/src/test/java/org/apache/any23/vocab/RDFSchemaUtilsTest.java
+++ b/core/src/test/java/org/apache/any23/vocab/RDFSchemaUtilsTest.java
@@ -43,7 +43,7 @@ public class RDFSchemaUtilsTest {
      */
     @Test
     public void testSerializeVocabulariesNTriples() {
-        serializeVocabularies(RDFFormat.NTRIPLES, 2174);
+        serializeVocabularies(RDFFormat.NTRIPLES, 2178);
     }
 
     /**
@@ -53,7 +53,7 @@ public class RDFSchemaUtilsTest {
      */
     @Test
     public void testSerializeVocabulariesRDFXML() {
-        serializeVocabularies(RDFFormat.RDFXML, 5699); // Effective lines + separators.
+        serializeVocabularies(RDFFormat.RDFXML, 5709); // Effective lines + separators.
     }
 
     private void serializeVocabularies(RDFFormat format, int expectedLines) {

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.json/rfc7265-example1-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.json/rfc7265-example1-expected.nquads b/test-resources/src/test/resources/calendar.json/rfc7265-example1-expected.nquads
new file mode 100644
index 0000000..ae9c0bc
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.json/rfc7265-example1-expected.nquads
@@ -0,0 +1,26 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu3uv03x2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu3uv03x2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//Example Inc.//Example Calendar//EN" <http://bob.example.com/> .
+_:node1clu3uv03x2 <http://www.w3.org/2002/12/cal/icaltzd#calscale> "GREGORIAN" <http://bob.example.com/> .
+_:node1clu3uv03x2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu3uv03x3 <http://bob.example.com/> .
+_:node1clu3uv03x3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu3uv03x3 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "2008-02-05T19:12:24Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu3uv03x3 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2008-10-06"^^<http://www.w3.org/2001/XMLSchema#date> <http://bob.example.com/> .
+_:node1clu3uv03x3 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Planning meeting" <http://bob.example.com/> .
+_:node1clu3uv03x3 <http://www.w3.org/2002/12/cal/icaltzd#uid> "4088E990AD89CB3DBB484909" <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.json/rfc7265-example1.json
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.json/rfc7265-example1.json b/test-resources/src/test/resources/calendar.json/rfc7265-example1.json
new file mode 100755
index 0000000..c94699e
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.json/rfc7265-example1.json
@@ -0,0 +1,18 @@
+["vcalendar",
+  [
+    ["version", {}, "text", "2.0"],
+    ["prodid", {}, "text", "-//Example Inc.//Example Calendar//EN"],
+    ["calscale", {}, "text", "GREGORIAN"]
+  ],
+  [
+    ["vevent",
+      [
+        ["dtstamp", {}, "date-time", "2008-02-05T19:12:24Z"],
+        ["dtstart", {}, "date", "2008-10-06"],
+        ["summary", {}, "text", "Planning meeting"],
+        ["uid", {}, "text", "4088E990AD89CB3DBB484909"]
+      ],
+      []
+    ]
+  ]
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.json/rfc7265-example2-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.json/rfc7265-example2-expected.nquads b/test-resources/src/test/resources/calendar.json/rfc7265-example2-expected.nquads
new file mode 100644
index 0000000..11ce490
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.json/rfc7265-example2-expected.nquads
@@ -0,0 +1,75 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu415j2x2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu415j2x2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//Example Corp.//Example Client//EN" <http://bob.example.com/> .
+_:node1clu415j2x2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu415j2x3 <http://bob.example.com/> .
+_:node1clu415j2x3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vtimezone> <http://bob.example.com/> .
+_:node1clu415j2x3 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu415j2x3 <http://www.w3.org/2002/12/cal/icaltzd#lastModified> "2004-01-10T03:28:45Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x3 <http://www.w3.org/2002/12/cal/icaltzd#daylight> _:node1clu415j2x4 <http://bob.example.com/> .
+_:node1clu415j2x4 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2000-04-04T02:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x4 <http://www.w3.org/2002/12/cal/icaltzd#rrule> _:node1clu415j2x5 <http://bob.example.com/> .
+_:node1clu415j2x5 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_RECUR> <http://bob.example.com/> .
+_:node1clu415j2x5 <http://www.w3.org/2002/12/cal/icaltzd#freq> "YEARLY" <http://bob.example.com/> .
+_:node1clu415j2x5 <http://www.w3.org/2002/12/cal/icaltzd#byday> "1SU" <http://bob.example.com/> .
+_:node1clu415j2x5 <http://www.w3.org/2002/12/cal/icaltzd#bymonth> "4"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu415j2x4 <http://www.w3.org/2002/12/cal/icaltzd#tzname> "EDT" <http://bob.example.com/> .
+_:node1clu415j2x4 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetfrom> "-05:00" <http://bob.example.com/> .
+_:node1clu415j2x4 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetto> "-04:00" <http://bob.example.com/> .
+_:node1clu415j2x3 <http://www.w3.org/2002/12/cal/icaltzd#standard> _:node1clu415j2x6 <http://bob.example.com/> .
+_:node1clu415j2x6 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2000-10-26T02:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x6 <http://www.w3.org/2002/12/cal/icaltzd#rrule> _:node1clu415j2x7 <http://bob.example.com/> .
+_:node1clu415j2x7 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_RECUR> <http://bob.example.com/> .
+_:node1clu415j2x7 <http://www.w3.org/2002/12/cal/icaltzd#freq> "YEARLY" <http://bob.example.com/> .
+_:node1clu415j2x7 <http://www.w3.org/2002/12/cal/icaltzd#byday> "1SU" <http://bob.example.com/> .
+_:node1clu415j2x7 <http://www.w3.org/2002/12/cal/icaltzd#bymonth> "10"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu415j2x6 <http://www.w3.org/2002/12/cal/icaltzd#tzname> "EST" <http://bob.example.com/> .
+_:node1clu415j2x6 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetfrom> "-04:00" <http://bob.example.com/> .
+_:node1clu415j2x6 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetto> "-05:00" <http://bob.example.com/> .
+_:node1clu415j2x2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu415j2x8 <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "2006-02-06T00:11:21Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> _:node1clu415j2x9 <http://bob.example.com/> .
+_:node1clu415j2x9 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu415j2x9 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2006-01-02T12:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#duration> "PT1H"^^<http://www.w3.org/2001/XMLSchema#duration> <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#rrule> _:node1clu415j2x10 <http://bob.example.com/> .
+_:node1clu415j2x10 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_RECUR> <http://bob.example.com/> .
+_:node1clu415j2x10 <http://www.w3.org/2002/12/cal/icaltzd#freq> "DAILY" <http://bob.example.com/> .
+_:node1clu415j2x10 <http://www.w3.org/2002/12/cal/icaltzd#count> "5"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#rdate> _:node1clu415j2x11 <http://bob.example.com/> .
+_:node1clu415j2x11 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu415j2x11 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> _:node1clu415j2x12 <http://bob.example.com/> .
+_:node1clu415j2x12 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_PERIOD> <http://bob.example.com/> .
+_:node1clu415j2x12 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "2006-01-02T15:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x12 <http://www.w3.org/2002/12/cal/icaltzd#duration> "PT2H"^^<http://www.w3.org/2001/XMLSchema#duration> <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Event #2" <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#description> "We are having a meeting all this week at 12 pm for one hour, with an additional meeting on the first day 2 hours long.\nPlease bring your own lunch for the 12 pm meetings." <http://bob.example.com/> .
+_:node1clu415j2x8 <http://www.w3.org/2002/12/cal/icaltzd#uid> "00959BC664CA650E933C892C@example.com" <http://bob.example.com/> .
+_:node1clu415j2x2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu415j2x13 <http://bob.example.com/> .
+_:node1clu415j2x13 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu415j2x13 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "2006-02-06T00:11:21Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x13 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> _:node1clu415j2x14 <http://bob.example.com/> .
+_:node1clu415j2x14 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu415j2x14 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2006-01-02T14:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x13 <http://www.w3.org/2002/12/cal/icaltzd#duration> "PT1H"^^<http://www.w3.org/2001/XMLSchema#duration> <http://bob.example.com/> .
+_:node1clu415j2x13 <http://www.w3.org/2002/12/cal/icaltzd#recurrenceId> _:node1clu415j2x15 <http://bob.example.com/> .
+_:node1clu415j2x15 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "US/Eastern" <http://bob.example.com/> .
+_:node1clu415j2x15 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "2006-01-04T12:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu415j2x13 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Event #2" <http://bob.example.com/> .
+_:node1clu415j2x13 <http://www.w3.org/2002/12/cal/icaltzd#uid> "00959BC664CA650E933C892C@example.com" <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.json/rfc7265-example2.json
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.json/rfc7265-example2.json b/test-resources/src/test/resources/calendar.json/rfc7265-example2.json
new file mode 100755
index 0000000..1deb906
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.json/rfc7265-example2.json
@@ -0,0 +1,96 @@
+["vcalendar",
+  [
+    ["version", {}, "text", "2.0"],
+    ["prodid", {}, "text", "-//Example Corp.//Example Client//EN"]
+  ],
+  [
+    ["vtimezone",
+      [
+        ["tzid", {}, "text", "US/Eastern"],
+        ["last-modified", {}, "date-time", "2004-01-10T03:28:45Z"]
+      ],
+      [
+        ["daylight",
+          [
+            ["dtstart", {}, "date-time", "2000-04-04T02:00:00"],
+            ["rrule",
+             {},
+             "recur",
+             {
+               "freq": "YEARLY",
+               "byday": "1SU",
+               "bymonth": 4
+             }
+            ],
+            ["tzname", {}, "text", "EDT"],
+            ["tzoffsetfrom", {}, "utc-offset", "-05:00"],
+            ["tzoffsetto", {}, "utc-offset", "-04:00"]
+          ],
+          []
+        ],
+        ["standard",
+          [
+            ["dtstart", {}, "date-time", "2000-10-26T02:00:00"],
+            ["rrule",
+             {},
+             "recur",
+             {
+               "freq": "YEARLY",
+               "byday": "1SU",
+               "bymonth": 10
+             }
+            ],
+            ["tzname", {}, "text", "EST"],
+            ["tzoffsetfrom", {}, "utc-offset", "-04:00"],
+            ["tzoffsetto", {}, "utc-offset", "-05:00"]
+          ],
+          []
+        ]
+      ]
+    ],
+    ["vevent",
+      [
+        ["dtstamp", {}, "date-time", "2006-02-06T00:11:21Z"],
+        ["dtstart",
+         { "tzid": "US/Eastern" },
+         "date-time",
+         "2006-01-02T12:00:00"
+        ],
+        ["duration", {}, "duration", "PT1H"],
+        ["rrule", {}, "recur", {"freq": "DAILY", "count": 5 }],
+        ["rdate",
+         { "tzid": "US/Eastern" },
+         "period",
+         "2006-01-02T15:00:00/PT2H"
+        ],
+        ["summary", {}, "text", "Event #2"],
+        ["description",
+         {},
+         "text",
+         "We are having a meeting all this week at 12 pm for one hour, with an additional meeting on the first day 2 hours long.\nPlease bring your own lunch for the 12 pm meetings."
+        ],
+        ["uid", {}, "text", "00959BC664CA650E933C892C@example.com"]
+      ],
+      []
+    ],
+    ["vevent",
+      [
+        ["dtstamp", {}, "date-time", "2006-02-06T00:11:21Z"],
+        ["dtstart",
+         { "tzid": "US/Eastern" },
+         "date-time",
+         "2006-01-02T14:00:00"
+        ],
+        ["duration", {}, "duration", "PT1H"],
+        ["recurrence-id",
+         { "tzid": "US/Eastern" },
+         "date-time",
+         "2006-01-04T12:00:00"
+        ],
+        ["summary", {}, "text", "Event #2"],
+        ["uid", {}, "text", "00959BC664CA650E933C892C@example.com"]
+      ],
+      []
+    ]
+  ]
+]

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example1-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example1-expected.nquads b/test-resources/src/test/resources/calendar.text/rfc5545-example1-expected.nquads
new file mode 100644
index 0000000..c043a1c
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example1-expected.nquads
@@ -0,0 +1,30 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu1knnlx2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu1knnlx2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//xyz Corp//NONSGML PDA Calendar Version 1.0//EN" <http://bob.example.com/> .
+_:node1clu1knnlx2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu1knnlx3 <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "1996-07-04T12:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#uid> "uid1@example.com" <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#organizer> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1996-09-18T14:30:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#dtend> "1996-09-20T22:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#status> "CONFIRMED" <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#categories> "CONFERENCE" <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Networld+Interop Conference" <http://bob.example.com/> .
+_:node1clu1knnlx3 <http://www.w3.org/2002/12/cal/icaltzd#description> "Networld+Interop Conferenceand Exhibit\nAtlanta World Congress Center\nAtlanta, Georgia" <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example1.ics
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example1.ics b/test-resources/src/test/resources/calendar.text/rfc5545-example1.ics
new file mode 100755
index 0000000..34ba23e
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example1.ics
@@ -0,0 +1,17 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//xyz Corp//NONSGML PDA Calendar Version 1.0//EN
+BEGIN:VEVENT
+DTSTAMP:19960704T120000Z
+UID:uid1@example.com
+ORGANIZER:mailto:jsmith@example.com
+DTSTART:19960918T143000Z
+DTEND:19960920T220000Z
+STATUS:CONFIRMED
+CATEGORIES:CONFERENCE
+SUMMARY:Networld+Interop Conference
+DESCRIPTION:Networld+Interop Conference
+ and Exhibit\nAtlanta World Congress Center\n
+ Atlanta\, Georgia
+END:VEVENT
+END:VCALENDAR

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example2-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example2-expected.nquads b/test-resources/src/test/resources/calendar.text/rfc5545-example2-expected.nquads
new file mode 100644
index 0000000..89f06e8
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example2-expected.nquads
@@ -0,0 +1,55 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu1u3ipx2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu1u3ipx2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//RDU Software//NONSGML HandCal//EN" <http://bob.example.com/> .
+_:node1clu1u3ipx2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu1u3ipx3 <http://bob.example.com/> .
+_:node1clu1u3ipx3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vtimezone> <http://bob.example.com/> .
+_:node1clu1u3ipx3 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "America/New_York" <http://bob.example.com/> .
+_:node1clu1u3ipx3 <http://www.w3.org/2002/12/cal/icaltzd#standard> _:node1clu1u3ipx4 <http://bob.example.com/> .
+_:node1clu1u3ipx4 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1998-10-25T02:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1u3ipx4 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetfrom> "-04:00" <http://bob.example.com/> .
+_:node1clu1u3ipx4 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetto> "-05:00" <http://bob.example.com/> .
+_:node1clu1u3ipx4 <http://www.w3.org/2002/12/cal/icaltzd#tzname> "EST" <http://bob.example.com/> .
+_:node1clu1u3ipx3 <http://www.w3.org/2002/12/cal/icaltzd#daylight> _:node1clu1u3ipx5 <http://bob.example.com/> .
+_:node1clu1u3ipx5 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1999-04-04T02:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1u3ipx5 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetfrom> "-05:00" <http://bob.example.com/> .
+_:node1clu1u3ipx5 <http://www.w3.org/2002/12/cal/icaltzd#tzoffsetto> "-04:00" <http://bob.example.com/> .
+_:node1clu1u3ipx5 <http://www.w3.org/2002/12/cal/icaltzd#tzname> "EDT" <http://bob.example.com/> .
+_:node1clu1u3ipx2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu1u3ipx6 <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "1998-03-09T23:10:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#uid> "guid-1.example.com" <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#organizer> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#attendee> _:node1clu1u3ipx7 <http://bob.example.com/> .
+_:node1clu1u3ipx7 <http://www.w3.org/2002/12/cal/icaltzd#cutype> "GROUP" <http://bob.example.com/> .
+_:node1clu1u3ipx7 <http://www.w3.org/2002/12/cal/icaltzd#rsvp> "TRUE" <http://bob.example.com/> .
+_:node1clu1u3ipx7 <http://www.w3.org/2002/12/cal/icaltzd#role> "REQ-PARTICIPANT" <http://bob.example.com/> .
+_:node1clu1u3ipx7 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#description> "Project XYZ Review Meeting" <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#categories> "MEETING" <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#class> "PUBLIC" <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#created> "1998-03-09T13:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#summary> "XYZ Project Review" <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> _:node1clu1u3ipx8 <http://bob.example.com/> .
+_:node1clu1u3ipx8 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "America/New_York" <http://bob.example.com/> .
+_:node1clu1u3ipx8 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "1998-03-12T08:30:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#dtend> _:node1clu1u3ipx9 <http://bob.example.com/> .
+_:node1clu1u3ipx9 <http://www.w3.org/2002/12/cal/icaltzd#tzid> "America/New_York" <http://bob.example.com/> .
+_:node1clu1u3ipx9 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> "1998-03-12T09:30:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu1u3ipx6 <http://www.w3.org/2002/12/cal/icaltzd#location> "1CP Conference Room 4350" <http://bob.example.com/> .
+

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example2.ics
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example2.ics b/test-resources/src/test/resources/calendar.text/rfc5545-example2.ics
new file mode 100755
index 0000000..0bb0c27
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example2.ics
@@ -0,0 +1,34 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//RDU Software//NONSGML HandCal//EN
+BEGIN:VTIMEZONE
+TZID:America/New_York
+BEGIN:STANDARD
+DTSTART:19981025T020000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19990404T020000
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:19980309T231000Z
+UID:guid-1.example.com
+ORGANIZER:mailto:mrbig@example.com
+ATTENDEE;CUTYPE=GROUP;RSVP=TRUE;ROLE=REQ-PARTICIPANT:
+ mailto:employee-A@example.com
+DESCRIPTION:Project XYZ Review Meeting
+CATEGORIES:MEETING
+CLASS:PUBLIC
+CREATED:19980309T130000Z
+SUMMARY:XYZ Project Review
+DTSTART;TZID=America/New_York:19980312T083000
+DTEND;TZID=America/New_York:19980312T093000
+LOCATION:1CP Conference Room 4350
+END:VEVENT
+END:VCALENDAR

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example3-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example3-expected.nquads b/test-resources/src/test/resources/calendar.text/rfc5545-example3-expected.nquads
new file mode 100644
index 0000000..9d48895
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example3-expected.nquads
@@ -0,0 +1,40 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu24refx2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu24refx2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//ABC Corporation//NONSGML My Product//EN" <http://bob.example.com/> .
+_:node1clu24refx2 <http://www.w3.org/2002/12/cal/icaltzd#method> "xyz" <http://bob.example.com/> .
+_:node1clu24refx2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu24refx3 <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vevent> <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "1997-03-24T12:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#sequence> "0"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#uid> "uid3@example.com" <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#organizer> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#attendee> _:node1clu24refx4 <http://bob.example.com/> .
+_:node1clu24refx4 <http://www.w3.org/2002/12/cal/icaltzd#rsvp> "TRUE" <http://bob.example.com/> .
+_:node1clu24refx4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1997-03-24T12:30:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#dtend> "1997-03-24T21:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#categories> "MEETING" <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#categories> "PROJECT" <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#class> "PUBLIC" <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Calendaring Interoperability Planning Meeting" <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#description> "Discuss how we can test c&s interoperability\nusing iCalendar and other IETF standards." <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#location> "LDB Lobby" <http://bob.example.com/> .
+_:node1clu24refx3 <http://www.w3.org/2002/12/cal/icaltzd#attach> _:node1clu24refx5 <http://bob.example.com/> .
+_:node1clu24refx5 <http://www.w3.org/2002/12/cal/icaltzd#fmttype> "application/postscript" <http://bob.example.com/> .
+_:node1clu24refx5 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <ftp://example.com/pub/conf/bkgrnd.ps> <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example3.ics
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example3.ics b/test-resources/src/test/resources/calendar.text/rfc5545-example3.ics
new file mode 100755
index 0000000..da83a1b
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example3.ics
@@ -0,0 +1,22 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ABC Corporation//NONSGML My Product//EN
+METHOD:xyz
+BEGIN:VEVENT
+DTSTAMP:19970324T120000Z
+SEQUENCE:0
+UID:uid3@example.com
+ORGANIZER:mailto:jdoe@example.com
+ATTENDEE;RSVP=TRUE:mailto:jsmith@example.com
+DTSTART:19970324T123000Z
+DTEND:19970324T210000Z
+CATEGORIES:MEETING,PROJECT
+CLASS:PUBLIC
+SUMMARY:Calendaring Interoperability Planning Meeting
+DESCRIPTION:Discuss how we can test c&s interoperability\n
+ using iCalendar and other IETF standards.
+LOCATION:LDB Lobby
+ATTACH;FMTTYPE=application/postscript:ftp://example.com/pub/
+ conf/bkgrnd.ps
+END:VEVENT
+END:VCALENDAR

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example4-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example4-expected.nquads b/test-resources/src/test/resources/calendar.text/rfc5545-example4-expected.nquads
new file mode 100644
index 0000000..7b34215
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example4-expected.nquads
@@ -0,0 +1,40 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu27ji5x2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu27ji5x2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//ABC Corporation//NONSGML My Product//EN" <http://bob.example.com/> .
+_:node1clu27ji5x2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu27ji5x3 <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vtodo> <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "1998-01-30T13:45:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#sequence> "2"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#uid> "uid4@example.com" <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#organizer> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#attendee> _:node1clu27ji5x4 <http://bob.example.com/> .
+_:node1clu27ji5x4 <http://www.w3.org/2002/12/cal/icaltzd#partstat> "ACCEPTED" <http://bob.example.com/> .
+_:node1clu27ji5x4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#due> "1998-04-15T00:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#status> "NEEDS-ACTION" <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#summary> "Submit Income Taxes" <http://bob.example.com/> .
+_:node1clu27ji5x3 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu27ji5x5 <http://bob.example.com/> .
+_:node1clu27ji5x5 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Valarm> <http://bob.example.com/> .
+_:node1clu27ji5x5 <http://www.w3.org/2002/12/cal/icaltzd#action> "AUDIO" <http://bob.example.com/> .
+_:node1clu27ji5x5 <http://www.w3.org/2002/12/cal/icaltzd#trigger> "1998-04-03T12:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu27ji5x5 <http://www.w3.org/2002/12/cal/icaltzd#attach> _:node1clu27ji5x6 <http://bob.example.com/> .
+_:node1clu27ji5x6 <http://www.w3.org/2002/12/cal/icaltzd#fmttype> "audio/basic" <http://bob.example.com/> .
+_:node1clu27ji5x6 <http://www.w3.org/1999/02/22-rdf-syntax-ns#value> <http://example.com/pub/audio-files/ssbanner.aud> <http://bob.example.com/> .
+_:node1clu27ji5x5 <http://www.w3.org/2002/12/cal/icaltzd#repeat> "4"^^<http://www.w3.org/2001/XMLSchema#int> <http://bob.example.com/> .
+_:node1clu27ji5x5 <http://www.w3.org/2002/12/cal/icaltzd#duration> "PT1H"^^<http://www.w3.org/2001/XMLSchema#duration> <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example4.ics
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example4.ics b/test-resources/src/test/resources/calendar.text/rfc5545-example4.ics
new file mode 100755
index 0000000..18d53df
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example4.ics
@@ -0,0 +1,22 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ABC Corporation//NONSGML My Product//EN
+BEGIN:VTODO
+DTSTAMP:19980130T134500Z
+SEQUENCE:2
+UID:uid4@example.com
+ORGANIZER:mailto:unclesam@example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:jqpublic@example.com
+DUE:19980415T000000
+STATUS:NEEDS-ACTION
+SUMMARY:Submit Income Taxes
+BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;VALUE=DATE-TIME:19980403T120000Z
+ATTACH;FMTTYPE=audio/basic:http://example.com/pub/audio-
+ files/ssbanner.aud
+REPEAT:4
+DURATION:PT1H
+END:VALARM
+END:VTODO
+END:VCALENDAR

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example5-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example5-expected.nquads b/test-resources/src/test/resources/calendar.text/rfc5545-example5-expected.nquads
new file mode 100644
index 0000000..1fb93ed
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example5-expected.nquads
@@ -0,0 +1,30 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu28m86x2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu28m86x2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//ABC Corporation//NONSGML My Product//EN" <http://bob.example.com/> .
+_:node1clu28m86x2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu28m86x3 <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vjournal> <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#dtstamp> "1997-03-24T12:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#uid> "uid5@example.com" <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#organizer> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#status> "DRAFT" <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#class> "PUBLIC" <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#categories> "Project Report" <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#categories> "XYZ" <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#categories> "Weekly Meeting" <http://bob.example.com/> .
+_:node1clu28m86x3 <http://www.w3.org/2002/12/cal/icaltzd#description> "Project xyz Review Meeting Minutes\nAgenda\n1. Review of project version 1.0 requirements.\n2.Definitionof project processes.\n3. Review of project schedule.\nParticipants: John Smith, Jane Doe, Jim Dandy\n-It wasdecided that the requirements need to be signed off byproduct marketing.\n-Project processes were accepted.\n-Project schedule needs to account for scheduled holidaysand employee vacation time. Check with HR for specificdates.\n-New schedule will be distributed by Friday.\n-Next weeks meeting is cancelled. No meeting until 3/23." <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example5.ics
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example5.ics b/test-resources/src/test/resources/calendar.text/rfc5545-example5.ics
new file mode 100755
index 0000000..2dfa4a6
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example5.ics
@@ -0,0 +1,23 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//ABC Corporation//NONSGML My Product//EN
+BEGIN:VJOURNAL
+DTSTAMP:19970324T120000Z
+UID:uid5@example.com
+ORGANIZER:mailto:jsmith@example.com
+STATUS:DRAFT
+CLASS:PUBLIC
+CATEGORIES: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
+END:VCALENDAR

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example6-expected.nquads
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example6-expected.nquads b/test-resources/src/test/resources/calendar.text/rfc5545-example6-expected.nquads
new file mode 100644
index 0000000..0425e4b
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example6-expected.nquads
@@ -0,0 +1,37 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You 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.
+#
+
+_:node1clu29scrx2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vcalendar> <http://bob.example.com/> .
+_:node1clu29scrx2 <http://www.w3.org/2002/12/cal/icaltzd#prodid> "-//RDU Software//NONSGML HandCal//EN" <http://bob.example.com/> .
+_:node1clu29scrx2 <http://www.w3.org/2002/12/cal/icaltzd#component> _:node1clu29scrx3 <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Vfreebusy> <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/2002/12/cal/icaltzd#organizer> <ma...@example.com> <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1998-03-13T14:17:11Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/2002/12/cal/icaltzd#dtend> "1998-04-10T14:17:11Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/2002/12/cal/icaltzd#freebusy> _:node1clu29scrx4 <http://bob.example.com/> .
+_:node1clu29scrx4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_PERIOD> <http://bob.example.com/> .
+_:node1clu29scrx4 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1998-03-14T23:30:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx4 <http://www.w3.org/2002/12/cal/icaltzd#dtend> "1998-03-15T00:30:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/2002/12/cal/icaltzd#freebusy> _:node1clu29scrx5 <http://bob.example.com/> .
+_:node1clu29scrx5 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_PERIOD> <http://bob.example.com/> .
+_:node1clu29scrx5 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1998-03-16T15:30:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx5 <http://www.w3.org/2002/12/cal/icaltzd#dtend> "1998-03-16T16:30:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/2002/12/cal/icaltzd#freebusy> _:node1clu29scrx6 <http://bob.example.com/> .
+_:node1clu29scrx6 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/12/cal/icaltzd#Value_PERIOD> <http://bob.example.com/> .
+_:node1clu29scrx6 <http://www.w3.org/2002/12/cal/icaltzd#dtstart> "1998-03-18T03:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx6 <http://www.w3.org/2002/12/cal/icaltzd#dtend> "1998-03-18T04:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> <http://bob.example.com/> .
+_:node1clu29scrx3 <http://www.w3.org/2002/12/cal/icaltzd#url> <http://www.example.com/calendar/busytime/jsmith.ifb> <http://bob.example.com/> .

http://git-wip-us.apache.org/repos/asf/any23/blob/19d85f2f/test-resources/src/test/resources/calendar.text/rfc5545-example6.ics
----------------------------------------------------------------------
diff --git a/test-resources/src/test/resources/calendar.text/rfc5545-example6.ics b/test-resources/src/test/resources/calendar.text/rfc5545-example6.ics
new file mode 100755
index 0000000..2623678
--- /dev/null
+++ b/test-resources/src/test/resources/calendar.text/rfc5545-example6.ics
@@ -0,0 +1,13 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//RDU Software//NONSGML HandCal//EN
+BEGIN:VFREEBUSY
+ORGANIZER:mailto:jsmith@example.com
+DTSTART:19980313T141711Z
+DTEND:19980410T141711Z
+FREEBUSY:19980314T233000Z/19980315T003000Z
+FREEBUSY:19980316T153000Z/19980316T163000Z
+FREEBUSY:19980318T030000Z/19980318T040000Z
+URL:http://www.example.com/calendar/busytime/jsmith.ifb
+END:VFREEBUSY
+END:VCALENDAR