Merge commit 'a4c93019cfca1e816230cd5417af6d9596aabd9e'
diff --git a/features/org.eclipse.objectteams.otdt.feature/category.xml b/features/org.eclipse.objectteams.otdt.feature/category.xml
index 9828f16..9353da3 100644
--- a/features/org.eclipse.objectteams.otdt.feature/category.xml
+++ b/features/org.eclipse.objectteams.otdt.feature/category.xml
@@ -53,4 +53,7 @@
    <iu id="org.eclipse.objectteams.otequinox.feature.group" range="[2.3.0,2.4.0)">
       <category name="org.eclipse.objectteams.otdt_2.3"/>
    </iu>
+   <iu id="org.eclipse.objectteams.otequinox.turbo.feature.group" range="[2.3.0,2.4.0)">
+      <category name="org.eclipse.objectteams.otdt_2.3"/>
+   </iu>
 </site>
diff --git a/features/org.eclipse.objectteams.otequinox.turbo.feature/.project b/features/org.eclipse.objectteams.otequinox.turbo.feature/.project
new file mode 100644
index 0000000..31a1003
--- /dev/null
+++ b/features/org.eclipse.objectteams.otequinox.turbo.feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.objectteams.otequinox.turbo.feature</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.pde.FeatureBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.FeatureNature</nature>
+	</natures>
+</projectDescription>
diff --git a/features/org.eclipse.objectteams.otequinox.turbo.feature/build.properties b/features/org.eclipse.objectteams.otequinox.turbo.feature/build.properties
new file mode 100644
index 0000000..94bb883
--- /dev/null
+++ b/features/org.eclipse.objectteams.otequinox.turbo.feature/build.properties
@@ -0,0 +1,4 @@
+bin.includes = feature.xml,\
+               feature.properties,\
+               license.html,\
+               epl-v10.html
diff --git a/features/org.eclipse.objectteams.otequinox.turbo.feature/epl-v10.html b/features/org.eclipse.objectteams.otequinox.turbo.feature/epl-v10.html
new file mode 100644
index 0000000..fd39122
--- /dev/null
+++ b/features/org.eclipse.objectteams.otequinox.turbo.feature/epl-v10.html
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Public License - Version 1.0</title>
+<style type="text/css">
+  body {
+    size: 8.5in 11.0in;
+    margin: 0.25in 0.5in 0.25in 0.5in;
+    tab-interval: 0.5in;
+    }
+  p {  	
+    margin-left: auto;
+    margin-top:  0.5em;
+    margin-bottom: 0.5em;
+    }
+  p.list {
+  	margin-left: 0.5in;
+    margin-top:  0.05em;
+    margin-bottom: 0.05em;
+    }
+  </style>
+
+</head>
+
+<body lang="EN-US">
+
+<h2>Eclipse Public License - v 1.0</h2>
+
+<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
+AGREEMENT.</p>
+
+<p><b>1. DEFINITIONS</b></p>
+
+<p>&quot;Contribution&quot; means:</p>
+
+<p class="list">a) in the case of the initial Contributor, the initial
+code and documentation distributed under this Agreement, and</p>
+<p class="list">b) in the case of each subsequent Contributor:</p>
+<p class="list">i) changes to the Program, and</p>
+<p class="list">ii) additions to the Program;</p>
+<p class="list">where such changes and/or additions to the Program
+originate from and are distributed by that particular Contributor. A
+Contribution 'originates' from a Contributor if it was added to the
+Program by such Contributor itself or anyone acting on such
+Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii)
+are not derivative works of the Program.</p>
+
+<p>&quot;Contributor&quot; means any person or entity that distributes
+the Program.</p>
+
+<p>&quot;Licensed Patents&quot; mean patent claims licensable by a
+Contributor which are necessarily infringed by the use or sale of its
+Contribution alone or when combined with the Program.</p>
+
+<p>&quot;Program&quot; means the Contributions distributed in accordance
+with this Agreement.</p>
+
+<p>&quot;Recipient&quot; means anyone who receives the Program under
+this Agreement, including all Contributors.</p>
+
+<p><b>2. GRANT OF RIGHTS</b></p>
+
+<p class="list">a) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works
+of, publicly display, publicly perform, distribute and sublicense the
+Contribution of such Contributor, if any, and such derivative works, in
+source code and object code form.</p>
+
+<p class="list">b) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell,
+offer to sell, import and otherwise transfer the Contribution of such
+Contributor, if any, in source code and object code form. This patent
+license shall apply to the combination of the Contribution and the
+Program if, at the time the Contribution is added by the Contributor,
+such addition of the Contribution causes such combination to be covered
+by the Licensed Patents. The patent license shall not apply to any other
+combinations which include the Contribution. No hardware per se is
+licensed hereunder.</p>
+
+<p class="list">c) Recipient understands that although each Contributor
+grants the licenses to its Contributions set forth herein, no assurances
+are provided by any Contributor that the Program does not infringe the
+patent or other intellectual property rights of any other entity. Each
+Contributor disclaims any liability to Recipient for claims brought by
+any other entity based on infringement of intellectual property rights
+or otherwise. As a condition to exercising the rights and licenses
+granted hereunder, each Recipient hereby assumes sole responsibility to
+secure any other intellectual property rights needed, if any. For
+example, if a third party patent license is required to allow Recipient
+to distribute the Program, it is Recipient's responsibility to acquire
+that license before distributing the Program.</p>
+
+<p class="list">d) Each Contributor represents that to its knowledge it
+has sufficient copyright rights in its Contribution, if any, to grant
+the copyright license set forth in this Agreement.</p>
+
+<p><b>3. REQUIREMENTS</b></p>
+
+<p>A Contributor may choose to distribute the Program in object code
+form under its own license agreement, provided that:</p>
+
+<p class="list">a) it complies with the terms and conditions of this
+Agreement; and</p>
+
+<p class="list">b) its license agreement:</p>
+
+<p class="list">i) effectively disclaims on behalf of all Contributors
+all warranties and conditions, express and implied, including warranties
+or conditions of title and non-infringement, and implied warranties or
+conditions of merchantability and fitness for a particular purpose;</p>
+
+<p class="list">ii) effectively excludes on behalf of all Contributors
+all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;</p>
+
+<p class="list">iii) states that any provisions which differ from this
+Agreement are offered by that Contributor alone and not by any other
+party; and</p>
+
+<p class="list">iv) states that source code for the Program is available
+from such Contributor, and informs licensees how to obtain it in a
+reasonable manner on or through a medium customarily used for software
+exchange.</p>
+
+<p>When the Program is made available in source code form:</p>
+
+<p class="list">a) it must be made available under this Agreement; and</p>
+
+<p class="list">b) a copy of this Agreement must be included with each
+copy of the Program.</p>
+
+<p>Contributors may not remove or alter any copyright notices contained
+within the Program.</p>
+
+<p>Each Contributor must identify itself as the originator of its
+Contribution, if any, in a manner that reasonably allows subsequent
+Recipients to identify the originator of the Contribution.</p>
+
+<p><b>4. COMMERCIAL DISTRIBUTION</b></p>
+
+<p>Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use of
+the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create
+potential liability for other Contributors. Therefore, if a Contributor
+includes the Program in a commercial product offering, such Contributor
+(&quot;Commercial Contributor&quot;) hereby agrees to defend and
+indemnify every other Contributor (&quot;Indemnified Contributor&quot;)
+against any losses, damages and costs (collectively &quot;Losses&quot;)
+arising from claims, lawsuits and other legal actions brought by a third
+party against the Indemnified Contributor to the extent caused by the
+acts or omissions of such Commercial Contributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In
+order to qualify, an Indemnified Contributor must: a) promptly notify
+the Commercial Contributor in writing of such claim, and b) allow the
+Commercial Contributor to control, and cooperate with the Commercial
+Contributor in, the defense and any related settlement negotiations. The
+Indemnified Contributor may participate in any such claim at its own
+expense.</p>
+
+<p>For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those
+performance claims and warranties, and if a court requires any other
+Contributor to pay any damages as a result, the Commercial Contributor
+must pay those damages.</p>
+
+<p><b>5. NO WARRANTY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN &quot;AS IS&quot; 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. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to
+the risks and costs of program errors, compliance with applicable laws,
+damage to or loss of data, programs or equipment, and unavailability or
+interruption of operations.</p>
+
+<p><b>6. DISCLAIMER OF LIABILITY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
+NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>
+
+<p><b>7. GENERAL</b></p>
+
+<p>If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further action
+by the parties hereto, such provision shall be reformed to the minimum
+extent necessary to make such provision valid and enforceable.</p>
+
+<p>If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other
+software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the
+date such litigation is filed.</p>
+
+<p>All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of time
+after becoming aware of such noncompliance. If all Recipient's rights
+under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive.</p>
+
+<p>Everyone is permitted to copy and distribute copies of this
+Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The
+Agreement Steward reserves the right to publish new versions (including
+revisions) of this Agreement from time to time. No one other than the
+Agreement Steward has the right to modify this Agreement. The Eclipse
+Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a
+suitable separate entity. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version
+of the Agreement is published, Contributor may elect to distribute the
+Program (including its Contributions) under the new version. Except as
+expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+rights or licenses to the intellectual property of any Contributor under
+this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this
+Agreement are reserved.</p>
+
+<p>This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No party
+to this Agreement will bring a legal action under this Agreement more
+than one year after the cause of action arose. Each party waives its
+rights to a jury trial in any resulting litigation.</p>
+
+</body>
+
+</html>
diff --git a/features/org.eclipse.objectteams.otequinox.turbo.feature/feature.properties b/features/org.eclipse.objectteams.otequinox.turbo.feature/feature.properties
new file mode 100644
index 0000000..390b1c0
--- /dev/null
+++ b/features/org.eclipse.objectteams.otequinox.turbo.feature/feature.properties
@@ -0,0 +1,149 @@
+###############################################################################
+# Copyright (c) 2014 GK Software AG.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+# 
+# Contributors:
+#    Stephan Herrmann - initial API and implementation
+###############################################################################
+# feature.properties
+# contains externalized strings for feature.xml
+# "%foo" in feature.xml corresponds to the key "foo" in this file
+# java.io.Properties file (ISO 8859-1 with "\" escapes)
+# This file should be translated.
+
+featureName=Object Teams Equinox Integration - Turbo Add-On
+providerName=Eclipse.org - Object Teams
+
+# "licenseURL" property - URL of the "Feature License"
+# do not translate value - just change to point to a locale-specific HTML page
+licenseURL=license.html
+
+# "license" property - text of the "Feature Update License"
+# should be plain text version of license agreement pointed to be "licenseURL"
+license=\
+Eclipse Foundation Software User Agreement\n\
+April 9, 2014\n\
+\n\
+Usage Of Content\n\
+\n\
+THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR\n\
+OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT").\n\
+USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS\n\
+AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR\n\
+NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU\n\
+AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT\n\
+AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS\n\
+OR NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE\n\
+TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS\n\
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n\
+BELOW, THEN YOU MAY NOT USE THE CONTENT.\n\
+\n\
+Applicable Licenses\n\
+\n\
+Unless otherwise indicated, all Content made available by the\n\
+Eclipse Foundation is provided to you under the terms and conditions of\n\
+the Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is\n\
+provided with this Content and is also available at http://www.eclipse.org/legal/epl-v10.html.\n\
+For purposes of the EPL, "Program" will mean the Content.\n\
+\n\
+Content includes, but is not limited to, source code, object code,\n\
+documentation and other files maintained in the Eclipse Foundation source code\n\
+repository ("Repository") in software modules ("Modules") and made available\n\
+as downloadable archives ("Downloads").\n\
+\n\
+\t- Content may be structured and packaged into modules to facilitate delivering,\n\
+\t  extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"),\n\
+\t  plug-in fragments ("Fragments"), and features ("Features").\n\
+\t- Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java(TM) ARchive)\n\
+\t  in a directory named "plugins".\n\
+\t- A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.\n\
+\t  Each Feature may be packaged as a sub-directory in a directory named "features".\n\
+\t  Within a Feature, files named "feature.xml" may contain a list of the names and version\n\
+\t  numbers of the Plug-ins and/or Fragments associated with that Feature.\n\
+\t- Features may also include other Features ("Included Features"). Within a Feature, files\n\
+\t  named "feature.xml" may contain a list of the names and version numbers of Included Features.\n\
+\n\
+The terms and conditions governing Plug-ins and Fragments should be\n\
+contained in files named "about.html" ("Abouts"). The terms and\n\
+conditions governing Features and Included Features should be contained\n\
+in files named "license.html" ("Feature Licenses"). Abouts and Feature\n\
+Licenses may be located in any directory of a Download or Module\n\
+including, but not limited to the following locations:\n\
+\n\
+\t- The top-level (root) directory\n\
+\t- Plug-in and Fragment directories\n\
+\t- Inside Plug-ins and Fragments packaged as JARs\n\
+\t- Sub-directories of the directory named "src" of certain Plug-ins\n\
+\t- Feature directories\n\
+\n\
+Note: if a Feature made available by the Eclipse Foundation is installed using the\n\
+Provisioning Technology (as defined below), you must agree to a license ("Feature \n\
+Update License") during the installation process. If the Feature contains\n\
+Included Features, the Feature Update License should either provide you\n\
+with the terms and conditions governing the Included Features or inform\n\
+you where you can locate them. Feature Update Licenses may be found in\n\
+the "license" property of files named "feature.properties" found within a Feature.\n\
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the\n\
+terms and conditions (or references to such terms and conditions) that\n\
+govern your use of the associated Content in that directory.\n\
+\n\
+THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER\n\
+TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.\n\
+SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):\n\
+\n\
+\t- Eclipse Distribution License Version 1.0 (available at http://www.eclipse.org/licenses/edl-v1.0.html)\n\
+\t- Common Public License Version 1.0 (available at http://www.eclipse.org/legal/cpl-v10.html)\n\
+\t- Apache Software License 1.1 (available at http://www.apache.org/licenses/LICENSE)\n\
+\t- Apache Software License 2.0 (available at http://www.apache.org/licenses/LICENSE-2.0)\n\
+\t- Mozilla Public License Version 1.1 (available at http://www.mozilla.org/MPL/MPL-1.1.html)\n\
+\n\
+IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR\n\
+TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License\n\
+is provided, please contact the Eclipse Foundation to determine what terms and conditions\n\
+govern that particular Content.\n\
+\n\
+\n\Use of Provisioning Technology\n\
+\n\
+The Eclipse Foundation makes available provisioning software, examples of which include,\n\
+but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for\n\
+the purpose of allowing users to install software, documentation, information and/or\n\
+other materials (collectively "Installable Software"). This capability is provided with\n\
+the intent of allowing such users to install, extend and update Eclipse-based products.\n\
+Information about packaging Installable Software is available at\n\
+http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").\n\
+\n\
+You may use Provisioning Technology to allow other parties to install Installable Software.\n\
+You shall be responsible for enabling the applicable license agreements relating to the\n\
+Installable Software to be presented to, and accepted by, the users of the Provisioning Technology\n\
+in accordance with the Specification. By using Provisioning Technology in such a manner and\n\
+making it available in accordance with the Specification, you further acknowledge your\n\
+agreement to, and the acquisition of all necessary rights to permit the following:\n\
+\n\
+\t1. A series of actions may occur ("Provisioning Process") in which a user may execute\n\
+\t   the Provisioning Technology on a machine ("Target Machine") with the intent of installing,\n\
+\t   extending or updating the functionality of an Eclipse-based product.\n\
+\t2. During the Provisioning Process, the Provisioning Technology may cause third party\n\
+\t   Installable Software or a portion thereof to be accessed and copied to the Target Machine.\n\
+\t3. Pursuant to the Specification, you will provide to the user the terms and conditions that\n\
+\t   govern the use of the Installable Software ("Installable Software Agreement") and such\n\
+\t   Installable Software Agreement shall be accessed from the Target Machine in accordance\n\
+\t   with the Specification. Such Installable Software Agreement must inform the user of the\n\
+\t   terms and conditions that govern the Installable Software and must solicit acceptance by\n\
+\t   the end user in the manner prescribed in such Installable Software Agreement. Upon such\n\
+\t   indication of agreement by the user, the provisioning Technology will complete installation\n\
+\t   of the Installable Software.\n\
+\n\
+Cryptography\n\
+\n\
+Content may contain encryption software. The country in which you are\n\
+currently may have restrictions on the import, possession, and use,\n\
+and/or re-export to another country, of encryption software. BEFORE\n\
+using any encryption software, please check the country's laws,\n\
+regulations and policies concerning the import, possession, or use, and\n\
+re-export of encryption software, to see if this is permitted.\n\
+\n\
+Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.\n
+########### end of license property ##########################################
\ No newline at end of file
diff --git a/features/org.eclipse.objectteams.otequinox.turbo.feature/feature.xml b/features/org.eclipse.objectteams.otequinox.turbo.feature/feature.xml
new file mode 100644
index 0000000..d66ba92
--- /dev/null
+++ b/features/org.eclipse.objectteams.otequinox.turbo.feature/feature.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+      id="org.eclipse.objectteams.otequinox.turbo"
+      label="%featureName"
+      version="2.3.1.qualifier"
+      provider-name="%providerName"
+      colocation-affinity="org.eclipse.rcp">
+
+   <description url="http://www.eclipse.org/objectteams">
+      This feature enhances OT/Equinox to support "forced exports".
+   </description>
+
+   <copyright>
+      Copyright (c) 2014 GK Software AG.
+Author: Stephan Herrmann.
+   </copyright>
+
+   <license url="%licenseURL">
+   		%license
+   </license>
+
+   <requires>
+      <import feature="org.eclipse.objectteams.otequinox" version="2.3.1.qualifier"/>
+   </requires>
+
+   <plugin
+         id="org.eclipse.objectteams.otequinox.turbo"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         fragment="true"
+         unpack="false"/>
+
+</feature>
diff --git a/features/org.eclipse.objectteams.otequinox.turbo.feature/license.html b/features/org.eclipse.objectteams.otequinox.turbo.feature/license.html
new file mode 100644
index 0000000..c3d34c3
--- /dev/null
+++ b/features/org.eclipse.objectteams.otequinox.turbo.feature/license.html
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Foundation Software User Agreement</title>
+</head>
+
+<body lang="EN-US">
+<h2>Eclipse Foundation Software User Agreement</h2>
+<p>April 9, 2014</p>
+
+<h3>Usage Of Content</h3>
+
+<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS
+   (COLLECTIVELY &quot;CONTENT&quot;).  USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND
+   CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW.  BY USING THE CONTENT, YOU AGREE THAT YOUR USE
+   OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR
+   NOTICES INDICATED OR REFERENCED BELOW.  IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND
+   CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.</p>
+
+<h3>Applicable Licenses</h3>
+
+<p>Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 1.0
+   (&quot;EPL&quot;).  A copy of the EPL is provided with this Content and is also available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+   For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code
+   repository (&quot;Repository&quot;) in software modules (&quot;Modules&quot;) and made available as downloadable archives (&quot;Downloads&quot;).</p>
+
+<ul>
+       <li>Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content.  Typical modules may include plug-ins (&quot;Plug-ins&quot;), plug-in fragments (&quot;Fragments&quot;), and features (&quot;Features&quot;).</li>
+       <li>Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java&trade; ARchive) in a directory named &quot;plugins&quot;.</li>
+       <li>A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material.  Each Feature may be packaged as a sub-directory in a directory named &quot;features&quot;.  Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of the Plug-ins
+      and/or Fragments associated with that Feature.</li>
+       <li>Features may also include other Features (&quot;Included Features&quot;). Within a Feature, files named &quot;feature.xml&quot; may contain a list of the names and version numbers of Included Features.</li>
+</ul>
+
+<p>The terms and conditions governing Plug-ins and Fragments should be contained in files named &quot;about.html&quot; (&quot;Abouts&quot;). The terms and conditions governing Features and
+Included Features should be contained in files named &quot;license.html&quot; (&quot;Feature Licenses&quot;).  Abouts and Feature Licenses may be located in any directory of a Download or Module
+including, but not limited to the following locations:</p>
+
+<ul>
+       <li>The top-level (root) directory</li>
+       <li>Plug-in and Fragment directories</li>
+       <li>Inside Plug-ins and Fragments packaged as JARs</li>
+       <li>Sub-directories of the directory named &quot;src&quot; of certain Plug-ins</li>
+       <li>Feature directories</li>
+</ul>
+
+<p>Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license (&quot;Feature Update License&quot;) during the
+installation process.  If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or
+inform you where you can locate them.  Feature Update Licenses may be found in the &quot;license&quot; property of files named &quot;feature.properties&quot; found within a Feature.
+Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in
+that directory.</p>
+
+<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS.  SOME OF THESE
+OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):</p>
+
+<ul>
+       <li>Eclipse Distribution License Version 1.0 (available at <a href="http://www.eclipse.org/licenses/edl-v10.html">http://www.eclipse.org/licenses/edl-v1.0.html</a>)</li>
+       <li>Common Public License Version 1.0 (available at <a href="http://www.eclipse.org/legal/cpl-v10.html">http://www.eclipse.org/legal/cpl-v10.html</a>)</li>
+       <li>Apache Software License 1.1 (available at <a href="http://www.apache.org/licenses/LICENSE">http://www.apache.org/licenses/LICENSE</a>)</li>
+       <li>Apache Software License 2.0 (available at <a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a>)</li>
+       <li>Mozilla Public License Version 1.1 (available at <a href="http://www.mozilla.org/MPL/MPL-1.1.html">http://www.mozilla.org/MPL/MPL-1.1.html</a>)</li>
+</ul>
+
+<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT.  If no About, Feature License, or Feature Update License is provided, please
+contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.</p>
+
+
+<h3>Use of Provisioning Technology</h3>
+
+<p>The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse
+   Update Manager (&quot;Provisioning Technology&quot;) for the purpose of allowing users to install software, documentation, information and/or
+   other materials (collectively &quot;Installable Software&quot;). This capability is provided with the intent of allowing such users to
+   install, extend and update Eclipse-based products. Information about packaging Installable Software is available at <a
+       href="http://eclipse.org/equinox/p2/repository_packaging.html">http://eclipse.org/equinox/p2/repository_packaging.html</a>
+   (&quot;Specification&quot;).</p>
+
+<p>You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the
+   applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology
+   in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the
+   Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:</p>
+
+<ol>
+       <li>A series of actions may occur (&quot;Provisioning Process&quot;) in which a user may execute the Provisioning Technology
+       on a machine (&quot;Target Machine&quot;) with the intent of installing, extending or updating the functionality of an Eclipse-based
+       product.</li>
+       <li>During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be
+       accessed and copied to the Target Machine.</li>
+       <li>Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable
+       Software (&quot;Installable Software Agreement&quot;) and such Installable Software Agreement shall be accessed from the Target
+       Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern
+       the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such
+       indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.</li>
+</ol>
+
+<h3>Cryptography</h3>
+
+<p>Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to
+   another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import,
+   possession, or use, and re-export of encryption software, to see if this is permitted.</p>
+
+<p><small>Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.</small></p>
+</body>
+</html>
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
index a571f00..b0ede4a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -523,9 +523,12 @@
     receiverType = receiverType.leafComponentType();
 
     // strip off RoleTypeBinding for determining visibility
-    ReferenceBinding receiverClass = ((ReferenceBinding)receiverType).getRealClass();
-    receiverType = ((ReferenceBinding)receiverType).getRealType();
-
+    ReferenceBinding receiverClass = null;
+    if (receiverType.isRole()) {
+    	receiverClass = ((ReferenceBinding)receiverType).getRealClass();
+    	receiverType = ((ReferenceBinding)receiverType).getRealType();
+    }
+	
     // short-cut for generated methods (here: callin wrappers)
 	if (scope.methodScope() != null && scope.methodScope().isCallinWrapper())
 		if (   !isPrivate()
@@ -535,11 +538,11 @@
 			return true;
 		}
 // SH}
-//{ObjectTeams: use receiverClass:
+//{ObjectTeams: use receiverClass, if available
 /* orig:
 	if (TypeBinding.equalsEquals(invocationType, this.declaringClass) && TypeBinding.equalsEquals(invocationType, receiverType)) return true;
   :giro */
-	if (TypeBinding.equalsEquals(invocationType, this.declaringClass) && TypeBinding.equalsEquals(invocationType, receiverClass)) return true;
+	if (TypeBinding.equalsEquals(invocationType, this.declaringClass) && TypeBinding.equalsEquals(invocationType, receiverClass != null ? receiverClass : receiverType)) return true;
 // SH}
 
 	if (invocationType == null) // static import call
@@ -564,7 +567,8 @@
 /* orig:
 		TypeBinding receiverErasure = receiverType.erasure();
   :giro*/
-		TypeBinding receiverErasure = receiverClass.erasure();
+		TypeBinding receiverErasure = receiverClass != null ? receiverClass.erasure() 
+									: receiverType.erasure();
 // SH}
 		ReferenceBinding declaringErasure = (ReferenceBinding) this.declaringClass.erasure();
 		int depth = 0;
@@ -645,7 +649,8 @@
 /* orig:
 	ReferenceBinding currentType = (ReferenceBinding) (receiverType);
   :giro */
-	ReferenceBinding currentType = receiverClass;
+	ReferenceBinding currentType = receiverClass != null ? receiverClass
+									: (ReferenceBinding) receiverType;
 // SH}
 	do {
 		if (currentType.isCapture()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=285002
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/.classpath b/plugins/org.eclipse.objectteams.otequinox.turbo/.classpath
new file mode 100644
index 0000000..098194c
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/.project b/plugins/org.eclipse.objectteams.otequinox.turbo/.project
new file mode 100644
index 0000000..6a04c29
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.objectteams.otequinox.turbo</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.objectteams.otequinox.turbo/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..c2a6c9e
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,96 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.7
+org.eclipse.objectteams.otdt.compiler.option.pure_java=enabled
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otequinox.turbo/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b36a5e4
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: OT/Equinox Turbo
+Bundle-SymbolicName: org.eclipse.objectteams.otequinox.turbo
+Bundle-Version: 2.3.1.qualifier
+Bundle-Vendor: Eclipse.org - Object Teams
+Fragment-Host: org.eclipse.osgi;bundle-version="[3.10.1,4.0.0)"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
+Export-Package: org.eclipse.objectteams.otequinox.turbo
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/build.properties b/plugins/org.eclipse.objectteams.otequinox.turbo/build.properties
new file mode 100644
index 0000000..40a1314
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               hookconfigurators.properties
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/hookconfigurators.properties b/plugins/org.eclipse.objectteams.otequinox.turbo/hookconfigurators.properties
new file mode 100644
index 0000000..20cc368
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/hookconfigurators.properties
@@ -0,0 +1 @@
+hook.configurators=org.eclipse.objectteams.otequinox.turbo.OTStorageHook
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/AspectPermission.java b/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/AspectPermission.java
new file mode 100644
index 0000000..cab247b
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/AspectPermission.java
@@ -0,0 +1,28 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2009, 2014 Technical University Berlin, Germany.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * Technical University Berlin - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otequinox.turbo;
+
+/**
+ * Copy of corresponding type in org.eclipse.objectteams.otequinox (inaccessible to this fragment).
+ */
+public enum AspectPermission {
+	/** Not influencing negotiation between other parties. */
+	UNDEFINED,
+	/** A permission is granted unless someone else denies it. */
+	GRANT, 
+	/** A permission is explicitly denied. Cannot be overridden. */
+	DENY;
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/ForcedExportsRegistry.java b/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/ForcedExportsRegistry.java
new file mode 100644
index 0000000..eb67a16
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/ForcedExportsRegistry.java
@@ -0,0 +1,309 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2014 GK Software AG
+ *  
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * 	Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otequinox.turbo;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.osgi.framework.log.FrameworkLog;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
+
+/**
+ * Reads forced exports from various locations (granted/denied).
+ * 
+ * All members are static to facilitate reflexive access from org.eclipse.objectteams.otequinox.
+ */
+public class ForcedExportsRegistry {
+	// property names:
+	private static final String FORCED_EXPORTS_DENIED  = "otequinox.forced.exports.denied"; // //$NON-NLS-1$
+	private static final String FORCED_EXPORTS_GRANTED = "otequinox.forced.exports.granted"; // //$NON-NLS-1$
+	
+	// terminal tokens:
+	private static final String XFRIENDS = "x-friends:="; //$NON-NLS-1$
+
+	private static HashMap<String, String> grantedForcedExports = null;
+	private static HashMap<String, String> deniedForcedExports = null;
+
+	static FrameworkLog fwLog;
+
+	public static void install(FrameworkLog log) {
+		fwLog = log;
+		readForcedExports();
+	}
+
+	static void logError(String message, Throwable e) {
+		fwLog.log(new FrameworkLogEntry(ForcedExportsRegistry.class.getName(),
+									    message,
+									    FrameworkLogEntry.ERROR,
+									    e, null));
+	}
+
+	static void logError(String message) {
+		fwLog.log(new FrameworkLogEntry(ForcedExportsRegistry.class.getName(),
+									    message,
+									    FrameworkLogEntry.ERROR,
+									    null, null));
+	}
+
+	private static void readForcedExports() {
+		// read forced exports from config.ini (system properties), or file(s)
+		deniedForcedExports= new HashMap<String, String>();
+		grantedForcedExports= new HashMap<String, String>();
+		readForcedExportsFromProperty(FORCED_EXPORTS_DENIED, AspectPermission.DENY);
+		readForcedExportsFromProperty(FORCED_EXPORTS_GRANTED, AspectPermission.GRANT);
+	}
+
+	private static void readForcedExportsFromProperty(String propKey, AspectPermission perm) {
+		String value= System.getProperty(propKey);
+		if (value != null) {
+			if (value.length() > 0 && value.charAt(0) == '@') {
+				// follows: comma-separated list for filenames to read from:
+				int pos = 1;
+				while (pos < value.length()) {
+					int comma = value.indexOf(',', pos);
+					String fileName;
+					if (comma > -1) {
+						fileName = value.substring(pos, comma);
+						pos = comma+1;
+					} else {
+						fileName = value.substring(pos);
+						pos = value.length();
+					}
+					parseForcedExportsFile(new File(fileName), perm);
+				}
+			} else {
+				parseForcedExports(value, perm);
+			}
+		}
+	}
+	/**
+	 * API:
+	 * Adds the definitions from a given file to the set of granted forced exports.
+	 * @param file file to read from
+	 * @param perm either ALLOW or DENY (via their ordinal()),
+	 * 	 determines how the found forced export decls are interpreted.
+	 */
+	public static void parseForcedExportsFile(File file, int perm) {
+		parseForcedExportsFile(file, AspectPermission.values()[perm]);
+	}
+	private static synchronized void parseForcedExportsFile(File file, AspectPermission perm) {
+		StringBuffer newVal = new StringBuffer();
+		try {
+			// read content of one file:
+			FileInputStream fis = new FileInputStream(file);
+			try (BufferedReader br = new BufferedReader(new InputStreamReader(fis, "UTF8"))) { //$NON-NLS-1$
+				String line;
+				boolean afterClosingBrace = false;
+				while ((line = br.readLine()) != null) {
+					line = line.trim();
+					if (line.length() > 0) {
+						if (line.charAt(0) == '#') continue;
+						// may need to replace linebreak after ']' with ',' - to match one-line syntax in config.ini
+						char lastReadChar = line.charAt(line.length()-1);
+						if (afterClosingBrace && lastReadChar != ',')
+							newVal.append(',');
+						afterClosingBrace = lastReadChar == ']';
+							
+						newVal.append(line);
+					}
+				}
+				if (newVal.length() > 0)
+					parseForcedExports(newVal.toString(), perm);
+			}
+		} catch (IOException e) {
+			fwLog.log(new FrameworkLogEntry(OTStorageHook.class.getName(),
+						    "failed to read forcedExports file "+file.getName(), //$NON-NLS-1$
+						    FrameworkLogEntry.ERROR, e, null));
+		}							
+	}
+	/* Adds the given definitions to the set of granted forced exports. */
+	private static void parseForcedExports(String value, AspectPermission perm) {
+		HashMap<String, String> map = getForcedExportsMap(perm);
+		if (map == null) return; // DONT_CARE
+		int pos = 0;
+		String[] values = new String[2]; // { BaseBundleID , PackageExports }
+		while (true) {
+			pos = getForcedExportForOneBase(value, pos, values);
+			String plugin= values[0];
+			String pack= values[1];
+			if (map.containsKey(plugin)) {
+				String oldPack = map.get(plugin);
+				pack = oldPack+','+pack;  // append to existing definition
+			}
+			map.put(plugin, pack);
+			if (pos >= value.length())
+				break; // eot: done without errors
+			if (value.charAt(pos) != ',')
+				throwSyntaxError(value, pos, "missing ','"); //$NON-NLS-1$
+			pos++; // skip the ','
+		}
+	}
+	/**
+	 * fetch one chunk of forced exports specification from `spec`:
+	 * <ul>
+	 * <li>my.base.plugin[<em>specification-of-force-exported-packages</em>]<em>tail</em></li>
+	 * </ul>
+	 * is split into:
+	 * <ul>
+	 * <li>my.base.plugin</li>
+	 * <li><em>specification-of-force-exported-packages</em></li>
+	 * </ul>
+	 * and return value points to <em>tail</em>
+	 * @param spec where to read from
+	 * @param start where to start reading (within spec)
+	 * @param value store result chunks in this array: [0] = base plugin, [1] = packages specification
+	 * @return position after what has been interpreted so far
+	 */
+	private static int getForcedExportForOneBase(String spec, int start, String[] values) {
+		int open = spec.indexOf('[', start);
+		if (open == -1)
+			throwSyntaxError(spec, start, "missing '['"); //$NON-NLS-1$
+		int close = spec.indexOf(']', start);
+		if (close == -1)
+			throwSyntaxError(spec, open, "missing ']'"); //$NON-NLS-1$
+		values[0] = spec.substring(start, open);
+		values[1] = spec.substring(open+1, close);
+		return close+1;
+	}
+
+	private static void throwSyntaxError(String spec, int pos, String string) {
+		throw new RuntimeException("Illegal syntax in 'forcedExports' directive at position "+pos+" (not counting whitespace): "+string+"\n value is:\n"+spec); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$		
+	}
+
+	private static HashMap<String, String> getForcedExportsMap(AspectPermission perm) {
+		switch (perm) {
+			case GRANT:     return grantedForcedExports;
+			case DENY:      return deniedForcedExports;
+			case UNDEFINED: return null; 
+//			default: // not implementing a default case, want to be warned when new enum-constants are added
+		}
+		// for binary compatibility; see also https://bugs.eclipse.org/bugs/show_bug.cgi?id=265744
+		throw new IncompatibleClassChangeError("enum "+AspectPermission.class.getName()+" has changed unexpectedly."); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	/** 
+	 * API for {@link OTStorageHook.StorageHookImpl}.
+	 * Query whether any forced-exports are declared for the given base bundle.
+	 * @param baseBundleId
+	 * @param the permission we are asking for
+	 * @return comma-separated package names
+	 */ 
+	public static String getGrantedForcedExportsByBase(String baseBundleId) {
+
+		// can be queried before we had a chance to initialize our data structures
+		synchronized (OTStorageHook.class) {
+			if (grantedForcedExports == null)
+				readForcedExports();
+		}
+
+		String exports = grantedForcedExports.get(baseBundleId);
+		if (exports != null) {
+			// yes, we need to add forced exports:
+			if (!exports.contains(XFRIENDS)) { // FIXME: check once for each package?
+				// invalid directive:
+				grantedForcedExports.remove(baseBundleId); 
+				logError("config.ini: missing x-friends directive in forced export of "+exports); //$NON-NLS-1$
+				return null; // don't install illegal forced exports
+			}
+		}
+		return exports;
+	}
+
+	/**
+	 * API for org.eclipse.objectteams.otequinox (as a service and using reflection).
+	 * Query whether any forced-exports are declared in config.ini (or other location) 
+	 * for the given aspect bundle.
+	 * @param aspectBundleId
+	 * @param the permission we are asking for
+	 * @return list of pairs (baseBundleId x packageName)
+	 */ 
+	public static /*@NonNull*/ List<String[]> getForcedExportsByAspect(String aspectBundleId, int perm) 
+	{
+		// can be queried before we had a chance to initialize our data structures
+		synchronized (OTStorageHook.class) {
+			if (grantedForcedExports == null)
+				readForcedExports();
+		}
+
+		ArrayList<String[]> result= new ArrayList<String[]>(5);
+		
+		HashMap<String, String> map = getForcedExportsMap(AspectPermission.values()[perm]);
+		if (map == null) 
+			return result; // DONT_CARE: useless query.
+		
+		for (Map.Entry<String,String> entry: map.entrySet()) {
+			String export= entry.getValue();
+			int start = 0;
+			while (start >= 0 && start < export.length()) {
+				if (start > 0) {
+					// skip separator after previous entry
+					if (export.charAt(start) == ',')
+						start++;
+					else
+						logError("Error parsing forced exports: "+export+", comma expected at position "+start); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+				int pos= export.indexOf(';'+XFRIENDS, start);
+				if (pos == -1)
+					break;
+				String packageName = export.substring(start, pos);
+				List<String> aspectBundles = new ArrayList<String>(); 
+				start = scanAspectBundles(export, pos+XFRIENDS.length()+1, aspectBundles);
+				for (String aspect : aspectBundles) {
+					if (aspect.equals(aspectBundleId)) {
+						result.add(new String[]{entry.getKey(), packageName});
+					}
+				}
+			}
+		}
+		return result;
+	}
+
+	private static int scanAspectBundles(String export, int pos, List<String> result) {
+		String termChars = ",]"; //$NON-NLS-1$
+		if (export.charAt(pos) == '"') {
+			pos++;
+			termChars = "\""; //$NON-NLS-1$
+		}
+		int start = pos;
+		while (pos < export.length()) {
+			char c = export.charAt(pos);
+			switch (c) {
+			case ',':
+			case ']':
+			case '"':
+				String next = export.substring(start, pos);
+				result.add(next);
+				start = pos+1;
+				if (termChars.indexOf(c) != -1)
+					return start;
+				break;
+			}
+			pos++;
+		}
+		logError("Unterminated forced exports: "+export); //$NON-NLS-1$
+		if (pos > start)
+			result.add(export.substring(start));
+		return export.length();
+	}
+
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/OTStorageHook.java b/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/OTStorageHook.java
new file mode 100644
index 0000000..8cb54af
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox.turbo/src/org/eclipse/objectteams/otequinox/turbo/OTStorageHook.java
@@ -0,0 +1,122 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2014 GK Software AG
+ *  
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * 	Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otequinox.turbo;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Dictionary;
+
+import org.eclipse.osgi.framework.log.FrameworkLog;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
+import org.eclipse.osgi.framework.util.Headers;
+import org.eclipse.osgi.internal.hookregistry.HookConfigurator;
+import org.eclipse.osgi.internal.hookregistry.HookRegistry;
+import org.eclipse.osgi.internal.hookregistry.StorageHookFactory;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+
+/** This class intercepts each bundle manifest and checks if forced exports must be injected. */
+public class OTStorageHook extends StorageHookFactory<Object, Object, OTStorageHook.StorageHookImpl> implements HookConfigurator {
+	// HINTS FOR DEBUGGING:
+	// - This fragment must be colocated with org.eclipse.osgi - perhaps a symbolic link helps to establish this.
+	// - This class must be accessible by its qualified name with no leading "src", again a symbolic link my help:
+	//   $ ln -s bin/org org
+
+	private FrameworkLog fwLog;
+
+	class StorageHookImpl extends StorageHookFactory.StorageHook<Object,Object> {
+
+		public StorageHookImpl(Generation generation) {
+			super(generation, OTStorageHook.class);
+		}
+
+		@Override
+		public void initialize(Dictionary<String, String> manifest) throws BundleException {
+			// when initializing, intercept the manifest and conditionally inject forced exports
+			String[] id = manifest.get(Constants.BUNDLE_SYMBOLICNAME).split(";");
+			if (id.length > 0) {
+				String packages = ForcedExportsRegistry.getGrantedForcedExportsByBase(id[0]);
+				if (packages != null && !packages.isEmpty()) {
+					String exportedPackages = manifest.get(Constants.EXPORT_PACKAGE);
+					if (exportedPackages != null && !exportedPackages.isEmpty())
+						exportedPackages = exportedPackages+','+packages;
+					else
+						exportedPackages = packages;
+					putHeader(id[0], Constants.EXPORT_PACKAGE, exportedPackages, packages);
+				}
+			}
+		}
+		/** Reflexively perform our (unusual) work. */
+		void putHeader(String id, String header, String value, String added) {
+			try {
+				Generation gen = getGeneration();
+				Method getRawHeaders = gen.getClass().getDeclaredMethod("getRawHeaders", new Class<?>[0]);
+				getRawHeaders.setAccessible(true);
+				@SuppressWarnings("unchecked")
+				Headers<String,String> headers = (Headers<String, String>) getRawHeaders.invoke(gen, new Object[0]);
+				Field readOnly = headers.getClass().getDeclaredField("readOnly");
+				readOnly.setAccessible(true);
+				readOnly.set(headers, false);
+				// pay-load:
+				headers.put(header, value);
+				// restore:
+				readOnly.setAccessible(false);
+				getRawHeaders.setAccessible(false);
+				fwLog.log(new FrameworkLogEntry(OTStorageHook.class.getName(), "OT/Equinox Turbo: added forced export into base bundle "+id+":\n\t"+added, FrameworkLogEntry.INFO, null, null));
+			} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchFieldException e) {
+				fwLog.log(new FrameworkLogEntry(OTStorageHook.class.getName(), "Unable to inject forced exports", FrameworkLogEntry.ERROR, e, null));
+			}
+		}
+
+		@Override
+		public void load(Object loadContext, DataInputStream is) throws IOException {
+			// nop
+		}
+
+		@Override
+		public void save(Object saveContext, DataOutputStream os) throws IOException {
+			// nop
+		}
+	}
+
+	@Override
+	public void addHooks(HookRegistry hookRegistry) {
+		hookRegistry.addStorageHookFactory(this);
+		fwLog = hookRegistry.getContainer().getLogServices().getFrameworkLog();
+		ForcedExportsRegistry.install(fwLog);
+	}
+	
+	@Override
+	protected StorageHookImpl createStorageHook(Generation generation) {
+		return new StorageHookImpl(generation);
+	}
+
+	@Override
+	public int getStorageVersion() {
+		return 0;
+	}
+
+	@Override
+	public boolean isCompatibleWith(int version) {
+		return false; // FIXME: forcing to re-init every time, is this OK?
+	}
+
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
index 98ea905..fbc0730 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBinding.java
@@ -33,6 +33,7 @@
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.objectteams.internal.osgi.weaving.Util.ProfileKind;
 import org.eclipse.objectteams.otequinox.ActivationKind;
+import org.eclipse.objectteams.otequinox.AspectPermission;
 import org.objectteams.Team;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.hooks.weaving.WovenClass;
@@ -70,7 +71,8 @@
 		private ActivationKind activation; // clients must use accessor getActivation()!
 		boolean hasScannedBases;
 		boolean hasScannedRoles;
-
+		@Nullable AspectPermission checkedPermission; // null means: not yet checked
+		
 		boolean isActivated;
 
 		boolean importsAdded;
@@ -85,6 +87,10 @@
 			this.superTeamName = superTeamName;
 			this.equivalenceSet.add(this);
 		}
+		
+		AspectBinding getAspectBinding() {
+			return AspectBinding.this;
+		}
 
 		/** After scanning class file attributes: add the names of all bound base classes. */
 		public void addBaseClassNames(Collection<String> baseClassNames) {
@@ -99,17 +105,16 @@
 		}
 
 		@SuppressWarnings("unchecked")
-		public @Nullable Class<? extends Team> loadTeamClass(Bundle fallbackBundle) {
+		public @Nullable Class<? extends Team> loadTeamClass() {
 			if (teamClass != null) return teamClass;
 			for (String candidate : TeamLoader.possibleTeamNames(teamName)) {
 				try {
 					Bundle aspectBundle = AspectBinding.this.aspectBundle;
-					// FIXME: no aspectBundle if no PackageAdmin was found, is using the fallbackBundle OK?
-					if (aspectBundle == null)
-						aspectBundle = fallbackBundle;
-					Class<?> result = aspectBundle.loadClass(candidate);
-					if (result != null)
-						return this.teamClass = (Class<? extends Team>) result;
+					if (aspectBundle != null) {
+						Class<?> result = aspectBundle.loadClass(candidate);
+						if (result != null)
+							return this.teamClass = (Class<? extends Team>) result;
+					}
 				} catch (NoClassDefFoundError|ClassNotFoundException e) {
 					e.printStackTrace();
 					// keep looking
@@ -125,6 +130,7 @@
 		 */
 		public void addImportTo(WovenClass baseClass, int direction) {
 			importsAdded = true;
+			if (AspectBinding.this.hasBeenDenied) return;
 			
 			String packageOfTeam = "";
 			int dot = teamName.lastIndexOf('.'); // TODO: can we detect if thats really the package (vs. Outer.Inner)?
@@ -193,6 +199,20 @@
 			}
 			return activation;
 		}
+
+		public @Nullable TeamBinding getOtherTeamToActivate() {
+			TeamBinding superTeam = this.superTeam;
+			if (superTeam != null && superTeam.getActivation() != ActivationKind.NONE) {
+				return superTeam;
+			}
+			// sub teams?
+			return null;
+		}
+
+		public boolean hasBeenDenied() {
+			return this.checkedPermission == AspectPermission.DENY
+						|| AspectBinding.this.hasBeenDenied;
+		}
 	}
 	
 	/**
@@ -202,7 +222,7 @@
 	static class BaseBundle {
 		String bundleName;
 		/** Team classes indexed by base classes that should trigger activating the team. */
-		private HashMap<String, Set<TeamBinding>> teamsPerBase = new HashMap<>();
+		final HashMap<String, Set<TeamBinding>> teamsPerBase = new HashMap<>();
 		boolean otreAdded;		
 
 		public BaseBundle(String bundleName) {
@@ -219,6 +239,8 @@
 	public Set<String> allBaseClassNames = new HashSet<>();
 
 	public boolean hasScannedTeams;
+	public AspectPermission forcedExportsPermission = AspectPermission.UNDEFINED;
+	public boolean hasBeenDenied = false;
 	
 	Set<TeamBinding> teamsInProgress = new HashSet<>(); // TODO cleanup teams that are done
 	
@@ -285,16 +307,6 @@
 		return teams;		
 	}
 
-	/** If a given team requires no activation, check if its super team should be activated instead. */
-	public @Nullable TeamBinding getOtherTeamToActivate(TeamBinding team) {
-		TeamBinding superTeam = team.superTeam;
-		if (superTeam != null && superTeam.getActivation() != ActivationKind.NONE) {
-			return superTeam;
-		}
-		// sub teams?
-		return null;
-	}
-
 	/**
 	 * Read OT attributes of all teams in this aspectBinding 
 	 * and collect affected base classes into the teamBindings.
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
index 5d9da54..3c81fca 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectBindingRegistry.java
@@ -150,7 +150,7 @@
 				@NonNull String realBaseBundleId = baseBundleId.toUpperCase().equals(SELF) ? aspectBundleId : baseBundleId;
 				addBindingForBaseBundle(realBaseBundleId, binding);
 				addBindingForAspectBundle(aspectBundleId, binding);
-				hook.setBaseTripWire(packageAdmin, realBaseBundleId, baseBundleLookup.get(realBaseBundleId));
+				hook.setBaseTripWire(packageAdmin, realBaseBundleId, baseBundle);
 
 				log(IStatus.INFO, "registered:\n"+binding);
 			} catch (Throwable t) {
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectPermissionManager.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectPermissionManager.java
index 78343ab..36cddb7 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectPermissionManager.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/AspectPermissionManager.java
@@ -20,17 +20,13 @@
 import static org.eclipse.objectteams.otequinox.AspectPermission.UNDEFINED;
 import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
 
 import org.eclipse.core.internal.runtime.InternalPlatform;
 import org.eclipse.core.runtime.CoreException;
@@ -91,6 +87,8 @@
 	private static final String GRANTED_FORCED_EXPORTS_FILE = "grantedForcedExports.txt";
 	private static final String DENIED_FORCED_EXPORTS_FILE  = "deniedForcedExports.txt";
 
+	private static final String GRANTED_TEAMS_FILE = "grantedTeams.txt";
+	private static final String DENIED_TEAMS_FILE  = "deniedTeams.txt";
 
 	// set of aspect plug-ins for which some permission has been denied:
 	private Set<String> deniedAspects = new HashSet<String>();
@@ -104,8 +102,8 @@
 	
 	// collect all forced exports (denied/granted), granted should balance to an empty structure.
 	// structure is: aspect-id -> (base bundle x base package)*
-	private HashMap<String, ArrayList<String[]>> deniedForcedExportsByAspect= new HashMap<String, ArrayList<String[]>>();
-	private HashMap<String, ArrayList<String[]>> grantedForcedExportsByAspect= new HashMap<String, ArrayList<String[]>>();
+	private HashMap<String, List<String[]>> deniedForcedExportsByAspect= new HashMap<String, List<String[]>>();
+	private HashMap<String, List<String[]>> grantedForcedExportsByAspect= new HashMap<String, List<String[]>>();
 	
 	// key is aspectId+"->"+baseId, value is array of team names
 	private HashMap<String, Set<String>> deniedTeamsByAspectBinding = new HashMap<String, Set<String>>();
@@ -119,11 +117,14 @@
 	@SuppressWarnings("deprecation")
 	@Nullable private org.osgi.service.packageadmin.PackageAdmin packageAdmin;
 	
+	private ForcedExportsDelegate forcedExportsDelegate;
+	
 	public AspectPermissionManager(Bundle bundle, 
 			@SuppressWarnings("deprecation") @Nullable org.osgi.service.packageadmin.PackageAdmin packageAdmin)
 	{
 		this.transformerBundle = bundle;
 		this.packageAdmin = packageAdmin;
+		this.forcedExportsDelegate = new ForcedExportsDelegate();
 	}
 
 	/* local cache for isReady(): */
@@ -169,72 +170,6 @@
 		}
 	}
 
-	private void internalFetchAspectBindingPermssionsFromWorkspace(IPath state) {
-		// defaults:
-		IPath configFilePath = state.append(NEGOTIATION_DEFAULTS_FILE);
-		File configFile = new File(configFilePath.toOSString());		
-		if (configFile.exists()) {
-			Properties props = new Properties();
-			try {
-				try (FileInputStream inStream = new FileInputStream(configFile)) {
-					props.load(inStream);
-				}
-				String value = (String) props.get(ASPECT_BINDING_DEFAULT);
-				if (value != null)
-					try {
-						defaultAspectBindingPermission = AspectPermission.valueOf(value); // known API of all enums
-					} catch (IllegalArgumentException iae) {
-						defaultAspectBindingPermission = AspectPermission.DENY;
-						log(iae, "Cannot set default aspect permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
-					}
-				value = (String) props.get(FORCED_EXPORT_DEFAULT);
-				if (value != null)
-					try {
-						defaultForcedExportPermission = AspectPermission.valueOf(value); // known API of all enums
-					} catch (IllegalArgumentException iae) {
-						defaultForcedExportPermission = AspectPermission.DENY;
-						log(iae, "Cannot set default forced exports permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
-					}
-			} catch (IOException ioex) {
-				log(ioex, "Failed to read configuration file "+configFilePath.toOSString());
-			}
-		} else {
-			try {
-				File stateDir = new File(state.toOSString());
-				if (!stateDir.exists())
-					stateDir.mkdirs();
-				configFile.createNewFile();
-				writeNegotiationDefaults(configFile);
-			} catch (IOException ioex) {
-				log(ioex, "Failed to create configuration file "+configFilePath.toOSString());
-			}
-		}
-		
-//		// explicitly denied:
-//		configFilePath = this.otequinoxState.append(DENIED_FORCED_EXPORTS_FILE);
-//		configFile = new File(configFilePath.toOSString());
-//		if (configFile.exists())
-//			HookConfigurator.parseForcedExportsFile(configFile, DENY);
-		
-//		// explicitly granted:
-//		configFilePath = this.otequinoxState.append(GRANTED_FORCED_EXPORTS_FILE);
-//		configFile = new File(configFilePath.toOSString());
-//		if (configFile.exists())
-//			HookConfigurator.parseForcedExportsFile(configFile, GRANT);
-	}
-
-	private void writeNegotiationDefaults(File configFile)
-			throws IOException 
-	{
-		try (FileWriter writer = new FileWriter(configFile)) {
-			writer.append(ASPECT_BINDING_DEFAULT+'='+defaultAspectBindingPermission.toString()+'\n');
-			writer.append(FORCED_EXPORT_DEFAULT+'='+defaultForcedExportPermission.toString()+'\n');
-			writer.flush();
-		}
-		log(IStatus.INFO, "Created aspect binding defaults file "+configFile.getCanonicalPath());
-	}
-
-		
 	/** Load extensions for EP org.eclipse.objectteams.otequinox.aspectBindingNegotiators. */
 	public void loadAspectBindingNegotiators(IExtensionRegistry extensionRegistry) {
 		IConfigurationElement[] aspectBindingNegotiatorsConfigs = extensionRegistry.getConfigurationElementsFor(
@@ -269,13 +204,25 @@
      * @param forcedExports any forced exports requested in this aspect binding.
 	 * @return whether all requests (if any) have been granted
 	 */
-	public boolean checkForcedExports(String aspectId, String baseBundleId, @Nullable IConfigurationElement[] forcedExports) 
-	{
+	public boolean checkForcedExports(AspectBinding aspectBinding) {
+		switch (aspectBinding.forcedExportsPermission) {
+			case GRANT: return true;
+			case DENY: return false;
+			case UNDEFINED: 
+				aspectBinding.forcedExportsPermission = internalCheckForcedExports(aspectBinding);
+				return aspectBinding.forcedExportsPermission == GRANT;
+		}
+		return true;
+	}
+	private AspectPermission internalCheckForcedExports(AspectBinding aspectBinding) {
+		IConfigurationElement[] forcedExports = aspectBinding.forcedExports;
 		if (forcedExports == null || forcedExports.length == 0)
-			return true;
+			return GRANT;
 		
-		ArrayList<String[]> deniedForcedExports = getConfiguredForcedExports(aspectId, DENY,  deniedForcedExportsByAspect);
-		ArrayList<String[]> grantedForcedExports= getConfiguredForcedExports(aspectId, GRANT, grantedForcedExportsByAspect);
+		String aspectId = aspectBinding.aspectPlugin;
+		String baseBundleId = aspectBinding.basePluginName; 
+		List<String[]> deniedForcedExports = getConfiguredForcedExports(aspectId, DENY,  deniedForcedExportsByAspect);
+		List<String[]> grantedForcedExports= getConfiguredForcedExports(aspectId, GRANT, grantedForcedExportsByAspect);
 
 		// iterate all requested forcedExports to search for a matching permission:
 		for (IConfigurationElement forcedExport : forcedExports) { // [0..1] (as defined in the schema)
@@ -295,7 +242,7 @@
 					log(IStatus.ERROR, "Default denial of forced export regarding package "+singleForcedExportRequest+
 									   " from bundle "+baseBundleId+" as requested by bundle "+aspectId+"; bundle not activated");
 					this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
-					return false; // NOPE!					
+					return DENY; // NOPE!					
 				}
 				
 				// DENY from configuration?
@@ -304,7 +251,7 @@
 					log(IStatus.ERROR, "Explicit denial of forced export regarding package "+singleForcedExportRequest+
 									   " from bundle "+baseBundleId+" as requested by bundle "+aspectId+"; bundle not activated");
 					this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
-					return false; // NOPE!
+					return DENY; // NOPE!
 				}
 
 				// GRANT from configuration?
@@ -350,13 +297,13 @@
 									   ": "+singleForcedExportRequest+" (from bundle "+baseBundleId+")"+
 									   ". Aspect is not activated.");
 					this.deniedAspects.add(aspectId); // keep for answering the TransformerHook.
-					return false; // don't install illegal aspect
+					return DENY; // don't install illegal aspect
 				}
 			}
 		}
 		if (!grantedForcedExports.isEmpty())
 			reportUnmatchForcedExports(aspectId, grantedForcedExports);
-		return true;
+		return GRANT;
 	}
 
 	/**
@@ -368,22 +315,20 @@
 	 * @param map		in/out param for storing results from OTStorageHook
 	 * @return		 	list of pairs (base bundle x base package)
 	 */
-	private ArrayList<String[]> getConfiguredForcedExports(String                               aspectId, 
-														   AspectPermission 				    perm, 
-														   HashMap<String, ArrayList<String[]>> map) 
+	private List<String[]> getConfiguredForcedExports( String                          aspectId, 
+														AspectPermission 				perm, 
+														HashMap<String, List<String[]>> map)
     {
-		ArrayList<String[]> forcedExports= map.get(aspectId);
+		List<String[]> forcedExports= map.get(aspectId);
 		if (forcedExports == null) {
 			// fetch declarations from config.ini or other locations.
-// FIXME
-//			forcedExports= HookConfigurator.getForcedExportsByAspect(aspectId, perm);
-//			map.put(aspectId, forcedExports);
-			forcedExports = new ArrayList<String[]>();
+			forcedExports= forcedExportsDelegate.getForcedExportsByAspect(aspectId, perm);
+			map.put(aspectId, forcedExports);
 		}
 		return forcedExports;
 	}
 
-	private @Nullable String[] findRequestInList(String baseBundleId, String basePackage, @Nullable ArrayList<String[]> list) {
+	private @Nullable String[] findRequestInList(String baseBundleId, String basePackage, @Nullable List<String[]> list) {
 		if (list != null)
 			for (String[] singleExport : list)
 				if (   singleExport[0].equals(baseBundleId)
@@ -398,7 +343,7 @@
 	 * If the structure of grantedForcedExports is not empty we have mismatches between forced-export declarations.
 	 * Report these mismatches as warnings.
 	 */
-	void reportUnmatchForcedExports(String aspectId, ArrayList<String[]> unmatchedForcedExports) 
+	void reportUnmatchForcedExports(String aspectId, List<String[]> unmatchedForcedExports) 
 	{
 		for (String[] export: unmatchedForcedExports) {
 			String baseId = export[0];
@@ -441,30 +386,43 @@
 	
 	/**
 	 * Check the permissions for all given teams.
-	 * @param aspectBundle the bundle containing the given teams
-	 * @param aspectBinding the binding mentioning the given teams
 	 * @param teamsForBase the teams to check
-	 * @return true if at least one binding was denied.
+	 * @return the set of denied teams
 	 */
-	boolean checkAspectPermissionDenial(Bundle aspectBundle, AspectBinding aspectBinding, Collection<TeamBinding> teamsForBase)
+	Set<TeamBinding> checkAspectPermissionDenial(Collection<TeamBinding> teamsForBase)
 	{
-		boolean hasDenial = false;
-		String aspectBundleName = aspectBundle.getSymbolicName();
-		if (aspectBundleName == null) {
-			log(IStatus.ERROR, "Cannot handle unnamed bundle "+aspectBundle);
-		} else {
-			for (TeamBinding teamForBase : teamsForBase)
-				if (!checkTeamBinding(aspectBundleName, aspectBinding.basePluginName, teamForBase.teamName)) {
-					hasDenial = true;
-					try {
-						aspectBundle.stop();
-						log(IStatus.ERROR, "Stopped bundle "+aspectBundleName+" which requests unconfirmed aspect binding(s).");
-					} catch (Throwable t) { // don't let the aspect bundle get by by throwing an unexpected exception!
-						log(t, "Failed to stop bundle "+aspectBundleName+" which requests unconfirmed aspect binding(s).");
-					}
+		Set<TeamBinding> deniedTeams = new HashSet<TeamBinding>();
+		for (TeamBinding teamForBase : teamsForBase) {
+			AspectBinding aspectBinding = teamForBase.getAspectBinding();
+			String aspectBundleName = aspectBinding.aspectPlugin;
+			if (aspectBinding.hasBeenDenied) {
+				deniedTeams.add(teamForBase);
+			} else {
+				if (!checkForcedExports(aspectBinding)) {
+					deniedTeams.add(teamForBase);
+					stopAspectBundle(aspectBinding, aspectBundleName, "requests unconfirmed forced export(s).");
+				} else if (!checkTeamBinding(aspectBundleName, aspectBinding.basePluginName, teamForBase)) {
+					deniedTeams.add(teamForBase);
+					stopAspectBundle(aspectBinding, aspectBundleName, "requests unconfirmed aspect binding(s).");
 				}
+			}
 		}
-		return hasDenial;
+		return deniedTeams;
+	}
+
+	void stopAspectBundle(AspectBinding aspectBinding, String aspectBundleName, String reason) {
+		try {
+			aspectBinding.hasBeenDenied = true;
+			Bundle aspectBundle = aspectBinding.aspectBundle;
+			if (aspectBundle != null) {
+				aspectBundle.stop();
+				log(IStatus.ERROR, "Stopped bundle "+aspectBundleName+" which "+reason);
+			} else {
+				log(IStatus.ERROR, "Cannot stop aspect bundle "+aspectBundleName);
+			}
+		} catch (Throwable t) { // don't let the aspect bundle get by by throwing an unexpected exception!
+			log(t, "Failed to stop bundle "+aspectBundleName+" which "+reason);
+		}
 	}
 
 	/**
@@ -475,10 +433,19 @@
  	 * 
 	 * @param aspectBundleId
 	 * @param baseBundleId
-	 * @param teamClass
+	 * @param teamBinding
 	 * @return whether this team is permitted to adapt classes from the given base bundle.
 	 */
-	boolean checkTeamBinding(String aspectBundleId, String baseBundleId, String teamClass) 
+	boolean checkTeamBinding(String aspectBundleId, String baseBundleId, TeamBinding teamBinding) {
+		if (teamBinding.checkedPermission != null)
+			return teamBinding.checkedPermission == AspectPermission.GRANT;
+
+		boolean isGranted = internalCheckTeamBinding(aspectBundleId, baseBundleId, teamBinding.teamName);
+		teamBinding.checkedPermission = isGranted ? AspectPermission.GRANT : AspectPermission.DENY;
+		return isGranted;
+	}
+
+	boolean internalCheckTeamBinding(String aspectBundleId, String baseBundleId, String teamClass) 
 	{
 		boolean shouldReportGrant = false; // grant by default should not be reported
 		AspectPermission negotiatedPermission = this.defaultAspectBindingPermission;
@@ -498,6 +465,8 @@
 		Set<String> deniedTeams = deniedTeamsByAspectBinding.get(key);
 		if (deniedTeams != null && !deniedTeams.isEmpty()) {
 			if (deniedTeams.contains(teamClass)) {
+				log(IStatus.ERROR, "Configured denial of aspect binding regarding base bundle "+baseBundleId+
+						   " as requested by bundle "+aspectBundleId+"; bundle not activated");
 				deniedAspects.add(aspectBundleId);
 				return false;
 			}
@@ -522,7 +491,7 @@
 				shouldReportGrant = negotiatedPermission == GRANT;
 				// locally store as default for subsequent requests:
 				if (answer.allRequests)
-					this.defaultAspectBindingPermission = negotiatedPermission;
+					this.defaultAspectBindingPermission = negotiatedPermission; // FIXME: differentiate: apply to all / all of same aspect bundle
 
 				if (negotiatedPermission == DENY) {
 					denyingNegotiator = negotiator.getClass().getName();
@@ -547,31 +516,21 @@
 			log(IStatus.ERROR, front+" aspect binding for "+aspectBundleId+
 							   " to base bundle "+baseBundleId+" by means of team "+teamClass+
 							   ". Aspect is not activated.");
-			this.deniedAspects.add(aspectBundleId); // keep for answering the TransformerHook.
+			this.deniedAspects.add(aspectBundleId); // keep for answering the TransformerPlugin.
 			return false; // don't install illegal aspect
 		}
 		return true;
 	}
 
-	private void persistTeamBindingAnswer(String aspectBundleId, String baseBundleId, String teamClass, AspectPermission negotiatedPermission) 
-	{
-		// FIXME(SH): implement persisting these!		
-	}
-		
 	List<Runnable> obligations = new ArrayList<Runnable>();
-	public void addBaseBundleObligations(final List<Team> teamInstances, final Collection<TeamBinding> teamClasses, final Bundle aspectBundle, final BaseBundle baseBundle) {
+	public void addBaseBundleObligations(final List<Team> teamInstances, final Collection<TeamBinding> teamClasses, final BaseBundle baseBundle) {
 		schedule(new Runnable() {
 			public void run() {
 				List<TeamBinding> teamsToRevert = new ArrayList<TeamBinding>();
 				// aspect bindings:
-				String aspectBundleName = aspectBundle.getSymbolicName();
-				if (aspectBundleName == null) {
-					log(IStatus.ERROR, "Cannot handle unnamed aspect bundle "+aspectBundle);
-				} else {
-					for (TeamBinding teamClass : teamClasses)
-						if (!checkTeamBinding(aspectBundleName, baseBundle.bundleName, teamClass.teamName))
-							teamsToRevert.add(teamClass);
-				}
+				for (TeamBinding teamClass : teamClasses)
+					if (!checkTeamBinding(teamClass.getAspectBinding().aspectPlugin, baseBundle.bundleName, teamClass))
+						teamsToRevert.add(teamClass);
 				if (!teamsToRevert.isEmpty())
 					revert(teamsToRevert);
 			}
@@ -585,11 +544,13 @@
 									teamInstance.deactivate(Team.ALL_THREADS);
 							// could also check if roles are present already ...
 						}
-						bundlesToStop.add(aspectBundle);
+						bundlesToStop.add(teamClass.getAspectBinding().aspectBundle);
 					}
 					for (Bundle bundle : bundlesToStop) {
-						log(IStatus.ERROR, "Stopping aspect bundle "+bundle.getSymbolicName()+" with denied aspect binding(s)");
-						bundle.stop();
+						if ((bundle.getState() & (Bundle.STARTING|Bundle.ACTIVE)) != 0) {
+							log(IStatus.ERROR, "Stopping aspect bundle "+bundle.getSymbolicName()+" with denied aspect binding(s)");
+							bundle.stop();
+						}
 					}
 				} catch (Exception e) {
 					log(e, "Failed to revert aspect bundle with denied aspect bindings.");
@@ -598,21 +559,6 @@
 		});
 	}
 
-	public void addForcedExportsObligations(final List<AspectBinding> aspects, final Bundle baseBundle) {
-		final String baseBundleName = baseBundle.getSymbolicName();
-		if (baseBundleName == null) {
-			log(IStatus.ERROR, "Cannot handle unnamed base bundle "+baseBundle);
-		} else {
-			schedule(new Runnable () {
-				public void run() {
-					for (AspectBinding aspectBinding : aspects)
-						if (!checkForcedExports(aspectBinding.aspectPlugin, baseBundleName, aspectBinding.forcedExports))
-							stopIllegalBundle(aspectBinding.aspectPlugin);
-				}
-			});
-		}
-	}
-
 	void schedule(Runnable job) {
 		if (isReady()) // became ready since last query?
 			job.run();
@@ -641,4 +587,151 @@
 				}
 		}
 	}
+
+	// ==== File I/O: ====
+
+	private void internalFetchAspectBindingPermssionsFromWorkspace(IPath state) {
+		// defaults:
+		IPath configFilePath = state.append(NEGOTIATION_DEFAULTS_FILE);
+		File configFile = new File(configFilePath.toOSString());		
+		if (configFile.exists()) {
+			Properties props = new Properties();
+			try {
+				try (FileInputStream inStream = new FileInputStream(configFile)) {
+					props.load(inStream);
+				}
+				String value = (String) props.get(ASPECT_BINDING_DEFAULT);
+				if (value != null)
+					try {
+						defaultAspectBindingPermission = AspectPermission.valueOf(value); // known API of all enums
+					} catch (IllegalArgumentException iae) {
+						defaultAspectBindingPermission = AspectPermission.DENY;
+						log(iae, "Cannot set default aspect permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
+					}
+				value = (String) props.get(FORCED_EXPORT_DEFAULT);
+				if (value != null)
+					try {
+						defaultForcedExportPermission = AspectPermission.valueOf(value); // known API of all enums
+					} catch (IllegalArgumentException iae) {
+						defaultForcedExportPermission = AspectPermission.DENY;
+						log(iae, "Cannot set default forced exports permission from file "+NEGOTIATION_DEFAULTS_FILE+", assuming DENY.");
+					}
+			} catch (IOException ioex) {
+				log(ioex, "Failed to read configuration file "+configFilePath.toOSString());
+			}
+		} else {
+			try {
+				File stateDir = new File(state.toOSString());
+				if (!stateDir.exists())
+					stateDir.mkdirs();
+				configFile.createNewFile();
+				writeNegotiationDefaults(configFile);
+			} catch (IOException ioex) {
+				log(ioex, "Failed to create configuration file "+configFilePath.toOSString());
+			}
+		}
+
+		// configured grant / deny per team:
+
+		configFilePath = state.append(GRANTED_TEAMS_FILE);
+		configFile = new File(configFilePath.toOSString());
+		if (configFile.exists())
+			parseTeamPermissionFile(grantedTeamsByAspectBinding, configFile);
+		
+		configFilePath = state.append(DENIED_TEAMS_FILE);
+		configFile = new File(configFilePath.toOSString());
+		if (configFile.exists())
+			parseTeamPermissionFile(deniedTeamsByAspectBinding, configFile);
+
+		// configured grant / denied for forced exports:
+		configFilePath = state.append(DENIED_FORCED_EXPORTS_FILE);
+		configFile = new File(configFilePath.toOSString());
+		if (configFile.exists())
+			forcedExportsDelegate.parseForcedExportsFile(configFile, DENY);
+		
+		configFilePath = state.append(GRANTED_FORCED_EXPORTS_FILE);
+		configFile = new File(configFilePath.toOSString());
+		if (configFile.exists())
+			forcedExportsDelegate.parseForcedExportsFile(configFile, GRANT);
+	}
+
+	private void writeNegotiationDefaults(File configFile)
+			throws IOException 
+	{
+		try (FileWriter writer = new FileWriter(configFile)) {
+			writer.append(ASPECT_BINDING_DEFAULT+'='+defaultAspectBindingPermission.toString()+'\n');
+			writer.append(FORCED_EXPORT_DEFAULT+'='+defaultForcedExportPermission.toString()+'\n');
+			writer.flush();
+		}
+		log(IStatus.INFO, "Created aspect binding defaults file "+configFile.getCanonicalPath());
+	}
+
+	private void parseTeamPermissionFile(HashMap<String, Set<String>> teamsByAspectBinding, File configFile) {
+		try (BufferedReader reader = new BufferedReader(new FileReader(configFile))) {
+			String line;
+			while ((line = reader.readLine()) != null) {
+				if (line.length() > 0 && line.charAt(0) == '#') continue;
+				String[] parts = line.split("=");
+				if (parts.length == 2) {
+					Set<String> teams = new HashSet<String>();
+					StringTokenizer teamToks = new StringTokenizer(parts[1], ",");
+					while (teamToks.hasMoreElements())
+						teams.add(teamToks.nextToken());
+					teamsByAspectBinding.put(parts[0], teams);
+				}
+			}
+		} catch (IOException e) {
+			log(e, "Failed to read permission file "+configFile.getAbsolutePath());
+		}
+	}
+
+	private void persistTeamBindingAnswer(String aspectBundleId, String baseBundleId, String teamClass, AspectPermission negotiatedPermission) 
+	{
+		IPath state = this.otequinoxState;
+		if (state != null) {
+			HashMap<String, Set<String>> teamsByAspect = null;
+			IPath configFilePath = null;
+			switch (negotiatedPermission) {
+			case GRANT:
+				teamsByAspect = this.grantedTeamsByAspectBinding;
+				configFilePath = state.append(GRANTED_TEAMS_FILE);
+				break;
+			case DENY:
+				teamsByAspect = this.deniedTeamsByAspectBinding;
+				configFilePath = state.append(DENIED_TEAMS_FILE);
+				break;
+			default: return; // TODO: also persist UNDEFINED (just to avoid asking again?)
+			}
+			
+			// in fact we store the entire state for the given category (grant / deny)
+			// so first insert the new answer into the existing map:
+			String key = aspectBundleId+"->"+baseBundleId;
+			Set<String> teams = teamsByAspect.get(key);
+			if (teams == null)
+				teamsByAspect.put(key, teams = new HashSet<String>());
+			teams.add(teamClass);
+
+			// now dump the entire map:
+			File configFile = new File(configFilePath.toOSString());
+			try {
+				if (!configFile.exists())
+					configFile.createNewFile();
+				try (FileWriter writer = new FileWriter(configFile, false)) {
+					writer.write("# Aspect permission file generated from aspect negotiation results.\n");
+					for (Map.Entry<String, Set<String>> entry : teamsByAspect.entrySet()) {
+						writer.append(entry.getKey()).append('=');
+						String sep = "";
+						for (String t : entry.getValue()) {
+							writer.append(sep).append(t);
+							sep = ",";
+						}
+						writer.append('\n');
+					}
+					writer.flush();
+				}
+			} catch (IOException ioe) {
+				log(ioe, "Failed to persist negotiation result");
+			}
+		}
+	}
 }
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
index c3351d2..27ba96a 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/BaseBundleLoadTrigger.java
@@ -104,11 +104,16 @@
 				if (!useDynamicWeaver) // OTDRE access aspects by generic interface in o.o.Team
 					aspectBinding.addImports(baseClass);
 
-				// (4) try optional steps:
-				TeamLoader loading = new TeamLoader(deferredTeamClasses, beingDefined, useDynamicWeaver);
-				loading.loadTeamsForBase(aspectBundle, aspectBinding, baseClass, hook.getAspectPermissionManager());
 			}
 		}
+		// (4) try optional steps concerning all teams for this base (across all involved aspect bindings):
+		TeamLoader loading = new TeamLoader(deferredTeamClasses, beingDefined, useDynamicWeaver);
+		final BaseBundle baseBundle3 = this.baseBundle;
+		if (baseBundle3 != null) {
+			loading.loadTeamsForBase(baseBundle3, baseClass, hook.getAspectPermissionManager());
+		} else {
+			// FIXME: handle SELF adapting aspect binding!! (perhaps using a special kind of BaseBundle??
+		}
 
 		// if some had to be deferred collect them now:
 		if (!deferredTeamClasses.isEmpty()) {
@@ -144,4 +149,11 @@
 				return false;
 		return true;
 	}
+
+	public boolean areAllAspectsDenied() {
+		for (AspectBinding binding : aspectBindings)
+			if (!binding.hasBeenDenied)
+				return false;
+		return true;
+	}
 }
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/ForcedExportsDelegate.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/ForcedExportsDelegate.java
new file mode 100644
index 0000000..bb0438a
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/ForcedExportsDelegate.java
@@ -0,0 +1,74 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2014 GK Software AG
+ *  
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
+ * 
+ * Contributors:
+ * 	Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.internal.osgi.weaving;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.objectteams.otequinox.AspectPermission;
+import org.eclipse.objectteams.otequinox.TransformerPlugin;
+
+/** Reflexive gateway to a class from fragment org.eclipse.objectteams.otequinox.turbo, if present. */
+public class ForcedExportsDelegate {
+
+	Class<?> registryClass;
+	Method getForcedExportsByAspect;
+	Method parseForcedExportsFile;
+	
+	public ForcedExportsDelegate() {
+		try {
+			registryClass = getClass().getClassLoader().loadClass("org.eclipse.objectteams.otequinox.turbo.ForcedExportsRegistry");
+			getForcedExportsByAspect = registryClass.getMethod("getForcedExportsByAspect", new Class<?>[] { String.class, int.class } );
+			parseForcedExportsFile = registryClass.getMethod("parseForcedExportsFile", new Class<?>[] { File.class, int.class } );
+		} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
+			// ignore, turbo fragment may just be absent.
+		}
+	}
+	
+	public boolean isAvailable() {
+		return registryClass != null;
+	}
+
+	@SuppressWarnings({ "unchecked", "null" }) // neither reflection nor Collections.emptyList() knows about nullness
+	public @NonNull List<String[]> getForcedExportsByAspect(String aspectBundleId, AspectPermission perm) {
+		if (getForcedExportsByAspect != null) {
+			try {
+				return (List<String[]>) getForcedExportsByAspect.invoke(null, new Object[] {aspectBundleId, perm.ordinal()});
+			} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+				TransformerPlugin.log(e, "Failed to access forced exports");
+			}
+		}
+		return Collections.emptyList();
+	}
+
+	/**
+	 * Called when we know the workspace location to read workspace-specific permissions.
+	 * New information is integrated with existing information inside the ForcedExportsRegistry.
+	 */
+	public void parseForcedExportsFile(File configFile, AspectPermission perm) {
+		if (parseForcedExportsFile != null) {
+			try {
+				parseForcedExportsFile.invoke(null, new Object[] {configFile, perm.ordinal()});
+			} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+				TransformerPlugin.log(e, "Failed to access forced exports file");
+			}
+		}
+	}
+}
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
index f5a26a6..83bfa92 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/OTWeavingHook.java
@@ -8,18 +8,22 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  * 
- * Please visit http://www.objectteams.org for updates and contact.
+ * Please visit http://www.eclipse.org/objectteams for updates and contact.
  * 
  * Contributors:
  * 	Stephan Herrmann - Initial API and implementation
  **********************************************************************/
 package org.eclipse.objectteams.internal.osgi.weaving;
 
+import static org.eclipse.objectteams.otequinox.Constants.LIFTING_PARTICIPANT_EXTPOINT_ID;
+import static org.eclipse.objectteams.otequinox.Constants.TRANSFORMER_PLUGIN_ID;
+import static org.eclipse.objectteams.otequinox.Constants.ORG_OBJECTTEAMS_TEAM;
 import static org.eclipse.objectteams.otequinox.TransformerPlugin.log;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.instrument.IllegalClassFormatException;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -28,6 +32,7 @@
 import java.util.List;
 import java.util.Set;
 
+import org.eclipse.core.runtime.IConfigurationElement;
 import org.eclipse.core.runtime.IExtensionRegistry;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jdt.annotation.NonNull;
@@ -66,12 +71,16 @@
  */
 public class OTWeavingHook implements WeavingHook, WovenClassListener {
 
+
 	// TODO: this master-switch, which selects the weaver, should probably be replaced by s.t. else?
 	boolean useDynamicWeaver = "dynamic".equals(System.getProperty("ot.weaving"));
 	
 	// TODO: temporary switch to fall back to coarse grain checking:
 	boolean skipBaseClassCheck = "skip".equals(System.getProperty("otequinox.baseClassChecks"));
 
+	// for installing a lifting participant:
+	private static final String LIFTING_PARTICIPANT_FIELD = "_OT$liftingParticipant";
+
 	enum WeavingReason { None, Aspect, Base, Thread }
 	
 	/** Interface to data about aspectBinding extensions. */
@@ -90,6 +99,10 @@
 
 	private AspectPermissionManager permissionManager;
 
+	/** A registered lifting participant is directly handled by us. */
+	private @Nullable IConfigurationElement liftingParticipantConfig;
+	private @Nullable Class<?> ooTeam;
+
 	/** Call-back once the extension registry is up and running. */
 	public void activate(BundleContext bundleContext, ServiceReference<IExtensionRegistry> serviceReference) {
 		loadAspectBindingRegistry(bundleContext, serviceReference);
@@ -119,6 +132,8 @@
 			permissionManager.loadAspectBindingNegotiators(extensionRegistry);
 
 			aspectBindingRegistry.loadAspectBindings(extensionRegistry, packageAdmin, this);
+
+			loadLiftingParticipant(extensionRegistry);
 		}
 	}
 
@@ -129,6 +144,35 @@
 		return manager;
 	}
 
+	/* Load extension for org.eclipse.objectteams.otequinox.liftingParticipant. */
+	private void loadLiftingParticipant(IExtensionRegistry extensionRegistry) {
+		IConfigurationElement[] liftingParticipantConfigs = extensionRegistry.getConfigurationElementsFor(
+				TRANSFORMER_PLUGIN_ID, LIFTING_PARTICIPANT_EXTPOINT_ID);
+		
+		if (liftingParticipantConfigs.length != 1) {
+			if (liftingParticipantConfigs.length > 1)
+				log(IStatus.ERROR, "Cannot install more than one lifting participant.");
+			return;
+		}
+		this.liftingParticipantConfig = liftingParticipantConfigs[0];
+		installLiftingParticipant();
+	}
+	
+	private void installLiftingParticipant() {
+		Class<?> teamClass = this.ooTeam;
+		IConfigurationElement config = this.liftingParticipantConfig;
+		if (teamClass != null && config != null) {
+			try {
+				Field field = teamClass.getDeclaredField(LIFTING_PARTICIPANT_FIELD); // field name cannot be mentioned in source
+				field.set(null, config.createExecutableExtension(Constants.CLASS));
+				log(IStatus.INFO, "Registered Lifting Participant from "+config.getContributor().getName());
+			} catch (Exception e) {
+				log(e, "Failed to install lifting participant from "+config.getContributor().getName());
+			}
+			this.liftingParticipantConfig = null; // signal done
+		}
+	}
+
 	// ====== Base Bundle Trip Wires: ======
 	
 	/**
@@ -142,14 +186,19 @@
 			baseTripWires.put(baseBundleId, new BaseBundleLoadTrigger(baseBundleId, baseBundle, aspectBindingRegistry, packageAdmin));
 	}
 
-	/** Check if the given base bundle / base class mandate any loading/instantiation/activation of teams. */
-	void triggerBaseTripWires(@Nullable String bundleName, @NonNull WovenClass baseClass) {
+	/**
+	 * Check if the given base bundle / base class mandate any loading/instantiation/activation of teams.
+	 * @return true if all involved aspect bindings have been denied (permissions).
+	 */
+	boolean triggerBaseTripWires(@Nullable String bundleName, @NonNull WovenClass baseClass) {
 		BaseBundleLoadTrigger activation = baseTripWires.get(bundleName);
 		if (activation != null) {
 			activation.fire(baseClass, beingDefined, this);
 			if (activation.isDone())
 				baseTripWires.remove(bundleName);
+			return activation.areAllAspectsDenied();
 		}
+		return false;
 	}
 
 	// ====== Main Weaving Entry: ======
@@ -176,11 +225,13 @@
 			WeavingReason reason = requiresWeaving(bundleWiring, className, bytes);
 			if (reason != WeavingReason.None) {
 				// do whatever is needed *before* loading this class:
-				triggerBaseTripWires(bundleName, wovenClass);
-				if (reason == WeavingReason.Thread) {
+				boolean allAspectsAreDenied = triggerBaseTripWires(bundleName, wovenClass);
+				if (reason == WeavingReason.Base && allAspectsAreDenied) {
+					return; // don't weave for denied bindings
+				} else if (reason == WeavingReason.Thread) {
 					BaseBundle baseBundle = this.aspectBindingRegistry.getBaseBundle(bundleName);
 					BaseBundleLoadTrigger.addOTREImport(baseBundle, bundleName, wovenClass, this.useDynamicWeaver);
-				}
+				} 
 
 				long time = 0;
 
@@ -222,7 +273,7 @@
 		if (aspectBindings != null && !aspectBindings.isEmpty()) {
 			// potential base class: look deeper:
 			for (AspectBinding aspectBinding : aspectBindings) {
-				if (!aspectBinding.hasScannedTeams)
+				if (!aspectBinding.hasScannedTeams && !aspectBinding.hasBeenDenied)
 					return WeavingReason.Base; // we may be first, go ahead and trigger the trip wire
 			}
 			if (isAdaptedBaseClass(aspectBindings, className, bytes, bundleWiring.getClassLoader()))
@@ -251,7 +302,7 @@
 
 		try {
 			for (AspectBinding aspectBinding : aspectBindings) {
-				if (aspectBinding.allBaseClassNames.contains(className))
+				if (aspectBinding.allBaseClassNames.contains(className) && !aspectBinding.hasBeenDenied)
 					return true;					
 			}
 			// attempt recursion to superclass (not superInterfaces atm):
@@ -344,6 +395,10 @@
 	@Override
 	public void modified(WovenClass wovenClass) {
 		if (wovenClass.getState() == WovenClass.DEFINED) {
+			if (wovenClass.getClassName().equals(ORG_OBJECTTEAMS_TEAM)) {
+				this.ooTeam = wovenClass.getDefinedClass();
+				installLiftingParticipant();
+			}
 			beingDefined.remove(wovenClass.getClassName());
 			@SuppressWarnings("null") @NonNull String className = wovenClass.getClassName();
 			instantiateScheduledTeams(className);
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
index 8f8512a..404c252 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/TeamLoader.java
@@ -27,6 +27,7 @@
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.BaseBundle;
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding.TeamBinding;
 import org.eclipse.objectteams.internal.osgi.weaving.Util.ProfileKind;
 import org.eclipse.objectteams.otequinox.ActivationKind;
@@ -70,9 +71,9 @@
 	 * Team loading, 1st attempt before the base class is even loaded
 	 * Trying to do these phases: load (now) instantiate/activate (if ready),
 	 */
-	public void loadTeamsForBase(Bundle aspectBundle, AspectBinding aspectBinding, WovenClass baseClass, AspectPermissionManager permissionManager) {
+	public void loadTeamsForBase(BaseBundle baseBundle, WovenClass baseClass, AspectPermissionManager permissionManager) {
 		@SuppressWarnings("null")@NonNull String className = baseClass.getClassName();
-		Collection<TeamBinding> teamsForBase = aspectBinding.getTeamsForBase(className);
+		Collection<TeamBinding> teamsForBase = baseBundle.teamsPerBase.get(className);
 		if (teamsForBase == null) 
 			return; // not done
 
@@ -81,16 +82,24 @@
 
 		// ==== check permissions before we start activating:
 		if (permissionManagerReady) { // otherwise we will register pending obligations below.
-			if (permissionManager.checkAspectPermissionDenial(aspectBundle, aspectBinding, teamsForBase))
-				return;
+			Set<TeamBinding> deniedTeams = permissionManager.checkAspectPermissionDenial(teamsForBase);
+			if (!deniedTeams.isEmpty()){
+				for (WaitingTeamRecord rec : new ArrayList<>(this.deferredTeams))
+					if (deniedTeams.contains(rec.team))
+						this.deferredTeams.remove(rec);
+			}
 		}
 		
 		List<Team> teamInstances = new ArrayList<>();
 		for (TeamBinding teamForBase : teamsForBase) {
 			if (teamForBase.isActivated) continue;
+			if (teamForBase.hasBeenDenied()) {
+				log(IStatus.WARNING, "Not activating team "+teamForBase.teamName+" due to denied permissions.");
+				continue;
+			}
 			// Load:
 			Class<? extends Team> teamClass;
-			teamClass = teamForBase.loadTeamClass(aspectBundle);
+			teamClass = teamForBase.loadTeamClass();
 			if (teamClass == null) {
 				log(new ClassNotFoundException("Not found: "+teamForBase), "Failed to load team "+teamForBase);
 				continue;
@@ -98,13 +107,13 @@
 			// Try to instantiate & activate, failures are recorded in deferredTeams
 			ActivationKind activationKind = teamForBase.getActivation();
 			if (activationKind == ActivationKind.NONE) {
-				teamForBase = aspectBinding.getOtherTeamToActivate(teamForBase);
+				teamForBase = teamForBase.getOtherTeamToActivate();
 				if (teamForBase != null) {
 					if (teamForBase.isActivated) continue;
 					activationKind = teamForBase.getActivation();
-					teamClass = teamForBase.loadTeamClass(aspectBundle);
+					teamClass = teamForBase.loadTeamClass();
 					if (teamClass == null) {
-						log(new ClassNotFoundException("Not found: "+teamForBase.teamName+" in bundle "+aspectBundle.getSymbolicName()), "Failed to load team "+teamForBase);
+						log(new ClassNotFoundException("Not found: "+teamForBase.teamName+" in bundle "+teamForBase.getAspectBinding().aspectPlugin), "Failed to load team "+teamForBase);
 						continue;						
 					}
 				} else {
@@ -113,13 +122,13 @@
 			}
 			if (activationKind == ActivationKind.NONE) 
 				continue;
-			Team instance = instantiateAndActivate(aspectBinding, teamForBase, activationKind);
+			Team instance = instantiateAndActivate(teamForBase.getAspectBinding(), teamForBase, activationKind);
 			if (instance != null)
 				teamInstances.add(instance);
 		}
 
 		if (!permissionManagerReady)
-			permissionManager.addBaseBundleObligations(teamInstances, teamsForBase, aspectBundle, aspectBinding.baseBundle);
+			permissionManager.addBaseBundleObligations(teamInstances, teamsForBase, baseBundle);
 	}
 
 	public static @Nullable Pair<URL,String> findTeamClassResource(String className, Bundle bundle) {
@@ -206,6 +215,21 @@
 					break;
 				}
 				if (Util.PROFILE) Util.profile(time, ProfileKind.Activation, teamName);
+			} catch (NoClassDefFoundError e) {
+				try { // clean up:
+					switch (activationKind) {
+					case ALL_THREADS: instance.deactivate(Team.ALL_THREADS); break;
+					case THREAD: instance.deactivate(); break;
+					default: break;
+					}
+				} catch (Throwable t) { /* ignore */ }
+				for (TeamBinding eq : team.equivalenceSet)
+					eq.isActivated = false;
+				@SuppressWarnings("null") @NonNull // known API
+				String notFoundName = e.getMessage().replace('/', '.');
+				synchronized (this.deferredTeams) {
+					this.deferredTeams.add(new WaitingTeamRecord(team, activationKind, notFoundName));
+				}
 			} catch (Throwable t) {
 				// application errors during activation
 				log(t, "Failed to activate team "+teamName);
@@ -225,7 +249,7 @@
 		for (@SuppressWarnings("null")@NonNull String baseclass : team.baseClassNames) {
 			if (this.beingDefined.contains(baseclass)) {
 				synchronized (deferredTeams) {
-					WaitingTeamRecord record = new WaitingTeamRecord(team, aspectBinding, activationKind, baseclass);
+					WaitingTeamRecord record = new WaitingTeamRecord(team, activationKind, baseclass);
 					deferredTeams.add(record);
 				}
 				log(IStatus.INFO, "Defer instantation/activation of team "+teamName);
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/WaitingTeamRecord.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/WaitingTeamRecord.java
index b954565..b9fedd4 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/WaitingTeamRecord.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/internal/osgi/weaving/WaitingTeamRecord.java
@@ -1,7 +1,7 @@
 /**********************************************************************
  * This file is part of "Object Teams Development Tooling"-Software
  * 
- * Copyright 2013 GK Software AG
+ * Copyright 2013, 2014 GK Software AG
  *  
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -27,9 +27,9 @@
 	ActivationKind activationKind;
 	String notFoundClass;
 	
-	public WaitingTeamRecord(TeamBinding team, AspectBinding aspectBinding, ActivationKind activationKind, String notFoundClass) {
+	public WaitingTeamRecord(TeamBinding team, ActivationKind activationKind, String notFoundClass) {
 		this.team = team;
-		this.aspectBinding = aspectBinding;
+		this.aspectBinding = team.getAspectBinding();
 		this.notFoundClass = notFoundClass;
 		this.activationKind = activationKind;
 	}	
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/Constants.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/Constants.java
index fada6ab..6671d9a 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/Constants.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/Constants.java
@@ -25,7 +25,10 @@
 	
 	/** ID of this plugin. */
 	public static final String TRANSFORMER_PLUGIN_ID         = "org.eclipse.objectteams.otequinox" ; //$NON-NLS-1$
-	
+
+	/** Qualified name of class Team. */
+	public static final String ORG_OBJECTTEAMS_TEAM = "org.objectteams.Team";
+
 	// === Extension point elements: ===
 	
 	/** Simple name of the extension point org.eclipse.objectteams.otequinox.aspectBindings. */
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
index 3735251..5f00886 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/IAspectRegistry.java
@@ -16,7 +16,7 @@
  **********************************************************************/
 package org.eclipse.objectteams.otequinox;
 
-import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.osgi.framework.Bundle;
 
@@ -27,6 +27,7 @@
  * @author stephan
  * @since OTDT 1.1.4
  */
+@NonNullByDefault
 public interface IAspectRegistry {
 
 	/** Are we running within the OTDT? */
@@ -40,7 +41,7 @@
 	 * @param basePlugin base plugin.
 	 * @return non-null array of symbolic names of aspect plugins.
  	 */
-	public @NonNull String[] getAdaptingAspectPlugins(Bundle baseBundle);
+	public String[] getAdaptingAspectPlugins(Bundle baseBundle);
 
 	/**
 	 *  Get the plugin IDs of all base plugins adapted by this aspect plugin.
@@ -63,5 +64,5 @@
 	 * @param symbolicName
 	 * @return
 	 */
-	public boolean isDeniedAspectPlugin(@NonNull String symbolicName);
+	public boolean isDeniedAspectPlugin(String symbolicName);
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
index d3c8aa6..cfa532c 100644
--- a/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
+++ b/plugins/org.eclipse.objectteams.otequinox/src/org/eclipse/objectteams/otequinox/TransformerPlugin.java
@@ -24,6 +24,9 @@
 import org.eclipse.core.runtime.ILog;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.log.ExtendedLogReaderService;
+import org.eclipse.equinox.log.ExtendedLogService;
+import org.eclipse.equinox.log.Logger;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBinding;
 import org.eclipse.objectteams.internal.osgi.weaving.AspectBindingRegistry;
@@ -40,6 +43,7 @@
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.hooks.weaving.WeavingHook;
 import org.osgi.framework.hooks.weaving.WovenClassListener;
+import org.osgi.util.tracker.ServiceTracker;
 
 public class TransformerPlugin implements BundleActivator, IAspectRegistry {
 
@@ -100,9 +104,25 @@
 	@SuppressWarnings("restriction")
 	private static void acquireLog(BundleContext bundleContext) {
 		try {
-			TransformerPlugin.log = org.eclipse.core.internal.runtime.InternalPlatform.getDefault().getLog(bundleContext.getBundle());
+			log = org.eclipse.core.internal.runtime.InternalPlatform.getDefault().getLog(bundleContext.getBundle());
 		} catch (NullPointerException npe) {
-			// WTF?
+			// in case InternalPlatform isn't initialized yet, perform the same tasks manually:
+
+			ServiceTracker<ExtendedLogService,ExtendedLogService> tracker
+					= new ServiceTracker<ExtendedLogService,ExtendedLogService>(context, ExtendedLogService.class, null);
+			tracker.open();
+			ExtendedLogService logService = tracker.getService();
+			Bundle bundle = bundleContext.getBundle();
+			Logger logger = logService == null ? null 
+					: logService.getLogger(bundle, org.eclipse.core.internal.runtime.PlatformLogWriter.EQUINOX_LOGGER_NAME);
+			org.eclipse.core.internal.runtime.Log result = new org.eclipse.core.internal.runtime.Log(bundle, logger);
+
+			ServiceTracker<ExtendedLogReaderService, ExtendedLogReaderService> logReaderTracker 
+					= new ServiceTracker<ExtendedLogReaderService,ExtendedLogReaderService>(context, ExtendedLogReaderService.class.getName(), null);
+			logReaderTracker.open();
+			ExtendedLogReaderService logReader = logReaderTracker.getService();
+			logReader.addLogListener(result, result);
+			log = result;
 		}
 	}
 
@@ -146,9 +166,14 @@
 
 	public static synchronized void log (Throwable ex, String msg) {
 		msg = "OT/Equinox: "+msg;
-		System.err.println(msg);
-		ex.printStackTrace();
-		pendingLogEntries.add(new Status(IStatus.ERROR, TRANSFORMER_PLUGIN_ID, msg, ex));
+		Status status = new Status(IStatus.ERROR, TRANSFORMER_PLUGIN_ID, msg, ex);
+		if (log != null) {
+			log.log(status);
+		} else {
+			System.err.println(msg);
+			ex.printStackTrace();
+			pendingLogEntries.add(status);
+		}
 	}
 	
 	public static void log(int status, String msg) {
@@ -156,15 +181,12 @@
 			doLog(status, msg);
 	}
 
-	public static synchronized void doLog(int status, String msg) {
-		msg = "OT/Equinox: "+msg;
-		try {
-// this seems to cause java.lang.NoClassDefFoundError: org/eclipse/ui/statushandlers/StatusAdapter etc.
-//		if (log == null) acquireLog(context);
-			pendingLogEntries.add(new Status(status, TRANSFORMER_PLUGIN_ID, msg));
-		} catch (NoClassDefFoundError e) {
-			System.err.println("OT/Euqinox (not ready for logging): "+msg);
-		}
+	public static synchronized void doLog(int level, String msg) {
+		Status status = new Status(level, TRANSFORMER_PLUGIN_ID, "OT/Equinox: "+msg);
+		if (log != null)
+			log.log(status);
+		else
+			pendingLogEntries.add(status);
 	}
 	
 	public static void flushLog() {
@@ -202,7 +224,7 @@
 	 * public API:
 	 * {@link IAspectRegistry#getAdaptingAspectPlugins(Bundle)} 
 	 */
-	public @NonNull String[] getAdaptingAspectPlugins(Bundle basePlugin) {
+	public @NonNull String[] getAdaptingAspectPlugins(@NonNull Bundle basePlugin) {
 		return getAdaptingAspectPlugins(basePlugin.getSymbolicName());
 	}
 
@@ -232,17 +254,17 @@
 	}
 
 	@Override
-	public boolean isAdaptedBasePlugin(String baseBundleName) {
+	public boolean isAdaptedBasePlugin(@NonNull String baseBundleName) {
 		return this.aspectBindingRegistry.isAdaptedBasePlugin(baseBundleName);
 	}
 
 	@Override
-	public String[] getAdaptedBasePlugins(Bundle aspectBundle) {
+	public String[] getAdaptedBasePlugins(@NonNull Bundle aspectBundle) {
 		return this.aspectBindingRegistry.getAdaptedBasePlugins(aspectBundle);
 	}
 
 	@Override
-	public boolean hasInternalTeams(Bundle bundle) {
+	public boolean hasInternalTeams(@NonNull Bundle bundle) {
 		// TODO Auto-generated method stub
 		return false;
 	}
diff --git a/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
index dd6c842..e4efea6 100644
--- a/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.otredyn/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.objectteams.otredyn
-Bundle-Version: 1.0.0.qualifier
+Bundle-Version: 1.0.1.qualifier
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Export-Package: org.eclipse.objectteams.otredyn.bytecode,
@@ -13,7 +13,7 @@
  org.eclipse.objectteams.otredyn.util
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Bundle-ClassPath: .
-Require-Bundle: org.eclipse.objectteams.runtime;bundle-version="[2.3.0,3.0.0)",
+Require-Bundle: org.eclipse.objectteams.runtime;bundle-version="[2.3.1,3.0.0)",
  org.objectweb.asm;bundle-version="5.0.1",
  org.objectweb.asm.tree;bundle-version="5.0.1",
  org.objectweb.asm.commons;bundle-version="5.0.1"
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
index cf22779..e810bb2 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/AbstractBoundClass.java
@@ -588,12 +588,14 @@
 			parseBytecode();
 			prepareAsPossibleBaseClass();
 			prepareTeamActivation();
+			prepareLiftingParticipant();
 		} else if (isFirstTransformation()) {
 			// No, so only do load time transforming, if this method is called
 			// at load time
 			startTransformation();
 			prepareAsPossibleBaseClass();
 			prepareTeamActivation();
+			prepareLiftingParticipant();
 			endTransformation();
 		}
 
@@ -1005,6 +1007,8 @@
 
 	protected abstract void prepareTeamActivation();
 
+	protected abstract void prepareLiftingParticipant();
+
 	protected abstract void createSuperCallInCallOrig(int boundMethodId);
 
 	protected abstract void createCallAllBindingsCallInOrgMethod(
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
index a943878..49c94e7 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/AsmWritableBoundClass.java
@@ -112,7 +112,7 @@
 		

 		reader = new ClassReader(allocateAndGetBytecode());

 

-		writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);

+		writer = new LoaderAwareClassWriter(reader, ClassWriter.COMPUTE_FRAMES, this.loader);

 		multiAdapter = new MultiClassAdapter(writer);

 		nodes = new ArrayList<AbstractTransformableClassNode>();

 		isTransformationActive = true;

@@ -141,7 +141,7 @@
 			reader = new ClassReader(allocateAndGetBytecode());

 			reader.accept(node, ClassReader.SKIP_FRAMES);

 			if (node.transform()) {

-				writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);

+				writer = new LoaderAwareClassWriter(reader, ClassWriter.COMPUTE_FRAMES, this.loader);

 				node.accept(writer);

 				setBytecode(writer.toByteArray());

 			}

@@ -385,6 +385,13 @@
 		AddGlobalTeamActivationAdapter.checkAddVisitor(this.multiAdapter, this.writer);

 	}

 

+	@Override

+	protected void prepareLiftingParticipant() {

+		if (isTeam() && LiftingParticipantAdapter.isLiftingParticipantConfigured(this.loader)) {

+			multiAdapter.addVisitor(new LiftingParticipantAdapter(this.writer));

+		}

+	}

+

 	/**

 	 * Prepares the methods callAllBindings and callOrig with an empty

 	 * switch statement

diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/LiftingParticipantAdapter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/LiftingParticipantAdapter.java
new file mode 100644
index 0000000..c3cce1f
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/LiftingParticipantAdapter.java
@@ -0,0 +1,149 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2014 GK Software AG
+ *  
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.objectteams.org for updates and contact.
+ * 
+ * Contributors:
+ * 	Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import static org.eclipse.objectteams.otredyn.bytecode.asm.AsmBoundClass.ASM_API;
+import static org.eclipse.objectteams.otredyn.transformer.names.ClassNames.*;
+import static org.objectweb.asm.Opcodes.*;
+
+import java.lang.reflect.Field;
+
+import org.objectteams.Team;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.InstructionAdapter;
+
+/**
+ * If a lifting participant has been configured, insert the code to invoke it.
+ * @since 2.3.1
+ */
+public class LiftingParticipantAdapter extends ClassVisitor {
+
+	private static boolean checked = false;
+	private static String PARTICIPANT_NAME = System.getProperty("ot.lifting.participant");
+	private static final String LIFTING_PARTICIPANT_FIELD = "_OT$liftingParticipant";
+
+	private static final String LIFT_PREFIX = "_OT$liftTo"; 
+
+	private static final String CREATE_ROLE_METHOD = "createRole";
+	private static final String CREATE_ROLE_DESC = "(L"+ITEAM_SLASH+";L"+OBJECT_SLASH+";Ljava/lang/String;)L"+OBJECT_SLASH+";";
+
+	public LiftingParticipantAdapter(ClassVisitor cv) {
+		super(ASM_API, cv);
+	}
+	
+	public static synchronized boolean isLiftingParticipantConfigured(ClassLoader loader) {
+		try {
+			Field participantField = Team.class.getField(LIFTING_PARTICIPANT_FIELD);
+
+			boolean shouldInstantiateAndRegister = check(participantField);
+
+			if (shouldInstantiateAndRegister) {			
+				// install a shared instance into class Team:
+				Class<?> participantClass = loader.loadClass(PARTICIPANT_NAME); 
+				participantField.set(null, participantClass.newInstance());
+			}
+		} catch (Exception e) {
+			new IllegalArgumentException("Lifting participant "+PARTICIPANT_NAME+" is invalid.", e).printStackTrace();
+			PARTICIPANT_NAME = null; // disable requested lifting participant
+		}
+		return PARTICIPANT_NAME != null;
+	}
+
+	/** Check configuration via system property and directly preset object in the field. */
+	synchronized static boolean check(Field participantField) throws IllegalAccessException {
+		// perform class loading *outside* this synchronized method
+		if (!checked) {
+			checked = true;
+	
+			Object participant = participantField.get(null);
+	
+			if (PARTICIPANT_NAME != null) 
+			{
+				// initialized from property "ot.lifting.participant"
+				if (participant != null)
+					throw new IllegalStateException("liftingParticipant already installed.");
+				return true;
+			} 
+			else if (participant != null) 
+			{
+				// field was already initialized by a third party
+				
+				// fetch the class name to signal that transformations are needed.
+				PARTICIPANT_NAME = participant.getClass().getName();
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+		if (name.startsWith(LIFT_PREFIX)) {
+        	final MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, null, null);
+			return new InstructionAdapter(this.api, methodVisitor) {
+				private Label done = null;
+				@Override
+				public void visitTypeInsn(int opcode, String type) {
+					if (isRelevantAllocation(opcode, type))
+						insertParticipantSequence(type);
+					super.visitTypeInsn(opcode, type);
+				}
+				boolean isRelevantAllocation(int opcode, String type) {
+					return opcode == NEW
+							&& !(type.equals(LIFTING_FAILED_EXCEPTION)
+									|| type.equals(LIFTING_VETO_EXCEPTION)
+									|| type.equals(WRONG_ROLE_EXCEPTION));
+				}
+				void insertParticipantSequence(String roleType) {
+					// o = Team._OT$liftingParticipant.createRole(aTeam, aBase, roleType);
+					getstatic(TEAM_SLASH, LIFTING_PARTICIPANT_FIELD, 'L'+ILIFTING_PARTICIPANT+';');
+					visitVarInsn(ALOAD, 0); 	// team 			: Team
+					visitVarInsn(ALOAD, 1); 	// base				: Object
+					visitLdcInsn(roleType); 	// role class name	: String
+					invokeinterface(ILIFTING_PARTICIPANT, CREATE_ROLE_METHOD, CREATE_ROLE_DESC);
+		
+					// if (o != null)
+					dup();
+					Label doCreate = new Label(); 
+					ifnull(doCreate);
+					
+					// { ...
+					checkcast(Type.getObjectType(roleType));
+					done = new Label();
+					goTo(done);
+					
+					// } else {...
+					visitLabel(doCreate);
+					pop(); // discard unused DUP above
+					// ... continue with original role allocation...
+				}
+				@Override
+				public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+					super.visitMethodInsn(opcode, owner, name, desc, itf);
+					if (done != null && opcode == INVOKESPECIAL) { // is it the <init> invocation after the original "new"?
+						// }
+						visitLabel(done);
+						done = null;
+					}
+				}
+			};
+		}
+		return null;
+	}
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/LoaderAwareClassWriter.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/LoaderAwareClassWriter.java
new file mode 100644
index 0000000..4bcd275
--- /dev/null
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/bytecode/asm/LoaderAwareClassWriter.java
@@ -0,0 +1,67 @@
+/**********************************************************************
+ * This file is part of "Object Teams Development Tooling"-Software
+ * 
+ * Copyright 2014 GK Software AG
+ *  
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Please visit http://www.objectteams.org for updates and contact.
+ * 
+ * Contributors:
+ * 	Stephan Herrmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.objectteams.otredyn.bytecode.asm;
+
+import java.io.InputStream;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * Variant of its superclass which strictly avoids the use of Class.forName(),
+ * because that would by-pass our transformer, when invoked from within the transformer!
+ */
+public class LoaderAwareClassWriter extends ClassWriter {
+
+	// Only use as a resource loader!
+	private ClassLoader loader;
+
+	public LoaderAwareClassWriter(ClassReader reader, int computeFrames, ClassLoader loader) {
+		super(reader, computeFrames);
+		this.loader = loader;
+	}
+	
+	@Override
+	protected String getCommonSuperClass(String type1, String type2) {
+        try {
+    		InputStream s1 = this.loader.getResourceAsStream(type1+".class");
+    		InputStream s2 = this.loader.getResourceAsStream(type2+".class");
+        } catch (Exception e) {
+            throw new RuntimeException(e.toString());
+        }
+        // FIXME: analyse super types from the above streams!
+        // consider using (a copy of?) org.eclipse.objectteams.internal.osgi.weaving.ASMByteCodeAnalyzer
+        return type2;
+//        if (c.isAssignableFrom(d)) {
+//        	System.err.println("answer "+type1);
+//            return type1;
+//        }
+//        if (d.isAssignableFrom(c)) {
+//        	System.err.println("answer "+type2);
+//            return type2;
+//        }
+//        System.err.println("not assignable");
+//        if (c.isInterface() || d.isInterface()) {
+//            return "java/lang/Object";
+//        } else {
+//            do {
+//                c = c.getSuperclass();
+//            } while (!c.isAssignableFrom(d));
+//            return c.getName().replace('.', '/');
+//        }
+	}
+
+}
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
index b95dbce..bb57d19 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/jplis/ObjectTeamsTransformer.java
@@ -46,7 +46,7 @@
 	
 	public byte[] transform(ClassLoader loader, String className, String classId, Class<?> classBeingRedefined,
             byte[] classfileBuffer) {
-		if (!ObjectTeamsTransformer.isWeavable(className))
+		if (!ObjectTeamsTransformer.isWeavable(className) || loader == null)
 			return null;
 		
 		AbstractBoundClass clazz = ClassRepository.getInstance().getBoundClass(
diff --git a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
index 3a36580..a12c862 100644
--- a/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
+++ b/plugins/org.eclipse.objectteams.otredyn/src/org/eclipse/objectteams/otredyn/transformer/names/ClassNames.java
@@ -21,11 +21,15 @@
 

 import org.eclipse.objectteams.otredyn.runtime.TeamManager;

 import org.objectteams.IBoundBase2;

+import org.objectteams.ILiftingParticipant;

 import org.objectteams.ITeam;

 import org.objectteams.ImplicitTeamActivation;

+import org.objectteams.LiftingFailedException;

+import org.objectteams.LiftingVetoException;

 import org.objectteams.SneakyException;

 import org.objectteams.Team;

 import org.objectteams.TeamThreadManager;

+import org.objectteams.WrongRoleException;

 

 /**

  * Container for class names used in the bytecode manipulating classes

@@ -42,6 +46,10 @@
 	public final static String LIST_SLASH = List.class.getName().replace('.', '/');

 	public final static String HASH_SET_SLASH = HashSet.class.getName().replace('.', '/');

 	public final static String IMPLICIT_ACTIVATION = ImplicitTeamActivation.class.getName().replace('.', '/');

+	public final static String ILIFTING_PARTICIPANT = ILiftingParticipant.class.getName().replace('.', '/');

+	public static final String WRONG_ROLE_EXCEPTION = WrongRoleException.class.getName().replace('.', '/');

+	public static final String LIFTING_FAILED_EXCEPTION = LiftingFailedException.class.getName().replace('.', '/');

+	public static final String LIFTING_VETO_EXCEPTION = LiftingVetoException.class.getName().replace('.', '/');

 

 	public static final String SNEAKY_EXCEPTION_SLASH = SneakyException.class.getName().replace('.', '/');

 	// member of SneakyException:

diff --git a/plugins/org.eclipse.objectteams.runtime/META-INF/MANIFEST.MF b/plugins/org.eclipse.objectteams.runtime/META-INF/MANIFEST.MF
index 085ecbb..9152a3c 100644
--- a/plugins/org.eclipse.objectteams.runtime/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.objectteams.runtime/META-INF/MANIFEST.MF
@@ -2,11 +2,11 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.objectteams.runtime
-Bundle-Version: 2.3.0.qualifier
+Bundle-Version: 2.3.1.qualifier
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
-Export-Package: org.objectteams;version="2.3.0",
- org.eclipse.objectteams.otredyn.runtime;version="2.3.0"
+Export-Package: org.objectteams;version="2.3.1",
+ org.eclipse.objectteams.otredyn.runtime;version="2.3.1"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Bundle-ClassPath: .
 
diff --git a/releng/build-scripts/bin/addDownloadStats.xsl b/releng/build-scripts/bin/addDownloadStats.xsl
index c2ae269..4967a89 100644
--- a/releng/build-scripts/bin/addDownloadStats.xsl
+++ b/releng/build-scripts/bin/addDownloadStats.xsl
@@ -43,6 +43,10 @@
                 <xsl:call-template name="artifact_properties"/>
         </xsl:template>
 
+        <xsl:template match="artifact[@classifier='org.eclipse.update.feature' and @id='org.eclipse.objectteams.otequinox.turbo']/properties">
+                <xsl:call-template name="artifact_properties"/>
+        </xsl:template>
+
         <xsl:template name="artifact_properties">
                 <properties size='{@size+1}'>
                         <xsl:copy-of select="property" />
diff --git a/releng/build-scripts/build/OTDT-Build/allElements.xml b/releng/build-scripts/build/OTDT-Build/allElements.xml
index 8dcbbdd..f166213 100644
--- a/releng/build-scripts/build/OTDT-Build/allElements.xml
+++ b/releng/build-scripts/build/OTDT-Build/allElements.xml
@@ -27,6 +27,11 @@
 			<property name="id" value="org.eclipse.objectteams.otequinox" />
 		</ant>
 
+ 		<ant antfile="${genericTargets}" target="${target}" >
+			<property name="type" value="feature" />
+			<property name="id" value="org.eclipse.objectteams.otequinox.turbo" />
+		</ant>
+
 		<ant antfile="${genericTargets}" target="${target}" >
 			<property name="type" value="feature" />
 			<property name="id" value="org.eclipse.objectteams.otdt" />
@@ -92,6 +97,14 @@
 		</ant>
  	</target>
 	
+	<!-- set output repository for otequinox.turbo.feature: -->
+	<property name="assemble.org.eclipse.objectteams.otequinox.turbo.p2" value="true" />
+ 	<target   name="assemble.org.eclipse.objectteams.otequinox.turbo.p2">
+        <ant antfile="${assembleScriptName}" dir="${buildDirectory}">
+			<property name="p2.build.repo" value="file://${otdtUpdatesDir}"/>
+		</ant>
+ 	</target>
+	
 	<!-- set output repository for otdt.feature: -->
 	<property name="assemble.org.eclipse.objectteams.otdt.p2" value="true" />
     <target   name="assemble.org.eclipse.objectteams.otdt.p2">
diff --git a/releng/build-scripts/build/otdt_prerequisites.sh b/releng/build-scripts/build/otdt_prerequisites.sh
index 1f7152b..f9d64ac 100644
--- a/releng/build-scripts/build/otdt_prerequisites.sh
+++ b/releng/build-scripts/build/otdt_prerequisites.sh
@@ -68,5 +68,5 @@
 ECLIPSE_TESTLIB_ZIP=${DROP}/eclipse-test-framework-${EVERSION}.zip
 
 # EXPORT: where to find previously published plugins&features:
-PUBLISHED_UPDATES=${HOME}/downloads/objectteams/updates/ot2.2
+PUBLISHED_UPDATES=${HOME}/downloads/objectteams/updates/ot2.3
 
diff --git a/releng/build-scripts/build/p2helper.xml b/releng/build-scripts/build/p2helper.xml
index 1874100..dd32c6c 100644
--- a/releng/build-scripts/build/p2helper.xml
+++ b/releng/build-scripts/build/p2helper.xml
@@ -56,6 +56,12 @@
             <param name="sourceUpdatesDir" value="${otdtUpdatesDir}"/>
             <param name="targetEclipseDir" value="${test.eclipseDir}"/>
         </antcall>
+		<!-- optional: -->
+	    <antcall target="installFeature">
+	        <param name="feature" value="org.eclipse.objectteams.otequinox.turbo.feature.group"/>
+	        <param name="sourceUpdatesDir" value="${otdtUpdatesDir}"/>
+	        <param name="targetEclipseDir" value="${test.eclipseDir}"/>
+	    </antcall>
         <antcall target="installFeature">
             <param name="feature" value="org.eclipse.objectteams.otdt.feature.group"/>
             <param name="sourceUpdatesDir" value="${otdtUpdatesDir}"/>
diff --git a/releng/map/otdt.map.in b/releng/map/otdt.map.in
index 8fc0351..6348280 100644
--- a/releng/map/otdt.map.in
+++ b/releng/map/otdt.map.in
@@ -23,7 +23,8 @@
 plugin@org.eclipse.objectteams.otredyn=GIT,repo=git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,path=plugins/org.eclipse.objectteams.otredyn

 !the following is also referenced in otdt.doc/buildDoc.xml (plugin-name without version):

 plugin@org.eclipse.objectteams.otequinox=GIT,repo=git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,path=plugins/org.eclipse.objectteams.otequinox

-plugin@org.eclipse.objectteams.eclipse.monitor=GIT,repo=git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,path=plugins/org.eclipse.objectteams.eclipse.monitor

+fragment@org.eclipse.objectteams.otequinox.turbo=GIT,repo=git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,path=plugins/org.eclipse.objectteams.otequinox.turbo

+plugin@org.eclipse.objectteams.eclipse.monitor=GIT,repo=git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,path=plugins/org.eclipse.objectteams.eclipse.monitor
 

 !not currently maintained:

 !plugin@org.eclipse.objectteams.otdt.earlyui=GIT,repo=git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,path=plugins/org.eclipse.objectteams.otdt.earlyui

diff --git a/releng/map/otdt.psf b/releng/map/otdt.psf
index 2391aab..f08cd7d 100644
--- a/releng/map/otdt.psf
+++ b/releng/map/otdt.psf
@@ -19,8 +19,10 @@
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.otdt.ui"/>
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.otdt.ui.help"/>
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.otequinox"/>
+<project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.otequinox.turbo"/>
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.otequinox.branding"/>
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,features/org.eclipse.objectteams.otequinox.feature"/>
+<project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,features/org.eclipse.objectteams.otequinox.turbo.feature"/>
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.otre"/>
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.otredyn"/>
 <project reference="1.0,git://git.eclipse.org/gitroot/objectteams/org.eclipse.objectteams.git,master,plugins/org.eclipse.objectteams.runtime"/>