[med-svn] [plip] 02/09: New upstream version 1.3.5+dfsg

Alex Mestiashvili malex-guest at moszumanska.debian.org
Fri Dec 1 15:58:11 UTC 2017


This is an automated email from the git hooks/post-receive script.

malex-guest pushed a commit to branch master
in repository plip.

commit efab1b850bd8c70e27726d0c72ffe602b857cd4c
Author: Alexandre Mestiashvili <alex at biotec.tu-dresden.de>
Date:   Fri Dec 1 15:11:35 2017 +0100

    New upstream version 1.3.5+dfsg
---
 CHANGES.txt                            |  19 +-
 DOCUMENTATION.md                       |  20 ++
 LICENSE.txt                            | 455 ++++++++++++++++++++-------------
 TODO.txt                               |  14 +
 plip/__init__.py                       |  15 +-
 plip/modules/__init__.py               |  15 +-
 plip/modules/chimeraplip.py            |  13 -
 plip/modules/config.py                 |  27 +-
 plip/modules/detection.py              | 153 +++++++----
 plip/modules/mp.py                     |  30 +--
 plip/modules/plipremote.py             |  13 -
 plip/modules/plipxml.py                |  22 +-
 plip/modules/preparation.py            | 183 ++++++++-----
 plip/modules/pymolplip.py              |  29 ++-
 plip/modules/report.py                 |  59 ++---
 plip/modules/supplemental.py           |  53 ++--
 plip/modules/visualize.py              |  32 +--
 plip/modules/webservices.py            |  22 +-
 plip/plipcmd                           |  43 +---
 plip/test/run_all_tests.sh             |   1 +
 plip/test/test_basic_functions.py      |  13 -
 plip/test/test_literature_validated.py |  13 -
 plip/test/test_metal_coordination.py   |  13 -
 plip/test/test_remote_services.py      |  13 -
 plip/test/test_special_cases.py        |  15 --
 plip/test/test_xml_parser.py           |  13 -
 setup.py                               |  19 +-
 27 files changed, 678 insertions(+), 639 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 121f740..2d53bd6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,7 +1,24 @@
 Changelog
 ---------
 
-# 1.3.3
+### Next version
+-
+
+### 1.3.5
+* Preparation for Python 3: Imports
+* small correction for PDB fixing
+* includes TODO files with user suggestions
+* license adapted to GNU GPLv2
+
+### 1.3.4
+* __DNA/RNA can be selected as receptor with --dnareceptor__
+* __Composite ligands and intra-protein mode: Annotation which part of the ligand interacts with the receptor__
+* Improved handling of NMR structures
+* Filter for extremely large ligands
+* Speed-up for file reading and parallel visualization
+* More debugging messages
+
+### 1.3.3
 * __Adds XML Parser module for PLIP XML files__
 * Detection of intramolecular interactions with --intra
 * improved error correction in PDB files
diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index ae28206..ca20f1b 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -140,6 +140,12 @@ plip -i 5b2m --intra A -yv
 Please note that detection within a chain takes much longer than detection of protein-ligand interactions,
 especially for large structures.
 
+### Interactions of molecules with DNA/RNA (__beta__)
+PLIP can characterize interactions between ligands and DNA/RNA.
+A special mode allows to switch from protein to DNA/RNA as the receptor molecule in the structure.
+To change the receptor mode, start PLIP with the option `--dnareceptor`.
+
+
 ## Changing detection thresholds
 The PLIP algorithm uses a rule-based detection to report non-covalent interaction between proteins and their partners.
 The current settings are based on literature values and have been refined based on extensive testing with independent cases from mainly crystallography journals, covering a broad range of structure resolutions.
@@ -480,6 +486,20 @@ Residue type of interacting amino acid
 
 Residue chain of interacting amino acid
 
+**resnr_ligand**
+
+Residue number of interacting ligand residue
+
+
+**restype_ligand**
+
+Residue type of interacting ligand residue
+
+
+**reschain_ligand**
+
+Residue chain of interacting ligand residue
+
 
 **dist**
 
diff --git a/LICENSE.txt b/LICENSE.txt
index 92cfcfd..846c036 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,177 +1,280 @@
+GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
 
-              Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, 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 Library 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
diff --git a/TODO.txt b/TODO.txt
new file mode 100644
index 0000000..93d3639
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,14 @@
+Possible future features
+========================
+
+* Python 3 support
+* support special characters in filenames (e.g. spanish accents), currently cause problems in XML report
+* support for mmcif format
+* support presets for hydrogenation
+* detection of steric clashes
+* detection of anion-pi interactions
+* detection of electrostatic repulsion force_string
+* detection of Keesom forces
+* weak hydrogen bonding
+* visualization: show hydrogen atoms in PyMOL for hydrogen bonds and adapt interaction vector accordingly
+* use SMARTS for detection of chemical features (charged groups, etc.)
diff --git a/plip/__init__.py b/plip/__init__.py
index 1ab663b..a1e3ed0 100644
--- a/plip/__init__.py
+++ b/plip/__init__.py
@@ -1,17 +1,4 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 __init__.py - Needed for python modules.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-"""
\ No newline at end of file
+"""
diff --git a/plip/modules/__init__.py b/plip/modules/__init__.py
index 1ab663b..a1e3ed0 100644
--- a/plip/modules/__init__.py
+++ b/plip/modules/__init__.py
@@ -1,17 +1,4 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 __init__.py - Needed for python modules.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-"""
\ No newline at end of file
+"""
diff --git a/plip/modules/chimeraplip.py b/plip/modules/chimeraplip.py
index 1505a62..96d658d 100644
--- a/plip/modules/chimeraplip.py
+++ b/plip/modules/chimeraplip.py
@@ -1,19 +1,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 chimeraplip.py - Visualization class for Chimera.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 class ChimeraVisualizer():
diff --git a/plip/modules/config.py b/plip/modules/config.py
index 4ae5e4c..4915fb6 100644
--- a/plip/modules/config.py
+++ b/plip/modules/config.py
@@ -1,19 +1,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 config.py - Store thresholds used by PLIP.
-Copyright 2014 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 VERBOSE = False  # Set verbose mode
@@ -32,6 +19,7 @@ NOFIX = False  # Turn off fixing of errors in PDB files
 PEPTIDES = []  # Definition which chains should be considered as peptide ligands
 INTRA = None
 KEEPMOD = False
+DNARECEPTOR = False
 
 # Configuration file for Protein-Ligand Interaction Profiler (PLIP)
 # Set thresholds for detection of interactions
@@ -44,7 +32,7 @@ MIN_DIST = 0.5 # Minimum distance for all distance thresholds
 HYDROPH_DIST_MAX = 4.0  # Distance cutoff for detection of hydrophobic contacts
 HBOND_DIST_MAX = 4.1  # Max. distance between hydrogen bond donor and acceptor (Hubbard & Haider, 2001) + 0.6 A
 HBOND_DON_ANGLE_MIN = 100  # Min. angle at the hydrogen bond donor (Hubbard & Haider, 2001) + 10
-PISTACK_DIST_MAX = 7.5  # Max. distance for parallel or offset pistacking (McGaughey, 1998)
+PISTACK_DIST_MAX = 5.5  # Max. distance for parallel or offset pistacking (McGaughey, 1998)
 PISTACK_ANG_DEV = 30  # Max. Deviation from parallel or perpendicular orientation (in degrees)
 PISTACK_OFFSET_MAX = 2.0  # Maximum offset of the two rings (corresponds to the radius of benzene + 0.5 A)
 PICATION_DIST_MAX = 6.0  # Max. distance between charged atom and aromatic ring center (Gallivan and Dougherty, 1999)
@@ -60,6 +48,17 @@ WATER_BRIDGE_OMEGA_MAX = 140  # Max. angle between acceptor, water oxygen and do
 WATER_BRIDGE_THETA_MIN = 100  # Min. angle between water oxygen, donor hydrogen and donor atom (Jiang et al., 2005)
 METAL_DIST_MAX = 3.0  # Max. distance between metal ion and interacting atom (Harding, 2001)
 
+# Other thresholds
+MAX_COMPOSITE_LENGTH = 200 # Filter out ligands with more than 200 fragments
+
+#########
+# Names #
+#########
+
+# Names of RNA and DNA residues to be considered (detection by name)
+RNA = ['U', 'A', 'C', 'G']
+DNA = ['DT', 'DA', 'DC', 'DG']
+
 #############
 # Whitelist #
 #############
diff --git a/plip/modules/detection.py b/plip/modules/detection.py
index 6143ea8..61a4f8b 100644
--- a/plip/modules/detection.py
+++ b/plip/modules/detection.py
@@ -1,28 +1,42 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 detection.py - Detect non-covalent interactions.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 # Python standard library
+from __future__ import absolute_import
 import itertools
 from collections import defaultdict
 
 # Own modules
-from supplemental import *
-import config
+from plip.modules.supplemental import *
+import plip.modules.config
+
+
+def filter_contacts(pairings):
+    """Filter interactions by two criteria:
+    1. No interactions between the same residue (important for intra mode).
+    2. No duplicate interactions (A with B and B with A, also important for intra mode)."""
+    if config.INTRA:
+        filtered1_pairings = [p for p in pairings if (p.resnr, p.reschain) != (p.resnr_l, p.reschain_l)]
+        already_considered = []
+        filtered2_pairings = []
+        for contact in filtered1_pairings:
+            try:
+                dist = 'D{}'.format(round(contact.distance,2))
+            except AttributeError:
+                try:
+                    dist = 'D{}'.format(round(contact.distance_ah,2))
+                except AttributeError:
+                    dist = 'D{}'.format(round(contact.distance_aw,2))
+            res1, res2 = ''.join([str(contact.resnr), contact.reschain]), ''.join([str(contact.resnr_l), contact.reschain_l])
+            data = set([res1, res2, dist])
+            if data not in already_considered:
+                filtered2_pairings.append(contact)
+                already_considered.append(data)
+        return filtered2_pairings
+    else:
+        return pairings
 
 
 ##################################################
@@ -34,18 +48,21 @@ def hydrophobic_interactions(atom_set_a, atom_set_b):
     Definition: All pairs of qualified carbon atoms within a distance of HYDROPH_DIST_MAX
     """
     data = namedtuple('hydroph_interaction', 'bsatom bsatom_orig_idx ligatom ligatom_orig_idx '
-                                             'distance restype resnr reschain')
+                                             'distance restype resnr reschain restype_l, resnr_l, reschain_l')
     pairings = []
     for a, b in itertools.product(atom_set_a, atom_set_b):
         if a.orig_idx == b.orig_idx:
             continue
         e = euclidean3d(a.atom.coords, b.atom.coords)
         if config.MIN_DIST < e < config.HYDROPH_DIST_MAX:
+            restype, resnr, reschain = whichrestype(a.atom), whichresnumber(a.atom), whichchain(a.atom)
+            restype_l, resnr_l, reschain_l = whichrestype(b.orig_atom), whichresnumber(b.orig_atom), whichchain(b.orig_atom)
             contact = data(bsatom=a.atom, bsatom_orig_idx=a.orig_idx, ligatom=b.atom, ligatom_orig_idx=b.orig_idx,
-                           distance=e, restype=whichrestype(a.atom), resnr=whichresnumber(a.atom),
-                           reschain=whichchain(a.atom))
+                           distance=e, restype=restype, resnr=resnr,
+                           reschain=reschain, restype_l=restype_l,
+                           resnr_l=resnr_l, reschain_l=reschain_l)
             pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
 
 
 def hbonds(acceptors, donor_pairs, protisdon, typ):
@@ -55,7 +72,7 @@ def hbonds(acceptors, donor_pairs, protisdon, typ):
     and donor angles above HBOND_DON_ANGLE_MIN
     """
     data = namedtuple('hbond', 'a a_orig_idx d d_orig_idx h distance_ah distance_ad angle type protisdon resnr '
-                               'restype reschain sidechain atype dtype')
+                               'restype reschain resnr_l restype_l reschain_l sidechain atype dtype')
     pairings = []
     for acc, don in itertools.product(acceptors, donor_pairs):
         if typ == 'strong':  # Regular (strong) hydrogen bonds
@@ -65,27 +82,31 @@ def hbonds(acceptors, donor_pairs, protisdon, typ):
                 vec1, vec2 = vector(don.h.coords, don.d.coords), vector(don.h.coords, acc.a.coords)
                 v = vecangle(vec1, vec2)
                 if v > config.HBOND_DON_ANGLE_MIN:
-                    restype = whichrestype(don.d) if protisdon else whichrestype(acc.a)
-                    reschain = whichchain(don.d) if protisdon else whichchain(acc.a)
                     protatom = don.d.OBAtom if protisdon else acc.a.OBAtom
                     ligatom = don.d.OBAtom if not protisdon else acc.a.OBAtom
                     is_sidechain_hbond = protatom.GetResidue().GetAtomProperty(protatom, 8)  # Check if sidechain atom
-                    resnr = whichresnumber(don.d)if protisdon else whichresnumber(acc.a)
+                    resnr = whichresnumber(don.d) if protisdon else whichresnumber(acc.a)
+                    resnr_l = whichresnumber(acc.a_orig_atom) if protisdon else whichresnumber(don.d_orig_atom)
+                    restype = whichrestype(don.d) if protisdon else whichrestype(acc.a)
+                    restype_l = whichrestype(acc.a_orig_atom) if protisdon else whichrestype(don.d_orig_atom)
+                    reschain = whichchain(don.d) if protisdon else whichchain(acc.a)
+                    rechain_l = whichchain(acc.a_orig_atom) if protisdon else whichchain(don.d_orig_atom)
                     # Next line prevents H-Bonds within amino acids in intermolecular interactions
                     if config.INTRA is not None and whichresnumber(don.d) == whichresnumber(acc.a): continue
                     # Next line prevents backbone-backbone H-Bonds
                     if config.INTRA is not None and protatom.GetResidue().GetAtomProperty(protatom, 8) and ligatom.GetResidue().GetAtomProperty(ligatom, 8): continue
                     contact = data(a=acc.a, a_orig_idx=acc.a_orig_idx, d=don.d, d_orig_idx=don.d_orig_idx, h=don.h,
                                    distance_ah=dist_ah, distance_ad=dist_ad, angle=v, type=typ, protisdon=protisdon,
-                                   resnr=resnr, restype=restype, reschain=reschain, sidechain=is_sidechain_hbond,
+                                   resnr=resnr, restype=restype, reschain=reschain, resnr_l=resnr_l,
+                                   restype_l=restype_l, reschain_l=rechain_l, sidechain=is_sidechain_hbond,
                                    atype=acc.a.type, dtype=don.d.type)
                     pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
 
 
 def pistacking(rings_bs, rings_lig):
     """Return all pi-stackings between the given aromatic ring systems in receptor and ligand."""
-    data = namedtuple('pistack', 'proteinring ligandring distance angle offset type restype resnr reschain')
+    data = namedtuple('pistack', 'proteinring ligandring distance angle offset type restype resnr reschain restype_l resnr_l reschain_l')
     pairings = []
     for r, l in itertools.product(rings_bs, rings_lig):
         # DISTANCE AND RING ANGLE CALCULATION
@@ -100,25 +121,30 @@ def pistacking(rings_bs, rings_lig):
 
         # RECEPTOR DATA
         resnr, restype, reschain = whichresnumber(r.atoms[0]), whichrestype(r.atoms[0]), whichchain(r.atoms[0])
+        resnr_l, restype_l, reschain_l = whichresnumber(l.orig_atoms[0]), whichrestype(l.orig_atoms[0]), whichchain(l.orig_atoms[0])
 
         # SELECTION BY DISTANCE, ANGLE AND OFFSET
+        passed = False
         if config.MIN_DIST < d < config.PISTACK_DIST_MAX:
             if 0 < a < config.PISTACK_ANG_DEV and offset < config.PISTACK_OFFSET_MAX:
-                contact = data(proteinring=r, ligandring=l, distance=d, angle=a, offset=offset,
-                               type='P', resnr=resnr, restype=restype, reschain=reschain)
-                pairings.append(contact)
+                ptype = 'P'
+                passed = True
             if 90 - config.PISTACK_ANG_DEV < a < 90 + config.PISTACK_ANG_DEV and offset < config.PISTACK_OFFSET_MAX:
+                ptype = 'T'
+                passed = True
+            if passed:
                 contact = data(proteinring=r, ligandring=l, distance=d, angle=a, offset=offset,
-                               type='T', resnr=resnr, restype=restype, reschain=reschain)
+                               type=ptype, resnr=resnr, restype=restype, reschain=reschain,
+                               resnr_l=resnr_l, restype_l=restype_l, reschain_l=reschain_l)
                 pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
 
 
 def pication(rings, pos_charged, protcharged):
     """Return all pi-Cation interaction between aromatic rings and positively charged groups.
     For tertiary and quaternary amines, check also the angle between the ring and the nitrogen.
     """
-    data = namedtuple('pication', 'ring charge distance offset type restype resnr reschain protcharged')
+    data = namedtuple('pication', 'ring charge distance offset type restype resnr reschain restype_l resnr_l reschain_l protcharged')
     pairings = []
     if not len(rings) == 0 and not len(pos_charged) == 0:
         for ring in rings:
@@ -142,38 +168,50 @@ def pication(rings, pos_charged, protcharged):
                         if not a > 30.0:
                             resnr, restype = whichresnumber(ring.atoms[0]), whichrestype(ring.atoms[0])
                             reschain = whichchain(ring.atoms[0])
+                            resnr_l, restype_l = whichresnumber(p.orig_atoms[0]), whichrestype(p.orig_atoms[0])
+                            reschain_l = whichchain(p.orig_atoms[0])
                             contact = data(ring=ring, charge=p, distance=d, offset=offset, type='regular',
-                                           restype=restype, resnr=resnr, reschain=reschain, protcharged=protcharged)
+                                           restype=restype, resnr=resnr, reschain=reschain,
+                                           restype_l=restype_l, resnr_l=resnr_l, reschain_l=reschain_l,
+                                           protcharged=protcharged)
                             pairings.append(contact)
                         break
                     resnr = whichresnumber(p.atoms[0]) if protcharged else whichresnumber(ring.atoms[0])
+                    resnr_l = whichresnumber(ring.orig_atoms[0]) if protcharged else whichresnumber(p.orig_atoms[0])
                     restype = whichrestype(p.atoms[0]) if protcharged else whichrestype(ring.atoms[0])
+                    restype_l = whichrestype(ring.orig_atoms[0]) if protcharged else whichrestype(p.orig_atoms[0])
                     reschain = whichchain(p.atoms[0]) if protcharged else whichchain(ring.atoms[0])
+                    reschain_l = whichchain(ring.orig_atoms[0]) if protcharged else whichchain(p.orig_atoms[0])
                     contact = data(ring=ring, charge=p, distance=d, offset=offset, type='regular', restype=restype,
-                                   resnr=resnr, reschain=reschain, protcharged=protcharged)
+                                   resnr=resnr, reschain=reschain, restype_l=restype_l, resnr_l=resnr_l,
+                                   reschain_l=reschain_l, protcharged=protcharged)
                     pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
 
 
 def saltbridge(poscenter, negcenter, protispos):
     """Detect all salt bridges (pliprofiler between centers of positive and negative charge)"""
-    data = namedtuple('saltbridge', 'positive negative distance protispos resnr restype reschain')
+    data = namedtuple('saltbridge', 'positive negative distance protispos resnr restype reschain resnr_l restype_l reschain_l')
     pairings = []
     for pc, nc in itertools.product(poscenter, negcenter):
         if config.MIN_DIST < euclidean3d(pc.center, nc.center) < config.SALTBRIDGE_DIST_MAX:
             resnr = pc.resnr if protispos else nc.resnr
+            resnr_l = whichresnumber(nc.orig_atoms[0]) if protispos else whichresnumber(pc.orig_atoms[0])
             restype = pc.restype if protispos else nc.restype
+            restype_l = whichrestype(nc.orig_atoms[0]) if protispos else whichrestype(pc.orig_atoms[0])
             reschain = pc.reschain if protispos else nc.reschain
+            reschain_l = whichchain(nc.orig_atoms[0]) if protispos else whichchain(pc.orig_atoms[0])
             contact = data(positive=pc, negative=nc, distance=euclidean3d(pc.center, nc.center), protispos=protispos,
-                           resnr=resnr, restype=restype, reschain=reschain)
+                           resnr=resnr, restype=restype, reschain=reschain, resnr_l=resnr_l, restype_l=restype_l,
+                           reschain_l=reschain_l)
             pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
 
 
 def halogen(acceptor, donor):
     """Detect all halogen bonds of the type Y-O...X-C"""
     data = namedtuple('halogenbond', 'acc acc_orig_idx don don_orig_idx distance don_angle acc_angle restype '
-                                     'resnr reschain donortype acctype sidechain')
+                                     'resnr reschain restype_l resnr_l reschain_l donortype acctype sidechain')
     pairings = []
     for acc, don in itertools.product(acceptor, donor):
         dist = euclidean3d(acc.o.coords, don.x.coords)
@@ -186,19 +224,22 @@ def halogen(acceptor, donor):
                     < config.HALOGEN_ACC_ANGLE + config.HALOGEN_ANGLE_DEV:
                 if config.HALOGEN_DON_ANGLE - config.HALOGEN_ANGLE_DEV < don_angle \
                         < config.HALOGEN_DON_ANGLE + config.HALOGEN_ANGLE_DEV:
+                    restype, reschain, resnr = whichrestype(acc.o), whichchain(acc.o), whichresnumber(acc.o)
+                    restype_l, reschain_l, resnr_l = whichrestype(don.orig_x), whichchain(don.orig_x), whichresnumber(don.orig_x)
                     contact = data(acc=acc, acc_orig_idx=acc.o_orig_idx, don=don, don_orig_idx=don.x_orig_idx,
                                    distance=dist, don_angle=don_angle, acc_angle=acc_angle,
-                                   restype=whichrestype(acc.o), resnr=whichresnumber(acc.o),
-                                   reschain=whichchain(acc.o), donortype=don.x.OBAtom.GetType(), acctype=acc.o.type,
+                                   restype=restype, resnr=resnr,
+                                   reschain=reschain, restype_l=restype_l,
+                                   reschain_l=reschain_l, resnr_l=resnr_l, donortype=don.x.OBAtom.GetType(), acctype=acc.o.type,
                                    sidechain=is_sidechain_hal)
                     pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
 
 
 def water_bridges(bs_hba, lig_hba, bs_hbd, lig_hbd, water):
     """Find water-bridged hydrogen bonds between ligand and protein. For now only considers bridged of first degree."""
     data = namedtuple('waterbridge', 'a a_orig_idx atype d d_orig_idx dtype h water water_orig_idx distance_aw '
-                                     'distance_dw d_angle w_angle type resnr restype reschain protisdon')
+                                     'distance_dw d_angle w_angle type resnr restype reschain resnr_l restype_l reschain_l protisdon')
     pairings = []
     # First find all acceptor-water pairs with distance within d
     # and all donor-water pairs with distance within d and angle greater theta
@@ -231,11 +272,13 @@ def water_bridges(bs_hba, lig_hba, bs_hbd, lig_hbd, water):
         if wl.oxy == wd.oxy:  # Same water molecule and angle within omega
             w_angle = vecangle(vector(acc.a.coords, wl.oxy.coords), vector(wl.oxy.coords, don.h.coords))
             if config.WATER_BRIDGE_OMEGA_MIN < w_angle < config.WATER_BRIDGE_OMEGA_MAX:
+                resnr, reschain, restype = whichresnumber(don.d), whichchain(don.d), whichrestype(don.d)
+                resnr_l, reschain_l, restype_l = whichresnumber(acc.a_orig_atom), whichchain(acc.a_orig_atom), whichrestype(acc.a_orig_atom)
                 contact = data(a=acc.a, a_orig_idx=acc.a_orig_idx, atype=acc.a.type, d=don.d, d_orig_idx=don.d_orig_idx,
                                dtype=don.d.type, h=don.h, water=wl.oxy, water_orig_idx=wl.oxy_orig_idx,
                                distance_aw=distance_aw, distance_dw=distance_dw, d_angle=d_angle, w_angle=w_angle,
-                               type='first_deg', resnr=whichresnumber(don.d), restype=whichrestype(don.d),
-                               reschain=whichchain(don.d), protisdon=True)
+                               type='first_deg', resnr=resnr, restype=restype,
+                               reschain=reschain, restype_l=restype_l, resnr_l=resnr_l, reschain_l=reschain_l, protisdon=True)
                 pairings.append(contact)
     for p, l in itertools.product(prot_aw, lig_dw):
         acc, wl, distance_aw = p
@@ -243,30 +286,35 @@ def water_bridges(bs_hba, lig_hba, bs_hbd, lig_hbd, water):
         if wl.oxy == wd.oxy:  # Same water molecule and angle within omega
             w_angle = vecangle(vector(acc.a.coords, wl.oxy.coords), vector(wl.oxy.coords, don.h.coords))
             if config.WATER_BRIDGE_OMEGA_MIN < w_angle < config.WATER_BRIDGE_OMEGA_MAX:
+                resnr, reschain, restype = whichresnumber(acc.a), whichchain(acc.a), whichrestype(acc.a)
+                resnr_l, reschain_l, restype_l = whichresnumber(don.d_orig_atom), whichchain(don.d_orig_atom), whichrestype(don.d_orig_atom)
                 contact = data(a=acc.a, a_orig_idx=acc.a_orig_idx, atype=acc.a.type, d=don.d, d_orig_idx=don.d_orig_idx,
                                dtype=don.d.type, h=don.h, water=wl.oxy, water_orig_idx=wl.oxy_orig_idx,
                                distance_aw=distance_aw, distance_dw=distance_dw,
-                               d_angle=d_angle, w_angle=w_angle, type='first_deg', resnr=whichresnumber(acc.a),
-                               restype=whichrestype(acc.a), reschain=whichchain(acc.a), protisdon=False)
+                               d_angle=d_angle, w_angle=w_angle, type='first_deg', resnr=resnr,
+                               restype=restype, reschain=reschain,
+                               restype_l=restype_l, reschain_l=reschain_l, resnr_l=resnr_l, protisdon=False)
                 pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
 
 
 def metal_complexation(metals, metal_binding_lig, metal_binding_bs):
     """Find all metal complexes between metals and appropriate groups in both protein and ligand, as well as water"""
     data = namedtuple('metal_complex', 'metal metal_orig_idx metal_type target target_orig_idx target_type '
                                        'coordination_num distance resnr restype '
-                                       'reschain location rms, geometry num_partners complexnum')
+                                       'reschain  restype_l reschain_l resnr_l location rms, geometry num_partners complexnum')
     pairings_dict = {}
     pairings = []
     # #@todo Refactor
     metal_to_id = {}
+    metal_to_orig_atom = {}
     for metal, target in itertools.product(metals, metal_binding_lig + metal_binding_bs):
         distance = euclidean3d(metal.m.coords, target.atom.coords)
         if distance < config.METAL_DIST_MAX:
             if metal.m not in pairings_dict:
                 pairings_dict[metal.m] = [(target, distance), ]
                 metal_to_id[metal.m] = metal.m_orig_idx
+                metal_to_orig_atom[metal.m] = metal.orig_m
             else:
                 pairings_dict[metal.m].append((target, distance))
     for cnum, metal in enumerate(pairings_dict):
@@ -391,10 +439,13 @@ def metal_complexation(metals, metal_binding_lig, metal_binding_bs):
             for contact_pair in contact_pairs:
                 target, distance = contact_pair
                 if target.atom.idx not in excluded:
+                    metal_orig_atom = metal_to_orig_atom[metal]
+                    restype_l, reschain_l, resnr_l = whichrestype(metal_orig_atom), whichchain(metal_orig_atom), whichresnumber(metal_orig_atom)
                     contact = data(metal=metal, metal_orig_idx=metal_to_id[metal], metal_type=metal.type,
                                    target=target, target_orig_idx=target.atom_orig_idx, target_type=target.type,
                                    coordination_num=final_coo, distance=distance, resnr=target.resnr,
                                    restype=target.restype, reschain=target.reschain, location=target.location,
-                                   rms=rms, geometry=final_geom, num_partners=num_targets, complexnum=cnum + 1)
+                                   rms=rms, geometry=final_geom, num_partners=num_targets, complexnum=cnum + 1,
+                                   resnr_l=resnr_l, restype_l=restype_l, reschain_l=reschain_l)
                     pairings.append(contact)
-    return pairings
+    return filter_contacts(pairings)
diff --git a/plip/modules/mp.py b/plip/modules/mp.py
index ae5a951..ec78f7b 100644
--- a/plip/modules/mp.py
+++ b/plip/modules/mp.py
@@ -1,19 +1,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 mp.py - Functions for parallel processing
-Copyright 2014-2015 Sebastian Salentin, Joachim Haupt
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 # Python Standard Library
@@ -34,7 +21,7 @@ class SubProcessError(Exception):
 def universal_worker(input_pair):
     """This is a wrapper function expecting a tiplet of function, single
        argument, dict of keyword arguments. The provided function is called
-       with the appropriate arguments.""" 
+       with the appropriate arguments."""
     function, arg, kwargs = input_pair
     return function(arg, **kwargs)
 
@@ -48,22 +35,21 @@ def parallel_fn(f):
     """Simple wrapper function, returning a parallel version of the given function f.
        The function f must have one argument and may have an arbitray number of
        keyword arguments. """
-       
+
     def simple_parallel(func, sequence, **args):
         """ f takes an element of sequence as input and the keyword args in **args"""
-        multiprocessing.freeze_support()
         if 'processes' in args:
             processes = args.get('processes')
             del args['processes']
         else:
             processes = multiprocessing.cpu_count()
-        
-        pool = multiprocessing.Pool(processes=processes)  # depends on available cores
-        result = pool.map(universal_worker, pool_args(func, sequence, args))
-        cleaned = [x for x in result if x is not None]  # getting results
-        cleaned = asarray(cleaned)
+
+        pool = multiprocessing.Pool(processes)  # depends on available cores
+
+        result = pool.map_async(universal_worker, pool_args(func, sequence, args))
         pool.close()
         pool.join()
+        cleaned = [x for x in result.get() if x is not None]  # getting results
+        cleaned = asarray(cleaned)
         return cleaned
     return partial(simple_parallel, f)
-
diff --git a/plip/modules/plipremote.py b/plip/modules/plipremote.py
index e2fd18f..f35cc55 100644
--- a/plip/modules/plipremote.py
+++ b/plip/modules/plipremote.py
@@ -1,19 +1,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 plipremote.py - Modules involved in multiprocessing and remote computation.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 # Python Standard Library
diff --git a/plip/modules/plipxml.py b/plip/modules/plipxml.py
index 96e7f24..a856cac 100644
--- a/plip/modules/plipxml.py
+++ b/plip/modules/plipxml.py
@@ -1,19 +1,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 plipxml.py - Read in PLIP XML files for further analysis.
-Copyright 2014-2016 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 # Python standard library
@@ -24,7 +11,6 @@ from itertools import groupby
 import sys
 import urllib2
 
-#TODO True/False values for all corresponding attributes
 
 class XMLStorage:
     """Generic class for storing XML data from PLIP XML files."""
@@ -64,7 +50,10 @@ class Interaction(XMLStorage):
         self.id = interaction_part.get('id')
         self.resnr = self.getdata(interaction_part, 'resnr')
         self.restype = self.getdata(interaction_part, 'restype')
-        self.reschain = self.getdata(interaction_part, 'reschain')
+        self.reschain = self.getdata(interaction_part, 'reschain', force_string=True)
+        self.resnr_lig = self.getdata(interaction_part, 'resnr_lig')
+        self.restype_lig = self.getdata(interaction_part, 'restype_lig')
+        self.reschain_lig = self.getdata(interaction_part, 'reschain_lig', force_string=True)
         self.ligcoo = self.getcoordinates(interaction_part, 'ligcoo')
         self.protcoo = self.getcoordinates(interaction_part, 'protcoo')
 
@@ -267,11 +256,12 @@ class BSite(XMLStorage):
     def get_counts(self):
         """counts the interaction types and backbone hydrogen bonding in a binding site"""
 
-        hbondsback = len([hb for hb in self.hbonds if hb.sidechain == 'F'])
+        hbondsback = len([hb for hb in self.hbonds if not hb.sidechain])
         counts = {'hydrophobics': len(self.hydrophobics), 'hbonds': len(self.hbonds),
                       'wbridges': len(self.wbridges), 'sbridges': len(self.sbridges), 'pistacks': len(self.pi_stacks),
                       'pications': len(self.pi_cations), 'halogens': len(self.halogens), 'metal': len(self.metal_complexes),
                       'hbond_back': hbondsback, 'hbond_nonback': (len(self.hbonds) - hbondsback)}
+        counts['total'] = counts['hydrophobics'] + counts['hbonds'] + counts['wbridges'] + counts['sbridges'] + counts['pistacks'] + counts['pications'] + counts['halogens'] + counts['metal']
         return counts
 
 class PLIPXML(XMLStorage):
diff --git a/plip/modules/preparation.py b/plip/modules/preparation.py
index b839caf..207c474 100644
--- a/plip/modules/preparation.py
+++ b/plip/modules/preparation.py
@@ -1,29 +1,17 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 preparation.py - Prepare PDB input files for processing.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 
 # Python Standard Library
+from __future__ import absolute_import
 from operator import itemgetter
 
 # Own modules
-from detection import *
-from supplemental import *
-import config
+from plip.modules.detection import *
+from plip.modules.supplemental import *
+import plip.modules.config
 
 
 ################
@@ -38,6 +26,7 @@ class PDBParser:
         self.covlinkage = namedtuple("covlinkage", "id1 chain1 pos1 conf1 id2 chain2 pos2 conf2")
         self.proteinmap, self.modres, self.covalent, self.altconformations, self.corrected_pdb = self.parse_pdb()
 
+
     def parse_pdb(self):
         """Extracts additional information from PDB files.
         I. When reading in a PDB file, OpenBabel numbers ATOMS and HETATOMS continously.
@@ -64,11 +53,20 @@ class PDBParser:
         if not config.NOFIX:
             if not config.PLUGIN_MODE:
                 lastnum = 0 # Atom numbering (has to be consecutive)
+                other_models = False
                 for line in fil:
-                    corrected_line, newnum = self.fix_pdbline(line, lastnum)
-                    if corrected_line is not None:
-                        corrected_lines.append(corrected_line)
-                        lastnum = newnum
+                    if not other_models: # Only consider the first model in an NRM structure
+                        corrected_line, newnum = self.fix_pdbline(line, lastnum)
+                        if corrected_line is not None:
+                            if corrected_line.startswith('MODEL'):
+                                try: # Get number of MODEL (1,2,3)
+                                    model_num = int(corrected_line[10:14])
+                                    if model_num > 1: # MODEL 2,3,4 etc.
+                                        other_models = True
+                                except ValueError:
+                                    write_message("Ignoring invalid MODEL entry: %s\n" % corrected_line, mtype='debug')
+                            corrected_lines.append(corrected_line)
+                            lastnum = newnum
                 corrected_pdb = ''.join(corrected_lines)
             else:
                 corrected_pdb = self.pdbpath
@@ -156,12 +154,16 @@ class PDBParser:
                     self.num_fixed_lines += 1
         if pdbline.startswith('HETATM'):
             newnum = lastnum + 1
-            currentnum = int(pdbline[6:11])
+            try:
+                currentnum = int(pdbline[6:11])
+            except ValueError:
+                currentnum = None
+                write_message("Invalid HETATM entry: %s\n" % pdbline, mtype='debug')
             if lastnum + 1 != currentnum:
                 pdbline = pdbline[:6] + (5 - len(str(newnum))) * ' ' + str(newnum) + ' ' + pdbline[12:]
                 fixed = True
             # No chain assigned or number assigned as chain
-            if pdbline[21] == ' ' or re.match("[0-9]", pdbline[21]):
+            if pdbline[21] == ' ':
                 pdbline = pdbline[:21] + 'Z' + pdbline[22:]
                 fixed = True
             # No residue number assigned
@@ -221,7 +223,6 @@ class LigandFinder:
         if len(all_from_chain) == 0:
             return None
         else:
-            #TODO Can be done shorter with a split
             water = [o for o in all_from_chain if o.GetResidueProperty(9)]
             non_water = water = [o for o in all_from_chain if not o.GetResidueProperty(9)]
             ligand = self.extract_ligand(non_water)
@@ -250,8 +251,12 @@ class LigandFinder:
                 res_kmers = self.identify_kmers(all_res_dict)
             else:
                 res_kmers = [[a, ] for a in ligand_residues]
+            write_message("{} ligand kmer(s) detected for closer inspection.\n".format(len(res_kmers)), mtype='debug')
             for kmer in res_kmers:  # iterate over all ligands and extract molecules + information
-                ligands.append(self.extract_ligand(kmer))
+                if len(kmer) > config.MAX_COMPOSITE_LENGTH:
+                    write_message("Ligand kmer(s) filtered out with a length of {} fragments ({} allowed).\n".format(len(kmer), config.MAX_COMPOSITE_LENGTH), mtype='debug')
+                else:
+                    ligands.append(self.extract_ligand(kmer))
 
         else:
             # Extract peptides from given chains
@@ -272,7 +277,7 @@ class LigandFinder:
         members = [(res.GetName(), res.GetChain(), int32_to_negative(res.GetNum())) for res in kmer]
         members = sort_members_by_importance(members)
         rname, rchain, rnum = members[0]
-        write_message("Finalizing extraction for ligand %s:%s:%s\n" % (rname, rchain, rnum), mtype='debug')
+        write_message("Finalizing extraction for ligand %s:%s:%s with %i elements\n" % (rname, rchain, rnum, len(kmer)), mtype='debug')
         names = [x[0] for x in members]
         longname = '-'.join([x[0] for x in members])
 
@@ -283,6 +288,7 @@ class LigandFinder:
         else:
             # Classify a ligand by its HETID(s)
             ligtype = classify_by_name(names)
+        write_message("Ligand classified as {}\n".format(ligtype), mtype='debug')
 
         hetatoms = set()
         for obresidue in kmer:
@@ -295,6 +301,7 @@ class LigandFinder:
                                     if not self.mapper.mapid(atm[0], mtype='protein',
                                                              to='internal') in self.altconformations])
             hetatoms.update(hetatoms_res)
+        write_message("Hetero atoms determined (n={})\n".format(len(hetatoms)), mtype='debug')
 
         hetatoms = dict(hetatoms)  # make it a dict with idx as key and OBAtom as value
         lig = pybel.ob.OBMol()  # new ligand mol
@@ -305,6 +312,7 @@ class LigandFinder:
             # ids of all neighbours of obatom
             neighbours[idx] = set([neighbour_atom.GetIdx() for neighbour_atom
                                    in pybel.ob.OBAtomAtomIter(obatom)]) & set(hetatoms.keys())
+        write_message("Atom neighbours mapped\n", mtype='debug')
 
         ##############################################################
         # map the old atom idx of OBMol to the new idx of the ligand #
@@ -329,6 +337,8 @@ class LigandFinder:
         lig.title = ':'.join((rname, rchain, str(rnum)))
         self.mapper.ligandmaps[lig.title] = mapold
 
+        write_message("Renumerated molecule generated\n", mtype='debug')
+
         atomorder = canonicalize(lig)
 
         can_to_pdb = {}
@@ -354,7 +364,7 @@ class LigandFinder:
             # Only residues with at least one HETATM entry are processed as ligands
             het_atoms = []
             for atm in pybel.ob.OBResidueAtomIter(obres):
-                    het_atoms.append(obres.IsHetAtom(atm))
+                het_atoms.append(obres.IsHetAtom(atm))
             if True in het_atoms:
                 return True
         return False
@@ -364,6 +374,9 @@ class LigandFinder:
         """Given an OpenBabel Molecule, get all ligands, their names, and water"""
 
         candidates1 = [o for o in pybel.ob.OBResidueIter(self.proteincomplex.OBMol) if not o.GetResidueProperty(9) and self.is_het_residue(o)]
+
+        if config.DNARECEPTOR: # If DNA is the receptor, don't consider DNA as a ligand
+            candidates1 = [res for res in candidates1 if res.GetName() not in config.DNA+config.RNA]
         all_lignames = set([a.GetName() for a in candidates1])
 
         water = [o for o in pybel.ob.OBResidueIter(self.proteincomplex.OBMol) if o.GetResidueProperty(9)]
@@ -396,7 +409,8 @@ class LigandFinder:
                        (link.id2, link.chain2, link.pos2)] for link in
                       [c for c in self.covalent if c.id1 in self.lignames_kept and c.id2 in self.lignames_kept and
                        c.conf1 in ['A', ''] and c.conf2 in ['A', '']
-                      and (c.id1, c.chain1, c.pos1) in residues and (c.id2, c.chain2, c.pos2) in residues]]
+                      and (c.id1, c.chain1, c.pos1) in residues
+                      and (c.id2, c.chain2, c.pos2) in residues]]
         kmers = cluster_doubles(ligdoubles)
         if not kmers:  # No ligand kmers, just normal independent ligands
             return [[residues[res]] for res in residues]
@@ -422,10 +436,11 @@ class Mapper:
     def __init__(self):
         self.proteinmap = None  # Map internal atom IDs of protein residues to original PDB Atom IDs
         self.ligandmaps = {}  # Map IDs of new ligand molecules to internal IDs (or PDB IDs?)
+        self.original_structure = None
 
     def mapid(self, idx, mtype, bsid=None, to='original'):  # Mapping to original IDs is standard for ligands
-        # #@todo Check for correct type of idx
-        # #@todo Include more safety checks
+        if mtype == 'reversed': # Needed to map internal ID back to original protein ID
+            return self.reversed_proteinmap[idx]
         if mtype == 'protein':
             return self.proteinmap[idx]
         elif mtype == 'ligand':
@@ -434,7 +449,13 @@ class Mapper:
             elif to == 'original':
                 return self.proteinmap[self.ligandmaps[bsid][idx]]
 
-    # #@todo Include chains, resnr and positions here!
+    def id_to_atom(self, idx):
+        """Returns the atom for a given original ligand ID.
+        To do this, the ID is mapped to the protein first and then the atom returned.
+        """
+        mapped_idx = self.mapid(idx, 'reversed')
+        return pybel.Atom(self.original_structure.GetAtom(mapped_idx))
+
 
 
 class Mol:
@@ -452,47 +473,51 @@ class Mol:
     def hydrophobic_atoms(self, all_atoms):
         """Select all carbon atoms which have only carbons and/or hydrogens as direct neighbors."""
         atom_set = []
-        data = namedtuple('hydrophobic', 'atom orig_idx')
+        data = namedtuple('hydrophobic', 'atom orig_atom orig_idx')
         atm = [a for a in all_atoms if a.atomicnum == 6 and set([natom.GetAtomicNum() for natom
                                                                  in pybel.ob.OBAtomAtomIter(a.OBAtom)]).issubset(
             {1, 6})]
         for atom in atm:
             orig_idx = self.Mapper.mapid(atom.idx, mtype=self.mtype, bsid=self.bsid)
+            orig_atom = self.Mapper.id_to_atom(orig_idx)
             if atom.idx not in self.altconf:
-                atom_set.append(data(atom=atom, orig_idx=orig_idx))
+                atom_set.append(data(atom=atom, orig_atom=orig_atom, orig_idx=orig_idx))
         return atom_set
 
     def find_hba(self, all_atoms):
         """Find all possible hydrogen bond acceptors"""
-        data = namedtuple('hbondacceptor', 'a a_orig_idx type')
+        data = namedtuple('hbondacceptor', 'a a_orig_atom a_orig_idx type')
         a_set = []
         for atom in itertools.ifilter(lambda at: at.OBAtom.IsHbondAcceptor(), all_atoms):
             if atom.atomicnum not in [9, 17, 35, 53] and atom.idx not in self.altconf:  # Exclude halogen atoms
                 a_orig_idx = self.Mapper.mapid(atom.idx, mtype=self.mtype, bsid=self.bsid)
-                a_set.append(data(a=atom, a_orig_idx=a_orig_idx, type='regular'))
+                a_orig_atom = self.Mapper.id_to_atom(a_orig_idx)
+                a_set.append(data(a=atom, a_orig_atom=a_orig_atom, a_orig_idx=a_orig_idx, type='regular'))
         return a_set
 
     def find_hbd(self, all_atoms, hydroph_atoms):
         """Find all possible strong and weak hydrogen bonds donors (all hydrophobic C-H pairings)"""
         donor_pairs = []
-        data = namedtuple('hbonddonor', 'd d_orig_idx h type')
+        data = namedtuple('hbonddonor', 'd d_orig_atom d_orig_idx h type')
         for donor in [a for a in all_atoms if a.OBAtom.IsHbondDonor() and a.idx not in self.altconf]:
             in_ring = False
             if not in_ring:
                 for adj_atom in [a for a in pybel.ob.OBAtomAtomIter(donor.OBAtom) if a.IsHbondDonorH()]:
                     d_orig_idx = self.Mapper.mapid(donor.idx, mtype=self.mtype, bsid=self.bsid)
-                    donor_pairs.append(data(d=donor, d_orig_idx=d_orig_idx, h=pybel.Atom(adj_atom), type='regular'))
+                    d_orig_atom = self.Mapper.id_to_atom(d_orig_idx)
+                    donor_pairs.append(data(d=donor, d_orig_atom=d_orig_atom, d_orig_idx=d_orig_idx, h=pybel.Atom(adj_atom), type='regular'))
         for carbon in hydroph_atoms:
             for adj_atom in [a for a in pybel.ob.OBAtomAtomIter(carbon.atom.OBAtom) if a.GetAtomicNum() == 1]:
                 d_orig_idx = self.Mapper.mapid(carbon.atom.idx, mtype=self.mtype, bsid=self.bsid)
-                donor_pairs.append(data(d=carbon, d_orig_idx=d_orig_idx, h=pybel.Atom(adj_atom), type='weak'))
+                d_orig_atom = self.Mapper.id_to_atom(d_orig_idx)
+                donor_pairs.append(data(d=carbon, d_orig_atom=d_orig_atom, d_orig_idx=d_orig_idx, h=pybel.Atom(adj_atom), type='weak'))
         return donor_pairs
 
 
     def find_rings(self, mol, all_atoms):
         """Find rings and return only aromatic.
         Rings have to be sufficiently planar OR be detected by OpenBabel as aromatic."""
-        data = namedtuple('aromatic_ring', 'atoms atoms_orig_idx normal obj center type')
+        data = namedtuple('aromatic_ring', 'atoms orig_atoms atoms_orig_idx normal obj center type')
         rings = []
         aromatic_amino = ['TYR', 'TRP', 'HIS', 'PHE']
         ring_candidates = mol.OBMol.GetSSSR()
@@ -511,7 +536,9 @@ class Mol:
                     ringv1 = vector(ring_atms[0], ring_atms[1])
                     ringv2 = vector(ring_atms[2], ring_atms[0])
                     atoms_orig_idx = [self.Mapper.mapid(r_atom.idx, mtype=self.mtype, bsid=self.bsid) for r_atom in r_atoms]
+                    orig_atoms = [self.Mapper.id_to_atom(idx) for idx in atoms_orig_idx]
                     rings.append(data(atoms=r_atoms,
+                                  orig_atoms=orig_atoms,
                                   atoms_orig_idx=atoms_orig_idx,
                                   normal=normalize_vector(np.cross(ringv1, ringv2)),
                                   obj=ring,
@@ -981,13 +1008,14 @@ class Ligand(Mol):
 
         ######
         donor_pairs = []
-        data = namedtuple('hbonddonor', 'd d_orig_idx h type')
+        data = namedtuple('hbonddonor', 'd d_orig_atom d_orig_idx h type')
         for donor in self.all_atoms:
             pdbidx = self.Mapper.mapid(donor.idx, mtype='ligand', bsid=self.bsid, to='original')
             d = cclass.atoms[self.pdb_to_idx_mapping[pdbidx]]
             if d.OBAtom.IsHbondDonor():
                 for adj_atom in [a for a in pybel.ob.OBAtomAtomIter(d.OBAtom) if a.IsHbondDonorH()]:
-                    donor_pairs.append(data(d=donor, d_orig_idx=pdbidx, h=pybel.Atom(adj_atom), type='regular'))
+                    d_orig_atom = self.Mapper.id_to_atom(pdbidx)
+                    donor_pairs.append(data(d=donor, d_orig_atom=d_orig_atom, d_orig_idx=pdbidx, h=pybel.Atom(adj_atom), type='regular'))
         self.hbond_don_atom_pairs = donor_pairs
         #######
 
@@ -1009,9 +1037,11 @@ class Ligand(Mol):
         self.halogenbond_don = self.find_hal(self.all_atoms)
         self.metal_binding = self.find_metal_binding(self.all_atoms, self.water)
         self.metals = []
-        data = namedtuple('metal', 'm m_orig_idx')
+        data = namedtuple('metal', 'm orig_m m_orig_idx')
         for a in [a for a in self.all_atoms if a.type.upper() in config.METAL_IONS]:
-            self.metals.append(data(m=a, m_orig_idx=self.Mapper.mapid(a.idx, mtype=self.mtype, bsid=self.bsid)))
+            m_orig_idx = self.Mapper.mapid(a.idx, mtype=self.mtype, bsid=self.bsid)
+            orig_m = self.Mapper.id_to_atom(m_orig_idx)
+            self.metals.append(data(m=a, m_orig_idx=m_orig_idx, orig_m=orig_m))
         self.num_hba, self.num_hbd = len(self.hbond_acc_atoms), len(self.hbond_don_atom_pairs)
         self.num_hal = len(self.halogenbond_don)
 
@@ -1064,14 +1094,15 @@ class Ligand(Mol):
 
     def find_hal(self, atoms):
         """Look for halogen bond donors (X-C, with X=F, Cl, Br, I)"""
-        data = namedtuple('hal_donor', 'x x_orig_idx c c_orig_idx')
+        data = namedtuple('hal_donor', 'x orig_x x_orig_idx c c_orig_idx')
         a_set = []
         for a in atoms:
             if self.is_functional_group(a, 'halocarbon'):
                 n_atoms = [na for na in pybel.ob.OBAtomAtomIter(a.OBAtom) if na.GetAtomicNum() == 6]
                 x_orig_idx = self.Mapper.mapid(a.idx, mtype=self.mtype, bsid=self.bsid)
+                orig_x = self.Mapper.id_to_atom(x_orig_idx)
                 c_orig_idx = [self.Mapper.mapid(na.GetIdx(), mtype=self.mtype, bsid=self.bsid) for na in n_atoms]
-                a_set.append(data(x=a, x_orig_idx=x_orig_idx, c=pybel.Atom(n_atoms[0]), c_orig_idx=c_orig_idx))
+                a_set.append(data(x=a, orig_x=orig_x, x_orig_idx=x_orig_idx, c=pybel.Atom(n_atoms[0]), c_orig_idx=c_orig_idx))
         if len(a_set) != 0:
             write_message('Ligand contains %i halogen atom(s).\n' % len(a_set), indent=True)
         return a_set
@@ -1082,18 +1113,19 @@ class Ligand(Mol):
         as mentioned in 'Cation-pi interactions in ligand recognition and catalysis' (Zacharias et al., 2002)).
         Identify negatively charged groups in the ligand.
         """
-        data = namedtuple('lcharge', 'atoms atoms_orig_idx type center fgroup')
+        data = namedtuple('lcharge', 'atoms orig_atoms atoms_orig_idx type center fgroup')
         a_set = []
         for a in all_atoms:
             a_orig_idx = self.Mapper.mapid(a.idx, mtype=self.mtype, bsid=self.bsid)
+            a_orig = self.Mapper.id_to_atom(a_orig_idx)
             if self.is_functional_group(a, 'quartamine'):
-                a_set.append(data(atoms=[a, ], atoms_orig_idx=[a_orig_idx, ], type='positive',
+                a_set.append(data(atoms=[a, ], orig_atoms = [a_orig, ], atoms_orig_idx=[a_orig_idx, ], type='positive',
                                   center=list(a.coords), fgroup='quartamine'))
             elif self.is_functional_group(a, 'tertamine'):
-                a_set.append(data(atoms=[a, ], atoms_orig_idx=[a_orig_idx, ], type='positive', center=list(a.coords),
+                a_set.append(data(atoms=[a, ], orig_atoms = [a_orig, ], atoms_orig_idx=[a_orig_idx, ], type='positive', center=list(a.coords),
                                   fgroup='tertamine'))
             if self.is_functional_group(a, 'sulfonium'):
-                a_set.append(data(atoms=[a, ], atoms_orig_idx=[a_orig_idx, ], type='positive', center=list(a.coords),
+                a_set.append(data(atoms=[a, ], orig_atoms = [a_orig, ], atoms_orig_idx=[a_orig_idx, ], type='positive', center=list(a.coords),
                                   fgroup='sulfonium'))
             if self.is_functional_group(a, 'phosphate'):
                 a_contributing = [a, ]
@@ -1101,7 +1133,8 @@ class Ligand(Mol):
                 [a_contributing.append(pybel.Atom(neighbor)) for neighbor in pybel.ob.OBAtomAtomIter(a.OBAtom)]
                 [a_contributing_orig_idx.append(self.Mapper.mapid(neighbor.idx, mtype=self.mtype, bsid=self.bsid))
                  for neighbor in a_contributing]
-                a_set.append(data(atoms=a_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
+                orig_contributing = [self.Mapper.id_to_atom(idx) for idx in a_contributing_orig_idx]
+                a_set.append(data(atoms=a_contributing, orig_atoms=orig_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
                                   center=a.coords, fgroup='phosphate'))
             if self.is_functional_group(a, 'sulfonicacid'):
                 a_contributing = [a, ]
@@ -1110,7 +1143,8 @@ class Ligand(Mol):
                  neighbor.GetAtomicNum() == 8]
                 [a_contributing_orig_idx.append(self.Mapper.mapid(neighbor.idx, mtype=self.mtype, bsid=self.bsid))
                  for neighbor in a_contributing]
-                a_set.append(data(atoms=a_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
+                orig_contributing = [self.Mapper.id_to_atom(idx) for idx in a_contributing_orig_idx]
+                a_set.append(data(atoms=a_contributing, orig_atoms=orig_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
                                   center=a.coords, fgroup='sulfonicacid'))
             elif self.is_functional_group(a, 'sulfate'):
                 a_contributing = [a, ]
@@ -1118,21 +1152,24 @@ class Ligand(Mol):
                 [a_contributing_orig_idx.append(self.Mapper.mapid(neighbor.idx, mtype=self.mtype, bsid=self.bsid))
                  for neighbor in a_contributing]
                 [a_contributing.append(pybel.Atom(neighbor)) for neighbor in pybel.ob.OBAtomAtomIter(a.OBAtom)]
-                a_set.append(data(atoms=a_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
+                orig_contributing = [self.Mapper.id_to_atom(idx) for idx in a_contributing_orig_idx]
+                a_set.append(data(atoms=a_contributing, orig_atoms=orig_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
                                   center=a.coords, fgroup='sulfate'))
             if self.is_functional_group(a, 'carboxylate'):
                 a_contributing = [pybel.Atom(neighbor) for neighbor in pybel.ob.OBAtomAtomIter(a.OBAtom)
                                   if neighbor.GetAtomicNum() == 8]
                 a_contributing_orig_idx = [self.Mapper.mapid(neighbor.idx, mtype=self.mtype, bsid=self.bsid)
                                            for neighbor in a_contributing]
-                a_set.append(data(atoms=a_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
+                orig_contributing = [self.Mapper.id_to_atom(idx) for idx in a_contributing_orig_idx]
+                a_set.append(data(atoms=a_contributing, orig_atoms=orig_contributing, atoms_orig_idx=a_contributing_orig_idx, type='negative',
                                   center=centroid([a.coords for a in a_contributing]), fgroup='carboxylate'))
             elif self.is_functional_group(a, 'guanidine'):
                 a_contributing = [pybel.Atom(neighbor) for neighbor in pybel.ob.OBAtomAtomIter(a.OBAtom)
                                   if neighbor.GetAtomicNum() == 7]
                 a_contributing_orig_idx = [self.Mapper.mapid(neighbor.idx, mtype=self.mtype, bsid=self.bsid)
                                            for neighbor in a_contributing]
-                a_set.append(data(atoms=a_contributing, atoms_orig_idx=a_contributing_orig_idx, type='positive',
+                orig_contributing = [self.Mapper.id_to_atom(idx) for idx in a_contributing_orig_idx]
+                a_set.append(data(atoms=a_contributing, orig_atoms=orig_contributing, atoms_orig_idx=a_contributing_orig_idx, type='positive',
                                   center=a.coords, fgroup='guanidine'))
         return a_set
 
@@ -1142,11 +1179,11 @@ class Ligand(Mol):
         nitrogen from imidazole; sulfur from thiolate.
         """
         a_set = []
-        data = namedtuple('metal_binding', 'atom atom_orig_idx type fgroup restype resnr reschain location')
+        data = namedtuple('metal_binding', 'atom orig_atom atom_orig_idx type fgroup restype resnr reschain location')
         for oxygen in water_oxygens:
             a_set.append(data(atom=oxygen.oxy, atom_orig_idx=oxygen.oxy_orig_idx, type='O', fgroup='water',
                               restype=whichrestype(oxygen.oxy), resnr=whichresnumber(oxygen.oxy),
-                              reschain=whichchain(oxygen.oxy), location='water'))
+                              reschain=whichchain(oxygen.oxy), location='water', orig_atom=self.Mapper.id_to_atom(oxygen.oxy_orig_idx)))
         # #@todo Refactor code
         for a in lig_atoms:
             a_orig_idx = self.Mapper.mapid(a.idx, mtype='ligand', bsid=self.bsid)
@@ -1157,11 +1194,11 @@ class Ligand(Mol):
                 if n_atoms_atomicnum.count('1') == 1 and len(n_atoms_atomicnum) == 2:  # Oxygen in alcohol (R-[O]-H)
                     a_set.append(data(atom=a, atom_orig_idx=a_orig_idx, type='O', fgroup='alcohol',
                                       restype=self.hetid, resnr=self.position, reschain=self.chain,
-                                      location='ligand'))
+                                      location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
                 if True in [n.IsAromatic() for n in n_atoms] and not a.OBAtom.IsAromatic():  # Phenolate oxygen
                     a_set.append(data(atom=a, atom_orig_idx=a_orig_idx, type='O', fgroup='phenolate',
                                       restype=self.hetid, resnr=self.position, reschain=self.chain,
-                                      location='ligand'))
+                                      location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
             if a.atomicnum == 6:  # It's a carbon atom
                 if n_atoms_atomicnum.count(8) == 2 and n_atoms_atomicnum.count(6) == 1:  # It's a carboxylate group
                     for neighbor in [n for n in n_atoms if n.GetAtomicNum() == 8]:
@@ -1170,7 +1207,7 @@ class Ligand(Mol):
                                           fgroup='carboxylate',
                                           restype=self.hetid,
                                           resnr=self.position, reschain=self.chain,
-                                          location='ligand'))
+                                          location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
             if a.atomicnum == 15:  # It's a phosphor atom
                 if n_atoms_atomicnum.count(8) >= 3:  # It's a phosphoryl
                     for neighbor in [n for n in n_atoms if n.GetAtomicNum() == 8]:
@@ -1179,28 +1216,28 @@ class Ligand(Mol):
                                           fgroup='phosphoryl',
                                           restype=self.hetid,
                                           resnr=self.position, reschain=self.chain,
-                                          location='ligand'))
+                                          location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
                 if n_atoms_atomicnum.count(8) == 2:  # It's another phosphor-containing group #@todo (correct name?)
                     for neighbor in [n for n in n_atoms if n.GetAtomicNum() == 8]:
                         neighbor_orig_idx = self.Mapper.mapid(neighbor.GetIdx(), mtype='ligand', bsid=self.bsid)
                         a_set.append(data(atom=pybel.Atom(neighbor), atom_orig_idx=neighbor_orig_idx, type='O',
                                           fgroup='phosphor.other', restype=self.hetid,
                                           resnr=self.position,
-                                          reschain=self.chain, location='ligand'))
+                                          reschain=self.chain, location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
             if a.atomicnum == 7:  # It's a nitrogen atom
                 if n_atoms_atomicnum.count(6) == 2:  # It's imidazole/pyrrole or similar
                     a_set.append(data(atom=a, atom_orig_idx=a_orig_idx, type='N', fgroup='imidazole/pyrrole',
                                       restype=self.hetid, resnr=self.position, reschain=self.chain,
-                                      location='ligand'))
+                                      location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
             if a.atomicnum == 16:  # It's a sulfur atom
                 if True in [n.IsAromatic() for n in n_atoms] and not a.OBAtom.IsAromatic():  # Thiolate
                     a_set.append(data(atom=a, atom_orig_idx=a_orig_idx, type='S', fgroup='thiolate',
                                       restype=self.hetid, resnr=self.position, reschain=self.chain,
-                                      location='ligand'))
+                                      location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
                 if set(n_atoms_atomicnum) == {26}:  # Sulfur in Iron sulfur cluster
                     a_set.append(data(atom=a, atom_orig_idx=a_orig_idx, type='S', fgroup='iron-sulfur.cluster',
                                       restype=self.hetid, resnr=self.position, reschain=self.chain,
-                                      location='ligand'))
+                                      location='ligand', orig_atom=self.Mapper.id_to_atom(a_orig_idx)))
 
         return a_set
 
@@ -1247,6 +1284,7 @@ class PDBComplex:
         pdbparser = PDBParser(pdbpath, as_string=as_string)  # Parse PDB file to find errors and get additonal data
         # #@todo Refactor and rename here
         self.Mapper.proteinmap = pdbparser.proteinmap
+        self.Mapper.reversed_proteinmap = inv_map = {v: k for k, v in self.Mapper.proteinmap.iteritems()}
         self.modres = pdbparser.modres
         self.covalent = pdbparser.covalent
         self.altconf = pdbparser.altconformations
@@ -1270,8 +1308,12 @@ class PDBComplex:
         else:
             self.sourcefiles['filename'] = os.path.basename(self.sourcefiles['pdbcomplex'])
             self.protcomplex, self.filetype = read_pdb(self.sourcefiles['pdbcomplex'], as_string=as_string)
+
+        # Update the model in the Mapper class instance
+        self.Mapper.original_structure = self.protcomplex.OBMol
         write_message('PDB structure successfully read.\n')
 
+
         # Determine (temporary) PyMOL Name from Filename
         self.pymol_name = pdbpath.split('/')[-1].split('.')[0] + '-Protein'
         # Replace characters causing problems in PyMOL
@@ -1283,19 +1325,24 @@ class PDBComplex:
                 self.pymol_name = potential_name
         write_message("Pymol Name set as: '%s'\n" % self.pymol_name, mtype='debug')
 
-        self.protcomplex.OBMol.AddPolarHydrogens()
-        for atm in self.protcomplex:
-            self.atoms[atm.idx] = atm
-
         # Extract and prepare ligands
         ligandfinder = LigandFinder(self.protcomplex, self.altconf, self.modres, self.covalent, self.Mapper)
         self.ligands = ligandfinder.ligands
         self.excluded = ligandfinder.excluded
 
+        # Add polar hydrogens
+        self.protcomplex.OBMol.AddPolarHydrogens()
+        for atm in self.protcomplex:
+            self.atoms[atm.idx] = atm
+        write_message("Assigned polar hydrogens\n", mtype='debug')
+
         if len(self.excluded) != 0:
             write_message("Excluded molecules as ligands: %s\n" % ','.join([lig for lig in self.excluded]))
 
-        self.resis = [obres for obres in pybel.ob.OBResidueIter(self.protcomplex.OBMol) if obres.GetResidueProperty(0)]
+        if config.DNARECEPTOR:
+            self.resis = [obres for obres in pybel.ob.OBResidueIter(self.protcomplex.OBMol) if obres.GetName() in config.DNA+config.RNA]
+        else:
+            self.resis = [obres for obres in pybel.ob.OBResidueIter(self.protcomplex.OBMol) if obres.GetResidueProperty(0)]
 
         num_ligs = len(self.ligands)
         if num_ligs == 1:
diff --git a/plip/modules/pymolplip.py b/plip/modules/pymolplip.py
index 166064f..b654781 100644
--- a/plip/modules/pymolplip.py
+++ b/plip/modules/pymolplip.py
@@ -1,20 +1,8 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 pymolplip.py - Visualization class for PyMOL.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
+
 from pymol import cmd
 from time import sleep
 import sys
@@ -98,6 +86,7 @@ class PyMOLVisualizer:
         if not len(hydroph.bs_ids) == 0:
             self.select_by_ids('Hydrophobic-P', hydroph.bs_ids, restrict=self.protname)
             self.select_by_ids('Hydrophobic-L', hydroph.lig_ids, restrict=self.ligname)
+
             for i in hydroph.pairs_ids:
                 cmd.select('tmp_bs', 'id %i & %s' % (i[0], self.protname))
                 cmd.select('tmp_lig', 'id %i & %s' % (i[1], self.ligname))
@@ -291,7 +280,11 @@ class PyMOLVisualizer:
 
         selections = cmd.get_names("selections")
         for selection in selections:
-            if cmd.count_atoms(selection) == 0:
+            try:
+                empty = len(cmd.get_model(selection).atom) == 0
+            except:
+                empty = True
+            if empty:
                 cmd.delete(selection)
         cmd.deselect()
         cmd.delete('tmp*')
@@ -401,6 +394,7 @@ class PyMOLVisualizer:
         cmd.set('direct', 0)
         cmd.set('ray_shadow', 0)  # Gives the molecules a flat, modern look
         cmd.set('ambient_occlusion_mode', 1)
+        cmd.set('ray_opaque_background', 0) # Transparent background
 
     def adapt_for_peptides(self):
         """Adapt visualization for peptide ligands and interchain contacts"""
@@ -412,6 +406,10 @@ class PyMOLVisualizer:
         cmd.remove('%sCartoon and chain %s' % (self.protname, self.plcomplex.chain))
         cmd.set('cartoon_side_chain_helper', 0)
 
+    def adapt_for_intra(self):
+        """Adapt visualization for intra-protein interactions"""
+
+
 
 
 
@@ -456,3 +454,6 @@ class PyMOLVisualizer:
 
         if self.ligandtype in ['PEPTIDE', 'INTRA']:
             self.adapt_for_peptides()
+
+        if self.ligandtype == 'INTRA':
+            self.adapt_for_intra()
diff --git a/plip/modules/report.py b/plip/modules/report.py
index b45b998..d622bff 100644
--- a/plip/modules/report.py
+++ b/plip/modules/report.py
@@ -1,19 +1,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 report.py - Write PLIP results to output files.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 
@@ -21,12 +8,13 @@ limitations under the License.
 import time
 from operator import itemgetter
 import sys
+import config
 
 
 # External libraries
 import lxml.etree as et
 
-__version__ = '1.3.3'
+__version__ = '1.3.4'
 
 class StructureReport:
     """Creates reports (xml or txt) for one structure/"""
@@ -48,6 +36,11 @@ class StructureReport:
         citation_information = et.SubElement(report, 'citation_information')
         citation_information.text = "Salentin,S. et al. PLIP: fully automated protein-ligand interaction profiler. " \
            "Nucl. Acids Res. (1 July 2015) 43 (W1): W443-W447. doi: 10.1093/nar/gkv315"
+        mode = et.SubElement(report, 'mode')
+        if config.DNARECEPTOR:
+            mode.text = 'dna_receptor'
+        else:
+            mode.text = 'default'
         pdbid = et.SubElement(report, 'pdbid')
         pdbid.text = self.mol.pymol_name.upper()
         filetype = et.SubElement(report, 'filetype')
@@ -74,6 +67,8 @@ class StructureReport:
         textlines.append('Nucl. Acids Res. (1 July 2015) 43 (W1): W443-W447. doi: 10.1093/nar/gkv315\n')
         if len(self.excluded) != 0:
             textlines.append('Excluded molecules as ligands: %s\n' % ','.join([lig for lig in self.excluded]))
+        if config.DNARECEPTOR:
+            textlines.append('DNA/RNA in structure was chosen as the receptor part.\n')
         return textlines
 
     def get_bindingsite_data(self):
@@ -134,11 +129,11 @@ class BindingSiteReport:
         # HYDROPHOBIC INTERACTIONS #
         ############################
 
-        self.hydrophobic_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'DIST', 'LIGCARBONIDX', 'PROTCARBONIDX', 'LIGCOO',
+        self.hydrophobic_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST', 'LIGCARBONIDX', 'PROTCARBONIDX', 'LIGCOO',
                                      'PROTCOO')
         self.hydrophobic_info = []
         for hydroph in self.complex.hydrophobic_contacts:
-            self.hydrophobic_info.append((hydroph.resnr, hydroph.restype, hydroph.reschain, '%.2f' % hydroph.distance,
+            self.hydrophobic_info.append((hydroph.resnr, hydroph.restype, hydroph.reschain, hydroph.resnr_l, hydroph.restype_l, hydroph.reschain_l, '%.2f' % hydroph.distance,
                                           hydroph.ligatom_orig_idx, hydroph.bsatom_orig_idx, hydroph.ligatom.coords,
                                           hydroph.bsatom.coords))
 
@@ -146,12 +141,12 @@ class BindingSiteReport:
         # HYDROGEN BONDS #
         ##################
 
-        self.hbond_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'SIDECHAIN', 'DIST_H-A', 'DIST_D-A', 'DON_ANGLE',
+        self.hbond_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'SIDECHAIN', 'DIST_H-A', 'DIST_D-A', 'DON_ANGLE',
                                'PROTISDON', 'DONORIDX', 'DONORTYPE', 'ACCEPTORIDX', 'ACCEPTORTYPE', 'LIGCOO', 'PROTCOO')
         self.hbond_info = []
         for hbond in self.complex.hbonds_pdon + self.complex.hbonds_ldon:
             ligatom, protatom = (hbond.a, hbond.d) if hbond.protisdon else (hbond.d, hbond.a)
-            self.hbond_info.append((hbond.resnr, hbond.restype, hbond.reschain, hbond.sidechain,
+            self.hbond_info.append((hbond.resnr, hbond.restype, hbond.reschain, hbond.resnr_l, hbond.restype_l, hbond.reschain_l, hbond.sidechain,
                                     '%.2f' % hbond.distance_ah, '%.2f' % hbond.distance_ad, '%.2f' % hbond.angle,
                                     hbond.protisdon, hbond.d_orig_idx, hbond.dtype, hbond.a_orig_idx, hbond.atype,
                                     ligatom.coords, protatom.coords))
@@ -160,14 +155,14 @@ class BindingSiteReport:
         # WATER-BRIDGES #
         #################
 
-        self.waterbridge_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'DIST_A-W', 'DIST_D-W', 'DON_ANGLE', 'WATER_ANGLE',
+        self.waterbridge_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST_A-W', 'DIST_D-W', 'DON_ANGLE', 'WATER_ANGLE',
                                      'PROTISDON', 'DONOR_IDX', 'DONORTYPE', 'ACCEPTOR_IDX', 'ACCEPTORTYPE', 'WATER_IDX',
                                      'LIGCOO', 'PROTCOO', 'WATERCOO')
         # The coordinate format is an exception here, since the interaction is not only between ligand and protein
         self.waterbridge_info = []
         for wbridge in self.complex.water_bridges:
             lig, prot = (wbridge.a, wbridge.d) if wbridge.protisdon else (wbridge.d, wbridge.a)
-            self.waterbridge_info.append((wbridge.resnr, wbridge.restype, wbridge.reschain,
+            self.waterbridge_info.append((wbridge.resnr, wbridge.restype, wbridge.reschain, wbridge.resnr_l, wbridge.restype_l, wbridge.reschain_l,
                                           '%.2f' % wbridge.distance_aw, '%.2f' % wbridge.distance_dw,
                                           '%.2f' % wbridge.d_angle, '%.2f' % wbridge.w_angle, wbridge.protisdon,
                                           wbridge.d_orig_idx, wbridge.dtype, wbridge.a_orig_idx, wbridge.atype,
@@ -177,18 +172,18 @@ class BindingSiteReport:
         # SALT BRIDGES #
         ################
 
-        self.saltbridge_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'DIST', 'PROTISPOS', 'LIG_GROUP', 'LIG_IDX_LIST',
+        self.saltbridge_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST', 'PROTISPOS', 'LIG_GROUP', 'LIG_IDX_LIST',
                                     'LIGCOO', 'PROTCOO')
         self.saltbridge_info = []
         for sb in self.complex.saltbridge_lneg + self.complex.saltbridge_pneg:
             if sb.protispos:
                 group, ids = sb.negative.fgroup, [str(x) for x in sb.negative.atoms_orig_idx]
-                self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, '%.2f' % sb.distance, sb.protispos,
+                self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, sb.resnr_l, sb.restype_l, sb.reschain_l, '%.2f' % sb.distance, sb.protispos,
                                              group.capitalize(), ",".join(ids),
                                              tuple(sb.negative.center), tuple(sb.positive.center)))
             else:
                 group, ids = sb.positive.fgroup, [str(x) for x in sb.positive.atoms_orig_idx]
-                self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, '%.2f' % sb.distance, sb.protispos,
+                self.saltbridge_info.append((sb.resnr, sb.restype, sb.reschain, sb.resnr_l, sb.restype_l, sb.reschain_l, '%.2f' % sb.distance, sb.protispos,
                                              group.capitalize(), ",".join(ids),
                                              tuple(sb.positive.center), tuple(sb.negative.center)))
 
@@ -196,12 +191,12 @@ class BindingSiteReport:
         # PI-STACKING #
         ###############
 
-        self.pistacking_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'CENTDIST', 'ANGLE', 'OFFSET', 'TYPE',
+        self.pistacking_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'CENTDIST', 'ANGLE', 'OFFSET', 'TYPE',
                                     'LIG_IDX_LIST', 'LIGCOO', 'PROTCOO')
         self.pistacking_info = []
         for stack in self.complex.pistacking:
             ids = [str(x) for x in stack.ligandring.atoms_orig_idx]
-            self.pistacking_info.append((stack.resnr, stack.restype, stack.reschain, '%.2f' % stack.distance,
+            self.pistacking_info.append((stack.resnr, stack.restype, stack.reschain, stack.resnr_l, stack.restype_l, stack.reschain_l, '%.2f' % stack.distance,
                                          '%.2f' % stack.angle, '%.2f' % stack.offset, stack.type, ",".join(ids),
                                          tuple(stack.ligandring.center), tuple(stack.proteinring.center)))
 
@@ -209,20 +204,20 @@ class BindingSiteReport:
         # PI-CATION INTERACTIONS #
         ##########################
 
-        self.pication_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'DIST', 'OFFSET', 'PROTCHARGED', 'LIG_GROUP',
+        self.pication_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'DIST', 'OFFSET', 'PROTCHARGED', 'LIG_GROUP',
                                   'LIG_IDX_LIST', 'LIGCOO', 'PROTCOO')
         self.pication_info = []
         for picat in self.complex.pication_laro + self.complex.pication_paro:
             if picat.protcharged:
                 ids = [str(x) for x in picat.ring.atoms_orig_idx]
                 group = 'Aromatic'
-                self.pication_info.append((picat.resnr, picat.restype, picat.reschain, '%.2f' % picat.distance,
+                self.pication_info.append((picat.resnr, picat.restype, picat.reschain, picat.resnr_l, picat.restype_l, picat.reschain_l, '%.2f' % picat.distance,
                                            '%.2f' % picat.offset, picat.protcharged, group, ",".join(ids),
                                            tuple(picat.ring.center), tuple(picat.charge.center)))
             else:
                 ids = [str(x) for x in picat.charge.atoms_orig_idx]
                 group = picat.charge.fgroup
-                self.pication_info.append((picat.resnr, picat.restype, picat.reschain, '%.2f' % picat.distance,
+                self.pication_info.append((picat.resnr, picat.restype, picat.reschain, picat.resnr_l, picat.restype_l, picat.reschain_l, '%.2f' % picat.distance,
                                            '%.2f' % picat.offset, picat.protcharged, group, ",".join(ids),
                                            tuple(picat.charge.center), tuple(picat.ring.center)))
 
@@ -230,11 +225,11 @@ class BindingSiteReport:
         # HALOGEN BONDS #
         #################
 
-        self.halogen_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'SIDECHAIN', 'DIST', 'DON_ANGLE', 'ACC_ANGLE',
+        self.halogen_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'SIDECHAIN', 'DIST', 'DON_ANGLE', 'ACC_ANGLE',
                                  'DON_IDX', 'DONORTYPE', 'ACC_IDX', 'ACCEPTORTYPE', 'LIGCOO', 'PROTCOO')
         self.halogen_info = []
         for halogen in self.complex.halogen_bonds:
-            self.halogen_info.append((halogen.resnr, halogen.restype, halogen.reschain, halogen.sidechain,
+            self.halogen_info.append((halogen.resnr, halogen.restype, halogen.reschain, halogen.resnr_l, halogen.restype_l, halogen.reschain_l, halogen.sidechain,
                                       '%.2f' % halogen.distance, '%.2f' % halogen.don_angle, '%.2f' % halogen.acc_angle,
                                       halogen.don_orig_idx, halogen.donortype,
                                       halogen.acc_orig_idx, halogen.acctype,
@@ -244,13 +239,13 @@ class BindingSiteReport:
         # METAL COMPLEXES #
         ###################
 
-        self.metal_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'METAL_IDX', 'METAL_TYPE', 'TARGET_IDX', 'TARGET_TYPE',
+        self.metal_features = ('RESNR', 'RESTYPE', 'RESCHAIN', 'RESNR_LIG', 'RESTYPE_LIG', 'RESCHAIN_LIG', 'METAL_IDX', 'METAL_TYPE', 'TARGET_IDX', 'TARGET_TYPE',
                                'COORDINATION', 'DIST', 'LOCATION', 'RMS', 'GEOMETRY', 'COMPLEXNUM', 'METALCOO',
                                'TARGETCOO')
         self.metal_info = []
         # Coordinate format here is non-standard since the interaction partner can be either ligand or protein
         for m in self.complex.metal_complexes:
-            self.metal_info.append((m.resnr, m.restype, m.reschain, m.metal_orig_idx, m.metal_type,
+            self.metal_info.append((m.resnr, m.restype, m.reschain, m.resnr_l, m.restype_l, m.reschain_l, m.metal_orig_idx, m.metal_type,
                                     m.target_orig_idx, m.target_type, m.coordination_num, '%.2f' % m.distance,
                                     m.location, '%.2f' % m.rms, m.geometry, str(m.complexnum), m.metal.coords,
                                     m.target.atom.coords))
diff --git a/plip/modules/supplemental.py b/plip/modules/supplemental.py
index be56ccf..a94cfc4 100644
--- a/plip/modules/supplemental.py
+++ b/plip/modules/supplemental.py
@@ -1,26 +1,14 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 supplemental.py - Supplemental functions for PLIP analysis.
-Copyright 2014-2015 Sebastian Salentin, Joachim Haupt
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 # Compatibility
 from __future__ import print_function
+from __future__ import absolute_import
 
 # PLIP Modules
-import config
+import plip.modules.config as config
 
 # Python standard library
 import re
@@ -300,9 +288,9 @@ def ring_is_planar(ring, r_atoms):
 def classify_by_name(names):
     """Classify a (composite) ligand by the HETID(s)"""
     if len(names) > 3:  # Polymer
-        if len({'U', 'A', 'C', 'G'}.intersection(set(names))) != 0:
+        if len(set(config.RNA).intersection(set(names))) != 0:
             ligtype = 'RNA'
-        elif len({'DT', 'DA', 'DC', 'DG'}.intersection(set(names))) != 0:
+        elif len(set(config.DNA).intersection(set(names))) != 0:
             ligtype = 'DNA'
         else:
             ligtype = "POLYMER"
@@ -420,25 +408,30 @@ def read(fil):
 def readmol(path, as_string=False):
     """Reads the given molecule file and returns the corresponding Pybel molecule as well as the input file type.
     In contrast to the standard Pybel implementation, the file is closed properly."""
-    supported_formats = ['pdb', 'pdbqt', 'mmcif']
+    supported_formats = ['pdb', 'mmcif']
     obc = pybel.ob.OBConversion()
 
-    if as_string:
-        filestr = path
-    else:
-        with read(path) as f:
-            filestr = str(f.read())
     for sformat in supported_formats:
         obc.SetInFormat(sformat)
+        write_message("Detected {} as format. Now trying to read file with OpenBabel...\n".format(sformat), mtype='debug')
         mol = pybel.ob.OBMol()
-        obc.ReadString(mol, filestr)
-        if not mol.Empty():
-            if sformat == 'pdbqt':
-                write_message('[EXPERIMENTAL] Input is PDBQT file. Some features (especially visualization) might not '
-                        'work as expected. Please consider using PDB format instead.\n')
-            if sformat == 'mmcif':
-                write_message('[EXPERIMENTAL] Input is mmCIF file. Most features do currently not work with this format.\n')
-            return pybel.Molecule(mol), sformat
+
+        # Read molecules with single bond information
+        if as_string:
+            read_file = pybel.readstring(format=sformat, filename=path, opt={"s": None})
+        else:
+            read_file = pybel.readfile(format=sformat, filename=path, opt={"s": None})
+        try:
+            mymol = read_file.next()
+        except StopIteration:
+            sysexit(4, 'File contains no valid molecules.\n')
+
+        write_message("Molecule successfully read.\n", mtype='debug')
+
+        # Assign multiple bonds
+        mymol.OBMol.PerceiveBondOrders()
+        return mymol, sformat
+
     sysexit(4, 'No valid file format provided.')
 
 
diff --git a/plip/modules/visualize.py b/plip/modules/visualize.py
index 60858d0..640c6d5 100644
--- a/plip/modules/visualize.py
+++ b/plip/modules/visualize.py
@@ -1,27 +1,16 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 visualize.py - Visualization of PLIP results using PyMOL.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
+# Python standard library
+from __future__ import absolute_import
 
 # Own modules
-from supplemental import initialize_pymol, start_pymol, write_message, colorlog, sysexit
-import config
-from pymolplip import PyMOLVisualizer
-from plipremote import VisualizerData
+from plip.modules.supplemental import initialize_pymol, start_pymol, write_message, colorlog, sysexit
+import plip.modules.config as config
+from plip.modules.pymolplip import PyMOLVisualizer
+from plip.modules.plipremote import VisualizerData
 
 # Python Standard Library
 import json
@@ -114,6 +103,7 @@ def visualize_in_pymol(plcomplex):
 
 
     vis.make_initial_selections()
+
     vis.show_hydrophobic()  # Hydrophobic Contacts
     vis.show_hbonds()  # Hydrogen Bonds
     vis.show_halogen()  # Halogen Bonds
@@ -125,12 +115,18 @@ def visualize_in_pymol(plcomplex):
 
     vis.refinements()
 
-
     vis.zoom_to_ligand()
 
     vis.selections_cleanup()
+
     vis.selections_group()
     vis.additional_cleanup()
+    if config.DNARECEPTOR:
+        # Rename Cartoon selection to Line selection and change repr.
+        cmd.set_name('%sCartoon' % plcomplex.pdbid, '%sLines' % plcomplex.pdbid)
+        cmd.hide('cartoon', '%sLines' % plcomplex.pdbid)
+        cmd.show('lines', '%sLines' % plcomplex.pdbid)
+
     if config.PEPTIDES != []:
         filename = "%s_PeptideChain%s" % (pdbid.upper(), plcomplex.chain)
         if config.PYMOL:
diff --git a/plip/modules/webservices.py b/plip/modules/webservices.py
index c1f283f..b790dc6 100644
--- a/plip/modules/webservices.py
+++ b/plip/modules/webservices.py
@@ -1,27 +1,15 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 webservices.py - Connect to various webservices to retrieve data
-Copyright 2014-2016 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
-# Own modules
-from supplemental import write_message, sysexit
-
-# Python standard libary
+# Python standard library
+from __future__ import absolute_import
 import urllib2
 
+# Own modules
+from plip.modules.supplemental import write_message, sysexit
+
 # External libraries
 import lxml.etree as et
 
diff --git a/plip/plipcmd b/plip/plipcmd
index 3bfd0f7..406ddc9 100755
--- a/plip/plipcmd
+++ b/plip/plipcmd
@@ -2,41 +2,20 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 plipcmd - Main script for PLIP command line execution.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 # Compatibility
 from __future__ import print_function
+from __future__ import absolute_import
 
 # Own modules
-try:
-    from plip.modules.preparation import *
-    from plip.modules.visualize import visualize_in_pymol
-    from plip.modules.plipremote import VisualizerData
-    from plip.modules.report import StructureReport,__version__
-    from plip.modules import config
-    from plip.modules.mp import parallel_fn
-    from plip.modules.webservices import check_pdb_status, fetch_pdb
-except ImportError:
-    from modules.preparation import *
-    from modules.visualize import visualize_in_pymol
-    from modules.plipremote import VisualizerData
-    from modules.report import StructureReport, __version__
-    from modules import config
-    from modules.mp import parallel_fn
-    from modules.webservices import check_pdb_status, fetch_pdb
+from plip.modules.preparation import *
+from plip.modules.visualize import visualize_in_pymol
+from plip.modules.plipremote import VisualizerData
+from plip.modules.report import StructureReport,__version__
+from plip.modules import config
+from plip.modules.mp import parallel_fn
+from plip.modules.webservices import check_pdb_status, fetch_pdb
 
 # Python standard library
 import sys
@@ -152,7 +131,7 @@ def main(inputstructs, inputpdbids):
             if os.path.getsize(inputstruct) == 0:
                 sysexit(2, 'Empty PDB file\n')  # Exit if input file is empty
             if num_structures > 1:
-                basename = inputstruct.split('.')[0].split('/')[-1]
+                basename = inputstruct.split('.')[-2].split('/')[-1]
                 config.OUTPATH = '/'.join([config.BASEPATH, basename])
             process_pdb(inputstruct, config.OUTPATH)
     else:  # Try to fetch the current PDB structure(s) directly from the RCBS server
@@ -206,6 +185,9 @@ if __name__ == '__main__':
     parser.add_argument("--nofix", dest="nofix", default=False,
                         help="Turns off fixing of PDB files.",
                         action="store_true")
+    parser.add_argument("--dnareceptor", dest="dnareceptor", default=False,
+                        help="Uses the DNA instead of the protein as a receptor for interactions.",
+                        action="store_true")
     ligandtype = parser.add_mutually_exclusive_group()  # Either peptide/inter or intra mode
     ligandtype.add_argument("--peptides", "--inter", dest="peptides", default=[],
                         help="Allows to define one or multiple chains as peptide ligands or to detect inter-chain contacts",
@@ -248,6 +230,7 @@ if __name__ == '__main__':
     config.INTRA = arguments.intra
     config.NOFIX = arguments.nofix
     config.KEEPMOD = arguments.keepmod
+    config.DNARECEPTOR = arguments.dnareceptor
     # Assign values to global thresholds
     for t in thresholds:
         tvalue = getattr(arguments, t.name)
diff --git a/plip/test/run_all_tests.sh b/plip/test/run_all_tests.sh
new file mode 100755
index 0000000..99c0fc0
--- /dev/null
+++ b/plip/test/run_all_tests.sh
@@ -0,0 +1 @@
+python -m unittest discover -s . -p 'test_*.py'
diff --git a/plip/test/test_basic_functions.py b/plip/test/test_basic_functions.py
index 79ffd51..6e3437d 100644
--- a/plip/test/test_basic_functions.py
+++ b/plip/test/test_basic_functions.py
@@ -2,19 +2,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 test_basic_functions.py - Unit Tests for basic functionality.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 # Python Standard Library
diff --git a/plip/test/test_literature_validated.py b/plip/test/test_literature_validated.py
index 31c56a7..7fe2502 100644
--- a/plip/test/test_literature_validated.py
+++ b/plip/test/test_literature_validated.py
@@ -2,19 +2,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 test_literature_validated.py - Unit Tests for literature-validated cases.
-Copyright 2014-2015 Sebastian Salentin, Melissa Adasme
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 
diff --git a/plip/test/test_metal_coordination.py b/plip/test/test_metal_coordination.py
index 8073ec5..16dd4a8 100644
--- a/plip/test/test_metal_coordination.py
+++ b/plip/test/test_metal_coordination.py
@@ -2,19 +2,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 test_metal_coordination.py - Unit Tests for Metal Coordination.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 
diff --git a/plip/test/test_remote_services.py b/plip/test/test_remote_services.py
index c8ecde8..fb61d34 100644
--- a/plip/test/test_remote_services.py
+++ b/plip/test/test_remote_services.py
@@ -2,19 +2,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 test_remote_services.py - Unit Tests for remote services.
-Copyright 2014-2016 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 
diff --git a/plip/test/test_special_cases.py b/plip/test/test_special_cases.py
index 440d68e..d2791c5 100644
--- a/plip/test/test_special_cases.py
+++ b/plip/test/test_special_cases.py
@@ -2,19 +2,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 test_special_cases.py - Unit Tests for special cases.
-Copyright 2014-2015 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 
@@ -44,5 +31,3 @@ class SpecialCasesTest(unittest.TestCase):
         """A valid PDB ID is provided, but there is no entry in PDB format from wwPDB"""
         exitcode1 = subprocess.call('../plipcmd -i 4v59 -o /tmp', shell=True)
         self.assertEqual(exitcode1, 5)  # Specific exitcode 5
-
-
diff --git a/plip/test/test_xml_parser.py b/plip/test/test_xml_parser.py
index 64bed55..53f65ac 100644
--- a/plip/test/test_xml_parser.py
+++ b/plip/test/test_xml_parser.py
@@ -2,19 +2,6 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 test_xml_parser.py - Unit Tests for XML Parser.
-Copyright 2014-2016 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 
diff --git a/setup.py b/setup.py
index 6d068b6..b5580cb 100644
--- a/setup.py
+++ b/setup.py
@@ -1,38 +1,25 @@
 """
 Protein-Ligand Interaction Profiler - Analyze and visualize protein-ligand interactions in PDB files.
 setup.py - Setup configuration file for pip, etc.
-Copyright 2014 Sebastian Salentin
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
 """
 
 from setuptools import setup
 
 setup(name='plip',
-      version='1.3.3',
+      version='1.3.5',
       description='PLIP - Fully automated protein-ligand interaction profiler',
       classifiers=[
           'Development Status :: 5 - Production/Stable',
           'Intended Audience :: Science/Research',
           'Natural Language :: English',
-          'License :: OSI Approved :: Apache Software License',
+          'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
           'Programming Language :: Python :: 2.7',
           'Topic :: Scientific/Engineering :: Bio-Informatics'
       ],
       url='https://github.com/ssalentin/plip',
       author='Sebastian Salentin',
       author_email='sebastian.salentin at biotec.tu-dresden.de',
-      license='Apache',
+      license='GPLv2',
       packages=['plip', 'plip/modules'],
       scripts=['plip/plipcmd'],
       install_requires=[

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/plip.git



More information about the debian-med-commit mailing list