You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by Adrian Crum <ad...@hlmksw.com> on 2008/11/04 00:37:13 UTC

Re: iCalendar Servlet (was CalDAV Servlet (was Work Effort Event Reminders))

I decided to go with a plain iCalendar servlet instead of CalDAV. CalDAV 
was too complicated and I felt that I was in over my head. All an 
iCalendar servlet has to do is return an iCalendar file in response to 
an HTTP GET.

Using David's example, the servlet looks up work effort ID 11011. That 
work effort is set up as a kind of "Calendar Properties" value. It is 
used to publish a group of work efforts as a calendar. The field 
contents tell the servlet what to do next.

I figure the servlet would get the parties related to the "Calendar 
Properties" work effort, and return all of their public work efforts. 
Likewise, the servlet would get the fixed assets related to the 
"Calendar Properties" work effort, and return all of their public work 
efforts.

To summarize:

http://whatever.foo/calendar/11011/workEffortName.ics Request ->
   Look up work effort #11011 ->
   Get parties related to w/e #11011 ->
   Get all public work efforts for all related parties ->
   Get all fixed assets related to w/e #11011 ->
   Get all public work efforts for all related fixed assets ->
   <- Return work efforts as iCalendar file

-Adrian


David E Jones wrote:
> 
> Or use the workEffortId as part of the URL, ie something like:
> 
> http://whatever.foo/calendar/11011/workEffortName.ics
> 
> This uniquely identifies the calendar and allows the user to specify (in 
> the workEffortName field) what they want the ics file and calendar to be 
> called.
> 
> -David
> 
> 
> On Oct 31, 2008, at 6:52 AM, Adrian Crum wrote:
> 
>> Are you saying to just add the calDavUrl field to WorkEffort? That 
>> would work too.
>>
>> -Adrian
>>
>>
>> --- On Thu, 10/30/08, David E Jones <jo...@hotwaxmedia.com> wrote:
>>
>>> From: David E Jones <jo...@hotwaxmedia.com>
>>> Subject: Re: CalDAV Servlet (was Work Effort Event Reminders)
>>> To: dev@ofbiz.apache.org
>>> Date: Thursday, October 30, 2008, 10:21 PM
>>> We could probably just use WorkEffort itself for a
>>> "calendar" with the proper type ID and what what.
>>> Conveniently WorkEffort already has associations with all of
>>> these things, including other WorkEfforts through the
>>> WorkEffortAssoc entity.
>>>
>>> -David
>>>
>>>
>>> On Oct 30, 2008, at 1:00 PM, Adrian Crum wrote:
>>>
>>>> Thanks BJ. If no one else comes up with a better idea,
>>> I was thinking of using relationship entities:
>>>>
>>>> Calendar Entity
>>>> ---------------
>>>> calDavUrl, id-vlong-ne
>>>> Description, description
>>>> partyId, id
>>>> fixedAssetId, id
>>>> calendarId, id (Optional - to support multiple
>>> calendars)
>>>>
>>>>
>>>> WorkEffortCalendarAssign Entity (To support multiple
>>> calendars)
>>>> -------------------------------
>>>> workEffortId, id-ne
>>>> calendarId, id-ne
>>>>
>>>> The CalDAV servlet would look up the request URL in
>>> the Calendar entity, then use either the partyId or
>>> fixedAssetId to look up the work efforts.
>>>>
>>>> -Adrian
>>>>
>>>>
>>>> BJ Freeman wrote:
>>>>> just off the top of my head how about a
>>> contactmech that is for calendars
>>>>> then you can use the contactmech ID for the
>>> calendar.
>>>>> Adrian Crum sent the following on 10/30/2008 11:13
>>> AM:
>>>>>> I need your thoughts/comments/suggestions on
>>> some CalDAV implementation
>>>>>> issues I need to resolve...
>>>>>>
>>>>>> In OFBiz, parties and fixed assets can be
>>> assigned to work efforts. In
>>>>>> CalDAV, calendars are viewed as a folder
>>> structure with *.ics files in
>>>>>> them. The simplest way to map the CalDAV spec
>>> to OFBiz (that I can
>>>>>> imagine) would be to have two main collections
>>> (folders) - parties and
>>>>>> fixedassets. Within each collection would be
>>> one calendar per
>>>>>> party/fixed asset. Within each collection the
>>> iCal "files" (the request
>>>>>> for a file will do a WorkEffort lookup and
>>> return an iCal text stream -
>>>>>> there is no physical file) will be named
>>> according to user login ID or
>>>>>> fixed asset ID.
>>>>>>
>>>>>> So, assuming a base URL of
>>> https://localhost:8443/ical - the calendar
>>>>>> for the admin user login would be
>>>>>> https://localhost:8443/ical/parties/admin.ics,
>>> and the calendar for the
>>>>>> DEMO_MACHINE fixed asset would be
>>>>>>
>>> https://localhost:8443/ical/fixedassets/DEMO_MACHINE.ics.
>>>>>>
>>>>>> This is a crude and simple implementation that
>>> would serve my immediate
>>>>>> needs, but it needs more work to make it more
>>> appealing to others (and
>>>>>> to make it RFC compliant). Here is where I
>>> need your help - I need ideas
>>>>>> on these potential issues:
>>>>>>
>>>>>> 1. Some users might balk at the idea of using
>>> their login ID as a
>>>>>> calendar name - since the URL could become
>>> public if the user wants to
>>>>>> share their calendar. We would need a way to
>>> map an iCal URL to a user's
>>>>>> work efforts. Example:
>>> https://localhost:8443/ical/TheAdministrator.ics
>>>>>> maps to user login ID admin.
>>>>>>
>>>>>> 2. The CalDAV specification allows for an
>>> arbitrary arrangement of
>>>>>> collections - just like the folder structure
>>> on a hard disk. So, I could
>>>>>> have something like -
>>>>>>
>>>>>> https://localhost:8443/ical/adrian.ics
>>>>>> or
>>>>>> https://localhost:8443/ical/adrian/public.ics
>>>>>> https://localhost:8443/ical/adrian/private.ics
>>>>>>
>>>>>> So there would have to be a way to map
>>> multiple calendars to each user.
>>>>>> The example brings up another issue - how to
>>> map work efforts to
>>>>>> different calendars.
>>>>>>
>>>>>> Let me know what you think.
>>>>>>
>>>>>> -Adrian
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>
>>
>>
> 
> 

Re: iCalendar Servlet (was CalDAV Servlet (was Work Effort Event Reminders))

Posted by Adrian Crum <ad...@hlmksw.com>.
The iCalendar integration has been committed - revision 718684.

I followed a strategy similar to the one I discussed previously:

The integration has been set up as a servlet. Work efforts can be 
accessed in iCalendar format by using a URL in the form of

https://whatever.foo:8443/iCalendar/[work effort ID]/CalendarName.ics

where [work effort ID] is the ID of the work effort used for calendar 
publishing properties, and CalendarName.ics can be any name you want.

There is a demo set up, use:

https://localhost:8443/iCalendar/CALENDAR_PUB_DEMO/MyCalendar.ics

to try it out.

View the CALENDAR_PUB_DEMO work effort to see how the publish property 
work effort is set up.

Child work efforts that are related to the publish property work effort 
will be published. If parties or fixed assets are related to the publish 
property work effort, then their public work efforts will be published.

The published calendar is read-only.

Complex temporal expressions might not translate to iCalendar 
recurrences. This is due to the limitations in the iCalendar format.

I will continue to work on this as I have time.

-Adrian


Adrian Crum wrote:
> I decided to go with a plain iCalendar servlet instead of CalDAV. CalDAV 
> was too complicated and I felt that I was in over my head. All an 
> iCalendar servlet has to do is return an iCalendar file in response to 
> an HTTP GET.
> 
> Using David's example, the servlet looks up work effort ID 11011. That 
> work effort is set up as a kind of "Calendar Properties" value. It is 
> used to publish a group of work efforts as a calendar. The field 
> contents tell the servlet what to do next.
> 
> I figure the servlet would get the parties related to the "Calendar 
> Properties" work effort, and return all of their public work efforts. 
> Likewise, the servlet would get the fixed assets related to the 
> "Calendar Properties" work effort, and return all of their public work 
> efforts.
> 
> To summarize:
> 
> http://whatever.foo/calendar/11011/workEffortName.ics Request ->
>   Look up work effort #11011 ->
>   Get parties related to w/e #11011 ->
>   Get all public work efforts for all related parties ->
>   Get all fixed assets related to w/e #11011 ->
>   Get all public work efforts for all related fixed assets ->
>   <- Return work efforts as iCalendar file
> 
> -Adrian
> 
> 
> David E Jones wrote:
>>
>> Or use the workEffortId as part of the URL, ie something like:
>>
>> http://whatever.foo/calendar/11011/workEffortName.ics
>>
>> This uniquely identifies the calendar and allows the user to specify 
>> (in the workEffortName field) what they want the ics file and calendar 
>> to be called.
>>
>> -David
>>
>>
>> On Oct 31, 2008, at 6:52 AM, Adrian Crum wrote:
>>
>>> Are you saying to just add the calDavUrl field to WorkEffort? That 
>>> would work too.
>>>
>>> -Adrian
>>>
>>>
>>> --- On Thu, 10/30/08, David E Jones <jo...@hotwaxmedia.com> wrote:
>>>
>>>> From: David E Jones <jo...@hotwaxmedia.com>
>>>> Subject: Re: CalDAV Servlet (was Work Effort Event Reminders)
>>>> To: dev@ofbiz.apache.org
>>>> Date: Thursday, October 30, 2008, 10:21 PM
>>>> We could probably just use WorkEffort itself for a
>>>> "calendar" with the proper type ID and what what.
>>>> Conveniently WorkEffort already has associations with all of
>>>> these things, including other WorkEfforts through the
>>>> WorkEffortAssoc entity.
>>>>
>>>> -David
>>>>
>>>>
>>>> On Oct 30, 2008, at 1:00 PM, Adrian Crum wrote:
>>>>
>>>>> Thanks BJ. If no one else comes up with a better idea,
>>>> I was thinking of using relationship entities:
>>>>>
>>>>> Calendar Entity
>>>>> ---------------
>>>>> calDavUrl, id-vlong-ne
>>>>> Description, description
>>>>> partyId, id
>>>>> fixedAssetId, id
>>>>> calendarId, id (Optional - to support multiple
>>>> calendars)
>>>>>
>>>>>
>>>>> WorkEffortCalendarAssign Entity (To support multiple
>>>> calendars)
>>>>> -------------------------------
>>>>> workEffortId, id-ne
>>>>> calendarId, id-ne
>>>>>
>>>>> The CalDAV servlet would look up the request URL in
>>>> the Calendar entity, then use either the partyId or
>>>> fixedAssetId to look up the work efforts.
>>>>>
>>>>> -Adrian
>>>>>
>>>>>
>>>>> BJ Freeman wrote:
>>>>>> just off the top of my head how about a
>>>> contactmech that is for calendars
>>>>>> then you can use the contactmech ID for the
>>>> calendar.
>>>>>> Adrian Crum sent the following on 10/30/2008 11:13
>>>> AM:
>>>>>>> I need your thoughts/comments/suggestions on
>>>> some CalDAV implementation
>>>>>>> issues I need to resolve...
>>>>>>>
>>>>>>> In OFBiz, parties and fixed assets can be
>>>> assigned to work efforts. In
>>>>>>> CalDAV, calendars are viewed as a folder
>>>> structure with *.ics files in
>>>>>>> them. The simplest way to map the CalDAV spec
>>>> to OFBiz (that I can
>>>>>>> imagine) would be to have two main collections
>>>> (folders) - parties and
>>>>>>> fixedassets. Within each collection would be
>>>> one calendar per
>>>>>>> party/fixed asset. Within each collection the
>>>> iCal "files" (the request
>>>>>>> for a file will do a WorkEffort lookup and
>>>> return an iCal text stream -
>>>>>>> there is no physical file) will be named
>>>> according to user login ID or
>>>>>>> fixed asset ID.
>>>>>>>
>>>>>>> So, assuming a base URL of
>>>> https://localhost:8443/ical - the calendar
>>>>>>> for the admin user login would be
>>>>>>> https://localhost:8443/ical/parties/admin.ics,
>>>> and the calendar for the
>>>>>>> DEMO_MACHINE fixed asset would be
>>>>>>>
>>>> https://localhost:8443/ical/fixedassets/DEMO_MACHINE.ics.
>>>>>>>
>>>>>>> This is a crude and simple implementation that
>>>> would serve my immediate
>>>>>>> needs, but it needs more work to make it more
>>>> appealing to others (and
>>>>>>> to make it RFC compliant). Here is where I
>>>> need your help - I need ideas
>>>>>>> on these potential issues:
>>>>>>>
>>>>>>> 1. Some users might balk at the idea of using
>>>> their login ID as a
>>>>>>> calendar name - since the URL could become
>>>> public if the user wants to
>>>>>>> share their calendar. We would need a way to
>>>> map an iCal URL to a user's
>>>>>>> work efforts. Example:
>>>> https://localhost:8443/ical/TheAdministrator.ics
>>>>>>> maps to user login ID admin.
>>>>>>>
>>>>>>> 2. The CalDAV specification allows for an
>>>> arbitrary arrangement of
>>>>>>> collections - just like the folder structure
>>>> on a hard disk. So, I could
>>>>>>> have something like -
>>>>>>>
>>>>>>> https://localhost:8443/ical/adrian.ics
>>>>>>> or
>>>>>>> https://localhost:8443/ical/adrian/public.ics
>>>>>>> https://localhost:8443/ical/adrian/private.ics
>>>>>>>
>>>>>>> So there would have to be a way to map
>>>> multiple calendars to each user.
>>>>>>> The example brings up another issue - how to
>>>> map work efforts to
>>>>>>> different calendars.
>>>>>>>
>>>>>>> Let me know what you think.
>>>>>>>
>>>>>>> -Adrian
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>
>>>
>>>
>>
>>
> 

Re: iCalendar Servlet (was CalDAV Servlet (was Work Effort Event Reminders))

Posted by Adrian Crum <ad...@hlmksw.com>.
I hadn't thought of that - thanks!

-Adrian

David E Jones wrote:
> 
> On Nov 4, 2008, at 10:45 AM, Adrian Crum wrote:
> 
>> Thanks for the reply David! Comments inline...
>>
>> David E Jones wrote:
>>> 1. if you're doing a custom servlet you could even just do a 
>>> ControlServlet request event, and then all of the OFBiz context stuff 
>>> (service/entity engines, etc) is already setup for you
>>
>> I considered that, but all I needed in the end was the delegator, so I 
>> C&P the ControlServlet code to get that. The iCalendar servlet is 
>> around 100 lines, and I guessed a new request handler might take more 
>> than that. *shrug* Six of one, half a dozen of the other.
> 
> You wouldn't need a new request handler, just an event written in java 
> (ie <event type="java" ...>).
> 
> -David
> 
> 

Re: iCalendar Servlet (was CalDAV Servlet (was Work Effort Event Reminders))

Posted by David E Jones <jo...@hotwaxmedia.com>.
On Nov 4, 2008, at 10:45 AM, Adrian Crum wrote:

> Thanks for the reply David! Comments inline...
>
> David E Jones wrote:
>> 1. if you're doing a custom servlet you could even just do a  
>> ControlServlet request event, and then all of the OFBiz context  
>> stuff (service/entity engines, etc) is already setup for you
>
> I considered that, but all I needed in the end was the delegator, so  
> I C&P the ControlServlet code to get that. The iCalendar servlet is  
> around 100 lines, and I guessed a new request handler might take  
> more than that. *shrug* Six of one, half a dozen of the other.

You wouldn't need a new request handler, just an event written in java  
(ie <event type="java" ...>).

-David


Re: iCalendar Servlet (was CalDAV Servlet (was Work Effort Event Reminders))

Posted by Adrian Crum <ad...@hlmksw.com>.
Thanks for the reply David! Comments inline...

David E Jones wrote:
> 1. if you're doing a custom servlet you could even just do a 
> ControlServlet request event, and then all of the OFBiz context stuff 
> (service/entity engines, etc) is already setup for you

I considered that, but all I needed in the end was the delegator, so I 
C&P the ControlServlet code to get that. The iCalendar servlet is around 
100 lines, and I guessed a new request handler might take more than 
that. *shrug* Six of one, half a dozen of the other.

> 2. the idea of following the fixed assets and finding more work effort 
> records to include is interesting, but I'm not sure about it

Maybe because we see different applications. Example: I'm a maintenance 
person in charge of a piece of equipment and I want to add it to my 
calendar so I can see when it is being used for production runs and when 
maintenances are due.

> 3. I have more significant doubts about following the party and finding 
> other work efforts; what I'm thinking is that people will have calendar 
> events associated directly with them (ie with a WorkEffortPartyAssign) 
> and they will select events from all of their events and add them to one 
> of their calendars; in other words, when looking at a single calendar 
> they will just want to see events in that calendar and not every event 
> associated with that party; in other words, my vote is that we do not 
> lookup all parties associated with the calendar work effort and then 
> look for events associated with the parties

That could be done too. I was looking at it more from the perspective of 
someone wanting to "throw a switch" to allow others to see their 
calendar. I can create a setting that will make it work either way.

Good thoughts on your part - I appreciate your comments!

-Adrian

Re: iCalendar Servlet (was CalDAV Servlet (was Work Effort Event Reminders))

Posted by David E Jones <jo...@hotwaxmedia.com>.
This sounds fine, probably the most flexible long-term approach.

A couple of thoughts:

1. if you're doing a custom servlet you could even just do a  
ControlServlet request event, and then all of the OFBiz context stuff  
(service/entity engines, etc) is already setup for you

2. the idea of following the fixed assets and finding more work effort  
records to include is interesting, but I'm not sure about it

3. I have more significant doubts about following the party and  
finding other work efforts; what I'm thinking is that people will have  
calendar events associated directly with them (ie with a  
WorkEffortPartyAssign) and they will select events from all of their  
events and add them to one of their calendars; in other words, when  
looking at a single calendar they will just want to see events in that  
calendar and not every event associated with that party; in other  
words, my vote is that we do not lookup all parties associated with  
the calendar work effort and then look for events associated with the  
parties

-David


On Nov 3, 2008, at 5:37 PM, Adrian Crum wrote:

> I decided to go with a plain iCalendar servlet instead of CalDAV.  
> CalDAV was too complicated and I felt that I was in over my head.  
> All an iCalendar servlet has to do is return an iCalendar file in  
> response to an HTTP GET.
>
> Using David's example, the servlet looks up work effort ID 11011.  
> That work effort is set up as a kind of "Calendar Properties" value.  
> It is used to publish a group of work efforts as a calendar. The  
> field contents tell the servlet what to do next.
>
> I figure the servlet would get the parties related to the "Calendar  
> Properties" work effort, and return all of their public work  
> efforts. Likewise, the servlet would get the fixed assets related to  
> the "Calendar Properties" work effort, and return all of their  
> public work efforts.
>
> To summarize:
>
> http://whatever.foo/calendar/11011/workEffortName.ics Request ->
>  Look up work effort #11011 ->
>  Get parties related to w/e #11011 ->
>  Get all public work efforts for all related parties ->
>  Get all fixed assets related to w/e #11011 ->
>  Get all public work efforts for all related fixed assets ->
>  <- Return work efforts as iCalendar file
>
> -Adrian
>
>
> David E Jones wrote:
>> Or use the workEffortId as part of the URL, ie something like:
>> http://whatever.foo/calendar/11011/workEffortName.ics
>> This uniquely identifies the calendar and allows the user to  
>> specify (in the workEffortName field) what they want the ics file  
>> and calendar to be called.
>> -David
>> On Oct 31, 2008, at 6:52 AM, Adrian Crum wrote:
>>> Are you saying to just add the calDavUrl field to WorkEffort? That  
>>> would work too.
>>>
>>> -Adrian
>>>
>>>
>>> --- On Thu, 10/30/08, David E Jones <jo...@hotwaxmedia.com> wrote:
>>>
>>>> From: David E Jones <jo...@hotwaxmedia.com>
>>>> Subject: Re: CalDAV Servlet (was Work Effort Event Reminders)
>>>> To: dev@ofbiz.apache.org
>>>> Date: Thursday, October 30, 2008, 10:21 PM
>>>> We could probably just use WorkEffort itself for a
>>>> "calendar" with the proper type ID and what what.
>>>> Conveniently WorkEffort already has associations with all of
>>>> these things, including other WorkEfforts through the
>>>> WorkEffortAssoc entity.
>>>>
>>>> -David
>>>>
>>>>
>>>> On Oct 30, 2008, at 1:00 PM, Adrian Crum wrote:
>>>>
>>>>> Thanks BJ. If no one else comes up with a better idea,
>>>> I was thinking of using relationship entities:
>>>>>
>>>>> Calendar Entity
>>>>> ---------------
>>>>> calDavUrl, id-vlong-ne
>>>>> Description, description
>>>>> partyId, id
>>>>> fixedAssetId, id
>>>>> calendarId, id (Optional - to support multiple
>>>> calendars)
>>>>>
>>>>>
>>>>> WorkEffortCalendarAssign Entity (To support multiple
>>>> calendars)
>>>>> -------------------------------
>>>>> workEffortId, id-ne
>>>>> calendarId, id-ne
>>>>>
>>>>> The CalDAV servlet would look up the request URL in
>>>> the Calendar entity, then use either the partyId or
>>>> fixedAssetId to look up the work efforts.
>>>>>
>>>>> -Adrian
>>>>>
>>>>>
>>>>> BJ Freeman wrote:
>>>>>> just off the top of my head how about a
>>>> contactmech that is for calendars
>>>>>> then you can use the contactmech ID for the
>>>> calendar.
>>>>>> Adrian Crum sent the following on 10/30/2008 11:13
>>>> AM:
>>>>>>> I need your thoughts/comments/suggestions on
>>>> some CalDAV implementation
>>>>>>> issues I need to resolve...
>>>>>>>
>>>>>>> In OFBiz, parties and fixed assets can be
>>>> assigned to work efforts. In
>>>>>>> CalDAV, calendars are viewed as a folder
>>>> structure with *.ics files in
>>>>>>> them. The simplest way to map the CalDAV spec
>>>> to OFBiz (that I can
>>>>>>> imagine) would be to have two main collections
>>>> (folders) - parties and
>>>>>>> fixedassets. Within each collection would be
>>>> one calendar per
>>>>>>> party/fixed asset. Within each collection the
>>>> iCal "files" (the request
>>>>>>> for a file will do a WorkEffort lookup and
>>>> return an iCal text stream -
>>>>>>> there is no physical file) will be named
>>>> according to user login ID or
>>>>>>> fixed asset ID.
>>>>>>>
>>>>>>> So, assuming a base URL of
>>>> https://localhost:8443/ical - the calendar
>>>>>>> for the admin user login would be
>>>>>>> https://localhost:8443/ical/parties/admin.ics,
>>>> and the calendar for the
>>>>>>> DEMO_MACHINE fixed asset would be
>>>>>>>
>>>> https://localhost:8443/ical/fixedassets/DEMO_MACHINE.ics.
>>>>>>>
>>>>>>> This is a crude and simple implementation that
>>>> would serve my immediate
>>>>>>> needs, but it needs more work to make it more
>>>> appealing to others (and
>>>>>>> to make it RFC compliant). Here is where I
>>>> need your help - I need ideas
>>>>>>> on these potential issues:
>>>>>>>
>>>>>>> 1. Some users might balk at the idea of using
>>>> their login ID as a
>>>>>>> calendar name - since the URL could become
>>>> public if the user wants to
>>>>>>> share their calendar. We would need a way to
>>>> map an iCal URL to a user's
>>>>>>> work efforts. Example:
>>>> https://localhost:8443/ical/TheAdministrator.ics
>>>>>>> maps to user login ID admin.
>>>>>>>
>>>>>>> 2. The CalDAV specification allows for an
>>>> arbitrary arrangement of
>>>>>>> collections - just like the folder structure
>>>> on a hard disk. So, I could
>>>>>>> have something like -
>>>>>>>
>>>>>>> https://localhost:8443/ical/adrian.ics
>>>>>>> or
>>>>>>> https://localhost:8443/ical/adrian/public.ics
>>>>>>> https://localhost:8443/ical/adrian/private.ics
>>>>>>>
>>>>>>> So there would have to be a way to map
>>>> multiple calendars to each user.
>>>>>>> The example brings up another issue - how to
>>>> map work efforts to
>>>>>>> different calendars.
>>>>>>>
>>>>>>> Let me know what you think.
>>>>>>>
>>>>>>> -Adrian
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>
>>>
>>>