OSDN Git Service

Support for Java Access Bridge 2.02 (including for 64 bit JVMs). Hopefully does not...
authorMichael Curran <mick@kulgan.net>
Thu, 4 Aug 2011 05:01:17 +0000 (15:01 +1000)
committerMichael Curran <mick@kulgan.net>
Thu, 4 Aug 2011 05:01:17 +0000 (15:01 +1000)
Specific changes:
* Rather than loading windowsAccessBridge.dll in initialize, load either windowsAccessBridge-32 or windowsAccessBridge at the top of JABHandler, and take note of which one worked (whether we're using legacy or not).
* Rewrite defines of all structs, types and function prototypes using java-specific types (jint, JOBJECT64) and make sure that JOBJECT64 is 64 bit for the new java access bridge and 32 bit for legacy.
* Don't ever handle JOBJECT64 as an int, but instead always an opaque type.

source/JABHandler.py

index eed7079..cf02ced 100644 (file)
@@ -17,7 +17,180 @@ import eventHandler
 import controlTypes\r
 import NVDAObjects.JAB\r
 \r
-bridgeDll=None\r
+#Some utility functions to help with function defines\r
+\r
+def _errcheck(res, func, args):\r
+       if not res:\r
+               raise RuntimeError("Result %s" % res)\r
+       return res\r
+\r
+def _fixBridgeFunc(restype,name,*argtypes,**kwargs):\r
+       func=getattr(bridgeDll,name)\r
+       func.restype=restype\r
+       func.argtypes=argtypes\r
+       if kwargs.get('errcheck'):\r
+               func.errcheck=_errcheck\r
+\r
+#Load the first available access bridge dll\r
+legacyAccessBridge=True\r
+try:\r
+       bridgeDll=getattr(cdll,'windowsAccessBridge-32')\r
+       legacyAccessBridge=False\r
+except WindowsError:\r
+       try:\r
+               bridgeDll=cdll.windowsAccessBridge\r
+       except WindowsError:\r
+               bridgeDll=None\r
+\r
+#Definitions of access bridge types, structs and prototypes\r
+\r
+jint=c_int\r
+jfloat=c_float\r
+class JOBJECT64(c_int if legacyAccessBridge else c_int64):\r
+       pass\r
+\r
+MAX_STRING_SIZE=1024\r
+SHORT_STRING_SIZE=256\r
+\r
+class AccessBridgeVersionInfo(Structure):\r
+       _fields_=[\r
+               ('VMVersion',WCHAR*SHORT_STRING_SIZE),\r
+               ('bridgeJavaClassVersion',WCHAR*SHORT_STRING_SIZE),\r
+               ('bridgeJavaDLLVersion',WCHAR*SHORT_STRING_SIZE),\r
+               ('bridgeWinDLLVersion',WCHAR*SHORT_STRING_SIZE),\r
+       ]\r
+\r
+class AccessibleContextInfo(Structure):\r
+       _fields_=[\r
+               ('name',WCHAR*MAX_STRING_SIZE),\r
+               ('description',WCHAR*MAX_STRING_SIZE),\r
+               ('role',WCHAR*SHORT_STRING_SIZE),\r
+               ('role_en_US',WCHAR*SHORT_STRING_SIZE),\r
+               ('states',WCHAR*SHORT_STRING_SIZE),\r
+               ('states_en_US',WCHAR*SHORT_STRING_SIZE),\r
+               ('indexInParent',jint),\r
+               ('childrenCount',jint),\r
+               ('x',jint),\r
+               ('y',jint),\r
+               ('width',jint),\r
+               ('height',jint),\r
+               ('accessibleComponent',BOOL),\r
+               ('accessibleAction',BOOL),\r
+               ('accessibleSelection',BOOL),\r
+               ('accessibleText',BOOL),\r
+               ('accessibleValue',BOOL),\r
+       ]\r
+\r
+class AccessibleTextInfo(Structure):\r
+       _fields_=[\r
+               ('charCount',jint),\r
+               ('caretIndex',jint),\r
+               ('indexAtPoint',jint),\r
+       ]\r
+\r
+class AccessibleTextItemsInfo(Structure):\r
+       _fields_=[\r
+               ('letter',WCHAR),\r
+               ('word',WCHAR*SHORT_STRING_SIZE),\r
+               ('sentence',WCHAR*MAX_STRING_SIZE),\r
+       ]\r
+\r
+class AccessibleTextSelectionInfo(Structure):\r
+       _fields_=[\r
+               ('selectionStartIndex',jint),\r
+               ('selectionEndIndex',jint),\r
+               ('selectedText',WCHAR*MAX_STRING_SIZE),\r
+       ]\r
+\r
+class AccessibleTextRectInfo(Structure):\r
+       _fields_=[\r
+               ('x',jint),\r
+               ('y',jint),\r
+               ('width',jint),\r
+               ('height',jint),\r
+       ]\r
+\r
+class AccessibleTextAttributesInfo(Structure):\r
+       _fields_=[\r
+               ('bold',BOOL),\r
+               ('italic',BOOL),\r
+               ('underline',BOOL),\r
+               ('strikethrough',BOOL),\r
+               ('superscript',BOOL),\r
+               ('subscript',BOOL),\r
+               ('backgroundColor',WCHAR*SHORT_STRING_SIZE),\r
+               ('foregroundColor',WCHAR*SHORT_STRING_SIZE),\r
+               ('fontFamily',WCHAR*SHORT_STRING_SIZE),\r
+               ('fontSize',jint),\r
+               ('alignment',jint),\r
+               ('bidiLevel',jint),\r
+               ('firstLineIndent',jfloat),\r
+               ('LeftIndent',jfloat),\r
+               ('rightIndent',jfloat),\r
+               ('lineSpacing',jfloat),\r
+               ('spaceAbove',jfloat),\r
+               ('spaceBelow',jfloat),\r
+               ('fullAttributesString',WCHAR*MAX_STRING_SIZE),\r
+       ]\r
+\r
+MAX_RELATION_TARGETS = 25\r
+MAX_RELATIONS = 5\r
+\r
+class AccessibleRelationInfo(Structure):\r
+       _fields_ = [\r
+               ("key", WCHAR * SHORT_STRING_SIZE),\r
+               ("targetCount", jint),\r
+               ("targets", JOBJECT64 * MAX_RELATION_TARGETS),\r
+       ]\r
+\r
+class AccessibleRelationSetInfo(Structure):\r
+       _fields_ = [\r
+               ("relationCount", jint),\r
+               ("relations", AccessibleRelationInfo * MAX_RELATIONS),\r
+       ]\r
+\r
+AccessBridge_FocusGainedFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64)\r
+AccessBridge_PropertyStateChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,c_wchar_p,c_wchar_p)\r
+AccessBridge_PropertyCaretChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,c_int,c_int)\r
+AccessBridge_PropertyActiveDescendentChangeFP=CFUNCTYPE(None,c_long,JOBJECT64,JOBJECT64,JOBJECT64,JOBJECT64)\r
+\r
+#Appropriately set the return and argument types of all the access bridge dll functions\r
+if bridgeDll:\r
+       _fixBridgeFunc(None,'Windows_run')\r
+       _fixBridgeFunc(None,'setFocusGainedFP',c_void_p)\r
+       _fixBridgeFunc(None,'setPropertyStateChangeFP',c_void_p)\r
+       _fixBridgeFunc(None,'setPropertyCaretChangeFP',c_void_p)\r
+       _fixBridgeFunc(None,'setPropertyActiveDescendentChangeFP',c_void_p)\r
+       _fixBridgeFunc(None,'releaseJavaObject',c_long,JOBJECT64)\r
+       _fixBridgeFunc(BOOL,'getVersionInfo',POINTER(AccessBridgeVersionInfo),errcheck=True)\r
+       _fixBridgeFunc(BOOL,'isJavaWindow',HWND)\r
+       _fixBridgeFunc(BOOL,'isSameObject',c_long,JOBJECT64,JOBJECT64)\r
+       _fixBridgeFunc(BOOL,'getAccessibleContextFromHWND',HWND,POINTER(c_long),POINTER(JOBJECT64),errcheck=True)\r
+       _fixBridgeFunc(HWND,'getHWNDFromAccessibleContext',c_long,JOBJECT64,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleContextAt',c_long,JOBJECT64,jint,jint,POINTER(JOBJECT64),errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleContextWithFocus',HWND,POINTER(c_long),POINTER(JOBJECT64),errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleContextInfo',c_long,JOBJECT64,POINTER(AccessibleContextInfo),errcheck=True)\r
+       _fixBridgeFunc(JOBJECT64,'getAccessibleChildFromContext',c_long,JOBJECT64,jint,errcheck=True)\r
+       _fixBridgeFunc(JOBJECT64,'getAccessibleParentFromContext',c_long,JOBJECT64)\r
+       _fixBridgeFunc(BOOL,'getAccessibleRelationSet',c_long,JOBJECT64,POINTER(AccessibleRelationSetInfo),errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleTextInfo',c_long,JOBJECT64,POINTER(AccessibleTextInfo),jint,jint,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleTextItems',c_long,JOBJECT64,POINTER(AccessibleTextItemsInfo),jint,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleTextSelectionInfo',c_long,JOBJECT64,POINTER(AccessibleTextSelectionInfo),errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleTextAttributes',c_long,JOBJECT64,jint,POINTER(AccessibleTextAttributesInfo),errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleTextLineBounds',c_long,JOBJECT64,jint,POINTER(jint),POINTER(jint),errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getAccessibleTextRange',c_long,JOBJECT64,jint,jint,POINTER(c_wchar),c_short,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getCurrentAccessibleValueFromContext',c_long,JOBJECT64,POINTER(c_wchar),c_short,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'selectTextRange',c_long,JOBJECT64,c_int,c_int,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getTextAttributesInRange',c_long,JOBJECT64,c_int,c_int,POINTER(AccessibleTextAttributesInfo),POINTER(c_short),errcheck=True)\r
+       _fixBridgeFunc(JOBJECT64,'getTopLevelObject',c_long,JOBJECT64,errcheck=True)\r
+       _fixBridgeFunc(c_int,'getObjectDepth',c_long,JOBJECT64)\r
+       _fixBridgeFunc(JOBJECT64,'getActiveDescendent',c_long,JOBJECT64)\r
+       _fixBridgeFunc(BOOL,'requestFocus',c_long,JOBJECT64,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'setCaretPosition',c_long,JOBJECT64,c_int,errcheck=True)\r
+       _fixBridgeFunc(BOOL,'getCaretLocation',c_long,JOBJECT64,POINTER(AccessibleTextRectInfo),jint,errcheck=True)\r
+\r
+#NVDA specific code\r
+\r
 isRunning=False\r
 vmIDsToWindowHandles={}\r
 internalFunctionQueue=Queue.Queue(1000)\r
@@ -26,18 +199,14 @@ internalFunctionQueue.__name__="JABHandler.internalFunctionQueue"
 def internalQueueFunction(func,*args,**kwargs):\r
        internalFunctionQueue.put_nowait((func,args,kwargs))\r
 \r
-MAX_STRING_SIZE=1024\r
-SHORT_STRING_SIZE=256\r
-\r
 class JABContext(object):\r
 \r
        def __init__(self,hwnd=None,vmID=None,accContext=None):\r
                if hwnd and not vmID:\r
                        vmID=c_int()\r
-                       accContext=c_int()\r
+                       accContext=JOBJECT64()\r
                        bridgeDll.getAccessibleContextFromHWND(hwnd,byref(vmID),byref(accContext))\r
                        vmID=vmID.value\r
-                       accContext=accContext.value\r
                        #Record  this vm ID and window handle for later use with other objects\r
                        vmIDsToWindowHandles[vmID]=hwnd\r
                elif vmID and not hwnd:\r
@@ -169,9 +338,8 @@ class JABContext(object):
                        return None\r
 \r
        def getAccessibleContextAt(self,x,y):\r
-               newAccContext=c_int()\r
+               newAccContext=JOBJECT64()\r
                res=bridgeDll.getAccessibleContextAt(self.vmID,self.accContext,x,y,byref(newAccContext))\r
-               newAccContext=newAccContext.value\r
                if not res or not newAccContext:\r
                        return None\r
                if not bridgeDll.isSameObject(self.vmID,newAccContext,self.accContext):\r
@@ -202,104 +370,7 @@ class JABContext(object):
                bridgeDll.getAccessibleRelationSet(self.vmID, self.accContext, byref(relations))\r
                return relations\r
 \r
-class AccessBridgeVersionInfo(Structure):\r
-       _fields_=[\r
-               ('VMVersion',WCHAR*SHORT_STRING_SIZE),\r
-               ('bridgeJavaClassVersion',WCHAR*SHORT_STRING_SIZE),\r
-               ('bridgeJavaDLLVersion',WCHAR*SHORT_STRING_SIZE),\r
-               ('bridgeWinDLLVersion',WCHAR*SHORT_STRING_SIZE),\r
-       ]\r
-\r
-class AccessibleContextInfo(Structure):\r
-       _fields_=[\r
-               ('name',WCHAR*MAX_STRING_SIZE),\r
-               ('description',WCHAR*MAX_STRING_SIZE),\r
-               ('role',WCHAR*SHORT_STRING_SIZE),\r
-               ('role_en_US',WCHAR*SHORT_STRING_SIZE),\r
-               ('states',WCHAR*SHORT_STRING_SIZE),\r
-               ('states_en_US',WCHAR*SHORT_STRING_SIZE),\r
-               ('indexInParent',c_int),\r
-               ('childrenCount',c_int),\r
-               ('x',c_int),\r
-               ('y',c_int),\r
-               ('width',c_int),\r
-               ('height',c_int),\r
-               ('accessibleComponent',BOOL),\r
-               ('accessibleAction',BOOL),\r
-               ('accessibleSelection',BOOL),\r
-               ('accessibleText',BOOL),\r
-               ('accessibleValue',BOOL),\r
-       ]\r
-\r
-class AccessibleTextInfo(Structure):\r
-       _fields_=[\r
-               ('charCount',c_int),\r
-               ('caretIndex',c_int),\r
-               ('indexAtPoint',c_int),\r
-       ]\r
-\r
-class AccessibleTextItemsInfo(Structure):\r
-       _fields_=[\r
-               ('letter',WCHAR),\r
-               ('word',WCHAR*SHORT_STRING_SIZE),\r
-               ('sentence',WCHAR*MAX_STRING_SIZE),\r
-       ]\r
-\r
-class AccessibleTextSelectionInfo(Structure):\r
-       _fields_=[\r
-               ('selectionStartIndex',c_int),\r
-               ('selectionEndIndex',c_int),\r
-               ('selectedText',WCHAR*MAX_STRING_SIZE),\r
-       ]\r
-\r
-class AccessibleTextRectInfo(Structure):\r
-       _fields_=[\r
-               ('x',c_int),\r
-               ('y',c_int),\r
-               ('width',c_int),\r
-               ('height',c_int),\r
-       ]\r
-\r
-class AccessibleTextAttributesInfo(Structure):\r
-       _fields_=[\r
-               ('bold',BOOL),\r
-               ('italic',BOOL),\r
-               ('underline',BOOL),\r
-               ('strikethrough',BOOL),\r
-               ('superscript',BOOL),\r
-               ('subscript',BOOL),\r
-               ('backgroundColor',WCHAR*SHORT_STRING_SIZE),\r
-               ('foregroundColor',WCHAR*SHORT_STRING_SIZE),\r
-               ('fontFamily',WCHAR*SHORT_STRING_SIZE),\r
-               ('fontSize',c_int),\r
-               ('alignment',c_int),\r
-               ('bidiLevel',c_int),\r
-               ('firstLineIndent',c_float),\r
-               ('LeftIndent',c_float),\r
-               ('rightIndent',c_float),\r
-               ('lineSpacing',c_float),\r
-               ('spaceAbove',c_float),\r
-               ('spaceBelow',c_float),\r
-               ('fullAttributesString',WCHAR*MAX_STRING_SIZE),\r
-       ]\r
-\r
-MAX_RELATION_TARGETS = 25\r
-MAX_RELATIONS = 5\r
-\r
-class AccessibleRelationInfo(Structure):\r
-       _fields_ = [\r
-               ("key", WCHAR * SHORT_STRING_SIZE),\r
-               ("targetCount", c_int),\r
-               ("targets", c_int * MAX_RELATION_TARGETS),\r
-       ]\r
-\r
-class AccessibleRelationSetInfo(Structure):\r
-       _fields_ = [\r
-               ("relationCount", c_int),\r
-               ("relations", AccessibleRelationInfo * MAX_RELATIONS),\r
-       ]\r
-\r
-@CFUNCTYPE(None,c_int,c_int,c_int)\r
+@AccessBridge_FocusGainedFP\r
 def internal_event_focusGained(vmID, event,source):\r
        internalQueueFunction(event_gainFocus,vmID,source)\r
        bridgeDll.releaseJavaObject(vmID,event)\r
@@ -331,13 +402,13 @@ def event_gainFocus(vmID,accContext):
                return\r
        eventHandler.queueEvent("gainFocus",obj)\r
 \r
-@CFUNCTYPE(None,c_int,c_int,c_int,c_int,c_int)\r
+@AccessBridge_PropertyActiveDescendentChangeFP\r
 def internal_event_activeDescendantChange(vmID, event,source,oldDescendant,newDescendant):\r
        internalQueueFunction(event_gainFocus,vmID,newDescendant)\r
        for accContext in [event,oldDescendant]:\r
                bridgeDll.releaseJavaObject(vmID,accContext)\r
 \r
-@CFUNCTYPE(None,c_int,c_int,c_int,c_wchar_p,c_wchar_p)\r
+@AccessBridge_PropertyStateChangeFP\r
 def internal_event_stateChange(vmID,event,source,oldState,newState):\r
        internalQueueFunction(event_stateChange,vmID,source,oldState,newState)\r
        bridgeDll.releaseJavaObject(vmID,event)\r
@@ -362,7 +433,7 @@ def event_stateChange(vmID,accContext,oldState,newState):
                        return\r
        eventHandler.queueEvent("stateChange",obj)\r
 \r
-@CFUNCTYPE(None,c_int,c_int,c_int,c_int,c_int)\r
+@AccessBridge_PropertyCaretChangeFP\r
 def internal_event_caretChange(vmID, event,source,oldPos,newPos):\r
        if oldPos<0 and newPos>=0:\r
                internalQueueFunction(event_gainFocus,vmID,source)\r
@@ -370,57 +441,42 @@ def internal_event_caretChange(vmID, event,source,oldPos,newPos):
 \r
 def event_enterJavaWindow(hwnd):\r
        vmID=c_int()\r
-       accContext=c_int()\r
+       accContext=JOBJECT64()\r
        try:\r
                bridgeDll.getAccessibleContextFromHWND(hwnd,byref(vmID),byref(accContext))\r
        except:\r
                return\r
-       vmIDsToWindowHandles[vmID.value]=hwnd\r
+       vmID=vmID.value\r
+       vmIDsToWindowHandles[vmID]=hwnd\r
        lastFocus=eventHandler.lastQueuedFocusObject\r
        if isinstance(lastFocus,NVDAObjects.JAB.JAB) and lastFocus.windowHandle==hwnd:\r
                return\r
-       internalQueueFunction(event_gainFocus,vmID.value,accContext.value)\r
+       internalQueueFunction(event_gainFocus,vmID,accContext)\r
 \r
 def isJavaWindow(hwnd):\r
-       if not isRunning:\r
+       if not bridgeDll or not isRunning:\r
                return False\r
        return bridgeDll.isJavaWindow(hwnd)\r
 \r
-def _errcheck(res, func, args):\r
-       if not res:\r
-               raise RuntimeError("Result %d" % res)\r
-\r
 def initialize():\r
-       global bridgeDll, isRunning\r
-       try:\r
-               bridgeDll=cdll.WINDOWSACCESSBRIDGE\r
-               for func in (\r
-                       bridgeDll.Windows_run, bridgeDll.getAccessibleContextFromHWND, bridgeDll.getVersionInfo, \r
-                       bridgeDll.getAccessibleContextInfo, bridgeDll.getAccessibleTextInfo, bridgeDll.getAccessibleTextItems,\r
-                       bridgeDll.getAccessibleTextSelectionInfo, bridgeDll.getAccessibleTextRange, bridgeDll.getAccessibleTextLineBounds,\r
-                       bridgeDll.getCurrentAccessibleValueFromContext, bridgeDll.selectTextRange, bridgeDll.setCaretPosition,\r
-                       bridgeDll.getAccessibleContextWithFocus, \r
-               ):\r
-                       func.errcheck = _errcheck\r
-               bridgeDll.Windows_run()\r
-               #Accept wm_copydata and any wm_user messages from other processes even if running with higher privilages\r
-               ChangeWindowMessageFilter=getattr(windll.user32,'ChangeWindowMessageFilter',None)\r
-               if ChangeWindowMessageFilter:\r
-                       if not ChangeWindowMessageFilter(winUser.WM_COPYDATA,1):\r
+       global isRunning\r
+       if not bridgeDll:\r
+               raise NotImplementedError("dll not available")\r
+       bridgeDll.Windows_run()\r
+       #Accept wm_copydata and any wm_user messages from other processes even if running with higher privilages\r
+       ChangeWindowMessageFilter=getattr(windll.user32,'ChangeWindowMessageFilter',None)\r
+       if ChangeWindowMessageFilter:\r
+               if not ChangeWindowMessageFilter(winUser.WM_COPYDATA,1):\r
+                       raise WinError()\r
+               for msg in xrange(winUser.WM_USER+1,65535):\r
+                       if not ChangeWindowMessageFilter(msg,1):\r
                                raise WinError()\r
-                       for msg in xrange(winUser.WM_USER+1,65535):\r
-                               if not ChangeWindowMessageFilter(msg,1):\r
-                                       raise WinError()\r
-               #Register java events\r
-               bridgeDll.setFocusGainedFP(internal_event_focusGained)\r
-               bridgeDll.setPropertyActiveDescendentChangeFP(internal_event_activeDescendantChange)\r
-               bridgeDll.setPropertyStateChangeFP(internal_event_stateChange)\r
-               bridgeDll.setPropertyCaretChangeFP(internal_event_caretChange)\r
-               isRunning=True\r
-               return True\r
-       except:\r
-               log.debugWarning("Error initializing java access bridge",exc_info=True)\r
-               return False\r
+       #Register java events\r
+       bridgeDll.setFocusGainedFP(internal_event_focusGained)\r
+       bridgeDll.setPropertyActiveDescendentChangeFP(internal_event_activeDescendantChange)\r
+       bridgeDll.setPropertyStateChangeFP(internal_event_stateChange)\r
+       bridgeDll.setPropertyCaretChangeFP(internal_event_caretChange)\r
+       isRunning=True\r
 \r
 def pumpAll():\r
        if isRunning: \r
@@ -428,12 +484,17 @@ def pumpAll():
 \r
 def terminate():\r
        global isRunning, bridgeDll\r
-       if not isRunning:\r
+       if not bridgeDll or not isRunning:\r
                return\r
        bridgeDll.setFocusGainedFP(None)\r
        bridgeDll.setPropertyActiveDescendentChangeFP(None)\r
        bridgeDll.setPropertyStateChangeFP(None)\r
        bridgeDll.setPropertyCaretChangeFP(None)\r
-       windll.kernel32.FreeLibrary(bridgeDll._handle)\r
-       cdll.WINDOWSACCESSBRIDGE=bridgeDll=None\r
+       h=bridgeDll._handle\r
+       bridgeDll=None\r
+       if legacyAccessBridge:\r
+               del cdll.windowsAccessBridge \r
+       else:\r
+               delattr(cdll,'windowsAccessBridge-32')\r
+       windll.kernel32.FreeLibrary(h)\r
        isRunning=False\r