Add package-level documentation referencing the guide. am: 52c473f
am: 84dc2cd

* commit '84dc2cd14c86ca635e28ef140bdf329fea3737f9':
  Add package-level documentation referencing the guide.

Change-Id: I30296ce9006248c0f4fcae725ba087942bcf3998
diff --git a/.gitignore b/.gitignore
index 448ab8f..3093115 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,7 @@
 .gradle
 maven-repo
 .caches
+*.DS_Store
+.idea/workspace.xml
+.idea/libraries
+.idea/modules
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..9e84af0
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+data-binding
\ No newline at end of file
diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
new file mode 100755
index 0000000..003973d
--- /dev/null
+++ b/.idea/codeStyleSettings.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectCodeStyleSettingsManager">
+    <option name="PER_PROJECT_SETTINGS">
+      <value>
+        <option name="LINE_SEPARATOR" value="&#10;" />
+        <option name="FIELD_NAME_PREFIX" value="m" />
+        <option name="STATIC_FIELD_NAME_PREFIX" value="m" />
+        <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+        <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+        <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+          <value />
+        </option>
+        <option name="IMPORT_LAYOUT_TABLE">
+          <value>
+            <package name="android" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="com" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="junit" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="net" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="org" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="java" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="javax" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="" withSubpackages="true" static="true" />
+            <emptyLine />
+          </value>
+        </option>
+        <option name="RIGHT_MARGIN" value="100" />
+        <option name="JD_P_AT_EMPTY_LINES" value="false" />
+        <option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
+        <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
+        <option name="JD_KEEP_EMPTY_RETURN" value="false" />
+        <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+        <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+        <option name="BLANK_LINES_AROUND_FIELD" value="1" />
+        <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
+        <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+        <option name="ALIGN_MULTILINE_FOR" value="false" />
+        <option name="CALL_PARAMETERS_WRAP" value="1" />
+        <option name="METHOD_PARAMETERS_WRAP" value="1" />
+        <option name="EXTENDS_LIST_WRAP" value="1" />
+        <option name="THROWS_LIST_WRAP" value="1" />
+        <option name="EXTENDS_KEYWORD_WRAP" value="1" />
+        <option name="THROWS_KEYWORD_WRAP" value="1" />
+        <option name="METHOD_CALL_CHAIN_WRAP" value="1" />
+        <option name="BINARY_OPERATION_WRAP" value="1" />
+        <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
+        <option name="TERNARY_OPERATION_WRAP" value="1" />
+        <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
+        <option name="FOR_STATEMENT_WRAP" value="1" />
+        <option name="ARRAY_INITIALIZER_WRAP" value="1" />
+        <option name="ASSIGNMENT_WRAP" value="1" />
+        <option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
+        <option name="WRAP_COMMENTS" value="true" />
+        <option name="IF_BRACE_FORCE" value="3" />
+        <option name="DOWHILE_BRACE_FORCE" value="3" />
+        <option name="WHILE_BRACE_FORCE" value="3" />
+        <option name="FOR_BRACE_FORCE" value="3" />
+        <GroovyCodeStyleSettings>
+          <option name="USE_FQ_CLASS_NAMES_IN_JAVADOC" value="false" />
+          <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+          <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+          <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+            <value />
+          </option>
+          <option name="IMPORT_LAYOUT_TABLE">
+            <value>
+              <package name="" withSubpackages="true" static="false" />
+              <emptyLine />
+              <package name="javax" withSubpackages="true" static="false" />
+              <package name="java" withSubpackages="true" static="false" />
+              <emptyLine />
+              <package name="" withSubpackages="true" static="true" />
+              <emptyLine />
+            </value>
+          </option>
+        </GroovyCodeStyleSettings>
+        <JetCodeStyleSettings>
+          <option name="PACKAGES_TO_USE_STAR_IMPORTS">
+            <value>
+              <package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
+            </value>
+          </option>
+          <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
+          <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
+        </JetCodeStyleSettings>
+        <XML>
+          <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
+        </XML>
+        <codeStyleSettings language="Groovy">
+          <option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
+          <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+          <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+          <option name="BLANK_LINES_AROUND_FIELD" value="1" />
+          <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
+          <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+          <option name="ALIGN_MULTILINE_FOR" value="false" />
+          <option name="CALL_PARAMETERS_WRAP" value="1" />
+          <option name="METHOD_PARAMETERS_WRAP" value="1" />
+          <option name="EXTENDS_LIST_WRAP" value="1" />
+          <option name="THROWS_LIST_WRAP" value="1" />
+          <option name="EXTENDS_KEYWORD_WRAP" value="1" />
+          <option name="THROWS_KEYWORD_WRAP" value="1" />
+          <option name="METHOD_CALL_CHAIN_WRAP" value="1" />
+          <option name="BINARY_OPERATION_WRAP" value="1" />
+          <option name="TERNARY_OPERATION_WRAP" value="1" />
+          <option name="FOR_STATEMENT_WRAP" value="1" />
+          <option name="ASSIGNMENT_WRAP" value="1" />
+          <option name="IF_BRACE_FORCE" value="3" />
+          <option name="WHILE_BRACE_FORCE" value="3" />
+          <option name="FOR_BRACE_FORCE" value="3" />
+          <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+        </codeStyleSettings>
+        <codeStyleSettings language="JAVA">
+          <option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
+          <option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
+          <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+          <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+          <option name="BLANK_LINES_AROUND_FIELD" value="1" />
+          <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
+          <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+          <option name="ALIGN_MULTILINE_FOR" value="false" />
+          <option name="CALL_PARAMETERS_WRAP" value="1" />
+          <option name="METHOD_PARAMETERS_WRAP" value="1" />
+          <option name="EXTENDS_LIST_WRAP" value="1" />
+          <option name="THROWS_LIST_WRAP" value="1" />
+          <option name="EXTENDS_KEYWORD_WRAP" value="1" />
+          <option name="THROWS_KEYWORD_WRAP" value="1" />
+          <option name="METHOD_CALL_CHAIN_WRAP" value="1" />
+          <option name="BINARY_OPERATION_WRAP" value="1" />
+          <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
+          <option name="TERNARY_OPERATION_WRAP" value="1" />
+          <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
+          <option name="FOR_STATEMENT_WRAP" value="1" />
+          <option name="ARRAY_INITIALIZER_WRAP" value="1" />
+          <option name="ASSIGNMENT_WRAP" value="1" />
+          <option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
+          <option name="IF_BRACE_FORCE" value="3" />
+          <option name="DOWHILE_BRACE_FORCE" value="3" />
+          <option name="WHILE_BRACE_FORCE" value="3" />
+          <option name="FOR_BRACE_FORCE" value="3" />
+          <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+        </codeStyleSettings>
+        <codeStyleSettings language="JSON">
+          <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+          <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+        </codeStyleSettings>
+      </value>
+    </option>
+    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
+  </component>
+</project>
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..96cc43e
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <resourceExtensions />
+    <wildcardResourcePatterns>
+      <entry name="!?*.java" />
+      <entry name="!?*.form" />
+      <entry name="!?*.class" />
+      <entry name="!?*.groovy" />
+      <entry name="!?*.scala" />
+      <entry name="!?*.flex" />
+      <entry name="!?*.kt" />
+      <entry name="!?*.clj" />
+      <entry name="!?*.aj" />
+    </wildcardResourcePatterns>
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="false">
+        <processorPath useClasspath="true" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/copyright/aosp.xml b/.idea/copyright/aosp.xml
new file mode 100644
index 0000000..077aec6
--- /dev/null
+++ b/.idea/copyright/aosp.xml
@@ -0,0 +1,9 @@
+<component name="CopyrightManager">
+  <copyright>
+    <option name="notice" value="Copyright (C) &amp;#36;today.year The Android Open Source Project&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;     http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
+    <option name="keyword" value="Copyright" />
+    <option name="allowReplaceKeyword" value="" />
+    <option name="myName" value="aosp" />
+    <option name="myLocal" value="true" />
+  </copyright>
+</component>
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..fc5a2c3
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,7 @@
+<component name="CopyrightManager">
+  <settings default="">
+    <module2copyright>
+      <element module="All" copyright="aosp" />
+    </module2copyright>
+  </settings>
+</component>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..97626ba
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="PROJECT" charset="UTF-8" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..c9e59e1
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="gradleJvm" value="1.6" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/baseLibrary" />
+            <option value="$PROJECT_DIR$/compilationTests" />
+            <option value="$PROJECT_DIR$/compiler" />
+            <option value="$PROJECT_DIR$/compilerCommon" />
+            <option value="$PROJECT_DIR$/dataBinding" />
+          </set>
+        </option>
+        <option name="useAutoImport" value="true" />
+        <option name="myModules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/baseLibrary" />
+            <option value="$PROJECT_DIR$/compilationTests" />
+            <option value="$PROJECT_DIR$/compiler" />
+            <option value="$PROJECT_DIR$/compilerCommon" />
+            <option value="$PROJECT_DIR$/dataBinding" />
+          </set>
+        </option>
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..caac652
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="EntryPointsManager">
+    <entry_points version="2.0" />
+  </component>
+  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
+    <OptionsSetting value="true" id="Add" />
+    <OptionsSetting value="true" id="Remove" />
+    <OptionsSetting value="true" id="Checkout" />
+    <OptionsSetting value="true" id="Update" />
+    <OptionsSetting value="true" id="Status" />
+    <OptionsSetting value="true" id="Edit" />
+    <ConfirmationsSetting value="0" id="Add" />
+    <ConfirmationsSetting value="0" id="Remove" />
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" default="false" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/classes" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..7eefe60
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/baseLibrary/baseLibrary.iml" filepath="$PROJECT_DIR$/baseLibrary/baseLibrary.iml" />
+      <module fileurl="file://$PROJECT_DIR$/compilationTests/compilationTests.iml" filepath="$PROJECT_DIR$/compilationTests/compilationTests.iml" />
+      <module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
+      <module fileurl="file://$PROJECT_DIR$/compilerCommon/compilerCommon.iml" filepath="$PROJECT_DIR$/compilerCommon/compilerCommon.iml" />
+      <module fileurl="file://$PROJECT_DIR$/data-binding.iml" filepath="$PROJECT_DIR$/data-binding.iml" />
+      <module fileurl="file://$PROJECT_DIR$/dataBinding/dataBinding.iml" filepath="$PROJECT_DIR$/dataBinding/dataBinding.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/baseLibrary/baseLibrary.iml b/baseLibrary/baseLibrary.iml
new file mode 100644
index 0000000..c6163c1
--- /dev/null
+++ b/baseLibrary/baseLibrary.iml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":dataBinding:baseLibrary" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="com.android.databinding" external.system.module.version="1.1" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build/classes/main" />
+    <output-test url="file://$MODULE_DIR$/build/classes/test" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/baseLibrary/build.gradle b/baseLibrary/build.gradle
index 241e4a8..7489e0d 100644
--- a/baseLibrary/build.gradle
+++ b/baseLibrary/build.gradle
@@ -15,10 +15,9 @@
  */
 
 apply plugin: 'java'
-apply plugin: 'application'
 
-sourceCompatibility = config.javaTargetCompatibility
-targetCompatibility = config.javaSourceCompatibility
+sourceCompatibility = dataBindingConfig.javaTargetCompatibility
+targetCompatibility = dataBindingConfig.javaSourceCompatibility
 
 sourceSets {
     main {
@@ -37,25 +36,6 @@
     testCompile 'junit:junit:4.12'
 }
 
-def javadocTask = project.tasks.create(name: "javadocBaseLibrary", type: Javadoc) {
-    source sourceSets.main.allJava
-}
-
-def javadocJarTask = project.tasks.create(name: "javadocJarBaseLibrary", type: Jar) {
-    classifier = 'javadoc'
-    from 'build/docs/javadoc'
-}
-javadocJarTask.dependsOn javadocTask
-
-def sourcesJarTask = project.tasks.create(name: "sourceJarBaseLibrary", type: Jar) {
-    classifier = 'sources'
-    from sourceSets.main.java.srcDirs
-}
-
-artifacts.add('archives', javadocJarTask);
-artifacts.add('archives', sourcesJarTask);
-
-
 uploadArchives {
     repositories {
         mavenDeployer {
@@ -63,9 +43,9 @@
             pom.project {
                 licenses {
                     license {
-                        name config.licenseName
-                        url config.licenseUrl
-                        distribution config.licenseDistribution
+                        name dataBindingConfig.licenseName
+                        url dataBindingConfig.licenseUrl
+                        distribution dataBindingConfig.licenseDistribution
                     }
                 }
             }
@@ -76,8 +56,12 @@
 task prebuildJar(type : Copy) {
     dependsOn uploadArchives
     from "$buildDir/libs/baseLibrary-${version}.jar"
-    into config.prebuildFolder
+    into dataBindingConfig.prebuildFolder
     rename { String fileName ->
         "databinding-baseLibrary.jar"
     }
-}
\ No newline at end of file
+}
+
+project.ext.pomName = 'Data Binding Base Library'
+project.ext.pomDesc = 'Shared library between Data Binding runtime lib and compiler'
+enablePublishing(this, true)
\ No newline at end of file
diff --git a/baseLibrary/db-baseLibrary.iml b/baseLibrary/db-baseLibrary.iml
new file mode 100644
index 0000000..7cf9983
--- /dev/null
+++ b/baseLibrary/db-baseLibrary.iml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../out/build/dataBinding/baseLibrary/build" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+  </component>
+</module>
\ No newline at end of file
diff --git a/baseLibrary/src/main/java/android/databinding/BindingAdapter.java b/baseLibrary/src/main/java/android/databinding/BindingAdapter.java
index 09bc482..7409d02 100644
--- a/baseLibrary/src/main/java/android/databinding/BindingAdapter.java
+++ b/baseLibrary/src/main/java/android/databinding/BindingAdapter.java
@@ -72,4 +72,17 @@
      * @return The attributes associated with this binding adapter.
      */
     String[] value();
+
+    /**
+     * Whether every attribute must be assigned a binding expression or if some
+     * can be absent. When this is false, the BindingAdapter will be called
+     * when at least one associated attribute has a binding expression. The attributes
+     * for which there was no binding expression (even a normal XML value) will
+     * cause the associated parameter receive the Java default value. Care must be
+     * taken to ensure that a default value is not confused with a valid XML value.
+     *
+     * @return whether or not every attribute must be assigned a binding expression. The default
+     *         value is true.
+     */
+    boolean requireAll() default true;
 }
diff --git a/baseLibrary/src/main/java/android/databinding/BindingMethod.java b/baseLibrary/src/main/java/android/databinding/BindingMethod.java
index 3585c0c..d96b930 100644
--- a/baseLibrary/src/main/java/android/databinding/BindingMethod.java
+++ b/baseLibrary/src/main/java/android/databinding/BindingMethod.java
@@ -15,11 +15,15 @@
  */
 package android.databinding;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
 /**
  * Used within an {@link BindingMethods} annotation to describe a renaming of an attribute to
  * the setter used to set that attribute. By default, an attribute attr will be associated with
  * setter setAttr.
  */
+@Target(ElementType.ANNOTATION_TYPE)
 public @interface BindingMethod {
 
     /**
diff --git a/baseLibrary/src/main/java/android/databinding/InverseBindingAdapter.java b/baseLibrary/src/main/java/android/databinding/InverseBindingAdapter.java
new file mode 100644
index 0000000..0ac85ec
--- /dev/null
+++ b/baseLibrary/src/main/java/android/databinding/InverseBindingAdapter.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * InverseBindingAdapter is associated with a method used to retrieve the value for a View
+ * when setting values gathered from the View. This is similar to {@link BindingAdapter}s:
+ * <pre>
+ * &commat;InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
+ * public static String captureTextValue(TextView view, CharSequence originalValue) {
+ *     CharSequence newValue = view.getText();
+ *     CharSequence oldValue = value.get();
+ *     if (oldValue == null) {
+ *         value.set(newValue);
+ *     } else if (!contentEquals(newValue, oldValue)) {
+ *         value.set(newValue);
+ *     }
+ * }
+ * </pre>
+ * <p>
+ * The default value for event is the attribute name suffixed with "AttrChanged". In the
+ * above example, the default value would have been <code>android:textAttrChanged</code> even
+ * if it wasn't provided.
+ * <p>
+ * The event attribute is used to notify the data binding system that the value has changed.
+ * The developer will typically create a {@link BindingAdapter} to assign the event. For example:
+ * <p>
+ * <pre>
+ * &commat;BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
+ *                          "android:afterTextChanged", "android:textAttrChanged"},
+ *                          requireAll = false)
+ * public static void setTextWatcher(TextView view, final BeforeTextChanged before,
+ *                                   final OnTextChanged on, final AfterTextChanged after,
+ *                                   final InverseBindingListener textAttrChanged) {
+ *     TextWatcher newValue = new TextWatcher() {
+ *         ...
+ *         &commat;Override
+ *         public void onTextChanged(CharSequence s, int start, int before, int count) {
+ *             if (on != null) {
+ *                 on.onTextChanged(s, start, before, count);
+ *             }
+ *             if (textAttrChanged != null) {
+ *                 textAttrChanged.onChange();
+ *             }
+ *         }
+ *     }
+ *     TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
+ *     if (oldValue != null) {
+ *         view.removeTextChangedListener(oldValue);
+ *     }
+ *     view.addTextChangedListener(newValue);
+ * }
+ * </pre>
+ * <p>
+ * Like <code>BindingAdapter</code>s, InverseBindingAdapter methods may also take
+ * {@link DataBindingComponent} as the first parameter and may be an instance method with the
+ * instance retrieved from the <code>DataBindingComponent</code>.
+ *
+ * @see DataBindingUtil#setDefaultComponent(DataBindingComponent)
+ * @see InverseBindingMethod
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+public @interface InverseBindingAdapter {
+
+    /**
+     * The attribute that the value is to be retrieved for.
+     */
+    String attribute();
+
+    /**
+     * The event used to trigger changes. This is used in {@link BindingAdapter}s for the
+     * data binding system to set the event listener when two-way binding is used.
+     */
+    String event() default "";
+}
diff --git a/baseLibrary/src/main/java/android/databinding/InverseBindingListener.java b/baseLibrary/src/main/java/android/databinding/InverseBindingListener.java
new file mode 100644
index 0000000..ec5e6dd
--- /dev/null
+++ b/baseLibrary/src/main/java/android/databinding/InverseBindingListener.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding;
+
+/**
+ * A listener implemented by all two-way bindings to be notified when a triggering change happens.
+ * For example, when there is a two-way binding for android:text, an implementation of
+ * <code>InverseBindingListener</code> will be generated in the layout's binding class.
+ * <pre>
+ * private static class InverseListenerTextView implements InverseBindingListener {
+ *     &commat;Override
+ *     public void onChange() {
+ *         mObj.setTextValue(mTextView.getText());
+ *     }
+ * }
+ * </pre>
+ * <p>
+ * A {@link BindingAdapter} should be used to assign the event listener.
+ * For example, <code>android:onTextChanged</code> will need to trigger the event listener
+ * for the <code>android:text</code> attribute.
+ * <pre>
+ * &commat;InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
+ * public static void captureTextValue(TextView view, ObservableField&lt;CharSequence> value) {
+ *     CharSequence newValue = view.getText();
+ *     CharSequence oldValue = value.get();
+ *     if (oldValue == null) {
+ *         value.set(newValue);
+ *     } else if (!contentEquals(newValue, oldValue)) {
+ *         value.set(newValue);
+ *     }
+ * }
+ * &commat;BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
+ *                          "android:afterTextChanged", "android:textAttrChanged"},
+ *                          requireAll = false)
+ * public static void setTextWatcher(TextView view, final BeforeTextChanged before,
+ *                                   final OnTextChanged on, final AfterTextChanged after,
+ *                                   final InverseBindingListener textAttrChanged) {
+ *     TextWatcher newValue = new TextWatcher() {
+ *         ...
+ *         &commat;Override
+ *         public void onTextChanged(CharSequence s, int start, int before, int count) {
+ *             if (on != null) {
+ *                 on.onTextChanged(s, start, before, count);
+ *             }
+ *             if (textAttrChanged != null) {
+ *                 textAttrChanged.onChange();
+ *             }
+ *         }
+ *     }
+ *     TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
+ *     if (oldValue != null) {
+ *         view.removeTextChangedListener(oldValue);
+ *     }
+ *     view.addTextChangedListener(newValue);
+ * }
+ * </pre>
+ */
+public interface InverseBindingListener {
+    /**
+     * Notifies the data binding system that the attribute value has changed.
+     */
+    void onChange();
+}
diff --git a/baseLibrary/src/main/java/android/databinding/InverseBindingMethod.java b/baseLibrary/src/main/java/android/databinding/InverseBindingMethod.java
new file mode 100644
index 0000000..5f5c0d9
--- /dev/null
+++ b/baseLibrary/src/main/java/android/databinding/InverseBindingMethod.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * InverseBindingMethod is used to identify how to listen for changes to a View property and which
+ * getter method to call. InverseBindingMethod should be associated with any class as part of
+ * {@link InverseBindingMethods}.
+ * <p>
+ * <pre>
+ * &commat;InverseBindingMethods({&commat;InverseBindingMethod(
+ *     type = android.widget.TextView.class,
+ *     attribute = "android:text",
+ *     event = "android:textAttrChanged",
+ *     method = "getText")})
+ * public class MyTextViewBindingAdapters { ... }
+ * </pre>
+ * <p>
+ * <code>method</code> is optional. If it isn't provided, the attribute name is used to
+ * find the method name, either prefixing with "is" or "get". For the attribute
+ * <code>android:text</code>, data binding will search for a
+ * <code>public CharSequence getText()</code> method on {@link android.widget.TextView}.
+ * <p>
+ * <code>event</code> is optional. If it isn't provided, the event name is assigned the
+ * attribute name suffixed with <code>AttrChanged</code>. For the <code>android:text</code>
+ * attribute, the default event name would be <code>android:textAttrChanged</code>. The event
+ * should be set using a {@link BindingAdapter}. For example:
+ * <pre>
+ * &commat;BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
+ *                          "android:afterTextChanged", "android:textAttrChanged"},
+ *                          requireAll = false)
+ * public static void setTextWatcher(TextView view, final BeforeTextChanged before,
+ *                                   final OnTextChanged on, final AfterTextChanged after,
+ *                                   final InverseBindingListener textAttrChanged) {
+ *     TextWatcher newValue = new TextWatcher() {
+ *         ...
+ *         &commat;Override
+ *         public void onTextChanged(CharSequence s, int start, int before, int count) {
+ *             if (on != null) {
+ *                 on.onTextChanged(s, start, before, count);
+ *             }
+ *             if (textAttrChanged != null) {
+ *                 textAttrChanged.onChange();
+ *             }
+ *         }
+ *     }
+ *     TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
+ *     if (oldValue != null) {
+ *         view.removeTextChangedListener(oldValue);
+ *     }
+ *     view.addTextChangedListener(newValue);
+ * }
+ * </pre>
+ *
+ * @see InverseBindingAdapter
+ * @see InverseBindingListener
+ */
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface InverseBindingMethod {
+
+    /**
+     * The View type that is associated with the attribute.
+     */
+    Class type();
+
+    /**
+     * The attribute that supports two-way binding.
+     */
+    String attribute();
+
+    /**
+     * The event used to notify the data binding system that the attribute value has changed.
+     * Defaults to attribute() + "AttrChanged"
+     */
+    String event() default "";
+
+    /**
+     * The getter method to retrieve the attribute value from the View. The default is
+     * the bean method name based on the attribute name.
+     */
+    String method() default "";
+}
diff --git a/developmentPlugins/bintrayPlugin/build.gradle b/baseLibrary/src/main/java/android/databinding/InverseBindingMethods.java
similarity index 63%
rename from developmentPlugins/bintrayPlugin/build.gradle
rename to baseLibrary/src/main/java/android/databinding/InverseBindingMethods.java
index 364a5bb..29e2374 100644
--- a/developmentPlugins/bintrayPlugin/build.gradle
+++ b/baseLibrary/src/main/java/android/databinding/InverseBindingMethods.java
@@ -13,22 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-apply plugin: 'groovy'
+package android.databinding;
 
-repositories {
-    mavenCentral()
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Used to enumerate attribute, getter, and event association. The value is an array of
+ * {@link InverseBindingMethod}s.
+ */
+@Target(ElementType.TYPE)
+public @interface InverseBindingMethods {
+    InverseBindingMethod[] value();
 }
-
-dependencies {
-    compile gradleApi()
-    testCompile group: 'junit', name: 'junit', version: '4.12'
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            pom.artifactId = 'bintray'
-            repository(url: "file://${config.extraPluginsRepoDir}")
-        }
-    }
-}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index acf68f4..c33a72c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,67 +1,83 @@
+import groovy.xml.QName
 
 buildscript {
-    ext.rootFolder = project.projectDir
+    ext.dataBindingRootFolder = project.projectDir
     apply from: 'propLoader.gradle'
     ext.addRepos(repositories)
-    if (ext.config.addRemoteRepos) {
+    if (ext.dataBindingConfig.addRemoteRepos) {
         dependencies {
-            classpath "com.android.databinding:localizemaven:${config.extraPluginsVersion}"
+            classpath "com.android.databinding:localizemaven:${dataBindingConfig.extraPluginsVersion}"
         }
     }
+    dependencies {
+        classpath 'net.sf.proguard:proguard-gradle:5.2.1'
+    }
 }
+
 subprojects {
-    apply plugin: 'maven'
-    if (config.addRemoteRepos) {
-        apply plugin: 'com.android.databinding.localizemaven'
+    if (dataBindingConfig.isIndependent) {
+        apply plugin: 'maven'
+        if (dataBindingConfig.addRemoteRepos && !dataBindingConfig.forGradlePlugin) {
+            apply plugin: 'com.android.databinding.localizemaven'
+        }
+    } else {
+        apply from: "${project.projectDir}/../../buildSrc/base/baseJava.gradle"
     }
 
-    group = config.group
-    version = config.version
-    uploadArchives {
-        repositories {
-            mavenDeployer {
-                repository(url: "file://${config.mavenRepoDir}")
+    if (it.name != "compilationTests") {
+        group = dataBindingConfig.group
+        version = dataBindingConfig.version
+        uploadArchives {
+            repositories {
+                mavenDeployer {
+                    repository(url: "file://${dataBindingConfig.mavenRepoDir}")
+                }
             }
         }
     }
+
     buildscript {
         addRepos(repositories)
-        dependencies {
-            classpath "com.android.databinding:bintray:${config.extraPluginsVersion}"
-        }
     }
+
 }
 
-if (config.addRemoteRepos) {
-    localizeMaven {
-        localRepoDir = file(config.megaRepoDir)
-        otherRepoDirs = config.localRepositories
+if (dataBindingConfig.addRemoteRepos && !dataBindingConfig.forGradlePlugin) {
+    rootProject.localizeMaven {
+        localRepoDir = file(dataBindingConfig.megaRepoDir)
+        otherRepoDirs = dataBindingConfig.localRepositories
     }
 }
 
 task deleteRepo(type: Delete) {
-    delete "${config.mavenRepoDir}/${config.group.replace('.', '/')}"
+    delete "${dataBindingConfig.mavenRepoDir}/${dataBindingConfig.group.replace('.', '/')}"
 }
 
 task deletePrebuildFolder(type: Delete) {
-    delete "${config.prebuildFolder}"
+    delete "${dataBindingConfig.prebuildFolder}"
 }
 
 task deleteEap(type: Delete) {
-    delete "${config.eapOutDir}"
+    delete "${dataBindingConfig.eapOutDir}"
 }
 
 
 def buildExtensionsTask = project.tasks.create "buildExtensionsTask", Exec
 buildExtensionsTask.workingDir file('extensions').getAbsolutePath()
 buildExtensionsTask.commandLine './gradlew'
-buildExtensionsTask.args 'clean', 'uploadArchives', '--info', '--stacktrace'
+buildExtensionsTask.args 'clean', 'uploadArchives', '--info', '--stacktrace',
+        "-PuseReleaseVersion=${dataBindingConfig.inReleaseBuild ? 'true' : 'false'}",
+        "-PaddRemoteRepos=${dataBindingConfig.addRemoteRepos ? 'true' : 'false'}",
+        "-PforGradlePlugin=${dataBindingConfig.forGradlePlugin ? 'true' : 'false'}"
 buildExtensionsTask.dependsOn subprojects.uploadArchives
 
 def prepareExtensionPrebuilds = project.tasks.create "prepareExtensionPrebuilds", Exec
 prepareExtensionPrebuilds.workingDir file('extensions').getAbsolutePath()
 prepareExtensionPrebuilds.commandLine './gradlew'
-prepareExtensionPrebuilds.args 'clean', 'preparePrebuilds', '--info', '--stacktrace'
+prepareExtensionPrebuilds.args 'clean', 'preparePrebuilds', '--info', '--stacktrace',
+        "-PuseReleaseVersion=${dataBindingConfig.inReleaseBuild ? 'true' : 'false'}",
+        "-PaddRemoteRepos=${dataBindingConfig.addRemoteRepos ? 'true' : 'false'}",
+        "-PforGradlePlugin=${dataBindingConfig.forGradlePlugin ? 'true' : 'false'}"
 prepareExtensionPrebuilds.dependsOn subprojects.uploadArchives
 
 file('integration-tests').listFiles().findAll { it.isDirectory() }.each {
@@ -70,9 +86,11 @@
     testTask.workingDir it.getAbsolutePath()
     //on linux
     testTask.commandLine './gradlew'
-    testTask.args 'clean', 'connectedCheck', '--info', '--stacktrace'
+    testTask.args 'clean', 'connectedCheck', '--info', '--stacktrace',
+            "-PuseReleaseVersion=${dataBindingConfig.inReleaseBuild ? 'true' : 'false'}",
+            "-PaddRemoteRepos=${dataBindingConfig.addRemoteRepos ? 'true' : 'false'}",
+            "-PforGradlePlugin=${dataBindingConfig.forGradlePlugin ? 'true' : 'false'}"
     testTask.dependsOn subprojects.uploadArchives
-    testTask.dependsOn buildExtensionsTask
 }
 
 task runIntegrationTests {
@@ -98,6 +116,7 @@
 
 subprojects.uploadArchives.each { it.shouldRunAfter deleteRepo  }
 subprojects.uploadArchives.each { it.shouldRunAfter deletePrebuildFolder  }
+
 buildExtensionsTask.shouldRunAfter deleteRepo
 tasks['runTestsOfMultiModuleTestApp'].dependsOn tasks['runTestsOfIndependentLibrary']
 
@@ -105,7 +124,6 @@
 task rebuildRepo() {
     dependsOn deleteRepo
     dependsOn subprojects.uploadArchives
-    dependsOn buildExtensionsTask
 }
 
 task copySamplesToEap(type : Copy) {
@@ -114,29 +132,161 @@
         exclude "**/build"
         exclude "**/local.properties"
     }
-    into "${config.eapOutDir}/samples"
+    into "${dataBindingConfig.eapOutDir}/samples"
 }
 
 
 task copyMavenRepoToEap(type : Copy) {
     mustRunAfter deleteEap
     dependsOn rebuildRepo
-    from(config.mavenRepoDir)
-    into "${config.eapOutDir}/${config.mavenRepoName}"
+    from(dataBindingConfig.mavenRepoDir)
+    into "${dataBindingConfig.eapOutDir}/${dataBindingConfig.mavenRepoName}"
 }
 
-tasks.create(name : 'createEapConfigFile') << {
-    def propsFile = new File("${config.eapOutDir}/databinding.properties")
+tasks.create(name : 'createEapdataBindingConfigFile') << {
+    def propsFile = new File("${dataBindingConfig.eapOutDir}/databinding.properties")
     Properties props = new Properties()
-    props.setProperty('version', config.version)
-    props.setProperty('mavenRepoName', config.mavenRepoName)
+    props.setProperty('version', dataBindingConfig.version)
+    props.setProperty('mavenRepoName', dataBindingConfig.mavenRepoName)
     props.store(propsFile.newWriter(), null)
 }
 
-
 task batchEAP() {
     dependsOn deleteEap
     dependsOn copyMavenRepoToEap
     dependsOn copySamplesToEap
-    dependsOn createEapConfigFile
+    dependsOn createEapdataBindingConfigFile
+}
+
+def findChildByTag(node, tag) {
+    return node.children().find {
+        it.name().getLocalPart().equals(tag)
+    }
+}
+
+def fullJar(project) {
+    def localizeTask = project.parent.tasks.findByName('localizeDependencies')
+    if (localizeTask != null) {
+        localizeTask.dependsOn project.tasks.findByName('buildLicenseNotice')
+    }
+
+    if (!dataBindingConfig.runProguard || !dataBindingConfig.inReleaseBuild) {
+        return
+    }
+    def jarName = project.uploadArchives.repositories.mavenDeployer.pom.artifactId
+    def workingDir = "${project.buildDir}/intermediates/fullJar"
+    def fatJar = "${workingDir}/${jarName}-fat.jar"
+    def proguardJar = "${workingDir}/${jarName}-proguard.jar"
+    def jarJar = project.jar.archivePath
+
+    project.configurations {
+        jarJarArchives
+    }
+
+    project.tasks.create(name: 'fatJar', type: Jar) {
+        baseName = jarName + '-fat'
+        doFirst {
+            file(workingDir).mkdirs()
+        }
+        def deps = new HashSet<ResolvedDependency>()
+        project.configurations.compile.resolvedConfiguration.firstLevelModuleDependencies.each {
+            if (!it.moduleGroup.startsWith('com.android.tools')) {
+                deps.addAll(it.allModuleArtifacts)
+            }
+        }
+        from { deps.findAll { !it.name.contains('baseLibrary') && !it.name.contains("juniversalchardet")}.collect {
+            it.file.isDirectory() ? it.file : project.zipTree(it.file)
+        } } {
+            exclude "META-INF/maven/**"
+            exclude "META-INF/MANIFEST.MF"
+            exclude "META-INF/LICENSE.txt"
+            exclude "META-INF/NOTICE.txt"
+            exclude "META-INF/services/javax.annotation.processing.Processor"
+            exclude "**/*.stg"
+        }
+        archiveName "${baseName}.jar"
+        destinationDir = new File(workingDir)
+        with project.jar
+    }
+    project.tasks.create(name: 'proguard', type: proguard.gradle.ProGuardTask) {
+        dependsOn 'fatJar'
+
+        injars  fatJar
+        outjars proguardJar
+
+        configuration '../proguard.cfg'
+    }
+
+    project.tasks.create(name: 'jarJarFile') {
+        dependsOn 'proguard'
+        dependsOn project.jar
+        def inputLibrary = proguardJar
+        def outputLibrary = jarJar
+        inputs.file(inputLibrary)
+        outputs.file(outputLibrary)
+
+        doLast {
+            def jarJarLibrary = new File(dataBindingConfig.externalPrebuiltsBase,
+                    'tools/common/m2/repository/com/googlecode/jarjar/jarjar/1.3/jarjar-1.3.jar').
+                    getCanonicalPath()
+            // in Ant
+            ant.taskdef(name: "jarjarIt",
+                    classname: 'com.tonicsystems.jarjar.JarJarTask',
+                    classpath: jarJarLibrary)
+            // start jarjar task
+            ant.jarjarIt(jarfile: outputLibrary) {
+                // input is our inputLibrary
+                zipfileset(src: inputLibrary)
+                // rule to repackage antlr to new package
+                rule pattern: 'org.antlr.**', result: 'com.google.repacked.antlr.@1'
+                rule pattern: 'com.tunnelvisionlabs.**', result: 'com.google.repacked.tunnelvision.@1'
+                rule pattern: 'org.abego.treelayout.**', result: 'com.google.repacked.treelayout.@1'
+                // rule to repackage commons
+                rule pattern: 'org.apache.**', result: 'com.google.repacked.apache.@1'
+                rule pattern: 'kotlin.**', result: 'com.google.repacked.kotlin.@1'
+            }
+        }
+    }
+
+    project.uploadArchives {
+        dependsOn 'jarJarFile'
+        repositories {
+            mavenDeployer {
+                pom.whenConfigured { pom ->
+                    pom.dependencies.removeAll { dep ->
+                        def isBaseLibrary = dep.groupId == 'com.android.databinding' &&
+                                dep.artifactId == 'baseLibrary'
+                        def isGradle = dep.groupId == 'com.android.tools.build' &&
+                                dep.artifactId == 'gradle'
+                        def isChardet = dep.groupId == 'com.googlecode.juniversalchardet' &&
+                                dep.artifactId == 'juniversalchardet'
+                        return !isBaseLibrary && !isGradle && !isChardet
+                    }
+                }
+            }
+        }
+        outputs.upToDateWhen { false } // force it to re-run all the time.
+    }
+    project.bintrayUpload.dependsOn 'jarJarFile'
+    project.publishing.publications.mavenJava(MavenPublication) {
+            pom.withXml {
+                def deps = findChildByTag(asNode(), "dependencies")
+                if (deps == null) {
+                    throw new IllegalArgumentException("cannot find dependencies in pom file")
+                }
+                def unwanted = deps.children().findAll {
+                    def groupId = findChildByTag(it, "groupId").localText()[0]
+                    def artifactId = findChildByTag(it, "artifactId").localText()[0]
+                    def isBaseLibrary = groupId == 'com.android.databinding' &&
+                            artifactId == 'baseLibrary'
+                    def isGradle = groupId == 'com.android.tools.build' && artifactId == 'gradle'
+                    def isChardet = groupId == 'com.googlecode.juniversalchardet' &&
+                            artifactId == 'juniversalchardet'
+                    return !isBaseLibrary && !isGradle && !isChardet
+                }
+                unwanted.each {
+                    deps.remove(it)
+                }
+            }
+    }
 }
diff --git a/buildForGradlePlugin.sh b/buildForGradlePlugin.sh
new file mode 100755
index 0000000..c222fb3
--- /dev/null
+++ b/buildForGradlePlugin.sh
@@ -0,0 +1 @@
+./gradlew :dB:compiler:uploadArchives :dB:compilerCommon:uploadArchives :dB:baseLibrary:uploadArchives -PaddRemoteRepos=true -PuseReleaseVersion=true -PforGradlePlugin=true
diff --git a/compilationTests/build.gradle b/compilationTests/build.gradle
index 743050c..0ca1877 100644
--- a/compilationTests/build.gradle
+++ b/compilationTests/build.gradle
@@ -1,12 +1,17 @@
 apply plugin: 'java'
 
-sourceCompatibility = 1.7
+sourceCompatibility = 1.6
 version = '1.0'
 
 dependencies {
-    testCompile group: 'junit', name: 'junit', version: '4.12'
+    testCompile 'junit:junit:4.12'
     testCompile 'org.apache.commons:commons-lang3:3.3.2'
     testCompile 'commons-io:commons-io:2.4'
     testCompile 'commons-codec:commons-codec:1.10'
-    testCompile project(':compilerCommon')
+    testCompile project(':dataBinding:compilerCommon')
+}
+
+afterEvaluate {
+    tasks['test'].systemProperties['useReleaseVersion'] = dataBindingConfig.inReleaseBuild ? 'true' : 'false'
+    tasks['test'].systemProperties['addRemoteRepos'] = dataBindingConfig.addRemoteRepos ? 'true' : 'false'
 }
\ No newline at end of file
diff --git a/compilationTests/compilationTests.iml b/compilationTests/compilationTests.iml
new file mode 100644
index 0000000..751bf1e
--- /dev/null
+++ b/compilationTests/compilationTests.iml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":dataBinding:compilationTests" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="data-binding.dataBinding" external.system.module.version="1.0" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build/classes/main" />
+    <output-test url="file://$MODULE_DIR$/build/classes/test" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="compilerCommon" scope="TEST" />
+    <orderEntry type="module" module-name="baseLibrary" scope="TEST" />
+    <orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.apache.commons:commons-lang3:3.3.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: commons-io:commons-io:2.4" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: commons-codec:commons-codec:1.10" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: com.tunnelvisionlabs:antlr4:4.5" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: com.googlecode.juniversalchardet:juniversalchardet:1.0.3" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: com.tunnelvisionlabs:antlr4-runtime:4.5" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: com.tunnelvisionlabs:antlr4-annotations:4.5" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.antlr:antlr-runtime:3.5.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.antlr:ST4:4.0.8" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.abego.treelayout:org.abego.treelayout.core:1.0.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: com.google.guava:guava:17.0" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java b/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java
index 814f4aa..08bfde5 100644
--- a/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java
+++ b/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java
@@ -25,15 +25,15 @@
 
 import android.databinding.tool.store.Location;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.URISyntaxException;
 import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.attribute.PosixFilePermission;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -52,7 +52,7 @@
 public class BaseCompilationTest {
 
     private static final String PRINT_ENCODED_ERRORS_PROPERTY
-            = "android.databinding.injected.print.encoded.errors";
+            = "android.injected.invoked.from.ide";
     @Rule
     public TestName name = new TestName();
     static Pattern VARIABLES = Pattern.compile("!@\\{([A-Za-z0-9_-]*)}");
@@ -147,7 +147,7 @@
 
     protected static Map<String, String> toMap(String... keysAndValues) {
         assertEquals(0, keysAndValues.length % 2);
-        Map<String, String> map = new HashMap<>();
+        Map<String, String> map = new HashMap<String, String>();
         for (int i = 0; i < keysAndValues.length; i += 2) {
             map.put(keysAndValues[i], keysAndValues[i + 1]);
         }
@@ -191,7 +191,7 @@
 
     private Map<String, String> addDefaults(Map<String, String> map) {
         if (map == null) {
-            map = new HashMap<>();
+            map = new HashMap<String, String>();
         }
         if (!map.containsKey(KEY_MANIFEST_PACKAGE)) {
             map.put(KEY_MANIFEST_PACKAGE, DEFAULT_APP_PACKAGE);
@@ -216,7 +216,8 @@
         if (localProperties.exists()) {
             FileUtils.copyFile(localProperties, new File(testFolder, "local.properties"));
         }
-        FileUtils.copyFile(new File("../propLoader.gradle"), new File(testFolder, "propLoaderClone.gradle"));
+        FileUtils.copyFile(new File("../propLoader.gradle"),
+                new File(testFolder, "propLoaderClone.gradle"));
         FileUtils.copyFile(new File("../gradlew"), new File(testFolder, "gradlew"));
         FileUtils.copyDirectory(new File("../gradle"), new File(testFolder, "gradle"));
     }
@@ -240,9 +241,15 @@
             throws IOException, InterruptedException {
         setExecutable();
         File pathToExecutable = new File(testFolder, "gradlew");
-        List<String> args = new ArrayList<>();
+        List<String> args = new ArrayList<String>();
         args.add(pathToExecutable.getAbsolutePath());
         args.add("-P" + PRINT_ENCODED_ERRORS_PROPERTY + "=true");
+        if ("true".equals(System.getProperties().getProperty("useReleaseVersion", "false"))) {
+            args.add("-PuseReleaseVersion=true");
+        }
+        if ("true".equals(System.getProperties().getProperty("addRemoteRepos", "false"))) {
+            args.add("-PaddRemoteRepos=true");
+        }
         args.add("--project-cache-dir");
         args.add(new File("../.caches/", name.getMethodName()).getAbsolutePath());
         Collections.addAll(args, params);
@@ -254,25 +261,27 @@
         }
         builder.directory(testFolder);
         Process process = builder.start();
-        String output = IOUtils.toString(process.getInputStream());
-        String error = IOUtils.toString(process.getErrorStream());
+        String output = collect(process.getInputStream());
+        String error = collect(process.getErrorStream());
         int result = process.waitFor();
         return new CompilationResult(result, output, error);
     }
 
     private void setExecutable() throws IOException {
-        Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>();
-        //add owners permission
-        perms.add(PosixFilePermission.OWNER_READ);
-        perms.add(PosixFilePermission.OWNER_WRITE);
-        perms.add(PosixFilePermission.OWNER_EXECUTE);
-        //add group permissions
-        perms.add(PosixFilePermission.GROUP_READ);
-        //add others permissions
-        perms.add(PosixFilePermission.OTHERS_READ);
-        Files.setPosixFilePermissions(Paths.get(new File(testFolder, "gradlew").getAbsolutePath()),
-                perms);
+        File gw = new File(testFolder, "gradlew");
+        gw.setExecutable(true);
     }
 
-
+    /**
+     * Use this instead of IO utils so that we can easily log the output when necessary
+     */
+    private static String collect(InputStream stream) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        String line;
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+        while ((line = reader.readLine()) != null) {
+            sb.append(line).append("\n");
+        }
+        return sb.toString();
+    }
 }
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/MultiLayoutVerificationTest.java b/compilationTests/src/test/java/android/databinding/compilationTest/MultiLayoutVerificationTest.java
index 0591ea9..bbf86e7 100644
--- a/compilationTests/src/test/java/android/databinding/compilationTest/MultiLayoutVerificationTest.java
+++ b/compilationTests/src/test/java/android/databinding/compilationTest/MultiLayoutVerificationTest.java
@@ -58,25 +58,24 @@
             assertTrue(file.exists());
             assertEquals(1, report.getLocations().size());
             Location location = report.getLocations().get(0);
-            switch (file.getParentFile().getName()) {
-                case "layout":
-                    assertEquals(new File(testFolder,
-                            "/app/src/main/res/layout/with_class_name.xml")
-                            .getCanonicalFile(), file.getCanonicalFile());
-                    String extract = extract("/app/src/main/res/layout/with_class_name.xml",
-                            location);
-                    assertEquals(extract, "AClassName");
-                    assertEquals(String.format(
-                            ErrorMessages.MULTI_CONFIG_LAYOUT_CLASS_NAME_MISMATCH,
-                            DEFAULT_APP_PACKAGE + ".databinding.AClassName",
-                            "layout/with_class_name"), exception.getBareMessage());
-                    foundNormal = true;
-                    break;
-                case "layout-land":
+            String name = file.getParentFile().getName();
+            if ("layout".equals(name)) {
+                assertEquals(new File(testFolder,
+                        "/app/src/main/res/layout/with_class_name.xml")
+                        .getCanonicalFile(), file.getCanonicalFile());
+                String extract = extract("/app/src/main/res/layout/with_class_name.xml",
+                        location);
+                assertEquals(extract, "AClassName");
+                assertEquals(String.format(
+                        ErrorMessages.MULTI_CONFIG_LAYOUT_CLASS_NAME_MISMATCH,
+                        DEFAULT_APP_PACKAGE + ".databinding.AClassName",
+                        "layout/with_class_name"), exception.getBareMessage());
+                foundNormal = true;
+            } else if ("layout-land".equals(name)) {
                     assertEquals(new File(testFolder,
                             "/app/src/main/res/layout-land/with_class_name.xml")
                             .getCanonicalFile(), file.getCanonicalFile());
-                    extract = extract("/app/src/main/res/layout-land/with_class_name.xml",
+                    String extract = extract("/app/src/main/res/layout-land/with_class_name.xml",
                             location);
                     assertEquals("SomeOtherClassName", extract);
                     assertEquals(String.format(
@@ -84,13 +83,12 @@
                             DEFAULT_APP_PACKAGE + ".databinding.SomeOtherClassName",
                             "layout-land/with_class_name"), exception.getBareMessage());
                     foundLandscape = true;
-                    break;
-                default:
-                    fail("unexpected error file");
+            } else {
+                fail("unexpected error file");
             }
         }
-        assertTrue(result.error, foundNormal);
-        assertTrue(result.error, foundLandscape);
+        assertTrue("should find default config error\n" + result.error, foundNormal);
+        assertTrue("should find landscape error\n" + result.error, foundLandscape);
     }
 
     @Test
@@ -117,19 +115,17 @@
             assertEquals(result.error, 1, report.getLocations().size());
             Location location = report.getLocations().get(0);
             // validated in switch
-            String config = file.getParentFile().getName();
+            String name = file.getParentFile().getName();
+            String config = name;
             String type = "???";
-            switch (file.getParentFile().getName()) {
-                case "layout":
-                    type = "String";
-                    foundNormal = true;
-                    break;
-                case "layout-land":
-                    type = "CharSequence";
-                    foundLandscape = true;
-                    break;
-                default:
-                    fail("unexpected error file");
+            if ("layout".equals(name)) {
+                type = "String";
+                foundNormal = true;
+            } else if ("layout-land".equals(name)) {
+                type = "CharSequence";
+                foundLandscape = true;
+            } else {
+                fail("unexpected error file");
             }
             assertEquals(new File(testFolder,
                     "/app/src/main/res/" + config + "/layout_with_variable_type.xml")
@@ -172,19 +168,17 @@
             assertEquals(result.error, 1, report.getLocations().size());
             Location location = report.getLocations().get(0);
             // validated in switch
-            String config = file.getParentFile().getName();
+            String name = file.getParentFile().getName();
+            String config = name;
             String type = "???";
-            switch (file.getParentFile().getName()) {
-                case "layout":
-                    type = typeNormal;
-                    foundNormal = true;
-                    break;
-                case "layout-land":
-                    type = typeLand;
-                    foundLandscape = true;
-                    break;
-                default:
-                    fail("unexpected error file");
+            if ("layout".equals(name)) {
+                type = typeNormal;
+                foundNormal = true;
+            } else if ("layout-land".equals(name)) {
+                type = typeLand;
+                foundLandscape = true;
+            } else {
+                fail("unexpected error file");
             }
             assertEquals(new File(testFolder,
                     "/app/src/main/res/" + config + "/layout_with_import_type.xml")
@@ -227,22 +221,19 @@
             Location location = report.getLocations().get(0);
             // validated in switch
             String config = file.getParentFile().getName();
-            switch (file.getParentFile().getName()) {
-                case "layout":
-                    String extract = extract("/app/src/main/res/" + config + "/foo.xml", location);
-                    assertEquals(extract, "<include layout=\"@layout/basic_layout\" "
-                            + "android:id=\"@+id/sharedId\" bind:myVariable=\"@{myVariable}\"/>");
-                    foundNormal = true;
-                    break;
-                case "layout-land":
-                    extract = extract("/app/src/main/res/" + config + "/foo.xml", location);
-                    assertEquals(extract, "<TextView android:layout_width=\"wrap_content\" "
-                            + "android:layout_height=\"wrap_content\" android:id=\"@+id/sharedId\" "
-                            + "android:text=\"@{myVariable}\"/>");
-                    foundLandscape = true;
-                    break;
-                default:
-                    fail("unexpected error file");
+            if ("layout".equals(config)) {
+                String extract = extract("/app/src/main/res/" + config + "/foo.xml", location);
+                assertEquals(extract, "<include layout=\"@layout/basic_layout\" "
+                        + "android:id=\"@+id/sharedId\" bind:myVariable=\"@{myVariable}\"/>");
+                foundNormal = true;
+            } else if ("layout-land".equals(config)) {
+                String extract = extract("/app/src/main/res/" + config + "/foo.xml", location);
+                assertEquals(extract, "<TextView android:layout_width=\"wrap_content\" "
+                        + "android:layout_height=\"wrap_content\" android:id=\"@+id/sharedId\" "
+                        + "android:text=\"@{myVariable}\"/>");
+                foundLandscape = true;
+            } else {
+                fail("unexpected error file");
             }
             assertEquals(new File(testFolder,
                     "/app/src/main/res/" + config + "/foo.xml").getCanonicalFile(),
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java
index 43efbb8..229323f 100644
--- a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java
+++ b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java
@@ -17,6 +17,9 @@
 package android.databinding.compilationTest;
 
 
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.PrefixFileFilter;
+import org.apache.commons.io.filefilter.SuffixFileFilter;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.Test;
 
@@ -28,6 +31,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
+import java.util.Collection;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
@@ -36,6 +40,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
 public class SimpleCompilationTest extends BaseCompilationTest {
 
     @Test
@@ -53,11 +58,39 @@
         prepareProject();
         CompilationResult result = runGradle("assembleDebug");
         assertEquals(result.error, 0, result.resultCode);
-        assertTrue("there should not be any errors " + result.error, StringUtils.isEmpty(result.error));
+        assertTrue("there should not be any errors " + result.error,
+                StringUtils.isEmpty(result.error));
         assertTrue("Test sanity, should compile fine",
                 result.resultContainsText("BUILD SUCCESSFUL"));
     }
 
+    @Test
+    public void testMultipleConfigs() throws IOException, URISyntaxException, InterruptedException {
+        prepareProject();
+        copyResourceTo("/layout/basic_layout.xml",
+                "/app/src/main/res/layout/main.xml");
+        copyResourceTo("/layout/basic_layout.xml",
+                "/app/src/main/res/layout-sw100dp/main.xml");
+        CompilationResult result = runGradle("assembleDebug");
+        assertEquals(result.error, 0, result.resultCode);
+        File debugOut = new File(testFolder,
+                "app/build/intermediates/data-binding-layout-out/debug");
+        Collection<File> layoutFiles = FileUtils.listFiles(debugOut, new SuffixFileFilter(".xml"),
+                new PrefixFileFilter("layout"));
+        assertTrue("test sanity", layoutFiles.size() > 1);
+        for (File layout : layoutFiles) {
+            final String contents = FileUtils.readFileToString(layout);
+            if (layout.getParent().contains("sw100")) {
+                assertTrue("File has wrong tag:" + layout.getPath(),
+                        contents.indexOf("android:tag=\"layout-sw100dp/main_0\"") > 0);
+            } else {
+                assertTrue("File has wrong tag:" + layout.getPath() + "\n" + contents,
+                        contents.indexOf("android:tag=\"layout/main_0\"")
+                                > 0);
+            }
+        }
+    }
+
     private ScopedException singleFileErrorTest(String resource, String targetFile,
             String expectedExtract, String errorMessage)
             throws IOException, URISyntaxException, InterruptedException {
@@ -123,6 +156,28 @@
     }
 
     @Test
+    public void testBadSyntax() throws IOException, URISyntaxException, InterruptedException {
+        singleFileErrorTest("/layout/layout_with_bad_syntax.xml",
+                "/app/src/main/res/layout/broken.xml",
+                "myVar.length())",
+                String.format(ErrorMessages.SYNTAX_ERROR,
+                        "extraneous input ')' expecting {<EOF>, ',', '.', '[', '+', '-', '*', '/', "
+                                + "'%', '<<', '>>>', '>>', '<=', '>=', '>', '<', 'instanceof', "
+                                + "'==', '!=', '&', '^', '|', '&&', '||', '?', '??'}"));
+    }
+
+    @Test
+    public void testBrokenSyntax() throws IOException, URISyntaxException, InterruptedException {
+        singleFileErrorTest("/layout/layout_with_completely_broken_syntax.xml",
+                "/app/src/main/res/layout/broken.xml",
+                "new String()",
+                String.format(ErrorMessages.SYNTAX_ERROR,
+                        "mismatched input 'String' expecting {<EOF>, ',', '.', '[', '+', '-', '*', "
+                                + "'/', '%', '<<', '>>>', '>>', '<=', '>=', '>', '<', 'instanceof',"
+                                + " '==', '!=', '&', '^', '|', '&&', '||', '?', '??'}"));
+    }
+
+    @Test
     public void testUndefinedVariable() throws IOException, URISyntaxException,
             InterruptedException {
         ScopedException ex = singleFileErrorTest("/layout/undefined_variable_binding.xml",
@@ -141,6 +196,18 @@
     }
 
     @Test
+    public void testRootTag() throws IOException, URISyntaxException,
+            InterruptedException {
+        prepareProject();
+        copyResourceTo("/layout/root_tag.xml", "/app/src/main/res/layout/root_tag.xml");
+        CompilationResult result = runGradle("assembleDebug");
+        assertNotEquals(0, result.resultCode);
+        assertNotNull(result.error);
+        final String expected = String.format(ErrorMessages.ROOT_TAG_NOT_SUPPORTED, "hello");
+        assertTrue(result.error.contains(expected));
+    }
+
+    @Test
     public void testInvalidVariableType() throws IOException, URISyntaxException,
             InterruptedException {
         prepareProject();
@@ -161,6 +228,25 @@
     }
 
     @Test
+    public void testModuleDependencyChange() throws IOException, URISyntaxException,
+            InterruptedException {
+        prepareApp(toMap(KEY_DEPENDENCIES, "compile project(':module1')",
+                KEY_SETTINGS_INCLUDES, "include ':app'\ninclude ':module1'"));
+        prepareModule("module1", "com.example.module1", toMap(
+                KEY_DEPENDENCIES, "compile 'com.android.support:appcompat-v7:23.1.1'"
+        ));
+        copyResourceTo("/layout/basic_layout.xml", "/module1/src/main/res/layout/module_layout.xml");
+        copyResourceTo("/layout/basic_layout.xml", "/app/src/main/res/layout/app_layout.xml");
+        CompilationResult result = runGradle("assembleDebug");
+        assertEquals(result.error, 0, result.resultCode);
+        File moduleFolder = new File(testFolder, "module1");
+        copyResourceTo("/module_build.gradle", new File(moduleFolder, "build.gradle"),
+                toMap());
+        result = runGradle("assembleDebug");
+        assertEquals(result.error, 0, result.resultCode);
+    }
+
+    @Test
     public void testTwoLevelDependency() throws IOException, URISyntaxException, InterruptedException {
         prepareApp(toMap(KEY_DEPENDENCIES, "compile project(':module1')",
                 KEY_SETTINGS_INCLUDES, "include ':app'\ninclude ':module1'\n"
diff --git a/compilationTests/src/test/resources/app_build.gradle b/compilationTests/src/test/resources/app_build.gradle
index 982f842..22632c5 100644
--- a/compilationTests/src/test/resources/app_build.gradle
+++ b/compilationTests/src/test/resources/app_build.gradle
@@ -1,10 +1,11 @@
 apply plugin: 'com.android.application'
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "22"
-
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
+    dataBinding {
+        enabled = true
+    }
     defaultConfig {
         minSdkVersion 7
         targetSdkVersion 21
@@ -22,8 +23,8 @@
         exclude 'META-INF/services/javax.annotation.processing.Processor'
     }
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
+        sourceCompatibility JavaVersion.VERSION_1_6
+        targetCompatibility JavaVersion.VERSION_1_6
     }
 }
 
diff --git a/compilationTests/src/test/resources/layout/layout_with_bad_syntax.xml b/compilationTests/src/test/resources/layout/layout_with_bad_syntax.xml
new file mode 100644
index 0000000..6a90af8
--- /dev/null
+++ b/compilationTests/src/test/resources/layout/layout_with_bad_syntax.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:bind="http://schemas.android.com/apk/res-auto">
+    <data>
+        <variable name="myVar" type="String"/>
+    </data>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <!-- undefined variable -->
+        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:text="@{myVar.length())}"/>
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/compilationTests/src/test/resources/layout/layout_with_completely_broken_syntax.xml b/compilationTests/src/test/resources/layout/layout_with_completely_broken_syntax.xml
new file mode 100644
index 0000000..dca87ae
--- /dev/null
+++ b/compilationTests/src/test/resources/layout/layout_with_completely_broken_syntax.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <!-- undefined variable -->
+        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:text="@{new String()}"/>
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/compilationTests/src/test/resources/layout/root_tag.xml b/compilationTests/src/test/resources/layout/root_tag.xml
new file mode 100644
index 0000000..ed93ce0
--- /dev/null
+++ b/compilationTests/src/test/resources/layout/root_tag.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:bind="http://schemas.android.com/apk/res-auto">
+    <data>
+        <variable name="myVar" type="String"/>
+    </data>
+    <LinearLayout
+            android:tag="hello"
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <!-- undefined variable -->
+        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:text="@{myVar}"/>
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/compilationTests/src/test/resources/module_build.gradle b/compilationTests/src/test/resources/module_build.gradle
index 7287ad6..112b27b 100644
--- a/compilationTests/src/test/resources/module_build.gradle
+++ b/compilationTests/src/test/resources/module_build.gradle
@@ -15,12 +15,13 @@
  */
 
 apply plugin: 'com.android.library'
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "22"
-
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
+    dataBinding {
+        enabled = true
+    }
     defaultConfig {
         minSdkVersion 7
         targetSdkVersion 21
@@ -38,8 +39,8 @@
         exclude 'META-INF/services/javax.annotation.processing.Processor'
     }
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
+        sourceCompatibility JavaVersion.VERSION_1_6
+        targetCompatibility JavaVersion.VERSION_1_6
     }
 }
 
diff --git a/compilationTests/src/test/resources/project_build.gradle b/compilationTests/src/test/resources/project_build.gradle
index fcf1b75..4622a5b 100644
--- a/compilationTests/src/test/resources/project_build.gradle
+++ b/compilationTests/src/test/resources/project_build.gradle
@@ -1,23 +1,23 @@
 buildscript {
-    ext.rootFolder = new File(project.projectDir, "../../..")
+    ext.dataBindingRootFolder = new File(project.projectDir, "../../..")
     apply from: "${project.projectDir}/propLoaderClone.gradle"
     ext.addRepos(repositories)
     dependencies {
-        classpath "com.android.databinding:dataBinder:${config.version}"
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
     }
 }
 
 subprojects {
     apply plugin: 'maven'
-    group = config.group
-    version = config.version
+    group = dataBindingConfig.group
+    version = dataBindingConfig.version
 }
 
 allprojects {
     repositories {
         jcenter()
         maven {
-            url config.mavenRepoDir
+            url dataBindingConfig.mavenRepoDir
         }
     }
 }
diff --git a/compiler/build.gradle b/compiler/build.gradle
index 711bb39..8a9e991 100644
--- a/compiler/build.gradle
+++ b/compiler/build.gradle
@@ -14,31 +14,32 @@
  * limitations under the License.
  */
 apply plugin: 'java'
-apply plugin: "kotlin"
-apply plugin: 'com.android.databinding.bintray'
+apply plugin: 'kotlin'
 
+sourceCompatibility = dataBindingConfig.javaTargetCompatibility
+targetCompatibility = dataBindingConfig.javaSourceCompatibility
 
-sourceCompatibility = config.javaTargetCompatibility
-targetCompatibility = config.javaSourceCompatibility
+sourceSets {
+    main.java.srcDirs += 'src/main/kotlin'
+}
 
 buildscript {
+    // to make IJ happy
+    ext.kotlin_version = dataBindingConfig.kotlinVersion
     dependencies {
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${config.kotlinVersion}"
         classpath 'commons-io:commons-io:2.4'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
 
 dependencies {
-    compile project(":compilerCommon")
-    compile project(':baseLibrary')
-    compile 'org.apache.commons:commons-lang3:3.3.2'
+    compile project(':dataBinding:compilerCommon')
+    compile project(':dataBinding:baseLibrary')
+    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
     compile 'commons-io:commons-io:2.4'
     compile 'commons-codec:commons-codec:1.10'
-    compile "org.jetbrains.kotlin:kotlin-stdlib:${config.kotlinVersion}"
-
     compile 'com.tunnelvisionlabs:antlr4:4.5'
-    testCompile files('../baseLibrary/src/main/java')
-    testCompile files('../library/src/main/java')
+    compile 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3'
     testCompile 'junit:junit:4.12'
 }
 
@@ -49,9 +50,9 @@
             pom.project {
                 licenses {
                     license {
-                        name config.licenseName
-                        url config.licenseUrl
-                        distribution config.licenseDistribution
+                        name dataBindingConfig.licenseName
+                        url dataBindingConfig.licenseUrl
+                        distribution dataBindingConfig.licenseDistribution
                     }
                 }
             }
@@ -59,23 +60,10 @@
     }
 }
 
-project(':library').afterEvaluate { libProject ->
-    tasks['compileTestKotlin'].dependsOn libProject.tasks['uploadJarArchives']
-}
 
-task fatJar(type: Jar) {
-    baseName = project.name + '-all'
-    doFirst {
-        tasks.findByName("buildLicenseNoticeFor${project.name.capitalize()}").execute()
-    }
-    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
-    from new File(project.buildDir,'NOTICE.txt')
-    archiveName "databinding-studio-bundle.jar"
-    destinationDir = new File(config.prebuildFolder)
-    with jar
-}
 
-task prebuild() {
-    dependsOn fatJar
-}
-
+project.ext.pomName = 'Data Binding Annotation Processor'
+project.ext.pomDesc = 'The annotation processor for Data Binding. Generates binding classes for runtime.'
+enablePublishing(this, true)
+fullJar(project)
+test.enabled = !System.getProperty("java.version").startsWith("1.6")
diff --git a/compiler/compiler.iml b/compiler/compiler.iml
new file mode 100644
index 0000000..b0d4edf
--- /dev/null
+++ b/compiler/compiler.iml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":dataBinding:compiler" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="com.android.databinding" external.system.module.version="1.1" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build/classes/main" />
+    <output-test url="file://$MODULE_DIR$/build/classes/test" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="compilerCommon" />
+    <orderEntry type="module" module-name="baseLibrary" />
+    <orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.0.0-beta-4584" level="project" />
+    <orderEntry type="library" name="Gradle: commons-io:commons-io:2.4" level="project" />
+    <orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10" level="project" />
+    <orderEntry type="library" name="Gradle: com.tunnelvisionlabs:antlr4:4.5" level="project" />
+    <orderEntry type="library" name="Gradle: com.googlecode.juniversalchardet:juniversalchardet:1.0.3" level="project" />
+    <orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-runtime:1.0.0-beta-4584" level="project" />
+    <orderEntry type="library" name="Gradle: com.tunnelvisionlabs:antlr4-runtime:4.5" level="project" />
+    <orderEntry type="library" name="Gradle: com.tunnelvisionlabs:antlr4-annotations:4.5" level="project" />
+    <orderEntry type="library" name="Gradle: org.antlr:antlr-runtime:3.5.2" level="project" />
+    <orderEntry type="library" name="Gradle: org.antlr:ST4:4.0.8" level="project" />
+    <orderEntry type="library" name="Gradle: org.abego.treelayout:org.abego.treelayout.core:1.0.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.guava:guava:17.0" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/compiler/db-compiler.iml b/compiler/db-compiler.iml
new file mode 100644
index 0000000..2f3a0d2
--- /dev/null
+++ b/compiler/db-compiler.iml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+      <excludeFolder url="file://$MODULE_DIR$/gradle" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="db-baseLibrary" exported="" />
+    <orderEntry type="module" module-name="db-compilerCommon" />
+    <orderEntry type="library" name="KotlinJavaRuntime" level="project" />
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+  </component>
+</module>
\ No newline at end of file
diff --git a/compiler/gradle/wrapper/gradle-wrapper.properties b/compiler/gradle/wrapper/gradle-wrapper.properties
index 29fb85e..1f1bbb6 100644
--- a/compiler/gradle/wrapper/gradle-wrapper.properties
+++ b/compiler/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java
index ae73d95..d96e5da 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java
@@ -33,8 +33,6 @@
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedSourceVersion;
-import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -45,7 +43,6 @@
 import javax.lang.model.util.Types;
 
 // binding app info and library info are necessary to trigger this.
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
 public class ProcessBindable extends ProcessDataBinding.ProcessingStep implements BindableHolder {
     Intermediate mProperties;
     HashMap<String, HashSet<String>> mLayoutVariables = new HashMap<String, HashSet<String>>();
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
index e6d925e..4d1fadb 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
@@ -20,6 +20,7 @@
 import android.databinding.tool.CompilerChef;
 import android.databinding.tool.processing.Scope;
 import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
 import android.databinding.tool.writer.AnnotationJavaFileWriter;
 import android.databinding.tool.writer.BRWriter;
@@ -33,9 +34,9 @@
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.annotation.processing.SupportedSourceVersion;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.TypeElement;
+import javax.xml.bind.JAXBException;
 
 @SupportedAnnotationTypes({
         "android.databinding.BindingAdapter",
@@ -44,7 +45,6 @@
         "android.databinding.BindingConversion",
         "android.databinding.BindingBuildInfo"}
 )
-@SupportedSourceVersion(SourceVersion.RELEASE_7)
 /**
  * Parent annotation processor that dispatches sub steps to ensure execution order.
  * Use initProcessingSteps to add a new step.
@@ -62,7 +62,11 @@
         }
         boolean done = true;
         for (ProcessingStep step : mProcessingSteps) {
-            done = step.runStep(roundEnv, processingEnv, buildInfo) && done;
+            try {
+                done = step.runStep(roundEnv, processingEnv, buildInfo) && done;
+            } catch (JAXBException e) {
+                L.e(e, "Exception while handling step %s", step);
+            }
         }
         if (roundEnv.processingOver()) {
             for (ProcessingStep step : mProcessingSteps) {
@@ -73,6 +77,11 @@
         return done;
     }
 
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
     private void initProcessingSteps() {
         final ProcessBindable processBindable = new ProcessBindable();
         mProcessingSteps = Arrays.asList(
@@ -94,6 +103,7 @@
                 mLibraryProject = libraryProject;
                 mMinSdk = minSdk;
                 considerWritingMapper();
+                mChef.writeDynamicUtil();
             }
 
             private void considerWritingMapper() {
@@ -137,7 +147,7 @@
 
         private boolean runStep(RoundEnvironment roundEnvironment,
                 ProcessingEnvironment processingEnvironment,
-                BindingBuildInfo buildInfo) {
+                BindingBuildInfo buildInfo) throws JAXBException {
             if (mDone) {
                 return true;
             }
@@ -152,7 +162,7 @@
          */
         abstract public boolean onHandleStep(RoundEnvironment roundEnvironment,
                 ProcessingEnvironment processingEnvironment,
-                BindingBuildInfo buildInfo);
+                BindingBuildInfo buildInfo) throws JAXBException;
 
         /**
          * Invoked when processing is done. A good place to generate the output if the
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
index ab2b8bf..e1c447c 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
@@ -16,23 +16,29 @@
 
 package android.databinding.annotationprocessor;
 
+import com.google.common.base.Joiner;
+
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
 
 import android.databinding.BindingBuildInfo;
 import android.databinding.tool.CompilerChef;
+import android.databinding.tool.LayoutXmlProcessor;
 import android.databinding.tool.reflection.SdkUtil;
 import android.databinding.tool.store.ResourceBundle;
 import android.databinding.tool.util.GenerationalClassUtil;
 import android.databinding.tool.util.L;
+import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.util.StringUtils;
 
 import java.io.File;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -49,30 +55,55 @@
 
     @Override
     public boolean onHandleStep(RoundEnvironment roundEnvironment,
-            ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) {
+            ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo)
+            throws JAXBException {
         ResourceBundle resourceBundle;
         SdkUtil.initialize(buildInfo.minSdk(), new File(buildInfo.sdkRoot()));
         resourceBundle = new ResourceBundle(buildInfo.modulePackage());
-        List<Intermediate> intermediateList =
-                GenerationalClassUtil.loadObjects(
-                        GenerationalClassUtil.ExtensionFilter.LAYOUT);
-        IntermediateV1 mine = createIntermediateFromLayouts(buildInfo.layoutInfoDir());
+        List<IntermediateV2> intermediateList = loadDependencyIntermediates();
+        for (Intermediate intermediate : intermediateList) {
+            try {
+                intermediate.appendTo(resourceBundle);
+            } catch (Throwable throwable) {
+                L.e(throwable, "unable to prepare resource bundle");
+            }
+        }
+
+        IntermediateV2 mine = createIntermediateFromLayouts(buildInfo.layoutInfoDir(),
+                intermediateList);
         if (mine != null) {
-            mine.removeOverridden(intermediateList);
+            mine.updateOverridden(resourceBundle);
             intermediateList.add(mine);
             saveIntermediate(processingEnvironment, buildInfo, mine);
+            mine.appendTo(resourceBundle);
         }
         // generate them here so that bindable parser can read
         try {
-            generateBinders(resourceBundle, buildInfo, intermediateList);
+            writeResourceBundle(resourceBundle, buildInfo.isLibrary(), buildInfo.minSdk(),
+                    buildInfo.exportClassListTo());
         } catch (Throwable t) {
             L.e(t, "cannot generate view binders");
         }
         return true;
     }
 
+    private List<IntermediateV2> loadDependencyIntermediates() {
+        final List<Intermediate> original = GenerationalClassUtil.loadObjects(
+                GenerationalClassUtil.ExtensionFilter.LAYOUT);
+        final List<IntermediateV2> upgraded = new ArrayList<IntermediateV2>(original.size());
+        for (Intermediate intermediate : original) {
+            final Intermediate updatedIntermediate = intermediate.upgrade();
+            Preconditions.check(updatedIntermediate instanceof IntermediateV2, "Incompatible data"
+                    + " binding dependency. Please update your dependencies or recompile them with"
+                    + " application module's data binding version.");
+            //noinspection ConstantConditions
+            upgraded.add((IntermediateV2) updatedIntermediate);
+        }
+        return upgraded;
+    }
+
     private void saveIntermediate(ProcessingEnvironment processingEnvironment,
-            BindingBuildInfo buildInfo, IntermediateV1 intermediate) {
+            BindingBuildInfo buildInfo, IntermediateV2 intermediate) {
         GenerationalClassUtil.writeIntermediateFile(processingEnvironment,
                 buildInfo.modulePackage(), buildInfo.modulePackage() +
                         GenerationalClassUtil.ExtensionFilter.LAYOUT.getExtension(),
@@ -84,27 +115,22 @@
             ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) {
     }
 
-    private void generateBinders(ResourceBundle resourceBundle, BindingBuildInfo buildInfo,
-            List<Intermediate> intermediates)
-            throws Throwable {
-        for (Intermediate intermediate : intermediates) {
-            intermediate.appendTo(resourceBundle);
+    private IntermediateV2 createIntermediateFromLayouts(String layoutInfoFolderPath,
+            List<IntermediateV2> intermediateList) {
+        final Set<String> excludeList = new HashSet<String>();
+        for (IntermediateV2 lib : intermediateList) {
+            excludeList.addAll(lib.mLayoutInfoMap.keySet());
         }
-        writeResourceBundle(resourceBundle, buildInfo.isLibrary(), buildInfo.minSdk(),
-                buildInfo.exportClassListTo());
-    }
-
-    private IntermediateV1 createIntermediateFromLayouts(String layoutInfoFolderPath) {
         final File layoutInfoFolder = new File(layoutInfoFolderPath);
         if (!layoutInfoFolder.isDirectory()) {
             L.d("layout info folder does not exist, skipping for %s", layoutInfoFolderPath);
             return null;
         }
-        IntermediateV1 result = new IntermediateV1();
+        IntermediateV2 result = new IntermediateV2();
         for (File layoutFile : layoutInfoFolder.listFiles(new FilenameFilter() {
             @Override
             public boolean accept(File dir, String name) {
-                return name.endsWith(".xml");
+                return name.endsWith(".xml") && !excludeList.contains(name);
             }
         })) {
             try {
@@ -133,7 +159,7 @@
         }
         if (forLibraryModule) {
             Set<String> classNames = compilerChef.getWrittenClassNames();
-            String out = StringUtils.join(classNames, System.getProperty("line.separator"));
+            String out = Joiner.on(StringUtils.LINE_SEPARATOR).join(classNames);
             L.d("Writing list of classes to %s . \nList:%s", exportClassNamesTo, out);
             try {
                 //noinspection ConstantConditions
@@ -145,11 +171,11 @@
         mCallback.onChefReady(compilerChef, forLibraryModule, minSdk);
     }
 
-    public static interface Intermediate extends Serializable {
+    public interface Intermediate extends Serializable {
 
         Intermediate upgrade();
 
-        public void appendTo(ResourceBundle resourceBundle) throws Throwable;
+        void appendTo(ResourceBundle resourceBundle) throws Throwable;
     }
 
     public static class IntermediateV1 implements Intermediate {
@@ -161,7 +187,10 @@
 
         @Override
         public Intermediate upgrade() {
-            return this;
+            final IntermediateV2 updated = new IntermediateV2();
+            updated.mLayoutInfoMap = mLayoutInfoMap;
+            updated.mUnmarshaller = mUnmarshaller;
+            return updated;
         }
 
         @Override
@@ -188,19 +217,53 @@
             mLayoutInfoMap.put(name, contents);
         }
 
+        // keeping the method to match deserialized structure
+        @SuppressWarnings("unused")
         public void removeOverridden(List<Intermediate> existing) {
-            // this is the way we get rid of files that are copied from previous modules
-            // it is important to do this before saving the intermediate file
-            for (Intermediate old : existing) {
-                if (old instanceof IntermediateV1) {
-                    IntermediateV1 other = (IntermediateV1) old;
-                    for (String key : other.mLayoutInfoMap.keySet()) {
-                        // TODO we should consider the original file as the key here
-                        // but aapt probably cannot provide that information
-                        if (mLayoutInfoMap.remove(key) != null) {
-                            L.d("removing %s from bundle because it came from another module", key);
-                        }
-                    }
+        }
+    }
+
+    public static class IntermediateV2 extends IntermediateV1 {
+        // specify so that we can define updates ourselves.
+        private static final long serialVersionUID = 2L;
+        @Override
+        public void appendTo(ResourceBundle resourceBundle) throws JAXBException {
+            for (Map.Entry<String, String> entry : mLayoutInfoMap.entrySet()) {
+                final InputStream is = IOUtils.toInputStream(entry.getValue());
+                try {
+                    final ResourceBundle.LayoutFileBundle bundle = ResourceBundle.LayoutFileBundle
+                            .fromXML(is);
+                    resourceBundle.addLayoutBundle(bundle);
+                    L.d("loaded layout info file %s", bundle);
+                } finally {
+                    IOUtils.closeQuietly(is);
+                }
+            }
+        }
+
+        /**
+         * if a layout is overridden from a module (which happens when layout is auto-generated),
+         * we need to update its contents from the class that overrides it.
+         * This must be done before this bundle is saved, otherwise, it will not be recognized
+         * when it is used in another project.
+         */
+        public void updateOverridden(ResourceBundle bundle) throws JAXBException {
+            // When a layout is copied from inherited module, it is eleminated while reading
+            // info files. (createIntermediateFromLayouts).
+            // Build process may also duplicate some files at compile time. This is where
+            // we detect those copies and force inherit their module and classname information.
+            final HashMap<String, List<ResourceBundle.LayoutFileBundle>> bundles = bundle
+                    .getLayoutBundles();
+            for (Map.Entry<String, String> info : mLayoutInfoMap.entrySet()) {
+                String key = LayoutXmlProcessor.exportLayoutNameFromInfoFileName(info.getKey());
+                final List<ResourceBundle.LayoutFileBundle> existingList = bundles.get(key);
+                if (existingList != null && !existingList.isEmpty()) {
+                    ResourceBundle.LayoutFileBundle myBundle = ResourceBundle.LayoutFileBundle
+                            .fromXML(IOUtils.toInputStream(info.getValue()));
+                    final ResourceBundle.LayoutFileBundle inheritFrom = existingList.get(0);
+                    myBundle.inheritConfigurationFrom(inheritFrom);
+                    L.d("inheriting data for %s (%s) from %s", info.getKey(), key, inheritFrom);
+                    mLayoutInfoMap.put(info.getKey(), myBundle.toXML());
                 }
             }
         }
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessMethodAdapters.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessMethodAdapters.java
index 72cfc62..36c4dd8 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessMethodAdapters.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessMethodAdapters.java
@@ -20,6 +20,9 @@
 import android.databinding.BindingConversion;
 import android.databinding.BindingMethod;
 import android.databinding.BindingMethods;
+import android.databinding.InverseBindingAdapter;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
 import android.databinding.Untaggable;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.store.SetterStore;
@@ -43,9 +46,10 @@
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
-import javax.tools.Diagnostic;
 
 public class ProcessMethodAdapters extends ProcessDataBinding.ProcessingStep {
+    private final static String INVERSE_BINDING_EVENT_ATTR_SUFFIX = "AttrChanged";
+
     public ProcessMethodAdapters() {
     }
 
@@ -60,9 +64,11 @@
         clearIncrementalClasses(roundEnv, store);
 
         addBindingAdapters(roundEnv, processingEnvironment, store);
-        addRenamed(roundEnv, processingEnvironment, store);
-        addConversions(roundEnv, processingEnvironment, store);
-        addUntaggable(roundEnv, processingEnvironment, store);
+        addRenamed(roundEnv, store);
+        addConversions(roundEnv, store);
+        addUntaggable(roundEnv, store);
+        addInverseAdapters(roundEnv, processingEnvironment, store);
+        addInverseMethods(roundEnv, store);
 
         try {
             store.write(buildInfo.modulePackage(), processingEnvironment);
@@ -84,7 +90,7 @@
                 .getElementsAnnotatedWith(roundEnv, BindingAdapter.class)) {
             if (element.getKind() != ElementKind.METHOD ||
                     !element.getModifiers().contains(Modifier.PUBLIC)) {
-                L.e("@BindingAdapter on invalid element: %s", element);
+                L.e(element, "@BindingAdapter on invalid element: %s", element);
                 continue;
             }
             BindingAdapter bindingAdapter = element.getAnnotation(BindingAdapter.class);
@@ -92,7 +98,8 @@
             ExecutableElement executableElement = (ExecutableElement) element;
             List<? extends VariableElement> parameters = executableElement.getParameters();
             if (bindingAdapter.value().length == 0) {
-                L.e("@BindingAdapter requires at least one attribute. %s", element);
+                L.e(element, "@BindingAdapter requires at least one attribute. %s",
+                        element);
                 continue;
             }
 
@@ -107,9 +114,9 @@
                 for (int i = startIndex; i < numAttributes + startIndex; i++) {
                     if (!typeUtils.isSameType(parameters.get(i).asType(),
                             parameters.get(i + numAttributes).asType())) {
-                        L.e("BindingAdapter %s: old values should be followed by new values. " +
-                                "Parameter %d must be the same type as parameter %d.",
-                                executableElement, i + 1, i + numAttributes + 1);
+                        L.e(executableElement, "BindingAdapter %s: old values should be followed " +
+                                "by new values. Parameter %d must be the same type as parameter " +
+                                "%d.", executableElement, i + 1, i + numAttributes + 1);
                         hasParameterError = true;
                         break;
                     }
@@ -118,24 +125,24 @@
                     continue;
                 }
             } else if (numAdditionalArgs != numAttributes) {
-                L.e("@BindingAdapter %s has %d attributes and %d value parameters. There should " +
-                        "be %d or %d value parameters.", executableElement, numAttributes,
-                        numAdditionalArgs, numAttributes, numAttributes * 2);
+                L.e(element, "@BindingAdapter %s has %d attributes and %d value " +
+                        "parameters. There should be %d or %d value parameters.",
+                        executableElement, numAttributes, numAdditionalArgs, numAttributes,
+                        numAttributes * 2);
                 continue;
             }
-            warnAttributeNamespaces(bindingAdapter.value());
+            warnAttributeNamespaces(element, bindingAdapter.value());
             try {
                 if (numAttributes == 1) {
                     final String attribute = bindingAdapter.value()[0];
-                    L.d("------------------ @BindingAdapter for %s", element);
                     store.addBindingAdapter(processingEnv, attribute, executableElement,
                             takesComponent);
                 } else {
                     store.addBindingAdapter(processingEnv, bindingAdapter.value(),
-                            executableElement, takesComponent);
+                            executableElement, takesComponent, bindingAdapter.requireAll());
                 }
             } catch (IllegalArgumentException e) {
-                L.e(e, "@BindingAdapter for duplicate View and parameter type: %s", element);
+                L.e(element, "@BindingAdapter for duplicate View and parameter type: %s", element);
             }
         }
     }
@@ -158,8 +165,8 @@
             TypeMirror viewStubProxy = elementUtils.
                     getTypeElement("android.databinding.ViewStubProxy").asType();
             if (!typeUtils.isAssignable(parameter1, viewStubProxy)) {
-                L.e("@BindingAdapter %s is applied to a method that has two parameters, the " +
-                        "first must be a View type", executableElement);
+                L.e(executableElement, "@BindingAdapter %s is applied to a method that has two " +
+                        "parameters, the first must be a View type", executableElement);
             }
             return false;
         }
@@ -167,27 +174,27 @@
         if (typeUtils.isAssignable(parameter2, viewElement)) {
             return true; // second parameter is a View
         }
-        L.e("@BindingAdapter %s is applied to a method that doesn't take a View subclass as the " +
-                "first or second parameter. When a BindingAdapter uses a DataBindingComponent, " +
-                "the component parameter is first and the View parameter is second, otherwise " +
-                "the View parameter is first.", executableElement);
+        L.e(executableElement, "@BindingAdapter %s is applied to a method that doesn't take a " +
+                "View subclass as the first or second parameter. When a BindingAdapter uses a " +
+                "DataBindingComponent, the component parameter is first and the View " +
+                "parameter is second, otherwise the View parameter is first.",
+                executableElement);
         return false;
     }
 
-    private static void warnAttributeNamespace(String attribute) {
+    private static void warnAttributeNamespace(Element element, String attribute) {
         if (attribute.contains(":") && !attribute.startsWith("android:")) {
-            L.w("Application namespace for attribute %s will be ignored.", attribute);
+            L.w(element, "Application namespace for attribute %s will be ignored.", attribute);
         }
     }
 
-    private static void warnAttributeNamespaces(String[] attributes) {
+    private static void warnAttributeNamespaces(Element element, String[] attributes) {
         for (String attribute : attributes) {
-            warnAttributeNamespace(attribute);
+            warnAttributeNamespace(element, attribute);
         }
     }
 
-    private void addRenamed(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv,
-            SetterStore store) {
+    private void addRenamed(RoundEnvironment roundEnv, SetterStore store) {
         for (Element element : AnnotationUtil
                 .getElementsAnnotatedWith(roundEnv, BindingMethods.class)) {
             BindingMethods bindingMethods = element.getAnnotation(BindingMethods.class);
@@ -195,7 +202,7 @@
             for (BindingMethod bindingMethod : bindingMethods.value()) {
                 final String attribute = bindingMethod.attribute();
                 final String method = bindingMethod.method();
-                warnAttributeNamespace(attribute);
+                warnAttributeNamespace(element, attribute);
                 String type;
                 try {
                     type = bindingMethod.type().getCanonicalName();
@@ -207,38 +214,97 @@
         }
     }
 
-    private void addConversions(RoundEnvironment roundEnv,
-            ProcessingEnvironment processingEnv, SetterStore store) {
+    private void addConversions(RoundEnvironment roundEnv, SetterStore store) {
         for (Element element : AnnotationUtil
                 .getElementsAnnotatedWith(roundEnv, BindingConversion.class)) {
             if (element.getKind() != ElementKind.METHOD ||
                     !element.getModifiers().contains(Modifier.STATIC) ||
                     !element.getModifiers().contains(Modifier.PUBLIC)) {
-                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
-                        "@BindingConversion is only allowed on public static methods: " + element);
+                L.e(element, "@BindingConversion is only allowed on public static methods %s",
+                        element);
                 continue;
             }
 
             ExecutableElement executableElement = (ExecutableElement) element;
             if (executableElement.getParameters().size() != 1) {
-                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
-                        "@BindingConversion method should have one parameter: " + element);
+                L.e(element, "@BindingConversion method should have one parameter %s", element);
                 continue;
             }
             if (executableElement.getReturnType().getKind() == TypeKind.VOID) {
-                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
-                        "@BindingConversion method must return a value: " + element);
+                L.e(element, "@BindingConversion method must return a value %s", element);
                 continue;
             }
-            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
-                    "added conversion: " + element);
             store.addConversionMethod(executableElement);
         }
     }
 
-    private void addUntaggable(RoundEnvironment roundEnv,
+    private void addInverseAdapters(RoundEnvironment roundEnv,
             ProcessingEnvironment processingEnv, SetterStore store) {
-        for (Element element : AnnotationUtil.getElementsAnnotatedWith(roundEnv, Untaggable.class)) {
+        for (Element element : AnnotationUtil
+                .getElementsAnnotatedWith(roundEnv, InverseBindingAdapter.class)) {
+            if (!element.getModifiers().contains(Modifier.PUBLIC)) {
+                L.e(element, "@InverseBindingAdapter must be associated with a public method");
+                continue;
+            }
+            ExecutableElement executableElement = (ExecutableElement) element;
+            if (executableElement.getReturnType().getKind() == TypeKind.VOID) {
+                L.e(element, "@InverseBindingAdapter must have a non-void return type");
+                continue;
+            }
+            final InverseBindingAdapter inverseBindingAdapter =
+                    executableElement.getAnnotation(InverseBindingAdapter.class);
+            final String attribute = inverseBindingAdapter.attribute();
+            warnAttributeNamespace(element, attribute);
+            final String event = inverseBindingAdapter.event().isEmpty()
+                    ? inverseBindingAdapter.attribute() + INVERSE_BINDING_EVENT_ATTR_SUFFIX
+                    : inverseBindingAdapter.event();
+            warnAttributeNamespace(element, event);
+            final boolean takesComponent = takesComponent(executableElement, processingEnv);
+            final int expectedArgs = takesComponent ? 2 : 1;
+            final int numParameters = executableElement.getParameters().size();
+            if (numParameters != expectedArgs) {
+                L.e(element, "@InverseBindingAdapter %s takes %s parameters, but %s parameters " +
+                        "were expected", element, numParameters, expectedArgs);
+                continue;
+            }
+            try {
+                store.addInverseAdapter(processingEnv, attribute, event, executableElement,
+                        takesComponent);
+            } catch (IllegalArgumentException e) {
+                L.e(element, "@InverseBindingAdapter for duplicate View and parameter type: %s",
+                        element);
+            }
+        }
+    }
+
+    private void addInverseMethods(RoundEnvironment roundEnv, SetterStore store) {
+        for (Element element : AnnotationUtil
+                .getElementsAnnotatedWith(roundEnv, InverseBindingMethods.class)) {
+            InverseBindingMethods bindingMethods =
+                    element.getAnnotation(InverseBindingMethods.class);
+
+            for (InverseBindingMethod bindingMethod : bindingMethods.value()) {
+                final String attribute = bindingMethod.attribute();
+                final String method = bindingMethod.method();
+                final String event = bindingMethod.event().isEmpty()
+                        ? bindingMethod.attribute() + INVERSE_BINDING_EVENT_ATTR_SUFFIX
+                        : bindingMethod.event();
+                warnAttributeNamespace(element, attribute);
+                warnAttributeNamespace(element, event);
+                String type;
+                try {
+                    type = bindingMethod.type().getCanonicalName();
+                } catch (MirroredTypeException e) {
+                    type = e.getTypeMirror().toString();
+                }
+                store.addInverseMethod(attribute, event, type, method, (TypeElement) element);
+            }
+        }
+    }
+
+    private void addUntaggable(RoundEnvironment roundEnv, SetterStore store) {
+        for (Element element : AnnotationUtil.
+                getElementsAnnotatedWith(roundEnv, Untaggable.class)) {
             Untaggable untaggable = element.getAnnotation(Untaggable.class);
             store.addUntaggableTypes(untaggable.value(), (TypeElement) element);
         }
@@ -261,10 +327,10 @@
             classes.add(((TypeElement) element.getEnclosingElement()).getQualifiedName().
                     toString());
         }
-        for (Element element : AnnotationUtil.getElementsAnnotatedWith(roundEnv, Untaggable.class)) {
+        for (Element element : AnnotationUtil.
+                getElementsAnnotatedWith(roundEnv, Untaggable.class)) {
             classes.add(((TypeElement) element).getQualifiedName().toString());
         }
         store.clear(classes);
     }
-
 }
diff --git a/compiler/src/main/java/android/databinding/tool/Binding.java b/compiler/src/main/java/android/databinding/tool/Binding.java
index 5238edb..aba6b3e 100644
--- a/compiler/src/main/java/android/databinding/tool/Binding.java
+++ b/compiler/src/main/java/android/databinding/tool/Binding.java
@@ -24,24 +24,29 @@
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.store.Location;
 import android.databinding.tool.store.SetterStore;
+import android.databinding.tool.store.SetterStore.BindingSetterCall;
 import android.databinding.tool.store.SetterStore.SetterCall;
 import android.databinding.tool.util.L;
-import android.databinding.tool.writer.CodeGenUtil;
-import android.databinding.tool.writer.WriterPackage;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
 
 import java.util.List;
 
 public class Binding implements LocationScopeProvider {
 
     private final String mName;
-    private final Expr mExpr;
+    private Expr mExpr;
     private final BindingTarget mTarget;
-    private SetterStore.SetterCall mSetterCall;
+    private BindingSetterCall mSetterCall;
 
     public Binding(BindingTarget target, String name, Expr expr) {
+        this(target, name, expr, null);
+    }
+
+    public Binding(BindingTarget target, String name, Expr expr, BindingSetterCall setterCall) {
         mTarget = target;
         mName = name;
         mExpr = expr;
+        mSetterCall = setterCall;
     }
 
     @Override
@@ -50,9 +55,18 @@
     }
 
     public void resolveListeners() {
-        ModelClass listenerParameter = getListenerParameter();
-        if (listenerParameter != null) {
-            mExpr.resolveListeners(listenerParameter);
+        final ModelClass listenerParameter = getListenerParameter(mTarget, mName, mExpr);
+        Expr listenerExpr = mExpr.resolveListeners(listenerParameter, null);
+        if (listenerExpr != mExpr) {
+            listenerExpr.setBindingExpression(true);
+            mExpr = listenerExpr;
+        }
+    }
+
+    public void resolveTwoWayExpressions() {
+        Expr expr = mExpr.resolveTwoWayExpressions(null);
+        if (expr != mExpr) {
+            mExpr = expr;
         }
     }
 
@@ -76,19 +90,20 @@
     private void resolveSetterCall() {
         ModelClass viewType = mTarget.getResolvedType();
         if (viewType != null && viewType.extendsViewStub()) {
-            if (isListenerAttribute()) {
+            if (isListenerAttribute(mName)) {
                 ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
                 ModelClass viewStubProxy = modelAnalyzer.
                         findClass("android.databinding.ViewStubProxy", null);
                 mSetterCall = SetterStore.get(modelAnalyzer).getSetterCall(mName,
                         viewStubProxy, mExpr.getResolvedType(), mExpr.getModel().getImports());
-            } else if (isViewStubAttribute()) {
+            } else if (isViewStubAttribute(mName)) {
                 mSetterCall = new ViewStubDirectCall(mName, viewType, mExpr);
             } else {
                 mSetterCall = new ViewStubSetterCall(mName);
             }
         } else {
-            mSetterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName,
+            final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
+            mSetterCall = setterStore.getSetterCall(mName,
                     viewType, mExpr.getResolvedType(), mExpr.getModel().getImports());
         }
     }
@@ -96,31 +111,38 @@
     /**
      * Similar to getSetterCall, but assumes an Object parameter to find the best matching listener.
      */
-    private ModelClass getListenerParameter() {
-        ModelClass viewType = mTarget.getResolvedType();
+    private static ModelClass getListenerParameter(BindingTarget target, String name, Expr expr) {
+        ModelClass viewType = target.getResolvedType();
         SetterCall setterCall;
         ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
         ModelClass objectParameter = modelAnalyzer.findClass(Object.class);
+        SetterStore setterStore = SetterStore.get(modelAnalyzer);
         if (viewType != null && viewType.extendsViewStub()) {
-            if (isListenerAttribute()) {
+            if (isListenerAttribute(name)) {
                 ModelClass viewStubProxy = modelAnalyzer.
                         findClass("android.databinding.ViewStubProxy", null);
-                setterCall = SetterStore.get(modelAnalyzer).getSetterCall(mName,
-                        viewStubProxy, objectParameter, mExpr.getModel().getImports());
-            } else if (isViewStubAttribute()) {
-                setterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName,
-                        viewType, objectParameter, mExpr.getModel().getImports());
+                setterCall = SetterStore.get(modelAnalyzer).getSetterCall(name,
+                        viewStubProxy, objectParameter, expr.getModel().getImports());
+            } else if (isViewStubAttribute(name)) {
+                setterCall = new ViewStubDirectCall(name, viewType, expr);
             } else {
-                setterCall = new ViewStubSetterCall(mName);
+                setterCall = new ViewStubSetterCall(name);
             }
         } else {
-            setterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName,
-                    viewType, objectParameter, mExpr.getModel().getImports());
+            setterCall = setterStore.getSetterCall(name, viewType, objectParameter,
+                    expr.getModel().getImports());
         }
-        if (setterCall == null) {
+        if (setterCall != null) {
+            return setterCall.getParameterTypes()[0];
+        }
+        List<SetterStore.MultiAttributeSetter> setters =
+                setterStore.getMultiAttributeSetterCalls(new String[]{name}, viewType,
+                new ModelClass[] {modelAnalyzer.findClass(Object.class)});
+        if (setters.isEmpty()) {
             return null;
+        } else {
+            return setters.get(0).getParameterTypes()[0];
         }
-        return setterCall.getParameterTypes()[0];
     }
 
     public BindingTarget getTarget() {
@@ -129,8 +151,8 @@
 
     public String toJavaCode(String targetViewName, String bindingComponent) {
         final String currentValue = requiresOldValue()
-                ? "this." + WriterPackage.getOldValueName(mExpr) : null;
-        final String argCode = CodeGenUtil.Companion.toCode(getExpr(), false).generate();
+                ? "this." + LayoutBinderWriterKt.getOldValueName(mExpr) : null;
+        final String argCode = getExpr().toCode().generate();
         return getSetterCall().toJava(bindingComponent, targetViewName, currentValue, argCode);
     }
 
@@ -138,10 +160,6 @@
         return getSetterCall().getBindingAdapterInstanceClass();
     }
 
-    public void setBindingAdapterCall(String method) {
-        getSetterCall().setBindingAdapterCall(method);
-    }
-
     public Expr[] getComponentExpressions() {
         return new Expr[] { mExpr };
     }
@@ -168,17 +186,16 @@
         return mExpr;
     }
 
-    private boolean isViewStubAttribute() {
-        return ("android:inflatedId".equals(mName) ||
-                "android:layout".equals(mName) ||
-                "android:visibility".equals(mName) ||
-                "android:layoutInflater".equals(mName));
+    private static boolean isViewStubAttribute(String name) {
+        return ("android:inflatedId".equals(name) ||
+                "android:layout".equals(name) ||
+                "android:visibility".equals(name) ||
+                "android:layoutInflater".equals(name));
     }
 
-    private boolean isListenerAttribute() {
-        return ("android:onInflate".equals(mName) ||
-                "android:onInflateListener".equals(mName));
-
+    private static boolean isListenerAttribute(String name) {
+        return ("android:onInflate".equals(name) ||
+                "android:onInflateListener".equals(name));
     }
 
     private static class ViewStubSetterCall extends SetterCall {
@@ -222,10 +239,6 @@
         public String getBindingAdapterInstanceClass() {
             return null;
         }
-
-        @Override
-        public void setBindingAdapterCall(String method) {
-        }
     }
 
     private static class ViewStubDirectCall extends SetterCall {
@@ -275,10 +288,5 @@
         public String getBindingAdapterInstanceClass() {
             return mWrappedCall.getBindingAdapterInstanceClass();
         }
-
-        @Override
-        public void setBindingAdapterCall(String method) {
-            mWrappedCall.setBindingAdapterCall(method);
-        }
     }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/BindingTarget.java b/compiler/src/main/java/android/databinding/tool/BindingTarget.java
index 5c3fac5..d8db559 100644
--- a/compiler/src/main/java/android/databinding/tool/BindingTarget.java
+++ b/compiler/src/main/java/android/databinding/tool/BindingTarget.java
@@ -18,31 +18,32 @@
 
 import android.databinding.tool.expr.Expr;
 import android.databinding.tool.expr.ExprModel;
+import android.databinding.tool.processing.ErrorMessages;
 import android.databinding.tool.processing.Scope;
-import android.databinding.tool.processing.scopes.FileScopeProvider;
 import android.databinding.tool.processing.scopes.LocationScopeProvider;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.store.Location;
 import android.databinding.tool.store.ResourceBundle;
 import android.databinding.tool.store.SetterStore;
+import android.databinding.tool.store.SetterStore.BindingGetterCall;
 import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 public class BindingTarget implements LocationScopeProvider {
     List<Binding> mBindings = new ArrayList<Binding>();
+    List<InverseBinding> mInverseBindings = new ArrayList<InverseBinding>();
     ExprModel mModel;
     ModelClass mResolvedClass;
 
     // if this target presents itself in multiple layout files with different view types,
     // it receives an interface type and should use it in the getter instead.
-    private ResourceBundle.BindingTargetBundle mBundle;
+    ResourceBundle.BindingTargetBundle mBundle;
 
     public BindingTarget(ResourceBundle.BindingTargetBundle bundle) {
         mBundle = bundle;
@@ -53,13 +54,38 @@
     }
 
     public void addBinding(String name, Expr expr) {
+        if (SetterStore.get(ModelAnalyzer.getInstance()).isTwoWayEventAttribute(name)) {
+            L.e(ErrorMessages.TWO_WAY_EVENT_ATTRIBUTE, name);
+        }
         mBindings.add(new Binding(this, name, expr));
+        if (expr.isTwoWay()) {
+            try {
+                Scope.enter(expr);
+                expr.assertIsInvertible();
+                final InverseBinding inverseBinding = new InverseBinding(this, name, expr);
+                mInverseBindings.add(inverseBinding);
+                mBindings.add(new Binding(this, inverseBinding.getEventAttribute(),
+                        mModel.twoWayListenerExpr(inverseBinding),
+                        inverseBinding.getEventSetter()));
+            } finally {
+                Scope.exit();
+            }
+        }
     }
 
     public String getInterfaceType() {
         return mBundle.getInterfaceType() == null ? mBundle.getFullClassName() : mBundle.getInterfaceType();
     }
 
+    public InverseBinding addInverseBinding(String name, BindingGetterCall call) {
+        final InverseBinding inverseBinding = new InverseBinding(this, name, null);
+        inverseBinding.setGetterCall(call);
+        mInverseBindings.add(inverseBinding);
+        mBindings.add(new Binding(this, inverseBinding.getEventAttribute(),
+                mModel.twoWayListenerExpr(inverseBinding)));
+        return inverseBinding;
+    }
+
     @Override
     public List<Location> provideScopeLocation() {
         return mBundle.provideScopeLocation();
@@ -83,8 +109,13 @@
 
     public ModelClass getResolvedType() {
         if (mResolvedClass == null) {
-            mResolvedClass = ModelAnalyzer.getInstance().findClass(mBundle.getFullClassName(),
-                    mModel.getImports());
+            if (mBundle.isBinder()) {
+                mResolvedClass = ModelAnalyzer.getInstance().
+                        findClass(ModelAnalyzer.VIEW_DATA_BINDING, mModel.getImports());
+            } else {
+                mResolvedClass = ModelAnalyzer.getInstance().findClass(mBundle.getFullClassName(),
+                        mModel.getImports());
+            }
         }
         return mResolvedClass;
     }
@@ -106,6 +137,10 @@
         return mBindings;
     }
 
+    public List<InverseBinding> getInverseBindings() {
+        return mInverseBindings;
+    }
+
     public ExprModel getModel() {
         return mModel;
     }
@@ -114,6 +149,18 @@
         mModel = model;
     }
 
+    public void resolveListeners() {
+        for (Binding binding : mBindings) {
+            binding.resolveListeners();
+        }
+    }
+
+    public void resolveTwoWayExpressions() {
+        for (Binding binding : mBindings) {
+            binding.resolveTwoWayExpressions();
+        }
+    }
+
     /**
      * Called after BindingTarget is finalized.
      * <p>
@@ -158,7 +205,7 @@
         List<MergedBinding> mergeBindings = new ArrayList<MergedBinding>();
         for (final SetterStore.MultiAttributeSetter setter : multiAttributeSetterCalls) {
             L.d("resolved %s", setter);
-            final List<Binding> mergedBindings = new ArrayList<>();
+            final List<Binding> mergedBindings = new ArrayList<Binding>();
             for (String attribute : setter.attributes) {
                 Binding binding = lookup.get(attribute);
                 Preconditions.checkNotNull(binding, "cannot find binding for %s", attribute);
diff --git a/compiler/src/main/java/android/databinding/tool/CompilerChef.java b/compiler/src/main/java/android/databinding/tool/CompilerChef.java
index df36560..b7456da 100644
--- a/compiler/src/main/java/android/databinding/tool/CompilerChef.java
+++ b/compiler/src/main/java/android/databinding/tool/CompilerChef.java
@@ -13,10 +13,14 @@
 
 package android.databinding.tool;
 
+import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.store.ResourceBundle;
 import android.databinding.tool.util.L;
+import android.databinding.tool.util.Preconditions;
 import android.databinding.tool.writer.BRWriter;
 import android.databinding.tool.writer.DataBinderWriter;
+import android.databinding.tool.writer.DynamicUtilWriter;
 import android.databinding.tool.writer.JavaFileWriter;
 
 import java.util.Set;
@@ -27,6 +31,31 @@
  * Different build systems can initiate a version of this to handle their work
  */
 public class CompilerChef {
+    private static final String[] VERSION_CODES = {
+            "BASE",                 // 1
+            "BASE_1_1",             // 2
+            "CUPCAKE",              // 3
+            "DONUT",                // 4
+            "ECLAIR",               // 5
+            "ECLAIRE_0_1",          // 6
+            "ECLAIR_MR1",           // 7
+            "FROYO",                // 8
+            "GINGERBREAD",          // 9
+            "GINGERBREAD_MR1",      // 10
+            "HONEYCOMB",            // 11
+            "HONEYCOMB_MR1",        // 12
+            "HONEYCOMB_MR2",        // 13
+            "ICE_CREAM_SANDWICH",   // 14
+            "ICE_CREAM_SANDWICH_MR1",// 15
+            "JELLY_BEAN",           // 16
+            "JELLY_BEAN_MR1",       // 17
+            "JELLY_BEAN_MR2",       // 18
+            "KITKAT",               // 19
+            "KITKAT_WATCH",         // 20
+            "LOLLIPOP",             // 21
+            "LOLLIPOP_MR1",         // 22
+            "M",                    // 23
+    };
     private JavaFileWriter mFileWriter;
     private ResourceBundle mResourceBundle;
     private DataBinder mDataBinder;
@@ -68,6 +97,23 @@
         mFileWriter.writeToFile(pkg + "." + dbr.getClassName(), dbr.write(brWriter));
     }
 
+    public void writeDynamicUtil() {
+        DynamicUtilWriter dynamicUtil = new DynamicUtilWriter();
+        // TODO: Replace this with targetSDK check from plugin
+        ModelClass versionCodes = ModelAnalyzer.getInstance().findClass(
+                "android.os.Build.VERSION_CODES", null);
+        Preconditions.checkNotNull(versionCodes, "Could not find compile SDK");
+        int compileVersion = 1;
+        for (int i = VERSION_CODES.length - 1; i >= 0; i--) {
+            if (versionCodes.findGetterOrField(VERSION_CODES[i], true) != null) {
+                compileVersion = i + 1;
+                break;
+            }
+        }
+        mFileWriter.writeToFile("android.databinding.DynamicUtil",
+                dynamicUtil.write(compileVersion).generate());
+    }
+
     /**
      * Adds variables to list of Bindables.
      */
diff --git a/compiler/src/main/java/android/databinding/tool/DataBinder.java b/compiler/src/main/java/android/databinding/tool/DataBinder.java
index 1acb16b..0280bd4 100644
--- a/compiler/src/main/java/android/databinding/tool/DataBinder.java
+++ b/compiler/src/main/java/android/databinding/tool/DataBinder.java
@@ -104,7 +104,7 @@
     }
 
     public void writeComponent() {
-        ComponentWriter componentWriter = new ComponentWriter(mLayoutBinders);
+        ComponentWriter componentWriter = new ComponentWriter();
 
         writtenClasses.add(COMPONENT_CLASS);
         mFileWriter.writeToFile(COMPONENT_CLASS, componentWriter.createComponent());
diff --git a/compiler/src/main/java/android/databinding/tool/ExpressionParser.java b/compiler/src/main/java/android/databinding/tool/ExpressionParser.java
index 467f658..5468c93 100644
--- a/compiler/src/main/java/android/databinding/tool/ExpressionParser.java
+++ b/compiler/src/main/java/android/databinding/tool/ExpressionParser.java
@@ -17,8 +17,12 @@
 package android.databinding.tool;
 
 import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.BaseErrorListener;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.misc.Nullable;
 import org.antlr.v4.runtime.tree.ErrorNode;
 import org.antlr.v4.runtime.tree.ParseTreeListener;
@@ -28,6 +32,7 @@
 import android.databinding.parser.BindingExpressionParser;
 import android.databinding.tool.expr.Expr;
 import android.databinding.tool.expr.ExprModel;
+import android.databinding.tool.processing.ErrorMessages;
 import android.databinding.tool.store.Location;
 import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
@@ -49,6 +54,14 @@
         BindingExpressionLexer lexer = new BindingExpressionLexer(inputStream);
         CommonTokenStream tokenStream = new CommonTokenStream(lexer);
         final BindingExpressionParser parser = new BindingExpressionParser(tokenStream);
+        parser.addErrorListener(new BaseErrorListener() {
+            @Override
+            public <T extends Token> void syntaxError(Recognizer<T, ?> recognizer,
+                    @Nullable T offendingSymbol, int line, int charPositionInLine, String msg,
+                    @Nullable RecognitionException e) {
+                L.e(ErrorMessages.SYNTAX_ERROR, msg);
+            }
+        });
         BindingExpressionParser.BindingSyntaxContext root = parser.bindingSyntax();
         try {
             mModel.setCurrentLocationInFile(locationInFile);
diff --git a/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java b/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java
index 7507890..08e6744 100644
--- a/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java
+++ b/compiler/src/main/java/android/databinding/tool/ExpressionVisitor.java
@@ -16,12 +16,13 @@
 
 package android.databinding.tool;
 
+import com.google.common.base.Objects;
+
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.misc.NotNull;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTreeListener;
 import org.antlr.v4.runtime.tree.TerminalNode;
-import org.apache.commons.lang3.ObjectUtils;
 
 import android.databinding.parser.BindingExpressionBaseVisitor;
 import android.databinding.parser.BindingExpressionParser;
@@ -218,7 +219,7 @@
             List<Expr> args = new ArrayList<Expr>();
             if (ctx.args != null) {
                 for (ParseTree item : ctx.args.children) {
-                    if (ObjectUtils.equals(item.getText(), ",")) {
+                    if (Objects.equal(item.getText(), ",")) {
                         continue;
                     }
                     args.add(item.accept(this));
@@ -298,7 +299,7 @@
             final List<Expr> args = new ArrayList<Expr>();
             if (ctx.resourceParameters() != null) {
                 for (ParseTree item : ctx.resourceParameters().expressionList().children) {
-                    if (ObjectUtils.equals(item.getText(), ",")) {
+                    if (Objects.equal(item.getText(), ",")) {
                         continue;
                     }
                     args.add(item.accept(this));
diff --git a/compiler/src/main/java/android/databinding/tool/InverseBinding.java b/compiler/src/main/java/android/databinding/tool/InverseBinding.java
new file mode 100644
index 0000000..e04be28
--- /dev/null
+++ b/compiler/src/main/java/android/databinding/tool/InverseBinding.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool;
+
+import android.databinding.tool.expr.Expr;
+import android.databinding.tool.expr.ExprModel;
+import android.databinding.tool.expr.FieldAccessExpr;
+import android.databinding.tool.processing.ErrorMessages;
+import android.databinding.tool.processing.Scope;
+import android.databinding.tool.processing.scopes.LocationScopeProvider;
+import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.store.Location;
+import android.databinding.tool.store.SetterStore;
+import android.databinding.tool.store.SetterStore.BindingGetterCall;
+import android.databinding.tool.store.SetterStore.BindingSetterCall;
+import android.databinding.tool.util.L;
+import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.writer.FlagSet;
+import android.databinding.tool.writer.KCode;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
+
+import kotlin.jvm.functions.Function2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InverseBinding implements LocationScopeProvider {
+
+    private final String mName;
+    private final Expr mExpr;
+    private final BindingTarget mTarget;
+    private BindingGetterCall mGetterCall;
+    private final ArrayList<FieldAccessExpr> mChainedExpressions = new ArrayList<FieldAccessExpr>();
+
+    public InverseBinding(BindingTarget target, String name, Expr expr) {
+        mTarget = target;
+        mName = name;
+        mExpr = expr;
+    }
+
+    @Override
+    public List<Location> provideScopeLocation() {
+        if (mExpr != null) {
+            return mExpr.getLocations();
+        } else {
+            return mChainedExpressions.get(0).getLocations();
+        }
+    }
+
+    void setGetterCall(BindingGetterCall getterCall) {
+        mGetterCall = getterCall;
+    }
+
+    public void addChainedExpression(FieldAccessExpr expr) {
+        mChainedExpressions.add(expr);
+    }
+
+    public boolean isOnBinder() {
+        return mTarget.getResolvedType().isViewDataBinding();
+    }
+
+    private SetterStore.BindingGetterCall getGetterCall() {
+        if (mGetterCall == null) {
+            if (mExpr != null) {
+                mExpr.getResolvedType(); // force resolve of ObservableFields
+            }
+            try {
+                Scope.enter(mTarget);
+                Scope.enter(this);
+                resolveGetterCall();
+                if (mGetterCall == null) {
+                    L.e(ErrorMessages.CANNOT_FIND_GETTER_CALL, mName,
+                            mExpr == null ? "Unknown" : mExpr.getResolvedType(),
+                            mTarget.getResolvedType());
+                }
+            } finally {
+                Scope.exit();
+                Scope.exit();
+            }
+        }
+        return mGetterCall;
+    }
+
+    private void resolveGetterCall() {
+        ModelClass viewType = mTarget.getResolvedType();
+        final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
+        final ModelClass resolvedType = mExpr == null ? null : mExpr.getResolvedType();
+        mGetterCall = setterStore.getGetterCall(mName, viewType, resolvedType,
+                getModel().getImports());
+    }
+
+    public BindingTarget getTarget() {
+        return mTarget;
+    }
+
+    public KCode toJavaCode(String bindingComponent, final FlagSet flagField) {
+        final String targetViewName = LayoutBinderWriterKt.getFieldName(getTarget());
+        KCode code = new KCode();
+        // A chained expression will have substituted its chained value for the expression
+        // unless the attribute has no expression. Therefore, chaining and expressions are
+        // mutually exclusive.
+        Preconditions.check((mExpr == null) != mChainedExpressions.isEmpty(),
+                "Chained expressions are only against unbound attributes.");
+        if (mExpr != null) {
+            code.app("", mExpr.toInverseCode(new KCode(getGetterCall().toJava(bindingComponent,
+                    targetViewName))));
+        } else { // !mChainedExpressions.isEmpty())
+            final String fieldName = flagField.getLocalName();
+            FlagSet flagSet = new FlagSet();
+            for (FieldAccessExpr expr : mChainedExpressions) {
+                flagSet = flagSet.or(new FlagSet(expr.getId()));
+            }
+            final FlagSet allFlags = flagSet;
+            code.nl(new KCode("synchronized(this) {"));
+            code.tab(LayoutBinderWriterKt
+                    .mapOr(flagField, flagSet, new Function2<String, Integer, KCode>() {
+                        @Override
+                        public KCode invoke(String suffix, Integer index) {
+                            return new KCode(fieldName)
+                                    .app(suffix)
+                                    .app(" |= ")
+                                    .app(LayoutBinderWriterKt.binaryCode(allFlags, index))
+                                    .app(";");
+                        }
+                    }));
+            code.nl(new KCode("}"));
+            code.nl(new KCode("requestRebind()"));
+        }
+        return code;
+    }
+
+    public String getBindingAdapterInstanceClass() {
+        return getGetterCall().getBindingAdapterInstanceClass();
+    }
+
+    /**
+     * The min api level in which this binding should be executed.
+     * <p>
+     * This should be the minimum value among the dependencies of this binding.
+     */
+    public int getMinApi() {
+        final BindingGetterCall getterCall = getGetterCall();
+        return Math.max(getterCall.getMinApi(), getterCall.getEvent().getMinApi());
+    }
+
+    public BindingSetterCall getEventSetter() {
+        final BindingGetterCall getterCall = getGetterCall();
+        return getterCall.getEvent();
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public String getEventAttribute() {
+        return getGetterCall().getEventAttribute();
+    }
+
+    public ExprModel getModel() {
+        if (mExpr != null) {
+            return mExpr.getModel();
+        }
+        return mChainedExpressions.get(0).getModel();
+    }
+}
diff --git a/compiler/src/main/java/android/databinding/tool/LayoutBinder.java b/compiler/src/main/java/android/databinding/tool/LayoutBinder.java
index be523bd..7ed944a 100644
--- a/compiler/src/main/java/android/databinding/tool/LayoutBinder.java
+++ b/compiler/src/main/java/android/databinding/tool/LayoutBinder.java
@@ -16,37 +16,38 @@
 
 package android.databinding.tool;
 
-import org.antlr.v4.runtime.misc.Nullable;
-
 import android.databinding.tool.expr.Dependency;
 import android.databinding.tool.expr.Expr;
 import android.databinding.tool.expr.ExprModel;
-import android.databinding.tool.expr.ExprModel.ResolveListenersCallback;
 import android.databinding.tool.expr.IdentifierExpr;
 import android.databinding.tool.processing.Scope;
 import android.databinding.tool.processing.scopes.FileScopeProvider;
 import android.databinding.tool.store.Location;
 import android.databinding.tool.store.ResourceBundle;
 import android.databinding.tool.store.ResourceBundle.BindingTargetBundle;
+import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
 import android.databinding.tool.writer.LayoutBinderWriter;
-import android.databinding.tool.writer.WriterPackage;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
+
+import org.antlr.v4.runtime.misc.Nullable;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 
 /**
  * Keeps all information about the bindings per layout file
  */
-public class LayoutBinder implements ResolveListenersCallback, FileScopeProvider {
+public class LayoutBinder implements FileScopeProvider {
     private static final Comparator<BindingTarget> COMPARE_FIELD_NAME = new Comparator<BindingTarget>() {
         @Override
         public int compare(BindingTarget first, BindingTarget second) {
-            final String fieldName1 = WriterPackage.getFieldName(first);
-            final String fieldName2 = WriterPackage.getFieldName(second);
+            final String fieldName1 = LayoutBinderWriterKt.getFieldName(first);
+            final String fieldName2 = LayoutBinderWriterKt.getFieldName(second);
             return fieldName1.compareTo(fieldName2);
         }
     };
@@ -172,27 +173,63 @@
             mBindingTargets = new ArrayList<BindingTarget>();
             mBundle = layoutBundle;
             mModulePackage = layoutBundle.getModulePackage();
+            HashSet<String> names = new HashSet<String>();
             // copy over data.
-            for (ResourceBundle.NameTypeLocation variable : mBundle.getVariables()) {
-                addVariable(variable.name, variable.type, variable.location);
+            for (ResourceBundle.VariableDeclaration variable : mBundle.getVariables()) {
+                addVariable(variable.name, variable.type, variable.location, variable.declared);
+                names.add(variable.name);
             }
 
             for (ResourceBundle.NameTypeLocation userImport : mBundle.getImports()) {
                 mExprModel.addImport(userImport.name, userImport.type, userImport.location);
+                names.add(userImport.name);
+            }
+            if (!names.contains("context")) {
+                mExprModel.builtInVariable("context", "android.content.Context",
+                        "getRoot().getContext()");
+                names.add("context");
             }
             for (String javaLangClass : sJavaLangClasses) {
                 mExprModel.addImport(javaLangClass, "java.lang." + javaLangClass, null);
             }
+            // First resolve all the View fields
+            // Ensure there are no conflicts with variable names
             for (BindingTargetBundle targetBundle : mBundle.getBindingTargetBundles()) {
                 try {
                     Scope.enter(targetBundle);
                     final BindingTarget bindingTarget = createBindingTarget(targetBundle);
-                    for (BindingTargetBundle.BindingBundle bindingBundle : targetBundle
-                            .getBindingBundleList()) {
-                        bindingTarget.addBinding(bindingBundle.getName(),
-                                parse(bindingBundle.getExpr(), bindingBundle.getValueLocation()));
+                    if (bindingTarget.getId() != null) {
+                        final String fieldName = LayoutBinderWriterKt.
+                                getReadableName(bindingTarget);
+                        if (names.contains(fieldName)) {
+                            L.w("View field %s collides with a variable or import", fieldName);
+                        } else {
+                            names.add(fieldName);
+                            mExprModel.viewFieldExpr(bindingTarget);
+                        }
                     }
+                } finally {
+                    Scope.exit();
+                }
+            }
+
+            for (BindingTarget bindingTarget : mBindingTargets) {
+                try {
+                    Scope.enter(bindingTarget.mBundle);
+                    for (BindingTargetBundle.BindingBundle bindingBundle : bindingTarget.mBundle
+                            .getBindingBundleList()) {
+                        try {
+                            Scope.enter(bindingBundle.getValueLocation());
+                            bindingTarget.addBinding(bindingBundle.getName(),
+                                    parse(bindingBundle.getExpr(), bindingBundle.isTwoWay(),
+                                            bindingBundle.getValueLocation()));
+                        } finally {
+                            Scope.exit();
+                        }
+                    }
+                    bindingTarget.resolveTwoWayExpressions();
                     bindingTarget.resolveMultiSetters();
+                    bindingTarget.resolveListeners();
                 } finally {
                     Scope.exit();
                 }
@@ -223,7 +260,8 @@
         }
     }
 
-    public IdentifierExpr addVariable(String name, String type, Location location) {
+    public IdentifierExpr addVariable(String name, String type, Location location,
+            boolean declared) {
         Preconditions.check(!mUserDefinedVariables.containsKey(name),
                 "%s has already been defined as %s", name, type);
         final IdentifierExpr id = mExprModel.identifier(name);
@@ -233,6 +271,9 @@
             id.addLocation(location);
         }
         mUserDefinedVariables.put(name, type);
+        if (declared) {
+            id.setDeclared();
+        }
         return id;
     }
 
@@ -247,9 +288,10 @@
         return target;
     }
 
-    public Expr parse(String input, @Nullable Location locationInFile) {
+    public Expr parse(String input, boolean isTwoWay, @Nullable Location locationInFile) {
         final Expr parsed = mExpressionParser.parse(input, locationInFile);
         parsed.setBindingExpression(true);
+        parsed.setTwoWay(isTwoWay);
         return parsed;
     }
 
@@ -276,7 +318,7 @@
     }
 
     public void sealModel() {
-        mExprModel.seal(this);
+        mExprModel.seal();
     }
 
     public String writeViewBinderBaseClass(boolean forLibrary) {
@@ -328,15 +370,6 @@
     }
 
     @Override
-    public void resolveListeners() {
-        for (BindingTarget target : mBindingTargets) {
-            for (Binding binding : target.getBindings()) {
-                binding.resolveListeners();
-            }
-        }
-    }
-
-    @Override
     public String provideScopeFilePath() {
         return mBundle.getAbsoluteFilePath();
     }
diff --git a/compiler/src/main/java/android/databinding/tool/MakeCopy.java b/compiler/src/main/java/android/databinding/tool/MakeCopy.java
index f143e21..7627e06 100644
--- a/compiler/src/main/java/android/databinding/tool/MakeCopy.java
+++ b/compiler/src/main/java/android/databinding/tool/MakeCopy.java
@@ -28,6 +28,7 @@
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -166,13 +167,19 @@
 
     private static void processLayoutFiles(String applicationPackage, File resTarget, File srcDir,
             File xmlDir, int minSdk, boolean isLibrary) {
-        ArrayList<File> resourceFolders = new ArrayList<File>();
-        resourceFolders.add(resTarget);
         MakeFileWriter makeFileWriter = new MakeFileWriter(srcDir);
         LayoutXmlProcessor xmlProcessor = new LayoutXmlProcessor(applicationPackage,
-                resourceFolders, makeFileWriter, minSdk, isLibrary);
+                makeFileWriter, minSdk, isLibrary, new LayoutXmlProcessor.OriginalFileLookup() {
+            @Override
+            public File getOriginalFileFor(File file) {
+                return file;
+            }
+        });
         try {
-            xmlProcessor.processResources(minSdk);
+            LayoutXmlProcessor.ResourceInput input = new LayoutXmlProcessor.ResourceInput(
+                    false, resTarget,resTarget
+            );
+            xmlProcessor.processResources(input);
             xmlProcessor.writeLayoutInfoFiles(xmlDir);
             // TODO Looks like make does not support excluding from libs ?
             xmlProcessor.writeInfoClass(null, xmlDir, null);
diff --git a/compiler/src/main/java/android/databinding/tool/MergedBinding.java b/compiler/src/main/java/android/databinding/tool/MergedBinding.java
index e420b95..0f64695 100644
--- a/compiler/src/main/java/android/databinding/tool/MergedBinding.java
+++ b/compiler/src/main/java/android/databinding/tool/MergedBinding.java
@@ -22,8 +22,7 @@
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.store.SetterStore;
 import android.databinding.tool.util.L;
-import android.databinding.tool.writer.CodeGenUtil;
-import android.databinding.tool.writer.WriterPackage;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
 
 import java.lang.reflect.Array;
 import java.util.ArrayList;
@@ -42,8 +41,19 @@
         mMultiAttributeSetter = multiAttributeSetter;
     }
 
+    @Override
+    public void resolveListeners() {
+        ModelClass[] parameters = mMultiAttributeSetter.getParameterTypes();
+        List<Expr> children = getExpr().getChildren();
+        final Expr expr = getExpr();
+        for (int i = 0; i < children.size(); i++) {
+            final Expr child = children.get(i);
+            child.resolveListeners(parameters[i], expr);
+        }
+    }
+
     private static Expr createArgListExpr(ExprModel model, final Iterable<Binding> bindings) {
-        List<Expr> args = new ArrayList<>();
+        List<Expr> args = new ArrayList<Expr>();
         for (Binding binding : bindings) {
             args.add(binding.getExpr());
         }
@@ -60,28 +70,18 @@
         return sb.toString();
     }
 
-    @Override
-    public void resolveListeners() {
-        ModelClass[] params = mMultiAttributeSetter.getParameterTypes();
-        List<Expr> expressions = getExpr().getChildren();
-        for (int i = 0; i < params.length; i++) {
-            expressions.get(i).resolveListeners(params[i]);
-        }
-    }
-
     public Expr[] getComponentExpressions() {
         ArgListExpr args = (ArgListExpr) getExpr();
         return args.getChildren().toArray(new Expr[args.getChildren().size()]);
     }
 
-    @Override
-    public String getBindingAdapterInstanceClass() {
-        return mMultiAttributeSetter.getBindingAdapterInstanceClass();
+    public String[] getAttributes() {
+        return mMultiAttributeSetter.attributes;
     }
 
     @Override
-    public void setBindingAdapterCall(String method) {
-        mMultiAttributeSetter.setBindingAdapterCall(method);
+    public String getBindingAdapterInstanceClass() {
+        return mMultiAttributeSetter.getBindingAdapterInstanceClass();
     }
 
     @Override
@@ -97,15 +97,15 @@
     @Override
     public String toJavaCode(String targetViewName, String bindingComponent) {
         final ArgListExpr args = (ArgListExpr) getExpr();
-        final List<String> newValues = new ArrayList<>();
+        final List<String> newValues = new ArrayList<String>();
         for (Expr expr : args.getChildren()) {
-            newValues.add(CodeGenUtil.Companion.toCode(expr, false).generate());
+            newValues.add(expr.toCode().generate());
         }
         final List<String> oldValues;
         if (requiresOldValue()) {
-            oldValues = new ArrayList<>();
+            oldValues = new ArrayList<String>();
             for (Expr expr : args.getChildren()) {
-                oldValues.add("this." + WriterPackage.getOldValueName(expr));
+                oldValues.add("this." + LayoutBinderWriterKt.getOldValueName(expr));
             }
         } else {
             oldValues = Arrays.asList(new String[args.getChildren().size()]);
@@ -116,7 +116,7 @@
     }
 
     private static <T> T[] concat(List<T> l1, List<T> l2, Class<T> klass) {
-        List<T> result = new ArrayList<>();
+        List<T> result = new ArrayList<T>();
         result.addAll(l1);
         result.addAll(l2);
         return result.toArray((T[]) Array.newInstance(klass, result.size()));
diff --git a/compiler/src/main/java/android/databinding/tool/expr/ArgListExpr.java b/compiler/src/main/java/android/databinding/tool/expr/ArgListExpr.java
index 91ae649..c8f6e2c 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/ArgListExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/ArgListExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -41,6 +42,12 @@
     }
 
     @Override
+    protected KCode generateCode(boolean expand) {
+        throw new IllegalStateException("should never try to convert an argument expressions"
+                + " into code");
+    }
+
+    @Override
     protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
         return modelAnalyzer.findClass(Void.class);
     }
@@ -54,4 +61,9 @@
     public boolean canBeEvaluatedToAVariable() {
         return false;
     }
+
+    @Override
+    public String getInvertibleError() {
+        return "Merged bindings are not invertible.";
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/BitShiftExpr.java b/compiler/src/main/java/android/databinding/tool/expr/BitShiftExpr.java
index e5db9df..cbc895b 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/BitShiftExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/BitShiftExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -54,4 +55,17 @@
     public Expr getRight() {
         return getChildren().get(1);
     }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode()
+                .app("", getLeft().toCode(expand))
+                .app(getOp())
+                .app("", getRight().toCode(expand));
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return "Bit shift operators cannot be inverted in two-way binding";
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/BracketExpr.java b/compiler/src/main/java/android/databinding/tool/expr/BracketExpr.java
index a5ea5a7..392512c 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/BracketExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/BracketExpr.java
@@ -18,12 +18,13 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
 public class BracketExpr extends Expr {
 
-    public static enum BracketAccessor {
+    public enum BracketAccessor {
         ARRAY,
         LIST,
         MAP,
@@ -54,11 +55,23 @@
 
     @Override
     protected List<Dependency> constructDependencies() {
-        return constructDynamicChildrenDependencies();
+        final List<Dependency> dependencies = constructDynamicChildrenDependencies();
+        for (Dependency dependency : dependencies) {
+            if (dependency.getOther() == getTarget()) {
+                dependency.setMandatory(true);
+            }
+        }
+        return dependencies;
     }
 
     protected String computeUniqueKey() {
-        return join(getTarget().computeUniqueKey(), "$", getArg().computeUniqueKey(), "$");
+        final String targetKey = getTarget().computeUniqueKey();
+        return addTwoWay(join(targetKey, "$", getArg().computeUniqueKey(), "$"));
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return null;
     }
 
     public Expr getTarget() {
@@ -74,6 +87,53 @@
     }
 
     public boolean argCastsInteger() {
-        return Object.class.equals(getArg().getResolvedType());
+        return mAccessor != BracketAccessor.MAP && getArg().getResolvedType().isObject();
+    }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        String cast = argCastsInteger() ? "(Integer) " : "";
+        switch (getAccessor()) {
+            case ARRAY: {
+                return new KCode().
+                        app("getFromArray(", getTarget().toCode()).
+                        app(", ").
+                        app(cast, getArg().toCode()).app(")");
+            }
+            case LIST: {
+                ModelClass listType = ModelAnalyzer.getInstance().findClass(java.util.List.class).
+                        erasure();
+                ModelClass targetType = getTarget().getResolvedType().erasure();
+                if (listType.isAssignableFrom(targetType)) {
+                    return new KCode().
+                            app("getFromList(", getTarget().toCode()).
+                            app(", ").
+                            app(cast, getArg().toCode()).
+                            app(")");
+                } else {
+                    return new KCode().
+                            app("", getTarget().toCode()).
+                            app(".get(").
+                            app(cast, getArg().toCode()).
+                            app(")");
+                }
+            }
+            case MAP:
+                return new KCode().
+                        app("", getTarget().toCode()).
+                        app(".get(", getArg().toCode()).
+                        app(")");
+        }
+        throw new IllegalStateException("Invalid BracketAccessor type");
+    }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        String cast = argCastsInteger() ? "(Integer) " : "";
+        return new KCode().
+                app("setTo(", getTarget().toCode(true)).
+                app(", ").
+                app(cast, getArg().toCode(true)).
+                app(", ", value).app(");");
     }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/BuiltInVariableExpr.java b/compiler/src/main/java/android/databinding/tool/expr/BuiltInVariableExpr.java
new file mode 100644
index 0000000..d2fdea1
--- /dev/null
+++ b/compiler/src/main/java/android/databinding/tool/expr/BuiltInVariableExpr.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool.expr;
+
+import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BuiltInVariableExpr extends IdentifierExpr {
+    private final String mAccessCode;
+
+    BuiltInVariableExpr(String name, String type, String accessCode) {
+        super(name);
+        super.setUserDefinedType(type);
+        this.mAccessCode = accessCode;
+    }
+
+    @Override
+    public boolean isDynamic() {
+        return false;
+    }
+
+    @Override
+    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
+        ModelClass modelClass = super.resolveType(modelAnalyzer);
+        return modelClass;
+    }
+
+    @Override
+    protected List<Dependency> constructDependencies() {
+        return new ArrayList<Dependency>();
+    }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        if (mAccessCode == null) {
+            return new KCode().app(mName);
+        } else {
+            return new KCode().app(mAccessCode);
+        }
+    }
+
+    public boolean isDeclared() {
+        return false;
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return "Built-in variables may not be the target of two-way binding";
+    }
+}
diff --git a/compiler/src/main/java/android/databinding/tool/expr/CastExpr.java b/compiler/src/main/java/android/databinding/tool/expr/CastExpr.java
index 552de30..9a4a36a 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/CastExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/CastExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -45,7 +46,7 @@
     }
 
     protected String computeUniqueKey() {
-        return join(mType, getCastExpr().computeUniqueKey());
+        return addTwoWay(join(mType, getCastExpr().computeUniqueKey()));
     }
 
     public Expr getCastExpr() {
@@ -55,4 +56,23 @@
     public String getCastType() {
         return getResolvedType().toJavaCode();
     }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode()
+                .app("(")
+                .app(getCastType())
+                .app(") ", getCastExpr().toCode(expand));
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return getCastExpr().getInvertibleError();
+    }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        // assume no need to cast in reverse
+        return getCastExpr().toInverseCode(value);
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/ComparisonExpr.java b/compiler/src/main/java/android/databinding/tool/expr/ComparisonExpr.java
index 42b188a..172ea21 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/ComparisonExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/ComparisonExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -59,4 +60,16 @@
     public boolean isEqualityCheck() {
         return "==".equals(mOp.trim());
     }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode().app("", getLeft().toCode(expand))
+        .app(" ").app(getOp()).app(" ")
+        .app("", getRight().toCode(expand));
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return "Comparison operators are not valid as targets of two-way binding";
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/Expr.java b/compiler/src/main/java/android/databinding/tool/expr/Expr.java
index 1712bb1..193501c 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/Expr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/Expr.java
@@ -21,17 +21,19 @@
 import android.databinding.tool.processing.ErrorMessages;
 import android.databinding.tool.processing.Scope;
 import android.databinding.tool.processing.scopes.LocationScopeProvider;
-import android.databinding.tool.processing.scopes.ScopeProvider;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.store.Location;
 import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.writer.KCode;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
 
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 abstract public class Expr implements VersionProvider, LocationScopeProvider {
 
@@ -61,7 +63,7 @@
     private boolean mCanBeInvalidated = false;
 
     @Nullable
-    private List<Location> mLocations = new ArrayList<>();
+    private List<Location> mLocations = new ArrayList<Location>();
 
     /**
      * This set denotes the times when this expression is invalid.
@@ -96,6 +98,7 @@
      */
     private boolean mRead;
     private boolean mIsUsed = false;
+    private boolean mIsTwoWay = false;
 
     Expr(Iterable<Expr> children) {
         for (Expr expr : children) {
@@ -167,17 +170,21 @@
         return getResolvedType().isObservable();
     }
 
-    public boolean resolveListeners(ModelClass valueType) {
-        boolean resetResolvedType = false;
-        for (Expr child : getChildren()) {
-            if (child.resolveListeners(valueType)) {
-                resetResolvedType = true;
-            }
+    public Expr resolveListeners(ModelClass valueType, Expr parent) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            Expr child = mChildren.get(i);
+            child.resolveListeners(valueType, this);
         }
-        if (resetResolvedType) {
-            mResolvedType = null;
+        resetResolvedType();
+        return this;
+    }
+
+    public Expr resolveTwoWayExpressions(Expr parent) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final Expr child = mChildren.get(i);
+            child.resolveTwoWayExpressions(this);
         }
-        return resetResolvedType;
+        return this;
     }
 
     protected void resetResolvedType() {
@@ -203,6 +210,22 @@
         mModel = model;
     }
 
+    public void setTwoWay(boolean isTwoWay) {
+        mIsTwoWay = isTwoWay;
+    }
+
+    public boolean isTwoWay() {
+        return mIsTwoWay;
+    }
+
+    protected String addTwoWay(String uniqueKey) {
+        if (mIsTwoWay) {
+            return "twoWay(" + uniqueKey + ")";
+        } else {
+            return "oneWay(" + uniqueKey + ")";
+        }
+    }
+
     private BitSet resolveShouldReadWithConditionals() {
         // ensure we have invalid flags
         BitSet bitSet = new BitSet();
@@ -212,7 +235,6 @@
         }
 
         for (Dependency dependency : getDependants()) {
-            // first traverse non-conditionals because we'll avoid adding conditionals if we are get because of these anyways
             if (dependency.getCondition() == null) {
                 bitSet.or(dependency.getDependant().getShouldReadFlagsWithConditionals());
             } else {
@@ -411,7 +433,7 @@
      */
     public int getRequirementFlagIndex(boolean expectedOutput) {
         Preconditions.check(mRequirementId != NO_ID, "If this is an expression w/ conditional"
-                + " dependencies, it must be assigned a requirement ID");
+                + " dependencies, it must be assigned a requirement ID. %s", this);
         return expectedOutput ? mRequirementId + 1 : mRequirementId;
     }
 
@@ -476,6 +498,7 @@
 
         clone.andNot(mReadSoFar);
         mRead = clone.isEmpty();
+
         if (!mRead && !mReadSoFar.isEmpty()) {
             // check if remaining dependencies can be satisfied w/ existing values
             // for predicate flags, this expr may already be calculated to get the predicate
@@ -483,25 +506,29 @@
             // them. If any of them is completely covered w/ our non-conditional flags, no reason
             // to add them to the list since we'll already be calculated due to our non-conditional
             // flags
-
+            boolean allCovered = true;
             for (int i = clone.nextSetBit(0); i != -1; i = clone.nextSetBit(i + 1)) {
                 final Expr expr = mModel.findFlagExpression(i);
-                if (expr == null || !expr.isConditional()) {
+                if (expr == null) {
                     continue;
                 }
-                final BitSet readForConditional = expr.findConditionalFlags();
+                if (!expr.isConditional()) {
+                    allCovered = false;
+                    break;
+                }
+                final BitSet readForConditional = (BitSet) expr.findConditionalFlags().clone();
+
+                // FIXME: this does not do full traversal so misses some cases
                 // to calculate that conditional, i should've read /readForConditional/ flags
-                // if my read-so-far bits has any common w/ that; that means i would've already
+                // if my read-so-far bits cover that; that means i would've already
                 // read myself
-                clone.andNot(readForConditional);
-                final BitSet invalidFlags = (BitSet) getInvalidFlags().clone();
-                invalidFlags.andNot(readForConditional);
-                mRead = invalidFlags.isEmpty() || clone.isEmpty();
-                if (mRead) {
+                readForConditional.andNot(mReadSoFar);
+                if (!readForConditional.isEmpty()) {
+                    allCovered = false;
                     break;
                 }
             }
-
+            mRead = allCovered;
         }
         if (mRead) {
             mShouldReadFlags = null; // if we've been marked as read, clear should read flags
@@ -545,10 +572,12 @@
 
     private Node mCalculationPaths = null;
 
+    /**
+     * All flag paths that will result in calculation of this expression.
+     */
     protected Node getAllCalculationPaths() {
         if (mCalculationPaths == null) {
             Node node = new Node();
-            // TODO distant parent w/ conditionals are still not traversed :/
             if (isConditional()) {
                 node.mBitSet.or(getPredicateInvalidFlags());
             } else {
@@ -561,6 +590,7 @@
                     cond.setConditionFlag(
                             dependant.getRequirementFlagIndex(dependency.getExpectedOutput()));
                     cond.mParents.add(dependant.getAllCalculationPaths());
+                    node.mParents.add(cond);
                 } else {
                     node.mParents.add(dependant.getAllCalculationPaths());
                 }
@@ -612,6 +642,13 @@
     }
 
     public void updateExpr(ModelAnalyzer modelAnalyzer) {
+        final Map<String, Expr> exprMap = mModel.getExprMap();
+        for (int i = mParents.size() - 1; i >= 0; i--) {
+            final Expr parent = mParents.get(i);
+            if (exprMap.get(parent.getUniqueKey()) != parent) {
+                mParents.remove(i);
+            }
+        }
         for (Expr child : mChildren) {
             child.updateExpr(modelAnalyzer);
         }
@@ -648,6 +685,54 @@
         return mLocations;
     }
 
+    public KCode toCode() {
+        return toCode(false);
+    }
+
+    protected KCode toCode(boolean expand) {
+        if (!expand && isDynamic()) {
+            return new KCode(LayoutBinderWriterKt.getExecutePendingLocalName(this));
+        }
+        return generateCode(expand);
+    }
+
+    public KCode toFullCode() {
+        return generateCode(false);
+    }
+
+    protected abstract KCode generateCode(boolean expand);
+
+    public KCode toInverseCode(KCode value) {
+        throw new IllegalStateException("expression does not support two-way binding");
+    }
+
+    public void assertIsInvertible() {
+        final String errorMessage = getInvertibleError();
+        if (errorMessage != null) {
+            L.e(ErrorMessages.EXPRESSION_NOT_INVERTIBLE, toFullCode().generate(),
+                    errorMessage);
+        }
+    }
+
+    /**
+     * @return The reason the expression wasn't invertible or null if it was invertible.
+     */
+    protected abstract String getInvertibleError();
+
+    /**
+     * This expression is the predicate for 1 or more ternary expressions.
+     */
+    public boolean hasConditionalDependant() {
+        for (Dependency dependency : getDependants()) {
+            Expr dependant = dependency.getDependant();
+            if (dependant.isConditional() && dependant instanceof TernaryExpr) {
+                TernaryExpr ternary = (TernaryExpr) dependant;
+                return ternary.getPred() == this;
+            }
+        }
+        return false;
+    }
+
     static class Node {
 
         BitSet mBitSet = new BitSet();
@@ -656,19 +741,24 @@
 
         public boolean areAllPathsSatisfied(BitSet readSoFar) {
             if (mConditionFlag != -1) {
-                return readSoFar.get(mConditionFlag) || mParents.get(0)
-                        .areAllPathsSatisfied(readSoFar);
+                return readSoFar.get(mConditionFlag)
+                        || mParents.get(0).areAllPathsSatisfied(readSoFar);
             } else {
-                final BitSet clone = (BitSet) readSoFar.clone();
-                clone.and(mBitSet);
-                if (!clone.isEmpty()) {
-                    return true;
-                }
-                if (mParents.isEmpty()) {
+                final BitSet myBitsClone = (BitSet) mBitSet.clone();
+                myBitsClone.andNot(readSoFar);
+                if (!myBitsClone.isEmpty()) {
+                    // read so far does not cover all of my invalidation. The only way I could be
+                    // covered is that I only have 1 conditional dependent which is covered by this.
+                    if (mParents.size() == 1 && mParents.get(0).mConditionFlag != -1) {
+                        return mParents.get(0).areAllPathsSatisfied(readSoFar);
+                    }
                     return false;
                 }
+                if (mParents.isEmpty()) {
+                    return true;
+                }
                 for (Node parent : mParents) {
-                    if (!parent.areAllPathsSatisfied(clone)) {
+                    if (!parent.areAllPathsSatisfied(readSoFar)) {
                         return false;
                     }
                 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java b/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java
index e1f6f79..058427e 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/ExprModel.java
@@ -16,15 +16,18 @@
 
 package android.databinding.tool.expr;
 
-import org.antlr.v4.runtime.ParserRuleContext;
-
+import android.databinding.tool.BindingTarget;
+import android.databinding.tool.InverseBinding;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.reflection.ModelMethod;
 import android.databinding.tool.store.Location;
 import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
 import android.databinding.tool.writer.FlagSet;
 
+import org.antlr.v4.runtime.ParserRuleContext;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -52,6 +55,7 @@
      * Any expression can be invalidated by invalidating this flag.
      */
     private BitSet mInvalidateAnyFlags;
+    private int mInvalidateAnyFlagIndex;
 
     /**
      * Used by code generation. Keeps the list of expressions that are waiting to be evaluated.
@@ -116,10 +120,6 @@
         mCurrentParserContext = currentParserContext;
     }
 
-    public void unregister(Expr expr) {
-        mExprMap.remove(expr.getUniqueKey());
-    }
-
     public Map<String, Expr> getExprMap() {
         return mExprMap;
     }
@@ -160,6 +160,14 @@
         return register(new StaticIdentifierExpr(name));
     }
 
+    public BuiltInVariableExpr builtInVariable(String name, String type, String accessCode) {
+        return register(new BuiltInVariableExpr(name, type, accessCode));
+    }
+
+    public ViewFieldExpr viewFieldExpr(BindingTarget bindingTarget) {
+        return register(new ViewFieldExpr(bindingTarget));
+    }
+
     /**
      * Creates a static identifier for the given class or returns the existing one.
      */
@@ -240,6 +248,9 @@
         return register(new CastExpr(type, expr));
     }
 
+    public TwoWayListenerExpr twoWayListenerExpr(InverseBinding inverseBinding) {
+        return register(new TwoWayListenerExpr(inverseBinding));
+    }
     public List<Expr> getBindingExpressions() {
         return mBindingExpressions;
     }
@@ -275,31 +286,30 @@
         return bindingExpr;
     }
 
+    public void removeExpr(Expr expr) {
+        Preconditions.check(!mSealed, "Can't modify the expression list after sealing the model.");
+        mBindingExpressions.remove(expr);
+        mExprMap.remove(expr.computeUniqueKey());
+    }
+
     public List<Expr> getObservables() {
         return mObservables;
     }
 
-    public void seal() {
-        seal(null);
-    }
     /**
      * Give id to each expression. Will be useful if we serialize.
      */
-    public void seal(ResolveListenersCallback resolveListeners) {
+    public void seal() {
         L.d("sealing model");
         List<Expr> notifiableExpressions = new ArrayList<Expr>();
         //ensure class analyzer. We need to know observables at this point
         final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
         updateExpressions(modelAnalyzer);
 
-        if (resolveListeners != null) {
-            resolveListeners.resolveListeners();
-        }
-
         int counter = 0;
         final Iterable<Expr> observables = filterObservables(modelAnalyzer);
-        List<String> flagMapping = new ArrayList<>();
-        mObservables = new ArrayList<>();
+        List<String> flagMapping = new ArrayList<String>();
+        mObservables = new ArrayList<Expr>();
         for (Expr expr : observables) {
             // observables gets initial ids
             flagMapping.add(expr.getUniqueKey());
@@ -341,6 +351,17 @@
             }
         }
 
+        // now all 2-way bound view fields
+        for (Expr expr : mExprMap.values()) {
+            if (expr instanceof FieldAccessExpr) {
+                FieldAccessExpr fieldAccessExpr = (FieldAccessExpr) expr;
+                if (fieldAccessExpr.getChild() instanceof ViewFieldExpr) {
+                    flagMapping.add(fieldAccessExpr.getUniqueKey());
+                    fieldAccessExpr.setId(counter++);
+                }
+            }
+        }
+
         // non-dynamic binding expressions receive some ids so that they can be invalidated
         L.d("list of binding expressions");
         for (int i = 0; i < mBindingExpressions.size(); i++) {
@@ -357,7 +378,7 @@
         for (Expr expr : mExprMap.values()) {
             expr.getDependencies();
         }
-        final int invalidateAnyFlagIndex = counter ++;
+        mInvalidateAnyFlagIndex = counter ++;
         flagMapping.add("INVALIDATE ANY");
         mInvalidateableFieldLimit = counter;
         mInvalidateableFlags = new BitSet();
@@ -394,7 +415,7 @@
 
         mFlagBucketCount = 1 + (getTotalFlagCount() / FlagSet.sBucketSize);
         mInvalidateAnyFlags = new BitSet();
-        mInvalidateAnyFlags.set(invalidateAnyFlagIndex, true);
+        mInvalidateAnyFlags.set(mInvalidateAnyFlagIndex, true);
 
         for (Expr expr : mExprMap.values()) {
             expr.getShouldReadFlagsWithConditionals();
@@ -446,7 +467,7 @@
     }
 
     private List<Expr> filterNonObservableIds(final ModelAnalyzer modelAnalyzer) {
-        List<Expr> result = new ArrayList<>();
+        List<Expr> result = new ArrayList<Expr>();
         for (Expr input : mExprMap.values()) {
             if (input instanceof IdentifierExpr
                     && !input.hasId()
@@ -459,7 +480,7 @@
     }
 
     private Iterable<Expr> filterObservables(final ModelAnalyzer modelAnalyzer) {
-        List<Expr> result = new ArrayList<>();
+        List<Expr> result = new ArrayList<Expr>();
         for (Expr input : mExprMap.values()) {
             if (input.isObservable()) {
                 result.add(input);
@@ -470,9 +491,11 @@
 
     public List<Expr> getPendingExpressions() {
         if (mPendingExpressions == null) {
-            mPendingExpressions = new ArrayList<>();
+            mPendingExpressions = new ArrayList<Expr>();
             for (Expr expr : mExprMap.values()) {
-                if (!expr.isRead() && expr.isDynamic()) {
+                // if an expression is NOT dynanic but has conditional dependants, still return it
+                // so that conditional flags can be set
+                if (!expr.isRead() && (expr.isDynamic() || expr.hasConditionalDependant())) {
                     mPendingExpressions.add(expr);
                 }
             }
@@ -482,7 +505,7 @@
 
     public boolean markBitsRead() {
         // each has should read flags, we set them back on them
-        List<Expr> markedSomeFlagsRead = new ArrayList<>();
+        List<Expr> markedSomeFlagsRead = new ArrayList<Expr>();
         for (Expr expr : filterShouldRead(getPendingExpressions())) {
             expr.markFlagsAsRead(expr.getShouldReadFlags());
             markedSomeFlagsRead.add(expr);
@@ -492,7 +515,7 @@
 
     private boolean pruneDone(List<Expr> markedSomeFlagsAsRead) {
         boolean marked = true;
-        List<Expr> markedAsReadList = new ArrayList<>();
+        List<Expr> markedAsReadList = new ArrayList<Expr>();
         while (marked) {
             marked = false;
             for (Expr expr : mExprMap.values()) {
@@ -516,14 +539,15 @@
             }
         }
         for (Expr partialRead : markedSomeFlagsAsRead) {
-            boolean allPathsAreSatisfied = partialRead.getAllCalculationPaths()
-                    .areAllPathsSatisfied(partialRead.mReadSoFar);
-            if (!allPathsAreSatisfied) {
-                continue;
-            }
+            // even if all paths are not satisfied, we can elevate certain conditional dependencies
+            // if all of their paths are satisfied.
             for (Dependency dependency : partialRead.getDependants()) {
-                if (dependency.getDependant().considerElevatingConditionals(partialRead)) {
-                    elevated = true;
+                Expr dependant = dependency.getDependant();
+                if (dependant.isConditional() && dependant.getAllCalculationPaths()
+                        .areAllPathsSatisfied(partialRead.mReadSoFar)) {
+                    if (dependant.considerElevatingConditionals(partialRead)) {
+                        elevated = true;
+                    }
                 }
             }
         }
@@ -549,7 +573,7 @@
     }
 
     public static List<Expr> filterShouldRead(Iterable<Expr> exprs) {
-        List<Expr> result = new ArrayList<>();
+        List<Expr> result = new ArrayList<Expr>();
         for (Expr expr : exprs) {
             if (!expr.getShouldReadFlags().isEmpty() &&
                     !hasConditionalOrNestedCannotReadDependency(expr)) {
@@ -594,6 +618,10 @@
         return mInvalidateAnyFlags;
     }
 
+    public int getInvalidateAnyFlagIndex() {
+        return mInvalidateAnyFlagIndex;
+    }
+
     public Expr argListExpr(Iterable<Expr> expressions) {
         return register(new ArgListExpr(mArgListIdCounter ++, expressions));
     }
@@ -602,7 +630,8 @@
         mCurrentLocationInFile = location;
     }
 
-    public interface ResolveListenersCallback {
-        void resolveListeners();
+    public Expr listenerExpr(Expr expression, String name, ModelClass listenerType,
+            ModelMethod listenerMethod) {
+        return register(new ListenerExpr(expression, name, listenerType, listenerMethod));
     }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java b/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java
index 220cb54..ff55a00 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/FieldAccessExpr.java
@@ -16,25 +16,33 @@
 
 package android.databinding.tool.expr;
 
+import android.databinding.tool.ext.ExtKt;
+import android.databinding.tool.Binding;
+import android.databinding.tool.BindingTarget;
+import android.databinding.tool.InverseBinding;
 import android.databinding.tool.processing.Scope;
 import android.databinding.tool.reflection.Callable;
 import android.databinding.tool.reflection.Callable.Type;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.reflection.ModelMethod;
+import android.databinding.tool.util.BrNameUtil;
+import android.databinding.tool.store.SetterStore;
+import android.databinding.tool.store.SetterStore.BindingGetterCall;
 import android.databinding.tool.util.L;
+import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.writer.KCode;
 
-import java.util.ArrayList;
 import java.util.List;
 
 public class FieldAccessExpr extends Expr {
     String mName;
+    // notification name for the field. Important when we map this to a method w/ different name
+    String mBrName;
     Callable mGetter;
     final boolean mIsObservableField;
-    private List<ModelMethod> mListenerMethods;
-    private List<ModelMethod> mCalledMethods;
-    private List<ModelClass> mListenerTypes;
-    private List<ModelMethod> mPotentialListeners;
+    boolean mIsListener;
+    boolean mIsViewAttributeAccess;
 
     FieldAccessExpr(Expr parent, String name) {
         super(parent);
@@ -59,29 +67,20 @@
         return mGetter;
     }
 
-    public List<ModelMethod> getListenerMethods() {
-        return mListenerMethods;
-    }
-
-    public List<ModelMethod> getCalledMethods() {
-        return mCalledMethods;
-    }
-
-    public List<ModelClass> getListenerTypes() { return mListenerTypes; }
-
-    public boolean isListener() {
-        return mListenerMethods != null && !mListenerMethods.isEmpty();
+    @Override
+    public String getInvertibleError() {
+        if (getGetter().setterName == null) {
+            return "Two-way binding cannot resolve a setter for " + getResolvedType().toJavaCode() +
+                    " property '" + mName + "'";
+        }
+        if (!mGetter.isDynamic()) {
+            return "Cannot change a final field in " + getResolvedType().toJavaCode() +
+                    " property " + mName;
+        }
+        return null;
     }
 
     public int getMinApi() {
-        if (isListener()) {
-            int minApi = 1;
-            for (ModelClass listener : mListenerTypes) {
-                int listenerApi = listener.getMinApi();
-                minApi = Math.max(minApi, listenerApi);
-            }
-            return minApi;
-        }
         return mGetter.getMinApi();
     }
 
@@ -91,7 +90,7 @@
             getResolvedType();
         }
         if (mGetter == null || mGetter.type == Type.METHOD) {
-            return !isListener();
+            return true;
         }
         // if it is static final, gone
         if (getChild().isDynamic()) {
@@ -99,6 +98,10 @@
             return !mGetter.isStatic() || mGetter.isDynamic();
         }
 
+        if (mIsViewAttributeAccess) {
+            return true; // must be able to invalidate this
+        }
+
         // if owner is NOT dynamic, we can be dynamic if an only if getter is dynamic
         return mGetter.isDynamic();
     }
@@ -108,55 +111,71 @@
     }
 
     @Override
-    public boolean resolveListeners(ModelClass listener) {
-        if (mPotentialListeners == null) {
-            return false;
+    public Expr resolveListeners(ModelClass listener, Expr parent) {
+        if (mName == null || mName.isEmpty()) {
+            return this; // ObservableFields aren't listeners
         }
-
+        final ModelClass childType = getChild().getResolvedType();
+        if (getGetter() == null) {
+            if (listener == null || !mIsListener) {
+                L.e("Could not resolve %s.%s as an accessor or listener on the attribute.",
+                        childType.getCanonicalName(), mName);
+                return this;
+            }
+            getChild().getParents().remove(this);
+        } else if (listener == null) {
+            return this; // Not a listener, but we have a getter.
+        }
         List<ModelMethod> abstractMethods = listener.getAbstractMethods();
         int numberOfAbstractMethods = abstractMethods == null ? 0 : abstractMethods.size();
         if (numberOfAbstractMethods != 1) {
             if (mGetter == null) {
                 L.e("Could not find accessor %s.%s and %s has %d abstract methods, so is" +
                                 " not resolved as a listener",
-                        getChild().getResolvedType().getCanonicalName(), mName,
+                        childType.getCanonicalName(), mName,
                         listener.getCanonicalName(), numberOfAbstractMethods);
             }
-            return false;
-        }
-
-        // See if we've already resolved this listener type
-        if (mListenerMethods == null) {
-            mListenerMethods = new ArrayList<ModelMethod>();
-            mCalledMethods = new ArrayList<ModelMethod>();
-            mListenerTypes = new ArrayList<ModelClass>();
-        } else {
-            for (ModelClass previousListeners : mListenerTypes) {
-                if (previousListeners.equals(listener)) {
-                    return false;
-                }
-            }
+            return this;
         }
 
         // Look for a signature matching the abstract method
         final ModelMethod listenerMethod = abstractMethods.get(0);
         final ModelClass[] listenerParameters = listenerMethod.getParameterTypes();
-        for (ModelMethod method : mPotentialListeners) {
-            if (acceptsParameters(method, listenerParameters)) {
-                mListenerTypes.add(listener);
-                mListenerMethods.add(listenerMethod);
-                mCalledMethods.add(method);
+        boolean isStatic = getChild() instanceof StaticIdentifierExpr;
+        List<ModelMethod> methods = childType.findMethods(mName, isStatic);
+        if (methods == null) {
+            return this;
+        }
+        for (ModelMethod method : methods) {
+            if (acceptsParameters(method, listenerParameters) &&
+                    method.getReturnType(null).equals(listenerMethod.getReturnType(null))) {
                 resetResolvedType();
-                return true;
+                // replace this with ListenerExpr in parent
+                Expr listenerExpr = getModel().listenerExpr(getChild(), mName, listener,
+                        listenerMethod);
+                if (parent != null) {
+                    int index;
+                    while ((index = parent.getChildren().indexOf(this)) != -1) {
+                        parent.getChildren().set(index, listenerExpr);
+                    }
+                }
+                if (getModel().mBindingExpressions.contains(this)) {
+                    getModel().bindingExpr(listenerExpr);
+                }
+                getParents().remove(parent);
+                if (getParents().isEmpty()) {
+                    getModel().removeExpr(this);
+                }
+                return listenerExpr;
             }
         }
 
         if (mGetter == null) {
             L.e("Listener class %s with method %s did not match signature of any method %s.%s",
                     listener.getCanonicalName(), listenerMethod.getName(),
-                    getChild().getResolvedType().getCanonicalName(), mName);
+                    childType.getCanonicalName(), mName);
         }
-        return false;
+        return this;
     }
 
     private boolean acceptsParameters(ModelMethod method, ModelClass[] listenerParameters) {
@@ -186,15 +205,28 @@
     @Override
     protected String computeUniqueKey() {
         if (mIsObservableField) {
-            return join(mName, "..", super.computeUniqueKey());
+            return addTwoWay(join(mName, "..", super.computeUniqueKey()));
         }
-        return join(mName, ".", super.computeUniqueKey());
+        return addTwoWay(join(mName, ".", super.computeUniqueKey()));
     }
 
     public String getName() {
         return mName;
     }
 
+    public String getBrName() {
+        if (mIsListener) {
+            return null;
+        }
+        try {
+            Scope.enter(this);
+            Preconditions.checkNotNull(mGetter, "cannot get br name before resolving the getter");
+            return mBrName;
+        } finally {
+            Scope.exit();
+        }
+    }
+
     @Override
     public void updateExpr(ModelAnalyzer modelAnalyzer) {
         try {
@@ -208,10 +240,10 @@
 
     @Override
     protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
+        if (mIsListener) {
+            return modelAnalyzer.findClass(Object.class);
+        }
         if (mGetter == null) {
-            if (mPotentialListeners != null) {
-                return modelAnalyzer.findClass(Object.class);
-            }
             Expr child = getChild();
             child.getResolvedType();
             boolean isStatic = child instanceof StaticIdentifierExpr;
@@ -219,10 +251,10 @@
             L.d("resolving %s. Resolved class type: %s", this, resolvedType);
 
             mGetter = resolvedType.findGetterOrField(mName, isStatic);
-            mPotentialListeners = resolvedType.findMethods(mName, isStatic);
 
             if (mGetter == null) {
-                if (mPotentialListeners == null) {
+                mIsListener = resolvedType.findMethods(mName, isStatic) != null;
+                if (!mIsListener) {
                     L.e("Could not find accessor %s.%s", resolvedType.getCanonicalName(), mName);
                 }
                 return modelAnalyzer.findClass(Object.class);
@@ -248,19 +280,134 @@
 
                 getChildren().add(observableField);
                 observableField.getParents().add(this);
-                mGetter = mGetter.resolvedType.findGetterOrField("get", false);
+                mGetter = mGetter.resolvedType.findGetterOrField("", false);
                 mName = "";
+                mBrName = ExtKt.br(mName);
+            } else if (hasBindableAnnotations()) {
+                mBrName = ExtKt.br(BrNameUtil.brKey(mGetter));
             }
         }
-        if (isListener()) {
-            return modelAnalyzer.findClass(Object.class);
-        }
         return mGetter.resolvedType;
     }
 
     @Override
+    public Expr resolveTwoWayExpressions(Expr parent) {
+        final Expr child = getChild();
+        if (!(child instanceof ViewFieldExpr)) {
+            return this;
+        }
+        final ViewFieldExpr expr = (ViewFieldExpr) child;
+        final BindingTarget bindingTarget = expr.getBindingTarget();
+
+        // This is a binding to a View's attribute, so look for matching attribute
+        // on that View's BindingTarget. If there is an expression, we simply replace
+        // the binding with that binding expression.
+        for (Binding binding : bindingTarget.getBindings()) {
+            if (attributeMatchesName(binding.getName(), mName)) {
+                final Expr replacement = binding.getExpr();
+                replaceExpression(parent, replacement);
+                return replacement;
+            }
+        }
+
+        // There was no binding expression to bind to. This should be a two-way binding.
+        // This is a synthesized two-way binding because we must capture the events from
+        // the View and change the value when the target View's attribute changes.
+        final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
+        final ModelClass targetClass = expr.getResolvedType();
+        BindingGetterCall getter = setterStore.getGetterCall(mName, targetClass, null, null);
+        if (getter == null) {
+            getter = setterStore.getGetterCall("android:" + mName, targetClass, null, null);
+            if (getter == null) {
+                L.e("Could not resolve the two-way binding attribute '%s' on type '%s'",
+                        mName, targetClass);
+            }
+        }
+        InverseBinding inverseBinding = null;
+        for (Binding binding : bindingTarget.getBindings()) {
+            final Expr testExpr = binding.getExpr();
+            if (testExpr instanceof TwoWayListenerExpr &&
+                    getter.getEventAttribute().equals(binding.getName())) {
+                inverseBinding = ((TwoWayListenerExpr) testExpr).mInverseBinding;
+                break;
+            }
+        }
+        if (inverseBinding == null) {
+            inverseBinding = bindingTarget.addInverseBinding(mName, getter);
+        }
+        inverseBinding.addChainedExpression(this);
+        mIsViewAttributeAccess = true;
+        enableDirectInvalidation();
+        return this;
+    }
+
+    private static boolean attributeMatchesName(String attribute, String field) {
+        int colonIndex = attribute.indexOf(':');
+        return attribute.substring(colonIndex + 1).equals(field);
+    }
+
+    private void replaceExpression(Expr parent, Expr replacement) {
+        if (parent != null) {
+            List<Expr> children = parent.getChildren();
+            int index;
+            while ((index = children.indexOf(this)) >= 0) {
+                children.set(index, replacement);
+                replacement.getParents().add(parent);
+            }
+            while (getParents().remove(parent)) {
+                // just remove all copies of parent.
+            }
+        }
+        if (getParents().isEmpty()) {
+            getModel().removeExpr(this);
+        }
+    }
+
+    @Override
     protected String asPackage() {
         String parentPackage = getChild().asPackage();
         return parentPackage == null ? null : parentPackage + "." + mName;
     }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        KCode code = new KCode();
+        if (expand) {
+            String defaultValue = ModelAnalyzer.getInstance().getDefaultValue(
+                    getResolvedType().toJavaCode());
+            code.app("(", getChild().toCode(true))
+                    .app(" == null) ? ")
+                    .app(defaultValue)
+                    .app(" : ");
+        }
+        code.app("", getChild().toCode(expand)).app(".");
+        if (getGetter().type == Callable.Type.FIELD) {
+            return code.app(getGetter().name);
+        } else {
+            return code.app(getGetter().name).app("()");
+        }
+    }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        if (mGetter.setterName == null) {
+            throw new IllegalStateException("There is no inverse for " + toCode().generate());
+        }
+        KCode castValue = new KCode("(").app(getResolvedType().toJavaCode() + ")(", value).app(")");
+        String type = getChild().getResolvedType().toJavaCode();
+        KCode code = new KCode("targetObj_.");
+        if (getGetter().type == Callable.Type.FIELD) {
+            code.app(getGetter().setterName).app(" = ", castValue).app(";");
+        } else {
+            code.app(getGetter().setterName).app("(", castValue).app(")").app(";");
+        }
+        return new KCode()
+                .app("final ")
+                .app(type)
+                .app(" targetObj_ = ", getChild().toCode(true))
+                .app(";")
+                .nl(new KCode("if (targetObj_ != null) {"))
+                .tab(code)
+                .nl(new KCode("}"));
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/GroupExpr.java b/compiler/src/main/java/android/databinding/tool/expr/GroupExpr.java
index bacfe8d..4a76688 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/GroupExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/GroupExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -36,7 +37,23 @@
         return getWrapped().constructDependencies();
     }
 
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode().app("(", getWrapped().toCode(expand)).app(")");
+    }
+
     public Expr getWrapped() {
         return getChildren().get(0);
     }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        // Nothing to do here. Other expressions should automatically take care of grouping.
+        return getWrapped().toInverseCode(value);
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return getWrapped().getInvertibleError();
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/IdentifierExpr.java b/compiler/src/main/java/android/databinding/tool/expr/IdentifierExpr.java
index f68e3d6..efe4fb1 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/IdentifierExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/IdentifierExpr.java
@@ -19,8 +19,9 @@
 import android.databinding.tool.processing.ErrorMessages;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
-import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.writer.KCode;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -28,6 +29,8 @@
 public class IdentifierExpr extends Expr {
     String mName;
     String mUserDefinedType;
+    private boolean mIsDeclared;
+
     IdentifierExpr(String name) {
         mName = name;
     }
@@ -66,11 +69,38 @@
 
     @Override
     protected List<Dependency> constructDependencies() {
-        return new ArrayList<>();
+        return new ArrayList<Dependency>();
     }
 
     @Override
     protected String asPackage() {
         return mUserDefinedType == null ? mName : null;
     }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        if (expand) {
+            return new KCode(LayoutBinderWriterKt.getFieldName(this));
+        } else {
+            return new KCode(LayoutBinderWriterKt.getExecutePendingLocalName(this));
+        }
+    }
+
+    public void setDeclared() {
+        mIsDeclared = true;
+    }
+
+    public boolean isDeclared() {
+        return mIsDeclared;
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return null;
+    }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        return new KCode().app(LayoutBinderWriterKt.getSetterName(this)).app("(", value).app(");");
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/InstanceOfExpr.java b/compiler/src/main/java/android/databinding/tool/expr/InstanceOfExpr.java
index a3ebd13..980d635 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/InstanceOfExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/InstanceOfExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -36,6 +37,14 @@
     }
 
     @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode()
+                .app("", getExpr().toCode(expand))
+                .app(" instanceof ")
+                .app(getType().toJavaCode());
+    }
+
+    @Override
     protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
         mType = modelAnalyzer.findClass(mTypeStr, getModel().getImports());
         return modelAnalyzer.loadPrimitive("boolean");
@@ -53,4 +62,9 @@
     public ModelClass getType() {
         return mType;
     }
+
+    @Override
+    public String getInvertibleError() {
+        return "two-way binding can't target a value with the 'instanceof' operator";
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/ListenerExpr.java b/compiler/src/main/java/android/databinding/tool/expr/ListenerExpr.java
new file mode 100644
index 0000000..6adf997
--- /dev/null
+++ b/compiler/src/main/java/android/databinding/tool/expr/ListenerExpr.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool.expr;
+
+import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.reflection.ModelMethod;
+import android.databinding.tool.writer.KCode;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This wraps an expression, but makes it unique for a particular event listener type.
+ * This is used to differentiate listener methods. For example:
+ * <pre>
+ *     public void onFoo(String str) {...}
+ *     public void onFoo(int i) {...}
+ * </pre>
+ */
+public class ListenerExpr extends Expr {
+    private final String mName;
+    private final ModelClass mListenerType;
+    private final ModelMethod mMethod;
+
+    ListenerExpr(Expr expr, String name, ModelClass listenerType, ModelMethod method) {
+        super(expr);
+        mName = name;
+        mListenerType = listenerType;
+        mMethod = method;
+    }
+
+    @Override
+    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
+        return mListenerType;
+    }
+
+    public ModelMethod getMethod() {
+        return mMethod;
+    }
+
+    public Expr getChild() {
+        return getChildren().get(0);
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    @Override
+    public boolean isDynamic() {
+        return getChild().isDynamic();
+    }
+
+    @Override
+    protected List<Dependency> constructDependencies() {
+        final List<Dependency> dependencies = new ArrayList<Dependency>();
+        Dependency dependency = new Dependency(this, getChild());
+        dependency.setMandatory(true);
+        dependencies.add(dependency);
+        return dependencies;
+    }
+
+    protected String computeUniqueKey() {
+        return join(getResolvedType().getCanonicalName(), getChild().computeUniqueKey(), mName);
+    }
+
+    @Override
+    public KCode generateCode(boolean expand) {
+        KCode code = new KCode("(");
+        final int minApi = Math.max(mListenerType.getMinApi(), mMethod.getMinApi());
+        if (minApi > 1) {
+            code.app("(getBuildSdkInt() < " + minApi + ") ? null : ");
+        }
+        final String fieldName = LayoutBinderWriterKt.getFieldName(this);
+        final String listenerClassName = LayoutBinderWriterKt.getListenerClassName(this);
+        final KCode value = getChild().toCode();
+            code.app("((")
+                    .app(fieldName)
+                    .app(" == null) ? (")
+                    .app(fieldName)
+                    .app(" = new ")
+                    .app(listenerClassName)
+                    .app("()) : ")
+                    .app(fieldName)
+                    .app(")");
+        if (getChild().isDynamic()) {
+            code.app(".setValue(", value)
+                    .app(")");
+        }
+        code.app(")");
+        return code;
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return "Listeners cannot be the target of a two-way binding";
+    }
+}
diff --git a/compiler/src/main/java/android/databinding/tool/expr/MathExpr.java b/compiler/src/main/java/android/databinding/tool/expr/MathExpr.java
index a105a34..a302659 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/MathExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/MathExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -30,7 +31,7 @@
 
     @Override
     protected String computeUniqueKey() {
-        return join(getLeft().getUniqueKey(), mOp, getRight().getUniqueKey());
+        return addTwoWay(join(getLeft().getUniqueKey(), mOp, getRight().getUniqueKey()));
     }
 
     @Override
@@ -62,4 +63,83 @@
     public Expr getRight() {
         return getChildren().get(1);
     }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode().app("", getLeft().toCode(expand)).app(mOp, getRight().toCode(expand));
+    }
+
+    @Override
+    public String getInvertibleError() {
+        if (mOp.equals("%")) {
+            return "The modulus operator (%) is not supported in two-way binding.";
+        } else if (getResolvedType().isString()) {
+            return "String concatenation operator (+) is not supported in two-way binding.";
+        }
+        if (!getLeft().isDynamic()) {
+            return getRight().getInvertibleError();
+        } else if (!getRight().isDynamic()) {
+            return getLeft().getInvertibleError();
+        } else {
+            return "Arithmetic operator " + mOp + " is not supported with two dynamic expressions.";
+        }
+    }
+
+    private String inverseCast() {
+        if (!getLeft().isDynamic()) {
+            return inverseCast(getRight());
+        } else {
+            return inverseCast(getLeft());
+        }
+    }
+
+    private String inverseCast(Expr expr) {
+        if (!expr.getResolvedType().isAssignableFrom(getResolvedType())) {
+            return "(" + getResolvedType() + ")";
+        }
+        return null;
+    }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        if (!isDynamic()) {
+            return toCode();
+        }
+        final Expr left = getLeft();
+        final Expr right = getRight();
+        final Expr constExpr = left.isDynamic() ? right : left;
+        final Expr varExpr = left.isDynamic() ? left : right;
+        final String cast = inverseCast();
+        if (cast != null) {
+            value = new KCode(cast).app("(", value).app(")");
+        }
+        switch (mOp.charAt(0)) {
+            case '+': // const + x = value  => x = value - const
+                return varExpr.toInverseCode(value.app(" - (", constExpr.toCode()).app(")"));
+            case '*': // const * x = value => x = value / const
+                return varExpr.toInverseCode(value.app(" / (", constExpr.toCode()).app(")"));
+            case '-':
+                if (!left.isDynamic()) { // const - x = value => x = const - value)
+                    return varExpr.toInverseCode(new KCode()
+                            .app("(", constExpr.toCode())
+                            .app(") - (", value)
+                            .app(")"));
+                } else { // x - const = value => x = value + const)
+                    return varExpr.toInverseCode(value.app(" + ", constExpr.toCode()));
+                }
+            case '/':
+                if (!left.isDynamic()) { // const / x = value => x = const / value
+                    return varExpr.toInverseCode(new KCode("(")
+                            .app("", constExpr.toCode())
+                            .app(") / (", value)
+                            .app(")"));
+                } else { // x / const = value => x = value * const
+                    return varExpr.toInverseCode(new KCode("(")
+                            .app("", value)
+                            .app(") * (", constExpr.toCode())
+                            .app(")"));
+                }
+        }
+        throw new IllegalStateException("Invalid math operation is not invertible: " + mOp);
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java b/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java
index a96e8f8..4990981 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/MethodCallExpr.java
@@ -16,6 +16,9 @@
 
 package android.databinding.tool.expr;
 
+import static android.databinding.tool.reflection.Callable.DYNAMIC;
+import static android.databinding.tool.reflection.Callable.STATIC;
+
 import android.databinding.tool.processing.Scope;
 import android.databinding.tool.reflection.Callable;
 import android.databinding.tool.reflection.Callable.Type;
@@ -23,13 +26,10 @@
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.reflection.ModelMethod;
 import android.databinding.tool.util.L;
+import android.databinding.tool.writer.KCode;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-import static android.databinding.tool.reflection.Callable.STATIC;
-import static android.databinding.tool.reflection.Callable.DYNAMIC;
-import static android.databinding.tool.reflection.Callable.CAN_BE_INVALIDATED;
 
 
 public class MethodCallExpr extends Expr {
@@ -38,7 +38,7 @@
     Callable mGetter;
 
     static List<Expr> concat(Expr e, List<Expr> list) {
-        List<Expr> merged = new ArrayList<>();
+        List<Expr> merged = new ArrayList<Expr>();
         merged.add(e);
         merged.addAll(list);
         return merged;
@@ -61,6 +61,26 @@
     }
 
     @Override
+    protected KCode generateCode(boolean expand) {
+        KCode code = new KCode()
+        .app("", getTarget().toCode(expand))
+        .app(".")
+        .app(getGetter().name)
+        .app("(");
+        boolean first = true;
+        for (Expr arg : getArgs()) {
+            if (first) {
+                first = false;
+            } else {
+                code.app(", ");
+            }
+            code.app("", arg.toCode(expand));
+        }
+        code.app(")");
+        return code;
+    }
+
+    @Override
     protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
         if (mGetter == null) {
             List<ModelClass> args = new ArrayList<ModelClass>();
@@ -94,7 +114,8 @@
             if (method.isStatic()) {
                 flags |= STATIC;
             }
-            mGetter = new Callable(Type.METHOD, method.getName(), method.getReturnType(args), flags);
+            mGetter = new Callable(Type.METHOD, method.getName(), null, method.getReturnType(args),
+                    method.getParameterTypes().length, flags);
         }
         return mGetter.resolvedType;
     }
@@ -131,4 +152,9 @@
     public Callable getGetter() {
         return mGetter;
     }
+
+    @Override
+    public String getInvertibleError() {
+        return "Method calls may not be used in two-way expressions";
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/ResourceExpr.java b/compiler/src/main/java/android/databinding/tool/expr/ResourceExpr.java
index fbf7166..752cb9f 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/ResourceExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/ResourceExpr.java
@@ -17,7 +17,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
-import android.databinding.tool.writer.WriterPackage;
+import android.databinding.tool.writer.KCode;
 
 import java.util.HashMap;
 import java.util.List;
@@ -27,7 +27,7 @@
 
     private final static Map<String, String> RESOURCE_TYPE_TO_R_OBJECT;
     static {
-        RESOURCE_TYPE_TO_R_OBJECT = new HashMap<>();
+        RESOURCE_TYPE_TO_R_OBJECT = new HashMap<String, String>();
         RESOURCE_TYPE_TO_R_OBJECT.put("colorStateList", "color  ");
         RESOURCE_TYPE_TO_R_OBJECT.put("dimenOffset", "dimen  ");
         RESOURCE_TYPE_TO_R_OBJECT.put("dimenSize", "dimen  ");
@@ -60,7 +60,7 @@
     private Map<String, ModelClass> getResourceToTypeMapping(ModelAnalyzer modelAnalyzer) {
         if (mResourceToTypeMapping == null) {
             final Map<String, String> imports = getModel().getImports();
-            mResourceToTypeMapping = new HashMap<>();
+            mResourceToTypeMapping = new HashMap<String, ModelClass>();
             mResourceToTypeMapping.put("anim", modelAnalyzer.findClass("android.view.animation.Animation",
                             imports));
             mResourceToTypeMapping.put("animator", modelAnalyzer.findClass("android.animation.Animator",
@@ -129,10 +129,21 @@
         return join(base, computeChildrenKey());
     }
 
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode(toJava());
+    }
+
     public String getResourceId() {
         return mPackage + "R." + getResourceObject() + "." + mResourceId;
     }
 
+    @Override
+    public String getInvertibleError() {
+        return "Resources may not be the target of a two-way binding expression: " +
+                computeUniqueKey();
+    }
+
     public String toJava() {
         final String context = "getRoot().getContext()";
         final String resources = "getRoot().getResources()";
@@ -140,12 +151,12 @@
         if ("anim".equals(mResourceType)) return "android.view.animation.AnimationUtils.loadAnimation(" + context + ", " + resourceName + ")";
         if ("animator".equals(mResourceType)) return "android.animation.AnimatorInflater.loadAnimator(" + context + ", " + resourceName + ")";
         if ("bool".equals(mResourceType)) return resources + ".getBoolean(" + resourceName + ")";
-        if ("color".equals(mResourceType)) return resources + ".getColor(" + resourceName + ")";
-        if ("colorStateList".equals(mResourceType)) return resources + ".getColorStateList(" + resourceName + ")";
+        if ("color".equals(mResourceType)) return "android.databinding.DynamicUtil.getColorFromResource(getRoot(), " + resourceName + ")";
+        if ("colorStateList".equals(mResourceType)) return "getColorStateListFromResource(" + resourceName + ")";
         if ("dimen".equals(mResourceType)) return resources + ".getDimension(" + resourceName + ")";
         if ("dimenOffset".equals(mResourceType)) return resources + ".getDimensionPixelOffset(" + resourceName + ")";
         if ("dimenSize".equals(mResourceType)) return resources + ".getDimensionPixelSize(" + resourceName + ")";
-        if ("drawable".equals(mResourceType)) return resources + ".getDrawable(" + resourceName + ")";
+        if ("drawable".equals(mResourceType)) return "getDrawableFromResource(" + resourceName + ")";
         if ("fraction".equals(mResourceType)) {
             String base = getChildCode(0, "1");
             String pbase = getChildCode(1, "1");
@@ -179,7 +190,7 @@
         if (getChildren().size() <= childIndex) {
             return defaultValue;
         } else {
-            return WriterPackage.toCode(getChildren().get(childIndex), false).generate();
+            return getChildren().get(childIndex).toCode().generate();
         }
     }
 
@@ -187,7 +198,7 @@
         StringBuilder sb = new StringBuilder("getRoot().getResources().");
         sb.append(methodCall).append("(").append(resourceName);
         for (Expr expr : getChildren()) {
-            sb.append(", ").append(WriterPackage.toCode(expr, false).generate());
+            sb.append(", ").append(expr.toCode().generate());
         }
         sb.append(")");
         return sb.toString();
diff --git a/compiler/src/main/java/android/databinding/tool/expr/StaticIdentifierExpr.java b/compiler/src/main/java/android/databinding/tool/expr/StaticIdentifierExpr.java
index 8ca5128..7618e94 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/StaticIdentifierExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/StaticIdentifierExpr.java
@@ -16,6 +16,8 @@
 
 package android.databinding.tool.expr;
 
+import android.databinding.tool.writer.KCode;
+
 public class StaticIdentifierExpr extends IdentifierExpr {
 
     StaticIdentifierExpr(String name) {
@@ -31,4 +33,19 @@
     public boolean isDynamic() {
         return false;
     }
+
+    @Override
+    public String getInvertibleError() {
+        return "Class " + getResolvedType().toJavaCode() +
+                " may not be the target of a two-way binding expression";
+    }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        throw new IllegalStateException("StaticIdentifierExpr is not invertible.");
+    }
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode(getResolvedType().toJavaCode());
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/SymbolExpr.java b/compiler/src/main/java/android/databinding/tool/expr/SymbolExpr.java
index ca4ad72..38708c0 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/SymbolExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/SymbolExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -47,7 +48,17 @@
     }
 
     @Override
+    public String getInvertibleError() {
+        return "Symbol '" + mText + "' cannot be the target of a two-way binding expression";
+    }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode(getText());
+    }
+
+    @Override
     protected List<Dependency> constructDependencies() {
-        return new ArrayList<>();
+        return new ArrayList<Dependency>();
     }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/TernaryExpr.java b/compiler/src/main/java/android/databinding/tool/expr/TernaryExpr.java
index e49c8ce..d4a3727 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/TernaryExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/TernaryExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.ArrayList;
 import java.util.BitSet;
@@ -46,20 +47,46 @@
     }
 
     @Override
+    public String getInvertibleError() {
+        if (getPred().isDynamic()) {
+            return "The condition of a ternary operator must be constant: " +
+                    getPred().toFullCode();
+        }
+        final String trueInvertible = getIfTrue().getInvertibleError();
+        if (trueInvertible != null) {
+            return trueInvertible;
+        } else {
+            return getIfFalse().getInvertibleError();
+        }
+    }
+
+    @Override
     protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
+        final Expr ifTrue = getIfTrue();
+        final Expr ifFalse = getIfFalse();
+        if (isNullLiteral(ifTrue)) {
+            return ifFalse.getResolvedType();
+        } else if (isNullLiteral(ifFalse)) {
+            return ifTrue.getResolvedType();
+        }
         return modelAnalyzer.findCommonParentOf(getIfTrue().getResolvedType(),
                 getIfFalse().getResolvedType());
     }
 
+    private static boolean isNullLiteral(Expr expr) {
+        final ModelClass type = expr.getResolvedType();
+        return (type.isObject() && (expr instanceof SymbolExpr) &&
+                "null".equals(((SymbolExpr)expr).getText()));
+    }
+
     @Override
     protected List<Dependency> constructDependencies() {
-        List<Dependency> deps = new ArrayList<>();
+        List<Dependency> deps = new ArrayList<Dependency>();
         Expr predExpr = getPred();
-        if (predExpr.isDynamic()) {
-            final Dependency pred = new Dependency(this, predExpr);
-            pred.setMandatory(true);
-            deps.add(pred);
-        }
+        final Dependency pred = new Dependency(this, predExpr);
+        pred.setMandatory(true);
+        deps.add(pred);
+
         Expr ifTrueExpr = getIfTrue();
         if (ifTrueExpr.isDynamic()) {
             deps.add(new Dependency(this, ifTrueExpr, predExpr, true));
@@ -77,6 +104,26 @@
     }
 
     @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode()
+                .app("", getPred().toCode(expand))
+                .app(" ? ", getIfTrue().toCode(expand))
+                .app(" : ", getIfFalse().toCode(expand));
+
+    }
+
+    @Override
+    public KCode toInverseCode(KCode variable) {
+        return new KCode()
+                .app("if (", getPred().toCode(true))
+                .app(") {")
+                .tab(getIfTrue().toInverseCode(variable))
+                .nl(new KCode("} else {"))
+                .tab(getIfFalse().toInverseCode(variable))
+                .nl(new KCode("}"));
+    }
+
+    @Override
     public boolean isConditional() {
         return true;
     }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/TwoWayListenerExpr.java b/compiler/src/main/java/android/databinding/tool/expr/TwoWayListenerExpr.java
new file mode 100644
index 0000000..1a65673
--- /dev/null
+++ b/compiler/src/main/java/android/databinding/tool/expr/TwoWayListenerExpr.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.tool.expr;
+
+import android.databinding.InverseBindingListener;
+import android.databinding.tool.InverseBinding;
+import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
+
+import java.util.List;
+
+/**
+ * TwoWayListenerExpr is used to set the event listener for a two-way binding expression.
+ */
+public class TwoWayListenerExpr extends Expr {
+    final InverseBinding mInverseBinding;
+
+    public TwoWayListenerExpr(InverseBinding inverseBinding) {
+        mInverseBinding = inverseBinding;
+    }
+
+    @Override
+    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
+        return modelAnalyzer.findClass(InverseBindingListener.class);
+    }
+
+    @Override
+    protected List<Dependency> constructDependencies() {
+        return constructDynamicChildrenDependencies();
+    }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        final String fieldName = LayoutBinderWriterKt.getFieldName(mInverseBinding);
+        return new KCode(fieldName);
+    }
+
+    @Override
+    protected String computeUniqueKey() {
+        return "event(" + mInverseBinding.getEventAttribute() + ", " +
+                System.identityHashCode(mInverseBinding) + ")";
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return "Inverted expressions are already inverted!";
+    }
+}
diff --git a/compiler/src/main/java/android/databinding/tool/expr/UnaryExpr.java b/compiler/src/main/java/android/databinding/tool/expr/UnaryExpr.java
index 1aff945..881a352 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/UnaryExpr.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/UnaryExpr.java
@@ -18,6 +18,7 @@
 
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.KCode;
 
 import java.util.List;
 
@@ -29,8 +30,23 @@
     }
 
     @Override
+    public String getInvertibleError() {
+        return getExpr().getInvertibleError();
+    }
+
+    @Override
     protected String computeUniqueKey() {
-        return join(getOpStr(), getExpr().getUniqueKey());
+        return addTwoWay(join(getOpStr(), getExpr().getUniqueKey()));
+    }
+
+    @Override
+    public KCode toInverseCode(KCode value) {
+        return getExpr().toInverseCode(new KCode().app(mOp, value));
+    }
+
+    @Override
+    protected KCode generateCode(boolean expand) {
+        return new KCode().app(getOp(), getExpr().toCode(expand));
     }
 
     @Override
diff --git a/compiler/src/main/java/android/databinding/tool/expr/VersionProvider.java b/compiler/src/main/java/android/databinding/tool/expr/VersionProvider.java
index cef58f7..8e066a4 100644
--- a/compiler/src/main/java/android/databinding/tool/expr/VersionProvider.java
+++ b/compiler/src/main/java/android/databinding/tool/expr/VersionProvider.java
@@ -21,5 +21,5 @@
  * This number is used when caching values in code generation. (like flags)
  */
 public interface VersionProvider {
-    public int getVersion();
+    int getVersion();
 }
diff --git a/compiler/src/main/java/android/databinding/tool/expr/ViewFieldExpr.java b/compiler/src/main/java/android/databinding/tool/expr/ViewFieldExpr.java
new file mode 100644
index 0000000..0a6b15b
--- /dev/null
+++ b/compiler/src/main/java/android/databinding/tool/expr/ViewFieldExpr.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool.expr;
+
+import android.databinding.tool.BindingTarget;
+import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.reflection.ModelClass;
+import android.databinding.tool.writer.LayoutBinderWriterKt;
+
+public class ViewFieldExpr extends BuiltInVariableExpr {
+    private final BindingTarget mBindingTarget;
+
+    ViewFieldExpr(BindingTarget bindingTarget) {
+        super(LayoutBinderWriterKt.getFieldName(bindingTarget), initialType(bindingTarget),
+                LayoutBinderWriterKt.getFieldName(bindingTarget));
+        mBindingTarget = bindingTarget;
+    }
+
+    @Override
+    public String getInvertibleError() {
+        return "View fields may not be the target of two-way binding";
+    }
+
+    private static String initialType(BindingTarget bindingTarget) {
+        return bindingTarget.isBinder()
+                ? "android.databinding.ViewDataBinding"
+                : bindingTarget.getInterfaceType();
+    }
+
+    public BindingTarget getBindingTarget() {
+        return mBindingTarget;
+    }
+
+    @Override
+    protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
+        final ModelClass type = modelAnalyzer.findClass(mBindingTarget.getInterfaceType(), null);
+        if (type == null) {
+            return modelAnalyzer.findClass("android.databinding.ViewDataBinding", null);
+        }
+        return type;
+    }
+}
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/Callable.java b/compiler/src/main/java/android/databinding/tool/reflection/Callable.java
index 4bd0906..5b9acf2 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/Callable.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/Callable.java
@@ -15,13 +15,9 @@
  */
 package android.databinding.tool.reflection;
 
-import android.databinding.tool.util.L;
-
-import java.util.List;
-
 public class Callable {
 
-    public static enum Type {
+    public enum Type {
         METHOD,
         FIELD
     }
@@ -34,14 +30,21 @@
 
     public final String name;
 
+    public final String setterName;
+
     public final ModelClass resolvedType;
 
     private final int mFlags;
 
-    public Callable(Type type, String name, ModelClass resolvedType, int flags) {
+    private final int mParameterCount;
+
+    public Callable(Type type, String name, String setterName, ModelClass resolvedType,
+                    int parameterCount, int flags) {
         this.type = type;
         this.name = name;
         this.resolvedType = resolvedType;
+        mParameterCount = parameterCount;
+        this.setterName = setterName;
         mFlags = flags;
     }
 
@@ -49,6 +52,10 @@
         return resolvedType.toJavaCode();
     }
 
+    public int getParameterCount() {
+        return mParameterCount;
+    }
+
     public boolean isDynamic() {
         return (mFlags & DYNAMIC) != 0;
     }
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java b/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java
index 739c9e0..b1de46e 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/ModelAnalyzer.java
@@ -94,6 +94,12 @@
             curr = curr.getSuperclass();
         }
         if (curr == null) {
+            if (modelClass1.isObject() && modelClass2.isInterface()) {
+                return modelClass1;
+            } else if (modelClass2.isObject() && modelClass1.isInterface()) {
+                return modelClass2;
+            }
+
             ModelClass primitive1 = modelClass1.unbox();
             ModelClass primitive2 = modelClass2.unbox();
             if (!modelClass1.equals(primitive1) || !modelClass2.equals(primitive2)) {
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java b/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
index 2bc2c86..6fbc5a0 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/ModelClass.java
@@ -15,10 +15,9 @@
  */
 package android.databinding.tool.reflection;
 
-import org.apache.commons.lang3.StringUtils;
-
 import android.databinding.tool.reflection.Callable.Type;
 import android.databinding.tool.util.L;
+import android.databinding.tool.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -143,6 +142,11 @@
     public abstract boolean isTypeVar();
 
     /**
+     * @return whether this is a wildcard type argument or not.
+     */
+    public abstract boolean isWildcard();
+
+    /**
      * @return whether or not this ModelClass is java.lang.Object and not a primitive or subclass.
      */
     public boolean isObject() {
@@ -321,6 +325,19 @@
     }
 
     /**
+     * @return The class or interface name of this type or the primitive type if it isn't a
+     * reference type.
+     */
+    public String getSimpleName() {
+        final String canonicalName = getCanonicalName();
+        final int dotIndex = canonicalName.lastIndexOf('.');
+        if (dotIndex >= 0) {
+            return canonicalName.substring(dotIndex + 1);
+        }
+        return canonicalName;
+    }
+
+    /**
      * Returns this class type without any generic type arguments.
      * @return this class type without any generic type arguments.
      */
@@ -367,8 +384,8 @@
      */
     public Callable findGetterOrField(String name, boolean staticOnly) {
         if ("length".equals(name) && isArray()) {
-            return new Callable(Type.FIELD, name, ModelAnalyzer.getInstance().loadPrimitive("int"),
-                    0);
+            return new Callable(Type.FIELD, name, null,
+                    ModelAnalyzer.getInstance().loadPrimitive("int"), 0, 0);
         }
         String capitalized = StringUtils.capitalize(name);
         String[] methodNames = {
@@ -396,8 +413,11 @@
                             flags |= CAN_BE_INVALIDATED;
                         }
                     }
+                    final ModelMethod setterMethod = findSetter(method, name);
+                    final String setterName = setterMethod == null ? null : setterMethod.getName();
                     final Callable result = new Callable(Callable.Type.METHOD, methodName,
-                            method.getReturnType(null), flags);
+                            setterName, method.getReturnType(null), method.getParameterTypes().length,
+                            flags);
                     return result;
                 }
             }
@@ -420,16 +440,37 @@
         }
         ModelClass fieldType = publicField.getFieldType();
         int flags = 0;
+        String setterFieldName = name;
+        if (publicField.isStatic()) {
+            flags |= STATIC;
+        }
         if (!publicField.isFinal()) {
+            setterFieldName = null;
             flags |= DYNAMIC;
         }
         if (publicField.isBindable()) {
             flags |= CAN_BE_INVALIDATED;
         }
-        if (publicField.isStatic()) {
-            flags |= STATIC;
+        return new Callable(Callable.Type.FIELD, name, setterFieldName, fieldType, 0, flags);
+    }
+
+    public ModelMethod findInstanceGetter(String name) {
+        String capitalized = StringUtils.capitalize(name);
+        String[] methodNames = {
+                "get" + capitalized,
+                "is" + capitalized,
+                name
+        };
+        for (String methodName : methodNames) {
+            ModelMethod[] methods = getMethods(methodName, new ArrayList<ModelClass>(), false);
+            for (ModelMethod method : methods) {
+                if (method.isPublic() && !method.isStatic() &&
+                        !method.getReturnType(Arrays.asList(method.getParameterTypes())).isVoid()) {
+                    return method;
+                }
+            }
         }
-        return new Callable(Callable.Type.FIELD, name, fieldType, flags);
+        return null;
     }
 
     private ModelField getField(String name, boolean allowPrivate, boolean isStatic) {
@@ -445,6 +486,33 @@
         return null;
     }
 
+    private ModelMethod findSetter(ModelMethod getter, String originalName) {
+        final String capitalized = StringUtils.capitalize(originalName);
+        final String[] possibleNames;
+        if (originalName.equals(getter.getName())) {
+            possibleNames = new String[] { originalName, "set" + capitalized };
+        } else if (getter.getName().startsWith("is")){
+            possibleNames = new String[] { "set" + capitalized, "setIs" + capitalized };
+        } else {
+            possibleNames = new String[] { "set" + capitalized };
+        }
+        for (String name : possibleNames) {
+            List<ModelMethod> methods = findMethods(name, getter.isStatic());
+            if (methods != null) {
+                ModelClass param = getter.getReturnType(null);
+                for (ModelMethod method : methods) {
+                    ModelClass[] parameterTypes = method.getParameterTypes();
+                    if (parameterTypes != null && parameterTypes.length == 1 &&
+                            parameterTypes[0].equals(param) &&
+                            method.isStatic() == getter.isStatic()) {
+                        return method;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
     /**
      * Finds public methods that matches the given name exactly. These may be resolved into
      * listener methods during Expr.resolveListeners.
@@ -464,6 +532,21 @@
         return matching;
     }
 
+    public boolean isIncomplete() {
+        if (isTypeVar() || isWildcard()) {
+            return true;
+        }
+        List<ModelClass> typeArgs = getTypeArguments();
+        if (typeArgs != null) {
+            for (ModelClass typeArg : typeArgs) {
+                if (typeArg.isIncomplete()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     protected abstract ModelField[] getDeclaredFields();
 
     protected abstract ModelMethod[] getDeclaredMethods();
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/SdkUtil.java b/compiler/src/main/java/android/databinding/tool/reflection/SdkUtil.java
index 4b5e09f..da73f66 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/SdkUtil.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/SdkUtil.java
@@ -64,7 +64,7 @@
             int result = sApiChecker.getMinApi(classDesc, methodDesc);
             L.d("checking method api for %s, class:%s method:%s. result: %d", modelMethod.getName(),
                     classDesc, methodDesc, result);
-            if (result > 1) {
+            if (result > 0) {
                 return result;
             }
             declaringClass = declaringClass.getSuperclass();
@@ -74,7 +74,7 @@
 
     static class ApiChecker {
 
-        private Map<String, Integer> mFullLookup = new HashMap<String, Integer>();
+        private Map<String, Integer> mFullLookup;
 
         private Document mDoc;
 
@@ -103,6 +103,7 @@
 
         private void buildFullLookup() throws XPathExpressionException {
             NodeList allClasses = mDoc.getChildNodes().item(0).getChildNodes();
+            mFullLookup = new HashMap<String, Integer>(allClasses.getLength() * 4);
             for (int j = 0; j < allClasses.getLength(); j++) {
                 Node node = allClasses.item(j);
                 if (node.getNodeType() != Node.ELEMENT_NODE || !"class"
@@ -122,16 +123,17 @@
                     }
                     int methodSince = getSince(child);
                     int since = Math.max(classSince, methodSince);
-                    if (since > SdkUtil.sMinSdk) {
-                        String methodDesc = child.getAttributes().getNamedItem("name")
-                                .getNodeValue();
-                        String key = cacheKey(classDesc, methodDesc);
-                        mFullLookup.put(key, since);
-                    }
+                    String methodDesc = child.getAttributes().getNamedItem("name")
+                            .getNodeValue();
+                    String key = cacheKey(classDesc, methodDesc);
+                    mFullLookup.put(key, since);
                 }
             }
         }
 
+        /**
+         * Returns 0 if we cannot find the API level for the method.
+         */
         public int getMinApi(String classDesc, String methodOrFieldDesc) {
             if (mDoc == null || mXPath == null) {
                 return 1;
@@ -141,7 +143,7 @@
             }
             final String key = cacheKey(classDesc, methodOrFieldDesc);
             Integer since = mFullLookup.get(key);
-            return since == null ? 1 : since;
+            return since == null ? 0 : since;
         }
 
         private static String cacheKey(String classDesc, String methodOrFieldDesc) {
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java
index f02e051..4773f17 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationAnalyzer.java
@@ -24,7 +24,10 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.annotation.processing.Messager;
 import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
@@ -37,7 +40,7 @@
 
     public static final Map<String, TypeKind> PRIMITIVE_TYPES;
     static {
-        PRIMITIVE_TYPES = new HashMap<>();
+        PRIMITIVE_TYPES = new HashMap<String, TypeKind>();
         PRIMITIVE_TYPES.put("boolean", TypeKind.BOOLEAN);
         PRIMITIVE_TYPES.put("byte", TypeKind.BYTE);
         PRIMITIVE_TYPES.put("short", TypeKind.SHORT);
@@ -55,8 +58,13 @@
         setInstance(this);
         L.setClient(new L.Client() {
             @Override
-            public void printMessage(Diagnostic.Kind kind, String message) {
-                mProcessingEnv.getMessager().printMessage(kind, message);
+            public void printMessage(Diagnostic.Kind kind, String message, Element element) {
+                Messager messager = mProcessingEnv.getMessager();
+                if (element != null) {
+                    messager.printMessage(kind, message, element);
+                } else {
+                    messager.printMessage(kind, message);
+                }
             }
         });
     }
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java
index 52a7add..02e767e 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationClass.java
@@ -15,8 +15,6 @@
  */
 package android.databinding.tool.reflection.annotation;
 
-import org.antlr.v4.codegen.model.decl.Decl;
-
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.reflection.ModelField;
@@ -57,6 +55,9 @@
 
     @Override
     public String toJavaCode() {
+        if (isIncomplete()) {
+            return getCanonicalName();
+        }
         return mTypeMirror.toString();
     }
 
@@ -247,6 +248,11 @@
     }
 
     @Override
+    public boolean isWildcard() {
+        return mTypeMirror.getKind() == TypeKind.WILDCARD;
+    }
+
+    @Override
     public boolean isInterface() {
         return mTypeMirror.getKind() == TypeKind.DECLARED &&
                 ((DeclaredType)mTypeMirror).asElement().getKind() == ElementKind.INTERFACE;
diff --git a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java
index 26ca573..d7caa45 100644
--- a/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java
+++ b/compiler/src/main/java/android/databinding/tool/reflection/annotation/AnnotationMethod.java
@@ -23,12 +23,16 @@
 
 import java.util.List;
 
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.ExecutableType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
 
 class AnnotationMethod extends ModelMethod {
@@ -36,6 +40,7 @@
     final DeclaredType mDeclaringType;
     final ExecutableElement mExecutableElement;
     int mApiLevel = -1; // calculated on demand
+    ModelClass mReceiverType;
 
     public AnnotationMethod(DeclaredType declaringType, ExecutableElement executableElement) {
         mDeclaringType = declaringType;
@@ -46,7 +51,46 @@
 
     @Override
     public ModelClass getDeclaringClass() {
-        return new AnnotationClass(mDeclaringType);
+        if (mReceiverType == null) {
+            mReceiverType = findReceiverType(mDeclaringType);
+            if (mReceiverType == null) {
+                mReceiverType = new AnnotationClass(mDeclaringType);
+            }
+        }
+        return mReceiverType;
+    }
+
+    // TODO: When going to Java 1.8, use mExecutableElement.getReceiverType()
+    private ModelClass findReceiverType(DeclaredType subType) {
+        List<? extends TypeMirror> supers = getTypeUtils().directSupertypes(subType);
+        for (TypeMirror superType : supers) {
+            if (superType.getKind() == TypeKind.DECLARED) {
+                DeclaredType declaredType = (DeclaredType) superType;
+                ModelClass inSuper = findReceiverType(declaredType);
+                if (inSuper != null) {
+                    return inSuper;
+                } else if (hasExecutableMethod(declaredType)) {
+                    return new AnnotationClass(declaredType);
+                }
+            }
+        }
+        return null;
+    }
+
+    private boolean hasExecutableMethod(DeclaredType declaredType) {
+        Elements elementUtils = getElementUtils();
+        TypeElement enclosing = (TypeElement) mExecutableElement.getEnclosingElement();
+        TypeElement typeElement = (TypeElement) declaredType.asElement();
+        for (Element element : typeElement.getEnclosedElements()) {
+            if (element.getKind() == ElementKind.METHOD) {
+                ExecutableElement executableElement = (ExecutableElement) element;
+                if (executableElement.equals(mExecutableElement) ||
+                        elementUtils.overrides(mExecutableElement, executableElement, enclosing)) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     @Override
@@ -115,6 +159,14 @@
         return mExecutableElement.isVarArgs();
     }
 
+    private static Types getTypeUtils() {
+        return AnnotationAnalyzer.get().mProcessingEnv.getTypeUtils();
+    }
+
+    private static Elements getElementUtils() {
+        return AnnotationAnalyzer.get().mProcessingEnv.getElementUtils();
+    }
+
     @Override
     public String toString() {
         return "AnnotationMethod{" +
diff --git a/compiler/src/main/java/android/databinding/tool/store/SetterStore.java b/compiler/src/main/java/android/databinding/tool/store/SetterStore.java
index e9f34db..9568810 100644
--- a/compiler/src/main/java/android/databinding/tool/store/SetterStore.java
+++ b/compiler/src/main/java/android/databinding/tool/store/SetterStore.java
@@ -15,14 +15,14 @@
  */
 package android.databinding.tool.store;
 
-import org.apache.commons.lang3.StringUtils;
-
+import android.databinding.InverseBindingListener;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.reflection.ModelMethod;
 import android.databinding.tool.util.GenerationalClassUtil;
 import android.databinding.tool.util.L;
 import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.util.StringUtils;
 
 import java.io.IOException;
 import java.io.Serializable;
@@ -31,6 +31,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -50,8 +51,10 @@
 public class SetterStore {
     private static SetterStore sStore;
 
-    private final IntermediateV1 mStore;
+    private final IntermediateV2 mStore;
     private final ModelAnalyzer mClassAnalyzer;
+    private HashMap<String, List<String>> mInstanceAdapters;
+    private final HashSet<String> mInverseEventAttributes = new HashSet<String>();
 
     private Comparator<MultiAttributeSetter> COMPARE_MULTI_ATTRIBUTE_SETTERS =
             new Comparator<MultiAttributeSetter>() {
@@ -140,9 +143,19 @@
                 }
             };
 
-    private SetterStore(ModelAnalyzer modelAnalyzer, IntermediateV1 store) {
+    private SetterStore(ModelAnalyzer modelAnalyzer, IntermediateV2 store) {
         mClassAnalyzer = modelAnalyzer;
         mStore = store;
+        for (HashMap<AccessorKey, InverseDescription> adapter : mStore.inverseAdapters.values()) {
+            for (InverseDescription inverseDescription : adapter.values()) {
+                mInverseEventAttributes.add(inverseDescription.event);
+            }
+        }
+        for (HashMap<String, InverseDescription> method : mStore.inverseMethods.values()) {
+            for (InverseDescription inverseDescription : method.values()) {
+                mInverseEventAttributes.add(inverseDescription.event);
+            }
+        }
     }
 
     public static SetterStore get(ModelAnalyzer modelAnalyzer) {
@@ -153,7 +166,7 @@
     }
 
     private static SetterStore load(ModelAnalyzer modelAnalyzer) {
-        IntermediateV1 store = new IntermediateV1();
+        IntermediateV2 store = new IntermediateV2();
         List<Intermediate> previousStores = GenerationalClassUtil
                 .loadObjects(GenerationalClassUtil.ExtensionFilter.SETTER_STORE);
         for (Intermediate intermediate : previousStores) {
@@ -176,6 +189,21 @@
         renamed.put(declaringClass, methodDescription);
     }
 
+    public void addInverseMethod(String attribute, String event, String declaringClass,
+            String method, TypeElement declaredOn) {
+        attribute = stripNamespace(attribute);
+        event = stripNamespace(event);
+        HashMap<String, InverseDescription> inverseMethods = mStore.inverseMethods.get(attribute);
+        if (inverseMethods == null) {
+            inverseMethods = new HashMap<String, InverseDescription>();
+            mStore.inverseMethods.put(attribute, inverseMethods);
+        }
+        InverseDescription methodDescription = new InverseDescription(
+                declaredOn.getQualifiedName().toString(), method, event);
+        L.d("STORE addInverseMethod desc %s", methodDescription);
+        inverseMethods.put(declaringClass, methodDescription);
+    }
+
     public void addBindingAdapter(ProcessingEnvironment processingEnv, String attribute,
             ExecutableElement bindingMethod, boolean takesComponent) {
         attribute = stripNamespace(attribute);
@@ -201,6 +229,32 @@
         adapters.put(key, new MethodDescription(bindingMethod, 1, takesComponent));
     }
 
+    public void addInverseAdapter(ProcessingEnvironment processingEnv, String attribute,
+            String event, ExecutableElement bindingMethod, boolean takesComponent) {
+        attribute = stripNamespace(attribute);
+        event = stripNamespace(event);
+        L.d("STORE addInverseAdapter %s %s", attribute, bindingMethod);
+        HashMap<AccessorKey, InverseDescription> adapters = mStore.inverseAdapters.get(attribute);
+
+        if (adapters == null) {
+            adapters = new HashMap<AccessorKey, InverseDescription>();
+            mStore.inverseAdapters.put(attribute, adapters);
+        }
+        List<? extends VariableElement> parameters = bindingMethod.getParameters();
+        final int viewIndex = takesComponent ? 1 : 0;
+        TypeMirror viewType = eraseType(processingEnv, parameters.get(viewIndex).asType());
+        String view = getQualifiedName(viewType);
+        TypeMirror returnType = eraseType(processingEnv, bindingMethod.getReturnType());
+        String value = getQualifiedName(returnType);
+
+        AccessorKey key = new AccessorKey(view, value);
+        if (adapters.containsKey(key)) {
+            throw new IllegalArgumentException("Already exists!");
+        }
+
+        adapters.put(key, new InverseDescription(bindingMethod, event, takesComponent));
+    }
+
     private static TypeMirror eraseType(ProcessingEnvironment processingEnv,
             TypeMirror typeMirror) {
         if (hasTypeVar(typeMirror)) {
@@ -261,10 +315,10 @@
     }
 
     public void addBindingAdapter(ProcessingEnvironment processingEnv, String[] attributes,
-            ExecutableElement bindingMethod, boolean takesComponent) {
+            ExecutableElement bindingMethod, boolean takesComponent, boolean requireAll) {
         L.d("STORE add multi-value BindingAdapter %d %s", attributes.length, bindingMethod);
         MultiValueAdapterKey key = new MultiValueAdapterKey(processingEnv, bindingMethod,
-                attributes, takesComponent);
+                attributes, takesComponent, requireAll);
         MethodDescription methodDescription = new MethodDescription(bindingMethod,
                 attributes.length, takesComponent);
         mStore.multiValueAdapters.put(key, methodDescription);
@@ -273,7 +327,9 @@
     private static String[] stripAttributes(String[] attributes) {
         String[] strippedAttributes = new String[attributes.length];
         for (int i = 0; i < attributes.length; i++) {
-            strippedAttributes[i] = stripNamespace(attributes[i]);
+            if (attributes[i] != null) {
+                strippedAttributes[i] = stripNamespace(attributes[i]);
+            }
         }
         return strippedAttributes;
     }
@@ -287,13 +343,36 @@
     }
 
     private static String getQualifiedName(TypeMirror type) {
-        if (type.getKind() == TypeKind.ARRAY) {
+        final TypeKind kind = type.getKind();
+        if (kind == TypeKind.ARRAY) {
             return getQualifiedName(((ArrayType) type).getComponentType()) + "[]";
+        } else if (kind == TypeKind.DECLARED && isIncompleteType(type)) {
+            DeclaredType declaredType = (DeclaredType) type;
+            return declaredType.asElement().toString();
         } else {
             return type.toString();
         }
     }
 
+    private static boolean isIncompleteType(TypeMirror type) {
+        final TypeKind kind = type.getKind();
+        if (kind == TypeKind.TYPEVAR || kind == TypeKind.WILDCARD) {
+            return true;
+        } else if (kind == TypeKind.DECLARED) {
+            DeclaredType declaredType = (DeclaredType) type;
+            List<? extends TypeMirror> typeArgs = declaredType.getTypeArguments();
+            if (typeArgs == null) {
+                return false;
+            }
+            for (TypeMirror arg : typeArgs) {
+                if (isIncompleteType(arg)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     public void addConversionMethod(ExecutableElement conversionMethod) {
         L.d("STORE addConversionMethod %s", conversionMethod);
         List<? extends VariableElement> parameters = conversionMethod.getParameters();
@@ -374,6 +453,10 @@
         return attribute;
     }
 
+    public boolean isTwoWayEventAttribute(String attribute) {
+        attribute = stripNamespace(attribute);
+        return mInverseEventAttributes.contains(attribute);
+    }
     public List<MultiAttributeSetter> getMultiAttributeSetterCalls(String[] attributes,
             ModelClass viewType, ModelClass[] valueType) {
         attributes = stripAttributes(attributes);
@@ -396,6 +479,72 @@
         return calls;
     }
 
+    private static String simpleName(String className) {
+        int dotIndex = className.lastIndexOf('.');
+        if (dotIndex < 0) {
+            return className;
+        } else {
+            return className.substring(dotIndex + 1);
+        }
+    }
+
+    public Map<String, List<String>> getComponentBindingAdapters() {
+        ensureInstanceAdapters();
+        return mInstanceAdapters;
+    }
+
+    private String getBindingAdapterCall(String className) {
+        ensureInstanceAdapters();
+        final String simpleName = simpleName(className);
+        List<String> adapters = mInstanceAdapters.get(simpleName);
+        if (adapters.size() == 1) {
+            return "get" + simpleName + "()";
+        } else {
+            int index = adapters.indexOf(className) + 1;
+            return "get" + simpleName + index + "()";
+        }
+    }
+
+    private void ensureInstanceAdapters() {
+        if (mInstanceAdapters == null) {
+            HashSet<String> adapters = new HashSet<String>();
+            for (HashMap<AccessorKey, MethodDescription> methods : mStore.adapterMethods.values()) {
+                for (MethodDescription method : methods.values()) {
+                    if (!method.isStatic) {
+                        adapters.add(method.type);
+                    }
+                }
+            }
+            for (MethodDescription method : mStore.multiValueAdapters.values()) {
+                if (!method.isStatic) {
+                    adapters.add(method.type);
+                }
+            }
+            for (Map<AccessorKey, InverseDescription> methods : mStore.inverseAdapters.values()) {
+                for (InverseDescription method : methods.values()) {
+                    if (!method.isStatic) {
+                        adapters.add(method.type);
+                    }
+                }
+            }
+            mInstanceAdapters = new HashMap<String, List<String>>();
+            for (String adapter : adapters) {
+                final String simpleName = simpleName(adapter);
+                List<String> list = mInstanceAdapters.get(simpleName);
+                if (list == null) {
+                    list = new ArrayList<String>();
+                    mInstanceAdapters.put(simpleName, list);
+                }
+                list.add(adapter);
+            }
+            for (List<String> list : mInstanceAdapters.values()) {
+                if (list.size() > 1) {
+                    Collections.sort(list);
+                }
+            }
+        }
+    }
+
     // Removes all MultiAttributeSetters that require any of the values in attributes
     private static void removeConsumedAttributes(ArrayList<MultiAttributeSetter> matching,
             String[] attributes) {
@@ -428,7 +577,7 @@
             ModelClass viewType, ModelClass[] valueType) {
         final ArrayList<MultiAttributeSetter> setters = new ArrayList<MultiAttributeSetter>();
         for (MultiValueAdapterKey adapter : mStore.multiValueAdapters.keySet()) {
-            if (adapter.attributes.length > attributes.length) {
+            if (adapter.requireAll && adapter.attributes.length > attributes.length) {
                 continue;
             }
             ModelClass viewClass = mClassAnalyzer.findClass(adapter.viewType, null);
@@ -453,10 +602,12 @@
         int matchingAttributes = 0;
         String[] casts = new String[adapter.attributes.length];
         MethodDescription[] conversions = new MethodDescription[adapter.attributes.length];
+        boolean[] supplied = new boolean[adapter.attributes.length];
 
         for (int i = 0; i < allAttributes.length; i++) {
             Integer index = adapter.attributeIndices.get(allAttributes[i]);
             if (index != null) {
+                supplied[index] = true;
                 matchingAttributes++;
                 final String parameterTypeStr = adapter.parameterTypes[index];
                 final ModelClass parameterType = eraseType(
@@ -485,11 +636,11 @@
             }
         }
 
-        if (matchingAttributes != adapter.attributes.length) {
+        if ((adapter.requireAll && matchingAttributes != adapter.attributes.length) ||
+                matchingAttributes == 0) {
             return null;
         } else {
-            return new MultiAttributeSetter(adapter, adapter.attributes, method, conversions,
-                    casts);
+            return new MultiAttributeSetter(adapter, supplied, method, conversions, casts);
         }
     }
 
@@ -524,7 +675,7 @@
                                         adapters.get(key).method, adapterValueType.toJavaCode(),
                                         valueType.toJavaCode());
                                 boolean isBetterView = bestViewType == null ||
-                                        bestValueType.isAssignableFrom(adapterValueType);
+                                        bestViewType.isAssignableFrom(adapterViewType);
                                 if (isBetterParameter(valueType, adapterValueType, bestValueType,
                                         isBetterView, imports)) {
                                     bestViewType = adapterViewType;
@@ -558,6 +709,76 @@
         return setterCall;
     }
 
+    public BindingGetterCall getGetterCall(String attribute, ModelClass viewType,
+            ModelClass valueType, Map<String, String> imports) {
+        if (viewType == null) {
+            return null;
+        } else if (viewType.isViewDataBinding()) {
+            return new ViewDataBindingGetterCall(attribute);
+        }
+
+        attribute = stripNamespace(attribute);
+        viewType = viewType.erasure();
+
+        InverseMethod bestMethod = getBestGetter(viewType, valueType, attribute, imports);
+        HashMap<AccessorKey, InverseDescription> adapters = mStore.inverseAdapters.get(attribute);
+        if (adapters != null) {
+            for (AccessorKey key : adapters.keySet()) {
+                try {
+                    ModelClass adapterViewType = mClassAnalyzer
+                            .findClass(key.viewType, imports).erasure();
+                    if (adapterViewType != null && adapterViewType.isAssignableFrom(viewType)) {
+                        try {
+                            L.d("getter return type is %s", key.valueType);
+                            final ModelClass adapterValueType = eraseType(mClassAnalyzer
+                                    .findClass(key.valueType, imports));
+                            L.d("getter %s returns type %s, compared to %s",
+                                    adapters.get(key).method, adapterValueType.toJavaCode(),
+                                    valueType);
+                            boolean isBetterView = bestMethod.viewType == null ||
+                                    bestMethod.viewType.isAssignableFrom(adapterViewType);
+                            if (valueType == null ||
+                                    isBetterParameter(adapterValueType, valueType,
+                                            bestMethod.returnType, isBetterView, imports)) {
+                                bestMethod.viewType = adapterViewType;
+                                bestMethod.returnType = adapterValueType;
+                                InverseDescription inverseDescription = adapters.get(key);
+                                ModelClass listenerType = ModelAnalyzer.getInstance().findClass(
+                                        InverseBindingListener.class);
+                                BindingSetterCall eventCall = getSetterCall(
+                                        inverseDescription.event, viewType, listenerType, imports);
+                                if (eventCall == null) {
+                                    List<MultiAttributeSetter> setters =
+                                            getMultiAttributeSetterCalls(
+                                                    new String[]{inverseDescription.event},
+                                                    viewType, new ModelClass[] {listenerType});
+                                    if (setters.size() != 1) {
+                                        L.e("Could not find event '%s' on View type '%s'",
+                                                inverseDescription.event,
+                                                viewType.getCanonicalName());
+                                    } else {
+                                        bestMethod.call = new AdapterGetter(inverseDescription,
+                                                setters.get(0));
+                                    }
+                                } else {
+                                    bestMethod.call = new AdapterGetter(inverseDescription,
+                                            eventCall);
+                                }
+                            }
+
+                        } catch (Exception e) {
+                            L.e(e, "Unknown class: %s", key.valueType);
+                        }
+                    }
+                } catch (Exception e) {
+                    L.e(e, "Unknown class: %s", key.viewType);
+                }
+            }
+        }
+
+        return bestMethod.call;
+    }
+
     public boolean isUntaggable(String viewType) {
         return mStore.untaggableTypes.containsKey(viewType);
     }
@@ -606,6 +827,72 @@
         return bestMethod;
     }
 
+    private InverseMethod getBestGetter(ModelClass viewType, ModelClass valueType,
+            String attribute, Map<String, String> imports) {
+        if (viewType.isGeneric()) {
+            if (valueType != null) {
+                valueType = eraseType(valueType, viewType.getTypeArguments());
+            }
+            viewType = viewType.erasure();
+        }
+        ModelClass bestReturnType = null;
+        InverseDescription bestDescription = null;
+        ModelClass bestViewType = null;
+        ModelMethod bestMethod = null;
+
+        HashMap<String, InverseDescription> inverseMethods = mStore.inverseMethods.get(attribute);
+        if (inverseMethods != null) {
+            for (String className : inverseMethods.keySet()) {
+                try {
+                    ModelClass methodViewType = mClassAnalyzer.findClass(className, imports);
+                    if (methodViewType.erasure().isAssignableFrom(viewType)) {
+                        boolean isBetterViewType = bestViewType == null ||
+                                bestViewType.isAssignableFrom(methodViewType);
+                        final InverseDescription inverseDescription = inverseMethods.get(className);
+                        final String name =  inverseDescription.method.isEmpty() ?
+                                trimAttributeNamespace(attribute) : inverseDescription.method;
+                        ModelMethod method = methodViewType.findInstanceGetter(name);
+                        ModelClass returnType = method.getReturnType(null); // no parameters
+                        if (valueType == null || bestReturnType == null ||
+                                isBetterParameter(returnType, valueType, bestReturnType,
+                                        isBetterViewType, imports)) {
+                            bestDescription = inverseDescription;
+                            bestReturnType = returnType;
+                            bestViewType = methodViewType;
+                            bestMethod = method;
+                        }
+                    }
+                } catch (Exception e) {
+                    //printMessage(Diagnostic.Kind.NOTE, "Unknown class: " + className);
+                }
+            }
+        }
+
+        BindingGetterCall call = null;
+        if (bestDescription != null) {
+            final ModelClass listenerType = ModelAnalyzer.getInstance().findClass(
+                    InverseBindingListener.class);
+            SetterCall eventSetter = getSetterCall(bestDescription.event, viewType,
+                    listenerType, imports);
+            if (eventSetter == null) {
+                List<MultiAttributeSetter> setters = getMultiAttributeSetterCalls(
+                        new String[] {bestDescription.event}, viewType,
+                        new ModelClass[] {listenerType});
+                if (setters.size() != 1) {
+                    L.e("Could not find event '%s' on View type '%s'", bestDescription.event,
+                            viewType.getCanonicalName());
+                    bestViewType = null;
+                    bestReturnType = null;
+                } else {
+                    call = new ViewGetterCall(bestDescription, bestMethod, setters.get(0));
+                }
+            } else {
+                call = new ViewGetterCall(bestDescription, bestMethod, eventSetter);
+            }
+        }
+        return new InverseMethod(call, bestReturnType, bestViewType);
+    }
+
     private static ModelClass eraseType(ModelClass type, List<ModelClass> typeParameters) {
         List<ModelClass> typeArguments = type.getTypeArguments();
         if (typeArguments == null || typeParameters == null) {
@@ -674,6 +961,9 @@
     private MethodDescription getConversionMethod(ModelClass from, ModelClass to,
             Map<String, String> imports) {
         if (from != null && to != null) {
+            if (to.isObject()) {
+                return null;
+            }
             for (String fromClassName : mStore.conversionMethods.keySet()) {
                 try {
                     ModelClass convertFrom = mClassAnalyzer.findClass(fromClassName, imports);
@@ -701,24 +991,30 @@
     }
 
     private boolean canUseForConversion(ModelClass from, ModelClass to) {
+        if (from.isIncomplete() || to.isIncomplete()) {
+            from = from.erasure();
+            to = to.erasure();
+        }
         return from.equals(to) || ModelMethod.isBoxingConversion(from, to) ||
                 to.isAssignableFrom(from);
     }
 
-    private static void merge(IntermediateV1 store, Intermediate dumpStore) {
-        IntermediateV1 intermediateV1 = (IntermediateV1) dumpStore.upgrade();
-        merge(store.adapterMethods, intermediateV1.adapterMethods);
-        merge(store.renamedMethods, intermediateV1.renamedMethods);
-        merge(store.conversionMethods, intermediateV1.conversionMethods);
-        store.multiValueAdapters.putAll(intermediateV1.multiValueAdapters);
-        store.untaggableTypes.putAll(intermediateV1.untaggableTypes);
+    private static void merge(IntermediateV2 store, Intermediate dumpStore) {
+        IntermediateV2 intermediateV2 = (IntermediateV2) dumpStore.upgrade();
+        merge(store.adapterMethods, intermediateV2.adapterMethods);
+        merge(store.renamedMethods, intermediateV2.renamedMethods);
+        merge(store.conversionMethods, intermediateV2.conversionMethods);
+        store.multiValueAdapters.putAll(intermediateV2.multiValueAdapters);
+        store.untaggableTypes.putAll(intermediateV2.untaggableTypes);
+        merge(store.inverseAdapters, intermediateV2.inverseAdapters);
+        merge(store.inverseMethods, intermediateV2.inverseMethods);
     }
 
-    private static <K, V> void merge(HashMap<K, HashMap<V, MethodDescription>> first,
-            HashMap<K, HashMap<V, MethodDescription>> second) {
+    private static <K, V, D> void merge(HashMap<K, HashMap<V, D>> first,
+            HashMap<K, HashMap<V, D>> second) {
         for (K key : second.keySet()) {
-            HashMap<V, MethodDescription> firstVals = first.get(key);
-            HashMap<V, MethodDescription> secondVals = second.get(key);
+            HashMap<V, D> firstVals = first.get(key);
+            HashMap<V, D> secondVals = second.get(key);
             if (firstVals == null) {
                 first.put(key, secondVals);
             } else {
@@ -731,14 +1027,16 @@
         }
     }
 
-    private static String createAdapterCall(MethodDescription adapter, String bindingAdapterCall,
+    private static String createAdapterCall(MethodDescription adapter,
             String componentExpression, String viewExpression, String... args) {
         StringBuilder sb = new StringBuilder();
 
         if (adapter.isStatic) {
             sb.append(adapter.type);
         } else {
-            sb.append(componentExpression).append('.').append(bindingAdapterCall);
+            final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
+            final String binderCall =  setterStore.getBindingAdapterCall(adapter.type);
+            sb.append(componentExpression).append('.').append(binderCall);
         }
         sb.append('.').append(adapter.method).append('(');
         if (adapter.componentClass != null) {
@@ -764,11 +1062,15 @@
 
         public final String[] parameterTypes;
 
+        public final boolean requireAll;
+
         public final TreeMap<String, Integer> attributeIndices = new TreeMap<String, Integer>();
 
         public MultiValueAdapterKey(ProcessingEnvironment processingEnv,
-                ExecutableElement method, String[] attributes, boolean takesComponent) {
+                ExecutableElement method, String[] attributes, boolean takesComponent,
+                boolean requireAll) {
             this.attributes = stripAttributes(attributes);
+            this.requireAll = requireAll;
             List<? extends VariableElement> parameters = method.getParameters();
             final int argStart = 1 + (takesComponent ? 1 : 0);
             this.viewType = getQualifiedName(eraseType(processingEnv,
@@ -874,6 +1176,35 @@
         }
     }
 
+    private static class InverseDescription extends MethodDescription {
+        private static final long serialVersionUID = 1;
+
+        public final String event;
+
+        public InverseDescription(String type, String method, String event) {
+            super(type, method);
+            this.event = event;
+        }
+
+        public InverseDescription(ExecutableElement method, String event, boolean takesComponent) {
+            super(method, 1, takesComponent);
+            this.event = event;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!super.equals(obj) || !(obj instanceof InverseDescription)) {
+                return false;
+            }
+            return event.equals(((InverseDescription) obj).event);
+        }
+
+        @Override
+        public int hashCode() {
+            return mergedHashCode(type, method, event);
+        }
+    }
+
     private static class AccessorKey implements Serializable {
 
         private static final long serialVersionUID = 1;
@@ -929,6 +1260,24 @@
 
         @Override
         public Intermediate upgrade() {
+            IntermediateV2 v2 = new IntermediateV2();
+            v2.adapterMethods.putAll(adapterMethods);
+            v2.renamedMethods.putAll(renamedMethods);
+            v2.conversionMethods.putAll(conversionMethods);
+            v2.untaggableTypes.putAll(untaggableTypes);
+            v2.multiValueAdapters.putAll(multiValueAdapters);
+            return v2;
+        }
+    }
+
+    private static class IntermediateV2 extends IntermediateV1 {
+        public final HashMap<String, HashMap<AccessorKey, InverseDescription>> inverseAdapters =
+                new HashMap<String, HashMap<AccessorKey, InverseDescription>>();
+        public final HashMap<String, HashMap<String, InverseDescription>> inverseMethods =
+                new HashMap<String, HashMap<String, InverseDescription>>();
+
+        @Override
+        public Intermediate upgrade() {
             return this;
         }
     }
@@ -973,16 +1322,11 @@
         public String getBindingAdapterInstanceClass() {
             return null;
         }
-
-        @Override
-        public void setBindingAdapterCall(String method) {
-        }
     }
 
     public static class AdapterSetter extends SetterCall {
         final MethodDescription mAdapter;
         final ModelClass mParameterType;
-        String mBindingAdapterCall;
 
         public AdapterSetter(MethodDescription adapter, ModelClass parameterType) {
             mAdapter = adapter;
@@ -992,14 +1336,14 @@
         @Override
         public String toJavaInternal(String componentExpression, String viewExpression,
                 String valueExpression) {
-            return createAdapterCall(mAdapter, mBindingAdapterCall, componentExpression,
+            return createAdapterCall(mAdapter, componentExpression,
                     viewExpression, mCastString + valueExpression);
         }
 
         @Override
         protected String toJavaInternal(String componentExpression, String viewExpression,
                 String oldValue, String valueExpression) {
-            return createAdapterCall(mAdapter, mBindingAdapterCall, componentExpression,
+            return createAdapterCall(mAdapter, componentExpression,
                     viewExpression, mCastString + oldValue, mCastString + valueExpression);
         }
 
@@ -1022,11 +1366,6 @@
         public String getBindingAdapterInstanceClass() {
             return mAdapter.isStatic ? null : mAdapter.type;
         }
-
-        @Override
-        public void setBindingAdapterCall(String method) {
-            mBindingAdapterCall = method;
-        }
     }
 
     public static class ModelMethodSetter extends SetterCall {
@@ -1069,10 +1408,6 @@
         public String getBindingAdapterInstanceClass() {
             return null;
         }
-
-        @Override
-        public void setBindingAdapterCall(String method) {
-        }
     }
 
     public interface BindingSetterCall {
@@ -1086,8 +1421,6 @@
         ModelClass[] getParameterTypes();
 
         String getBindingAdapterInstanceClass();
-
-        void setBindingAdapterCall(String method);
     }
 
     public static abstract class SetterCall implements BindingSetterCall {
@@ -1138,19 +1471,41 @@
         private final MethodDescription[] mConverters;
         private final String[] mCasts;
         private final MultiValueAdapterKey mKey;
-        String mBindingAdapterCall;
+        private final boolean[] mSupplied;
 
-        public MultiAttributeSetter(MultiValueAdapterKey key, String[] attributes,
+        public MultiAttributeSetter(MultiValueAdapterKey key, boolean[] supplied,
                 MethodDescription adapter, MethodDescription[] converters, String[] casts) {
             Preconditions.check(converters != null &&
-                    converters.length == attributes.length &&
-                    casts != null && casts.length == attributes.length,
+                    converters.length == key.attributes.length &&
+                    casts != null && casts.length == key.attributes.length &&
+                    supplied.length == key.attributes.length,
                     "invalid arguments to create multi attr setter");
-            this.attributes = attributes;
             this.mAdapter = adapter;
             this.mConverters = converters;
             this.mCasts = casts;
             this.mKey = key;
+            this.mSupplied = supplied;
+            if (key.requireAll) {
+                this.attributes = key.attributes;
+            } else {
+                int numSupplied = 0;
+                for (int i = 0; i < mKey.attributes.length; i++) {
+                    if (supplied[i]) {
+                        numSupplied++;
+                    }
+                }
+                if (numSupplied == key.attributes.length) {
+                    this.attributes = key.attributes;
+                } else {
+                    this.attributes = new String[numSupplied];
+                    int attrIndex = 0;
+                    for (int i = 0; i < key.attributes.length; i++) {
+                        if (supplied[i]) {
+                            attributes[attrIndex++] = key.attributes[i];
+                        }
+                    }
+                }
+            }
         }
 
         @Override
@@ -1159,33 +1514,45 @@
             Preconditions.check(valueExpressions.length == attributes.length * 2,
                     "MultiAttributeSetter needs %s items, received %s",
                     Arrays.toString(attributes), Arrays.toString(valueExpressions));
-            final int numAttrs = attributes.length;
+            final int numAttrs = mKey.attributes.length;
             String[] args = new String[numAttrs + (requiresOldValue() ? numAttrs : 0)];
 
-            final int startIndex = mAdapter.requiresOldValue ? 0 : attributes.length;
+            final int startIndex = mAdapter.requiresOldValue ? 0 : numAttrs;
+            int attrIndex = mAdapter.requiresOldValue ? 0 : attributes.length;
+            final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
             StringBuilder argBuilder = new StringBuilder();
-            for (int i = startIndex; i < valueExpressions.length; i++) {
+            final int endIndex = numAttrs * 2;
+            for (int i = startIndex; i < endIndex; i++) {
                 argBuilder.setLength(0);
-                if (mConverters[i % attributes.length] != null) {
-                    final MethodDescription converter = mConverters[i % attributes.length];
-                    argBuilder.append(converter.type)
-                            .append('.')
-                            .append(converter.method)
-                            .append('(')
-                            .append(valueExpressions[i])
-                            .append(')');
+                if (!mSupplied[i % numAttrs]) {
+                    final String paramType = mKey.parameterTypes[i % numAttrs];
+                    final String defaultValue = modelAnalyzer.getDefaultValue(paramType);
+                    argBuilder.append('(')
+                            .append(paramType)
+                            .append(')')
+                            .append(defaultValue);
                 } else {
-                    if (mCasts[i % attributes.length] != null) {
-                        argBuilder.append('(')
-                                .append(mCasts[i % attributes.length])
+                    if (mConverters[i % numAttrs] != null) {
+                        final MethodDescription converter = mConverters[i % numAttrs];
+                        argBuilder.append(converter.type)
+                                .append('.')
+                                .append(converter.method)
+                                .append('(')
+                                .append(valueExpressions[attrIndex])
                                 .append(')');
+                    } else {
+                        if (mCasts[i % numAttrs] != null) {
+                            argBuilder.append('(')
+                                    .append(mCasts[i % numAttrs])
+                                    .append(')');
+                        }
+                        argBuilder.append(valueExpressions[attrIndex]);
                     }
-                    argBuilder.append(valueExpressions[i]);
+                    attrIndex++;
                 }
                 args[i - startIndex] = argBuilder.toString();
             }
-            return createAdapterCall(mAdapter, mBindingAdapterCall, componentExpression,
-                    viewExpression, args);
+            return createAdapterCall(mAdapter, componentExpression, viewExpression, args);
         }
 
         @Override
@@ -1203,8 +1570,11 @@
             ModelClass[] parameters = new ModelClass[attributes.length];
             String[] paramTypeStrings = mKey.parameterTypes;
             ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
-            for (int i = 0; i < attributes.length; i++) {
-                parameters[i] = modelAnalyzer.findClass(paramTypeStrings[i], null);
+            int attrIndex = 0;
+            for (int i = 0; i < mKey.attributes.length; i++) {
+                if (mSupplied[i]) {
+                    parameters[attrIndex++] = modelAnalyzer.findClass(paramTypeStrings[i], null);
+                }
             }
             return parameters;
         }
@@ -1215,11 +1585,6 @@
         }
 
         @Override
-        public void setBindingAdapterCall(String method) {
-            mBindingAdapterCall = method;
-        }
-
-        @Override
         public String toString() {
             return "MultiAttributeSetter{" +
                     "attributes=" + Arrays.toString(attributes) +
@@ -1230,4 +1595,206 @@
                     '}';
         }
     }
+
+    public static class ViewDataBindingEventSetter implements BindingSetterCall {
+
+        public ViewDataBindingEventSetter() {
+        }
+
+        @Override
+        public String toJava(String componentExpression, String viewExpression,
+                String... valueExpressions) {
+            return "setBindingInverseListener(" + viewExpression + ", " +
+                    valueExpressions[0] + ", " + valueExpressions[1] + ")";
+        }
+
+        @Override
+        public int getMinApi() {
+            return 0;
+        }
+
+        @Override
+        public boolean requiresOldValue() {
+            return true;
+        }
+
+        @Override
+        public ModelClass[] getParameterTypes() {
+            ModelClass[] parameterTypes = new ModelClass[1];
+            parameterTypes[0] = ModelAnalyzer.getInstance().findClass(
+                    "android.databinding.ViewDataBinder.PropertyChangedInverseListener", null);
+            return parameterTypes;
+        }
+
+        @Override
+        public String getBindingAdapterInstanceClass() {
+            return null;
+        }
+    }
+
+    public interface BindingGetterCall {
+        String toJava(String componentExpression, String viewExpression);
+
+        int getMinApi();
+
+        String getBindingAdapterInstanceClass();
+
+        void setBindingAdapterCall(String method);
+
+        BindingSetterCall getEvent();
+
+        String getEventAttribute();
+    }
+
+    public static class ViewDataBindingGetterCall implements BindingGetterCall {
+        private final String mGetter;
+        private final BindingSetterCall mEventSetter;
+        private final String mAttribute;
+
+        public ViewDataBindingGetterCall(String attribute) {
+            final int colonIndex = attribute.indexOf(':');
+            mAttribute = attribute.substring(colonIndex + 1);
+            mGetter = "get" + StringUtils.capitalize(mAttribute);
+            mEventSetter = new ViewDataBindingEventSetter();
+        }
+
+        @Override
+        public String toJava(String componentExpression, String viewExpression) {
+            return viewExpression + "." + mGetter + "()";
+        }
+
+        @Override
+        public int getMinApi() {
+            return 0;
+        }
+
+        @Override
+        public String getBindingAdapterInstanceClass() {
+            return null;
+        }
+
+        @Override
+        public void setBindingAdapterCall(String method) {
+        }
+
+        @Override
+        public BindingSetterCall getEvent() {
+            return mEventSetter;
+        }
+
+        @Override
+        public String getEventAttribute() {
+            return mAttribute;
+        }
+    }
+
+    public static class ViewGetterCall implements BindingGetterCall {
+        private final InverseDescription mInverseDescription;
+        private final BindingSetterCall mEventCall;
+        private final ModelMethod mMethod;
+
+        public ViewGetterCall(InverseDescription inverseDescription, ModelMethod method,
+                BindingSetterCall eventCall) {
+            mInverseDescription = inverseDescription;
+            mEventCall = eventCall;
+            mMethod = method;
+        }
+
+        @Override
+        public BindingSetterCall getEvent() {
+            return mEventCall;
+        }
+
+        @Override
+        public String getEventAttribute() {
+            return mInverseDescription.event;
+        }
+
+        @Override
+        public String toJava(String componentExpression, String viewExpression) {
+            return viewExpression + "." + mMethod.getName() + "()";
+        }
+
+        @Override
+        public int getMinApi() {
+            return mMethod.getMinApi();
+        }
+
+        @Override
+        public String getBindingAdapterInstanceClass() {
+            return null;
+        }
+
+        @Override
+        public void setBindingAdapterCall(String method) {
+        }
+    }
+
+    public static class AdapterGetter implements BindingGetterCall {
+        private final InverseDescription mInverseDescription;
+        private String mBindingAdapterCall;
+        private final BindingSetterCall mEventCall;
+
+        public AdapterGetter(InverseDescription description, BindingSetterCall eventCall) {
+            mInverseDescription = description;
+            mEventCall = eventCall;
+        }
+
+        @Override
+        public String toJava(String componentExpression, String viewExpression) {
+            StringBuilder sb = new StringBuilder();
+
+            if (mInverseDescription.isStatic) {
+                sb.append(mInverseDescription.type);
+            } else {
+                sb.append(componentExpression).append('.').append(mBindingAdapterCall);
+            }
+            sb.append('.').append(mInverseDescription.method).append('(');
+            if (mInverseDescription.componentClass != null) {
+                if (!"DataBindingComponent".equals(mInverseDescription.componentClass)) {
+                    sb.append('(').append(mInverseDescription.componentClass).append(") ");
+                }
+                sb.append(componentExpression).append(", ");
+            }
+            sb.append(viewExpression).append(')');
+            return sb.toString();
+        }
+
+        @Override
+        public int getMinApi() {
+            return 1;
+        }
+
+        @Override
+        public String getBindingAdapterInstanceClass() {
+            return mInverseDescription.isStatic ? null : mInverseDescription.type;
+        }
+
+        @Override
+        public void setBindingAdapterCall(String method) {
+            mBindingAdapterCall = method;
+        }
+
+        @Override
+        public BindingSetterCall getEvent() {
+            return mEventCall;
+        }
+
+        @Override
+        public String getEventAttribute() {
+            return mInverseDescription.event;
+        }
+    }
+
+    private static class InverseMethod {
+        public BindingGetterCall call;
+        public ModelClass returnType;
+        public ModelClass viewType;
+
+        public InverseMethod(BindingGetterCall call, ModelClass returnType, ModelClass viewType) {
+            this.call = call;
+            this.returnType = returnType;
+            this.viewType = viewType;
+        }
+    }
 }
diff --git a/compiler/src/main/java/android/databinding/tool/util/BrNameUtil.java b/compiler/src/main/java/android/databinding/tool/util/BrNameUtil.java
new file mode 100644
index 0000000..f79f37c
--- /dev/null
+++ b/compiler/src/main/java/android/databinding/tool/util/BrNameUtil.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool.util;
+
+import android.databinding.tool.reflection.Callable;
+
+/**
+ * Central place to convert method/field names to BR observable fields
+ */
+public class BrNameUtil {
+    private static String stripPrefixFromField(String name) {
+        if (name.length() >= 2) {
+            char firstChar = name.charAt(0);
+            char secondChar = name.charAt(1);
+            if (name.length() > 2 && firstChar == 'm' && secondChar == '_') {
+                char thirdChar = name.charAt(2);
+                if (Character.isJavaIdentifierStart(thirdChar)) {
+                    return "" + Character.toLowerCase(thirdChar) +
+                            name.subSequence(3, name.length());
+                }
+            } else if ((firstChar == 'm' && Character.isUpperCase(secondChar)) ||
+                    (firstChar == '_' && Character.isJavaIdentifierStart(secondChar))) {
+                return "" + Character.toLowerCase(secondChar) + name.subSequence(2, name.length());
+            }
+        }
+        return name;
+    }
+
+    public static String brKey(Callable callable) {
+        if (callable.type == Callable.Type.FIELD) {
+            return stripPrefixFromField(callable.name);
+        }
+        CharSequence propertyName;
+        final String name = callable.name;
+        if (isGetter(callable) || isSetter(callable)) {
+            propertyName = name.subSequence(3, name.length());
+        } else if (isBooleanGetter(callable)) {
+            propertyName = name.subSequence(2, name.length());
+        } else {
+            L.e("@Bindable associated with method must follow JavaBeans convention %s", callable);
+            return null;
+        }
+        char firstChar = propertyName.charAt(0);
+        return "" + Character.toLowerCase(firstChar) +
+                propertyName.subSequence(1, propertyName.length());
+    }
+
+    private static boolean isGetter(Callable callable) {
+        return prefixes(callable.name, "get") &&
+                Character.isJavaIdentifierStart(callable.name.charAt(3)) &&
+                callable.getParameterCount() == 0 &&
+                !callable.resolvedType.isVoid();
+    }
+
+    private static boolean isSetter(Callable callable) {
+        return prefixes(callable.name, "set") &&
+                Character.isJavaIdentifierStart(callable.name.charAt(3)) &&
+                callable.getParameterCount() == 1 &&
+                callable.resolvedType.isVoid();
+    }
+
+    private static boolean isBooleanGetter(Callable callable) {
+        return prefixes(callable.name, "is") &&
+                Character.isJavaIdentifierStart(callable.name.charAt(2)) &&
+                callable.getParameterCount() == 0 &&
+                callable.resolvedType.isBoolean();
+    }
+
+    private static boolean prefixes(CharSequence sequence, String prefix) {
+        boolean prefixes = false;
+        if (sequence.length() > prefix.length()) {
+            int count = prefix.length();
+            prefixes = true;
+            for (int i = 0; i < count; i++) {
+                if (sequence.charAt(i) != prefix.charAt(i)) {
+                    prefixes = false;
+                    break;
+                }
+            }
+        }
+        return prefixes;
+    }
+}
diff --git a/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java b/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java
index 6a06b75..18e4b96 100644
--- a/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java
+++ b/compiler/src/main/java/android/databinding/tool/util/GenerationalClassUtil.java
@@ -80,7 +80,9 @@
                     // assume it is a zip file
                     loadFomZipFile(file);
                 }
-            } catch (IOException | URISyntaxException e) {
+            } catch (IOException e) {
+                L.d("cannot open zip file from %s", url);
+            } catch (URISyntaxException e) {
                 L.d("cannot open zip file from %s", url);
             }
         }
diff --git a/compiler/src/main/java/android/databinding/tool/writer/ComponentWriter.java b/compiler/src/main/java/android/databinding/tool/writer/ComponentWriter.java
index e35cc2c..bc03893 100644
--- a/compiler/src/main/java/android/databinding/tool/writer/ComponentWriter.java
+++ b/compiler/src/main/java/android/databinding/tool/writer/ComponentWriter.java
@@ -15,81 +15,26 @@
  */
 package android.databinding.tool.writer;
 
-import android.databinding.tool.Binding;
-import android.databinding.tool.BindingTarget;
-import android.databinding.tool.LayoutBinder;
-import android.databinding.tool.processing.ScopedException;
+import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.store.SetterStore;
 
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map.Entry;
+import java.util.Map;
 
 public class ComponentWriter {
     private static final String INDENT = "    ";
-    private final HashMap<String, ArrayList<String>> mBindingAdapters = new HashMap<>();
 
-    public ComponentWriter(List<LayoutBinder> binders) {
-        HashMap<Binding, ArrayList<String>> bindings = new HashMap<>();
-
-        for (LayoutBinder layoutBinder : binders) {
-            try {
-                android.databinding.tool.processing.Scope.enter(layoutBinder);
-                for (BindingTarget target : layoutBinder.getBindingTargets()) {
-                    try {
-                        android.databinding.tool.processing.Scope.enter(target);
-                        for (Binding binding : target.getBindings()) {
-                            try {
-                                android.databinding.tool.processing.Scope.enter(binding);
-                                final String bindingAdapter = binding
-                                        .getBindingAdapterInstanceClass();
-                                if (bindingAdapter != null) {
-                                    final String simpleName = simpleName(bindingAdapter);
-                                    ArrayList<String> classes = mBindingAdapters.get(simpleName);
-                                    if (classes == null) {
-                                        classes = new ArrayList<>();
-                                        mBindingAdapters.put(simpleName, classes);
-                                        classes.add(bindingAdapter);
-                                    } else if (!classes.contains(bindingAdapter)) {
-                                        classes.add(bindingAdapter);
-                                    }
-                                    bindings.put(binding, classes);
-                                }
-                            } catch (ScopedException ex) {
-                                android.databinding.tool.processing.Scope.defer(ex);
-                            } finally{
-                                android.databinding.tool.processing.Scope.exit();
-                            }
-                        }
-                    } finally {
-                        android.databinding.tool.processing.Scope.exit();
-                    }
-                }
-            } finally {
-                android.databinding.tool.processing.Scope.exit();
-            }
-        }
-
-        for (Entry<Binding, ArrayList<String>> entry : bindings.entrySet()) {
-            final Binding binding = entry.getKey();
-            final ArrayList<String> classes = entry.getValue();
-            final String call;
-            if (classes.size() == 1) {
-                call = "get" + simpleName(classes.get(0)) + "()";
-            } else {
-                int index = classes.indexOf(binding.getBindingAdapterInstanceClass());
-                call = "get" + simpleName(classes.get(index)) + (index + 1) + "()";
-            }
-            binding.setBindingAdapterCall(call);
-        }
+    public ComponentWriter() {
     }
 
     public String createComponent() {
         final StringBuilder builder = new StringBuilder();
         builder.append("package android.databinding;\n\n");
         builder.append("public interface DataBindingComponent {\n");
-        for (final String simpleName : mBindingAdapters.keySet()) {
-            final ArrayList<String> classes = mBindingAdapters.get(simpleName);
+        final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
+        Map<String, List<String>> bindingAdapters = setterStore.getComponentBindingAdapters();
+        for (final String simpleName : bindingAdapters.keySet()) {
+            final List<String> classes = bindingAdapters.get(simpleName);
             if (classes.size() > 1) {
                 int index = 1;
                 for (String className : classes) {
@@ -103,15 +48,6 @@
         return builder.toString();
     }
 
-    private static String simpleName(String className) {
-        int dotIndex = className.lastIndexOf('.');
-        if (dotIndex < 0) {
-            return className;
-        } else {
-            return className.substring(dotIndex + 1);
-        }
-    }
-
     private static void addGetter(StringBuilder builder, String simpleName, String className,
             int index) {
         builder.append(INDENT)
diff --git a/compiler/src/main/java/android/databinding/tool/writer/FlagSet.java b/compiler/src/main/java/android/databinding/tool/writer/FlagSet.java
index a5e799e..de01e5f 100644
--- a/compiler/src/main/java/android/databinding/tool/writer/FlagSet.java
+++ b/compiler/src/main/java/android/databinding/tool/writer/FlagSet.java
@@ -16,7 +16,6 @@
 
 package android.databinding.tool.writer;
 
-import java.util.Arrays;
 import java.util.BitSet;
 
 /**
@@ -34,7 +33,7 @@
         buckets = new long[bucketCount];
         for (int i = bitSet.nextSetBit(0);
                 i != -1; i = bitSet.nextSetBit(i + 1)) {
-            buckets[i / sBucketSize] |= 1 << (i % sBucketSize);
+            buckets[i / sBucketSize] |= 1L << (i % sBucketSize);
         }
         type = "long";
     }
@@ -59,7 +58,7 @@
         buckets = new long[1 + (max / sBucketSize)];
         for (int x = 0 ; x < bits.length; x ++) {
             final int i = bits[x];
-            buckets[i / sBucketSize] |= 1 << (i % sBucketSize);
+            buckets[i / sBucketSize] |= 1L << (i % sBucketSize);
         }
         type = "long";
     }
@@ -139,4 +138,32 @@
         }
         return true;
     }
+
+    @Override
+    public int hashCode() {
+        int hash = 1;
+        for (long bucket : buckets) {
+            hash = (hash * 7) ^ (int)(bucket >>> 32);
+            hash = (hash * 13) ^ (int)(bucket & 0xFFFF);
+        }
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof FlagSet) {
+            FlagSet other = (FlagSet) obj;
+            if (other.buckets.length != buckets.length) {
+                return false;
+            }
+            for (int i = 0; i < buckets.length; i++) {
+                if (buckets[i] != other.buckets[i]) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/compiler/src/main/kotlin/android/databinding/tool/ext/ext.kt b/compiler/src/main/kotlin/android/databinding/tool/ext/ext.kt
index c88f91e..a7f3a1b 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/ext/ext.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/ext/ext.kt
@@ -15,17 +15,12 @@
 
 import android.databinding.tool.expr.VersionProvider
 import kotlin.properties.ReadOnlyProperty
-import kotlin.properties.Delegates
-import android.databinding.tool.ext.joinToCamelCase
-import android.databinding.tool.ext.joinToCamelCaseAsVar
-import android.databinding.tool.reflection.ModelAnalyzer
-import android.databinding.tool.reflection.ModelClass
-import android.databinding.tool.reflection.ModelAnalyzer
+import kotlin.reflect.KProperty
 
 private class LazyExt<K, T>(private val initializer: (k : K) -> T) : ReadOnlyProperty<K, T> {
     private val mapping = hashMapOf<K, T>()
-    override fun get(thisRef: K, desc: PropertyMetadata): T {
-        val t = mapping.get(thisRef)
+    override fun getValue(thisRef: K, property: kotlin.reflect.KProperty<*>): T {
+        val t = mapping[thisRef]
         if (t != null) {
             return t
         }
@@ -37,9 +32,10 @@
 
 private class VersionedLazyExt<K, T>(private val initializer: (k : K) -> T) : ReadOnlyProperty<K, T> {
     private val mapping = hashMapOf<K, VersionedResult<T>>()
-    override fun get(thisRef: K, desc: PropertyMetadata): T {
-        val t = mapping.get(thisRef)
-        val version = if(thisRef is VersionProvider) thisRef.getVersion() else 1
+
+    override fun getValue(thisRef: K, property: KProperty<*>): T {
+        val t = mapping[thisRef]
+        val version = if(thisRef is VersionProvider) thisRef.version else 1
         if (t != null && version == t.version) {
             return t.result
         }
@@ -51,19 +47,18 @@
 
 data class VersionedResult<T>(val version : Int, val result : T)
 
-fun Delegates.lazy<K, T>(initializer: (k : K) -> T): ReadOnlyProperty<K, T> = LazyExt(initializer)
-fun Delegates.versionedLazy<K, T>(initializer: (k : K) -> T): ReadOnlyProperty<K, T> = VersionedLazyExt(initializer)
+fun <K, T> lazyProp(initializer: (k : K) -> T): ReadOnlyProperty<K, T> = LazyExt(initializer)
+fun <K, T> versionedLazy(initializer: (k : K) -> T): ReadOnlyProperty<K, T> = VersionedLazyExt(initializer)
 
 public fun Class<*>.toJavaCode() : String {
-    val name = getName();
     if (name.startsWith('[')) {
         val numArray = name.lastIndexOf('[') + 1;
         val componentType : String;
-        when (name.charAt(numArray)) {
+        when (name[numArray]) {
             'Z' -> componentType = "boolean"
             'B' -> componentType = "byte"
             'C' -> componentType = "char"
-            'L' -> componentType = name.substring(numArray + 1, name.length() - 1).replace('$', '.');
+            'L' -> componentType = name.substring(numArray + 1, name.length - 1).replace('$', '.');
             'D' -> componentType = "double"
             'F' -> componentType = "float"
             'I' -> componentType = "int"
@@ -78,19 +73,19 @@
     }
 }
 
-public fun String.androidId() : String = this.splitBy("/")[1]
+public fun String.androidId() : String = this.split("/")[1]
 
 public fun String.toCamelCase() : String {
-    val split = this.splitBy("_")
-    if (split.size() == 0) return ""
-    if (split.size() == 1) return split[0].capitalize()
+    val split = this.split("_")
+    if (split.size == 0) return ""
+    if (split.size == 1) return split[0].capitalize()
     return split.joinToCamelCase()
 }
 
 public fun String.toCamelCaseAsVar() : String {
-    val split = this.splitBy("_")
-    if (split.size() == 0) return ""
-    if (split.size() == 1) return split[0]
+    val split = this.split("_")
+    if (split.size == 0) return ""
+    if (split.size == 1) return split[0]
     return split.joinToCamelCaseAsVar()
 }
 
diff --git a/compiler/src/main/kotlin/android/databinding/tool/ext/list_ext.kt b/compiler/src/main/kotlin/android/databinding/tool/ext/list_ext.kt
index 9126103..4d420dd 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/ext/list_ext.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/ext/list_ext.kt
@@ -16,29 +16,14 @@
 
 package android.databinding.tool.ext
 
-import android.databinding.tool.ext.toCamelCase
-import android.databinding.tool.ext.toCamelCaseAsVar
-
-public fun List<String>.joinToCamelCase(): String = when(size()) {
+public fun List<String>.joinToCamelCase(): String = when(size) {
     0 -> throw IllegalArgumentException("invalid section size, cannot be zero")
-    1 -> this.get(0).toCamelCase()
+    1 -> this[0].toCamelCase()
     else -> this.map {it.toCamelCase()}.joinToString("")
 }
 
-public fun List<String>.joinToCamelCaseAsVar(): String = when(size()) {
+public fun List<String>.joinToCamelCaseAsVar(): String = when(size) {
     0 -> throw IllegalArgumentException("invalid section size, cannot be zero")
-    1 -> this.get(0).toCamelCaseAsVar()
-    else -> get(0).toCamelCaseAsVar() + drop(1).joinToCamelCase()
-}
-
-public fun Array<String>.joinToCamelCase(): String = when(size()) {
-    0 -> throw IllegalArgumentException("invalid section size, cannot be zero")
-    1 -> this.get(0).toCamelCase()
-    else -> this.map {it.toCamelCase()}.joinToString("")
-}
-
-public fun Array<String>.joinToCamelCaseAsVar(): String = when(size()) {
-    0 -> throw IllegalArgumentException("invalid section size, cannot be zero")
-    1 -> this.get(0).toCamelCaseAsVar()
+    1 -> this[0].toCamelCaseAsVar()
     else -> get(0).toCamelCaseAsVar() + drop(1).joinToCamelCase()
 }
\ No newline at end of file
diff --git a/compiler/src/main/kotlin/android/databinding/tool/ext/node_ext.kt b/compiler/src/main/kotlin/android/databinding/tool/ext/node_ext.kt
deleted file mode 100644
index 83a34ba..0000000
--- a/compiler/src/main/kotlin/android/databinding/tool/ext/node_ext.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.databinding.tool.ext
-
-import org.w3c.dom.Node
-import org.w3c.dom.NodeList
-import java.util.ArrayList
-
-public fun Node.getAndroidId() : String? =
-    getAttributes()?.getNamedItem("android:id")?.getNodeValue()
-
-public fun Node.getAndroidIdPath(includeRoot : Boolean) : List<String> {
-    val ids = arrayListOf<String>()
-    ids.add(getAndroidId()!!)
-    var parent : Node? = getParentNode()
-    while (parent != null && (includeRoot || parent.getParentNode()?.getParentNode() != null)) {
-        val id = parent.getAndroidId()
-        if (id != null) {
-            ids.add(id)
-        }
-        parent = parent.getParentNode()
-    }
-    return ids
-}
-
-public fun NodeList.forEach( f : (Node) -> Unit ) {
-    val cnt = getLength()
-    if (cnt == 0) return
-    for (i in 0..cnt - 1) {
-        f(item(i))
-    }
-}
-public fun NodeList.toArrayList() : ArrayList<Node> {
-    val cnt = getLength()
-    val arrayList = arrayListOf<Node>()
-    for (i in 0..cnt - 1) {
-        arrayList.add(item(i))
-    }
-    return arrayList
-}
-
-
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt
index 9e41c2d..261025d 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt
@@ -16,12 +16,12 @@
 
 package android.databinding.tool.writer
 
-import kotlin.properties.Delegates
+import android.databinding.tool.util.StringUtils
 
 class BRWriter(properties: Set<String>, val useFinal : Boolean) {
-    val indexedProps = properties.sort().withIndex()
-    public fun write(pkg : String): String = "package $pkg;${System.lineSeparator()}$klass"
-    val klass: String by Delegates.lazy {
+    val indexedProps = properties.sorted().withIndex()
+    public fun write(pkg : String): String = "package $pkg;${StringUtils.LINE_SEPARATOR}$klass"
+    val klass: String by lazy {
         kcode("") {
             val prefix = if (useFinal) "final " else "";
             nl("public class BR {") {
@@ -32,4 +32,4 @@
             } nl ("}")
         }.generate()
     }
-}
\ No newline at end of file
+}
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/CodeGenUtil.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/CodeGenUtil.kt
deleted file mode 100644
index d48516f..0000000
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/CodeGenUtil.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *      http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.databinding.tool.writer
-
-import android.databinding.tool.expr.*
-import android.databinding.tool.reflection.Callable
-
-class CodeGenUtil {
-    companion object {
-        fun toCode(it : Expr, full : Boolean) : KCode {
-            if (it.isDynamic() && !full) {
-                return kcode(it.executePendingLocalName)
-            }
-            return when (it) {
-                is ComparisonExpr -> kcode("") {
-                    app("", it.getLeft().toCode())
-                    app(" ", it.getOp()).app(" ")
-                    app("", it.getRight().toCode())
-                }
-                is InstanceOfExpr -> kcode("") {
-                    app("", it.getExpr().toCode())
-                    app(" instanceof ")
-                    app("", it.getType().toJavaCode())
-                }
-                is FieldAccessExpr -> kcode("") {
-                    if (it.isListener()) {
-                        app("(")
-                        if (it.getMinApi() > 1) {
-                            app("", "(getBuildSdkInt() < ${it.getMinApi()}) ? null : ")
-                        }
-                        if (it.getChild().isDynamic()) {
-                            val value = it.getChild().toCode().generate();
-                            app("", "((${it.fieldName} == null) ? (${it.fieldName} = (new ${it.listenerClassName}()).setValue(${value})) : ${it.fieldName}.setValue(${value}))")
-                        } else {
-                            app("", "((${it.fieldName} == null) ? (${it.fieldName} = new ${it.listenerClassName}()) : ${it.fieldName})")
-                        }
-                        app(")")
-                    } else {
-                        app("", it.getChild().toCode())
-                        if (it.getGetter().type == Callable.Type.FIELD) {
-                            app(".", it.getGetter().name)
-                        } else {
-                            app(".", it.getGetter().name).app("()")
-                        }
-                    }
-                }
-                is GroupExpr -> kcode("(").app("", it.getWrapped().toCode()).app(")")
-                is StaticIdentifierExpr -> kcode(it.getResolvedType().toJavaCode())
-                is IdentifierExpr -> kcode(it.executePendingLocalName)
-                is MathExpr -> kcode("") {
-                    app("", it.getLeft().toCode())
-                    app(it.getOp())
-                    app("", it.getRight().toCode())
-                }
-                is UnaryExpr -> kcode("") {
-                    app(it.getOp(), it.getExpr().toCode())
-                }
-                is BitShiftExpr -> kcode("") {
-                    app("", it.getLeft().toCode())
-                    app(it.getOp())
-                    app("", it.getRight().toCode())
-                }
-                is MethodCallExpr -> kcode("") {
-                    app("", it.getTarget().toCode())
-                    app(".", it.getGetter().name)
-                    app("(")
-                    var first = true
-                    it.getArgs().forEach {
-                        apps(if (first) "" else ",", it.toCode())
-                        first = false
-                    }
-                    app(")")
-                }
-                is SymbolExpr -> kcode(it.getText()) // TODO
-                is TernaryExpr -> kcode("") {
-                    app("", it.getPred().toCode())
-                    app(" ? ", it.getIfTrue().toCode())
-                    app(" : ", it.getIfFalse().toCode())
-                }
-                is ResourceExpr -> kcode("") {
-                    app("", it.toJava())
-                }
-                is BracketExpr -> kcode("") {
-                    app("", it.getTarget().toCode())
-                    val bracketType = it.getAccessor()!!
-                    when (bracketType) {
-                        BracketExpr.BracketAccessor.ARRAY -> {
-                            app("[", it.getArg().toCode())
-                            app("]")
-                        }
-                        BracketExpr.BracketAccessor.LIST -> {
-                            app(".get(")
-                            if (it.argCastsInteger()) {
-                                app("(Integer)")
-                            }
-                            app("", it.getArg().toCode())
-                            app(")")
-                        }
-                        BracketExpr.BracketAccessor.MAP -> {
-                            app(".get(", it.getArg().toCode())
-                            app(")")
-                        }
-                    }
-                }
-                is CastExpr -> kcode("") {
-                    app("(", it.getCastType())
-                    app(") ", it.getCastExpr().toCode())
-                }
-                is ArgListExpr -> throw IllegalStateException("should never try to convert an argument expressions into code");
-                else -> kcode("//NOT IMPLEMENTED YET")
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt
index 9b26c51..da953e4 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt
@@ -21,7 +21,7 @@
         nl("package $pkg;")
         nl("import $projectPackage.BR;")
         nl("class $className {") {
-            tab("final static int TARGET_MIN_SDK = ${minSdk};")
+            tab("final static int TARGET_MIN_SDK = $minSdk;")
             nl("")
             tab("public $className() {") {
             }
@@ -29,14 +29,14 @@
             nl("")
             tab("public android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View view, int layoutId) {") {
                 tab("switch(layoutId) {") {
-                    layoutBinders.groupBy{it.getLayoutname()}.forEach {
-                        val firstVal = it.value.get(0)
-                        tab("case ${firstVal.getModulePackage()}.R.layout.${firstVal.getLayoutname()}:") {
-                            if (it.value.size() == 1) {
-                                if (firstVal.isMerge()) {
-                                    tab("return new ${firstVal.getPackage()}.${firstVal.getImplementationName()}(bindingComponent, new android.view.View[]{view});")
+                    layoutBinders.groupBy{it.layoutname }.forEach {
+                        val firstVal = it.value[0]
+                        tab("case ${firstVal.modulePackage}.R.layout.${firstVal.layoutname}:") {
+                            if (it.value.size == 1) {
+                                if (firstVal.isMerge) {
+                                    tab("return new ${firstVal.`package`}.${firstVal.implementationName}(bindingComponent, new android.view.View[]{view});")
                                 } else {
-                                    tab("return ${firstVal.getPackage()}.${firstVal.getImplementationName()}.bind(view, bindingComponent);")
+                                    tab("return ${firstVal.`package`}.${firstVal.implementationName}.bind(view, bindingComponent);")
                                 }
                             } else {
                                 // we should check the tag to decide which layout we need to inflate
@@ -44,14 +44,15 @@
                                     tab("final Object tag = view.getTag();")
                                     tab("if(tag == null) throw new java.lang.RuntimeException(\"view must have a tag\");")
                                     it.value.forEach {
-                                        tab("if (\"${it.getTag()}_0\".equals(tag)) {") {
-                                            if (it.isMerge()) {
-                                                tab("return new ${it.getPackage()}.${it.getImplementationName()}(bindingComponent, new android.view.View[]{view});")
+                                        tab("if (\"${it.tag}_0\".equals(tag)) {") {
+                                            if (it.isMerge) {
+                                                tab("return new ${it.`package`}.${it.implementationName}(bindingComponent, new android.view.View[]{view});")
                                             } else {
-                                                tab("return new ${it.getPackage()}.${it.getImplementationName()}(bindingComponent, view);")
+                                                tab("return new ${it.`package`}.${it.implementationName}(bindingComponent, view);")
                                             }
                                         } tab("}")
                                     }
+                                    tab("throw new java.lang.IllegalArgumentException(\"The tag for ${firstVal.layoutname} is invalid. Received: \" + tag);");
                                 }tab("}")
                             }
 
@@ -65,19 +66,19 @@
 
             tab("android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View[] views, int layoutId) {") {
                 tab("switch(layoutId) {") {
-                    layoutBinders.filter{it.isMerge()}.groupBy{it.getLayoutname()}.forEach {
-                        val firstVal = it.value.get(0)
-                        tab("case ${firstVal.getModulePackage()}.R.layout.${firstVal.getLayoutname()}:") {
-                            if (it.value.size() == 1) {
-                                tab("return new ${firstVal.getPackage()}.${firstVal.getImplementationName()}(bindingComponent, views);")
+                    layoutBinders.filter{it.isMerge }.groupBy{it.layoutname }.forEach {
+                        val firstVal = it.value[0]
+                        tab("case ${firstVal.modulePackage}.R.layout.${firstVal.layoutname}:") {
+                            if (it.value.size == 1) {
+                                tab("return new ${firstVal.`package`}.${firstVal.implementationName}(bindingComponent, views);")
                             } else {
                                 // we should check the tag to decide which layout we need to inflate
                                 tab("{") {
                                     tab("final Object tag = views[0].getTag();")
                                     tab("if(tag == null) throw new java.lang.RuntimeException(\"view must have a tag\");")
                                     it.value.forEach {
-                                        tab("if (\"${it.getTag()}_0\".equals(tag)) {") {
-                                            tab("return new ${it.getPackage()}.${it.getImplementationName()}(bindingComponent, views);")
+                                        tab("if (\"${it.tag}_0\".equals(tag)) {") {
+                                            tab("return new ${it.`package`}.${it.implementationName}(bindingComponent, views);")
                                         } tab("}")
                                     }
                                 }tab("}")
@@ -98,11 +99,11 @@
                 // String.hashCode is well defined in the API so we can rely on it being the same on the device and the host machine
                 tab("final int code = tag.hashCode();");
                 tab("switch(code) {") {
-                    layoutBinders.groupBy {"${it.getTag()}_0".hashCode()}.forEach {
+                    layoutBinders.groupBy {"${it.tag}_0".hashCode()}.forEach {
                         tab("case ${it.key}:") {
                             it.value.forEach {
-                                tab("if(tag.equals(\"${it.getTag()}_0\"))") {
-                                    tab("return ${it.getModulePackage()}.R.layout.${it.getLayoutname()};")
+                                tab("if(tag.equals(\"${it.tag}_0\"))") {
+                                    tab("return ${it.modulePackage}.R.layout.${it.layoutname};")
                                 }
                             }
                             tab("break;")
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/DynamicUtilWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/DynamicUtilWriter.kt
new file mode 100644
index 0000000..34ac043
--- /dev/null
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/DynamicUtilWriter.kt
@@ -0,0 +1,23 @@
+package android.databinding.tool.writer;
+
+class DynamicUtilWriter() {
+    public fun write(targetSdk : kotlin.Int) : KCode = kcode("package android.databinding;") {
+        nl("")
+        nl("import android.os.Build.VERSION;")
+        nl("import android.os.Build.VERSION_CODES;")
+        nl("")
+        nl("public class DynamicUtil {")
+        tab("@SuppressWarnings(\"deprecation\")")
+        tab("public static int getColorFromResource(final android.view.View root, final int resourceId) {") {
+            if (targetSdk >= 23) {
+                tab("if (VERSION.SDK_INT >= VERSION_CODES.M) {") {
+                    tab("return root.getContext().getColor(resourceId);")
+                }
+                tab("}")
+            }
+            tab("return root.getResources().getColor(resourceId);")
+        }
+        tab("}")
+        nl("}")
+    }
+}
\ No newline at end of file
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/KCode.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/KCode.kt
index e1ceb3b..a9b282a 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/KCode.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/KCode.kt
@@ -13,13 +13,14 @@
 
 package android.databinding.tool.writer
 
+import android.databinding.tool.util.StringUtils
 import java.util.BitSet
 
 class KCode (private val s : String? = null){
 
     private var sameLine = false
 
-    private val lineSeparator = System.getProperty("line.separator")
+    private val lineSeparator = StringUtils.LINE_SEPARATOR
 
     class Appendix(val glue : String, val code : KCode)
 
@@ -30,14 +31,14 @@
         private val indentCache = arrayListOf<String>()
         fun indent(n: Int): String {
             if (cachedIndentations.get(n)) {
-                return indentCache.get(n)
+                return indentCache[n]
             }
-            val s = (0..n-1).fold(""){prev, next -> "${prev}    "}
+            val s = (0..n-1).fold(""){prev, next -> "$prev    "}
             cachedIndentations.set(n, true )
-            while (indentCache.size() <= n) {
+            while (indentCache.size <= n) {
                 indentCache.add("");
             }
-            indentCache.set(n, s)
+            indentCache[n] = s
             return s
         }
     }
@@ -54,7 +55,7 @@
         return this
     }
 
-    fun tab(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
+    infix fun tab(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
         val c = KCode(s)
         if (init != null) {
             c.init()
@@ -62,34 +63,24 @@
         return tab(c)
     }
 
-    private fun tab(c : KCode?) : KCode {
-        if (isNull(c)) {
+    fun tab(c : KCode?) : KCode {
+        if (c == null || isNull(c)) {
             return this
         }
         nodes.add(c)
         return this
     }
 
-    fun nls(vararg codes : KCode?) : KCode {
-        codes.forEach { nl(it) }
-        return this
-    }
-
-    fun nls(codes : Collection<KCode?>) : KCode {
-        codes.forEach { nl(it) }
-        return this
-    }
-
-    fun nl(c : KCode?) : KCode {
-        if (isNull(c)) {
+    infix fun nl(c : KCode?) : KCode {
+        if (c == null || isNull(c)) {
             return this
         }
         nodes.add(c)
-        c!!.sameLine = true
+        c.sameLine = true
         return this
     }
 
-    fun nl(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
+    infix fun nl(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
         val c = KCode(s)
         if (init != null) {
             c.init()
@@ -97,16 +88,6 @@
         return nl(c)
     }
 
-    fun apps(glue : String = "", vararg codes : KCode?) : KCode {
-        codes.forEach { app(glue, it)}
-        return this
-    }
-
-    fun apps(glue : String = "", codes : Collection<KCode?>) : KCode {
-        codes.forEach { app(glue, it)}
-        return this
-    }
-
     fun app(glue : String = "", c : KCode?) : KCode {
         if (isNull(c)) {
             return this
@@ -115,7 +96,7 @@
         return this
     }
 
-    fun app(s : String) : KCode {
+    infix fun app(s : String) : KCode {
         val c = KCode(s)
         return app("", c)
     }
@@ -166,4 +147,4 @@
         c.init()
     }
     return c
-}
\ No newline at end of file
+}
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt
index d87d8d4..690a4d6 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt
@@ -14,25 +14,27 @@
 package android.databinding.tool.writer
 
 import android.databinding.tool.BindingTarget
+import android.databinding.tool.InverseBinding
 import android.databinding.tool.LayoutBinder
 import android.databinding.tool.expr.Expr
 import android.databinding.tool.expr.ExprModel
 import android.databinding.tool.expr.FieldAccessExpr
 import android.databinding.tool.expr.IdentifierExpr
+import android.databinding.tool.expr.ListenerExpr
+import android.databinding.tool.expr.ResourceExpr
 import android.databinding.tool.expr.TernaryExpr
 import android.databinding.tool.ext.androidId
 import android.databinding.tool.ext.br
 import android.databinding.tool.ext.joinToCamelCaseAsVar
-import android.databinding.tool.ext.lazy
+import android.databinding.tool.ext.lazyProp
 import android.databinding.tool.ext.versionedLazy
+import android.databinding.tool.processing.ErrorMessages
 import android.databinding.tool.reflection.ModelAnalyzer
 import android.databinding.tool.util.L
 import java.util.ArrayList
 import java.util.Arrays
 import java.util.BitSet
 import java.util.HashMap
-import java.util.HashSet
-import kotlin.properties.Delegates
 
 fun String.stripNonJava() = this.split("[^a-zA-Z0-9]".toRegex()).map{ it.trim() }.joinToCamelCaseAsVar()
 
@@ -53,150 +55,167 @@
 
     fun localizeFlag(set : FlagSet, name:String) : FlagSet {
         localizedFlags.add(set)
-        val result = getUniqueName(name, Scope.FLAG)
-        set.setLocalName(result)
+        val result = getUniqueName(name, Scope.FLAG, false)
+        set.localName = result
         return set
     }
 
-    fun getUniqueName(base : String, scope : Scope) : String {
-        var candidate = base
-        var i = 0
-        while (usedFieldNames[scope].contains(candidate)) {
-            i ++
-            candidate = base + i
+    fun getUniqueName(base : String, scope : Scope, isPublic : kotlin.Boolean) : String {
+        var candidateBase = base
+        if (!isPublic && candidateBase.length > 20) {
+            candidateBase = candidateBase.substring(0, 20);
         }
-        usedFieldNames[scope].add(candidate)
+        var candidate = candidateBase
+        var i = 0
+        while (usedFieldNames[scope]!!.contains(candidate)) {
+            i ++
+            candidate = candidateBase + i
+        }
+        usedFieldNames[scope]!!.add(candidate)
         return candidate
     }
 }
 
-val ExprModel.ext by Delegates.lazy { target : ExprModel ->
+val ExprModel.ext by lazyProp { target : ExprModel ->
     ExprModelExt()
 }
 
-fun ExprModel.getUniqueFieldName(base : String) : String = ext.getUniqueName(base, Scope.FIELD)
-fun ExprModel.getUniqueMethodName(base : String) : String = ext.getUniqueName(base, Scope.METHOD)
-fun ExprModel.getUniqueFlagName(base : String) : String = ext.getUniqueName(base, Scope.FLAG)
-fun ExprModel.getConstructorParamName(base : String) : String = ext.getUniqueName(base, Scope.CONSTRUCTOR_PARAM)
+fun ExprModel.getUniqueFieldName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.FIELD, isPublic)
+fun ExprModel.getUniqueMethodName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.METHOD, isPublic)
+fun ExprModel.getConstructorParamName(base : String) : String = ext.getUniqueName(base, Scope.CONSTRUCTOR_PARAM, false)
 
 fun ExprModel.localizeFlag(set : FlagSet, base : String) : FlagSet = ext.localizeFlag(set, base)
 
+val Expr.needsLocalField by lazyProp { expr : Expr ->
+    expr.canBeEvaluatedToAVariable() && !(expr.isVariable() && !expr.isUsed) && (expr.isDynamic || expr is ResourceExpr)
+}
+
+
 // not necessarily unique. Uniqueness is solved per scope
-val BindingTarget.readableName by Delegates.lazy { target: BindingTarget ->
-    if (target.getId() == null) {
-        "boundView" + indexFromTag(target.getTag())
+val BindingTarget.readableName by lazyProp { target: BindingTarget ->
+    if (target.id == null) {
+        "boundView" + indexFromTag(target.tag)
     } else {
-        target.getId().androidId().stripNonJava()
+        target.id.androidId().stripNonJava()
     }
 }
 
 fun BindingTarget.superConversion(variable : String) : String {
-    if (getResolvedType() != null && getResolvedType().extendsViewStub()) {
-        return "new android.databinding.ViewStubProxy((android.view.ViewStub) ${variable})"
+    if (resolvedType != null && resolvedType.extendsViewStub()) {
+        return "new android.databinding.ViewStubProxy((android.view.ViewStub) $variable)"
     } else {
-        return "(${interfaceType}) ${variable}"
+        return "($interfaceClass) $variable"
     }
 }
 
-val BindingTarget.fieldName : String by Delegates.lazy { target : BindingTarget ->
+val BindingTarget.fieldName : String by lazyProp { target : BindingTarget ->
     val name : String
-    if (target.getId() == null) {
+    val isPublic : kotlin.Boolean
+    if (target.id == null) {
         name = "m${target.readableName}"
+        isPublic = false
     } else {
         name = target.readableName
+        isPublic = true
     }
-    target.getModel().getUniqueFieldName(name)
+    target.model.getUniqueFieldName(name, isPublic)
 }
 
-val BindingTarget.androidId by Delegates.lazy { target : BindingTarget ->
-    if (target.getId().startsWith("@android:id/")) {
-        "android.R.id.${target.getId().androidId()}"
+val BindingTarget.androidId by lazyProp { target : BindingTarget ->
+    if (target.id.startsWith("@android:id/")) {
+        "android.R.id.${target.id.androidId()}"
     } else {
-        "R.id.${target.getId().androidId()}"
+        "R.id.${target.id.androidId()}"
     }
 }
 
-val BindingTarget.interfaceType by Delegates.lazy { target : BindingTarget ->
-    if (target.getResolvedType() != null && target.getResolvedType().extendsViewStub()) {
+val BindingTarget.interfaceClass by lazyProp { target : BindingTarget ->
+    if (target.resolvedType != null && target.resolvedType.extendsViewStub()) {
         "android.databinding.ViewStubProxy"
     } else {
-        target.getInterfaceType()
+        target.interfaceType
     }
 }
 
-val BindingTarget.constructorParamName by Delegates.lazy { target : BindingTarget ->
-    target.getModel().getConstructorParamName(target.readableName)
+val BindingTarget.constructorParamName by lazyProp { target : BindingTarget ->
+    target.model.getConstructorParamName(target.readableName)
 }
 
 // not necessarily unique. Uniqueness is decided per scope
-val Expr.readableName by Delegates.lazy { expr : Expr ->
-    val stripped = "${expr.getUniqueKey().stripNonJava()}"
-    L.d("readableUniqueName for [%s] %s is %s", System.identityHashCode(expr), expr.getUniqueKey(), stripped)
+val Expr.readableName by lazyProp { expr : Expr ->
+    val stripped = "${expr.uniqueKey.stripNonJava()}"
+    L.d("readableUniqueName for [%s] %s is %s", System.identityHashCode(expr), expr.uniqueKey, stripped)
     stripped
 }
 
-val Expr.fieldName by Delegates.lazy { expr : Expr ->
-    expr.getModel().getUniqueFieldName("m${expr.readableName.capitalize()}")
+val Expr.fieldName by lazyProp { expr : Expr ->
+    expr.model.getUniqueFieldName("m${expr.readableName.capitalize()}", false)
 }
 
-val Expr.listenerClassName by Delegates.lazy { expr : Expr ->
-    expr.getModel().getUniqueFieldName("${expr.readableName.capitalize()}Impl")
+val InverseBinding.fieldName by lazyProp { inverseBinding : InverseBinding ->
+    val targetName = inverseBinding.target.fieldName;
+    val eventName = inverseBinding.eventAttribute.stripNonJava()
+    inverseBinding.model.getUniqueFieldName("$targetName$eventName", false)
 }
 
-val Expr.oldValueName by Delegates.lazy { expr : Expr ->
-    expr.getModel().getUniqueFieldName("mOld${expr.readableName.capitalize()}")
+val Expr.listenerClassName by lazyProp { expr : Expr ->
+    expr.model.getUniqueFieldName("${expr.resolvedType.simpleName}Impl", false)
 }
 
-val Expr.executePendingLocalName by Delegates.lazy { expr : Expr ->
-    "${expr.getModel().ext.getUniqueName(expr.readableName, Scope.EXECUTE_PENDING_METHOD)}"
+val Expr.oldValueName by lazyProp { expr : Expr ->
+    expr.model.getUniqueFieldName("mOld${expr.readableName.capitalize()}", false)
 }
 
-val Expr.setterName by Delegates.lazy { expr : Expr ->
-    expr.getModel().getUniqueMethodName("set${expr.readableName.capitalize()}")
+val Expr.executePendingLocalName by lazyProp { expr : Expr ->
+    if(expr.needsLocalField) "${expr.model.ext.getUniqueName(expr.readableName, Scope.EXECUTE_PENDING_METHOD, false)}"
+    else expr.toCode().generate()
 }
 
-val Expr.onChangeName by Delegates.lazy { expr : Expr ->
-    expr.getModel().getUniqueMethodName("onChange${expr.readableName.capitalize()}")
+val Expr.setterName by lazyProp { expr : Expr ->
+    expr.model.getUniqueMethodName("set${expr.readableName.capitalize()}", true)
 }
 
-val Expr.getterName by Delegates.lazy { expr : Expr ->
-    expr.getModel().getUniqueMethodName("get${expr.readableName.capitalize()}")
+val Expr.onChangeName by lazyProp { expr : Expr ->
+    expr.model.getUniqueMethodName("onChange${expr.readableName.capitalize()}", false)
 }
 
-val Expr.dirtyFlagName by Delegates.lazy { expr : Expr ->
-    expr.getModel().getUniqueFlagName("sFlag${expr.readableName.capitalize()}")
+val Expr.getterName by lazyProp { expr : Expr ->
+    expr.model.getUniqueMethodName("get${expr.readableName.capitalize()}", true)
 }
 
+fun Expr.isVariable() = this is IdentifierExpr && this.isDynamic
 
-fun Expr.toCode(full : Boolean = false) : KCode = CodeGenUtil.toCode(this, full)
-
-fun Expr.isVariable() = this is IdentifierExpr && this.isDynamic()
-
-fun Expr.conditionalFlagName(output : Boolean, suffix : String) = "${dirtyFlagName}_${output}$suffix"
-
-val Expr.dirtyFlagSet by Delegates.lazy { expr : Expr ->
-    FlagSet(expr.getInvalidFlags(), expr.getModel().getFlagBucketCount())
+val Expr.dirtyFlagSet by lazyProp { expr : Expr ->
+    FlagSet(expr.invalidFlags, expr.model.flagBucketCount)
 }
 
-val Expr.invalidateFlagSet by Delegates.lazy { expr : Expr ->
-    FlagSet(expr.getId())
+val Expr.invalidateFlagSet by lazyProp { expr : Expr ->
+    FlagSet(expr.id)
 }
 
-val Expr.shouldReadFlagSet by Delegates.versionedLazy { expr : Expr ->
-    FlagSet(expr.getShouldReadFlags(), expr.getModel().getFlagBucketCount())
+val Expr.shouldReadFlagSet by versionedLazy { expr : Expr ->
+    FlagSet(expr.shouldReadFlags, expr.model.flagBucketCount)
 }
 
-val Expr.conditionalFlags by Delegates.lazy { expr : Expr ->
+val Expr.shouldReadWithConditionalsFlagSet by versionedLazy { expr : Expr ->
+    FlagSet(expr.shouldReadFlagsWithConditionals, expr.model.flagBucketCount)
+}
+
+val Expr.conditionalFlags by lazyProp { expr : Expr ->
     arrayListOf(FlagSet(expr.getRequirementFlagIndex(false)),
             FlagSet(expr.getRequirementFlagIndex(true)))
 }
 
-val LayoutBinder.requiredComponent by Delegates.lazy { layoutBinder: LayoutBinder ->
-    val required = layoutBinder.
-            getBindingTargets().
-            flatMap { it.getBindings() }.
-            firstOrNull { it.getBindingAdapterInstanceClass() != null }
-    required?.getBindingAdapterInstanceClass()
+val LayoutBinder.requiredComponent by lazyProp { layoutBinder: LayoutBinder ->
+    val requiredFromBindings = layoutBinder.
+            bindingTargets.
+            flatMap { it.bindings }.
+            firstOrNull { it.bindingAdapterInstanceClass != null }?.bindingAdapterInstanceClass
+    val requiredFromInverse = layoutBinder.
+            bindingTargets.
+            flatMap { it.inverseBindings }.
+            firstOrNull { it.bindingAdapterInstanceClass != null }?.bindingAdapterInstanceClass
+    requiredFromBindings ?: requiredFromInverse
 }
 
 fun Expr.getRequirementFlagSet(expected : Boolean) : FlagSet = conditionalFlags[if(expected) 1 else 0]
@@ -209,22 +228,21 @@
     }
 }
 
-fun FlagSet.getWordSuffix(wordIndex : Int) : String {
-    return if(wordIndex == 0) "" else "_${wordIndex}"
+fun getWordSuffix(wordIndex : Int) : String {
+    return if(wordIndex == 0) "" else "_$wordIndex"
 }
 
 fun FlagSet.localValue(bucketIndex : Int) =
-        if (getLocalName() == null) binaryCode(bucketIndex)
-        else "${getLocalName()}${getWordSuffix(bucketIndex)}"
+        if (localName == null) binaryCode(bucketIndex)
+        else "$localName${getWordSuffix(bucketIndex)}"
 
 fun FlagSet.binaryCode(bucketIndex : Int) = longToBinary(buckets[bucketIndex])
 
 
-fun longToBinary(l : Long) =
-        "0b${java.lang.Long.toBinaryString(l)}L"
+fun longToBinary(l : Long) = "0x${java.lang.Long.toHexString(l)}L"
 
 fun <T> FlagSet.mapOr(other : FlagSet, cb : (suffix : String, index : Int) -> T) : List<T> {
-    val min = Math.min(buckets.size(), other.buckets.size())
+    val min = Math.min(buckets.size, other.buckets.size)
     val result = arrayListOf<T>()
     for (i in 0..(min - 1)) {
         // if these two can match by any chance, call the callback
@@ -238,7 +256,7 @@
 fun indexFromTag(tag : String) : kotlin.Int {
     val startIndex : kotlin.Int
     if (tag.startsWith("binding_")) {
-        startIndex = "binding_".length();
+        startIndex = "binding_".length;
     } else {
         startIndex = tag.lastIndexOf('_') + 1
     }
@@ -246,56 +264,55 @@
 }
 
 class LayoutBinderWriter(val layoutBinder : LayoutBinder) {
-    val model = layoutBinder.getModel()
+    val model = layoutBinder.model
     val indices = HashMap<BindingTarget, kotlin.Int>()
-    val mDirtyFlags by Delegates.lazy {
-        val fs = FlagSet(BitSet(), model.getFlagBucketCount());
+    val mDirtyFlags by lazy {
+        val fs = FlagSet(BitSet(), model.flagBucketCount);
         Arrays.fill(fs.buckets, -1)
-        fs.setDynamic(true)
+        fs.isDynamic = true
         model.localizeFlag(fs, "mDirtyFlags")
         fs
     }
 
-    val dynamics by Delegates.lazy { model.getExprMap().values().filter { it.isDynamic() } }
-    val className = layoutBinder.getImplementationName()
+    val className = layoutBinder.implementationName
 
-    val baseClassName = "${layoutBinder.getClassName()}"
+    val baseClassName = "${layoutBinder.className}"
 
-    val includedBinders by Delegates.lazy {
-        layoutBinder.getBindingTargets().filter { it.isBinder() }
+    val includedBinders by lazy {
+        layoutBinder.bindingTargets.filter { it.isBinder }
     }
 
-    val variables by Delegates.lazy {
-        model.getExprMap().values().filterIsInstance(javaClass<IdentifierExpr>()).filter { it.isVariable() }
+    val variables by lazy {
+        model.exprMap.values.filterIsInstance(IdentifierExpr::class.java).filter { it.isVariable() }
     }
 
-    val usedVariables by Delegates.lazy {
-        variables.filter {it.isUsed()}
+    val usedVariables by lazy {
+        variables.filter {it.isUsed }
     }
 
     public fun write(minSdk : kotlin.Int) : String  {
         layoutBinder.resolveWhichExpressionsAreUsed()
         calculateIndices();
-        return kcode("package ${layoutBinder.getPackage()};") {
-            nl("import ${layoutBinder.getModulePackage()}.R;")
-            nl("import ${layoutBinder.getModulePackage()}.BR;")
+        return kcode("package ${layoutBinder.`package`};") {
+            nl("import ${layoutBinder.modulePackage}.R;")
+            nl("import ${layoutBinder.modulePackage}.BR;")
             nl("import android.view.View;")
             val classDeclaration : String
             if (layoutBinder.hasVariations()) {
-                classDeclaration = "${className} extends ${baseClassName}"
+                classDeclaration = "$className extends $baseClassName"
             } else {
-                classDeclaration = "${className} extends android.databinding.ViewDataBinding"
+                classDeclaration = "$className extends android.databinding.ViewDataBinding"
             }
-            nl("public class ${classDeclaration} {") {
+            nl("public class $classDeclaration {") {
                 tab(declareIncludeViews())
                 tab(declareViews())
                 tab(declareVariables())
                 tab(declareBoundValues())
                 tab(declareListeners())
+                tab(declareInverseBindingImpls());
                 tab(declareConstructor(minSdk))
                 tab(declareInvalidateAll())
                 tab(declareHasPendingBindings())
-                tab(declareLog())
                 tab(declareSetVariable())
                 tab(variableSettersAndGetters())
                 tab(onFieldChange())
@@ -314,15 +331,15 @@
         }.generate()
     }
     fun calculateIndices() : Unit {
-        val taggedViews = layoutBinder.getBindingTargets().filter{
-            it.isUsed() && it.getTag() != null && !it.isBinder()
+        val taggedViews = layoutBinder.bindingTargets.filter{
+            it.isUsed && it.tag != null && !it.isBinder
         }
         taggedViews.forEach {
-            indices.put(it, indexFromTag(it.getTag()))
+            indices.put(it, indexFromTag(it.tag))
         }
         val indexStart = maxIndex() + 1
-        layoutBinder.getBindingTargets().filter{
-            it.isUsed() && !taggedViews.contains(it)
+        layoutBinder.bindingTargets.filter{
+            it.isUsed && !taggedViews.contains(it)
         }.withIndex().forEach {
             indices.put(it.value, it.index + indexStart)
         }
@@ -331,22 +348,19 @@
         nl("private static final android.databinding.ViewDataBinding.IncludedLayouts sIncludes;")
         nl("private static final android.util.SparseIntArray sViewsWithIds;")
         nl("static {") {
-            val hasBinders = layoutBinder.getBindingTargets().firstOrNull{ it.isUsed() && it.isBinder()} != null
+            val hasBinders = layoutBinder.bindingTargets.firstOrNull{ it.isUsed && it.isBinder } != null
             if (!hasBinders) {
                 tab("sIncludes = null;")
             } else {
-                val numBindings = layoutBinder.getBindingTargets().filter{ it.isUsed() }.count()
-                tab("sIncludes = new android.databinding.ViewDataBinding.IncludedLayouts(${numBindings});")
+                val numBindings = layoutBinder.bindingTargets.filter{ it.isUsed }.count()
+                tab("sIncludes = new android.databinding.ViewDataBinding.IncludedLayouts($numBindings);")
                 val includeMap = HashMap<BindingTarget, ArrayList<BindingTarget>>()
-                layoutBinder.getBindingTargets().filter{ it.isUsed() && it.isBinder() }.forEach {
-                    val includeTag = it.getTag();
-                    val parent = layoutBinder.getBindingTargets().firstOrNull {
-                        it.isUsed() && !it.isBinder() && includeTag.equals(it.getTag())
-                    }
-                    if (parent == null) {
-                        throw IllegalStateException("Could not find parent of include file")
-                    }
-                    var list = includeMap.get(parent)
+                layoutBinder.bindingTargets.filter{ it.isUsed && it.isBinder }.forEach {
+                    val includeTag = it.tag;
+                    val parent = layoutBinder.bindingTargets.firstOrNull {
+                        it.isUsed && !it.isBinder && includeTag.equals(it.tag)
+                    } ?: throw IllegalStateException("Could not find parent of include file")
+                    var list = includeMap[parent]
                     if (list == null) {
                         list = ArrayList<BindingTarget>()
                         includeMap.put(parent, list)
@@ -354,36 +368,36 @@
                     list.add(it)
                 }
 
-                includeMap.keySet().forEach {
-                    val index = indices.get(it)
-                    tab("sIncludes.setIncludes(${index}, ") {
+                includeMap.keys.forEach {
+                    val index = indices[it]
+                    tab("sIncludes.setIncludes($index, ") {
                         tab ("new String[] {${
-                        includeMap.get(it).map {
-                            "\"${it.getIncludedLayout()}\""
+                        includeMap[it]!!.map {
+                            "\"${it.includedLayout}\""
                         }.joinToString(", ")
                         }},")
                         tab("new int[] {${
-                        includeMap.get(it).map {
-                            "${indices.get(it)}"
+                        includeMap[it]!!.map {
+                            "${indices[it]}"
                         }.joinToString(", ")
                         }},")
                         tab("new int[] {${
-                        includeMap.get(it).map {
-                            "R.layout.${it.getIncludedLayout()}"
+                        includeMap[it]!!.map {
+                            "R.layout.${it.includedLayout}"
                         }.joinToString(", ")
                         }});")
                     }
                 }
             }
-            val viewsWithIds = layoutBinder.getBindingTargets().filter {
-                it.isUsed() && !it.isBinder() && (!it.supportsTag() || (it.getId() != null && it.getTag() == null))
+            val viewsWithIds = layoutBinder.bindingTargets.filter {
+                it.isUsed && !it.isBinder && (!it.supportsTag() || (it.id != null && it.tag == null))
             }
             if (viewsWithIds.isEmpty()) {
                 tab("sViewsWithIds = null;")
             } else {
                 tab("sViewsWithIds = new android.util.SparseIntArray();")
                 viewsWithIds.forEach {
-                    tab("sViewsWithIds.put(${it.androidId}, ${indices.get(it)});")
+                    tab("sViewsWithIds.put(${it.androidId}, ${indices[it]});")
                 }
             }
         }
@@ -391,7 +405,7 @@
     }
 
     fun maxIndex() : kotlin.Int {
-        val maxIndex = indices.values().max()
+        val maxIndex = indices.values.max()
         if (maxIndex == null) {
             return -1
         } else {
@@ -403,7 +417,7 @@
         val bindingCount = maxIndex() + 1
         val parameterType : String
         val superParam : String
-        if (layoutBinder.isMerge()) {
+        if (layoutBinder.isMerge) {
             parameterType = "View[]"
             superParam = "root[0]"
         } else {
@@ -413,53 +427,56 @@
         val rootTagsSupported = minSdk >= 14
         if (layoutBinder.hasVariations()) {
             nl("")
-            nl("public ${className}(android.databinding.DataBindingComponent bindingComponent, ${parameterType} root) {") {
-                tab("this(bindingComponent, ${superParam}, mapBindings(bindingComponent, root, ${bindingCount}, sIncludes, sViewsWithIds));")
+            nl("public $className(android.databinding.DataBindingComponent bindingComponent, $parameterType root) {") {
+                tab("this(bindingComponent, $superParam, mapBindings(bindingComponent, root, $bindingCount, sIncludes, sViewsWithIds));")
             }
             nl("}")
-            nl("private ${className}(android.databinding.DataBindingComponent bindingComponent, ${parameterType} root, Object[] bindings) {") {
-                tab("super(bindingComponent, ${superParam}, ${model.getObservables().size()}") {
-                    layoutBinder.getSortedTargets().filter { it.getId() != null }.forEach {
+            nl("private $className(android.databinding.DataBindingComponent bindingComponent, $parameterType root, Object[] bindings) {") {
+                tab("super(bindingComponent, $superParam, ${model.observables.size}") {
+                    layoutBinder.sortedTargets.filter { it.id != null }.forEach {
                         tab(", ${fieldConversion(it)}")
                     }
                     tab(");")
                 }
             }
         } else {
-            nl("public ${baseClassName}(android.databinding.DataBindingComponent bindingComponent, ${parameterType} root) {") {
-                tab("super(bindingComponent, ${superParam}, ${model.getObservables().size()});")
-                tab("final Object[] bindings = mapBindings(bindingComponent, root, ${bindingCount}, sIncludes, sViewsWithIds);")
+            nl("public $baseClassName(android.databinding.DataBindingComponent bindingComponent, $parameterType root) {") {
+                tab("super(bindingComponent, $superParam, ${model.observables.size});")
+                tab("final Object[] bindings = mapBindings(bindingComponent, root, $bindingCount, sIncludes, sViewsWithIds);")
             }
         }
         if (layoutBinder.requiredComponent != null) {
             tab("ensureBindingComponentIsNotNull(${layoutBinder.requiredComponent}.class);")
         }
-        val taggedViews = layoutBinder.getSortedTargets().filter{it.isUsed()}
+        val taggedViews = layoutBinder.sortedTargets.filter{it.isUsed }
         taggedViews.forEach {
-            if (!layoutBinder.hasVariations() || it.getId() == null) {
+            if (!layoutBinder.hasVariations() || it.id == null) {
                 tab("this.${it.fieldName} = ${fieldConversion(it)};")
             }
-            if (!it.isBinder()) {
-                if (it.getResolvedType() != null && it.getResolvedType().extendsViewStub()) {
+            if (!it.isBinder) {
+                if (it.resolvedType != null && it.resolvedType.extendsViewStub()) {
                     tab("this.${it.fieldName}.setContainingBinding(this);")
                 }
-                if (it.supportsTag() && it.getTag() != null &&
-                        (rootTagsSupported || it.getTag().startsWith("binding_"))) {
-                    val originalTag = it.getOriginalTag();
+                if (it.supportsTag() && it.tag != null &&
+                        (rootTagsSupported || it.tag.startsWith("binding_"))) {
+                    val originalTag = it.originalTag;
                     var tagValue = "null"
-                    if (originalTag != null) {
-                        tagValue = "\"${originalTag}\""
+                    if (originalTag != null && !originalTag.startsWith("@{")) {
+                        tagValue = "\"$originalTag\""
                         if (originalTag.startsWith("@")) {
-                            var packageName = layoutBinder.getModulePackage()
+                            var packageName = layoutBinder.modulePackage
                             if (originalTag.startsWith("@android:")) {
                                 packageName = "android"
                             }
                             val slashIndex = originalTag.indexOf('/')
                             val resourceId = originalTag.substring(slashIndex + 1)
-                            tagValue = "root.getResources().getString(${packageName}.R.string.${resourceId})"
+                            tagValue = "root.getResources().getString($packageName.R.string.$resourceId)"
                         }
                     }
-                    tab("this.${it.fieldName}.setTag(${tagValue});")
+                    tab("this.${it.fieldName}.setTag($tagValue);")
+                } else if (it.tag != null && !it.tag.startsWith("binding_") &&
+                    it.originalTag != null) {
+                    L.e(ErrorMessages.ROOT_TAG_NOT_SUPPORTED, it.originalTag)
                 }
             }
         }
@@ -469,14 +486,11 @@
     }
 
     fun fieldConversion(target : BindingTarget) : String {
-        if (!target.isUsed()) {
+        if (!target.isUsed) {
             return "null"
         } else {
-            val index = indices.get(target)
-            if (index == null) {
-                throw IllegalStateException("Unknown binding target")
-            }
-            val variableName = "bindings[${index}]"
+            val index = indices[target] ?: throw IllegalStateException("Unknown binding target")
+            val variableName = "bindings[$index]"
             return target.superConversion(variableName)
         }
     }
@@ -484,14 +498,14 @@
     fun declareInvalidateAll() = kcode("") {
         nl("@Override")
         nl("public void invalidateAll() {") {
-            val fs = FlagSet(layoutBinder.getModel().getInvalidateAnyBitSet(),
-                    layoutBinder.getModel().getFlagBucketCount());
+            val fs = FlagSet(layoutBinder.model.invalidateAnyBitSet,
+                    layoutBinder.model.flagBucketCount);
             tab("synchronized(this) {") {
-                for (i in (0..(mDirtyFlags.buckets.size() - 1))) {
+                for (i in (0..(mDirtyFlags.buckets.size - 1))) {
                     tab("${mDirtyFlags.localValue(i)} = ${fs.localValue(i)};")
                 }
             } tab("}")
-            includedBinders.filter{it.isUsed()}.forEach { binder ->
+            includedBinders.filter{it.isUsed }.forEach { binder ->
                 tab("${binder.fieldName}.invalidateAll();")
             }
             tab("requestRebind();");
@@ -502,19 +516,19 @@
     fun declareHasPendingBindings()  = kcode("") {
         nl("@Override")
         nl("public boolean hasPendingBindings() {") {
-            if (mDirtyFlags.buckets.size() > 0) {
+            if (mDirtyFlags.buckets.size > 0) {
                 tab("synchronized(this) {") {
-                    val flagCheck = 0.rangeTo(mDirtyFlags.buckets.size() - 1).map {
+                    val flagCheck = 0.rangeTo(mDirtyFlags.buckets.size - 1).map {
                             "${mDirtyFlags.localValue(it)} != 0"
                     }.joinToString(" || ")
-                    tab("if (${flagCheck}) {") {
+                    tab("if ($flagCheck) {") {
                         tab("return true;")
                     }
                     tab("}")
                 }
                 tab("}")
             }
-            includedBinders.filter{it.isUsed()}.forEach { binder ->
+            includedBinders.filter{it.isUsed }.forEach { binder ->
                 tab("if (${binder.fieldName}.hasPendingBindings()) {") {
                     tab("return true;")
                 }
@@ -529,11 +543,19 @@
         nl("public boolean setVariable(int variableId, Object variable) {") {
             tab("switch(variableId) {") {
                 usedVariables.forEach {
-                    tab ("case ${it.getName().br()} :") {
-                        tab("${it.setterName}((${it.getResolvedType().toJavaCode()}) variable);")
+                    tab ("case ${it.name.br()} :") {
+                        tab("${it.setterName}((${it.resolvedType.toJavaCode()}) variable);")
                         tab("return true;")
                     }
                 }
+                val declaredOnly = variables.filter { !it.isUsed && it.isDeclared };
+                declaredOnly.forEachIndexed { i, identifierExpr ->
+                    tab ("case ${identifierExpr.name.br()} :") {
+                        if (i == declaredOnly.size - 1) {
+                            tab("return true;")
+                        }
+                    }
+                }
             }
             tab("}")
             tab("return false;")
@@ -541,44 +563,41 @@
         nl("}")
     }
 
-    fun declareLog() = kcode("") {
-        nl("private void log(String msg, long i) {") {
-            tab("""android.util.Log.d("BINDER", msg + ":" + Long.toHexString(i));""")
-        }
-        nl("}")
-    }
-
     fun variableSettersAndGetters() = kcode("") {
-        variables.filterNot{it.isUsed()}.forEach {
-            nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableName}) {") {
+        variables.filterNot{it.isUsed }.forEach {
+            nl("public void ${it.setterName}(${it.resolvedType.toJavaCode()} ${it.readableName}) {") {
                 tab("// not used, ignore")
             }
             nl("}")
             nl("")
-            nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
-                tab("return ${it.getDefaultValue()};")
+            nl("public ${it.resolvedType.toJavaCode()} ${it.getterName}() {") {
+                tab("return ${it.defaultValue};")
             }
             nl("}")
         }
         usedVariables.forEach {
-            if (it.getUserDefinedType() != null) {
-                nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableName}) {") {
-                    if (it.isObservable()) {
-                        tab("updateRegistration(${it.getId()}, ${it.readableName});");
+            if (it.userDefinedType != null) {
+                nl("public void ${it.setterName}(${it.resolvedType.toJavaCode()} ${it.readableName}) {") {
+                    if (it.isObservable) {
+                        tab("updateRegistration(${it.id}, ${it.readableName});");
                     }
                     tab("this.${it.fieldName} = ${it.readableName};")
                     // set dirty flags!
                     val flagSet = it.invalidateFlagSet
                     tab("synchronized(this) {") {
                         mDirtyFlags.mapOr(flagSet) { suffix, index ->
-                            tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
+                            tab("${mDirtyFlags.localName}$suffix |= ${flagSet.localValue(index)};")
                         }
                     } tab ("}")
+                    // TODO: Remove this condition after releasing version 1.1 of SDK
+                    if (ModelAnalyzer.getInstance().findClass("android.databinding.ViewDataBinding", null).isObservable) {
+                        tab("notifyPropertyChanged(${it.name.br()});")
+                    }
                     tab("super.requestRebind();")
                 }
                 nl("}")
                 nl("")
-                nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") {
+                nl("public ${it.resolvedType.toJavaCode()} ${it.getterName}() {") {
                     tab("return ${it.fieldName};")
                 }
                 nl("}")
@@ -590,9 +609,9 @@
         nl("@Override")
         nl("protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {") {
             tab("switch (localFieldId) {") {
-                model.getObservables().forEach {
-                    tab("case ${it.getId()} :") {
-                        tab("return ${it.onChangeName}((${it.getResolvedType().toJavaCode()}) object, fieldId);")
+                model.observables.forEach {
+                    tab("case ${it.id} :") {
+                        tab("return ${it.onChangeName}((${it.resolvedType.toJavaCode()}) object, fieldId);")
                     }
                 }
             }
@@ -602,18 +621,22 @@
         nl("}")
         nl("")
 
-        model.getObservables().forEach {
-            nl("private boolean ${it.onChangeName}(${it.getResolvedType().toJavaCode()} ${it.readableName}, int fieldId) {") {
+        model.observables.forEach {
+            nl("private boolean ${it.onChangeName}(${it.resolvedType.toJavaCode()} ${it.readableName}, int fieldId) {") {
                 tab("switch (fieldId) {", {
-                    val accessedFields: List<FieldAccessExpr> = it.getParents().filterIsInstance(javaClass<FieldAccessExpr>())
+                    val accessedFields: List<FieldAccessExpr> = it.parents.filterIsInstance(FieldAccessExpr::class.java)
                     accessedFields.filter { it.hasBindableAnnotations() }
-                            .groupBy { it.getName() }
+                            .groupBy { it.brName }
                             .forEach {
-                                tab("case ${it.key.br()}:") {
-                                    val field = it.value.first()
+                                // If two expressions look different but resolve to the same method,
+                                // we are not yet able to merge them. This is why we merge their
+                                // flags below.
+                                tab("case ${it.key}:") {
                                     tab("synchronized(this) {") {
-                                        mDirtyFlags.mapOr(field.invalidateFlagSet) { suffix, index ->
-                                            tab("${mDirtyFlags.localValue(index)} |= ${field.invalidateFlagSet.localValue(index)};")
+                                        val flagSet = it.value.foldRight(FlagSet()) { l, r -> l.invalidateFlagSet.or(r) }
+
+                                        mDirtyFlags.mapOr(flagSet) { suffix, index ->
+                                            tab("${mDirtyFlags.localValue(index)} |= ${flagSet.localValue(index)};")
                                         }
                                     } tab("}")
                                     tab("return true;")
@@ -624,7 +647,7 @@
                         val flagSet = it.invalidateFlagSet
                         tab("synchronized(this) {") {
                             mDirtyFlags.mapOr(flagSet) { suffix, index ->
-                                tab("${mDirtyFlags.getLocalName()}$suffix |= ${flagSet.localValue(index)};")
+                                tab("${mDirtyFlags.localName}$suffix |= ${flagSet.localValue(index)};")
                             }
                         } tab("}")
                         tab("return true;")
@@ -641,57 +664,80 @@
 
     fun declareViews() = kcode("// views") {
         val oneLayout = !layoutBinder.hasVariations();
-        layoutBinder.getSortedTargets().filter {it.isUsed() && (oneLayout || it.getId() == null)}.forEach {
+        layoutBinder.sortedTargets.filter {it.isUsed && (oneLayout || it.id == null)}.forEach {
             val access : String
-            if (oneLayout && it.getId() != null) {
+            if (oneLayout && it.id != null) {
                 access = "public"
             } else {
                 access = "private"
             }
-            nl("${access} final ${it.interfaceType} ${it.fieldName};")
+            nl("$access final ${it.interfaceClass} ${it.fieldName};")
         }
     }
 
     fun declareVariables() = kcode("// variables") {
         usedVariables.forEach {
-            nl("private ${it.getResolvedType().toJavaCode()} ${it.fieldName};")
+            nl("private ${it.resolvedType.toJavaCode()} ${it.fieldName};")
         }
     }
 
     fun declareBoundValues() = kcode("// values") {
-        layoutBinder.getSortedTargets().filter { it.isUsed() }
-                .flatMap { it.getBindings() }
+        layoutBinder.sortedTargets.filter { it.isUsed }
+                .flatMap { it.bindings }
                 .filter { it.requiresOldValue() }
-                .flatMap{ it.getComponentExpressions().toArrayList() }
+                .flatMap{ it.componentExpressions.toArrayList() }
                 .groupBy { it }
                 .forEach {
-                    val expr = it.getKey()
-                    nl("private ${expr.getResolvedType().toJavaCode()} ${expr.oldValueName};")
+                    val expr = it.key
+                    nl("private ${expr.resolvedType.toJavaCode()} ${expr.oldValueName};")
                 }
     }
 
     fun declareListeners() = kcode("// listeners") {
-        model.getExprMap().values().filter {
-            it is FieldAccessExpr && it.isListener()
+        model.exprMap.values.filter {
+            it is ListenerExpr
         }.groupBy { it }.forEach {
-            val expr = it.key as FieldAccessExpr
+            val expr = it.key as ListenerExpr
             nl("private ${expr.listenerClassName} ${expr.fieldName};")
         }
     }
 
+    fun declareInverseBindingImpls() = kcode("// Inverse Binding Event Handlers") {
+        layoutBinder.sortedTargets.filter { it.isUsed }.forEach { target ->
+            target.inverseBindings.forEach { inverseBinding ->
+                val className : String
+                val param : String
+                if (inverseBinding.isOnBinder) {
+                    className = "android.databinding.ViewDataBinding.PropertyChangedInverseListener"
+                    param = "BR.${inverseBinding.eventAttribute}"
+                } else {
+                    className = "android.databinding.InverseBindingListener"
+                    param = ""
+                }
+                nl("private $className ${inverseBinding.fieldName} = new $className($param) {") {
+                    tab("@Override")
+                    tab("public void onChange() {") {
+                        tab(inverseBinding.toJavaCode("mBindingComponent", mDirtyFlags)).app(";");
+                    }
+                    tab("}")
+                }
+                nl("};")
+            }
+        }
+    }
     fun declareDirtyFlags() = kcode("// dirty flag") {
         model.ext.localizedFlags.forEach { flag ->
             flag.notEmpty { suffix, value ->
                 nl("private")
-                app(" ", if(flag.isDynamic()) null else "static final");
-                app(" ", " ${flag.type} ${flag.getLocalName()}$suffix = ${longToBinary(value)};")
+                app(" ", if(flag.isDynamic) null else "static final");
+                app(" ", " ${flag.type} ${flag.localName}$suffix = ${longToBinary(value)};")
             }
         }
     }
 
     fun flagMapping() = kcode("/* flag mapping") {
-        if (model.getFlagMapping() != null) {
-            val mapping = model.getFlagMapping()
+        if (model.flagMapping != null) {
+            val mapping = model.flagMapping
             for (i in mapping.indices) {
                 tab("flag $i: ${mapping[i]}")
             }
@@ -703,98 +749,100 @@
         nl("@Override")
         nl("protected void executeBindings() {") {
             val tmpDirtyFlags = FlagSet(mDirtyFlags.buckets)
-            tmpDirtyFlags.setLocalName("dirtyFlags");
-            for (i in (0..mDirtyFlags.buckets.size() - 1)) {
+            tmpDirtyFlags.localName = "dirtyFlags";
+            for (i in (0..mDirtyFlags.buckets.size - 1)) {
                 tab("${tmpDirtyFlags.type} ${tmpDirtyFlags.localValue(i)} = 0;")
             }
             tab("synchronized(this) {") {
-                for (i in (0..mDirtyFlags.buckets.size() - 1)) {
+                for (i in (0..mDirtyFlags.buckets.size - 1)) {
                     tab("${tmpDirtyFlags.localValue(i)} = ${mDirtyFlags.localValue(i)};")
                     tab("${mDirtyFlags.localValue(i)} = 0;")
                 }
             } tab("}")
-            model.getPendingExpressions().filterNot {!it.canBeEvaluatedToAVariable() || (it.isVariable() && !it.isUsed())}.forEach {
-                tab("${it.getResolvedType().toJavaCode()} ${it.executePendingLocalName} = ${if(it.isVariable()) it.fieldName else it.getDefaultValue()};")
+            model.pendingExpressions.filter { it.needsLocalField }.forEach {
+                tab("${it.resolvedType.toJavaCode()} ${it.executePendingLocalName} = ${if (it.isVariable()) it.fieldName else it.defaultValue};")
             }
             L.d("writing executePendingBindings for %s", className)
             do {
-                val batch = ExprModel.filterShouldRead(model.getPendingExpressions()).toArrayList()
+                val batch = ExprModel.filterShouldRead(model.pendingExpressions).toArrayList()
+                val justRead = arrayListOf<Expr>()
                 L.d("batch: %s", batch)
-                val mJustRead = arrayListOf<Expr>()
                 while (!batch.none()) {
-                    val readNow = batch.filter { it.shouldReadNow(mJustRead) }
+                    val readNow = batch.filter { it.shouldReadNow(justRead) }
                     if (readNow.isEmpty()) {
                         throw IllegalStateException("do not know what I can read. bailing out ${batch.joinToString("\n")}")
                     }
-                    L.d("new read now. batch size: %d, readNow size: %d", batch.size(), readNow.size())
-
-                    readNow.forEach {
-                        nl(readWithDependants(it, mJustRead, batch, tmpDirtyFlags))
-                    }
-                    batch.removeAll(mJustRead)
+                    L.d("new read now. batch size: %d, readNow size: %d", batch.size, readNow.size)
+                    nl(readWithDependants(readNow, justRead, batch, tmpDirtyFlags))
+                    batch.removeAll(justRead)
                 }
                 tab("// batch finished")
-            } while(model.markBitsRead())
+            } while (model.markBitsRead())
             // verify everything is read.
-            val batch = ExprModel.filterShouldRead(model.getPendingExpressions()).toArrayList()
+            val batch = ExprModel.filterShouldRead(model.pendingExpressions).toArrayList()
             if (batch.isNotEmpty()) {
                 L.e("could not generate code for %s. This might be caused by circular dependencies."
-                        + "Please report on b.android.com", layoutBinder.getLayoutname())
+                        + "Please report on b.android.com. %d %s %s", layoutBinder.layoutname,
+                        batch.size, batch[0], batch[0].toCode().generate())
             }
             //
-            layoutBinder.getSortedTargets().filter { it.isUsed() }
-                    .flatMap { it.getBindings() }
-                    .groupBy { it.getExpr() }
-                    .forEach {
-                        val flagSet = it.key.dirtyFlagSet
-                        tab("if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
-                            "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
-                        }.joinToString(" || ")
-                        }) {") {
+            layoutBinder.sortedTargets.filter { it.isUsed }
+                    .flatMap { it.bindings }
+                    .groupBy {
+                        "${tmpDirtyFlags.mapOr(it.expr.dirtyFlagSet) { suffix, index ->
+                            "(${tmpDirtyFlags.localValue(index)} & ${it.expr.dirtyFlagSet.localValue(index)}) != 0"
+                        }.joinToString(" || ") }"
+                    }.forEach {
+                tab("if (${it.key}) {") {
+                    it.value.groupBy { Math.max(1, it.minApi) }.forEach {
+                        val setterValues = kcode("") {
                             it.value.forEach { binding ->
-                                tab("// api target ${binding.getMinApi()}")
-                                val fieldName : String
-                                if (binding.getTarget().getViewClass().
-                                        equals(binding.getTarget().getInterfaceType())) {
-                                    fieldName = "this.${binding.getTarget().fieldName}"
+                                val fieldName: String
+                                if (binding.target.viewClass.
+                                        equals(binding.target.interfaceType)) {
+                                    fieldName = "this.${binding.target.fieldName}"
                                 } else {
-                                    fieldName = "((${binding.getTarget().getViewClass()}) this.${binding.getTarget().fieldName})"
+                                    fieldName = "((${binding.target.viewClass}) this.${binding.target.fieldName})"
                                 }
-                                val bindingCode = binding.toJavaCode(fieldName, "this.mBindingComponent")
-                                if (binding.getMinApi() > 1) {
-                                    tab("if(getBuildSdkInt() >= ${binding.getMinApi()}) {") {
-                                        tab("$bindingCode;")
-                                    }
-                                    tab("}")
-                                } else {
-                                    tab("$bindingCode;")
-                                }
+                                tab(binding.toJavaCode(fieldName, "this.mBindingComponent")).app(";")
                             }
                         }
-                        tab("}")
+                        tab("// api target ${it.key}")
+                        if (it.key > 1) {
+                            tab("if(getBuildSdkInt() >= ${it.key}) {") {
+                                app("", setterValues)
+                            }
+                            tab("}")
+                        } else {
+                            app("", setterValues)
+                        }
                     }
+                }
+                tab("}")
+            }
 
-            layoutBinder.getSortedTargets().filter { it.isUsed() }
-                    .flatMap { it.getBindings() }
+
+            layoutBinder.sortedTargets.filter { it.isUsed }
+                    .flatMap { it.bindings }
                     .filter { it.requiresOldValue() }
-                    .groupBy { it.getExpr() }
-                    .forEach {
-                        val flagSet = it.key.dirtyFlagSet
-                        tab("if (${tmpDirtyFlags.mapOr(flagSet) { suffix, index ->
-                            "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
-                        }.joinToString(" || ")
-                        }) {") {
-                            it.value.first().getComponentExpressions().forEach { expr ->
-                                tab("this.${expr.oldValueName} = ${expr.toCode(false).generate()};")
-                            }
+                    .groupBy {"${tmpDirtyFlags.mapOr(it.expr.dirtyFlagSet) { suffix, index ->
+                        "(${tmpDirtyFlags.localValue(index)} & ${it.expr.dirtyFlagSet.localValue(index)}) != 0"
+                    }.joinToString(" || ")
+                    }"}.forEach {
+                tab("if (${it.key}) {") {
+                    it.value.groupBy { it.expr }.map { it.value.first() }.forEach {
+                        it.componentExpressions.forEach { expr ->
+                            tab("this.${expr.oldValueName} = ${expr.toCode().generate()};")
                         }
-                        tab("}")
                     }
-            includedBinders.filter{it.isUsed()}.forEach { binder ->
+                }
+                tab("}")
+            }
+            includedBinders.filter{it.isUsed }.forEach { binder ->
                 tab("${binder.fieldName}.executePendingBindings();")
             }
-            layoutBinder.getSortedTargets().filter{
-                it.isUsed() && it.getResolvedType() != null && it.getResolvedType().extendsViewStub()
+            layoutBinder.sortedTargets.filter{
+                it.isUsed && it.resolvedType != null && it.resolvedType.extendsViewStub()
             }.forEach {
                 tab("if (${it.fieldName}.getBinding() != null) {") {
                     tab("${it.fieldName}.getBinding().executePendingBindings();")
@@ -805,182 +853,234 @@
         nl("}")
     }
 
-    fun readWithDependants(expr : Expr, mJustRead : MutableList<Expr>, batch : MutableList<Expr>,
-            tmpDirtyFlags : FlagSet, inheritedFlags : FlagSet? = null) : KCode = kcode("") {
-        mJustRead.add(expr)
-        L.d("%s / readWithDependants %s", className, expr.getUniqueKey());
-        val flagSet = expr.shouldReadFlagSet
-        val needsIfWrapper = inheritedFlags == null || !flagSet.bitsEqual(inheritedFlags)
-        L.d("flag set:%s . inherited flags: %s. need another if: %s", flagSet, inheritedFlags, needsIfWrapper);
-        val ifClause = "if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
-            "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
-        }.joinToString(" || ")
-        })"
-
-        val readCode = kcode("") {
-            if (expr.canBeEvaluatedToAVariable() && !expr.isVariable()) {
-                // it is not a variable read it.
-                tab("// read ${expr.getUniqueKey()}")
-                // create an if case for all dependencies that might be null
-                val nullables = expr.getDependencies().filter {
-                    it.isMandatory() && it.getOther().getResolvedType().isNullable()
-                }.map { it.getOther() }
-                if (!expr.isEqualityCheck() && nullables.isNotEmpty()) {
-                    tab ("if ( ${nullables.map { "${it.executePendingLocalName} != null" }.joinToString(" && ")}) {") {
-                        tab("${expr.executePendingLocalName}").app(" = ", expr.toCode(true)).app(";")
+    fun readWithDependants(expressionList: List<Expr>, justRead: MutableList<Expr>,
+            batch: MutableList<Expr>, tmpDirtyFlags: FlagSet,
+            inheritedFlags: FlagSet? = null) : KCode = kcode("") {
+        expressionList.groupBy { it.shouldReadFlagSet }.forEach {
+            val flagSet = it.key
+            val needsIfWrapper = inheritedFlags == null || !flagSet.bitsEqual(inheritedFlags)
+            val expressions = it.value
+            val ifClause = "if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
+                "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
+            }.joinToString(" || ")
+            })"
+            val readCode = kcode("") {
+                val dependants = ArrayList<Expr>()
+                expressions.groupBy { condition(it) }.forEach {
+                    val condition = it.key
+                    val assignedValues = it.value.filter { it.needsLocalField && !it.isVariable() }
+                    if (!assignedValues.isEmpty()) {
+                        val assignment = kcode("") {
+                            assignedValues.forEach { expr: Expr ->
+                                tab("// read ${expr.uniqueKey}")
+                                tab("${expr.executePendingLocalName}").app(" = ", expr.toFullCode()).app(";")
+                            }
+                        }
+                        if (condition != null) {
+                            tab("if ($condition) {") {
+                                app("", assignment)
+                            }
+                            tab ("}")
+                        } else {
+                            app("", assignment)
+                        }
+                        it.value.filter { it.isObservable }.forEach { expr: Expr ->
+                            tab("updateRegistration(${expr.id}, ${expr.executePendingLocalName});")
+                        }
                     }
-                    tab("}")
-                } else {
-                    tab("${expr.executePendingLocalName}").app(" = ", expr.toCode(true)).app(";")
-                }
-                if (expr.isObservable()) {
-                    tab("updateRegistration(${expr.getId()}, ${expr.executePendingLocalName});")
-                }
-            }
 
-            // if I am the condition for an expression, set its flag
-            val conditionals = expr.getDependants().filter { !it.isConditional()
-                    && it.getDependant() is TernaryExpr && (it.getDependant() as TernaryExpr).getPred() == expr }
-                    .map { it.getDependant() }
-            if (conditionals.isNotEmpty()) {
-                tab("// setting conditional flags")
-                tab("if (${expr.executePendingLocalName}) {") {
-                    conditionals.forEach {
-                        val set = it.getRequirementFlagSet(true)
-                        mDirtyFlags.mapOr(set) { suffix , index ->
-                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
+                    it.value.forEach { expr: Expr ->
+                        justRead.add(expr)
+                        L.d("%s / readWithDependants %s", className, expr.uniqueKey);
+                        L.d("flag set:%s . inherited flags: %s. need another if: %s", flagSet, inheritedFlags, needsIfWrapper);
+
+                        // if I am the condition for an expression, set its flag
+                        expr.dependants.filter {
+                            !it.isConditional && it.dependant is TernaryExpr &&
+                                    (it.dependant as TernaryExpr).pred == expr
+                        }.map { it.dependant }.groupBy {
+                            // group by when those ternaries will be evaluated (e.g. don't set conditional flags for no reason)
+                            val ternaryBitSet = it.shouldReadFlagsWithConditionals
+                            val isBehindTernary = ternaryBitSet.nextSetBit(model.invalidateAnyFlagIndex) == -1
+                            if (!isBehindTernary) {
+                                val ternaryFlags = it.shouldReadWithConditionalsFlagSet
+                                "if(${tmpDirtyFlags.mapOr(ternaryFlags){ suffix, index ->
+                                    "(${tmpDirtyFlags.localValue(index)} & ${ternaryFlags.localValue(index)}) != 0"
+                                }.joinToString(" || ")}) {"
+                            } else {
+                                // TODO if it is behind a ternary, we should set it when its predicate is elevated
+                                // Normally, this would mean that there is another code path to re-read our current expression.
+                                // Unfortunately, this may not be true due to the coverage detection in `expr#markAsReadIfDone`, this may never happen.
+                                // for v1.0, we'll go with always setting it and suffering an unnecessary calculation for this edge case.
+                                // we can solve this by listening to elevation events from the model.
+                                ""
+                            }
+                        }.forEach {
+                            val hasAnotherIf = it.key != ""
+                            if (hasAnotherIf) {
+                                tab(it.key) {
+                                    tab("if (${expr.executePendingLocalName}) {") {
+                                        it.value.forEach {
+                                            val set = it.getRequirementFlagSet(true)
+                                            mDirtyFlags.mapOr(set) { suffix, index ->
+                                                tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
+                                            }
+                                        }
+                                    }
+                                    tab("} else {") {
+                                        it.value.forEach {
+                                            val set = it.getRequirementFlagSet(false)
+                                            mDirtyFlags.mapOr(set) { suffix, index ->
+                                                tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
+                                            }
+                                        }
+                                    }.tab("}")
+                                }.app("}")
+                            } else {
+                                tab("if (${expr.executePendingLocalName}) {") {
+                                    it.value.forEach {
+                                        val set = it.getRequirementFlagSet(true)
+                                        mDirtyFlags.mapOr(set) { suffix, index ->
+                                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
+                                        }
+                                    }
+                                }
+                                tab("} else {") {
+                                    it.value.forEach {
+                                        val set = it.getRequirementFlagSet(false)
+                                        mDirtyFlags.mapOr(set) { suffix, index ->
+                                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
+                                        }
+                                    }
+                                } app("}")
+                            }
+                        }
+                        val chosen = expr.dependants.filter {
+                            val dependant = it.dependant
+                            batch.contains(dependant) &&
+                                    dependant.shouldReadFlagSet.andNot(flagSet).isEmpty &&
+                                    dependant.shouldReadNow(justRead)
+                        }
+                        if (chosen.isNotEmpty()) {
+                            dependants.addAll(chosen.map { it.dependant })
                         }
                     }
                 }
-                tab("} else {") {
-                    conditionals.forEach {
-                        val set = it.getRequirementFlagSet(false)
-                        mDirtyFlags.mapOr(set) { suffix , index ->
-                            tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
-                        }
-                    }
-                } tab("}")
+                if (dependants.isNotEmpty()) {
+                    val nextInheritedFlags = if (needsIfWrapper) flagSet else inheritedFlags
+                    nl(readWithDependants(dependants, justRead, batch, tmpDirtyFlags, nextInheritedFlags))
+                }
             }
 
-            val chosen = expr.getDependants().filter {
-                val dependant = it.getDependant()
-                batch.contains(dependant) &&
-                        dependant.shouldReadFlagSet.andNot(flagSet).isEmpty() &&
-                        dependant.shouldReadNow(mJustRead)
-            }
-            if (chosen.isNotEmpty()) {
-                val nextInheritedFlags = if (needsIfWrapper) flagSet else inheritedFlags
-                chosen.forEach {
-                    nl(readWithDependants(it.getDependant(), mJustRead, batch, tmpDirtyFlags, nextInheritedFlags))
+            if (needsIfWrapper) {
+                tab(ifClause) {
+                    app(" {")
+                    app("", readCode)
                 }
+                tab("}")
+            } else {
+                app("", readCode)
             }
         }
-        if (needsIfWrapper) {
-            tab(ifClause) {
-                app(" {")
-                nl(readCode)
+    }
+
+    fun condition(expr : Expr) : String? {
+        if (expr.canBeEvaluatedToAVariable() && !expr.isVariable()) {
+            // create an if case for all dependencies that might be null
+            val nullables = expr.dependencies.filter {
+                it.isMandatory && it.other.resolvedType.isNullable
+            }.map { it.other }
+            if (!expr.isEqualityCheck && nullables.isNotEmpty()) {
+                return "${nullables.map { "${it.executePendingLocalName} != null" }.joinToString(" && ")}"
+            } else {
+                return null
             }
-            tab("}")
         } else {
-            nl(readCode)
+            return null
         }
     }
 
     fun declareListenerImpls() = kcode("// Listener Stub Implementations") {
-        model.getExprMap().values().filter {
-            it.isUsed() && it is FieldAccessExpr && it.isListener()
+        model.exprMap.values.filter {
+            it.isUsed && it is ListenerExpr
         }.groupBy { it }.forEach {
-            val expr = it.key as FieldAccessExpr
-            val listeners = expr.getListenerTypes()
-            val extends = listeners.firstOrNull{ !it.isInterface() }
-            val extendsImplements = StringBuilder()
-            if (extends != null) {
-                extendsImplements.append("extends ${extends.toJavaCode()} ");
+            val expr = it.key as ListenerExpr
+            val listenerType = expr.resolvedType;
+            val extendsImplements : String
+            if (listenerType.isInterface) {
+                extendsImplements = "implements"
+            } else {
+                extendsImplements = "extends"
             }
-            val implements = expr.getListenerTypes().filter{ it.isInterface() }.map {
-                it.toJavaCode()
-            }.joinToString(", ")
-            if (!implements.isEmpty()) {
-                extendsImplements.append("implements ${implements}")
-            }
-            nl("public static class ${expr.listenerClassName} ${extendsImplements} {") {
-                tab("public ${expr.listenerClassName}() {}")
-                if (expr.getChild().isDynamic()) {
-                    tab("private ${expr.getChild().getResolvedType().toJavaCode()} value;")
-                    tab("public ${expr.listenerClassName} setValue(${expr.getChild().getResolvedType().toJavaCode()} value) {") {
+            nl("public static class ${expr.listenerClassName} $extendsImplements ${listenerType.canonicalName}{") {
+                if (expr.child.isDynamic) {
+                    tab("private ${expr.child.resolvedType.toJavaCode()} value;")
+                    tab("public ${expr.listenerClassName} setValue(${expr.child.resolvedType.toJavaCode()} value) {") {
                         tab("this.value = value;")
                         tab("return value == null ? null : this;")
                     }
                     tab("}")
                 }
-                val signatures = HashSet<String>()
-                expr.getListenerMethods().withIndex().forEach {
-                    val listener = it.value
-                    val calledMethod = expr.getCalledMethods().get(it.index)
-                    val parameterTypes = listener.getParameterTypes()
-                    val returnType = listener.getReturnType(parameterTypes.toArrayList())
-                    val signature = "public ${returnType} ${listener.getName()}(${
+                val listenerMethod = expr.method
+                val parameterTypes = listenerMethod.parameterTypes
+                val returnType = listenerMethod.getReturnType(parameterTypes.toArrayList())
+                tab("@Override")
+                tab("public $returnType ${listenerMethod.name}(${
                     parameterTypes.withIndex().map {
                         "${it.value.toJavaCode()} arg${it.index}"
                     }.joinToString(", ")
-                    }) {"
-                    if (!signatures.contains(signature)) {
-                        signatures.add(signature)
-                        tab("@Override")
-                        tab(signature) {
-                            val obj : String
-                            if (expr.getChild().isDynamic()) {
-                                obj = "this.value"
-                            } else {
-                                obj = expr.getChild().toCode(false).generate();
-                            }
-                            val returnStr : String
-                            if (!returnType.isVoid()) {
-                                returnStr = "return "
-                            } else {
-                                returnStr = ""
-                            }
-                            val args = parameterTypes.withIndex().map {
-                                "arg${it.index}"
-                            }.joinToString(", ")
-                            tab("${returnStr}${obj}.${calledMethod.getName()}(${args});")
-                        }
-                        tab("}")
+                }) {") {
+                    val obj : String
+                    if (expr.child.isDynamic) {
+                        obj = "this.value"
+                    } else {
+                        obj = expr.child.toCode().generate();
                     }
+                    val returnStr : String
+                    if (!returnType.isVoid) {
+                        returnStr = "return "
+                    } else {
+                        returnStr = ""
+                    }
+                    val args = parameterTypes.withIndex().map {
+                        "arg${it.index}"
+                    }.joinToString(", ")
+                    tab("$returnStr$obj.${expr.name}($args);")
                 }
+                tab("}")
             }
             nl("}")
         }
     }
 
     fun declareFactories() = kcode("") {
-        nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
+        nl("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
             tab("return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());")
         }
         nl("}")
-        nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent) {") {
-            tab("return android.databinding.DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, root, attachToRoot, bindingComponent);")
+        nl("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent) {") {
+            tab("return android.databinding.DataBindingUtil.<$baseClassName>inflate(inflater, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, root, attachToRoot, bindingComponent);")
         }
         nl("}")
-        if (!layoutBinder.isMerge()) {
-            nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater) {") {
+        if (!layoutBinder.isMerge) {
+            nl("public static $baseClassName inflate(android.view.LayoutInflater inflater) {") {
                 tab("return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());")
             }
             nl("}")
-            nl("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent) {") {
-                tab("return bind(inflater.inflate(${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false), bindingComponent);")
+            nl("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent) {") {
+                tab("return bind(inflater.inflate(${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, null, false), bindingComponent);")
             }
             nl("}")
-            nl("public static ${baseClassName} bind(android.view.View view) {") {
+            nl("public static $baseClassName bind(android.view.View view) {") {
                 tab("return bind(view, android.databinding.DataBindingUtil.getDefaultComponent());")
             }
             nl("}")
-            nl("public static ${baseClassName} bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {") {
-                tab("if (!\"${layoutBinder.getTag()}_0\".equals(view.getTag())) {") {
+            nl("public static $baseClassName bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {") {
+                tab("if (!\"${layoutBinder.tag}_0\".equals(view.getTag())) {") {
                     tab("throw new RuntimeException(\"view tag isn't correct on view:\" + view.getTag());")
                 }
                 tab("}")
-                tab("return new ${baseClassName}(bindingComponent, view);")
+                tab("return new $baseClassName(bindingComponent, view);")
             }
             nl("}")
         }
@@ -990,43 +1090,43 @@
      * When called for a library compilation, we do not generate real implementations
      */
     public fun writeBaseClass(forLibrary : Boolean) : String =
-        kcode("package ${layoutBinder.getPackage()};") {
+        kcode("package ${layoutBinder.`package`};") {
             nl("import android.databinding.Bindable;")
             nl("import android.databinding.DataBindingUtil;")
             nl("import android.databinding.ViewDataBinding;")
-            nl("public abstract class ${baseClassName} extends ViewDataBinding {")
-            layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
-                tab("public final ${it.interfaceType} ${it.fieldName};")
+            nl("public abstract class $baseClassName extends ViewDataBinding {")
+            layoutBinder.sortedTargets.filter{it.id != null}.forEach {
+                tab("public final ${it.interfaceClass} ${it.fieldName};")
             }
             nl("")
-            tab("protected ${baseClassName}(android.databinding.DataBindingComponent bindingComponent, android.view.View root_, int localFieldCount") {
-                layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
-                    tab(", ${it.interfaceType} ${it.constructorParamName}")
+            tab("protected $baseClassName(android.databinding.DataBindingComponent bindingComponent, android.view.View root_, int localFieldCount") {
+                layoutBinder.sortedTargets.filter{it.id != null}.forEach {
+                    tab(", ${it.interfaceClass} ${it.constructorParamName}")
                 }
             }
             tab(") {") {
                 tab("super(bindingComponent, root_, localFieldCount);")
-                layoutBinder.getSortedTargets().filter{it.getId() != null}.forEach {
+                layoutBinder.sortedTargets.filter{it.id != null}.forEach {
                     tab("this.${it.fieldName} = ${it.constructorParamName};")
                 }
             }
             tab("}")
             nl("")
             variables.forEach {
-                if (it.getUserDefinedType() != null) {
-                    val type = ModelAnalyzer.getInstance().applyImports(it.getUserDefinedType(), model.getImports())
-                    tab("public abstract void ${it.setterName}(${type} ${it.readableName});")
+                if (it.userDefinedType != null) {
+                    val type = ModelAnalyzer.getInstance().applyImports(it.userDefinedType, model.imports)
+                    tab("public abstract void ${it.setterName}($type ${it.readableName});")
                 }
             }
-            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
+            tab("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
                 tab("return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());")
             }
             tab("}")
-            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater) {") {
+            tab("public static $baseClassName inflate(android.view.LayoutInflater inflater) {") {
                 tab("return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());")
             }
             tab("}")
-            tab("public static ${baseClassName} bind(android.view.View view) {") {
+            tab("public static $baseClassName bind(android.view.View view) {") {
                 if (forLibrary) {
                     tab("return null;")
                 } else {
@@ -1034,27 +1134,27 @@
                 }
             }
             tab("}")
-            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent) {") {
+            tab("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent) {") {
                 if (forLibrary) {
                     tab("return null;")
                 } else {
-                    tab("return DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, root, attachToRoot, bindingComponent);")
+                    tab("return DataBindingUtil.<$baseClassName>inflate(inflater, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, root, attachToRoot, bindingComponent);")
                 }
             }
             tab("}")
-            tab("public static ${baseClassName} inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent) {") {
+            tab("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent) {") {
                 if (forLibrary) {
                     tab("return null;")
                 } else {
-                    tab("return DataBindingUtil.<${baseClassName}>inflate(inflater, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false, bindingComponent);")
+                    tab("return DataBindingUtil.<$baseClassName>inflate(inflater, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, null, false, bindingComponent);")
                 }
             }
             tab("}")
-            tab("public static ${baseClassName} bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {") {
+            tab("public static $baseClassName bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {") {
                 if (forLibrary) {
                     tab("return null;")
                 } else {
-                    tab("return (${baseClassName})bind(bindingComponent, view, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()});")
+                    tab("return ($baseClassName)bind(bindingComponent, view, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname});")
                 }
             }
             tab("}")
diff --git a/compiler/src/main/resources/NOTICE.txt b/compiler/src/main/resources/NOTICE.txt
new file mode 100644
index 0000000..36ed1c9
--- /dev/null
+++ b/compiler/src/main/resources/NOTICE.txt
@@ -0,0 +1,1823 @@
+List of 3rd party licenses:
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@51d6b1e name:antlr4 classifier:null extension:jar type:jar]
+
+ ****** LICENSE:
+[The "BSD license"]
+Copyright (c) 2015 Terence Parr, Sam Harwell
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@651cb3d9 name:kotlin-stdlib classifier:null extension:jar type:jar]
+
+ ****** NOTICE:
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Kotlin Compiler distribution.                 ==
+   =========================================================================
+
+   Kotlin Compiler
+   Copyright 2010-2015 JetBrains s.r.o and respective authors and developers
+
+ ****** LICENSE:
+/*
+ * Copyright 2010-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ ****** LICENSE:
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@2fc42657 name:commons-io classifier:null extension:jar type:jar]
+
+ ****** NOTICE:
+Apache Commons IO
+Copyright 2002-2014 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+ ****** LICENSE:
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@15859779 name:antlr4-annotations classifier:null extension:jar type:jar]
+
+ ****** LICENSE:
+[The "BSD license"]
+Copyright (c) 2015 Terence Parr, Sam Harwell
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@a364cb2 name:commons-codec classifier:null extension:jar type:jar]
+
+ ****** NOTICE:
+Apache Commons Codec
+Copyright 2002-2015 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java
+contains test data from http://aspell.net/test/orig/batch0.tab.
+Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org)
+
+===============================================================================
+
+The content of package org.apache.commons.codec.language.bm has been translated
+from the original php source code available at http://stevemorse.org/phoneticinfo.htm
+with permission from the original authors.
+Original source copyright:
+Copyright (c) 2008 Alexander Beider & Stephen P. Morse.
+
+ ****** LICENSE:
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@6c2e3a1a name:antlr-runtime classifier:null extension:jar type:jar]
+
+ ****** LICENSE:
+[The "BSD license"]
+Copyright (c) 2015 Terence Parr, Sam Harwell
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@76957ab3 name:juniversalchardet classifier:null extension:jar type:jar]
+
+ ****** LICENSE:
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the MPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+     ``The contents of this file are subject to the Mozilla Public License
+     Version 1.1 (the "License"); you may not use this file except in
+     compliance with the License. You may obtain a copy of the License at
+     https://www.mozilla.org/MPL/
+
+     Software distributed under the License is distributed on an "AS IS"
+     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+     License for the specific language governing rights and limitations
+     under the License.
+
+     The Original Code is ______________________________________.
+
+     The Initial Developer of the Original Code is ________________________.
+     Portions created by ______________________ are Copyright (C) ______
+     _______________________. All Rights Reserved.
+
+     Contributor(s): ______________________________________.
+
+     Alternatively, the contents of this file may be used under the terms
+     of the _____ license (the  "[___] License"), in which case the
+     provisions of [______] License are applicable instead of those
+     above.  If you wish to allow use of your version of this file only
+     under the terms of the [____] License and not to allow others to use
+     your version of this file under the MPL, indicate your decision by
+     deleting  the provisions above and replace  them with the notice and
+     other provisions required by the [___] License.  If you do not delete
+     the provisions above, a recipient may use your version of this file
+     under either the MPL or the [___] License."
+
+     [NOTE: The text of this Exhibit A may differ slightly from the text of
+     the notices in the Source Code files of the Original Code. You should
+     use the text of this Exhibit A rather than the text found in the
+     Original Code Source Code for Your Modifications.]
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@1abebee9 name:org.abego.treelayout.core classifier:null extension:jar type:jar]
+
+ ****** LICENSE:
+[The "BSD license"]
+Copyright (c) 2011, abego Software GmbH, Germany (http://www.abego.org)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, 
+   this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice, 
+   this list of conditions and the following disclaimer in the documentation 
+   and/or other materials provided with the distribution.
+3. Neither the name of the abego Software GmbH nor the names of its 
+   contributors may be used to endorse or promote products derived from this 
+   software without specific prior written permission.
+   
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@1bfa74bc name:antlr4-runtime classifier:null extension:jar type:jar]
+
+ ****** LICENSE:
+[The "BSD license"]
+Copyright (c) 2015 Terence Parr, Sam Harwell
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@3b9eaadc name:ST4 classifier:null extension:jar type:jar]
+
+ ****** LICENSE:
+[The "BSD license"]
+Copyright (c) 2011-2013 Terence Parr
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@4770644e name:commons-lang3 classifier:null extension:jar type:jar]
+
+ ****** NOTICE:
+Apache Commons Lang
+Copyright 2001-2015 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes software from the Spring Framework,
+under the Apache License 2.0 (see: StringUtils.containsWhitespace())
+
+ ****** LICENSE:
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+
+-----------------------------------------------------------------------------
+* [ResolvedArtifact dependency:org.gradle.api.internal.artifacts.ivyservice.dynamicversions.DefaultResolvedModuleVersion@238af8b0 name:kotlin-runtime classifier:null extension:jar type:jar]
+
+ ****** NOTICE:
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Kotlin Compiler distribution.                 ==
+   =========================================================================
+
+   Kotlin Compiler
+   Copyright 2010-2015 JetBrains s.r.o and respective authors and developers
+
+ ****** LICENSE:
+/*
+ * Copyright 2010-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ ****** LICENSE:
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
diff --git a/compiler/src/test/java/android/databinding/tool/LayoutBinderTest.java b/compiler/src/test/java/android/databinding/tool/LayoutBinderTest.java
index 042b563..8b1f820 100644
--- a/compiler/src/test/java/android/databinding/tool/LayoutBinderTest.java
+++ b/compiler/src/test/java/android/databinding/tool/LayoutBinderTest.java
@@ -14,17 +14,18 @@
 package android.databinding.tool;
 
 
-import org.junit.Before;
-import org.junit.Test;
-
 import android.databinding.tool.expr.Expr;
 import android.databinding.tool.expr.ExprModel;
 import android.databinding.tool.expr.FieldAccessExpr;
 import android.databinding.tool.expr.IdentifierExpr;
 import android.databinding.tool.expr.StaticIdentifierExpr;
 import android.databinding.tool.reflection.Callable;
+import android.databinding.tool.reflection.java.JavaAnalyzer;
 import android.databinding.tool.reflection.java.JavaClass;
 
+import org.junit.Before;
+import org.junit.Test;
+
 import java.util.List;
 import java.util.Map;
 
@@ -34,12 +35,13 @@
 import static org.junit.Assert.assertTrue;
 
 public class LayoutBinderTest {
-    LayoutBinder mLayoutBinder;
+    MockLayoutBinder mLayoutBinder;
     ExprModel mExprModel;
     @Before
     public void setUp() throws Exception {
         mLayoutBinder = new MockLayoutBinder();
         mExprModel = mLayoutBinder.getModel();
+        JavaAnalyzer.initForTests();
     }
 
     @Test
@@ -75,8 +77,8 @@
         int originalSize = mExprModel.size();
         mLayoutBinder.addVariable("user", "android.databinding.tool2.LayoutBinderTest.TestUser",
                 null);
-        mLayoutBinder.parse("user.name", null);
-        mLayoutBinder.parse("user.lastName", null);
+        mLayoutBinder.parse("user.name", false, null);
+        mLayoutBinder.parse("user.lastName", false, null);
         assertEquals(originalSize + 3, mExprModel.size());
         final List<Expr> bindingExprs = mExprModel.getBindingExpressions();
         assertEquals(2, bindingExprs.size());
@@ -92,7 +94,7 @@
     public void testParseWithMethods() {
         mLayoutBinder.addVariable("user", "android.databinding.tool.LayoutBinderTest.TestUser",
                 null);
-        mLayoutBinder.parse("user.fullName", null);
+        mLayoutBinder.parse("user.fullName", false, null);
         Expr item = mExprModel.getBindingExpressions().get(0);
         assertTrue(item instanceof FieldAccessExpr);
         IdentifierExpr id = mExprModel.identifier("user");
diff --git a/compiler/src/test/java/android/databinding/tool/MockLayoutBinder.java b/compiler/src/test/java/android/databinding/tool/MockLayoutBinder.java
index 3380ffa..0807e7c 100644
--- a/compiler/src/test/java/android/databinding/tool/MockLayoutBinder.java
+++ b/compiler/src/test/java/android/databinding/tool/MockLayoutBinder.java
@@ -13,6 +13,8 @@
 
 package android.databinding.tool;
 
+import android.databinding.tool.expr.IdentifierExpr;
+import android.databinding.tool.store.Location;
 import android.databinding.tool.store.ResourceBundle;
 
 import java.io.File;
@@ -24,4 +26,8 @@
                 "com.test.submodule",
                 false));
     }
+
+    public IdentifierExpr addVariable(String name, String type, Location location) {
+        return super.addVariable(name, type, location, true);
+    }
 }
diff --git a/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java b/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java
index bcd6794..04813e1 100644
--- a/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java
+++ b/compiler/src/test/java/android/databinding/tool/expr/ExprModelTest.java
@@ -16,14 +16,8 @@
 
 package android.databinding.tool.expr;
 
-import org.apache.commons.lang3.ArrayUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-
-import android.databinding.BaseObservable;
+import android.databinding.Bindable;
+import android.databinding.Observable;
 import android.databinding.tool.LayoutBinder;
 import android.databinding.tool.MockLayoutBinder;
 import android.databinding.tool.reflection.ModelAnalyzer;
@@ -31,6 +25,13 @@
 import android.databinding.tool.reflection.java.JavaAnalyzer;
 import android.databinding.tool.store.Location;
 import android.databinding.tool.util.L;
+import android.databinding.tool.writer.KCode;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -70,6 +71,16 @@
         protected String computeUniqueKey() {
             return mKey + super.computeUniqueKey();
         }
+
+        @Override
+        protected KCode generateCode(boolean full) {
+            return new KCode();
+        }
+
+        @Override
+        protected String getInvertibleError() {
+            return "DummyExpr cannot be 2-way.";
+        }
     }
 
     ExprModel mExprModel;
@@ -131,12 +142,12 @@
 
     @Test
     public void testShouldRead() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", "java.lang.String", null);
         IdentifierExpr b = lb.addVariable("b", "java.lang.String", null);
         IdentifierExpr c = lb.addVariable("c", "java.lang.String", null);
-        lb.parse("a == null ? b : c", null);
+        lb.parse("a == null ? b : c", false, null);
         mExprModel.comparison("==", a, mExprModel.symbol("null", Object.class));
         lb.getModel().seal();
         List<Expr> shouldRead = getShouldRead();
@@ -152,8 +163,33 @@
     }
 
     @Test
+    public void testReadConstantTernary() {
+        MockLayoutBinder lb = new MockLayoutBinder();
+        mExprModel = lb.getModel();
+        IdentifierExpr a = lb.addVariable("a", "java.lang.String", null);
+        IdentifierExpr b = lb.addVariable("b", "java.lang.String", null);
+        TernaryExpr ternaryExpr = parse(lb, "true ? a : b", TernaryExpr.class);
+        mExprModel.seal();
+        List<Expr> shouldRead = getShouldRead();
+        assertExactMatch(shouldRead, ternaryExpr.getPred());
+        List<Expr> first = getReadFirst(shouldRead);
+        assertExactMatch(first, ternaryExpr.getPred());
+        mExprModel.markBitsRead();
+        shouldRead = getShouldRead();
+        assertExactMatch(shouldRead, a, b, ternaryExpr);
+        first = getReadFirst(shouldRead);
+        assertExactMatch(first, a, b);
+        List<Expr> justRead = new ArrayList<Expr>();
+        justRead.add(a);
+        justRead.add(b);
+        first = filterOut(getReadFirst(shouldRead, justRead), justRead);
+        assertExactMatch(first, ternaryExpr);
+        assertFalse(mExprModel.markBitsRead());
+    }
+
+    @Test
     public void testTernaryWithPlus() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr user = lb
                 .addVariable("user", "android.databinding.tool.expr.ExprModelTest.User",
@@ -208,7 +244,7 @@
 
     @Test
     public void testTernaryInsideTernary() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr cond1 = lb.addVariable("cond1", "boolean", null);
         IdentifierExpr cond2 = lb.addVariable("cond2", "boolean", null);
@@ -253,14 +289,14 @@
 
     @Test
     public void testRequirementFlags() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", "java.lang.String", null);
         IdentifierExpr b = lb.addVariable("b", "java.lang.String", null);
         IdentifierExpr c = lb.addVariable("c", "java.lang.String", null);
         IdentifierExpr d = lb.addVariable("d", "java.lang.String", null);
         IdentifierExpr e = lb.addVariable("e", "java.lang.String", null);
-        final Expr aTernary = lb.parse("a == null ? b == null ? c : d : e", null);
+        final Expr aTernary = lb.parse("a == null ? b == null ? c : d : e", false, null);
         assertTrue(aTernary instanceof TernaryExpr);
         final Expr bTernary = ((TernaryExpr) aTernary).getIfTrue();
         assertTrue(bTernary instanceof TernaryExpr);
@@ -325,7 +361,7 @@
 
     @Test
     public void testPostConditionalDependencies() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
 
         IdentifierExpr u1 = lb.addVariable("u1", User.class.getCanonicalName(), null);
@@ -389,24 +425,26 @@
         assertTrue(mExprModel.markBitsRead());
 
         shouldRead = getShouldRead();
-        // actually, there is no real case to read u1 anymore because if b>c was not true,
+        // FIXME: there is no real case to read u1 anymore because if b>c was not true,
         // u1.getCond(d) will never be set. Right now, we don't have mechanism to figure this out
         // and also it does not affect correctness (just an unnecessary if stmt)
-        assertExactMatch(shouldRead, u2, u1LastName, u2LastName, bcTernary.getIfTrue(), bcTernary);
+        assertExactMatch(shouldRead, u1, u2, u1LastName, u2LastName, bcTernary.getIfTrue(), bcTernary);
         firstRead = getReadFirst(shouldRead);
-        assertExactMatch(firstRead, u1LastName, u2);
-
+        assertExactMatch(firstRead, u1, u2);
+        assertFlags(u1, bcTernary.getIfTrue().getRequirementFlagIndex(true));
+        assertFlags(u2, bcTernary.getIfTrue().getRequirementFlagIndex(false));
         assertFlags(u1LastName, bcTernary.getIfTrue().getRequirementFlagIndex(true));
         assertFlags(u2LastName, bcTernary.getIfTrue().getRequirementFlagIndex(false));
-        assertFlags(u2, bcTernary.getIfTrue().getRequirementFlagIndex(false));
 
         assertFlags(bcTernary.getIfTrue(), bcTernary.getRequirementFlagIndex(true));
         assertFlags(bcTernary, b, c, u1, u2, d, u1LastName, u2LastName, e);
+
+        assertFalse(mExprModel.markBitsRead());
     }
 
     @Test
     public void testCircularDependency() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName(),
                 null);
@@ -424,7 +462,7 @@
 
     @Test
     public void testNestedCircularDependency() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName(),
                 null);
@@ -446,8 +484,25 @@
     }
 
     @Test
+    public void testInterExprDependency() {
+        MockLayoutBinder lb = new MockLayoutBinder();
+        mExprModel = lb.getModel();
+        IdentifierExpr u = lb.addVariable("u", User.class.getCanonicalName(),
+                null);
+        final Expr uComment = parse(lb, "u.comment", FieldAccessExpr.class);
+        final TernaryExpr uTernary = parse(lb, "u.getUseComment ? u.comment : `xx`", TernaryExpr.class);
+        mExprModel.seal();
+        assertTrue(uTernary.getPred().canBeInvalidated());
+        List<Expr> shouldRead = getShouldRead();
+        assertExactMatch(shouldRead, u, uComment, uTernary.getPred());
+        assertTrue(mExprModel.markBitsRead());
+        shouldRead = getShouldRead();
+        assertExactMatch(shouldRead, uComment, uTernary);
+    }
+
+    @Test
     public void testInterExprCircularDependency() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", int.class.getCanonicalName(),
                 null);
@@ -465,7 +520,7 @@
 
     @Test
     public void testInterExprCircularDependency2() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(),
                 null);
@@ -476,20 +531,15 @@
         mExprModel.seal();
         List<Expr> shouldRead = getShouldRead();
         assertExactMatch(shouldRead, a, b);
+        assertFlags(a, a, b);
+        assertFlags(b, a, b);
         List<Expr> readFirst = getReadFirst(shouldRead);
         assertExactMatch(readFirst, a, b);
         assertTrue(mExprModel.markBitsRead());
         shouldRead = getShouldRead();
-        // read a and b again, this time for their dependencies and also the rest since everything
-        // is ready to be read
-        assertExactMatch(shouldRead, a, b, abTernary, baTernary);
-        List<Expr> justRead = new ArrayList<Expr>();
+        assertExactMatch(shouldRead, abTernary, baTernary);
         readFirst = getReadFirst(shouldRead);
-        assertExactMatch(readFirst, a, b);
-        Collections.addAll(justRead, a, b);
-        readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
         assertExactMatch(readFirst, abTernary, baTernary);
-
         assertFalse(mExprModel.markBitsRead());
         shouldRead = getShouldRead();
         assertEquals(0, shouldRead.size());
@@ -497,7 +547,7 @@
 
     @Test
     public void testInterExprCircularDependency3() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(),
                 null);
@@ -514,7 +564,7 @@
         shouldRead = getShouldRead();
         // read a and b again, this time for their dependencies and also the rest since everything
         // is ready to be read
-        assertExactMatch(shouldRead, a, b, c, abTernary, abTernary2);
+        assertExactMatch(shouldRead, c, abTernary, abTernary2);
         mExprModel.markBitsRead();
         shouldRead = getShouldRead();
         assertEquals(0, shouldRead.size());
@@ -522,7 +572,7 @@
 
     @Test
     public void testInterExprCircularDependency4() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(),
                 null);
@@ -537,6 +587,8 @@
         final TernaryExpr baTernary = parse(lb, "b ? a : false", TernaryExpr.class);
         mExprModel.seal();
         List<Expr> shouldRead = getShouldRead();
+        // check if a,b or c should be read. these are easily calculated from binding expressions'
+        // invalidation
         assertExactMatch(shouldRead, c, a, b);
 
         List<Expr> justRead = new ArrayList<Expr>();
@@ -546,16 +598,36 @@
         assertEquals(0, filterOut(getReadFirst(shouldRead, justRead), justRead).size());
         assertTrue(mExprModel.markBitsRead());
         shouldRead = getShouldRead();
-        assertExactMatch(shouldRead, a, b, d, cTernary.getIfTrue(), cTernary, abTernary, baTernary);
+        // if a and b are not invalid, a won't be read in the first step. But if c's expression
+        // is invalid and c == true, a must be read. Depending on a, d might be read as well.
+        // don't need to read b anymore because `a ? b : true` and `b ? a : false` has the same
+        // invalidation flags.
+        assertExactMatch(shouldRead, a, abTernary, baTernary);
         justRead.clear();
 
         readFirst = getReadFirst(shouldRead);
-        assertExactMatch(readFirst, a, b, d);
-        Collections.addAll(justRead, a, b, d);
+        // first must read `a`.
+        assertExactMatch(readFirst, a);
+        Collections.addAll(justRead, a);
 
         readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
-        assertExactMatch(readFirst, cTernary.getIfTrue(), abTernary, baTernary);
-        Collections.addAll(justRead, cTernary.getIfTrue(), abTernary, baTernary);
+        assertExactMatch(readFirst, abTernary, baTernary);
+        Collections.addAll(justRead, abTernary, baTernary);
+
+        readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
+        assertEquals(0, filterOut(getReadFirst(shouldRead, justRead), justRead).size());
+        assertTrue(mExprModel.markBitsRead());
+
+        shouldRead = getShouldRead();
+        // now we can read adf ternary and c ternary
+        justRead.clear();
+        assertExactMatch(shouldRead, d, cTernary.getIfTrue(), cTernary);
+        readFirst = getReadFirst(shouldRead);
+        assertExactMatch(readFirst, d);
+        Collections.addAll(justRead, d);
+        readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
+        assertExactMatch(readFirst, cTernary.getIfTrue());
+        Collections.addAll(justRead, cTernary.getIfTrue());
 
         readFirst = filterOut(getReadFirst(shouldRead, justRead), justRead);
         assertExactMatch(readFirst, cTernary);
@@ -567,8 +639,33 @@
     }
 
     @Test
+    public void testInterExprDeepDependency() {
+        MockLayoutBinder lb = new MockLayoutBinder();
+        mExprModel = lb.getModel();
+        IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(), null);
+        IdentifierExpr b = lb.addVariable("b", boolean.class.getCanonicalName(), null);
+        IdentifierExpr c = lb.addVariable("c", boolean.class.getCanonicalName(), null);
+        final TernaryExpr t1 = parse(lb, "c ? (a ? b : true) : false", TernaryExpr.class);
+        final TernaryExpr t2 = parse(lb, "c ? (b ? a : false) : true", TernaryExpr.class);
+        final TernaryExpr abTernary = (TernaryExpr) t1.getIfTrue();
+        final TernaryExpr baTernary = (TernaryExpr) t2.getIfTrue();
+        mExprModel.seal();
+        List<Expr> shouldRead = getShouldRead();
+        assertExactMatch(shouldRead, c);
+        assertTrue(mExprModel.markBitsRead());
+        shouldRead = getShouldRead();
+        assertExactMatch(shouldRead, a, b);
+        assertTrue(mExprModel.markBitsRead());
+        shouldRead = getShouldRead();
+        assertExactMatch(shouldRead, a, b, t1.getIfTrue(), t2.getIfTrue(), t1, t2);
+        assertFlags(b, abTernary.getRequirementFlagIndex(true));
+        assertFlags(a, baTernary.getRequirementFlagIndex(true));
+        assertFalse(mExprModel.markBitsRead());
+    }
+
+    @Test
     public void testInterExprDependencyNotReadyYet() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr a = lb.addVariable("a", boolean.class.getCanonicalName(), null);
         IdentifierExpr b = lb.addVariable("b", boolean.class.getCanonicalName(), null);
@@ -592,7 +689,7 @@
 
     @Test
     public void testNoFlagsForNonBindingStatic() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         lb.addVariable("a", int.class.getCanonicalName(), null);
         final MathExpr parsed = parse(lb, "a * (3 + 2)", MathExpr.class);
@@ -607,7 +704,7 @@
 
     @Test
     public void testFlagsForBindingStatic() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         lb.addVariable("a", int.class.getCanonicalName(), null);
         final Expr staticParsed = parse(lb, "3 + 2", MathExpr.class);
@@ -625,7 +722,7 @@
 
     @Test
     public void testFinalFieldOfAVariable() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         IdentifierExpr user = lb.addVariable("user", User.class.getCanonicalName(),
                 null);
@@ -641,7 +738,7 @@
 
     @Test
     public void testFinalFieldOfAField() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         lb.addVariable("user", User.class.getCanonicalName(), null);
         Expr finalFieldGet = parse(lb, "user.subObj.finalField", FieldAccessExpr.class);
@@ -660,7 +757,7 @@
 
     @Test
     public void testFinalFieldOfAMethod() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         lb.addVariable("user", User.class.getCanonicalName(), null);
         Expr finalFieldGet = parse(lb, "user.anotherSubObj.finalField", FieldAccessExpr.class);
@@ -679,7 +776,7 @@
 
     @Test
     public void testFinalOfAClass() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         mExprModel.addImport("View", "android.view.View", null);
         FieldAccessExpr fieldAccess = parse(lb, "View.VISIBLE", FieldAccessExpr.class);
@@ -690,7 +787,7 @@
 
     @Test
     public void testStaticFieldOfInstance() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         lb.addVariable("myView", "android.view.View", null);
         FieldAccessExpr fieldAccess = parse(lb, "myView.VISIBLE", FieldAccessExpr.class);
@@ -707,7 +804,7 @@
 
     @Test
     public void testOnDemandImportConflict() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         final IdentifierExpr myView = lb.addVariable("u", "android.view.View",
                 null);
@@ -722,7 +819,7 @@
 
     @Test
     public void testOnDemandImportAlreadyImported() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         final StaticIdentifierExpr ux = mExprModel.addImport("UX", User.class.getCanonicalName(),
                 null);
@@ -736,7 +833,7 @@
 
     @Test
     public void testStaticMethodOfInstance() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         lb.addVariable("user", User.class.getCanonicalName(), null);
         MethodCallExpr methodCall = parse(lb, "user.ourStaticMethod()", MethodCallExpr.class);
@@ -750,7 +847,7 @@
 
     @Test
     public void testFinalOfStaticField() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         mExprModel.addImport("UX", User.class.getCanonicalName(), null);
         FieldAccessExpr fieldAccess = parse(lb, "UX.innerStaticInstance.finalStaticField",
@@ -763,7 +860,7 @@
 
     @Test
     public void testFinalOfFinalStaticField() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         mExprModel.addImport("User", User.class.getCanonicalName(), null);
         FieldAccessExpr fieldAccess = parse(lb, "User.innerFinalStaticInstance.finalStaticField",
@@ -775,7 +872,7 @@
 
     @Test
     public void testLocationTracking() {
-        LayoutBinder lb = new MockLayoutBinder();
+        MockLayoutBinder lb = new MockLayoutBinder();
         mExprModel = lb.getModel();
         final String input = "a > 3 ? b : c";
         TernaryExpr ternaryExpr = parse(lb, input, TernaryExpr.class);
@@ -826,7 +923,7 @@
 //    TODO uncomment when we have inner static access
 //    @Test
 //    public void testFinalOfInnerStaticClass() {
-//        LayoutBinder lb = new MockLayoutBinder();
+//        MockLayoutBinder lb = new MockLayoutBinder();
 //        mExprModel = lb.getModel();
 //        mExprModel.addImport("User", User.class.getCanonicalName());
 //        FieldAccessExpr fieldAccess = parse(lb, "User.InnerStaticClass.finalStaticField", FieldAccessExpr.class);
@@ -861,7 +958,9 @@
 
     private void assertExactMatch(List<Expr> iterable, Expr... exprs) {
         int i = 0;
-        String log = Arrays.toString(iterable.toArray());
+        String listLog = Arrays.toString(iterable.toArray());
+        String itemsLog = Arrays.toString(exprs);
+        String log = "list: " + listLog + "\nitems: " + itemsLog;
         log("list", iterable);
         for (Expr expr : exprs) {
             assertTrue((i++) + ":must contain " + expr.getUniqueKey() + "\n" + log,
@@ -869,13 +968,13 @@
         }
         i = 0;
         for (Expr expr : iterable) {
-            assertTrue((i++) + ":must be expected " + expr.getUniqueKey(),
-                    ArrayUtils.contains(exprs, expr));
+            assertTrue((i++) + ":must be expected " + expr.getUniqueKey() + "\n" + log,
+                    Arrays.asList(exprs).contains(expr));
         }
     }
 
     private <T extends Expr> T parse(LayoutBinder binder, String input, Class<T> klass) {
-        final Expr parsed = binder.parse(input, null);
+        final Expr parsed = binder.parse(input, false, null);
         assertTrue(klass.isAssignableFrom(parsed.getClass()));
         return (T) parsed;
     }
@@ -904,10 +1003,10 @@
     }
 
     private List<Expr> getShouldRead() {
-        return mExprModel.filterShouldRead(mExprModel.getPendingExpressions());
+        return ExprModel.filterShouldRead(mExprModel.getPendingExpressions());
     }
 
-    public static class User extends BaseObservable {
+    public static class User implements Observable {
 
         String name;
 
@@ -941,6 +1040,23 @@
             return true;
         }
 
+        public String comment;
+
+        @Bindable
+        public boolean getUseComment() {
+            return true;
+        }
+
+        @Override
+        public void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
+
+        }
+
+        @Override
+        public void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
+
+        }
+
         public static class InnerStaticClass {
 
             public static final int finalField = 3;
diff --git a/compiler/src/test/java/android/databinding/tool/expr/ExprTest.java b/compiler/src/test/java/android/databinding/tool/expr/ExprTest.java
index 8c9c367..61d04cb 100644
--- a/compiler/src/test/java/android/databinding/tool/expr/ExprTest.java
+++ b/compiler/src/test/java/android/databinding/tool/expr/ExprTest.java
@@ -16,14 +16,15 @@
 
 package android.databinding.tool.expr;
 
-import org.junit.Before;
-import org.junit.Test;
-
 import android.databinding.tool.LayoutBinder;
 import android.databinding.tool.MockLayoutBinder;
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.reflection.java.JavaAnalyzer;
+import android.databinding.tool.writer.KCode;
+
+import org.junit.Before;
+import org.junit.Test;
 
 import java.util.BitSet;
 import java.util.List;
@@ -55,6 +56,16 @@
         }
 
         @Override
+        protected KCode generateCode(boolean full) {
+            return new KCode();
+        }
+
+        @Override
+        protected String getInvertibleError() {
+            return null;
+        }
+
+        @Override
         public boolean isDynamic() {
             return true;
         }
@@ -77,6 +88,16 @@
             protected List<Dependency> constructDependencies() {
                 return constructDynamicChildrenDependencies();
             }
+
+            @Override
+            protected KCode generateCode(boolean full) {
+                return new KCode();
+            }
+
+            @Override
+            protected String getInvertibleError() {
+                return null;
+            }
         };
         expr.getUniqueKey();
     }
diff --git a/compiler/src/test/java/android/databinding/tool/reflection/SdkVersionTest.java b/compiler/src/test/java/android/databinding/tool/reflection/SdkVersionTest.java
index 0045664..b4ecb01 100644
--- a/compiler/src/test/java/android/databinding/tool/reflection/SdkVersionTest.java
+++ b/compiler/src/test/java/android/databinding/tool/reflection/SdkVersionTest.java
@@ -56,4 +56,12 @@
         ModelMethod setElevation = view.getMethods("testCustomCode", 0)[0];
         assertEquals(1, SdkUtil.getMinApi(setElevation));
     }
+
+    @Test
+    public void testSetForeground() {
+        ModelClass view = ModelAnalyzer.getInstance()
+                .findClass("android.widget.FrameLayout", null);
+        ModelMethod setForeground = view.getMethods("setForeground", 1)[0];
+        assertEquals(1, SdkUtil.getMinApi(setForeground));
+    }
 }
diff --git a/compiler/src/test/java/android/databinding/tool/reflection/java/JavaAnalyzer.java b/compiler/src/test/java/android/databinding/tool/reflection/java/JavaAnalyzer.java
index dea092b..1b97cd9 100644
--- a/compiler/src/test/java/android/databinding/tool/reflection/java/JavaAnalyzer.java
+++ b/compiler/src/test/java/android/databinding/tool/reflection/java/JavaAnalyzer.java
@@ -13,6 +13,11 @@
 
 package android.databinding.tool.reflection.java;
 
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+
+import org.apache.commons.io.FileUtils;
+
 import android.databinding.tool.reflection.ModelAnalyzer;
 import android.databinding.tool.reflection.ModelClass;
 import android.databinding.tool.reflection.SdkUtil;
@@ -20,10 +25,12 @@
 import android.databinding.tool.util.L;
 
 import java.io.File;
+import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class JavaAnalyzer extends ModelAnalyzer {
@@ -124,13 +131,40 @@
         }
     }
 
-    public static void initForTests() {
+    private static String loadAndroidHome() {
         Map<String, String> env = System.getenv();
         for (Map.Entry<String, String> entry : env.entrySet()) {
             L.d("%s %s", entry.getKey(), entry.getValue());
         }
-        String androidHome = env.get("ANDROID_HOME");
-        if (androidHome == null) {
+        if(env.containsKey("ANDROID_HOME")) {
+            return env.get("ANDROID_HOME");
+        }
+        // check for local.properties file
+        File folder = new File(".").getAbsoluteFile();
+        while (folder != null && folder.exists()) {
+            File f = new File(folder, "local.properties");
+            if (f.exists() && f.canRead()) {
+                try {
+                    for (String line : FileUtils.readLines(f)) {
+                        List<String> keyValue = Splitter.on('=').splitToList(line);
+                        if (keyValue.size() == 2) {
+                            String key = keyValue.get(0).trim();
+                            if (key.equals("sdk.dir")) {
+                                return keyValue.get(1).trim();
+                            }
+                        }
+                    }
+                } catch (IOException ignored) {}
+            }
+            folder = folder.getParentFile();
+        }
+
+        return null;
+    }
+
+    public static void initForTests() {
+        String androidHome = loadAndroidHome();
+        if (Strings.isNullOrEmpty(androidHome) || !new File(androidHome).exists()) {
             throw new IllegalStateException(
                     "you need to have ANDROID_HOME set in your environment"
                             + " to run compiler tests");
diff --git a/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java b/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java
index cc6891e..3136e7f 100644
--- a/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java
+++ b/compiler/src/test/java/android/databinding/tool/reflection/java/JavaClass.java
@@ -125,6 +125,11 @@
     }
 
     @Override
+    public boolean isWildcard() {
+        return false;
+    }
+
+    @Override
     public boolean isInterface() {
         return mClass.isInterface();
     }
diff --git a/compiler/src/test/java/android/databinding/tool/writer/FlagSetTest.java b/compiler/src/test/java/android/databinding/tool/writer/FlagSetTest.java
index 327593a..cf322fd 100644
--- a/compiler/src/test/java/android/databinding/tool/writer/FlagSetTest.java
+++ b/compiler/src/test/java/android/databinding/tool/writer/FlagSetTest.java
@@ -57,4 +57,13 @@
         assertEquals(1 << 2, flagSet.buckets[1]);
         assertEquals(1 << 10, flagSet.buckets[2]);
     }
+
+    @Test
+    public void testLargeValue() {
+        BitSet bs = new BitSet();
+        bs.set(43);
+        FlagSet flagSet = new FlagSet(bs, 1);
+        assertEquals(1, flagSet.buckets.length);
+        assertEquals(1L << 43, flagSet.buckets[0]);
+    }
 }
diff --git a/compilerCommon/build.gradle b/compilerCommon/build.gradle
index 61477da..91ce05d 100644
--- a/compilerCommon/build.gradle
+++ b/compilerCommon/build.gradle
@@ -15,10 +15,9 @@
  */
 
 apply plugin: 'java'
-apply plugin: 'com.android.databinding.bintray'
 
-sourceCompatibility = config.javaTargetCompatibility
-targetCompatibility = config.javaSourceCompatibility
+sourceCompatibility = dataBindingConfig.javaSourceCompatibility
+targetCompatibility = dataBindingConfig.javaTargetCompatibility
 
 sourceSets {
     main {
@@ -37,11 +36,12 @@
 }
 
 dependencies {
-    testCompile group: 'junit', name: 'junit', version: '4.12'
-    compile project(':baseLibrary')
-    compile 'org.apache.commons:commons-lang3:3.3.2'
+    testCompile 'junit:junit:4.12'
+    compile project(':dataBinding:baseLibrary')
     compile 'com.tunnelvisionlabs:antlr4:4.5'
     compile 'commons-io:commons-io:2.4'
+    compile 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3'
+    compile 'com.google.guava:guava:17.0'
 }
 
 project.tasks.create(name : "generateXmlParser", type : JavaExec) {
@@ -57,3 +57,27 @@
     args "BindingExpression.g4", "-visitor", "-o", "src/main/grammar-gen/android/databinding/parser", "-package", "android.databinding.parser"
 }
 
+tasks.create(name : 'exportBuildVersions') << {
+    def props = new HashMap();
+    def buildVersionFile = new File(sourceSets.main.output.resourcesDir,"data_binding_version_info.properties")
+    // Using Java Properties appends date to the output which is bad for incremental compilation.
+    // Instead, we build it manually.
+    props.put("compilerCommon", project.version)
+    props.put("compiler", rootProject.findProject("dataBinding:compiler").version)
+    props.put("baseLibrary", rootProject.findProject("dataBinding:baseLibrary").version)
+    props.put("extensions", dataBindingConfig.extensionsVersion)
+    buildVersionFile.getParentFile().mkdirs()
+    println("writing build versions file to $buildVersionFile")
+    def propText = new StringBuilder();
+    props.each {
+        propText.append(it.key).append("=").append(it.value).append(System.getProperty("line.separator"))
+    }
+    file(buildVersionFile).write(propText.toString())
+}
+
+tasks['jar'].dependsOn('exportBuildVersions')
+tasks['exportBuildVersions'].dependsOn('processResources')
+
+project.ext.pomName = 'Data Binding Compiler Common'
+project.ext.pomDesc = 'Common library that can be shared between different build tools'
+enablePublishing(this, true)
diff --git a/compilerCommon/compilerCommon.iml b/compilerCommon/compilerCommon.iml
new file mode 100644
index 0000000..d9cc2c6
--- /dev/null
+++ b/compilerCommon/compilerCommon.iml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":dataBinding:compilerCommon" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="com.android.databinding" external.system.module.version="1.1" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build/classes/main" />
+    <output-test url="file://$MODULE_DIR$/build/classes/test" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/grammar-gen" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/xml-gen" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="baseLibrary" />
+    <orderEntry type="library" name="Gradle: com.tunnelvisionlabs:antlr4:4.5" level="project" />
+    <orderEntry type="library" name="Gradle: commons-io:commons-io:2.4" level="project" />
+    <orderEntry type="library" name="Gradle: com.googlecode.juniversalchardet:juniversalchardet:1.0.3" level="project" />
+    <orderEntry type="library" name="Gradle: com.tunnelvisionlabs:antlr4-runtime:4.5" level="project" />
+    <orderEntry type="library" name="Gradle: com.tunnelvisionlabs:antlr4-annotations:4.5" level="project" />
+    <orderEntry type="library" name="Gradle: org.antlr:antlr-runtime:3.5.2" level="project" />
+    <orderEntry type="library" name="Gradle: org.antlr:ST4:4.0.8" level="project" />
+    <orderEntry type="library" name="Gradle: org.abego.treelayout:org.abego.treelayout.core:1.0.1" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.guava:guava:17.0" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/compilerCommon/db-compilerCommon-base.iml b/compilerCommon/db-compilerCommon-base.iml
new file mode 100644
index 0000000..38f8122
--- /dev/null
+++ b/compilerCommon/db-compilerCommon-base.iml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/xml-gen" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/grammar-gen" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../out/build/dataBinding/compilerCommon/build" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="db-baseLibrary" exported="" />
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/com/tunnelvisionlabs/antlr4/4.5/antlr4-4.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/commons-io/commons-io/2.4/commons-io-2.4.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/commons-io/commons-io/2.4/commons-io-2.4-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/com/googlecode/juniversalchardet/juniversalchardet/1.0.3/juniversalchardet-1.0.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/com/tunnelvisionlabs/antlr4-runtime/4.5/antlr4-runtime-4.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/com/tunnelvisionlabs/antlr4-annotations/4.5/antlr4-annotations-4.5.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/antlr/antlr-runtime/3.5.2/antlr-runtime-3.5.2.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/antlr/ST4/4.0.8/ST4-4.0.8.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" exported="">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/abego/treelayout/org.abego.treelayout.core/1.0.1/org.abego.treelayout.core-1.0.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="library" exported="" name="guava-tools" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/compilerCommon/db-compilerCommon.iml b/compilerCommon/db-compilerCommon.iml
new file mode 100644
index 0000000..3b18b8a
--- /dev/null
+++ b/compilerCommon/db-compilerCommon.iml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/xml-gen" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/grammar-gen" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/../../../out/build/dataBinding/compilerCommon/build" />
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="db-baseLibrary" />
+    <orderEntry type="library" exported="" name="Guava" level="project" />
+    <orderEntry type="library" exported="" name="commons-io-2.4" level="project" />
+    <orderEntry type="module-library" exported="">
+      <library name="juniversalchardet-1.0.3">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../adt/idea/android/lib/juniversalchardet-1.0.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="library" exported="" name="antlr4-runtime-4.5" level="project" />
+    <orderEntry type="library" exported="" name="antlr4-annotations-4.5" level="project" />
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/junit/junit/4.12/junit-4.12-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library" scope="TEST">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+  </component>
+</module>
\ No newline at end of file
diff --git a/compilerCommon/src/main/java/android/databinding/tool/DataBindingBuilder.java b/compilerCommon/src/main/java/android/databinding/tool/DataBindingBuilder.java
new file mode 100644
index 0000000..0e5d757
--- /dev/null
+++ b/compilerCommon/src/main/java/android/databinding/tool/DataBindingBuilder.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool;
+
+import org.apache.commons.io.IOUtils;
+
+import android.databinding.tool.processing.Scope;
+import android.databinding.tool.processing.ScopedException;
+import android.databinding.tool.util.L;
+import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.writer.JavaFileWriter;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * This class is used by Android Gradle plugin.
+ */
+@SuppressWarnings("unused")
+public class DataBindingBuilder {
+    Versions mVersions;
+    private final static String EXCLUDE_PATTERN = "android/databinding/layouts/*.*";
+    public String getCompilerVersion() {
+        return getVersions().compiler;
+    }
+
+    public String getBaseLibraryVersion(String compilerVersion) {
+        return getVersions().baseLibrary;
+    }
+
+    public String getLibraryVersion(String compilerVersion) {
+        return getVersions().extensions;
+    }
+
+    public String getBaseAdaptersVersion(String compilerVersion) {
+        return getVersions().extensions;
+    }
+
+    public void setPrintMachineReadableOutput(boolean machineReadableOutput) {
+        ScopedException.encodeOutput(machineReadableOutput);
+    }
+
+    public boolean getPrintMachineReadableOutput() {
+        return ScopedException.issEncodeOutput();
+    }
+
+    public void setDebugLogEnabled(boolean enableDebugLogs) {
+        L.setDebugLog(enableDebugLogs);
+    }
+
+    public boolean isDebugLogEnabled() {
+        return L.isDebugEnabled();
+    }
+
+    private Versions getVersions() {
+        if (mVersions != null) {
+            return mVersions;
+        }
+        try {
+            Properties props = new Properties();
+            InputStream stream = getClass().getResourceAsStream("/data_binding_version_info.properties");
+            try {
+                props.load(stream);
+                mVersions = new Versions(props);
+            } finally {
+                IOUtils.closeQuietly(stream);
+            }
+        } catch (IOException exception) {
+            L.e(exception, "Cannot read data binding version");
+        }
+        return mVersions;
+    }
+
+    /**
+     * Returns the list of classes that should be excluded from package task
+     *
+     * @param layoutXmlProcessor The LayoutXmlProcessor for this variant
+     * @param generatedClassListFile The location of the File into which data binding compiler wrote
+     *                               list of generated classes
+     *
+     * @return The list of classes to exclude. They are already in JNI format.
+     */
+    public List<String> getJarExcludeList(LayoutXmlProcessor layoutXmlProcessor,
+            File generatedClassListFile) {
+        List<String> excludes = new ArrayList<String>();
+        String appPkgAsClass = layoutXmlProcessor.getPackage().replace('.', '/');
+        String infoClassAsClass = layoutXmlProcessor.getInfoClassFullName().replace('.', '/');
+
+        excludes.add(infoClassAsClass + ".class");
+        excludes.add(EXCLUDE_PATTERN);
+        excludes.add(appPkgAsClass + "/BR.*");
+        excludes.add("android/databinding/DynamicUtil.class");
+        if (generatedClassListFile != null) {
+            List<String> generatedClasses = readGeneratedClasses(generatedClassListFile);
+            for (String klass : generatedClasses) {
+                excludes.add(klass.replace('.', '/') + ".class");
+            }
+        }
+        Scope.assertNoError();
+        return excludes;
+    }
+
+    private List<String> readGeneratedClasses(File generatedClassListFile) {
+        Preconditions.checkNotNull(generatedClassListFile, "Data binding exclude generated task"
+                + " is not configured properly");
+        Preconditions.check(generatedClassListFile.exists(),
+                "Generated class list does not exist %s", generatedClassListFile.getAbsolutePath());
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream(generatedClassListFile);
+            return IOUtils.readLines(fis);
+        } catch (FileNotFoundException e) {
+            L.e(e, "Unable to read generated class list from %s",
+                    generatedClassListFile.getAbsoluteFile());
+        } catch (IOException e) {
+            L.e(e, "Unexpected exception while reading %s",
+                    generatedClassListFile.getAbsoluteFile());
+        } finally {
+            IOUtils.closeQuietly(fis);
+        }
+        L.e("Could not read data binding generated class list");
+        return null;
+    }
+
+    public JavaFileWriter createJavaFileWriter(File outFolder) {
+        return new GradleFileWriter(outFolder.getAbsolutePath());
+    }
+
+    static class GradleFileWriter extends JavaFileWriter {
+
+        private final String outputBase;
+
+        public GradleFileWriter(String outputBase) {
+            this.outputBase = outputBase;
+        }
+
+        @Override
+        public void writeToFile(String canonicalName, String contents) {
+            String asPath = canonicalName.replace('.', '/');
+            File f = new File(outputBase + "/" + asPath + ".java");
+            //noinspection ResultOfMethodCallIgnored
+            f.getParentFile().mkdirs();
+            FileOutputStream fos = null;
+            try {
+                fos = new FileOutputStream(f);
+                IOUtils.write(contents, fos);
+            } catch (IOException e) {
+                L.e(e, "cannot write file " + f.getAbsolutePath());
+            } finally {
+                IOUtils.closeQuietly(fos);
+            }
+        }
+    }
+
+    private static class Versions {
+        final String compilerCommon;
+        final String compiler;
+        final String baseLibrary;
+        final String extensions;
+
+        public Versions(Properties properties) {
+            compilerCommon = properties.getProperty("compilerCommon");
+            compiler = properties.getProperty("compiler");
+            baseLibrary = properties.getProperty("baseLibrary");
+            extensions = properties.getProperty("extensions");
+            Preconditions.checkNotNull(compilerCommon, "cannot read compiler common version");
+            Preconditions.checkNotNull(compiler, "cannot read compiler version");
+            Preconditions.checkNotNull(baseLibrary, "cannot read baseLibrary version");
+            Preconditions.checkNotNull(extensions, "cannot read extensions version");
+        }
+    }
+}
\ No newline at end of file
diff --git a/compilerCommon/src/main/java/android/databinding/tool/LayoutXmlProcessor.java b/compilerCommon/src/main/java/android/databinding/tool/LayoutXmlProcessor.java
index 046bddb..41436f0 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/LayoutXmlProcessor.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/LayoutXmlProcessor.java
@@ -13,25 +13,28 @@
 
 package android.databinding.tool;
 
-import org.apache.commons.lang3.StringEscapeUtils;
+import com.google.common.escape.Escaper;
+
+import org.apache.commons.io.FileUtils;
 import org.xml.sax.SAXException;
 
 import android.databinding.BindingBuildInfo;
 import android.databinding.tool.store.LayoutFileParser;
 import android.databinding.tool.store.ResourceBundle;
+import android.databinding.tool.util.L;
+import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.util.SourceCodeEscapers;
 import android.databinding.tool.writer.JavaFileWriter;
 
 import java.io.File;
 import java.io.FilenameFilter;
 import java.io.IOException;
-import java.io.StringWriter;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
-import javax.xml.bind.Marshaller;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.xpath.XPathExpressionException;
 
@@ -52,36 +55,82 @@
     private boolean mWritten;
     private final boolean mIsLibrary;
     private final String mBuildId = UUID.randomUUID().toString();
-    // can be a list of xml files or folders that contain XML files
-    private final List<File> mResources;
+    private final OriginalFileLookup mOriginalFileLookup;
 
-    public LayoutXmlProcessor(String applicationPackage, List<File> resources,
-            JavaFileWriter fileWriter, int minSdk, boolean isLibrary) {
+    public LayoutXmlProcessor(String applicationPackage,
+            JavaFileWriter fileWriter, int minSdk, boolean isLibrary,
+            OriginalFileLookup originalFileLookup) {
         mFileWriter = fileWriter;
         mResourceBundle = new ResourceBundle(applicationPackage);
-        mResources = resources;
         mMinSdk = minSdk;
         mIsLibrary = isLibrary;
+        mOriginalFileLookup = originalFileLookup;
     }
 
-    public static List<File> getLayoutFiles(List<File> resources) {
-        List<File> result = new ArrayList<File>();
-        for (File resource : resources) {
-            if (!resource.exists() || !resource.canRead()) {
-                continue;
-            }
-            if (resource.isDirectory()) {
-                for (File layoutFolder : resource.listFiles(layoutFolderFilter)) {
-                    for (File xmlFile : layoutFolder.listFiles(xmlFileFilter)) {
-                        result.add(xmlFile);
-                    }
+    private static void processIncrementalInputFiles(ResourceInput input,
+            ProcessFileCallback callback)
+            throws IOException, ParserConfigurationException, XPathExpressionException,
+            SAXException {
+        processExistingIncrementalFiles(input.getRootInputFolder(), input.getAdded(), callback);
+        processExistingIncrementalFiles(input.getRootInputFolder(), input.getChanged(), callback);
+        processRemovedIncrementalFiles(input.getRootInputFolder(), input.getRemoved(), callback);
+    }
 
-                }
-            } else if (xmlFileFilter.accept(resource.getParentFile(), resource.getName())) {
-                result.add(resource);
+    private static void processExistingIncrementalFiles(File inputRoot, List<File> files,
+            ProcessFileCallback callback)
+            throws IOException, XPathExpressionException, SAXException,
+            ParserConfigurationException {
+        for (File file : files) {
+            File parent = file.getParentFile();
+            if (inputRoot.equals(parent)) {
+                callback.processOtherRootFile(file);
+            } else if (layoutFolderFilter.accept(parent, parent.getName())) {
+                callback.processLayoutFile(file);
+            } else {
+                callback.processOtherFile(parent, file);
             }
         }
-        return result;
+    }
+
+    private static void processRemovedIncrementalFiles(File inputRoot, List<File> files,
+            ProcessFileCallback callback)
+            throws IOException {
+        for (File file : files) {
+            File parent = file.getParentFile();
+            if (inputRoot.equals(parent)) {
+                callback.processRemovedOtherRootFile(file);
+            } else if (layoutFolderFilter.accept(parent, parent.getName())) {
+                callback.processRemovedLayoutFile(file);
+            } else {
+                callback.processRemovedOtherFile(parent, file);
+            }
+        }
+    }
+
+    private static void processAllInputFiles(ResourceInput input, ProcessFileCallback callback)
+            throws IOException, XPathExpressionException, SAXException,
+            ParserConfigurationException {
+        FileUtils.deleteDirectory(input.getRootOutputFolder());
+        Preconditions.check(input.getRootOutputFolder().mkdirs(), "out dir should be re-created");
+        Preconditions.check(input.getRootInputFolder().isDirectory(), "it must be a directory");
+        for (File firstLevel : input.getRootInputFolder().listFiles()) {
+            if (firstLevel.isDirectory()) {
+                if (layoutFolderFilter.accept(firstLevel, firstLevel.getName())) {
+                    callback.processLayoutFolder(firstLevel);
+                    for (File xmlFile : firstLevel.listFiles(xmlFileFilter)) {
+                        callback.processLayoutFile(xmlFile);
+                    }
+                } else {
+                    callback.processOtherFolder(firstLevel);
+                    for (File file : firstLevel.listFiles()) {
+                        callback.processOtherFile(firstLevel, file);
+                    }
+                }
+            } else {
+                callback.processOtherRootFile(firstLevel);
+            }
+
+        }
     }
 
     /**
@@ -91,74 +140,142 @@
         return mResourceBundle;
     }
 
-    public boolean processResources(int minSdk)
+    public boolean processResources(final ResourceInput input)
             throws ParserConfigurationException, SAXException, XPathExpressionException,
             IOException {
         if (mProcessingComplete) {
             return false;
         }
-        LayoutFileParser layoutFileParser = new LayoutFileParser();
-        for (File xmlFile : getLayoutFiles(mResources)) {
-            final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser
-                    .parseXml(xmlFile, mResourceBundle.getAppPackage(), minSdk);
-            if (bindingLayout != null && !bindingLayout.isEmpty()) {
-                mResourceBundle.addLayoutBundle(bindingLayout);
+        final LayoutFileParser layoutFileParser = new LayoutFileParser();
+        final URI inputRootUri = input.getRootInputFolder().toURI();
+        ProcessFileCallback callback = new ProcessFileCallback() {
+            private File convertToOutFile(File file) {
+                final String subPath = toSystemDependentPath(inputRootUri
+                        .relativize(file.toURI()).getPath());
+                return new File(input.getRootOutputFolder(), subPath);
             }
+            @Override
+            public void processLayoutFile(File file)
+                    throws ParserConfigurationException, SAXException, XPathExpressionException,
+                    IOException {
+                final File output = convertToOutFile(file);
+                final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser
+                        .parseXml(file, output, mResourceBundle.getAppPackage(), mOriginalFileLookup);
+                if (bindingLayout != null && !bindingLayout.isEmpty()) {
+                    mResourceBundle.addLayoutBundle(bindingLayout);
+                }
+            }
+
+            @Override
+            public void processOtherFile(File parentFolder, File file) throws IOException {
+                final File outParent = convertToOutFile(parentFolder);
+                FileUtils.copyFile(file, new File(outParent, file.getName()));
+            }
+
+            @Override
+            public void processRemovedLayoutFile(File file) {
+                mResourceBundle.addRemovedFile(file);
+                final File out = convertToOutFile(file);
+                FileUtils.deleteQuietly(out);
+            }
+
+            @Override
+            public void processRemovedOtherFile(File parentFolder, File file) throws IOException {
+                final File outParent = convertToOutFile(parentFolder);
+                FileUtils.deleteQuietly(new File(outParent, file.getName()));
+            }
+
+            @Override
+            public void processOtherFolder(File folder) {
+                //noinspection ResultOfMethodCallIgnored
+                convertToOutFile(folder).mkdirs();
+            }
+
+            @Override
+            public void processLayoutFolder(File folder) {
+                //noinspection ResultOfMethodCallIgnored
+                convertToOutFile(folder).mkdirs();
+            }
+
+            @Override
+            public void processOtherRootFile(File file) throws IOException {
+                final File outFile = convertToOutFile(file);
+                if (file.isDirectory()) {
+                    FileUtils.copyDirectory(file, outFile);
+                } else {
+                    FileUtils.copyFile(file, outFile);
+                }
+            }
+
+            @Override
+            public void processRemovedOtherRootFile(File file) throws IOException {
+                final File outFile = convertToOutFile(file);
+                FileUtils.deleteQuietly(outFile);
+            }
+        };
+        if (input.isIncremental()) {
+            processIncrementalInputFiles(input, callback);
+        } else {
+            processAllInputFiles(input, callback);
         }
         mProcessingComplete = true;
         return true;
     }
 
+    public static String toSystemDependentPath(String path) {
+        if (File.separatorChar != '/') {
+            path = path.replace('/', File.separatorChar);
+        }
+        return path;
+    }
+
     public void writeLayoutInfoFiles(File xmlOutDir) throws JAXBException {
         if (mWritten) {
             return;
         }
-        JAXBContext context = JAXBContext.newInstance(ResourceBundle.LayoutFileBundle.class);
-        Marshaller marshaller = context.createMarshaller();
-
         for (List<ResourceBundle.LayoutFileBundle> layouts : mResourceBundle.getLayoutBundles()
                 .values()) {
             for (ResourceBundle.LayoutFileBundle layout : layouts) {
-                writeXmlFile(xmlOutDir, layout, marshaller);
+                writeXmlFile(xmlOutDir, layout);
             }
         }
+        for (File file : mResourceBundle.getRemovedFiles()) {
+            String exportFileName = generateExportFileName(file);
+            FileUtils.deleteQuietly(new File(xmlOutDir, exportFileName));
+        }
         mWritten = true;
     }
 
-    private void writeXmlFile(File xmlOutDir, ResourceBundle.LayoutFileBundle layout,
-            Marshaller marshaller) throws JAXBException {
-        String filename = generateExportFileName(layout) + ".xml";
-        String xml = toXML(layout, marshaller);
-        mFileWriter.writeToFile(new File(xmlOutDir, filename), xml);
+    private void writeXmlFile(File xmlOutDir, ResourceBundle.LayoutFileBundle layout)
+            throws JAXBException {
+        String filename = generateExportFileName(layout);
+        mFileWriter.writeToFile(new File(xmlOutDir, filename), layout.toXML());
     }
 
     public String getInfoClassFullName() {
         return RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME;
     }
 
-    private String toXML(ResourceBundle.LayoutFileBundle layout, Marshaller marshaller)
-            throws JAXBException {
-        StringWriter writer = new StringWriter();
-        marshaller.marshal(layout, writer);
-        return writer.getBuffer().toString();
-    }
-
     /**
      * Generates a string identifier that can uniquely identify the given layout bundle.
      * This identifier can be used when we need to export data about this layout bundle.
      */
-    public String generateExportFileName(ResourceBundle.LayoutFileBundle layout) {
-        StringBuilder name = new StringBuilder(layout.getFileName());
-        name.append('-').append(layout.getDirectory());
-        for (int i = name.length() - 1; i >= 0; i--) {
-            char c = name.charAt(i);
-            if (c == '-') {
-                name.deleteCharAt(i);
-                c = Character.toUpperCase(name.charAt(i));
-                name.setCharAt(i, c);
-            }
-        }
-        return name.toString();
+    private static String generateExportFileName(ResourceBundle.LayoutFileBundle layout) {
+        return generateExportFileName(layout.getFileName(), layout.getDirectory());
+    }
+
+    private static String generateExportFileName(File file) {
+        final String fileName = file.getName();
+        return generateExportFileName(fileName.substring(0, fileName.lastIndexOf('.')),
+                file.getParentFile().getName());
+    }
+
+    public static String generateExportFileName(String fileName, String dirName) {
+        return fileName + '-' + dirName + ".xml";
+    }
+
+    public static String exportLayoutNameFromInfoFileName(String infoFileName) {
+        return infoFileName.substring(0, infoFileName.indexOf('-'));
     }
 
     public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir,
@@ -166,13 +283,18 @@
         writeInfoClass(sdkDir, xmlOutDir, exportClassListTo, false, false);
     }
 
+    public String getPackage() {
+        return mResourceBundle.getAppPackage();
+    }
+
     public void writeInfoClass(/*Nullable*/ File sdkDir, File xmlOutDir, File exportClassListTo,
             boolean enableDebugLogs, boolean printEncodedErrorLogs) {
-        final String sdkPath = sdkDir == null ? null : StringEscapeUtils.escapeJava(sdkDir.getAbsolutePath());
+        Escaper javaEscaper = SourceCodeEscapers.javaCharEscaper();
+        final String sdkPath = sdkDir == null ? null : javaEscaper.escape(sdkDir.getAbsolutePath());
         final Class annotation = BindingBuildInfo.class;
-        final String layoutInfoPath = StringEscapeUtils.escapeJava(xmlOutDir.getAbsolutePath());
+        final String layoutInfoPath = javaEscaper.escape(xmlOutDir.getAbsolutePath());
         final String exportClassListToPath = exportClassListTo == null ? "" :
-                StringEscapeUtils.escapeJava(exportClassListTo.getAbsolutePath());
+                javaEscaper.escape(exportClassListTo.getAbsolutePath());
         String classString = "package " + RESOURCE_BUNDLE_PACKAGE + ";\n\n" +
                 "import " + annotation.getCanonicalName() + ";\n\n" +
                 "@" + annotation.getSimpleName() + "(buildId=\"" + mBuildId + "\", " +
@@ -201,4 +323,111 @@
             return name.toLowerCase().endsWith(".xml");
         }
     };
+
+    /**
+     * Helper interface that can find the original copy of a resource XML.
+     */
+    public interface OriginalFileLookup {
+
+        /**
+         * @param file The intermediate build file
+         * @return The original file or null if original File cannot be found.
+         */
+        File getOriginalFileFor(File file);
+    }
+
+    /**
+     * API agnostic class to get resource changes incrementally.
+     */
+    public static class ResourceInput {
+        private final boolean mIncremental;
+        private final File mRootInputFolder;
+        private final File mRootOutputFolder;
+
+        private List<File> mAdded = new ArrayList<File>();
+        private List<File> mRemoved = new ArrayList<File>();
+        private List<File> mChanged = new ArrayList<File>();
+
+        public ResourceInput(boolean incremental, File rootInputFolder, File rootOutputFolder) {
+            mIncremental = incremental;
+            mRootInputFolder = rootInputFolder;
+            mRootOutputFolder = rootOutputFolder;
+        }
+
+        public void added(File file) {
+            mAdded.add(file);
+        }
+        public void removed(File file) {
+            mRemoved.add(file);
+        }
+        public void changed(File file) {
+            mChanged.add(file);
+        }
+
+        public boolean shouldCopy() {
+            return !mRootInputFolder.equals(mRootOutputFolder);
+        }
+
+        List<File> getAdded() {
+            return mAdded;
+        }
+
+        List<File> getRemoved() {
+            return mRemoved;
+        }
+
+        List<File> getChanged() {
+            return mChanged;
+        }
+
+        File getRootInputFolder() {
+            return mRootInputFolder;
+        }
+
+        File getRootOutputFolder() {
+            return mRootOutputFolder;
+        }
+
+        public boolean isIncremental() {
+            return mIncremental;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder out = new StringBuilder();
+            out.append("ResourceInput{")
+                    .append("mIncremental=").append(mIncremental)
+                    .append(", mRootInputFolder=").append(mRootInputFolder)
+                    .append(", mRootOutputFolder=").append(mRootOutputFolder);
+            logFiles(out, "added", mAdded);
+            logFiles(out, "removed", mRemoved);
+            logFiles(out, "changed", mChanged);
+            return out.toString();
+
+        }
+
+        private static void logFiles(StringBuilder out, String name, List<File> files) {
+            out.append("\n  ").append(name);
+            for (File file : files) {
+                out.append("\n   - ").append(file.getAbsolutePath());
+            }
+        }
+    }
+
+    private interface ProcessFileCallback {
+        void processLayoutFile(File file)
+                throws ParserConfigurationException, SAXException, XPathExpressionException,
+                IOException;
+        void processOtherFile(File parentFolder, File file) throws IOException;
+        void processRemovedLayoutFile(File file);
+        void processRemovedOtherFile(File parentFolder, File file) throws IOException;
+
+        void processOtherFolder(File folder);
+
+        void processLayoutFolder(File folder);
+
+        void processOtherRootFile(File file) throws IOException;
+
+        void processRemovedOtherRootFile(File file) throws IOException;
+    }
 }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java b/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java
index a4ed1cb..a2ec898 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/processing/ErrorMessages.java
@@ -36,4 +36,14 @@
                     + " configurations";
     public static final String MULTI_CONFIG_ID_USED_AS_IMPORT =
             "Cannot use the same id (%s) for a View and an include tag.";
+    public static final String ROOT_TAG_NOT_SUPPORTED = "android:tag is not supported on root " +
+            "elements of data bound layouts unless targeting API version 14 or greater. Value " +
+            "is '%s'";
+    public static final String SYNTAX_ERROR = "Syntax error: %s";
+    public static final String CANNOT_FIND_GETTER_CALL =
+            "Cannot find the getter for attribute '%s' with value type %s on %s.";
+    public static final String EXPRESSION_NOT_INVERTIBLE =
+            "The expression %s cannot cannot be inverted: %s";
+    public static final String TWO_WAY_EVENT_ATTRIBUTE =
+            "The attribute %s is a two-way binding event attribute and cannot be assigned.";
 }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/processing/Scope.java b/compilerCommon/src/main/java/android/databinding/tool/processing/Scope.java
index c723c80..9e0a692 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/processing/Scope.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/processing/Scope.java
@@ -34,7 +34,7 @@
 public class Scope {
 
     private static ThreadLocal<ScopeEntry> sScopeItems = new ThreadLocal<ScopeEntry>();
-    static List<ScopedException> sDeferredExceptions = new ArrayList<>();
+    static List<ScopedException> sDeferredExceptions = new ArrayList<ScopedException>();
 
     public static void enter(final Location location) {
         enter(new LocationScopeProvider() {
@@ -165,7 +165,7 @@
             return Arrays.asList(locations.get(0).toAbsoluteLocation());
         }
         // We have more than 1 location. Depending on the scope, we may or may not want all of them
-        List<Location> chosen = new ArrayList<>();
+        List<Location> chosen = new ArrayList<Location>();
         for (Location location : locations) {
             Location absLocation = location.toAbsoluteLocation();
             if (validatedContained(entry.mParent, absLocation)) {
diff --git a/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedErrorReport.java b/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedErrorReport.java
index dfd2039..b645b37 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedErrorReport.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedErrorReport.java
@@ -16,9 +16,8 @@
 
 package android.databinding.tool.processing;
 
-import org.apache.commons.lang3.StringUtils;
-
 import android.databinding.tool.store.Location;
+import android.databinding.tool.util.StringUtils;
 
 import java.util.List;
 
diff --git a/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java b/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java
index 238a895..0f98072 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/processing/ScopedException.java
@@ -16,10 +16,14 @@
 
 package android.databinding.tool.processing;
 
-import org.apache.commons.lang3.StringUtils;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
 
 import android.databinding.tool.store.Location;
 import android.databinding.tool.util.L;
+import android.databinding.tool.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -40,7 +44,8 @@
     private String mScopeLog;
 
     public ScopedException(String message, Object... args) {
-        super(message == null ? "unknown data binding exception" : String.format(message, args));
+        super(message == null ? "unknown data binding exception" :
+                args.length == 0 ? message : String.format(message, args));
         mScopedErrorReport = Scope.createReport();
         mScopeLog = L.isDebugEnabled() ? Scope.produceScopeLog() : null;
     }
@@ -84,7 +89,7 @@
             }
         }
         sb.append(ERROR_LOG_SUFFIX);
-        return StringUtils.join(StringUtils.split(sb.toString(), System.lineSeparator()), " ");
+        return Joiner.on(' ').join(Splitter.on(StringUtils.LINE_SEPARATOR).split(sb));
     }
 
     public ScopedErrorReport getScopedErrorReport() {
@@ -98,7 +103,7 @@
     public static ScopedException createFromOutput(String output) {
         String message = "";
         String file = "";
-        List<Location> locations = new ArrayList<>();
+        List<Location> locations = new ArrayList<Location>();
         int msgStart = output.indexOf(MSG_KEY);
         if (msgStart < 0) {
             message = output;
@@ -133,11 +138,11 @@
             }
         }
         return new ScopedException(message.trim(),
-                new ScopedErrorReport(StringUtils.isEmpty(file) ? null : file.trim(), locations));
+                new ScopedErrorReport(Strings.isNullOrEmpty(file) ? null : file.trim(), locations));
     }
 
     public static List<ScopedException> extractErrors(String output) {
-        List<ScopedException> errors = new ArrayList<>();
+        List<ScopedException> errors = new ArrayList<ScopedException>();
         int index = output.indexOf(ERROR_LOG_PREFIX);
         final int limit = output.length();
         while (index >= 0 && index < limit) {
@@ -157,4 +162,8 @@
     public static void encodeOutput(boolean encodeOutput) {
         sEncodeOutput = encodeOutput;
     }
+
+    public static boolean issEncodeOutput() {
+        return sEncodeOutput;
+    }
 }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/processing/scopes/LocationScopeProvider.java b/compilerCommon/src/main/java/android/databinding/tool/processing/scopes/LocationScopeProvider.java
index ee7f8a9..4272cfd 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/processing/scopes/LocationScopeProvider.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/processing/scopes/LocationScopeProvider.java
@@ -25,5 +25,5 @@
  * An item that is tight to locations in a source file.
  */
 public interface LocationScopeProvider extends ScopeProvider {
-    public List<Location> provideScopeLocation();
+    List<Location> provideScopeLocation();
 }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/store/LayoutFileParser.java b/compilerCommon/src/main/java/android/databinding/tool/store/LayoutFileParser.java
index 91be28f..4b20131 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/store/LayoutFileParser.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/store/LayoutFileParser.java
@@ -13,35 +13,36 @@
 
 package android.databinding.tool.store;
 
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.misc.NotNull;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
 import android.databinding.parser.XMLLexer;
 import android.databinding.parser.XMLParser;
 import android.databinding.parser.XMLParserBaseVisitor;
+import android.databinding.tool.LayoutXmlProcessor;
 import android.databinding.tool.processing.ErrorMessages;
 import android.databinding.tool.processing.Scope;
 import android.databinding.tool.processing.scopes.FileScopeProvider;
 import android.databinding.tool.util.L;
 import android.databinding.tool.util.ParserHelper;
 import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.util.StringUtils;
 import android.databinding.tool.util.XmlEditor;
 
+import com.google.common.base.Strings;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.misc.NotNull;
+import org.apache.commons.io.FileUtils;
+import org.mozilla.universalchardet.UniversalDetector;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
 import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URISyntaxException;
-import java.net.URL;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -67,31 +68,29 @@
 
     private static final String LAYOUT_PREFIX = "@layout/";
 
-    public ResourceBundle.LayoutFileBundle parseXml(final File xml, String pkg, int minSdk)
+    public ResourceBundle.LayoutFileBundle parseXml(final File inputFile, final File outputFile,
+            String pkg, final LayoutXmlProcessor.OriginalFileLookup originalFileLookup)
             throws ParserConfigurationException, IOException, SAXException,
             XPathExpressionException {
+        File originalFileFor = originalFileLookup.getOriginalFileFor(inputFile);
+        final String originalFilePath = originalFileFor.getAbsolutePath();
         try {
             Scope.enter(new FileScopeProvider() {
                 @Override
                 public String provideScopeFilePath() {
-                    return xml.getAbsolutePath();
+                    return originalFilePath;
                 }
             });
-            final String xmlNoExtension = ParserHelper.stripExtension(xml.getName());
-            final String newTag = xml.getParentFile().getName() + '/' + xmlNoExtension;
-            File original = stripFileAndGetOriginal(xml, newTag);
-            if (original == null) {
-                L.d("assuming the file is the original for %s", xml.getAbsoluteFile());
-                original = xml;
-            }
-            return parseXml(original, pkg);
+            final String encoding = findEncoding(inputFile);
+            stripFile(inputFile, outputFile, encoding, originalFileLookup);
+            return parseOriginalXml(originalFileFor, pkg, encoding);
         } finally {
             Scope.exit();
         }
     }
 
-    private ResourceBundle.LayoutFileBundle parseXml(final File original, String pkg)
-            throws IOException {
+    private ResourceBundle.LayoutFileBundle parseOriginalXml(final File original, String pkg,
+            String encoding) throws IOException {
         try {
             Scope.enter(new FileScopeProvider() {
                 @Override
@@ -100,7 +99,9 @@
                 }
             });
             final String xmlNoExtension = ParserHelper.stripExtension(original.getName());
-            ANTLRInputStream inputStream = new ANTLRInputStream(new FileReader(original));
+            FileInputStream fin = new FileInputStream(original);
+            InputStreamReader reader = new InputStreamReader(fin, encoding);
+            ANTLRInputStream inputStream = new ANTLRInputStream(reader);
             XMLLexer lexer = new XMLLexer(inputStream);
             CommonTokenStream tokenStream = new CommonTokenStream(lexer);
             XMLParser parser = new XMLParser(tokenStream);
@@ -129,10 +130,22 @@
         }
     }
 
+    private static boolean isProcessedElement(String name) {
+        if (Strings.isNullOrEmpty(name)) {
+            return false;
+        }
+        if ("view".equals(name) || "include".equals(name) || name.indexOf('.') >= 0) {
+            return true;
+        }
+        return !name.toLowerCase().equals(name);
+    }
+
     private void parseExpressions(String newTag, final XMLParser.ElementContext rootView,
             final boolean isMerge, ResourceBundle.LayoutFileBundle bundle) {
-        final List<XMLParser.ElementContext> bindingElements = new ArrayList<>();
-        final List<XMLParser.ElementContext> otherElementsWithIds = new ArrayList<>();
+        final List<XMLParser.ElementContext> bindingElements
+                = new ArrayList<XMLParser.ElementContext>();
+        final List<XMLParser.ElementContext> otherElementsWithIds
+                = new ArrayList<XMLParser.ElementContext>();
         rootView.accept(new XMLParserBaseVisitor<Void>() {
             @Override
             public Void visitElement(@NotNull XMLParser.ElementContext ctx) {
@@ -140,7 +153,7 @@
                     bindingElements.add(ctx);
                 } else {
                     String name = ctx.elmName.getText();
-                    if (!"include".equals(name) && !"fragment".equals(name) &&
+                    if (isProcessedElement(name) &&
                             attributeMap(ctx).containsKey("android:id")) {
                         otherElementsWithIds.add(ctx);
                     }
@@ -158,13 +171,8 @@
                 } else if (ctx == rootView) {
                     return true;
                 }
-                if (hasIncludeChild(ctx)) {
-                    return true;
-                }
-                if (XmlEditor.hasExpressionAttributes(ctx)) {
-                    return true;
-                }
-                return false;
+                return hasIncludeChild(ctx) || XmlEditor.hasExpressionAttributes(ctx) ||
+                        "include".equals(ctx.elmName.getText());
             }
 
             private boolean hasIncludeChild(XMLParser.ElementContext ctx) {
@@ -192,7 +200,7 @@
             if ("include".equals(nodeName)) {
                 // get the layout attribute
                 final String includeValue = attributes.get("layout");
-                if (StringUtils.isEmpty(includeValue)) {
+                if (Strings.isNullOrEmpty(includeValue)) {
                     L.e("%s must include a layout", parent);
                 }
                 if (!includeValue.startsWith(LAYOUT_PREFIX)) {
@@ -201,8 +209,7 @@
                 }
                 // if user is binding something there, there MUST be a layout file to be
                 // generated.
-                String layoutName = includeValue.substring(LAYOUT_PREFIX.length());
-                includedLayoutName = layoutName;
+                includedLayoutName = includeValue.substring(LAYOUT_PREFIX.length());
                 final ParserRuleContext myParentContent = parent.getParent();
                 Preconditions.check(myParentContent instanceof XMLParser.ContentContext,
                         "parent of an include tag must be a content context but it is %s",
@@ -214,7 +221,9 @@
                 //noinspection SuspiciousMethodCalls
                 tag = nodeTagMap.get(grandParent);
             } else if ("fragment".equals(nodeName)) {
-                L.e("fragments do not support data binding expressions.");
+                if (XmlEditor.hasExpressionAttributes(parent)) {
+                    L.e("fragments do not support data binding expressions.");
+                }
                 continue;
             } else {
                 viewName = getViewName(parent);
@@ -234,9 +243,15 @@
 
             for (XMLParser.AttributeContext attr : XmlEditor.expressionAttributes(parent)) {
                 String value = escapeQuotes(attr.attrValue.getText(), true);
-                if (value.charAt(0) == '@' && value.charAt(1) == '{' &&
-                        value.charAt(value.length() - 1) == '}') {
-                    final String strippedValue = value.substring(2, value.length() - 1);
+                final boolean isOneWay = value.startsWith("@{");
+                final boolean isTwoWay = value.startsWith("@={");
+                if (isOneWay || isTwoWay) {
+                    if (value.charAt(value.length() - 1) != '}') {
+                        L.e("Expecting '}' in expression '%s'", attr.attrValue.getText());
+                    }
+                    final int startIndex = isTwoWay ? 3 : 2;
+                    final int endIndex = value.length() - 1;
+                    final String strippedValue = value.substring(startIndex, endIndex);
                     Location attrLocation = new Location(attr);
                     Location valueLocation = new Location();
                     // offset to 0 based
@@ -245,8 +260,8 @@
                             attr.attrValue.getText().indexOf(strippedValue);
                     valueLocation.endLine = attrLocation.endLine;
                     valueLocation.endOffset = attrLocation.endOffset - 2; // account for: "}
-                    bindingTargetBundle.addBinding(escapeQuotes(attr.attrName.getText(), false)
-                            , strippedValue, attrLocation, valueLocation);
+                    bindingTargetBundle.addBinding(escapeQuotes(attr.attrName.getText(), false),
+                            strippedValue, isTwoWay, attrLocation, valueLocation);
                 }
             }
         }
@@ -262,10 +277,12 @@
         String viewName = elm.elmName.getText();
         if ("view".equals(viewName)) {
             String classNode = attributeMap(elm).get("class");
-            if (StringUtils.isEmpty(classNode)) {
+            if (Strings.isNullOrEmpty(classNode)) {
                 L.e("No class attribute for 'view' node");
             }
             viewName = classNode;
+        } else if ("include".equals(viewName) && !XmlEditor.hasExpressionAttributes(elm)) {
+            viewName = "android.view.View";
         }
         return viewName;
     }
@@ -281,9 +298,8 @@
             String alias = attrMap.get("alias");
             Preconditions.check(StringUtils.isNotBlank(type), "Type of an import cannot be empty."
                     + " %s in %s", imp.toStringTree(), xml);
-            if (StringUtils.isEmpty(alias)) {
-                final String[] split = StringUtils.split(type, '.');
-                alias = split[split.length - 1];
+            if (Strings.isNullOrEmpty(alias)) {
+                alias = type.substring(type.lastIndexOf('.') + 1);
             }
             bundle.addImport(alias, type, new Location(imp));
         }
@@ -296,7 +312,7 @@
                     variable.toStringTree(), xml);
             Preconditions.checkNotNull(name, "variable must have a name %s in %s",
                     variable.toStringTree(), xml);
-            bundle.addVariable(name, type, new Location(variable));
+            bundle.addVariable(name, type, new Location(variable), true);
         }
         final XMLParser.AttributeContext className = findAttribute(data, "class");
         if (className != null) {
@@ -331,7 +347,7 @@
 
     private List<XMLParser.ElementContext> filter(XMLParser.ElementContext root,
             String name) {
-        List<XMLParser.ElementContext> result = new ArrayList<>();
+        List<XMLParser.ElementContext> result = new ArrayList<XMLParser.ElementContext>();
         if (root == null) {
             return result;
         }
@@ -349,7 +365,7 @@
 
     private List<XMLParser.ElementContext> filterNot(XMLParser.ElementContext root,
             String name) {
-        List<XMLParser.ElementContext> result = new ArrayList<>();
+        List<XMLParser.ElementContext> result = new ArrayList<XMLParser.ElementContext>();
         if (root == null) {
             return result;
         }
@@ -369,40 +385,31 @@
         return "merge".equals(rootView.elmName.getText()) && filter(rootView, "include").size() > 0;
     }
 
-    private File stripFileAndGetOriginal(File xml, String binderId)
+    private void stripFile(File xml, File out, String encoding,
+            LayoutXmlProcessor.OriginalFileLookup originalFileLookup)
             throws ParserConfigurationException, IOException, SAXException,
             XPathExpressionException {
-        L.d("parsing resource file %s", xml.getAbsolutePath());
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         DocumentBuilder builder = factory.newDocumentBuilder();
         Document doc = builder.parse(xml);
         XPathFactory xPathFactory = XPathFactory.newInstance();
         XPath xPath = xPathFactory.newXPath();
-        final XPathExpression commentElementExpr = xPath
-                .compile("//comment()[starts-with(., \" From: file:\")][last()]");
-        final NodeList commentElementNodes = (NodeList) commentElementExpr
-                .evaluate(doc, XPathConstants.NODESET);
-        L.d("comment element nodes count %s", commentElementNodes.getLength());
-        if (commentElementNodes.getLength() == 0) {
-            L.d("cannot find comment element to find the actual file");
-            return null;
+        File actualFile = originalFileLookup == null ? null
+                : originalFileLookup.getOriginalFileFor(xml);
+        // TODO get rid of original file lookup
+        if (actualFile == null) {
+            actualFile = xml;
         }
-        final Node first = commentElementNodes.item(0);
-        String actualFilePath = first.getNodeValue().substring(" From:".length()).trim();
-        L.d("actual file to parse: %s", actualFilePath);
-        File actualFile = urlToFile(new java.net.URL(actualFilePath));
-        if (!actualFile.canRead()) {
-            L.d("cannot find original, skipping. %s", actualFile.getAbsolutePath());
-            return null;
-        }
-
+        // always create id from actual file when available. Gradle may duplicate files.
+        String noExt = ParserHelper.stripExtension(actualFile.getName());
+        String binderId = actualFile.getParentFile().getName() + '/' + noExt;
         // now if file has any binding expressions, find and delete them
-        // TODO we should rely on namespace to avoid parsing file twice
         boolean changed = isBindingLayout(doc, xPath);
         if (changed) {
-            stripBindingTags(xml, binderId);
+            stripBindingTags(xml, out, binderId, encoding);
+        } else if (!xml.equals(out)){
+            FileUtils.copyFile(xml, out);
         }
-        return actualFile;
     }
 
     private boolean isBindingLayout(Document doc, XPath xPath) throws XPathExpressionException {
@@ -423,28 +430,40 @@
         return result;
     }
 
-    private void stripBindingTags(File xml, String newTag) throws IOException {
-        String res = XmlEditor.strip(xml, newTag);
+    private void stripBindingTags(File xml, File output, String newTag, String encoding) throws IOException {
+        String res = XmlEditor.strip(xml, newTag, encoding);
+        Preconditions.checkNotNull(res, "layout file should've changed %s", xml.getAbsolutePath());
         if (res != null) {
             L.d("file %s has changed, overwriting %s", xml.getName(), xml.getAbsolutePath());
-            FileUtils.writeStringToFile(xml, res);
+            FileUtils.writeStringToFile(output, res, encoding);
         }
     }
 
-    public static File urlToFile(URL url) throws MalformedURLException {
+    private static String findEncoding(File f) throws IOException {
+        FileInputStream fin = new FileInputStream(f);
         try {
-            return new File(url.toURI());
-        } catch (IllegalArgumentException e) {
-            MalformedURLException ex = new MalformedURLException(e.getLocalizedMessage());
-            ex.initCause(e);
-            throw ex;
-        } catch (URISyntaxException e) {
-            return new File(url.getPath());
+            UniversalDetector universalDetector = new UniversalDetector(null);
+
+            byte[] buf = new byte[4096];
+            int nread;
+            while ((nread = fin.read(buf)) > 0 && !universalDetector.isDone()) {
+                universalDetector.handleData(buf, 0, nread);
+            }
+
+            universalDetector.dataEnd();
+
+            String encoding = universalDetector.getDetectedCharset();
+            if (encoding == null) {
+                encoding = "utf-8";
+            }
+            return encoding;
+        } finally {
+            fin.close();
         }
     }
 
     private static Map<String, String> attributeMap(XMLParser.ElementContext root) {
-        final Map<String, String> result = new HashMap<>();
+        final Map<String, String> result = new HashMap<String, String>();
         for (XMLParser.AttributeContext attr : XmlEditor.attributes(root)) {
             result.put(escapeQuotes(attr.attrName.getText(), false),
                     escapeQuotes(attr.attrValue.getText(), true));
@@ -474,7 +493,7 @@
         }
         String val = textWithQuotes.substring(start, end);
         if (unescapeValue) {
-            return StringEscapeUtils.unescapeXml(val);
+            return StringUtils.unescapeXml(val);
         } else {
             return val;
         }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/store/Location.java b/compilerCommon/src/main/java/android/databinding/tool/store/Location.java
index d88f0de..67ed6a1 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/store/Location.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/store/Location.java
@@ -15,13 +15,14 @@
  */
 
 package android.databinding.tool.store;
+
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.Token;
-import org.apache.commons.lang3.StringUtils;
 
 import android.databinding.tool.processing.scopes.LocationScopeProvider;
+import android.databinding.tool.util.StringUtils;
 
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import javax.xml.bind.annotation.XmlAccessType;
@@ -74,7 +75,7 @@
         } else {
             endLine = end.getLine() - 1; // token lines start from 1
             String endText = end.getText();
-            int lastLineStart = endText.lastIndexOf(System.lineSeparator());
+            int lastLineStart = endText.lastIndexOf(StringUtils.LINE_SEPARATOR);
             String lastLine = lastLineStart < 0 ? endText : endText.substring(lastLineStart + 1);
             endOffset = end.getCharPositionInLine() + lastLine.length() - 1;//end is inclusive
         }
@@ -130,12 +131,9 @@
         if (startOffset != location.startOffset) {
             return false;
         }
-        if (parentLocation != null ? !parentLocation.equals(location.parentLocation)
-                : location.parentLocation != null) {
-            return false;
-        }
+        return !(parentLocation != null ? !parentLocation.equals(location.parentLocation)
+                : location.parentLocation != null);
 
-        return true;
     }
 
     @Override
@@ -161,10 +159,7 @@
         if (endLine < other.endLine) {
             return false;
         }
-        if (endLine == other.endLine && endOffset < other.endOffset) {
-            return false;
-        }
-        return true;
+        return !(endLine == other.endLine && endOffset < other.endOffset);
     }
 
     private Location getValidParentAbsoluteLocation() {
@@ -233,7 +228,7 @@
         return new LocationScopeProvider() {
             @Override
             public List<Location> provideScopeLocation() {
-                return Arrays.asList(Location.this);
+                return Collections.singletonList(Location.this);
             }
         };
     }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/store/ResourceBundle.java b/compilerCommon/src/main/java/android/databinding/tool/store/ResourceBundle.java
index 74a0676..f9d0fe9 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/store/ResourceBundle.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/store/ResourceBundle.java
@@ -13,8 +13,6 @@
 
 package android.databinding.tool.store;
 
-import org.apache.commons.lang3.ArrayUtils;
-
 import android.databinding.tool.processing.ErrorMessages;
 import android.databinding.tool.processing.Scope;
 import android.databinding.tool.processing.ScopedException;
@@ -25,7 +23,9 @@
 import android.databinding.tool.util.Preconditions;
 
 import java.io.File;
+import java.io.InputStream;
 import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -34,6 +34,10 @@
 import java.util.Map;
 import java.util.Set;
 
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
@@ -52,6 +56,8 @@
     private HashMap<String, List<LayoutFileBundle>> mLayoutBundles
             = new HashMap<String, List<LayoutFileBundle>>();
 
+    private List<File> mRemovedFiles = new ArrayList<File>();
+
     public ResourceBundle(String appPackage) {
         mAppPackage = appPackage;
     }
@@ -86,18 +92,28 @@
     public void validateMultiResLayouts() {
         for (List<LayoutFileBundle> layoutFileBundles : mLayoutBundles.values()) {
             for (LayoutFileBundle layoutFileBundle : layoutFileBundles) {
+                List<BindingTargetBundle> unboundIncludes = new ArrayList<BindingTargetBundle>();
                 for (BindingTargetBundle target : layoutFileBundle.getBindingTargetBundles()) {
                     if (target.isBinder()) {
                         List<LayoutFileBundle> boundTo =
                                 mLayoutBundles.get(target.getIncludedLayout());
                         if (boundTo == null || boundTo.isEmpty()) {
-                            L.e("There is no binding for %s", target.getIncludedLayout());
+                            L.d("There is no binding for %s, reverting to plain layout",
+                                    target.getIncludedLayout());
+                            if (target.getId() == null) {
+                                unboundIncludes.add(target);
+                            } else {
+                                target.setIncludedLayout(null);
+                                target.setInterfaceType("android.view.View");
+                                target.mViewName = "android.view.View";
+                            }
                         } else {
                             String binding = boundTo.get(0).getFullBindingClass();
                             target.setInterfaceType(binding);
                         }
                     }
                 }
+                layoutFileBundle.getBindingTargetBundles().removeAll(unboundIncludes);
             }
         }
 
@@ -116,7 +132,7 @@
                     bundles.getValue(), ErrorMessages.MULTI_CONFIG_VARIABLE_TYPE_MISMATCH,
                     new ValidateAndFilterCallback() {
                         @Override
-                        public List<NameTypeLocation> get(LayoutFileBundle bundle) {
+                        public List<? extends NameTypeLocation> get(LayoutFileBundle bundle) {
                             return bundle.mVariables;
                         }
                     });
@@ -136,7 +152,8 @@
                         bundle.mConfigName);
                 for (Map.Entry<String, NameTypeLocation> variable : variableTypes.entrySet()) {
                     if (!NameTypeLocation.contains(bundle.mVariables, variable.getKey())) {
-                        bundle.mVariables.add(variable.getValue());
+                        NameTypeLocation orig = variable.getValue();
+                        bundle.addVariable(orig.name, orig.type, orig.location, false);
                         L.d("adding missing variable %s to %s / %s", variable.getKey(),
                                 bundle.mFileName, bundle.mConfigName);
                     }
@@ -155,7 +172,7 @@
             Map<String, String> viewTypes = new HashMap<String, String>();
             Map<String, String> includes = new HashMap<String, String>();
             L.d("validating ids for %s", bundles.getKey());
-            Set<String> conflictingIds = new HashSet<>();
+            Set<String> conflictingIds = new HashSet<String>();
             for (LayoutFileBundle bundle : bundles.getValue()) {
                 try {
                     Scope.enter(bundle);
@@ -284,8 +301,8 @@
     private Map<String, NameTypeLocation> validateAndMergeNameTypeLocations(
             List<LayoutFileBundle> bundles, String errorMessage,
             ValidateAndFilterCallback callback) {
-        Map<String, NameTypeLocation> result = new HashMap<>();
-        Set<String> mismatched = new HashSet<>();
+        Map<String, NameTypeLocation> result = new HashMap<String, NameTypeLocation>();
+        Set<String> mismatched = new HashSet<String>();
         for (LayoutFileBundle bundle : bundles) {
             for (NameTypeLocation item : callback.get(bundle)) {
                 NameTypeLocation existing = result.get(item.name);
@@ -354,6 +371,14 @@
         return sharedClassName;
     }
 
+    public void addRemovedFile(File file) {
+        mRemovedFiles.add(file);
+    }
+
+    public List<File> getRemovedFiles() {
+        return mRemovedFiles;
+    }
+
     @XmlAccessorType(XmlAccessType.NONE)
     @XmlRootElement(name="Layout")
     public static class LayoutFileBundle implements Serializable, FileScopeProvider {
@@ -386,10 +411,10 @@
         public boolean mHasVariations;
 
         @XmlElement(name="Variables")
-        public List<NameTypeLocation> mVariables = new ArrayList<>();
+        public List<VariableDeclaration> mVariables = new ArrayList<VariableDeclaration>();
 
         @XmlElement(name="Imports")
-        public List<NameTypeLocation> mImports = new ArrayList<>();
+        public List<NameTypeLocation> mImports = new ArrayList<NameTypeLocation>();
 
         @XmlElementWrapper(name="Targets")
         @XmlElement(name="Target")
@@ -404,6 +429,21 @@
         public LayoutFileBundle() {
         }
 
+        /**
+         * Updates configuration fields from the given bundle but does not change variables,
+         * binding expressions etc.
+         */
+        public void inheritConfigurationFrom(LayoutFileBundle other) {
+            mFileName = other.mFileName;
+            mModulePackage = other.mModulePackage;
+            mBindingClass = other.mBindingClass;
+            mFullBindingClass = other.mFullBindingClass;
+            mBindingClassName = other.mBindingClassName;
+            mBindingPackage = other.mBindingPackage;
+            mHasVariations = other.mHasVariations;
+            mIsMerge = other.mIsMerge;
+        }
+
         public LayoutFileBundle(File file, String fileName, String directory,
                 String modulePackage, boolean isMerge) {
             mFileName = fileName;
@@ -421,10 +461,10 @@
             return mClassNameLocationProvider;
         }
 
-        public void addVariable(String name, String type, Location location) {
+        public void addVariable(String name, String type, Location location, boolean declared) {
             Preconditions.check(!NameTypeLocation.contains(mVariables, name),
                     "Cannot use same variable name twice. %s in %s", name, location);
-            mVariables.add(new NameTypeLocation(name, type, location));
+            mVariables.add(new VariableDeclaration(name, type, location, declared));
         }
 
         public void addImport(String alias, String type, Location location) {
@@ -470,7 +510,7 @@
             return mHasVariations;
         }
 
-        public List<NameTypeLocation> getVariables() {
+        public List<VariableDeclaration> getVariables() {
             return mVariables;
         }
 
@@ -544,12 +584,9 @@
                     : bundle.mDirectory != null) {
                 return false;
             }
-            if (mFileName != null ? !mFileName.equals(bundle.mFileName)
-                    : bundle.mFileName != null) {
-                return false;
-            }
+            return !(mFileName != null ? !mFileName.equals(bundle.mFileName)
+                    : bundle.mFileName != null);
 
-            return true;
         }
 
         @Override
@@ -583,6 +620,37 @@
         public String provideScopeFilePath() {
             return mAbsoluteFilePath;
         }
+
+        private static Marshaller sMarshaller;
+        private static Unmarshaller sUmarshaller;
+
+        public String toXML() throws JAXBException {
+            StringWriter writer = new StringWriter();
+            getMarshaller().marshal(this, writer);
+            return writer.getBuffer().toString();
+        }
+
+        public static LayoutFileBundle fromXML(InputStream inputStream) throws JAXBException {
+            return (LayoutFileBundle) getUnmarshaller().unmarshal(inputStream);
+        }
+
+        private static Marshaller getMarshaller() throws JAXBException {
+            if (sMarshaller == null) {
+                JAXBContext context = JAXBContext
+                        .newInstance(ResourceBundle.LayoutFileBundle.class);
+                sMarshaller = context.createMarshaller();
+            }
+            return sMarshaller;
+        }
+
+        private static Unmarshaller getUnmarshaller() throws JAXBException {
+            if (sUmarshaller == null) {
+                JAXBContext context = JAXBContext
+                        .newInstance(ResourceBundle.LayoutFileBundle.class);
+                sUmarshaller = context.createUnmarshaller();
+            }
+            return sUmarshaller;
+        }
     }
 
     @XmlAccessorType(XmlAccessType.NONE)
@@ -631,11 +699,8 @@
             if (!name.equals(that.name)) {
                 return false;
             }
-            if (!type.equals(that.type)) {
-                return false;
-            }
+            return type.equals(that.type);
 
-            return true;
         }
 
         @Override
@@ -646,7 +711,7 @@
             return result;
         }
 
-        public static boolean contains(List<NameTypeLocation> list, String name) {
+        public static boolean contains(List<? extends NameTypeLocation> list, String name) {
             for (NameTypeLocation ntl : list) {
                 if (name.equals(ntl.name)) {
                     return true;
@@ -656,6 +721,21 @@
         }
     }
 
+    @XmlAccessorType(XmlAccessType.NONE)
+    public static class VariableDeclaration extends NameTypeLocation {
+        @XmlAttribute(name="declared", required = false)
+        public boolean declared;
+
+        public VariableDeclaration() {
+
+        }
+
+        public VariableDeclaration(String name, String type, Location location, boolean declared) {
+            super(name, type, location);
+            this.declared = declared;
+        }
+    }
+
     public static class MarshalledMapType {
         public List<NameTypeLocation> entries;
     }
@@ -696,8 +776,9 @@
             mLocation = location;
         }
 
-        public void addBinding(String name, String expr, Location location, Location valueLocation) {
-            mBindingBundleList.add(new BindingBundle(name, expr, location, valueLocation));
+        public void addBinding(String name, String expr, boolean isTwoWay, Location location,
+                Location valueLocation) {
+            mBindingBundleList.add(new BindingBundle(name, expr, isTwoWay, location, valueLocation));
         }
 
         public void setIncludedLayout(String includedLayout) {
@@ -741,7 +822,7 @@
                 if (isBinder()) {
                     mFullClassName = mInterfaceType;
                 } else if (mViewName.indexOf('.') == -1) {
-                    if (ArrayUtils.contains(ANDROID_VIEW_PACKAGE_VIEWS, mViewName)) {
+                    if (Arrays.asList(ANDROID_VIEW_PACKAGE_VIEWS).contains(mViewName)) {
                         mFullClassName = "android.view." + mViewName;
                     } else if("WebView".equals(mViewName)) {
                         mFullClassName = "android.webkit." + mViewName;
@@ -783,14 +864,16 @@
             private String mExpr;
             private Location mLocation;
             private Location mValueLocation;
+            private boolean mIsTwoWay;
 
             public BindingBundle() {}
 
-            public BindingBundle(String name, String expr, Location location,
+            public BindingBundle(String name, String expr, boolean isTwoWay, Location location,
                     Location valueLocation) {
                 mName = name;
                 mExpr = expr;
                 mLocation = location;
+                mIsTwoWay = isTwoWay;
                 mValueLocation = valueLocation;
             }
 
@@ -812,6 +895,10 @@
                 mExpr = expr;
             }
 
+            public void setTwoWay(boolean isTwoWay) {
+                mIsTwoWay = isTwoWay;
+            }
+
             @XmlElement(name="Location")
             public Location getLocation() {
                 return mLocation;
@@ -826,6 +913,11 @@
                 return mValueLocation;
             }
 
+            @XmlElement(name="TwoWay")
+            public boolean isTwoWay() {
+                return mIsTwoWay;
+            }
+
             public void setValueLocation(Location valueLocation) {
                 mValueLocation = valueLocation;
             }
@@ -836,6 +928,6 @@
      * Just an inner callback class to process imports and variables w/ the same code.
      */
     private interface ValidateAndFilterCallback {
-        List<NameTypeLocation> get(LayoutFileBundle bundle);
+        List<? extends NameTypeLocation> get(LayoutFileBundle bundle);
     }
 }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/util/L.java b/compilerCommon/src/main/java/android/databinding/tool/util/L.java
index fe888ca..37292b2 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/util/L.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/util/L.java
@@ -16,10 +16,12 @@
 
 package android.databinding.tool.util;
 
-import org.apache.commons.lang3.exception.ExceptionUtils;
-
 import android.databinding.tool.processing.ScopedException;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.lang.model.element.Element;
 import javax.tools.Diagnostic;
 import javax.tools.Diagnostic.Kind;
 
@@ -27,7 +29,7 @@
     private static boolean sEnableDebug = false;
     private static final Client sSystemClient = new Client() {
         @Override
-        public void printMessage(Kind kind, String message) {
+        public void printMessage(Kind kind, String message, Element element) {
             if (kind == Kind.ERROR) {
                 System.err.println(message);
             } else {
@@ -39,7 +41,7 @@
     private static Client sClient = sSystemClient;
 
     public static void setClient(Client systemClient) {
-        L.sClient = systemClient;
+        sClient = systemClient;
     }
 
     public static void setDebugLog(boolean enabled) {
@@ -48,24 +50,34 @@
 
     public static void d(String msg, Object... args) {
         if (sEnableDebug) {
-            printMessage(Diagnostic.Kind.NOTE, String.format(msg, args));
+            printMessage(null, Diagnostic.Kind.NOTE, String.format(msg, args));
+        }
+    }
+
+    public static void d(Element element, String msg, Object... args) {
+        if (sEnableDebug) {
+            printMessage(element, Diagnostic.Kind.NOTE, String.format(msg, args));
         }
     }
 
     public static void d(Throwable t, String msg, Object... args) {
         if (sEnableDebug) {
-            printMessage(Diagnostic.Kind.NOTE,
-                    String.format(msg, args) + " " + ExceptionUtils.getStackTrace(t));
+            printMessage(null, Diagnostic.Kind.NOTE,
+                    String.format(msg, args) + " " + getStackTrace(t));
         }
     }
 
     public static void w(String msg, Object... args) {
-        printMessage(Kind.WARNING, String.format(msg, args));
+        printMessage(null, Kind.WARNING, String.format(msg, args));
+    }
+
+    public static void w(Element element, String msg, Object... args) {
+        printMessage(element, Kind.WARNING, String.format(msg, args));
     }
 
     public static void w(Throwable t, String msg, Object... args) {
-        printMessage(Kind.WARNING,
-                String.format(msg, args) + " " + ExceptionUtils.getStackTrace(t));
+        printMessage(null, Kind.WARNING,
+                String.format(msg, args) + " " + getStackTrace(t));
     }
 
     private static void tryToThrowScoped(Throwable t, String fullMessage) {
@@ -84,18 +96,24 @@
     public static void e(String msg, Object... args) {
         String fullMsg = String.format(msg, args);
         tryToThrowScoped(null, fullMsg);
-        printMessage(Diagnostic.Kind.ERROR, fullMsg);
+        printMessage(null, Diagnostic.Kind.ERROR, fullMsg);
+    }
+
+    public static void e(Element element, String msg, Object... args) {
+        String fullMsg = String.format(msg, args);
+        tryToThrowScoped(null, fullMsg);
+        printMessage(element, Diagnostic.Kind.ERROR, fullMsg);
     }
 
     public static void e(Throwable t, String msg, Object... args) {
         String fullMsg = String.format(msg, args);
         tryToThrowScoped(t, fullMsg);
-        printMessage(Diagnostic.Kind.ERROR,
-                fullMsg + " " + ExceptionUtils.getStackTrace(t));
+        printMessage(null, Diagnostic.Kind.ERROR,
+                fullMsg + " " + getStackTrace(t));
     }
 
-    private static void printMessage(Diagnostic.Kind kind, String message) {
-        sClient.printMessage(kind, message);
+    private static void printMessage(Element element, Diagnostic.Kind kind, String message) {
+        sClient.printMessage(kind, message, element);
         if (kind == Diagnostic.Kind.ERROR) {
             throw new RuntimeException("failure, see logs for details.\n" + message);
         }
@@ -105,7 +123,18 @@
         return sEnableDebug;
     }
 
-    public static interface Client {
-        public void printMessage(Diagnostic.Kind kind, String message);
+    public interface Client {
+        void printMessage(Diagnostic.Kind kind, String message, Element element);
+    }
+
+    private static String getStackTrace(Throwable t) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        try {
+            t.printStackTrace(pw);
+        } finally {
+            pw.close();
+        }
+        return sw.toString();
     }
 }
diff --git a/compilerCommon/src/main/java/android/databinding/tool/util/ParserHelper.java b/compilerCommon/src/main/java/android/databinding/tool/util/ParserHelper.java
index c3740e5..8b3a93b 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/util/ParserHelper.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/util/ParserHelper.java
@@ -16,8 +16,6 @@
 
 package android.databinding.tool.util;
 
-import org.apache.commons.lang3.StringUtils;
-
 public class ParserHelper {
     public static String toClassName(String name) {
         StringBuilder builder = new StringBuilder();
diff --git a/compilerCommon/src/main/java/android/databinding/tool/util/SourceCodeEscapers.java b/compilerCommon/src/main/java/android/databinding/tool/util/SourceCodeEscapers.java
new file mode 100644
index 0000000..d979b67
--- /dev/null
+++ b/compilerCommon/src/main/java/android/databinding/tool/util/SourceCodeEscapers.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2009 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool.util;
+
+import com.google.common.escape.ArrayBasedCharEscaper;
+import com.google.common.escape.CharEscaper;
+import com.google.common.escape.Escaper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This file has been copied from the google internal implementation of guava. Some unused parts of
+ * the file have been removed.
+ */
+
+/**
+ * A factory for Escaper instances used to escape strings for safe use in
+ * various common programming languages.
+ *
+ * @author Alex Matevossian
+ * @author David Beaumont
+ */
+public final class SourceCodeEscapers {
+    private SourceCodeEscapers() {}
+
+    // For each xxxEscaper() method, please add links to external reference pages
+    // that are considered authoritative for the behavior of that escaper.
+
+    // From: http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
+    private static final char PRINTABLE_ASCII_MIN = 0x20;  // ' '
+    private static final char PRINTABLE_ASCII_MAX = 0x7E;  // '~'
+
+    private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
+
+    /**
+     * Returns an {@link Escaper} instance that escapes special characters in a
+     * string so it can safely be included in either a Java character literal or
+     * string literal. This is the preferred way to escape Java characters for
+     * use in String or character literals.
+     *
+     * <p>For more details, see <a href="http://goo.gl/NsGW7">Escape Sequences for
+     * Character and String Literals</a> in The Java Language Specification.
+     */
+    public static Escaper javaCharEscaper() {
+        return JAVA_CHAR_ESCAPER;
+    }
+
+    /**
+     * Returns an {@link Escaper} instance that escapes special characters in a
+     * string so it can safely be included in either a Java character literal or
+     * string literal. The behavior of this escaper is the same as that of the
+     * {@link #javaStringEscaperWithOctal()} except it also escapes single quotes.
+     *
+     * <p>Unlike {@link #javaCharEscaper} this escaper produces octal escape
+     * sequences ({@literal \}nnn) for characters with values less than 256. While
+     * the escaped output can be shorter than when the standard Unicode escape
+     * sequence ({@literal \}uxxxx) is used, the Java Language Specification
+     * discourages the use of octal for escaping Java strings. It is strongly
+     * recommended that, if possible, you use {@code javaCharEscaper()} in
+     * preference to this method.
+     *
+     * <p>For more details, see <a href="http://goo.gl/NsGW7">Escape Sequences for
+     * Character and String Literals</a> in The Java Language Specification.
+     */
+    public static Escaper javaCharEscaperWithOctal() {
+        return JAVA_CHAR_ESCAPER_WITH_OCTAL;
+    }
+
+    /**
+     * Returns an {@link Escaper} instance that escapes special characters in a
+     * string so it can safely be included in a Java string literal.
+     *
+     * <p><b>Note:</b> Single quotes are not escaped, so it is <b>not safe</b> to
+     * use this escaper for escaping character literals.
+     *
+     * <p>Unlike {@link #javaCharEscaper} this escaper produces octal escape
+     * sequences ({@literal \}nnn) for characters with values less than 256. While
+     * the escaped output can be shorter than when the standard Unicode escape
+     * sequence ({@literal \}uxxxx) is used, the Java Language Specification
+     * discourages the use of octal for escaping Java strings. It is strongly
+     * recommended that, if possible, you use {@code javaCharEscaper()} in
+     * preference to this method.
+     *
+     * <p>For more details, see <a href="http://goo.gl/NsGW7">Escape Sequences for
+     * Character and String Literals</a> in The Java Language Specification.
+     */
+    public static Escaper javaStringEscaperWithOctal() {
+        return JAVA_STRING_ESCAPER_WITH_OCTAL;
+    }
+
+    private static final Escaper JAVA_CHAR_ESCAPER;
+    private static final Escaper JAVA_CHAR_ESCAPER_WITH_OCTAL;
+    private static final Escaper JAVA_STRING_ESCAPER_WITH_OCTAL;
+    static {
+        Map<Character, String> javaMap = new HashMap<Character, String>();
+        javaMap.put('\b', "\\b");
+        javaMap.put('\f', "\\f");
+        javaMap.put('\n', "\\n");
+        javaMap.put('\r', "\\r");
+        javaMap.put('\t', "\\t");
+        javaMap.put('\"', "\\\"");
+        javaMap.put('\\', "\\\\");
+        JAVA_STRING_ESCAPER_WITH_OCTAL = new JavaCharEscaperWithOctal(javaMap);
+        // The only difference is that the char escaper also escapes single quotes.
+        javaMap.put('\'', "\\'");
+        JAVA_CHAR_ESCAPER = new JavaCharEscaper(javaMap);
+        JAVA_CHAR_ESCAPER_WITH_OCTAL = new JavaCharEscaperWithOctal(javaMap);
+    }
+
+    // This escaper does not produce octal escape sequences. See:
+    // http://goo.gl/NsGW7
+    //  "Octal escapes are provided for compatibility with C, but can express
+    //   only Unicode values \u0000 through \u00FF, so Unicode escapes are
+    //   usually preferred."
+    private static class JavaCharEscaper extends ArrayBasedCharEscaper {
+        JavaCharEscaper(Map<Character, String> replacements) {
+            super(replacements, PRINTABLE_ASCII_MIN, PRINTABLE_ASCII_MAX);
+        }
+
+        @Override protected char[] escapeUnsafe(char c) {
+            return asUnicodeHexEscape(c);
+        }
+    }
+
+    private static class JavaCharEscaperWithOctal extends ArrayBasedCharEscaper {
+        JavaCharEscaperWithOctal(Map<Character, String> replacements) {
+            super(replacements, PRINTABLE_ASCII_MIN, PRINTABLE_ASCII_MAX);
+        }
+
+        @Override protected char[] escapeUnsafe(char c) {
+            if (c < 0x100) {
+                return asOctalEscape(c);
+            } else {
+                return asUnicodeHexEscape(c);
+            }
+        }
+    }
+
+    /**
+     * Returns an {@link Escaper} instance that replaces non-ASCII characters
+     * in a string with their Unicode escape sequences ({@code \\uxxxx} where
+     * {@code xxxx} is a hex number). Existing escape sequences won't be affected.
+     *
+     * <p>As existing escape sequences are not re-escaped, this escaper is
+     * idempotent. However this means that there can be no well defined inverse
+     * function for this escaper.
+     *
+     * <p><b>Note:</b> the returned escaper is still a {@code CharEscaper} and
+     * will not combine surrogate pairs into a single code point before escaping.
+     */
+    public static Escaper javaStringUnicodeEscaper() {
+        return JAVA_STRING_UNICODE_ESCAPER;
+    }
+
+    private static final Escaper JAVA_STRING_UNICODE_ESCAPER
+            = new CharEscaper() {
+        @Override protected char[] escape(char c) {
+            if (c < 0x80) {
+                return null;
+            }
+            return asUnicodeHexEscape(c);
+        }
+    };
+
+    // Helper for common case of escaping a single char.
+    private static char[] asUnicodeHexEscape(char c) {
+        // Equivalent to String.format("\\u%04x", (int) c);
+        char[] r = new char[6];
+        r[0] = '\\';
+        r[1] = 'u';
+        r[5] = HEX_DIGITS[c & 0xF];
+        c >>>= 4;
+        r[4] = HEX_DIGITS[c & 0xF];
+        c >>>= 4;
+        r[3] = HEX_DIGITS[c & 0xF];
+        c >>>= 4;
+        r[2] = HEX_DIGITS[c & 0xF];
+        return r;
+    }
+
+    // Helper for backward compatible octal escape sequences (c < 256)
+    private static char[] asOctalEscape(char c) {
+        char[] r = new char[4];
+        r[0] = '\\';
+        r[3] = HEX_DIGITS[c & 0x7];
+        c >>>= 3;
+        r[2] = HEX_DIGITS[c & 0x7];
+        c >>>= 3;
+        r[1] = HEX_DIGITS[c & 0x3];
+        return r;
+    }
+}
diff --git a/compilerCommon/src/main/java/android/databinding/tool/util/StringUtils.java b/compilerCommon/src/main/java/android/databinding/tool/util/StringUtils.java
new file mode 100644
index 0000000..5f535ba
--- /dev/null
+++ b/compilerCommon/src/main/java/android/databinding/tool/util/StringUtils.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool.util;
+
+import com.google.common.base.StandardSystemProperty;
+import com.google.common.base.Strings;
+
+import org.antlr.v4.runtime.misc.Nullable;
+
+public class StringUtils {
+
+    public static final String LINE_SEPARATOR = StandardSystemProperty.LINE_SEPARATOR.value();
+    /** The entity for the ampersand character */
+    private static final String AMP_ENTITY = "&amp;";
+    /** The entity for the quote character */
+    private static final String QUOT_ENTITY = "&quot;";
+    /** The entity for the apostrophe character */
+    private static final String APOS_ENTITY = "&apos;";
+    /** The entity for the less than character */
+    private static final String LT_ENTITY = "&lt;";
+    /** The entity for the greater than character */
+    private static final String GT_ENTITY = "&gt;";
+    /** The entity for the tab character */
+    private static final String TAB_ENTITY = "&#x9;";
+    /** The entity for the carriage return character */
+    private static final String CR_ENTITY = "&#xD;";
+    /** The entity for the line feed character */
+    private static final String LFEED_ENTITY = "&#xA;";
+
+    public static boolean isNotBlank(@Nullable CharSequence string) {
+        if (string == null) {
+            return false;
+        }
+        for (int i = 0, n = string.length(); i < n; i++) {
+            if (!Character.isWhitespace(string.charAt(i))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static String capitalize(@Nullable String string) {
+        if (Strings.isNullOrEmpty(string)) {
+            return string;
+        }
+        char ch = string.charAt(0);
+        if (Character.isTitleCase(ch)) {
+            return string;
+        }
+        return Character.toTitleCase(ch) + string.substring(1);
+    }
+
+    public static String unescapeXml(String escaped) {
+        // TODO: unescape unicode codepoints
+        return escaped.replace(QUOT_ENTITY, "\"")
+                .replace(LT_ENTITY, "<")
+                .replace(GT_ENTITY, ">")
+                .replace(APOS_ENTITY, "'")
+                .replace(AMP_ENTITY, "&")
+                .replace(TAB_ENTITY, "\t")
+                .replace(CR_ENTITY, "\r")
+                .replace(LFEED_ENTITY, "\n");
+    }
+
+    private StringUtils() {
+    }
+
+}
diff --git a/compilerCommon/src/main/java/android/databinding/tool/util/XmlEditor.java b/compilerCommon/src/main/java/android/databinding/tool/util/XmlEditor.java
index c5f1c6c..e5a3da2 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/util/XmlEditor.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/util/XmlEditor.java
@@ -16,16 +16,6 @@
 
 package android.databinding.tool.util;
 
-import org.antlr.v4.runtime.ANTLRInputStream;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.Token;
-import org.antlr.v4.runtime.tree.TerminalNode;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.ImmutablePair;
-import org.apache.commons.lang3.tuple.Pair;
-
 import android.databinding.parser.BindingExpressionLexer;
 import android.databinding.parser.BindingExpressionParser;
 import android.databinding.parser.XMLLexer;
@@ -33,9 +23,19 @@
 import android.databinding.parser.XMLParser.AttributeContext;
 import android.databinding.parser.XMLParser.ElementContext;
 
+import com.google.common.base.Joiner;
+import com.google.common.xml.XmlEscapers;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.apache.commons.io.FileUtils;
+
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -47,43 +47,43 @@
  */
 public class XmlEditor {
 
-    public static String strip(File f, String newTag) throws IOException {
-        ANTLRInputStream inputStream = new ANTLRInputStream(new FileReader(f));
+    public static String strip(File f, String newTag, String encoding) throws IOException {
+        FileInputStream fin = new FileInputStream(f);
+        InputStreamReader reader = new InputStreamReader(fin, encoding);
+        ANTLRInputStream inputStream = new ANTLRInputStream(reader);
         XMLLexer lexer = new XMLLexer(inputStream);
         CommonTokenStream tokenStream = new CommonTokenStream(lexer);
         XMLParser parser = new XMLParser(tokenStream);
         XMLParser.DocumentContext expr = parser.document();
-        XMLParser.ElementContext root = expr.element();
+        ElementContext root = expr.element();
 
         if (root == null || !"layout".equals(nodeName(root))) {
             return null; // not a binding layout
         }
 
         List<? extends ElementContext> childrenOfRoot = elements(root);
-        List<? extends XMLParser.ElementContext> dataNodes = filterNodesByName("data",
-                childrenOfRoot);
+        List<? extends ElementContext> dataNodes = filterNodesByName("data", childrenOfRoot);
         if (dataNodes.size() > 1) {
             L.e("Multiple binding data tags in %s. Expecting a maximum of one.",
                     f.getAbsolutePath());
         }
 
-        ArrayList<String> lines = new ArrayList<>();
+        ArrayList<String> lines = new ArrayList<String>();
         lines.addAll(FileUtils.readLines(f, "utf-8"));
 
-        for (android.databinding.parser.XMLParser.ElementContext it : dataNodes) {
+        for (ElementContext it : dataNodes) {
             replace(lines, toPosition(it.getStart()), toEndPosition(it.getStop()), "");
         }
-        List<? extends XMLParser.ElementContext> layoutNodes =
+        List<? extends ElementContext> layoutNodes =
                 excludeNodesByName("data", childrenOfRoot);
         if (layoutNodes.size() != 1) {
             L.e("Only one layout element and one data element are allowed. %s has %d",
                     f.getAbsolutePath(), layoutNodes.size());
         }
 
-        final XMLParser.ElementContext layoutNode = layoutNodes.get(0);
+        final ElementContext layoutNode = layoutNodes.get(0);
 
-        ArrayList<Pair<String, android.databinding.parser.XMLParser.ElementContext>> noTag =
-                new ArrayList<>();
+        ArrayList<TagAndContext> noTag = new ArrayList<TagAndContext>();
 
         recurseReplace(layoutNode, lines, noTag, newTag, 0);
 
@@ -93,48 +93,46 @@
         replace(lines, rootStartTag, rootEndTag, "");
 
         // Remove the </layout>
-        ImmutablePair<Position, Position> endLayoutPositions = findTerminalPositions(root, lines);
+        PositionPair endLayoutPositions = findTerminalPositions(root, lines);
         replace(lines, endLayoutPositions.left, endLayoutPositions.right, "");
 
         StringBuilder rootAttributes = new StringBuilder();
         for (AttributeContext attr : attributes(root)) {
             rootAttributes.append(' ').append(attr.getText());
         }
-        Pair<String, XMLParser.ElementContext> noTagRoot = null;
-        for (Pair<String, XMLParser.ElementContext> pair : noTag) {
-            if (pair.getRight() == layoutNode) {
-                noTagRoot = pair;
+        TagAndContext noTagRoot = null;
+        for (TagAndContext tagAndContext : noTag) {
+            if (tagAndContext.getContext() == layoutNode) {
+                noTagRoot = tagAndContext;
                 break;
             }
         }
         if (noTagRoot != null) {
-            ImmutablePair<String, XMLParser.ElementContext>
-                    newRootTag = new ImmutablePair<>(
-                    noTagRoot.getLeft() + rootAttributes.toString(), layoutNode);
+            TagAndContext newRootTag = new TagAndContext(
+                    noTagRoot.getTag() + rootAttributes.toString(), layoutNode);
             int index = noTag.indexOf(noTagRoot);
             noTag.set(index, newRootTag);
         } else {
-            ImmutablePair<String, XMLParser.ElementContext> newRootTag =
-                    new ImmutablePair<>(rootAttributes.toString(), layoutNode);
+            TagAndContext newRootTag =
+                    new TagAndContext(rootAttributes.toString(), layoutNode);
             noTag.add(newRootTag);
         }
         //noinspection NullableProblems
-        Collections.sort(noTag, new Comparator<Pair<String, XMLParser.ElementContext>>() {
+        Collections.sort(noTag, new Comparator<TagAndContext>() {
             @Override
-            public int compare(Pair<String, XMLParser.ElementContext> o1,
-                    Pair<String, XMLParser.ElementContext> o2) {
-                Position start1 = toPosition(o1.getRight().getStart());
-                Position start2 = toPosition(o2.getRight().getStart());
-                int lineCmp = Integer.compare(start2.line, start1.line);
+            public int compare(TagAndContext o1, TagAndContext o2) {
+                Position start1 = toPosition(o1.getContext().getStart());
+                Position start2 = toPosition(o2.getContext().getStart());
+                int lineCmp = start2.line - start1.line;
                 if (lineCmp != 0) {
                     return lineCmp;
                 }
-                return Integer.compare(start2.charIndex, start1.charIndex);
+                return start2.charIndex - start1.charIndex;
             }
         });
-        for (Pair<String, android.databinding.parser.XMLParser.ElementContext> it : noTag) {
-            XMLParser.ElementContext element = it.getRight();
-            String tag = it.getLeft();
+        for (TagAndContext it : noTag) {
+            ElementContext element = it.getContext();
+            String tag = it.getTag();
             Position endTagPosition = endTagPosition(element);
             fixPosition(lines, endTagPosition);
             String line = lines.get(endTagPosition.line);
@@ -142,12 +140,12 @@
                     line.substring(endTagPosition.charIndex);
             lines.set(endTagPosition.line, newLine);
         }
-        return StringUtils.join(lines, System.getProperty("line.separator"));
+        return Joiner.on(StringUtils.LINE_SEPARATOR).join(lines);
     }
 
     private static <T extends XMLParser.ElementContext> List<T>
             filterNodesByName(String name, Iterable<T> items) {
-        List<T> result = new ArrayList<>();
+        List<T> result = new ArrayList<T>();
         for (T item : items) {
             if (name.equals(nodeName(item))) {
                 result.add(item);
@@ -158,7 +156,7 @@
 
     private static <T extends XMLParser.ElementContext> List<T>
             excludeNodesByName(String name, Iterable<T> items) {
-        List<T> result = new ArrayList<>();
+        List<T> result = new ArrayList<T>();
         for (T item : items) {
             if (!name.equals(nodeName(item))) {
                 result.add(item);
@@ -176,41 +174,49 @@
                 token.getCharPositionInLine() + token.getText().length());
     }
 
-    public static String nodeName(XMLParser.ElementContext elementContext) {
+    public static String nodeName(ElementContext elementContext) {
         return elementContext.elmName.getText();
     }
 
-    public static List<? extends AttributeContext> attributes(XMLParser.ElementContext elementContext) {
-        if (elementContext.attribute() == null) {
-            return new ArrayList<>();
-        } else {
+    public static List<? extends AttributeContext> attributes(ElementContext elementContext) {
+        if (elementContext.attribute() == null)
+            return new ArrayList<AttributeContext>();
+        else {
             return elementContext.attribute();
         }
     }
 
-    public static List<? extends AttributeContext> expressionAttributes (
-            XMLParser.ElementContext elementContext) {
-        List<AttributeContext> result = new ArrayList<>();
+    public static List<? extends AttributeContext> expressionAttributes(
+            ElementContext elementContext) {
+        List<AttributeContext> result = new ArrayList<AttributeContext>();
         for (AttributeContext input : attributes(elementContext)) {
             String attrName = input.attrName.getText();
-            String value = input.attrValue.getText();
-            if (attrName.equals("android:tag") ||
-                    (value.startsWith("\"@{") && value.endsWith("}\"")) ||
-                    (value.startsWith("'@{") && value.endsWith("}'"))) {
+            boolean isExpression = attrName.equals("android:tag");
+            if (!isExpression) {
+                final String value = input.attrValue.getText();
+                isExpression = isExpressionText(input.attrValue.getText());
+            }
+            if (isExpression) {
                 result.add(input);
             }
         }
         return result;
     }
 
-    private static Position endTagPosition(XMLParser.ElementContext context) {
+    private static boolean isExpressionText(String value) {
+        // Check if the expression ends with "}" and starts with "@{" or "@={", ignoring
+        // the surrounding quotes.
+        return (value.length() > 5 && value.charAt(value.length() - 2) == '}' &&
+                ("@{".equals(value.substring(1, 3)) || "@={".equals(value.substring(1, 4))));
+    }
+
+    private static Position endTagPosition(ElementContext context) {
         if (context.content() == null) {
-            // no content, so just subtract from the "/>"
-            Position endTag = toEndPosition(context.getStop());
+            // no content, so just choose the start of the "/>"
+            Position endTag = toPosition(context.getStop());
             if (endTag.charIndex <= 0) {
                 L.e("invalid input in %s", context);
             }
-            endTag.charIndex -= 2;
             return endTag;
         } else {
             // tag with no attributes, but with content
@@ -223,12 +229,11 @@
         }
     }
 
-    public static List<? extends android.databinding.parser.XMLParser.ElementContext> elements(
-            XMLParser.ElementContext context) {
+    public static List<? extends ElementContext> elements(ElementContext context) {
         if (context.content() != null && context.content().element() != null) {
             return context.content().element();
         }
-        return new ArrayList<>();
+        return new ArrayList<ElementContext>();
     }
 
     private static boolean replace(ArrayList<String> lines, Position start, Position end,
@@ -266,16 +271,22 @@
         return line.substring(0, start) + newText + line.substring(end);
     }
 
-    public static boolean hasExpressionAttributes(XMLParser.ElementContext context) {
+    public static boolean hasExpressionAttributes(ElementContext context) {
         List<? extends AttributeContext> expressions = expressionAttributes(context);
         int size = expressions.size();
-        //noinspection ConstantConditions
-        return size > 1 || (size == 1 &&
-                !expressions.get(0).attrName.getText().equals("android:tag"));
+        if (size == 0) {
+            return false;
+        } else if (size > 1) {
+            return true;
+        } else {
+            // android:tag is included, regardless, so we must only count as an expression
+            // if android:tag has a binding expression.
+            return isExpressionText(expressions.get(0).attrValue.getText());
+        }
     }
 
-    private static int recurseReplace(XMLParser.ElementContext node, ArrayList<String> lines,
-            ArrayList<Pair<String, XMLParser.ElementContext>> noTag,
+    private static int recurseReplace(ElementContext node, ArrayList<String> lines,
+            ArrayList<TagAndContext> noTag,
             String newTag, int bindingIndex) {
         int nextBindingIndex = bindingIndex;
         boolean isMerge = "merge".equals(nodeName(node));
@@ -300,7 +311,7 @@
                 }
             }
             if (tag.length() != 0) {
-                noTag.add(new ImmutablePair<>(tag, node));
+                noTag.add(new TagAndContext(tag, node));
             }
         }
 
@@ -310,7 +321,7 @@
         } else {
             nextTag = null;
         }
-        for (XMLParser.ElementContext it : elements(node)) {
+        for (ElementContext it : elements(node)) {
             nextBindingIndex = recurseReplace(it, lines, noTag, nextTag, nextBindingIndex);
         }
         return nextBindingIndex;
@@ -319,11 +330,14 @@
     private static String defaultReplacement(XMLParser.AttributeContext attr) {
         String textWithQuotes = attr.attrValue.getText();
         String escapedText = textWithQuotes.substring(1, textWithQuotes.length() - 1);
-        if (!escapedText.startsWith("@{") || !escapedText.endsWith("}")) {
+        final boolean isTwoWay = escapedText.startsWith("@={");
+        final boolean isOneWay = escapedText.startsWith("@{");
+        if ((!isTwoWay && !isOneWay) || !escapedText.endsWith("}")) {
             return null;
         }
-        String text = StringEscapeUtils
-                .unescapeXml(escapedText.substring(2, escapedText.length() - 1));
+        final int startIndex = isTwoWay ? 3 : 2;
+        final int endIndex = escapedText.length() - 1;
+        String text = StringUtils.unescapeXml(escapedText.substring(startIndex, endIndex));
         ANTLRInputStream inputStream = new ANTLRInputStream(text);
         BindingExpressionLexer lexer = new BindingExpressionLexer(inputStream);
         CommonTokenStream tokenStream = new CommonTokenStream(lexer);
@@ -342,12 +356,12 @@
                     if (doubleQuote != null) {
                         String quotedStr = doubleQuote.getText();
                         String unquoted = quotedStr.substring(1, quotedStr.length() - 1);
-                        return StringEscapeUtils.escapeXml10(unquoted);
+                        return XmlEscapers.xmlAttributeEscaper().escape(unquoted);
                     } else {
                         String quotedStr = stringLiteral.SingleQuoteString().getText();
                         String unquoted = quotedStr.substring(1, quotedStr.length() - 1);
                         String unescaped = unquoted.replace("\"", "\\\"").replace("\\`", "`");
-                        return StringEscapeUtils.escapeXml10(unescaped);
+                        return XmlEscapers.xmlAttributeEscaper().escape(unescaped);
                     }
                 }
             }
@@ -356,8 +370,8 @@
         return null;
     }
 
-    private static ImmutablePair<Position, Position> findTerminalPositions(
-            XMLParser.ElementContext node,  ArrayList<String> lines) {
+    private static PositionPair findTerminalPositions(ElementContext node,
+            ArrayList<String> lines) {
         Position endPosition = toEndPosition(node.getStop());
         Position startPosition = toPosition(node.getStop());
         int index;
@@ -368,7 +382,7 @@
         startPosition.line++;
         startPosition.charIndex = index;
         //noinspection unchecked
-        return new ImmutablePair<>(startPosition, endPosition);
+        return new PositionPair(startPosition, endPosition);
     }
 
     private static String replaceWithSpaces(String line, int start, int end) {
@@ -397,4 +411,31 @@
         }
     }
 
+    private static class TagAndContext {
+        private final String mTag;
+        private final ElementContext mElementContext;
+
+        private TagAndContext(String tag, ElementContext elementContext) {
+            mTag = tag;
+            mElementContext = elementContext;
+        }
+
+        private ElementContext getContext() {
+            return mElementContext;
+        }
+
+        private String getTag() {
+            return mTag;
+        }
+    }
+
+    private static class PositionPair {
+        private final Position left;
+        private final Position right;
+
+        private PositionPair(Position left, Position right) {
+            this.left = left;
+            this.right = right;
+        }
+    }
 }
diff --git a/data-binding.iml b/data-binding.iml
new file mode 100644
index 0000000..bebe401
--- /dev/null
+++ b/data-binding.iml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id="data-binding" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build" />
+    <output-test url="file://$MODULE_DIR$/build" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/dataBinding/dataBinding.iml b/dataBinding/dataBinding.iml
new file mode 100644
index 0000000..0d65182
--- /dev/null
+++ b/dataBinding/dataBinding.iml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":dataBinding" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="com.android.databinding" external.system.module.version="1.1" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/build" />
+    <output-test url="file://$MODULE_DIR$/build" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/databinding.properties b/databinding.properties
index 2a8a107..120a93e 100644
--- a/databinding.properties
+++ b/databinding.properties
@@ -1,11 +1,12 @@
 # global settings for projects
-kotlinVersion = 0.12.613
-version = 1.0-rc2-SNAPSHOT
-releaseVersion = 1.0-rc2-SNAPSHOT
-androidPluginVersion = 1.3.0-beta4
-javaTargetCompatibility = 1.7
-javaSourceCompatibility = 1.7
-
+kotlinVersion = 1.0.0-beta-4584
+extensionsVersion = 1.0-rc5
+# we use a public plugin so that it does not need data binding while compiling library
+androidPublicPluginVersion= 1.5.0
+javaTargetCompatibility = 1.6
+javaSourceCompatibility = 1.6
+buildToolsVersion = 22.0.1
+compileSdkVersionStr = 23
 prebuildFolderName=prebuilds
 group=com.android.databinding
 testGroup=com.android.databinding.test
@@ -19,6 +20,6 @@
 # mavenRepoAbsolutePath is /Volumes/ssd/src and mavenRepoName is maven-repo
 mavenRepoAbsolutePath=.
 mavenRepoName=maven-repo
-extraPluginsRepoName=plugins-repo
-extraPluginsVersion=1.0
-
+internalPrebuiltsRepoName=internal-prebuilts
+extraPluginsVersion=1.1
+androidGradlePluginOutRepo=out/repo
diff --git a/developmentPlugins/bintrayPlugin/gradle/wrapper/gradle-wrapper.jar b/developmentPlugins/bintrayPlugin/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 0087cd3..0000000
--- a/developmentPlugins/bintrayPlugin/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/developmentPlugins/bintrayPlugin/gradle/wrapper/gradle-wrapper.properties b/developmentPlugins/bintrayPlugin/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 72508b4..0000000
--- a/developmentPlugins/bintrayPlugin/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Fri Jul 10 10:59:20 PDT 2015
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/developmentPlugins/bintrayPlugin/gradlew b/developmentPlugins/bintrayPlugin/gradlew
deleted file mode 100755
index 91a7e26..0000000
--- a/developmentPlugins/bintrayPlugin/gradlew
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/env bash
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
-    echo "$*"
-}
-
-die ( ) {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-esac
-
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=$((i+1))
-    done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
-    JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/developmentPlugins/bintrayPlugin/gradlew.bat b/developmentPlugins/bintrayPlugin/gradlew.bat
deleted file mode 100644
index aec9973..0000000
--- a/developmentPlugins/bintrayPlugin/gradlew.bat
+++ /dev/null
@@ -1,90 +0,0 @@
-@if "%DEBUG%" == "" @echo off

-@rem ##########################################################################

-@rem

-@rem  Gradle startup script for Windows

-@rem

-@rem ##########################################################################

-

-@rem Set local scope for the variables with windows NT shell

-if "%OS%"=="Windows_NT" setlocal

-

-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

-set DEFAULT_JVM_OPTS=

-

-set DIRNAME=%~dp0

-if "%DIRNAME%" == "" set DIRNAME=.

-set APP_BASE_NAME=%~n0

-set APP_HOME=%DIRNAME%

-

-@rem Find java.exe

-if defined JAVA_HOME goto findJavaFromJavaHome

-

-set JAVA_EXE=java.exe

-%JAVA_EXE% -version >NUL 2>&1

-if "%ERRORLEVEL%" == "0" goto init

-

-echo.

-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

-echo.

-echo Please set the JAVA_HOME variable in your environment to match the

-echo location of your Java installation.

-

-goto fail

-

-:findJavaFromJavaHome

-set JAVA_HOME=%JAVA_HOME:"=%

-set JAVA_EXE=%JAVA_HOME%/bin/java.exe

-

-if exist "%JAVA_EXE%" goto init

-

-echo.

-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

-echo.

-echo Please set the JAVA_HOME variable in your environment to match the

-echo location of your Java installation.

-

-goto fail

-

-:init

-@rem Get command-line arguments, handling Windowz variants

-

-if not "%OS%" == "Windows_NT" goto win9xME_args

-if "%@eval[2+2]" == "4" goto 4NT_args

-

-:win9xME_args

-@rem Slurp the command line arguments.

-set CMD_LINE_ARGS=

-set _SKIP=2

-

-:win9xME_args_slurp

-if "x%~1" == "x" goto execute

-

-set CMD_LINE_ARGS=%*

-goto execute

-

-:4NT_args

-@rem Get arguments from the 4NT Shell from JP Software

-set CMD_LINE_ARGS=%$

-

-:execute

-@rem Setup the command line

-

-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

-

-@rem Execute Gradle

-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

-

-:end

-@rem End local scope for the variables with windows NT shell

-if "%ERRORLEVEL%"=="0" goto mainEnd

-

-:fail

-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

-rem the _cmd.exe /c_ return code!

-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

-exit /b 1

-

-:mainEnd

-if "%OS%"=="Windows_NT" endlocal

-

-:omega

diff --git a/developmentPlugins/bintrayPlugin/src/main/groovy/android/databinding/BintrayPlugin.groovy b/developmentPlugins/bintrayPlugin/src/main/groovy/android/databinding/BintrayPlugin.groovy
deleted file mode 100644
index fe9d1b1..0000000
--- a/developmentPlugins/bintrayPlugin/src/main/groovy/android/databinding/BintrayPlugin.groovy
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.databinding
-
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.publication.maven.internal.ant.DefaultGroovyMavenDeployer
-import org.gradle.api.tasks.Upload
-
-class BintrayPlugin implements Plugin<Project> {
-    public static final USER_PROP = "bintrayUser"
-    public static final API_KEY_PROP = "bintrayApiKey"
-    public static final DEFAULT_TASK_NAME = "uploadToBintray"
-
-    @Override
-    void apply(Project target) {
-        def taskName = DEFAULT_TASK_NAME
-        String user = target.getProperties().get(USER_PROP)
-        String apiKey = target.getProperties().get(API_KEY_PROP)
-        def uploadArchivesTask = target.tasks.findByName("uploadArchives")
-        if (uploadArchivesTask == null) {
-            throw new RuntimeException("Cannot find uploadArchives task in $target")
-        }
-        Upload uploadTask = uploadArchivesTask
-        def bintrayTask = target.tasks.create(taskName, UploadToBintrayTask, {
-            it.dependsOn uploadTask
-            it.apiKey = apiKey
-            it.username = user
-        })
-        target.afterEvaluate({
-            def mavenDeployerRepo = uploadTask.repositories.findByName("mavenDeployer")
-            if (mavenDeployerRepo == null) {
-                throw new RuntimeException("Cannot find maven deployer repository")
-            }
-            DefaultGroovyMavenDeployer mavenDeployer = mavenDeployerRepo
-            mavenDeployer.pom.whenConfigured({
-                bintrayTask.configureFrom(mavenDeployer)
-            })
-        })
-
-
-    }
-}
diff --git a/developmentPlugins/bintrayPlugin/src/main/groovy/android/databinding/UploadToBintrayTask.groovy b/developmentPlugins/bintrayPlugin/src/main/groovy/android/databinding/UploadToBintrayTask.groovy
deleted file mode 100644
index 0f1cc9a..0000000
--- a/developmentPlugins/bintrayPlugin/src/main/groovy/android/databinding/UploadToBintrayTask.groovy
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.databinding;
-
-import org.gradle.api.DefaultTask
-import org.gradle.api.artifacts.maven.MavenPom
-import org.gradle.api.file.FileCollection
-import org.gradle.api.publication.maven.internal.ant.DefaultGroovyMavenDeployer
-import org.gradle.api.tasks.Input;
-import org.gradle.api.tasks.TaskAction;
-import groovy.json.JsonSlurper;
-
-public class UploadToBintrayTask extends DefaultTask {
-    static final String API_URL = "https://api.bintray.com";
-    static final String PACKAGE_HEADER = "X-Bintray-Package"
-    static final String VERSION_HEADER = "X-Bintray-Version"
-    static final String PUBLISH_HEADER = "X-Bintray-Publish"
-    static final String OVERRIDE_HEADER = "X-Bintray-Override"
-    static final String EXPLODE_HEADER = "X-Bintray-Explode"
-    static final String CONTENT_PREFIX = "content/android/android-tools"
-    String username;
-    String apiKey;
-    String pkg;
-    String version;
-    FileCollection localFiles;
-    String mavenRepoAbsPath;
-    String targetPath;
-    public void configureFrom(DefaultGroovyMavenDeployer deployer) {
-        String repoUrl = deployer.repository.url
-        if (repoUrl == null) {
-            throw new RuntimeException("Cannot find repo url for $deployer")
-        }
-
-        def pom = deployer.pom
-        pkg = pom.groupId + "." + pom.artifactId
-        version = pom.version
-        mavenRepoAbsPath = repoUrl
-        targetPath = "${pkg.replaceAll("\\.", "/")}/${version}"
-        localFiles = project.fileTree(mavenRepoAbsPath + "/" + targetPath)
-    }
-    @TaskAction
-    public void upload() {
-        if (username == null || apiKey == null) {
-            throw new IllegalArgumentException("You should pass your bintray user and " +
-                    "api key as params e.g. ./gradlew ${BintrayPlugin.DEFAULT_TASK_NAME}" +
-                    " -P${BintrayPlugin.USER_PROP}=<my username>" +
-                    " -P${BintrayPlugin.API_KEY_PROP}=<my api key>")
-        }
-        println(log())
-        for (File localFile : localFiles) {
-            def p = ['curl', '-u', "$username:$apiKey", "-H",
-                     "$PACKAGE_HEADER: $pkg", "-H", "$VERSION_HEADER: $version",
-                     "-X", "PUT", "--data-binary", "@${localFile.getAbsolutePath()}",
-                     "$API_URL/$CONTENT_PREFIX/$targetPath/${localFile.name}"]
-            println("executing $p")
-            def execute = p.execute()
-            execute.waitFor()
-            if (execute.exitValue() != 0) {
-                throw new RuntimeException("failed to upload artifact. error: ${execute.err.text}")
-            }
-            def responseText = execute.text
-            def json = new JsonSlurper().parseText(responseText)
-            if (json.getAt("message") != "success") {
-                throw new RuntimeException("Cannot upload artifact. Error response: " +
-                        "${json.getAt("message")}")
-            }
-            println("uploaded $localFile")
-        }
-    }
-
-    public String log() {
-        return "UploadToBintrayTask{" +
-                "username='" + username + '\'' +
-                ", apiKey='" + apiKey + '\'' +
-                ", pkg='" + pkg + '\'' +
-                ", version='" + version + '\'' +
-                ", localFile=" + localFiles +
-                ", mavenRepo=" + mavenRepoAbsPath +
-                '}';
-    }
-}
diff --git a/developmentPlugins/bintrayPlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.bintray.properties b/developmentPlugins/bintrayPlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.bintray.properties
deleted file mode 100644
index 3cf2d8c..0000000
--- a/developmentPlugins/bintrayPlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.bintray.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-implementation-class=android.databinding.BintrayPlugin
\ No newline at end of file
diff --git a/developmentPlugins/build.gradle b/developmentPlugins/build.gradle
index a99d215..dd70646 100644
--- a/developmentPlugins/build.gradle
+++ b/developmentPlugins/build.gradle
@@ -1,13 +1,13 @@
-ext.rootFolder = "${project.projectDir}/.."
+ext.dataBindingRootFolder = "${project.projectDir}/.."
 apply from: '../propLoader.gradle'
 subprojects {
     apply plugin: 'maven'
-    group = config.group
-    version = config.extraPluginsVersion
+    group = dataBindingConfig.group
+    version = dataBindingConfig.extraPluginsVersion
     uploadArchives {
         repositories {
             mavenDeployer {
-                repository(url: "file://${config.extraPluginsRepoDir}")
+                repository(url: "file://${dataBindingConfig.internalPrebuiltsRepoDir}")
             }
         }
     }
diff --git a/developmentPlugins/gradle/wrapper/gradle-wrapper.properties b/developmentPlugins/gradle/wrapper/gradle-wrapper.properties
index c2fda82..2e3da3f 100644
--- a/developmentPlugins/gradle/wrapper/gradle-wrapper.properties
+++ b/developmentPlugins/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/developmentPlugins/localizeMavenPlugin/build.gradle b/developmentPlugins/localizeMavenPlugin/build.gradle
index 02d9b16..6b4c989 100644
--- a/developmentPlugins/localizeMavenPlugin/build.gradle
+++ b/developmentPlugins/localizeMavenPlugin/build.gradle
@@ -36,7 +36,6 @@
     repositories {
         mavenDeployer {
             pom.artifactId = 'localizemaven'
-            repository(url: "file://${config.extraPluginsRepoDir}")
         }
     }
 }
\ No newline at end of file
diff --git a/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/ExportLicensesTask.groovy b/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/ExportLicensesTask.groovy
index cf3ef59..4db1f39 100644
--- a/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/ExportLicensesTask.groovy
+++ b/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/ExportLicensesTask.groovy
@@ -24,7 +24,8 @@
 
     static def knownLicenses = [
             [
-                    libraries: ["kotlin-stdlib", "kotlin-runtime", "kotlin-annotation-processing", "kotlin-gradle-plugin", "kotlin-gradle-plugin-api"],
+                    libraries: ["kotlin-stdlib", "kotlin-runtime", "kotlin-annotation-processing", "kotlin-gradle-plugin", "kotlin-gradle-plugin-api",
+                    "kdoc", "kotlin-gradle-plugin-core", "kotlin-jdk-annotations", "kotlin-compiler", "kotlin-compiler-embeddable"],
                     licenses : ["https://raw.githubusercontent.com/JetBrains/kotlin/master/license/LICENSE.txt",
                                 "http://www.apache.org/licenses/LICENSE-2.0.txt"],
                     notices  : ["https://raw.githubusercontent.com/JetBrains/kotlin/master/license/NOTICE.txt"]
@@ -96,9 +97,12 @@
             ],
             [
                     libraries: ["logkit"],
-                    licenses: ["unknown. see: http://commons.apache.org/proper/commons-logging/dependencies.html"]
-            ]
-
+                    licenseText: ["unknown. see: http://commons.apache.org/proper/commons-logging/dependencies.html"]
+            ],
+            [
+                    libraries: ["juniversalchardet"],
+                    licenses: ["https://mozorg.cdn.mozilla.net/media/MPL/1.1/index.0c5913925d40.txt"]
+            ],
     ]
 
     Map<String, Object> usedLicenses = new HashMap<>();
@@ -121,12 +125,15 @@
 
     @TaskAction
     public void exportNotice() {
-        project.configurations.compile.getResolvedConfiguration().getResolvedArtifacts().each {
-            add(it)
+        project.configurations.compile.getResolvedConfiguration()
+                .getFirstLevelModuleDependencies().each {
+            if (!it.getModuleGroup().equals("com.android.tools.build")) {
+                it.getAllModuleArtifacts().each { add(it) }
+            }
         }
         resolveLicenses()
         def notice = buildNotice(usedLicenses)
-        def noticeFile = new File(project.buildDir,'NOTICE.txt')
+        def noticeFile = new File("${project.projectDir}/src/main/resources",'NOTICE.txt')
         noticeFile.delete()
         println ("writing notice file to: ${noticeFile.getAbsolutePath()}")
         noticeFile << notice
@@ -149,8 +156,7 @@
     }
 
     public static String urlToText(String url) {
-        //return new URL(url).getText()
-        return url
+        return new URL(url).getText()
     }
 
     public boolean shouldSkip(ResolvedArtifact artifact) {
@@ -174,6 +180,9 @@
             license.licenses.each {
                 notice.append("\n ****** LICENSE:\n${urlToText(it)}")
             }
+            license.licenseText.each {
+                notice.append("\n ****** LICENSE:\n${it}")
+            }
             notice.append("\n\n\n")
         }
         return notice.toString()
diff --git a/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/LocalizeDependenciesTask.groovy b/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/LocalizeDependenciesTask.groovy
index a9e8d05..a14fabc 100644
--- a/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/LocalizeDependenciesTask.groovy
+++ b/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/LocalizeDependenciesTask.groovy
@@ -46,6 +46,12 @@
 
     private Set<String> fetchTestDependencies = new HashSet<>();
 
+    // force download these if they are seen as a dependency
+    private Set<String>  wildCard = new HashSet<>();
+    {
+        wildCard.add("kotlin-gradle-plugin-core")
+    }
+
     List<Artifact> artifactsToResolve = new LinkedList<>();
 
     Set<String> resolvedArtifacts = new HashSet<>();
@@ -64,9 +70,14 @@
         LocalizePluginExtension extension = project.extensions.
                 getByName(MavenDependencyCollectorPlugin.EXTENSION_NAME)
         if (extension.localRepoDir == null || extension.otherRepoDirs == null) {
-            throw new IllegalArgumentException("you must configure " +
+
+            def msg = "you must configure " +
                     "${MavenDependencyCollectorPlugin.EXTENSION_NAME} with localRepoDir and" +
-                    " otherRepoDirs")
+                    " otherRepoDirs. localRepoDir: " + extension.localRepoDir +
+                    "\notherRepoDir:" + extension.otherRepoDirs;
+            println(msg)
+            println("skipping ${project}")
+            return
         }
         localRepoDir = extension.localRepoDir
         downloadAll(extension.localRepoDir, extension.otherRepoDirs)
@@ -205,10 +216,10 @@
                 continue
             }
             if ("test".equals(dependency.scope)) {
-                if (fetchTestDependencies.contains(key)) {
+                if (wildCard.contains(dependency.artifact.getArtifactId()) || fetchTestDependencies.contains(key)) {
                     println("${dependency} is test scope but including because $key is in direct dependencies")
                 } else {
-                    println("skipping $dependency because test and not first level dependency")
+                    println("skipping $dependency because test and $key is not first level dependency. artifact id: ${dependency.artifact.getArtifactId()}")
                     continue
                 }
             }
diff --git a/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/MavenDependencyCollectorPlugin.groovy b/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/MavenDependencyCollectorPlugin.groovy
index c3a318d..0fd805d 100644
--- a/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/MavenDependencyCollectorPlugin.groovy
+++ b/developmentPlugins/localizeMavenPlugin/src/main/groovy/android/databinding/MavenDependencyCollectorPlugin.groovy
@@ -24,7 +24,7 @@
     static final String EXTENSION_NAME = "localizeMaven"
     @Override
     void apply(Project project) {
-        Project parent = project.parent == null ? project : project.parent;
+        Project parent = project.getRootProject();
         def localizeDependenciesTask = parent.tasks.findByName(DEFAULT_TASK_NAME)
         if (localizeDependenciesTask == null) {
             localizeDependenciesTask = parent.tasks.
@@ -34,11 +34,12 @@
 
         project.allprojects {
             afterEvaluate { p ->
-                project.tasks.create("collectDependenciesOf${it.getName().capitalize()}", MavenDependencyCollectorTask, {
-                    it.localizeTask = localizeDependenciesTask
-                    localizeDependenciesTask.dependsOn it
-                })
-
+                if (!p.name.equals("dataBinding")) {
+                    project.tasks.create("collectDependenciesOf${it.getName().capitalize()}", MavenDependencyCollectorTask, {
+                        it.localizeTask = localizeDependenciesTask
+                        localizeDependenciesTask.dependsOn it
+                    })
+                }
             }
         }
         project.tasks.create("buildLicenseNotice", ExportLicensesTask) {
diff --git a/extensions/baseAdapters/build.gradle b/extensions/baseAdapters/build.gradle
index 9450d42..d375aeb 100644
--- a/extensions/baseAdapters/build.gradle
+++ b/extensions/baseAdapters/build.gradle
@@ -13,18 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+buildscript {
+    dependencies {
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
 apply plugin: 'com.android.library'
-project.ext.addDataBindingAdapters = false
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "21.1.2"
-
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
+    dataBinding {
+        enabled = true
+        addDefaultAdapters = false
+    }
     defaultConfig {
         minSdkVersion 7
-        targetSdkVersion 21
+        targetSdkVersion 23
         versionCode 1
         versionName "1.0"
     }
@@ -81,14 +88,13 @@
 uploadArchives {
     repositories {
         mavenDeployer {
-            repository(url: "file://${config.mavenRepoDir}")
             pom.artifactId = "adapters"
             pom.project {
                 licenses {
                     license {
-                        name config.licenseName
-                        url config.licenseUrl
-                        distribution config.licenseDistribution
+                        name dataBindingConfig.licenseName
+                        url dataBindingConfig.licenseUrl
+                        distribution dataBindingConfig.licenseDistribution
                     }
                 }
             }
@@ -100,7 +106,7 @@
 task prebuild(type : Copy) {
     dependsOn uploadArchives
     from "$buildDir/outputs/aar/baseAdapters-release.aar"
-    into config.prebuildFolder
+    into dataBindingConfig.prebuildFolder
     rename { String fileName ->
         "databinding-adapters.aar"
     }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsListViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsListViewBindingAdapter.java
index 50851ac..d2166ff 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsListViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsListViewBindingAdapter.java
@@ -29,17 +29,8 @@
 })
 public class AbsListViewBindingAdapter {
 
-    @BindingAdapter("android:onScroll")
-    public static void setOnScroll(AbsListView view, OnScroll listener) {
-        setOnScroll(view, listener, null);
-    }
-
-    @BindingAdapter("android:onScrollStateChanged")
-    public static void setOnScroll(AbsListView view, OnScrollStateChanged listener) {
-        setOnScroll(view, null, listener);
-    }
-
-    @BindingAdapter({"android:onScroll", "android:onScrollStateChanged"})
+    @BindingAdapter(value = {"android:onScroll", "android:onScrollStateChanged"},
+            requireAll = false)
     public static void setOnScroll(AbsListView view, final OnScroll scrollListener,
             final OnScrollStateChanged scrollStateListener) {
         view.setOnScrollListener(new OnScrollListener() {
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsSpinnerBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsSpinnerBindingAdapter.java
index 1dc6974..2948c03 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsSpinnerBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AbsSpinnerBindingAdapter.java
@@ -20,10 +20,12 @@
 import android.widget.ArrayAdapter;
 import android.widget.SpinnerAdapter;
 
+import java.util.List;
+
 public class AbsSpinnerBindingAdapter {
 
     @BindingAdapter({"android:entries"})
-    public static void setEntries(AbsSpinner view, CharSequence[] entries) {
+    public static <T extends CharSequence> void setEntries(AbsSpinner view, T[] entries) {
         if (entries != null) {
             SpinnerAdapter oldAdapter = view.getAdapter();
             boolean changed = true;
@@ -47,4 +49,20 @@
             view.setAdapter(null);
         }
     }
+
+    @BindingAdapter({"android:entries"})
+    public static <T> void setEntries(AbsSpinner view, List<T> entries) {
+        if (entries != null) {
+            SpinnerAdapter oldAdapter = view.getAdapter();
+            if (oldAdapter instanceof ObservableListAdapter) {
+                ((ObservableListAdapter) oldAdapter).setList(entries);
+            } else {
+                view.setAdapter(new ObservableListAdapter<T>(view.getContext(), entries,
+                        android.R.layout.simple_spinner_item,
+                        android.R.layout.simple_spinner_dropdown_item, 0));
+            }
+        } else {
+            view.setAdapter(null);
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AdapterViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AdapterViewBindingAdapter.java
index ad85d79..5e51913 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AdapterViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AdapterViewBindingAdapter.java
@@ -18,7 +18,11 @@
 import android.databinding.BindingAdapter;
 import android.databinding.BindingMethod;
 import android.databinding.BindingMethods;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
 import android.view.View;
+import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 
@@ -26,43 +30,50 @@
         @BindingMethod(type = AdapterView.class, attribute = "android:onItemClick", method = "setOnItemClickListener"),
         @BindingMethod(type = AdapterView.class, attribute = "android:onItemLongClick", method = "setOnItemLongClickListener"),
 })
+@InverseBindingMethods({
+        @InverseBindingMethod(type = AbsListView.class, attribute = "android:selectedItemPosition"),
+})
 public class AdapterViewBindingAdapter {
 
-    @BindingAdapter("android:onItemSelected")
-    public static void setListener(AdapterView view, OnItemSelected listener) {
-        setListener(view, listener, null);
+    @BindingAdapter("android:selectedItemPosition")
+    public static void setSelectedItemPosition(AdapterView view, int position) {
+        if (view.getSelectedItemPosition() != position) {
+            view.setSelection(position);
+        }
     }
 
-    @BindingAdapter("android:onNothingSelected")
-    public static void setListener(AdapterView view, OnNothingSelected listener) {
-        setListener(view, null, listener);
-    }
-
-    @BindingAdapter({"android:onItemSelected", "android:onNothingSelected"})
-    public static void setListener(AdapterView view, final OnItemSelected selected,
-            final OnNothingSelected nothingSelected) {
-        if (selected == null && nothingSelected == null) {
+    @BindingAdapter(value = {"android:onItemSelected", "android:onNothingSelected",
+            "android:selectedItemPositionAttrChanged"}, requireAll = false)
+    public static void setOnItemSelectedListener(AdapterView view, final OnItemSelected selected,
+            final OnNothingSelected nothingSelected, final InverseBindingListener attrChanged) {
+        if (selected == null && nothingSelected == null && attrChanged == null) {
             view.setOnItemSelectedListener(null);
         } else {
             view.setOnItemSelectedListener(
-                    new OnItemSelectedComponentListener(selected, nothingSelected));
+                    new OnItemSelectedComponentListener(selected, nothingSelected, attrChanged));
         }
     }
 
     public static class OnItemSelectedComponentListener implements OnItemSelectedListener {
         private final OnItemSelected mSelected;
         private final OnNothingSelected mNothingSelected;
+        private final InverseBindingListener mAttrChanged;
 
         public OnItemSelectedComponentListener(OnItemSelected selected,
-                OnNothingSelected nothingSelected) {
+                OnNothingSelected nothingSelected, InverseBindingListener attrChanged) {
             this.mSelected = selected;
             this.mNothingSelected = nothingSelected;
+            this.mAttrChanged = attrChanged;
         }
+
         @Override
         public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
             if (mSelected != null) {
                 mSelected.onItemSelected(parent, view, position, id);
             }
+            if (mAttrChanged != null) {
+                mAttrChanged.onChange();
+            }
         }
 
         @Override
@@ -70,6 +81,9 @@
             if (mNothingSelected != null) {
                 mNothingSelected.onNothingSelected(parent);
             }
+            if (mAttrChanged != null) {
+                mAttrChanged.onChange();
+            }
         }
     }
 
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AutoCompleteTextViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AutoCompleteTextViewBindingAdapter.java
index 72f465e..ebcd118 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/AutoCompleteTextViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/AutoCompleteTextViewBindingAdapter.java
@@ -32,18 +32,8 @@
 })
 public class AutoCompleteTextViewBindingAdapter {
 
-    @BindingAdapter("android:fixText")
-    public static void setListener(AutoCompleteTextView view, FixText listener) {
-        setListener(view, listener, null);
-    }
-
-    @BindingAdapter("android:isValid")
-    public static void setListener(AutoCompleteTextView view, IsValid listener) {
-        setListener(view, null, listener);
-    }
-
-    @BindingAdapter({"android:fixText", "android:isValid"})
-    public static void setListener(AutoCompleteTextView view, final FixText fixText,
+    @BindingAdapter(value = {"android:fixText", "android:isValid"}, requireAll = false)
+    public static void setValidator(AutoCompleteTextView view, final FixText fixText,
             final IsValid isValid) {
         if (fixText == null && isValid == null) {
             view.setValidator(null);
@@ -70,24 +60,15 @@
         }
     }
 
-    @BindingAdapter("android:onItemSelected")
-    public static void setListener(AutoCompleteTextView view, OnItemSelected listener) {
-        setListener(view, listener, null);
-    }
-
-    @BindingAdapter("android:onNothingSelected")
-    public static void setListener(AutoCompleteTextView view, OnNothingSelected listener) {
-        setListener(view, null, listener);
-    }
-
-    @BindingAdapter({"android:onItemSelected", "android:onNothingSelected"})
-    public static void setListener(AutoCompleteTextView view, final OnItemSelected selected,
-            final OnNothingSelected nothingSelected) {
+    @BindingAdapter(value = {"android:onItemSelected", "android:onNothingSelected"},
+            requireAll = false)
+    public static void setOnItemSelectedListener(AutoCompleteTextView view,
+            final OnItemSelected selected, final OnNothingSelected nothingSelected) {
         if (selected == null && nothingSelected == null) {
             view.setOnItemSelectedListener(null);
         } else {
             view.setOnItemSelectedListener(
-                    new OnItemSelectedComponentListener(selected, nothingSelected));
+                    new OnItemSelectedComponentListener(selected, nothingSelected, null));
         }
     }
 
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/CalendarViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/CalendarViewBindingAdapter.java
index fc7fb2f..f17fd7d 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/CalendarViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/CalendarViewBindingAdapter.java
@@ -15,12 +15,41 @@
  */
 package android.databinding.adapters;
 
-import android.databinding.BindingMethod;
-import android.databinding.BindingMethods;
+import android.databinding.BindingAdapter;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
 import android.widget.CalendarView;
+import android.widget.CalendarView.OnDateChangeListener;
 
-@BindingMethods({
-        @BindingMethod(type = CalendarView.class, attribute = "android:onSelectedDayChange", method = "setOnDateChangeListener"),
+@InverseBindingMethods({
+        @InverseBindingMethod(type = CalendarView.class, attribute = "android:date"),
 })
 public class CalendarViewBindingAdapter {
+    @BindingAdapter("android:date")
+    public static void setDate(CalendarView view, long date) {
+        if (view.getDate() != date) {
+            view.setDate(date);
+        }
+    }
+
+    @BindingAdapter(value = {"android:onSelectedDayChange", "android:dateAttrChanged"},
+            requireAll = false)
+    public static void setListeners(CalendarView view, final OnDateChangeListener onDayChange,
+            final InverseBindingListener attrChange) {
+        if (attrChange == null) {
+            view.setOnDateChangeListener(onDayChange);
+        } else {
+            view.setOnDateChangeListener(new OnDateChangeListener() {
+                @Override
+                public void onSelectedDayChange(CalendarView view, int year, int month,
+                        int dayOfMonth) {
+                    if (onDayChange != null) {
+                        onDayChange.onSelectedDayChange(view, year, month, dayOfMonth);
+                    }
+                    attrChange.onChange();
+                }
+            });
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/CompoundButtonBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/CompoundButtonBindingAdapter.java
index 3859019..15c5d00 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/CompoundButtonBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/CompoundButtonBindingAdapter.java
@@ -18,6 +18,9 @@
 import android.databinding.BindingAdapter;
 import android.databinding.BindingMethod;
 import android.databinding.BindingMethods;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 
@@ -25,5 +28,35 @@
         @BindingMethod(type = CompoundButton.class, attribute = "android:buttonTint", method = "setButtonTintList"),
         @BindingMethod(type = CompoundButton.class, attribute = "android:onCheckedChanged", method = "setOnCheckedChangeListener"),
 })
+@InverseBindingMethods({
+        @InverseBindingMethod(type = CompoundButton.class, attribute = "android:checked"),
+})
 public class CompoundButtonBindingAdapter {
+
+    @BindingAdapter("android:checked")
+    public static void setChecked(CompoundButton view, boolean checked) {
+        if (view.isChecked() != checked) {
+            view.setChecked(checked);
+        }
+    }
+
+    @BindingAdapter(value = {"android:onCheckedChanged", "android:checkedAttrChanged"},
+            requireAll = false)
+    public static void setListeners(CompoundButton view, final OnCheckedChangeListener listener,
+            final InverseBindingListener attrChange) {
+        if (attrChange == null) {
+            view.setOnCheckedChangeListener(listener);
+        } else {
+            view.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+                @Override
+                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                    if (listener != null) {
+                        listener.onCheckedChanged(buttonView, isChecked);
+                    }
+                    attrChange.onChange();
+                }
+            });
+        }
+    }
+
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/DatePickerBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/DatePickerBindingAdapter.java
new file mode 100644
index 0000000..abf345d
--- /dev/null
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/DatePickerBindingAdapter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.adapters;
+
+import android.databinding.BindingAdapter;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
+import android.widget.DatePicker;
+import android.widget.DatePicker.OnDateChangedListener;
+import com.android.databinding.library.baseAdapters.R;
+
+@InverseBindingMethods({
+        @InverseBindingMethod(type = DatePicker.class, attribute = "android:year"),
+        @InverseBindingMethod(type = DatePicker.class, attribute = "android:month"),
+        @InverseBindingMethod(type = DatePicker.class, attribute = "android:day", method = "getDayOfMonth"),
+})
+public class DatePickerBindingAdapter {
+    @BindingAdapter(value = {"android:year", "android:month", "android:day",
+            "android:onDateChanged", "android:yearAttrChanged",
+            "android:monthAttrChanged", "android:dayAttrChanged"}, requireAll = false)
+    public static void setListeners(DatePicker view, int year, int month, int day,
+            final OnDateChangedListener listener, final InverseBindingListener yearChanged,
+            final InverseBindingListener monthChanged, final InverseBindingListener dayChanged) {
+        if (year == 0) {
+            year = view.getYear();
+        }
+        if (day == 0) {
+            day = view.getDayOfMonth();
+        }
+        if (yearChanged == null && monthChanged == null && dayChanged == null) {
+            view.init(year, month, day, listener);
+        } else {
+            DateChangedListener oldListener = ListenerUtil.getListener(view, R.id.onDateChanged);
+            if (oldListener == null) {
+                oldListener = new DateChangedListener();
+                ListenerUtil.trackListener(view, oldListener, R.id.onDateChanged);
+            }
+            oldListener.setListeners(listener, yearChanged, monthChanged, dayChanged);
+            view.init(year, month, day, oldListener);
+        }
+    }
+
+    private static class DateChangedListener implements OnDateChangedListener {
+        OnDateChangedListener mListener;
+        InverseBindingListener mYearChanged;
+        InverseBindingListener mMonthChanged;
+        InverseBindingListener mDayChanged;
+
+        public void setListeners(OnDateChangedListener listener, InverseBindingListener yearChanged,
+                InverseBindingListener monthChanged, InverseBindingListener dayChanged) {
+            mListener = listener;
+            mYearChanged = yearChanged;
+            mMonthChanged = monthChanged;
+            mDayChanged = dayChanged;
+        }
+
+        @Override
+        public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
+            if (mListener != null) {
+                mListener.onDateChanged(view, year, monthOfYear, dayOfMonth);
+            }
+            if (mYearChanged != null) {
+                mYearChanged.onChange();
+            }
+            if (mMonthChanged != null) {
+                mMonthChanged.onChange();
+            }
+            if (mDayChanged != null) {
+                mDayChanged.onChange();
+            }
+        }
+    }
+}
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ImageViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ImageViewBindingAdapter.java
index 5236d8d..abf5dfb 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ImageViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ImageViewBindingAdapter.java
@@ -42,7 +42,7 @@
     }
 
     @BindingAdapter("android:src")
-    public static void setImageUri(ImageView view, Drawable drawable) {
+    public static void setImageDrawable(ImageView view, Drawable drawable) {
         view.setImageDrawable(drawable);
     }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ListenerUtil.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ListenerUtil.java
index 9643be2..6869cdb 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ListenerUtil.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ListenerUtil.java
@@ -25,7 +25,7 @@
 
 public class ListenerUtil {
     private static SparseArray<WeakHashMap<View, WeakReference<?>>> sListeners =
-            new SparseArray<>();
+            new SparseArray<WeakHashMap<View, WeakReference<?>>>();
 
     /**
      * This method tracks listeners for a View. Only one listener per listenerResourceId
@@ -61,7 +61,7 @@
             synchronized (sListeners) {
                 WeakHashMap<View, WeakReference<?>> listeners = sListeners.get(listenerResourceId);
                 if (listeners == null) {
-                    listeners = new WeakHashMap<>();
+                    listeners = new WeakHashMap<View, WeakReference<?>>();
                     sListeners.put(listenerResourceId, listeners);
                 }
                 final WeakReference<T> oldValue;
@@ -79,4 +79,31 @@
         }
     }
 
+    /**
+     * Returns the previous value for a listener if one was stored previously with
+     * {@link #trackListener(View, Object, int)}
+     * @param view The View to check for a listener previously stored with
+     * {@link #trackListener(View, Object, int)}
+     * @param listenerResourceId A unique resource ID associated with the listener type.
+     * @return The previously tracked listener. This will be null if the View did not have
+     * a previously-tracked listener.
+     */
+    public static <T> T getListener(View view, int listenerResourceId) {
+        if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return (T) view.getTag(listenerResourceId);
+        } else {
+            synchronized (sListeners) {
+                WeakHashMap<View, WeakReference<?>> listeners = sListeners.get(listenerResourceId);
+                if (listeners == null) {
+                    return null;
+                }
+                final WeakReference<T> oldValue = (WeakReference<T>) listeners.get(view);
+                if (oldValue == null) {
+                    return null;
+                } else {
+                    return oldValue.get();
+                }
+            }
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/NumberPickerBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/NumberPickerBindingAdapter.java
index 17e53cd..612b320 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/NumberPickerBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/NumberPickerBindingAdapter.java
@@ -15,14 +15,49 @@
  */
 package android.databinding.adapters;
 
+import android.databinding.BindingAdapter;
 import android.databinding.BindingMethod;
 import android.databinding.BindingMethods;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.NumberPicker;
+import android.widget.NumberPicker.OnValueChangeListener;
 
 @BindingMethods({
         @BindingMethod(type = NumberPicker.class, attribute = "android:format", method = "setFormatter"),
         @BindingMethod(type = NumberPicker.class, attribute = "android:onScrollStateChange", method = "setOnScrollListener"),
-        @BindingMethod(type = NumberPicker.class, attribute = "android:onValueChange", method = "setOnValueChangedListener"),
+})
+@InverseBindingMethods({
+        @InverseBindingMethod(type = NumberPicker.class, attribute = "android:value"),
 })
 public class NumberPickerBindingAdapter {
+
+    @BindingAdapter("android:value")
+    public static void setValue(NumberPicker view, int value) {
+        if (view.getValue() != value) {
+            view.setValue(value);
+        }
+    }
+
+    @BindingAdapter(value = {"android:onValueChange", "android:valueAttrChanged"},
+            requireAll = false)
+    public static void setListeners(NumberPicker view, final OnValueChangeListener listener,
+            final InverseBindingListener attrChange) {
+        if (attrChange == null) {
+            view.setOnValueChangedListener(listener);
+        } else {
+            view.setOnValueChangedListener(new OnValueChangeListener() {
+                @Override
+                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                    if (listener != null) {
+                        listener.onValueChange(picker, oldVal, newVal);
+                    }
+                    attrChange.onChange();
+                }
+            });
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ObservableListAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ObservableListAdapter.java
new file mode 100644
index 0000000..93f76a9
--- /dev/null
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ObservableListAdapter.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.adapters;
+
+import android.content.Context;
+import android.databinding.ObservableList;
+import android.databinding.ObservableList.OnListChangedCallback;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.List;
+
+class ObservableListAdapter<T> extends BaseAdapter {
+    private List<T> mList;
+    private ObservableList.OnListChangedCallback mListChangedCallback;
+    private final Context mContext;
+    private final int mDropDownResourceId;
+    private final int mResourceId;
+    private final int mTextViewResourceId;
+    private final LayoutInflater mLayoutInflater;
+
+    public ObservableListAdapter(Context context, List<T> list, int resourceId,
+            int dropDownResourceId, int textViewResourceId) {
+        mContext = context;
+        mResourceId = resourceId;
+        mDropDownResourceId = dropDownResourceId;
+        mTextViewResourceId = textViewResourceId;
+        mLayoutInflater = (resourceId == 0) ? null :
+                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        setList(list);
+    }
+
+    public void setList(List<T> list) {
+        if (mList == list) {
+            return;
+        }
+        if (mList instanceof ObservableList) {
+            ((ObservableList) mList).removeOnListChangedCallback(mListChangedCallback);
+        }
+        mList = list;
+        if (mList instanceof ObservableList) {
+            if (mListChangedCallback == null) {
+                mListChangedCallback = new OnListChangedCallback() {
+                    @Override
+                    public void onChanged(ObservableList observableList) {
+                        notifyDataSetChanged();
+                    }
+
+                    @Override
+                    public void onItemRangeChanged(ObservableList observableList, int i,
+                            int i1) {
+                        notifyDataSetChanged();
+                    }
+
+                    @Override
+                    public void onItemRangeInserted(ObservableList observableList, int i,
+                            int i1) {
+                        notifyDataSetChanged();
+                    }
+
+                    @Override
+                    public void onItemRangeMoved(ObservableList observableList, int i, int i1,
+                            int i2) {
+                        notifyDataSetChanged();
+                    }
+
+                    @Override
+                    public void onItemRangeRemoved(ObservableList observableList, int i,
+                            int i1) {
+                        notifyDataSetChanged();
+                    }
+                };
+            }
+            ((ObservableList) mList).addOnListChangedCallback(mListChangedCallback);
+        }
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public int getCount() {
+        return mList.size();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mList.get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        return getViewForResource(mResourceId, position, convertView, parent);
+    }
+
+    @Override
+    public View getDropDownView(int position, View convertView, ViewGroup parent) {
+        return getViewForResource(mDropDownResourceId, position, convertView, parent);
+    }
+
+    public View getViewForResource(int resourceId, int position, View convertView,
+            ViewGroup parent) {
+        if (convertView == null) {
+            if (resourceId == 0) {
+                convertView = new TextView(mContext);
+            } else {
+                convertView = mLayoutInflater.inflate(resourceId, parent, false);
+            }
+        }
+        TextView text = (TextView) (mTextViewResourceId == 0 ? convertView :
+                convertView.findViewById(mTextViewResourceId));
+        T item = mList.get(position);
+        CharSequence value;
+        if (item instanceof CharSequence) {
+            value = (CharSequence) item;
+        } else {
+            value = String.valueOf(item);
+        }
+        text.setText(value);
+        return convertView;
+    }
+}
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/RadioGroupBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/RadioGroupBindingAdapter.java
index af9f042..a84a691 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/RadioGroupBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/RadioGroupBindingAdapter.java
@@ -15,13 +15,41 @@
  */
 package android.databinding.adapters;
 
-import android.databinding.BindingMethod;
-import android.databinding.BindingMethods;
+import android.databinding.BindingAdapter;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
 import android.widget.RadioGroup;
+import android.widget.RadioGroup.OnCheckedChangeListener;
 
-@BindingMethods({
-        @BindingMethod(type = RadioGroup.class, attribute = "android:checkedButton", method = "check"),
-        @BindingMethod(type = RadioGroup.class, attribute = "android:onCheckedChanged", method = "setOnCheckedChangeListener"),
+@InverseBindingMethods({
+        @InverseBindingMethod(type = RadioGroup.class, attribute = "android:checkedButton", method = "getCheckedRadioButtonId"),
 })
 public class RadioGroupBindingAdapter {
+    @BindingAdapter("android:checkedButton")
+    public static void setCheckedButton(RadioGroup view, int id) {
+        if (id != view.getCheckedRadioButtonId()) {
+            view.check(id);
+        }
+    }
+
+    @BindingAdapter(value = {"android:onCheckedChanged", "android:checkedButtonAttrChanged"},
+            requireAll = false)
+    public static void setListeners(RadioGroup view, final OnCheckedChangeListener listener,
+            final InverseBindingListener attrChange) {
+        if (attrChange == null) {
+            view.setOnCheckedChangeListener(listener);
+        } else {
+            view.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+                @Override
+                public void onCheckedChanged(RadioGroup group, int checkedId) {
+                    if (listener != null) {
+                        listener.onCheckedChanged(group, checkedId);
+                    }
+
+                    attrChange.onChange();
+                }
+            });
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/RatingBarBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/RatingBarBindingAdapter.java
index 5e49c72..4896df0 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/RatingBarBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/RatingBarBindingAdapter.java
@@ -15,12 +15,40 @@
  */
 package android.databinding.adapters;
 
-import android.databinding.BindingMethod;
-import android.databinding.BindingMethods;
+import android.databinding.BindingAdapter;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
 import android.widget.RatingBar;
+import android.widget.RatingBar.OnRatingBarChangeListener;
 
-@BindingMethods({
-        @BindingMethod(type = RatingBar.class, attribute = "android:onRatingChanged", method = "setOnRatingBarChangeListener"),
+@InverseBindingMethods({
+        @InverseBindingMethod(type = RatingBar.class, attribute = "android:rating"),
 })
 public class RatingBarBindingAdapter {
+    @BindingAdapter("android:rating")
+    public static void setRating(RatingBar view, float rating) {
+        if (view.getRating() != rating) {
+            view.setRating(rating);
+        }
+    }
+
+    @BindingAdapter(value = {"android:onRatingChanged", "android:ratingAttrChanged"},
+            requireAll = false)
+    public static void setListeners(RatingBar view, final OnRatingBarChangeListener listener,
+            final InverseBindingListener ratingChange) {
+        if (ratingChange == null) {
+            view.setOnRatingBarChangeListener(listener);
+        } else {
+            view.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
+                @Override
+                public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
+                    if (listener != null) {
+                        listener.onRatingChanged(ratingBar, rating, fromUser);
+                    }
+                    ratingChange.onChange();
+                }
+            });
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/SearchViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/SearchViewBindingAdapter.java
index 25ddcf8..64d7270 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/SearchViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/SearchViewBindingAdapter.java
@@ -19,12 +19,9 @@
 import android.databinding.BindingAdapter;
 import android.databinding.BindingMethod;
 import android.databinding.BindingMethods;
-import android.os.Build;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
-import android.widget.RatingBar;
 import android.widget.SearchView;
-import android.widget.SearchView.OnCloseListener;
 import android.widget.SearchView.OnQueryTextListener;
 import android.widget.SearchView.OnSuggestionListener;
 
@@ -34,18 +31,9 @@
         @BindingMethod(type = SearchView.class, attribute = "android:onClose", method = "setOnCloseListener"),
 })
 public class SearchViewBindingAdapter {
-    @BindingAdapter("android:onQueryTextChange")
-    public static void setListener(SearchView view, OnQueryTextChange listener) {
-        setListener(view, null, listener);
-    }
-
-    @BindingAdapter("android:onQueryTextSubmit")
-    public static void setListener(SearchView view, OnQueryTextSubmit listener) {
-        setListener(view, listener, null);
-    }
-
-    @BindingAdapter({"android:onQueryTextSubmit", "android:onQueryTextChange"})
-    public static void setListener(SearchView view, final OnQueryTextSubmit submit,
+    @BindingAdapter(value = {"android:onQueryTextSubmit", "android:onQueryTextChange"},
+            requireAll = false)
+    public static void setOnQueryTextListener(SearchView view, final OnQueryTextSubmit submit,
             final OnQueryTextChange change) {
         if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
             if (submit == null && change == null){
@@ -74,18 +62,9 @@
         }
     }
 
-    @BindingAdapter("android:onSuggestionClick")
-    public static void setListener(SearchView view, OnSuggestionClick listener) {
-        setListener(view, null, listener);
-    }
-
-    @BindingAdapter("android:onSuggestionSelect")
-    public static void setListener(SearchView view, OnSuggestionSelect listener) {
-        setListener(view, listener, null);
-    }
-
-    @BindingAdapter({"android:onSuggestionSelect", "android:onSuggestionClick"})
-    public static void setListener(SearchView view, final OnSuggestionSelect submit,
+    @BindingAdapter(value = {"android:onSuggestionSelect", "android:onSuggestionClick"},
+            requireAll = false)
+    public static void setOnSuggestListener(SearchView view, final OnSuggestionSelect submit,
             final OnSuggestionClick change) {
         if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
             if (submit == null && change == null) {
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/SeekBarBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/SeekBarBindingAdapter.java
index eeac77c..625c037 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/SeekBarBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/SeekBarBindingAdapter.java
@@ -16,47 +16,30 @@
 package android.databinding.adapters;
 
 import android.databinding.BindingAdapter;
+import android.databinding.InverseBindingListener;
+import android.databinding.InverseBindingMethod;
+import android.databinding.InverseBindingMethods;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
+@InverseBindingMethods({
+        @InverseBindingMethod(type = SeekBar.class, attribute = "android:progress"),
+})
 public class SeekBarBindingAdapter {
-    @BindingAdapter("android:onProgressChanged")
-    public static void setListener(SeekBar view, OnProgressChanged listener) {
-        setListener(view, null, null, listener);
+
+    @BindingAdapter("android:progress")
+    public static void setProgress(SeekBar view, int progress) {
+        if (progress != view.getProgress()) {
+            view.setProgress(progress);
+        }
     }
 
-    @BindingAdapter("android:onStartTrackingTouch")
-    public static void setListener(SeekBar view, OnStartTrackingTouch listener) {
-        setListener(view, listener, null, null);
-    }
-
-    @BindingAdapter("android:onStopTrackingTouch")
-    public static void setListener(SeekBar view, OnStopTrackingTouch listener) {
-        setListener(view, null, listener, null);
-    }
-
-    @BindingAdapter({"android:onStartTrackingTouch", "android:onStopTrackingTouch"})
-    public static void setListener(SeekBar view, final OnStartTrackingTouch start,
-            final OnStopTrackingTouch stop) {
-        setListener(view, start, stop, null);
-    }
-
-    @BindingAdapter({"android:onStartTrackingTouch", "android:onProgressChanged"})
-    public static void setListener(SeekBar view, final OnStartTrackingTouch start,
-            final OnProgressChanged progressChanged) {
-        setListener(view, start, null, progressChanged);
-    }
-
-    @BindingAdapter({"android:onStopTrackingTouch", "android:onProgressChanged"})
-    public static void setListener(SeekBar view, final OnStopTrackingTouch stop,
-            final OnProgressChanged progressChanged) {
-        setListener(view, null, stop, progressChanged);
-    }
-
-    @BindingAdapter({"android:onStartTrackingTouch", "android:onStopTrackingTouch", "android:onProgressChanged"})
-    public static void setListener(SeekBar view, final OnStartTrackingTouch start,
-            final OnStopTrackingTouch stop, final OnProgressChanged progressChanged) {
-        if (start == null && stop == null && progressChanged == null) {
+    @BindingAdapter(value = {"android:onStartTrackingTouch", "android:onStopTrackingTouch",
+            "android:onProgressChanged", "android:progressAttrChanged"}, requireAll = false)
+    public static void setOnSeekBarChangeListener(SeekBar view, final OnStartTrackingTouch start,
+            final OnStopTrackingTouch stop, final OnProgressChanged progressChanged,
+            final InverseBindingListener attrChanged) {
+        if (start == null && stop == null && progressChanged == null && attrChanged == null) {
             view.setOnSeekBarChangeListener(null);
         } else {
             view.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@@ -65,6 +48,9 @@
                     if (progressChanged != null) {
                         progressChanged.onProgressChanged(seekBar, progress, fromUser);
                     }
+                    if (attrChanged != null) {
+                        attrChanged.onChange();
+                    }
                 }
 
                 @Override
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/TabHostBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/TabHostBindingAdapter.java
index 78f06b0..151a711 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/TabHostBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/TabHostBindingAdapter.java
@@ -15,12 +15,54 @@
  */
 package android.databinding.adapters;
 
-import android.databinding.BindingMethod;
-import android.databinding.BindingMethods;
+import android.databinding.BindingAdapter;
+import android.databinding.InverseBindingAdapter;
+import android.databinding.InverseBindingListener;
 import android.widget.TabHost;
+import android.widget.TabHost.OnTabChangeListener;
 
-@BindingMethods({
-        @BindingMethod(type = TabHost.class, attribute = "android:onTabChanged", method = "setOnTabChangedListener"),
-})
 public class TabHostBindingAdapter {
+
+    @InverseBindingAdapter(attribute = "android:currentTab")
+    public static int getCurrentTab(TabHost view) {
+        return view.getCurrentTab();
+    }
+
+    @InverseBindingAdapter(attribute = "android:currentTab")
+    public static String getCurrentTabTag(TabHost view) {
+        return view.getCurrentTabTag();
+    }
+
+    @BindingAdapter("android:currentTab")
+    public static void setCurrentTab(TabHost view, int tab) {
+        if (view.getCurrentTab() != tab) {
+            view.setCurrentTab(tab);
+        }
+    }
+
+    @BindingAdapter("android:currentTab")
+    public static void setCurrentTabTag(TabHost view, String tabTag) {
+        if (view.getCurrentTabTag() != tabTag) {
+            view.setCurrentTabByTag(tabTag);
+        }
+    }
+
+    @BindingAdapter(value = {"android:onTabChanged", "android:currentTabAttrChanged"},
+            requireAll = false)
+    public static void setListeners(TabHost view, final OnTabChangeListener listener,
+            final InverseBindingListener attrChange) {
+        if (attrChange == null) {
+            view.setOnTabChangedListener(listener);
+        } else {
+            view.setOnTabChangedListener(new OnTabChangeListener() {
+                @Override
+                public void onTabChanged(String tabId) {
+                    if (listener != null) {
+                        listener.onTabChanged(tabId);
+                    }
+                    attrChange.onChange();
+                }
+            });
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/TextViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/TextViewBindingAdapter.java
index 01ea006..2d3bebb 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/TextViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/TextViewBindingAdapter.java
@@ -15,14 +15,21 @@
  */
 package android.databinding.adapters;
 
+import com.android.databinding.library.baseAdapters.R;
+
 import android.databinding.BindingAdapter;
 import android.databinding.BindingMethod;
 import android.databinding.BindingMethods;
+import android.databinding.InverseBindingAdapter;
+import android.databinding.InverseBindingListener;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.InputType;
+import android.text.Spanned;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
 import android.text.TextWatcher;
 import android.text.method.DialerKeyListener;
 import android.text.method.DigitsKeyListener;
@@ -33,8 +40,6 @@
 import android.util.TypedValue;
 import android.widget.TextView;
 
-import com.android.databinding.library.baseAdapters.R;
-
 @BindingMethods({
         @BindingMethod(type = TextView.class, attribute = "android:autoLink", method = "setAutoLinkMask"),
         @BindingMethod(type = TextView.class, attribute = "android:drawablePadding", method = "setCompoundDrawablePadding"),
@@ -50,13 +55,31 @@
 public class TextViewBindingAdapter {
 
     private static final String TAG = "TextViewBindingAdapters";
-
     public static final int INTEGER = 0x01;
-
     public static final int SIGNED = 0x03;
-
     public static final int DECIMAL = 0x05;
 
+    @BindingAdapter("android:text")
+    public static void setText(TextView view, CharSequence text) {
+        final CharSequence oldText = view.getText();
+        if (text == oldText || (text == null && oldText.length() == 0)) {
+            return;
+        }
+        if (text instanceof Spanned) {
+            if (text.equals(oldText)) {
+                return; // No change in the spans, so don't set anything.
+            }
+        } else if (!haveContentsChanged(text, oldText)) {
+            return; // No content changes, so don't set anything.
+        }
+        view.setText(text);
+    }
+
+    @InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
+    public static String getTextString(TextView view) {
+        return view.getText().toString();
+    }
+
     @BindingAdapter({"android:autoText"})
     public static void setAutoText(TextView view, boolean autoText) {
         KeyListener listener = view.getKeyListener();
@@ -112,28 +135,40 @@
         }
     }
 
+    private static void setIntrinsicBounds(Drawable drawable) {
+        if (drawable != null) {
+            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+        }
+    }
+
     @BindingAdapter({"android:drawableBottom"})
     public static void setDrawableBottom(TextView view, Drawable drawable) {
+        setIntrinsicBounds(drawable);
         Drawable[] drawables = view.getCompoundDrawables();
         view.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawable);
     }
 
     @BindingAdapter({"android:drawableLeft"})
     public static void setDrawableLeft(TextView view, Drawable drawable) {
+        setIntrinsicBounds(drawable);
         Drawable[] drawables = view.getCompoundDrawables();
         view.setCompoundDrawables(drawable, drawables[1], drawables[2], drawables[3]);
     }
 
     @BindingAdapter({"android:drawableRight"})
     public static void setDrawableRight(TextView view, Drawable drawable) {
+        setIntrinsicBounds(drawable);
         Drawable[] drawables = view.getCompoundDrawables();
-        view.setCompoundDrawables(drawables[0], drawables[1], drawable, drawables[3]);
+        view.setCompoundDrawables(drawables[0], drawables[1], drawable,
+                drawables[3]);
     }
 
     @BindingAdapter({"android:drawableTop"})
     public static void setDrawableTop(TextView view, Drawable drawable) {
+        setIntrinsicBounds(drawable);
         Drawable[] drawables = view.getCompoundDrawables();
-        view.setCompoundDrawables(drawables[0], drawable, drawables[2], drawables[3]);
+        view.setCompoundDrawables(drawables[0], drawable, drawables[2],
+                drawables[3]);
     }
 
     @BindingAdapter({"android:drawableStart"})
@@ -141,6 +176,7 @@
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
             setDrawableLeft(view, drawable);
         } else {
+            setIntrinsicBounds(drawable);
             Drawable[] drawables = view.getCompoundDrawablesRelative();
             view.setCompoundDrawablesRelative(drawable, drawables[1], drawables[2], drawables[3]);
         }
@@ -151,6 +187,7 @@
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
             setDrawableRight(view, drawable);
         } else {
+            setIntrinsicBounds(drawable);
             Drawable[] drawables = view.getCompoundDrawablesRelative();
             view.setCompoundDrawablesRelative(drawables[0], drawables[1], drawable, drawables[3]);
         }
@@ -286,44 +323,31 @@
         view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
     }
 
-    @BindingAdapter("android:afterTextChanged")
-    public static void setListener(TextView view, AfterTextChanged after) {
-        setListener(view, null, null, after);
+    private static boolean haveContentsChanged(CharSequence str1, CharSequence str2) {
+        if ((str1 == null) != (str2 == null)) {
+            return true;
+        } else if (str1 == null) {
+            return false;
+        }
+        final int length = str1.length();
+        if (length != str2.length()) {
+            return true;
+        }
+        for (int i = 0; i < length; i++) {
+            if (str1.charAt(i) != str2.charAt(i)) {
+                return true;
+            }
+        }
+        return false;
     }
 
-    @BindingAdapter("android:beforeTextChanged")
-    public static void setListener(TextView view, BeforeTextChanged before) {
-        setListener(view, before, null, null);
-    }
-
-    @BindingAdapter("android:onTextChanged")
-    public static void setListener(TextView view, OnTextChanged onTextChanged) {
-        setListener(view, null, onTextChanged, null);
-    }
-
-    @BindingAdapter({"android:beforeTextChanged", "android:afterTextChanged"})
-    public static void setListener(TextView view, final BeforeTextChanged before,
-            final AfterTextChanged after) {
-        setListener(view, before, null, after);
-    }
-
-    @BindingAdapter({"android:beforeTextChanged", "android:onTextChanged"})
-    public static void setListener(TextView view, final BeforeTextChanged before,
-            final OnTextChanged on) {
-        setListener(view, before, on, null);
-    }
-
-    @BindingAdapter({"android:onTextChanged", "android:afterTextChanged"})
-    public static void setListener(TextView view,final OnTextChanged on,
-            final AfterTextChanged after) {
-        setListener(view, null, on, after);
-    }
-
-    @BindingAdapter({"android:beforeTextChanged", "android:onTextChanged", "android:afterTextChanged"})
-    public static void setListener(TextView view, final BeforeTextChanged before,
-            final OnTextChanged on, final AfterTextChanged after) {
+    @BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
+            "android:afterTextChanged", "android:textAttrChanged"}, requireAll = false)
+    public static void setTextWatcher(TextView view, final BeforeTextChanged before,
+            final OnTextChanged on, final AfterTextChanged after,
+            final InverseBindingListener textAttrChanged) {
         final TextWatcher newValue;
-        if (before == null && after == null && on == null) {
+        if (before == null && after == null && on == null && textAttrChanged == null) {
             newValue = null;
         } else {
             newValue = new TextWatcher() {
@@ -339,6 +363,9 @@
                     if (on != null) {
                         on.onTextChanged(s, start, before, count);
                     }
+                    if (textAttrChanged != null) {
+                        textAttrChanged.onChange();
+                    }
                 }
 
                 @Override
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/TimePickerBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/TimePickerBindingAdapter.java
index 3a11dab..803342d 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/TimePickerBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/TimePickerBindingAdapter.java
@@ -15,12 +15,95 @@
  */
 package android.databinding.adapters;
 
-import android.databinding.BindingMethod;
-import android.databinding.BindingMethods;
+import android.databinding.BindingAdapter;
+import android.databinding.InverseBindingAdapter;
+import android.databinding.InverseBindingListener;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
 import android.widget.TimePicker;
+import android.widget.TimePicker.OnTimeChangedListener;
 
-@BindingMethods({
-        @BindingMethod(type = TimePicker.class, attribute = "android:onTimeChanged", method = "setOnTimeChangedListener"),
-})
 public class TimePickerBindingAdapter {
+
+    @SuppressWarnings("deprecation")
+    @BindingAdapter("android:hour")
+    public static void setHour(TimePicker view, int hour) {
+        if (VERSION.SDK_INT >= VERSION_CODES.M) {
+            if (view.getHour() != hour) {
+                view.setHour(hour);
+            }
+        } else {
+            if (view.getCurrentHour() != hour) {
+                view.setCurrentHour(hour);
+            }
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @BindingAdapter("android:minute")
+    public static void setMinute(TimePicker view, int minute) {
+        if (VERSION.SDK_INT >= VERSION_CODES.M) {
+            if (view.getMinute() != minute) {
+                view.setMinute(minute);
+            }
+        } else {
+            if (view.getCurrentMinute() != minute) {
+                view.setCurrentHour(minute);
+            }
+        }
+    }
+
+    @InverseBindingAdapter(attribute = "android:hour")
+    public static int getHour(TimePicker view) {
+        if (VERSION.SDK_INT >= VERSION_CODES.M) {
+            return view.getHour();
+        } else {
+            @SuppressWarnings("deprecation")
+            Integer hour = view.getCurrentHour();
+            if (hour == null) {
+                return 0;
+            } else {
+                return hour;
+            }
+        }
+    }
+
+    @InverseBindingAdapter(attribute = "android:minute")
+    public static int getMinute(TimePicker view) {
+        if (VERSION.SDK_INT >= VERSION_CODES.M) {
+            return view.getMinute();
+        } else {
+            @SuppressWarnings("deprecation")
+            Integer minute = view.getCurrentMinute();
+            if (minute == null) {
+                return 0;
+            } else {
+                return minute;
+            }
+        }
+    }
+
+    @BindingAdapter(value = {"android:onTimeChanged", "android:hourAttrChanged",
+            "android:minuteAttrChanged"}, requireAll = false)
+    public static void setListeners(TimePicker view, final OnTimeChangedListener listener,
+            final InverseBindingListener hourChange, final InverseBindingListener minuteChange) {
+        if (hourChange == null && minuteChange == null) {
+            view.setOnTimeChangedListener(listener);
+        } else {
+            view.setOnTimeChangedListener(new OnTimeChangedListener() {
+                @Override
+                public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
+                    if (listener != null) {
+                        listener.onTimeChanged(view, hourOfDay, minute);
+                    }
+                    if (hourChange != null) {
+                        hourChange.onChange();
+                    }
+                    if (minuteChange != null) {
+                        minuteChange.onChange();
+                    }
+                }
+            });
+        }
+    }
 }
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewBindingAdapter.java
index f9fae7b..aece41b 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewBindingAdapter.java
@@ -19,6 +19,7 @@
 import android.databinding.BindingAdapter;
 import android.databinding.BindingMethod;
 import android.databinding.BindingMethods;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
@@ -60,18 +61,21 @@
     public static int FADING_EDGE_VERTICAL = 2;
 
     @BindingAdapter({"android:padding"})
-    public static void setPadding(View view, int padding) {
+    public static void setPadding(View view, float paddingFloat) {
+        final int padding = pixelsToDimensionPixelSize(paddingFloat);
         view.setPadding(padding, padding, padding, padding);
     }
 
     @BindingAdapter({"android:paddingBottom"})
-    public static void setPaddingBottom(View view, int padding) {
+    public static void setPaddingBottom(View view, float paddingFloat) {
+        final int padding = pixelsToDimensionPixelSize(paddingFloat);
         view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
                 padding);
     }
 
     @BindingAdapter({"android:paddingEnd"})
-    public static void setPaddingEnd(View view, int padding) {
+    public static void setPaddingEnd(View view, float paddingFloat) {
+        final int padding = pixelsToDimensionPixelSize(paddingFloat);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
             view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), padding,
                     view.getPaddingBottom());
@@ -82,19 +86,22 @@
     }
 
     @BindingAdapter({"android:paddingLeft"})
-    public static void setPaddingLeft(View view, int padding) {
+    public static void setPaddingLeft(View view, float paddingFloat) {
+        final int padding = pixelsToDimensionPixelSize(paddingFloat);
         view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(),
                 view.getPaddingBottom());
     }
 
     @BindingAdapter({"android:paddingRight"})
-    public static void setPaddingRight(View view, int padding) {
+    public static void setPaddingRight(View view, float paddingFloat) {
+        final int padding = pixelsToDimensionPixelSize(paddingFloat);
         view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding,
                 view.getPaddingBottom());
     }
 
     @BindingAdapter({"android:paddingStart"})
-    public static void setPaddingStart(View view, int padding) {
+    public static void setPaddingStart(View view, float paddingFloat) {
+        final int padding = pixelsToDimensionPixelSize(paddingFloat);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
             view.setPaddingRelative(padding, view.getPaddingTop(), view.getPaddingEnd(),
                     view.getPaddingBottom());
@@ -105,7 +112,8 @@
     }
 
     @BindingAdapter({"android:paddingTop"})
-    public static void setPaddingTop(View view, int padding) {
+    public static void setPaddingTop(View view, float paddingFloat) {
+        final int padding = pixelsToDimensionPixelSize(paddingFloat);
         view.setPadding(view.getPaddingLeft(), padding, view.getPaddingRight(),
                 view.getPaddingBottom());
     }
@@ -133,7 +141,7 @@
     }
 
     @BindingAdapter({"android:onLongClickListener", "android:longClickable"})
-    public static void setListener(View view, View.OnLongClickListener clickListener,
+    public static void setOnLongClickListener(View view, View.OnLongClickListener clickListener,
             boolean clickable) {
         view.setOnLongClickListener(clickListener);
         view.setLongClickable(clickable);
@@ -146,19 +154,10 @@
         view.setLongClickable(clickable);
     }
 
-    @BindingAdapter("android:onViewAttachedToWindow")
-    public static void setListener(View view, OnViewAttachedToWindow attached) {
-        setListener(view, null, attached);
-    }
-
-    @BindingAdapter("android:onViewDetachedFromWindow")
-    public static void setListener(View view, OnViewDetachedFromWindow detached) {
-        setListener(view, detached, null);
-    }
-
-    @BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"})
-    public static void setListener(View view, final OnViewDetachedFromWindow detach,
-            final OnViewAttachedToWindow attach) {
+    @BindingAdapter(value = {"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"},
+            requireAll = false)
+    public static void setOnAttachStateChangeListener(View view,
+            final OnViewDetachedFromWindow detach, final OnViewAttachedToWindow attach) {
         if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
             final OnAttachStateChangeListener newListener;
             if (detach == null && attach == null) {
@@ -204,6 +203,32 @@
         }
     }
 
+    @SuppressWarnings("deprecation")
+    @BindingAdapter("android:background")
+    public static void setBackground(View view, Drawable drawable) {
+        if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+            view.setBackground(drawable);
+        } else {
+            view.setBackgroundDrawable(drawable);
+        }
+    }
+
+    // Follows the same conversion mechanism as in TypedValue.complexToDimensionPixelSize as used
+    // when setting padding. It rounds off the float value unless the value is < 1.
+    // When a value is between 0 and 1, it is set to 1. A value less than 0 is set to -1.
+    private static int pixelsToDimensionPixelSize(float pixels) {
+        final int result = (int) (pixels + 0.5f);
+        if (result != 0) {
+            return result;
+        } else if (pixels == 0) {
+            return 0;
+        } else if (pixels > 0) {
+            return 1;
+        } else {
+            return -1;
+        }
+    }
+
     @TargetApi(VERSION_CODES.HONEYCOMB_MR1)
     public interface OnViewDetachedFromWindow {
         void onViewDetachedFromWindow(View v);
diff --git a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewGroupBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewGroupBindingAdapter.java
index af10818..8b1978c 100644
--- a/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewGroupBindingAdapter.java
+++ b/extensions/baseAdapters/src/main/java/android/databinding/adapters/ViewGroupBindingAdapter.java
@@ -44,17 +44,8 @@
         }
     }
 
-    @BindingAdapter("android:onChildViewAdded")
-    public static void setListener(ViewGroup view, OnChildViewAdded listener) {
-        setListener(view, listener, null);
-    }
-
-    @BindingAdapter("android:onChildViewRemoved")
-    public static void setListener(ViewGroup view, OnChildViewRemoved listener) {
-        setListener(view, null, listener);
-    }
-
-    @BindingAdapter({"android:onChildViewAdded", "android:onChildViewRemoved"})
+    @BindingAdapter(value = {"android:onChildViewAdded", "android:onChildViewRemoved"},
+            requireAll = false)
     public static void setListener(ViewGroup view, final OnChildViewAdded added,
             final OnChildViewRemoved removed) {
         if (added == null && removed == null) {
@@ -78,8 +69,8 @@
         }
     }
 
-    @BindingAdapter({"android:onAnimationStart", "android:onAnimationEnd",
-            "android:onAnimationRepeat"})
+    @BindingAdapter(value = {"android:onAnimationStart", "android:onAnimationEnd",
+            "android:onAnimationRepeat"}, requireAll = false)
     public static void setListener(ViewGroup view, final OnAnimationStart start,
             final OnAnimationEnd end, final OnAnimationRepeat repeat) {
         if (start == null && end == null && repeat == null) {
@@ -110,39 +101,6 @@
         }
     }
 
-    @BindingAdapter({"android:onAnimationStart", "android:onAnimationEnd"})
-    public static void setListener(ViewGroup view, final OnAnimationStart start,
-            final OnAnimationEnd end) {
-        setListener(view, start, end, null);
-    }
-
-    @BindingAdapter({"android:onAnimationEnd", "android:onAnimationRepeat"})
-    public static void setListener(ViewGroup view, final OnAnimationEnd end,
-            final OnAnimationRepeat repeat) {
-        setListener(view, null, end, repeat);
-    }
-
-    @BindingAdapter({"android:onAnimationStart", "android:onAnimationRepeat"})
-    public static void setListener(ViewGroup view, final OnAnimationStart start,
-            final OnAnimationRepeat repeat) {
-        setListener(view, start, null, repeat);
-    }
-
-    @BindingAdapter("android:onAnimationStart")
-    public static void setListener(ViewGroup view, final OnAnimationStart start) {
-        setListener(view, start, null, null);
-    }
-
-    @BindingAdapter("android:onAnimationEnd")
-    public static void setListener(ViewGroup view, final OnAnimationEnd end) {
-        setListener(view, null, end, null);
-    }
-
-    @BindingAdapter("android:onAnimationRepeat")
-    public static void setListener(ViewGroup view, final OnAnimationRepeat repeat) {
-        setListener(view, null, null, repeat);
-    }
-
     public interface OnChildViewAdded {
         void onChildViewAdded(View parent, View child);
     }
diff --git a/extensions/baseAdapters/src/main/res/values/ids.xml b/extensions/baseAdapters/src/main/res/values/ids.xml
index 7e76dbe..3383fb5 100644
--- a/extensions/baseAdapters/src/main/res/values/ids.xml
+++ b/extensions/baseAdapters/src/main/res/values/ids.xml
@@ -4,4 +4,6 @@
     <item type="id" name="onAttachStateChangeListener"/>
     <!-- Used to track TextWatcher for TextView BindingAdapter -->
     <item type="id" name="textWatcher"/>
+    <!-- Used to track DatePicker OnDateChanged BindingAdapter -->
+    <item type="id" name="onDateChanged"/>
 </resources>
\ No newline at end of file
diff --git a/extensions/build.gradle b/extensions/build.gradle
index 51aad32..0ab14be 100644
--- a/extensions/build.gradle
+++ b/extensions/build.gradle
@@ -13,22 +13,41 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-ext.rootFolder = new File(project.projectDir, "..")
+ext.dataBindingRootFolder = new File(project.projectDir, "..")
 buildscript {
-    ext.rootFolder = new File(project.projectDir, "..")
+    ext.dataBindingRootFolder = new File(project.projectDir, "..")
     apply from: "${project.projectDir}/../propLoader.gradle"
+    apply from: "${project.projectDir}/../supportBundle.gradle"
     ext.addRepos(repositories)
-    dependencies {
-        classpath "com.android.databinding:dataBinder:${config.version}"
-    }
 }
 
+def bundleSupportLibTask = tasks['bundleSupportLib']
+
 subprojects {
     apply plugin: 'maven'
-    group = config.group
-    version = config.version
+    group = dataBindingConfig.group
+    version = dataBindingConfig.extensionsVersion
+    uploadArchives {
+        repositories {
+            mavenDeployer {
+                repository(url: "file://${dataBindingConfig.internalPrebuiltsRepoDir}")
+            }
+        }
+    }
+    bundleSupportLibTask.dependsOn tasks['uploadArchives']
+
+    def configureOut = tasks.create(name: 'configureOut') << {
+        println("configuring out...")
+        def deployer = tasks['uploadArchives'].repositories.mavenDeployer.repository
+        println "changing ${deployer.url} to ${rootProject.ext.supportRepoOut}"
+        deployer.url = "file://${rootProject.ext.supportRepoOut}"
+    }
+    bundleSupportLibTask.dependsOn configureOut
+    tasks['uploadArchives'].mustRunAfter configureOut
+    tasks['uploadArchives'].mustRunAfter unzipRepo
 }
 
+
 task preparePrebuilds() {
 }
 
diff --git a/extensions/gradle/wrapper/gradle-wrapper.properties b/extensions/gradle/wrapper/gradle-wrapper.properties
index e5fd879..50ce379 100644
--- a/extensions/gradle/wrapper/gradle-wrapper.properties
+++ b/extensions/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/extensions/library/build.gradle b/extensions/library/build.gradle
new file mode 100644
index 0000000..339a20f
--- /dev/null
+++ b/extensions/library/build.gradle
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import com.android.build.api.transform.Format;
+import com.android.build.api.transform.QualifiedContent;
+import com.android.build.api.transform.QualifiedContent.ContentType;
+import com.android.build.api.transform.QualifiedContent.Scope;
+import com.android.build.api.transform.Transform;
+import com.android.build.api.transform.Context;
+import com.android.build.api.transform.TransformInput;
+import com.android.build.api.transform.TransformOutputProvider;
+import com.android.build.api.transform.TransformException;
+import com.android.build.gradle.internal.pipeline.TransformManager;
+// Top-level build file where you can add dataBindingConfiguration options common to all sub-projects/modules.
+
+buildscript {
+    dependencies {
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
+
+    defaultConfig {
+        minSdkVersion 7
+        targetSdkVersion 23
+        versionCode 1
+        versionName "1.0"
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_6
+        targetCompatibility JavaVersion.VERSION_1_6
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+        }
+    }
+    packagingOptions {
+        exclude 'META-INF/services/javax.annotation.processing.Processor'
+        exclude 'META-INF/LICENSE.txt'
+        exclude 'META-INF/NOTICE.txt'
+        exclude 'android/databinding/DataBinderMapper.class'
+    }
+}
+
+configurations {
+    jarArchives
+}
+
+
+dependencies {
+    compile 'com.android.support:support-v4:21.0.3'
+    compile "com.android.databinding:baseLibrary:${dataBindingConfig.version}"
+}
+
+//create jar tasks
+android.libraryVariants.all { variant ->
+    def name = variant.buildType.name
+
+    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
+        return; // Skip debug builds.
+    }
+    def suffix = name.capitalize()
+
+    def javadocTask = project.tasks.create(name: "javadoc${suffix}", type: Javadoc) {
+        source variant.javaCompile.source
+        classpath = files(variant.javaCompile.classpath.files) + files(
+                "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
+    }
+
+    def javadocJarTask = project.tasks.create(name: "javadocJar${suffix}", type: Jar) {
+        classifier = 'javadoc'
+        from 'build/docs/javadoc'
+    }
+    javadocJarTask.dependsOn javadocTask
+
+    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
+        classifier = 'sources'
+        from android.sourceSets.main.java.srcDirs
+    }
+
+    artifacts.add('archives', javadocJarTask);
+    artifacts.add('archives', sourcesJarTask);
+}
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            pom.artifactId = 'library'
+            pom.project {
+                licenses {
+                    license {
+                        name dataBindingConfig.licenseName
+                        url dataBindingConfig.licenseUrl
+                        distribution dataBindingConfig.licenseDistribution
+                    }
+                }
+            }
+        }
+    }
+}
+
+class ExcludeShimTransform extends Transform {
+    Project project;
+    public ExcludeShimTransform(Project project) {
+        this.project = project;
+    }
+    public Set<ContentType> getInputTypes() {
+        return TransformManager.CONTENT_CLASS;
+    }
+
+    public Set<Scope> getScopes() {
+        def result = new HashSet<Scope>();
+        result.add(Scope.PROJECT);
+        return result;
+    }
+
+    public Set<Scope> getReferencedScopes() {
+        return TransformManager.SCOPE_FULL_LIBRARY;
+    }
+
+    public boolean isIncremental() {
+        return false;
+    }
+
+    public String getName() {
+        return "DataBindingExcludeShimTransform";
+    }
+
+    public void transform(Context context, Collection<TransformInput> inputs,
+            Collection<TransformInput> referencedInputs,
+            TransformOutputProvider outputProvider,
+            boolean isIncremental) throws IOException, TransformException, InterruptedException {
+        inputs.each { transformInput ->
+            transformInput.getDirectoryInputs().each {
+                File outputDir = outputProvider.getContentLocation("data-binding-filtered",
+                        it.getContentTypes(), it.getScopes(), Format.DIRECTORY);
+                outputDir.delete();
+                outputDir.mkdirs();
+                FileTree tree = project.fileTree(dir: it.getFile())
+                tree.include '**/*.class'
+                tree.exclude 'android/databinding/DataBindingComponent.*'
+                tree.exclude 'android/databinding/DataBinderMapper.*'
+                tree.copy {
+                    into outputDir
+                }
+            }
+        }
+    }
+}
+
+android.registerTransform(new ExcludeShimTransform(project))
+
+task prebuildAar(type : Copy) {
+    dependsOn uploadArchives
+    from "$buildDir/outputs/aar/library-release.aar"
+    into dataBindingConfig.prebuildFolder
+    rename { String fileName ->
+        "databinding-library.aar"
+    }
+}
diff --git a/library/src/androidTest/java/android/databinding/ObservableParcelTest.java b/extensions/library/src/androidTest/java/android/databinding/ObservableParcelTest.java
similarity index 100%
rename from library/src/androidTest/java/android/databinding/ObservableParcelTest.java
rename to extensions/library/src/androidTest/java/android/databinding/ObservableParcelTest.java
diff --git a/library/src/doc/java/com/android/databinding/library/R.java b/extensions/library/src/doc/java/com/android/databinding/library/R.java
similarity index 100%
rename from library/src/doc/java/com/android/databinding/library/R.java
rename to extensions/library/src/doc/java/com/android/databinding/library/R.java
diff --git a/library/src/main/AndroidManifest.xml b/extensions/library/src/main/AndroidManifest.xml
similarity index 100%
rename from library/src/main/AndroidManifest.xml
rename to extensions/library/src/main/AndroidManifest.xml
diff --git a/library/src/main/java/android/databinding/BaseObservable.java b/extensions/library/src/main/java/android/databinding/BaseObservable.java
similarity index 100%
rename from library/src/main/java/android/databinding/BaseObservable.java
rename to extensions/library/src/main/java/android/databinding/BaseObservable.java
diff --git a/library/src/main/java/android/databinding/DataBinderMapper.java b/extensions/library/src/main/java/android/databinding/DataBinderMapper.java
similarity index 100%
rename from library/src/main/java/android/databinding/DataBinderMapper.java
rename to extensions/library/src/main/java/android/databinding/DataBinderMapper.java
diff --git a/library/src/main/java/android/databinding/DataBindingComponent.java b/extensions/library/src/main/java/android/databinding/DataBindingComponent.java
similarity index 100%
rename from library/src/main/java/android/databinding/DataBindingComponent.java
rename to extensions/library/src/main/java/android/databinding/DataBindingComponent.java
diff --git a/library/src/main/java/android/databinding/DataBindingUtil.java b/extensions/library/src/main/java/android/databinding/DataBindingUtil.java
similarity index 93%
rename from library/src/main/java/android/databinding/DataBindingUtil.java
rename to extensions/library/src/main/java/android/databinding/DataBindingUtil.java
index c2e616f..55a6b4e 100644
--- a/library/src/main/java/android/databinding/DataBindingUtil.java
+++ b/extensions/library/src/main/java/android/databinding/DataBindingUtil.java
@@ -115,18 +115,7 @@
         final int startChildren = useChildren ? parent.getChildCount() : 0;
         final View view = inflater.inflate(layoutId, parent, attachToParent);
         if (useChildren) {
-            final int endChildren = parent.getChildCount();
-            final int childrenAdded = endChildren - startChildren;
-            if (childrenAdded == 1) {
-                final View childView = parent.getChildAt(endChildren - 1);
-                return bind(bindingComponent, childView, layoutId);
-            } else {
-                final View[] children = new View[childrenAdded];
-                for (int i = 0; i < childrenAdded; i++) {
-                    children[i] = parent.getChildAt(i + startChildren);
-                }
-                return bind(bindingComponent, children, layoutId);
-            }
+            return bindToAddedViews(bindingComponent, parent, startChildren, layoutId);
         } else {
             return bind(bindingComponent, view, layoutId);
         }
@@ -284,13 +273,10 @@
      */
     public static <T extends ViewDataBinding> T setContentView(Activity activity, int layoutId,
             DataBindingComponent bindingComponent) {
-        // Force the content view to exist if it didn't already.
+        activity.setContentView(layoutId);
         View decorView = activity.getWindow().getDecorView();
         ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
-        T binding = inflate(activity.getLayoutInflater(), layoutId, contentView, false,
-                bindingComponent);
-        activity.setContentView(binding.getRoot(), binding.getRoot().getLayoutParams());
-        return binding;
+        return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
     }
 
     /**
@@ -303,4 +289,20 @@
     public static String convertBrIdToString(int id) {
         return sMapper.convertBrIdToString(id);
     }
+
+    private static <T extends ViewDataBinding> T bindToAddedViews(DataBindingComponent component,
+            ViewGroup parent, int startChildren, int layoutId) {
+        final int endChildren = parent.getChildCount();
+        final int childrenAdded = endChildren - startChildren;
+        if (childrenAdded == 1) {
+            final View childView = parent.getChildAt(endChildren - 1);
+            return bind(component, childView, layoutId);
+        } else {
+            final View[] children = new View[childrenAdded];
+            for (int i = 0; i < childrenAdded; i++) {
+                children[i] = parent.getChildAt(i + startChildren);
+            }
+            return bind(component, children, layoutId);
+        }
+    }
 }
diff --git a/library/src/main/java/android/databinding/ListChangeRegistry.java b/extensions/library/src/main/java/android/databinding/ListChangeRegistry.java
similarity index 98%
rename from library/src/main/java/android/databinding/ListChangeRegistry.java
rename to extensions/library/src/main/java/android/databinding/ListChangeRegistry.java
index e13f867..3b88fe5 100644
--- a/library/src/main/java/android/databinding/ListChangeRegistry.java
+++ b/extensions/library/src/main/java/android/databinding/ListChangeRegistry.java
@@ -25,7 +25,7 @@
         CallbackRegistry<ObservableList.OnListChangedCallback, ObservableList,
                 ListChangeRegistry.ListChanges> {
     private static final Pools.SynchronizedPool<ListChanges> sListChanges =
-            new Pools.SynchronizedPool<>(10);
+            new Pools.SynchronizedPool<ListChanges>(10);
 
     private static final int ALL = 0;
     private static final int CHANGED = 1;
diff --git a/library/src/main/java/android/databinding/MapChangeRegistry.java b/extensions/library/src/main/java/android/databinding/MapChangeRegistry.java
similarity index 100%
rename from library/src/main/java/android/databinding/MapChangeRegistry.java
rename to extensions/library/src/main/java/android/databinding/MapChangeRegistry.java
diff --git a/library/src/main/java/android/databinding/ObservableArrayList.java b/extensions/library/src/main/java/android/databinding/ObservableArrayList.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableArrayList.java
rename to extensions/library/src/main/java/android/databinding/ObservableArrayList.java
diff --git a/library/src/main/java/android/databinding/ObservableArrayMap.java b/extensions/library/src/main/java/android/databinding/ObservableArrayMap.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableArrayMap.java
rename to extensions/library/src/main/java/android/databinding/ObservableArrayMap.java
diff --git a/library/src/main/java/android/databinding/ObservableBoolean.java b/extensions/library/src/main/java/android/databinding/ObservableBoolean.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableBoolean.java
rename to extensions/library/src/main/java/android/databinding/ObservableBoolean.java
diff --git a/library/src/main/java/android/databinding/ObservableByte.java b/extensions/library/src/main/java/android/databinding/ObservableByte.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableByte.java
rename to extensions/library/src/main/java/android/databinding/ObservableByte.java
diff --git a/library/src/main/java/android/databinding/ObservableChar.java b/extensions/library/src/main/java/android/databinding/ObservableChar.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableChar.java
rename to extensions/library/src/main/java/android/databinding/ObservableChar.java
diff --git a/library/src/main/java/android/databinding/ObservableDouble.java b/extensions/library/src/main/java/android/databinding/ObservableDouble.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableDouble.java
rename to extensions/library/src/main/java/android/databinding/ObservableDouble.java
diff --git a/library/src/main/java/android/databinding/ObservableField.java b/extensions/library/src/main/java/android/databinding/ObservableField.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableField.java
rename to extensions/library/src/main/java/android/databinding/ObservableField.java
diff --git a/library/src/main/java/android/databinding/ObservableFloat.java b/extensions/library/src/main/java/android/databinding/ObservableFloat.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableFloat.java
rename to extensions/library/src/main/java/android/databinding/ObservableFloat.java
diff --git a/library/src/main/java/android/databinding/ObservableInt.java b/extensions/library/src/main/java/android/databinding/ObservableInt.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableInt.java
rename to extensions/library/src/main/java/android/databinding/ObservableInt.java
diff --git a/library/src/main/java/android/databinding/ObservableLong.java b/extensions/library/src/main/java/android/databinding/ObservableLong.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableLong.java
rename to extensions/library/src/main/java/android/databinding/ObservableLong.java
diff --git a/library/src/main/java/android/databinding/ObservableParcelable.java b/extensions/library/src/main/java/android/databinding/ObservableParcelable.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableParcelable.java
rename to extensions/library/src/main/java/android/databinding/ObservableParcelable.java
diff --git a/library/src/main/java/android/databinding/ObservableShort.java b/extensions/library/src/main/java/android/databinding/ObservableShort.java
similarity index 100%
rename from library/src/main/java/android/databinding/ObservableShort.java
rename to extensions/library/src/main/java/android/databinding/ObservableShort.java
diff --git a/library/src/main/java/android/databinding/OnRebindCallback.java b/extensions/library/src/main/java/android/databinding/OnRebindCallback.java
similarity index 100%
rename from library/src/main/java/android/databinding/OnRebindCallback.java
rename to extensions/library/src/main/java/android/databinding/OnRebindCallback.java
diff --git a/library/src/main/java/android/databinding/PropertyChangeRegistry.java b/extensions/library/src/main/java/android/databinding/PropertyChangeRegistry.java
similarity index 100%
rename from library/src/main/java/android/databinding/PropertyChangeRegistry.java
rename to extensions/library/src/main/java/android/databinding/PropertyChangeRegistry.java
diff --git a/library/src/main/java/android/databinding/ViewDataBinding.java b/extensions/library/src/main/java/android/databinding/ViewDataBinding.java
similarity index 76%
rename from library/src/main/java/android/databinding/ViewDataBinding.java
rename to extensions/library/src/main/java/android/databinding/ViewDataBinding.java
index b23d7b8..5e76023 100644
--- a/library/src/main/java/android/databinding/ViewDataBinding.java
+++ b/extensions/library/src/main/java/android/databinding/ViewDataBinding.java
@@ -16,23 +16,31 @@
 
 package android.databinding;
 
-import com.android.databinding.library.R;
-
 import android.annotation.TargetApi;
+import android.content.res.ColorStateList;
 import android.databinding.CallbackRegistry.NotifierCallback;
+import android.graphics.drawable.Drawable;
 import android.os.Build.VERSION;
 import android.os.Build.VERSION_CODES;
 import android.os.Handler;
 import android.os.Looper;
 import android.text.TextUtils;
+import android.util.LongSparseArray;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
+import android.util.SparseLongArray;
 import android.view.Choreographer;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
 
+import com.android.databinding.library.R;
+
 import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Base class for generated data binding classes. If possible, the generated binding should
@@ -40,7 +48,7 @@
  * binding is unknown, {@link DataBindingUtil#bind(View)} or
  * {@link DataBindingUtil#inflate(LayoutInflater, int, ViewGroup, boolean)} should be used.
  */
-public abstract class ViewDataBinding {
+public abstract class ViewDataBinding extends BaseObservable {
 
     /**
      * Instead of directly accessing Build.VERSION.SDK_INT, generated code uses this value so that
@@ -292,8 +300,8 @@
      * @param variableId the BR id of the variable to be set. For example, if the variable is
      *                   <code>x</code>, then variableId will be <code>BR.x</code>.
      * @param value The new value of the variable to be set.
-     * @return <code>true</code> if the variable exists in the binding or <code>false</code>
-     * otherwise.
+     * @return <code>true</code> if the variable is declared or used in the binding or
+     * <code>false</code> otherwise.
      */
     public abstract boolean setVariable(int variableId, Object value);
 
@@ -561,6 +569,324 @@
         return bindings;
     }
 
+    /** @hide */
+    protected int getColorFromResource(int resourceId) {
+        if (VERSION.SDK_INT >= VERSION_CODES.M) {
+            return getRoot().getContext().getColor(resourceId);
+        } else {
+            return getRoot().getResources().getColor(resourceId);
+        }
+    }
+
+    /** @hide */
+    protected ColorStateList getColorStateListFromResource(int resourceId) {
+        if (VERSION.SDK_INT >= VERSION_CODES.M) {
+            return getRoot().getContext().getColorStateList(resourceId);
+        } else {
+            return getRoot().getResources().getColorStateList(resourceId);
+        }
+    }
+
+    /** @hide */
+    protected Drawable getDrawableFromResource(int resourceId) {
+        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+            return getRoot().getContext().getDrawable(resourceId);
+        } else {
+            return getRoot().getResources().getDrawable(resourceId);
+        }
+    }
+
+    /** @hide */
+    protected static <T> T getFromArray(T[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return null;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static <T> void setTo(T[] arr, int index, T value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static boolean getFromArray(boolean[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return false;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(boolean[] arr, int index, boolean value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static byte getFromArray(byte[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return 0;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(byte[] arr, int index, byte value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static short getFromArray(short[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return 0;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(short[] arr, int index, short value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static char getFromArray(char[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return 0;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(char[] arr, int index, char value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static int getFromArray(int[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return 0;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(int[] arr, int index, int value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static long getFromArray(long[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return 0;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(long[] arr, int index, long value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static float getFromArray(float[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return 0;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(float[] arr, int index, float value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static double getFromArray(double[] arr, int index) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return 0;
+        }
+        return arr[index];
+    }
+
+    /** @hide */
+    protected static void setTo(double[] arr, int index, double value) {
+        if (arr == null || index < 0 || index >= arr.length) {
+            return;
+        }
+        arr[index] = value;
+    }
+
+    /** @hide */
+    protected static <T> T getFromList(List<T> list, int index) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return null;
+        }
+        return list.get(index);
+    }
+
+    /** @hide */
+    protected static <T> void setTo(List<T> list, int index, T value) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return;
+        }
+        list.set(index, value);
+    }
+
+    /** @hide */
+    protected static <T> T getFromList(SparseArray<T> list, int index) {
+        if (list == null || index < 0) {
+            return null;
+        }
+        return list.get(index);
+    }
+
+    /** @hide */
+    protected static <T> void setTo(SparseArray<T> list, int index, T value) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return;
+        }
+        list.put(index, value);
+    }
+
+    /** @hide */
+    @TargetApi(VERSION_CODES.JELLY_BEAN)
+    protected static <T> T getFromList(LongSparseArray<T> list, int index) {
+        if (list == null || index < 0) {
+            return null;
+        }
+        return list.get(index);
+    }
+
+    /** @hide */
+    @TargetApi(VERSION_CODES.JELLY_BEAN)
+    protected static <T> void setTo(LongSparseArray<T> list, int index, T value) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return;
+        }
+        list.put(index, value);
+    }
+
+    /** @hide */
+    protected static <T> T getFromList(android.support.v4.util.LongSparseArray<T> list, int index) {
+        if (list == null || index < 0) {
+            return null;
+        }
+        return list.get(index);
+    }
+
+    /** @hide */
+    protected static <T> void setTo(android.support.v4.util.LongSparseArray<T> list, int index,
+            T value) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return;
+        }
+        list.put(index, value);
+    }
+
+    /** @hide */
+    protected static boolean getFromList(SparseBooleanArray list, int index) {
+        if (list == null || index < 0) {
+            return false;
+        }
+        return list.get(index);
+    }
+
+    /** @hide */
+    protected static void setTo(SparseBooleanArray list, int index, boolean value) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return;
+        }
+        list.put(index, value);
+    }
+
+    /** @hide */
+    protected static int getFromList(SparseIntArray list, int index) {
+        if (list == null || index < 0) {
+            return 0;
+        }
+        return list.get(index);
+    }
+
+    /** @hide */
+    protected static void setTo(SparseIntArray list, int index, int value) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return;
+        }
+        list.put(index, value);
+    }
+
+    /** @hide */
+    @TargetApi(VERSION_CODES.JELLY_BEAN_MR2)
+    protected static long getFromList(SparseLongArray list, int index) {
+        if (list == null || index < 0) {
+            return 0;
+        }
+        return list.get(index);
+    }
+
+    /** @hide */
+    @TargetApi(VERSION_CODES.JELLY_BEAN_MR2)
+    protected static void setTo(SparseLongArray list, int index, long value) {
+        if (list == null || index < 0 || index >= list.size()) {
+            return;
+        }
+        list.put(index, value);
+    }
+
+    /** @hide */
+    protected static <K, T> T getFrom(Map<K, T> map, K key) {
+        if (map == null) {
+            return null;
+        }
+        return map.get(key);
+    }
+
+    /** @hide */
+    protected static <K, T> void setTo(Map<K, T> map, K key, T value) {
+        if (map == null) {
+            return;
+        }
+        map.put(key, value);
+    }
+
+    /** @hide */
+    protected static void setBindingInverseListener(ViewDataBinding binder,
+            InverseBindingListener oldListener, PropertyChangedInverseListener listener) {
+        if (oldListener != listener) {
+            if (oldListener != null) {
+                binder.removeOnPropertyChangedCallback(
+                        (PropertyChangedInverseListener) oldListener);
+            }
+            if (listener != null) {
+                binder.addOnPropertyChangedCallback(listener);
+            }
+        }
+    }
+
     /**
      * Walks the view hierarchy under roots and pulls out tagged Views, includes, and views with
      * IDs into an Object[] that is returned. This is used to walk the view hierarchy once to find
@@ -945,4 +1271,26 @@
             this.layoutIds[index] = layoutIds;
         }
     }
+
+    /**
+     * This class is used by generated subclasses of {@link ViewDataBinding} to listen for
+     * changes on variables of Bindings. This is important for two-way data binding on variables
+     * in included Bindings.
+     * @hide
+     */
+    protected static abstract class PropertyChangedInverseListener
+            extends Observable.OnPropertyChangedCallback implements InverseBindingListener {
+        final int mPropertyId;
+
+        public PropertyChangedInverseListener(int propertyId) {
+            mPropertyId = propertyId;
+        }
+
+        @Override
+        public void onPropertyChanged(Observable sender, int propertyId) {
+            if (propertyId == mPropertyId || propertyId == 0) {
+                onChange();
+            }
+        }
+    }
 }
diff --git a/library/src/main/java/android/databinding/ViewStubProxy.java b/extensions/library/src/main/java/android/databinding/ViewStubProxy.java
similarity index 100%
rename from library/src/main/java/android/databinding/ViewStubProxy.java
rename to extensions/library/src/main/java/android/databinding/ViewStubProxy.java
diff --git a/library/src/main/res/values/ids.xml b/extensions/library/src/main/res/values/ids.xml
similarity index 100%
rename from library/src/main/res/values/ids.xml
rename to extensions/library/src/main/res/values/ids.xml
diff --git a/extensions/publishExtensions.sh b/extensions/publishExtensions.sh
new file mode 100755
index 0000000..32c032e
--- /dev/null
+++ b/extensions/publishExtensions.sh
@@ -0,0 +1,2 @@
+ #!/bin/bash
+ ./gradlew l:upArch --configure-on-demand && ./gradlew bA:upArch --configure-on-demand
diff --git a/extensions/settings.gradle b/extensions/settings.gradle
index 80ebcc8..da0d959 100644
--- a/extensions/settings.gradle
+++ b/extensions/settings.gradle
@@ -17,4 +17,5 @@
 /**
  * These are projects that requires a compiled version of data binding.
  */
+include ':library'
 include ':baseAdapters'
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e5fd879..50ce379 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/gradlePlugin/build.gradle b/gradlePlugin/build.gradle
deleted file mode 100644
index 203105a..0000000
--- a/gradlePlugin/build.gradle
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-apply plugin: 'java'
-apply plugin: 'com.android.databinding.bintray'
-sourceCompatibility = config.javaTargetCompatibility
-targetCompatibility = config.javaSourceCompatibility
-
-
-tasks.create(name : 'copyBuildVersion') << {
-    def buildVersionFile = new File(sourceSets.main.output.resourcesDir,"data_binding_build_info")
-    buildVersionFile.delete()
-    println "writing build version file"
-    buildVersionFile << project.version
-}
-
-tasks['uploadArchives'].dependsOn('copyBuildVersion')
-tasks['copyBuildVersion'].dependsOn('processResources')
-
-dependencies {
-    compile "com.android.tools.build:gradle:${config.androidPluginVersion}"
-    compile gradleApi()
-    compile project(":compilerCommon")
-}
-
-compileJava {
-    options.compilerArgs = ["-proc:none"]
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            pom.artifactId = 'dataBinder'
-            pom.project {
-                licenses {
-                    license {
-                        name config.licenseName
-                        url config.licenseUrl
-                        distribution config.licenseDistribution
-                    }
-                }
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/gradlePlugin/gradle/wrapper/gradle-wrapper.jar b/gradlePlugin/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 3d0dee6..0000000
--- a/gradlePlugin/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/gradlePlugin/gradle/wrapper/gradle-wrapper.properties b/gradlePlugin/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 8b80a06..0000000
--- a/gradlePlugin/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-#Thu Dec 11 16:01:54 PST 2014
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-bin.zip
diff --git a/gradlePlugin/gradlew b/gradlePlugin/gradlew
deleted file mode 100755
index 91a7e26..0000000
--- a/gradlePlugin/gradlew
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/env bash
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn ( ) {
-    echo "$*"
-}
-
-die ( ) {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-esac
-
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=$((i+1))
-    done
-    case $i in
-        (0) set -- ;;
-        (1) set -- "$args0" ;;
-        (2) set -- "$args0" "$args1" ;;
-        (3) set -- "$args0" "$args1" "$args2" ;;
-        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
-    JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
-
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlePlugin/gradlew.bat b/gradlePlugin/gradlew.bat
deleted file mode 100644
index aec9973..0000000
--- a/gradlePlugin/gradlew.bat
+++ /dev/null
@@ -1,90 +0,0 @@
-@if "%DEBUG%" == "" @echo off

-@rem ##########################################################################

-@rem

-@rem  Gradle startup script for Windows

-@rem

-@rem ##########################################################################

-

-@rem Set local scope for the variables with windows NT shell

-if "%OS%"=="Windows_NT" setlocal

-

-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

-set DEFAULT_JVM_OPTS=

-

-set DIRNAME=%~dp0

-if "%DIRNAME%" == "" set DIRNAME=.

-set APP_BASE_NAME=%~n0

-set APP_HOME=%DIRNAME%

-

-@rem Find java.exe

-if defined JAVA_HOME goto findJavaFromJavaHome

-

-set JAVA_EXE=java.exe

-%JAVA_EXE% -version >NUL 2>&1

-if "%ERRORLEVEL%" == "0" goto init

-

-echo.

-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

-echo.

-echo Please set the JAVA_HOME variable in your environment to match the

-echo location of your Java installation.

-

-goto fail

-

-:findJavaFromJavaHome

-set JAVA_HOME=%JAVA_HOME:"=%

-set JAVA_EXE=%JAVA_HOME%/bin/java.exe

-

-if exist "%JAVA_EXE%" goto init

-

-echo.

-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

-echo.

-echo Please set the JAVA_HOME variable in your environment to match the

-echo location of your Java installation.

-

-goto fail

-

-:init

-@rem Get command-line arguments, handling Windowz variants

-

-if not "%OS%" == "Windows_NT" goto win9xME_args

-if "%@eval[2+2]" == "4" goto 4NT_args

-

-:win9xME_args

-@rem Slurp the command line arguments.

-set CMD_LINE_ARGS=

-set _SKIP=2

-

-:win9xME_args_slurp

-if "x%~1" == "x" goto execute

-

-set CMD_LINE_ARGS=%*

-goto execute

-

-:4NT_args

-@rem Get arguments from the 4NT Shell from JP Software

-set CMD_LINE_ARGS=%$

-

-:execute

-@rem Setup the command line

-

-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

-

-@rem Execute Gradle

-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

-

-:end

-@rem End local scope for the variables with windows NT shell

-if "%ERRORLEVEL%"=="0" goto mainEnd

-

-:fail

-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

-rem the _cmd.exe /c_ return code!

-if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

-exit /b 1

-

-:mainEnd

-if "%OS%"=="Windows_NT" endlocal

-

-:omega

diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBinderPlugin.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBinderPlugin.java
deleted file mode 100644
index a116dc1..0000000
--- a/gradlePlugin/src/main/java/android/databinding/tool/DataBinderPlugin.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.databinding.tool;
-
-import com.google.common.base.Preconditions;
-
-import com.android.build.gradle.AppExtension;
-import com.android.build.gradle.BaseExtension;
-import com.android.build.gradle.LibraryExtension;
-import com.android.build.gradle.api.ApplicationVariant;
-import com.android.build.gradle.api.LibraryVariant;
-import com.android.build.gradle.api.TestVariant;
-import com.android.build.gradle.internal.api.ApplicationVariantImpl;
-import com.android.build.gradle.internal.api.LibraryVariantImpl;
-import com.android.build.gradle.internal.api.TestVariantImpl;
-import com.android.build.gradle.internal.core.GradleVariantConfiguration;
-import com.android.build.gradle.internal.variant.ApplicationVariantData;
-import com.android.build.gradle.internal.variant.BaseVariantData;
-import com.android.build.gradle.internal.variant.LibraryVariantData;
-import com.android.build.gradle.internal.variant.TestVariantData;
-import com.android.build.gradle.tasks.ProcessAndroidResources;
-import com.android.builder.model.ApiVersion;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.gradle.api.Action;
-import org.gradle.api.Plugin;
-import org.gradle.api.Project;
-import org.gradle.api.Task;
-import org.gradle.api.logging.LogLevel;
-import org.gradle.api.logging.Logger;
-import org.gradle.api.plugins.ExtraPropertiesExtension;
-import org.gradle.api.tasks.bundling.Jar;
-import org.gradle.api.tasks.compile.AbstractCompile;
-
-import android.databinding.tool.processing.ScopedException;
-import android.databinding.tool.util.L;
-import android.databinding.tool.writer.JavaFileWriter;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.tools.Diagnostic;
-import javax.xml.bind.JAXBException;
-
-public class DataBinderPlugin implements Plugin<Project> {
-
-    private static final String INVOKED_FROM_IDE_PROPERTY = "android.injected.invoked.from.ide";
-    private static final String PRINT_ENCODED_ERRORS_PROPERTY
-            = "android.databinding.injected.print.encoded.errors";
-    private Logger logger;
-    private boolean printEncodedErrors = false;
-
-    class GradleFileWriter extends JavaFileWriter {
-
-        private final String outputBase;
-
-        public GradleFileWriter(String outputBase) {
-            this.outputBase = outputBase;
-        }
-
-        @Override
-        public void writeToFile(String canonicalName, String contents) {
-            String asPath = canonicalName.replace('.', '/');
-            File f = new File(outputBase + "/" + asPath + ".java");
-            logD("Asked to write to " + canonicalName + ". outputting to:" +
-                    f.getAbsolutePath());
-            //noinspection ResultOfMethodCallIgnored
-            f.getParentFile().mkdirs();
-            FileOutputStream fos = null;
-            try {
-                fos = new FileOutputStream(f);
-                IOUtils.write(contents, fos);
-            } catch (IOException e) {
-                logE(e, "cannot write file " + f.getAbsolutePath());
-            } finally {
-                IOUtils.closeQuietly(fos);
-            }
-        }
-    }
-
-    private boolean safeGetBooleanProperty(Project project, String property) {
-        boolean hasProperty = project.hasProperty(property);
-        if (!hasProperty) {
-            return false;
-        }
-        try {
-            if (Boolean.parseBoolean(String.valueOf(project.getProperties().get(property)))) {
-                return true;
-            }
-        } catch (Throwable t) {
-            L.w("unable to read property %s", project);
-        }
-        return false;
-    }
-
-    private boolean resolvePrintEncodedErrors(Project project) {
-        return safeGetBooleanProperty(project, INVOKED_FROM_IDE_PROPERTY) ||
-                safeGetBooleanProperty(project, PRINT_ENCODED_ERRORS_PROPERTY);
-    }
-
-    @Override
-    public void apply(Project project) {
-        if (project == null) {
-            return;
-        }
-        setupLogger(project);
-
-        String myVersion = readMyVersion();
-        logD("data binding plugin version is %s", myVersion);
-        if (StringUtils.isEmpty(myVersion)) {
-            throw new IllegalStateException("cannot read version of the plugin :/");
-        }
-        printEncodedErrors = resolvePrintEncodedErrors(project);
-        ScopedException.encodeOutput(printEncodedErrors);
-        project.getDependencies().add("compile", "com.android.databinding:library:" + myVersion);
-        boolean addAdapters = true;
-        if (project.hasProperty("ext")) {
-            Object ext = project.getProperties().get("ext");
-            if (ext instanceof ExtraPropertiesExtension) {
-                ExtraPropertiesExtension propExt = (ExtraPropertiesExtension) ext;
-                if (propExt.has("addDataBindingAdapters")) {
-                    addAdapters = Boolean.valueOf(
-                            String.valueOf(propExt.get("addDataBindingAdapters")));
-                }
-            }
-        }
-        if (addAdapters) {
-            project.getDependencies()
-                    .add("compile", "com.android.databinding:adapters:" + myVersion);
-        }
-        project.getDependencies().add("provided", "com.android.databinding:compiler:" + myVersion);
-        project.afterEvaluate(new Action<Project>() {
-            @Override
-            public void execute(Project project) {
-                try {
-                    createXmlProcessor(project);
-                } catch (Throwable t) {
-                    logE(t, "failed to setup data binding");
-                }
-            }
-        });
-    }
-
-    private void setupLogger(Project project) {
-        logger = project.getLogger();
-        L.setClient(new L.Client() {
-            @Override
-            public void printMessage(Diagnostic.Kind kind, String message) {
-                if (kind == Diagnostic.Kind.ERROR) {
-                    logE(null, message);
-                } else {
-                    logD(message);
-                }
-            }
-        });
-    }
-
-    String readMyVersion() {
-        try {
-            InputStream stream = getClass().getResourceAsStream("/data_binding_build_info");
-            try {
-                return IOUtils.toString(stream, "utf-8").trim();
-            } finally {
-                IOUtils.closeQuietly(stream);
-            }
-        } catch (IOException exception) {
-            logE(exception, "Cannot read data binding version");
-        }
-        return null;
-    }
-
-    private void createXmlProcessor(Project project)
-            throws NoSuchFieldException, IllegalAccessException {
-        L.d("creating xml processor for " + project);
-        Object androidExt = project.getExtensions().getByName("android");
-        if (!(androidExt instanceof BaseExtension)) {
-            return;
-        }
-        if (androidExt instanceof AppExtension) {
-            createXmlProcessorForApp(project, (AppExtension) androidExt);
-        } else if (androidExt instanceof LibraryExtension) {
-            createXmlProcessorForLibrary(project, (LibraryExtension) androidExt);
-        } else {
-            logE(new UnsupportedOperationException("cannot understand android ext"),
-                    "unsupported android extension. What is it? %s", androidExt);
-        }
-    }
-
-    private void createXmlProcessorForLibrary(Project project, LibraryExtension lib)
-            throws NoSuchFieldException, IllegalAccessException {
-        File sdkDir = lib.getSdkDirectory();
-        L.d("create xml processor for " + lib);
-        for (TestVariant variant : lib.getTestVariants()) {
-            logD("test variant %s. dir name %s", variant, variant.getDirName());
-            BaseVariantData variantData = getVariantData(variant);
-            attachXmlProcessor(project, variantData, sdkDir, false);//tests extend apk variant
-        }
-        for (LibraryVariant variant : lib.getLibraryVariants()) {
-            logD("library variant %s. dir name %s", variant, variant.getDirName());
-            BaseVariantData variantData = getVariantData(variant);
-            attachXmlProcessor(project, variantData, sdkDir, true);
-        }
-    }
-
-    private void createXmlProcessorForApp(Project project, AppExtension appExt)
-            throws NoSuchFieldException, IllegalAccessException {
-        L.d("create xml processor for " + appExt);
-        File sdkDir = appExt.getSdkDirectory();
-        for (TestVariant testVariant : appExt.getTestVariants()) {
-            TestVariantData variantData = getVariantData(testVariant);
-            attachXmlProcessor(project, variantData, sdkDir, false);
-        }
-        for (ApplicationVariant appVariant : appExt.getApplicationVariants()) {
-            ApplicationVariantData variantData = getVariantData(appVariant);
-            attachXmlProcessor(project, variantData, sdkDir, false);
-        }
-    }
-
-    private LibraryVariantData getVariantData(LibraryVariant variant)
-            throws NoSuchFieldException, IllegalAccessException {
-        Field field = LibraryVariantImpl.class.getDeclaredField("variantData");
-        field.setAccessible(true);
-        return (LibraryVariantData) field.get(variant);
-    }
-
-    private TestVariantData getVariantData(TestVariant variant)
-            throws IllegalAccessException, NoSuchFieldException {
-        Field field = TestVariantImpl.class.getDeclaredField("variantData");
-        field.setAccessible(true);
-        return (TestVariantData) field.get(variant);
-    }
-
-    private ApplicationVariantData getVariantData(ApplicationVariant variant)
-            throws IllegalAccessException, NoSuchFieldException {
-        Field field = ApplicationVariantImpl.class.getDeclaredField("variantData");
-        field.setAccessible(true);
-        return (ApplicationVariantData) field.get(variant);
-    }
-
-    private void attachXmlProcessor(Project project, final BaseVariantData variantData,
-            final File sdkDir,
-            final Boolean isLibrary) {
-        final GradleVariantConfiguration configuration = variantData.getVariantConfiguration();
-        final ApiVersion minSdkVersion = configuration.getMinSdkVersion();
-        ProcessAndroidResources generateRTask = variantData.generateRClassTask;
-        final String packageName = generateRTask.getPackageForR();
-        String fullName = configuration.getFullName();
-        List<File> resourceFolders = Arrays.asList(variantData.mergeResourcesTask.getOutputDir());
-
-        final File codeGenTargetFolder = new File(project.getBuildDir() + "/data-binding-info/" +
-                configuration.getDirName());
-        String writerOutBase = codeGenTargetFolder.getAbsolutePath();
-        JavaFileWriter fileWriter = new GradleFileWriter(writerOutBase);
-        final LayoutXmlProcessor xmlProcessor = new LayoutXmlProcessor(packageName, resourceFolders,
-                fileWriter, minSdkVersion.getApiLevel(), isLibrary);
-        final ProcessAndroidResources processResTask = generateRTask;
-        final File xmlOutDir = new File(project.getBuildDir() + "/layout-info/" +
-                configuration.getDirName());
-        final File generatedClassListOut = isLibrary ? new File(xmlOutDir, "_generated.txt") : null;
-        logD("xml output for %s is %s", variantData, xmlOutDir);
-        String layoutTaskName = "dataBindingLayouts" + StringUtils
-                .capitalize(processResTask.getName());
-        String infoClassTaskName = "dataBindingInfoClass" + StringUtils
-                .capitalize(processResTask.getName());
-
-        final DataBindingProcessLayoutsTask[] processLayoutsTasks
-                = new DataBindingProcessLayoutsTask[1];
-        project.getTasks().create(layoutTaskName,
-                DataBindingProcessLayoutsTask.class,
-                new Action<DataBindingProcessLayoutsTask>() {
-                    @Override
-                    public void execute(final DataBindingProcessLayoutsTask task) {
-                        processLayoutsTasks[0] = task;
-                        task.setXmlProcessor(xmlProcessor);
-                        task.setSdkDir(sdkDir);
-                        task.setXmlOutFolder(xmlOutDir);
-                        task.setMinSdk(minSdkVersion.getApiLevel());
-
-                        logD("TASK adding dependency on %s for %s", task, processResTask);
-                        processResTask.dependsOn(task);
-                        processResTask.getInputs().dir(xmlOutDir);
-                        for (Object dep : processResTask.getDependsOn()) {
-                            if (dep == task) {
-                                continue;
-                            }
-                            logD("adding dependency on %s for %s", dep, task);
-                            task.dependsOn(dep);
-                        }
-                        processResTask.doLast(new Action<Task>() {
-                            @Override
-                            public void execute(Task unused) {
-                                try {
-                                    task.writeLayoutXmls();
-                                } catch (JAXBException e) {
-                                    // gradle sometimes fails to resolve JAXBException.
-                                    // We get stack trace manually to ensure we have the log
-                                    logE(e, "cannot write layout xmls %s",
-                                            ExceptionUtils.getStackTrace(e));
-                                }
-                            }
-                        });
-                    }
-                });
-        final DataBindingProcessLayoutsTask processLayoutsTask = processLayoutsTasks[0];
-        project.getTasks().create(infoClassTaskName,
-                DataBindingExportInfoTask.class,
-                new Action<DataBindingExportInfoTask>() {
-
-                    @Override
-                    public void execute(DataBindingExportInfoTask task) {
-                        task.dependsOn(processLayoutsTask);
-                        task.dependsOn(processResTask);
-                        task.setXmlProcessor(xmlProcessor);
-                        task.setSdkDir(sdkDir);
-                        task.setXmlOutFolder(xmlOutDir);
-                        task.setExportClassListTo(generatedClassListOut);
-                        task.setPrintEncodedErrors(printEncodedErrors);
-                        task.setEnableDebugLogs(logger.isEnabled(LogLevel.DEBUG));
-
-                        variantData.registerJavaGeneratingTask(task, codeGenTargetFolder);
-                    }
-                });
-        String packageJarTaskName = "package" + StringUtils.capitalize(fullName) + "Jar";
-        final Task packageTask = project.getTasks().findByName(packageJarTaskName);
-        if (packageTask instanceof Jar) {
-            String removeGeneratedTaskName = "dataBindingExcludeGeneratedFrom" +
-                    StringUtils.capitalize(packageTask.getName());
-            if (project.getTasks().findByName(removeGeneratedTaskName) == null) {
-                final AbstractCompile javaCompileTask = variantData.javacTask;
-                Preconditions.checkNotNull(javaCompileTask);
-
-                project.getTasks().create(removeGeneratedTaskName,
-                        DataBindingExcludeGeneratedTask.class,
-                        new Action<DataBindingExcludeGeneratedTask>() {
-                            @Override
-                            public void execute(DataBindingExcludeGeneratedTask task) {
-                                packageTask.dependsOn(task);
-                                task.dependsOn(javaCompileTask);
-                                task.setAppPackage(packageName);
-                                task.setInfoClassQualifiedName(xmlProcessor.getInfoClassFullName());
-                                task.setPackageTask((Jar) packageTask);
-                                task.setLibrary(isLibrary);
-                                task.setGeneratedClassListFile(generatedClassListOut);
-                            }
-                        });
-            }
-        }
-    }
-
-    private void logD(String s, Object... args) {
-        logger.info(formatLog(s, args));
-    }
-
-    private void logE(Throwable t, String s, Object... args) {
-        logger.error(formatLog(s, args), t);
-    }
-
-    private String formatLog(String s, Object... args) {
-        return "[data binding plugin]: " + String.format(s, args);
-    }
-}
diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExcludeGeneratedTask.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExcludeGeneratedTask.java
index a58d97a..f311513 100644
--- a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExcludeGeneratedTask.java
+++ b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExcludeGeneratedTask.java
@@ -88,6 +88,7 @@
         exclude(EXCLUDE_PATTERN);
         if (isLibrary) {
             exclude(appPkgAsClass + "/BR.*");
+            exclude("android/databinding/DynamicUtil.class");
             List<String> generatedClasses = readGeneratedClasses();
             for (String klass : generatedClasses) {
                 exclude(klass.replace('.', '/') + ".class");
diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExportInfoTask.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExportInfoTask.java
deleted file mode 100644
index 768fe68..0000000
--- a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingExportInfoTask.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.databinding.tool;
-
-import org.gradle.api.DefaultTask;
-import org.gradle.api.tasks.TaskAction;
-
-import android.databinding.tool.processing.Scope;
-
-import java.io.File;
-
-/**
- * Task to pass environment info to javac
- */
-public class DataBindingExportInfoTask extends DefaultTask {
-    private LayoutXmlProcessor xmlProcessor;
-    private File sdkDir;
-    private File xmlOutFolder;
-    private File exportClassListTo;
-    private boolean printEncodedErrors;
-    private boolean enableDebugLogs = false;
-    @TaskAction
-    public void exportInfo() {
-        xmlProcessor.writeInfoClass(sdkDir, xmlOutFolder, exportClassListTo, enableDebugLogs,
-                printEncodedErrors);
-        Scope.assertNoError();
-    }
-
-    public LayoutXmlProcessor getXmlProcessor() {
-        return xmlProcessor;
-    }
-
-    public void setXmlProcessor(LayoutXmlProcessor xmlProcessor) {
-        this.xmlProcessor = xmlProcessor;
-    }
-
-    public File getSdkDir() {
-        return sdkDir;
-    }
-
-    public void setSdkDir(File sdkDir) {
-        this.sdkDir = sdkDir;
-    }
-
-    public File getXmlOutFolder() {
-        return xmlOutFolder;
-    }
-
-    public void setXmlOutFolder(File xmlOutFolder) {
-        this.xmlOutFolder = xmlOutFolder;
-    }
-
-    public File getExportClassListTo() {
-        return exportClassListTo;
-    }
-
-    public void setExportClassListTo(File exportClassListTo) {
-        this.exportClassListTo = exportClassListTo;
-    }
-
-    public boolean isPrintEncodedErrors() {
-        return printEncodedErrors;
-    }
-
-    public void setPrintEncodedErrors(boolean printEncodedErrors) {
-        this.printEncodedErrors = printEncodedErrors;
-    }
-
-    public boolean isEnableDebugLogs() {
-        return enableDebugLogs;
-    }
-
-    public void setEnableDebugLogs(boolean enableDebugLogs) {
-        this.enableDebugLogs = enableDebugLogs;
-    }
-}
\ No newline at end of file
diff --git a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingProcessLayoutsTask.java b/gradlePlugin/src/main/java/android/databinding/tool/DataBindingProcessLayoutsTask.java
deleted file mode 100644
index 320d4dc..0000000
--- a/gradlePlugin/src/main/java/android/databinding/tool/DataBindingProcessLayoutsTask.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.databinding.tool;
-
-import android.databinding.tool.processing.Scope;
-import android.databinding.tool.util.L;
-
-import org.gradle.api.DefaultTask;
-import org.gradle.api.tasks.TaskAction;
-import org.xml.sax.SAXException;
-import java.io.File;
-import java.io.IOException;
-
-import javax.xml.bind.JAXBException;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPathExpressionException;
-
-/**
- * Task that parses xml files and generated metadata.
- * Will be removed when aapt supports binding tags.
- */
-public class DataBindingProcessLayoutsTask extends DefaultTask {
-
-    private LayoutXmlProcessor xmlProcessor;
-
-    private File sdkDir;
-
-    private File xmlOutFolder;
-
-    private int minSdk;
-
-    @TaskAction
-    public void processResources()
-            throws ParserConfigurationException, SAXException, XPathExpressionException,
-            IOException {
-        L.d("running process layouts task %s", getName());
-        xmlProcessor.processResources(minSdk);
-        Scope.assertNoError();
-    }
-
-    public void writeLayoutXmls() throws JAXBException {
-        xmlProcessor.writeLayoutInfoFiles(xmlOutFolder);
-    }
-
-    public LayoutXmlProcessor getXmlProcessor() {
-        return xmlProcessor;
-    }
-
-    public void setXmlProcessor(LayoutXmlProcessor xmlProcessor) {
-        this.xmlProcessor = xmlProcessor;
-    }
-
-    public File getSdkDir() {
-        return sdkDir;
-    }
-
-    public void setSdkDir(File sdkDir) {
-        this.sdkDir = sdkDir;
-    }
-
-    public File getXmlOutFolder() {
-        return xmlOutFolder;
-    }
-
-    public void setXmlOutFolder(File xmlOutFolder) {
-        this.xmlOutFolder = xmlOutFolder;
-    }
-
-    public int getMinSdk() {
-        return minSdk;
-    }
-
-    public void setMinSdk(int minSdk) {
-        this.minSdk = minSdk;
-    }
-}
diff --git a/gradlePlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties b/gradlePlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties
deleted file mode 100644
index 2e04d00..0000000
--- a/gradlePlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-implementation-class=android.databinding.tool.DataBinderPlugin
\ No newline at end of file
diff --git a/integration-tests/App With Spaces/app/build.gradle b/integration-tests/App With Spaces/app/build.gradle
index 4c8a182..15d5165 100644
--- a/integration-tests/App With Spaces/app/build.gradle
+++ b/integration-tests/App With Spaces/app/build.gradle
@@ -15,11 +15,10 @@
  */
 
 apply plugin: 'com.android.application'
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "22"
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
 
     defaultConfig {
         applicationId "com.android.databinding.appwithspaces"
@@ -28,6 +27,9 @@
         versionCode 1
         versionName "1.0"
     }
+    dataBinding {
+        enabled = true
+    }
     buildTypes {
         release {
             minifyEnabled false
diff --git a/integration-tests/App With Spaces/build.gradle b/integration-tests/App With Spaces/build.gradle
index b13840a..53e677e 100644
--- a/integration-tests/App With Spaces/build.gradle
+++ b/integration-tests/App With Spaces/build.gradle
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 buildscript {
-    ext.rootFolder = new File(project.projectDir, "../..")
+    ext.dataBindingRootFolder = new File(project.projectDir, "../..")
     apply from: "${project.projectDir}/../../propLoader.gradle"
     ext.addRepos(repositories)
     dependencies {
-        classpath "com.android.tools.build:gradle:${config.androidPluginVersion}"
-        classpath "com.android.databinding:dataBinder:${config.version}"
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
     }
 }
diff --git a/integration-tests/App With Spaces/gradle/wrapper/gradle-wrapper.properties b/integration-tests/App With Spaces/gradle/wrapper/gradle-wrapper.properties
index 992e276..f429d72 100644
--- a/integration-tests/App With Spaces/gradle/wrapper/gradle-wrapper.properties
+++ b/integration-tests/App With Spaces/gradle/wrapper/gradle-wrapper.properties
@@ -19,4 +19,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/integration-tests/IndependentLibrary/app/build.gradle b/integration-tests/IndependentLibrary/app/build.gradle
index e4e7ab9..90d7328 100644
--- a/integration-tests/IndependentLibrary/app/build.gradle
+++ b/integration-tests/IndependentLibrary/app/build.gradle
@@ -14,11 +14,10 @@
  */
 apply plugin: 'maven'
 apply plugin: 'com.android.library'
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "21.1.2"
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
 
     defaultConfig {
         minSdkVersion 7
@@ -26,6 +25,9 @@
         versionCode 1
         versionName "1.0"
     }
+    dataBinding {
+        enabled = true
+    }
     buildTypes {
         release {
             minifyEnabled false
@@ -47,10 +49,10 @@
 uploadArchives {
     repositories {
         mavenDeployer {
-            repository(url: "file://${config.mavenRepoDir}")
+            repository(url: "file://${dataBindingConfig.mavenRepoDir}")
             pom.artifactId = 'independent-library'
-            pom.version = config.version
-            pom.groupId = config.testGroup
+            pom.version = dataBindingConfig.version
+            pom.groupId = dataBindingConfig.testGroup
         }
     }
 }
diff --git a/integration-tests/IndependentLibrary/app/src/main/res/layout-sw600dp-land/library_layout.xml b/integration-tests/IndependentLibrary/app/src/main/res/layout-sw600dp-land/library_layout.xml
new file mode 100644
index 0000000..301663b
--- /dev/null
+++ b/integration-tests/IndependentLibrary/app/src/main/res/layout-sw600dp-land/library_layout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <data class=".IndependentLibraryBinding">
+        <variable name="foo"
+                  type="android.databinding.test.independentlibrary.vo.MyBindableObject"/>
+    </data>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
+                  android:id="@+id/fooTextView"
+                  android:text='@{foo.field +  " " + foo.field}'/>
+    </LinearLayout>
+</layout>
diff --git a/integration-tests/IndependentLibrary/build.gradle b/integration-tests/IndependentLibrary/build.gradle
index db36a5b..ca2e97c 100644
--- a/integration-tests/IndependentLibrary/build.gradle
+++ b/integration-tests/IndependentLibrary/build.gradle
@@ -14,11 +14,10 @@
  */
 
 buildscript {
-    ext.rootFolder = new File(project.projectDir, "../..")
+    ext.dataBindingRootFolder = new File(project.projectDir, "../..")
     apply from: "${project.projectDir}/../../propLoader.gradle"
     ext.addRepos(repositories)
     dependencies {
-        classpath "com.android.tools.build:gradle:${config.androidPluginVersion}"
-        classpath "com.android.databinding:dataBinder:${config.version}"
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
     }
 }
\ No newline at end of file
diff --git a/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.properties b/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.properties
index de86a57..8bb2e20 100644
--- a/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.properties
+++ b/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.properties
@@ -18,4 +18,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/integration-tests/MultiModuleTestApp/app/build.gradle b/integration-tests/MultiModuleTestApp/app/build.gradle
index 67a52d5..261a902 100644
--- a/integration-tests/MultiModuleTestApp/app/build.gradle
+++ b/integration-tests/MultiModuleTestApp/app/build.gradle
@@ -15,11 +15,10 @@
  */
 
 apply plugin: 'com.android.application'
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "22"
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
 
     defaultConfig {
         applicationId "com.android.databinding.multimoduletestapp"
@@ -28,6 +27,9 @@
         versionCode 1
         versionName "1.0"
     }
+    dataBinding {
+        enabled = true
+    }
     buildTypes {
         release {
             minifyEnabled false
@@ -42,10 +44,10 @@
     }
 }
 
-println "combined ${config.testGroup}.independent-library:${config.version}"
+println "combined ${dataBindingConfig.testGroup}.independent-library:${dataBindingConfig.version}"
 dependencies {
     compile fileTree(dir: 'libs', include: ['*.jar'])
     compile project(':testlibrary')
     compile "com.android.support:support-v4:+"
-    compile "${config.testGroup}:independent-library:${config.version}"
+    compile "${dataBindingConfig.testGroup}:independent-library:${dataBindingConfig.version}"
 }
diff --git a/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/EventIdsTest.java b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/EventIdsTest.java
index 9a04368..ec6df34 100644
--- a/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/EventIdsTest.java
+++ b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/EventIdsTest.java
@@ -20,7 +20,6 @@
 
 import android.databinding.Observable;
 import android.databinding.Observable.OnPropertyChangedCallback;
-import android.os.Debug;
 import android.test.AndroidTestCase;
 
 import java.util.HashMap;
@@ -113,7 +112,7 @@
     }
 
     private static class EventCounter extends OnPropertyChangedCallback {
-        Map<Integer, Integer> mCounter = new HashMap<>();
+        Map<Integer, Integer> mCounter = new HashMap<Integer, Integer>();
 
         @Override
         public void onPropertyChanged(Observable observable, int propertyId) {
diff --git a/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/GeneratedLayoutTest.java b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/GeneratedLayoutTest.java
new file mode 100644
index 0000000..f83e9c0
--- /dev/null
+++ b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/GeneratedLayoutTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.databinding.multimoduletestapp;
+
+import android.databinding.DataBindingUtil;
+import android.databinding.ViewDataBinding;
+import android.databinding.multimoduletestapp.R;
+import android.test.AndroidTestCase;
+import android.view.LayoutInflater;
+import android.view.View;
+
+public class GeneratedLayoutTest extends AndroidTestCase {
+    public void testBindToGeneratedLayout() {
+        LayoutInflater inflater = LayoutInflater.from(getContext());
+        View view = inflater.inflate(R.layout.library_layout, null);
+        // force override tag
+        view.setTag("layout-sw600dp-land-v13/library_layout_0");
+        ViewDataBinding bind = DataBindingUtil.bind(view);
+        assertEquals("IndependentLibraryBindingSw600dpLandV13Impl",
+                bind.getClass().getSimpleName());
+    }
+
+    public void testBindToDefault() {
+        LayoutInflater inflater = LayoutInflater.from(getContext());
+        View view = inflater.inflate(R.layout.library_layout, null);
+        // force override tag
+        view.setTag("layout/library_layout_0");
+        ViewDataBinding bind = DataBindingUtil.bind(view);
+        assertEquals("IndependentLibraryBindingImpl",
+                bind.getClass().getSimpleName());
+    }
+
+    public void testBindToSw600() {
+        LayoutInflater inflater = LayoutInflater.from(getContext());
+        View view = inflater.inflate(R.layout.library_layout, null);
+        // force override tag
+        view.setTag("layout-sw600dp-land/library_layout_0");
+        ViewDataBinding bind = DataBindingUtil.bind(view);
+        assertEquals("IndependentLibraryBindingSw600dpLandImpl",
+                bind.getClass().getSimpleName());
+    }
+}
diff --git a/integration-tests/MultiModuleTestApp/build.gradle b/integration-tests/MultiModuleTestApp/build.gradle
index 5e5a3e2..7dc5032 100644
--- a/integration-tests/MultiModuleTestApp/build.gradle
+++ b/integration-tests/MultiModuleTestApp/build.gradle
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 buildscript {
-    ext.rootFolder = new File(project.projectDir, "../..")
+    ext.dataBindingRootFolder = new File(project.projectDir, "../..")
     apply from: "${project.projectDir}/../../propLoader.gradle"
     ext.addRepos(repositories)
     dependencies {
-        classpath "com.android.tools.build:gradle:${config.androidPluginVersion}"
-        classpath "com.android.databinding:dataBinder:${config.version}"
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
     }
 }
\ No newline at end of file
diff --git a/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.properties b/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.properties
index 992e276..f429d72 100644
--- a/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.properties
+++ b/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.properties
@@ -19,4 +19,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/integration-tests/MultiModuleTestApp/testlibrary/build.gradle b/integration-tests/MultiModuleTestApp/testlibrary/build.gradle
index bbcff86..d1bde4d 100644
--- a/integration-tests/MultiModuleTestApp/testlibrary/build.gradle
+++ b/integration-tests/MultiModuleTestApp/testlibrary/build.gradle
@@ -15,11 +15,10 @@
  */
 
 apply plugin: 'com.android.library'
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 21
-    buildToolsVersion "21.1.2"
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
 
     defaultConfig {
         minSdkVersion 7
@@ -27,6 +26,9 @@
         versionCode 1
         versionName "1.0"
     }
+    dataBinding {
+        enabled = true
+    }
     buildTypes {
         release {
             minifyEnabled false
diff --git a/integration-tests/TestApp/app/build.gradle b/integration-tests/TestApp/app/build.gradle
index 652bde2..0701944 100644
--- a/integration-tests/TestApp/app/build.gradle
+++ b/integration-tests/TestApp/app/build.gradle
@@ -1,9 +1,8 @@
 apply plugin: 'com.android.application'
-apply plugin: 'com.android.databinding'
 
 android {
     compileSdkVersion 21
-    buildToolsVersion "22"
+    buildToolsVersion dataBindingConfig.buildToolsVersion
 
     defaultConfig {
         applicationId "com.android.databinding.testapp"
@@ -12,6 +11,9 @@
         versionCode 1
         versionName "1.0"
     }
+    dataBinding {
+        enabled = true
+    }
     buildTypes {
         release {
             minifyEnabled false
@@ -30,6 +32,9 @@
         api7 {
             minSdkVersion 7
         }
+        api14 {
+            minSdkVersion 14
+        }
     }
 }
 
diff --git a/integration-tests/TestApp/app/src/androidTest/java/android/databinding/DataBindingMapperTest.java b/integration-tests/TestApp/app/src/androidTest/java/android/databinding/DataBindingMapperTest.java
new file mode 100644
index 0000000..47075fd
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTest/java/android/databinding/DataBindingMapperTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding;
+
+
+import android.test.AndroidTestCase;
+import android.view.View;
+
+public class DataBindingMapperTest extends AndroidTestCase {
+    public void testNotDataBindingId() {
+        View view = new View(getContext());
+        view.setTag("layout/unexpected");
+        android.databinding.DataBinderMapper mapper = new android.databinding.DataBinderMapper();
+        ViewDataBinding binding = mapper.getDataBinder(null, view, 1);
+        assertNull(binding);
+    }
+    public void testInvalidView() {
+        View view = new View(getContext());
+        view.setTag("layout/unexpected");
+        android.databinding.DataBinderMapper mapper = new android.databinding.DataBinderMapper();
+        Throwable error = null;
+        try {
+            mapper.getDataBinder(null, view, android.databinding.testapp.R.layout.multi_res_layout);
+        } catch (Throwable t) {
+            error = t;
+        }
+        assertNotNull(error);
+        assertEquals("The tag for multi_res_layout is invalid. Received: layout/unexpected",
+                error.getMessage());
+
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi14/java/android/databinding/testapp/RootTag.java b/integration-tests/TestApp/app/src/androidTestApi14/java/android/databinding/testapp/RootTag.java
new file mode 100644
index 0000000..132beb6
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi14/java/android/databinding/testapp/RootTag.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp;
+
+import android.databinding.testapp.BaseDataBinderTest;
+import android.databinding.testapp.databinding.RootTagBinding;
+
+public class RootTag extends BaseDataBinderTest<RootTagBinding> {
+    public RootTag() {
+        super(RootTagBinding.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        initBinder();
+    }
+
+    public void testRootTagSet() throws Throwable {
+        mBinder.executePendingBindings();
+        assertEquals("foo", mBinder.textView1.getTag());
+        assertEquals("hello world", mBinder.textView1.getText().toString());
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/AbsSpinnerBindingAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/AbsSpinnerBindingAdapterTest.java
index d1d45f5..06f6477 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/AbsSpinnerBindingAdapterTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/AbsSpinnerBindingAdapterTest.java
@@ -17,11 +17,13 @@
 
 import android.databinding.testapp.databinding.AbsSpinnerAdapterTestBinding;
 import android.databinding.testapp.vo.AbsSpinnerBindingObject;
-
 import android.os.Build;
+import android.test.UiThreadTest;
 import android.widget.Spinner;
 import android.widget.SpinnerAdapter;
 
+import java.util.List;
+
 public class AbsSpinnerBindingAdapterTest
         extends BindingAdapterTestBase<AbsSpinnerAdapterTestBinding, AbsSpinnerBindingObject> {
 
@@ -38,6 +40,7 @@
         mView = mBinder.view;
     }
 
+    @UiThreadTest
     public void testEntries() throws Throwable {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             validateEntries();
@@ -48,6 +51,18 @@
         }
     }
 
+    @UiThreadTest
+    public void testList() throws Throwable {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            validateList();
+
+            mBindingObject.getList().add(1, "Cruel");
+            mBinder.executePendingBindings();
+
+            validateList();
+        }
+    }
+
     private void validateEntries() {
         assertEquals(mBindingObject.getEntries().length, mView.getAdapter().getCount());
         CharSequence[] entries = mBindingObject.getEntries();
@@ -56,4 +71,13 @@
             assertEquals(adapter.getItem(i), entries[i]);
         }
     }
+
+    private void validateList() {
+        List<String> entries = mBindingObject.getList();
+        SpinnerAdapter adapter = mBinder.view2.getAdapter();
+        assertEquals(entries.size(), adapter.getCount());
+        for (int i = 0; i < entries.size(); i++) {
+            assertEquals(adapter.getItem(i), entries.get(i));
+        }
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/AutoContextTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/AutoContextTest.java
new file mode 100644
index 0000000..74869c2
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/AutoContextTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.AutoContextBinding;
+
+import android.test.UiThreadTest;
+import android.widget.TextView;
+
+public class AutoContextTest extends BaseDataBinderTest<AutoContextBinding> {
+
+    public AutoContextTest() {
+        super(AutoContextBinding.class);
+    }
+
+    @UiThreadTest
+    public void testContext() throws Throwable {
+        AutoContextBinding binding = initBinder();
+        binding.executePendingBindings();
+        assertNotSame("", binding.textView1.getText().toString());
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java
index 031509d..136b7cc 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java
@@ -54,6 +54,7 @@
                 mBinder.setSparseBooleanArray(mSparseBooleanArray);
                 mBinder.setSparseLongArray(mSparseLongArray);
                 mBinder.setLongSparseArray(mLongSparseArray);
+                mBinder.setIndexObj((Integer) 0);
 
                 mBinder.executePendingBindings();
             }
@@ -69,4 +70,36 @@
         assertEquals("true", mBinder.sparseBooleanArrayText.getText().toString());
         assertEquals("5", mBinder.sparseLongArrayText.getText().toString());
     }
+
+    @UiThreadTest
+    public void testBracketOutOfBounds() {
+        mBinder.setIndex(1);
+        mBinder.executePendingBindings();
+        assertEquals("", mBinder.arrayText.getText().toString());
+        assertEquals("", mBinder.sparseArrayText.getText().toString());
+        assertEquals("", mBinder.longSparseArrayText.getText().toString());
+        assertEquals("0", mBinder.sparseIntArrayText.getText().toString());
+        assertEquals("false", mBinder.sparseBooleanArrayText.getText().toString());
+        assertEquals("0", mBinder.sparseLongArrayText.getText().toString());
+        mBinder.setIndex(-1);
+        mBinder.executePendingBindings();
+        assertEquals("", mBinder.arrayText.getText().toString());
+        assertEquals("", mBinder.sparseArrayText.getText().toString());
+        assertEquals("", mBinder.longSparseArrayText.getText().toString());
+        assertEquals("0", mBinder.sparseIntArrayText.getText().toString());
+        assertEquals("false", mBinder.sparseBooleanArrayText.getText().toString());
+        assertEquals("0", mBinder.sparseLongArrayText.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testBracketObj() {
+        mBinder.executePendingBindings();
+        assertEquals("Hello World", mBinder.indexObj.getText().toString());
+        assertEquals("Hello", mBinder.sparseArrayTextObj.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testBracketMap() throws Throwable {
+        assertEquals("", mBinder.bracketMap.getText().toString());
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConditionalBindingTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConditionalBindingTest.java
index 6f325c9..73c8c58 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConditionalBindingTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConditionalBindingTest.java
@@ -1,6 +1,7 @@
 package android.databinding.testapp;
 
 import android.databinding.testapp.databinding.ConditionalBindingBinding;
+import android.databinding.testapp.vo.ConditionalVo;
 import android.databinding.testapp.vo.NotBindableVo;
 
 import android.test.UiThreadTest;
@@ -17,6 +18,32 @@
         testCorrectness(true, true);
     }
 
+    @UiThreadTest
+    public void testTernary() throws Throwable {
+        ConditionalVo obj4 = new ConditionalVo();
+        initBinder();
+        mBinder.setObj4(obj4);
+        mBinder.executePendingBindings();
+        assertEquals("hello", mBinder.textView1.getText().toString());
+        obj4.setUseHello(true);
+        mBinder.executePendingBindings();
+        assertEquals("Hello World", mBinder.textView1.getText().toString());
+    }
+
+    @UiThreadTest
+    public void testNullListener() throws Throwable {
+        ConditionalVo obj4 = new ConditionalVo();
+        initBinder();
+        mBinder.setObj4(obj4);
+        mBinder.executePendingBindings();
+        mBinder.view1.callOnClick();
+        assertFalse(obj4.wasClicked);
+        mBinder.setCond1(true);
+        mBinder.executePendingBindings();
+        mBinder.view1.callOnClick();
+        assertTrue(obj4.wasClicked);
+    }
+
     private void testCorrectness(boolean cond1, boolean cond2) {
         NotBindableVo o1 = new NotBindableVo("a");
         NotBindableVo o2 = new NotBindableVo("b");
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConstExpressionTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConstExpressionTest.java
new file mode 100644
index 0000000..30d7926
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConstExpressionTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.ConstExpressionTestBinding;
+import android.databinding.testapp.databinding.ExpressionTestBinding;
+import android.test.UiThreadTest;
+
+public class ConstExpressionTest extends BaseDataBinderTest<ConstExpressionTestBinding> {
+    public ConstExpressionTest() {
+        super(ConstExpressionTestBinding.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        initBinder();
+    }
+
+
+    @UiThreadTest
+    public void testConstantExpression() throws Throwable {
+        mBinder.setVar1(1000);
+        mBinder.setVar2(2000);
+        mBinder.executePendingBindings();
+        assertEquals("1000", mBinder.textView.getText().toString());
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConverterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConverterTest.java
new file mode 100644
index 0000000..35a98fc
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ConverterTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.ConvertersBinding;
+
+import android.test.UiThreadTest;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+public class ConverterTest extends BaseDataBinderTest<ConvertersBinding> {
+    public ConverterTest() {
+        super(ConvertersBinding.class);
+    }
+
+    @UiThreadTest
+    public void testGenericConverter() {
+        initBinder();
+        ArrayList<String> values = new ArrayList<String>();
+        LinkedList<String> linkedValues = new LinkedList<String>();
+        values.add("Hello");
+        values.add("World");
+        linkedValues.add("Holy");
+        linkedValues.add("Cow!");
+        mBinder.setList(values);
+        mBinder.setLinked(linkedValues);
+        mBinder.executePendingBindings();
+        assertEquals("Hello World", mBinder.textView1.getText().toString());
+        assertEquals("Holy Cow!", mBinder.textView2.getText().toString());
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/DuplicateContextTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/DuplicateContextTest.java
new file mode 100644
index 0000000..43a2f8a
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/DuplicateContextTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.DuplicateContextBinding;
+
+import android.test.UiThreadTest;
+import android.widget.TextView;
+
+public class DuplicateContextTest extends BaseDataBinderTest<DuplicateContextBinding> {
+
+    public DuplicateContextTest() {
+        super(DuplicateContextBinding.class);
+    }
+
+    @UiThreadTest
+    public void testContext() throws Throwable {
+        DuplicateContextBinding binding = initBinder();
+        binding.setContext("Hello World");
+        binding.executePendingBindings();
+        assertEquals("Hello World", binding.textView1.getText().toString());
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ExpressionTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ExpressionTest.java
index ce1eafa..25965a7 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ExpressionTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ExpressionTest.java
@@ -16,11 +16,8 @@
 package android.databinding.testapp;
 
 import android.databinding.testapp.databinding.ExpressionTestBinding;
-import android.support.v4.util.ArrayMap;
 import android.test.UiThreadTest;
 
-import java.util.ArrayList;
-
 public class ExpressionTest extends BaseDataBinderTest<ExpressionTestBinding> {
     public ExpressionTest() {
         super(ExpressionTestBinding.class);
@@ -158,4 +155,23 @@
         assertEquals(mBinder.getBool1() ? appName : mBinder.getBool2() ? rain : "",
                 mBinder.textView18.getText().toString());
     }
+
+    @UiThreadTest
+    public void testBoundTag() throws Throwable {
+        mBinder.setBool1(false);
+        mBinder.executePendingBindings();
+        assertEquals("bar", mBinder.textView19.getTag());
+        mBinder.setBool1(true);
+        mBinder.executePendingBindings();
+        assertEquals("foo", mBinder.textView19.getTag());
+    }
+
+    @UiThreadTest
+    public void testConstantExpression() throws Throwable {
+        mBinder.setVar1(1000);
+        mBinder.setVar2(2000);
+        mBinder.executePendingBindings();
+        assertEquals("1000", mBinder.textView20.getText().toString());
+        assertEquals("2000", mBinder.textView21.getText().toString());
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindFieldTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindFieldTest.java
index 6c73cde..ca0ed53 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindFieldTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindFieldTest.java
@@ -33,4 +33,11 @@
         mBinder.executePendingBindings();
         assertEquals(obj.mPublicField, mBinder.textView1.getText().toString());
     }
+
+    @UiThreadTest
+    public void testFieldOnGeneric() {
+        initBinder();
+        mBinder.executePendingBindings();
+        assertEquals("Hello", mBinder.textView2.getText().toString());
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindMethodTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindMethodTest.java
index f5f5c72..a7799dc 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindMethodTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FindMethodTest.java
@@ -116,4 +116,11 @@
         mBinder.executePendingBindings();
         assertEquals("barfoo", mBinder.textView26.getText().toString());
     }
+
+    @UiThreadTest
+    public void testPrimitiveToObject() throws Throwable {
+        mBinder.executePendingBindings();
+        assertTrue(mBinder.textView27.getTag() instanceof Integer);
+        assertEquals((Integer)1, mBinder.textView27.getTag());
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FrameLayoutBindingAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FrameLayoutBindingAdapterTest.java
index 1f2f835..5246f6b 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FrameLayoutBindingAdapterTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/FrameLayoutBindingAdapterTest.java
@@ -19,6 +19,7 @@
 import android.databinding.testapp.vo.FrameLayoutBindingObject;
 
 import android.os.Build;
+import android.test.UiThreadTest;
 import android.widget.FrameLayout;
 
 public class FrameLayoutBindingAdapterTest
@@ -37,6 +38,7 @@
         mView = mBinder.view;
     }
 
+    @UiThreadTest
     public void testTint() throws Throwable {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             assertEquals(mBindingObject.getForegroundTint(),
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ImageViewBindingAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ImageViewBindingAdapterTest.java
index 5b995f4..19f025d 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ImageViewBindingAdapterTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ImageViewBindingAdapterTest.java
@@ -66,4 +66,14 @@
         assertNotNull(mBinder.view2.getDrawable());
         assertNotNull(mBinder.view3.getDrawable());
     }
+
+    @UiThreadTest
+    public void testConditionalSource() throws Throwable {
+        mBinder.setObj(null);
+        mBinder.executePendingBindings();
+        assertNotNull(mBinder.view4.getDrawable());
+        mBinder.setObj(new ImageViewBindingObject());
+        mBinder.executePendingBindings();
+        assertNull(mBinder.view4.getDrawable());
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/IncludeTagTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/IncludeTagTest.java
index f9ba635..5c2b860 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/IncludeTagTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/IncludeTagTest.java
@@ -19,6 +19,7 @@
 import android.databinding.testapp.vo.NotBindableVo;
 
 import android.test.UiThreadTest;
+import android.widget.FrameLayout;
 import android.widget.TextView;
 
 public class IncludeTagTest extends BaseDataBinderTest<LayoutWithIncludeBinding> {
@@ -30,6 +31,8 @@
     @UiThreadTest
     public void testIncludeTag() {
         initBinder();
+        assertNotNull(mBinder.includedPlainLayout);
+        assertTrue(mBinder.includedPlainLayout instanceof FrameLayout);
         NotBindableVo vo = new NotBindableVo(3, "a");
         mBinder.setOuterObject(vo);
         mBinder.executePendingBindings();
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/InstanceAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/InstanceAdapterTest.java
index c4e7dd0..f8ad690 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/InstanceAdapterTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/InstanceAdapterTest.java
@@ -18,6 +18,8 @@
 import android.databinding.DataBindingComponent;
 import android.databinding.DataBindingUtil;
 import android.databinding.testapp.adapter.InstanceAdapter;
+import android.databinding.testapp.adapter.NameClashAdapter;
+import android.databinding.testapp.adapter.NameClashAdapter.MyAdapter;
 import android.databinding.testapp.databinding.IncludeInstanceAdapterBinding;
 import android.databinding.testapp.databinding.InstanceAdapterBinding;
 import android.test.UiThreadTest;
@@ -38,6 +40,26 @@
             private InstanceAdapter mInstanceAdapter = new InstanceAdapter("Hello %s %s %s %s");
 
             @Override
+            public MyAdapter getMyAdapter1() {
+                return null;
+            }
+
+            @Override
+            public android.databinding.testapp.adapter2.NameClashAdapter.MyAdapter getMyAdapter2() {
+                return null;
+            }
+
+            @Override
+            public NameClashAdapter getNameClashAdapter1() {
+                return null;
+            }
+
+            @Override
+            public android.databinding.testapp.adapter2.NameClashAdapter getNameClashAdapter2() {
+                return null;
+            }
+
+            @Override
             public InstanceAdapter getInstanceAdapter() {
                 return mInstanceAdapter;
             }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java
index d9fa756..8f63bcc 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java
@@ -82,7 +82,7 @@
             public void run() {
                 getActivity().setContentView(new FrameLayout(getActivity()));
                 binding.setName("goodbye world");
-                binding.getRoot().postOnAnimation(watcher);
+                getActivity().getWindow().getDecorView().postOnAnimation(watcher);
             }
         });
 
@@ -93,7 +93,7 @@
             public void run() {
                 assertEquals("hello world", binding.textView.getText().toString());
                 getActivity().setContentView(binding.getRoot());
-                binding.getRoot().postOnAnimation(watcher);
+                getActivity().getWindow().getDecorView().postOnAnimation(watcher);
             }
         });
 
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ListenerTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ListenerTest.java
index 8fc67bf..d15f829 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ListenerTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ListenerTest.java
@@ -16,6 +16,7 @@
 import android.databinding.ViewStubProxy;
 import android.databinding.testapp.databinding.ListenersBinding;
 import android.databinding.testapp.vo.ListenerBindingObject;
+import android.databinding.testapp.vo.ListenerBindingObject.Inner;
 import android.test.UiThreadTest;
 import android.view.View;
 
@@ -113,4 +114,15 @@
         assertTrue(mBindingObject.inflateCalled);
         assertTrue(viewStubProxy.isInflated());
     }
+
+    @UiThreadTest
+    public void testBaseObservableClick() throws Throwable {
+        View view = mBinder.click6;
+        Inner inner = new Inner();
+        mBinder.setObj2(inner);
+        mBinder.executePendingBindings();
+        assertFalse(inner.clicked);
+        view.callOnClick();
+        assertTrue(inner.clicked);
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/NameMappingTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/NameMappingTest.java
new file mode 100644
index 0000000..ce505d5
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/NameMappingTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.NameMappingTestBinding;
+import android.databinding.testapp.vo.BasicObject;
+import android.test.UiThreadTest;
+import android.databinding.testapp.BR;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class NameMappingTest extends BaseDataBinderTest<NameMappingTestBinding> {
+
+    public NameMappingTest() {
+        super(NameMappingTestBinding.class);
+    }
+
+    @UiThreadTest
+    public void testChanges() {
+        initBinder();
+        final AtomicBoolean f1 = new AtomicBoolean(false);
+        final AtomicBoolean f2 = new AtomicBoolean(false);
+        BasicObject object = new BasicObject() {
+            @Override
+            public boolean isThisNameDoesNotMatchAnythingElse1() {
+                return f1.get();
+            }
+
+            @Override
+            public boolean getThisNameDoesNotMatchAnythingElse2() {
+                return f2.get();
+            }
+        };
+        mBinder.setObj(object);
+        mBinder.executePendingBindings();
+        for (int i = 0; i < 5; i ++) {
+            boolean f1New = (i & 1) != 0;
+            boolean f2New = (i & 1 << 1) != 0;
+            if (f1New != f1.get()) {
+                f1.set(f1New);
+                object.notifyPropertyChanged(BR.thisNameDoesNotMatchAnythingElse1);
+            }
+            if (f2New != f2.get()) {
+                f1.set(f2New);
+                object.notifyPropertyChanged(BR.thisNameDoesNotMatchAnythingElse2);
+            }
+            mBinder.executePendingBindings();
+            assertEquals(f2.get(), mBinder.textView.isEnabled());
+            assertEquals(f2.get(), mBinder.textView2.isEnabled());
+            assertEquals(false, mBinder.textView3.isEnabled());
+
+            assertEquals(f1.get(), mBinder.textView.isFocusable());
+            assertEquals(f1.get(), mBinder.textView2.isFocusable());
+            assertEquals(false, mBinder.textView3.isFocusable());
+        }
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/NoVariableIncludeTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/NoVariableIncludeTest.java
new file mode 100644
index 0000000..916cb50
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/NoVariableIncludeTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.IncludeNoVariablesBinding;
+import android.test.UiThreadTest;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class NoVariableIncludeTest extends BaseDataBinderTest<IncludeNoVariablesBinding> {
+
+    public NoVariableIncludeTest() {
+        super(IncludeNoVariablesBinding.class);
+    }
+
+    @UiThreadTest
+    public void testInclude() {
+        initBinder();
+        mBinder.executePendingBindings();
+        assertNotNull(mBinder.included);
+        assertNotNull(mBinder.included.textView);
+        String expectedValue = getActivity().getResources().getString(R.string.app_name);
+        assertEquals(expectedValue, mBinder.included.textView.getText().toString());
+        TextView noIdInclude = (TextView) ((ViewGroup) mBinder.getRoot()).getChildAt(1);
+        assertEquals(expectedValue, noIdInclude.getText().toString());
+    }
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java
index 98272dd..c6bc671 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java
@@ -22,6 +22,7 @@
 import android.databinding.adapters.TextViewBindingAdapter;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Build;
+import android.test.UiThreadTest;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.InputType;
@@ -301,4 +302,17 @@
         assertTrue(TextViewBindingObject.KeyListener2.class.isInstance(textView.getKeyListener()));
     }
 
+    @UiThreadTest
+    public void testTextWithTheme() throws Throwable {
+        TextView textView = mBinder.textWithTheme;
+        assertNotNull(textView.getTextColors());
+    }
+
+    @UiThreadTest
+    public void testTextWithColor() throws Throwable {
+        TextView textView = mBinder.textWithColor;
+        int expectedColor = mBinder.getRoot().getResources().getColor(
+                android.R.color.holo_blue_bright);
+        assertEquals(expectedColor, textView.getCurrentTextColor());
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/UnnecessaryCalculationTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/UnnecessaryCalculationTest.java
new file mode 100644
index 0000000..986156c
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/UnnecessaryCalculationTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp;
+
+import android.databinding.testapp.databinding.UnnecessaryCalculationBinding;
+import android.databinding.testapp.vo.BasicObject;
+import android.support.annotation.UiThread;
+import android.test.UiThreadTest;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class UnnecessaryCalculationTest extends BaseDataBinderTest<UnnecessaryCalculationBinding> {
+
+    public UnnecessaryCalculationTest() {
+        super(UnnecessaryCalculationBinding.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        initBinder();
+    }
+
+    @UiThreadTest
+    public void testDontSetUnnecessaryFlags() {
+        BasicObjWithCounter obja = new BasicObjWithCounter();
+        BasicObjWithCounter objb = new BasicObjWithCounter();
+        BasicObjWithCounter objc = new BasicObjWithCounter();
+        mBinder.setObja(obja);
+        mBinder.setObjb(objb);
+        mBinder.setObjc(objc);
+        mBinder.setA(true);
+        mBinder.setB(true);
+        mBinder.setC(false);
+        mBinder.executePendingBindings();
+        assertEquals("true", mBinder.textView.getText().toString());
+        assertEquals("true", mBinder.textView2.getText().toString());
+        assertEquals(1, obja.counter);
+        assertEquals(1, objb.counter);
+        assertEquals(0, objc.counter);
+        obja = new BasicObjWithCounter();
+        mBinder.setObja(obja);
+        mBinder.executePendingBindings();
+        assertEquals("true", mBinder.textView.getText().toString());
+        assertEquals("true", mBinder.textView2.getText().toString());
+        assertEquals(1, obja.counter);
+        assertEquals(1, objb.counter);
+        assertEquals(0, objc.counter);
+    }
+
+    private static class BasicObjWithCounter extends BasicObject {
+        int counter = 0;
+
+        @Override
+        public String boolMethod(boolean value) {
+            counter ++;
+            return super.boolMethod(value);
+        }
+    }
+
+}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewBindingAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewBindingAdapterTest.java
index c9bbb35..3fe918a 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewBindingAdapterTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewBindingAdapterTest.java
@@ -15,10 +15,10 @@
  */
 package android.databinding.testapp;
 
+import android.content.res.ColorStateList;
 import android.databinding.testapp.databinding.ViewAdapterTestBinding;
 import android.databinding.testapp.vo.ViewBindingObject;
-
-import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.test.UiThreadTest;
 import android.view.View;
@@ -177,4 +177,17 @@
             assertEquals(mBindingObject.getTransformPivotY(), view.getPivotY());
         }
     }
+
+    @UiThreadTest
+    public void testBackgroundDrawableDrawable() throws Throwable {
+        View view = mBinder.backgroundDrawable;
+        Drawable drawable = view.getBackground();
+        assertNotNull(drawable);
+    }
+
+    @UiThreadTest
+    public void testBackgroundDrawableWithTheme() throws Throwable {
+        View view = mBinder.backgroundWithTheme;
+        assertNotNull(view.getBackground());
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewWithTagTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewWithTagTest.java
index 05ad2b1..f1f5e9e 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewWithTagTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/ViewWithTagTest.java
@@ -37,5 +37,6 @@
         assertTrue(view2 instanceof TextView);
         assertEquals("i don't have tag", ((TextView) view2).getText().toString());
         assertEquals("i have a tag", view1.getTag().toString());
+        assertEquals("Hello", view2.getTag(R.id.customTag));
     }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/LandscapeConfigTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/LandscapeConfigTest.java
index 965562f..ddda269 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/LandscapeConfigTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/LandscapeConfigTest.java
@@ -15,6 +15,7 @@
 
 import android.databinding.ViewDataBinding;
 import android.databinding.testapp.BaseLandDataBinderTest;
+import android.databinding.testapp.BR;
 import android.databinding.testapp.R;
 import android.databinding.testapp.databinding.BasicBindingBinding;
 import android.databinding.testapp.databinding.ConditionalBindingBinding;
@@ -23,6 +24,7 @@
 import android.databinding.testapp.vo.NotBindableVo;
 
 import android.content.pm.ActivityInfo;
+import android.test.UiThreadTest;
 import android.view.View;
 import android.widget.TextView;
 
@@ -49,4 +51,13 @@
         assertPublicField(ConditionalBindingBinding.class, "includedLayoutPort");
         assertPublicField(ConditionalBindingBinding.class, "includedLayoutLand");
     }
+
+    @UiThreadTest
+    public void testSetVariable() throws Throwable {
+        initBinder();
+        assertTrue(mBinder.setVariable(BR.objectInBoth, null));
+        assertTrue(mBinder.setVariable(BR.objectInDefault, null));
+        assertTrue(mBinder.setVariable(BR.objectInLand, null));
+        assertFalse(mBinder.setVariable(BR.obj, null));
+    }
 }
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/PortraitConfigTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/PortraitConfigTest.java
index b1d1469..6a259bb 100644
--- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/PortraitConfigTest.java
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/multiconfig/PortraitConfigTest.java
@@ -15,6 +15,7 @@
 
 import android.databinding.ViewDataBinding;
 import android.databinding.testapp.BaseDataBinderTest;
+import android.databinding.testapp.BR;
 import android.databinding.testapp.databinding.BasicBindingBinding;
 import android.databinding.testapp.databinding.ConditionalBindingBinding;
 import android.databinding.testapp.databinding.IncludedLayoutBinding;
@@ -22,6 +23,7 @@
 import android.databinding.testapp.vo.NotBindableVo;
 
 import android.content.pm.ActivityInfo;
+import android.test.UiThreadTest;
 import android.view.View;
 import android.widget.EditText;
 import android.widget.TextView;
@@ -47,4 +49,13 @@
         assertPublicField(ConditionalBindingBinding.class, "includedLayoutPort");
         assertPublicField(ConditionalBindingBinding.class, "includedLayoutLand");
     }
+
+    @UiThreadTest
+    public void testSetVariable() throws Throwable {
+        initBinder();
+        assertTrue(mBinder.setVariable(BR.objectInBoth, null));
+        assertTrue(mBinder.setVariable(BR.objectInDefault, null));
+        assertFalse(mBinder.setVariable(BR.obj, null));
+        assertFalse(mBinder.setVariable(BR.objectInLand, null));
+    }
 }
diff --git a/integration-tests/TestApp/app/src/api14/res/layout/root_tag.xml b/integration-tests/TestApp/app/src/api14/res/layout/root_tag.xml
new file mode 100644
index 0000000..b7be6bf
--- /dev/null
+++ b/integration-tests/TestApp/app/src/api14/res/layout/root_tag.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <data>
+        <variable name="var1" type="int"/>
+        <variable name="var2" type="int"/>
+        <variable name="bool1" type="boolean"/>
+        <variable name="bool2" type="boolean"/>
+    </data>
+    <TextView
+            android:id="@+id/textView1"
+            android:tag="@{`foo`}"
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:text="@{`hello world`}"/>
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/GenericConverter.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/GenericConverter.java
new file mode 100644
index 0000000..a8aae55
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/GenericConverter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp.adapter;
+
+import android.databinding.BindingConversion;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+public class GenericConverter {
+    @BindingConversion
+    public static <T> String convertArrayList(ArrayList<T> values) {
+        return convert(values);
+    }
+
+    @BindingConversion
+    public static String convertLinkedList(LinkedList<?> values) {
+        return convert(values);
+    }
+
+    private static <T> String convert(List<T> values) {
+        if (values == null) {
+            return "";
+        }
+        StringBuilder vals = new StringBuilder();
+        for (T val : values) {
+            if (vals.length() != 0) {
+                vals.append(' ');
+            }
+            vals.append(val);
+        }
+        return vals.toString();
+    }
+}
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/MultiArgTestAdapter.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/MultiArgTestAdapter.java
index f83cd8d..062b884 100644
--- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/MultiArgTestAdapter.java
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/MultiArgTestAdapter.java
@@ -21,8 +21,6 @@
 import android.databinding.testapp.BR;
 import android.widget.TextView;
 
-import org.apache.commons.lang3.StringUtils;
-
 public class MultiArgTestAdapter {
 
     public static String join(BaseMultiBindingClass... classes) {
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/NameClashAdapter.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/NameClashAdapter.java
new file mode 100644
index 0000000..9435698
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/NameClashAdapter.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp.adapter;
+
+import android.databinding.BindingAdapter;
+import android.view.View;
+
+public class NameClashAdapter {
+    @BindingAdapter("gabble-babble")
+    public void setGabbleBabble(View view, String value) {
+    }
+
+    public static class MyAdapter {
+        @BindingAdapter({"gabble-babble-flabble", "booble-beeble-bee"})
+        public void setGabbleBabbleFlabble(View view, String value, String value2) {
+        }
+    }
+}
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/WeirdListeners.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/WeirdListeners.java
index 5f7bb5d..df20022 100644
--- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/WeirdListeners.java
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/WeirdListeners.java
@@ -27,6 +27,17 @@
     @BindingAdapter("android:onFoo2")
     public static void setListener(View view, OnFoo2 onFoo) {}
 
+    @BindingAdapter("android:onBar1")
+    public static void setListener(View view, OnBar1 onBar) {}
+
+    @BindingAdapter("android:onBar2")
+    public static void setListener(View view, OnBar2 onBar) {}
+
+    @BindingAdapter({"runnable", "fooId", "barId"})
+    public static void setRunnable(View view, Runnable runnable, int foo, int bar) {
+        runnable.run();
+    }
+
     @TargetApi(VERSION_CODES.ICE_CREAM_SANDWICH)
     public static abstract class OnFoo {
         public abstract void onFoo();
@@ -37,4 +48,14 @@
     public interface OnFoo2 {
         void onFoo();
     }
+
+    @TargetApi(VERSION_CODES.ICE_CREAM_SANDWICH)
+    public interface OnBar1 {
+        void onBar();
+    }
+
+    @TargetApi(VERSION_CODES.GINGERBREAD)
+    public interface OnBar2 {
+        boolean onBar(View view);
+    }
 }
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter2/NameClashAdapter.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter2/NameClashAdapter.java
new file mode 100644
index 0000000..53eb77b
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter2/NameClashAdapter.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp.adapter2;
+
+import android.databinding.BindingAdapter;
+import android.view.View;
+
+public class NameClashAdapter {
+    @BindingAdapter("gooble-flooble")
+    public void setGoogleFlooble(View view, String value) {
+    }
+
+    public static class MyAdapter {
+        @BindingAdapter({"gooble-flooble-booble", "rumple-bumple-bum"})
+        public void setGoogleFloobleBooble(View view, String value, String value2) {
+        }
+    }
+}
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/AbsSpinnerBindingObject.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/AbsSpinnerBindingObject.java
index 05d7ed7..61b8a36 100644
--- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/AbsSpinnerBindingObject.java
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/AbsSpinnerBindingObject.java
@@ -16,6 +16,10 @@
 package android.databinding.testapp.vo;
 
 import android.databinding.Bindable;
+import android.databinding.ObservableArrayList;
+import android.databinding.ObservableList;
+
+import java.util.List;
 
 public class AbsSpinnerBindingObject extends BindingAdapterBindingObject {
     @Bindable
@@ -30,6 +34,13 @@
             "world"
     };
 
+    private ObservableList<String> mList = new ObservableArrayList<String>();
+
+    public AbsSpinnerBindingObject() {
+        mList.add("Hello");
+        mList.add("World");
+    }
+
     public CharSequence[] getEntries() {
         return mEntries;
     }
@@ -38,4 +49,8 @@
         mEntries = CHANGED_VALUES;
         notifyChange();
     }
+
+    public List<String> getList() {
+        return mList;
+    }
 }
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java
index 450f7fb..5f332ef 100644
--- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BasicObject.java
@@ -42,4 +42,19 @@
         this.mField2 = field2;
         notifyPropertyChanged(BR.field1);
     }
+
+    @Bindable
+    public boolean isThisNameDoesNotMatchAnythingElse1() {
+        // see: https://code.google.com/p/android/issues/detail?id=190207
+        return false;
+    }
+
+    @Bindable
+    public boolean getThisNameDoesNotMatchAnythingElse2() {
+        return false;
+    }
+
+    public String boolMethod(boolean value) {
+        return value ? "true" : "false";
+    }
 }
diff --git a/developmentPlugins/bintrayPlugin/build.gradle b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BracketObject.java
similarity index 63%
copy from developmentPlugins/bintrayPlugin/build.gradle
copy to integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BracketObject.java
index 364a5bb..aa6187f 100644
--- a/developmentPlugins/bintrayPlugin/build.gradle
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/BracketObject.java
@@ -13,22 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-apply plugin: 'groovy'
+package android.databinding.testapp.vo;
 
-repositories {
-    mavenCentral()
+import java.util.HashMap;
+
+public class BracketObject {
+    public HashMap<String, String> map = new HashMap<>();
 }
-
-dependencies {
-    compile gradleApi()
-    testCompile group: 'junit', name: 'junit', version: '4.12'
-}
-
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            pom.artifactId = 'bintray'
-            repository(url: "file://${config.extraPluginsRepoDir}")
-        }
-    }
-}
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/ConditionalVo.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/ConditionalVo.java
new file mode 100644
index 0000000..22ecb05
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/ConditionalVo.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.databinding.testapp.vo;
+
+import android.databinding.BaseObservable;
+import android.databinding.Bindable;
+import android.databinding.testapp.BR;
+import android.view.View;
+
+public class ConditionalVo extends BaseObservable {
+    private boolean useHello;
+    public String text = "Hello World";
+    public boolean wasClicked;
+
+    @Bindable
+    public boolean getUseHello() {
+        return useHello;
+    }
+
+    public void setUseHello(boolean useHello) {
+        this.useHello = useHello;
+        notifyPropertyChanged(BR.useHello);
+    }
+
+    public void clicked(View view) {
+        wasClicked = true;
+    }
+}
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/FindFieldBindingObject.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/FindFieldBindingObject.java
index 32d7b0e..d0e0043 100644
--- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/FindFieldBindingObject.java
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/FindFieldBindingObject.java
@@ -18,4 +18,8 @@
 
 public class FindFieldBindingObject {
     public String mPublicField;
+
+    public static class Inner<T> {
+        public static final String HELLO = "Hello";
+    }
 }
diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/ListenerBindingObject.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/ListenerBindingObject.java
index cc0c42c..94a71a0 100644
--- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/ListenerBindingObject.java
+++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/ListenerBindingObject.java
@@ -16,11 +16,11 @@
 package android.databinding.testapp.vo;
 
 import android.content.Context;
+import android.databinding.BaseObservable;
 import android.databinding.ObservableBoolean;
 import android.graphics.Outline;
 import android.media.MediaPlayer;
 import android.text.Editable;
-import android.view.ActionMode;
 import android.view.ContextMenu;
 import android.view.DragEvent;
 import android.view.KeyEvent;
@@ -47,6 +47,7 @@
     public static int lastClick = 0;
     public boolean inflateCalled;
     private final Context mContext;
+    public boolean wasRunnableRun;
 
     public final ObservableBoolean clickable = new ObservableBoolean();
     public final ObservableBoolean useOne = new ObservableBoolean();
@@ -247,7 +248,23 @@
         lastClick = 4;
     }
 
+    public void runnableRun() {
+        this.wasRunnableRun = true;
+    }
+
     public void onFoo() {
     }
 
+    public void onBar() {}
+
+    public boolean onBar(View view) {
+        return true;
+    }
+
+    public static class Inner extends BaseObservable {
+        public boolean clicked;
+        public void onClick(View view) {
+            clicked = true;
+        }
+    }
 }
diff --git a/integration-tests/TestApp/app/src/main/res/color/text_colors.xml b/integration-tests/TestApp/app/src/main/res/color/text_colors.xml
new file mode 100644
index 0000000..0043a02
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/color/text_colors.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+            android:color="?android:selectedWeekBackgroundColor"
+            android:state_pressed="false"
+            android:state_focused="false"
+            android:state_selected="false"
+            android:state_checkable="false"
+            android:state_checked="false"
+            android:state_enabled="false"
+            android:state_window_focused="false"/>
+</selector>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/drawable/circle.xml b/integration-tests/TestApp/app/src/main/res/drawable/circle.xml
new file mode 100644
index 0000000..e325ab3
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/drawable/circle.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shape="oval">
+    <solid
+        android:color="?android:selectedWeekBackgroundColor"/>
+</shape>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml b/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml
index bb2f58d..2b47694 100644
--- a/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml
@@ -14,12 +14,9 @@
 
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:bind="http://schemas.android.com/apk/res-auto">
-
-
-
-
     <data>
         <variable name="objectInLand" type="android.databinding.testapp.vo.NotBindableVo"/>
+        <variable name="objectInBoth" type="Object"/>
     </data>
     <LinearLayout
             android:orientation="vertical"
diff --git a/integration-tests/TestApp/app/src/main/res/layout/abs_spinner_adapter_test.xml b/integration-tests/TestApp/app/src/main/res/layout/abs_spinner_adapter_test.xml
index e24dfa3..579d4fe 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/abs_spinner_adapter_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/abs_spinner_adapter_test.xml
@@ -22,5 +22,8 @@
         <Spinner android:layout_width="match_parent" android:layout_height="match_parent"
                  android:id="@+id/view"
                  android:entries="@{obj.entries}"/>
+        <Spinner android:layout_width="match_parent" android:layout_height="match_parent"
+                 android:id="@+id/view2"
+                 android:entries="@{obj.list}"/>
     </LinearLayout>
 </layout>
diff --git a/integration-tests/TestApp/app/src/main/res/layout/auto_context.xml b/integration-tests/TestApp/app/src/main/res/layout/auto_context.xml
new file mode 100644
index 0000000..7098061
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/auto_context.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto">
+    <data>
+        <import type="android.text.format.DateUtils"/>
+    </data>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <TextView
+                android:id="@+id/textView1"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:text="@{DateUtils.formatDateTime(context, 0, 0)}"/>
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml b/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml
index 141ddb4..e9a0e2f 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml
@@ -19,6 +19,9 @@
         <variable name="sparseIntArray" type="android.util.SparseIntArray"/>
         <variable name="sparseLongArray" type="android.util.SparseLongArray"/>
         <variable name="longSparseArray" type="android.util.LongSparseArray&lt;String>"/>
+        <variable name="index" type="int"/>
+        <variable name="indexObj" type="Object"/>
+        <variable name="obj" type="android.databinding.testapp.vo.BracketObject"/>
     </data>
     <LinearLayout
             android:layout_width="match_parent"
@@ -28,32 +31,46 @@
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:id="@+id/arrayText"
-                  android:text="@{array[0]}"/>
+                  android:text="@{array[index]}"/>
+
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:id="@+id/indexObj"
+                  android:text="@{array[indexObj]}"/>
 
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:id="@+id/sparseArrayText"
-                  android:text='@{sparseArray[0]}'/>
+                  android:text='@{sparseArray[index]}'/>
+
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:id="@+id/sparseArrayTextObj"
+                  android:text='@{sparseArray[indexObj]}'/>
 
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:id="@+id/sparseBooleanArrayText"
-                  android:text='@{"" + sparseBooleanArray[0]}'/>
+                  android:text='@{"" + sparseBooleanArray[index]}'/>
 
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:id="@+id/sparseIntArrayText"
-                  android:text='@{"" + sparseIntArray[0]}'/>
+                  android:text='@{"" + sparseIntArray[index]}'/>
 
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:id="@+id/sparseLongArrayText"
-                  android:text='@{"" + sparseLongArray[0]}'/>
+                  android:text='@{"" + sparseLongArray[index]}'/>
 
         <TextView android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:id="@+id/longSparseArrayText"
-                  android:text='@{longSparseArray[0]}'/>
+                  android:text='@{longSparseArray[index]}'/>
 
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:id="@+id/bracketMap"
+                  android:text='@{obj.map["Hello"]}'/>
     </LinearLayout>
 </layout>
diff --git a/integration-tests/TestApp/app/src/main/res/layout/conditional_binding.xml b/integration-tests/TestApp/app/src/main/res/layout/conditional_binding.xml
index dabed89..675c37c 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/conditional_binding.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/conditional_binding.xml
@@ -16,6 +16,7 @@
         <variable name="obj1" type="android.databinding.testapp.vo.NotBindableVo"/>
         <variable name="obj2" type="android.databinding.testapp.vo.NotBindableVo"/>
         <variable name="obj3" type="android.databinding.testapp.vo.NotBindableVo"/>
+        <variable name="obj4" type="android.databinding.testapp.vo.ConditionalVo"/>
         <variable name="cond1" type="boolean"/>
         <variable name="cond2" type="boolean"/>
     </data>
@@ -28,5 +29,20 @@
                 android:text="@{cond1 ? cond2 ? obj1.stringValue : obj2.stringValue : obj3.stringValue}"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"/>
+        <TextView
+                android:id="@+id/textView2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@{obj4.text}"/>
+        <TextView
+                android:id="@+id/textView1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@{obj4.useHello ? obj4.text : `hello`}"/>
+        <View
+                android:id="@+id/view1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="@{cond1 ? obj4.clicked : null}"/>
     </LinearLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/const_expression_test.xml b/integration-tests/TestApp/app/src/main/res/layout/const_expression_test.xml
new file mode 100644
index 0000000..fa13e22
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/const_expression_test.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <data>
+        <variable name="var1" type="int"/>
+        <variable name="var2" type="int"/>
+    </data>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <TextView
+                android:id="@+id/textView"
+                android:text='@{true ? "" + var1 : "" + var2}'
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"/>
+    </LinearLayout>
+    <!--android:textIsSelectable="@{var1 > 1 ? true ? true : false : false}"-->
+
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/converters.xml b/integration-tests/TestApp/app/src/main/res/layout/converters.xml
new file mode 100644
index 0000000..f133819
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/converters.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <data>
+        <variable name="list" type="java.util.ArrayList&lt;String>"/>
+        <variable name="linked" type="java.util.LinkedList&lt;String>"/>
+    </data>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+        <TextView
+                android:id="@+id/textView1"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:text="@{list}"/>
+        <TextView
+                android:id="@+id/textView2"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:text="@{linked}"/>
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/duplicate_context.xml b/integration-tests/TestApp/app/src/main/res/layout/duplicate_context.xml
new file mode 100644
index 0000000..716b80f
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/duplicate_context.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto">
+    <data>
+        <variable name="context" type="String"/>
+    </data>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <TextView
+                android:id="@+id/textView1"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:text="@{context}"/>
+
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/expression_test.xml b/integration-tests/TestApp/app/src/main/res/layout/expression_test.xml
index 063f771..5858b81 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/expression_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/expression_test.xml
@@ -101,5 +101,20 @@
                 android:id="@+id/textView18"
                 android:layout_width="wrap_content" android:layout_height="wrap_content"
                 android:text="@{bool1 ? @string/app_name : bool2 ? @string/rain : null}"/>
+        <TextView
+                android:id="@+id/textView19"
+                android:tag="@{bool1 ? `foo` : `bar`}"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"/>
+        <TextView
+                android:id="@+id/textView20"
+                android:text='@{@bool/alwaysTrue ? "" + var1 : "" + var2}'
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"/>
+        <TextView
+                android:id="@+id/textView21"
+                android:text='@{@bool/alwaysFalse ? "" + var1 : "" + var2}'
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"/>
     </LinearLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/find_field_test.xml b/integration-tests/TestApp/app/src/main/res/layout/find_field_test.xml
index f9a9f7c..7c3e2e0 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/find_field_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/find_field_test.xml
@@ -13,6 +13,7 @@
   -->
 <layout xmlns:android="http://schemas.android.com/apk/res/android">
     <data>
+        <import type="android.databinding.testapp.vo.FindFieldBindingObject.Inner"/>
         <variable name="obj" type="android.databinding.testapp.vo.FindFieldBindingObject"/>
     </data>
     <LinearLayout
@@ -23,5 +24,10 @@
             android:text="@{obj.mPublicField}"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
+        <TextView
+                android:id="@+id/textView2"
+                android:text="@{Inner.HELLO}"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
     </LinearLayout>
 </layout>
diff --git a/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml b/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml
index 3755b73..509517f 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/find_method_test.xml
@@ -11,7 +11,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<layout xmlns:android="http://schemas.android.com/apk/res/android">
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto">
     <data>
         <variable name="obj" type="android.databinding.testapp.vo.FindMethodBindingObject"/>
         <import type="android.databinding.testapp.vo.FindMethodBindingObject.Bar"/>
@@ -134,5 +135,9 @@
             android:id="@+id/textView26"
             android:layout_width="wrap_content" android:layout_height="wrap_content"
             android:text="@{obj.observableClass.x}"/>
+        <TextView
+                android:id="@+id/textView27"
+                android:layout_width="wrap_content" android:layout_height="wrap_content"
+                app:tag="@{1}"/>
     </LinearLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/fragment_main.xml b/integration-tests/TestApp/app/src/main/res/layout/fragment_main.xml
new file mode 100644
index 0000000..e2fbf7c
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/fragment_main.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <fragment
+            android:id="@+id/fragment"
+            android:name="android.databinding.testapp.TestFragment"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+            />
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/image_view_adapter_test.xml b/integration-tests/TestApp/app/src/main/res/layout/image_view_adapter_test.xml
index b459dda..fb79249 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/image_view_adapter_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/image_view_adapter_test.xml
@@ -38,5 +38,10 @@
                 android:id="@+id/view3"
                 android:src="@{uriString}"
                 />
+        <ImageView
+                android:layout_width="match_parent" android:layout_height="match_parent"
+                android:id="@+id/view4"
+                android:src="@{obj == null ? @drawable/ic_launcher : null}"
+                />
     </LinearLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/include_no_variables.xml b/integration-tests/TestApp/app/src/main/res/layout/include_no_variables.xml
new file mode 100644
index 0000000..f0db2a3
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/include_no_variables.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent">
+        <include android:id="@+id/included" layout="@layout/no_variables"/>
+        <include layout="@layout/no_variables"/>
+    </FrameLayout>
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/layout_with_include.xml b/integration-tests/TestApp/app/src/main/res/layout/layout_with_include.xml
index 292db4f..06156f6 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/layout_with_include.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/layout_with_include.xml
@@ -49,6 +49,12 @@
                      android:id="@+id/thirdMerge"
                      bind:innerObject="@{outerObject}"
                      bind:innerValue="@{`third ` + outerObject.intValue}"/>
+
+            <FrameLayout android:layout_width="wrap_content"
+                         android:layout_height="wrap_content">
+                <!-- an included layout with just an id -->
+                <include android:id="@+id/includedPlainLayout" layout="@layout/plain_layout"/>
+            </FrameLayout>
         </LinearLayout>
     </FrameLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/listeners.xml b/integration-tests/TestApp/app/src/main/res/layout/listeners.xml
index 2922177..00a26ff 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/listeners.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/listeners.xml
@@ -12,9 +12,11 @@
   ~ limitations under the License.
   -->
 
-<layout xmlns:android="http://schemas.android.com/apk/res/android">
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto">
     <data>
         <variable name="obj" type="android.databinding.testapp.vo.ListenerBindingObject"/>
+        <variable name="obj2" type="android.databinding.testapp.vo.ListenerBindingObject.Inner"/>
         <import type="android.databinding.testapp.vo.ListenerBindingObject"/>
     </data>
     <LinearLayout
@@ -317,5 +319,23 @@
               android:onFoo="@{obj.onFoo}"
               android:onFoo2="@{obj.onFoo}"
                 />
+        <View android:id="@+id/listener2"
+              android:layout_width="10dp"
+              android:layout_height="10dp"
+              android:onBar1="@{obj.onBar}"
+              android:onBar2="@{obj.onBar}"
+                />
+        <View android:id="@+id/click6"
+              android:layout_width="10dp"
+              android:layout_height="10dp"
+              android:onClick="@{obj2.onClick}"
+                />
+        <View android:id="@+id/click7"
+              android:layout_width="10dp"
+              android:layout_height="10dp"
+              app:fooId="@{1}"
+              app:barId="@{2}"
+              app:runnable="@{obj.runnableRun}"
+                />
     </LinearLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/multi_res_layout.xml b/integration-tests/TestApp/app/src/main/res/layout/multi_res_layout.xml
index 41031a7..0a80250 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/multi_res_layout.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/multi_res_layout.xml
@@ -16,6 +16,7 @@
         xmlns:bind="http://schemas.android.com/apk/res-auto">
     <data>
         <variable name="objectInDefault" type="android.databinding.testapp.vo.NotBindableVo"/>
+        <variable name="objectInBoth" type="Object"/>
     </data>
     <LinearLayout
             android:orientation="vertical"
diff --git a/integration-tests/TestApp/app/src/main/res/layout/name_mapping_test.xml b/integration-tests/TestApp/app/src/main/res/layout/name_mapping_test.xml
new file mode 100644
index 0000000..1ed651b
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/name_mapping_test.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout>
+    <data>
+        <variable name="obj" type="android.databinding.testapp.vo.BasicObject"/>
+    </data>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+                android:id="@+id/textView"
+                  android:enabled="@{obj.getThisNameDoesNotMatchAnythingElse2}"
+                  android:focusable="@{obj.isThisNameDoesNotMatchAnythingElse1}"/>
+        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:id="@+id/textView2"
+                  android:enabled="@{obj.thisNameDoesNotMatchAnythingElse2}"
+                  android:focusable="@{obj.thisNameDoesNotMatchAnythingElse1}"/>
+        <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+                  android:id="@+id/textView3"
+                  android:enabled="@{obj.getThisNameDoesNotMatchAnythingElse2()}"
+                  android:focusable="@{obj.isThisNameDoesNotMatchAnythingElse1()}"/>
+
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml b/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml
index a37031b..43b11da 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml
@@ -80,6 +80,13 @@
                   android:id="@+id/textInputMethod"
                   android:inputMethod="@{obj.inputMethod}"
                 />
-
+        <TextView android:layout_width="match_parent" android:layout_height="match_parent"
+                  android:id="@+id/textWithTheme"
+                  android:textColor="@{@colorStateList/text_colors}"
+                />
+        <TextView android:layout_width="match_parent" android:layout_height="match_parent"
+                  android:id="@+id/textWithColor"
+                  android:textColor="@{@android:color/holo_blue_bright}"
+        />
     </LinearLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/unnecessary_calculation.xml b/integration-tests/TestApp/app/src/main/res/layout/unnecessary_calculation.xml
new file mode 100644
index 0000000..0410189
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/layout/unnecessary_calculation.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <data>
+        <variable name="obja" type="android.databinding.testapp.vo.BasicObject"/>
+        <variable name="objb" type="android.databinding.testapp.vo.BasicObject"/>
+        <variable name="objc" type="android.databinding.testapp.vo.BasicObject"/>
+        <variable name="a" type="boolean"/>
+        <variable name="b" type="boolean"/>
+        <variable name="c" type="boolean"/>
+    </data>
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+        <TextView
+                android:id="@+id/textView"
+                android:text="@{obja.boolMethod(a)}"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+        <android.databinding.testapp.view.MyTextView
+                android:id="@+id/textView2"
+                android:text="@{a ? objb.boolMethod(b) : objc.boolMethod(c)}"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"/>
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/view_adapter_test.xml b/integration-tests/TestApp/app/src/main/res/layout/view_adapter_test.xml
index a3d40ff..ce3b895 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/view_adapter_test.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/view_adapter_test.xml
@@ -28,6 +28,12 @@
                 android:padding="@{obj.padding}"
                 />
         <View
+                android:id="@+id/paddingFloat"
+                android:layout_width="10dp"
+                android:layout_height="10dp"
+                android:padding="@{@dimen/testPadding}"
+                />
+        <View
                 android:id="@+id/paddingStartEnd"
                 android:layout_width="10dp"
                 android:layout_height="10dp"
@@ -35,6 +41,15 @@
                 android:paddingStart="@{obj.paddingStart}"
                 />
         <View
+                android:id="@+id/paddingStartEndFloat"
+                android:layout_width="10dp"
+                android:layout_height="10dp"
+                android:paddingTop="@{@dimen/testPadding}"
+                android:paddingBottom="@{@dimen/testPadding}"
+                android:paddingEnd="@{@dimen/testPadding}"
+                android:paddingStart="@{@dimen/testPadding}"
+                />
+        <View
                 android:id="@+id/paddingTopBottom"
                 android:layout_width="10dp"
                 android:layout_height="10dp"
@@ -49,6 +64,15 @@
                 android:paddingRight="@{obj.paddingRight}"
                 />
         <View
+                android:id="@+id/paddingLeftRightFloat"
+                android:layout_width="10dp"
+                android:layout_height="10dp"
+                android:paddingTop="@{@dimen/testPadding}"
+                android:paddingBottom="@{@dimen/testPadding}"
+                android:paddingLeft="@{@dimen/testPadding}"
+                android:paddingRight="@{@dimen/testPadding}"
+                />
+        <View
                 android:id="@+id/backgroundTint"
                 android:backgroundTint="@{obj.backgroundTint}"
                 android:layout_width="10dp"
@@ -86,5 +110,16 @@
                 android:transformPivotY="@{obj.transformPivotY}"
                 android:layout_width="10dp"
                 android:layout_height="10dp"/>
+
+        <View
+                android:id="@+id/backgroundDrawable"
+                android:layout_width="10dp"
+                android:layout_height="10dp"
+                android:background="@{@drawable/ic_launcher}"/>
+        <View
+                android:id="@+id/backgroundWithTheme"
+                android:layout_width="10dp"
+                android:layout_height="10dp"
+                android:background="@{@drawable/circle}"/>
     </LinearLayout>
 </layout>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/layout/view_with_tag.xml b/integration-tests/TestApp/app/src/main/res/layout/view_with_tag.xml
index a710390..6672c99 100644
--- a/integration-tests/TestApp/app/src/main/res/layout/view_with_tag.xml
+++ b/integration-tests/TestApp/app/src/main/res/layout/view_with_tag.xml
@@ -25,6 +25,8 @@
         <TextView
             android:text="@{str}"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
+            android:layout_height="wrap_content" >
+            <tag android:id="@+id/customTag" android:value="Hello"/>
+        </TextView>
     </LinearLayout>
 </layout>
diff --git a/integration-tests/TestApp/app/src/main/res/values/booleans.xml b/integration-tests/TestApp/app/src/main/res/values/booleans.xml
new file mode 100644
index 0000000..5cf5a37
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/values/booleans.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <bool name="alwaysTrue">true</bool>
+    <bool name="alwaysFalse">false</bool>
+</resources>
\ No newline at end of file
diff --git a/integration-tests/TestApp/app/src/main/res/values/dimens.xml b/integration-tests/TestApp/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..dbcada0
--- /dev/null
+++ b/integration-tests/TestApp/app/src/main/res/values/dimens.xml
@@ -0,0 +1,16 @@
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <dimen name="testPadding">10dp</dimen>
+</resources>
diff --git a/integration-tests/TestApp/build.gradle b/integration-tests/TestApp/build.gradle
index c15f7f5..35f8e95 100644
--- a/integration-tests/TestApp/build.gradle
+++ b/integration-tests/TestApp/build.gradle
@@ -1,9 +1,8 @@
 buildscript {
-    ext.rootFolder = new File(project.projectDir, "../..")
+    ext.dataBindingRootFolder = new File(project.projectDir, "../..")
     apply from: "${project.projectDir}/../../propLoader.gradle"
     ext.addRepos(repositories)
     dependencies {
-        classpath "com.android.tools.build:gradle:${config.androidPluginVersion}"
-        classpath "com.android.databinding:dataBinder:${config.version}"
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
     }
 }
diff --git a/integration-tests/TestApp/gradle/wrapper/gradle-wrapper.properties b/integration-tests/TestApp/gradle/wrapper/gradle-wrapper.properties
index 0c71e76..d570517 100644
--- a/integration-tests/TestApp/gradle/wrapper/gradle-wrapper.properties
+++ b/integration-tests/TestApp/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/internal-prebuilts/README.md b/internal-prebuilts/README.md
new file mode 100644
index 0000000..92116c7
--- /dev/null
+++ b/internal-prebuilts/README.md
@@ -0,0 +1,6 @@
+This maven repository includes prebuilts of data binding libs that
+a) depend on android gradle plugin
+b) used druing development of data binding itself.
+
+This repository is designed to only be referenced by the Android Gradle Plugin (platform/tools).
+To access data binding prebuilds for your own app, use /platform/prebuilt/ projects.
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar
new file mode 100644
index 0000000..3c0acac
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar.md5
new file mode 100644
index 0000000..01e0832
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar.md5
@@ -0,0 +1 @@
+feca24e4477fba87b8593eb845cd60df
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar.sha1
new file mode 100644
index 0000000..e02f829
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-javadoc.jar.sha1
@@ -0,0 +1 @@
+73c27a8c2ceb3283e0ff24caab4491ff10eff03d
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar
new file mode 100644
index 0000000..97ed60c
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar.md5
new file mode 100644
index 0000000..7c9174a
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar.md5
@@ -0,0 +1 @@
+1bbcf17edb9febc5ce467432eec6c451
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar.sha1
new file mode 100644
index 0000000..b3e1249
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3-sources.jar.sha1
@@ -0,0 +1 @@
+3dbcbe676b3b81d1b9085ced28a279bba30da2eb
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar
new file mode 100644
index 0000000..f646a94
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar.md5
new file mode 100644
index 0000000..dab61c0
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar.md5
@@ -0,0 +1 @@
+e2c580d1670caa594f617c8d1ea9b41c
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar.sha1
new file mode 100644
index 0000000..38d6efc
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.aar.sha1
@@ -0,0 +1 @@
+cda5ac229c41ab2000a394eaa9e4dbf33adc8658
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom
new file mode 100644
index 0000000..9b99982
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>adapters</artifactId>
+  <version>1.0-rc3</version>
+  <packaging>aar</packaging>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <dependencies>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>library</artifactId>
+      <version>1.0-rc3</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom.md5
new file mode 100644
index 0000000..2ef600c
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom.md5
@@ -0,0 +1 @@
+86843dc92dafc8aa8816088108d6175d
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom.sha1
new file mode 100644
index 0000000..375c72d
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc3/adapters-1.0-rc3.pom.sha1
@@ -0,0 +1 @@
+22547691cf3cc9ca63b6e872a04b111964674193
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar
new file mode 100644
index 0000000..0a4baeb
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar.md5
new file mode 100644
index 0000000..c61e62c
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar.md5
@@ -0,0 +1 @@
+3653511ec6a902c0cb8cb1c35e83d8bf
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar.sha1
new file mode 100644
index 0000000..5c8cbca
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-javadoc.jar.sha1
@@ -0,0 +1 @@
+9e4a7cc9ec5c09320c93d52db381a21413a88c7b
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar
new file mode 100644
index 0000000..8fda1f2
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar.md5
new file mode 100644
index 0000000..9c6cdef
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar.md5
@@ -0,0 +1 @@
+886d28a28d1507215a5b52de8aafe501
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar.sha1
new file mode 100644
index 0000000..9595681
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5-sources.jar.sha1
@@ -0,0 +1 @@
+8cddf09f2b4ce33b8acefbc8395a23cd09220608
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar
new file mode 100644
index 0000000..072d0c8
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar.md5
new file mode 100644
index 0000000..ebe5ac3
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar.md5
@@ -0,0 +1 @@
+15dfee32a3045fb217e8ebd14d840ffb
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar.sha1
new file mode 100644
index 0000000..3ef5c33
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.aar.sha1
@@ -0,0 +1 @@
+01ac2f4916e93f32049bbc564217f51fabed2955
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom
new file mode 100644
index 0000000..f7824b1
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>adapters</artifactId>
+  <version>1.0-rc5</version>
+  <packaging>aar</packaging>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <dependencies>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>library</artifactId>
+      <version>1.0-rc5</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>baseLibrary</artifactId>
+      <version>1.0-rc5</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom.md5 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom.md5
new file mode 100644
index 0000000..7f5e52e
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom.md5
@@ -0,0 +1 @@
+9550c15097a003ffd03006215e07d17c
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom.sha1
new file mode 100644
index 0000000..7c06238
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.0-rc5/adapters-1.0-rc5.pom.sha1
@@ -0,0 +1 @@
+084728a93397ecc99af002f2c5614b4a64510cfb
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar
new file mode 100644
index 0000000..741e5b6
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar.md5
new file mode 100644
index 0000000..c4ad48c
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar.md5
@@ -0,0 +1 @@
+3102e4c3a8b533ecadf7a79f8cc0e6ed
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar.sha1
new file mode 100644
index 0000000..a8506d5
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-javadoc.jar.sha1
@@ -0,0 +1 @@
+96b2b1883d2ea46bfcc65c1e6addfda97814825f
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar
new file mode 100644
index 0000000..a65eed3
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar.md5
new file mode 100644
index 0000000..a1b3e16
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar.md5
@@ -0,0 +1 @@
+d9447e86bde083ce29e475269f408094
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar.sha1
new file mode 100644
index 0000000..4e30a01
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1-sources.jar.sha1
@@ -0,0 +1 @@
+271f7d5792857458ee31eaafa2f00ab75ee68a27
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar
new file mode 100644
index 0000000..91ffc8e
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar.md5 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar.md5
new file mode 100644
index 0000000..ed95514
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar.md5
@@ -0,0 +1 @@
+63c9e012af57aacb15d1b998711077c0
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar.sha1
new file mode 100644
index 0000000..07ea678
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.aar.sha1
@@ -0,0 +1 @@
+110c163a806a7317374e98d9a8ab460e91c0d3d3
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom
new file mode 100644
index 0000000..c22b386
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>adapters</artifactId>
+  <version>1.1</version>
+  <packaging>aar</packaging>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <dependencies>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>library</artifactId>
+      <version>1.1</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>baseLibrary</artifactId>
+      <version>1.1</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom.md5 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom.md5
new file mode 100644
index 0000000..d928121
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom.md5
@@ -0,0 +1 @@
+7f884655cb412a87b69247d382edcf2e
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom.sha1 b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom.sha1
new file mode 100644
index 0000000..eb40518
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/1.1/adapters-1.1.pom.sha1
@@ -0,0 +1 @@
+bd7626a61823c5e1b5ea49a6315cac64c016c220
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml b/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml
new file mode 100644
index 0000000..da35a08
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>adapters</artifactId>
+  <versioning>
+    <release>1.1</release>
+    <versions>
+      <version>1.0-rc5</version>
+      <version>1.1</version>
+    </versions>
+    <lastUpdated>20160114222429</lastUpdated>
+  </versioning>
+</metadata>
diff --git a/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml.md5 b/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml.md5
new file mode 100644
index 0000000..cd35679
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml.md5
@@ -0,0 +1 @@
+08b9a4a0ba5bfce3cf77ae92007003e5
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml.sha1 b/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml.sha1
new file mode 100644
index 0000000..b604175
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/adapters/maven-metadata.xml.sha1
@@ -0,0 +1 @@
+98de00cc52ce9a2a7b71d15e67fe22926c88d528
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-javadoc.jar b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-javadoc.jar
new file mode 100644
index 0000000..c218838
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-javadoc.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-sources.jar b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-sources.jar
new file mode 100644
index 0000000..402b6f3
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-sources.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-sources.jar.md5 b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-sources.jar.md5
new file mode 100644
index 0000000..fd611e0
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3-sources.jar.md5
@@ -0,0 +1 @@
+06eaa31170fbda8df4bfabbd9e597dbb
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.jar b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.jar
new file mode 100644
index 0000000..f2ba523
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.jar.md5 b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.jar.md5
new file mode 100644
index 0000000..8cfaa39
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.jar.md5
@@ -0,0 +1 @@
+e4d9cb379ec08bd5605f50ae46f4931a
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.pom
similarity index 64%
rename from plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom
rename to internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.pom
index 7b2ffc5..a7cb4c7 100644
--- a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom
+++ b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.pom
@@ -3,8 +3,15 @@
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.android.databinding</groupId>
-  <artifactId>bintray</artifactId>
-  <version>1.0</version>
+  <artifactId>baseLibrary</artifactId>
+  <version>1.0-rc3</version>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
diff --git a/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.pom.md5 b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.pom.md5
new file mode 100644
index 0000000..0865ba5
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/baseLibrary/1.0-rc3/baseLibrary-1.0-rc3.pom.md5
@@ -0,0 +1 @@
+b27ce565d94a8fa1510cf091bd392cea
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar
new file mode 100644
index 0000000..8691f34
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar.md5
new file mode 100644
index 0000000..5570186
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar.md5
@@ -0,0 +1 @@
+7f9c5798e927f862c9e3b297a15ba841
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar.sha1
new file mode 100644
index 0000000..222e7f2
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-javadoc.jar.sha1
@@ -0,0 +1 @@
+7599391632f87f2b33c0c392b6e1593ef1196221
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar
new file mode 100644
index 0000000..652ad8d
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar.md5
new file mode 100644
index 0000000..f6b98ed
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar.md5
@@ -0,0 +1 @@
+7ed58210198f3afb13226a42f3d97b80
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar.sha1
new file mode 100644
index 0000000..06663fb
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3-sources.jar.sha1
@@ -0,0 +1 @@
+a25430b7adff8cd8f6eb5d4ba1066fbe92099b81
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar
new file mode 100644
index 0000000..439fce5
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar.md5
new file mode 100644
index 0000000..d454d0f
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar.md5
@@ -0,0 +1 @@
+3ca01d790d7efee212362a168a74b6c7
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar.sha1
new file mode 100644
index 0000000..af0648b
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.aar.sha1
@@ -0,0 +1 @@
+33a2cacd38ea6e7ea750a50b1be3e5ecddc07fd2
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom
new file mode 100644
index 0000000..d836832
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>library</artifactId>
+  <version>1.0-rc3</version>
+  <packaging>aar</packaging>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <dependencies>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>baseLibrary</artifactId>
+      <version>1.0-rc3</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.android.support</groupId>
+      <artifactId>support-v4</artifactId>
+      <version>21.0.3</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom.md5
new file mode 100644
index 0000000..f5d608b
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom.md5
@@ -0,0 +1 @@
+ef14709e30f81059e4e466e3cbda2c05
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom.sha1
new file mode 100644
index 0000000..c97a628
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc3/library-1.0-rc3.pom.sha1
@@ -0,0 +1 @@
+e7aea023ae8188c8130bdf68e39a3a0fe3b392b1
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar
new file mode 100644
index 0000000..2496be0
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar.md5
new file mode 100644
index 0000000..029c0b1
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar.md5
@@ -0,0 +1 @@
+55b0c81b3729025054081437f34155ec
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar.sha1
new file mode 100644
index 0000000..b6ac5a8
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-javadoc.jar.sha1
@@ -0,0 +1 @@
+34c8d79bd66d99f81666593c35ae7cdb036b1a03
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar
new file mode 100644
index 0000000..b83ae6f
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar.md5
new file mode 100644
index 0000000..9cb4087
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar.md5
@@ -0,0 +1 @@
+0f225a5c73a58cf525994b1a183e75ad
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar.sha1
new file mode 100644
index 0000000..436c4c7
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5-sources.jar.sha1
@@ -0,0 +1 @@
+b0e6dfbe9daf46fe0503957b81da6e888fdfcf30
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar
new file mode 100644
index 0000000..1bc5ca8
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar.md5
new file mode 100644
index 0000000..7db41ee
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar.md5
@@ -0,0 +1 @@
+a2166f6f9663d36ee0414f85f229f765
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar.sha1
new file mode 100644
index 0000000..4aced33
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.aar.sha1
@@ -0,0 +1 @@
+aba6c5f9ad349a476c59826b53c1a2deb1af3add
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom
new file mode 100644
index 0000000..c2e5066
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>library</artifactId>
+  <version>1.0-rc5</version>
+  <packaging>aar</packaging>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <dependencies>
+    <dependency>
+      <groupId>com.android.support</groupId>
+      <artifactId>support-v4</artifactId>
+      <version>21.0.3</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>baseLibrary</artifactId>
+      <version>1.0-rc5</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom.md5 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom.md5
new file mode 100644
index 0000000..67798ba
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom.md5
@@ -0,0 +1 @@
+f2a81f3066450c88c406125052d0b4b7
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom.sha1 b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom.sha1
new file mode 100644
index 0000000..fdd031f
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.0-rc5/library-1.0-rc5.pom.sha1
@@ -0,0 +1 @@
+328129fafbd49107574154efdefd115efe26c60b
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar
new file mode 100644
index 0000000..fa82708
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar.md5 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar.md5
new file mode 100644
index 0000000..ad758d9
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar.md5
@@ -0,0 +1 @@
+d7e559f25a20f061c62cc4dbbfb6a36c
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar.sha1 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar.sha1
new file mode 100644
index 0000000..54e287c
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-javadoc.jar.sha1
@@ -0,0 +1 @@
+339a3b20fd98775796dfb6c248cc7ddbf526f635
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar
new file mode 100644
index 0000000..d8bd208
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar.md5 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar.md5
new file mode 100644
index 0000000..964df96
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar.md5
@@ -0,0 +1 @@
+ca88a210328f9c3655c3524421874a97
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar.sha1 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar.sha1
new file mode 100644
index 0000000..e640354
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1-sources.jar.sha1
@@ -0,0 +1 @@
+12e3f88b119fbaccf46fe28b6c4f35adbe60daf3
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar
new file mode 100644
index 0000000..d25e0d1
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar.md5 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar.md5
new file mode 100644
index 0000000..97b2c02
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar.md5
@@ -0,0 +1 @@
+786980fe30ef7a7015ec9d9e4f340ecb
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar.sha1 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar.sha1
new file mode 100644
index 0000000..a2e0c86
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.aar.sha1
@@ -0,0 +1 @@
+6d305d8c838bbb1e16584a3053097699b5353d11
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom
new file mode 100644
index 0000000..bcb1d9b
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>library</artifactId>
+  <version>1.1</version>
+  <packaging>aar</packaging>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <dependencies>
+    <dependency>
+      <groupId>com.android.support</groupId>
+      <artifactId>support-v4</artifactId>
+      <version>21.0.3</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.android.databinding</groupId>
+      <artifactId>baseLibrary</artifactId>
+      <version>1.1</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom.md5 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom.md5
new file mode 100644
index 0000000..4559ce5
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom.md5
@@ -0,0 +1 @@
+8177aaf76c6da0bc8f881a78327f0355
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom.sha1 b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom.sha1
new file mode 100644
index 0000000..b2c05a2
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/1.1/library-1.1.pom.sha1
@@ -0,0 +1 @@
+5a4b0208f2a1722c23341d0d163d4c459c60ae3a
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/maven-metadata.xml b/internal-prebuilts/com/android/databinding/library/maven-metadata.xml
new file mode 100644
index 0000000..ddcb12e
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/maven-metadata.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata>
+  <groupId>com.android.databinding</groupId>
+  <artifactId>library</artifactId>
+  <versioning>
+    <release>1.1</release>
+    <versions>
+      <version>1.0-rc5</version>
+      <version>1.1</version>
+    </versions>
+    <lastUpdated>20160114222429</lastUpdated>
+  </versioning>
+</metadata>
diff --git a/internal-prebuilts/com/android/databinding/library/maven-metadata.xml.md5 b/internal-prebuilts/com/android/databinding/library/maven-metadata.xml.md5
new file mode 100644
index 0000000..04ab5a4
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/maven-metadata.xml.md5
@@ -0,0 +1 @@
+614659348ea658cd97eda5b27231b223
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/library/maven-metadata.xml.sha1 b/internal-prebuilts/com/android/databinding/library/maven-metadata.xml.sha1
new file mode 100644
index 0000000..e87a0a4
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/library/maven-metadata.xml.sha1
@@ -0,0 +1 @@
+0fecc097f9c2a8973c7169112cea421b48b87cb0
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar
new file mode 100644
index 0000000..e003a04
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar
Binary files differ
diff --git a/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar.md5 b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar.md5
new file mode 100644
index 0000000..d93d95d
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar.md5
@@ -0,0 +1 @@
+4b81f88150cd2be1b1f6d886100af1c2
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar.sha1 b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar.sha1
new file mode 100644
index 0000000..77d5422
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.jar.sha1
@@ -0,0 +1 @@
+6e19c0ca82802428346c624673e66479089c6814
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom
similarity index 97%
rename from plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom
rename to internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom
index e9cc223..08a876c 100644
--- a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom
+++ b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom
@@ -4,7 +4,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.android.databinding</groupId>
   <artifactId>localizemaven</artifactId>
-  <version>1.0</version>
+  <version>1.1</version>
   <dependencies>
     <dependency>
       <groupId>org.eclipse.aether</groupId>
diff --git a/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom.md5 b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom.md5
new file mode 100644
index 0000000..20a4982
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom.md5
@@ -0,0 +1 @@
+1e4d10cf9c8ffc6040e22c7e76f0aa2a
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom.sha1 b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom.sha1
new file mode 100644
index 0000000..6705f12
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/localizemaven/1.1/localizemaven-1.1.pom.sha1
@@ -0,0 +1 @@
+89065de70856a47fcf5e51f9b8a5529644952303
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml b/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml
similarity index 67%
rename from plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml
rename to internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml
index 6761fe8..4f263e9 100644
--- a/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml
+++ b/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml
@@ -2,11 +2,11 @@
 <metadata>
   <groupId>com.android.databinding</groupId>
   <artifactId>localizemaven</artifactId>
-  <version>1.0</version>
+  <version>1.1</version>
   <versioning>
     <versions>
-      <version>1.0</version>
+      <version>1.1</version>
     </versions>
-    <lastUpdated>20150717200705</lastUpdated>
+    <lastUpdated>20151104222707</lastUpdated>
   </versioning>
 </metadata>
diff --git a/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml.md5 b/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml.md5
new file mode 100644
index 0000000..accb9a0
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml.md5
@@ -0,0 +1 @@
+71903e14023ca5e2adb851cf065715e7
\ No newline at end of file
diff --git a/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml.sha1 b/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml.sha1
new file mode 100644
index 0000000..c2964b1
--- /dev/null
+++ b/internal-prebuilts/com/android/databinding/localizemaven/maven-metadata.xml.sha1
@@ -0,0 +1 @@
+f30fef09adcbc55cf74ad44c7607accc884d87f9
\ No newline at end of file
diff --git a/library/build.gradle b/library/build.gradle
deleted file mode 100644
index 937a383..0000000
--- a/library/build.gradle
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
-    dependencies {
-        classpath "com.android.tools.build:gradle:${config.androidPluginVersion}"
-        // NOTE: Do not place your application dependencies here; they belong
-        // in the individual module build.gradle files
-    }
-}
-
-apply plugin: 'com.android.library'
-
-android {
-    compileSdkVersion 21
-    buildToolsVersion "21.1"
-
-    defaultConfig {
-        minSdkVersion 7
-        targetSdkVersion 21
-        versionCode 1
-        versionName "1.0"
-    }
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_7
-        targetCompatibility JavaVersion.VERSION_1_7
-    }
-    buildTypes {
-        release {
-            minifyEnabled false
-        }
-    }
-    packagingOptions {
-        exclude 'META-INF/services/javax.annotation.processing.Processor'
-        exclude 'META-INF/LICENSE.txt'
-        exclude 'META-INF/NOTICE.txt'
-        exclude 'android/databinding/DataBinderMapper.class'
-    }
-}
-
-configurations {
-    jarArchives
-}
-
-
-dependencies {
-    compile 'com.android.support:support-v4:21.0.3'
-    compile project(':baseLibrary')
-}
-
-//create jar tasks
-android.libraryVariants.all { variant ->
-    def name = variant.buildType.name
-
-    if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
-        return; // Skip debug builds.
-    }
-    def suffix = name.capitalize()
-
-    def javadocTask = project.tasks.create(name: "javadoc${suffix}", type: Javadoc) {
-        source variant.javaCompile.source + project(":baseLibrary").tasks['compileJava'].source
-        classpath = files(variant.javaCompile.classpath.files) + files(
-                "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar")
-    }
-
-    def javadocJarTask = project.tasks.create(name: "javadocJar${suffix}", type: Jar) {
-        classifier = 'javadoc'
-        from 'build/docs/javadoc'
-    }
-    javadocJarTask.dependsOn javadocTask
-
-    def sourcesJarTask = project.tasks.create(name: "sourceJar${suffix}", type: Jar) {
-        classifier = 'sources'
-        from android.sourceSets.main.java.srcDirs + project(":baseLibrary").sourceSets.main.java.srcDirs
-    }
-
-    artifacts.add('archives', javadocJarTask);
-    artifacts.add('archives', sourcesJarTask);
-}
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            pom.artifactId = 'library'
-            pom.project {
-                licenses {
-                    license {
-                        name config.licenseName
-                        url config.licenseUrl
-                        distribution config.licenseDistribution
-                    }
-                }
-            }
-        }
-    }
-}
-
-
-afterEvaluate {
-    tasks['packageReleaseJar'].exclude('android/databinding/DataBinderMapper.*')
-    tasks['packageReleaseJar'].exclude('android/databinding/DataBindingComponent.*')
-    tasks['packageDebugJar'].exclude('android/databinding/DataBinderMapper.*')
-    tasks['packageDebugJar'].exclude('android/databinding/DataBindingComponent.*')
-}
-
-task prebuildAar(type : Copy) {
-    dependsOn uploadArchives
-    from "$buildDir/outputs/aar/library-release.aar"
-    into config.prebuildFolder
-    rename { String fileName ->
-        "databinding-library.aar"
-    }
-}
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar b/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar
deleted file mode 100644
index 87bd3b5..0000000
--- a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar
+++ /dev/null
Binary files differ
diff --git a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar.md5 b/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar.md5
deleted file mode 100644
index 5240a5e..0000000
--- a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar.md5
+++ /dev/null
@@ -1 +0,0 @@
-7587c61bfa00ad541010853edda211f8
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar.sha1 b/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar.sha1
deleted file mode 100644
index 3533a16..0000000
--- a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-b23e75f6609abbd735115394773b64d7d715cfc4
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom.md5 b/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom.md5
deleted file mode 100644
index 06b668b..0000000
--- a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom.md5
+++ /dev/null
@@ -1 +0,0 @@
-3dc6ce6e2b0f405e0e005bfd61824683
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom.sha1 b/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom.sha1
deleted file mode 100644
index c071f7c..0000000
--- a/plugins-repo/com/android/databinding/bintray/1.0/bintray-1.0.pom.sha1
+++ /dev/null
@@ -1 +0,0 @@
-05fa26e81f15809f9e231099f05fc62d0c4a536b
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/bintray/maven-metadata.xml b/plugins-repo/com/android/databinding/bintray/maven-metadata.xml
deleted file mode 100644
index 1a3143d..0000000
--- a/plugins-repo/com/android/databinding/bintray/maven-metadata.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<metadata>
-  <groupId>com.android.databinding</groupId>
-  <artifactId>bintray</artifactId>
-  <version>1.0</version>
-  <versioning>
-    <versions>
-      <version>1.0</version>
-    </versions>
-    <lastUpdated>20150717200702</lastUpdated>
-  </versioning>
-</metadata>
diff --git a/plugins-repo/com/android/databinding/bintray/maven-metadata.xml.md5 b/plugins-repo/com/android/databinding/bintray/maven-metadata.xml.md5
deleted file mode 100644
index bb48478..0000000
--- a/plugins-repo/com/android/databinding/bintray/maven-metadata.xml.md5
+++ /dev/null
@@ -1 +0,0 @@
-d5d20c728a5dafb939297c828fbb2375
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/bintray/maven-metadata.xml.sha1 b/plugins-repo/com/android/databinding/bintray/maven-metadata.xml.sha1
deleted file mode 100644
index 8b18d9e..0000000
--- a/plugins-repo/com/android/databinding/bintray/maven-metadata.xml.sha1
+++ /dev/null
@@ -1 +0,0 @@
-73eccf19ca9942f3df94ac2bc204d9648949ebdb
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar b/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar
deleted file mode 100644
index f768a31..0000000
--- a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar
+++ /dev/null
Binary files differ
diff --git a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar.md5 b/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar.md5
deleted file mode 100644
index 563dd69..0000000
--- a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar.md5
+++ /dev/null
@@ -1 +0,0 @@
-37be36f09bf80160e6dc45be75e1122f
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar.sha1 b/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar.sha1
deleted file mode 100644
index 2cff637..0000000
--- a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.jar.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d19dc6dac73676f13b4ef90e22302586aa41bcaa
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom.md5 b/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom.md5
deleted file mode 100644
index 21c3a27..0000000
--- a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom.md5
+++ /dev/null
@@ -1 +0,0 @@
-f7cd22c6b15280987bb23c4871f32d31
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom.sha1 b/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom.sha1
deleted file mode 100644
index f0713d2..0000000
--- a/plugins-repo/com/android/databinding/localizemaven/1.0/localizemaven-1.0.pom.sha1
+++ /dev/null
@@ -1 +0,0 @@
-2bae0e1507a55b8d3ad7f484c56a25896b490cc0
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml.md5 b/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml.md5
deleted file mode 100644
index 8c6accf..0000000
--- a/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml.md5
+++ /dev/null
@@ -1 +0,0 @@
-3ceff32cb0a00c72558b6d9f20cbae1e
\ No newline at end of file
diff --git a/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml.sha1 b/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml.sha1
deleted file mode 100644
index abac4ba..0000000
--- a/plugins-repo/com/android/databinding/localizemaven/maven-metadata.xml.sha1
+++ /dev/null
@@ -1 +0,0 @@
-727c5086bf5cb873142fa24454cb0c0ba9732d88
\ No newline at end of file
diff --git a/proguard.cfg b/proguard.cfg
new file mode 100644
index 0000000..e56368b
--- /dev/null
+++ b/proguard.cfg
@@ -0,0 +1,28 @@
+-keep class android.databinding.** { *; }
+
+-keepnames class * implements java.io.Serializable
+
+-keepclassmembers class * implements java.io.Serializable {
+    static final long serialVersionUID;
+    private static final java.io.ObjectStreamField[] serialPersistentFields;
+    !static !transient <fields>;
+    private void writeObject(java.io.ObjectOutputStream);
+    private void readObject(java.io.ObjectInputStream);
+    java.lang.Object writeReplace();
+    java.lang.Object readResolve();
+}
+
+-keepattributes *Annotation*
+-keepattributes javax.xml.bind.annotation.*
+-keepattributes javax.annotation.processing.*
+
+-keepclassmembers class * extends java.lang.Enum { *; }
+
+-keepclasseswithmembernames class android.**
+
+-keepclasseswithmembernames interface android.**
+
+-dontobfuscate
+-libraryjars  <java.home>/lib/rt.jar
+-libraryjars  <java.home>/lib/jce.jar
+-dontwarn
\ No newline at end of file
diff --git a/propLoader.gradle b/propLoader.gradle
index f8730ae..310d313 100644
--- a/propLoader.gradle
+++ b/propLoader.gradle
@@ -1,71 +1,80 @@
 /**
  * Helper build script that reads data binding variables and sets up the projects.
  */
-def root = ext.rootFolder
+def root = ext.dataBindingRootFolder
 Properties databindingProperties = new Properties()
 databindingProperties.load(new FileInputStream("${root}/databinding.properties"))
-def repoBase = databindingProperties.mavenRepoAbsolutePath == "." ? root : databindingProperties.mavenRepoAbsolutePath
-databindingProperties.mavenRepoDir = "${repoBase}/${databindingProperties.mavenRepoName}"
-databindingProperties.extraPluginsRepoDir = "${root}/${databindingProperties.extraPluginsRepoName}"
 
+// load android gradle plugin's version file
+apply from: "${root}/../buildSrc/base/version.gradle"
+
+databindingProperties.version = ext.buildVersion
+databindingProperties.compileSdkVersion = Integer.parseInt(databindingProperties.compileSdkVersionStr)
+def repoBase = databindingProperties.mavenRepoAbsolutePath == "." ? root : databindingProperties.mavenRepoAbsolutePath
+databindingProperties.androidGradlePluginRepoDir = "${root}/../../${databindingProperties.androidGradlePluginOutRepo}"
+databindingProperties.mavenRepoDir = "${databindingProperties.androidGradlePluginRepoDir}"
+databindingProperties.internalPrebuiltsRepoDir = "${root}/${databindingProperties.internalPrebuiltsRepoName}"
+databindingProperties.runProguard = project.hasProperty('runProguard') && project.getProperty('runProguard').equals("true")
+
+databindingProperties.inReleaseBuild = project.ext.hasProperty('release') && project.ext.release
+// load version from gradle build file
+apply from: "$root/../buildSrc/base/version.gradle"
+databindingProperties.androidPluginVersion=ext.buildVersion
+databindingProperties.isIndependent = rootProject.name.equals("data-binding")
 databindingProperties.eapOutDir = "${root}/${databindingProperties.eapOutFolderName}"
 databindingProperties.prebuildFolder = "${root}/${databindingProperties.prebuildFolderName}" +
         "/${databindingProperties.releaseVersion}"
 
-ext.config = databindingProperties
-ext.config.externalPrebuiltsBase = "${root}/../../prebuilts"
+ext.dataBindingConfig = databindingProperties
+ext.dataBindingConfig.externalPrebuiltsBase = "${root}/../../prebuilts"
 databindingProperties.megaRepoDir = "${databindingProperties.externalPrebuiltsBase}/tools/common/m2/repository"
 
-println "local maven repo is ${ext.config.mavenRepoDir}."
-println "local pre-build folder is ${ext.config.prebuildFolder}."
-println "mega-repo folder is ${ext.config.megaRepoDir}."
+new File(ext.dataBindingConfig.mavenRepoDir).mkdir()
+new File(ext.dataBindingConfig.prebuildFolder).mkdir()
 
-new File(ext.config.mavenRepoDir).mkdir()
-new File(ext.config.prebuildFolder).mkdir()
-
-def addRemoteRepos = !project.hasProperty('addRemoteRepos') || project.getProperty('addRemoteRepos').equals("true")
-ext.config.addRemoteRepos = addRemoteRepos
-def config = ext.config
-def localRepositories = ["${config.extraPluginsRepoDir}",
-                         "${config.megaRepoDir}",
-                         "${config.mavenRepoDir}",
-                         "${config.externalPrebuiltsBase}/maven_repo/android",
-                         "${config.externalPrebuiltsBase}/gradle-plugin",
-                         "${config.externalPrebuiltsBase}/tools/common/m2/repository"]
-ext.config.localRepositories = localRepositories
+def addRemoteRepos = project.hasProperty('addRemoteRepos') && project.getProperty('addRemoteRepos').equals("true")
+ext.dataBindingConfig.addRemoteRepos = addRemoteRepos
+ext.dataBindingConfig.sharedSupportRepoDir = "${ext.dataBindingConfig.externalPrebuiltsBase}/maven_repo/android"
+ext.dataBindingConfig.forGradlePlugin = project.hasProperty('forGradlePlugin') && project.getProperty('forGradlePlugin').equals("true")
+def dataBindingConfig = ext.dataBindingConfig
+def localRepositories = ["${dataBindingConfig.internalPrebuiltsRepoDir}",
+                         "${dataBindingConfig.megaRepoDir}",
+                         "${dataBindingConfig.mavenRepoDir}",
+                         "${dataBindingConfig.externalPrebuiltsBase}/tools/common/offline-m2",
+                         dataBindingConfig.sharedSupportRepoDir,
+                         "${dataBindingConfig.externalPrebuiltsBase}/gradle-plugin",
+                         "${dataBindingConfig.externalPrebuiltsBase}/tools/common/m2/repository",
+                         "${databindingProperties.androidGradlePluginRepoDir}"]
+ext.dataBindingConfig.localRepositories = localRepositories
 def addRepos(RepositoryHandler handler) {
-    config.localRepositories.each { repo ->
+    dataBindingConfig.localRepositories.each { repo ->
         handler.maven {
             url repo
         }
     }
-    handler.jcenter()
-    handler.mavenCentral()
+    if (dataBindingConfig.addRemoteRepos) {
+        handler.jcenter()
+        handler.mavenCentral()
+    }
 }
 ext.addRepos = this.&addRepos
 subprojects {
     buildscript {
-        config.localRepositories.each { repo ->
-            repositories.maven {
-                url repo
-            }
-        }
-        repositories {
-            if (config.addRemoteRepos) {
-                jcenter()
-                mavenCentral()
-            }
-        }
+        addRepos(repositories)
     }
     repositories {
-        config.localRepositories.each { repo ->
-            repositories.maven {
-                url repo
-            }
-        }
-        if (config.addRemoteRepos) {
-            jcenter()
-            mavenCentral()
-        }
+        addRepos(repositories)
     }
 }
+
+def enablePublishing(p, addJavadoc) {
+    if (!ext.dataBindingConfig.isIndependent) {
+        p.apply from: "$dataBindingRootFolder/../buildSrc/base/publish.gradle"
+        p.apply from: "$dataBindingRootFolder/../buildSrc/base/bintray.gradle"
+        if (addJavadoc) {
+            p.apply from: "$dataBindingRootFolder/../buildSrc/base/javadoc.gradle"
+        }
+        rootProject.project(":base:gradle-core").publishLocal.dependsOn p.publishLocal
+    }
+}
+ext.enablePublishing = this.&enablePublishing
\ No newline at end of file
diff --git a/samples/BindingDemo/app/build.gradle b/samples/BindingDemo/app/build.gradle
index 937ec65..651e33e 100644
--- a/samples/BindingDemo/app/build.gradle
+++ b/samples/BindingDemo/app/build.gradle
@@ -15,11 +15,10 @@
  */
 
 apply plugin: 'com.android.application'
-apply plugin: 'com.android.databinding'
 
 android {
-    compileSdkVersion 22
-    buildToolsVersion "22.0.1"
+    compileSdkVersion dataBindingConfig.compileSdkVersion
+    buildToolsVersion dataBindingConfig.buildToolsVersion
 
     defaultConfig {
         applicationId "com.android.bindingdemo"
@@ -28,6 +27,9 @@
         versionCode 1
         versionName "1.0"
     }
+    dataBinding {
+        enabled = true
+    }
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_7
         targetCompatibility JavaVersion.VERSION_1_7
diff --git a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java
index 93dc4c8..68c76c9 100644
--- a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java
+++ b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java
@@ -69,47 +69,34 @@
         mListeners.notifyChange(this, BR.selected);
     }
 
-    @Bindable
-    public View.OnClickListener onSave = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (selected == null) {
-                return;
-            }
-            selected.setName(dataBinder.selectedName.getText().toString());
-            selected.setLastName(dataBinder.selectedLastname.getText().toString());
+    public void onSave(View v) {
+        if (selected == null) {
+            return;
         }
-    };
+        selected.setName(dataBinder.selectedName.getText().toString());
+        selected.setLastName(dataBinder.selectedLastname.getText().toString());
+    }
 
-    @Bindable
-    public View.OnClickListener onUnselect = new View.OnClickListener() {
+    public void onUnselect (View v) {
+        setSelected(null);
+    }
 
-        @Override
-        public void onClick(View v) {
-            setSelected(null);
+    public void onDelete(View v) {
+        if (selected == null) {
+            return;
         }
-    };
-
-    @Bindable
-    public View.OnClickListener onDelete = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (selected == null) {
-                return;
-            }
-            if (selected.getGroup() == User.KITTEN) {
-                tkAdapter.remove(selected);
-                selected.setGroup(User.ROBOT);
-                robotAdapter.add(selected);
-                dataBinder.robotList.smoothScrollToPosition(robotAdapter.getItemCount() - 1);
-            } else {
-                tkAdapter.add(selected);
-                dataBinder.toolkittyList.smoothScrollToPosition(tkAdapter.getItemCount() - 1);
-                selected.setGroup(User.KITTEN);
-                robotAdapter.remove(selected);
-            }
+        if (selected.getGroup() == User.KITTEN) {
+            tkAdapter.remove(selected);
+            selected.setGroup(User.ROBOT);
+            robotAdapter.add(selected);
+            dataBinder.robotList.smoothScrollToPosition(robotAdapter.getItemCount() - 1);
+        } else {
+            tkAdapter.add(selected);
+            dataBinder.toolkittyList.smoothScrollToPosition(tkAdapter.getItemCount() - 1);
+            selected.setGroup(User.KITTEN);
+            robotAdapter.remove(selected);
         }
-    };
+    }
 
 
     @Override
diff --git a/samples/BindingDemo/app/src/main/res/layout/list_item.xml b/samples/BindingDemo/app/src/main/res/layout/list_item.xml
index d58221f..26b937f 100644
--- a/samples/BindingDemo/app/src/main/res/layout/list_item.xml
+++ b/samples/BindingDemo/app/src/main/res/layout/list_item.xml
@@ -14,7 +14,9 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-
+<!--DISCLAIMER: This is a demo layout showing various calculations you can make in binding
+expressions. It is usually a good practice to keep these expressions simple and use a ViewModel
+if they are getting complex.-->
 <layout xmlns:card_view="http://schemas.android.com/apk/res-auto"
     xmlns:bind="http://schemas.android.com/apk/res-auto"
     xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/samples/BindingDemo/app/src/main/res/layout/main_activity.xml b/samples/BindingDemo/app/src/main/res/layout/main_activity.xml
index 1898918..c16a94f 100644
--- a/samples/BindingDemo/app/src/main/res/layout/main_activity.xml
+++ b/samples/BindingDemo/app/src/main/res/layout/main_activity.xml
@@ -14,6 +14,9 @@
   limitations under the License.
   -->
 
+<!--DISCLAIMER: This is a demo layout showing various calculations you can make in binding
+expressions. It is usually a good practice to keep these expressions simple and use a ViewModel
+if they are getting complex.-->
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:bind="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools">
@@ -38,7 +41,7 @@
         android:id="@+id/activityRoot"
         tools:activity=".MainActivity"
         android:clickable="true"
-        android:onClickListener="@{activity.onUnselect}">
+        android:onClick="@{activity.onUnselect}">
         <TextView
             android:id="@+id/title"
             android:layout_width="wrap_content"
@@ -104,7 +107,7 @@
                     android:text="@{activity.selected.lastName}" />
                 <Button
                     android:id="@+id/edit_button"
-                    bind:onClickListener="@{activity.onSave}"
+                    android:onClick="@{activity.onSave}"
                     android:text='@{"Save changes to " + activity.selected.name}'
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
@@ -114,7 +117,7 @@
 
                 <Button
                     android:id="@+id/delete_button"
-                    bind:onClickListener="@{activity.onDelete}"
+                    android:onClick="@{activity.onDelete}"
                     android:text="@{activity.getString(activity.selected.group == User.KITTEN ? Strings.became_robot : Strings.became_kitten, activity.selected.name)}"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
diff --git a/samples/BindingDemo/build.gradle b/samples/BindingDemo/build.gradle
index 3a8758a..46aa275 100644
--- a/samples/BindingDemo/build.gradle
+++ b/samples/BindingDemo/build.gradle
@@ -14,32 +14,12 @@
  * limitations under the License.
  */
 
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
+// Top-level build file where you can add dataBindingConfiguration options common to all sub-projects/modules.
 buildscript {
-    def Properties dataBindingProperties = new Properties()
-    dataBindingProperties.load(new FileInputStream("${projectDir}/../../databinding.properties"))
-    dataBindingProperties.mavenRepoDir = "${projectDir}/../../${dataBindingProperties.mavenRepoName}"
-    ext.config = dataBindingProperties
-
-    repositories {
-        jcenter()
-        maven {
-            url "$projectDir/../../maven-repo"
-        }
-        mavenCentral()
-    }
+    ext.dataBindingRootFolder = new File(project.projectDir, "../..")
+    apply from: "${project.projectDir}/../../propLoader.gradle"
+    ext.addRepos(repositories)
     dependencies {
-        classpath "com.android.tools.build:gradle:${config.androidPluginVersion}"
-        classpath  "com.android.databinding:dataBinder:${config.version}"
-    }
-}
-
-allprojects {
-    repositories {
-        jcenter()
-        maven {
-            url "$projectDir/../../../maven-repo"
-        }
-        mavenCentral()
+        classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
     }
 }
diff --git a/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties b/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties
index f02c72a..de9d515 100644
--- a/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties
+++ b/samples/BindingDemo/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
diff --git a/settings.gradle b/settings.gradle
index 0d4e57c..24b44d3 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,7 +1,9 @@
-include ':baseLibrary'
-include ':library'
-include ':compiler'
-include ':gradlePlugin'
-include 'compilationTests'
-include 'compilerCommon'
+include ':dataBinding:baseLibrary'
+project(':dataBinding:baseLibrary').projectDir = new File("baseLibrary")
+include ':dataBinding:compiler'
+project(':dataBinding:compiler').projectDir = new File("compiler")
+include ':dataBinding:compilationTests'
+project(':dataBinding:compilationTests').projectDir = new File("compilationTests")
+include ':dataBinding:compilerCommon'
+project(':dataBinding:compilerCommon').projectDir = new File("compilerCommon")
 
diff --git a/supportBundle.gradle b/supportBundle.gradle
new file mode 100644
index 0000000..94e20ad
--- /dev/null
+++ b/supportBundle.gradle
@@ -0,0 +1,133 @@
+buildscript {
+    ext.addRepos(repositories)
+    dependencies {
+        classpath 'com.google.guava:guava:18.0'
+    }
+}
+import com.google.common.io.Files
+import com.google.common.base.Charsets
+import com.google.common.hash.HashCode
+import com.google.common.hash.HashFunction
+import com.google.common.hash.Hashing
+import java.nio.charset.Charset
+
+
+ext.extraVersion = 22
+ext.supportRepoOut = ''
+ext.buildToolsVersion = '22.1.0'
+ext.buildNumber = Integer.toString(ext.extraVersion)
+
+/*
+ * With the build server you are given two env variables.
+ * The OUT_DIR is a temporary directory you can use to put things during the build.
+ * The DIST_DIR is where you want to save things from the build.
+ *
+ * The build server will copy the contents of DIST_DIR to somewhere and make it available.
+ */
+if (System.env.DIST_DIR != null && System.env.OUT_DIR != null) {
+    buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build').getCanonicalFile()
+    project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile()
+
+    // the build server does not pass the build number so we infer it from the last folder of the dist path.
+    ext.buildNumber = project.ext.distDir.getName()
+} else {
+    buildDir = file('../../out/host/gradle/frameworks/support/build')
+    project.ext.distDir = file('../../out/dist')
+}
+project.ext.distDir.mkdirs()
+ext.supportRepoOut = new File(buildDir, 'support_repo')
+
+// Main task called by the build server.
+task(createArchive) << {
+}
+createArchive.doLast {
+    println "support repo out ${project.ext.supportRepoOut}"
+    println "dist dir ${project.ext.distDir}"
+
+}
+
+// upload anchor for subprojects to upload their artifacts
+// to the local repo.
+task(mainUpload) << {
+}
+
+// repository creation task
+task createRepository(type: Zip, dependsOn: mainUpload) {
+    from project.ext.supportRepoOut
+    destinationDir project.ext.distDir
+    into 'm2repository'
+    baseName = String.format("sdk-repo-linux-m2repository-%s", project.ext.buildNumber)
+}
+createArchive.dependsOn createRepository
+// prepare repository with older versions
+task unzipRepo(type: Copy) {
+    from "${dataBindingConfig.externalPrebuiltsBase}/maven_repo/android"
+    into project.ext.supportRepoOut
+}
+
+unzipRepo.doFirst {
+    project.ext.supportRepoOut.deleteDir()
+    project.ext.supportRepoOut.mkdirs()
+}
+
+// anchor for prepare repo. This is post unzip + sourceProp.
+task(prepareRepo) << {
+}
+
+task(createXml) << {
+    def repoArchive = createRepository.archivePath
+    def repoArchiveName = createRepository.archiveName
+    def size = repoArchive.length()
+    def sha1 = getSha1(repoArchive)
+
+    def xml =
+            "<sdk:sdk-addon xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:sdk=\"http://schemas.android.com/sdk/android/addon/6\">\n\
+  <sdk:extra>\n\
+    <sdk:revision>\n\
+      <sdk:major>${project.ext.extraVersion}</sdk:major>\n\
+    </sdk:revision>\n\
+    <sdk:vendor-display>Android</sdk:vendor-display>\n\
+    <sdk:vendor-id>android</sdk:vendor-id>\n\
+    <sdk:name-display>Local Maven repository for Support Libraries</sdk:name-display>\n\
+    <sdk:path>m2repository</sdk:path>\n\
+    <sdk:archives>\n\
+      <sdk:archive>\n\
+       <sdk:size>${size}</sdk:size>\n\
+       <sdk:checksum type=\"sha1\">${sha1}</sdk:checksum>\n\
+       <sdk:url>${repoArchiveName}</sdk:url>\n\
+      </sdk:archive>\n\
+    </sdk:archives>\n\
+  </sdk:extra>\n\
+</sdk:sdk-addon>"
+
+    Files.write(xml, new File(project.ext.distDir, 'repo-extras.xml'), Charsets.UTF_8)
+}
+createArchive.dependsOn createXml
+
+task(createSourceProp) << {
+    def sourceProp =
+            "Extra.VendorDisplay=Android\n\
+Extra.Path=m2repository\n\
+Archive.Arch=ANY\n\
+Extra.NameDisplay=Android Support Repository\n\
+Archive.Os=ANY\n\
+Pkg.Revision=${project.ext.extraVersion}.0.0\n\
+Extra.VendorId=android"
+    Files.write(sourceProp, new File(project.ext.supportRepoOut, 'source.properties'), Charsets.UTF_8)
+}
+createSourceProp.dependsOn unzipRepo
+prepareRepo.dependsOn createSourceProp
+
+
+def getSha1(File inputFile) {
+    HashFunction hashFunction = Hashing.sha1()
+    HashCode hashCode = hashFunction.hashString(inputFile.getAbsolutePath(), Charset.forName("UTF-8"))
+    return hashCode.toString()
+}
+
+task(bundleSupportLib) << {
+
+}
+createRepository.dependsOn prepareRepo
+createRepository.dependsOn unzipRepo
+createRepository.dependsOn bundleSupportLib