[pyatspi2] Fix property getting to use the correct interfaces.
- From: Mark Doffman <markdoffman src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [pyatspi2] Fix property getting to use the correct interfaces.
- Date: Sun, 24 Jan 2010 13:29:32 +0000 (UTC)
commit 90d1f73334703ea89a2bdd404e59465679eafb49
Author: Mark Doffman <mark doffman codethink co uk>
Date: Fri Jan 22 01:28:44 2010 -0800
Fix property getting to use the correct interfaces.
Re-factor the conversion between D-Bus and Corba event types.
pyatspi/accessible.py | 23 ++--
pyatspi/appevent.py | 275 +++++++++++++++++++++++-------------------------
pyatspi/application.py | 4 +-
pyatspi/factory.py | 6 +-
pyatspi/hyperlink.py | 6 +-
pyatspi/image.py | 4 +-
pyatspi/interfaces.py | 2 +-
pyatspi/registry.py | 3 +-
pyatspi/selection.py | 2 +-
pyatspi/table.py | 12 +-
pyatspi/text.py | 4 +-
pyatspi/value.py | 8 +-
12 files changed, 167 insertions(+), 182 deletions(-)
---
diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py
index fedf09d..4c4e1dd 100644
--- a/pyatspi/accessible.py
+++ b/pyatspi/accessible.py
@@ -353,18 +353,17 @@ class Accessible(BaseProxy):
@return : a long integer indicating this object's index in the
parent's list.
"""
- if self._cached:
- parent = self.get_parent()
- if parent == None:
- return -1
- for i in range(0, parent.childCount):
- child = parent.getChildAtIndex(i)
- if self == child:
- return i
- raise AccessibleObjectNoLongerExists("Child not found within parent")
- else:
- func = self.get_dbus_method("GetIndexInParent", dbus_interface=ATSPI_ACCESSIBLE)
- return func()
+ parent = self.get_parent()
+ if parent == None:
+ return -1
+ for i in range(0, parent.childCount):
+ child = parent.getChildAtIndex(i)
+ if self == child:
+ return i
+ raise AccessibleObjectNoLongerExists("Child not found within parent")
+
+ #func = self.get_dbus_method("GetIndexInParent", dbus_interface=ATSPI_ACCESSIBLE)
+ #return func()
def getLocalizedRoleName(self):
"""
diff --git a/pyatspi/appevent.py b/pyatspi/appevent.py
index b995758..7ba9b46 100644
--- a/pyatspi/appevent.py
+++ b/pyatspi/appevent.py
@@ -27,28 +27,6 @@ __all__ = [
#------------------------------------------------------------------------------
-_interface_to_klass = {
- "org.freedesktop.atspi.Event.Object":"object",
- "org.freedesktop.atspi.Event.Window":"window",
- "org.freedesktop.atspi.Event.Mouse":"mouse",
- "org.freedesktop.atspi.Event.Keyboard":"keyboard",
- "org.freedesktop.atspi.Event.Terminal":"terminal",
- "org.freedesktop.atspi.Event.Document":"document",
- "org.freedesktop.atspi.Event.Focus":"focus",
- }
-
-_klass_to_interface = {
- "object":"org.freedesktop.atspi.Event.Object",
- "window":"org.freedesktop.atspi.Event.Window",
- "mouse":"org.freedesktop.atspi.Event.Mouse",
- "keyboard":"org.freedesktop.atspi.Event.Keyboard",
- "terminal":"org.freedesktop.atspi.Event.Terminal",
- "document":"org.freedesktop.atspi.Event.Document",
- "focus":"org.freedesktop.atspi.Event.Focus",
- }
-
-#------------------------------------------------------------------------------
-
class _ELessList(list):
def __getitem__(self, index):
try:
@@ -124,67 +102,126 @@ class EventType(str):
#------------------------------------------------------------------------------
-def atspi_to_dbus(name):
- ret = string.upper(name[0])
- for i in range(1,len(name)):
- if (name[i] == '-'):
- pass
- elif (name[i-1] == '-'):
- ret += string.upper(name[i])
- else:
- ret += name[i]
- return ret
-
-def dbus_to_atspi(name):
- ret = string.lower(name[0])
- for i in range(1,len(name)):
- if (name[i] == str.lower(name[i])):
- ret += name[i]
- else:
- ret += "-" + string.lower(name[++i])
- return ret
+_interface_to_klass = {
+ "org.freedesktop.atspi.Event.Object":"object",
+ "org.freedesktop.atspi.Event.Window":"window",
+ "org.freedesktop.atspi.Event.Mouse":"mouse",
+ "org.freedesktop.atspi.Event.Keyboard":"keyboard",
+ "org.freedesktop.atspi.Event.Terminal":"terminal",
+ "org.freedesktop.atspi.Event.Document":"document",
+ "org.freedesktop.atspi.Event.Focus":"focus",
+ }
+
+_klass_to_interface = {
+ "object":"org.freedesktop.atspi.Event.Object",
+ "window":"org.freedesktop.atspi.Event.Window",
+ "mouse":"org.freedesktop.atspi.Event.Mouse",
+ "keyboard":"org.freedesktop.atspi.Event.Keyboard",
+ "terminal":"org.freedesktop.atspi.Event.Terminal",
+ "document":"org.freedesktop.atspi.Event.Document",
+ "focus":"org.freedesktop.atspi.Event.Focus",
+ }
+
+#------------------------------------------------------------------------------
+
+def _major_to_signal_name (name):
+ ret = string.upper(name[0])
+ for i in range(1,len(name)):
+ if (name[i] == '-'):
+ pass
+ elif (name[i-1] == '-'):
+ ret += string.upper(name[i])
+ else:
+ ret += name[i]
+ return ret
+
+def _signal_name_to_major (name):
+ ret = string.lower(name[0])
+ for i in range(1,len(name)):
+ if (name[i] == str.lower(name[i])):
+ ret += name[i]
+ else:
+ ret += "-" + string.lower(name[++i])
+ return ret
+
+#------------------------------------------------------------------------------
+
+def signal_spec_to_event_type (interface, name, minor):
+ """
+ Converts an AT-SPI D-Bus signal specification into a Corba AT-SPI
+ event type.
+ """
+ klass = _interface_to_klass[interface]
+ major = _signal_name_to_major (name)
+
+ if klass == "focus":
+ return EventType ("focus:")
+
+ event_string = klass + ':' + major + ':'
+ if minor:
+ event_string += minor
+ return EventType (event_string)
def event_type_to_signal_reciever(bus, factory, event_handler, event_type):
+ """
+ Converts a Corba AT-SPI event type to the correct D-Bus AT-SPI signal
+ reciever.
+ """
kwargs = {
'sender_keyword':'sender',
'interface_keyword':'interface',
'member_keyword':'member',
'path_keyword':'path',
}
- if event_type.major:
- major = atspi_to_dbus(event_type.major)
if event_type.klass:
kwargs['dbus_interface'] = _klass_to_interface[event_type.klass]
if event_type.major:
- kwargs['signal_name'] = major
+ kwargs['signal_name'] = _major_to_signal_name (event_type.major)
if event_type.minor:
kwargs['arg0'] = event_type.minor
- def handler_wrapper(app, minor, detail1, detail2, any_data,
- sender=None, interface=None, member=None, path=None):
- event = Event((minor, detail1, detail2, any_data), factory, path, app, interface, member)
+ def handler_wrapper(source_application,
+ minor,
+ detail1,
+ detail2,
+ any_data,
+ sender=None,
+ interface=None,
+ member=None,
+ path=None):
+
+ # Convert the event type
+ type = signal_spec_to_event_type (interface, member, minor)
+
+ # Marshal the 'any_data' to correct class / structure
+ if type.is_subtype (EventType ("object:bounds-changed")):
+ any_data = BoundingBox(*any_data)
+ elif (type.is_subtype (EventType ("object:children-changed")) or
+ type.is_subtype (EventType ("object:property-change:parent"))):
+ data_name, data_path = any_data;
+ any_data = factory (data_name, data_path, interfaces.ATSPI_ACCESSIBLE)
+
+ # Create the source application
+ source_app_name, source_app_path = source_application
+ source_application = factory (source_app_name, source_app_path, interfaces.ATSPI_APPLICATION)
+
+ # Create the source
+ source_name = sender
+ source_path = path
+ source = factory (source_name, source_path, interfaces.ATSPI_ACCESSIBLE)
+
+ event = Event (type,
+ detail1,
+ detail2,
+ any_data,
+ source_application,
+ source)
return event_handler(event)
return bus.add_signal_receiver(handler_wrapper, **kwargs)
#------------------------------------------------------------------------------
-def signal_spec_to_event_string (interface, name, minor):
- interface = _interface_to_klass[interface]
- name = dbus_to_atspi(name)
-
- if interface == "focus":
- return "focus:"
-
- result = interface + ':'
- if name:
- result += name + ':'
- if minor:
- result += minor
- return result
-
-#------------------------------------------------------------------------------
-
class Event(object):
"""
Wraps an AT-SPI event with a more Pythonic interface managing exceptions,
@@ -204,91 +241,39 @@ class Event(object):
@type any_data: object
@ivar host_application: Application owning the event source
@type host_application: Tuple (Name, Path)
- @ivar source_name: Name of the event source at the time of event dispatch
- @type source_name: string
- @ivar source_role: Role of the event source at the time of event dispatch
- @type source_role: Accessibility.Role
@ivar source: Source of the event
@type source: Accessibility.Accessible
"""
- def __init__(self, event,
- acc_factory=None,
- source_path=None,
- source_application=None,
- interface=None,
- name=None):
- """
- Extracts information from the provided event. If the event is a "normal"
- event, pulls the detail1, detail2, any_data, and source values out of the
- given object and stores it in this object. If the event is a device event,
- key ID is stored in detail1, scan code is stored in detail2, key name,
- key modifiers (e.g. ALT, CTRL, etc.), is text flag, and timestamp are
- stored as a 4-tuple in any_data, and source is None (since key events are
- global).
-
- @param event: Event from an AT-SPI callback
- @type event: Accessibility.Event or Accessibility.DeviceEvent
- """
-
- if acc_factory == None:
- #This alternative init is provided for compatibility with the old API.
- #The old API apparently allowed the event to be delivered as a class with
- #named parameters. (Something like a copy constructor)
- #Old API used in orca - focus_tracking_presenter.py line 1106
- self._source = event.source
- self._application = event.source
-
- self.type = event.type
- self.detail1 = event.detail1
- self.detail2 = event.detail2
- self.any_data = event.any_data
- else:
- self._acc_factory = acc_factory
- self._source_path = source_path
- self._source_application = source_application
-
- self._source = None
- self._application = None
-
- self.type = EventType(signal_spec_to_event_string(interface, name, event[0]))
-
- self.detail1 = event[1]
- self.detail2 = event[2]
-
- data = event[3]
-
- if self.type.is_subtype (EventType ("object:bounds-changed")):
- self.any_data = BoundingBox(*data)
- elif self.type.is_subtype (EventType ("object:children-changed")):
- name, path = data;
- self.any_data = self._acc_factory (name, path, interfaces.ATSPI_ACCESSIBLE)
- self.any_data = ""
- elif self.type.is_subtype (EventType ("object:property-change:parent")):
- name, path = data;
- self.any_data = self._acc_factory (name, path, interfaces.ATSPI_ACCESSIBLE)
- else:
- self.any_data = data
-
- @property
- def host_application(self):
- if not self._application:
- try:
- name, path = self._source_application
- return self._acc_factory (name, path, interfaces.ATSPI_APPLICATION)
- except AccessibleObjectNoLongerExists:
- pass
- return self._application
+ def __init__(self,
+ type_slash_event=None,
+ detail1=None,
+ detail2=None,
+ any_data=None,
+ host_application=None,
+ source=None):
+
+ if detail1 == None:
+ #This alternative init is provided for compatibility with the old API.
+ #The old API apparently allowed the event to be delivered as a class with
+ #named parameters. (Something like a copy constructor)
+ #Old API used in orca - focus_tracking_presenter.py line 1106
+ event = type_slash_event
+
+ self.type = event.type
+ self.detail1 = event.detail1
+ self.detail2 = event.detail2
+ self.any_data = event.any_data
+ self.source = event.source
+ self.application = event.source
+ else:
+ type = type_slash_event
- @property
- def source(self):
- if not self._source:
- try:
- self._source = self._acc_factory (self._source_application,
- self._source_path,
- interfaces.ATSPI_ACCESSIBLE)
- except AccessibleObjectNoLongerExists:
- pass
- return self._source
+ self.type = type
+ self.detail1 = detail1
+ self.detail2 = detail2
+ self.any_data = any_data
+ self.source = source
+ self.host_application = host_application
@property
def source_name(self):
@@ -316,7 +301,7 @@ class _ApplicationEventRegister (object):
def __init__ (self, factory):
self._bus = AccessibilityBus ()
- self._factory = factory
+ self._factory = factory
self._event_listeners = {}
diff --git a/pyatspi/application.py b/pyatspi/application.py
index ffa4b5b..f65baad 100644
--- a/pyatspi/application.py
+++ b/pyatspi/application.py
@@ -44,7 +44,7 @@ class Application(Accessible):
return func(local_type)
def get_toolkitName(self):
- return dbus.String(self._pgetter(self._dbus_interface, "ToolkitName"))
+ return dbus.String(self._pgetter(ATSPI_APPLICATION, "ToolkitName"))
_toolkitNameDoc = \
"""
A string indicating the type of user interface toolkit which
@@ -53,7 +53,7 @@ class Application(Accessible):
toolkitName = property(fget=get_toolkitName, doc=_toolkitNameDoc)
def get_version(self):
- return dbus.String(self._pgetter(self._dbus_interface, "Version"))
+ return dbus.String(self._pgetter(ATSPI_APPLICATION, "Version"))
_versionDoc = \
"""
A string indicating the version number of the application's accessibility
diff --git a/pyatspi/factory.py b/pyatspi/factory.py
index 2ed9c31..78ae11f 100644
--- a/pyatspi/factory.py
+++ b/pyatspi/factory.py
@@ -70,11 +70,11 @@ class AccessibleFactory (object):
self._cache = cache
def __call__ (self, name, path, itf, dbus_object=None):
- if dbus_object == None:
- dbus_object = self._connection.get_object (name, path)
-
if path == interfaces.ATSPI_NULL_PATH:
return None
+
+ if dbus_object == None:
+ dbus_object = self._connection.get_object (name, path)
return self._interfaces[itf] (self._cache, self, name, path, dbus_object)
diff --git a/pyatspi/hyperlink.py b/pyatspi/hyperlink.py
index 23f8516..48b59b4 100644
--- a/pyatspi/hyperlink.py
+++ b/pyatspi/hyperlink.py
@@ -74,7 +74,7 @@ class Hyperlink(Accessible):
return func()
def get_endIndex(self):
- return dbus.Int32(self._pgetter(self._dbus_interface, "EndIndex"))
+ return dbus.Int32(self._pgetter(ATSPI_HYPERLINK, "EndIndex"))
_endIndexDoc = \
"""
the ending offset within the containing Hypertext content with
@@ -85,7 +85,7 @@ class Hyperlink(Accessible):
endIndex = property(fget=get_endIndex, doc=_endIndexDoc)
def get_nAnchors(self):
- return dbus.Int16(self._pgetter(self._dbus_interface, "NAnchors"))
+ return dbus.Int16(self._pgetter(ATSPI_HYPERLINK, "NAnchors"))
_nAnchorsDoc = \
"""
the number of separate anchors associated with this Hyperlink
@@ -93,7 +93,7 @@ class Hyperlink(Accessible):
nAnchors = property(fget=get_nAnchors, doc=_nAnchorsDoc)
def get_startIndex(self):
- return dbus.Int32(self._pgetter(self._dbus_interface, "StartIndex"))
+ return dbus.Int32(self._pgetter(ATSPI_HYPERLINK, "StartIndex"))
_startIndexDoc = \
"""
the starting offset within the containing Hypertext content with
diff --git a/pyatspi/image.py b/pyatspi/image.py
index a4e417d..d496415 100644
--- a/pyatspi/image.py
+++ b/pyatspi/image.py
@@ -85,7 +85,7 @@ class Image(Accessible):
return func()
def get_imageDescription(self):
- return dbus.String(self._pgetter(self._dbus_interface, "ImageDescription"))
+ return dbus.String(self._pgetter(ATSPI_IMAGE, "ImageDescription"))
_imageDescriptionDoc = \
"""
A UTF-8 string providing a textual description of what is visually
@@ -94,7 +94,7 @@ class Image(Accessible):
imageDescription = property(fget=get_imageDescription, doc=_imageDescriptionDoc)
def get_imageLocale(self):
- return dbus.String(self._pgetter(self._dbus_interface, "ImageLocale"))
+ return dbus.String(self._pgetter(ATSPI_IMAGE, "ImageLocale"))
_imageLocaleDoc = \
"""
A string corresponding to the POSIX LC_MESSAGES locale used by
diff --git a/pyatspi/interfaces.py b/pyatspi/interfaces.py
index c55be51..43859af 100644
--- a/pyatspi/interfaces.py
+++ b/pyatspi/interfaces.py
@@ -26,7 +26,7 @@ ATSPI_IMAGE = 'org.freedesktop.atspi.Image'
ATSPI_LOGIN_HELPER = 'org.freedesktop.atspi.LoginHelper'
ATSPI_SELECTION = 'org.freedesktop.atspi.Selection'
ATSPI_SELECTOR = 'org.freedesktop.atspi.Selector'
-ATSPI_STREAMABLE_CONTENT = 'org.freedesktop.atspi.Content'
+ATSPI_STREAMABLE_CONTENT = 'org.freedesktop.atspi.StreamableContent'
ATSPI_TABLE = 'org.freedesktop.atspi.Table'
ATSPI_TEXT = 'org.freedesktop.atspi.Text'
ATSPI_VALUE = 'org.freedesktop.atspi.Value'
diff --git a/pyatspi/registry.py b/pyatspi/registry.py
index 3d6e99f..e166fb9 100644
--- a/pyatspi/registry.py
+++ b/pyatspi/registry.py
@@ -138,7 +138,8 @@ class Registry(object):
else:
devreg = _DeviceEventRegister()
appreg = _ApplicationEventRegister(factory)
- desktop = factory (_ATSPI_REGISTRY_NAME, _ATSPI_ROOT_PATH, _ATSPI_DESKTOP)
+ name = _bus_object.GetNameOwner (_ATSPI_REGISTRY_NAME)
+ desktop = factory (name, _ATSPI_ROOT_PATH, _ATSPI_DESKTOP)
# Create the registry object
self.has_implementations = True
diff --git a/pyatspi/selection.py b/pyatspi/selection.py
index 832800c..1ec8cac 100644
--- a/pyatspi/selection.py
+++ b/pyatspi/selection.py
@@ -123,7 +123,7 @@ class Selection(Accessible):
return func(index)
def get_nSelectedChildren(self):
- return dbus.Int32(self._pgetter(self._dbus_interface, "NSelectedChildren"))
+ return dbus.Int32(self._pgetter(ATSPI_SELECTION, "NSelectedChildren"))
_nSelectedChildrenDoc = \
"""
The number of children of a Selection implementor which are currently
diff --git a/pyatspi/table.py b/pyatspi/table.py
index eb5aa13..d45e2eb 100644
--- a/pyatspi/table.py
+++ b/pyatspi/table.py
@@ -312,7 +312,7 @@ class Table(Accessible):
return func(row)
def get_caption(self):
- (name, path) = self._pgetter(self._dbus_interface, "Caption")
+ (name, path) = self._pgetter(ATSPI_TABLE, "Caption")
if (name == ""):
name = self._app_name
return self.acc_factory (name, path, ATSPI_ACCESSIBLE)
@@ -323,7 +323,7 @@ class Table(Accessible):
caption = property(fget=get_caption, doc=_captionDoc)
def get_nColumns(self):
- return dbus.Int32(self._pgetter(self._dbus_interface, "NColumns"))
+ return dbus.Int32(self._pgetter(ATSPI_TABLE, "NColumns"))
_nColumnsDoc = \
"""
The total number of columns in this table (including empty columns),
@@ -334,7 +334,7 @@ class Table(Accessible):
nColumns = property(fget=get_nColumns, doc=_nColumnsDoc)
def get_nRows(self):
- return dbus.Int32(self._pgetter(self._dbus_interface, "NRows"))
+ return dbus.Int32(self._pgetter(ATSPI_TABLE, "NRows"))
_nRowsDoc = \
"""
The total number of rows in this table (including empty rows),
@@ -344,7 +344,7 @@ class Table(Accessible):
nRows = property(fget=get_nRows, doc=_nRowsDoc)
def get_nSelectedColumns(self):
- return dbus.Int32(self._pgetter(self._dbus_interface, "NSelectedColumns"))
+ return dbus.Int32(self._pgetter(ATSPI_TABLE, "NSelectedColumns"))
_nSelectedColumnsDoc = \
"""
The number of columns currently selected. A selected column is
@@ -353,7 +353,7 @@ class Table(Accessible):
nSelectedColumns = property(fget=get_nSelectedColumns, doc=_nSelectedColumnsDoc)
def get_nSelectedRows(self):
- return dbus.Int32(self._pgetter(self._dbus_interface, "NSelectedRows"))
+ return dbus.Int32(self._pgetter(ATSPI_TABLE, "NSelectedRows"))
_nSelectedRowsDoc = \
"""
The number of rows currently selected. A selected row is one
@@ -362,7 +362,7 @@ class Table(Accessible):
nSelectedRows = property(fget=get_nSelectedRows, doc=_nSelectedRowsDoc)
def get_summary(self):
- (name, path) = self._pgetter(self._dbus_interface, "Summary")
+ (name, path) = self._pgetter(ATSPI_TABLE, "Summary")
if (name == ""):
name = self._app_name
return self.acc_factory (name, path, ATSPI_ACCESSIBLE)
diff --git a/pyatspi/text.py b/pyatspi/text.py
index 1194440..c798df8 100644
--- a/pyatspi/text.py
+++ b/pyatspi/text.py
@@ -536,7 +536,7 @@ class Text(Accessible):
return func(selectionNum, startOffset, endOffset)
def get_caretOffset(self):
- return Int32(self._pgetter(self.dbus_interface, "CaretOffset"))
+ return Int32(self._pgetter(ATSPI_TEXT, "CaretOffset"))
_caretOffsetDoc = \
"""
The current offset of the text caret in the Text object. This
@@ -549,7 +549,7 @@ class Text(Accessible):
caretOffset = property(fget=get_caretOffset, doc=_caretOffsetDoc)
def get_characterCount(self):
- return Int32(self._pgetter(self.dbus_interface, "CharacterCount"))
+ return Int32(self._pgetter(ATSPI_TEXT, "CharacterCount"))
_characterCountDoc = \
"""
The total current number of characters in the Text object, including
diff --git a/pyatspi/value.py b/pyatspi/value.py
index 34a6928..534d9a2 100644
--- a/pyatspi/value.py
+++ b/pyatspi/value.py
@@ -32,7 +32,7 @@ class Value(Accessible):
"""
def get_currentValue(self):
- return dbus.Double(self._pgetter(self._dbus_interface, "CurrentValue"))
+ return dbus.Double(self._pgetter(ATSPI_VALUE, "CurrentValue"))
def set_currentValue(self, value):
self._psetter(self._dbus_interface, "currentValue", dbus.Double(value, variant_level=1))
_currentValueDoc = \
@@ -42,7 +42,7 @@ class Value(Accessible):
currentValue = property(fget=get_currentValue, fset=set_currentValue, doc=_currentValueDoc)
def get_maximumValue(self):
- return dbus.Double(self._pgetter(self._dbus_interface, "MaximumValue"))
+ return dbus.Double(self._pgetter(ATSPI_VALUE, "MaximumValue"))
_maximumValueDoc = \
"""
The maximum value allowed by this valuator.
@@ -50,7 +50,7 @@ class Value(Accessible):
maximumValue = property(fget=get_maximumValue, doc=_maximumValueDoc)
def get_minimumIncrement(self):
- return dbus.Double(self._pgetter(self._dbus_interface, "MinimumIncrement"))
+ return dbus.Double(self._pgetter(ATSPI_VALUE, "MinimumIncrement"))
_minimumIncrementDoc = \
"""
The smallest incremental change which this valuator allows. If
@@ -60,7 +60,7 @@ class Value(Accessible):
minimumIncrement = property(fget=get_minimumIncrement, doc=_minimumIncrementDoc)
def get_minimumValue(self):
- return dbus.Double(self._pgetter(self._dbus_interface, "MinimumValue"))
+ return dbus.Double(self._pgetter(ATSPI_VALUE, "MinimumValue"))
_minimumValueDoc = \
"""
The minimum value allowed by this valuator.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]