Parser.cs :  » Network-Clients » RemoteCalendars » Semaview » Shared » ICalParser » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Network Clients » RemoteCalendars 
RemoteCalendars » Semaview » Shared » ICalParser » Parser.cs
using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Collections;

/***
 * <copyright>
 *   ICalParser is a general purpose .Net parser for iCalendar format files (RFC 2445)
 * 
 *   Copyright (C) 2004  J. Tim Spurway
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * </copyright>
 */

namespace Semaview.Shared.ICalParser{
    /// <summary>
    /// Parse iCalendar rfc2445 streams and convert to another format based on the emitter used.
    /// </summary>
    /// 
    /// <remarks>
    /// This class is the main entry point for the ICalParser library.  A parser is created
    /// with a TextReader that contains the iCalendar stream to be parsed, and an IEmitter, which 
    /// is used to transform the iCalendar into another format.
    /// 
    /// Each iCalendar format file is in the form:
    /// 
    ///   ID[[;attr1;attr2;attr3;...;attrn]:value]
    ///   
    /// where ID is the main keyword identifying the iCalendar entry, followed optionally by a 
    /// set of attributes and a single value.  The parser works by identifying the specific IDs,
    /// attributes and values, categorizing them based on similar 'behaviour' (as defined in the <code>Token</code>
    /// class) and passing on recognized symbols to the emitter for further processing.  
    /// 
    /// The error recovery policy of the parser is pretty simple.  When an error is detected, it is recorded,
    /// and the rest of the (possibly folded) line is read, and parsing continues.  
    /// </remarks>
    /// 
    /// <example>
    /// The following snippet will read the contents of the file 'myCalendar.ics', which the
    /// parser will expect to contain iCalendar statements, and will write the RdfICalendar
    /// equivalent to standard output.
    /// <code>
    ///      RDFEmitter emitter = new RDFEmitter( );
    ///      StreamReader reader = new StreamReader( "myCalendar.ics" );
    ///      Parser parser = new Parser( reader, emitter );
    ///      parser.Parse( );
    ///      Console.WriteLine( emitter.Rdf );
    /// </code>
    /// </example>
    /// 
    public class Parser
    {
  ArrayList errors;
  Scanner scanner;
  StringBuilder buff;
  Stack stack, attributes;
  IEmitter emitter;
  int linenumber;
  Token id, iprop;  // id is the current ID for the current line

  /// <summary>
  /// Create a new iCalendar parser.
  /// </summary>
  /// <param name="reader">The reader that contains the stream of text iCalendar</param>
  /// <param name="_emitter">The emitter that will transform the iCalendar elements</param>
  public Parser( TextReader reader, IEmitter _emitter )
  {
      scanner = new Scanner( reader );
      emitter = _emitter;
      emitter.VParser = this;
      errors = new ArrayList();
  }

  public ArrayList Errors
  {
      get
      {
    return errors;
      }
  }

  public string ErrorString
  {
      get
      {
    if( !HasErrors )
    {
        return "";
    }

    StringBuilder rval = new StringBuilder();
    foreach( ParserError error in errors )
    {
        rval.Append( error.ToString() ).Append( "\r\n" );
    }
    return rval.ToString();
      }
  }

  public bool HasErrors
  {
      get { return errors.Count > 0; }
  }

  /// <summary>
  /// Give public access to the parse stack.
  /// </summary>
  /*private Stack VStack
  {
      get { return stack; }
  }*/

  /// <summary>
  /// Main entry point for starting the Parser.
  /// </summary>
  public void Parse( )
  {
      Parse( true );
  }

  /// <summary>
  /// Alternate entry point for starting the parser.
  /// </summary>
  /// <param name="emitHandT">Indicates if the emitter should be told to emit headers
  /// and trailers before and after emitting the iCalendar body</param>
  public void Parse( bool emitHandT )
  {
      buff = new StringBuilder();
      stack = new Stack( );
      linenumber = 0;
      attributes = new Stack( );  // a stack of key-value pairs (implemented as a stack of DitionaryEntry)

      if( emitHandT )
      {
    emitter.doIntro();
      }

      // each time through the loop will get a single (maybe folded) line
      while( true )
      {
    // check for termination condition
    if( scanner.isEOF() )
    {
        // end of file - do cleanup and go
        break;
    }

    // empty the attribute stack and the iprop value...
    attributes.Clear();
    iprop = null;
    id = null;

    //FIXME: linenumber doesn't really keep track of actual line numbers because
    //       it is not aware of folded lines...
    linenumber++;

    //DEBUG: emit line number
    //emitter.emit( linenumber + ". " );

    if( !parseID() )
    {
        continue;
    }

    // we now have to parse a set of attributes (semi-colon separated) or
    // a value (delimited by a colon)
    Token sep = scanner.GetNextToken( ScannerState.ParseSimple );
    if( sep == null || sep.TokenVal == TokenValue.Error )
    {
        // some kind of error - skip rest of line and continue
        reportError( scanner,  " expecting : or ; after id - found nothing." );
        continue;
    }
    else if( sep.TokenVal == TokenValue.SemiColon )
    {
        if( !parseAttributes( scanner ))
        {
      continue;
        }

        // now we have to parse the value
        sep = scanner.GetNextToken( ScannerState.ParseSimple );
        if( !parseValue() )
        {
      continue;
        }
    }
    else if( sep.TokenVal == TokenValue.Colon )
    {
        if( !parseValue() )
        {
      continue;
        }
    }
    else
    {
        reportError( scanner, "expecting : or ; after id - found: " + sep.TokenText );
        continue;
    }

    // now sploosh out the attributes (if any) and finish the ID tag
    while( attributes.Count > 0 )
    {
        DictionaryEntry entry = (DictionaryEntry) attributes.Pop();
        Token key = (Token) entry.Key;
        Token val = (Token) entry.Value;
        emitter.doAttribute( key, val );
    }

    emitter.doEnd( id );
      }

      if( emitHandT )
      {
    emitter.doOutro();
      }
  }

  protected void reportError( Scanner s, string msg )
  {
      s.ConsumeToEOL( );
      //Console.Error.WriteLine( "Found an error on line " + linenumber + " : " + msg );
      errors.Add( new ParserError( linenumber, msg ));
  }

  protected void reportFatalError( Scanner s, string msg )
  {
      s.ConsumeToEOL( );
      //Console.Error.WriteLine( "Found a fatal error on line " + linenumber + " : " + msg );
      errors.Add( new ParserError( linenumber, msg ));
  }

  /// <summary>
  /// Parse the first field (ID) of the line.  Returns a boolean on weather or not the
  /// method sucesfully recognized an ID.  If not, the method insures that the scanner
  /// will start at the beginning of a new line.
  /// </summary>
  /// <returns></returns>
  protected virtual bool parseID( )
  {
      Token t;  // re-usable token variable
      id = scanner.GetNextToken( ScannerState.ParseID );
      if( id == null || id.TokenVal == TokenValue.Error )
      {
    // some kind of error - skip rest of line and continue
    reportError( scanner, "expecting ID - found nothing." );
    return false;
      }

      switch( id.TokenVal )
      {
    case TokenValue.Tbegin:
        t = scanner.GetNextToken( ScannerState.ParseSimple );
        if( t == null || t.isError() || t.TokenVal != TokenValue.Colon )
        {
      if( t == null )
          reportError( scanner, " expecting : - found nothing." );
      else
          reportError( scanner, " expecting : - found " + t.TokenText );
      return false;
        }

        t = scanner.GetNextToken( ScannerState.ParseID );
        if( t == null || t.isError() || (!t.isBeginEndValue() && !t.isResourceProperty() ))
        {
      if( t == null )
          reportError( scanner, " expecting a valid beginend value - found nothing." );
      else
          reportError( scanner, " expecting a valid beginend value - found " + t.TokenText );
      return false;
        }

        // check for the different types of begin tags
        if( t.isResourceProperty() )
        {
      emitter.doResourceBegin( t );
        }
        else if( t.isComponent() )
        {
      emitter.doComponent();
      emitter.doComponentBegin( t );
        }
        else if( t.TokenVal == TokenValue.Tvcalendar )
        {
      emitter.doComponentBegin( t );
        }
        else
        {
      emitter.doBegin( t );
        }
        stack.Push( t );  // to match up to the corresponding end value
        //scanner.ConsumeToEOL();
        return false;

    case TokenValue.Tend:
        t = scanner.GetNextToken( ScannerState.ParseSimple );
        if( t == null || t.isError() || t.TokenVal != TokenValue.Colon )
        {
      if( t == null )
          reportError( scanner, " expecting : - found nothing." );
      else
          reportError( scanner, " expecting : - found " + t.TokenText );
      return false;
        }

        t = scanner.GetNextToken( ScannerState.ParseID );
        if( t == null || t.isError() || (!t.isBeginEndValue() && !t.isResourceProperty( )))
        {
      if( t == null )
          reportError( scanner, " expecting a valid beginend value - found nothing." );
      else
          reportError( scanner, " expecting a valid beginend value - found " + t.TokenText );
      return false;
        }

        // the end is easier - ignore the last one...  
        if( stack.Count != 0 )
        {
      emitter.doEnd( t );
      if( t.isComponent() )
      {
          emitter.doEndComponent();
      }
      stack.Pop();
        }
        else
        {
      reportError( scanner, "stack stuff is weird - probably illformed .ics file - parsing " + id.TokenText );
        }
        //scanner.ConsumeToEOL();
        return false;

    case TokenValue.Trrule:
        emitter.doResourceBegin( id );
        break;

    default:
        emitter.doID( id );
        break;
      }
      return true;
  }

  /// <summary>
  /// Parse the list of attributes - separated by ';'s.  Attributes always are in the
  /// form 'id=value' and indicate key/value pairs in the iCalendar attribute format.
  /// </summary>
  /// <returns></returns>
  protected virtual bool parseAttributes( Scanner scan )
  {
      Token key = scan.GetNextToken( ScannerState.ParseKey );
      if( key == null || key.TokenVal == TokenValue.Error )
      {
    // some kind of error - skip rest of line and continue
    if( key == null )
        reportError( scanner, " expecting ID - found nothing." );
    else
        reportError( scanner, " expecting ID - found " + key.TokenText );
    return false;
      }

      Token sep = scan.GetNextToken( ScannerState.ParseSimple );
      if( sep == null || sep.TokenVal == TokenValue.Error || sep.TokenVal != TokenValue.Equals )
      {
    // some kind of error - skip rest of line and continue
    if( sep == null )
        reportError( scanner, " expecting = - found nothing." );
    else
        reportError( scanner, " expecting = - found " + sep.TokenText );
    return false;
      }

      Token val = scan.GetNextToken( ScannerState.ParseParms );
      if( val == null || val.TokenVal == TokenValue.Error )
      {
    // some kind of error - skip rest of line and continue
    if( val == null )
        reportError( scanner, " expecting parameter - found nothing." );
    else
        reportError( scanner, " expecting parameter - found " + val.TokenText );
    return false;
      }

      if( key.TokenVal == TokenValue.Tvalue && scanner == scan )
      {
    // it's an IPROP - don't ask...
    iprop = val;
      }
      else
      {
    attributes.Push( new DictionaryEntry( key, val ));
      }

      // do a recursive case to identify all of the attributes
      sep = scan.GetNextToken( ScannerState.ParseSimple );
      if( sep == null || sep.TokenVal == TokenValue.Error )
      {
    // if we are parsing an rrule - this is the line termination
    if( scanner != scan )
    {
        return true;
    }

    // some kind of error - skip rest of line and continue
    if( sep == null )
        reportError( scanner, " expecting : or ; - found nothing." );
    else
        reportError( scanner, " expecting : or ; - found " + sep.TokenText );
    return false;
      }

      if( sep.TokenVal == TokenValue.Colon )
      {
    // termination case
    return true;
      }
      else if( sep.TokenVal == TokenValue.SemiColon )
      {
    // recursive case
    return parseAttributes( scan );
      }
      return true;
  }

  /// <summary>
  /// Parse the value.  The value is the last data item on a iCalendar input line.
  /// </summary>
  /// <returns></returns>
  protected virtual bool parseValue( )
  {
      Token val = scanner.GetNextToken( ScannerState.ParseValue );
      if( val == null || val.TokenVal == TokenValue.Error )
      {
    // some kind of error - skip rest of line and continue
    if( val == null )
        reportError( scanner, " expecting value - found nothing." );
    else
        reportError( scanner, " expecting value - found " + val.TokenText );
    return false;
      }

      // the emmision of code for the value will depend on the ID for this line
      if( id.isSymbolicProperty() )
      {
    emitter.doSymbolic( val );
    return false;  // because this ends the tag
      }
      else if( id.isMailtoProperty() )
      {
    emitter.doMailto( val );
      }
      else if( id.isValueProperty() )
      {
    if( id.TokenVal == TokenValue.Trrule )
    {
        // this is a special case - the value will be an attribute list...
        parseAttributes( new Scanner( new StringReader( val.TokenText )));
    }
    else
    {
        emitter.doValueProperty( val, iprop );
    }
      }
      else if( iprop != null && id.TokenVal != TokenValue.Xtension )
      {
    if( iprop.TokenText.ToLower() == "uri" )
    {
        // special case 
        emitter.doURIResource( val );
    }
    else
    {
        emitter.doIprop( val, iprop );
    }
    return false;
      }
      else
      {
    if( id.TokenVal == TokenValue.TrecurrenceId )
        val.FormatDateTime();  // if this is a recurrence id, then format the date so that it is a legal date type for RDF and RQL
    emitter.doRest( val, id );
    return false;
      }
      return true;
  }

    }

//    #region csUnit Tests
//#if DEBUG
//    namespace Test
//    {
//    using csUnit;

//    public class ParserTest
//    {
//        private const string testcaseDir = "ICalParser\\testcases\\";
//        private const string resultDir = "ICalParser\\testcases\\results\\";
//        private static string[] testcases = new string[]
//        {
//        "20030115mtg",
//        "20030122mtg",
//        "20030205mtg",
//        "20030212mtg",
//        "20030226mtg",
//        "20030312mtg",
//        "20030326mtg",
//        "Philosophers'Birthdays",
//        "Home",
//        "ComplexEvent",
//        "ComplexerEvents",
//        "allday",
//        "DVDs",
//        "RecurExept",
//        "RecurAnomoly",
//        "Mac32Events",
//        };
//        private const string icalExt = ".ics";
//        private const string rdfExt = ".rdf";
//        private const string rqlExt = ".rql";
//        private const string tripleExt = ".trp";
//        private int tally = 0;

//        public ParserTest(){}

//        public void testParser( )
//        {
//        string icalString = 
//@"BEGIN:VCALENDAR
//METHOD:REQUEST
//BEGIN:VEVENT
//SEQUENCE:2
//ATTENDEE;CN=Libby Miller:mailto:libby.miller@bristol.ac.uk
//DTSTAMP:20030109T123909Z
//SUMMARY:IRC Meet
//UID:EB825E41-23CE-11D7-B93D-003065B0C95E
//ORGANIZER;CN=Damian Steer:mailto:pldms@mac.com
//DTSTART;
// TZID=/softwarestudio.org/Olson_20011030_5/Europe/London:20030115T180000
//DURATION:PT1H
//BEGIN:VALARM
//ATTACH;VALUE=URI:Ping
//TRIGGER;VALUE=DURATION:-PT10M
//ACTION:AUDIO
//END:VALARM
//END:VEVENT
//
//BEGIN:VTIMEZONE
//TZID:/softwarestudio.org/Olson_20011030_5/Europe/London
//X-LIC-LOCATION:Europe/London
//BEGIN:STANDARD
//TZOFFSETFROM:+0100
//TZOFFSETTO:+0000
//TZNAME:GMT
//DTSTART:19701025T020000
//RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
//END:STANDARD
//BEGIN:DAYLIGHT
//TZOFFSETFROM:+0000
//TZOFFSETTO:+0100
//TZNAME:BST
//DTSTART:19700329T010000
//RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3
//END:DAYLIGHT
//END:VTIMEZONE
//
//END:VCALENDAR
//";

//        RDFEmitter emitter = new RDFEmitter( );
//        Parser parser = new Parser( new StringReader( icalString ), emitter );
//        parser.Parse( );
//        Console.WriteLine( emitter.Rdf );

//        }

//        public void testError( )
//        {
//        string icalString = 
//@"BEGIN:VCALENDAR
//METHOD:REQUEST
//BEGIN:VEVENT
//SEQUENCE:2
//ATTENDEE;CN--------<error here>Libby Miller:mailto:libby.miller@bristol.ac.uk
//DTSTAMP:20030109T123909Z
//SUMMARY:IRC Meet
//UID:EB825E41-23CE-11D7-B93D-003065B0C95E
//ORGANIZER;CN=Damian Steer:mailto:pldms@mac.com
//DTSTART;
// TZID=/softwarestudio.org/Olson_20011030_5/Europe/London:20030115T180000
//DURATION:PT1H
//BEGIN:VALARM
//ATTACH;VALUE=URI:Ping
//TRIGGER;VALUE=DURATION:-PT10M
//ACTION:AUDIO
//END:VALARM
//END:VEVENT
//
//BEGIN:VTIMEZONE
//TZID:/softwarestudio.org/Olson_20011030_5/Europe/London
//X-LIC-LOCATION:Europe/London
//BEGIN:STANDARD
//TZOFFSETFROM:+0100
//TZOFFSETTO:+0000
//TZNAME:GMT
//DTSTART:19701025T020000
//RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
//END:STANDARD
//BEGIN:DAYLIGHT
//TZOFFSETFROM:+0000
//TZOFFSETTO:+0100
//TZNAME:BST
//DTSTART:19700329T010000
//RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3
//END:DAYLIGHT
//END:VTIMEZONE
//
//END:VCALENDAR
//";

//        RDFEmitter emitter = new RDFEmitter( );
//        Parser parser = new Parser( new StringReader( icalString ), emitter );
//        parser.Parse( );
//        Console.WriteLine( emitter.Rdf );
//        Assert.True( parser.HasErrors );
//        }


//        public void testRDFQLParser( )
//        {
//        string icalString = 
//@"BEGIN:VCALENDAR
//METHOD:REQUEST
//BEGIN:VEVENT
//SEQUENCE:2
//ATTENDEE;CN=Libby Miller:mailto:libby.miller@bristol.ac.uk
//DTSTAMP:20030109T123909Z
//SUMMARY:IRC Meet
//UID:EB825E41-23CE-11D7-B93D-003065B0C95E
//ORGANIZER;CN=Damian Steer:mailto:pldms@mac.com
//DTSTART;VALUE=DATE:20030115
//DURATION:PT1H
//BEGIN:VALARM
//ATTACH;VALUE=URI:Ping
//TRIGGER;VALUE=DURATION:-PT10M
//ACTION:AUDIO
//END:VALARM
//END:VEVENT
//
//BEGIN:VTIMEZONE
//TZID:/softwarestudio.org/Olson_20011030_5/Europe/London
//X-LIC-LOCATION:Europe/London
//BEGIN:STANDARD
//TZOFFSETFROM:+0100
//TZOFFSETTO:+0000
//TZNAME:GMT
//DTSTART:19701025T020000
//RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
//END:STANDARD
//BEGIN:DAYLIGHT
//TZOFFSETFROM:+0000
//TZOFFSETTO:+0100
//TZNAME:BST
//DTSTART:19700329T010000
//RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3
//END:DAYLIGHT
//END:VTIMEZONE
//
//END:VCALENDAR
//";

//        RQLEmitter emitter = new RQLEmitter( );
//        Parser parser = new Parser( new StringReader( icalString ), emitter );
//        parser.Parse( );
//        Console.WriteLine( emitter.Rql );

//        }

//        public void testParser_testsuite( )
//        {
//        System.IO.Directory.CreateDirectory( resultDir );
//        for( int i = 0; i < testcases.Length; ++i )
//        {
//            RDFEmitter emitter = new RDFEmitter( );
//            RQLEmitter rqlEmitter = new RQLEmitter( );
//            StreamReader reader = new StreamReader( testcaseDir + testcases[i] + icalExt );
//            StreamReader rqlReader = new StreamReader( testcaseDir + testcases[i] + icalExt );
//            Parser parser = new Parser( reader, emitter );
//            Parser rqlParser = new Parser( rqlReader, rqlEmitter );
//            parser.Parse( );
//            rqlParser.Parse( );
//            StreamWriter writer = new StreamWriter( resultDir + testcases[i] + rdfExt );
//            StreamWriter rqlWriter = new StreamWriter( resultDir + testcases[i] + rqlExt );
//            writer.WriteLine( emitter.Rdf );
//            rqlWriter.WriteLine( String.Format( rqlEmitter.Rql, "icaltest" ));
//            writer.Close();
//            reader.Close();
//            rqlWriter.Close();
//            rqlReader.Close();
//        }
//        }

//        public void testTripleEmitter( )
//        {
//        System.IO.Directory.CreateDirectory( resultDir );
//        for( int i = 0; i < testcases.Length; ++i )
//        {
//            TripleEmitter emitter = new TripleEmitter( );
//            StreamReader reader = new StreamReader( testcaseDir + testcases[i] + icalExt );
//            Parser parser = new Parser( reader, emitter );
//            parser.Parse( );
//            StreamWriter writer = new StreamWriter( resultDir + testcases[i] + tripleExt );
//            foreach( Triple t in emitter.Triples )
//            {
//            Assert.True( t.GetObject() != null );
//            Assert.True( t.GetPredicate() != null );
//            Assert.True( t.GetSubject() != null );
//            writer.WriteLine( t.ToString() );
//            }
//            writer.Close();
//            reader.Close();
//        }
//        }

//        public void persister( string rql )
//        {
//        tally++;
//        Console.Out.WriteLine( "PERSISTER OUTPUT----------------------: " + tally );
//        Console.Out.WriteLine( rql );
//        }

//        public void testRQLPersister( )
//        {
//        tally = 0;
//        RQLEmitter rqlEmitter = new RQLEmitter( new Persister( persister ));
//        StreamReader rqlReader = new StreamReader( testcaseDir + "DVDs.ics" );
//        Parser rqlParser = new Parser( rqlReader, rqlEmitter );
//        rqlParser.Parse( );
//        rqlReader.Close();
//        Assert.True( tally > 0 );
//        }
//    }
//    }
//#endif
//    #endregion
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.