rianjs / ical.net Goto Github PK
View Code? Open in Web Editor NEWical.NET - an open source iCal library for .NET
License: MIT License
ical.NET - an open source iCal library for .NET
License: MIT License
ConcurrentDictionary
doesn't exist in .NET 3.5. Oh well.I have managed to get a Calendar invite setup and working as expected. However, when I reach a specific date for the Start date and after for an event, I get an email with the following file attached: "not supported calendar message.ics"
I am sending this using a multipart/alternative email. Adding a text/calendar alternative view with the relevant ICS content.
It seems to work as expected up until a specific start date and then after that start date, this is when it seems to get the email attachment included.
The code for this is as follows:
using (Calendar calendar = new Calendar())
{
// DateTime eventDate = new DateTime(2016, 10, 30).ToUniversalTime(); // This seems to work fine
DateTime eventDate = new DateTime(2016, 10, 31).ToUniversalTime(); // Using this date (and after) results in Attachment - "not supported calendar message.ics"
calendar.Method = "REQUEST";
// Create the event
Event eventTraineeReview = new Event()
{
Uid = Guid.NewGuid().ToString("N"),
Summary = "Test Event Invite",
Description = "Test Event Description",
Location = "Test Location",
Start = new CalDateTime(eventDate),
End = new CalDateTime(eventDate.AddHours(1)),
Sequence = 0,
Created = new CalDateTime(DateTime.Now),
LastModified = new CalDateTime(DateTime.Now)
};
// Set the organizer of the event
eventTraineeReview.Organizer = new Organizer()
{
CommonName = "Test Organizer",
Value = new Uri("MAILTO:[email protected]")
};
// Create an alarm for the event
Alarm alarmTraineeReview = new Alarm()
{
Action = AlarmAction.Display,
Description = "REMINDER",
Trigger = new Trigger()
{
Duration = TimeSpan.FromDays(-1),
Related = TriggerRelation.Start
}
};
// Add an alarm (reminder) for the event
eventTraineeReview.Alarms.Add(alarmTraineeReview);
// Add the event to the calendar
calendar.Events.Add(eventTraineeReview);
CalendarSerializer serializer = new CalendarSerializer();
string icsContent = serializer.SerializeToString(calendar);
// Save the calendar content to a file.
string calendarSavePath = System.IO.Path.Combine("C:\\Temp\\", string.Format("{0}-IcsEmail.txt", DateTime.Now.ToString("yyyyMMddHHmmssfff")));
System.IO.File.AppendAllText(calendarSavePath, icsContent);
return serializer.SerializeToString(calendar);
}
I have also supplied two text files showing the resulting ICS content for each event date. It seems that the the formatting of the value for DTSTART and DTEND dates differ between the two.
StartDate-31-10-2016-Ics.txt
StartDate-30-10-2016-Ics.txt
This is happening in Outlook 2013.
Title says it all - I'll put up a pull request for a test demonstrating.
While writing the LoadFromUri
example replacements for the Migrating from dday.ical wiki page, I discovered that CalendarCollection
doesn't have reasonable equality or hashing semantics. Should be a straightforward fix.
The previous nuget release (2.1.3) was not serializing any of the timezone info, but was serializing events (albeit setting any and all attendee properties other than uri to null as part of the Attendees.Add operation).
In the current github master branch, events are not serialized either.
Test cases are included with a pull request, but as a brief example:
using (var cal = new Calendar() { Method = "PUBLISH", Version = "2.0" })
{
var evt = new Event
{
Summary = "Testing",
Start = new CalDateTime(2010, 3, 25),
End = new CalDateTime(2010, 3, 26)
}
cal.Events.Add(evt);
var serializer = new CalendarSerializer(new SerializationContext());
var serializedCalendar = serializer.SerializeToString(cal);
}
will currently produce
BEGIN:VCALENDAR
METHOD:PUBLISH
PRODID:-//github.com/rianjs/ical.net//NONSGML ical.net 2.1//EN
VERSION:2.0
END:VCALENDAR
Extend the docs (and make sure there are no bugs!) around non-binary attachments. Write some unit tests proving that string attachments work properly, and serialization is symmetrical.
The example for Thanksgiving (https://github.com/rianjs/ical.net/wiki/Working-with-recurring-elements#the-fourth-thursday-of-every-november) produces the wrong results:
I am trying (and failing) to figure out how to build a recurrence rule for Thanksgiving... Could you update the example?
Thanks!
Get rid of:
HttpClient
out of it, which some client profiles may not support. Application developers can provide their own download-from-source implementation if they wish.VTimeZone:
FromSystemTimeZone
and FromLocalTimeZone
stuff which isn't well-defined in a cross-platform world.Attachment:
Data
properties on Attachment
s should be getter-onlybyte[]
that does the right thing WRT to base64-encoding on both serialization and deserializationMisc:
Assigning to @mcshaz :) -- It's in contributors.md
Hey this may just an oversight but I noticed the readme said:
It's aimed at providing full RFC 2445 compliance
RFC 2445 was made obsolete by RFC5545 so we should probably target that instead. Also, I was wondering if there was a roadmap to use jCal according to (RFC7265)?
https://tools.ietf.org/html/rfc5545
https://tools.ietf.org/html/rfc7265
I am implementing logic that will allow a user to upload ICS files and import a number of meetings/events into a DB.
For single instance meetings, I can just use the Uid
to check if we already have the meeting.
For recurring meetings though, I'd like to clarify what logic I should use to correctly get a unique Id for each instance of the recurring meeting series.
Are the following statements correct?
If the RecurrenceRules
collection contains any items then the event is a recurring meeting instance and I should use the StartTime
field from the occurrence Period as a unique identifier for that instance. The Start
field from the event itself contains the start date of the recurring series and not of the individual instance.
If the RecurrenceID
field is populated then this should be used as the unique identifier for the instance. My understanding is that this field will only be populated for exceptions to the recurring meeting series and will contain updated information for a single instance of a recurring meeting series.
The Sequence
field indicates that there can be multiple updates to a instance of a recurring meeting. The highest sequence number should contain the most recent changes to the instance.
Is there any wrapper method available that has already implemented logic to determine the recurring event ID and I can use that instead of having to implement my own logic?
The old dday.ical package tells people to use ical.net right in the title. Calling it ical.net looks less ridiculous.
The TimeSpanSerializer doesn't correctly serialize 0.
This is needed for alarm triggers at event start time for example which, should look like
TRIGGER:P0D
Instead the Serializer only generates:
TRIGGER:P
Bug was also already present in DDay.iCal
Let's make them sets.
Passing valid VEVENT text to the Event
constructor is a natural thing to want to do. Unfortunately the current deserialization approach doesn't allow for this.
Similarly, passing an icalendar string to a CalendarCollection
constructor (or similar) should allow you to create that representation.
Basically, serialization should feel natural, and almost invisible to the user.
First - huge thank you and kudos for getting this project under active development once again!
Setting the properties for an event instance, for example as below:
myEvt.Transparency = TransparencyType.Opaque;
myEvt.Status = EventStatus.Confirmed;
results in a serialised string with the following text:
STATUS:Confirmed
TRANSP:Opaque
this does not validate, as the string should be
STATUS:CONFIRMED
TRANSP:OPAQUE
I suspect most of it is unnecessary.
When setting a task DUE date, also a DURATION is serialized.
According to the RFC5545:
; Either 'due' or 'duration' MAY appear in ; a 'todoprop', but 'due' and 'duration' ; MUST NOT occur in the same 'todoprop'. ; If 'duration' appear in a 'todoprop', ; then 'dtstart' MUST also appear in ; the same 'todoprop'.
This bug was also present in DDay.iCal.
Hypothesis: they can be replaced by standard .NET collections.
Background: profiling the unit test runtimes shows slow GetEnumerator
performance quite often (5ms+). This is an eternity in CPU time. For normal .NET collections, getting the enumerator is basically unmeasurable. Even if we retain the same interfaces, perhaps the backing collections can be made more standard.
Will have to wait until 2.0 is out of pre-release so as not to go backward WRT the .NET Core port.
Continuation of #72
From #23 (comment) :
objectType.GetTypeInfo().IsEnum
in SerializerFactory
works in .NET 4.5+, but not in .NET 4.0. Maybe we need an ifdef. Ugh.
Maybe:
http://stackoverflow.com/questions/3436526/detect-target-framework-version-at-compile-time
I need this library for WinRT platform. I created separate project and moved your code to this project. I moved tests too. So now I have working library for WinRT.
I can put it on github as different library. But I'm afraid that nobody'll improve this library in the future.
Do you need this code? Can you implement it to your project?
I'm testing the serialization to string and I'm seeing that DESCRIPTION is inserting 0x0A 0x0D chars which causes problems when importing the .ics file into google or outlook. The code look like:
var calendar = new Calendar();
var e = new Event {
Uid = guid,
Summary = name,
Description = description,
Location = venue,
Status = eventStatus,
DtStart = new CalDateTime(start),
DtEnd = new CalDateTime(end),
};
calendar.Events.Add(e);
var serializer = new CalendarSerializer(new SerializationContext());
var serializedCalendar = serializer.SerializeToString(calendar);
File.WriteAllText(exportFilename, serializedCalendar);
While there, make sure that they're only implemented for VEVENT, VTODO, VJOURNAL, and VFREEBUSY blocks, per the spec:
I will reflow the Nuget package as soon as the infinite redirect loop is solved on https://nuget.org. I'd much prefer people are lead to your package, and I believe the stats will jump over too. So it will make ICal.Net more relevant, but don't quote me on it :)
Tags are empty. That's dumb.
https://github.com/rianjs/ical.net/wiki/Working-with-recurring-elements
Work in progress...
Repro:
public void Remove1Attendee()
{
var evt = VEventFactory(); //some new event
Assert.AreEqual(0, evt.Attendees.Count);
var attendee = _attendees.First();
evt.Attendees.Add(attendee);
Assert.AreEqual(1, evt.Attendees.Count);
evt.Attendees.Remove(attendee);
Assert.AreEqual(0, evt.Attendees.Count);
}
This may be myself not understanding the spec for ics/ical files however when using .AddProperty(string, string)
on a calendar the property name gets added twice.
For example using the following:
Calendar cal = new Calendar();
cal.AddProperty("test", "123");
Will give a serialised result with the following:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//github.com/rianjs/ical.net//NONSGML ical.net 2.1//EN
test:test:123
It also gets prepended to the value of the property on the calendar object, so its not a serialisation issue.
Edit:
I've just tried the same using the CalanderProperty
class and its (string, string)
constructor, seem to have the same issue: cal.AddProperty(new CalendarProperty("123", "test"));
will result in 123:123:test
, so again the name 123 and a colon is being prepended to the value of the property object
This also happens when adding properties to events.
E.g. iCalParser.number()
As of RFC 4.8.7.2 Date/Time Stamp
here or here the DTSTAMP property should be of UTC but without the TimeZone property.
Unfortunately (as I see it) we have no influence on this particular DateTime property during serialization.
Or do you have any ideas how to strip the TZID when serialize this property?
EnsureProperties() method
Additionally and in this matter I propose the followin code change for the default value of DTSTAMP:
if (DtStamp == null)
{
var now = DateTime.SpecifyKind(DateTime.Today.Add(DateTime.UtcNow.TimeOfDay), DateTimeKind.Utc);
DtStamp = new CalDateTime(now);
}
This way the CalDateTime() variable has the property IsUniversalTime
set true
.
Original:
if (DtStamp == null)
{
// Here, we don't simply set to DateTime.Now because DateTime.Now contains milliseconds, and
// the iCalendar standard doesn't care at all about milliseconds. Therefore, when comparing
// two calendars, one generated, and one loaded from file, they may be functionally identical,
// but be determined to be different due to millisecond differences.
var now = DateTime.Now;
DtStamp = new CalDateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
}
From here.
The problem is we get the followin output when serializing:
BEGIN:VCALENDAR
PRODID:TESTCAL
VERSION:2.0
X-WR-CALNAME:X-WR-CALNAME:Test
BEGIN:VEVENT
DESCRIPTION:Description
DTEND;TZID=W. Europe Standard Time:20160804T150000
DTSTAMP;TZID=UTC:20160804T110635Z
DTSTART;TZID=W. Europe Standard Time:20160804T140000
SEQUENCE:0
SUMMARY:Test-Event
UID:1234
END:VEVENT
END:VCALENDAR
With ical-validator we get Parser error at line 8: Cannot set timezone for UTC properties
.
When removed we have no errors.
@rianjs when you are ready, I can shoot this package over to someone at Microsoft and try to get it featured as a Nuget package of the week.
I am not hugely familiar with the library, and I may have missed important features of the library in which case I apologise. Assigning values to properties with a limited number of valid values under the spec seems inconsistent.
The Event property Class is a string, and the developer must know (or look up) valid values are "PUBLIC" or "PRIVATE", the same for an Attendee property Role (e.g. "REQ-PARTICIPANT").
the Event properties Transparency and Status are Enums.
An Attendee ParticipationStatus string property can be assigned from the const strings in the ParticipationStatus namespace. The same applies to the Calendar Method property and the CalendarMethods namespace
It would seem ideal if the above 6 properties all had a similar method of asignment.
Thanks
I've followed your tutorial on the wiki and the following namespaces are not found
using Ical.Net;
using Ical.Net.DataTypes;
using Ical.Net.Serialization.iCalendar.Serializers;
I'm using version 2.2.6.
How can I fix this?
This project should setup a CI build server to do the following:
master
This will help foster more collaboration and an understanding of why or why not a PR can be merged.
Also, as a side note: look into https://lgtm.co as potential point of collaboration.
Many properties, in order to meet the spec, should have a dateTime in UTC
currently, the CalDateTime Initializer method has the code HasTime = value.Second != 0 || value.Minute != 0 || value.Hour != 0;
that is to say if the developer want's to set a time for the DtStart property of a FreeBusy component, the period they want starts at 8 am and they are on a +08:00 timezone (25% of the world's population live in this timezone!), they have to know to explicitly set HasTime = True
in order to serialize correctly, and they would presumably not even be thinking what the UTC time is.
I would propose creating a CalDate class which inherits from CalDateTime, and has constructors accepting year, month, day or a DateTime, and sets the HasTime property to false (I would also make the setter for HasTime protected, with the base CalDateTime implementation always returning True (i.e. not performing the check in the initilizer function above), although that would be a breaking change and so possibly best done in a step wise pattern with an obsolete attribute on the setter).
in the interim, I could make the assignment to HasTime in the initializer a tiny bit more robust with something like HasTime = IsUniversalTime || value.TimeOfDay.Ticks!=0;
Thoughts? Could you suggest a better pattern?
Thank you for your patience with all these issues.
^^ That's not great. And should users use the ValueEncoding
or Encoding
property? It's not at all clear.
the date
LastModified = new CalDateTime(DateTime.SpecifyKind(new DateTime(2010, 3, 27, 13, 53, 35), DateTimeKind.Utc))
is serialising as:
LAST-MODIFIED;TZID=UTC:20100327T135335Z
the standard states:
The "TZID" property parameter MUST NOT be applied to DATE-TIME properties whose time values are specified in UTC.
(This was found using the test in my 'experimental' branch posting a serialised calendar object to icalendar.org for validation)
I'm having an issue with exceptions to recurring events, specifically date exceptions that should be omitted when you call GetOccurences.
In my sample file, i have:
RRULE:FREQ=WEEKLY;COUNT=35;BYDAY=TU,TH
EXDATE;TZID=America/Los_Angeles:20160823T123000
EXDATE;TZID=America/Los_Angeles:20160818T123000
EXDATE;TZID=America/Los_Angeles:20160816T123000
When I call GetOccurences, only the first exdate is omitted, but the others are still present.
I looked at event.ExceptionDates, and all 3 are present. I dug in and found out that something is happening in the Evaluate function. On line 32 in PeriodListEvaluator.cs - periods.UnionWith(_mPeriodList); _mPeriodList only has the first exception date in it. The other 2 are missing. So when the union is done, only the first exception date is retained. I haven't been able to figure out why the PeriodList isn't getting the other 2 dates.
Any ideas? Is this known? I believe when I had all the exception dates comma separated on one line it worked..
Collections, such as the calender's Event collection, and the event's Attendee collection are of type IList<>, with public getters and setters.
The problem is that it gives the idea that the collection can/should be assigned from any list or array, eg. (pseudocode)
evt.Attendees = context.People.Select(p=>new Attendee (p.Email){ CommonName = p.name }).ToList()
the above approach has hitherto not serialized to a string properly.
obvious solutions to this are
a more difficult solution would be to serialize the IList correctly, as it appears (from the example page) to occur with RecurrenceRules
Generating binary data for attachments is fine, but the Base64-encoded data is not serialized correctly. Here's a repro case with output:
public void BinaryAttachment_Tests()
{
var asBytes = Encoding.UTF8.GetBytes("This is a song that never ends. It just goes on and on my friends. Some people started singing it not...");
var attachment = new Attachment
{
Data = asBytes,
ValueEncoding = Encoding.UTF8,
};
var calendar = new Calendar();
var vEvent = GetSimpleEvent();
vEvent.Attachments = new List<IAttachment> { attachment };
calendar.Events.Add(vEvent);
var serialized = SerializeToString(calendar);
var unserialized = UnserializeCalendar(serialized);
Assert.AreEqual(calendar.GetHashCode(), unserialized.GetHashCode());
Assert.AreEqual(calendar, unserialized);
}
The output is incorrect. There should be spaces on the wrapped lines. This is causing deserialization to fail, because the regex is looking for \r\n[ \t]
in TextUtil.UnwrapLines
:
BEGIN:VCALENDAR
PRODID:-//github.com/rianjs/ical.net//NONSGML ical.net 2.1//EN
VERSION:2.0
BEGIN:VEVENT
ATTACH;VALUE=BINARY;ENCODING=BASE64:VGhpcyBpcyBhIHNvbmcgdGhhdCBuZXZlciBlbmR
zLiBJdCBqdXN0IGdvZXMgb24gYW5kIG9uIG15IGZyaWVuZHMuIFNvbWUgcGVvcGxlIHN0YXJ0Z
WQgc2luZ2luZyBpdCBub3QuLi4=
DTEND:20160721T145800
DTSTAMP:20160721T135802
DTSTART:20160721T135800
SEQUENCE:0
UID:d5437779-9ad2-4781-a1ee-c554f10594a6
END:VEVENT
END:VCALENDAR
The spec mandates that timezone contain at least 1 of these elements. Will post some tests which demonstrate.
When trying to load a timezone with Calendar.LoadFromStream() from tzurl.org, e.g. http://tzurl.org/zoneinfo/Europe/Berlin.ics
I get the following exception
System.FormatException: Die Zeichenfolge wurde nicht als gültiges DateTime erkannt.
bei System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, TimeSpan& offset)
bei System.DateTimeOffset.Parse(String input)
bei Ical.Net.Serialization.iCalendar.Serializers.DataTypes.UtcOffsetSerializer.GetOffset(String rawOffset) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\Serializers\DataTypes\UTCOffsetSerializer.cs:Zeile 42.
bei Ical.Net.DataTypes.UtcOffset..ctor(String value) in C:\dev\ical.net\ical.NET\DataTypes\UTCOffset.cs:Zeile 26.
bei Ical.Net.Serialization.iCalendar.Serializers.DataTypes.UtcOffsetSerializer.Deserialize(TextReader tr) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\Serializers\DataTypes\UTCOffsetSerializer.cs:Zeile 32.
bei Ical.Net.Serialization.iCalendar.Serializers.DataMapSerializer.Deserialize(TextReader tr) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\Serializers\DataMapSerializer.cs:Zeile 56.
bei Ical.Net.Serialization.iCalendar.iCalParser.property(ISerializationContext ctx, ICalendarPropertyListContainer c) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\iCalParser.cs:Zeile 292.
bei Ical.Net.Serialization.iCalendar.iCalParser.component(ISerializationContext ctx, ISerializerFactory sf, ICalendarComponentFactory cf, ICalendarObject o) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\iCalParser.cs:Zeile 415.
bei Ical.Net.Serialization.iCalendar.iCalParser.component(ISerializationContext ctx, ISerializerFactory sf, ICalendarComponentFactory cf, ICalendarObject o) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\iCalParser.cs:Zeile 420.
bei Ical.Net.Serialization.iCalendar.iCalParser.icalbody(ISerializationContext ctx, ICalendar cal) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\iCalParser.cs:Zeile 207.
bei Ical.Net.Serialization.iCalendar.iCalParser.icalendar(ISerializationContext ctx) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\iCalParser.cs:Zeile 144.
bei Ical.Net.Serialization.iCalendar.Serializers.CalendarSerializer.Deserialize(TextReader tr) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\Serializers\iCalendarSerializer.cs:Zeile 81.
bei Ical.Net.Serialization.iCalendar.Serializers.SerializerBase.Deserialize(Stream stream, Encoding encoding) in C:\dev\ical.net\ical.NET\Serialization\iCalendar\Serializers\SerializerBase.cs:Zeile 39.
bei Ical.Net.Calendar.LoadFromStream(Stream s, Encoding e, ISerializer serializer) in C:\dev\ical.net\ical.NET\Calendar.cs:Zeile 113.
bei Ical.Net.Calendar.LoadFromStream(TextReader tr, ISerializer serializer) in C:\dev\ical.net\ical.NET\Calendar.cs:Zeile 137.
bei Ical.Net.Calendar.LoadFromStream(TextReader tr) in C:\dev\ical.net\ical.NET\Calendar.cs:Zeile 118.
Will there be support for netcoreapp1.0 in the near future? Temporarily I can target net46 but unfortunately that isn't a great long term solution for us.
System.ArgumentException occurred
HResult=-2147024809
Message=An item with the same key has already been added.
Source=mscorlib
StackTrace:
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Ical.Net.Utility.SerializationUtil.GetDeserializingMethods(Type targetType) in C:\dev\ical.net\ical.NET\Utility\SerializationUtil.cs:line 60
InnerException:
Repro case. Code works fine if .AsParallel()
is removed.
public static IEnumerable<DowntimeWithExactTimes> GetDowntimesInRange(IEnumerable<Downtime> downtimes, DateTime earliestStart, DateTime latestEnd)
{
var sw = new Stopwatch();
sw.Start();
var earliestStartIcal = new CalDateTime(earliestStart, "UTC") {HasTime = true};
var latestEndIcal = new CalDateTime(latestEnd, "UTC") {HasTime = true};
var downtimesWithExactTimes = downtimes.AsParallel().SelectMany(downtime =>
{
IICalendarCollection calendar;
using (var reader = new StringReader(downtime.IcalString ?? ""))
{
// Originally calendar = iCalendar.LoadFromStream(reader), but that uses a static serializer so it isn't thread safe.
//calendar = Calendar.LoadFromStream(reader);
calendar = Calendar.LoadFromStream(reader, new CalendarSerializer { SerializationContext = new SerializationContext() });
}
var thisDowntime = downtime;
var occurrences = calendar.GetOccurrences(earliestStartIcal, latestEndIcal);
return occurrences.Select(occurrence => new DowntimeWithExactTimes(thisDowntime, occurrence.Period.StartTime.AsUtc, occurrence.Period.EndTime.AsUtc));
});
var orderedDowntimes = downtimesWithExactTimes.OrderBy(downtime => downtime.Start).ThenBy(downtime => downtime.End).ToList();
sw.Stop();
return orderedDowntimes;
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.