SlideShare a Scribd company logo
1 of 42
Download to read offline
ERGroupware
Pascal Robert
Druide informatique
• Let you generate iCalendar files, à la ERCalendar
• Let you connect to groupware solutions
• CalDAV
• MS Exchange 2007/2010
• Zimbra
• Many Bothans have died to provide this framework
What is ERGroupware?
iCalendar generation
iCalendar
• iCalendar is a standard (RFC 2445, written in 1998).
• A iCalendar object can have multiple components (VEVENT,
VTODO, etc.)
• Text file, with Base64 encoding for binary
• Key value
• You can add your own keys
iCalendar example
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
TRANSP:OPAQUE
DTEND:20130623T101500
UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4
DTSTAMP:20130514T135551Z
LOCATION:Verdun/Lachine/Lasalle
X-MOZ-GENERATION:1
URL;VALUE=URI:http://www.wocommunity.org/wowodc13/cayenne.html
SEQUENCE:10
SUMMARY:Cayenne Training Day
LAST-MODIFIED:20130509T165550Z
DTSTART:20130623T091500
CREATED:20130505T001152Z
END:VEVENT
END:VCALENDAR
UID
• Each component must have a UID
• UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4
• And it must be unique!
Attendees
• Attendees are invitees.
• Can be a individual, group, resource or room. (CUType)
• Also have status: needs action, accepted, etc. (Partstat)
• If you have attendees, you also need an organizer!
iCalendar in ERGroupware
• Similar to ERCalendar, but more modern and better validation.
• Using iCal4j, a solid iCalendar library for Java.
• Component to generate the file.
• Will generate a text/calendar response
iCalendar file generation
ERGWCalendar aCalendar = new ERGWCalendar();
ERGWEvent event = new ERGWEvent(aCalendar);
java.util.Calendar startTime = GregorianCalendar.getInstance();
event.setStartTime(new NSTimestamp(startTime.getTimeInMillis()));
java.util.Calendar endTime = GregorianCalendar.getInstance();
endTime.add(java.util.Calendar.HOUR, 2);
event.setEndTime(new NSTimestamp(endTime.getTimeInMillis()));
event.setClassification(ERGWClassification.PUBLIC);
event.setFreeBusyStatus(ERGWFreeBusyStatus.BUSY_TENTATIVE);
event.setLocation("Montreal");
event.setCategories(new NSArray<String>(new String[] { "Category 1", "Category 2" }));
event.setPriority(ERGWPriority.HIGH);
event.setSummary("WOWODC 2013");
event.setTransparency(ERGWTransparency.TRANSPARENT);
Calendar calendarData = ERGWCalendar.transformToICalObject(aCalendar);
ERGWPublishCalendarPage nextPage = (ERGWPublishCalendarPage)pageWithName(ERGWPublishCalendarPage.class);
nextPage.setCalendar(calendarData);
return nextPage;
CalDAV/CardDAV
• Both based on WebDAV
• Will store iCalendar objects (CalDAV) or vCard objects
(CardDAV)
• Many many server implementations
• But some of them are really basic (Google Calendar...)
• iCal Server is the best implementation
• Many clients too
CalDAV
• Open standard, defined in RFC 4791
• Servers must implements this RFC
• Many extensions
• Scheduling
• Delegations
• Sharing
• etc.
CalDAV
• Calendars are DAV collections.
• DAV collections have properties (ACL, owner, etc.).
• Can create as many collections as you want.
• Other DAV collections exists too.
Features/extensions
• CalDAV servers must send the supported features set in the
response.
• Can do a OPTIONS request to see them.
• Check the DAV header in the response.
OPTIONS request
$ curl --digest --user probert -X OPTIONS -v http://localhost:8008
< DAV: 1, access-control, calendar-access, calendar-schedule, calendar-
auto-schedule, calendar-availability, inbox-availability, calendar-
proxy, calendarserver-private-events, calendarserver-private-comments,
calendarserver-sharing, calendarserver-sharing-no-scheduling, calendar-
query-extended, calendar-default-alarms, addressbook, extended-mkcol,
calendarserver-principal-property-search, calendarserver-principal-
search
CalDAV and HTTP
• Almost REST-like
• Use HTTP verbs
• GET: fetch a object
• PUT: create OR update a object
• DELETE: delete a object
• MKCALENDAR: create a calendar collection
• Use headers, HTTP authentication (Basic, Digest, Kerberos...)
iCalendar objects
• You store iCalendar objects in calendar collections.
• But you can only store ONE component (VTODO,VEVENT,
etc.) per object.
PUT
• CalDAV don't use POST to create objects.
• Must use PUT
• If URL and UID already exists, will update the object.
• If URL and UID don't exists, will create the object.
• If URL don't exist but UID exist, will conflict.
• Creating a object will return a 201 status code.
• If you copy an object, don't forget to change the UID.
Example of creating event
PUT /calendars/__uids__/AD04C60B-3704-447B-8997-24F5ACF589C7/calendar/C440-473C-8FAD-D3E606159F40.ics HTTP/1.1
If-None-Match: 1f9e6e30-dfdb-4e5c-baf6-6dd107126a68
Content-Type: text/calendar
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
ATTENDEE;CN="probert@macti.ca";CUTYPE=INDIVIDUAL:mailto:probert@macti.ca
ATTENDEE;CN="Pascal Robert";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7
DTEND;VALUE=DATE:20130616
TRANSP:TRANSPARENT
ORGANIZER;CN="Pascal Robert":urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7
UID:B54100D2-C440-473C-8FAD-D3E606159F40
DTSTAMP:20130615T123551Z
LOCATION:Hilton Montréal Bonaventure
SEQUENCE:9
SUMMARY:Test for presentation
DTSTART;VALUE=DATE:20130615
CREATED:20130615T123241Z
END:VEVENT
END:VCALENDAR
CalDAV support in ERGroupware
• Based on iCal4j-connector, which I contributed to.
• Support for most CalDAV operations.
• Get calendars (collections)
• Create calendars
• Fetch/delete/update calendar objects
• Delete collections
• Fetch events by time-range
Connecting
import net.fortuna.ical4j.connector.ObjectStoreException;
import net.fortuna.ical4j.connector.dav.PathResolver;
import er.groupware.caldav.CalDAVStore;
import java.net.URL;
CalDAVStore store = null;
try {
store = new CalDAVStore("probert", "somepassword", new URL("http://127.0.0.1"),
PathResolver.ICAL_SERVER);
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (ObjectStoreException e) {
e.printStackTrace();
}
Fetching calendar collections and objects
NSArray<CalDAVCollection> collections = store.getCollections();
for (CalDAVCollection collection: collections) {
NSLog.out.appendln(collection.displayName());
// Fetch all events (e.g, VEVENT objects)
NSArray<ERGWCalendar> events = collection.events();
// Fetch all tasks (e.g, VTOTO objects)
NSArray<ERGWCalendar> tasks = collection.tasks();
}
Manipuling calendar objects
// Create a new event and send it to the server
ERGWCalendar aCalendar = new ERGWCalendar();
ERGWEvent event = new ERGWEvent(aCalendar);
java.util.Calendar startTime = GregorianCalendar.getInstance();
event.setStartTime(new NSTimestamp(startTime.getTimeInMillis()));
java.util.Calendar endTime = GregorianCalendar.getInstance();
endTime.add(java.util.Calendar.HOUR, 2);
event.setEndTime(new NSTimestamp(endTime.getTimeInMillis()));
event.setSummary("WOWODC 2013");
collection.addCalendarObject(aCalendar);
// Update the event and send it to the server
aCalendar.events().objectAtIndex(0).setSummary("WOWODC 2014");
collection.updateCalendarObject(aCalendar);
// Delete the event
collection.removeCalendarObject(aCalendar.events().objectAtIndex(0));
Queries
• REPORT request is the same idea as a SQL SELECT query.
• Let's you find calendar objects with a qualifier.
• "Find all todos that are completed"
• "Find events from June 22 to June 24"
• "Find all rooms"
• Won't work for custom properties
Find events by time range
REPORT /bernard/work/ HTTP/1.1
Depth: 1
Content-Type: application/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<C:calendar-data>
<C:limit-recurrence-set start="20060103T000000Z" end="20060105T000000Z"/>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20060103T000000Z" end="20060105T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Find participants that didn't not accept invitations
REPORT /bernard/work/ HTTP/1.1
Depth: 1
Content-Type: application/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:prop-filter name="ATTENDEE">
<C:param-filter name="PARTSTAT">
<C:text-match collation="i;ascii-casemap">NEEDS-ACTION</C:text-match>
</C:param-filter>
</C:prop-filter>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Queries support in ERGroupware
• Query by time range
• CalDavCollection.eventsForTimePeriod(java.util.Date startTime,
java.util.Date endTime)
• Find all individuals
• store.getIndividuals(String name);
• Find rooms or resources
• store.getAllRooms()
• store.getAllResources()
DEMO
MS Exchange
• Exchange Web Service (EWS)
• Based on SOAP
• Same protocol that Outlook 2011 uses
• Most EWS attributes are similar to iCalendar and DAV
collections attributes
Example of request
---[HTTP request - https://webmail.sherweb2010.com/EWS/Exchange.asmx]---
Content-type: text/xml;charset="utf-8"
Soapaction: "http://schemas.microsoft.com/exchange/services/2006/messages/SyncFolderHierarchy"
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<MailboxCulture xmlns="..." xmlns:ns2="...">en-US</MailboxCulture>
<RequestServerVersion xmlns="..." xmlns:ns2="..." Version="Exchange2007_SP1"/>
</S:Header>
<S:Body>
<ns2:SyncFolderHierarchy xmlns="..." xmlns:ns2="...">
<ns2:FolderShape>
<BaseShape>IdOnly</BaseShape>
<AdditionalProperties>
<FieldURI FieldURI="folder:DisplayName"/>
<FieldURI FieldURI="folder:FolderClass"/>
<ExtendedFieldURI PropertyType="Boolean" PropertyTag="0x10F4"/>
</AdditionalProperties>
</ns2:FolderShape>
</ns2:SyncFolderHierarchy>
</S:Body>
</S:Envelope>
Example of response
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo ... Version="Exchange2010_SP2" />
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<m:SyncFolderHierarchyResponse xmlns:m="..." xmlns:t="..."><m:ResponseMessages>
<m:SyncFolderHierarchyResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:SyncState>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt...</m:SyncState>
<m:Changes>
<t:Create>
<t:Folder>
<t:FolderId Id="AAMkAGEw...=" ChangeKey="AQAAABYAAACT3PaCL/2ASLnqcq9Sv0/DAAAAp5Bv"/>
<t:FolderClass>IPF.Note</t:FolderClass>
<t:DisplayName>INBOX</t:DisplayName>
<t:ExtendedProperty>
<t:ExtendedFieldURI PropertyTag="0x10f4" PropertyType="Boolean"/>
<t:Value>false</t:Value>
</t:ExtendedProperty>
</t:Folder>
</t:Create>
</m:Changes>
...
EWS support in ERGroupware
• Generated with JAXB.
• Very basic support outside the generated classes:
• Open connection
• Create folders
• Create task
• Create contact
• Create event
Opening a connection and fetch folders
URL urlToWSDL = ERXApplication.application().resourceManager().pathURLForResourceNamed("Services.wsdl",
"ERGroupware", null);
ExchangeStore store = new ExchangeStore(urlToWSDL, "https://myserver/EWS/Exchange.asmx", "aUser",
"aPassword", "AD.DOMAIN");
store.setServerVersionForRequest(ExchangeVersionType.EXCHANGE_2010_SP_1);
store.setTimeZone(TimeZone.getDefault());
NSArray<ExchangeBaseFolder> folders = store.folders();
for (ExchangeBaseFolder folder: folders) {
NSLog.out.appendln(folder.displayName());
}
Adding an event
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Calendar")) {
ERGWCalendar calendar = new ERGWCalendar();
calendar.setCalendarName("Test");
calendar.setTimeZone(TimeZone.getDefault());
Calendar later = GregorianCalendar.getInstance();
later.add(Calendar.HOUR_OF_DAY, 1);
event.setEndTime(new NSTimestamp(later.getTime()));
UidGenerator uidGen = new UidGenerator("allo");
event.setUid(uidGen.generateUid().getValue());
ERGWEvent event = new ERGWEvent(calendar);
event.setIsFullDay(false);
event.setStartTime(new NSTimestamp());
event.setSummary("WOWODC 2013");
event.setLastModifiedDate(new NSTimestamp());
calendar.addEvent(event);
exchangeStore.createCalendarEvent(calendar, (ExchangeCalendarFolder) folder);
}
}
Adding an event
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Tasks")) {
ERGWCalendar calendar = new ERGWCalendar();
calendar.setCalendarName("Test");
calendar.setTimeZone(TimeZone.getDefault());
Calendar later = GregorianCalendar.getInstance();
later.add(Calendar.HOUR_OF_DAY, 1);
task.setDueDate(new NSTimestamp(later.getTime()));
UidGenerator uidGen = new UidGenerator("allo");
event.setUid(uidGen.generateUid().getValue());
ERGWTask task = new ERGWTask(calendar);
task.setSummary("Finish that presentation");
task.setLastModifiedDate(new NSTimestamp());
calendar.addEvent(event);
exchangeStore.createTask(calendar, (ExchangeCalendarFolder) folder);
}
}
Adding a contact
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Contacts")) {
ERGWContact contact = new ERGWContact();
contact.setGivenName("Pascal");
contact.setFamilyName("Robert");
ERGWContactEmail personalEmail = new ERGWContactEmail();
personalEmail.setEmail("probert@macti.ca");
personalEmail.isPrefered(true);
personalEmail.setTypes(new NSArray<ERGWContactEmailType>(new ERGWContactEmailType[]
{ ERGWContactEmailType.HOME }));
contact.setEmails(new NSArray<ERGWContactEmail>(new ERGWContactEmail[] { personalEmail }));
exchangeStore.createContact(contact, (ExchangeCalendarFolder) folder);
}
}
Create folders
// Create a folder of a specific type
// ERGWFolderType values are: CALENDAR, CONTACTS, TASKS, SEARCH, PLAIN, etc.
store.createFolder("New calendar folder", ERGWFolderType.CALENDAR);
store.createFolder("New contacts folder", ERGWFolderType.CONTACTS);
// Shortcut to create a calendar folder
store.createCalendarFolder(String displayName)
// Shortcut to create a contacts folder
store.createContactsFolder(String displayName)
Zimbra
• SOAP and REST-based API.
• Have API for everything: management, data and Web client
(Zimlets).
• Very basic support in ERGroupware (need to migrate a lot of
code)
• Connect to store
• Add folder
Example of request
POST /service/soap/CreateAppointmentRequest HTTP/1.1
Content-Type: text/xml; charset=utf-8
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	 <soap:Header>
	 	 <context xmlns="urn:zimbra"><authToken>0_b6e206e6c3eee19a7e89f717d5972d9d6b9db224</authToken>...</context>
	 </soap:Header>
	 <soap:Body>
	 	 <CreateAppointmentRequest xmlns="urn:zimbraMail">
	 	 	 <m l="10">
	 	 	 	 <inv>
	 	 	 	 	 <comp status="CONF" allDay="0" name="Titre de la rencontre" loc="Montr[0xc3][0xa9]al" class="PUB" transp="O" fb="B">
	 	 	 	 	 	 <s d="20130619T050858" tz="America/Montreal"/>
	 	 	 	 	 	 <e d="20130619T070858" tz="America/Montreal"/>
	 	 	 	 	 	 <or d="Pascal Robert" a="root@zimbra.macti.lan"/>
	 	 	 	 	 	 <at d="Pascal Robert" cutype="IND" a="probert@macti.ca"/>
	 	 	 	 	 	 <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan"/>
	 	 	 	 	 	 <xprop name="X-RELATED-TO" value="281-280"/>
	 	 	 	 	 </comp>
	 	 	 	 </inv>
	 	 	 	 <su>Titre de la rencontre</su>
	 	 	 	 <mp ct="multipart/mixed"><mp ct="text/plain">
	 	 	 	 	 <content>Une plus long description</content>
	 	 	 	 </mp>
	 	 	 	 <mp ct="text/html">
	 	 	 	 	 <content>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></content>
	 	 	 	 </mp>
	 	 	 </m>
	 	 </CreateAppointmentRequest>
	 </soap:Body>
</soap:Envelope>
Example response
HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	 <soap:Header>
	 	 <context xmlns="urn:zimbra"><session id="11">11</session><change token="602"/>
	 	 	 <notify seq="2">
	 	 	 	 <created>
	 	 	 	 	 <appt id="283" uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" rev="602" s="0" l="10">
	 	 	 	 	 	 <inv id="282" seq="0" compNum="0" type="appt">
	 	 	 	 	 	 	 <tz id="America/Montreal" stdoff="-300" dayname="EDT" dayoff="-240" stdname="EST">...</tz>
	 	 	 	 	 	 	 <comp uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" status="CONF" ...>
	 	 	 	 	 	 	 	 <at d="Pascal Robert" cutype="IND" a="probert@macti.ca" url="probert@macti.ca"/>
	 	 	 	 	 	 	 	 <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan" url="Room1@zimbra.macti.lan"/>
	 	 	 	 	 	 	 	 <xprop name="X-RELATED-TO" value="281-280"/>
	 	 	 	 	 	 	 	 <desc>Une plus long description</desc>
	 	 	 	 	 	 	 	 <descHtml>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></descHtml>
	 	 	 	 	 	 	 	 <or d="Pascal Robert" a="admin@linux.conatus.lan" url="root@zimbra.macti.lan"/>
	 	 	 	 	 	 	 	 <s u="1371632938000" d="20130619T050858" tz="America/Montreal"/>
	 	 	 	 	 	 	 	 <e d="20130619T070858" u="1371640138000" tz="America/Montreal"/>
	 	 	 	 	 	 	 </comp>
	 	 	 	 	 	 </inv>
	 	 	 	 	 </appt>
	 	 	 	 </created>
	 	 	 	 <modified><folder id="10" i4next="284" s="0" i4ms="602" n="3" uuid="6630b004-40cd-49b4-af4b-eca7bac45be6"/></modified>
	 	 	 </notify>
	 	 </context>
	 </soap:Header>
	 <soap:Body>
	 	 <CreateAppointmentResponse rev="602" ms="602" invId="283-282" apptId="283" calItemId="283" xmlns="urn:zimbraMail"/>
	 </soap:Body>
</soap:Envelope>
TODO
• Move away from ical4j-connector
• Complete CalDAV and CardDAV support
• Complete calendar, contacts and email support for Zimbra
• Management API for Kerio, CGP and Zimbra
Resources
• https://github.com/pascalrobert/ERGroupware/
• http://www.macti.ca/wiki/
• http://www.calconnect.org
• http://wiki.modularity.net.au/ical4j/
• http://msdn.microsoft.com/en-us/library/exchange/bb204119(v=exchg.
140).aspx
Q&A

More Related Content

What's hot

20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-final20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-finalDavid Lapsley
 
20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-public20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-publicDavid Lapsley
 
Omnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the ThingsOmnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the ThingsJustin Edelson
 
Javascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JSJavascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JSMin Ming Lo
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Matthew Groves
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak SearchJustin Edelson
 
Effiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und HibernateEffiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und HibernateThorben Janssen
 
Barcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationBarcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationSociable
 
Adventures in Multithreaded Core Data
Adventures in Multithreaded Core DataAdventures in Multithreaded Core Data
Adventures in Multithreaded Core DataInferis
 
Create a Core Data Observer in 10mins
Create a Core Data Observer in 10minsCreate a Core Data Observer in 10mins
Create a Core Data Observer in 10minszmcartor
 
Using redux and angular 2 with meteor
Using redux and angular 2 with meteorUsing redux and angular 2 with meteor
Using redux and angular 2 with meteorKen Ono
 
Memory Management on iOS
Memory Management on iOSMemory Management on iOS
Memory Management on iOSMake School
 
Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentationGene Chang
 
Riak with node.js
Riak with node.jsRiak with node.js
Riak with node.jsSean Cribbs
 
iOS Memory Management Basics
iOS Memory Management BasicsiOS Memory Management Basics
iOS Memory Management BasicsBilue
 
Memory management in Objective C
Memory management in Objective CMemory management in Objective C
Memory management in Objective CNeha Gupta
 

What's hot (18)

20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-final20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-final
 
20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-public20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-public
 
Omnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the ThingsOmnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the Things
 
Javascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JSJavascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JS
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak Search
 
Effiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und HibernateEffiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und Hibernate
 
Oak Lucene Indexes
Oak Lucene IndexesOak Lucene Indexes
Oak Lucene Indexes
 
Barcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationBarcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentation
 
Adventures in Multithreaded Core Data
Adventures in Multithreaded Core DataAdventures in Multithreaded Core Data
Adventures in Multithreaded Core Data
 
CDI 2.0 Deep Dive
CDI 2.0 Deep DiveCDI 2.0 Deep Dive
CDI 2.0 Deep Dive
 
Create a Core Data Observer in 10mins
Create a Core Data Observer in 10minsCreate a Core Data Observer in 10mins
Create a Core Data Observer in 10mins
 
Using redux and angular 2 with meteor
Using redux and angular 2 with meteorUsing redux and angular 2 with meteor
Using redux and angular 2 with meteor
 
Memory Management on iOS
Memory Management on iOSMemory Management on iOS
Memory Management on iOS
 
Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentation
 
Riak with node.js
Riak with node.jsRiak with node.js
Riak with node.js
 
iOS Memory Management Basics
iOS Memory Management BasicsiOS Memory Management Basics
iOS Memory Management Basics
 
Memory management in Objective C
Memory management in Objective CMemory management in Objective C
Memory management in Objective C
 

Similar to ERGroupware

Integrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAEIntegrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAEctweney
 
Apache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series dataApache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series dataPatrick McFadin
 
Real time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache SparkReal time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache SparkRahul Jain
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scriptingmichid
 
ApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr IntegrationApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr Integrationthelabdude
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scriptingday
 
Pro2516 10 things about oracle and k8s.pptx-final
Pro2516   10 things about oracle and k8s.pptx-finalPro2516   10 things about oracle and k8s.pptx-final
Pro2516 10 things about oracle and k8s.pptx-finalMichel Schildmeijer
 
The Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da AppleThe Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da AppleRodrigo Leite
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive AppsJorge Ortiz
 
DataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New WorldDataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New WorldDatabricks
 
Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4VMware Tanzu
 
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)Alexandre Dutra
 
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)petabridge
 
Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022Andrzej Ludwikowski
 
SQL on Hadoop
SQL on HadoopSQL on Hadoop
SQL on Hadoopnvvrajesh
 
Cassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A ComparisonCassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A Comparisonshsedghi
 
StackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStackStackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStackChiradeep Vittal
 
Managing Your Content with Elasticsearch
Managing Your Content with ElasticsearchManaging Your Content with Elasticsearch
Managing Your Content with ElasticsearchSamantha Quiñones
 

Similar to ERGroupware (20)

Integrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAEIntegrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAE
 
Apache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series dataApache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series data
 
Real time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache SparkReal time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache Spark
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scripting
 
ApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr IntegrationApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr Integration
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scripting
 
Pro2516 10 things about oracle and k8s.pptx-final
Pro2516   10 things about oracle and k8s.pptx-finalPro2516   10 things about oracle and k8s.pptx-final
Pro2516 10 things about oracle and k8s.pptx-final
 
Spark etl
Spark etlSpark etl
Spark etl
 
The Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da AppleThe Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da Apple
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
 
DataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New WorldDataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New World
 
Unqlite
UnqliteUnqlite
Unqlite
 
Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4
 
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
 
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
 
Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022
 
SQL on Hadoop
SQL on HadoopSQL on Hadoop
SQL on Hadoop
 
Cassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A ComparisonCassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A Comparison
 
StackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStackStackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStack
 
Managing Your Content with Elasticsearch
Managing Your Content with ElasticsearchManaging Your Content with Elasticsearch
Managing Your Content with Elasticsearch
 

More from WO Community

In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engineWO Community
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsWO Community
 
Build and deployment
Build and deploymentBuild and deployment
Build and deploymentWO Community
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSWO Community
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldWO Community
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful ControllersWO Community
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on WindowsWO Community
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnitWO Community
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO DevsWO Community
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache CayenneWO Community
 
Migrating existing Projects to Wonder
Migrating existing Projects to WonderMigrating existing Projects to Wonder
Migrating existing Projects to WonderWO Community
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" patternWO Community
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W WO Community
 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languagesWO Community
 

More from WO Community (20)

KAAccessControl
KAAccessControlKAAccessControl
KAAccessControl
 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engine
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systems
 
Build and deployment
Build and deploymentBuild and deployment
Build and deployment
 
High availability
High availabilityHigh availability
High availability
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWS
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real World
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful Controllers
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on Windows
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnit
 
Life outside WO
Life outside WOLife outside WO
Life outside WO
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache Cayenne
 
Migrating existing Projects to Wonder
Migrating existing Projects to WonderMigrating existing Projects to Wonder
Migrating existing Projects to Wonder
 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERREST
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" pattern
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W
 
WOver
WOverWOver
WOver
 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languages
 
WOdka
WOdkaWOdka
WOdka
 

Recently uploaded

Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 

Recently uploaded (20)

Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 

ERGroupware

  • 2. • Let you generate iCalendar files, à la ERCalendar • Let you connect to groupware solutions • CalDAV • MS Exchange 2007/2010 • Zimbra • Many Bothans have died to provide this framework What is ERGroupware?
  • 4. iCalendar • iCalendar is a standard (RFC 2445, written in 1998). • A iCalendar object can have multiple components (VEVENT, VTODO, etc.) • Text file, with Base64 encoding for binary • Key value • You can add your own keys
  • 5. iCalendar example BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN CALSCALE:GREGORIAN BEGIN:VEVENT TRANSP:OPAQUE DTEND:20130623T101500 UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4 DTSTAMP:20130514T135551Z LOCATION:Verdun/Lachine/Lasalle X-MOZ-GENERATION:1 URL;VALUE=URI:http://www.wocommunity.org/wowodc13/cayenne.html SEQUENCE:10 SUMMARY:Cayenne Training Day LAST-MODIFIED:20130509T165550Z DTSTART:20130623T091500 CREATED:20130505T001152Z END:VEVENT END:VCALENDAR
  • 6. UID • Each component must have a UID • UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4 • And it must be unique!
  • 7. Attendees • Attendees are invitees. • Can be a individual, group, resource or room. (CUType) • Also have status: needs action, accepted, etc. (Partstat) • If you have attendees, you also need an organizer!
  • 8. iCalendar in ERGroupware • Similar to ERCalendar, but more modern and better validation. • Using iCal4j, a solid iCalendar library for Java. • Component to generate the file. • Will generate a text/calendar response
  • 9. iCalendar file generation ERGWCalendar aCalendar = new ERGWCalendar(); ERGWEvent event = new ERGWEvent(aCalendar); java.util.Calendar startTime = GregorianCalendar.getInstance(); event.setStartTime(new NSTimestamp(startTime.getTimeInMillis())); java.util.Calendar endTime = GregorianCalendar.getInstance(); endTime.add(java.util.Calendar.HOUR, 2); event.setEndTime(new NSTimestamp(endTime.getTimeInMillis())); event.setClassification(ERGWClassification.PUBLIC); event.setFreeBusyStatus(ERGWFreeBusyStatus.BUSY_TENTATIVE); event.setLocation("Montreal"); event.setCategories(new NSArray<String>(new String[] { "Category 1", "Category 2" })); event.setPriority(ERGWPriority.HIGH); event.setSummary("WOWODC 2013"); event.setTransparency(ERGWTransparency.TRANSPARENT); Calendar calendarData = ERGWCalendar.transformToICalObject(aCalendar); ERGWPublishCalendarPage nextPage = (ERGWPublishCalendarPage)pageWithName(ERGWPublishCalendarPage.class); nextPage.setCalendar(calendarData); return nextPage;
  • 10. CalDAV/CardDAV • Both based on WebDAV • Will store iCalendar objects (CalDAV) or vCard objects (CardDAV) • Many many server implementations • But some of them are really basic (Google Calendar...) • iCal Server is the best implementation • Many clients too
  • 11. CalDAV • Open standard, defined in RFC 4791 • Servers must implements this RFC • Many extensions • Scheduling • Delegations • Sharing • etc.
  • 12. CalDAV • Calendars are DAV collections. • DAV collections have properties (ACL, owner, etc.). • Can create as many collections as you want. • Other DAV collections exists too.
  • 13. Features/extensions • CalDAV servers must send the supported features set in the response. • Can do a OPTIONS request to see them. • Check the DAV header in the response.
  • 14. OPTIONS request $ curl --digest --user probert -X OPTIONS -v http://localhost:8008 < DAV: 1, access-control, calendar-access, calendar-schedule, calendar- auto-schedule, calendar-availability, inbox-availability, calendar- proxy, calendarserver-private-events, calendarserver-private-comments, calendarserver-sharing, calendarserver-sharing-no-scheduling, calendar- query-extended, calendar-default-alarms, addressbook, extended-mkcol, calendarserver-principal-property-search, calendarserver-principal- search
  • 15. CalDAV and HTTP • Almost REST-like • Use HTTP verbs • GET: fetch a object • PUT: create OR update a object • DELETE: delete a object • MKCALENDAR: create a calendar collection • Use headers, HTTP authentication (Basic, Digest, Kerberos...)
  • 16. iCalendar objects • You store iCalendar objects in calendar collections. • But you can only store ONE component (VTODO,VEVENT, etc.) per object.
  • 17. PUT • CalDAV don't use POST to create objects. • Must use PUT • If URL and UID already exists, will update the object. • If URL and UID don't exists, will create the object. • If URL don't exist but UID exist, will conflict. • Creating a object will return a 201 status code. • If you copy an object, don't forget to change the UID.
  • 18. Example of creating event PUT /calendars/__uids__/AD04C60B-3704-447B-8997-24F5ACF589C7/calendar/C440-473C-8FAD-D3E606159F40.ics HTTP/1.1 If-None-Match: 1f9e6e30-dfdb-4e5c-baf6-6dd107126a68 Content-Type: text/calendar BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN CALSCALE:GREGORIAN BEGIN:VEVENT ATTENDEE;CN="probert@macti.ca";CUTYPE=INDIVIDUAL:mailto:probert@macti.ca ATTENDEE;CN="Pascal Robert";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7 DTEND;VALUE=DATE:20130616 TRANSP:TRANSPARENT ORGANIZER;CN="Pascal Robert":urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7 UID:B54100D2-C440-473C-8FAD-D3E606159F40 DTSTAMP:20130615T123551Z LOCATION:Hilton Montréal Bonaventure SEQUENCE:9 SUMMARY:Test for presentation DTSTART;VALUE=DATE:20130615 CREATED:20130615T123241Z END:VEVENT END:VCALENDAR
  • 19. CalDAV support in ERGroupware • Based on iCal4j-connector, which I contributed to. • Support for most CalDAV operations. • Get calendars (collections) • Create calendars • Fetch/delete/update calendar objects • Delete collections • Fetch events by time-range
  • 20. Connecting import net.fortuna.ical4j.connector.ObjectStoreException; import net.fortuna.ical4j.connector.dav.PathResolver; import er.groupware.caldav.CalDAVStore; import java.net.URL; CalDAVStore store = null; try { store = new CalDAVStore("probert", "somepassword", new URL("http://127.0.0.1"), PathResolver.ICAL_SERVER); } catch (MalformedURLException e) { e.printStackTrace(); } catch (ObjectStoreException e) { e.printStackTrace(); }
  • 21. Fetching calendar collections and objects NSArray<CalDAVCollection> collections = store.getCollections(); for (CalDAVCollection collection: collections) { NSLog.out.appendln(collection.displayName()); // Fetch all events (e.g, VEVENT objects) NSArray<ERGWCalendar> events = collection.events(); // Fetch all tasks (e.g, VTOTO objects) NSArray<ERGWCalendar> tasks = collection.tasks(); }
  • 22. Manipuling calendar objects // Create a new event and send it to the server ERGWCalendar aCalendar = new ERGWCalendar(); ERGWEvent event = new ERGWEvent(aCalendar); java.util.Calendar startTime = GregorianCalendar.getInstance(); event.setStartTime(new NSTimestamp(startTime.getTimeInMillis())); java.util.Calendar endTime = GregorianCalendar.getInstance(); endTime.add(java.util.Calendar.HOUR, 2); event.setEndTime(new NSTimestamp(endTime.getTimeInMillis())); event.setSummary("WOWODC 2013"); collection.addCalendarObject(aCalendar); // Update the event and send it to the server aCalendar.events().objectAtIndex(0).setSummary("WOWODC 2014"); collection.updateCalendarObject(aCalendar); // Delete the event collection.removeCalendarObject(aCalendar.events().objectAtIndex(0));
  • 23. Queries • REPORT request is the same idea as a SQL SELECT query. • Let's you find calendar objects with a qualifier. • "Find all todos that are completed" • "Find events from June 22 to June 24" • "Find all rooms" • Won't work for custom properties
  • 24. Find events by time range REPORT /bernard/work/ HTTP/1.1 Depth: 1 Content-Type: application/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <D:prop> <C:calendar-data> <C:limit-recurrence-set start="20060103T000000Z" end="20060105T000000Z"/> </C:calendar-data> </D:prop> <C:filter> <C:comp-filter name="VCALENDAR"> <C:comp-filter name="VEVENT"> <C:time-range start="20060103T000000Z" end="20060105T000000Z"/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>
  • 25. Find participants that didn't not accept invitations REPORT /bernard/work/ HTTP/1.1 Depth: 1 Content-Type: application/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav"> <D:prop xmlns:D="DAV:"> <D:getetag/> <C:calendar-data/> </D:prop> <C:filter> <C:comp-filter name="VCALENDAR"> <C:comp-filter name="VEVENT"> <C:prop-filter name="ATTENDEE"> <C:param-filter name="PARTSTAT"> <C:text-match collation="i;ascii-casemap">NEEDS-ACTION</C:text-match> </C:param-filter> </C:prop-filter> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>
  • 26. Queries support in ERGroupware • Query by time range • CalDavCollection.eventsForTimePeriod(java.util.Date startTime, java.util.Date endTime) • Find all individuals • store.getIndividuals(String name); • Find rooms or resources • store.getAllRooms() • store.getAllResources()
  • 27. DEMO
  • 28. MS Exchange • Exchange Web Service (EWS) • Based on SOAP • Same protocol that Outlook 2011 uses • Most EWS attributes are similar to iCalendar and DAV collections attributes
  • 29. Example of request ---[HTTP request - https://webmail.sherweb2010.com/EWS/Exchange.asmx]--- Content-type: text/xml;charset="utf-8" Soapaction: "http://schemas.microsoft.com/exchange/services/2006/messages/SyncFolderHierarchy" Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header> <MailboxCulture xmlns="..." xmlns:ns2="...">en-US</MailboxCulture> <RequestServerVersion xmlns="..." xmlns:ns2="..." Version="Exchange2007_SP1"/> </S:Header> <S:Body> <ns2:SyncFolderHierarchy xmlns="..." xmlns:ns2="..."> <ns2:FolderShape> <BaseShape>IdOnly</BaseShape> <AdditionalProperties> <FieldURI FieldURI="folder:DisplayName"/> <FieldURI FieldURI="folder:FolderClass"/> <ExtendedFieldURI PropertyType="Boolean" PropertyTag="0x10F4"/> </AdditionalProperties> </ns2:FolderShape> </ns2:SyncFolderHierarchy> </S:Body> </S:Envelope>
  • 30. Example of response <?xml version="1.0" encoding="utf-8"?> <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <h:ServerVersionInfo ... Version="Exchange2010_SP2" /> </s:Header> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <m:SyncFolderHierarchyResponse xmlns:m="..." xmlns:t="..."><m:ResponseMessages> <m:SyncFolderHierarchyResponseMessage ResponseClass="Success"> <m:ResponseCode>NoError</m:ResponseCode> <m:SyncState>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt...</m:SyncState> <m:Changes> <t:Create> <t:Folder> <t:FolderId Id="AAMkAGEw...=" ChangeKey="AQAAABYAAACT3PaCL/2ASLnqcq9Sv0/DAAAAp5Bv"/> <t:FolderClass>IPF.Note</t:FolderClass> <t:DisplayName>INBOX</t:DisplayName> <t:ExtendedProperty> <t:ExtendedFieldURI PropertyTag="0x10f4" PropertyType="Boolean"/> <t:Value>false</t:Value> </t:ExtendedProperty> </t:Folder> </t:Create> </m:Changes> ...
  • 31. EWS support in ERGroupware • Generated with JAXB. • Very basic support outside the generated classes: • Open connection • Create folders • Create task • Create contact • Create event
  • 32. Opening a connection and fetch folders URL urlToWSDL = ERXApplication.application().resourceManager().pathURLForResourceNamed("Services.wsdl", "ERGroupware", null); ExchangeStore store = new ExchangeStore(urlToWSDL, "https://myserver/EWS/Exchange.asmx", "aUser", "aPassword", "AD.DOMAIN"); store.setServerVersionForRequest(ExchangeVersionType.EXCHANGE_2010_SP_1); store.setTimeZone(TimeZone.getDefault()); NSArray<ExchangeBaseFolder> folders = store.folders(); for (ExchangeBaseFolder folder: folders) { NSLog.out.appendln(folder.displayName()); }
  • 33. Adding an event for (ExchangeBaseFolder folder: store.folders()) { if (folder.displayName().equals("Calendar")) { ERGWCalendar calendar = new ERGWCalendar(); calendar.setCalendarName("Test"); calendar.setTimeZone(TimeZone.getDefault()); Calendar later = GregorianCalendar.getInstance(); later.add(Calendar.HOUR_OF_DAY, 1); event.setEndTime(new NSTimestamp(later.getTime())); UidGenerator uidGen = new UidGenerator("allo"); event.setUid(uidGen.generateUid().getValue()); ERGWEvent event = new ERGWEvent(calendar); event.setIsFullDay(false); event.setStartTime(new NSTimestamp()); event.setSummary("WOWODC 2013"); event.setLastModifiedDate(new NSTimestamp()); calendar.addEvent(event); exchangeStore.createCalendarEvent(calendar, (ExchangeCalendarFolder) folder); } }
  • 34. Adding an event for (ExchangeBaseFolder folder: store.folders()) { if (folder.displayName().equals("Tasks")) { ERGWCalendar calendar = new ERGWCalendar(); calendar.setCalendarName("Test"); calendar.setTimeZone(TimeZone.getDefault()); Calendar later = GregorianCalendar.getInstance(); later.add(Calendar.HOUR_OF_DAY, 1); task.setDueDate(new NSTimestamp(later.getTime())); UidGenerator uidGen = new UidGenerator("allo"); event.setUid(uidGen.generateUid().getValue()); ERGWTask task = new ERGWTask(calendar); task.setSummary("Finish that presentation"); task.setLastModifiedDate(new NSTimestamp()); calendar.addEvent(event); exchangeStore.createTask(calendar, (ExchangeCalendarFolder) folder); } }
  • 35. Adding a contact for (ExchangeBaseFolder folder: store.folders()) { if (folder.displayName().equals("Contacts")) { ERGWContact contact = new ERGWContact(); contact.setGivenName("Pascal"); contact.setFamilyName("Robert"); ERGWContactEmail personalEmail = new ERGWContactEmail(); personalEmail.setEmail("probert@macti.ca"); personalEmail.isPrefered(true); personalEmail.setTypes(new NSArray<ERGWContactEmailType>(new ERGWContactEmailType[] { ERGWContactEmailType.HOME })); contact.setEmails(new NSArray<ERGWContactEmail>(new ERGWContactEmail[] { personalEmail })); exchangeStore.createContact(contact, (ExchangeCalendarFolder) folder); } }
  • 36. Create folders // Create a folder of a specific type // ERGWFolderType values are: CALENDAR, CONTACTS, TASKS, SEARCH, PLAIN, etc. store.createFolder("New calendar folder", ERGWFolderType.CALENDAR); store.createFolder("New contacts folder", ERGWFolderType.CONTACTS); // Shortcut to create a calendar folder store.createCalendarFolder(String displayName) // Shortcut to create a contacts folder store.createContactsFolder(String displayName)
  • 37. Zimbra • SOAP and REST-based API. • Have API for everything: management, data and Web client (Zimlets). • Very basic support in ERGroupware (need to migrate a lot of code) • Connect to store • Add folder
  • 38. Example of request POST /service/soap/CreateAppointmentRequest HTTP/1.1 Content-Type: text/xml; charset=utf-8 <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <context xmlns="urn:zimbra"><authToken>0_b6e206e6c3eee19a7e89f717d5972d9d6b9db224</authToken>...</context> </soap:Header> <soap:Body> <CreateAppointmentRequest xmlns="urn:zimbraMail"> <m l="10"> <inv> <comp status="CONF" allDay="0" name="Titre de la rencontre" loc="Montr[0xc3][0xa9]al" class="PUB" transp="O" fb="B"> <s d="20130619T050858" tz="America/Montreal"/> <e d="20130619T070858" tz="America/Montreal"/> <or d="Pascal Robert" a="root@zimbra.macti.lan"/> <at d="Pascal Robert" cutype="IND" a="probert@macti.ca"/> <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan"/> <xprop name="X-RELATED-TO" value="281-280"/> </comp> </inv> <su>Titre de la rencontre</su> <mp ct="multipart/mixed"><mp ct="text/plain"> <content>Une plus long description</content> </mp> <mp ct="text/html"> <content>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></content> </mp> </m> </CreateAppointmentRequest> </soap:Body> </soap:Envelope>
  • 39. Example response HTTP/1.1 200 OK Content-Type: text/xml;charset=UTF-8 <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <context xmlns="urn:zimbra"><session id="11">11</session><change token="602"/> <notify seq="2"> <created> <appt id="283" uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" rev="602" s="0" l="10"> <inv id="282" seq="0" compNum="0" type="appt"> <tz id="America/Montreal" stdoff="-300" dayname="EDT" dayoff="-240" stdname="EST">...</tz> <comp uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" status="CONF" ...> <at d="Pascal Robert" cutype="IND" a="probert@macti.ca" url="probert@macti.ca"/> <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan" url="Room1@zimbra.macti.lan"/> <xprop name="X-RELATED-TO" value="281-280"/> <desc>Une plus long description</desc> <descHtml>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></descHtml> <or d="Pascal Robert" a="admin@linux.conatus.lan" url="root@zimbra.macti.lan"/> <s u="1371632938000" d="20130619T050858" tz="America/Montreal"/> <e d="20130619T070858" u="1371640138000" tz="America/Montreal"/> </comp> </inv> </appt> </created> <modified><folder id="10" i4next="284" s="0" i4ms="602" n="3" uuid="6630b004-40cd-49b4-af4b-eca7bac45be6"/></modified> </notify> </context> </soap:Header> <soap:Body> <CreateAppointmentResponse rev="602" ms="602" invId="283-282" apptId="283" calItemId="283" xmlns="urn:zimbraMail"/> </soap:Body> </soap:Envelope>
  • 40. TODO • Move away from ical4j-connector • Complete CalDAV and CardDAV support • Complete calendar, contacts and email support for Zimbra • Management API for Kerio, CGP and Zimbra
  • 41. Resources • https://github.com/pascalrobert/ERGroupware/ • http://www.macti.ca/wiki/ • http://www.calconnect.org • http://wiki.modularity.net.au/ical4j/ • http://msdn.microsoft.com/en-us/library/exchange/bb204119(v=exchg. 140).aspx
  • 42. Q&A