10ac475d29f793079783f501126239ed6ce8aa31dTor Norbye/* 20ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * Copyright (C) 2011 The Android Open Source Project 30ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * 40ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 50ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * you may not use this file except in compliance with the License. 60ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * You may obtain a copy of the License at 70ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * 80ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * http://www.eclipse.org/org/documents/epl-v10.php 90ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * 100ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * Unless required by applicable law or agreed to in writing, software 110ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * distributed under the License is distributed on an "AS IS" BASIS, 120ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * See the License for the specific language governing permissions and 140ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * limitations under the License. 150ac475d29f793079783f501126239ed6ce8aa31dTor Norbye */ 160ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 170ac475d29f793079783f501126239ed6ce8aa31dTor Norbyepackage com.android.ide.eclipse.adt.internal.editors.layout.gle2; 180ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 197dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.annotations.NonNull; 207dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbyeimport com.android.annotations.Nullable; 217dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 220ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.SWT; 230ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.custom.CLabel; 240ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.events.MouseEvent; 250ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.events.MouseTrackListener; 260ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.events.PaintEvent; 270ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.events.PaintListener; 280ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.graphics.Color; 290ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.graphics.GC; 300ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.graphics.Image; 310ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.graphics.Point; 320ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.graphics.Rectangle; 330ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.widgets.Canvas; 340ac475d29f793079783f501126239ed6ce8aa31dTor Norbyeimport org.eclipse.swt.widgets.Composite; 350ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 360ac475d29f793079783f501126239ed6ce8aa31dTor Norbye/** 370ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * An ImageControl which simply renders an image, with optional margins and tooltips. This 380ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * is useful since a {@link CLabel}, even without text, will hide the image when there is 390ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * not enough room to fully fit it. 400ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * <p> 410ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * The image is always rendered left and top aligned. 420ac475d29f793079783f501126239ed6ce8aa31dTor Norbye */ 430ac475d29f793079783f501126239ed6ce8aa31dTor Norbyepublic class ImageControl extends Canvas implements MouseTrackListener { 440ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private Image mImage; 450ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private int mLeftMargin; 460ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private int mTopMargin; 470ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private int mRightMargin; 480ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private int mBottomMargin; 49a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye private boolean mDisposeImage = true; 500ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private boolean mMouseIn; 510ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private Color mHoverColor; 520ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private float mScale = 1.0f; 530ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 540ac475d29f793079783f501126239ed6ce8aa31dTor Norbye /** 559bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * Creates an ImageControl rendering the given image, which will be disposed when this 569bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * control is disposed (unless the {@link #setDisposeImage} method is called to turn 579bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * off auto dispose). 580ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * 590ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * @param parent the parent to add the image control to 600ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * @param style the SWT style to use 610ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * @param image the image to be rendered, which must not be null and should be unique 620ac475d29f793079783f501126239ed6ce8aa31dTor Norbye * for this image control since it will be disposed by this control when 639bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * the control is disposed (unless the {@link #setDisposeImage} method is 649bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * called to turn off auto dispose) 650ac475d29f793079783f501126239ed6ce8aa31dTor Norbye */ 667dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public ImageControl(@NonNull Composite parent, int style, @Nullable Image image) { 670ac475d29f793079783f501126239ed6ce8aa31dTor Norbye super(parent, style | SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED); 68a21b9b44b0db30f497b3507c8b97683387960b59Tor Norbye mImage = image; 690ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 700ac475d29f793079783f501126239ed6ce8aa31dTor Norbye addPaintListener(new PaintListener() { 71ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 720ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public void paintControl(PaintEvent event) { 730ac475d29f793079783f501126239ed6ce8aa31dTor Norbye onPaint(event); 740ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 750ac475d29f793079783f501126239ed6ce8aa31dTor Norbye }); 760ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 770ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 787dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Nullable 797dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public Image getImage() { 807dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return mImage; 817dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 827dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 837dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void setImage(@Nullable Image image) { 847dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (mDisposeImage && mImage != null) { 85bc095ab3017f4127ba3d4cf86499db21a5a19b76Tor Norbye mImage.dispose(); 86bc095ab3017f4127ba3d4cf86499db21a5a19b76Tor Norbye } 87bc095ab3017f4127ba3d4cf86499db21a5a19b76Tor Norbye mImage = image; 887dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye redraw(); 897dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 907dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 917dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void fitToWidth(int width) { 927dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (mImage == null) { 937dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return; 947dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 957dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye Rectangle imageRect = mImage.getBounds(); 967dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye int imageWidth = imageRect.width; 977dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (imageWidth <= width) { 987dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mScale = 1.0f; 997dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye return; 1007dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 1017dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye 1027dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye mScale = width / (float) imageWidth; 1037dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye redraw(); 104bc095ab3017f4127ba3d4cf86499db21a5a19b76Tor Norbye } 105bc095ab3017f4127ba3d4cf86499db21a5a19b76Tor Norbye 1060ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public void setScale(float scale) { 1070ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mScale = scale; 1080ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1090ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1100ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public float getScale() { 1110ac475d29f793079783f501126239ed6ce8aa31dTor Norbye return mScale; 1120ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1130ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1147dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye public void setHoverColor(@Nullable Color hoverColor) { 1157dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (mHoverColor != null) { 1167dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye removeMouseTrackListener(this); 1177dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye } 1180ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mHoverColor = hoverColor; 1190ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (hoverColor != null) { 1200ac475d29f793079783f501126239ed6ce8aa31dTor Norbye addMouseTrackListener(this); 1210ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1220ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1230ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1247dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye @Nullable 1250ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public Color getHoverColor() { 1260ac475d29f793079783f501126239ed6ce8aa31dTor Norbye return mHoverColor; 1270ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1280ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1290ac475d29f793079783f501126239ed6ce8aa31dTor Norbye @Override 1300ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public void dispose() { 1310ac475d29f793079783f501126239ed6ce8aa31dTor Norbye super.dispose(); 1320ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1337dd444ea0125e50a5e88604afb6de43e80b7c270Tor Norbye if (mDisposeImage && mImage != null && !mImage.isDisposed()) { 134a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye mImage.dispose(); 135a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye } 1360ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mImage = null; 1370ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1380ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 139a21b9b44b0db30f497b3507c8b97683387960b59Tor Norbye public void setDisposeImage(boolean disposeImage) { 140a21b9b44b0db30f497b3507c8b97683387960b59Tor Norbye mDisposeImage = disposeImage; 141a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye } 142a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye 143a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye public boolean getDisposeImage() { 144a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye return mDisposeImage; 145a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye } 146a7da09b74d5f41667823ddf36c0cd7f145f54a2dTor Norbye 1470ac475d29f793079783f501126239ed6ce8aa31dTor Norbye @Override 1480ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public Point computeSize(int wHint, int hHint, boolean changed) { 1490ac475d29f793079783f501126239ed6ce8aa31dTor Norbye checkWidget(); 1500ac475d29f793079783f501126239ed6ce8aa31dTor Norbye Point e = new Point(0, 0); 1510ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (mImage != null) { 1520ac475d29f793079783f501126239ed6ce8aa31dTor Norbye Rectangle r = mImage.getBounds(); 1530ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (mScale != 1.0f) { 1540ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.x += mScale * r.width; 1550ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.y += mScale * r.height; 1560ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } else { 1570ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.x += r.width; 1580ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.y += r.height; 1590ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1600ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1610ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (wHint == SWT.DEFAULT) { 1620ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.x += mLeftMargin + mRightMargin; 1630ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } else { 1640ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.x = wHint; 1650ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1660ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (hHint == SWT.DEFAULT) { 1670ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.y += mTopMargin + mBottomMargin; 1680ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } else { 1690ac475d29f793079783f501126239ed6ce8aa31dTor Norbye e.y = hHint; 1700ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1710ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1720ac475d29f793079783f501126239ed6ce8aa31dTor Norbye return e; 1730ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1740ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1750ac475d29f793079783f501126239ed6ce8aa31dTor Norbye private void onPaint(PaintEvent event) { 1760ac475d29f793079783f501126239ed6ce8aa31dTor Norbye Rectangle rect = getClientArea(); 1770ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (mImage == null || rect.width == 0 || rect.height == 0) { 1780ac475d29f793079783f501126239ed6ce8aa31dTor Norbye return; 1790ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1800ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1810ac475d29f793079783f501126239ed6ce8aa31dTor Norbye GC gc = event.gc; 1820ac475d29f793079783f501126239ed6ce8aa31dTor Norbye Rectangle imageRect = mImage.getBounds(); 1830ac475d29f793079783f501126239ed6ce8aa31dTor Norbye int imageHeight = imageRect.height; 1840ac475d29f793079783f501126239ed6ce8aa31dTor Norbye int imageWidth = imageRect.width; 1850ac475d29f793079783f501126239ed6ce8aa31dTor Norbye int destWidth = imageWidth; 1860ac475d29f793079783f501126239ed6ce8aa31dTor Norbye int destHeight = imageHeight; 1870ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1887a18f14d98bbf7094dd0faa55cb6d90c7645ec80Tor Norbye int oldGcAlias = gc.getAntialias(); 1897a18f14d98bbf7094dd0faa55cb6d90c7645ec80Tor Norbye int oldGcInterpolation = gc.getInterpolation(); 1900ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (mScale != 1.0f) { 1910ac475d29f793079783f501126239ed6ce8aa31dTor Norbye destWidth = (int) (mScale * destWidth); 1920ac475d29f793079783f501126239ed6ce8aa31dTor Norbye destHeight = (int) (mScale * destHeight); 1937a18f14d98bbf7094dd0faa55cb6d90c7645ec80Tor Norbye gc.setAntialias(SWT.ON); 1947a18f14d98bbf7094dd0faa55cb6d90c7645ec80Tor Norbye gc.setInterpolation(SWT.HIGH); 1950ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 1960ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 1970ac475d29f793079783f501126239ed6ce8aa31dTor Norbye gc.drawImage(mImage, 0, 0, imageWidth, imageHeight, rect.x + mLeftMargin, rect.y 1980ac475d29f793079783f501126239ed6ce8aa31dTor Norbye + mTopMargin, destWidth, destHeight); 1990ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 2007a18f14d98bbf7094dd0faa55cb6d90c7645ec80Tor Norbye gc.setAntialias(oldGcAlias); 2017a18f14d98bbf7094dd0faa55cb6d90c7645ec80Tor Norbye gc.setInterpolation(oldGcInterpolation); 2027a18f14d98bbf7094dd0faa55cb6d90c7645ec80Tor Norbye 2030ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (mHoverColor != null && mMouseIn) { 2040ac475d29f793079783f501126239ed6ce8aa31dTor Norbye gc.setAlpha(60); 2050ac475d29f793079783f501126239ed6ce8aa31dTor Norbye gc.setBackground(mHoverColor); 2060ac475d29f793079783f501126239ed6ce8aa31dTor Norbye gc.setLineWidth(1); 2070ac475d29f793079783f501126239ed6ce8aa31dTor Norbye gc.fillRectangle(0, 0, destWidth, destHeight); 2080ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2090ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2100ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 2110ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public void setMargins(int leftMargin, int topMargin, int rightMargin, int bottomMargin) { 2120ac475d29f793079783f501126239ed6ce8aa31dTor Norbye checkWidget(); 2130ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mLeftMargin = Math.max(0, leftMargin); 2140ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mTopMargin = Math.max(0, topMargin); 2150ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mRightMargin = Math.max(0, rightMargin); 2160ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mBottomMargin = Math.max(0, bottomMargin); 2170ac475d29f793079783f501126239ed6ce8aa31dTor Norbye redraw(); 2180ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2190ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 2200ac475d29f793079783f501126239ed6ce8aa31dTor Norbye // ---- Implements MouseTrackListener ---- 2210ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 222ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 2230ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public void mouseEnter(MouseEvent e) { 2240ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mMouseIn = true; 2250ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (mHoverColor != null) { 2260ac475d29f793079783f501126239ed6ce8aa31dTor Norbye redraw(); 2270ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2280ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2290ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 230ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 2310ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public void mouseExit(MouseEvent e) { 2320ac475d29f793079783f501126239ed6ce8aa31dTor Norbye mMouseIn = false; 2330ac475d29f793079783f501126239ed6ce8aa31dTor Norbye if (mHoverColor != null) { 2340ac475d29f793079783f501126239ed6ce8aa31dTor Norbye redraw(); 2350ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2360ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2370ac475d29f793079783f501126239ed6ce8aa31dTor Norbye 238ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 2390ac475d29f793079783f501126239ed6ce8aa31dTor Norbye public void mouseHover(MouseEvent e) { 2400ac475d29f793079783f501126239ed6ce8aa31dTor Norbye } 2410ac475d29f793079783f501126239ed6ce8aa31dTor Norbye} 242