changeset 0:daa24f8a557b

TightVNC original
author YU
date Thu, 11 Sep 2014 07:30:03 +0900
parents
children 7bee64adbbfd
files LICENSE.txt README.txt build.gradle src/libs/jsch-0.1.50.jar src/main/java/com/glavsoft/core/SettingsChangedEvent.java src/main/java/com/glavsoft/drawing/ColorDecoder.java src/main/java/com/glavsoft/drawing/Renderer.java src/main/java/com/glavsoft/drawing/SoftCursor.java src/main/java/com/glavsoft/exceptions/AuthenticationFailedException.java src/main/java/com/glavsoft/exceptions/ClosedConnectionException.java src/main/java/com/glavsoft/exceptions/CommonException.java src/main/java/com/glavsoft/exceptions/CryptoException.java src/main/java/com/glavsoft/exceptions/FatalException.java src/main/java/com/glavsoft/exceptions/ProtocolException.java src/main/java/com/glavsoft/exceptions/TransportException.java src/main/java/com/glavsoft/exceptions/UnsupportedProtocolVersionException.java src/main/java/com/glavsoft/exceptions/UnsupportedSecurityTypeException.java src/main/java/com/glavsoft/rfb/CapabilityContainer.java src/main/java/com/glavsoft/rfb/ClipboardController.java src/main/java/com/glavsoft/rfb/IChangeSettingsListener.java src/main/java/com/glavsoft/rfb/IPasswordRetriever.java src/main/java/com/glavsoft/rfb/IRepaintController.java src/main/java/com/glavsoft/rfb/IRfbSessionListener.java src/main/java/com/glavsoft/rfb/RfbCapabilityInfo.java src/main/java/com/glavsoft/rfb/client/ClientCutTextMessage.java src/main/java/com/glavsoft/rfb/client/ClientToServerMessage.java src/main/java/com/glavsoft/rfb/client/FramebufferUpdateRequestMessage.java src/main/java/com/glavsoft/rfb/client/KeyEventMessage.java src/main/java/com/glavsoft/rfb/client/PointerEventMessage.java src/main/java/com/glavsoft/rfb/client/SetEncodingsMessage.java src/main/java/com/glavsoft/rfb/client/SetPixelFormatMessage.java src/main/java/com/glavsoft/rfb/encoding/EncodingType.java src/main/java/com/glavsoft/rfb/encoding/PixelFormat.java src/main/java/com/glavsoft/rfb/encoding/ServerInitMessage.java src/main/java/com/glavsoft/rfb/encoding/decoder/ByteBuffer.java src/main/java/com/glavsoft/rfb/encoding/decoder/CopyRectDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/Decoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/DecodersContainer.java src/main/java/com/glavsoft/rfb/encoding/decoder/FramebufferUpdateRectangle.java src/main/java/com/glavsoft/rfb/encoding/decoder/HextileDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/RREDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/RawDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/RichCursorDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/TightDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/ZlibDecoder.java src/main/java/com/glavsoft/rfb/protocol/LocalPointer.java src/main/java/com/glavsoft/rfb/protocol/MessageQueue.java src/main/java/com/glavsoft/rfb/protocol/Protocol.java src/main/java/com/glavsoft/rfb/protocol/ProtocolContext.java src/main/java/com/glavsoft/rfb/protocol/ProtocolSettings.java src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java src/main/java/com/glavsoft/rfb/protocol/SenderTask.java src/main/java/com/glavsoft/rfb/protocol/auth/AuthHandler.java src/main/java/com/glavsoft/rfb/protocol/auth/NoneAuthentication.java src/main/java/com/glavsoft/rfb/protocol/auth/SecurityType.java src/main/java/com/glavsoft/rfb/protocol/auth/TightAuthentication.java src/main/java/com/glavsoft/rfb/protocol/auth/VncAuthentication.java src/main/java/com/glavsoft/rfb/protocol/state/AuthenticationState.java src/main/java/com/glavsoft/rfb/protocol/state/HandshakeState.java src/main/java/com/glavsoft/rfb/protocol/state/InitState.java src/main/java/com/glavsoft/rfb/protocol/state/InitTightState.java src/main/java/com/glavsoft/rfb/protocol/state/ProtocolState.java src/main/java/com/glavsoft/rfb/protocol/state/SecurityType33State.java src/main/java/com/glavsoft/rfb/protocol/state/SecurityType37State.java src/main/java/com/glavsoft/rfb/protocol/state/SecurityTypeState.java src/main/java/com/glavsoft/transport/Reader.java src/main/java/com/glavsoft/transport/Writer.java src/main/java/com/glavsoft/utils/Keymap.java src/main/java/com/glavsoft/utils/Strings.java src/viewer_swing/java/com/glavsoft/viewer/AbstractConnectionWorkerFactory.java src/viewer_swing/java/com/glavsoft/viewer/CancelConnectionException.java src/viewer_swing/java/com/glavsoft/viewer/ConnectionErrorException.java src/viewer_swing/java/com/glavsoft/viewer/ConnectionPresenter.java src/viewer_swing/java/com/glavsoft/viewer/ConnectionWorker.java src/viewer_swing/java/com/glavsoft/viewer/NetworkConnectionWorker.java src/viewer_swing/java/com/glavsoft/viewer/RfbConnectionWorker.java src/viewer_swing/java/com/glavsoft/viewer/UiSettings.java src/viewer_swing/java/com/glavsoft/viewer/UiSettingsData.java src/viewer_swing/java/com/glavsoft/viewer/Viewer.java src/viewer_swing/java/com/glavsoft/viewer/cli/Parser.java src/viewer_swing/java/com/glavsoft/viewer/mvp/Model.java src/viewer_swing/java/com/glavsoft/viewer/mvp/Presenter.java src/viewer_swing/java/com/glavsoft/viewer/mvp/View.java src/viewer_swing/java/com/glavsoft/viewer/swing/ClipboardControllerImpl.java src/viewer_swing/java/com/glavsoft/viewer/swing/ConnectionParams.java src/viewer_swing/java/com/glavsoft/viewer/swing/KeyEventListener.java src/viewer_swing/java/com/glavsoft/viewer/swing/KeyboardConvertor.java src/viewer_swing/java/com/glavsoft/viewer/swing/LocalMouseCursorShape.java src/viewer_swing/java/com/glavsoft/viewer/swing/ModifierButtonEventListener.java src/viewer_swing/java/com/glavsoft/viewer/swing/MouseEventListener.java src/viewer_swing/java/com/glavsoft/viewer/swing/ParametersHandler.java src/viewer_swing/java/com/glavsoft/viewer/swing/RendererImpl.java src/viewer_swing/java/com/glavsoft/viewer/swing/SoftCursorImpl.java src/viewer_swing/java/com/glavsoft/viewer/swing/Surface.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingConnectionWorkerFactory.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingNetworkConnectionWorker.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingRfbConnectionWorker.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindowFactory.java src/viewer_swing/java/com/glavsoft/viewer/swing/Utils.java src/viewer_swing/java/com/glavsoft/viewer/swing/WrongParameterException.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/AutoCompletionComboEditorDocument.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/ConnectionView.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/ConnectionsHistory.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/HostnameComboboxRenderer.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/OptionsDialog.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/PasswordDialog.java src/viewer_swing/java/com/glavsoft/viewer/swing/ssh/SshConnectionManager.java src/viewer_swing/java/com/glavsoft/viewer/swing/ssh/SshKnownHostsManager.java src/viewer_swing/java/com/glavsoft/viewer/swing/ssh/SwingSshUserInfo.java src/viewer_swing/resources/com/glavsoft/viewer/images/button-alt.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-close.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-ctrl-alt-del.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-ctrl.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-file-transfer.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-info.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-new-connection.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-options.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-rec.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-refresh.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-save.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-win.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-100.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-fit.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-fullscreen.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-in.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-out.png src/viewer_swing/resources/com/glavsoft/viewer/images/cursor-dot.png src/viewer_swing/resources/com/glavsoft/viewer/images/cursor-nocursor.png src/viewer_swing/resources/com/glavsoft/viewer/images/cursor-smalldot.png src/viewer_swing/resources/com/glavsoft/viewer/images/tightvnc-logo-16x16.png src/viewer_swing/resources/com/glavsoft/viewer/images/tightvnc-logo-32x32.png src/web/viewer-applet-example.html
diffstat 134 files changed, 14241 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE.txt	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.txt	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,52 @@
+
+TightVNC Java Viewer version 2.7.2
+Copyright (C) 2011, 2012 GlavSoft LLC. All rights reserved.
+======================================================================
+
+This software is distributed under the GNU General Public Licence
+as published by the Free Software Foundation. Please see the file
+LICENCE.txt for the exact licensing terms and conditions.
+
+The license does not permit incorporating this software into
+proprietary programs. If you wish to do so, please order commercial
+source code license. See the details here:
+
+  http://www.tightvnc.com/licensing/
+
+
+Using TightVNC Java Viewer
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+TightVNC Java Viewer can work either as a normal application or as
+an applet. To run it as an application, just execute the JAR file
+(tightvnc-jviewer.jar), e.g. double-click it in the Windows Explorer.
+If Java Runtime is installed on your computer correctly, that should
+be enough. You will be prompted for the TightVNC Server to connect to.
+
+If you would like to start the viewer from the command line, here are
+a few examples:
+
+  java -jar tightvnc-jviewer.jar
+  java -jar tightvnc-jviewer.jar hostname
+  java -jar tightvnc-jviewer.jar -port=nnn hostname
+  java -jar tightvnc-jviewer.jar -port=nnn -host=hostname
+
+... where hostname and nnn should be replaced with the actual hostname
+and port number correspondingly. Note that you can use an IP address
+as a hostname. Port 5900 will be used if not specified.
+
+Important: the syntax like hostname:display or hostname::port is not
+           supported in this version of TightVNC Java Viewer.
+
+For more command line params info run:
+
+  java -jar tightvnc-jviewer.jar -help
+
+Finally, if you would like to use the viewer as an applet, please see
+the example HTML page included (viewer-applet-example.html).
+
+======================================================================
+
+Thank you for using TightVNC!
+
+Visit our Web site:    http://www.tightvnc.com/
+Follow us on Twitter:  http://www.twitter.com/tighvnc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build.gradle	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,129 @@
+apply plugin:'java'
+apply plugin: 'eclipse'
+
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
+version = '2.7.2'
+
+project.ext.baseName = 'tightvnc-jviewer'
+def buildNo = processBuildNo(version)
+
+defaultTasks 'clean', 'dist'
+
+configurations {
+    viewerSwingCompile { extendsFrom compile }
+    viewerSwingRuntime { extendsFrom viewerSwingCompile, runtime }
+}
+
+sourceSets {
+	viewerSwing {
+		java {
+			srcDir 'src/viewer_swing/java'
+		}
+		resources {
+			srcDir 'src/viewer_swing/resources'
+		}
+	}
+	main {
+		java.srcDirs += viewerSwing.java.srcDirs
+		resources.srcDirs += viewerSwing.resources.srcDirs
+	}
+}
+
+repositories {
+    flatDir {
+        dirs 'src/libs/'
+    }
+}
+
+dependencies {
+    compile group: 'com.jcraft', name: 'jsch', version: '0.1.+', ext: 'jar'
+    viewerSwingCompile group: 'com.jcraft', name: 'jsch', version: '0.1.+', ext: 'jar'
+    viewerSwingRuntime configurations.viewerSwingCompile
+}
+
+def manifestAttributes = ['Main-Class': 'com.glavsoft.viewer.Viewer',
+        'Implementation-Version': "${project.version} (${buildNo})",
+        'Implementation-Title': 'TightVNC Viewer',
+        'Implementation-Vendor': 'GlavSoft LLC.']
+
+jar {
+    baseName = project.baseName
+    version = null
+    manifest {
+        attributes manifestAttributes
+    }
+    def runtimeDeps = configurations.viewerSwingRuntime.collect {
+        it.isDirectory() ? it : zipTree(it)
+    }
+    from(runtimeDeps) {
+        exclude 'META-INF/**'
+    }
+}
+
+task noSshJar (type: Jar, dependsOn: classes) {
+    baseName = 'nossh/' + project.baseName
+    version = null
+    manifest {
+        attributes manifestAttributes
+    }
+    from sourceSets.main.output
+}
+
+artifacts {
+    archives file('src/web/viewer-applet-example.html')
+    archives noSshJar
+}
+
+uploadArchives {
+    repositories {
+        add(new org.apache.ivy.plugins.resolver.FileSystemResolver()) {
+            addArtifactPattern("$projectDir/dist/${project.baseName}-${project.version}/[artifact].[ext]")
+        }
+    }
+	uploadDescriptor = false
+}
+
+task dist(dependsOn: uploadArchives)
+
+def processBuildNo(currentVersion) {
+    final String VERSION = 'version'
+    final String BUILD = 'build'
+
+    def lastVersion = currentVersion
+    def lastBuild = 0
+    def buildNoFile = new File('.build_no')
+    if ( ! buildNoFile.exists()) {
+        buildNoFile.createNewFile()
+        buildNoFile << "${VERSION}=${lastVersion}\n${BUILD}=${lastBuild}"
+    }
+    def versions = [:]
+    buildNoFile.eachLine {
+        def splitted = it.split('=')
+        if (splitted.size() == 2) {
+            def (key, value) = splitted
+            switch(key.trim()) {
+                case VERSION:
+                    lastVersion = value.trim()
+                    break
+                case BUILD:
+                    try {
+                        lastBuild = value != null ? value.trim() as Integer : 0
+                    } catch (NumberFormatException) {}
+                    versions[lastVersion] = lastBuild
+                    break
+            }
+        }
+    }
+    lastVersion = versions[currentVersion]
+    if (null == lastVersion) {
+        versions[currentVersion] = 0
+    }
+    ++versions[currentVersion]
+    def outString = ''
+    versions.each { v, b ->
+        outString += "${VERSION}=${v}\n${BUILD}=${b}\n\n"
+    }
+    buildNoFile.write(outString)
+    versions[currentVersion]
+}
Binary file src/libs/jsch-0.1.50.jar has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/core/SettingsChangedEvent.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,41 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.core;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class SettingsChangedEvent {
+	private final Object source;
+
+	public SettingsChangedEvent(Object source) {
+		this.source = source;
+	}
+
+	public Object getSource() {
+		return source;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/drawing/ColorDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,140 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.drawing;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.transport.Reader;
+
+public class ColorDecoder {
+    protected byte redShift;
+	protected byte greenShift;
+	protected byte blueShift;
+	public short redMax;
+	public short greenMax;
+	public short blueMax;
+	public final int bytesPerPixel;
+	public final int bytesPerCPixel;
+    public final int bytesPerPixelTight;
+	private final byte[] buff;
+
+	private int startShift;
+	private int startShiftCompact;
+	private int addShiftItem;
+	private final boolean isTightSpecific;
+
+    public ColorDecoder(PixelFormat pf) {
+		redShift = pf.redShift;
+		greenShift = pf.greenShift;
+		blueShift = pf.blueShift;
+		redMax = pf.redMax;
+		greenMax = pf.greenMax;
+		blueMax = pf.blueMax;
+		bytesPerPixel = pf.bitsPerPixel / 8;
+        final long significant = redMax << redShift | greenMax << greenShift | blueMax << blueShift;
+        bytesPerCPixel = pf.depth <= 24 // as in RFB
+//                          || 32 == pf.depth) // UltraVNC use this... :(
+                    && 32 == pf.bitsPerPixel
+                    && ((significant & 0x00ff000000L) == 0 || (significant & 0x000000ffL) == 0)
+                ? 3
+                : bytesPerPixel;
+        bytesPerPixelTight = 24 == pf.depth && 32 == pf.bitsPerPixel ? 3 : bytesPerPixel;
+		buff = new byte[bytesPerPixel];
+		if (0 == pf.bigEndianFlag) {
+			startShift = 0;
+			startShiftCompact = 0;
+			addShiftItem = 8;
+		} else {
+			startShift = pf.bitsPerPixel - 8;
+			startShiftCompact = Math.max(0, pf.depth - 8);
+			addShiftItem = -8;
+		}
+		isTightSpecific = 4==bytesPerPixel && 3==bytesPerPixelTight &&
+				255 == redMax && 255 == greenMax && 255 == blueMax;
+	}
+
+	protected int readColor(Reader reader) throws TransportException {
+		return getColor(reader.readBytes(buff, 0, bytesPerPixel), 0);
+	}
+
+	protected int readCompactColor(Reader reader) throws TransportException {
+		return getCompactColor(reader.readBytes(buff, 0, bytesPerCPixel), 0);
+	}
+
+	protected int readTightColor(Reader reader) throws TransportException {
+		return getTightColor(reader.readBytes(buff, 0, bytesPerPixelTight), 0);
+	}
+
+	protected int convertColor(int rawColor) {
+		return  255 * (rawColor >> redShift & redMax) / redMax << 16 |
+				255 * (rawColor >> greenShift & greenMax) / greenMax << 8 |
+				255 * (rawColor >> blueShift & blueMax) / blueMax;
+	}
+
+	public void fillRawComponents(byte[] comp, byte[] bytes, int offset) {
+		int rawColor = getRawTightColor(bytes, offset);
+		comp[0] = (byte) (rawColor >> redShift & redMax);
+		comp[1] = (byte) (rawColor >> greenShift & greenMax);
+		comp[2] = (byte) (rawColor >> blueShift & blueMax);
+	}
+
+	public int getTightColor(byte[] bytes, int offset) {
+		return convertColor(getRawTightColor(bytes, offset));
+	}
+
+	private int getRawTightColor(byte[] bytes, int offset) {
+		if (isTightSpecific)
+			return (bytes[offset++] & 0xff)<<16 |
+					(bytes[offset++] & 0xff)<<8 |
+					bytes[offset] & 0xff;
+		else
+			return getRawColor(bytes, offset);
+	}
+
+	protected int getColor(byte[] bytes, int offset) {
+		return convertColor(getRawColor(bytes, offset));
+	}
+
+	private int getRawColor(byte[] bytes, int offset) {
+		int shift = startShift;
+		int item = addShiftItem;
+		int rawColor = (bytes[offset++] & 0xff)<<shift;
+		for (int i=1; i<bytesPerPixel; ++i) {
+			rawColor |= (bytes[offset++] & 0xff)<<(shift+=item);
+		}
+		return rawColor;
+	}
+
+	protected int getCompactColor(byte[] bytes, int offset) {
+		int shift = startShiftCompact;
+		int item = addShiftItem;
+		int rawColor = (bytes[offset++] & 0xff)<<shift;
+		for (int i=1; i< bytesPerCPixel; ++i) {
+			rawColor |= (bytes[offset++] & 0xff)<<(shift+=item);
+		}
+		return convertColor(rawColor);
+	}
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/drawing/Renderer.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,347 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.drawing;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.transport.Reader;
+
+import java.util.Arrays;
+
+/**
+ * Render bitmap data
+ *
+ * @author dime @ tightvnc.com
+ */
+public abstract class Renderer {
+
+    protected Reader reader;
+    private final Object lock = new Object();
+
+    public abstract void drawJpegImage(byte[] bytes, int offset,
+                                       int jpegBufferLength, FramebufferUpdateRectangle rect);
+
+    protected int width;
+    protected int height;
+    protected int[] pixels;
+    protected SoftCursor cursor;
+    public PixelFormat pixelFormat;
+    protected ColorDecoder colorDecoder;
+
+    protected void init(Reader reader, int width, int height, PixelFormat pixelFormat) {
+        this.reader = reader;
+        this.width = width;
+        this.height = height;
+        initPixelFormat(pixelFormat);
+        pixels = new int[width * height];
+        Arrays.fill(pixels, 0);
+    }
+
+    public void initPixelFormat(PixelFormat pixelFormat) {
+        synchronized (lock) {
+            this.pixelFormat = pixelFormat;
+            colorDecoder = new ColorDecoder(pixelFormat);
+        }
+    }
+
+    /**
+     * Draw byte array bitmap data
+     *
+     * @param bytes  bitmap data
+     * @param x      bitmap x position
+     * @param y      bitmap y position
+     * @param width  bitmap width
+     * @param height bitmap height
+     */
+    public void drawBytes(byte[] bytes, int x, int y, int width, int height) {
+        int i = 0;
+        for (int ly = y; ly < y + height; ++ly) {
+            int end = ly * this.width + x + width;
+            for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+                pixels[pixelsOffset] = getPixelColor(bytes, i);
+                i += colorDecoder.bytesPerPixel;
+            }
+        }
+    }
+
+    /**
+     * Draw byte array bitmap data (for ZRLE)
+     */
+    public int drawCompactBytes(byte[] bytes, int offset, int x, int y, int width, int height) {
+        synchronized (lock) {
+            int i = offset;
+            for (int ly = y; ly < y + height; ++ly) {
+                int end = ly * this.width + x + width;
+                for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+                    pixels[pixelsOffset] = getCompactPixelColor(bytes, i);
+                    i += colorDecoder.bytesPerCPixel;
+                }
+            }
+            return i - offset;
+        }
+    }
+
+    /**
+     * Draw int (colors) array bitmap data (for ZRLE)
+     */
+    public void drawColoredBitmap(int[] colors, int x, int y, int width, int height) {
+        synchronized (lock) {
+            int i = 0;
+            for (int ly = y; ly < y + height; ++ly) {
+                int end = ly * this.width + x + width;
+                for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+                    pixels[pixelsOffset] = colors[i++];
+                }
+            }
+        }
+    }
+
+    /**
+     * Draw byte array bitmap data (for Tight)
+     */
+    public int drawTightBytes(byte[] bytes, int offset, int x, int y, int width, int height) {
+        synchronized (lock) {
+            int i = offset;
+            for (int ly = y; ly < y + height; ++ly) {
+                int end = ly * this.width + x + width;
+                for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+                    pixels[pixelsOffset] = colorDecoder.getTightColor(bytes, i);
+                    i += colorDecoder.bytesPerPixelTight;
+                }
+            }
+            return i - offset;
+        }
+    }
+
+    /**
+     * Draw byte array bitmap data (from array with plain RGB color components. Assumed: rrrrrrrr gggggggg bbbbbbbb)
+     */
+    public void drawUncaliberedRGBLine(byte[] bytes, int x, int y, int width) {
+        synchronized (lock) {
+            int end = y * this.width + x + width;
+            for (int i = 3, pixelsOffset = y * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+                pixels[pixelsOffset] =
+//					(0xff & bytes[i++]) << 16 |
+//					(0xff & bytes[i++]) << 8 |
+//					0xff & bytes[i++];
+                        (0xff & 255 * (colorDecoder.redMax & bytes[i++]) / colorDecoder.redMax) << 16 |
+                                (0xff & 255 * (colorDecoder.greenMax & bytes[i++]) / colorDecoder.greenMax) << 8 |
+                                0xff & 255 * (colorDecoder.blueMax & bytes[i++]) / colorDecoder.blueMax;
+            }
+        }
+    }
+
+    /**
+     * Draw paletted byte array bitmap data
+     *
+     * @param buffer  bitmap data
+     * @param rect    bitmap location and dimensions
+     * @param palette colour palette
+     * @param paletteSize number of colors in palette
+     */
+    public void drawBytesWithPalette(byte[] buffer, FramebufferUpdateRectangle rect,
+                                     int[] palette, int paletteSize) {
+        synchronized (lock) {
+            // 2 colors
+            if (2 == paletteSize) {
+                int dx, dy, n;
+                int i = rect.y * this.width + rect.x;
+                int rowBytes = (rect.width + 7) / 8;
+                byte b;
+
+                for (dy = 0; dy < rect.height; dy++) {
+                    for (dx = 0; dx < rect.width / 8; dx++) {
+                        b = buffer[dy * rowBytes + dx];
+                        for (n = 7; n >= 0; n--) {
+                            pixels[i++] = palette[b >> n & 1];
+                        }
+                    }
+                    for (n = 7; n >= 8 - rect.width % 8; n--) {
+                        pixels[i++] = palette[buffer[dy * rowBytes + dx] >> n & 1];
+                    }
+                    i += this.width - rect.width;
+                }
+            } else {
+                // 3..255 colors (assuming bytesPixel == 4).
+                int i = 0;
+                for (int ly = rect.y; ly < rect.y + rect.height; ++ly) {
+                    for (int lx = rect.x; lx < rect.x + rect.width; ++lx) {
+                        int pixelsOffset = ly * this.width + lx;
+                        pixels[pixelsOffset] = palette[buffer[i++] & 0xFF];
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Copy rectangle region from one position to another. Regions may be overlapped.
+     *
+     * @param srcX    source rectangle x position
+     * @param srcY    source rectangle y position
+     * @param dstRect destination rectangle
+     */
+    public void copyRect(int srcX, int srcY, FramebufferUpdateRectangle dstRect) {
+        int startSrcY, endSrcY, dstY, deltaY;
+        if (srcY > dstRect.y) {
+            startSrcY = srcY;
+            endSrcY = srcY + dstRect.height;
+            dstY = dstRect.y;
+            deltaY = +1;
+        } else {
+            startSrcY = srcY + dstRect.height - 1;
+            endSrcY = srcY - 1;
+            dstY = dstRect.y + dstRect.height - 1;
+            deltaY = -1;
+        }
+        synchronized (lock) {
+            for (int y = startSrcY; y != endSrcY; y += deltaY) {
+                System.arraycopy(pixels, y * width + srcX,
+                        pixels, dstY * width + dstRect.x, dstRect.width);
+                dstY += deltaY;
+            }
+        }
+    }
+
+    /**
+     * Fill rectangle region with specified colour
+     *
+     * @param color colour to fill with
+     * @param rect  rectangle region positions and dimensions
+     */
+    public void fillRect(int color, FramebufferUpdateRectangle rect) {
+        fillRect(color, rect.x, rect.y, rect.width, rect.height);
+    }
+
+    /**
+     * Fill rectangle region with specified colour
+     *
+     * @param color  colour to fill with
+     * @param x      rectangle x position
+     * @param y      rectangle y position
+     * @param width  rectangle width
+     * @param height rectangle height
+     */
+    public void fillRect(int color, int x, int y, int width, int height) {
+        synchronized (lock) {
+            int sy = y * this.width + x;
+            int ey = sy + height * this.width;
+            for (int i = sy; i < ey; i += this.width) {
+                Arrays.fill(pixels, i, i + width, color);
+            }
+        }
+    }
+
+    /**
+     * Reads color bytes (PIXEL) from reader, returns int combined RGB
+     * value consisting of the red component in bits 16-23, the green component
+     * in bits 8-15, and the blue component in bits 0-7. May be used directly for
+     * creation awt.Color object
+     */
+    public int readPixelColor(Reader reader) throws TransportException {
+        return colorDecoder.readColor(reader);
+    }
+
+    public int readTightPixelColor(Reader reader) throws TransportException {
+        return colorDecoder.readTightColor(reader);
+    }
+
+    public ColorDecoder getColorDecoder() {
+        return colorDecoder;
+    }
+
+    public int getCompactPixelColor(byte[] bytes, int offset) {
+        return colorDecoder.getCompactColor(bytes, offset);
+    }
+
+    public int getPixelColor(byte[] bytes, int offset) {
+        return colorDecoder.getColor(bytes, offset);
+    }
+
+    public int getBytesPerPixel() {
+        return colorDecoder.bytesPerPixel;
+    }
+
+    public int getBytesPerCPixel() {
+        return colorDecoder.bytesPerCPixel;
+    }
+
+    public int getBytesPerPixelTight() {
+        return colorDecoder.bytesPerPixelTight;
+    }
+
+    public void fillColorBitmapWithColor(int[] bitmapData, int decodedOffset, int rlength, int color) {
+        while (rlength-- > 0) {
+            bitmapData[decodedOffset++] = color;
+        }
+    }
+
+    /**
+     * Width of rendered image
+     *
+     * @return width
+     */
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Height of rendered image
+     *
+     * @return height
+     */
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Read and decode cursor image
+     *
+     * @param rect new cursor hot point position and cursor dimensions
+     * @throws TransportException
+     */
+    public void createCursor(int[] cursorPixels, FramebufferUpdateRectangle rect)
+            throws TransportException {
+        synchronized (cursor.getLock()) {
+            cursor.createCursor(cursorPixels, rect.x, rect.y, rect.width, rect.height);
+        }
+    }
+
+    /**
+     * Read and decode new cursor position
+     *
+     * @param rect cursor position
+     */
+    public void decodeCursorPosition(FramebufferUpdateRectangle rect) {
+        synchronized (cursor.getLock()) {
+            cursor.updatePosition(rect.x, rect.y);
+        }
+    }
+
+    public Object getLock() {
+        return lock;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/drawing/SoftCursor.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,92 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.drawing;
+
+/**
+ * Abstract class for operations with soft cursor positions, dimensions and
+ * hot point position.
+ */
+public abstract class SoftCursor {
+
+	protected int hotX, hotY;
+	private int x, y;
+	public int width, height;
+	public int rX, rY;
+	public int oldRX, oldRY;
+	public int oldWidth, oldHeight;
+    private final Object lock = new Object();
+
+    public SoftCursor(int hotX, int hotY, int width, int height) {
+		this.hotX = hotX;
+		this.hotY = hotY;
+		oldWidth = this.width = width;
+		oldHeight = this.height = height;
+		oldRX = rX = 0;
+		oldRY = rY = 0;
+	}
+
+	/**
+	 * Update cursor position
+	 *
+	 * @param newX
+	 * @param newY
+	 */
+	public void updatePosition(int newX, int newY) {
+		oldRX = rX; oldRY = rY;
+		oldWidth = width; oldHeight = height;
+		x = newX; y = newY;
+		rX = x - hotX; rY = y - hotY;
+	}
+
+	/**
+	 * Set new cursor dimensions and hot point position
+	 *
+	 * @param hotX
+	 * @param hotY
+	 * @param width
+	 * @param height
+	 */
+	public void setNewDimensions(int hotX, int hotY, int width,	int height) {
+		this.hotX = hotX;
+		this.hotY = hotY;
+		oldWidth = this.width;
+		oldHeight = this.height;
+		oldRX = rX; oldRY = rY;
+		rX = x - hotX; rY = y - hotY;
+		this.width = width;
+		this.height = height;
+	}
+
+	public void createCursor(int[] cursorPixels, int hotX, int hotY, int width, int height) {
+		createNewCursorImage(cursorPixels, hotX, hotY, width, height);
+		setNewDimensions(hotX, hotY, width, height);
+	}
+
+	protected abstract void createNewCursorImage(int[] cursorPixels, int hotX, int hotY, int width, int height);
+
+    public Object getLock() {
+        return lock;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/AuthenticationFailedException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,46 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Throws when authentication was wrong
+ */
+@SuppressWarnings("serial")
+public class AuthenticationFailedException extends ProtocolException {
+
+	private String reason;
+
+	public AuthenticationFailedException(String message) {
+		super(message);
+	}
+	public AuthenticationFailedException(String message, String reason) {
+		super(message);
+		this.reason = reason;
+	}
+	public String getReason() {
+		return reason;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/ClosedConnectionException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,37 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Throwed when connection closed (EOF)
+ */
+@SuppressWarnings("serial")
+public class ClosedConnectionException extends TransportException {
+
+	public ClosedConnectionException(Throwable exception) {
+		super(exception);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/CommonException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,40 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class CommonException extends Exception {
+
+	public CommonException(Throwable exception) {
+		super(exception);
+	}
+	public CommonException(String message, Throwable exception) {
+		super(message, exception);
+	}
+	public CommonException(String message) {
+		super(message);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/CryptoException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,35 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Throws when problem with DES (or smth else) cryptosystem occured
+ */
+@SuppressWarnings("serial")
+public class CryptoException extends FatalException {
+	public CryptoException(String message, Throwable exception) {
+		super(message, exception);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/FatalException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,35 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Trhows when further normal program execution unavailable
+ */
+@SuppressWarnings("serial")
+public class FatalException extends CommonException {
+	public FatalException(String message, Throwable e) {
+		super(message, e);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/ProtocolException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,32 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class ProtocolException extends CommonException {
+	public ProtocolException(String message) {
+		super(message);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/TransportException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,37 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+
+@SuppressWarnings("serial")
+public class TransportException extends CommonException {
+	public TransportException(String message, Throwable exception) {
+		super(message, exception);
+	}
+	public TransportException(Throwable exception) {
+		super(exception);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/UnsupportedProtocolVersionException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,33 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class UnsupportedProtocolVersionException extends ProtocolException {
+	public UnsupportedProtocolVersionException(String message) {
+		super(message);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/UnsupportedSecurityTypeException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,33 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class UnsupportedSecurityTypeException extends ProtocolException {
+	public UnsupportedSecurityTypeException(String message) {
+		super(message);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/CapabilityContainer.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,107 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Container for Tight extention protocol capabilities
+ *
+ * Needed to set what capabilities we support, which of them supported
+ * by server and for enabling/disabling ops on them.
+ */
+public class CapabilityContainer {
+	public CapabilityContainer() { }
+
+	private final Map<Integer, RfbCapabilityInfo> caps = new HashMap<Integer, RfbCapabilityInfo>();
+
+	public void add(RfbCapabilityInfo capabilityInfo) {
+		caps.put(capabilityInfo.getCode(), capabilityInfo);
+	}
+
+	public void add(int code, String vendor, String name) {
+		caps.put(code, new RfbCapabilityInfo(code, vendor, name));
+	}
+
+	public void addEnabled(int code, String vendor, String name) {
+		RfbCapabilityInfo capability = new RfbCapabilityInfo(code, vendor, name);
+		capability.setEnable(true);
+		caps.put(code, capability);
+	}
+
+	public void setEnable(int id, boolean enable) {
+		RfbCapabilityInfo c = caps.get(id);
+		if (c != null) {
+			c.setEnable(enable);
+		}
+	}
+
+	public void setAllEnable(boolean enable) {
+		for (RfbCapabilityInfo c : caps.values()) {
+			c.setEnable(enable);
+		}
+	}
+
+	public Collection<EncodingType> getEnabledEncodingTypes() {
+		Collection<EncodingType> types = new LinkedList<EncodingType>();
+		for (RfbCapabilityInfo c : caps.values()) {
+			if (c.isEnabled()) {
+				types.add(EncodingType.byId(c.getCode()));
+			}
+		}
+		return types;
+	}
+
+	public void read(Reader reader, int count) throws TransportException {
+		while (count-- > 0) {
+			RfbCapabilityInfo capInfoReceived = new RfbCapabilityInfo(reader);
+			Logger.getLogger("com.glavsoft.rfb").fine(capInfoReceived.toString());
+			RfbCapabilityInfo myCapInfo = caps.get(capInfoReceived.getCode());
+			if (myCapInfo != null) {
+				myCapInfo.setEnable(true);
+			}
+		}
+	}
+
+	public boolean isSupported(int code) {
+		RfbCapabilityInfo myCapInfo = caps.get(code);
+		if (myCapInfo != null)
+			return myCapInfo.isEnabled();
+		return false;
+	}
+
+	public boolean isSupported(RfbCapabilityInfo rfbCapabilityInfo) {
+		return isSupported(rfbCapabilityInfo.getCode());
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/ClipboardController.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,59 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+/**
+ * Interface for handling clipboard texts
+ */
+public interface ClipboardController extends IChangeSettingsListener {
+	void updateSystemClipboard(byte[] bytes);
+
+	/**
+	 * Get text clipboard contens when needed send to remote, or null vise versa
+	 * Implement this method such a way in swing context, because swing's clipboard
+	 * update listener invoked only on DataFlavor changes not content changes.
+	 * Implement as returned null on systems where clipboard listeners work correctly.
+	 *
+	 * @return clipboad string contents if it is changed from last method call
+	 * or null when clipboard contains non text object or clipboard contents didn't changed
+	 */
+	String getRenewedClipboardText();
+
+	/**
+	 * Returns clipboard text content previously retrieved frim system clipboard by
+	 * updateSavedClippoardContent()
+	 *
+	 * @return clipboard text content
+	 */
+	String getClipboardText();
+
+	/**
+	 * Enable/disable clipboard transfer
+	 *
+	 * @param enable
+	 */
+	void setEnabled(boolean enable);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IChangeSettingsListener.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,34 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import com.glavsoft.core.SettingsChangedEvent;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public interface IChangeSettingsListener {
+	void settingsChanged(SettingsChangedEvent event);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IPasswordRetriever.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,29 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+public interface IPasswordRetriever {
+	String getPassword();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IRepaintController.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,42 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Interface for sending repaint event from worker thread to GUI thread
+ */
+public interface IRepaintController extends IChangeSettingsListener {
+	void repaintBitmap(FramebufferUpdateRectangle rect);
+	void repaintBitmap(int x, int y, int width, int height);
+	void repaintCursor();
+	void updateCursorPosition(short x, short y);
+	Renderer createRenderer(Reader reader, int width, int height, PixelFormat pixelFormat);
+	void setPixelFormat(PixelFormat pixelFormat);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IRfbSessionListener.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,39 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+/**
+ * Fires Rfb session [start]-stop events
+ */
+public interface IRfbSessionListener {
+
+	/**
+	 * Fired after rfb session closed (threads stopped, other resources fried).
+	 * Note: this event may be fired from unpredictable thread.
+	 * @param reason reason to show why session closed
+	 */
+	void rfbSessionStopped(String reason);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/RfbCapabilityInfo.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,122 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Structure used to describe protocol options such as tunneling methods,
+ * authentication schemes and message types (protocol versions 3.7t, 3.8t).
+ * typedef struct _rfbCapabilityInfo {
+ *  CARD32 code;                // numeric identifier
+ *  CARD8 vendorSignature[4];   // vendor identification
+ *  CARD8 nameSignature[8];     // abbreviated option name
+ * } rfbCapabilityInfo;
+ */
+public class RfbCapabilityInfo {
+	/*
+	 * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+	 * #define rfbStandardVendor "STDV"
+	 * #define rfbTridiaVncVendor "TRDV"
+	 * #define rfbTightVncVendor "TGHT"
+	 */
+	public static final String VENDOR_STANDARD = "STDV";
+	public static final String VENDOR_TRIADA = "TRDV";
+	public static final String VENDOR_TIGHT = "TGHT";
+
+	public static final String TUNNELING_NO_TUNNELING = "NOTUNNEL";
+
+	public static final String AUTHENTICATION_NO_AUTH = "NOAUTH__";
+	public static final String AUTHENTICATION_VNC_AUTH ="VNCAUTH_";
+
+	public static final String ENCODING_COPYRECT = "COPYRECT";
+	public static final String ENCODING_HEXTILE = "HEXTILE_";
+	public static final String ENCODING_ZLIB = "ZLIB____";
+	public static final String ENCODING_ZRLE = "ZRLE____";
+	public static final String ENCODING_RRE = "RRE_____";
+	public static final String ENCODING_TIGHT = "TIGHT___";
+	// "Pseudo" encoding types
+	public static final String ENCODING_RICH_CURSOR = "RCHCURSR";
+	public static final String ENCODING_CURSOR_POS = "POINTPOS";
+	public static final String ENCODING_DESKTOP_SIZE = "NEWFBSIZ";
+
+	private int code;
+	private String vendorSignature;
+	private String nameSignature;
+	private boolean enable;
+
+	public RfbCapabilityInfo(int code, String vendorSignature, String nameSignature) {
+		this.code = code;
+		this.vendorSignature = vendorSignature;
+		this.nameSignature = nameSignature;
+		enable = true;
+	}
+
+	public RfbCapabilityInfo(Reader reader) throws TransportException {
+		code = reader.readInt32();
+		vendorSignature = reader.readString(4);
+		nameSignature = reader.readString(8);
+	}
+
+	@Override
+	public boolean equals(Object otherObj) {
+		if (this == otherObj) { return true; }
+		if (null == otherObj) { return false; }
+		if (getClass() != otherObj.getClass()) { return false; }
+		RfbCapabilityInfo other = (RfbCapabilityInfo) otherObj;
+		return code == other.code &&
+			vendorSignature.equals(other.vendorSignature) &&
+			nameSignature.equals(other.nameSignature);
+	}
+
+	public void setEnable(boolean enable) {
+		this.enable = enable;
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	public String getVendorSignature() {
+		return vendorSignature;
+	}
+
+	public String getNameSignature() {
+		return nameSignature;
+	}
+
+	public boolean isEnabled() {
+		return enable;
+	}
+
+	@Override
+	public String toString() {
+		return "RfbCapabilityInfo: [code: " + code +
+		", vendor: " + vendorSignature +
+		", name: " + nameSignature +
+		"]";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/ClientCutTextMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,61 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+/**
+ * ClientCutText
+ * The client has new ISO 8859-1 (Latin-1) text in its cut buffer. Ends of lines are repre-
+ * sented by the linefeed / newline character (value 10) alone. No carriage-return (value
+ * 13) is needed. There is currently no way to transfer text outside the Latin-1 character
+ * set.
+ * 1      - U8       - 6
+ * 3      -          - padding
+ * 4      - U32      - length
+ * length - U8 array - text
+ */
+public class ClientCutTextMessage implements ClientToServerMessage {
+	private final byte [] bytes;
+
+	public ClientCutTextMessage(byte[] bytes) {
+		this.bytes = bytes;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.write(CLIENT_CUT_TEXT);
+		writer.writeByte(0); writer.writeInt16(0); // padding
+		writer.write(bytes.length);
+		writer.write(bytes); // TODO: [dime] convert 'text' String to byte arrya using right charset
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "ClientCutTextMessage: [length: " + bytes.length +", text: ...]";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/ClientToServerMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,39 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+public interface ClientToServerMessage {
+	byte SET_PIXEL_FORMAT = 0;
+	byte SET_ENCODINGS = 2;
+	byte FRAMEBUFFER_UPDATE_REQUEST = 3;
+	byte KEY_EVENT = 4;
+	byte POINTER_EVENT = 5;
+	byte CLIENT_CUT_TEXT = 6;
+
+	void send(Writer writer) throws TransportException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/FramebufferUpdateRequestMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,65 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+
+public class FramebufferUpdateRequestMessage implements ClientToServerMessage {
+	private final boolean incremental;
+	private final int height;
+	private final int width;
+	private final int y;
+	private final int x;
+
+	public FramebufferUpdateRequestMessage(int x, int y, int width,
+			int height, boolean incremental) {
+		this.x = x;
+		this.y = y;
+		this.width = width;
+		this.height = height;
+		this.incremental = incremental;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(FRAMEBUFFER_UPDATE_REQUEST);
+		writer.writeByte(incremental ? 1 : 0);
+		writer.writeInt16(x);
+		writer.writeInt16(y);
+		writer.writeInt16(width);
+		writer.writeInt16(height);
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "FramebufferUpdateRequestMessage: [x: " + x + " y: " + y
+		+ " width: " + width + " height: " + height +
+		" incremental: " + incremental + "]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/KeyEventMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,67 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+/**
+ * A key press or release. Down-flag is non-zero (true) if the key is now pressed, zero
+ * (false) if it is now released. The key itself is specified using the “keysym” values
+ * defined by the X Window System.
+ * 1 - U8  - message-type
+ * 1 - U8  - down-flag
+ * 2 - -   - padding
+ * 4 - U32 - key
+ * For most ordinary keys, the “keysym” is the same as the corresponding ASCII value.
+ * For full details, see The Xlib Reference Manual, published by O’Reilly & Associates,
+ * or see the header file <X11/keysymdef.h> from any X Window System installa-
+ * tion.
+ */
+public class KeyEventMessage implements ClientToServerMessage {
+
+	private final int key;
+	private final boolean downFlag;
+
+	public KeyEventMessage(int key, boolean downFlag) {
+		this.downFlag = downFlag;
+		this.key = key;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(KEY_EVENT);
+		writer.writeByte(downFlag ? 1 : 0);
+		writer.writeInt16(0); // padding
+		writer.write(key);
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "[KeyEventMessage: [down-flag: "+downFlag + ", key: " + key +"("+Integer.toHexString(key)+")]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/PointerEventMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,56 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+public class PointerEventMessage implements ClientToServerMessage {
+	private final byte buttonMask;
+	private final short x;
+	private final short y;
+
+	public PointerEventMessage(byte buttonMask, short x, short y) {
+		this.buttonMask = buttonMask;
+		this.x = x;
+		this.y = y;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(POINTER_EVENT);
+		writer.writeByte(buttonMask);
+		writer.writeInt16(x);
+		writer.writeInt16(y);
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "PointerEventMessage: [x: "+ x +", y: "+ y + ", button-mask: " +
+		buttonMask +"]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/SetEncodingsMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,61 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import java.util.Set;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.transport.Writer;
+
+public class SetEncodingsMessage implements ClientToServerMessage {
+	private final Set<EncodingType> encodings;
+
+	public SetEncodingsMessage(Set<EncodingType> set) {
+		this.encodings = set;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(SET_ENCODINGS);
+		writer.writeByte(0); // padding byte
+		writer.writeInt16(encodings.size());
+		for (EncodingType enc : encodings) {
+			writer.writeInt32(enc.getId());
+		}
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("SetEncodingsMessage: [encodings: ");
+		for (EncodingType enc : encodings) {
+			sb.append(enc.name()).append(',');
+		}
+		sb.setLength(sb.length()-1);
+		return sb.append(']').toString();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/SetPixelFormatMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,47 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.transport.Writer;
+
+public class SetPixelFormatMessage implements ClientToServerMessage {
+	private final PixelFormat pixelFormat;
+
+	public SetPixelFormatMessage(PixelFormat pixelFormat) {
+		this.pixelFormat = pixelFormat;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(SET_PIXEL_FORMAT);
+		writer.writeInt16(0);
+		writer.writeByte(0);
+		pixelFormat.send(writer);
+		writer.flush();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/EncodingType.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,147 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding;
+
+import java.util.LinkedHashSet;
+
+/**
+ * Encoding types
+ */
+public enum EncodingType {
+	/**
+	 * Desktop data representes as raw bytes stream
+	 */
+	RAW_ENCODING(0, "Raw"),
+	/**
+	 * Specfies encodings which allow to copy part of image in client's
+	 * framebuffer from one place to another.
+	 */
+	COPY_RECT(1, "CopyRect"),
+	RRE(2, "RRE"),
+	/**
+	 *  Hextile encoding, uses palettes, filling and raw subencoding
+	 */
+    HEXTILE(5, "Hextile"),
+    /**
+     * This encoding is like raw but previously all data compressed with zlib.
+     */
+    ZLIB(6, "ZLib"),
+	/**
+	 * Tight Encoding for slow connection. It is uses raw data, palettes, filling
+	 * and jpeg subencodings
+	 */
+	TIGHT(7, "Tight"),
+    //ZlibHex(8),
+	/**
+	 * ZRLE Encoding is like Hextile but previously all data compressed with zlib.
+	 */
+    ZRLE(16, "ZRLE"),
+
+    /**
+     * Rich Cursor pseudo encoding which allows to transfer cursor shape
+     * with transparency
+     */
+    RICH_CURSOR(0xFFFFFF11, "RichCursor"),
+    /**
+     * Desktop Size Pseudo encoding allows to notificate client about
+     *  remote screen resolution changed.
+     */
+    DESKTOP_SIZE(0xFFFFFF21, "DesctopSize"),
+    /**
+     * Cusros position encoding allows to transfer remote cursor position to
+     * client side.
+     */
+	CURSOR_POS(0xFFFFFF18, "CursorPos"),
+
+	COMPRESS_LEVEL_0(0xFFFFFF00 + 0, "CompressionLevel0"),
+	COMPRESS_LEVEL_1(0xFFFFFF00 + 1, "CompressionLevel1"),
+	COMPRESS_LEVEL_2(0xFFFFFF00 + 2, "CompressionLevel2"),
+	COMPRESS_LEVEL_3(0xFFFFFF00 + 3, "CompressionLevel3"),
+	COMPRESS_LEVEL_4(0xFFFFFF00 + 4, "CompressionLevel4"),
+	COMPRESS_LEVEL_5(0xFFFFFF00 + 5, "CompressionLevel5"),
+	COMPRESS_LEVEL_6(0xFFFFFF00 + 6, "CompressionLevel6"),
+	COMPRESS_LEVEL_7(0xFFFFFF00 + 7, "CompressionLevel7"),
+	COMPRESS_LEVEL_8(0xFFFFFF00 + 8, "CompressionLevel8"),
+	COMPRESS_LEVEL_9(0xFFFFFF00 + 9, "CompressionLevel9"),
+
+	JPEG_QUALITY_LEVEL_0(0xFFFFFFE0 + 0, "JpegQualityLevel0"),
+	JPEG_QUALITY_LEVEL_1(0xFFFFFFE0 + 1, "JpegQualityLevel1"),
+	JPEG_QUALITY_LEVEL_2(0xFFFFFFE0 + 2, "JpegQualityLevel2"),
+	JPEG_QUALITY_LEVEL_3(0xFFFFFFE0 + 3, "JpegQualityLevel3"),
+	JPEG_QUALITY_LEVEL_4(0xFFFFFFE0 + 4, "JpegQualityLevel4"),
+	JPEG_QUALITY_LEVEL_5(0xFFFFFFE0 + 5, "JpegQualityLevel5"),
+	JPEG_QUALITY_LEVEL_6(0xFFFFFFE0 + 6, "JpegQualityLevel6"),
+	JPEG_QUALITY_LEVEL_7(0xFFFFFFE0 + 7, "JpegQualityLevel7"),
+	JPEG_QUALITY_LEVEL_8(0xFFFFFFE0 + 8, "JpegQualityLevel8"),
+	JPEG_QUALITY_LEVEL_9(0xFFFFFFE0 + 9, "JpegQualityLevel9");
+
+	private int id;
+	private final String name;
+	private EncodingType(int id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public int getId() {
+		return id;
+	}
+	public String getName() {
+		return name;
+	}
+
+	public static LinkedHashSet<EncodingType> ordinaryEncodings = new LinkedHashSet<EncodingType>();
+	static {
+		ordinaryEncodings.add(TIGHT);
+		ordinaryEncodings.add(HEXTILE);
+		ordinaryEncodings.add(ZRLE);
+		ordinaryEncodings.add(ZLIB);
+		ordinaryEncodings.add(RRE);
+		ordinaryEncodings.add(COPY_RECT);
+//		ordinaryEncodings.add(RAW_ENCODING);
+	}
+
+	public static LinkedHashSet<EncodingType> pseudoEncodings = new LinkedHashSet<EncodingType>();
+	static {
+		pseudoEncodings.add(RICH_CURSOR);
+		pseudoEncodings.add(CURSOR_POS);
+		pseudoEncodings.add(DESKTOP_SIZE);
+	}
+
+	public static LinkedHashSet<EncodingType> compressionEncodings = new LinkedHashSet<EncodingType>();
+	static {
+		compressionEncodings.add(COMPRESS_LEVEL_0);
+		compressionEncodings.add(JPEG_QUALITY_LEVEL_0);
+	}
+
+	public static EncodingType byId(int id) {
+		// TODO needs to speedup with hash usage?
+		for (EncodingType type : values()) {
+			if (type.getId() == id)
+				return type;
+		}
+		throw new IllegalArgumentException("Unsupported encoding id: " + id);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/PixelFormat.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,187 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+/**
+ * Pixel Format:
+ * 1 - U8  - bits-per-pixel
+ * 1 - U8  - depth
+ * 1 - U8  - big-endian-flag
+ * 1 - U8  - true-color-flag
+ * 2 - U16 - red-max
+ * 2 - U16 - green-max
+ * 2 - U16 - blue-max
+ * 1 - U8  - red-shift
+ * 1 - U8  - green-shift
+ * 1 - U8  - blue-shift
+ * 3 -     - padding
+ */
+public class PixelFormat {
+	public byte bitsPerPixel;
+	public byte depth;
+	public byte bigEndianFlag;
+	public byte trueColourFlag;
+	public short redMax;
+	public short greenMax;
+	public short blueMax;
+	public byte redShift;
+	public byte greenShift;
+	public byte blueShift;
+
+	public void fill(Reader reader) throws TransportException {
+		bitsPerPixel = reader.readByte();
+		depth = reader.readByte();
+	    bigEndianFlag = reader.readByte();
+	    trueColourFlag = reader.readByte();
+	    redMax = reader.readInt16();
+	    greenMax = reader.readInt16();
+	    blueMax = reader.readInt16();
+	    redShift = reader.readByte();
+	    greenShift = reader.readByte();
+	    blueShift = reader.readByte();
+	    reader.readBytes(3); // skip padding bytes
+	}
+
+    public void send(Writer writer) throws TransportException {
+    	writer.write(bitsPerPixel);
+    	writer.write(depth);
+    	writer.write(bigEndianFlag);
+    	writer.write(trueColourFlag);
+    	writer.write(redMax);
+    	writer.write(greenMax);
+    	writer.write(blueMax);
+    	writer.write(redShift);
+    	writer.write(greenShift);
+    	writer.write(blueShift);
+    	writer.writeInt16(0); // padding bytes
+    	writer.writeByte(0); // padding bytes
+    }
+
+    public static PixelFormat create24bitColorDepthPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 32;
+		pixelFormat.blueMax = 255;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 255;
+		pixelFormat.greenShift = 8;
+		pixelFormat.redMax = 255;
+		pixelFormat.redShift = 16;
+		pixelFormat.depth = 24;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 65536 colors, 5bit per Red, 6bit per Green, 5bit per Blue
+     */
+    public static PixelFormat create16bitColorDepthPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 16;
+		pixelFormat.blueMax = 31;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 63;
+		pixelFormat.greenShift = 5;
+		pixelFormat.redMax = 31;
+		pixelFormat.redShift = 11;
+		pixelFormat.depth = 16;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 256 colors, 2bit per Blue, 3bit per Green & Red
+     */
+    public static PixelFormat create8bitColorDepthBGRPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 8;
+		pixelFormat.redMax = 7;
+		pixelFormat.redShift = 0;
+		pixelFormat.greenMax = 7;
+		pixelFormat.greenShift = 3;
+		pixelFormat.blueMax = 3;
+		pixelFormat.blueShift = 6;
+		pixelFormat.depth = 8;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 64 colors, 2bit per Red, Green & Blue
+     */
+    public static PixelFormat create6bitColorDepthPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 8;
+		pixelFormat.blueMax = 3;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 3;
+		pixelFormat.greenShift = 2;
+		pixelFormat.redMax = 3;
+		pixelFormat.redShift = 4;
+		pixelFormat.depth = 6;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 8 colors, 1bit per Red, Green & Blue
+     */
+    public static PixelFormat create3bppPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 8;
+		pixelFormat.blueMax = 1;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 1;
+		pixelFormat.greenShift = 1;
+		pixelFormat.redMax = 1;
+		pixelFormat.redShift = 2;
+		pixelFormat.depth = 3;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    @Override
+    public String toString() {
+    	return "PixelFormat: [bits-per-pixel: " + String.valueOf(0xff & bitsPerPixel) +
+    	", depth: " + String.valueOf(0xff & depth) +
+    	", big-endian-flag: " + String.valueOf(0xff & bigEndianFlag) +
+    	", true-color-flag: " + String.valueOf(0xff & trueColourFlag) +
+    	", red-max: " + String.valueOf(0xffff & redMax) +
+    	", green-max: " + String.valueOf(0xffff & greenMax) +
+    	", blue-max: " + String.valueOf(0xffff & blueMax) +
+    	", red-shift: " + String.valueOf(0xff & redShift) +
+    	", green-shift: " + String.valueOf(0xff & greenShift) +
+    	", blue-shift: " + String.valueOf(0xff & blueShift) +
+    	"]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/ServerInitMessage.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,80 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Struct filled from the ServerInit message
+ * 2  - U16         - framebuffer-width
+ * 2  - U16         - framebuffer-height
+ * 16 - PixelFormat - server-pixel-format
+ * 4  - U32         - name-length
+ * name-length - U8 array - name-string
+ */
+public class ServerInitMessage {
+	protected int frameBufferWidth;
+    protected int frameBufferHeight;
+    protected PixelFormat pixelFormat;
+    protected String name;
+
+	public ServerInitMessage(Reader reader) throws TransportException {
+		frameBufferWidth = reader.readUInt16();
+		frameBufferHeight = reader.readUInt16();
+		pixelFormat = new PixelFormat();
+		pixelFormat.fill(reader);
+		name = reader.readString();
+	}
+
+	protected ServerInitMessage() {
+		// empty
+	}
+
+	public int getFrameBufferWidth() {
+		return frameBufferWidth;
+	}
+
+	public int getFrameBufferHeight() {
+		return frameBufferHeight;
+	}
+
+	public PixelFormat getPixelFormat() {
+		return pixelFormat;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+    @Override
+    public String toString() {
+    	return "ServerInitMessage: [name: "+ name +
+    	", framebuffer-width: " + String.valueOf(frameBufferWidth) +
+    	", framebuffer-height: " + String.valueOf(frameBufferHeight) +
+    	", server-pixel-format: " + pixelFormat +
+    	"]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ByteBuffer.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,58 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+/**
+ * Resizeable to needed length byte buffer
+ * Singleton for share among decoders.
+ */
+public class ByteBuffer {
+	private static ByteBuffer instance = new ByteBuffer();
+	private byte [] buffer = new byte[0];
+
+	private ByteBuffer() { /*empty*/ }
+	public static ByteBuffer getInstance() {
+		return instance;
+	}
+
+	/**
+	 * Checks for buffer capacity is enougth ( < length) and enlarge it if not
+	 *
+	 * @param length
+	 */
+	public void correctBufferCapacity(int length) {
+		// procondition: buffer != null
+		assert (buffer != null);
+		if (buffer.length < length) {
+			buffer = new byte[length];
+		}
+	}
+
+	public byte[] getBuffer(int length) {
+		correctBufferCapacity(length);
+		return buffer;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/CopyRectDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,42 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class CopyRectDecoder extends Decoder {
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int srcX = reader.readUInt16();
+		int srcY = reader.readUInt16();
+		if (rect.width == 0  || rect.height == 0) return;
+		renderer.copyRect(srcX, srcY, rect);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/Decoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,45 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+
+public abstract class Decoder {
+
+	/**
+	 * Decode rectangle data.
+	 */
+	abstract public void decode(Reader reader, Renderer renderer,
+    		FramebufferUpdateRectangle rect) throws TransportException;
+
+	/**
+	 * Reset decoder when needed. Ex. reset ZLib stream inflaters for Z* and Tight decoders.
+	 */
+    public void reset() { /*empty*/ }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/DecodersContainer.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,93 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.rfb.encoding.EncodingType;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * Decoders container class
+ */
+public class DecodersContainer {
+	private static Map<EncodingType, Class<? extends Decoder>> knownDecoders =
+		new HashMap<EncodingType, Class<? extends Decoder>>();
+	static {
+		knownDecoders.put(EncodingType.TIGHT, TightDecoder.class);
+		knownDecoders.put(EncodingType.HEXTILE, HextileDecoder.class);
+		knownDecoders.put(EncodingType.ZRLE, ZRLEDecoder.class);
+		knownDecoders.put(EncodingType.ZLIB, ZlibDecoder.class);
+		knownDecoders.put(EncodingType.RRE, RREDecoder.class);
+		knownDecoders.put(EncodingType.COPY_RECT, CopyRectDecoder.class);
+//		knownDecoders.put(EncodingType.RAW_ENCODING, RawDecoder.class);
+	}
+	private final Map<EncodingType, Decoder> decoders =
+		new HashMap<EncodingType, Decoder>();
+
+	public DecodersContainer() {
+		decoders.put(EncodingType.RAW_ENCODING, RawDecoder.getInstance());
+	}
+
+	/**
+	 * Instantiate decoders for encodings we are going to use.
+	 *
+	 * @param encodings encodings we need to handle
+	 */
+	public void instantiateDecodersWhenNeeded(Collection<EncodingType> encodings) {
+		for (EncodingType enc : encodings) {
+			if (EncodingType.ordinaryEncodings.contains(enc) && ! decoders.containsKey(enc)) {
+				try {
+					decoders.put(enc, knownDecoders.get(enc).newInstance());
+				} catch (InstantiationException e) {
+					logError(enc, e);
+				} catch (IllegalAccessException e) {
+					logError(enc, e);
+				}
+			}
+		}
+	}
+
+	private void logError(EncodingType enc, Exception e) {
+		Logger.getLogger(this.getClass().getName()).severe("Can not instantiate decoder for encoding type '" +
+				enc.getName() + "' " + e.getMessage());
+	}
+
+	public Decoder getDecoderByType(EncodingType type) {
+		return decoders.get(type);
+	}
+
+	public void resetDecoders() {
+		for (Decoder decoder : decoders.values()) {
+			if (decoder != null) {
+				decoder.reset();
+			}
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/FramebufferUpdateRectangle.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,77 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Header for framebuffer-update-rectangle header server message
+ * 2 - U16 - x-position
+ * 2 - U16 - y-position
+ * 2 - U16 - width
+ * 2 - U16 - height
+ * 4 - S32 - encoding-type
+ * and then follows the pixel data in the specified encoding
+ */
+public class FramebufferUpdateRectangle {
+	public int x;
+	public int y;
+	public int width;
+	public int height;
+    private EncodingType encodingType;
+
+	public FramebufferUpdateRectangle() {
+		// nop
+	}
+
+	public FramebufferUpdateRectangle(int x, int y, int w, int h) {
+		this.x = x; this.y = y;
+		width = w; height = h;
+	}
+
+	public void fill(Reader reader) throws TransportException {
+    	x = reader.readUInt16();
+        y = reader.readUInt16();
+        width = reader.readUInt16();
+        height = reader.readUInt16();
+        int encoding = reader.readInt32();
+		encodingType = EncodingType.byId(encoding);
+    }
+
+	public EncodingType getEncodingType() {
+		return encodingType;
+	}
+
+	@Override
+	public String toString() {
+		return "FramebufferUpdateRect: [x: " + x + ", y: " + y +
+			", width: " + width + ", height: " + height +
+			", encodingType: " + encodingType +
+			"]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/HextileDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,110 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+
+public class HextileDecoder extends Decoder {
+	private static final int DEFAULT_TILE_SIZE = 16;
+	private static final int RAW_MASK = 1;
+	private static final int BACKGROUND_SPECIFIED_MASK = 2;
+	private static final int FOREGROUND_SPECIFIED_MASK = 4;
+	private static final int ANY_SUBRECTS_MASK = 8;
+	private static final int SUBRECTS_COLOURED_MASK = 16;
+	private static final int FG_COLOR_INDEX = 0;
+	private static final int BG_COLOR_INDEX = 1;
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		if (rect.width == 0  || rect.height == 0) return;
+		int[] colors = new int[] {-1, -1};
+		int maxX = rect.x + rect.width;
+		int maxY = rect.y + rect.height;
+		for (int tileY = rect.y; tileY < maxY;
+		tileY += DEFAULT_TILE_SIZE) {
+			int tileHeight = Math.min(maxY - tileY, DEFAULT_TILE_SIZE);
+			for (int tileX = rect.x; tileX < maxX;
+			tileX += DEFAULT_TILE_SIZE) {
+				int tileWidth = Math.min(maxX - tileX, DEFAULT_TILE_SIZE);
+				decodeHextileSubrectangle(reader, renderer, colors, tileX,
+						tileY, tileWidth, tileHeight);
+			}
+		}
+
+	}
+
+	private void decodeHextileSubrectangle(Reader reader,
+			Renderer renderer, int[] colors,
+			int tileX, int tileY, int tileWidth, int tileHeight)
+			throws TransportException {
+
+		int subencoding = reader.readUInt8();
+
+		if ((subencoding & RAW_MASK) != 0) {
+			RawDecoder.getInstance().decode(reader, renderer,
+					tileX, tileY, tileWidth, tileHeight);
+			return;
+		}
+
+		if ((subencoding & BACKGROUND_SPECIFIED_MASK) != 0) {
+			colors[BG_COLOR_INDEX] = renderer.readPixelColor(reader);
+		}
+		assert colors[BG_COLOR_INDEX] != -1;
+		renderer.fillRect(colors[BG_COLOR_INDEX],
+				tileX, tileY, tileWidth, tileHeight);
+
+		if ((subencoding & FOREGROUND_SPECIFIED_MASK) != 0) {
+			colors[FG_COLOR_INDEX] = renderer.readPixelColor(reader);
+		}
+
+		if ((subencoding & ANY_SUBRECTS_MASK) == 0)
+			return;
+
+		int numberOfSubrectangles = reader.readUInt8();
+		boolean colorSpecified =
+			(subencoding & SUBRECTS_COLOURED_MASK) != 0;
+		for (int i = 0; i < numberOfSubrectangles; ++i) {
+			if (colorSpecified) {
+				colors[FG_COLOR_INDEX] = renderer.readPixelColor(reader);
+			}
+			byte dimensions = reader.readByte(); // bits 7-4 for x, bits 3-0 for y
+			int subtileX = dimensions >> 4 & 0x0f;
+			int subtileY = dimensions & 0x0f;
+			dimensions = reader.readByte(); // bits 7-4 for w, bits 3-0 for h
+			int subtileWidth = 1 + (dimensions >> 4 & 0x0f);
+			int subtileHeight = 1 + (dimensions & 0x0f);
+			assert colors[FG_COLOR_INDEX] != -1;
+			renderer.fillRect(colors[FG_COLOR_INDEX],
+					tileX + subtileX, tileY + subtileY,
+					subtileWidth, subtileHeight);
+		}
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/RREDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,50 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class RREDecoder extends Decoder {
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int numOfSubrectangles = reader.readInt32();
+		int color = renderer.readPixelColor(reader);
+		renderer.fillRect(color, rect);
+		for (int i = 0; i < numOfSubrectangles; ++i) {
+			color = renderer.readPixelColor(reader);
+			int x = reader.readUInt16();
+			int y = reader.readUInt16();
+			int width = reader.readUInt16();
+			int height = reader.readUInt16();
+			renderer.fillRect(color, rect.x + x, rect.y + y, width, height);
+		}
+
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/RawDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,52 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class RawDecoder extends Decoder {
+	private static RawDecoder instance = new RawDecoder();
+	public static RawDecoder getInstance() {
+		return instance;
+	}
+	private RawDecoder() { /*empty*/ }
+
+	@Override
+	public void decode(Reader reader,
+			Renderer renderer, FramebufferUpdateRectangle rect) throws TransportException {
+		decode(reader, renderer, rect.x, rect.y, rect.width, rect.height);
+	}
+
+	public void decode(Reader reader, Renderer renderer, int x, int y,
+			int width, int height) throws TransportException {
+		int length = width * height * renderer.getBytesPerPixel();
+		byte [] bytes = ByteBuffer.getInstance().getBuffer(length);
+		reader.readBytes(bytes, 0, length);
+		renderer.drawBytes(bytes, x, y, width, height);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/RichCursorDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,81 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Decoder for RichCursor pseudo encoding
+ */
+public class RichCursorDecoder extends Decoder {
+	private static RichCursorDecoder instance = new RichCursorDecoder();
+
+	private RichCursorDecoder() { /*empty*/ }
+
+	public static RichCursorDecoder getInstance() {
+		return instance;
+	}
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int bytesPerPixel = renderer.getBytesPerPixel();
+		int length = rect.width * rect.height * bytesPerPixel;
+		if (0 == length)
+			return;
+		byte[] buffer = ByteBuffer.getInstance().getBuffer(length);
+		reader.readBytes(buffer, 0, length);
+
+		StringBuilder sb = new StringBuilder(" ");
+		for (int i=0; i<length; ++i) {
+			sb.append(Integer.toHexString(buffer[i]&0xff)).append(" ");
+		}
+		int scanLine = (int) Math.floor((rect.width + 7) / 8);
+		byte[] bitmask = new byte[scanLine * rect.height];
+		reader.readBytes(bitmask, 0, bitmask.length);
+
+		sb = new StringBuilder(" ");
+		for (int i=0; i<bitmask.length; ++i) {
+			sb.append(Integer.toHexString(bitmask[i]&0xff)).append(" ");
+		}
+		int[] cursorPixels = new int[rect.width * rect.height];
+		for (int y = 0; y < rect.height; ++y) {
+			for (int x = 0; x < rect.width; ++x) {
+				int offset = y * rect.width + x;
+				cursorPixels[offset] = isBitSet(bitmask[y * scanLine + x / 8], x % 8) ?
+					0xFF000000 | renderer.getPixelColor(buffer, offset * bytesPerPixel) :
+					0; // transparent
+			}
+		}
+		renderer.createCursor(cursorPixels, rect);
+	}
+
+	private boolean isBitSet(byte aByte, int index) {
+		return (aByte & 1 << 7 - index) > 0;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/TightDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,292 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.ColorDecoder;
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+import java.util.logging.Logger;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+/**
+ * Tight protocol extention decoder
+ */
+public class TightDecoder extends Decoder {
+	private static Logger logger = Logger.getLogger("com.glavsoft.rfb.encoding.decoder");
+
+    private static final int FILL_TYPE = 0x08;
+    private static final int JPEG_TYPE = 0x09;
+
+    private static final int FILTER_ID_MASK = 0x40;
+    private static final int STREAM_ID_MASK = 0x30;
+
+    private static final int BASIC_FILTER = 0x00;
+    private static final int PALETTE_FILTER = 0x01;
+    private static final int GRADIENT_FILTER = 0x02;
+    private static final int MIN_SIZE_TO_COMPRESS = 12;
+
+    static final int DECODERS_NUM = 4;
+	Inflater[] decoders;
+
+    private int decoderId;
+    private int[] palette;
+
+    public TightDecoder() {
+		reset();
+	}
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int bytesPerPixel = renderer.getBytesPerPixelTight();
+
+		/**
+		 * bits
+		 * 7 - FILL or JPEG type
+		 * 6 - filter presence flag
+		 * 5, 4 - decoder to use when Basic type (bit 7 not set)
+		 *    or
+		 * 4 - JPEG type when set bit 7
+		 * 3 - reset decoder #3
+		 * 2 - reset decoder #2
+		 * 1 - reset decoder #1
+		 * 0 - reset decoder #0
+		 */
+		int compControl = reader.readUInt8();
+		resetDecoders(compControl);
+
+		int compType = compControl >> 4 & 0x0F;
+		switch (compType) {
+		case FILL_TYPE:
+			int color = renderer.readTightPixelColor(reader);
+			renderer.fillRect(color, rect);
+			break;
+		case JPEG_TYPE:
+            assert 3 == bytesPerPixel : "Tight doesn't support JPEG subencoding while depth not equal to 24bpp is used";
+			processJpegType(reader, renderer, rect);
+			break;
+		default:
+			assert compType <= JPEG_TYPE : "Compression control byte is incorrect!";
+			processBasicType(compControl, reader, renderer, rect);
+		}
+	}
+
+	private void processBasicType(int compControl, Reader reader,
+			Renderer renderer, FramebufferUpdateRectangle rect) throws TransportException {
+		decoderId = (compControl & STREAM_ID_MASK) >> 4;
+
+		int filterId = 0;
+		if ((compControl & FILTER_ID_MASK) > 0) { // filter byte presence
+			filterId = reader.readUInt8();
+		}
+		int bytesPerCPixel = renderer.getBytesPerPixelTight();
+		int lengthCurrentbpp = bytesPerCPixel * rect.width * rect.height;
+		byte [] buffer;
+		switch (filterId) {
+		case BASIC_FILTER:
+			buffer = readTightData(lengthCurrentbpp, reader);
+			renderer.drawTightBytes(buffer, 0, rect.x, rect.y, rect.width, rect.height);
+			break;
+		case PALETTE_FILTER:
+			int paletteSize = reader.readUInt8() + 1;
+            completePalette(paletteSize, reader, renderer);
+			int dataLength = paletteSize == 2 ?
+				rect.height * ((rect.width + 7) / 8) :
+				rect.width * rect.height;
+			buffer = readTightData(dataLength, reader);
+			renderer.drawBytesWithPalette(buffer, rect, palette, paletteSize);
+			break;
+		case GRADIENT_FILTER:
+/*
+ * The "gradient" filter pre-processes pixel data with a simple algorithm
+ * which converts each color component to a difference between a "predicted"
+ * intensity and the actual intensity. Such a technique does not affect
+ * uncompressed data size, but helps to compress photo-like images better.
+ * Pseudo-code for converting intensities to differences is the following:
+ *
+ * 	P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
+ * 	if (P[i,j] < 0) then P[i,j] := 0;
+ * 	if (P[i,j] > MAX) then P[i,j] := MAX;
+ * 	D[i,j] := V[i,j] - P[i,j];
+ *
+ * Here V[i,j] is the intensity of a color component for a pixel at
+ * coordinates (i,j). MAX is the maximum value of intensity for a color
+ * component.*/
+			buffer = readTightData(bytesPerCPixel * rect.width * rect.height, reader);
+			byte [][] opRows = new byte[2][rect.width * 3 + 3];
+			int opRowIndex = 0;
+			byte [] components = new byte[3];
+			int pixelOffset = 0;
+			ColorDecoder colorDecoder = renderer.getColorDecoder();
+			for (int i = 0; i < rect.height; ++i) {
+				// exchange thisRow and prevRow:
+				byte [] thisRow = opRows[opRowIndex];
+				byte [] prevRow = opRows[opRowIndex = (opRowIndex + 1) % 2];
+				for (int j = 3; j < rect.width * 3 + 3; j += 3) {
+					colorDecoder.fillRawComponents(components, buffer, pixelOffset);
+					pixelOffset += bytesPerCPixel;
+					int
+					d = (0xff & prevRow[j + 0]) + // "upper" pixel (from prev row)
+						(0xff & thisRow[j + 0 - 3]) - // prev pixel
+						(0xff & prevRow[j + 0 - 3]); // "diagonal" prev pixel
+					thisRow[j + 0] = (byte) (components[0] + (d < 0 ? 0 : d > colorDecoder.redMax ? colorDecoder.redMax: d) & colorDecoder.redMax);
+					d = (0xff & prevRow[j + 1]) +
+						(0xff & thisRow[j + 1 - 3]) -
+						(0xff & prevRow[j + 1 - 3]);
+					thisRow[j + 1] = (byte) (components[1] + (d < 0 ? 0 : d > colorDecoder.greenMax ? colorDecoder.greenMax: d) & colorDecoder.greenMax);
+					d = (0xff & prevRow[j + 2]) +
+						(0xff & thisRow[j + 2 - 3]) -
+						(0xff & prevRow[j + 2 - 3]);
+					thisRow[j + 2] = (byte) (components[2] + (d < 0 ? 0 : d > colorDecoder.blueMax ? colorDecoder.blueMax: d) & colorDecoder.blueMax);
+				}
+				renderer.drawUncaliberedRGBLine(thisRow, rect.x, rect.y + i, rect.width);
+			}
+
+			break;
+		default:
+			break;
+		}
+	}
+
+	/**
+	 * Complete palette from reader
+	 */
+	private void completePalette(int paletteSize, Reader reader, Renderer renderer) throws TransportException {
+		/**
+		 * When bytesPerPixel == 1 && paletteSize == 2 read 2 bytes of palette
+		 * When bytesPerPixel == 1 && paletteSize != 2 - error
+		 * When bytesPerPixel == 3 (4) read (paletteSize * 3) bytes of palette
+		 * so use renderer.readPixelColor
+		 */
+        if (null == palette) palette = new int[256];
+		for (int i = 0; i < paletteSize; ++i) {
+			palette[i] = renderer.readTightPixelColor(reader);
+		}
+	}
+
+	/**
+	 * Reads compressed (expected length >= MIN_SIZE_TO_COMPRESS) or
+	 * uncompressed data. When compressed decompresses it.
+	 *
+	 * @param expectedLength expected data length in bytes
+	 * @param reader data source
+	 * @return result data
+	 * @throws TransportException
+	 */
+	private byte[] readTightData(int expectedLength, Reader reader) throws TransportException {
+		if (expectedLength < MIN_SIZE_TO_COMPRESS) {
+			byte [] buffer = ByteBuffer.getInstance().getBuffer(expectedLength);
+			reader.readBytes(buffer, 0, expectedLength);
+			return buffer;
+		} else
+			return readCompressedData(expectedLength, reader);
+	}
+
+	/**
+	 * Reads compressed data length, then read compressed data into rawBuffer
+     * and decompress data with expected length == length
+     *
+     * Note: returned data contains not only decompressed data but raw data at array tail
+     * which need to be ignored. Use only first expectedLength bytes.
+     *
+	 * @param expectedLength expected data length
+	 * @param reader data source
+	 * @return decompressed data (length == expectedLength) / + followed raw data (ignore, please)
+	 * @throws TransportException
+	 */
+	private byte[] readCompressedData(int expectedLength, Reader reader) throws TransportException {
+		int rawDataLength = readCompactSize(reader);
+
+		byte [] buffer = ByteBuffer.getInstance().getBuffer(expectedLength + rawDataLength);
+		// read compressed (raw) data behind space allocated for decompressed data
+		reader.readBytes(buffer, expectedLength, rawDataLength);
+		if (null == decoders[decoderId]) {
+			decoders[decoderId] = new Inflater();
+		}
+		Inflater decoder = decoders[decoderId];
+		decoder.setInput(buffer, expectedLength, rawDataLength);
+		try {
+			decoder.inflate(buffer, 0, expectedLength);
+		} catch (DataFormatException e) {
+			logger.throwing("TightDecoder", "readCompressedData", e);
+			throw new TransportException("cannot inflate tight compressed data", e);
+		}
+		return buffer;
+	}
+
+	private void processJpegType(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int jpegBufferLength = readCompactSize(reader);
+		byte [] bytes = ByteBuffer.getInstance().getBuffer(jpegBufferLength);
+		reader.readBytes(bytes, 0, jpegBufferLength);
+		renderer.drawJpegImage(bytes, 0, jpegBufferLength, rect);
+	}
+
+	/**
+	 * Read an integer from reader in compact representation (from 1 to 3 bytes).
+	 * Highest bit of read byte set to 1 means next byte contains data.
+	 * Lower 7 bit of each byte contains significant data. Max bytes = 3.
+	 * Less significant bytes first order.
+	 *
+	 * @param reader data source
+	 * @return int value
+	 * @throws TransportException
+	 */
+	private int readCompactSize(Reader reader) throws TransportException {
+		int b = reader.readUInt8();
+		int size = b & 0x7F;
+		if ((b & 0x80) != 0) {
+			b = reader.readUInt8();
+			size += (b & 0x7F) << 7;
+			if ((b & 0x80) != 0) {
+				size += reader.readUInt8() << 14;
+			}
+		}
+		return size;
+	}
+
+	/**
+	 * Flush (reset) zlib decoders when bits 3, 2, 1, 0 of compControl is set
+	 * @param compControl control flags
+	 */
+	private void resetDecoders(int compControl) {
+		for (int i=0; i < DECODERS_NUM; ++i) {
+			if ((compControl & 1) != 0 && decoders[i] != null) {
+				decoders[i].reset();
+			}
+			compControl >>= 1;
+		}
+
+	}
+
+	@Override
+	public void reset() {
+		decoders = new Inflater[DECODERS_NUM];
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,167 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class ZRLEDecoder extends ZlibDecoder {
+	private static final int MAX_TILE_SIZE = 64;
+    private int[] decodedBitmap;
+    private int[] palette;
+
+    @Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int zippedLength = (int) reader.readUInt32();
+		if (0 == zippedLength) return;
+		int length = rect.width * rect.height * renderer.getBytesPerPixel();
+		byte[] bytes = unzip(reader, zippedLength, length);
+		int offset = zippedLength;
+		int maxX = rect.x + rect.width;
+		int maxY = rect.y + rect.height;
+        if (null == palette) {
+            palette = new int [128];
+        }
+        if (null == decodedBitmap) {
+            decodedBitmap = new int[MAX_TILE_SIZE * MAX_TILE_SIZE];
+        }
+		for (int tileY = rect.y; tileY < maxY; tileY += MAX_TILE_SIZE) {
+			int tileHeight = Math.min(maxY - tileY, MAX_TILE_SIZE);
+
+			for (int tileX = rect.x; tileX < maxX; tileX += MAX_TILE_SIZE) {
+				int tileWidth = Math.min(maxX - tileX, MAX_TILE_SIZE);
+				int subencoding = bytes[offset++] & 0x0ff;
+				// 128 -plain RLE, 130-255 - Palette RLE
+				boolean isRle = (subencoding & 128) != 0;
+				// 2 to 16 for raw packed palette data, 130 to 255 for Palette RLE (subencoding - 128)
+				int paletteSize = subencoding & 127;
+				offset += readPalette(bytes, offset, renderer, paletteSize);
+				if (1 == subencoding) { // A solid tile consisting of a single colour
+					renderer.fillRect(palette[0], tileX, tileY, tileWidth, tileHeight);
+					continue;
+				}
+				if (isRle) {
+					if (0 == paletteSize) { // subencoding == 128 (or paletteSize == 0) - Plain RLE
+						offset += decodePlainRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+					} else {
+						offset += decodePaletteRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+					}
+				} else {
+					if (0 == paletteSize) { // subencoding == 0 (or paletteSize == 0) - raw CPIXEL data
+						offset += decodeRaw(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+					} else {
+						offset += decodePacked(bytes, offset, renderer, paletteSize, tileX, tileY, tileWidth, tileHeight);
+					}
+				}
+			}
+		}
+	}
+
+	private int decodePlainRle(byte[] bytes, int offset, Renderer renderer,
+			int tileX, int tileY, int tileWidth, int tileHeight) {
+		int bytesPerCPixel = renderer.getBytesPerCPixel();
+		int decodedOffset = 0;
+		int decodedEnd = tileWidth * tileHeight;
+		int index = offset;
+		while (decodedOffset < decodedEnd) {
+			int color = renderer.getCompactPixelColor(bytes, index);
+			index += bytesPerCPixel;
+			int rlength = 1;
+			do {
+				rlength += bytes[index] & 0x0ff;
+			} while ((bytes[index++] & 0x0ff) == 255);
+			assert rlength <= decodedEnd - decodedOffset;
+			renderer.fillColorBitmapWithColor(decodedBitmap, decodedOffset, rlength, color);
+			decodedOffset += rlength;
+		}
+		renderer.drawColoredBitmap(decodedBitmap, tileX, tileY, tileWidth, tileHeight);
+		return index - offset;
+	}
+
+	private int decodePaletteRle(byte[] bytes, int offset, Renderer renderer,
+                                 int tileX, int tileY, int tileWidth, int tileHeight) {
+		int decodedOffset = 0;
+		int decodedEnd = tileWidth * tileHeight;
+		int index = offset;
+		while (decodedOffset < decodedEnd) {
+			int colorIndex = bytes[index++];
+			int color = palette[colorIndex & 127];
+			int rlength = 1;
+			if ((colorIndex & 128) != 0) {
+				do {
+					rlength += bytes[index] & 0x0ff;
+				} while (bytes[index++] == (byte) 255);
+			}
+			assert rlength <= decodedEnd - decodedOffset;
+			renderer.fillColorBitmapWithColor(decodedBitmap, decodedOffset, rlength, color);
+			decodedOffset += rlength;
+		}
+		renderer.drawColoredBitmap(decodedBitmap, tileX, tileY, tileWidth, tileHeight);
+		return index - offset;
+	}
+
+	private int decodePacked(byte[] bytes, int offset, Renderer renderer,
+                             int paletteSize, int tileX, int tileY, int tileWidth, int tileHeight) {
+		int bitsPerPalletedPixel = paletteSize > 16 ? 8 : paletteSize > 4 ? 4
+				: paletteSize > 2 ? 2 : 1;
+		int packedOffset = offset;
+		int decodedOffset = 0;
+		for (int i = 0; i < tileHeight; ++i) {
+			int decodedRowEnd = decodedOffset + tileWidth;
+			int byteProcessed = 0;
+			int bitsRemain = 0;
+
+			while (decodedOffset < decodedRowEnd) {
+				if (bitsRemain == 0) {
+					byteProcessed = bytes[packedOffset++];
+					bitsRemain = 8;
+				}
+				bitsRemain -= bitsPerPalletedPixel;
+				int index = byteProcessed >> bitsRemain & (1 << bitsPerPalletedPixel) - 1 & 127;
+				int color = palette[index];
+				renderer.fillColorBitmapWithColor(decodedBitmap, decodedOffset, 1, color);
+				++decodedOffset;
+			}
+		}
+		renderer.drawColoredBitmap(decodedBitmap, tileX, tileY, tileWidth, tileHeight);
+		return packedOffset - offset;
+	}
+
+	private int decodeRaw(byte[] bytes, int offset, Renderer renderer,
+			int tileX, int tileY, int tileWidth, int tileHeight) throws TransportException {
+		return renderer.drawCompactBytes(bytes, offset, tileX, tileY, tileWidth, tileHeight);
+	}
+
+	private int readPalette(byte[] bytes, int offset, Renderer renderer, int paletteSize) {
+        final int bytesPerCPixel = renderer.getBytesPerCPixel();
+		for (int i=0; i<paletteSize; ++i) {
+            palette[i] = renderer.getCompactPixelColor(bytes, offset + i* bytesPerCPixel);
+		}
+		return paletteSize * bytesPerCPixel;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ZlibDecoder.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,72 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+import java.io.ByteArrayInputStream;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+public class ZlibDecoder extends Decoder {
+	private Inflater decoder;
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int zippedLength = (int) reader.readUInt32();
+		if (0 == zippedLength) return;
+		int length = rect.width * rect.height * renderer.getBytesPerPixel();
+		byte[] bytes = unzip(reader, zippedLength, length);
+		Reader unzippedReader =
+			new Reader(
+					new ByteArrayInputStream(bytes, zippedLength, length));
+		RawDecoder.getInstance().decode(unzippedReader, renderer, rect);
+	}
+
+	protected byte[] unzip(Reader reader, int zippedLength, int length)
+			throws TransportException {
+		byte [] bytes = ByteBuffer.getInstance().getBuffer(zippedLength + length);
+		reader.readBytes(bytes, 0, zippedLength);
+		if (null == decoder) {
+			decoder = new Inflater();
+		}
+		decoder.setInput(bytes, 0, zippedLength);
+		try {
+			decoder.inflate(bytes, zippedLength, length);
+		} catch (DataFormatException e) {
+			throw new TransportException("cannot inflate Zlib data", e);
+		}
+		return bytes;
+	}
+
+	@Override
+	public void reset() {
+		decoder = null;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/LocalPointer.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,34 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+/**
+ * How to track local mouse cursor.
+ */
+public enum LocalPointer {
+	ON,
+	OFF,
+	HIDE,
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/MessageQueue.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,58 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.rfb.client.ClientToServerMessage;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class MessageQueue {
+	private final BlockingQueue<ClientToServerMessage> queue;
+
+	public MessageQueue() {
+		queue = new LinkedBlockingQueue<ClientToServerMessage>();
+	}
+
+	public void put(ClientToServerMessage message) {
+		queue.offer(message);
+	}
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
+     * Retrieves and removes the head of this queue, waiting up to the certain wait time if necessary for
+     * an element to become available.
+     * @return the head of this queue, or null if the specified waiting time elapses before an element is available
+     * @throws InterruptedException - if interrupted while waiting
+     */
+	public ClientToServerMessage get() throws InterruptedException {
+		return queue.poll(1, TimeUnit.SECONDS);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/Protocol.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,311 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.exceptions.*;
+import com.glavsoft.rfb.*;
+import com.glavsoft.rfb.client.ClientToServerMessage;
+import com.glavsoft.rfb.client.FramebufferUpdateRequestMessage;
+import com.glavsoft.rfb.client.SetEncodingsMessage;
+import com.glavsoft.rfb.client.SetPixelFormatMessage;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.DecodersContainer;
+import com.glavsoft.rfb.protocol.state.HandshakeState;
+import com.glavsoft.rfb.protocol.state.ProtocolState;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+import java.util.logging.Logger;
+
+public class Protocol implements ProtocolContext, IChangeSettingsListener {
+	private ProtocolState state;
+	private final Logger logger;
+	private final IPasswordRetriever passwordRetriever;
+	private final ProtocolSettings settings;
+	private int fbWidth;
+	private int fbHeight;
+	private PixelFormat pixelFormat;
+	private final Reader reader;
+	private final Writer writer;
+	private String remoteDesktopName;
+	private MessageQueue messageQueue;
+	private final DecodersContainer decoders;
+	private SenderTask senderTask;
+	private ReceiverTask receiverTask;
+	private IRfbSessionListener rfbSessionListener;
+	private IRepaintController repaintController;
+	private PixelFormat serverPixelFormat;
+	private Thread senderThread;
+	private Thread receiverThread;
+    private boolean isTight;
+    private String protocolVersion;
+
+    public Protocol(Reader reader, Writer writer,
+			IPasswordRetriever passwordRetriever, ProtocolSettings settings) {
+		this.reader = reader;
+		this.writer = writer;
+		this.passwordRetriever = passwordRetriever;
+		this.settings = settings;
+		decoders = new DecodersContainer();
+		decoders.instantiateDecodersWhenNeeded(settings.encodings);
+		state = new HandshakeState(this);
+        logger = Logger.getLogger(getClass().getName());
+    }
+
+	@Override
+	public void changeStateTo(ProtocolState state) {
+		this.state = state;
+	}
+
+	public void handshake() throws UnsupportedProtocolVersionException, UnsupportedSecurityTypeException,
+			AuthenticationFailedException, TransportException, FatalException {
+		while (state.next()) {
+			// continue;
+		}
+		this.messageQueue = new MessageQueue();
+	}
+
+	@Override
+	public PixelFormat getPixelFormat() {
+		return pixelFormat;
+	}
+
+	@Override
+	public void setPixelFormat(PixelFormat pixelFormat) {
+		this.pixelFormat = pixelFormat;
+		if (repaintController != null) {
+			repaintController.setPixelFormat(pixelFormat);
+		}
+	}
+
+	@Override
+	public String getRemoteDesktopName() {
+		return remoteDesktopName;
+	}
+
+	@Override
+	public void setRemoteDesktopName(String name) {
+		remoteDesktopName = name;
+	}
+
+	@Override
+	public int getFbWidth() {
+		return fbWidth;
+	}
+
+	@Override
+	public void setFbWidth(int fbWidth) {
+		this.fbWidth = fbWidth;
+	}
+
+	@Override
+	public int getFbHeight() {
+		return fbHeight;
+	}
+
+	@Override
+	public void setFbHeight(int fbHeight) {
+		this.fbHeight = fbHeight;
+	}
+
+	@Override
+	public IPasswordRetriever getPasswordRetriever() {
+		return passwordRetriever;
+	}
+
+	@Override
+	public ProtocolSettings getSettings() {
+		return settings;
+	}
+
+    @Override
+	public Writer getWriter() {
+		return writer;
+	}
+
+	@Override
+	public Reader getReader() {
+		return reader;
+	}
+
+	/**
+	 * Following the server initialisation message it's up to the client to send
+	 * whichever protocol messages it wants.  Typically it will send a
+	 * SetPixelFormat message and a SetEncodings message, followed by a
+	 * FramebufferUpdateRequest.  From then on the server will send
+	 * FramebufferUpdate messages in response to the client's
+	 * FramebufferUpdateRequest messages.  The client should send
+	 * FramebufferUpdateRequest messages with incremental set to true when it has
+	 * finished processing one FramebufferUpdate and is ready to process another.
+	 * With a fast client, the rate at which FramebufferUpdateRequests are sent
+	 * should be regulated to avoid hogging the network.
+	 */
+	public void startNormalHandling(IRfbSessionListener rfbSessionListener,
+			IRepaintController repaintController, ClipboardController clipboardController) {
+		this.rfbSessionListener = rfbSessionListener;
+		this.repaintController = repaintController;
+//		if (settings.getColorDepth() == 0) {
+//			settings.setColorDepth(pixelFormat.depth); // the same the server sent when not initialized yet
+//		}
+		serverPixelFormat = pixelFormat;
+        correctServerPixelFormat();
+		setPixelFormat(createPixelFormat(settings));
+		sendMessage(new SetPixelFormatMessage(pixelFormat));
+		logger.fine("sent: " + pixelFormat);
+
+		sendSupportedEncodingsMessage(settings);
+		settings.addListener(this); // to support pixel format (color depth), and encodings changes
+		settings.addListener(repaintController);
+
+		sendRefreshMessage();
+		senderTask = new SenderTask(messageQueue, writer, this);
+		senderThread = new Thread(senderTask, "RfbSenderTask");
+		senderThread.start();
+		decoders.resetDecoders();
+		receiverTask = new ReceiverTask(
+				reader, repaintController,
+				clipboardController,
+				decoders, this);
+		receiverThread = new Thread(receiverTask, "RfbReceiverTask");
+		receiverThread.start();
+	}
+
+    private void correctServerPixelFormat() {
+        // correct true color flag - we don't support color maps, so always set it up
+        serverPixelFormat.trueColourFlag = 1;
+        // correct .depth to use actual depth 24 instead of incorrect 32, used by ex. UltraVNC server, that cause
+        // protocol incompatibility in ZRLE encoding
+        final long significant = serverPixelFormat.redMax << serverPixelFormat.redShift |
+                serverPixelFormat.greenMax << serverPixelFormat.greenShift |
+                serverPixelFormat.blueMax << serverPixelFormat.blueShift;
+        if (32 == serverPixelFormat.bitsPerPixel &&
+                ((significant & 0x00ff000000L) == 0 || (significant & 0x000000ffL) == 0) &&
+                32 == serverPixelFormat.depth) {
+            serverPixelFormat.depth = 24;
+        }
+    }
+
+    @Override
+	public void sendMessage(ClientToServerMessage message) {
+		messageQueue.put(message);
+	}
+
+	private void sendSupportedEncodingsMessage(ProtocolSettings settings) {
+		decoders.instantiateDecodersWhenNeeded(settings.encodings);
+		SetEncodingsMessage encodingsMessage = new SetEncodingsMessage(settings.encodings);
+		sendMessage(encodingsMessage);
+		logger.fine("sent: " + encodingsMessage.toString());
+	}
+
+	/**
+	 * create pixel format by bpp
+	 */
+	private PixelFormat createPixelFormat(ProtocolSettings settings) {
+		int serverBigEndianFlag = serverPixelFormat.bigEndianFlag;
+		switch (settings.getColorDepth()) {
+		case ProtocolSettings.COLOR_DEPTH_24:
+			return PixelFormat.create24bitColorDepthPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.COLOR_DEPTH_16:
+			return PixelFormat.create16bitColorDepthPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.COLOR_DEPTH_8:
+			return PixelFormat.create8bitColorDepthBGRPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.COLOR_DEPTH_6:
+			return PixelFormat.create6bitColorDepthPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.COLOR_DEPTH_3:
+			return PixelFormat.create3bppPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.COLOR_DEPTH_SERVER_SETTINGS:
+			return serverPixelFormat;
+		default:
+			// unsupported bpp, use default
+			return PixelFormat.create24bitColorDepthPixelFormat(serverBigEndianFlag);
+		}
+	}
+
+	@Override
+	public void settingsChanged(SettingsChangedEvent e) {
+		ProtocolSettings settings = (ProtocolSettings) e.getSource();
+		if (settings.isChangedEncodings()) {
+			sendSupportedEncodingsMessage(settings);
+		}
+		if (settings.isChangedColorDepth() && receiverTask != null) {
+			receiverTask.queueUpdatePixelFormat(createPixelFormat(settings));
+		}
+	}
+
+	@Override
+	public void sendRefreshMessage() {
+		sendMessage(new FramebufferUpdateRequestMessage(0, 0, fbWidth, fbHeight, false));
+		logger.fine("sent: full FB Refresh");
+	}
+
+	@Override
+	public void cleanUpSession(String message) {
+		cleanUpSession();
+		rfbSessionListener.rfbSessionStopped(message);
+	}
+
+	public synchronized void cleanUpSession() {
+		if (senderTask != null) { senderTask.stopTask(); }
+		if (receiverTask != null) { receiverTask.stopTask(); }
+		if (senderTask != null) {
+			try {
+				senderThread.join(1000);
+			} catch (InterruptedException e) {
+				// nop
+			}
+			senderTask = null;
+		}
+		if (receiverTask != null) {
+			try {
+				receiverThread.join(1000);
+			} catch (InterruptedException e) {
+				// nop
+			}
+			receiverTask = null;
+		}
+	}
+
+    @Override
+    public void setTight(boolean isTight) {
+        this.isTight = isTight;
+    }
+
+    @Override
+    public boolean isTight() {
+        return isTight;
+    }
+
+    @Override
+    public void setProtocolVersion(String protocolVersion) {
+        this.protocolVersion = protocolVersion;
+    }
+
+    @Override
+    public String getProtocolVersion() {
+        return protocolVersion;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/ProtocolContext.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,72 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.rfb.client.ClientToServerMessage;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.protocol.state.ProtocolState;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+import java.util.logging.Logger;
+
+public interface ProtocolContext {
+
+	void changeStateTo(ProtocolState state);
+
+	IPasswordRetriever getPasswordRetriever();
+
+	ProtocolSettings getSettings();
+
+    Writer getWriter();
+	Reader getReader();
+
+	int getFbWidth();
+	void setFbWidth(int frameBufferWidth);
+
+	int getFbHeight();
+	void setFbHeight(int frameBufferHeight);
+
+	PixelFormat getPixelFormat();
+	void setPixelFormat(PixelFormat pixelFormat);
+
+	void setRemoteDesktopName(String name);
+
+	void sendMessage(ClientToServerMessage message);
+
+	String getRemoteDesktopName();
+
+	void sendRefreshMessage();
+	
+	void cleanUpSession(String message);
+
+    void setTight(boolean isTight);
+	boolean isTight();
+
+    void setProtocolVersion(String protocolVersion);
+    String getProtocolVersion();
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/ProtocolSettings.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,445 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IChangeSettingsListener;
+import com.glavsoft.rfb.RfbCapabilityInfo;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.protocol.auth.SecurityType;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Protocol Settings class
+ */
+public class ProtocolSettings implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private static final EncodingType DEFAULT_PREFERRED_ENCODING = EncodingType.TIGHT;
+	public static final int DEFAULT_JPEG_QUALITY = 6;
+	private static final int DEFAULT_COMPRESSION_LEVEL = -6;
+
+	// color depth constants
+	public static final int COLOR_DEPTH_32 = 32;
+    public static final int COLOR_DEPTH_24 = 24;
+	public static final int COLOR_DEPTH_16 = 16;
+	public static final int COLOR_DEPTH_8 = 8;
+	public static final int COLOR_DEPTH_6 = 6;
+	public static final int COLOR_DEPTH_3 = 3;
+
+	public static final int COLOR_DEPTH_SERVER_SETTINGS = 0;
+
+	private static final int DEFAULT_COLOR_DEPTH = COLOR_DEPTH_24;
+
+	public static final int CHANGED_VIEW_ONLY                   = 1; // 1 << 0;
+	public static final int CHANGED_ENCODINGS                   = 1 << 1;
+	public static final int CHANGED_ALLOW_COPY_RECT             = 1 << 2;
+	public static final int CHANGED_SHOW_REMOTE_CURSOR          = 1 << 3;
+	public static final int CHANGED_MOUSE_CURSOR_TRACK          = 1 << 4;
+	public static final int CHANGED_COMPRESSION_LEVEL           = 1 << 5;
+	public static final int CHANGED_JPEG_QUALITY                = 1 << 6;
+	public static final int CHANGED_ALLOW_CLIPBOARD_TRANSFER    = 1 << 7;
+	public static final int CHANGED_CONVERT_TO_ASCII            = 1 << 8;
+	public static final int CHANGED_COLOR_DEPTH = 1 << 9;
+    public static final int CHANGED_SHARED                      = 1 << 10;
+
+	private transient int changedSettingsMask;
+
+    private boolean sharedFlag;
+    private boolean viewOnly;
+    private EncodingType preferredEncoding;
+    private boolean allowCopyRect;
+    private boolean showRemoteCursor;
+    private LocalPointer mouseCursorTrack;
+    private int compressionLevel;
+    private int jpegQuality;
+	private boolean allowClipboardTransfer;
+	private boolean convertToAscii;
+	private int colorDepth;
+
+	public transient LinkedHashSet<EncodingType> encodings;
+	private transient final List<IChangeSettingsListener> listeners;
+
+    public transient CapabilityContainer
+		tunnelingCapabilities,
+		authCapabilities,
+		serverMessagesCapabilities,
+		clientMessagesCapabilities,
+		encodingTypesCapabilities;
+	private transient String remoteCharsetName;
+
+	public static ProtocolSettings getDefaultSettings() {
+    	ProtocolSettings settings = new ProtocolSettings();
+	    settings.initKnownAuthCapabilities(settings.authCapabilities);
+	    settings.initKnownEncodingTypesCapabilities(settings.encodingTypesCapabilities);
+        return settings;
+    }
+
+	private ProtocolSettings() {
+        sharedFlag = true;
+        viewOnly = false;
+        showRemoteCursor = true;
+        mouseCursorTrack = LocalPointer.ON;
+        preferredEncoding = DEFAULT_PREFERRED_ENCODING;
+        allowCopyRect = true;
+        compressionLevel = DEFAULT_COMPRESSION_LEVEL;
+        jpegQuality = DEFAULT_JPEG_QUALITY;
+        convertToAscii = false;
+        allowClipboardTransfer = true;
+        colorDepth = COLOR_DEPTH_SERVER_SETTINGS;
+        refine();
+
+        listeners = new LinkedList<IChangeSettingsListener>();
+		tunnelingCapabilities = new CapabilityContainer();
+		authCapabilities = new CapabilityContainer();
+		serverMessagesCapabilities = new CapabilityContainer();
+		clientMessagesCapabilities = new CapabilityContainer();
+		encodingTypesCapabilities = new CapabilityContainer();
+		changedSettingsMask = 0;
+   	}
+
+	public ProtocolSettings(ProtocolSettings s) {
+		this();
+        copyDataFrom(s);
+        changedSettingsMask = s.changedSettingsMask;
+        encodings = s.encodings;
+    }
+
+    public void copyDataFrom(ProtocolSettings s) {
+        copyDataFrom(s, 0);
+    }
+
+    public void copyDataFrom(ProtocolSettings s, int mask) {
+        if (null == s) return;
+        if ((mask & CHANGED_SHARED) == 0) setSharedFlag(s.sharedFlag);
+        if ((mask & CHANGED_VIEW_ONLY) == 0) setViewOnly(s.viewOnly);
+        if ((mask & CHANGED_ALLOW_COPY_RECT) == 0) setAllowCopyRect(s.allowCopyRect);
+        if ((mask & CHANGED_SHOW_REMOTE_CURSOR) == 0) setShowRemoteCursor(s.showRemoteCursor);
+        if ((mask & CHANGED_ALLOW_CLIPBOARD_TRANSFER) == 0) setAllowClipboardTransfer(s.allowClipboardTransfer);
+
+        if ((mask & CHANGED_MOUSE_CURSOR_TRACK) == 0) setMouseCursorTrack(s.mouseCursorTrack);
+        if ((mask & CHANGED_COMPRESSION_LEVEL) == 0) setCompressionLevel(s.compressionLevel);
+        if ((mask & CHANGED_JPEG_QUALITY) == 0) setJpegQuality(s.jpegQuality);
+        if ((mask & CHANGED_CONVERT_TO_ASCII) == 0) setConvertToAscii(s.convertToAscii);
+        if ((mask & CHANGED_COLOR_DEPTH) == 0) setColorDepth(s.colorDepth);
+        if ((mask & CHANGED_ENCODINGS) == 0) setPreferredEncoding(s.preferredEncoding);
+    }
+
+    private void initKnownAuthCapabilities(CapabilityContainer cc) {
+		cc.addEnabled(SecurityType.NONE_AUTHENTICATION.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.AUTHENTICATION_NO_AUTH);
+		cc.addEnabled(SecurityType.VNC_AUTHENTICATION.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.AUTHENTICATION_VNC_AUTH);
+	    //cc.addEnabled( 19, "VENC", "VENCRYPT");
+	    //cc.addEnabled( 20, "GTKV", "SASL____");
+	    //cc.addEnabled(129, RfbCapabilityInfo.TIGHT_VNC_VENDOR, "ULGNAUTH");
+	    //cc.addEnabled(130, RfbCapabilityInfo.TIGHT_VNC_VENDOR, "XTRNAUTH");
+	}
+
+	private void initKnownEncodingTypesCapabilities(CapabilityContainer cc) {
+		cc.add(EncodingType.COPY_RECT.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.ENCODING_COPYRECT);
+		cc.add(EncodingType.HEXTILE.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.ENCODING_HEXTILE);
+		cc.add(EncodingType.ZLIB.getId(),
+				RfbCapabilityInfo.VENDOR_TRIADA, RfbCapabilityInfo.ENCODING_ZLIB);
+		cc.add(EncodingType.ZRLE.getId(),
+				RfbCapabilityInfo.VENDOR_TRIADA, RfbCapabilityInfo.ENCODING_ZRLE);
+		cc.add(EncodingType.RRE.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.ENCODING_RRE);
+		cc.add(EncodingType.TIGHT.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_TIGHT);
+
+		cc.add(EncodingType.RICH_CURSOR.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_RICH_CURSOR);
+		cc.add(EncodingType.CURSOR_POS.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_CURSOR_POS);
+		cc.add(EncodingType.DESKTOP_SIZE.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_DESKTOP_SIZE);
+	}
+
+	public void addListener(IChangeSettingsListener listener) {
+		listeners.add(listener);
+	}
+
+	public byte getSharedFlag() {
+		return (byte) (sharedFlag ? 1 : 0);
+	}
+
+	public boolean isShared() {
+		return sharedFlag;
+	}
+
+	public void setSharedFlag(boolean sharedFlag) {
+        if (this.sharedFlag != sharedFlag) {
+		    this.sharedFlag = sharedFlag;
+            changedSettingsMask |= CHANGED_SHARED;
+        }
+	}
+
+	public boolean isViewOnly() {
+		return viewOnly;
+	}
+
+	public void setViewOnly(boolean viewOnly) {
+		if (this.viewOnly != viewOnly) {
+			this.viewOnly = viewOnly;
+			changedSettingsMask |= CHANGED_VIEW_ONLY;
+		}
+	}
+
+	public void enableAllEncodingCaps() {
+		encodingTypesCapabilities.setAllEnable(true);
+
+	}
+
+	public int getColorDepth() {
+		return colorDepth;
+	}
+
+	/**
+	 * Set depth only in 3, 6, 8, 16, 32. When depth is wrong, it resets to {@link #DEFAULT_COLOR_DEPTH}
+	 */
+	public void setColorDepth(int depth) {
+		if (colorDepth != depth) {
+			changedSettingsMask |= CHANGED_COLOR_DEPTH;
+			switch (depth) {
+            case COLOR_DEPTH_32:
+                colorDepth = COLOR_DEPTH_24;
+                break;
+			case COLOR_DEPTH_24:
+			case COLOR_DEPTH_16:
+			case COLOR_DEPTH_8:
+			case COLOR_DEPTH_6:
+			case COLOR_DEPTH_3:
+			case COLOR_DEPTH_SERVER_SETTINGS:
+				colorDepth = depth;
+				break;
+			default:
+				colorDepth = DEFAULT_COLOR_DEPTH;
+			}
+			refine();
+		}
+	}
+
+	public void refine() {
+		LinkedHashSet<EncodingType> encodings = new LinkedHashSet<EncodingType>();
+		if (EncodingType.RAW_ENCODING == preferredEncoding) {
+			// when RAW selected send no ordinary encodings so only default RAW encoding will be enabled
+		} else {
+			encodings.add(preferredEncoding); // preferred first
+			encodings.addAll(EncodingType.ordinaryEncodings);
+			if (compressionLevel > 0 && compressionLevel < 10) {
+				encodings.add(EncodingType.byId(
+						EncodingType.COMPRESS_LEVEL_0.getId() + compressionLevel));
+			}
+			if (jpegQuality > 0 && jpegQuality < 10 &&
+					(colorDepth == COLOR_DEPTH_24 || colorDepth == COLOR_DEPTH_SERVER_SETTINGS)) {
+				encodings.add(EncodingType.byId(
+						EncodingType.JPEG_QUALITY_LEVEL_0.getId() + jpegQuality));
+			}
+			if (allowCopyRect) {
+				encodings.add(EncodingType.COPY_RECT);
+			}
+		}
+		switch(mouseCursorTrack) {
+		case OFF:
+			setShowRemoteCursor(false);
+			break;
+		case HIDE:
+			setShowRemoteCursor(false);
+			encodings.add(EncodingType.RICH_CURSOR);
+			encodings.add(EncodingType.CURSOR_POS);
+			break;
+		case ON:
+		default:
+			setShowRemoteCursor(true);
+			encodings.add(EncodingType.RICH_CURSOR);
+			encodings.add(EncodingType.CURSOR_POS);
+		}
+		encodings.add(EncodingType.DESKTOP_SIZE);
+		if ( isEncodingsChanged(this.encodings, encodings) || isChangedEncodings()) {
+			this.encodings = encodings;
+			changedSettingsMask |= CHANGED_ENCODINGS;
+		}
+	}
+
+	private boolean isEncodingsChanged(LinkedHashSet<EncodingType> encodings1, LinkedHashSet<EncodingType> encodings2) {
+		if (null == encodings1 || encodings1.size() != encodings2.size()) return true;
+		Iterator<EncodingType> it1 = encodings1.iterator();
+		Iterator<EncodingType> it2 = encodings2.iterator();
+		while (it1.hasNext()) {
+			EncodingType v1 = it1.next();
+			EncodingType v2 = it2.next();
+			if (v1 != v2) return true;
+		}
+		return false;
+	}
+
+	public void fireListeners() {
+        if (null == listeners) return;
+        final SettingsChangedEvent event = new SettingsChangedEvent(new ProtocolSettings(this));
+		changedSettingsMask = 0;
+		for (IChangeSettingsListener listener : listeners) {
+			listener.settingsChanged(event);
+		}
+	}
+
+	public static boolean isRfbSettingsChangedFired(SettingsChangedEvent event) {
+		return event.getSource() instanceof ProtocolSettings;
+	}
+
+	public void setPreferredEncoding(EncodingType preferredEncoding) {
+		if (this.preferredEncoding != preferredEncoding) {
+			this.preferredEncoding = preferredEncoding;
+			changedSettingsMask |= CHANGED_ENCODINGS;
+			refine();
+		}
+	}
+
+	public EncodingType getPreferredEncoding() {
+		return preferredEncoding;
+	}
+
+	public void setAllowCopyRect(boolean allowCopyRect) {
+		if (this.allowCopyRect != allowCopyRect) {
+			this.allowCopyRect = allowCopyRect;
+			changedSettingsMask |= CHANGED_ALLOW_COPY_RECT;
+			refine();
+		}
+	}
+
+	public boolean isAllowCopyRect() {
+		return allowCopyRect;
+	}
+
+	private void setShowRemoteCursor(boolean showRemoteCursor) {
+		if (this.showRemoteCursor != showRemoteCursor) {
+			this.showRemoteCursor = showRemoteCursor;
+			changedSettingsMask |= CHANGED_SHOW_REMOTE_CURSOR;
+		}
+	}
+
+	public boolean isShowRemoteCursor() {
+		return showRemoteCursor;
+	}
+
+	public void setMouseCursorTrack(LocalPointer mouseCursorTrack) {
+		if (this.mouseCursorTrack != mouseCursorTrack) {
+			this.mouseCursorTrack = mouseCursorTrack;
+			changedSettingsMask |= CHANGED_MOUSE_CURSOR_TRACK;
+			refine();
+		}
+	}
+
+	public LocalPointer getMouseCursorTrack() {
+		return mouseCursorTrack;
+	}
+
+	public void setCompressionLevel(int compressionLevel) {
+		if (this.compressionLevel != compressionLevel) {
+			this.compressionLevel = compressionLevel;
+			changedSettingsMask |= CHANGED_COMPRESSION_LEVEL;
+			refine();
+		}
+	}
+
+	public int getCompressionLevel() {
+		return compressionLevel;
+	}
+
+	public void setJpegQuality(int jpegQuality) {
+		if (this.jpegQuality != jpegQuality) {
+			this.jpegQuality = jpegQuality;
+			changedSettingsMask |= CHANGED_JPEG_QUALITY;
+			refine();
+		}
+	}
+
+	public int getJpegQuality() {
+		return jpegQuality;
+	}
+
+	public void setAllowClipboardTransfer(boolean enable) {
+		if (this.allowClipboardTransfer != enable) {
+			this.allowClipboardTransfer = enable;
+			changedSettingsMask |= CHANGED_ALLOW_CLIPBOARD_TRANSFER;
+		}
+	}
+
+	public boolean isAllowClipboardTransfer() {
+		return allowClipboardTransfer;
+	}
+
+	public boolean isConvertToAscii() {
+		return convertToAscii;
+	}
+
+	public void setConvertToAscii(boolean convertToAscii) {
+		if (this.convertToAscii != convertToAscii) {
+			this.convertToAscii = convertToAscii;
+			changedSettingsMask |= CHANGED_CONVERT_TO_ASCII;
+		}
+	}
+
+	public boolean isChangedEncodings() {
+		return (changedSettingsMask & CHANGED_ENCODINGS) == CHANGED_ENCODINGS;
+	}
+
+	public boolean isChangedColorDepth() {
+		return (changedSettingsMask & CHANGED_COLOR_DEPTH) == CHANGED_COLOR_DEPTH;
+	}
+
+	public void setRemoteCharsetName(String remoteCharsetName) {
+		this.remoteCharsetName = remoteCharsetName;
+	}
+
+	public  String getRemoteCharsetName() {
+		return remoteCharsetName;
+	}
+
+    @Override
+    public String toString() {
+        return "ProtocolSettings{" +
+                "sharedFlag=" + sharedFlag +
+                ", viewOnly=" + viewOnly +
+                ", preferredEncoding=" + preferredEncoding +
+                ", allowCopyRect=" + allowCopyRect +
+                ", showRemoteCursor=" + showRemoteCursor +
+                ", mouseCursorTrack=" + mouseCursorTrack +
+                ", compressionLevel=" + compressionLevel +
+                ", jpegQuality=" + jpegQuality +
+                ", allowClipboardTransfer=" + allowClipboardTransfer +
+                ", convertToAscii=" + convertToAscii +
+                ", colorDepth=" + colorDepth +
+                '}';
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,209 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.CommonException;
+import com.glavsoft.exceptions.ProtocolException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.ClipboardController;
+import com.glavsoft.rfb.IRepaintController;
+import com.glavsoft.rfb.client.FramebufferUpdateRequestMessage;
+import com.glavsoft.rfb.client.SetPixelFormatMessage;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.Decoder;
+import com.glavsoft.rfb.encoding.decoder.DecodersContainer;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.rfb.encoding.decoder.RichCursorDecoder;
+import com.glavsoft.transport.Reader;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Logger;
+
+public class ReceiverTask implements Runnable {
+	private static final byte FRAMEBUFFER_UPDATE = 0;
+	private static final byte SET_COLOR_MAP_ENTRIES = 1;
+	private static final byte BELL = 2;
+	private static final byte SERVER_CUT_TEXT = 3;
+
+
+	private static Logger logger = Logger.getLogger("com.glavsoft.rfb.protocol.ReceiverTask");
+	private final Reader reader;
+	private volatile boolean isRunning = false;
+	private Renderer renderer;
+	private final IRepaintController repaintController;
+	private final ClipboardController clipboardController;
+	private final DecodersContainer decoders;
+	private FramebufferUpdateRequestMessage fullscreenFbUpdateIncrementalRequest;
+	private final ProtocolContext context;
+	private PixelFormat pixelFormat;
+	private boolean needSendPixelFormat;
+
+	public ReceiverTask(Reader reader,
+	                    IRepaintController repaintController, ClipboardController clipboardController,
+	                    DecodersContainer decoders, ProtocolContext context) {
+		this.reader = reader;
+		this.repaintController = repaintController;
+		this.clipboardController = clipboardController;
+		this.context = context;
+		this.decoders = decoders;
+		renderer = repaintController.createRenderer(reader, context.getFbWidth(), context.getFbHeight(),
+				context.getPixelFormat());
+		fullscreenFbUpdateIncrementalRequest =
+			new FramebufferUpdateRequestMessage(0, 0, context.getFbWidth(), context.getFbHeight(), true);
+	}
+
+	@Override
+	public void run() {
+		isRunning = true;
+		while (isRunning) {
+			try {
+				byte messageId = reader.readByte();
+				switch (messageId) {
+				case FRAMEBUFFER_UPDATE:
+//					logger.fine("Server message: FramebufferUpdate (0)");
+					framebufferUpdateMessage();
+					break;
+				case SET_COLOR_MAP_ENTRIES:
+					logger.severe("Server message SetColorMapEntries is not implemented. Skip.");
+					setColorMapEntries();
+					break;
+				case BELL:
+					logger.fine("Server message: Bell");
+					System.out.print("\0007");
+				    System.out.flush();
+					break;
+				case SERVER_CUT_TEXT:
+					logger.fine("Server message: CutText (3)");
+					serverCutText();
+					break;
+				default:
+					logger.severe("Unsupported server message. Id = " + messageId);
+				}
+			} catch (TransportException e) {
+				if (isRunning) {
+                    logger.severe("Close session: " + e.getMessage());
+					context.cleanUpSession("Connection closed.");
+				}
+				stopTask();
+			} catch (ProtocolException e) {
+				logger.severe(e.getMessage());
+				if (isRunning) {
+					context.cleanUpSession(e.getMessage() + "\nConnection closed.");
+				}
+				stopTask();
+			} catch (CommonException e) {
+				logger.severe(e.getMessage());
+				if (isRunning) {
+					context.cleanUpSession("Connection closed..");
+				}
+				stopTask();
+			} catch (Throwable te) {
+				StringWriter sw = new StringWriter();
+				PrintWriter pw = new PrintWriter(sw);
+				te.printStackTrace(pw);
+				if (isRunning) {
+					context.cleanUpSession(te.getMessage() + "\n" + sw.toString());
+				}
+				stopTask();
+			}
+		}
+	}
+
+	private void setColorMapEntries() throws TransportException {
+		reader.readByte();  // padding
+		reader.readUInt16(); // first color index
+		int length = reader.readUInt16();
+		while (length-- > 0) {
+			reader.readUInt16(); // R
+			reader.readUInt16(); // G
+			reader.readUInt16(); // B
+		}
+	}
+
+	private void serverCutText() throws TransportException {
+		reader.readByte();  // padding
+		reader.readInt16(); // padding
+		int length = reader.readInt32() & Integer.MAX_VALUE;
+		clipboardController.updateSystemClipboard(reader.readBytes(length));
+	}
+
+	public void framebufferUpdateMessage() throws CommonException {
+		reader.readByte(); // padding
+		int numberOfRectangles = reader.readUInt16();
+		while (numberOfRectangles-- > 0) {
+			FramebufferUpdateRectangle rect = new FramebufferUpdateRectangle();
+			rect.fill(reader);
+
+			Decoder decoder = decoders.getDecoderByType(rect.getEncodingType());
+			logger.finest(rect.toString() + (0 == numberOfRectangles ? "\n---" : ""));
+			if (decoder != null) {
+				decoder.decode(reader, renderer, rect);
+				repaintController.repaintBitmap(rect);
+			} else if (rect.getEncodingType() == EncodingType.RICH_CURSOR) {
+				RichCursorDecoder.getInstance().decode(reader, renderer, rect);
+				repaintController.repaintCursor();
+			} else if (rect.getEncodingType() == EncodingType.CURSOR_POS) {
+				renderer.decodeCursorPosition(rect);
+				repaintController.repaintCursor();
+			} else if (rect.getEncodingType() == EncodingType.DESKTOP_SIZE) {
+				fullscreenFbUpdateIncrementalRequest =
+					new FramebufferUpdateRequestMessage(0, 0, rect.width, rect.height, true);
+				synchronized (renderer.getLock()) {
+					renderer = repaintController.createRenderer(reader, rect.width, rect.height,
+							context.getPixelFormat());
+				}
+				context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, rect.width, rect.height, false));
+//				repaintController.repaintCursor();
+			} else
+				throw new CommonException("Unprocessed encoding: " + rect.toString());
+		}
+		synchronized (this) {
+			if (needSendPixelFormat) {
+				needSendPixelFormat = false;
+				context.setPixelFormat(pixelFormat);
+				context.sendMessage(new SetPixelFormatMessage(pixelFormat));
+				logger.fine("sent: "+pixelFormat);
+				context.sendRefreshMessage();
+				logger.fine("sent: nonincremental fb update");
+			} else {
+				context.sendMessage(fullscreenFbUpdateIncrementalRequest);
+			}
+		}
+	}
+
+	public synchronized void queueUpdatePixelFormat(PixelFormat pf) {
+		pixelFormat = pf;
+		needSendPixelFormat = true;
+//		context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, 1, 1, false));
+	}
+
+	public void stopTask() {
+		isRunning = false;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/SenderTask.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,91 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.client.ClientToServerMessage;
+import com.glavsoft.transport.Writer;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Logger;
+
+public class SenderTask implements Runnable {
+
+	private final MessageQueue queue;
+	private final Writer writer;
+	private final ProtocolContext protocolContext;
+	private volatile boolean isRunning = false;
+
+	/**
+	 * Create sender task
+	 * Task runs as thread, receive messages from queue and sends them to writer.
+	 * When no messages appears in queue longer than timeout period, sends FramebufferUpdate
+	 * request
+	 * @param messageQueue queue to poll messages
+	 * @param writer writer to send messages out
+	 * @param protocolContext protocol
+	 */
+	public SenderTask(MessageQueue messageQueue, Writer writer, ProtocolContext protocolContext) {
+		this.queue = messageQueue;
+		this.writer = writer;
+		this.protocolContext = protocolContext;
+	}
+
+	@Override
+	public void run() {
+		isRunning = true;
+		while (isRunning) {
+			ClientToServerMessage message;
+			try {
+				message = queue.get();
+				if (message != null) {
+					message.send(writer);
+				}
+			} catch (InterruptedException e) {
+				// nop
+			} catch (TransportException e) {
+				Logger.getLogger(getClass().getName()).severe("Close session: " + e.getMessage());
+				if (isRunning) {
+					protocolContext.cleanUpSession("Connection closed");
+				}
+				stopTask();
+			} catch (Throwable te) {
+				StringWriter sw = new StringWriter();
+				PrintWriter pw = new PrintWriter(sw);
+				te.printStackTrace(pw);
+				if (isRunning) {
+					protocolContext.cleanUpSession(te.getMessage() + "\n" + sw.toString());
+				}
+				stopTask();
+			}
+		}
+	}
+
+	public void stopTask() {
+		isRunning = false;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/AuthHandler.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,66 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+public abstract class AuthHandler {
+	/**
+	 * Authenticate using apropriate auth scheme
+	 * @param reader
+	 * @param writer
+	 * @param passwordRetriever interface that realise callback function for password retrieving,
+	 * ex. by asking user with dialog frame etc.
+	 * @param authCaps authentication capabilities
+	 *
+	 * @return true if there was Tight protocol extention used, false - in the other way
+	 * @throws TransportException
+	 * @throws FatalException
+	 * @throws UnsupportedSecurityTypeException
+	 */
+	public abstract boolean authenticate(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+		throws TransportException, FatalException, UnsupportedSecurityTypeException;
+	protected boolean useSecurityResult = true;
+	public abstract SecurityType getType();
+	public int getId() {
+		return getType().getId();
+	}
+	public String getName() {
+		return getType().name();
+	}
+	public boolean useSecurityResult() {
+		return useSecurityResult;
+	}
+	public void setUseSecurityResult(boolean enabled) {
+		useSecurityResult = enabled;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/NoneAuthentication.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,45 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+public class NoneAuthentication extends AuthHandler {
+
+	@Override
+	public boolean authenticate(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever) {
+		return false;
+	}
+
+	@Override
+	public SecurityType getType() {
+		return SecurityType.NONE_AUTHENTICATION;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/SecurityType.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,72 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+
+/**
+ * Security types that implemented
+ */
+public enum SecurityType {
+	NONE_AUTHENTICATION(1),
+	VNC_AUTHENTICATION(2),
+//	int RA2_AUTHENTICATION = 5;
+//	int RA2NE_AUTHENTICATION = 6;
+	TIGHT_AUTHENTICATION(16);
+//	int ULTRA_AUTHENTICATION = 17;
+//	int TLS_AUTHENTICATION = 18;
+//	int VENCRYPT_AUTHENTICATION = 19;
+
+	private int id;
+	private SecurityType(int id) {
+		this.id = id;
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	@SuppressWarnings("serial")
+	public
+	static Map<Integer, AuthHandler> implementedSecurityTypes =
+		new LinkedHashMap<Integer, AuthHandler>() {{
+			put(TIGHT_AUTHENTICATION.getId(), new TightAuthentication());
+			put(VNC_AUTHENTICATION.getId(), new VncAuthentication());
+			put(NONE_AUTHENTICATION.getId(), new NoneAuthentication());
+	}};
+
+	public static AuthHandler getAuthHandlerById(int id) throws UnsupportedSecurityTypeException {
+		AuthHandler typeSelected = null;
+		typeSelected = implementedSecurityTypes.get(id);
+		if (null == typeSelected) {
+			throw new UnsupportedSecurityTypeException("Not supported: " + id);
+		}
+		return typeSelected;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/TightAuthentication.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,153 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import java.util.logging.Logger;
+
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.rfb.RfbCapabilityInfo;
+import com.glavsoft.rfb.protocol.state.SecurityTypeState;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+/**
+ *
+ */
+public class TightAuthentication extends AuthHandler {
+
+	@Override
+	public SecurityType getType() {
+		return SecurityType.TIGHT_AUTHENTICATION;
+	}
+
+	@Override
+	public boolean authenticate(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+	throws TransportException, FatalException, UnsupportedSecurityTypeException {
+	      initTunnelling(reader, writer);
+	      initAuthorization(reader, writer, authCaps, passwordRetriever);
+	      return true;
+	}
+
+	/**
+	 * Negotiation of Tunneling Capabilities (protocol versions 3.7t, 3.8t)
+	 *
+	 * If the chosen security type is rfbSecTypeTight, the server sends a list of
+	 * supported tunneling methods ("tunneling" refers to any additional layer of
+	 * data transformation, such as encryption or external compression.)
+	 *
+	 * nTunnelTypes specifies the number of following rfbCapabilityInfo structures
+	 * that list all supported tunneling methods in the order of preference.
+	 *
+	 * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
+	 * used, and the client should not send a response requesting a tunneling
+	 * method.
+	 *
+	 * typedef struct _rfbTunnelingCapsMsg {
+	 *     CARD32 nTunnelTypes;
+	 *     //followed by nTunnelTypes * rfbCapabilityInfo structures
+	 *  } rfbTunnelingCapsMsg;
+	 * #define sz_rfbTunnelingCapsMsg 4
+	 * ----------------------------------------------------------------------------
+	 * Tunneling Method Request (protocol versions 3.7t, 3.8t)
+	 *
+	 * If the list of tunneling capabilities sent by the server was not empty, the
+	 * client should reply with a 32-bit code specifying a particular tunneling
+	 * method.  The following code should be used for no tunneling.
+	 *
+	 * #define rfbNoTunneling 0
+	 * #define sig_rfbNoTunneling "NOTUNNEL"
+	 *
+	 */
+	private void initTunnelling(Reader reader, Writer writer)
+			throws TransportException {
+		long tunnelsCount;
+		tunnelsCount = reader.readUInt32();
+		if (tunnelsCount > 0) {
+			for (int i = 0; i < tunnelsCount; ++i) {
+				RfbCapabilityInfo rfbCapabilityInfo = new RfbCapabilityInfo(reader);
+				Logger.getLogger("com.glavsoft.rfb.protocol.auth").fine(rfbCapabilityInfo.toString());
+			}
+			writer.writeInt32(0); // NOTUNNEL
+		}
+	}
+
+	/**
+	 * Negotiation of Authentication Capabilities (protocol versions 3.7t, 3.8t)
+	 *
+	 * After setting up tunneling, the server sends a list of supported
+	 * authentication schemes.
+	 *
+	 * nAuthTypes specifies the number of following rfbCapabilityInfo structures
+	 * that list all supported authentication schemes in the order of preference.
+	 *
+	 * NOTE: If nAuthTypes is 0, that tells the client that no authentication is
+	 * necessary, and the client should not send a response requesting an
+	 * authentication scheme.
+	 *
+	 * typedef struct _rfbAuthenticationCapsMsg {
+	 *     CARD32 nAuthTypes;
+	 *     // followed by nAuthTypes * rfbCapabilityInfo structures
+	 * } rfbAuthenticationCapsMsg;
+	 * #define sz_rfbAuthenticationCapsMsg 4
+	 * @param authCaps TODO
+	 * @param passwordRetriever
+	 * @throws UnsupportedSecurityTypeException
+	 * @throws TransportException
+	 * @throws FatalException
+	 */
+	private void initAuthorization(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+	throws UnsupportedSecurityTypeException, TransportException, FatalException {
+		int authCount;
+		authCount = reader.readInt32();
+		byte[] cap = new byte[authCount];
+		for (int i = 0; i < authCount; ++i) {
+			RfbCapabilityInfo rfbCapabilityInfo = new RfbCapabilityInfo(reader);
+			cap[i] = (byte) rfbCapabilityInfo.getCode();
+			Logger.getLogger("com.glavsoft.rfb.protocol.auth").fine(rfbCapabilityInfo.toString());
+		}
+		AuthHandler authHandler = null;
+		if (authCount > 0) {
+			authHandler = SecurityTypeState.selectAuthHandler(cap, authCaps);
+			for (int i = 0; i < authCount; ++i) {
+				if (authCaps.isSupported(cap[i])) {
+					//sending back RFB capability code
+					writer.writeInt32(cap[i]);
+					break;
+				}
+			}
+    	} else {
+    		authHandler = SecurityType.getAuthHandlerById(SecurityType.NONE_AUTHENTICATION.getId());
+    	}
+		Logger.getLogger("com.glavsoft.rfb.protocol.auth").info("Auth capability accepted: " + authHandler.getName());
+		authHandler.authenticate(reader, writer, authCaps, passwordRetriever);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/VncAuthentication.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,100 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import com.glavsoft.exceptions.CryptoException;
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+import javax.crypto.*;
+import javax.crypto.spec.DESKeySpec;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+
+public class VncAuthentication extends AuthHandler {
+	@Override
+	public SecurityType getType() {
+		return SecurityType.VNC_AUTHENTICATION;
+	}
+
+	@Override
+	public boolean authenticate(Reader reader,
+			Writer writer, CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+	throws TransportException, FatalException {
+		byte [] challenge = reader.readBytes(16);
+		String password = passwordRetriever.getPassword();
+        if (null == password) return false;
+		byte [] key = new byte[8];
+        System.arraycopy(password.getBytes(), 0, key, 0, Math.min(key.length, password.getBytes().length));
+	    writer.write(encrypt(challenge, key));
+	    return false;
+	}
+
+  /**
+	 * Encript challenge by key using DES
+	 * @return encripted bytes
+	 * @throws CryptoException on problem with DES algorithm support or smth about
+	 */
+	public byte[] encrypt(byte[] challenge, byte[] key) throws CryptoException {
+		try {
+		    DESKeySpec desKeySpec = new DESKeySpec(mirrorBits(key));
+		    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+		    SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
+		    Cipher desCipher = Cipher.getInstance("DES/ECB/NoPadding");
+		    desCipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            return desCipher.doFinal(challenge);
+		} catch (NoSuchAlgorithmException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (NoSuchPaddingException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (IllegalBlockSizeException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (BadPaddingException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (InvalidKeyException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (InvalidKeySpecException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		}
+	}
+
+	private byte[] mirrorBits(byte[] k) {
+		byte[] key = new byte[8];
+		for (int i = 0; i < 8; i++) {
+			byte s = k[i];
+			s = (byte) (((s >> 1) & 0x55) | ((s << 1) & 0xaa));
+	        s = (byte) (((s >> 2) & 0x33) | ((s << 2) & 0xcc));
+	        s = (byte) (((s >> 4) & 0x0f) | ((s << 4) & 0xf0));
+	        key[i] = s;
+		}
+		return key;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/AuthenticationState.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,84 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.*;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+
+public class AuthenticationState extends ProtocolState {
+
+	private static final int AUTH_RESULT_OK = 0;
+//	private static final int AUTH_RESULT_FAILED = 1;
+//	private static final int AUTH_RESULT_TOO_MANY = 2;
+	private final AuthHandler authHandler;
+
+	public AuthenticationState(ProtocolContext context,
+			AuthHandler authHandler) {
+		super(context);
+		this.authHandler = authHandler;
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException,
+			UnsupportedSecurityTypeException, AuthenticationFailedException, FatalException {
+		authenticate();
+		return true;
+	}
+
+	private void authenticate() throws TransportException, AuthenticationFailedException,
+			FatalException, UnsupportedSecurityTypeException {
+		boolean isTight = authHandler.authenticate(reader, writer,
+				context.getSettings().authCapabilities, context.getPasswordRetriever());
+		// skip when protocol < 3.8 and NONE_AUTH
+		if (authHandler.useSecurityResult()) {
+			checkSecurityResult();
+		}
+		changeStateTo(isTight ? new InitTightState(context) : new InitState(context));
+		context.setTight(isTight);
+	}
+
+	/**
+	 * Check Security Result received from server
+	 * May be:
+	 * * 0 - OK
+	 * * 1 - Failed
+	 * @throws TransportException
+	 * @throws AuthenticationFailedException
+	 */
+	protected void checkSecurityResult() throws TransportException,
+	AuthenticationFailedException {
+		if (reader.readInt32() != AUTH_RESULT_OK) {
+			try {
+				String reason = reader.readString();
+				throw new AuthenticationFailedException(reason);
+			} catch (ClosedConnectionException e) {
+				// protocol version 3.3 and 3.7 does not send reason string,
+				// but silently closes the connection
+				throw new AuthenticationFailedException("Authentication failed");
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/HandshakeState.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,97 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HandshakeState extends ProtocolState {
+
+	public static final String PROTOCOL_VERSION_3_8 = "3.8";
+	public static final String PROTOCOL_VERSION_3_7 = "3.7";
+	public static final String PROTOCOL_VERSION_3_3 = "3.3";
+	private static final int PROTOCOL_STRING_LENGTH = 12;
+	private static final String PROTOCOL_STRING_REGEXP = "^RFB (\\d\\d\\d).(\\d\\d\\d)\n$";
+
+	private static final int MIN_SUPPORTED_VERSION_MAJOR = 3;
+	private static final int MIN_SUPPORTED_VERSION_MINOR = 3;
+
+	private static final int MAX_SUPPORTED_VERSION_MAJOR = 3;
+	private static final int MAX_SUPPORTED_VERSION_MINOR = 8;
+
+	public HandshakeState(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException {
+		handshake();
+		return true;
+	}
+
+	private void handshake() throws TransportException, UnsupportedProtocolVersionException {
+		String protocolString = reader.readString(PROTOCOL_STRING_LENGTH);
+        Logger.getLogger(getClass().getName()).info("Server sent protocol string: " + protocolString.substring(0, protocolString.length() - 1));
+		Pattern pattern = Pattern.compile(PROTOCOL_STRING_REGEXP);
+		final Matcher matcher = pattern.matcher(protocolString);
+		if ( ! matcher.matches())
+			throw new UnsupportedProtocolVersionException(
+					"Unsupported protocol version: " + protocolString);
+		int major = Integer.parseInt(matcher.group(1));
+		int minor = Integer.parseInt(matcher.group(2));
+		if (major < MIN_SUPPORTED_VERSION_MAJOR ||
+				MIN_SUPPORTED_VERSION_MAJOR == major && minor <MIN_SUPPORTED_VERSION_MINOR)
+			throw new UnsupportedProtocolVersionException(
+					"Unsupported protocol version: " + major + "." + minor);
+		if (major > MAX_SUPPORTED_VERSION_MAJOR) {
+			major = MAX_SUPPORTED_VERSION_MAJOR;
+			minor = MAX_SUPPORTED_VERSION_MINOR;
+		}
+
+		if (minor >= MIN_SUPPORTED_VERSION_MINOR && minor < 7) {
+			changeStateTo(new SecurityType33State(context));
+			context.setProtocolVersion(PROTOCOL_VERSION_3_3);
+			minor = 3;
+		} else if (7 == minor) {
+			changeStateTo(new SecurityType37State(context));
+			context.setProtocolVersion(PROTOCOL_VERSION_3_7);
+			minor = 7;
+		} else if (minor >= MAX_SUPPORTED_VERSION_MINOR) {
+			changeStateTo(new SecurityTypeState(context));
+			context.setProtocolVersion(PROTOCOL_VERSION_3_8);
+			minor = 8;
+		} else
+			throw new UnsupportedProtocolVersionException(
+					"Unsupported protocol version: " + protocolString);
+		writer.write(("RFB 00" + major + ".00" + minor + "\n").getBytes());
+        Logger.getLogger(getClass().getName()).info("Set protocol version to: " + context.getProtocolVersion());
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/InitState.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,93 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.AuthenticationFailedException;
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.encoding.ServerInitMessage;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+
+import java.util.logging.Logger;
+
+/**
+ * ClientInit
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message onl@!,@!,y consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ *
+ * 1 - U8 - shared-flag
+ *
+ * Shared-flag is non-zero (true) if the server should try to share the desktop by leaving
+ * other clients connected, zero (false) if it should give exclusive access to this client by
+ * disconnecting all other clients.
+ *
+ * ServerInit
+ *
+ * After receiving the ClientInit message, the server sends a ServerInit message. This
+ * tells the client the width and height of the server’s framebuffer, its pixel format and the
+ * name associated with the desktop.
+ */
+public class InitState extends ProtocolState {
+
+	public InitState(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException,
+			UnsupportedSecurityTypeException, AuthenticationFailedException, FatalException {
+		clientAndServerInit();
+		return false;
+	}
+
+	protected void clientAndServerInit() throws TransportException {
+		ServerInitMessage serverInitMessage = getServerInitMessage();
+		ProtocolSettings settings = context.getSettings();
+		settings.enableAllEncodingCaps();
+		completeContextData(serverInitMessage);
+	}
+
+	protected void completeContextData(ServerInitMessage serverInitMessage) {
+		context.setPixelFormat(serverInitMessage.getPixelFormat());
+		context.setFbWidth(serverInitMessage.getFrameBufferWidth());
+		context.setFbHeight(serverInitMessage.getFrameBufferHeight());
+		context.setRemoteDesktopName(serverInitMessage.getName());
+        Logger.getLogger(getClass().getName()).fine(serverInitMessage.toString());
+	}
+
+	protected ServerInitMessage getServerInitMessage() throws TransportException {
+		writer.write(context.getSettings().getSharedFlag());
+        return new ServerInitMessage(reader);
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/InitTightState.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,75 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.ServerInitMessage;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+
+/**
+ * Server Interaction Capabilities Message (protocol versions 3.7t, 3.8t)
+ *
+ * If TightVNC protocol extensions are enabled, the server informs the client
+ * what message types it supports in addition to ones defined in the standard
+ * RFB protocol.
+ * Also, the server sends the list of all supported encodings (note that it's
+ * not necessary to advertise the "raw" encoding sinse it MUST be supported in
+ * RFB 3.x protocols).
+ *
+ * This data immediately follows the server initialisation message.
+ */
+public class InitTightState extends InitState {
+
+	public InitTightState(ProtocolContext context) {
+		super(context);
+	}
+
+	/**
+	 * typedef struct _rfbInteractionCapsMsg {
+	 * 		CARD16 nServerMessageTypes;
+	 * 		CARD16 nClientMessageTypes;
+	 * 		CARD16 nEncodingTypes;
+	 * 		CARD16 pad;><------><------>// reserved, must be 0
+	 * 		// followed by nServerMessageTypes * rfbCapabilityInfo structures
+	 * 		// followed by nClientMessageTypes * rfbCapabilityInfo structures
+	 * } rfbInteractionCapsMsg;
+	 * #define sz_rfbInteractionCapsMsg 8
+	 */
+	@Override
+	protected void clientAndServerInit() throws TransportException {
+		ServerInitMessage serverInitMessage = getServerInitMessage();
+		int nServerMessageTypes = reader.readUInt16();
+		int nClientMessageTypes = reader.readUInt16();
+		int nEncodingTypes = reader.readUInt16();
+		reader.readUInt16(); //padding
+		ProtocolSettings settings = context.getSettings();
+		settings.serverMessagesCapabilities.read(reader, nServerMessageTypes);
+		settings.clientMessagesCapabilities.read(reader, nClientMessageTypes);
+		settings.encodingTypesCapabilities.read(reader, nEncodingTypes);
+		completeContextData(serverInitMessage);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/ProtocolState.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,60 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.*;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+abstract public class ProtocolState {
+	protected ProtocolContext context;
+	protected Reader reader;
+	protected Writer writer;
+
+	public ProtocolState(ProtocolContext context) {
+		this.context = context;
+		this.reader = context.getReader();
+		this.writer = context.getWriter();
+	}
+
+	/**
+	 * Change state of finite machine.
+	 *
+	 * @param state state, the Finite Machine will switched to
+	 */
+	protected void changeStateTo(ProtocolState state) {
+		context.changeStateTo(state);
+	}
+
+	/**
+	 * Carry out next step of protocol flow.
+	 *
+	 * @return false when no next protocol steps availabe, true - when need to continue
+	 */
+	abstract public boolean next() throws UnsupportedProtocolVersionException, TransportException,
+			UnsupportedSecurityTypeException, AuthenticationFailedException, FatalException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/SecurityType33State.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,61 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+
+import java.util.logging.Logger;
+
+public class SecurityType33State extends SecurityType37State {
+
+	public SecurityType33State(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	protected void negotiateAboutSecurityType()
+			throws TransportException, UnsupportedSecurityTypeException {
+        Logger.getLogger(getClass().getName()).info("Get Security Type");
+		int type = reader.readInt32();
+		Logger.getLogger(getClass().getName()).info("Type received: " + type);
+		if (0 == type)
+			// throw exception with reason
+			throw new UnsupportedSecurityTypeException(reader.readString());
+		AuthHandler typeSelected = selectAuthHandler(new byte[] {(byte) (0xff & type)},
+					context.getSettings().authCapabilities);
+		if (typeSelected != null) {
+			setUseSecurityResult(typeSelected);
+			Logger.getLogger(getClass().getName()).info("Type accepted: " + typeSelected.getName());
+		} else
+			throw new UnsupportedSecurityTypeException(
+					"No security types supported. Server sent '" +
+					type + "' security type, but we do not support it.");
+		changeStateTo(new AuthenticationState(context, typeSelected));
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/SecurityType37State.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,43 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+import com.glavsoft.rfb.protocol.auth.SecurityType;
+
+public class SecurityType37State extends SecurityTypeState {
+
+	public SecurityType37State(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	protected void setUseSecurityResult(AuthHandler type) {
+		if (SecurityType.NONE_AUTHENTICATION == type.getType()) {
+			type.setUseSecurityResult(false);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/SecurityTypeState.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,107 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+import com.glavsoft.rfb.protocol.auth.SecurityType;
+import com.glavsoft.utils.Strings;
+
+import java.util.logging.Logger;
+
+public class SecurityTypeState extends ProtocolState {
+
+	public SecurityTypeState(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException, UnsupportedSecurityTypeException {
+		negotiateAboutSecurityType();
+		return true;
+	}
+
+	protected void negotiateAboutSecurityType() throws TransportException,
+			UnsupportedSecurityTypeException {
+		int secTypesNum = reader.readUInt8();
+		if (0 == secTypesNum)
+			// throw exception with reason
+			throw new UnsupportedSecurityTypeException(reader.readString());
+		byte[] secTypes = reader.readBytes(secTypesNum);
+        Logger.getLogger(getClass().getName()).info("Security Types received (" + secTypesNum + "): "
+                + Strings.toString(secTypes));
+		AuthHandler typeSelected = selectAuthHandler(
+				secTypes, context.getSettings().authCapabilities);
+		setUseSecurityResult(typeSelected);
+		writer.writeByte(typeSelected.getId());
+        Logger.getLogger(getClass().getName()).info("Security Type accepted: " + typeSelected.getName());
+
+		changeStateTo(new AuthenticationState(context, typeSelected));
+	}
+
+	/**
+	 * Select apropriate security type we supporded from types which server sent
+	 *
+	 * @param secTypes - byte array with security types server supported
+	 * @param authCapabilities
+	 * @return {@link AuthHandler} of selected type
+	 * @throws UnsupportedSecurityTypeException when no security types server sent we support
+	 */
+	public static AuthHandler selectAuthHandler(byte[] secTypes, CapabilityContainer authCapabilities)
+	throws UnsupportedSecurityTypeException {
+		AuthHandler typeSelected = null;
+		// Tigh Authentication first
+		for (byte type : secTypes) {
+			if (SecurityType.TIGHT_AUTHENTICATION.getId() == (0xff & type)) {
+				typeSelected = SecurityType.implementedSecurityTypes
+					.get(SecurityType.TIGHT_AUTHENTICATION.getId());
+				if (typeSelected != null)
+					return typeSelected;
+			}
+		}
+		for (byte type : secTypes) {
+			typeSelected = SecurityType.implementedSecurityTypes.get(0xff & type);
+			if (typeSelected != null &&
+					authCapabilities.isSupported(typeSelected.getId()))
+				return typeSelected;
+		}
+		throw new UnsupportedSecurityTypeException(
+				"No security types supported. Server sent '"
+						+ Strings.toString(secTypes)
+						+ "' security types, but we do not support any of their.");
+	}
+
+	/**
+	 * @param typeSelected
+	 */
+	protected void setUseSecurityResult(AuthHandler typeSelected) {
+		// nop for Protocol version 3.8 and above
+	}
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/transport/Reader.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,166 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.transport;
+
+import com.glavsoft.exceptions.ClosedConnectionException;
+import com.glavsoft.exceptions.TransportException;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+public class Reader {
+	final static Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+	final static Charset UTF8 = Charset.forName("UTF-8");
+	private final DataInputStream is;
+
+	public Reader(InputStream is) {
+		this.is = new DataInputStream(new BufferedInputStream(is));
+	}
+
+	public byte readByte() throws TransportException {
+		try {
+			byte readByte = is.readByte();
+			return readByte;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read byte", e);
+		}
+
+	}
+
+	public int readUInt8() throws TransportException {
+		return readByte() & 0x0ff;
+	}
+
+	public int readUInt16() throws TransportException {
+		return readInt16() & 0x0ffff;
+	}
+
+	public short readInt16() throws TransportException {
+		try {
+			short readShort = is.readShort();
+			return readShort;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read int16", e);
+		}
+	}
+
+	public long readUInt32() throws TransportException {
+		return readInt32() & 0xffffffffL;
+	}
+
+	public int readInt32() throws TransportException {
+		try {
+			int readInt = is.readInt();
+			return readInt;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read int32", e);
+		}
+	}
+
+	public long readInt64() throws TransportException {
+		try {
+			return is.readLong();
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read int32", e);
+		}
+	}
+
+	/**
+	 * Read string by it length.
+	 * Use this method only when sure no character accept ASCII will be read.
+	 * Use readBytes and character encoding conversion instead.
+	 *
+	 * @return String read
+	 */
+	public String readString(int length) throws TransportException {
+        return new String(readBytes(length));
+	}
+
+	/**
+	 * Read 32-bit string length and then string themself by it length
+	 * Use this method only when sure no character accept ASCII will be read.
+	 * Use readBytes and character encoding conversion instead or {@link #readUtf8String} method
+	 * when utf-8 encoding needed.
+	 *
+	 * @return String read
+	 * @throws TransportException
+	 */
+	public String readString() throws TransportException {
+		// unset most significant (sign) bit 'cause InputStream#readFully reads
+		// [int] length bytes from stream. Change when really need read string more
+		// than 2147483647 bytes length
+		int length = readInt32() & Integer.MAX_VALUE;
+		return readString(length);
+	}
+
+	/**
+	 * Read 32-bit string length and then string themself by it length
+	 * Assume UTF-8 character encoding used
+	 *
+	 * @return String read
+	 * @throws TransportException
+	 */
+	public String readUtf8String() throws TransportException {
+		// unset most significant (sign) bit 'cause InputStream#readFully  reads
+		// [int] length bytes from stream. Change when really need read string more
+		// than 2147483647 bytes length
+		int length = readInt32() & Integer.MAX_VALUE;
+		return new String(readBytes(length));
+	}
+
+	public byte[] readBytes(int length) throws TransportException {
+		byte b[] = new byte[length];
+		return readBytes(b, 0, length);
+	}
+
+	public byte[] readBytes(byte[] b, int offset, int length) throws TransportException {
+		try {
+			is.readFully(b, offset, length);
+			return b;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read " + length + " bytes array", e);
+		}
+	}
+
+	public void skip(int length) throws TransportException {
+		try {
+			is.skipBytes(length);
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot skip " + length + " bytes", e);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/transport/Writer.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,108 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.transport;
+
+import com.glavsoft.exceptions.TransportException;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Writer {
+	private final DataOutputStream os;
+
+	public Writer(OutputStream os) {
+		this.os = new DataOutputStream(os);
+	}
+
+	public void flush() throws TransportException {
+		try {
+			os.flush();
+		} catch (IOException e) {
+			throw new TransportException("Cannot flush output stream", e);
+		}
+	}
+
+	public void writeByte(int b) throws TransportException {
+		write((byte) (b & 0xff));
+	}
+
+	public void write(byte b) throws TransportException {
+		try {
+			os.writeByte(b);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write byte", e);
+		}
+	}
+
+	public void writeInt16(int sh) throws TransportException {
+		write((short) (sh & 0xffff));
+	}
+
+	public void write(short sh) throws TransportException {
+		try {
+			os.writeShort(sh);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write short", e);
+		}
+	}
+
+	public void writeInt32(int i) throws TransportException {
+		write(i);
+	}
+
+	public void writeInt64(long i) throws TransportException {
+		try {
+			os.writeLong(i);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write long", e);
+		}
+	}
+
+	public void write(int i) throws TransportException {
+		try {
+			os.writeInt(i);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write int", e);
+		}
+	}
+
+	public void write(byte[] b) throws TransportException {
+		write(b, 0, b.length);
+	}
+
+	public void write(byte[] b, int length) throws TransportException {
+		write(b, 0, length);
+	}
+
+	public void write(byte[] b, int offset, int length)
+			throws TransportException {
+		try {
+			os.write(b, offset, length <= b.length ? length : b.length);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write " + length + " bytes", e);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/utils/Keymap.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,905 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class Keymap {
+
+	public static final int K_F1 = 0xffbe;
+	public static final int K_F2 = 0xffbf;
+	public static final int K_F3 = 0xffc0;
+	public static final int K_F4 = 0xffc1;
+	public static final int K_F5 = 0xffc2;
+	public static final int K_F6 = 0xffc3;
+	public static final int K_F7 = 0xffc4;
+	public static final int K_F8 = 0xffc5;
+	public static final int K_F9 = 0xffc6;
+	public static final int K_F10 = 0xffc7;
+	public static final int K_F11 = 0xffc8;
+	public static final int K_F12 = 0xffc9;
+	public static final int K_INSERT = 0xff63;
+	public static final int K_DELETE = 0xffff;
+	public static final int K_HOME = 0xff50;
+	public static final int K_END = 0xff57;
+	public static final int K_PAGE_DOWN = 0xff56;
+	public static final int K_PAGE_UP = 0xff55;
+	public static final int K_DOWN = 0xff54;
+	public static final int K_RIGHT = 0xff53;
+	public static final int K_UP = 0xff52;
+	public static final int K_LEFT = 0xff51;
+	public static final int K_ESCAPE = 0xff1b;
+	public static final int K_ENTER = 0xff0d;
+	public static final int K_TAB = 0xff09;
+	public static final int K_BACK_SPACE = 0xff08;
+	public static final int K_ALT_LEFT = 0xffe9;
+	public static final int K_META_LEFT = 0xffe7;
+	public static final int K_SHIFT_LEFT = 0xffe1;
+	public static final int K_CTRL_LEFT = 0xffe3;
+	public static final int K_SUPER_LEFT = 0xffeb;
+	public static final int K_HYPER_LEFT = 0xffed;
+
+	public static final int K_KP_SPACE = 0xFF80;
+	public static final int K_KP_TAB = 0xFF89;
+	public static final int K_KP_ENTER = 0xFF8D;
+	public static final int K_KP_F1 = 0xFF91;
+	public static final int K_KP_F2 = 0xFF92;
+	public static final int K_KP_F3 = 0xFF93;
+	public static final int K_KP_F4 = 0xFF94;
+	public static final int K_KP_HOME = 0xFF95;
+	public static final int K_KP_LEFT = 0xFF96;
+	public static final int K_KP_UP = 0xFF97;
+	public static final int K_KP_RIGHT = 0xFF98;
+	public static final int K_KP_DOWN = 0xFF99;
+	public static final int K_KP_PRIOR = 0xFF9A;
+	public static final int K_KP_PAGE_UP = 0xFF9A;
+	public static final int K_KP_NEXT = 0xFF9B;
+	public static final int K_KP_PAGE_DOWN = 0xFF9B;
+	public static final int K_KP_END = 0xFF9C;
+	public static final int K_KP_BEGIN = 0xFF9D;
+	public static final int K_KP_INSERT = 0xFF9E;
+	public static final int K_KP_DELETE = 0xFF9F;
+	public static final int K_KP_EQUAL = 0xFFBD;
+
+	public static final int K_KP_MULTIPLY = 0xFFAA;
+	public static final int K_KP_ADD = 0xFFAB;
+	public static final int K_KP_SEPARATOR = 0xFFAC; /* separator, often comma */
+	public static final int K_KP_SUBTRACT = 0xFFAD;
+	public static final int K_KP_DECIMAL = 0xFFAE;
+	public static final int K_KP_DIVIDE = 0xFFAF;
+
+	public static final int K_KP_0 = 0xFFB0;
+	public static final int K_KP_1 = 0xFFB1;
+	public static final int K_KP_2 = 0xFFB2;
+	public static final int K_KP_3 = 0xFFB3;
+	public static final int K_KP_4 = 0xFFB4;
+	public static final int K_KP_5 = 0xFFB5;
+	public static final int K_KP_6 = 0xFFB6;
+	public static final int K_KP_7 = 0xFFB7;
+	public static final int K_KP_8 = 0xFFB8;
+	public static final int K_KP_9 = 0xFFB9;
+
+	private static Map<Integer, Integer> keyMap = toMap(new int[][] {
+		// X      Unicode
+		{ 0x01a1, 0x0104 }, /*                     Aogonek  LATIN CAPITAL LETTER A WITH OGONEK */
+		{ 0x01a2, 0x02d8 }, /*                       breve  BREVE */
+		{ 0x01a3, 0x0141 }, /*                     Lstroke  LATIN CAPITAL LETTER L WITH STROKE */
+		{ 0x01a5, 0x013d }, /*                      Lcaron  LATIN CAPITAL LETTER L WITH CARON */
+		{ 0x01a6, 0x015a }, /*                      Sacute  LATIN CAPITAL LETTER S WITH ACUTE */
+		{ 0x01a9, 0x0160 }, /*                      Scaron  LATIN CAPITAL LETTER S WITH CARON */
+		{ 0x01aa, 0x015e }, /*                    Scedilla  LATIN CAPITAL LETTER S WITH CEDILLA */
+		{ 0x01ab, 0x0164 }, /*                      Tcaron  LATIN CAPITAL LETTER T WITH CARON */
+		{ 0x01ac, 0x0179 }, /*                      Zacute  LATIN CAPITAL LETTER Z WITH ACUTE */
+		{ 0x01ae, 0x017d }, /*                      Zcaron  LATIN CAPITAL LETTER Z WITH CARON */
+		{ 0x01af, 0x017b }, /*                   Zabovedot  LATIN CAPITAL LETTER Z WITH DOT ABOVE */
+		{ 0x01b1, 0x0105 }, /*                     aogonek  LATIN SMALL LETTER A WITH OGONEK */
+		{ 0x01b2, 0x02db }, /*                      ogonek  OGONEK */
+		{ 0x01b3, 0x0142 }, /*                     lstroke  LATIN SMALL LETTER L WITH STROKE */
+		{ 0x01b5, 0x013e }, /*                      lcaron  LATIN SMALL LETTER L WITH CARON */
+		{ 0x01b6, 0x015b }, /*                      sacute  LATIN SMALL LETTER S WITH ACUTE */
+		{ 0x01b7, 0x02c7 }, /*                       caron  CARON */
+		{ 0x01b9, 0x0161 }, /*                      scaron  LATIN SMALL LETTER S WITH CARON */
+		{ 0x01ba, 0x015f }, /*                    scedilla  LATIN SMALL LETTER S WITH CEDILLA */
+		{ 0x01bb, 0x0165 }, /*                      tcaron  LATIN SMALL LETTER T WITH CARON */
+		{ 0x01bc, 0x017a }, /*                      zacute  LATIN SMALL LETTER Z WITH ACUTE */
+		{ 0x01bd, 0x02dd }, /*                 doubleacute  DOUBLE ACUTE ACCENT */
+		{ 0x01be, 0x017e }, /*                      zcaron  LATIN SMALL LETTER Z WITH CARON */
+		{ 0x01bf, 0x017c }, /*                   zabovedot  LATIN SMALL LETTER Z WITH DOT ABOVE */
+		{ 0x01c0, 0x0154 }, /*                      Racute  LATIN CAPITAL LETTER R WITH ACUTE */
+		{ 0x01c3, 0x0102 }, /*                      Abreve  LATIN CAPITAL LETTER A WITH BREVE */
+		{ 0x01c5, 0x0139 }, /*                      Lacute  LATIN CAPITAL LETTER L WITH ACUTE */
+		{ 0x01c6, 0x0106 }, /*                      Cacute  LATIN CAPITAL LETTER C WITH ACUTE */
+		{ 0x01c8, 0x010c }, /*                      Ccaron  LATIN CAPITAL LETTER C WITH CARON */
+		{ 0x01ca, 0x0118 }, /*                     Eogonek  LATIN CAPITAL LETTER E WITH OGONEK */
+		{ 0x01cc, 0x011a }, /*                      Ecaron  LATIN CAPITAL LETTER E WITH CARON */
+		{ 0x01cf, 0x010e }, /*                      Dcaron  LATIN CAPITAL LETTER D WITH CARON */
+		{ 0x01d0, 0x0110 }, /*                     Dstroke  LATIN CAPITAL LETTER D WITH STROKE */
+		{ 0x01d1, 0x0143 }, /*                      Nacute  LATIN CAPITAL LETTER N WITH ACUTE */
+		{ 0x01d2, 0x0147 }, /*                      Ncaron  LATIN CAPITAL LETTER N WITH CARON */
+		{ 0x01d5, 0x0150 }, /*                Odoubleacute  LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
+		{ 0x01d8, 0x0158 }, /*                      Rcaron  LATIN CAPITAL LETTER R WITH CARON */
+		{ 0x01d9, 0x016e }, /*                       Uring  LATIN CAPITAL LETTER U WITH RING ABOVE */
+		{ 0x01db, 0x0170 }, /*                Udoubleacute  LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
+		{ 0x01de, 0x0162 }, /*                    Tcedilla  LATIN CAPITAL LETTER T WITH CEDILLA */
+		{ 0x01e0, 0x0155 }, /*                      racute  LATIN SMALL LETTER R WITH ACUTE */
+		{ 0x01e3, 0x0103 }, /*                      abreve  LATIN SMALL LETTER A WITH BREVE */
+		{ 0x01e5, 0x013a }, /*                      lacute  LATIN SMALL LETTER L WITH ACUTE */
+		{ 0x01e6, 0x0107 }, /*                      cacute  LATIN SMALL LETTER C WITH ACUTE */
+		{ 0x01e8, 0x010d }, /*                      ccaron  LATIN SMALL LETTER C WITH CARON */
+		{ 0x01ea, 0x0119 }, /*                     eogonek  LATIN SMALL LETTER E WITH OGONEK */
+		{ 0x01ec, 0x011b }, /*                      ecaron  LATIN SMALL LETTER E WITH CARON */
+		{ 0x01ef, 0x010f }, /*                      dcaron  LATIN SMALL LETTER D WITH CARON */
+		{ 0x01f0, 0x0111 }, /*                     dstroke  LATIN SMALL LETTER D WITH STROKE */
+		{ 0x01f1, 0x0144 }, /*                      nacute  LATIN SMALL LETTER N WITH ACUTE */
+		{ 0x01f2, 0x0148 }, /*                      ncaron  LATIN SMALL LETTER N WITH CARON */
+		{ 0x01f5, 0x0151 }, /*                odoubleacute  LATIN SMALL LETTER O WITH DOUBLE ACUTE */
+		{ 0x01f8, 0x0159 }, /*                      rcaron  LATIN SMALL LETTER R WITH CARON */
+		{ 0x01f9, 0x016f }, /*                       uring  LATIN SMALL LETTER U WITH RING ABOVE */
+		{ 0x01fb, 0x0171 }, /*                udoubleacute  LATIN SMALL LETTER U WITH DOUBLE ACUTE */
+		{ 0x01fe, 0x0163 }, /*                    tcedilla  LATIN SMALL LETTER T WITH CEDILLA */
+		{ 0x01ff, 0x02d9 }, /*                    abovedot  DOT ABOVE */
+		{ 0x02a1, 0x0126 }, /*                     Hstroke  LATIN CAPITAL LETTER H WITH STROKE */
+		{ 0x02a6, 0x0124 }, /*                 Hcircumflex  LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
+		{ 0x02a9, 0x0130 }, /*                   Iabovedot  LATIN CAPITAL LETTER I WITH DOT ABOVE */
+		{ 0x02ab, 0x011e }, /*                      Gbreve  LATIN CAPITAL LETTER G WITH BREVE */
+		{ 0x02ac, 0x0134 }, /*                 Jcircumflex  LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
+		{ 0x02b1, 0x0127 }, /*                     hstroke  LATIN SMALL LETTER H WITH STROKE */
+		{ 0x02b6, 0x0125 }, /*                 hcircumflex  LATIN SMALL LETTER H WITH CIRCUMFLEX */
+		{ 0x02b9, 0x0131 }, /*                    idotless  LATIN SMALL LETTER DOTLESS I */
+		{ 0x02bb, 0x011f }, /*                      gbreve  LATIN SMALL LETTER G WITH BREVE */
+		{ 0x02bc, 0x0135 }, /*                 jcircumflex  LATIN SMALL LETTER J WITH CIRCUMFLEX */
+		{ 0x02c5, 0x010a }, /*                   Cabovedot  LATIN CAPITAL LETTER C WITH DOT ABOVE */
+		{ 0x02c6, 0x0108 }, /*                 Ccircumflex  LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
+		{ 0x02d5, 0x0120 }, /*                   Gabovedot  LATIN CAPITAL LETTER G WITH DOT ABOVE */
+		{ 0x02d8, 0x011c }, /*                 Gcircumflex  LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
+		{ 0x02dd, 0x016c }, /*                      Ubreve  LATIN CAPITAL LETTER U WITH BREVE */
+		{ 0x02de, 0x015c }, /*                 Scircumflex  LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
+		{ 0x02e5, 0x010b }, /*                   cabovedot  LATIN SMALL LETTER C WITH DOT ABOVE */
+		{ 0x02e6, 0x0109 }, /*                 ccircumflex  LATIN SMALL LETTER C WITH CIRCUMFLEX */
+		{ 0x02f5, 0x0121 }, /*                   gabovedot  LATIN SMALL LETTER G WITH DOT ABOVE */
+		{ 0x02f8, 0x011d }, /*                 gcircumflex  LATIN SMALL LETTER G WITH CIRCUMFLEX */
+		{ 0x02fd, 0x016d }, /*                      ubreve  LATIN SMALL LETTER U WITH BREVE */
+		{ 0x02fe, 0x015d }, /*                 scircumflex  LATIN SMALL LETTER S WITH CIRCUMFLEX */
+		{ 0x03a2, 0x0138 }, /*                         kra  LATIN SMALL LETTER KRA */
+		{ 0x03a3, 0x0156 }, /*                    Rcedilla  LATIN CAPITAL LETTER R WITH CEDILLA */
+		{ 0x03a5, 0x0128 }, /*                      Itilde  LATIN CAPITAL LETTER I WITH TILDE */
+		{ 0x03a6, 0x013b }, /*                    Lcedilla  LATIN CAPITAL LETTER L WITH CEDILLA */
+		{ 0x03aa, 0x0112 }, /*                     Emacron  LATIN CAPITAL LETTER E WITH MACRON */
+		{ 0x03ab, 0x0122 }, /*                    Gcedilla  LATIN CAPITAL LETTER G WITH CEDILLA */
+		{ 0x03ac, 0x0166 }, /*                      Tslash  LATIN CAPITAL LETTER T WITH STROKE */
+		{ 0x03b3, 0x0157 }, /*                    rcedilla  LATIN SMALL LETTER R WITH CEDILLA */
+		{ 0x03b5, 0x0129 }, /*                      itilde  LATIN SMALL LETTER I WITH TILDE */
+		{ 0x03b6, 0x013c }, /*                    lcedilla  LATIN SMALL LETTER L WITH CEDILLA */
+		{ 0x03ba, 0x0113 }, /*                     emacron  LATIN SMALL LETTER E WITH MACRON */
+		{ 0x03bb, 0x0123 }, /*                    gcedilla  LATIN SMALL LETTER G WITH CEDILLA */
+		{ 0x03bc, 0x0167 }, /*                      tslash  LATIN SMALL LETTER T WITH STROKE */
+		{ 0x03bd, 0x014a }, /*                         ENG  LATIN CAPITAL LETTER ENG */
+		{ 0x03bf, 0x014b }, /*                         eng  LATIN SMALL LETTER ENG */
+		{ 0x03c0, 0x0100 }, /*                     Amacron  LATIN CAPITAL LETTER A WITH MACRON */
+		{ 0x03c7, 0x012e }, /*                     Iogonek  LATIN CAPITAL LETTER I WITH OGONEK */
+		{ 0x03cc, 0x0116 }, /*                   Eabovedot  LATIN CAPITAL LETTER E WITH DOT ABOVE */
+		{ 0x03cf, 0x012a }, /*                     Imacron  LATIN CAPITAL LETTER I WITH MACRON */
+		{ 0x03d1, 0x0145 }, /*                    Ncedilla  LATIN CAPITAL LETTER N WITH CEDILLA */
+		{ 0x03d2, 0x014c }, /*                     Omacron  LATIN CAPITAL LETTER O WITH MACRON */
+		{ 0x03d3, 0x0136 }, /*                    Kcedilla  LATIN CAPITAL LETTER K WITH CEDILLA */
+		{ 0x03d9, 0x0172 }, /*                     Uogonek  LATIN CAPITAL LETTER U WITH OGONEK */
+		{ 0x03dd, 0x0168 }, /*                      Utilde  LATIN CAPITAL LETTER U WITH TILDE */
+		{ 0x03de, 0x016a }, /*                     Umacron  LATIN CAPITAL LETTER U WITH MACRON */
+		{ 0x03e0, 0x0101 }, /*                     amacron  LATIN SMALL LETTER A WITH MACRON */
+		{ 0x03e7, 0x012f }, /*                     iogonek  LATIN SMALL LETTER I WITH OGONEK */
+		{ 0x03ec, 0x0117 }, /*                   eabovedot  LATIN SMALL LETTER E WITH DOT ABOVE */
+		{ 0x03ef, 0x012b }, /*                     imacron  LATIN SMALL LETTER I WITH MACRON */
+		{ 0x03f1, 0x0146 }, /*                    ncedilla  LATIN SMALL LETTER N WITH CEDILLA */
+		{ 0x03f2, 0x014d }, /*                     omacron  LATIN SMALL LETTER O WITH MACRON */
+		{ 0x03f3, 0x0137 }, /*                    kcedilla  LATIN SMALL LETTER K WITH CEDILLA */
+		{ 0x03f9, 0x0173 }, /*                     uogonek  LATIN SMALL LETTER U WITH OGONEK */
+		{ 0x03fd, 0x0169 }, /*                      utilde  LATIN SMALL LETTER U WITH TILDE */
+		{ 0x03fe, 0x016b }, /*                     umacron  LATIN SMALL LETTER U WITH MACRON */
+		{ 0x047e, 0x203e }, /*                    overline  OVERLINE */
+		{ 0x04a1, 0x3002 }, /*               kana_fullstop  IDEOGRAPHIC FULL STOP */
+		{ 0x04a2, 0x300c }, /*         kana_openingbracket  LEFT CORNER BRACKET */
+		{ 0x04a3, 0x300d }, /*         kana_closingbracket  RIGHT CORNER BRACKET */
+		{ 0x04a4, 0x3001 }, /*                  kana_comma  IDEOGRAPHIC COMMA */
+		{ 0x04a5, 0x30fb }, /*            kana_conjunctive  KATAKANA MIDDLE DOT */
+		{ 0x04a6, 0x30f2 }, /*                     kana_WO  KATAKANA LETTER WO */
+		{ 0x04a7, 0x30a1 }, /*                      kana_a  KATAKANA LETTER SMALL A */
+		{ 0x04a8, 0x30a3 }, /*                      kana_i  KATAKANA LETTER SMALL I */
+		{ 0x04a9, 0x30a5 }, /*                      kana_u  KATAKANA LETTER SMALL U */
+		{ 0x04aa, 0x30a7 }, /*                      kana_e  KATAKANA LETTER SMALL E */
+		{ 0x04ab, 0x30a9 }, /*                      kana_o  KATAKANA LETTER SMALL O */
+		{ 0x04ac, 0x30e3 }, /*                     kana_ya  KATAKANA LETTER SMALL YA */
+		{ 0x04ad, 0x30e5 }, /*                     kana_yu  KATAKANA LETTER SMALL YU */
+		{ 0x04ae, 0x30e7 }, /*                     kana_yo  KATAKANA LETTER SMALL YO */
+		{ 0x04af, 0x30c3 }, /*                    kana_tsu  KATAKANA LETTER SMALL TU */
+		{ 0x04b0, 0x30fc }, /*              prolongedsound  KATAKANA-HIRAGANA PROLONGED SOUND MARK */
+		{ 0x04b1, 0x30a2 }, /*                      kana_A  KATAKANA LETTER A */
+		{ 0x04b2, 0x30a4 }, /*                      kana_I  KATAKANA LETTER I */
+		{ 0x04b3, 0x30a6 }, /*                      kana_U  KATAKANA LETTER U */
+		{ 0x04b4, 0x30a8 }, /*                      kana_E  KATAKANA LETTER E */
+		{ 0x04b5, 0x30aa }, /*                      kana_O  KATAKANA LETTER O */
+		{ 0x04b6, 0x30ab }, /*                     kana_KA  KATAKANA LETTER KA */
+		{ 0x04b7, 0x30ad }, /*                     kana_KI  KATAKANA LETTER KI */
+		{ 0x04b8, 0x30af }, /*                     kana_KU  KATAKANA LETTER KU */
+		{ 0x04b9, 0x30b1 }, /*                     kana_KE  KATAKANA LETTER KE */
+		{ 0x04ba, 0x30b3 }, /*                     kana_KO  KATAKANA LETTER KO */
+		{ 0x04bb, 0x30b5 }, /*                     kana_SA  KATAKANA LETTER SA */
+		{ 0x04bc, 0x30b7 }, /*                    kana_SHI  KATAKANA LETTER SI */
+		{ 0x04bd, 0x30b9 }, /*                     kana_SU  KATAKANA LETTER SU */
+		{ 0x04be, 0x30bb }, /*                     kana_SE  KATAKANA LETTER SE */
+		{ 0x04bf, 0x30bd }, /*                     kana_SO  KATAKANA LETTER SO */
+		{ 0x04c0, 0x30bf }, /*                     kana_TA  KATAKANA LETTER TA */
+		{ 0x04c1, 0x30c1 }, /*                    kana_CHI  KATAKANA LETTER TI */
+		{ 0x04c2, 0x30c4 }, /*                    kana_TSU  KATAKANA LETTER TU */
+		{ 0x04c3, 0x30c6 }, /*                     kana_TE  KATAKANA LETTER TE */
+		{ 0x04c4, 0x30c8 }, /*                     kana_TO  KATAKANA LETTER TO */
+		{ 0x04c5, 0x30ca }, /*                     kana_NA  KATAKANA LETTER NA */
+		{ 0x04c6, 0x30cb }, /*                     kana_NI  KATAKANA LETTER NI */
+		{ 0x04c7, 0x30cc }, /*                     kana_NU  KATAKANA LETTER NU */
+		{ 0x04c8, 0x30cd }, /*                     kana_NE  KATAKANA LETTER NE */
+		{ 0x04c9, 0x30ce }, /*                     kana_NO  KATAKANA LETTER NO */
+		{ 0x04ca, 0x30cf }, /*                     kana_HA  KATAKANA LETTER HA */
+		{ 0x04cb, 0x30d2 }, /*                     kana_HI  KATAKANA LETTER HI */
+		{ 0x04cc, 0x30d5 }, /*                     kana_FU  KATAKANA LETTER HU */
+		{ 0x04cd, 0x30d8 }, /*                     kana_HE  KATAKANA LETTER HE */
+		{ 0x04ce, 0x30db }, /*                     kana_HO  KATAKANA LETTER HO */
+		{ 0x04cf, 0x30de }, /*                     kana_MA  KATAKANA LETTER MA */
+		{ 0x04d0, 0x30df }, /*                     kana_MI  KATAKANA LETTER MI */
+		{ 0x04d1, 0x30e0 }, /*                     kana_MU  KATAKANA LETTER MU */
+		{ 0x04d2, 0x30e1 }, /*                     kana_ME  KATAKANA LETTER ME */
+		{ 0x04d3, 0x30e2 }, /*                     kana_MO  KATAKANA LETTER MO */
+		{ 0x04d4, 0x30e4 }, /*                     kana_YA  KATAKANA LETTER YA */
+		{ 0x04d5, 0x30e6 }, /*                     kana_YU  KATAKANA LETTER YU */
+		{ 0x04d6, 0x30e8 }, /*                     kana_YO  KATAKANA LETTER YO */
+		{ 0x04d7, 0x30e9 }, /*                     kana_RA  KATAKANA LETTER RA */
+		{ 0x04d8, 0x30ea }, /*                     kana_RI  KATAKANA LETTER RI */
+		{ 0x04d9, 0x30eb }, /*                     kana_RU  KATAKANA LETTER RU */
+		{ 0x04da, 0x30ec }, /*                     kana_RE  KATAKANA LETTER RE */
+		{ 0x04db, 0x30ed }, /*                     kana_RO  KATAKANA LETTER RO */
+		{ 0x04dc, 0x30ef }, /*                     kana_WA  KATAKANA LETTER WA */
+		{ 0x04dd, 0x30f3 }, /*                      kana_N  KATAKANA LETTER N */
+		{ 0x04de, 0x309b }, /*                 voicedsound  KATAKANA-HIRAGANA VOICED SOUND MARK */
+		{ 0x04df, 0x309c }, /*             semivoicedsound  KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
+		{ 0x05ac, 0x060c }, /*                Arabic_comma  ARABIC COMMA */
+		{ 0x05bb, 0x061b }, /*            Arabic_semicolon  ARABIC SEMICOLON */
+		{ 0x05bf, 0x061f }, /*        Arabic_question_mark  ARABIC QUESTION MARK */
+		{ 0x05c1, 0x0621 }, /*                Arabic_hamza  ARABIC LETTER HAMZA */
+		{ 0x05c2, 0x0622 }, /*          Arabic_maddaonalef  ARABIC LETTER ALEF WITH MADDA ABOVE */
+		{ 0x05c3, 0x0623 }, /*          Arabic_hamzaonalef  ARABIC LETTER ALEF WITH HAMZA ABOVE */
+		{ 0x05c4, 0x0624 }, /*           Arabic_hamzaonwaw  ARABIC LETTER WAW WITH HAMZA ABOVE */
+		{ 0x05c5, 0x0625 }, /*       Arabic_hamzaunderalef  ARABIC LETTER ALEF WITH HAMZA BELOW */
+		{ 0x05c6, 0x0626 }, /*           Arabic_hamzaonyeh  ARABIC LETTER YEH WITH HAMZA ABOVE */
+		{ 0x05c7, 0x0627 }, /*                 Arabic_alef  ARABIC LETTER ALEF */
+		{ 0x05c8, 0x0628 }, /*                  Arabic_beh  ARABIC LETTER BEH */
+		{ 0x05c9, 0x0629 }, /*           Arabic_tehmarbuta  ARABIC LETTER TEH MARBUTA */
+		{ 0x05ca, 0x062a }, /*                  Arabic_teh  ARABIC LETTER TEH */
+		{ 0x05cb, 0x062b }, /*                 Arabic_theh  ARABIC LETTER THEH */
+		{ 0x05cc, 0x062c }, /*                 Arabic_jeem  ARABIC LETTER JEEM */
+		{ 0x05cd, 0x062d }, /*                  Arabic_hah  ARABIC LETTER HAH */
+		{ 0x05ce, 0x062e }, /*                 Arabic_khah  ARABIC LETTER KHAH */
+		{ 0x05cf, 0x062f }, /*                  Arabic_dal  ARABIC LETTER DAL */
+		{ 0x05d0, 0x0630 }, /*                 Arabic_thal  ARABIC LETTER THAL */
+		{ 0x05d1, 0x0631 }, /*                   Arabic_ra  ARABIC LETTER REH */
+		{ 0x05d2, 0x0632 }, /*                 Arabic_zain  ARABIC LETTER ZAIN */
+		{ 0x05d3, 0x0633 }, /*                 Arabic_seen  ARABIC LETTER SEEN */
+		{ 0x05d4, 0x0634 }, /*                Arabic_sheen  ARABIC LETTER SHEEN */
+		{ 0x05d5, 0x0635 }, /*                  Arabic_sad  ARABIC LETTER SAD */
+		{ 0x05d6, 0x0636 }, /*                  Arabic_dad  ARABIC LETTER DAD */
+		{ 0x05d7, 0x0637 }, /*                  Arabic_tah  ARABIC LETTER TAH */
+		{ 0x05d8, 0x0638 }, /*                  Arabic_zah  ARABIC LETTER ZAH */
+		{ 0x05d9, 0x0639 }, /*                  Arabic_ain  ARABIC LETTER AIN */
+		{ 0x05da, 0x063a }, /*                Arabic_ghain  ARABIC LETTER GHAIN */
+		{ 0x05e0, 0x0640 }, /*              Arabic_tatweel  ARABIC TATWEEL */
+		{ 0x05e1, 0x0641 }, /*                  Arabic_feh  ARABIC LETTER FEH */
+		{ 0x05e2, 0x0642 }, /*                  Arabic_qaf  ARABIC LETTER QAF */
+		{ 0x05e3, 0x0643 }, /*                  Arabic_kaf  ARABIC LETTER KAF */
+		{ 0x05e4, 0x0644 }, /*                  Arabic_lam  ARABIC LETTER LAM */
+		{ 0x05e5, 0x0645 }, /*                 Arabic_meem  ARABIC LETTER MEEM */
+		{ 0x05e6, 0x0646 }, /*                 Arabic_noon  ARABIC LETTER NOON */
+		{ 0x05e7, 0x0647 }, /*                   Arabic_ha  ARABIC LETTER HEH */
+		{ 0x05e8, 0x0648 }, /*                  Arabic_waw  ARABIC LETTER WAW */
+		{ 0x05e9, 0x0649 }, /*          Arabic_alefmaksura  ARABIC LETTER ALEF MAKSURA */
+		{ 0x05ea, 0x064a }, /*                  Arabic_yeh  ARABIC LETTER YEH */
+		{ 0x05eb, 0x064b }, /*             Arabic_fathatan  ARABIC FATHATAN */
+		{ 0x05ec, 0x064c }, /*             Arabic_dammatan  ARABIC DAMMATAN */
+		{ 0x05ed, 0x064d }, /*             Arabic_kasratan  ARABIC KASRATAN */
+		{ 0x05ee, 0x064e }, /*                Arabic_fatha  ARABIC FATHA */
+		{ 0x05ef, 0x064f }, /*                Arabic_damma  ARABIC DAMMA */
+		{ 0x05f0, 0x0650 }, /*                Arabic_kasra  ARABIC KASRA */
+		{ 0x05f1, 0x0651 }, /*               Arabic_shadda  ARABIC SHADDA */
+		{ 0x05f2, 0x0652 }, /*                Arabic_sukun  ARABIC SUKUN */
+		{ 0x06a1, 0x0452 }, /*                 Serbian_dje  CYRILLIC SMALL LETTER DJE */
+		{ 0x06a2, 0x0453 }, /*               Macedonia_gje  CYRILLIC SMALL LETTER GJE */
+		{ 0x06a3, 0x0451 }, /*                 Cyrillic_io  CYRILLIC SMALL LETTER IO */
+		{ 0x06a4, 0x0454 }, /*                Ukrainian_ie  CYRILLIC SMALL LETTER UKRAINIAN IE */
+		{ 0x06a5, 0x0455 }, /*               Macedonia_dse  CYRILLIC SMALL LETTER DZE */
+		{ 0x06a6, 0x0456 }, /*                 Ukrainian_i  CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+		{ 0x06a7, 0x0457 }, /*                Ukrainian_yi  CYRILLIC SMALL LETTER YI */
+		{ 0x06a8, 0x0458 }, /*                 Cyrillic_je  CYRILLIC SMALL LETTER JE */
+		{ 0x06a9, 0x0459 }, /*                Cyrillic_lje  CYRILLIC SMALL LETTER LJE */
+		{ 0x06aa, 0x045a }, /*                Cyrillic_nje  CYRILLIC SMALL LETTER NJE */
+		{ 0x06ab, 0x045b }, /*                Serbian_tshe  CYRILLIC SMALL LETTER TSHE */
+		{ 0x06ac, 0x045c }, /*               Macedonia_kje  CYRILLIC SMALL LETTER KJE */
+		{ 0x06ae, 0x045e }, /*         Byelorussian_shortu  CYRILLIC SMALL LETTER SHORT U */
+		{ 0x06af, 0x045f }, /*               Cyrillic_dzhe  CYRILLIC SMALL LETTER DZHE */
+		{ 0x06b0, 0x2116 }, /*                  numerosign  NUMERO SIGN */
+		{ 0x06b1, 0x0402 }, /*                 Serbian_DJE  CYRILLIC CAPITAL LETTER DJE */
+		{ 0x06b2, 0x0403 }, /*               Macedonia_GJE  CYRILLIC CAPITAL LETTER GJE */
+		{ 0x06b3, 0x0401 }, /*                 Cyrillic_IO  CYRILLIC CAPITAL LETTER IO */
+		{ 0x06b4, 0x0404 }, /*                Ukrainian_IE  CYRILLIC CAPITAL LETTER UKRAINIAN IE */
+		{ 0x06b5, 0x0405 }, /*               Macedonia_DSE  CYRILLIC CAPITAL LETTER DZE */
+		{ 0x06b6, 0x0406 }, /*                 Ukrainian_I  CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
+		{ 0x06b7, 0x0407 }, /*                Ukrainian_YI  CYRILLIC CAPITAL LETTER YI */
+		{ 0x06b8, 0x0408 }, /*                 Cyrillic_JE  CYRILLIC CAPITAL LETTER JE */
+		{ 0x06b9, 0x0409 }, /*                Cyrillic_LJE  CYRILLIC CAPITAL LETTER LJE */
+		{ 0x06ba, 0x040a }, /*                Cyrillic_NJE  CYRILLIC CAPITAL LETTER NJE */
+		{ 0x06bb, 0x040b }, /*                Serbian_TSHE  CYRILLIC CAPITAL LETTER TSHE */
+		{ 0x06bc, 0x040c }, /*               Macedonia_KJE  CYRILLIC CAPITAL LETTER KJE */
+		{ 0x06be, 0x040e }, /*         Byelorussian_SHORTU  CYRILLIC CAPITAL LETTER SHORT U */
+		{ 0x06bf, 0x040f }, /*               Cyrillic_DZHE  CYRILLIC CAPITAL LETTER DZHE */
+		{ 0x06c0, 0x044e }, /*                 Cyrillic_yu  CYRILLIC SMALL LETTER YU */
+		{ 0x06c1, 0x0430 }, /*                  Cyrillic_a  CYRILLIC SMALL LETTER A */
+		{ 0x06c2, 0x0431 }, /*                 Cyrillic_be  CYRILLIC SMALL LETTER BE */
+		{ 0x06c3, 0x0446 }, /*                Cyrillic_tse  CYRILLIC SMALL LETTER TSE */
+		{ 0x06c4, 0x0434 }, /*                 Cyrillic_de  CYRILLIC SMALL LETTER DE */
+		{ 0x06c5, 0x0435 }, /*                 Cyrillic_ie  CYRILLIC SMALL LETTER IE */
+		{ 0x06c6, 0x0444 }, /*                 Cyrillic_ef  CYRILLIC SMALL LETTER EF */
+		{ 0x06c7, 0x0433 }, /*                Cyrillic_ghe  CYRILLIC SMALL LETTER GHE */
+		{ 0x06c8, 0x0445 }, /*                 Cyrillic_ha  CYRILLIC SMALL LETTER HA */
+		{ 0x06c9, 0x0438 }, /*                  Cyrillic_i  CYRILLIC SMALL LETTER I */
+		{ 0x06ca, 0x0439 }, /*             Cyrillic_shorti  CYRILLIC SMALL LETTER SHORT I */
+		{ 0x06cb, 0x043a }, /*                 Cyrillic_ka  CYRILLIC SMALL LETTER KA */
+		{ 0x06cc, 0x043b }, /*                 Cyrillic_el  CYRILLIC SMALL LETTER EL */
+		{ 0x06cd, 0x043c }, /*                 Cyrillic_em  CYRILLIC SMALL LETTER EM */
+		{ 0x06ce, 0x043d }, /*                 Cyrillic_en  CYRILLIC SMALL LETTER EN */
+		{ 0x06cf, 0x043e }, /*                  Cyrillic_o  CYRILLIC SMALL LETTER O */
+		{ 0x06d0, 0x043f }, /*                 Cyrillic_pe  CYRILLIC SMALL LETTER PE */
+		{ 0x06d1, 0x044f }, /*                 Cyrillic_ya  CYRILLIC SMALL LETTER YA */
+		{ 0x06d2, 0x0440 }, /*                 Cyrillic_er  CYRILLIC SMALL LETTER ER */
+		{ 0x06d3, 0x0441 }, /*                 Cyrillic_es  CYRILLIC SMALL LETTER ES */
+		{ 0x06d4, 0x0442 }, /*                 Cyrillic_te  CYRILLIC SMALL LETTER TE */
+		{ 0x06d5, 0x0443 }, /*                  Cyrillic_u  CYRILLIC SMALL LETTER U */
+		{ 0x06d6, 0x0436 }, /*                Cyrillic_zhe  CYRILLIC SMALL LETTER ZHE */
+		{ 0x06d7, 0x0432 }, /*                 Cyrillic_ve  CYRILLIC SMALL LETTER VE */
+		{ 0x06d8, 0x044c }, /*           Cyrillic_softsign  CYRILLIC SMALL LETTER SOFT SIGN */
+		{ 0x06d9, 0x044b }, /*               Cyrillic_yeru  CYRILLIC SMALL LETTER YERU */
+		{ 0x06da, 0x0437 }, /*                 Cyrillic_ze  CYRILLIC SMALL LETTER ZE */
+		{ 0x06db, 0x0448 }, /*                Cyrillic_sha  CYRILLIC SMALL LETTER SHA */
+		{ 0x06dc, 0x044d }, /*                  Cyrillic_e  CYRILLIC SMALL LETTER E */
+		{ 0x06dd, 0x0449 }, /*              Cyrillic_shcha  CYRILLIC SMALL LETTER SHCHA */
+		{ 0x06de, 0x0447 }, /*                Cyrillic_che  CYRILLIC SMALL LETTER CHE */
+		{ 0x06df, 0x044a }, /*           Cyrillic_hardsign  CYRILLIC SMALL LETTER HARD SIGN */
+		{ 0x06e0, 0x042e }, /*                 Cyrillic_YU  CYRILLIC CAPITAL LETTER YU */
+		{ 0x06e1, 0x0410 }, /*                  Cyrillic_A  CYRILLIC CAPITAL LETTER A */
+		{ 0x06e2, 0x0411 }, /*                 Cyrillic_BE  CYRILLIC CAPITAL LETTER BE */
+		{ 0x06e3, 0x0426 }, /*                Cyrillic_TSE  CYRILLIC CAPITAL LETTER TSE */
+		{ 0x06e4, 0x0414 }, /*                 Cyrillic_DE  CYRILLIC CAPITAL LETTER DE */
+		{ 0x06e5, 0x0415 }, /*                 Cyrillic_IE  CYRILLIC CAPITAL LETTER IE */
+		{ 0x06e6, 0x0424 }, /*                 Cyrillic_EF  CYRILLIC CAPITAL LETTER EF */
+		{ 0x06e7, 0x0413 }, /*                Cyrillic_GHE  CYRILLIC CAPITAL LETTER GHE */
+		{ 0x06e8, 0x0425 }, /*                 Cyrillic_HA  CYRILLIC CAPITAL LETTER HA */
+		{ 0x06e9, 0x0418 }, /*                  Cyrillic_I  CYRILLIC CAPITAL LETTER I */
+		{ 0x06ea, 0x0419 }, /*             Cyrillic_SHORTI  CYRILLIC CAPITAL LETTER SHORT I */
+		{ 0x06eb, 0x041a }, /*                 Cyrillic_KA  CYRILLIC CAPITAL LETTER KA */
+		{ 0x06ec, 0x041b }, /*                 Cyrillic_EL  CYRILLIC CAPITAL LETTER EL */
+		{ 0x06ed, 0x041c }, /*                 Cyrillic_EM  CYRILLIC CAPITAL LETTER EM */
+		{ 0x06ee, 0x041d }, /*                 Cyrillic_EN  CYRILLIC CAPITAL LETTER EN */
+		{ 0x06ef, 0x041e }, /*                  Cyrillic_O  CYRILLIC CAPITAL LETTER O */
+		{ 0x06f0, 0x041f }, /*                 Cyrillic_PE  CYRILLIC CAPITAL LETTER PE */
+		{ 0x06f1, 0x042f }, /*                 Cyrillic_YA  CYRILLIC CAPITAL LETTER YA */
+		{ 0x06f2, 0x0420 }, /*                 Cyrillic_ER  CYRILLIC CAPITAL LETTER ER */
+		{ 0x06f3, 0x0421 }, /*                 Cyrillic_ES  CYRILLIC CAPITAL LETTER ES */
+		{ 0x06f4, 0x0422 }, /*                 Cyrillic_TE  CYRILLIC CAPITAL LETTER TE */
+		{ 0x06f5, 0x0423 }, /*                  Cyrillic_U  CYRILLIC CAPITAL LETTER U */
+		{ 0x06f6, 0x0416 }, /*                Cyrillic_ZHE  CYRILLIC CAPITAL LETTER ZHE */
+		{ 0x06f7, 0x0412 }, /*                 Cyrillic_VE  CYRILLIC CAPITAL LETTER VE */
+		{ 0x06f8, 0x042c }, /*           Cyrillic_SOFTSIGN  CYRILLIC CAPITAL LETTER SOFT SIGN */
+		{ 0x06f9, 0x042b }, /*               Cyrillic_YERU  CYRILLIC CAPITAL LETTER YERU */
+		{ 0x06fa, 0x0417 }, /*                 Cyrillic_ZE  CYRILLIC CAPITAL LETTER ZE */
+		{ 0x06fb, 0x0428 }, /*                Cyrillic_SHA  CYRILLIC CAPITAL LETTER SHA */
+		{ 0x06fc, 0x042d }, /*                  Cyrillic_E  CYRILLIC CAPITAL LETTER E */
+		{ 0x06fd, 0x0429 }, /*              Cyrillic_SHCHA  CYRILLIC CAPITAL LETTER SHCHA */
+		{ 0x06fe, 0x0427 }, /*                Cyrillic_CHE  CYRILLIC CAPITAL LETTER CHE */
+		{ 0x06ff, 0x042a }, /*           Cyrillic_HARDSIGN  CYRILLIC CAPITAL LETTER HARD SIGN */
+		{ 0x07a1, 0x0386 }, /*           Greek_ALPHAaccent  GREEK CAPITAL LETTER ALPHA WITH TONOS */
+		{ 0x07a2, 0x0388 }, /*         Greek_EPSILONaccent  GREEK CAPITAL LETTER EPSILON WITH TONOS */
+		{ 0x07a3, 0x0389 }, /*             Greek_ETAaccent  GREEK CAPITAL LETTER ETA WITH TONOS */
+		{ 0x07a4, 0x038a }, /*            Greek_IOTAaccent  GREEK CAPITAL LETTER IOTA WITH TONOS */
+		{ 0x07a5, 0x03aa }, /*         Greek_IOTAdiaeresis  GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
+		{ 0x07a7, 0x038c }, /*         Greek_OMICRONaccent  GREEK CAPITAL LETTER OMICRON WITH TONOS */
+		{ 0x07a8, 0x038e }, /*         Greek_UPSILONaccent  GREEK CAPITAL LETTER UPSILON WITH TONOS */
+		{ 0x07a9, 0x03ab }, /*       Greek_UPSILONdieresis  GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
+		{ 0x07ab, 0x038f }, /*           Greek_OMEGAaccent  GREEK CAPITAL LETTER OMEGA WITH TONOS */
+		{ 0x07ae, 0x0385 }, /*        Greek_accentdieresis  GREEK DIALYTIKA TONOS */
+		{ 0x07af, 0x2015 }, /*              Greek_horizbar  HORIZONTAL BAR */
+		{ 0x07b1, 0x03ac }, /*           Greek_alphaaccent  GREEK SMALL LETTER ALPHA WITH TONOS */
+		{ 0x07b2, 0x03ad }, /*         Greek_epsilonaccent  GREEK SMALL LETTER EPSILON WITH TONOS */
+		{ 0x07b3, 0x03ae }, /*             Greek_etaaccent  GREEK SMALL LETTER ETA WITH TONOS */
+		{ 0x07b4, 0x03af }, /*            Greek_iotaaccent  GREEK SMALL LETTER IOTA WITH TONOS */
+		{ 0x07b5, 0x03ca }, /*          Greek_iotadieresis  GREEK SMALL LETTER IOTA WITH DIALYTIKA */
+		{ 0x07b6, 0x0390 }, /*    Greek_iotaaccentdieresis  GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+		{ 0x07b7, 0x03cc }, /*         Greek_omicronaccent  GREEK SMALL LETTER OMICRON WITH TONOS */
+		{ 0x07b8, 0x03cd }, /*         Greek_upsilonaccent  GREEK SMALL LETTER UPSILON WITH TONOS */
+		{ 0x07b9, 0x03cb }, /*       Greek_upsilondieresis  GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
+		{ 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis  GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+		{ 0x07bb, 0x03ce }, /*           Greek_omegaaccent  GREEK SMALL LETTER OMEGA WITH TONOS */
+		{ 0x07c1, 0x0391 }, /*                 Greek_ALPHA  GREEK CAPITAL LETTER ALPHA */
+		{ 0x07c2, 0x0392 }, /*                  Greek_BETA  GREEK CAPITAL LETTER BETA */
+		{ 0x07c3, 0x0393 }, /*                 Greek_GAMMA  GREEK CAPITAL LETTER GAMMA */
+		{ 0x07c4, 0x0394 }, /*                 Greek_DELTA  GREEK CAPITAL LETTER DELTA */
+		{ 0x07c5, 0x0395 }, /*               Greek_EPSILON  GREEK CAPITAL LETTER EPSILON */
+		{ 0x07c6, 0x0396 }, /*                  Greek_ZETA  GREEK CAPITAL LETTER ZETA */
+		{ 0x07c7, 0x0397 }, /*                   Greek_ETA  GREEK CAPITAL LETTER ETA */
+		{ 0x07c8, 0x0398 }, /*                 Greek_THETA  GREEK CAPITAL LETTER THETA */
+		{ 0x07c9, 0x0399 }, /*                  Greek_IOTA  GREEK CAPITAL LETTER IOTA */
+		{ 0x07ca, 0x039a }, /*                 Greek_KAPPA  GREEK CAPITAL LETTER KAPPA */
+		{ 0x07cb, 0x039b }, /*                Greek_LAMBDA  GREEK CAPITAL LETTER LAMDA */
+		{ 0x07cc, 0x039c }, /*                    Greek_MU  GREEK CAPITAL LETTER MU */
+		{ 0x07cd, 0x039d }, /*                    Greek_NU  GREEK CAPITAL LETTER NU */
+		{ 0x07ce, 0x039e }, /*                    Greek_XI  GREEK CAPITAL LETTER XI */
+		{ 0x07cf, 0x039f }, /*               Greek_OMICRON  GREEK CAPITAL LETTER OMICRON */
+		{ 0x07d0, 0x03a0 }, /*                    Greek_PI  GREEK CAPITAL LETTER PI */
+		{ 0x07d1, 0x03a1 }, /*                   Greek_RHO  GREEK CAPITAL LETTER RHO */
+		{ 0x07d2, 0x03a3 }, /*                 Greek_SIGMA  GREEK CAPITAL LETTER SIGMA */
+		{ 0x07d4, 0x03a4 }, /*                   Greek_TAU  GREEK CAPITAL LETTER TAU */
+		{ 0x07d5, 0x03a5 }, /*               Greek_UPSILON  GREEK CAPITAL LETTER UPSILON */
+		{ 0x07d6, 0x03a6 }, /*                   Greek_PHI  GREEK CAPITAL LETTER PHI */
+		{ 0x07d7, 0x03a7 }, /*                   Greek_CHI  GREEK CAPITAL LETTER CHI */
+		{ 0x07d8, 0x03a8 }, /*                   Greek_PSI  GREEK CAPITAL LETTER PSI */
+		{ 0x07d9, 0x03a9 }, /*                 Greek_OMEGA  GREEK CAPITAL LETTER OMEGA */
+		{ 0x07e1, 0x03b1 }, /*                 Greek_alpha  GREEK SMALL LETTER ALPHA */
+		{ 0x07e2, 0x03b2 }, /*                  Greek_beta  GREEK SMALL LETTER BETA */
+		{ 0x07e3, 0x03b3 }, /*                 Greek_gamma  GREEK SMALL LETTER GAMMA */
+		{ 0x07e4, 0x03b4 }, /*                 Greek_delta  GREEK SMALL LETTER DELTA */
+		{ 0x07e5, 0x03b5 }, /*               Greek_epsilon  GREEK SMALL LETTER EPSILON */
+		{ 0x07e6, 0x03b6 }, /*                  Greek_zeta  GREEK SMALL LETTER ZETA */
+		{ 0x07e7, 0x03b7 }, /*                   Greek_eta  GREEK SMALL LETTER ETA */
+		{ 0x07e8, 0x03b8 }, /*                 Greek_theta  GREEK SMALL LETTER THETA */
+		{ 0x07e9, 0x03b9 }, /*                  Greek_iota  GREEK SMALL LETTER IOTA */
+		{ 0x07ea, 0x03ba }, /*                 Greek_kappa  GREEK SMALL LETTER KAPPA */
+		{ 0x07eb, 0x03bb }, /*                Greek_lambda  GREEK SMALL LETTER LAMDA */
+		{ 0x07ec, 0x03bc }, /*                    Greek_mu  GREEK SMALL LETTER MU */
+		{ 0x07ed, 0x03bd }, /*                    Greek_nu  GREEK SMALL LETTER NU */
+		{ 0x07ee, 0x03be }, /*                    Greek_xi  GREEK SMALL LETTER XI */
+		{ 0x07ef, 0x03bf }, /*               Greek_omicron  GREEK SMALL LETTER OMICRON */
+		{ 0x07f0, 0x03c0 }, /*                    Greek_pi  GREEK SMALL LETTER PI */
+		{ 0x07f1, 0x03c1 }, /*                   Greek_rho  GREEK SMALL LETTER RHO */
+		{ 0x07f2, 0x03c3 }, /*                 Greek_sigma  GREEK SMALL LETTER SIGMA */
+		{ 0x07f3, 0x03c2 }, /*       Greek_finalsmallsigma  GREEK SMALL LETTER FINAL SIGMA */
+		{ 0x07f4, 0x03c4 }, /*                   Greek_tau  GREEK SMALL LETTER TAU */
+		{ 0x07f5, 0x03c5 }, /*               Greek_upsilon  GREEK SMALL LETTER UPSILON */
+		{ 0x07f6, 0x03c6 }, /*                   Greek_phi  GREEK SMALL LETTER PHI */
+		{ 0x07f7, 0x03c7 }, /*                   Greek_chi  GREEK SMALL LETTER CHI */
+		{ 0x07f8, 0x03c8 }, /*                   Greek_psi  GREEK SMALL LETTER PSI */
+		{ 0x07f9, 0x03c9 }, /*                 Greek_omega  GREEK SMALL LETTER OMEGA */
+		{ 0x08a1, 0x23b7 }, /*                 leftradical  ??? */
+		{ 0x08a2, 0x250c }, /*              topleftradical  BOX DRAWINGS LIGHT DOWN AND RIGHT */
+		{ 0x08a3, 0x2500 }, /*              horizconnector  BOX DRAWINGS LIGHT HORIZONTAL */
+		{ 0x08a4, 0x2320 }, /*                 topintegral  TOP HALF INTEGRAL */
+		{ 0x08a5, 0x2321 }, /*                 botintegral  BOTTOM HALF INTEGRAL */
+		{ 0x08a6, 0x2502 }, /*               vertconnector  BOX DRAWINGS LIGHT VERTICAL */
+		{ 0x08a7, 0x23a1 }, /*            topleftsqbracket  ??? */
+		{ 0x08a8, 0x23a3 }, /*            botleftsqbracket  ??? */
+		{ 0x08a9, 0x23a4 }, /*           toprightsqbracket  ??? */
+		{ 0x08aa, 0x23a6 }, /*           botrightsqbracket  ??? */
+		{ 0x08ab, 0x239b }, /*               topleftparens  ??? */
+		{ 0x08ac, 0x239d }, /*               botleftparens  ??? */
+		{ 0x08ad, 0x239e }, /*              toprightparens  ??? */
+		{ 0x08ae, 0x23a0 }, /*              botrightparens  ??? */
+		{ 0x08af, 0x23a8 }, /*        leftmiddlecurlybrace  ??? */
+		{ 0x08b0, 0x23ac }, /*       rightmiddlecurlybrace  ??? */
+		/*  0x08b1                          topleftsummation  ??? */
+		/*  0x08b2                          botleftsummation  ??? */
+		/*  0x08b3                 topvertsummationconnector  ??? */
+		/*  0x08b4                 botvertsummationconnector  ??? */
+		/*  0x08b5                         toprightsummation  ??? */
+		/*  0x08b6                         botrightsummation  ??? */
+		/*  0x08b7                      rightmiddlesummation  ??? */
+		{ 0x08bc, 0x2264 }, /*               lessthanequal  LESS-THAN OR EQUAL TO */
+		{ 0x08bd, 0x2260 }, /*                    notequal  NOT EQUAL TO */
+		{ 0x08be, 0x2265 }, /*            greaterthanequal  GREATER-THAN OR EQUAL TO */
+		{ 0x08bf, 0x222b }, /*                    integral  INTEGRAL */
+		{ 0x08c0, 0x2234 }, /*                   therefore  THEREFORE */
+		{ 0x08c1, 0x221d }, /*                   variation  PROPORTIONAL TO */
+		{ 0x08c2, 0x221e }, /*                    infinity  INFINITY */
+		{ 0x08c5, 0x2207 }, /*                       nabla  NABLA */
+		{ 0x08c8, 0x223c }, /*                 approximate  TILDE OPERATOR */
+		{ 0x08c9, 0x2243 }, /*                similarequal  ASYMPTOTICALLY EQUAL TO */
+		{ 0x08cd, 0x21d4 }, /*                    ifonlyif  LEFT RIGHT DOUBLE ARROW */
+		{ 0x08ce, 0x21d2 }, /*                     implies  RIGHTWARDS DOUBLE ARROW */
+		{ 0x08cf, 0x2261 }, /*                   identical  IDENTICAL TO */
+		{ 0x08d6, 0x221a }, /*                     radical  SQUARE ROOT */
+		{ 0x08da, 0x2282 }, /*                  includedin  SUBSET OF */
+		{ 0x08db, 0x2283 }, /*                    includes  SUPERSET OF */
+		{ 0x08dc, 0x2229 }, /*                intersection  INTERSECTION */
+		{ 0x08dd, 0x222a }, /*                       union  UNION */
+		{ 0x08de, 0x2227 }, /*                  logicaland  LOGICAL AND */
+		{ 0x08df, 0x2228 }, /*                   logicalor  LOGICAL OR */
+		{ 0x08ef, 0x2202 }, /*           partialderivative  PARTIAL DIFFERENTIAL */
+		{ 0x08f6, 0x0192 }, /*                    function  LATIN SMALL LETTER F WITH HOOK */
+		{ 0x08fb, 0x2190 }, /*                   leftarrow  LEFTWARDS ARROW */
+		{ 0x08fc, 0x2191 }, /*                     uparrow  UPWARDS ARROW */
+		{ 0x08fd, 0x2192 }, /*                  rightarrow  RIGHTWARDS ARROW */
+		{ 0x08fe, 0x2193 }, /*                   downarrow  DOWNWARDS ARROW */
+		/*  0x09df                                     blank  ??? */
+		{ 0x09e0, 0x25c6 }, /*                soliddiamond  BLACK DIAMOND */
+		{ 0x09e1, 0x2592 }, /*                checkerboard  MEDIUM SHADE */
+		{ 0x09e2, 0x2409 }, /*                          ht  SYMBOL FOR HORIZONTAL TABULATION */
+		{ 0x09e3, 0x240c }, /*                          ff  SYMBOL FOR FORM FEED */
+		{ 0x09e4, 0x240d }, /*                          cr  SYMBOL FOR CARRIAGE RETURN */
+		{ 0x09e5, 0x240a }, /*                          lf  SYMBOL FOR LINE FEED */
+		{ 0x09e8, 0x2424 }, /*                          nl  SYMBOL FOR NEWLINE */
+		{ 0x09e9, 0x240b }, /*                          vt  SYMBOL FOR VERTICAL TABULATION */
+		{ 0x09ea, 0x2518 }, /*              lowrightcorner  BOX DRAWINGS LIGHT UP AND LEFT */
+		{ 0x09eb, 0x2510 }, /*               uprightcorner  BOX DRAWINGS LIGHT DOWN AND LEFT */
+		{ 0x09ec, 0x250c }, /*                upleftcorner  BOX DRAWINGS LIGHT DOWN AND RIGHT */
+		{ 0x09ed, 0x2514 }, /*               lowleftcorner  BOX DRAWINGS LIGHT UP AND RIGHT */
+		{ 0x09ee, 0x253c }, /*               crossinglines  BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+		{ 0x09ef, 0x23ba }, /*              horizlinescan1  HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
+		{ 0x09f0, 0x23bb }, /*              horizlinescan3  HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
+		{ 0x09f1, 0x2500 }, /*              horizlinescan5  BOX DRAWINGS LIGHT HORIZONTAL */
+		{ 0x09f2, 0x23bc }, /*              horizlinescan7  HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
+		{ 0x09f3, 0x23bd }, /*              horizlinescan9  HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
+		{ 0x09f4, 0x251c }, /*                       leftt  BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+		{ 0x09f5, 0x2524 }, /*                      rightt  BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+		{ 0x09f6, 0x2534 }, /*                        bott  BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+		{ 0x09f7, 0x252c }, /*                        topt  BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+		{ 0x09f8, 0x2502 }, /*                     vertbar  BOX DRAWINGS LIGHT VERTICAL */
+		{ 0x0aa1, 0x2003 }, /*                     emspace  EM SPACE */
+		{ 0x0aa2, 0x2002 }, /*                     enspace  EN SPACE */
+		{ 0x0aa3, 0x2004 }, /*                    em3space  THREE-PER-EM SPACE */
+		{ 0x0aa4, 0x2005 }, /*                    em4space  FOUR-PER-EM SPACE */
+		{ 0x0aa5, 0x2007 }, /*                  digitspace  FIGURE SPACE */
+		{ 0x0aa6, 0x2008 }, /*                  punctspace  PUNCTUATION SPACE */
+		{ 0x0aa7, 0x2009 }, /*                   thinspace  THIN SPACE */
+		{ 0x0aa8, 0x200a }, /*                   hairspace  HAIR SPACE */
+		{ 0x0aa9, 0x2014 }, /*                      emdash  EM DASH */
+		{ 0x0aaa, 0x2013 }, /*                      endash  EN DASH */
+		/*  0x0aac                               signifblank  ??? */
+		{ 0x0aae, 0x2026 }, /*                    ellipsis  HORIZONTAL ELLIPSIS */
+		{ 0x0aaf, 0x2025 }, /*             doubbaselinedot  TWO DOT LEADER */
+		{ 0x0ab0, 0x2153 }, /*                    onethird  VULGAR FRACTION ONE THIRD */
+		{ 0x0ab1, 0x2154 }, /*                   twothirds  VULGAR FRACTION TWO THIRDS */
+		{ 0x0ab2, 0x2155 }, /*                    onefifth  VULGAR FRACTION ONE FIFTH */
+		{ 0x0ab3, 0x2156 }, /*                   twofifths  VULGAR FRACTION TWO FIFTHS */
+		{ 0x0ab4, 0x2157 }, /*                 threefifths  VULGAR FRACTION THREE FIFTHS */
+		{ 0x0ab5, 0x2158 }, /*                  fourfifths  VULGAR FRACTION FOUR FIFTHS */
+		{ 0x0ab6, 0x2159 }, /*                    onesixth  VULGAR FRACTION ONE SIXTH */
+		{ 0x0ab7, 0x215a }, /*                  fivesixths  VULGAR FRACTION FIVE SIXTHS */
+		{ 0x0ab8, 0x2105 }, /*                      careof  CARE OF */
+		{ 0x0abb, 0x2012 }, /*                     figdash  FIGURE DASH */
+		{ 0x0abc, 0x2329 }, /*            leftanglebracket  LEFT-POINTING ANGLE BRACKET */
+		/*  0x0abd                              decimalpoint  ??? */
+		{ 0x0abe, 0x232a }, /*           rightanglebracket  RIGHT-POINTING ANGLE BRACKET */
+		/*  0x0abf                                    marker  ??? */
+		{ 0x0ac3, 0x215b }, /*                   oneeighth  VULGAR FRACTION ONE EIGHTH */
+		{ 0x0ac4, 0x215c }, /*                threeeighths  VULGAR FRACTION THREE EIGHTHS */
+		{ 0x0ac5, 0x215d }, /*                 fiveeighths  VULGAR FRACTION FIVE EIGHTHS */
+		{ 0x0ac6, 0x215e }, /*                seveneighths  VULGAR FRACTION SEVEN EIGHTHS */
+		{ 0x0ac9, 0x2122 }, /*                   trademark  TRADE MARK SIGN */
+		{ 0x0aca, 0x2613 }, /*               signaturemark  SALTIRE */
+		/*  0x0acb                         trademarkincircle  ??? */
+		{ 0x0acc, 0x25c1 }, /*            leftopentriangle  WHITE LEFT-POINTING TRIANGLE */
+		{ 0x0acd, 0x25b7 }, /*           rightopentriangle  WHITE RIGHT-POINTING TRIANGLE */
+		{ 0x0ace, 0x25cb }, /*                emopencircle  WHITE CIRCLE */
+		{ 0x0acf, 0x25af }, /*             emopenrectangle  WHITE VERTICAL RECTANGLE */
+		{ 0x0ad0, 0x2018 }, /*         leftsinglequotemark  LEFT SINGLE QUOTATION MARK */
+		{ 0x0ad1, 0x2019 }, /*        rightsinglequotemark  RIGHT SINGLE QUOTATION MARK */
+		{ 0x0ad2, 0x201c }, /*         leftdoublequotemark  LEFT DOUBLE QUOTATION MARK */
+		{ 0x0ad3, 0x201d }, /*        rightdoublequotemark  RIGHT DOUBLE QUOTATION MARK */
+		{ 0x0ad4, 0x211e }, /*                prescription  PRESCRIPTION TAKE */
+		{ 0x0ad6, 0x2032 }, /*                     minutes  PRIME */
+		{ 0x0ad7, 0x2033 }, /*                     seconds  DOUBLE PRIME */
+		{ 0x0ad9, 0x271d }, /*                  latincross  LATIN CROSS */
+		/*  0x0ada                                  hexagram  ??? */
+		{ 0x0adb, 0x25ac }, /*            filledrectbullet  BLACK RECTANGLE */
+		{ 0x0adc, 0x25c0 }, /*         filledlefttribullet  BLACK LEFT-POINTING TRIANGLE */
+		{ 0x0add, 0x25b6 }, /*        filledrighttribullet  BLACK RIGHT-POINTING TRIANGLE */
+		{ 0x0ade, 0x25cf }, /*              emfilledcircle  BLACK CIRCLE */
+		{ 0x0adf, 0x25ae }, /*                emfilledrect  BLACK VERTICAL RECTANGLE */
+		{ 0x0ae0, 0x25e6 }, /*            enopencircbullet  WHITE BULLET */
+		{ 0x0ae1, 0x25ab }, /*          enopensquarebullet  WHITE SMALL SQUARE */
+		{ 0x0ae2, 0x25ad }, /*              openrectbullet  WHITE RECTANGLE */
+		{ 0x0ae3, 0x25b3 }, /*             opentribulletup  WHITE UP-POINTING TRIANGLE */
+		{ 0x0ae4, 0x25bd }, /*           opentribulletdown  WHITE DOWN-POINTING TRIANGLE */
+		{ 0x0ae5, 0x2606 }, /*                    openstar  WHITE STAR */
+		{ 0x0ae6, 0x2022 }, /*          enfilledcircbullet  BULLET */
+		{ 0x0ae7, 0x25aa }, /*            enfilledsqbullet  BLACK SMALL SQUARE */
+		{ 0x0ae8, 0x25b2 }, /*           filledtribulletup  BLACK UP-POINTING TRIANGLE */
+		{ 0x0ae9, 0x25bc }, /*         filledtribulletdown  BLACK DOWN-POINTING TRIANGLE */
+		{ 0x0aea, 0x261c }, /*                 leftpointer  WHITE LEFT POINTING INDEX */
+		{ 0x0aeb, 0x261e }, /*                rightpointer  WHITE RIGHT POINTING INDEX */
+		{ 0x0aec, 0x2663 }, /*                        club  BLACK CLUB SUIT */
+		{ 0x0aed, 0x2666 }, /*                     diamond  BLACK DIAMOND SUIT */
+		{ 0x0aee, 0x2665 }, /*                       heart  BLACK HEART SUIT */
+		{ 0x0af0, 0x2720 }, /*                maltesecross  MALTESE CROSS */
+		{ 0x0af1, 0x2020 }, /*                      dagger  DAGGER */
+		{ 0x0af2, 0x2021 }, /*                doubledagger  DOUBLE DAGGER */
+		{ 0x0af3, 0x2713 }, /*                   checkmark  CHECK MARK */
+		{ 0x0af4, 0x2717 }, /*                 ballotcross  BALLOT X */
+		{ 0x0af5, 0x266f }, /*                musicalsharp  MUSIC SHARP SIGN */
+		{ 0x0af6, 0x266d }, /*                 musicalflat  MUSIC FLAT SIGN */
+		{ 0x0af7, 0x2642 }, /*                  malesymbol  MALE SIGN */
+		{ 0x0af8, 0x2640 }, /*                femalesymbol  FEMALE SIGN */
+		{ 0x0af9, 0x260e }, /*                   telephone  BLACK TELEPHONE */
+		{ 0x0afa, 0x2315 }, /*           telephonerecorder  TELEPHONE RECORDER */
+		{ 0x0afb, 0x2117 }, /*         phonographcopyright  SOUND RECORDING COPYRIGHT */
+		{ 0x0afc, 0x2038 }, /*                       caret  CARET */
+		{ 0x0afd, 0x201a }, /*          singlelowquotemark  SINGLE LOW-9 QUOTATION MARK */
+		{ 0x0afe, 0x201e }, /*          doublelowquotemark  DOUBLE LOW-9 QUOTATION MARK */
+		/*  0x0aff                                    cursor  ??? */
+		{ 0x0ba3, 0x003c }, /*                   leftcaret  LESS-THAN SIGN */
+		{ 0x0ba6, 0x003e }, /*                  rightcaret  GREATER-THAN SIGN */
+		{ 0x0ba8, 0x2228 }, /*                   downcaret  LOGICAL OR */
+		{ 0x0ba9, 0x2227 }, /*                     upcaret  LOGICAL AND */
+		{ 0x0bc0, 0x00af }, /*                     overbar  MACRON */
+		{ 0x0bc2, 0x22a5 }, /*                    downtack  UP TACK */
+		{ 0x0bc3, 0x2229 }, /*                      upshoe  INTERSECTION */
+		{ 0x0bc4, 0x230a }, /*                   downstile  LEFT FLOOR */
+		{ 0x0bc6, 0x005f }, /*                    underbar  LOW LINE */
+		{ 0x0bca, 0x2218 }, /*                         jot  RING OPERATOR */
+		{ 0x0bcc, 0x2395 }, /*                        quad  APL FUNCTIONAL SYMBOL QUAD */
+		{ 0x0bce, 0x22a4 }, /*                      uptack  DOWN TACK */
+		{ 0x0bcf, 0x25cb }, /*                      circle  WHITE CIRCLE */
+		{ 0x0bd3, 0x2308 }, /*                     upstile  LEFT CEILING */
+		{ 0x0bd6, 0x222a }, /*                    downshoe  UNION */
+		{ 0x0bd8, 0x2283 }, /*                   rightshoe  SUPERSET OF */
+		{ 0x0bda, 0x2282 }, /*                    leftshoe  SUBSET OF */
+		{ 0x0bdc, 0x22a2 }, /*                    lefttack  RIGHT TACK */
+		{ 0x0bfc, 0x22a3 }, /*                   righttack  LEFT TACK */
+		{ 0x0cdf, 0x2017 }, /*        hebrew_doublelowline  DOUBLE LOW LINE */
+		{ 0x0ce0, 0x05d0 }, /*                hebrew_aleph  HEBREW LETTER ALEF */
+		{ 0x0ce1, 0x05d1 }, /*                  hebrew_bet  HEBREW LETTER BET */
+		{ 0x0ce2, 0x05d2 }, /*                hebrew_gimel  HEBREW LETTER GIMEL */
+		{ 0x0ce3, 0x05d3 }, /*                hebrew_dalet  HEBREW LETTER DALET */
+		{ 0x0ce4, 0x05d4 }, /*                   hebrew_he  HEBREW LETTER HE */
+		{ 0x0ce5, 0x05d5 }, /*                  hebrew_waw  HEBREW LETTER VAV */
+		{ 0x0ce6, 0x05d6 }, /*                 hebrew_zain  HEBREW LETTER ZAYIN */
+		{ 0x0ce7, 0x05d7 }, /*                 hebrew_chet  HEBREW LETTER HET */
+		{ 0x0ce8, 0x05d8 }, /*                  hebrew_tet  HEBREW LETTER TET */
+		{ 0x0ce9, 0x05d9 }, /*                  hebrew_yod  HEBREW LETTER YOD */
+		{ 0x0cea, 0x05da }, /*            hebrew_finalkaph  HEBREW LETTER FINAL KAF */
+		{ 0x0ceb, 0x05db }, /*                 hebrew_kaph  HEBREW LETTER KAF */
+		{ 0x0cec, 0x05dc }, /*                hebrew_lamed  HEBREW LETTER LAMED */
+		{ 0x0ced, 0x05dd }, /*             hebrew_finalmem  HEBREW LETTER FINAL MEM */
+		{ 0x0cee, 0x05de }, /*                  hebrew_mem  HEBREW LETTER MEM */
+		{ 0x0cef, 0x05df }, /*             hebrew_finalnun  HEBREW LETTER FINAL NUN */
+		{ 0x0cf0, 0x05e0 }, /*                  hebrew_nun  HEBREW LETTER NUN */
+		{ 0x0cf1, 0x05e1 }, /*               hebrew_samech  HEBREW LETTER SAMEKH */
+		{ 0x0cf2, 0x05e2 }, /*                 hebrew_ayin  HEBREW LETTER AYIN */
+		{ 0x0cf3, 0x05e3 }, /*              hebrew_finalpe  HEBREW LETTER FINAL PE */
+		{ 0x0cf4, 0x05e4 }, /*                   hebrew_pe  HEBREW LETTER PE */
+		{ 0x0cf5, 0x05e5 }, /*            hebrew_finalzade  HEBREW LETTER FINAL TSADI */
+		{ 0x0cf6, 0x05e6 }, /*                 hebrew_zade  HEBREW LETTER TSADI */
+		{ 0x0cf7, 0x05e7 }, /*                 hebrew_qoph  HEBREW LETTER QOF */
+		{ 0x0cf8, 0x05e8 }, /*                 hebrew_resh  HEBREW LETTER RESH */
+		{ 0x0cf9, 0x05e9 }, /*                 hebrew_shin  HEBREW LETTER SHIN */
+		{ 0x0cfa, 0x05ea }, /*                  hebrew_taw  HEBREW LETTER TAV */
+		{ 0x0da1, 0x0e01 }, /*                  Thai_kokai  THAI CHARACTER KO KAI */
+		{ 0x0da2, 0x0e02 }, /*                Thai_khokhai  THAI CHARACTER KHO KHAI */
+		{ 0x0da3, 0x0e03 }, /*               Thai_khokhuat  THAI CHARACTER KHO KHUAT */
+		{ 0x0da4, 0x0e04 }, /*               Thai_khokhwai  THAI CHARACTER KHO KHWAI */
+		{ 0x0da5, 0x0e05 }, /*                Thai_khokhon  THAI CHARACTER KHO KHON */
+		{ 0x0da6, 0x0e06 }, /*             Thai_khorakhang  THAI CHARACTER KHO RAKHANG */
+		{ 0x0da7, 0x0e07 }, /*                 Thai_ngongu  THAI CHARACTER NGO NGU */
+		{ 0x0da8, 0x0e08 }, /*                Thai_chochan  THAI CHARACTER CHO CHAN */
+		{ 0x0da9, 0x0e09 }, /*               Thai_choching  THAI CHARACTER CHO CHING */
+		{ 0x0daa, 0x0e0a }, /*               Thai_chochang  THAI CHARACTER CHO CHANG */
+		{ 0x0dab, 0x0e0b }, /*                   Thai_soso  THAI CHARACTER SO SO */
+		{ 0x0dac, 0x0e0c }, /*                Thai_chochoe  THAI CHARACTER CHO CHOE */
+		{ 0x0dad, 0x0e0d }, /*                 Thai_yoying  THAI CHARACTER YO YING */
+		{ 0x0dae, 0x0e0e }, /*                Thai_dochada  THAI CHARACTER DO CHADA */
+		{ 0x0daf, 0x0e0f }, /*                Thai_topatak  THAI CHARACTER TO PATAK */
+		{ 0x0db0, 0x0e10 }, /*                Thai_thothan  THAI CHARACTER THO THAN */
+		{ 0x0db1, 0x0e11 }, /*          Thai_thonangmontho  THAI CHARACTER THO NANGMONTHO */
+		{ 0x0db2, 0x0e12 }, /*             Thai_thophuthao  THAI CHARACTER THO PHUTHAO */
+		{ 0x0db3, 0x0e13 }, /*                  Thai_nonen  THAI CHARACTER NO NEN */
+		{ 0x0db4, 0x0e14 }, /*                  Thai_dodek  THAI CHARACTER DO DEK */
+		{ 0x0db5, 0x0e15 }, /*                  Thai_totao  THAI CHARACTER TO TAO */
+		{ 0x0db6, 0x0e16 }, /*               Thai_thothung  THAI CHARACTER THO THUNG */
+		{ 0x0db7, 0x0e17 }, /*              Thai_thothahan  THAI CHARACTER THO THAHAN */
+		{ 0x0db8, 0x0e18 }, /*               Thai_thothong  THAI CHARACTER THO THONG */
+		{ 0x0db9, 0x0e19 }, /*                   Thai_nonu  THAI CHARACTER NO NU */
+		{ 0x0dba, 0x0e1a }, /*               Thai_bobaimai  THAI CHARACTER BO BAIMAI */
+		{ 0x0dbb, 0x0e1b }, /*                  Thai_popla  THAI CHARACTER PO PLA */
+		{ 0x0dbc, 0x0e1c }, /*               Thai_phophung  THAI CHARACTER PHO PHUNG */
+		{ 0x0dbd, 0x0e1d }, /*                   Thai_fofa  THAI CHARACTER FO FA */
+		{ 0x0dbe, 0x0e1e }, /*                Thai_phophan  THAI CHARACTER PHO PHAN */
+		{ 0x0dbf, 0x0e1f }, /*                  Thai_fofan  THAI CHARACTER FO FAN */
+		{ 0x0dc0, 0x0e20 }, /*             Thai_phosamphao  THAI CHARACTER PHO SAMPHAO */
+		{ 0x0dc1, 0x0e21 }, /*                   Thai_moma  THAI CHARACTER MO MA */
+		{ 0x0dc2, 0x0e22 }, /*                  Thai_yoyak  THAI CHARACTER YO YAK */
+		{ 0x0dc3, 0x0e23 }, /*                  Thai_rorua  THAI CHARACTER RO RUA */
+		{ 0x0dc4, 0x0e24 }, /*                     Thai_ru  THAI CHARACTER RU */
+		{ 0x0dc5, 0x0e25 }, /*                 Thai_loling  THAI CHARACTER LO LING */
+		{ 0x0dc6, 0x0e26 }, /*                     Thai_lu  THAI CHARACTER LU */
+		{ 0x0dc7, 0x0e27 }, /*                 Thai_wowaen  THAI CHARACTER WO WAEN */
+		{ 0x0dc8, 0x0e28 }, /*                 Thai_sosala  THAI CHARACTER SO SALA */
+		{ 0x0dc9, 0x0e29 }, /*                 Thai_sorusi  THAI CHARACTER SO RUSI */
+		{ 0x0dca, 0x0e2a }, /*                  Thai_sosua  THAI CHARACTER SO SUA */
+		{ 0x0dcb, 0x0e2b }, /*                  Thai_hohip  THAI CHARACTER HO HIP */
+		{ 0x0dcc, 0x0e2c }, /*                Thai_lochula  THAI CHARACTER LO CHULA */
+		{ 0x0dcd, 0x0e2d }, /*                   Thai_oang  THAI CHARACTER O ANG */
+		{ 0x0dce, 0x0e2e }, /*               Thai_honokhuk  THAI CHARACTER HO NOKHUK */
+		{ 0x0dcf, 0x0e2f }, /*              Thai_paiyannoi  THAI CHARACTER PAIYANNOI */
+		{ 0x0dd0, 0x0e30 }, /*                  Thai_saraa  THAI CHARACTER SARA A */
+		{ 0x0dd1, 0x0e31 }, /*             Thai_maihanakat  THAI CHARACTER MAI HAN-AKAT */
+		{ 0x0dd2, 0x0e32 }, /*                 Thai_saraaa  THAI CHARACTER SARA AA */
+		{ 0x0dd3, 0x0e33 }, /*                 Thai_saraam  THAI CHARACTER SARA AM */
+		{ 0x0dd4, 0x0e34 }, /*                  Thai_sarai  THAI CHARACTER SARA I */
+		{ 0x0dd5, 0x0e35 }, /*                 Thai_saraii  THAI CHARACTER SARA II */
+		{ 0x0dd6, 0x0e36 }, /*                 Thai_saraue  THAI CHARACTER SARA UE */
+		{ 0x0dd7, 0x0e37 }, /*                Thai_sarauee  THAI CHARACTER SARA UEE */
+		{ 0x0dd8, 0x0e38 }, /*                  Thai_sarau  THAI CHARACTER SARA U */
+		{ 0x0dd9, 0x0e39 }, /*                 Thai_sarauu  THAI CHARACTER SARA UU */
+		{ 0x0dda, 0x0e3a }, /*                Thai_phinthu  THAI CHARACTER PHINTHU */
+		/*  0x0dde                    Thai_maihanakat_maitho  ??? */
+		{ 0x0ddf, 0x0e3f }, /*                   Thai_baht  THAI CURRENCY SYMBOL BAHT */
+		{ 0x0de0, 0x0e40 }, /*                  Thai_sarae  THAI CHARACTER SARA E */
+		{ 0x0de1, 0x0e41 }, /*                 Thai_saraae  THAI CHARACTER SARA AE */
+		{ 0x0de2, 0x0e42 }, /*                  Thai_sarao  THAI CHARACTER SARA O */
+		{ 0x0de3, 0x0e43 }, /*          Thai_saraaimaimuan  THAI CHARACTER SARA AI MAIMUAN */
+		{ 0x0de4, 0x0e44 }, /*         Thai_saraaimaimalai  THAI CHARACTER SARA AI MAIMALAI */
+		{ 0x0de5, 0x0e45 }, /*            Thai_lakkhangyao  THAI CHARACTER LAKKHANGYAO */
+		{ 0x0de6, 0x0e46 }, /*               Thai_maiyamok  THAI CHARACTER MAIYAMOK */
+		{ 0x0de7, 0x0e47 }, /*              Thai_maitaikhu  THAI CHARACTER MAITAIKHU */
+		{ 0x0de8, 0x0e48 }, /*                  Thai_maiek  THAI CHARACTER MAI EK */
+		{ 0x0de9, 0x0e49 }, /*                 Thai_maitho  THAI CHARACTER MAI THO */
+		{ 0x0dea, 0x0e4a }, /*                 Thai_maitri  THAI CHARACTER MAI TRI */
+		{ 0x0deb, 0x0e4b }, /*            Thai_maichattawa  THAI CHARACTER MAI CHATTAWA */
+		{ 0x0dec, 0x0e4c }, /*            Thai_thanthakhat  THAI CHARACTER THANTHAKHAT */
+		{ 0x0ded, 0x0e4d }, /*               Thai_nikhahit  THAI CHARACTER NIKHAHIT */
+		{ 0x0df0, 0x0e50 }, /*                 Thai_leksun  THAI DIGIT ZERO */
+		{ 0x0df1, 0x0e51 }, /*                Thai_leknung  THAI DIGIT ONE */
+		{ 0x0df2, 0x0e52 }, /*                Thai_leksong  THAI DIGIT TWO */
+		{ 0x0df3, 0x0e53 }, /*                 Thai_leksam  THAI DIGIT THREE */
+		{ 0x0df4, 0x0e54 }, /*                  Thai_leksi  THAI DIGIT FOUR */
+		{ 0x0df5, 0x0e55 }, /*                  Thai_lekha  THAI DIGIT FIVE */
+		{ 0x0df6, 0x0e56 }, /*                 Thai_lekhok  THAI DIGIT SIX */
+		{ 0x0df7, 0x0e57 }, /*                Thai_lekchet  THAI DIGIT SEVEN */
+		{ 0x0df8, 0x0e58 }, /*                Thai_lekpaet  THAI DIGIT EIGHT */
+		{ 0x0df9, 0x0e59 }, /*                 Thai_lekkao  THAI DIGIT NINE */
+		{ 0x0ea1, 0x3131 }, /*               Hangul_Kiyeog  HANGUL LETTER KIYEOK */
+		{ 0x0ea2, 0x3132 }, /*          Hangul_SsangKiyeog  HANGUL LETTER SSANGKIYEOK */
+		{ 0x0ea3, 0x3133 }, /*           Hangul_KiyeogSios  HANGUL LETTER KIYEOK-SIOS */
+		{ 0x0ea4, 0x3134 }, /*                Hangul_Nieun  HANGUL LETTER NIEUN */
+		{ 0x0ea5, 0x3135 }, /*           Hangul_NieunJieuj  HANGUL LETTER NIEUN-CIEUC */
+		{ 0x0ea6, 0x3136 }, /*           Hangul_NieunHieuh  HANGUL LETTER NIEUN-HIEUH */
+		{ 0x0ea7, 0x3137 }, /*               Hangul_Dikeud  HANGUL LETTER TIKEUT */
+		{ 0x0ea8, 0x3138 }, /*          Hangul_SsangDikeud  HANGUL LETTER SSANGTIKEUT */
+		{ 0x0ea9, 0x3139 }, /*                Hangul_Rieul  HANGUL LETTER RIEUL */
+		{ 0x0eaa, 0x313a }, /*          Hangul_RieulKiyeog  HANGUL LETTER RIEUL-KIYEOK */
+		{ 0x0eab, 0x313b }, /*           Hangul_RieulMieum  HANGUL LETTER RIEUL-MIEUM */
+		{ 0x0eac, 0x313c }, /*           Hangul_RieulPieub  HANGUL LETTER RIEUL-PIEUP */
+		{ 0x0ead, 0x313d }, /*            Hangul_RieulSios  HANGUL LETTER RIEUL-SIOS */
+		{ 0x0eae, 0x313e }, /*           Hangul_RieulTieut  HANGUL LETTER RIEUL-THIEUTH */
+		{ 0x0eaf, 0x313f }, /*          Hangul_RieulPhieuf  HANGUL LETTER RIEUL-PHIEUPH */
+		{ 0x0eb0, 0x3140 }, /*           Hangul_RieulHieuh  HANGUL LETTER RIEUL-HIEUH */
+		{ 0x0eb1, 0x3141 }, /*                Hangul_Mieum  HANGUL LETTER MIEUM */
+		{ 0x0eb2, 0x3142 }, /*                Hangul_Pieub  HANGUL LETTER PIEUP */
+		{ 0x0eb3, 0x3143 }, /*           Hangul_SsangPieub  HANGUL LETTER SSANGPIEUP */
+		{ 0x0eb4, 0x3144 }, /*            Hangul_PieubSios  HANGUL LETTER PIEUP-SIOS */
+		{ 0x0eb5, 0x3145 }, /*                 Hangul_Sios  HANGUL LETTER SIOS */
+		{ 0x0eb6, 0x3146 }, /*            Hangul_SsangSios  HANGUL LETTER SSANGSIOS */
+		{ 0x0eb7, 0x3147 }, /*                Hangul_Ieung  HANGUL LETTER IEUNG */
+		{ 0x0eb8, 0x3148 }, /*                Hangul_Jieuj  HANGUL LETTER CIEUC */
+		{ 0x0eb9, 0x3149 }, /*           Hangul_SsangJieuj  HANGUL LETTER SSANGCIEUC */
+		{ 0x0eba, 0x314a }, /*                Hangul_Cieuc  HANGUL LETTER CHIEUCH */
+		{ 0x0ebb, 0x314b }, /*               Hangul_Khieuq  HANGUL LETTER KHIEUKH */
+		{ 0x0ebc, 0x314c }, /*                Hangul_Tieut  HANGUL LETTER THIEUTH */
+		{ 0x0ebd, 0x314d }, /*               Hangul_Phieuf  HANGUL LETTER PHIEUPH */
+		{ 0x0ebe, 0x314e }, /*                Hangul_Hieuh  HANGUL LETTER HIEUH */
+		{ 0x0ebf, 0x314f }, /*                    Hangul_A  HANGUL LETTER A */
+		{ 0x0ec0, 0x3150 }, /*                   Hangul_AE  HANGUL LETTER AE */
+		{ 0x0ec1, 0x3151 }, /*                   Hangul_YA  HANGUL LETTER YA */
+		{ 0x0ec2, 0x3152 }, /*                  Hangul_YAE  HANGUL LETTER YAE */
+		{ 0x0ec3, 0x3153 }, /*                   Hangul_EO  HANGUL LETTER EO */
+		{ 0x0ec4, 0x3154 }, /*                    Hangul_E  HANGUL LETTER E */
+		{ 0x0ec5, 0x3155 }, /*                  Hangul_YEO  HANGUL LETTER YEO */
+		{ 0x0ec6, 0x3156 }, /*                   Hangul_YE  HANGUL LETTER YE */
+		{ 0x0ec7, 0x3157 }, /*                    Hangul_O  HANGUL LETTER O */
+		{ 0x0ec8, 0x3158 }, /*                   Hangul_WA  HANGUL LETTER WA */
+		{ 0x0ec9, 0x3159 }, /*                  Hangul_WAE  HANGUL LETTER WAE */
+		{ 0x0eca, 0x315a }, /*                   Hangul_OE  HANGUL LETTER OE */
+		{ 0x0ecb, 0x315b }, /*                   Hangul_YO  HANGUL LETTER YO */
+		{ 0x0ecc, 0x315c }, /*                    Hangul_U  HANGUL LETTER U */
+		{ 0x0ecd, 0x315d }, /*                  Hangul_WEO  HANGUL LETTER WEO */
+		{ 0x0ece, 0x315e }, /*                   Hangul_WE  HANGUL LETTER WE */
+		{ 0x0ecf, 0x315f }, /*                   Hangul_WI  HANGUL LETTER WI */
+		{ 0x0ed0, 0x3160 }, /*                   Hangul_YU  HANGUL LETTER YU */
+		{ 0x0ed1, 0x3161 }, /*                   Hangul_EU  HANGUL LETTER EU */
+		{ 0x0ed2, 0x3162 }, /*                   Hangul_YI  HANGUL LETTER YI */
+		{ 0x0ed3, 0x3163 }, /*                    Hangul_I  HANGUL LETTER I */
+		{ 0x0ed4, 0x11a8 }, /*             Hangul_J_Kiyeog  HANGUL JONGSEONG KIYEOK */
+		{ 0x0ed5, 0x11a9 }, /*        Hangul_J_SsangKiyeog  HANGUL JONGSEONG SSANGKIYEOK */
+		{ 0x0ed6, 0x11aa }, /*         Hangul_J_KiyeogSios  HANGUL JONGSEONG KIYEOK-SIOS */
+		{ 0x0ed7, 0x11ab }, /*              Hangul_J_Nieun  HANGUL JONGSEONG NIEUN */
+		{ 0x0ed8, 0x11ac }, /*         Hangul_J_NieunJieuj  HANGUL JONGSEONG NIEUN-CIEUC */
+		{ 0x0ed9, 0x11ad }, /*         Hangul_J_NieunHieuh  HANGUL JONGSEONG NIEUN-HIEUH */
+		{ 0x0eda, 0x11ae }, /*             Hangul_J_Dikeud  HANGUL JONGSEONG TIKEUT */
+		{ 0x0edb, 0x11af }, /*              Hangul_J_Rieul  HANGUL JONGSEONG RIEUL */
+		{ 0x0edc, 0x11b0 }, /*        Hangul_J_RieulKiyeog  HANGUL JONGSEONG RIEUL-KIYEOK */
+		{ 0x0edd, 0x11b1 }, /*         Hangul_J_RieulMieum  HANGUL JONGSEONG RIEUL-MIEUM */
+		{ 0x0ede, 0x11b2 }, /*         Hangul_J_RieulPieub  HANGUL JONGSEONG RIEUL-PIEUP */
+		{ 0x0edf, 0x11b3 }, /*          Hangul_J_RieulSios  HANGUL JONGSEONG RIEUL-SIOS */
+		{ 0x0ee0, 0x11b4 }, /*         Hangul_J_RieulTieut  HANGUL JONGSEONG RIEUL-THIEUTH */
+		{ 0x0ee1, 0x11b5 }, /*        Hangul_J_RieulPhieuf  HANGUL JONGSEONG RIEUL-PHIEUPH */
+		{ 0x0ee2, 0x11b6 }, /*         Hangul_J_RieulHieuh  HANGUL JONGSEONG RIEUL-HIEUH */
+		{ 0x0ee3, 0x11b7 }, /*              Hangul_J_Mieum  HANGUL JONGSEONG MIEUM */
+		{ 0x0ee4, 0x11b8 }, /*              Hangul_J_Pieub  HANGUL JONGSEONG PIEUP */
+		{ 0x0ee5, 0x11b9 }, /*          Hangul_J_PieubSios  HANGUL JONGSEONG PIEUP-SIOS */
+		{ 0x0ee6, 0x11ba }, /*               Hangul_J_Sios  HANGUL JONGSEONG SIOS */
+		{ 0x0ee7, 0x11bb }, /*          Hangul_J_SsangSios  HANGUL JONGSEONG SSANGSIOS */
+		{ 0x0ee8, 0x11bc }, /*              Hangul_J_Ieung  HANGUL JONGSEONG IEUNG */
+		{ 0x0ee9, 0x11bd }, /*              Hangul_J_Jieuj  HANGUL JONGSEONG CIEUC */
+		{ 0x0eea, 0x11be }, /*              Hangul_J_Cieuc  HANGUL JONGSEONG CHIEUCH */
+		{ 0x0eeb, 0x11bf }, /*             Hangul_J_Khieuq  HANGUL JONGSEONG KHIEUKH */
+		{ 0x0eec, 0x11c0 }, /*              Hangul_J_Tieut  HANGUL JONGSEONG THIEUTH */
+		{ 0x0eed, 0x11c1 }, /*             Hangul_J_Phieuf  HANGUL JONGSEONG PHIEUPH */
+		{ 0x0eee, 0x11c2 }, /*              Hangul_J_Hieuh  HANGUL JONGSEONG HIEUH */
+		{ 0x0eef, 0x316d }, /*     Hangul_RieulYeorinHieuh  HANGUL LETTER RIEUL-YEORINHIEUH */
+		{ 0x0ef0, 0x3171 }, /*    Hangul_SunkyeongeumMieum  HANGUL LETTER KAPYEOUNMIEUM */
+		{ 0x0ef1, 0x3178 }, /*    Hangul_SunkyeongeumPieub  HANGUL LETTER KAPYEOUNPIEUP */
+		{ 0x0ef2, 0x317f }, /*              Hangul_PanSios  HANGUL LETTER PANSIOS */
+		{ 0x0ef3, 0x3181 }, /*    Hangul_KkogjiDalrinIeung  HANGUL LETTER YESIEUNG */
+		{ 0x0ef4, 0x3184 }, /*   Hangul_SunkyeongeumPhieuf  HANGUL LETTER KAPYEOUNPHIEUPH */
+		{ 0x0ef5, 0x3186 }, /*          Hangul_YeorinHieuh  HANGUL LETTER YEORINHIEUH */
+		{ 0x0ef6, 0x318d }, /*                Hangul_AraeA  HANGUL LETTER ARAEA */
+		{ 0x0ef7, 0x318e }, /*               Hangul_AraeAE  HANGUL LETTER ARAEAE */
+		{ 0x0ef8, 0x11eb }, /*            Hangul_J_PanSios  HANGUL JONGSEONG PANSIOS */
+		{ 0x0ef9, 0x11f0 }, /*  Hangul_J_KkogjiDalrinIeung  HANGUL JONGSEONG YESIEUNG */
+		{ 0x0efa, 0x11f9 }, /*        Hangul_J_YeorinHieuh  HANGUL JONGSEONG YEORINHIEUH */
+		{ 0x0eff, 0x20a9 }, /*                  Korean_Won  WON SIGN */
+		{ 0x13a4, 0x20ac }, /*                        Euro  EURO SIGN */
+		{ 0x13bc, 0x0152 }, /*                          OE  LATIN CAPITAL LIGATURE OE */
+		{ 0x13bd, 0x0153 }, /*                          oe  LATIN SMALL LIGATURE OE */
+		{ 0x13be, 0x0178 }, /*                  Ydiaeresis  LATIN CAPITAL LETTER Y WITH DIAERESIS */
+		{ 0x20ac, 0x20ac }, /*                    EuroSign  EURO SIGN */
+	});
+
+	private static Map<Integer, Integer> toMap(int[][] keys) {
+		Map<Integer, Integer> keyMap = new HashMap<Integer, Integer>();
+		for (int[] km: keys) {
+			keyMap.put(km[1], km[0]);
+		}
+		return keyMap;
+	}
+
+	public static int unicode2keysym(int ch) {
+		if (ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255)
+			return ch;
+		Integer converted = keyMap.get(ch);
+		return converted != null ?
+				converted :
+				// No variants has been found for the unicode symbol then pass as unicode
+				// with the special flag.
+				// Note this method is valid only for 0x100-0x10ffff unicode value range.
+				ch | 0x01000000;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/utils/Strings.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,46 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.utils;
+
+public class Strings {
+	public static String toString(byte[] byteArray) {
+		StringBuilder sb = new StringBuilder("[");
+		boolean notFirst = false;
+		for (byte b : byteArray) {
+			if (notFirst) {
+				sb.append(", ");
+			} else {
+				notFirst = true;
+			}
+			sb.append(b);
+		}
+		return sb.append("]").toString();
+	}
+
+	public static boolean isTrimmedEmpty(String s) {
+		return null == s || (s.trim().length() == 0);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/AbstractConnectionWorkerFactory.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,36 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public abstract class AbstractConnectionWorkerFactory {
+    public abstract NetworkConnectionWorker createNetworkConnectionWorker();
+
+    public abstract RfbConnectionWorker createRfbConnectionWorker();
+
+    public abstract void setPredefinedPassword(String predefinedPassword);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/CancelConnectionException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,37 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.exceptions.CommonException;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class CancelConnectionException extends CommonException {
+
+    public CancelConnectionException(String message) {
+        super(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/ConnectionErrorException.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,37 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.exceptions.CommonException;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class ConnectionErrorException extends CommonException {
+
+    public ConnectionErrorException(String message) {
+        super(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/ConnectionPresenter.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,290 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.utils.Strings;
+import com.glavsoft.viewer.mvp.Presenter;
+import com.glavsoft.viewer.swing.ConnectionParams;
+import com.glavsoft.viewer.swing.WrongParameterException;
+import com.glavsoft.viewer.swing.gui.ConnectionView;
+import com.glavsoft.viewer.swing.gui.ConnectionsHistory;
+
+import java.net.Socket;
+import java.util.logging.Logger;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class ConnectionPresenter extends Presenter {
+    public static final String PROPERTY_HOST_NAME = "HostName";
+    public static final String PROPERTY_RFB_PORT_NUMBER = "PortNumber";
+    public static final String PROPERTY_USE_SSH = "UseSsh";
+    private static final String PROPERTY_SSH_USER_NAME = "SshUserName";
+    private static final String PROPERTY_SSH_HOST_NAME = "SshHostName";
+    private static final String PROPERTY_SSH_PORT_NUMBER = "SshPortNumber";
+    private static final String PROPERTY_STATUS_BAR_MESSAGE = "Message";
+    private static final String PROPERTY_CONNECTION_IN_PROGRESS = "ConnectionInProgress";
+    public static final String CONNECTION_PARAMS_MODEL = "ConnectionParamsModel";
+    public static final String CONNECTIONS_HISTORY_MODEL = "ConnectionsHistoryModel";
+    public static final String CONNECTION_VIEW = "ConnectionView";
+
+    private final boolean hasSshSupport;
+    private final boolean allowInteractive;
+    private ConnectionsHistory connectionsHistory;
+    private ProtocolSettings rfbSettings;
+    private UiSettings uiSettings;
+    private final Logger logger;
+    private RfbConnectionWorker rfbConnectionWorker;
+    private AbstractConnectionWorkerFactory connectionWorkerFactory;
+    private NetworkConnectionWorker networkConnectionWorker;
+    private boolean needReconnection = true;
+
+    public ConnectionPresenter(boolean hasSshSupport, boolean allowInteractive) {
+        this.hasSshSupport = hasSshSupport;
+        this.allowInteractive = allowInteractive;
+        logger = Logger.getLogger(getClass().getName());
+    }
+
+    public void startConnection(ProtocolSettings rfbSettings, UiSettings uiSettings, int paramSettingsMask)
+            throws IllegalStateException {
+        this.rfbSettings = rfbSettings;
+        this.uiSettings = uiSettings;
+        if ( ! isModelRegisteredByName(CONNECTION_PARAMS_MODEL)) {
+            throw new IllegalStateException("No Connection Params model added.");
+        }
+        connectionsHistory = new ConnectionsHistory();
+        addModel(CONNECTIONS_HISTORY_MODEL, connectionsHistory);
+        syncModels(paramSettingsMask);
+        if (allowInteractive) {
+            show();
+            populate();
+        } else {
+            connect();
+        }
+    }
+
+    public void setUseSsh(boolean useSsh) {
+        setModelProperty(PROPERTY_USE_SSH, useSsh, boolean.class);
+    }
+
+    public void submitConnection(String hostName) throws WrongParameterException {
+        if (Strings.isTrimmedEmpty(hostName)) {
+            throw new WrongParameterException("Host name is empty", PROPERTY_HOST_NAME);
+        }
+        setModelProperty(PROPERTY_HOST_NAME, hostName);
+
+        final String rfbPort = (String) getViewPropertyOrNull(PROPERTY_RFB_PORT_NUMBER);
+        setModelProperty(PROPERTY_RFB_PORT_NUMBER, rfbPort);
+        try {
+            throwPossiblyHappenedException();
+        } catch (Throwable e) {
+            throw new WrongParameterException("Wrong Port", PROPERTY_HOST_NAME);
+        }
+        setSshOptions();
+
+        saveHistory();
+        populateFrom(CONNECTIONS_HISTORY_MODEL);
+
+        connect();
+    }
+
+    public void saveHistory() {
+        final ConnectionParams cp = (ConnectionParams) getModel(CONNECTION_PARAMS_MODEL);
+        connectionsHistory.reorder(cp, rfbSettings, uiSettings);
+        connectionsHistory.save();
+    }
+
+    private void connect() {
+        final ConnectionParams connectionParams = (ConnectionParams) getModel(CONNECTION_PARAMS_MODEL);
+        // TODO check connectionWorkerFactory is init
+        networkConnectionWorker = connectionWorkerFactory.createNetworkConnectionWorker();
+        networkConnectionWorker.setConnectionParams(connectionParams);
+        networkConnectionWorker.setPresenter(this);
+        networkConnectionWorker.setHasSshSupport(hasSshSupport);
+        networkConnectionWorker.execute();
+    }
+
+    public void connectionFailed() {
+        cancelConnection();
+        if (allowInteractive) {
+            enableConnectionDialog();
+        } else {
+            connect();
+        }
+    }
+
+    public void connectionCancelled() {
+        cancelConnection();
+        if (allowInteractive) {
+            enableConnectionDialog();
+        } else {
+            final ConnectionView connectionView = (ConnectionView) getView(CONNECTION_VIEW);
+            if (connectionView != null) {
+                connectionView.closeApp();
+            }
+        }
+    }
+
+    private void enableConnectionDialog() {
+        setViewProperty(PROPERTY_CONNECTION_IN_PROGRESS, false, boolean.class);
+    }
+
+    public void successfulNetworkConnection(Socket workingSocket) { // EDT
+        logger.info("Connected");
+        showMessage("Connected");
+        rfbConnectionWorker = connectionWorkerFactory.createRfbConnectionWorker();
+        rfbConnectionWorker.setWorkingSocket(workingSocket);
+        rfbConnectionWorker.setRfbSettings(rfbSettings);
+        rfbConnectionWorker.setUiSettings(uiSettings);
+        rfbConnectionWorker.setConnectionString(
+                getModelProperty(PROPERTY_HOST_NAME) + ":" + getModelProperty(PROPERTY_RFB_PORT_NUMBER));
+        rfbConnectionWorker.execute();
+    }
+
+    public void successfulRfbConnection() {
+        enableConnectionDialog();
+        getView(CONNECTION_VIEW).closeView();
+    }
+
+    public void cancelConnection() {
+        if (networkConnectionWorker != null) {
+            networkConnectionWorker.cancel();
+        }
+        if (rfbConnectionWorker != null) {
+            rfbConnectionWorker.cancel();
+        }
+    }
+
+    public void showConnectionErrorDialog(String message) {
+        final ConnectionView connectionView = (ConnectionView) getView(CONNECTION_VIEW);
+        if (connectionView != null) {
+            connectionView.showConnectionErrorDialog(message);
+        }
+    }
+
+    public void showReconnectDialog(String errorTitle, String errorMessage) {
+        final ConnectionView connectionView = (ConnectionView) getView(CONNECTION_VIEW);
+        if (connectionView != null) {
+            connectionView.showReconnectDialog(errorTitle, errorMessage);
+        }
+    }
+
+    private void setSshOptions() {
+		if (hasSshSupport) {
+            try {
+                final boolean useSsh = (Boolean)getViewProperty(PROPERTY_USE_SSH);
+                setModelProperty(PROPERTY_USE_SSH, useSsh, boolean.class);
+            } catch (PropertyNotFoundException e) {
+                //nop
+            }
+            setModelProperty(PROPERTY_SSH_USER_NAME, getViewPropertyOrNull(PROPERTY_SSH_USER_NAME));
+            setModelProperty(PROPERTY_SSH_HOST_NAME, getViewPropertyOrNull(PROPERTY_SSH_HOST_NAME));
+            setModelProperty(PROPERTY_SSH_PORT_NUMBER, getViewPropertyOrNull(PROPERTY_SSH_PORT_NUMBER));
+            setViewProperty(PROPERTY_SSH_PORT_NUMBER, getModelProperty(PROPERTY_SSH_PORT_NUMBER));
+        }
+	}
+
+    private void syncModels(int paramSettingsMask) {
+        final ConnectionParams cp = (ConnectionParams) getModel(CONNECTION_PARAMS_MODEL);
+        final ConnectionParams mostSuitableConnection = connectionsHistory.getMostSuitableConnection(cp);
+        cp.completeEmptyFieldsFrom(mostSuitableConnection);
+        rfbSettings.copyDataFrom(connectionsHistory.getProtocolSettings(mostSuitableConnection), paramSettingsMask & 0xffff);
+        uiSettings.copyDataFrom(connectionsHistory.getUiSettingsData(mostSuitableConnection), (paramSettingsMask >> 16) & 0xffff);
+        if ( ! cp.isHostNameEmpty()) {
+            connectionsHistory.reorder(cp, rfbSettings, uiSettings);
+        }
+
+//        protocolSettings.addListener(connectionsHistory);
+//        uiSettings.addListener(connectionsHistory);
+    }
+
+    public void populateFromHistoryItem(ConnectionParams connectionParams) {
+        setModelProperty(PROPERTY_HOST_NAME, connectionParams.hostName);
+        setModelProperty(PROPERTY_RFB_PORT_NUMBER, connectionParams.getPortNumber(), int.class);
+        setModelProperty(PROPERTY_USE_SSH, connectionParams.useSsh(), boolean.class);
+        setModelProperty(PROPERTY_SSH_HOST_NAME, connectionParams.sshHostName);
+        setModelProperty(PROPERTY_SSH_PORT_NUMBER, connectionParams.getSshPortNumber(), int.class);
+        setModelProperty(PROPERTY_SSH_USER_NAME, connectionParams.sshUserName);
+        populateFrom(CONNECTION_PARAMS_MODEL);
+        rfbSettings.copyDataFrom(connectionsHistory.getProtocolSettings(connectionParams));
+        uiSettings.copyDataFrom(connectionsHistory.getUiSettingsData(connectionParams));
+    }
+
+    public void clearHistory() {
+        connectionsHistory.clear();
+        connectionsHistory.reorder((ConnectionParams) getModel(CONNECTION_PARAMS_MODEL), rfbSettings, uiSettings);
+        populateFrom(CONNECTIONS_HISTORY_MODEL);
+        clearMessage();
+    }
+
+    public void showMessage(String message) {
+        setViewProperty(PROPERTY_STATUS_BAR_MESSAGE, message);
+    }
+
+    public void clearMessage() {
+        showMessage("");
+    }
+
+    public void setConnectionWorkerFactory(AbstractConnectionWorkerFactory connectionWorkerFactory) {
+        this.connectionWorkerFactory = connectionWorkerFactory;
+    }
+
+    public void reconnect(String predefinedPassword) {
+        connectionWorkerFactory.setPredefinedPassword(predefinedPassword);
+        if (allowInteractive) {
+            clearMessage();
+            enableConnectionDialog();
+            show();
+            populate();
+        } else if (needReconnection) {
+            connect();
+        }
+    }
+
+    public void clearPredefinedPassword() {
+        connectionWorkerFactory.setPredefinedPassword(null);
+    }
+
+    public UiSettings getUiSettings() {
+        return uiSettings;
+    }
+
+    public ProtocolSettings getRfbSettings() {
+        return rfbSettings;
+    }
+
+    public boolean needReconnection() {
+        return needReconnection;
+    }
+
+    public void setNeedReconnection(boolean need) {
+        needReconnection = need;
+    }
+
+    public boolean allowInteractive() {
+        return allowInteractive;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/ConnectionWorker.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,47 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public interface ConnectionWorker<T> {
+    /**
+     * The same as in {@link javax.swing.SwingWorker}
+     */
+    T doInBackground() throws Exception;
+
+    /**
+     * The same as in {@link javax.swing.SwingWorker}
+     */
+    void execute();
+
+    /**
+     * Should cancel worker.
+     *
+     * @return true if cancelled successful, false if not (ex. worker is already cancelled)
+     */
+    boolean cancel();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/NetworkConnectionWorker.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,41 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.viewer.swing.ConnectionParams;
+
+import java.net.Socket;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public interface NetworkConnectionWorker extends ConnectionWorker<Socket> {
+
+    void setConnectionParams(ConnectionParams connectionParams);
+
+    void setPresenter(ConnectionPresenter presenter);
+
+    void setHasSshSupport(boolean hasSshSupport);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/RfbConnectionWorker.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,46 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.rfb.protocol.Protocol;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+
+import javax.swing.*;
+import java.net.Socket;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public interface RfbConnectionWorker extends ConnectionWorker<Void> {
+
+    void setWorkingSocket(Socket workingSocket);
+
+    void setRfbSettings(ProtocolSettings rfbSettings);
+
+    void setUiSettings(UiSettings uiSettings);
+
+    void setConnectionString(String connectionString);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/UiSettings.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,190 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.rfb.IChangeSettingsListener;
+import com.glavsoft.viewer.swing.LocalMouseCursorShape;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class UiSettings {
+
+    public static final int MIN_SCALE_PERCENT = 10;
+	public static final int MAX_SCALE_PERCENT = 500;
+    private static final int SCALE_PERCENT_ZOOMING_STEP = 10;
+	
+	@SuppressWarnings("PointlessBitwiseExpression")
+    public static final int CHANGED_SCALE_FACTOR = 1 << 0;
+    public static final int CHANGED_MOUSE_CURSOR_SHAPE = 1 << 1;
+    public static final int CHANGED_FULL_SCREEN = 1 << 2;
+
+    private final List<IChangeSettingsListener> listeners = new LinkedList<IChangeSettingsListener>();
+    private int changedSettingsMask = 0;
+
+    private final UiSettingsData uiSettingsData;
+    public boolean showControls = true;
+
+    public UiSettings() {
+        uiSettingsData = new UiSettingsData();
+		changedSettingsMask = 0;
+	}
+
+	public UiSettings(UiSettings uiSettings) {
+        uiSettingsData = new UiSettingsData(
+                uiSettings.getScalePercent(), uiSettings.getMouseCursorShape(), uiSettings.isFullScreen());
+        this.changedSettingsMask = uiSettings.changedSettingsMask;
+    }
+
+	public double getScaleFactor() {
+		return uiSettingsData.getScalePercent() / 100.;
+	}
+
+	public void setScalePercent(double scalePercent) {
+        if (this.uiSettingsData.setScalePercent(scalePercent)) {
+		    changedSettingsMask |= CHANGED_SCALE_FACTOR;
+        }
+	}
+
+	public void addListener(IChangeSettingsListener listener) {
+		listeners.add(listener);
+	}
+
+	void fireListeners() {
+        if (null == listeners) return;
+		final SettingsChangedEvent event = new SettingsChangedEvent(new UiSettings(this));
+		changedSettingsMask = 0;
+		for (IChangeSettingsListener listener : listeners) {
+			listener.settingsChanged(event);
+		}
+	}
+
+    public void zoomOut() {
+	    double oldScaleFactor = uiSettingsData.getScalePercent();
+	    double scaleFactor = (int)(this.uiSettingsData.getScalePercent() / SCALE_PERCENT_ZOOMING_STEP) * SCALE_PERCENT_ZOOMING_STEP;
+	    if (scaleFactor == oldScaleFactor) {
+		    scaleFactor -= SCALE_PERCENT_ZOOMING_STEP;
+	    }
+	    if (scaleFactor < MIN_SCALE_PERCENT) {
+		    scaleFactor = MIN_SCALE_PERCENT;
+	    }
+	    setScalePercent(scaleFactor);
+	    fireListeners();
+    }
+
+    public void zoomIn() {
+	    double scaleFactor = (int)(this.uiSettingsData.getScalePercent() / SCALE_PERCENT_ZOOMING_STEP) * SCALE_PERCENT_ZOOMING_STEP + SCALE_PERCENT_ZOOMING_STEP;
+	    if (scaleFactor > MAX_SCALE_PERCENT) {
+		    scaleFactor = MAX_SCALE_PERCENT;
+	    }
+	    setScalePercent(scaleFactor);
+	    fireListeners();
+    }
+
+    public void zoomAsIs() {
+	    setScalePercent(100);
+	    fireListeners();
+    }
+
+	public void zoomToFit(int containerWidth, int containerHeight, int fbWidth, int fbHeight) {
+		int scalePromille = Math.min(1000 * containerWidth / fbWidth,
+				1000 * containerHeight / fbHeight);
+		while (fbWidth * scalePromille / 1000. > containerWidth ||
+				fbHeight * scalePromille / 1000. > containerHeight) {
+			scalePromille -= 1;
+		}
+		setScalePercent(scalePromille / 10.);
+		fireListeners();
+	}
+
+	public boolean isChangedMouseCursorShape() {
+		return (changedSettingsMask & CHANGED_MOUSE_CURSOR_SHAPE) == CHANGED_MOUSE_CURSOR_SHAPE;
+	}
+
+	public static boolean isUiSettingsChangedFired(SettingsChangedEvent event) {
+		return event.getSource() instanceof UiSettings;
+	}
+
+	public double getScalePercent() {
+		return uiSettingsData.getScalePercent();
+	}
+
+	public String getScalePercentFormatted() {
+		NumberFormat numberFormat = new DecimalFormat("###.#");
+		return numberFormat.format(uiSettingsData.getScalePercent());
+	}
+
+    public LocalMouseCursorShape getMouseCursorShape() {
+        return uiSettingsData.getMouseCursorShape();
+    }
+
+    public void setMouseCursorShape(LocalMouseCursorShape mouseCursorShape) {
+        if (this.uiSettingsData.setMouseCursorShape(mouseCursorShape)) {
+            changedSettingsMask |= CHANGED_MOUSE_CURSOR_SHAPE;
+            fireListeners();
+        }
+    }
+
+    public void copyDataFrom(UiSettingsData other) {
+        copyDataFrom(other, 0);
+    }
+    public void copyDataFrom(UiSettingsData other, int mask) {
+        if (null == other) return;
+        if ((mask & CHANGED_SCALE_FACTOR) == 0) uiSettingsData.setScalePercent(other.getScalePercent());
+        if ((mask & CHANGED_MOUSE_CURSOR_SHAPE) == 0) uiSettingsData.setMouseCursorShape(other.getMouseCursorShape());
+        if ((mask & CHANGED_FULL_SCREEN) == 0) uiSettingsData.setFullScreen(other.isFullScreen());
+    }
+
+    public void setFullScreen(boolean isFullScreen) {
+        if (uiSettingsData.setFullScreen(isFullScreen)) {
+            changedSettingsMask |= CHANGED_FULL_SCREEN;
+            fireListeners();
+        }
+    }
+
+    public boolean isFullScreen() {
+        return uiSettingsData.isFullScreen();
+    }
+
+    public UiSettingsData getData() {
+        return uiSettingsData;
+    }
+
+    @Override
+    public String toString() {
+        return "UiSettings{" +
+                "scalePercent=" + uiSettingsData.getScalePercent() +
+                ", fullScreen=" + uiSettingsData.isFullScreen() +
+                ", mouseCursorShape=" + uiSettingsData.getMouseCursorShape() +
+                '}';
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/UiSettingsData.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,102 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.viewer.swing.LocalMouseCursorShape;
+
+import java.io.Serializable;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class UiSettingsData implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private double scalePercent;
+    private LocalMouseCursorShape mouseCursorShape;
+    private boolean fullScreen;
+
+
+    public UiSettingsData() {
+        scalePercent = 100;
+        mouseCursorShape = LocalMouseCursorShape.DOT;
+        fullScreen = false;
+    }
+
+    public UiSettingsData(double scalePercent, LocalMouseCursorShape mouseCursorShape, boolean fullScreen) {
+        this.scalePercent = scalePercent;
+        this.mouseCursorShape = mouseCursorShape;
+        this.fullScreen = fullScreen;
+    }
+
+    public UiSettingsData(UiSettingsData other) {
+        this(other.getScalePercent(), other.getMouseCursorShape(), other.isFullScreen());
+    }
+
+    public double getScalePercent() {
+        return scalePercent;
+    }
+
+    public boolean setScalePercent(double scalePercent) {
+        if (this.scalePercent != scalePercent) {
+            this.scalePercent = scalePercent;
+            return true;
+        }
+        return false;
+    }
+
+
+    public LocalMouseCursorShape getMouseCursorShape() {
+        return mouseCursorShape;
+    }
+
+    public boolean setMouseCursorShape(LocalMouseCursorShape mouseCursorShape) {
+        if (this.mouseCursorShape != mouseCursorShape && mouseCursorShape != null) {
+            this.mouseCursorShape = mouseCursorShape;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isFullScreen() {
+        return fullScreen;
+    }
+
+    public boolean setFullScreen(boolean fullScreen) {
+        if (this.fullScreen != fullScreen) {
+            this.fullScreen = fullScreen;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "UiSettingsData{" +
+                "scalePercent=" + scalePercent +
+                ", mouseCursorShape=" + mouseCursorShape +
+                ", fullScreen=" + fullScreen +
+                '}';
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/Viewer.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,264 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.viewer.cli.Parser;
+import com.glavsoft.viewer.mvp.View;
+import com.glavsoft.viewer.swing.ConnectionParams;
+import com.glavsoft.viewer.swing.ParametersHandler;
+import com.glavsoft.viewer.swing.SwingConnectionWorkerFactory;
+import com.glavsoft.viewer.swing.SwingViewerWindowFactory;
+import com.glavsoft.viewer.swing.gui.ConnectionView;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.logging.*;
+
+@SuppressWarnings("serial")
+public class Viewer extends JApplet implements Runnable, WindowListener {
+
+	private Logger logger;
+    private int paramsMask;
+    private boolean allowAppletInteractiveConnections;
+
+    private final ConnectionParams connectionParams;
+    private String passwordFromParams;
+    boolean isSeparateFrame = true;
+    boolean isApplet = true;
+    private final ProtocolSettings settings;
+    private final UiSettings uiSettings;
+    private volatile boolean isAppletStopped = false;
+    private ConnectionPresenter connectionPresenter;
+
+    public static void main(String[] args) {
+		Parser parser = new Parser();
+		ParametersHandler.completeParserOptions(parser);
+
+		parser.parse(args);
+		if (parser.isSet(ParametersHandler.ARG_HELP)) {
+			printUsage(parser.optionsUsage());
+			System.exit(0);
+		}
+		Viewer viewer = new Viewer(parser);
+		SwingUtilities.invokeLater(viewer);
+	}
+
+    public static void printUsage(String additional) {
+		System.out.println("Usage: java -jar (progfilename) [hostname [port_number]] [Options]\n" +
+				"    or\n"+
+				" java -jar (progfilename) [Options]\n" +
+				"    or\n java -jar (progfilename) -help\n    to view this help\n\n" +
+				"Where Options are:\n" + additional +
+				"\nOptions format: -optionName=optionValue. Ex. -host=localhost -port=5900 -viewonly=yes\n" +
+				"Both option name and option value are case insensitive.");
+	}
+
+	public Viewer() {
+        logger = Logger.getLogger(getClass().getName());
+		connectionParams = new ConnectionParams();
+		settings = ProtocolSettings.getDefaultSettings();
+		uiSettings = new UiSettings();
+	}
+
+	private Viewer(Parser parser) {
+		this();
+        setLoggingLevel(parser.isSet(ParametersHandler.ARG_VERBOSE) ? Level.FINE :
+                parser.isSet(ParametersHandler.ARG_VERBOSE_MORE) ? Level.FINER :
+                        Level.INFO);
+
+        paramsMask = ParametersHandler.completeSettingsFromCLI(parser, connectionParams, settings, uiSettings);
+		passwordFromParams = parser.getValueFor(ParametersHandler.ARG_PASSWORD);
+		logger.info("TightVNC Viewer version " + ver());
+		isApplet = false;
+	}
+
+    private void setLoggingLevel(Level levelToSet) {
+        final Logger appLogger = Logger.getLogger("com.glavsoft");
+        appLogger.setLevel(levelToSet);
+        ConsoleHandler ch = null;
+        for (Handler h : appLogger.getHandlers()) {
+            if (h instanceof ConsoleHandler) {
+                ch = (ConsoleHandler) h;
+                break;
+            }
+        }
+        if (null == ch) {
+            ch = new ConsoleHandler();
+            appLogger.addHandler(ch);
+        }
+//        ch.setFormatter(new SimpleFormatter());
+        ch.setLevel(levelToSet);
+    }
+
+
+    @Override
+	public void windowClosing(WindowEvent e) {
+		if (e != null && e.getComponent() != null) {
+            final Window w = e.getWindow();
+            if (w != null) {
+                w.setVisible(false);
+                w.dispose();
+            }
+		}
+		closeApp();
+	}
+
+	/**
+	 * Closes App(lication) or stops App(let).
+	 */
+    public void closeApp() {
+        if (connectionPresenter != null) {
+            connectionPresenter.cancelConnection();
+            logger.info("Connections cancelled.");
+        }
+        if (isApplet) {
+            if ( ! isAppletStopped) {
+                logger.severe("Applet is stopped.");
+                isAppletStopped  = true;
+                repaint();
+                stop();
+            }
+		} else {
+			System.exit(0);
+		}
+	}
+
+	@Override
+	public void paint(Graphics g) {
+		if ( ! isAppletStopped) {
+			super.paint(g);
+		} else {
+			getContentPane().removeAll();
+			g.clearRect(0, 0, getWidth(), getHeight());
+			g.drawString("Disconnected", 10, 20);
+		}
+	}
+
+	@Override
+	public void destroy() {
+		closeApp();
+		super.destroy();
+	}
+
+	@Override
+	public void init() {
+		paramsMask = ParametersHandler.completeSettingsFromApplet(this, connectionParams, settings, uiSettings);
+		isSeparateFrame = ParametersHandler.isSeparateFrame;
+		passwordFromParams = getParameter(ParametersHandler.ARG_PASSWORD);
+		isApplet = true;
+        allowAppletInteractiveConnections = ParametersHandler.allowAppletInteractiveConnections;
+		repaint();
+
+        try {
+            SwingUtilities.invokeAndWait(this);
+        } catch (Exception e) {
+            logger.severe(e.getMessage());
+        }
+    }
+
+	@Override
+	public void start() {
+		super.start();
+	}
+
+    private boolean checkJsch() {
+        try {
+            Class.forName("com.jcraft.jsch.JSch");
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
+    @Override
+	public void run() {
+
+        final boolean hasJsch = checkJsch();
+        final boolean allowInteractive = allowAppletInteractiveConnections || ! isApplet;
+        connectionPresenter = new ConnectionPresenter(hasJsch, allowInteractive);
+        connectionPresenter.addModel("ConnectionParamsModel", connectionParams);
+        final ConnectionView connectionView = new ConnectionView(
+                Viewer.this, // appWindowListener
+                connectionPresenter, hasJsch);
+        connectionPresenter.addView(ConnectionPresenter.CONNECTION_VIEW, connectionView);
+        if (isApplet) {
+            connectionPresenter.addView("AppletStatusStringView", new View() {
+                @Override
+                public void showView() { /*nop*/ }
+                @Override
+                public void closeView() { /*nop*/ }
+                @SuppressWarnings("UnusedDeclaration")
+                public void setMessage(String message) {
+                    Viewer.this.getAppletContext().showStatus(message);
+                }
+            });
+        }
+
+        SwingViewerWindowFactory viewerWindowFactory = new SwingViewerWindowFactory(isSeparateFrame, isApplet, this);
+
+        connectionPresenter.setConnectionWorkerFactory(
+                new SwingConnectionWorkerFactory(connectionView.getFrame(), passwordFromParams, connectionPresenter, viewerWindowFactory));
+
+        connectionPresenter.startConnection(settings, uiSettings, paramsMask);
+	}
+
+	@Override
+	public void windowOpened(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowClosed(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowIconified(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowDeiconified(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowActivated(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowDeactivated(WindowEvent e) { /* nop */ }
+
+	public static String ver() {
+		final InputStream mfStream = Viewer.class.getClassLoader().getResourceAsStream(
+				"META-INF/MANIFEST.MF");
+		if (null == mfStream) {
+			System.out.println("No Manifest file found.");
+			return "-1";
+		}
+		try {
+			Manifest mf = new Manifest();
+			mf.read(mfStream);
+			Attributes atts = mf.getMainAttributes();
+			return atts.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+		} catch (IOException e) {
+			return "-2";
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/cli/Parser.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,117 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.cli;
+
+import com.glavsoft.utils.Strings;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Command line interface parameters parser
+ */
+public class Parser {
+	private final Map<String, Option> options = new LinkedHashMap<String, Option>();
+	private final List<String> plainOptions = new ArrayList<String>();
+	private boolean isSetPlainOptions = false;
+
+	public void addOption(String opName, String defaultValue, String desc) {
+		Option op = new Option(opName, defaultValue, desc);
+		options.put(opName.toLowerCase(), op);
+	}
+
+	public void parse(String [] args) {
+		for (String p : args) {
+			if (p.startsWith("-")) {
+				int skipMinuses = p.startsWith("--") ? 2 : 1;
+				String[] params = p.split("=", 2);
+				Option op = options.get(params[0].toLowerCase().substring(skipMinuses));
+				if (op != null) {
+					op.isSet = true;
+					if (params.length > 1 && ! Strings.isTrimmedEmpty(params[1])) {
+						op.value = params[1];
+					}
+				}
+			} else if ( ! p.startsWith("-")) {
+				isSetPlainOptions = true;
+				plainOptions.add(p);
+			}
+		}
+	}
+
+	public String getValueFor(String param) {
+		Option op = options.get(param.toLowerCase());
+		return op != null ? op.value : null;
+	}
+
+	public boolean isSet(String param) {
+		Option op = options.get(param.toLowerCase());
+		return op != null && op.isSet;
+	}
+
+	public boolean isSetPlainOptions() {
+		return isSetPlainOptions;
+	}
+
+	public String getPlainOptionAt(int index) {
+		return plainOptions.get(index);
+	}
+
+	public int getPlainOptionsNumber() {
+		return plainOptions.size();
+	}
+
+	/**
+	 * Command line interface option
+	 */
+	private static class Option {
+		protected String opName, defaultValue, desc, value;
+		protected boolean isSet = false;
+		public Option(String opName, String defaultValue, String desc) {
+			this.opName = opName;
+			this.defaultValue = defaultValue;
+			this.desc = desc;
+			this.value = defaultValue;
+		}
+	}
+
+	public String optionsUsage() {
+		StringBuilder sb = new StringBuilder();
+		int maxNameLength = 0;
+		for (Option op : options.values()) {
+			maxNameLength = Math.max(maxNameLength, op.opName.length());
+		}
+		for (Option op : options.values()) {
+			sb.append(" -").append(op.opName);
+			for (int i=0; i<maxNameLength - op.opName.length(); ++i) {
+				sb.append(' ');
+			}
+			sb.append(" : ").append(op.desc).append('\n');
+		}
+		return sb.toString();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/mvp/Model.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,33 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.mvp;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public interface Model {
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/mvp/Presenter.java	Thu Sep 11 07:30:03 2014 +0900
@@ -0,0 +1,259 @@
+// Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// 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.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.mvp;
+
+import com.glavsoft.exceptions.CommonException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class Presenter {
+    private final Map<String, View> registeredViews;
+    private final Map<String, Model> registeredModels;
+    static private Logger logger = Logger.getLogger(Presenter.class.getName());
+    private Throwable savedInvocationTargetException;
+
+    public Presenter() {
+        registeredViews = new HashMap<String, View>();
+        registeredModels = new HashMap<String, Model>();
+    }
+
+    public void addView(String name, View view) {
+        registeredViews.put(name, view);
+    }
+
+    public void  addModel(String name, Model model) {
+        registeredModels.put(name, model);
+    }
+
+    protected void populate() {
+        savedInvocationTargetException = null;
+        for (Map.Entry<String, Model> entry : registeredModels.entrySet()) {
+            String modelName = entry.getKey();
+            Model model = entry.getValue();
+            populateFrom(modelName, model);
+        }
+    }
+
+    public void  populateFrom(String modelName) {
+        Model model = registeredModels.get(modelName);
+        if (modelName != null) {
+            populateFrom(modelName, model);
+        } else {
+            logger.finer("Cannot find model: " + modelName);
+        }
+    }
+
+    private void populateFrom(String modelName, Model model) {
+        Method methods[] = model.getClass().getDeclaredMethods();
+        for (Method m : methods) {
+            if (m.getName().startsWith("get") && m.getParameterTypes().length == 0) {
+                String propertyName = m.getName().substring(3);
+                try {
+                    final Object property = m.invoke(model);
+                    logger.finest("Load: " + modelName + ".get" + propertyName + "() # => " + property +
+                        "  type: " + m.getReturnType());
+                    setViewProperty(propertyName, property, m.getReturnType()); // TODO this can set savedInvocationTargetEx, so what to do whith it?
+                } catch (IllegalAccessException e) {
+                    // nop
+                } catch (InvocationTargetException e) {
+                    savedInvocationTargetException = e.getCause(); // TODO may be skip it?
+                    break;
+                }
+            }
+        }
+    }
+
+    protected boolean isModelRegisteredByName(String modelName) {
+        return registeredModels.containsKey(modelName);
+    }
+
+    protected Model getModel(String modelName) {
+        return registeredModels.get(modelName);
+    }
+
+    protected void show() {
+        for (View v : registeredViews.values()) {
+            v.showView();
+        }
+    }
+
+
+    protected void save() {
+        savedInvocationTargetException = null;
+        for (Map.Entry<String, Model> entry : registeredModels.entrySet()) {
+            String modelName = entry.getKey();
+            Model model = entry.getValue();
+            Method methods[] = model.getClass().getDeclaredMethods();
+            for (Method m : methods) {
+                if (m.getName().startsWith("set")) {
+                    String propertyName = m.getName().substring(3);
+                    try {
+                        final Object viewProperty = getViewProperty(propertyName);
+                        m.invoke(model, viewProperty);
+                        logger.finest("Save: " + modelName + ".set" + propertyName + "( " + viewProperty + " )");
+                    } catch (IllegalAccessException e) {
+                        // nop
+                    } catch (InvocationTargetException e) {
+                        savedInvocationTargetException = e.getCause();
+                        break;
+                    } catch (PropertyNotFoundException e) {
+                        // nop
+                    }
+                }
+            }
+        }
+    }
+
+    public Object getViewPropertyOrNull(String propertyName) {
+        try {
+            return getViewProperty(propertyName);
+        } catch (PropertyNotFoundException e) {
+            return null;
+        }
+    }
+
+    public Object getViewProperty(String propertyName) throws PropertyNotFoundException {
+        savedInvocationTargetException = null;
+        logger.finest("get" + propertyName + "()");
+        for (Map.Entry<String, View> entry : registeredViews.entrySet()) {
+            String viewName = entry.getKey();
+            View view = entry.getValue();
+            try {
+                Method getter = view.getClass().getMethod("get" + propertyName, new Class[0]);
+                final Object res = getter.invoke(view);
+                logger.finest("----from view: " + viewName + ".get" + propertyName + "() # +> " + res);
+                return res;
+                // oops, only first getter will be found TODO?
+            } catch (NoSuchMethodException e) {
+                // nop
+            } catch (InvocationTargetException e) {
+                savedInvocationTargetException = e.getCause();
+                break;
+            } catch (IllegalAccessException e) {
+                // nop
+            }
+        }
+        throw new PropertyNotFoundException(propertyName);
+    }
+
+    public Object getModelProperty(String propertyName) {
+        savedInvocationTargetException = null;
+        logger.finest("get" + propertyName + "()");
+        for (String modelName : registeredModels.keySet()) {
+            Model model = registeredModels.get(modelName);
+            try {
+                Method getter = model.getClass().getMethod("get" + propertyName, new Class[0]);
+                final Object res = getter.invoke(model);
+                logger.finest("----from model: " + modelName + ".get" + propertyName + "() # +> " + res);
+                return res;
+                // oops, only first getter will be found TODO?
+            } catch (NoSuchMethodException e) {
+                // nop
+            } catch (InvocationTargetException e) {
+                savedInvocationTargetException = e.getCause();
+                break;
+            } catch (IllegalAccessException e) {
+                // nop
+            }
+        }
+//        savedInvocationTargetException = new PropertyNotFoundException(propertyName);
+        return null;
+    }
+
+    public void setViewProperty(String propertyName, Object newValue) {
+        setViewProperty(propertyName, newValue, newValue.getClass());
+    }
+
+    public void setViewProperty(String propertyName, Object newValue, Class<?> valueType) {
+        savedInvocationTargetException = null;
+        logger.finest("set" + propertyName + "( " + newValue + " ) type: " + valueType);
+        for (Map.Entry<String, View> entry : registeredViews.entrySet()) {
+            String viewName = entry.getKey();
+            View view = entry.getValue();
+            try {
+                Method setter = view.getClass().getMethod("set" + propertyName, valueType);
+                setter.invoke(view, newValue);
+                logger.finest("----to view: " + viewName + ".set" + propertyName + "( " + newValue + " )");
+            } catch (NoSuchMethodException e) {
+                // nop
+            } catch (InvocationTargetException e) {
+                e.getCause().printStackTrace();
+                savedInvocationTargetException = e.getCause();
+                break;
+            } catch (IllegalAccessException e) {
+                // nop
+            }
+        }
+    }
+
+    protected void throwPossiblyHappenedException() throws Throwable {
+        if (savedInvocationTargetException != null) {
+            savedInvocationTargetException = null;
+            throw savedInvocationTargetException;
+        }
+    }
+
+    protected View getView(String name) {
+        return registeredViews.get(name);
+    }
+
+    protected class PropertyNotFoundException extends CommonException {
+        public PropertyNotFoundException(String message) {
+            super(message);
+        }
+    }
+
+    public void setModelProperty(String propertyName, Object newValue) {
+        setModelProperty(propertyName, newValue, newValue.getClass());
+    }
+
+    public void setModelProperty(String propertyName, Object newValue, Class<?> valueType) {