A package to handle the mouse in a cross-platform way. What: VirtualMouse 1.0 Where: here, alas Description: A simple package to interface with the mouse on the user platform's terms. Released: 02 May 2007 License: MIT-style If you find this useful, have questions or other commentary, bug fixes, etc. please post here. 02-05-2007 [Duoas] 05-10-2008 Alas, I no longer have online storage at the moment, so I'll post the entire package here. (It is pretty small.) ''[Lars H]: Have you considered using the [Half Bakery] for storage? It should be able to host the HTML without a wrapper.'' ====== # virtualmouse.tcl # # Provide cross-platform virtual mouse event handling. # Copyright 2006 Michael Thomas Greer # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # Except as contained in this notice, the name of the above copyright # holder shall not be used in advertising or otherwise to promote the sale, # use or other dealings in this Software without prior written authorization. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # package require Tk 8.0 #----------------------------------------------------------------------------- namespace eval ::virtualmouse:: { #----------------------------------------------------------------------------- namespace export setVirtualMouseEvents variable MouseButton 0 variable MouseLocked false ;# Prevent middle press after left or right has already triggered variable AfterInfoID 0 variable Timeout array set Timeout {macintosh 375 windows 150} package provide virtualmouse 1.0 } #----------------------------------------------------------------------------- # setVirtualMouseEvents #----------------------------------------------------------------------------- proc ::virtualmouse::setVirtualMouseEvents { {mode abstract} {platform default} } { # Remove all old event bindings ............................................ foreach vevent { <> <> <> <> <> <> <> <> <> } { event delete $vevent } foreach event { } { bind all $event {} } # Argument defaults ........................................................ if {$platform eq {default}} {set platform $::tcl_platform(platform)} if {[lsearch {direct abstract} $mode] < 0} { return -code error {Invalid mode. Must be one of: direct abstract} } if {[lsearch {macintosh unix windows} $platform] < 0} { return -code error {Invalid platform. Must be one of: macintosh unix windows} } # Bindings ................................................................. eval Set[string totitle $mode][string totitle $platform]MouseEvents } #----------------------------------------------------------------------------- proc ::virtualmouse::SetDirectMacintoshMouseEvents {} { #----------------------------------------------------------------------------- bind all {::virtualmouse::ButtonPress 1 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonPress 2 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonPress 3 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::Motion %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonRelease %W %X %Y %x %y %s %E %t} event add <> event add <> event add <> event add <> event add <> event add <> } #----------------------------------------------------------------------------- proc ::virtualmouse::SetDirectUnixMouseEvents {} { #----------------------------------------------------------------------------- event add <> event add <> event add <> event add <> event add <> event add <> event add <> event add <> event add <> } #----------------------------------------------------------------------------- proc ::virtualmouse::SetDirectWindowsMouseEvents {} { #----------------------------------------------------------------------------- bind all {::virtualmouse::ButtonPressTimer 1 %W %X %Y %x %y %s %E %t windows} bind all {::virtualmouse::ButtonPressTimer 3 %W %X %Y %x %y %s %E %t windows} bind all {::virtualmouse::ButtonPress 2 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonPress 2 %W %X %Y %x %y %s %E %t} bind all { ::virtualmouse::ButtonPressTimeout %W %X %Y %x %y %s %E %t ::virtualmouse::Motion %W %X %Y %x %y %s %E %t } bind all { ::virtualmouse::ButtonPressTimeout %W %X %Y %x %y %s %E %t ::virtualmouse::Motion %W %X %Y %x %y %s %E %t } bind all { ::virtualmouse::ButtonPressTimeout %W %X %Y %x %y %s %E %t ::virtualmouse::ButtonRelease %W %X %Y %x %y %s %E %t } bind all { ::virtualmouse::ButtonPressTimeout %W %X %Y %x %y %s %E %t ::virtualmouse::ButtonRelease %W %X %Y %x %y %s %E %t } bind all {::virtualmouse::ButtonPress 2 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::Motion %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonRelease %W %X %Y %x %y %s %E %t ::virtualmouse::setVirtualMouseEvents direct unix } } #----------------------------------------------------------------------------- proc ::virtualmouse::SetAbstractMacintoshMouseEvents {} { #----------------------------------------------------------------------------- bind all {::virtualmouse::ButtonPressTimer 3 %W %X %Y %x %y %s %E %t macintosh} bind all {::virtualmouse::ButtonPress 2 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonPress 3 %W %X %Y %x %y %s %E %t} bind all { ::virtualmouse::ButtonPressChoose 1 3 %W %X %Y %x %y %s %E %t ::virtualmouse::Motion %W %X %Y %x %y %s %E %t } bind all { ::virtualmouse::ButtonPressChoose 1 3 %W %X %Y %x %y %s %E %t ::virtualmouse::ButtonRelease %W %X %Y %x %y %s %E %t } bind all {::virtualmouse::ButtonPress 2 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonPress 3 %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::Motion %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::Motion %W %X %Y %x %y %s %E %t} bind all {::virtualmouse::ButtonRelease %W %X %Y %x %y %s %E %t ::virtualmouse::setVirtualMouseEvents direct macintosh} bind all [bind all ] } #----------------------------------------------------------------------------- proc ::virtualmouse::SetAbstractUnixMouseEvents {} { #----------------------------------------------------------------------------- SetDirectUnixMouseEvents } #----------------------------------------------------------------------------- proc ::virtualmouse::SetAbstractWindowsMouseEvents {} { #----------------------------------------------------------------------------- SetDirectWindowsMouseEvents } #----------------------------------------------------------------------------- proc ::virtualmouse::ButtonPress {btn win rootx rooty x y state event time} { #----------------------------------------------------------------------------- if {$::virtualmouse::MouseLocked} return set ::virtualmouse::MouseButton $btn set ::virtualmouse::MouseLocked true if {$::virtualmouse::AfterInfoID != 0} { after cancel $::virtualmouse::AfterInfoID set ::virtualmouse::AfterInfoID 0 } event generate $win [lindex {err <> <> <> } $btn] \ -rootx $rootx -rooty $rooty -x $x -y $y -state $state -sendevent $event -time $time return } #----------------------------------------------------------------------------- proc ::virtualmouse::ButtonPressTimer {btn win rootx rooty x y state event time platform} { #----------------------------------------------------------------------------- set ::virtualmouse::MouseButton $btn set ::virtualmouse::AfterInfoID \ [after $::virtualmouse::Timeout($platform) " ::virtualmouse::ButtonPress $btn $win $rootx $rooty $x $y $state $event $time set ::virtualmouse::AfterInfoID 0"] return } #----------------------------------------------------------------------------- proc ::virtualmouse::ButtonPressTimeout {win rootx rooty x y state event time} { #----------------------------------------------------------------------------- if {$::virtualmouse::MouseButton == 0} return ButtonPress $::virtualmouse::MouseButton $win $rootx $rooty $x $y $state $event $time } #----------------------------------------------------------------------------- proc ::virtualmouse::ButtonPressChoose {btn0 btn1 win rootx rooty x y state event time} { #----------------------------------------------------------------------------- if {!$::virtualmouse::MouseLocked} { if {$::virtualmouse::MouseButton == $btn1} { set ::virtualmouse::MouseButton $btn0 } } ButtonPressTimeout $win $rootx $rooty $x $y $state $event $time } #----------------------------------------------------------------------------- proc ::virtualmouse::Motion {win rootx rooty x y state event time} { #----------------------------------------------------------------------------- if {$::virtualmouse::MouseButton == 0} return event generate $win [lindex {err <> <> <> } $::virtualmouse::MouseButton] \ -rootx $rootx -rooty $rooty -x $x -y $y -state $state -sendevent $event -time $time return } #----------------------------------------------------------------------------- proc ::virtualmouse::ButtonRelease {win rootx rooty x y state event time} { #----------------------------------------------------------------------------- if {$::virtualmouse::MouseButton == 0} return event generate $win [lindex {err <> <> <> } $::virtualmouse::MouseButton] \ -rootx $rootx -rooty $rooty -x $x -y $y -state $state -sendevent $event -time $time set ::virtualmouse::MouseButton 0 set ::virtualmouse::MouseLocked false return } ::virtualmouse::setVirtualMouseEvents # end virtualmouse.tcl ====== The pkgIndex.tcl file: ====== package ifneeded virtualmouse 1.0 [list source [file join $dir virtualmouse.tcl]] ====== A simple test program ====== console show source virtualmouse.tcl proc mac {{e abstract}} {::virtualmouse::setVirtualMouseEvents $e macintosh} proc unix {{e abstract}} {::virtualmouse::setVirtualMouseEvents $e unix} proc win {{e abstract}} {::virtualmouse::setVirtualMouseEvents $e windows} bind . <> {puts {press left}} bind . <> {puts {press middle}} bind . <> {puts {press right}} bind . <> {puts -nonewline l} bind . <> {puts -nonewline m} bind . <> {puts -nonewline r} bind . <> {puts {release left}} bind . <> {puts {release middle}} bind . <> {puts {release right}} puts {Type one of} puts { unix win mac} puts {optionally followed by 'direct' or 'abstract'.} puts {Then play with the mouse in the window to see the events working.} ====== And finally, the HTML documentation. It isn't much, but due to size I have zipped it then MIME-encodeded using the usual base64 algorithm [http://www.fourmilab.ch/webtools/base64/]. Decode it with your favorite base64 decoder (or use one online [http://gtools.org/tool/base64-encode-decode/]), then unzip it. (Sorry for this. Until I get back some online storage it will have to do.) ====== UEsDBBQAAAAIACmtojbNh9mjqBUAAHlYAAARAHwAdmlydHVhbG1vdXNlLmh0bWxTRGcAvAAA AAAIAMSkiC5jZGBpEWFgYDBggAAfIGZkBTNZRYFEY/nNkt09xnHO4lxGb5lxyzEyMTAwMRQw sIBkBSQY/jPKM4DEQGoVgIQCiC0gAhFnhIgLgdWqQMTw2AkybyWDEIp5ikA2AFVUDQAHvT05 RuzJwkgMZ29I5Vxbcxs3ln5PVf4DwtRk7S1eJDu3lWWlFFmJVWVZLktJJo9gN0hi1N3gNtCi OFPz3/c7B0BfSEqibNna7DLjEdlEH5z7Dae5/9Wrs6OLP98di9cXp2/Eu99+fnNyJHqD0eiP 50ej0auLV/6Lb4c74qKUhdVOm0Jmo9Hx296XXwjRmzk33xuNFovFcPF8aMrp6OL96P3x0WDm 8uzbnVFmjFXD1KW9gy+/+PKLfbqMd/tfDQbiSpeuklluKqtELgu8F3M5VQQYryMzX5Z6OnPi SfJUPNvZ+V6c6mQmVSYuZiaXVvxaKlWG1YdZJni1FaWyqrxS6TB8NRj4vWnP0UO8PMT9mZLp wcPDJaz3c+WkIOYO1H9X+upl78gUThVucLGcq55I/KeXPaeu3YiY+kKANaVV7uXJ+dngxx+/ +6/Bbi9Cc9pl6qDD77lMLsFrkZqkygFKkmT3R35lg0Ihc/WylyqblHpOS1p73w2vtwYpiULt QTA1pC1FvQ5OVm5myh6LuQF30718t3XLTAkHNgbuJdYGwBCkV5mxSZfiX0F9oJrlVBd7ovV6 9t38WuzMr1/ENXOZprqYthe1v6aNBjLT0wZMAlRVWa8Yg3/T0lRFOkhMZkqs+/rVLv1XL/m3 f/N1oLNBcKFTN+vgJ3747rvW9hsoAHYC3DO3UUBE7tLC+KZePAEKg4nMdbaMN/R+V/AQqez1 Re+1yq6U0wl/OCy1zPDGwn8MYJl6chtbMjVxtzFlMdNO1Qvi1dZrnOGmNZ6RXxmQwaryMfm2 gaAuvpsYe2SqUgPvt2pB/Dw9FytXjq9UaU0hTk1h6HP4Gm9zXLEwTdXdwOp/qgbh6+tBBkJX 1iwUGWRcNTZZehvXv/4Fr8PDrSXbkcvEGPc55PI8yuX5X0IuNpdZ9pFMX/Eyke3OzHWyZg8b 2Mrsav3b1uFtUrOP17LNtu2JSREVdHYrMUTDs0jMs3tQE3fSRQp+Pttpdtlw4269ze7aPl1A 394L0LebAI1NCRHaBo6/0A1WbUXnrwccBMOiVNqZut24j/m1tjlpcbPzY5hIYUoYyRpiBpEI uYgQ/4rkwFR++GFn50XDuKxSfE+zZPeHH4+PvuMlfpHcy3Rx2V20s4PcCovY1lKVYCvKdPaA SqFedNCQe1caGbNKP/R2mTh9pTahuHY7PJcqga160dw+M2DuRgrvvJ0TUWREI1YUSnJHIdv9 BHk0ZVufKo9O9ZXQ6cteK/73uonwN8XYzl+I3eHO/girDzq3hVQrJo8+RwT4j3xF/rZ2anvk 3sHbw9PjBp21Zd7XrRFClvxCHJXG2sG7TLoJrEP87tfAwmjRz/A8cDM2Av+sVJ3/+fbs3fnJ +RaU7cP0C75OfqD92dt276BxnL7wKKlQKlW3qiSpjssD+hdpZa0GMICk+HrwtTBzX9Xu4Qu+ tL6ZB9DdUOdzUzqxt9fecW/vP9trUY8F/jP74e0KFKj7+uCn3KTqp/2RPuBP8yAtvrKKZ/zz CBJ7dXx+9P7k3cXJ2dsthBYRv0iy0cWlWKD20oV2SP+zpUANicQEzhB0CpLNQruZcDMl9scH 4MFvhb4Wf9/dJQ7sj8YNuwNr+pT6JzOq3FBYEMQZ4EtAQHk3GFfOIYx4qUvnZIKYNkQFqIT/ KoKTltDIWQ6yVH0Ukq4qCd5eW3D7To5RJvpw+bK30xBH35WtT/Q59Snry94zLITcXLq2gNOy lz1KgkmdDugNkbnF4htNgWJY7+CbzL34mWkc7H4zdS9W1WYV/qiD/gZitqQg12maKaLBu9AH peTZ56SEWw8PLoznH0DCiNVuxV/9MVPYwrE9TXRpnSDHA0tyJtjOqU7g9M3EiT/g383CRiNi +woWU/ukpXUqh/WkwhQwI5jQwnQMyNsNsoNSJQ6GmyCNwXe0fw6/IFDm1yUHFvrOjTe9AKZU udRk7DA3k2hJ2LK9h++f0xbainlprnSqanAUb3VRaQe0iCRbm7+lXYWSlujGprhzWso8RzAT TtpLeJrgd4a1Da95/tdmoZAT9YWczzPwhPy+DX6lVJkG7GoO9KTwyt0lyjqd1VwslALewppc CTsHi6h52cbJgNEFMKWEdRVggs0vxXhZi0TnVeZkofAtJDIvFbwUgIxNzTI7FCcTZIlOJHBb k4pdKnLGPrihbQSkC1eatEoUecZUWzmFc4RKLUXPZtV0qu2sR/1REAk0nAbyQLSFlB02WqcZ X/i/IqpV0B0L5blSjQq0HbBOlHgiHap9ad3TPvV1l/gwlcmyvpsZKdS1tm64LqQLL13YQS7G yFFzEDOXpdNJhQKS2QPTq4qEdIpMg6whsBz8bqRPlnEIQStxKhNwxthZtIsYTOYltA9RylmV TWAORBiB8oYRQYHNa/YB5cX/SB6FArutLDXb0liSfhKMkI+RWS4gsggshQZmZk66Q2ozCcGM oiLrdczbcnlJUpyDWmAJC+KgaSZtGj02DQv91fj3twKAXIUAp7Jln6Ev5JL/eomDgIrsCStQ ZwAJVv2aWUFetW7B+6BOkNzdZfXTk4kqqRM5KU1ew4enioABj8M6mW5QoQhNFUibjA/E4KdB GQoSCUbIHkiqXtGYy0BJwbhcjW4E1KDLRA1m2Cwj/sPQl2Khsqwv0sqrFFsCqwkw5O8jDYlq TEjIsXUlFV+m2KSfMQHpU7rSdSWNYyZKgBrkmmVm4XcMOgQnR3kgFV7/T1KOzZH4zvB9PxLF VfiEpLSVoMTkZAu6VyBswYTDzA3ajIib3cWOW7Z9R86fLWZmMh/rVncGbWdzf14zjruIS7Uk p5aRn2BvGM388zN++3zq/hync7DSZI/D9SOTI56lLbaPNqzimPMwomnlg9EJdeMbB6JMj0sJ ZxYq0zr5Qx2k8jm8KMV41GHT4GLrbIs7BXXEqYPuMuRlhKuET1uoEgkHojiCBCJQXUo1blJw q4nogrMb+IXBj/tQo66Co5+VpprOTOXE0lRlDapxon0xRqQILtTW9XyAAPeMmESpKwdCMLRq ZbYVhVRnP6lb3UpL6R9X/KxXb6BvrKf30NX7bXNqiHWffp/3ivI6df+NPt7lfADfT30A+Ayc /xw7Bd5/yFaPwv33FAU+B/M/w0aB9x+w0zYFPlU8vrDP5BJ+VFP11jjStp/1ZcvClJdYY4Uf zBg3BbQcwxPH0mOquZghR9v2sEhAc0Qop7jcRjD13rvlqCO0OpdG5iqsTP0HakVQLU+hAXUq eddegVjs8/KemCgg/QT7hBz46Q1FnkVxB0/fonkG/qpyA9l1ePEHFUtCg/GtywmODv3QBfaB y2Ykrk6hwsvEHLHYWDOfUTEki/VAQkXLKNa8qD1lqqd5bFZgF2IHELbVBOWb5grIEAOpNdP0 AOoCWdpL63sqMr2SqJ6moZADjBtJxndADvvU0oj7g7SCyuxeh+GhX4LCpOmZbGD8L0BUXUtS gL5oZBSqNmhGTheNmCrHAp4PqrlAlVYJPSFN8s2JWt0gP2QhlDNxL7upLUOtAw4WzByIY0bt 8kwVU+gOka/zUElHaHUeEwllBqDoTHyDntpCSE6oFCyBhgvKyG1g34Tq9noZ1Q08OEzTMMjm 6+JWCgViaIogly7U5dUc4gw9ApHIuRxr4KGVbXfqx9yW4tYRcUBeSZ1x1uF5MZNlSi0AoraC +gRO4oooq6Lw2gohRHDButY7232+L4HKcpsbouY1sUXEN1Jq5bsYtf6huDYQ1dL3JWK3aqwg F0UmXrNoc475i2ZONb0TryvEqgwFP3OC+x5tuzLkXApkY51eRVQLlozixJSS4/CxLyyhWvyH I4S1G4onJ863+bMSSV/dLxsrVYjLrEqnYLsqKKNs6fLwqeimxVGdCuPfczcTxNctGcN8Md5G 422UhtqQh94VLEgWm49tGAwsngAFRLopLSytUKV0pvT0e+WoDcyn8EGGRKCVufJqYKqMO6LU eEoyMx7DR3aNZbW9Ol56bQ+FwgbTqDuktAMsFluQOKjbSTgg8IAzCDJQMl/LWE2uBB5iKpFD wGsQ3y9rv2wRdRwN94AXyhdYXCVgSYxS+LwMW4XOIIU3BMRCiSfeBdp+c3yDwEj2Qs5BUWeR GkQfJaEoIAnAAbMWSpuCF82arpQlQYjgUuRxVCNbIfL6rpvvBbUsU1OHLvdn8I9Wr/ztjy0q 57DL7o27OJrtocSAgiZPZz5KGvq3vz8EMaUx7vpx8P/zofBfPg7+1w+B/yPxfvkQuD8S3+1D 4G4ddYie+LAuXr4UPz59HGqOH4QaVaTsnh+HBvcgblVv4Ug3FpUnvkThgCqTRM19XEEQb/XX mpAUMslwOBzKqTpO+YQVORhnzP5vTAqayBWnQuKY5N0d3YaI5kiBmwd8qjAuVxb4en/zd/7m UKjTkjaDNg3SxO8eYazmt/OTt7+Ki9fH4vTst/NtJr1qqdIJHR1qDcaKzsbS/moXt9NKbeqx kGAhaS+Ma9cuthr7HkJUCa6EW+2HWMOEVkCuUGOkdBztO7GhHGhSc+vCEVtxGbu0YSzHBnVb adBuUJt4KYy34spqVhQeAJkYo5Zbpkjf465tDh/qRv6b+sDsTgv+4V6wWcU/7KBi02zawUlx ZS47Rw6ouDeuPId9JB2ixl1+CV87BXXx59s0x1EshbqGkhVhYvTU+LybZ0lFUpWWDrA7J/D+ FQpXP/Lg6nmsvlAu4dz6pumhh5juuV0M3p08oBxelXJ6B2/5GN+3u3xpFyYX8shPTf73HxWs yLKsqMLNrFrMFE2rNUWrf5GoeBmbZpU5TdUYwbANh7uBYV3KYxpQgWewinpdjg+Q6krSt8g6 SiZGXVgdvfoKoLlmY+WhMRieOcAlrqpyfKIvxjSxmVHF1O8C49GLuF60mCrMXPl55Yg3Lx3T 0b5KyeXxxEEXGnUYdTibLwkA7oDxEaPAsHpuoUtevVG/PerkX0wU7jD4v5LnHSQ/N/LIqhzj Xrcn/RAabebbafSMp9MKTQ8TCFKujaIbbp3McExcGdy9Oyx8okhwujZK8JER4cPl3Xb708KU bbe/YkmbYsDPpqis+KXdJrpRtn4ErNPNCFNJG+fjmrZnAX9G7m3FWS1g1f3Q4EMwoeFCPpsg /fG9wMIsBHs6+jShPBXJBeiY4Xqr2+9fetP0mH+d01heDuaEs47r7pgOOSHNzPPUlRV1w6mr v6B0OTVdaNaEgbAJdbLAgtB4poCoE+24/6akRxOIE0+atIeasl14rfnF2LYM7ROfft9IFrI/ 32jKOLWLZ+V0+EIN1IJGrWvHbetJp7aUVrwtNeSCxzWMdfC7bNLI3mRr9C4WB8Q9L76/qDW/ b+ZT/pcndu/4/OXOxM7HLnHOB2pkpodJO7NZM2zoUYhfYDUShakOyQeLnd4kM0NHTJSYyELP qyxO53F6ootVA8lbEbEfTBgW4t0FNNOq0MKmLvth91zJrltHPaLKZ2rNyL9Xu9hl9fgONwYl 7E/nK25hBDczglm2NkYJc05nJwoVybB7//+JZPS15vNPcQKJ3RrCX2OZX8qOqS0aErbPL9ky +fTV6wcn/Hfb/18o1fEp7N3sCus28ur+DOo6yA1u8iKM1a4cxlpfkcMU8LY54F6dmh/SgW8E 1T73Dafb9D4J0YrgYg+LTfotb6D8MVjttvWBznMk3DxWzKVC6SVy08MA4dCnIKdCQUbW3sPz rJ6JI0l1bqUmgx9SkBaZg88T/HqeK160BvIJT3+eqOY3YeLPGempBIEFKbJT2wrU4G0r3eeT 65ov3h9aLgh8ksAU3UE5jS3U+NGOymrUKo3CbIj0p1Rq+74JAaIujzYlP6wEsDpzA80H9HXD Jxy7+fyF2nRUsNe7Gq7u6PQ5NmP8DDg9BBjrKDpv63dn7ONhf0bjEbXs4wFmVA5LMDmFi+lM OLquRxPIYZea5qubxzIeo+N2dHZ6evj21TaPHjaG15yUNmfIXJnTQWHiZ0FbB6XUNeVkduib r3d2uW5sjq4+4yjWnjL8qAcLb+qI1riicmt+8aX9MN4GKhqgJ/5ZP3rehRQknpC25opaZ931 2XQ8MG3gRJ6vZdI0mr/a7oQ2I6HgZgMZNo8/tdOTUN03j542Awzthzf8xIKfqPAPOvjmR1Vk rXEXwdJeoMbl5TN+ypwP5ZWD96jbCamayCqDQOIzIHRIvmyGk7ro1Q+UWp9DAb5qzxZhK30L axtgccj2kA7ao7cnEyVKGzcbsasHUbjs4tS/NXkgajo3CKHpDnO+x4zTFBOrrtZ/5KHATQ/Q prpsTZbcrNDNt2sKflhO+XeK7NbqfVt1sp7p3DeroecVYLm3VSV3gTwl1wRvT97JTPZW2dwF Jdbm2z1TY50R/pryvmDiDFsAMAx/T1xjFc6sARm37hsf3FgAC3oIDosjrv4Jx6KlnmEeg3P/ qvBTK8HVrILqzsq0pylFqILB1hg1ySe2H4YerzHCKu8y2AfdSUGb3G1oiMiuQuugrYuI69oJ E3bZjKBYk8UGvRut5fEfre3Rg/s8/u7W2ifW/rx5RJD376+tqJBxxi/XeXaDtaxBWcQHdFes YxViy1hiPcEJ/h0dIiH+hENH5E9kwUlAK0g1T9JTpshxrh5oXPrHMe2ajZjSz1vCSvzQYeGf 4HfKcgt9XpVzQ6N81EUaiuOSh2+5/m5n5/HlH2D1gJYilTkCX5O5UmeJfzEwZphkfdxc6K2E Ov8Kc489hGmns3BGbR0S2W6PrdwQ2tcMaSphPvWPEvjTAthgCBNDWvNBphIqvPVo1P30WdPh 3w/fnxz+/Ob4fvkwFSTklFgitVbE9OVKlpootXUqwfJcSJ/C5PSAFbF3g+7elRGsZr8XOlem ck9qo326Ev9vTry/XUlZnZpCzPAklRJhXp7EX1T52HdAc2ix9qPqbIz182HtSq+ByGWjH61d mUr21ScUdApDo9qJH15u0rKVoNCApLxgeKP6fCDrgh/6XIyrOcI1PgySOdOmcbVM91V25JZ/ NHnTDxVQIs97NsCaY03+PZc4IQzhySujU340wD8MXzcavQ8i72SNv6udo7eb4nTOxYeA4eF5 jyw/qV/3MMhJttoBDag4qM0D9n5i9IbDFM4Bbpb6YziNi7NXZ/fwF/tV1nZ6mT74VTkxV2bu x5AcT4qQ/EAuOQ+Qv/JzD7HfYCEtijdg3doRV6nmUpcWkTTTK/udyiU1P1KSePROfsB31WpO UWDlVe57sBcziNQ/0rD5VI38n5+lp562tmHUn5OrkLv5urH7rD0d8ad8KrXa8Jak3PHnAFom NNfXKrM/rZI2anG2rQkbfsCq9fuKUTJH4ky8E3+K9+JE/Cpei4v4E1jf0I+zvhDPxA7++z5e PcWyIyw7FMfiTbx4gQtn+OpQnMdLvwLgMf57H5SjxgvOLPzA1yj8+u+XX/wPUEsBAhcLFAAA AAgAKa2iNs2H2aOoFQAAeVgAABEAEQAAAAAAAQAgALaBAAAAAHZpcnR1YWxtb3VzZS5odG1s U0QEALwAAABVVAUAB709OUZQSwUGAAAAAAEAAQBQAAAAUxYAAAAA ====== [Duoas] ---- !!!!!! %| [Category Package] | Category… what? Is this about Device Control, Testing, Platform Issues, or something else? |% !!!!!!