Coder Social home page Coder Social logo

ical4j / ical4j Goto Github PK

View Code? Open in Web Editor NEW
726.0 42.0 199.0 23.19 MB

A Java library for parsing and building iCalendar data models

Home Page: https://www.ical4j.org

License: BSD 3-Clause "New" or "Revised" License

HTML 0.24% Shell 1.98% Groovy 15.29% Java 82.44% Makefile 0.05%
icalendar scheduling library java

ical4j's Introduction

iCal4j - iCalendar parser and object model

Table of Contents

  1. Introduction - What is iCal4j?
  2. Setup - Download and installation of iCal4j
  3. Usage - The iCal4j object model and how to use it
  4. References
  5. Configuration options
  6. Development - Guide for contributing to the iCalj project

Introduction

iCal4j is a Java library used to read and write iCalendar data streams as defined in RFC2445. The iCalendar standard provides a common data format used to store information about calendar-specific data such as events, appointments, to-do lists, etc. All of the popular calendaring tools, such as Lotus Notes, Outlook and Apple's iCal also support the iCalendar standard.

  • For a concise description of the goals and directions of iCal4j please take a look at the open issues.

  • You will find examples of how to use iCal4j in the official website and throughout the API documentation.

  • Detailed descriptions of changes included in each release may be found in the CHANGELOG.

  • iCal4j was created with the help of Open Source software.

Setup

System requirements

  • Version 4.x - Java 8 or later
  • Version 3.x - Java 8 or later
  • Version 2.x - Java 7 or later

Dependencies

In the interests of portability and compatibility with as many environments as possible, the number of dependent libraries for iCal4j is kept to a minimum. The following describes the required (and optional) dependencies and the functionality they provide.

  • slf4j-api [required] - A logging meta-library with integration to different logging framework implementations. Used in all classes that require logging.

  • commons-lang3 [required] - Provides enhancements to the standard Java library, including support for custom equals() and hashcode() implementations. Used in all classes requiring custom equality implementations.

  • commons-collections4 [required] - Provides enhancements to the standard Java collections API, including support for closures. Used in net.fortuna.ical4j.validate.Validator implementations to reduce the duplication of code in validity checks.

  • javax.cache.cache-api [optional*] - Supports caching timzeone definitions. * NOTE: when not included you must set a value for the net.fortuna.ical4j.timezone.cache.impl configuration

  • commons-codec [optional] - Provides support for encoding and decoding binary data in text form. Used in net.fortuna.ical4j.model.property.Attach

  • groovy-all [optional] - The runtime for the Groovy language. Required for library enhancements such as iCalendar object construction using the net.fortuna.ical4j.model.ContentBuilder DSL. This library is optional for all non-Groovy features of iCal4j.

  • bndlib [optional] - A tool for generating OSGi library metadata and packaging OSGi bundles. This library is not a runtime requirement, and is used only to generate version information in the javadoc API documentation.

Release Downloads

Install with Maven

Install with Gradle

Usage

Examples

References

  • RFC5545 - Internet Calendaring and Scheduling Core Object Specification (iCalendar)
  • RFC5546 - iCalendar Transport-Independent Interoperability Protocol (iTIP)
  • RFC6047 - iCalendar Message-Based Interoperability Protocol (iMIP)
  • RFC6868 - Parameter Value Encoding in iCalendar and vCard
  • RFC7953 - Calendar Availability
  • RFC7808 - Time Zone Data Distribution Service
  • RFC7986 - New Properties for iCalendar
  • RFC7529 - Non-Gregorian Recurrence Rules in iCalendar
  • RFC9073 - Event Publishing Extensions to iCalendar
  • RFC9074 - "VALARM" Extensions for iCalendar
  • RFC9253 - Support for iCalendar Relationships

Configuration

net.fortuna.ical4j.parser=net.fortuna.ical4j.data.HCalendarParserFactory

net.fortuna.ical4j.timezone.registry=net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory

net.fortuna.ical4j.timezone.update.enabled={true|false}

net.fortuna.ical4j.factory.decoder=net.fortuna.ical4j.util.DefaultDecoderFactory

net.fortuna.ical4j.factory.encoder=net.fortuna.ical4j.util.DefaultEncoderFactory

net.fortuna.ical4j.recur.maxincrementcount=1000

net.fortuna.ical4j.timezone.cache.impl=net.fortuna.ical4j.util.MapTimeZoneCache

Compatibility Hints

Relaxed Parsing

ical4j.parsing.relaxed={true|false}

iCal4j now has the capability to "relax" its parsing rules to enable parsing of *.ics files that don't properly conform to the iCalendar specification (RFC2445)

This property is intended as a general relaxation of parsing rules to allow for parsing otherwise invalid calendar files. Initially enabling this property will allow for the creation of properties and components with illegal names (e.g. Mozilla Calendar's "X" property). Note that although this will allow for parsing calendars with illegal names, validation will still identify such names as an error in the calendar model.

  • You can relax iCal4j's unfolding rules by specifying the following system property:

     ical4j.unfolding.relaxed={true|false}
    

Note that I believe this problem is not restricted to Mozilla calendaring products, but rather may be caused by UNIX/Linux-based applications relying on the default newline character (LF) to fold long lines (KOrganizer also seems to have this problem). This is, however, still incorrect as by definition long lines are folded using a (CRLF) combination.

I've obtained a couple of samples of non-standard iCalendar files that I've included in the latest release (0.9.11). There is a Sunbird, phpicalendar, and a KOrganizer sample there (open them in Notepad on Windows to see what I mean).

It seems that phpicalendar and KOrganizer always use LF instead of CRLF, and in addition KOrganizer seems to fold all property parameters and values (similar to Mozilla Calendar/Sunbird).

Mozilla Calendar/Sunbird uses CRLF to fold all property parameter/values, however it uses just LF to fold long lines (i.e. longer than 75 characters).

The latest release of iCal4j includes changes to UnfoldingReader that should work correctly with Mozilla Calendar/Sunbird, as long as the ical4j.unfolding.relaxed system property is set to true.

KOrganizer/phpicalendar files should also work with the relaxed property, although because ALL lines are separated with just LF it also relies on the StreamTokenizer to correctly identify LF as a newline on Windows, and CRLF as a newline on UNIX/Linux. The API documentation for Java 1.5 says that it does do this, so if you still see problems with parsing it could be a bug in the Java implementation.

The full set of system properties may be found in net.fortuna.ical4j.util.CompatibilityHints.

iCal4j and Timezones

net.fortuna.ical4j.timezone.date.floating={true|false}

Supporting timezones in an iCalendar implementation can be a complicated process, mostly due to the fact that there is not a definitive list of timezone definitions used by all iCalendar implementations. This means that an iCalendar file may be produced by one implementation and, if the file does not include all definitions for timezones relevant to the calendar properties, an alternate implementation may not know how to interpret the timezone identified in the calendar (or worse, it may interpret the timezone differently to the original implementation). All of these possibilities mean unpredictable behaviour which, to put it nicely, is not desireable.

iCal4j approaches the problem of timezones in two ways: The first and by far the preferred approach is for iCalendar files to include definitions for all timezones referenced in the calendar object. To support this, when an existing calendar is parsed a list of VTimeZone definitions contained in the calendar is constructed. This list may then be queried whenever a VTimeZone definition is required.

The second approach is to rely on a registry of VTimeZone definitions. iCal4j includes a default registry of timezone definitions (derived from the Olson timezone database - a defacto standard for timezone definitions), or you may also provide your own registry implementation from which to retreieve timezones. This approach is required when constructing new iCalendar files.

Note that the intention of the iCal4j model is not to provide continuous validation feedback for every change in the model. For this reason you are free to change timezones on Time objects, remove or add TzId parameters, remove or add VTimeZone definitions, etc. without restriction. However when validation is run (automatically on output of the calendar) you will be notified if the changes are invalid.

Validation

ical4j.validation.relaxed={true|false}

Micosoft Outlook compatibility

ical4j.compatibility.outlook={true|false}

Behaviour:

  • Enforces a folding length of 75 characters (by default ical4j will fold at 73 characters)
  • Allows for spaces when parsing a WEEKDAY list

Microsoft Outlook also appears to provide quoted TZID parameter values, as follows:

DTSTART;TZID="Pacific Time (US & Canada),Tijuana":20041011T223000

Lotus Notes compatibility

ical4j.compatibility.notes={true|false}

Development

Building with Gradle

iCal4j includes the Gradle wrapper for a simpler and more consistent build.

Run unit tests

./gradlew clean test

Build a new release

./gradlew clean test release -Prelease.forceVersion=2.0.0

Upload release binaries and packages

RELEASE_VERSION=2.0.0 ./gradlew uploadArchives uploadDist

Redistribution

If you intend to use and distribute iCal4j in your own project please follow these very simple guidelines:

  • Make a copy of the LICENSE, rename it to LICENSE.ical4j, and save it to the directory where you are re-distributing the iCal4j JAR.

  • I don't recommend extracting the iCal4j classes from its JAR and package in another JAR along with other classes. It may lead to version incompatibilites in the future. Rather I would suggest to include the ical4j.jar in your classpath as required.

Contributing

Open source software is made stronger by the community that supports it. Through participation you not only contribute to the quality of the software, but also gain a deeper insight into the inner workings.

Contributions may be in the form of feature enhancements, bug fixes, test cases, documentation and forum participation. If you have a question, just ask. If you have an answer, write it down.

And if you are somehow constrained from participation, through corporate policy or otherwise, consider financial support. After all, if you are profiting from open source it's only fair to give something back to the community that make it all possible.

ical4j's People

Contributors

arnaudq avatar arnyminerz avatar artheus avatar benfortuna avatar bgabrhelik avatar danielgrigore avatar db82407 avatar douglm avatar edwhiting avatar gitter-badger avatar grishick avatar hoijui avatar jcjveraa avatar leccyril avatar mernst avatar mkroening avatar nealeu avatar pashazz avatar peterox avatar pinhead84 avatar rfc2822 avatar ryejoon avatar schnatterer avatar sergiivlasiuk avatar singingbush avatar spitty avatar t-h-e avatar tbee avatar voronaam avatar ztravis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ical4j's Issues

create fluent API

Get a fluent API (DSL), in addition of the existing API style.
If you're ok with this kind of idea, i could be work on it and submit a PR

For example:

            Calendar calendar = new Calendar();
            PropertyList calendarProperties = calendar.getProperties();
            calendarProperties.add(new ProdId("-//Test//iCal4j 1.0//EN"));
            calendarProperties.add(Version.VERSION_2_0);
            calendarProperties.add(Method.REQUEST);

Fluent equivalent

Calendar calendar = new Calendar().version(VERSION_2_0)
                                  .prodId()
                                    .value("-//Test//iCal4j 1.0//EN")
                                  .method(REQUEST)
                                  .event(new VEvent(/**/));

TZID of DTSTART completely ignored when VALUE=DATE

Summary

ical4j seems to completely ignore the TZID parameter in DTSTART when VALUE=DATE.

Example .ics file:

https://www.mozilla.org/projects/calendar/caldata/JapanHolidays.ics

Example DTSTART:

DTSTART;VALUE=DATE;TZID=/mozilla.org/20070129_1/Asia/Tokyo:20070101

After parsing, Period.getStart() returns 20070101T000000Z. Expected is something like 20070101T000000+0900.

More details:

Actually, this behavior is somewhat documented in DateProperty.java, as it partially states that time zones are not supported by ical4j when VALUE=DATE (and effectively, unfortunately, become UTC).

    public void setValue(final String value) throws ParseException {
        // value can be either a date-time or a date..
        if (Value.DATE.equals(getParameter(Parameter.VALUE))) {
            // ensure timezone is null for VALUE=DATE properties..
            updateTimeZone(null);
    /**
     * Updates the timezone associated with the property's value. If the specified timezone is equivalent to UTC any
     * existing TZID parameters will be removed. Note that this method is only applicable where the current date is an
     * instance of <code>DateTime</code>. For all other cases an <code>UnsupportedOperationException</code> will be
     * thrown.
     * @param vTimeZone
     */
    private void updateTimeZone(final TimeZone timezone) {

Issue parsing EXDATE with America/Grand_Turk timezone

First of all this is with version 1.0.7, so I apologize if this should not be brought up here.

When I try to parse a recurrence rule with an EXDATE;TZID=America/Grand_Turk:20110630T133000 I get a ParseException:

java.text.ParseException: [EXDATE] Unparseable date: "20110630T133000"
    at net.fortuna.ical4j.data.CalendarParserImpl$PropertyParser.parse(CalendarParserImpl.java:252)
    at net.fortuna.ical4j.data.CalendarParserImpl$PropertyParser.access$1(CalendarParserImpl.java:200)
    at net.fortuna.ical4j.data.CalendarParserImpl$PropertyListParser.parse(CalendarParserImpl.java:178)
    at net.fortuna.ical4j.data.CalendarParserImpl$ComponentParser.parse(CalendarParserImpl.java:390)
    at net.fortuna.ical4j.data.CalendarParserImpl$ComponentParser.access$1(CalendarParserImpl.java:376)
    at net.fortuna.ical4j.data.CalendarParserImpl$PropertyListParser.parse(CalendarParserImpl.java:175)
    at net.fortuna.ical4j.data.CalendarParserImpl.parse(CalendarParserImpl.java:125)
    ... 30 more
Caused by: java.text.ParseException: Unparseable date: "20110630T133000"
    at java.text.DateFormat.parse(DateFormat.java:366)
    at net.fortuna.ical4j.model.DateTime.setTime(DateTime.java:397)
    at net.fortuna.ical4j.model.DateTime.<init>(DateTime.java:303)
    at net.fortuna.ical4j.model.DateList.<init>(DateList.java:141)
    at net.fortuna.ical4j.model.property.DateListProperty.setValue(DateListProperty.java:116)
    at net.fortuna.ical4j.data.CalendarBuilder$ContentHandlerImpl.propertyValue(CalendarBuilder.java:318)
    at net.fortuna.ical4j.data.CalendarParserImpl$PropertyParser.parse(CalendarParserImpl.java:249)
    ... 36 more

If I change the timezone to AST or Etc/GMT-4 it works fine.

Here's some test code:

        String parseText = "BEGIN:VCALENDAR\n" +
                "PRODID:SPANNING EXPORT\n" +
                "VERSION:2.0\n" +
                "CALSCALE:GREGORIAN\n" +
                "METHOD:PUBLISH\n" +
                "BEGIN:VEVENT\n" +
                "EXDATE;TZID=America/Grand_Turk:20110630T133000\n" +
                "END:VEVENT\n" +
                "END:VCALENDAR"

        // Now pass the parseText string into the CalendarBuilder to be parsed into a Calendar instance.
        ByteArrayInputStream in = new ByteArrayInputStream(parseText.getBytes(StandardCharsets.UTF_8));
        Reader reader = new InputStreamReader(in);
        CalendarBuilder calendarBuilder = new CalendarBuilder();
        Calendar recurrenceCalendar = calendarBuilder.build(reader);
        return (VEvent) recurrenceCalendar.getComponent(Component.VEVENT);

I don't know if this is at all useful, but both the start date and the end date for the calendar entry I'm trying to convert to iCal specify the same time timezone and work swimmingly.

Oh, and more possibly useless information, I do have a Grand_Turk.ics file in my zoneinfo/America directory, and I haven't messed the timezone registration stuff at all.

Groovy dependency

I was surprised to find out that ical4j library depends on groovy-all.jar, which makes it very expensive to add. We only use ical4j for simple ical generation, do we still need to ship groovy-all.jar?

I will appreciate for some clarification for when this library needed and when can be safely omitted.

Recur not supporting BY* Expansion

I was just reviewing the code in Recur.getCandidates, and it really looks like all By* handling code is ony doing filtering, no expansion. I'll continue to delve in and see if i can give you an automated test, but wanted to get the ball rolling.

I'm expecting that FREQ=WEEKLY;BYDAY=MO,WE,FR will expand out to 3 days per week for eternity. But I swear that Recur.getDayVariants only enforces the filtering/limit operation of BYDAY, not the expansion aspect.

The spec does mention that the BY* operations react differently depending on if they're smaller or larger than the FREQ scope:

http://www.kanzaki.com/docs/ical/recur.html

BYxxx rule parts modify the recurrence in some manner. BYxxx rule parts for a period of time which is the same or greater than the frequency generally reduce or limit the number of occurrences of the recurrence generated. For example, "FREQ=DAILY;BYMONTH=1" reduces the number of recurrence instances from all days (if BYMONTH tag is not present) to all days in January. BYxxx rule parts for a period of time less than the frequency generally increase or expand the number of occurrences of the recurrence. For example, "FREQ=YEARLY;BYMONTH=1,2" increases the number of days within the yearly recurrence set from 1 (if BYMONTH tag is not present) to 2.

It looks like someone else ran into this as well:

http://icalevents.com/2447-need-to-know-the-possible-combinations-for-repeating-dates-an-ical-cheatsheet/

ClassCastException in Cal4j beta 1

ClassCastException Back traces

+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+
| Name | Count |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+
| +---net.fortuna.ical4j.data.CalendarBuilder.updateTimeZone(Property, TimeZone) CalendarBuilder.java:353 | 238 96 % |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarBuilder.access$300(CalendarBuilder, Property, TimeZone) CalendarBuilder.java:68 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarBuilder$ContentHandlerImpl.parameter(String, String) CalendarBuilder.java:278 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$ParameterParser.parse(StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:328 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$ParameterParser.access$1700(CalendarParserImpl$ParameterParser, StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:283 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$ParameterListParser.parse(StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:271 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$PropertyParser.parse(StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:208 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$PropertyParser.access$1100(CalendarParserImpl$PropertyParser, StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:190 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$PropertyListParser.parse(StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:173 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$ComponentParser.parse(StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:383 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$ComponentParser.access$900(CalendarParserImpl$ComponentParser, StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:367 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl$PropertyListParser.parse(StreamTokenizer, Reader, ContentHandler) CalendarParserImpl.java:171 | |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserImpl.parse(Reader, ContentHandler) CalendarParserImpl.java:122 | |
| | | |
| +---com.stimulus.archiva.connect.google.GoogleUserSync.getHistoryID(GoogleUserAdapter) GoogleUserSync.java:394 | 9 4 % |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------+

Generated by YourKit Java Profiler 2014 build 14114 13 Nov 2015 10:50:07 AM

calculateRecurrenceSet does not discard invalid dates

When I want to calculate the recurrence set of a monthly recurring event that starts on a date with day of month > 28, I am getting unexpected results.

Example:

VEvent vEvent = new VEvent();
Date startDate = new Date("20140630");
vEvent.getProperties().add(new DtStart(startDate, true));

String recurrenceRule = "FREQ=MONTHLY";
vEvent.getProperties().add(new RRule(new Recur(recurrenceRule)));

PeriodList recurrenceSet = vEvent.calculateRecurrenceSet(
   new Period(new DateTime(startDate), new DateTime("20150630T000000Z")));

This will give me the following periods:

20140630T000000Z/PT0S
20140730T000000Z/PT0S
20140830T000000Z/PT0S
20140930T000000Z/PT0S
20141030T000000Z/PT0S
20141130T000000Z/PT0S
20141230T000000Z/PT0S
20150130T000000Z/PT0S
20150228T000000Z/PT0S
20150328T000000Z/PT0S
20150428T000000Z/PT0S
20150528T000000Z/PT0S
20150628T000000Z/PT0S

As you can see, starting with February 2015, the date is changed to 28. I would either expect that the invalid date 2015-02-30 would be discarded and not converted to 2015-02-28 or that the next occurrence would be 2015-03-30 and not 2015-03-28.

Is this the intended behavior of ical4j or is it a bug?

Version: 1.0.3, but latest (1.0.5.2) is also affected.

High memory consumption

We are using iCal4j beta 1 in our server application. The code base of our application is substantial in size and is using many libraries. iCal4j seems to consume more memory than any other library we use (see below for Yourkit memory shot).

How can it be that that there CalendarDateFormatFactory keeps a reference to 589,301 TimeFormat objects? Furthermore, how can it be that there are 534,901 Time objects? Is there some kind of cleanup function that we are not calling? Unless we are using it incorrectly, the iCal4j does not appear to be utilizing resources efficiently.

Thanks in advance for your input.

Issue with rrule detecting last day of month when months are specified

I build an RRULE as follows:

FREQ=MONTHLY;WKST=MO;INTERVAL=1;BYMONTH=2,3,9,10;BYMONTHDAY=28,29,30,31;BYSETPOS=-1

The intention for the above RRULE is to return the last day of month specified by the BYMONTH list. So in this case I expect the above rule to return the following:

Feb 28, 2015
Mar 31, 2015
Sep 30, 2015
Oct 31, 2015
Feb 29, 2015
... etc ...

So if I input July 1, 2015 as the starting date, then I will get Sep 30, 2015 as the next recurrence. I think this rule is correct as intended, by verifying it here: http://jkbrzt.github.io/rrule/

However, ical4j gives different result. I can see the candidate dates are calculated first resulting in the set similar to the following:
Feb 28, 2015
Mar 28, 2015
Mar 29, 2015
Mar 30, 2015
Mar 31, 2015
... etc...

This set is then the input to the BYSETPOS evaluation, in this case -1, which results in the last occurrence in the set being returned, irrespective the starting date.

Can we confirm if this is an issue with iCal4j?

EMAIL parameter not supported?

Caused by: java.lang.IllegalArgumentException: Unsupported parameter name: EMAIL
at net.fortuna.ical4j.model.ParameterFactoryImpl.createParameter(ParameterFactoryImpl.java:90)

ATTENDEE;CN=U O;CUTYPE=INDIVIDUAL;EMAIL=gj@localhost;PARTSTAT=NE
EDS-ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.2:urn:x-uid:gj

I use Darwin Calendar Server 6.0

XProperty as Duration

Hi,

I'd like to parse a duration field i.e : "PT30M" stored in a XProperty but :

java.lang.ClassCastException: net.fortuna.ical4j.model.property.XProperty cannot be cast to net.fortuna.ical4j.model.property.Duration

which makes sense because they both extends from Property...

Support for X-WR-TIMEZONE?

Hi all,

We're using ical4j (currently 1.0.5.2) to read any sorts of feeds from all over the internet. A problem we found is with feeds that have dates in local time, but no proper VTIMEZONE definition. Those feeds typically use the X-WR-TIMEZONE header to specifiy which time zone must be used to interpret the local times.

There is an article explaining the situation here: http://blog.jonudell.net/2011/10/17/x-wr-timezone-considered-harmful/

Now I do not entirely understand the code of ical4j, but as far as I can tell it does not care about the X-WR-TIMEZONE header at all, but falls back to the machine's local time zone (java.util.TimeZone.getDefault()) instead. This is consistent with what our experiments with real feed data showed us.

Now since the library runs on a server and our users use all sorts of time zones in the feeds and to view the feed data, the fall-back to the server's time zone is just plain wrong in our case. I imagine that interpreting the X-WR-TIMEZONE header as an Olson DB name and trying to convert it to a java.util.TimeZone should not be too difficult to do.

Am I right? If yes, is support for X-WR-TIMEZONE planned? If not, consider this to be a feature request :)

Thank you!

Recur.java setters?

I have an application in which I'm forced to recreate Recur objects every time a recurrence string changes instead of modifying a single Recur object. This is due to the fact that Recur doesn't expose accessors to all its properties. It's there a reason behind this?

If I created a pull request for this feature would it be considered?

ParserException illegal property for ics-files having breaks in the description

when running
FileInputStream fin = new FileInputStream(filename);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(fin);
I am getting the below exception with ical4j 2-beta1 and 1.0.7

Exception in thread "main" net.fortuna.ical4j.data.ParserException: Error at line 25:Illegal property [ SAALE)HBF, GLEIS 8\N\N2)]
at net.fortuna.ical4j.data.CalendarParserImpl.parse(CalendarParserImpl.java:148)
at net.fortuna.ical4j.data.CalendarBuilder.build(CalendarBuilder.java:210)
at net.fortuna.ical4j.data.CalendarBuilder.build(CalendarBuilder.java:191)
at net.fortuna.ical4j.data.CalendarBuilder.build(CalendarBuilder.java:179)
at com.penguineering.snuselpi.Weckzeitfinder.main(Weckzeitfinder.java:49)
Caused by: java.lang.IllegalArgumentException: Illegal property [ SAALE)HBF, GLEIS 8\N\N2)]
at net.fortuna.ical4j.model.PropertyFactoryImpl.createProperty(PropertyFactoryImpl.java:978)
at net.fortuna.ical4j.data.CalendarBuilder$ContentHandlerImpl.startProperty(CalendarBuilder.java:346)
at net.fortuna.ical4j.data.CalendarParserImpl$PropertyParser.parse(CalendarParserImpl.java:211)
at net.fortuna.ical4j.data.CalendarParserImpl$PropertyParser.access$1(CalendarParserImpl.java:200)
at net.fortuna.ical4j.data.CalendarParserImpl$PropertyListParser.parse(CalendarParserImpl.java:178)
at net.fortuna.ical4j.data.CalendarParserImpl$ComponentParser.parse(CalendarParserImpl.java:390)
at net.fortuna.ical4j.data.CalendarParserImpl$ComponentParser.access$1(CalendarParserImpl.java:376)
at net.fortuna.ical4j.data.CalendarParserImpl$PropertyListParser.parse(CalendarParserImpl.java:175)
at net.fortuna.ical4j.data.CalendarParserImpl.parse(CalendarParserImpl.java:125)
... 4 more

this is the calendar entry:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//dmfs.org//mimedir.icalendar//EN
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=Europe/Berlin:20150322T170300
DESCRIPTION:1) IC 2239\n Ab 17:03 Magdeburg Hbf, Gleis 3\n An 17:53 Halle(
Saale)Hbf, Gleis 8\n\n2) ICE 1715\n Ab 18:00 Halle(Saale)Hbf, Gleis 3\n
An 19:09 Erfurt Hbf\n\n3) ICE 1572\n Ab 19:18 Erfurt Hbf, Gleis 1\n An 21
:35 Frankfurt(Main)Süd, Gleis 7\n\n4) S 4\n-> Kronberg(Taunus)\n Ab 21:4
8 Frankfurt(Main)Süd, Gleis 4\n An 21:53 Frankfurt(M)Konstablerwache, G
leis 3\n\n5) Fußweg 4 Minuten\n\n6) U 6\n-> Praunheim Heerstraße, Frank
furt am Main\n Ab 21:57 Konstablerwache, Frankfurt am Main\n An 22:10 Hau
sener Weg, Frankfurt am Main\n
SUMMARY:Fahrt von Magdeburg Hbf nach Hausener Weg, Frankfurt am Main; Ums
tiege: 4x; Dauer: 05:07
LOCATION:Magdeburg Hbf
TRANSP:OPAQUE
DTEND;TZID=Europe/Berlin:20150322T221000
LAST-MODIFIED:20150322T160358Z
DTSTAMP:20150322T160358Z
CREATED:20150322T160358Z
UID:08b5d9ea-7759-4804-916e-6b1ec6f7fbe5
BEGIN:VALARM
TRIGGER;VALUE=DURATION:-PT15M
ACTION:DISPLAY
DESCRIPTION:Default Event Notification
X-WR-ALARMUID:92011d6e-04b6-420f-b8b9-df0f78ff47d9
END:VALARM
END:VEVENT
END:VCALENDAR

What can I do to parse those files?

Parsing VCALENDAR with only one VTIMEZONE possible?

Hello,

Thanks for your new 2.0-beta1 release. I have a question: is it possible to parse a VCALENDAR with only one VTIMEZONE component with the current ical4j version? Background: Calendar collections on CalDAV servers have a property called calendar-timezone which is »an iCalendar object with exactly one VTIMEZONE component«.

For instance, a server returns:

<?xml version='1.0' encoding='UTF-8'?>
<multistatus xmlns='DAV:'>
  <response>
    <href>/xxxxx/calendars/home/</href>
    <propstat>
      <prop>
        <calendar-timezone xmlns='urn:ietf:params:xml:ns:caldav'><![CDATA[BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//Mac OS X 10.9.4//EN
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:America/Los_Angeles
BEGIN:DAYLIGHT
TZOFFSETFROM:-0800
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
DTSTART:20070311T020000
TZNAME:GMT-7
TZOFFSETTO:-0700
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0700
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
DTSTART:20071104T020000
TZNAME:GMT-8
TZOFFSETTO:-0800
END:STANDARD
END:VTIMEZONE
END:VCALENDAR
]]></calendar-timezone>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>

When I try to parse this string (the content of calendar-timezone) with Calendar cal = builder.build(new StringReader(timezoneDef)), cal.getComponents() returns only one component which is of type net.fortuna.ical4j.model.component.XComponent, so I can't get the TZID.

Is there a new way to parse such a time zone definition?

NullPointer exception in ical4j beta 1

Back traces

+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+
| Name | Count |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+
| +---java.lang.Class.forName(String) Class.java:264 | 2 33 % |
| | | |
| +---java.util.Properties$LineReader.readLine() Properties.java:434 | 2 33 % |
| | | | |
| | +---java.util.Properties.load(InputStream) Properties.java:341 | |
| | | | |
| | +---net.fortuna.ical4j.model.TimeZoneRegistryImpl.() TimeZoneRegistryImpl.java:107 | 1 17 % |
| | | | | |
| | | +---net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory.createRegistry() DefaultTimeZoneRegistryFactory.java:48 | |
| | | | | |
| | | +---net.fortuna.ical4j.data.CalendarBuilder.() CalendarBuilder.java:104 | |
| | | | | |
| | | +---com.stimulus.archiva.plugin.blob.ICalBlob.parse(Data) ICalBlob.java:81 | |
| | | | | |
| | | +---com.stimulus.archiva.plugin.blob.AbstractCommonBlob.init(Data, PxBlobID, Principal) AbstractCommonBlob.java:63 | |
| | | | | |
| | | +---com.stimulus.archiva.plugin.blob.ICalBlob.init(Data, PxBlobID, Principal) ICalBlob.java:1 | |
| | | | | |
| | | +---com.stimulus.archiva.blob.Blob.init(Data, BlobID, FieldValues, Principal) Blob.java:110 | |
| | | | | |
| | | +---com.stimulus.archiva.service.BlobService.insertBlob(Principal, Connection, String, String, String, Data, boolean, int, TimeUnit) BlobService.java:661 | |
| | | | | |
| | | +---com.stimulus.archiva.connect.exchange.ExchangeConnectionHelper.updateBlob(ExchangeLink$ExchangeItem, String, boolean) ExchangeConnectionHelper.java:45 | |
| | | | | |
| | | +---com.stimulus.archiva.connect.exchange.ExchangeSync$ObjectFoundCallback.createItem(ExchangeLink$ExchangeItem) ExchangeSync.java:339 | |
| | | | | |
| | | +---com.stimulus.archiva.connect.exchange.AbstractEWSExchangeLink.syncItems(ExchangeLink$ExchangeFolder, ExchangeLink$ItemListener, String) AbstractEWSExchangeLink.java:885 | |
| | | | | |
| | | +---com.stimulus.archiva.connect.exchange.EWSOffice365Link.syncItems(ExchangeLink$ExchangeFolder, ExchangeLink$ItemListener, String) EWSOffice365Link.java:1 | |
| | | | |
| | +---net.fortuna.ical4j.util.Configurator.() Configurator.java:57 | 1 17 % |
| | | |
| +---com.stimulus.archiva.monitor.StatusService$Summary.getVolumesStatus() StatusService.java:345 | 1 17 % |
| | | |
| +---org.subethamail.smtp.command.AuthCommand.execute(String, Session) AuthCommand.java:88 | 1 17 % |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------+

Generated by YourKit Java Profiler 2014 build 14114 13 Nov 2015 10:53:21 AM

Documentation / Support Request

I've modified davdroid on android which is using ical4j. Unfortunately parsing my calendar entries yields XComponents and all properties are XProperties.

Thus I get massive errors using it, like class cast exceptions on .getUid() which leads me to assume the factory creation process is not working as intended.

Is there anything I am missing? Any configuration to influcence which properties are created?

NullPointerException in ical4j beta

java.lang.NullPointerException Back traces

+---------------------------------------------------------------------------------------------------------------------------------+------------+
| Name | Count |
+---------------------------------------------------------------------------------------------------------------------------------+------------+
| +---java.lang.Class.forName(String) Class.java:264 | 2 50 % |
| | | | |
| | +---net.fortuna.ical4j.data.CalendarParserFactory.() CalendarParserFactory.java:63 | 1 25 % |
| | | | | |
| | | +---net.fortuna.ical4j.data.CalendarBuilder.() CalendarBuilder.java:104 | |
| | | | | |
Generated by YourKit Java Profiler 2014 build 14114 25 Nov 2015 9:01:29 AM

Rrule incorrectly includes invalidCandidateCount in the count check

Consider for example this RRULE: FREQ=MONTHLY;WKST=FR;COUNT=3;INTERVAL=1;BYMONTH=1,9,10,12;BYMONTHDAY=12

Evaluated today it should give Oct 12, Dec 12 and Jan 12. Using iCal4j 2.0.1beta (and 1.0.6 as well) this is not happening. Only Oct 12 and Dec 12 are returned and Jan 12 is ruled out by the count check:

if (getCount() >= 1
    && (dates.size() + invalidCandidateCount) >= getCount()) {

That is in Recur.class:getDates(), line 630 (as of now).

This check should not include invalid candidates (the ones that were filtered out by BYMONTH rule in this example)

UTC timezone alias are being mapped to Europe/London

Hi,

Europe/London observes daylight saving, so it's not a good candidate for replacing UTC and its variants. I am able to fix this issue for my distribution by generating ics files from etcetera (containing timezones like Etc/GMT, Etc/Zulu).

I am not sure if that's the appropriate solution, but if you don't mind adding those extra ics - I could create a patch for you that address the UTC issue.

TimeZones

This is more sort of a question. I could not find a method to get or create VTimeZone object if I have offset from GMT (Greenwich Mean Time), i.e "GMT-8:00" or "GMT+3:30" etc.

Wrong output from RRULE

Hi, I was testing out some RRules from the RFC page but when I tested a particular rule ical returned the wrong set of dates.

The rule is FREQ=DAILY;BYMONTH=1
Start date = 2000-01-01
End date = 2000-02-01

This should return 31 dates but returns 366.
The output was multiple duplicated dates.
If I change the end date to 2000-01-30 it works up to that date but with 31 it duplicates the dates.
selection_002

Isolated issues with creating calendars.

I am having an issue creating calendars. When running on my local machine the following code works great.

final Calendar calendar = new Calendar();
calendar.getProperties().add(new XProperty("X-EXCHANGE-UUID", calendarID));
calendar.getProperties().add(Version.VERSION_2_0);
calendar.getProperties().add(CalScale.GREGORIAN);
calendar.getProperties().add(Method.PUBLISH);
calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
calendar.getProperties().add(new XProperty("X-WR-CALNAME", folderName));

However when running on the intended server it fails. The issue seems to be related to the lines...

calendar.getProperties().add(new XProperty("X-EXCHANGE-UUID", calendarID));
calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
calendar.getProperties().add(new XProperty("X-WR-CALNAME", folderName));

any code that follows any of these lines does not get executed when ran on our server. No errors are being thrown.

Any ideas what may be causing the issue on one machine and not the other?

Unparseable date

Hello,

I just started using iCal4j for my Android project, it's great but it seems to have problems with the datestamp.
It just seems unable to parse dates like this: 20151022T164500780Z.
The date should be correct (it's generated on the server.)

I tried searching around and the suggestion of enabling the relaxed parsing came up. So, I tried to add:

CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);

That worked but it also changed all the datestamps into today datestamp.

What can I do to fix this problem?

How to get the right start and end date of a recurring event?

Hi,

I hope I'm allowed to ask questions here.

I'm trying to get events for the next 24 hours and so far I get all of them. However the recurring event has wrong start and end date, i.e. the start and end date are the dates when the event was created.

Example: I created an every day recurring event on 10.06.15 from 1pm to 2pm. For the next 24 hours I have following three events:

  • 13.06.15 10am - 11am event1
  • 13.06.15 1pm - 2pm (the recurring event) event2
  • 13.06.15 4pm - 6pm event3

I get all three events, however the event2 (the recurring event ) has start and end date 10.06.15 instead 13.06.15. How to get the right start and end date for recurring events? I have also posted the question on stackoverflow.

Thanks in advance

ical4j.properties in Android Studio/Gradle

Hi,

I'm not able to make ical4j find my ical4j.properties.

I've tried to put it at several places :

  • src/main/
  • src/main/java/
  • src/main/java/com/blabla/myapp/

but always end up with "I/Configurator﹕ ical4j.properties not found."

Has anyone succeed in doing this ?

Thanks in advance,

Memory leak occurred (in StrictMode)

Hello. I'm a software engineer developing an android application.
First above all, i'd like to say "thank you" for your support.
I've developed all of things related with the ical4j module.

But, i got an issue for memory leak when composing an event.
It was occurred in TimeZoneRegistryFactory.
I guess the stream is leaked..because the thread is un-safe.

Is there any workaround for this?
(i.e options..)

Thanks.

05-12 10:48:08.808 952-967/com.android.calendar E/StrictMode﹕ A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'end' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:184)
at java.util.zip.Inflater.(Inflater.java:82)
at java.util.zip.ZipFile.getInputStream(ZipFile.java:331)
at java.util.jar.JarFile.getInputStream(JarFile.java:390)
at libcore.net.url.JarURLConnectionImpl.getInputStream(JarURLConnectionImpl.java:222)
at java.net.URL.openStream(URL.java:470)
at java.lang.ClassLoader.getResourceAsStream(ClassLoader.java:444)
at net.fortuna.ical4j.util.ResourceLoader.getResourceAsStream(ResourceLoader.java:77)
at net.fortuna.ical4j.model.TimeZoneRegistryImpl.(TimeZoneRegistryImpl.java:76)
at net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory.createRegistry(DefaultTimeZoneRegistryFactory.java:48)
at com.android.calendar.icalendar.encoder.BaseEventEncoder.addDateTimeProperty(BaseEventEncoder.java:169)

Can ical4j identify exceptions to recurring calendar events?

I get an iCalendar file from an external source, over which I have no control, and in that file there are entries like these:

BEGIN:VEVENT
DTSTART;TZID=Europe/Zurich:20130511T051500
DTEND;TZID=Europe/Zurich:20130511T171559
DTSTAMP:20150822T121746Z
UID:06984C6F68C24922B235F7C4D5DDA98D00000000000000000000000000000000
RECURRENCE-ID;VALUE=DATE:20130511
CREATED:20120117T180152Z
DESCRIPTION:Event info particular to this occurrence
LAST-MODIFIED:20150516T235258Z
LOCATION:
SEQUENCE:3
STATUS:CONFIRMED
SUMMARY:A recurring event
TRANSP:OPAQUE
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20150509
DTEND;VALUE=DATE:20150510
DTSTAMP:20150822T121746Z
UID:06984C6F68C24922B235F7C4D5DDA98D00000000000000000000000000000000
RECURRENCE-ID;VALUE=DATE:20150509
CREATED:20120117T180152Z
DESCRIPTION:Other event info particular to this occurrence
LAST-MODIFIED:20150509T093901Z
LOCATION:
SEQUENCE:2
STATUS:CONFIRMED
SUMMARY:A different summary for this occurrence
TRANSP:OPAQUE
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15H
X-WR-ALARMUID:85257BF6-4591-4522-A479-706130730C65
UID:85257BF6-4591-4522-A479-706130730C65
ATTACH;VALUE=URI:Basso
X-APPLE-DEFAULT-ALARM:TRUE
ACKNOWLEDGED:20150509T093901Z
END:VALARM
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20120512
DTEND;VALUE=DATE:20120513
RRULE:FREQ=MONTHLY;INTERVAL=12;BYDAY=2SA
EXDATE;VALUE=DATE:20140510
DTSTAMP:20150822T121746Z
UID:06984C6F68C24922B235F7C4D5DDA98D00000000000000000000000000000000
CREATED:20120117T180152Z
DESCRIPTION:
LAST-MODIFIED:20150508T180631Z
LOCATION:
SEQUENCE:2
STATUS:CONFIRMED
SUMMARY:A recurring event
TRANSP:OPAQUE
CATEGORIES:http://schemas.google.com/g/2005#event
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15H
X-WR-ALARMUID:16016C31-EE77-4551-8161-274745B1B7F8
UID:16016C31-EE77-4551-8161-274745B1B7F8
X-APPLE-DEFAULT-ALARM:TRUE
ATTACH;VALUE=URI:Basso
END:VALARM
END:VEVENT

So there is one VEVENT entry for a recurring event that happens year after year (this iCalendar file is old, and has accumulated a lot of cruft over the years) but from time to time someone has entered another VEVENT with exceptions to the DESCRIPTION or the SUMMARY of a particular occurrence of this recurring event.

Now I'm using ical4j to parse this file and produce a list of events, like this:

2015

  • May 9: "Other event info particular to this occurrence"

At the moment, I'm doing this with a simple loop over all the VEVENT entries:

for (VEvent event : (Iterable<VEvent>) calendar.getComponents(Component.VEVENT)) {
    for (Period period : (Iterable<Period>) event.calculateRecurrenceSet(year)) {
    // ...

That works pretty well, except for in the case of the VEVENT entries listed above, which then show up duplicated, one item for the original recurring event and one other item on that same day for the event with the exceptions. (Software like Google Calendar, on the other hand, will notice that the entries have the same UID and only show the one with the exception.)

This leads to these two questions, to which I've not been able to figure out answers on my own:

  • Is there any way in which I could use ical4j to identify these and resolve duplicates?
  • If not, would this not be a reasonable feature request?

ServiceLoader Action$Factory

I'm getting an error when i use it inside an OSGI environment. With an older version its running fine.
The error occurs when the runtime is running and when i deactivate and active a bundle (where ical4j is used inside).
Stacktrace:

Caused by: java.util.ServiceConfigurationError: net.fortuna.ical4j.model.PropertyFactory: Provider net.fortuna.ical4j.model.property.Action$Factory not a subtype
        at java.util.ServiceLoader.fail(ServiceLoader.java:231)
        at java.util.ServiceLoader.access$300(ServiceLoader.java:181)
        at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:369)
        at java.util.ServiceLoader$1.next(ServiceLoader.java:445)
        at net.fortuna.ical4j.model.AbstractContentFactory.getFactory(AbstractContentFactory.java:85)
        at net.fortuna.ical4j.model.PropertyFactoryImpl.createProperty(PropertyFactoryImpl.java:78)

Is It Possible to Directly Manipulate DTSTART and DTEND Times

  • VEVENTs have DTSTART and DTEND times in UTC (e.g., "20150817T160000Z")
  • I want to extend the event's time by subtracting 30 minutes from DTSTART and adding 30 minutes to DTEND
  • Is it possible to do this directly with DtStart and DtEnd objects, or do I have to take the long tour via DateTime?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.