diff options
Diffstat (limited to 'src/test/com/jogamp')
14 files changed, 122 insertions, 63 deletions
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java index 8c0213e8e..7127b0a5f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java @@ -91,7 +91,7 @@ public class TestInitConcurrentNEWT extends UITestCase { glWindow.setTitle("Task "+id); glWindow.setPosition(x + insets.getLeftWidth(), y + insets.getTopHeight() ); - glWindow.addGLEventListener(new GearsES2(1)); + glWindow.addGLEventListener(new GearsES2(0)); Animator animator = new Animator(glWindow); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java index fb2c9c7ea..5c82a43c6 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java @@ -48,6 +48,9 @@ public class GearsES1 implements GLEventListener { private GearsObject gear1=null, gear2=null, gear3=null; private float angle = 0.0f; private int swapInterval; + private MouseListener gearsMouse = new GearsMouseAdapter(); + private KeyListener gearsKeys = new GearsKeyAdapter(); + private int prevMouseX, prevMouseY; @@ -126,12 +129,8 @@ public class GearsES1 implements GLEventListener { gl.glEnable(GL2ES1.GL_NORMALIZE); - // MouseListener gearsMouse = new TraceMouseAdapter(new GearsMouseAdapter()); - MouseListener gearsMouse = new GearsMouseAdapter(); - KeyListener gearsKeys = new GearsKeyAdapter(); - - if (drawable instanceof Window) { - Window window = (Window) drawable; + if (drawable.getNativeSurface() instanceof Window) { + Window window = (Window) drawable.getNativeSurface(); window.addMouseListener(gearsMouse); window.addKeyListener(gearsKeys); } else if (GLProfile.isAWTAvailable() && drawable instanceof java.awt.Component) { @@ -166,6 +165,11 @@ public class GearsES1 implements GLEventListener { public void dispose(GLAutoDrawable drawable) { System.err.println(Thread.currentThread()+" GearsES1.dispose ... "); + if (drawable.getNativeSurface() instanceof Window) { + Window window = (Window) drawable.getNativeSurface(); + window.removeMouseListener(gearsMouse); + window.removeKeyListener(gearsKeys); + } GL gl = drawable.getGL(); gear1.destroy(gl); gear1 = null; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java index dffe61f69..ff168d9e9 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java @@ -51,8 +51,8 @@ public class TestGearsES1NEWT extends UITestCase { @BeforeClass public static void initClass() { - width = 512; - height = 512; + width = 640; + height = 480; } @AfterClass diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java index 6246b3e87..c6c34d05a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java @@ -163,8 +163,8 @@ public class GearsES2 implements GLEventListener { System.err.println("gear3 reused: "+gear3); } - if (drawable instanceof Window) { - Window window = (Window) drawable; + if (drawable.getNativeSurface() instanceof Window) { + Window window = (Window) drawable.getNativeSurface(); window.addMouseListener(gearsMouse); window.addKeyListener(gearsKeys); } else if (GLProfile.isAWTAvailable() && drawable instanceof java.awt.Component) { @@ -207,8 +207,8 @@ public class GearsES2 implements GLEventListener { public void dispose(GLAutoDrawable drawable) { System.err.println(Thread.currentThread()+" GearsES2.dispose ... "); - if (drawable instanceof Window) { - Window window = (Window) drawable; + if (drawable.getNativeSurface() instanceof Window) { + Window window = (Window) drawable.getNativeSurface(); window.removeMouseListener(gearsMouse); window.removeKeyListener(gearsKeys); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java index eceaa0637..11f96ed77 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java @@ -53,6 +53,8 @@ public class RedSquareES2 implements GLEventListener { private int swapInterval = 0; MyMouseAdapter myMouse = new MyMouseAdapter(); GLWindow glWindow = null; + float aspect = 1.0f; + boolean doRotate = true; public RedSquareES2(int swapInterval) { this.swapInterval = swapInterval; @@ -62,6 +64,9 @@ public class RedSquareES2 implements GLEventListener { this.swapInterval = 1; } + public void setAspect(float aspect) { this.aspect = aspect; } + public void setDoRotation(boolean rotate) { this.doRotate = rotate; } + public void init(GLAutoDrawable glad) { System.err.println(Thread.currentThread()+" RedSquareES2.init ..."); GL2ES2 gl = glad.getGL().getGL2ES2(); @@ -142,9 +147,11 @@ public class RedSquareES2 implements GLEventListener { pmvMatrix.glMatrixMode(PMVMatrix.GL_MODELVIEW); pmvMatrix.glLoadIdentity(); pmvMatrix.glTranslatef(0, 0, -10); - float ang = ((float) (t1 - t0) * 360.0F) / 4000.0F; - pmvMatrix.glRotatef(ang, 0, 0, 1); - pmvMatrix.glRotatef(ang, 0, 1, 0); + if(doRotate) { + float ang = ((float) (t1 - t0) * 360.0F) / 4000.0F; + pmvMatrix.glRotatef(ang, 0, 0, 1); + pmvMatrix.glRotatef(ang, 0, 1, 0); + } st.uniform(gl, pmvMatrixUniform); // Draw a square @@ -164,7 +171,7 @@ public class RedSquareES2 implements GLEventListener { // Set location in front of camera pmvMatrix.glMatrixMode(PMVMatrix.GL_PROJECTION); pmvMatrix.glLoadIdentity(); - pmvMatrix.gluPerspective(45.0F, (float) width / (float) height, 1.0F, 100.0F); + pmvMatrix.gluPerspective(45.0F, ( (float) width / (float) height ) / aspect, 1.0F, 100.0F); //pmvMatrix.glOrthof(-4.0f, 4.0f, -4.0f, 4.0f, 1.0f, 100.0f); st.uniform(gl, pmvMatrixUniform); st.useProgram(gl, false); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java index ba9113af5..b3fdaa0ca 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java @@ -69,8 +69,8 @@ public class TestGearsES2AWT extends UITestCase { @BeforeClass public static void initClass() { - width = 512; - height = 512; + width = 640; + height = 480; } @AfterClass diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java index 3fe0706c4..04563d62e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java @@ -89,7 +89,7 @@ public class TestGearsES2NEWT extends UITestCase { @BeforeClass public static void initClass() { if(null == wsize) { - wsize = new Dimension(200, 200); + wsize = new Dimension(640, 480); } } @@ -257,7 +257,7 @@ public class TestGearsES2NEWT extends UITestCase { } public static void main(String args[]) throws IOException { - int x=0, y=0, w=200, h=200; + int x=0, y=0, w=640, h=480; boolean useSize = false; boolean usePos = false; @@ -319,9 +319,8 @@ public class TestGearsES2NEWT extends UITestCase { } } } - if(useSize) { - wsize = new Dimension(w, h); - } + wsize = new Dimension(w, h); + if(usePos) { wpos = new Point(x, y); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java index b4881ab51..c09119a32 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/Gears.java @@ -29,6 +29,8 @@ public class Gears implements GLEventListener { private int gear1=0, gear2=0, gear3=0; private float angle = 0.0f; private int swapInterval; + private MouseListener gearsMouse = new GearsMouseAdapter(); + private KeyListener gearsKeys = new GearsKeyAdapter(); // private boolean mouseRButtonDown = false; private int prevMouseX, prevMouseY; @@ -122,18 +124,14 @@ public class Gears implements GLEventListener { gl.glEnable(GL2.GL_NORMALIZE); - // MouseListener gearsMouse = new TraceMouseAdapter(new GearsMouseAdapter()); - MouseListener gearsMouse = new GearsMouseAdapter(); - KeyListener gearsKeys = new GearsKeyAdapter(); - - if (drawable instanceof Window) { - Window window = (Window) drawable; - window.addMouseListener(gearsMouse); - window.addKeyListener(gearsKeys); - } else if (GLProfile.isAWTAvailable() && drawable instanceof java.awt.Component) { + if (GLProfile.isAWTAvailable() && drawable instanceof java.awt.Component) { java.awt.Component comp = (java.awt.Component) drawable; new AWTMouseAdapter(gearsMouse).addTo(comp); - new AWTKeyAdapter(gearsKeys).addTo(comp); + new AWTKeyAdapter(gearsKeys).addTo(comp); + } else if (drawable.getNativeSurface() instanceof Window) { + Window window = (Window) drawable.getNativeSurface(); + window.addMouseListener(gearsMouse); + window.addKeyListener(gearsKeys); } } @@ -143,12 +141,16 @@ public class Gears implements GLEventListener { gl.setSwapInterval(swapInterval); - float h = (float)height / (float)width; - gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); - gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f); + if(height>width) { + float h = (float)height / (float)width; + gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f); + } else { + float h = (float)width / (float)height; + gl.glFrustum(-h, h, -1.0f, 1.0f, 5.0f, 60.0f); + } gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f, -40.0f); @@ -156,6 +158,13 @@ public class Gears implements GLEventListener { public void dispose(GLAutoDrawable drawable) { System.err.println("Gears: Dispose"); + try { + if (drawable.getNativeSurface() instanceof Window) { + Window window = (Window) drawable.getNativeSurface(); + window.removeMouseListener(gearsMouse); + window.removeKeyListener(gearsKeys); + } + } catch (Exception e) { System.err.println("Catched: "); e.printStackTrace(); } setGears(0, 0, 0); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java index ff24979eb..498a3285a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java @@ -40,6 +40,8 @@ import com.jogamp.newt.event.TraceWindowAdapter; import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.test.junit.util.QuitAdapter; + +import java.awt.Dimension; import java.awt.Frame; import java.io.BufferedReader; import java.io.IOException; @@ -61,8 +63,8 @@ public class TestGearsAWT extends UITestCase { if(GLProfile.isAvailable(GLProfile.GL2)) { glp = GLProfile.get(GLProfile.GL2); Assert.assertNotNull(glp); - width = 512; - height = 512; + width = 640; + height = 480; } else { setTestSupported(false); } @@ -80,8 +82,11 @@ public class TestGearsAWT extends UITestCase { final GLCanvas glCanvas = new GLCanvas(caps); Assert.assertNotNull(glCanvas); + Dimension glc_sz = new Dimension(width, height); + glCanvas.setMinimumSize(glc_sz); + glCanvas.setPreferredSize(glc_sz); + glCanvas.setSize(glc_sz); frame.add(glCanvas); - frame.setSize(512, 512); glCanvas.addGLEventListener(new Gears(1)); @@ -93,6 +98,7 @@ public class TestGearsAWT extends UITestCase { javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { + frame.pack(); frame.setVisible(true); }}); animator.setUpdateFPSFrames(60, System.err); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWT.java index c7254dda6..cb54c26bd 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWT.java @@ -37,6 +37,7 @@ import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; import com.jogamp.opengl.test.junit.util.UITestCase; import java.awt.AWTException; import java.awt.BorderLayout; +import java.awt.Dimension; import java.lang.reflect.InvocationTargetException; import javax.swing.JFrame; import javax.swing.SwingUtilities; @@ -55,8 +56,8 @@ public class TestGearsGLJPanelAWT extends UITestCase { if(GLProfile.isAvailable(GLProfile.GL2)) { glp = GLProfile.get(GLProfile.GL2); Assert.assertNotNull(glp); - width = 512; - height = 512; + width = 640; + height = 480; } else { setTestSupported(false); } @@ -74,6 +75,10 @@ public class TestGearsGLJPanelAWT extends UITestCase { GLJPanel glJPanel = new GLJPanel(caps); Assert.assertNotNull(glJPanel); + Dimension glc_sz = new Dimension(width, height); + glJPanel.setMinimumSize(glc_sz); + glJPanel.setPreferredSize(glc_sz); + glJPanel.setSize(glc_sz); glJPanel.addGLEventListener(new Gears()); FPSAnimator animator = new FPSAnimator(glJPanel, 60); @@ -83,7 +88,8 @@ public class TestGearsGLJPanelAWT extends UITestCase { SwingUtilities.invokeAndWait(new Runnable() { public void run() { _frame.getContentPane().add(_glJPanel, BorderLayout.CENTER); - _frame.setSize(512, 512); + _frame.getContentPane().validate(); + _frame.pack(); _frame.setVisible(true); } } ) ; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWTBug450.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWTBug450.java index 7207e7815..e3f33e301 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWTBug450.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsGLJPanelAWTBug450.java @@ -30,14 +30,16 @@ import javax.media.opengl.*; import com.jogamp.opengl.util.FPSAnimator; +import com.jogamp.opengl.util.GLReadBufferUtil; import javax.media.opengl.awt.GLJPanel; import javax.media.opengl.glu.gl2.GLUgl2; -import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2; import com.jogamp.opengl.test.junit.util.UITestCase; import java.awt.AWTException; import java.awt.BorderLayout; +import java.io.File; import java.lang.reflect.InvocationTargetException; import java.nio.ByteBuffer; @@ -62,26 +64,32 @@ import org.junit.Test; public class TestGearsGLJPanelAWTBug450 extends UITestCase { static GLProfile glp; static int width, height; + static int r_x, r_y; /** Set this if test fails. Needed because we can't throw an exception * all the way up the stack from where we test the pixel. */ static boolean failed; @BeforeClass public static void initClass() { - if(GLProfile.isAvailable(GLProfile.GL2)) { - glp = GLProfile.get(GLProfile.GL2); - Assert.assertNotNull(glp); - width = 512; - height = 256; - } else { - setTestSupported(false); - } + glp = GLProfile.getGL2ES2(); + Assert.assertNotNull(glp); + height = 256; + width = 2*height; + r_x = 5*height/4; // 5/8 * width + r_y = height/2; } @AfterClass public static void releaseClass() { } + protected void snapshot(GLAutoDrawable drawable, boolean alpha, boolean flip, String filename) { + GLReadBufferUtil screenshot = new GLReadBufferUtil(alpha, false); + if(screenshot.readPixels(drawable.getGL(), drawable, flip)) { + screenshot.write(new File(filename)); + } + } + protected void runTestGL(GLCapabilities caps) throws AWTException, InterruptedException, InvocationTargetException { @@ -90,21 +98,39 @@ public class TestGearsGLJPanelAWTBug450 extends UITestCase { GLJPanel glJPanel = new GLJPanel(caps); Assert.assertNotNull(glJPanel); - glJPanel.addGLEventListener(new Gears() { + RedSquareES2 demo = new RedSquareES2(); + demo.setAspect((float)width/(float)height); + demo.setDoRotation(false); + glJPanel.addGLEventListener(demo); + glJPanel.addGLEventListener(new GLEventListener() { + int f = 0; + @Override + public void init(GLAutoDrawable drawable) { + // drawable.getGL().glClearColor(0, 0, 1, 1); + } @Override public void display(GLAutoDrawable drawable) { - super.display(drawable); // look at one pixel at the bottom of the frame, just right of // the center line, and make sure it's not black GL2 gl = GLUgl2.getCurrentGL2(); ByteBuffer bytebuffer = ByteBuffer.allocateDirect( 3 ); - gl.glReadPixels( 260, 10, 1, 1, GL2.GL_BGR, GL2.GL_UNSIGNED_BYTE, bytebuffer ); + gl.glReadPixels( r_x, r_y, 1, 1, GL2.GL_BGR, GL2.GL_UNSIGNED_BYTE, bytebuffer ); byte byte0 = bytebuffer.get( 0 ); byte byte1 = bytebuffer.get( 1 ); byte byte2 = bytebuffer.get( 2 ); - if( (byte0 == 0) && (byte1 == 0) && (byte2 == 0) ) + if( (byte0 == 0) && (byte1 == 0) && (byte2 == 0) ) { failed = true; + } + if(0 == f) { + System.err.println("BGR ("+r_x+"/"+r_y+"): "+byte0+", "+byte1+", "+byte2+" - OK "+(!failed)); + snapshot(drawable, true, false, getSimpleTestName(".")+".png"); + } + f++; } + @Override + public void dispose(GLAutoDrawable drawable) {} + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { } }); FPSAnimator animator = new FPSAnimator(glJPanel, 60); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java index 0f3c7e2ba..93dc885b6 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java @@ -55,8 +55,8 @@ public class TestGearsNEWT extends UITestCase { if(GLProfile.isAvailable(GLProfile.GL2)) { glp = GLProfile.get(GLProfile.GL2); Assert.assertNotNull(glp); - width = 512; - height = 512; + width = 640; + height = 480; } else { setTestSupported(false); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java index 54cfd0a99..62914bd4e 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java @@ -53,8 +53,8 @@ public class TestGearsNewtAWTWrapper extends UITestCase { public static void initClass() { glp = GLProfile.getGL2ES2(); Assert.assertNotNull(glp); - width = 512; - height = 512; + width = 640; + height = 480; } @AfterClass diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java index 4edac15ed..3f989bfa4 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java +++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java @@ -43,10 +43,12 @@ public class NEWTGLContext { public static class WindowContext { public final Window window; + public final GLDrawable drawable; public final GLContext context; - public WindowContext(Window w, GLContext c) { + public WindowContext(Window w, GLDrawable d, GLContext c) { window = w; + drawable = d; context = c; } } @@ -86,7 +88,7 @@ public class NEWTGLContext { int res = context.makeCurrent(); Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); - return new WindowContext(window, context); + return new WindowContext(window, drawable, context); } public static WindowContext createOnscreenWindow(GLCapabilities caps, int width, int height, boolean debugGL) throws InterruptedException { @@ -121,7 +123,7 @@ public class NEWTGLContext { int res = context.makeCurrent(); Assert.assertTrue(GLContext.CONTEXT_CURRENT_NEW==res || GLContext.CONTEXT_CURRENT==res); - return new WindowContext(window, context); + return new WindowContext(window, drawable, context); } public static void destroyWindow(WindowContext winctx) { |