Create ClientListener( Script ) constructor
diff --git a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java
index 477787b..2e339df 100644
--- a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java
+++ b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/CustomBehaviors.java
@@ -11,7 +11,9 @@
 package org.eclipse.rap.clientscripting.demo;
 
 import org.eclipse.rap.clientscripting.ClientListener;
+import org.eclipse.rap.clientscripting.Script;
 import org.eclipse.rap.clientscripting.WidgetDataWhiteList;
+import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.MouseAdapter;
@@ -19,6 +21,7 @@
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Device;
 import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Canvas;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Text;
@@ -123,4 +126,23 @@
     return new Color( device, rgb );
   }
 
+  public static void addNumKeyBehavior( Text text, int number, Button button ) {
+    button.setData( "textWidget", WidgetUtil.getId( text ) );
+    button.setData( "numValue", Integer.valueOf( number ) );
+    ClientListener listener = new ClientListener( getScript( "NumKey.js" ) );
+    button.addListener( SWT.MouseDown, listener );
+  }
+
+  private static Script getScript( String fileName ) {
+    String key = CustomBehaviors.class.getCanonicalName() + fileName;
+    Script result = ( Script )RWT.getUISession().getAttribute( key );
+    if( result == null ) {
+      String scriptCode
+        = ResourceLoaderUtil.readTextContent( RESOURCES_PREFIX + fileName );
+      result = new Script( scriptCode );
+      RWT.getUISession().setAttribute( key, result );
+    }
+    return result;
+  }
+
 }
diff --git a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java
index 4596373..f7cf226 100644
--- a/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java
+++ b/bundles/org.eclipse.rap.clientscripting.demo/src/org/eclipse/rap/clientscripting/demo/Demo.java
@@ -10,10 +10,8 @@
  ******************************************************************************/
 package org.eclipse.rap.clientscripting.demo;
 
-import org.eclipse.rap.clientscripting.ClientListener;
 import org.eclipse.rap.clientscripting.WidgetDataWhiteList;
 import org.eclipse.rap.rwt.application.AbstractEntryPoint;
-import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.FocusAdapter;
 import org.eclipse.swt.events.FocusEvent;
@@ -118,25 +116,21 @@
   private void createNumKeys( Composite parent, Text text ) {
     WidgetDataWhiteList.addKey( "textWidget" );
     WidgetDataWhiteList.addKey( "numValue" );
-    String scriptCode
-      = ResourceLoaderUtil.readTextContent( "org/eclipse/rap/clientscripting/demo/NumKey.js" );
-    ClientListener listener = new ClientListener( scriptCode );
     int[] numbers = new int[]{ 7, 8, 9, 4, 5, 6, 1, 2, 3 };
     for( int i = 0; i < numbers.length; i++ ) {
-      createNumButton( parent, text, listener, numbers[ i ] );
+      createNumButton( parent, text, numbers[ i ] );
     }
-    createNumButton( parent, text, listener, -1 ).setText( "C" );
-    createNumButton( parent, text, listener, 0 );
-    createNumButton( parent, text, listener, -2 ).setText( "." );
+    createNumButton( parent, text, -1 ).setText( "C" );
+    createNumButton( parent, text, 0 );
+    createNumButton( parent, text, -2 ).setText( "." );
   }
 
-  private Button createNumButton( Composite parent, Text text, ClientListener listener, int number ) {
+
+  private Button createNumButton( Composite parent, Text text, int number ) {
     Button button = new Button( parent, SWT.PUSH );
     button.setText( String.valueOf( number ) );
-    button.setData( "textWidget", WidgetUtil.getId( text ) );
-    button.setData( "numValue", Integer.valueOf( number ) );
-    button.addListener( SWT.MouseDown, listener );
     button.setLayoutData( new GridData( 80, 70 ) );
+    CustomBehaviors.addNumKeyBehavior( text, number, button );
     return button;
   }
 
diff --git a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java
index e34a59c..650419e 100644
--- a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java
+++ b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/ClientListener.java
@@ -65,6 +65,10 @@
     super( scriptCode );
   }
 
+  public ClientListener( Script script ) {
+    super( script );
+  }
+
   /**
    * This method will NOT be called on a ClientListener.
    */
diff --git a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/Script.java b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/Script.java
index 26eecef..f4ba7dc 100644
--- a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/Script.java
+++ b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/Script.java
@@ -20,13 +20,13 @@
   private static final String REMOTE_TYPE = "rwt.clientscripting.Script";
   private RemoteObject remoteObject;
 
-  public Script( String text ) {
-    if( text == null ) {
-      throw new NullPointerException( "Text must not be null" );
+  public Script( String scriptCode ) {
+    if( scriptCode == null ) {
+      throw new NullPointerException( "Parameter is null: scriptCode" );
     }
     Connection connection = RWT.getUISession().getConnection();
     remoteObject = connection.createRemoteObject( REMOTE_TYPE );
-    remoteObject.set( "text", text );
+    remoteObject.set( "text", scriptCode );
   }
 
   public String getId() {
diff --git a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/internal/ClientFunction.java b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/internal/ClientFunction.java
index 95e1d11..15708d5 100644
--- a/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/internal/ClientFunction.java
+++ b/bundles/org.eclipse.rap.clientscripting/src/org/eclipse/rap/clientscripting/internal/ClientFunction.java
@@ -25,15 +25,17 @@
 
   private final RemoteObject remoteObject;
   private final Collection<ClientListenerBinding> bindings;
-  private final Script script;
 
   public ClientFunction( String scriptCode ) {
-    if( scriptCode == null ) {
-      throw new NullPointerException( "Parameter is null: scriptCode" );
+    this( new Script( scriptCode ) );
+  }
+
+  public ClientFunction( Script script ) {
+    if( script == null ) {
+      throw new NullPointerException( "Parameter is null: script" );
     }
     ClientScriptingResources.ensure();
     bindings = new ArrayList<ClientListenerBinding>();
-    script = new Script( scriptCode );
     remoteObject = RWT.getUISession().getConnection().createRemoteObject( REMOTE_TYPE );
     remoteObject.set( "script", script.getId() );
   }
diff --git a/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/ClientListener_Test.java b/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/ClientListener_Test.java
index 87415f1..128d187 100644
--- a/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/ClientListener_Test.java
+++ b/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/ClientListener_Test.java
@@ -200,7 +200,7 @@
   }
 
   private void createListener() {
-    listener = spy( new ClientListener( "code" ) );
+    listener = spy( new ClientListener( new Script( "code" ) ) );
   }
 
 }
diff --git a/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/internal/ClientFunction_Test.java b/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/internal/ClientFunction_Test.java
index f54ca6e..581b763 100644
--- a/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/internal/ClientFunction_Test.java
+++ b/tests/org.eclipse.rap.clientscripting.test/src/org/eclipse/rap/clientscripting/internal/ClientFunction_Test.java
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import org.eclipse.rap.clientscripting.Script;
 import org.eclipse.rap.rwt.remote.Connection;
 import org.eclipse.rap.rwt.remote.RemoteObject;
 import org.eclipse.rap.rwt.testfixture.Fixture;
@@ -48,10 +49,11 @@
     Fixture.tearDown();
   }
 
+  @SuppressWarnings( "deprecation" )
   @Test
-  public void testCreation_failsWithNull() {
+  public void testCreation_failsWithStringNull() {
     try {
-      new ClientFunction( null );
+      new ClientFunction( ( String )null );
       fail();
     } catch( NullPointerException expected ) {
       assertTrue( expected.getMessage().contains( "scriptCode" ) );
@@ -59,16 +61,26 @@
   }
 
   @Test
+  public void testCreation_failsWithScriptNull() {
+    try {
+      new ClientFunction( ( Script )null );
+      fail();
+    } catch( NullPointerException expected ) {
+      assertTrue( expected.getMessage().contains( "script" ) );
+    }
+  }
+
+  @Test
   public void testCreation_createsRemoteObject() {
     Connection connection = fakeConnection( mock( RemoteObject.class ), CLIENT_LISTENER_TYPE );
 
-    new ClientFunction( "script code" );
+    new ClientFunction( new Script( "script code" ) );
 
     verify( connection ).createRemoteObject( "rwt.clientscripting.Listener" );
   }
 
   @Test
-  public void testCreation_initializesRemoteObject() {
+  public void testCreationWithString_initializesRemoteObject() {
     RemoteObject listenerRemoteObject = mock( RemoteObject.class );
     RemoteObject scriptRemoteObject = mock( RemoteObject.class );
     Connection connection = mock( Connection.class );
@@ -78,11 +90,22 @@
     when( scriptRemoteObject.getId() ).thenReturn( "fooId" );
     Fixture.fakeConnection( connection );
 
-    new ClientFunction( "script code" );
+    new ClientFunction( new Script( "script code" ) );
 
     verify( listenerRemoteObject ).set( eq( "script" ), eq( "fooId" ) );
   }
 
+  @Test
+  public void testCreationWithScript_initializesRemoteObject() {
+    RemoteObject listenerRemoteObject = mock( RemoteObject.class );
+    fakeConnection( listenerRemoteObject, CLIENT_LISTENER_TYPE );
+    Script script = mock( Script.class );
+    when( script.getId() ).thenReturn( "fooId" );
+
+    new ClientFunction( script );
+
+    verify( listenerRemoteObject ).set( eq( "script" ), eq( "fooId" ) );
+  }
 
   @Test
   public void testAddTo_createsBinding() {
@@ -140,7 +163,7 @@
   }
 
   private void createListener() {
-    function = spy( new ClientFunction( "code" ) );
+    function = spy( new ClientFunction( new Script( "code" ) ) );
   }
 
 }