-'''
-Creates functions at import time that are mixed into the
-Accessibility.Accessible base class to make it more Pythonic.
-
-Based on public domain code originally posted at
-U{http://wwwx.cs.unc.edu/~parente/cgi-bin/RuntimeClassMixins}.
-
-@var _ACCESSIBLE_CACHE: Pairs hash values for accessible objects to
- L{_PropertyCache} bags. We do not store actual accessibles in the dictionary
- because that would +1 their ref counts and cause __del__ to never be called
- which is the method we rely on to properly invalidate cache entries.
-@type _ACCESSIBLE_CACHE: dictionary
-@var _CACHE_LEVEL: Current level of caching enabled. Checked dynamically by
- L{_AccessibleMixin}
-@type _CACHE_LEVEL: integer
-
-@author: Peter Parente
-@organization: IBM Corporation
-@copyright: Copyright (c) 2005, 2007 IBM Corporation
-@license: LGPL
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public
-License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-This library 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
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with this library; if not, write to the
-Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
-
-Portions of this code originally licensed and copyright (c) 2005, 2007
-IBM Corporation under the BSD license, available at
-U{http://www.opensource.org/licenses/bsd-license.php}
-'''
-import new
-import types
-import ORBit
-import Accessibility
-import constants
-import utils
-import registry
-
-_ACCESSIBLE_CACHE = {}
-_CACHE_LEVEL = None
-
-class _PropertyCache(object):
- '''Fixed-size bag class for holding cached values.'''
- __slots__ = ('name', 'description', 'rolename')
-
-def getCacheLevel():
- '''
- Gets the current level of caching.
-
- @return: None indicating no caching is in effect.
- L{constants.CACHE_INTERFACES} indicating all interface query results are
- cached. L{constants.CACHE_PROPERTIES} indicating all basic accessible
- properties are cached.
- @rtype: integer
- '''
- return _CACHE_LEVEL
-
-def setCacheLevel(val):
- '''
- Sets the desired level of caching for all accessible objects created after
- this function is invoked. Immediately clears the current accessible cache.
-
- @param val: None indicating no caching is in effect.
- L{constants.CACHE_INTERFACES} indicating all interface query results are
- cached. L{constants.CACHE_PROPERTIES} indicating all basic accessible
- properties are cached plus all interfaces.
- @type val: integer
- '''
- global _CACHE_LEVEL
- if _CACHE_LEVEL != val:
- # empty our accessible cache
- _ACCESSIBLE_CACHE.clear()
- # need to register/unregister for listeners depending on caching level
- if val == constants.CACHE_PROPERTIES:
- r = registry.Registry()
- r.registerEventListener(_updateCache, *constants.CACHE_EVENTS)
- else:
- r = registry.Registry()
- r.deregisterEventListener(_updateCache, *constants.CACHE_EVENTS)
- _CACHE_LEVEL = val
-
-def clearCache():
- '''Forces a clear of the entire cache.'''
- _ACCESSIBLE_CACHE.clear()
-
-def printCache(template='%s'):
- '''
- Prints the contents of the cache.
-
- @param template: Format string to use when printing
- @type template: string
- '''
- print template % _ACCESSIBLE_CACHE
-
-def _updateCache(event):
- '''
- Invalidates an entry in the cache when the hash value of a source of an event
- matches an entry in the cache.
-
- @param event: One of the L{constants.CACHE_EVENTS} event types
- @type event: L{event.Event}
- '''
- try:
- del _ACCESSIBLE_CACHE[hash(event.source)]
- except KeyError:
- return
-
-def _makeQuery(interface):
- '''
- Builds a function querying to a specific interface and returns it.
-
- @param interface: Class representing an AT-SPI interface
- @type interface: class
- @return: Function querying to the given interface
- @rtype: function
- '''
- def _inner(self):
- '''
- Queries an object for another interface.
-
- @return: An object with the desired interface
- @rtype: object
- @raise NotImplementedError: When the desired interface is not supported
- '''
- iid = utils.getInterfaceIID(interface)
- try:
- i = self._icache[iid]
- except KeyError:
- # interface not cached
- caching = True
- except AttributeError:
- # determine if we're caching
- caching = _CACHE_LEVEL is not None
- if caching:
- # initialize the cache
- self._icache = {}
- else:
- # check if our cached result was an interface, or an indicator that the
- # interface is not supported
- if i is None:
- raise NotImplementedError
- else:
- return i
-
- try:
- # do the query remotely
- i = self.queryInterface(iid)
- if i is not None:
- i = i._narrow(interface)
- except Exception, e:
- raise LookupError(e)
- if i is None:
- # cache that the interface is not supported
- if caching:
- self._icache[iid] = None
- raise NotImplementedError
-
- if caching:
- # cache the narrow'ed result, but only if we're caching for this object
- self._icache[iid] = i
- return i
-
- return _inner
-
-def _makeExceptionHandler(func):
- '''
- Builds a function calling the one it wraps in try/except statements catching
- CORBA exceptions.
-
- @return: Function calling the method being wrapped
- @rtype: function
- '''
- def _inner(self, *args, **kwargs):
- try:
- # try calling the original func
- return func(self, *args, **kwargs)
- except ORBit.CORBA.NO_IMPLEMENT, e:
- # raise Python exception
- raise NotImplementedError(e)
- except ORBit.CORBA.Exception, e:
- # raise Python exception
- raise LookupError(e)
- return _inner
-
-def _mixInterfaces(cls, interfaces):
- '''
- Add methods for querying to interfaces other than the base accessible to
- the given class.
-
- @param cls: Class to mix interface methods into
- @type cls: class
- @param interfaces: Classes representing AT-SPI interfaces
- @type interfaces: list of class
- '''
- # create functions in this module for all interfaces listed in constants
- for interface in interfaces:
- # build name of converter from the name of the interface
- name = 'query%s' % utils.getInterfaceName(interface)
- # build a function that queries to the given interface
- func = _makeQuery(interface)
- # build a new method that is a clone of the original function
- method = new.function(func.func_code, func.func_globals, name,
- func.func_defaults, func.func_closure)
- # add the method to the given class
- setattr(cls, name, method)
-
-def _mixExceptions(cls):
- '''
- Wraps all methods and properties in a class with handlers for CORBA
- exceptions.
-
- @param cls: Class to mix interface methods into
- @type cls: class
- '''
- # get a method type as a reference from a known method
- method_type = Accessibility.Accessible.getRole.__class__
- # loop over all names in the new class
- for name in cls.__dict__.keys():
- obj = cls.__dict__[name]
- # check if we're on a protected or private method
- if name.startswith('_'):
- continue
- # check if we're on a method
- elif isinstance(obj, method_type):
- # wrap the function in an exception handler
- method = _makeExceptionHandler(obj)
- # add the wrapped function to the class
- setattr(cls, name, method)
- # check if we're on a property
- elif isinstance(obj, property):
- # wrap the getters and setters
- if obj.fget:
- func = getattr(cls, obj.fget.__name__)
- getter = _makeExceptionHandler(func)
- else:
- getter = None
- if obj.fset:
- func = getattr(cls, obj.fset.__name__)
- setter = _makeExceptionHandler(func)
- else:
- setter = None
- setattr(cls, name, property(getter, setter))
-
-def _mixClass(cls, new_cls, ignore=[]):
- '''
- Adds the methods in new_cls to cls. After mixing, all instances of cls will
- have the new methods. If there is a method name clash, the method already in
- cls will be prefixed with '_mix_' before the new method of the same name is
- mixed in.
-
- @note: _ is not the prefix because if you wind up with __ in front of a
- variable, it becomes private and mangled when an instance is created.
- Difficult to invoke from the mixin class.
-
- @param cls: Existing class to mix features into
- @type cls: class
- @param new_cls: Class containing features to add
- @type new_cls: class
- @param ignore: Ignore these methods from the mixin
- @type ignore: iterable
- '''
- # loop over all names in the new class
- for name, func in new_cls.__dict__.items():
- if name in ignore:
- continue
- if isinstance(func, types.FunctionType):
- # build a new function that is a clone of the one from new_cls
- method = new.function(func.func_code, func.func_globals, name,
- func.func_defaults, func.func_closure)
- try:
- # check if a method of the same name already exists in the target
- old_method = getattr(cls, name)
- except AttributeError:
- pass
- else:
- # rename the old method so we can still call it if need be
- setattr(cls, '_mix_'+name, old_method)
- # add the clone to cls
- setattr(cls, name, method)
- elif isinstance(func, staticmethod):
- try:
- # check if a method of the same name already exists in the target
- old_method = getattr(cls, name)
- except AttributeError:
- pass
- else:
- # rename the old method so we can still call it if need be
- setattr(cls, '_mix_'+name, old_method)
- setattr(cls, name, func)
- elif isinstance(func, property):
- try:
- # check if a method of the same name already exists in the target
- old_prop = getattr(cls, name)
- except AttributeError:
- pass
- else:
- # IMPORTANT: We save the old property before overwriting it, even
- # though we never end up calling the old prop from our mixin class.
- # If we don't save the old one, we seem to introduce a Python ref count
- # problem where the property get/set methods disappear before we can
- # use them at a later time. This is a minor waste of memory because
- # a property is a class object and we only overwrite a few of them.
- setattr(cls, '_mix_'+name, old_prop)
- setattr(cls, name, func)
-
-class _AccessibleMixin(object):
- '''
- Defines methods to be added to the Accessibility.Accessible class. The
- features defined here will be added to the Accessible class at run time so
- that all instances of Accessible have them (i.e. there is no need to
- explicitly wrap an Accessible in this class or derive a new class from it.)
-
- @cvar SLOTTED_CLASSES: Mapping from raw Accessibility class to a new class
- having the slots defined by L{SLOTS}
- @type SLOTTED_CLASSES: dictionary
- @cvar SLOTS: All slots to create
- @type SLOTS: tuple
- '''
- SLOTTED_CLASSES = {}
- SLOTS = ('_icache', 'user_data')
-
- def __new__(cls):
- '''
- Creates a new class mimicking the one requested, but with extra named
- defined in __slots__. The _cache attribute is used internally for interface
- caching. The user_data field may be populated with whatever data structure
- a client wishes to use. Neither is set to a default value by default.
-
- Note that we can't simply mix __slots__ into this class because __slots__
- has an effect only at class creation time.
-
- We also do not completely obliterate __slots__ to allow __dict__ to be
- instantiated as normal as reducing the initialization and memory overhead
- of the millions of accessible objects that are created is a good thing for
- many clients.
-
- @param cls: Accessibility object class
- @type cls: class
- @return: Instance of the new class
- @rtype: object
- '''
- try:
- # check if we've already created a new version of the class
- new_cls = _AccessibleMixin.SLOTTED_CLASSES[cls]
- except KeyError:
- # create the new class if not
- new_cls = type(cls.__name__, (cls,),
- {'__module__' : cls.__module__,
- '__slots__' : _AccessibleMixin.SLOTS})
- _AccessibleMixin.SLOTTED_CLASSES[cls] = new_cls
- obj = cls._mix___new__(new_cls)
- return obj
-
- def __del__(self):
- '''
- Decrements the reference count on the accessible object when there are no
- Python references to this object. This provides automatic reference
- counting for AT-SPI objects. Also removes this object from the cache if
- we're caching properties.
- '''
- try:
- del _ACCESSIBLE_CACHE[hash(self)]
- except Exception:
- pass
- try:
- self.unref()
- except Exception:
- pass
-
- def __iter__(self):
- '''
- Iterator that yields one accessible child per iteration. If an exception is
- encountered, None is yielded instead.
-
- @return: A child accessible
- @rtype: Accessibility.Accessible
- '''
- for i in xrange(self.childCount):
- try:
- yield self.getChildAtIndex(i)
- except LookupError:
- yield None
-
- def __str__(self):
- '''
- Gets a human readable representation of the accessible.
-
- @return: Role and name information for the accessible
- @rtype: string
- '''
- try:
- return '[%s | %s]' % (self.getRoleName(), self.name)
- except Exception:
- return '[DEAD]'
-
- def __nonzero__(self):
- '''
- @return: True, always
- @rtype: boolean
- '''
- return True
-
- def __getitem__(self, index):
- '''
- Thin wrapper around getChildAtIndex.
-
- @param index: Index of desired child
- @type index: integer
- @return: Accessible child
- @rtype: Accessibility.Accessible
- '''
- n = self.childCount
- if index >= n:
- raise IndexError
- elif index < -n:
- raise IndexError
- elif index < 0:
- index += n
- return self.getChildAtIndex(index)
-
- def __len__(self):
- '''
- Thin wrapper around childCount.
-
- @return: Number of child accessibles
- @rtype: integer
- '''
- return self.childCount
-
- def _get_name(self):
- '''
- Gets the name of the accessible from the cache if it is available,
- otherwise, fetches it remotely.
-
- @return: Name of the accessible
- @rtype: string
- '''
- if _CACHE_LEVEL != constants.CACHE_PROPERTIES:
- return self._get_name()
-
- cache = _ACCESSIBLE_CACHE
- h = hash(self)
- try:
- return cache[h].name
- except KeyError:
- # no cached info for this object yet
- name = self._get_name()
- pc = _PropertyCache()
- pc.name = name
- cache[h] = pc
- return name
- except AttributeError:
- # no cached name for this object yet
- name = self._get_name()
- cache[h].name = name
- return name
-
- name = property(_get_name, Accessibility.Accessible._set_name)
-
- def getRoleName(self):
- '''
- Gets the unlocalized role name of the accessible from the cache if it is
- available, otherwise, fetches it remotely.
-
- @return: Role name of the accessible
- @rtype: string
- '''
- if _CACHE_LEVEL != constants.CACHE_PROPERTIES:
- return self._mix_getRoleName()
-
- cache = _ACCESSIBLE_CACHE
- h = hash(self)
- try:
- return cache[h].rolename
- except KeyError, e:
- # no cached info for this object yet
- rolename = self._mix_getRoleName()
- pc = _PropertyCache()
- pc.rolename = rolename
- cache[h] = pc
- return rolename
- except AttributeError, e:
- # no cached name for this object yet
- rolename = self._mix_getRoleName()
- cache[h].rolename = rolename
- return rolename
-
- def _get_description(self):
- '''
- Gets the description of the accessible from the cache if it is available,
- otherwise, fetches it remotely.
-
- @return: Description of the accessible
- @rtype: string
- '''
- if _CACHE_LEVEL != constants.CACHE_PROPERTIES:
- return self._get_description()
-
- cache = _ACCESSIBLE_CACHE
- h = hash(self)
- try:
- return cache[h].description
- except KeyError:
- # no cached info for this object yet
- description = self._get_description()
- pc = _PropertyCache()
- pc.description = description
- cache[h] = pc
- return description
- except AttributeError:
- # no cached name for this object yet
- description = self._get_description()
- cache[h].description = description
- return description
-
- description = property(_get_description,
- Accessibility.Accessible._set_description)
-
- def getIndexInParent(self):
- '''
- Gets the index of this accessible in its parent. Uses the implementation of
- this method provided by the Accessibility.Accessible object, but checks the
- bound of the value to ensure it is not outside the range of childCount
- reported by this accessible's parent.
-
- @return: Index of this accessible in its parent
- @rtype: integer
- '''
- i = self._mix_getIndexInParent()
- try:
- # correct for out-of-bounds index reporting
- return min(self.parent.childCount-1, i)
- except AttributeError:
- # return sentinel if there is no parent
- return -1
-
- def getApplication(self):
- '''
- Gets the most-parent accessible (the application) of this accessible. Tries
- using the getApplication method introduced in AT-SPI 1.7.0 first before
- resorting to traversing parent links.
-
- @warning: Cycles involving more than the previously traversed accessible
- are not detected by this code.
- @return: Application object
- @rtype: Accessibility.Application
- '''
- try:
- return self._mix_getApplication()
- except AttributeError:
- pass
- curr = self
- try:
- while curr.parent is not None and (not curr.parent == curr):
- curr = curr.parent
- return curr
- except Exception:
- pass
- # return None if the application isn't reachable for any reason
- return None
-
-class _RelationMixin(object):
- '''
- Defines methods to be added to the Relation class. At this time it only
- overrides L{_RelationMixin.getTarget} which by the IDL's standard is
- supposed to return CORBA.Objects but we expect LAccessibility.Accessible
- objects (see http://bugzilla.gnome.org/show_bug.cgi?id=435833).
- This seems to be a problem especially with the Java implementation of CORBA.
- '''
- def getTarget(self, index):
- '''
- Overrides the regular getTarget to return Accessibility.Accessible
- objects.
-
- @return: The 'nth' target of this Relation.
- @rtype: Accessibility.Accessible
- '''
- target = self._mix_getTarget(index)
- target.ref()
- return target._narrow(Accessibility.Accessible)
-
-# 1. mix the exception handlers into all queryable interfaces
-map(_mixExceptions, constants.ALL_INTERFACES)
-# 2. mix the exception handlers into other Accessibility objects
-map(_mixExceptions, [Accessibility.StateSet])
-# 3. mix the new functions
-_mixClass(Accessibility.Accessible, _AccessibleMixin,
- ['_get_name', '_get_description'])
-# 4. mix queryInterface convenience methods
-_mixInterfaces(Accessibility.Accessible, constants.ALL_INTERFACES)
-# 5. mix Relation class
-_mixClass(Accessibility.Relation, _RelationMixin)
+#Copyright (C) 2008 Codethink Ltd
+
+#This library is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public
+#License version 2 as published by the Free Software Foundation.
+
+#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 Lesser General Public License
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import interfaces
+from base import BaseProxy
+from factory import create_accessible, add_accessible_class
+from stateset import StateSet, _marshal_state_set
+from relation import _marshal_relation_set
+
+__all__ = [
+ "Accessible",
+ ]
+
+#------------------------------------------------------------------------------
+
+class Accessible(BaseProxy):
+ """
+ The base interface which is implemented by all accessible objects.
+ All objects support interfaces for querying their contained
+ 'children' and position in the accessible-object hierarchy,
+ whether or not they actually have children.
+ """
+
+ def getApplication(self):
+ """
+ Get the containing Application for this object.
+ @return the Application instance to which this object belongs.
+ """
+ application_root = self._cache[self._app_name]._get_root()
+ #TODO Set the desktop object as the parent of this.
+ return create_accessible(self._cache,
+ self._app_name,
+ application_root,
+ interfaces.ATSPI_APPLICATION,
+ connection=self._cache._connection)
+
+ def getAttributes(self):
+ """
+ Get a list of properties applied to this object as a whole, as
+ an AttributeSet consisting of name-value pairs. As such these
+ attributes may be considered weakly-typed properties or annotations,
+ as distinct from the strongly-typed interface instance data declared
+ using the IDL "attribute" keyword.
+ Not all objects have explicit "name-value pair" AttributeSet
+ properties.
+ Attribute names and values may have any UTF-8 string value, however
+ where possible, in order to facilitate consistent use and exposure
+ of "attribute" properties by applications and AT clients, attribute
+ names and values should chosen from a publicly-specified namespace
+ where appropriate.
+ Where possible, the names and values in the name-value pairs
+ should be chosen from well-established attribute namespaces using
+ standard semantics. For example, attributes of Accessible objects
+ corresponding to XHTML content elements should correspond to
+ attribute names and values specified in the w3c XHTML specification,
+ at http://www.w3.org/TR/xhtml2, where such values are not already
+ exposed via a more strongly-typed aspect of the AT-SPI API. Metadata
+ names and values should be chosen from the 'Dublin Core' Metadata
+ namespace using Dublin Core semantics: http://dublincore.org/dcregistry/
+ Similarly, relevant structural metadata should be exposed using
+ attribute names and values chosen from the CSS2 and WICD specification:
+ http://www.w3.org/TR/1998/REC-CSS2-19980512 WICD (http://www.w3.org/TR/2005/WD-WICD-20051121/).
+
+ @return : An AttributeSet encapsulating any "attribute values"
+ currently defined for the object. An attribute set is a list of strings
+ with each string comprising an name-value pair format 'name:value'.
+ """
+ func = self.get_dbus_method("getAttributes")
+ return func()
+
+ def getChildAtIndex(self, index):
+ """
+ Get the accessible child of this object at index.
+ @param : index
+ an in parameter indicating which child is requested (zero-indexed).
+ @return : the 'nth' Accessible child of this object.
+ """
+ path = self.cached_data.children[index]
+ return create_accessible(self._cache,
+ self._app_name,
+ path,
+ interfaces.ATSPI_ACCESSIBLE,
+ connection=self._cache._connection)
+
+ def getIndexInParent(self):
+ """
+ Get the index of this object in its parent's child list.
+ @return : a long integer indicating this object's index in the
+ parent's list.
+ """
+ for i in range(0, self.parent.childCount):
+ child = self.parent.getChildAtIndex(i)
+ if self.isEqual(child):
+ return i
+ raise AccessibleObjectNoLongerExists("Child not found within parent")
+
+ def getLocalizedRoleName(self):
+ """
+ Get a string indicating the type of UI role played by this object,
+ translated to the current locale.
+ @return : a UTF-8 string indicating the type of UI role played
+ by this object.
+ """
+ func = self.get_dbus_method("getLocalizedRoleName")
+ return func()
+
+ def getRelationSet(self):
+ """
+ Get a set defining this object's relationship to other accessible
+ objects.
+ @return : a RelationSet defining this object's relationships.
+ """
+ func = self.get_dbus_method("getRelationSet")
+ relation_set = func()
+ return _marshal_relation_set(self._cache, self._dbus_object, self._app_name, relation_set)
+
+ def getRole(self):
+ """
+ Get the Role indicating the type of UI role played by this object.
+ @return : a Role indicating the type of UI role played by this
+ object.
+ """
+ return self.cached_data.role
+
+ def getRoleName(self):
+ """
+ Get a string indicating the type of UI role played by this object.
+ @return : a UTF-8 string indicating the type of UI role played
+ by this object.
+ """
+ func = self.get_dbus_method("getRoleName")
+ return func()
+
+ def getState(self):
+ """
+ Get the current state of the object as a StateSet.
+ @return : a StateSet encapsulating the currently true states
+ of the object.
+ """
+ func = self.get_dbus_method("getState")
+ bitfield = func()
+ return _marshal_state_set(bitfield)
+
+ def isEqual(self, accessible):
+ """
+ Determine whether an Accessible refers to the same object as
+ another. This method should be used rather than brute-force comparison
+ of object references (i.e. "by-value" comparison), as two object
+ references may have different apparent values yet refer to the
+ same object.
+ @param : obj
+ an Accessible object reference to compare to
+ @return : a boolean indicating whether the two object references
+ point to the same object.
+ """
+ return (self._app_name == accessible._app_name) and \
+ (self._acc_path == accessible._acc_path)
+
+ def get_childCount(self):
+ return len(self.cached_data.children)
+ _childCountDoc = \
+ """
+ childCount: the number of children contained by this object.
+ """
+ childCount = property(fget=get_childCount, doc=_childCountDoc)
+
+ def get_description(self):
+ return self.cached_data.description
+ _descriptionDoc = \
+ """
+ a string describing the object in more detail than name.
+ """
+ description = property(fget=get_description, doc=_descriptionDoc)
+
+ def get_name(self):
+ return self.cached_data.name
+ _nameDoc = \
+ """
+ a (short) string representing the object's name.
+ """
+ name = property(fget=get_name, doc=_nameDoc)
+
+ def get_parent(self):
+ if self._parent:
+ return self._parent
+ else:
+ return create_accessible(self._cache,
+ self._app_name,
+ self.cached_data.parent,
+ interfaces.ATSPI_ACCESSIBLE,
+ connection=self._cache._connection)
+
+ _parentDoc = \
+ """
+ an Accessible object which is this object's containing object.
+ """
+ parent = property(fget=get_parent, doc=_parentDoc)
+
+# Register the Accessible class with the accessible factory.
+add_accessible_class(interfaces.ATSPI_ACCESSIBLE, Accessible)
+
+#END----------------------------------------------------------------------------