19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
2251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19918aaa5717fce6081557c82ce1c439b6922737d5Xavier Ducrohetimport com.android.ide.common.rendering.api.LayoutLog;
20d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
21c2e9651bf386a1f7bf7fc706cf5424950570470cXavier Ducrohetimport com.android.layoutlib.bridge.impl.DelegateManager;
229a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohetimport com.android.tools.layoutlib.annotations.LayoutlibDelegate;
2345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
24251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohetimport android.graphics.Shader.TileMode;
25251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
26251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet/**
27251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * Delegate implementing the native methods of android.graphics.RadialGradient
28251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet *
29251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * Through the layoutlib_create tool, the original native methods of RadialGradient have been
30251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * replaced by calls to methods of the same name in this delegate class.
31251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet *
32251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * This class behaves like the original native implementation, but in Java, keeping previously
33251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * native data into its own objects and mapping them to int that are sent back and forth between
34251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * it and the original RadialGradient class.
35251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet *
36251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
37251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
38251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet *
39251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * @see Shader_Delegate
40251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet *
41251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet */
42251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohetpublic class RadialGradient_Delegate extends Gradient_Delegate {
43251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
44251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    // ---- delegate data ----
45251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    private java.awt.Paint mJavaPaint;
46251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
47251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    // ---- Public Helper methods ----
48251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
49251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    @Override
50d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    public java.awt.Paint getJavaPaint() {
51251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        return mJavaPaint;
52251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    }
53251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
54251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    // ---- native methods ----
55251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
569a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
57251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    /*package*/ static int nativeCreate1(float x, float y, float radius,
58251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet            int colors[], float positions[], int tileMode) {
59251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius,
60d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                colors, positions, Shader_Delegate.getTileMode(tileMode));
61cc4977d0fdaf657907912fd6cc2f9426dc8d2e36Xavier Ducrohet        return sManager.addNewDelegate(newDelegate);
62251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    }
63251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
649a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
65251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    /*package*/ static int nativeCreate2(float x, float y, float radius,
66251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet            int color0, int color1, int tileMode) {
67251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        return nativeCreate1(x, y, radius, new int[] { color0, color1 }, null /*positions*/,
68251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet                tileMode);
69251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    }
70251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
719a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
72251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    /*package*/ static int nativePostCreate1(int native_shader, float x, float y, float radius,
73251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet            int colors[], float positions[], int tileMode) {
74251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        // nothing to be done here.
75251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        return 0;
76251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    }
77251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
789a4fe29c8d92014d2d9a848e9116b8cc9d0842f9Xavier Ducrohet    @LayoutlibDelegate
79251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    /*package*/ static int nativePostCreate2(int native_shader, float x, float y, float radius,
80251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet            int color0, int color1, int tileMode) {
81251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        // nothing to be done here.
82251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        return 0;
83251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    }
84251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet
85251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    // ---- Private delegate/helper methods ----
8645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
8745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    /**
8845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * Create a shader that draws a radial gradient given the center and radius.
8945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *
9045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param x The x-coordinate of the center of the radius
9145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param y The y-coordinate of the center of the radius
9245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param radius Must be positive. The radius of the circle for this
9345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *            gradient
9445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param colors The colors to be distributed between the center and edge of
9545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *            the circle
9645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param positions May be NULL. The relative position of each corresponding
9745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *            color in the colors array. If this is NULL, the the colors are
9845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *            distributed evenly between the center and edge of the circle.
9945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param tile The Shader tiling mode
10045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     */
101251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    private RadialGradient_Delegate(float x, float y, float radius, int colors[], float positions[],
10245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            TileMode tile) {
10345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        super(colors, positions);
104251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet        mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
10563b2e616278c1b4284e1adbcc3936d0516083dcbXavier Ducrohet    }
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
107d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet    private class RadialGradientPaint extends GradientPaint {
10845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
10945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private final float mX;
11045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private final float mY;
11145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private final float mRadius;
11245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
113d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet        public RadialGradientPaint(float x, float y, float radius,
114d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                int[] colors, float[] positions, TileMode mode) {
11545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            super(colors, positions, mode);
11645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            mX = x;
11745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            mY = y;
11845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            mRadius = radius;
11945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
12045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
12146d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet        @Override
12245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        public java.awt.PaintContext createContext(
1233330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                java.awt.image.ColorModel     colorModel,
1243330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                java.awt.Rectangle            deviceBounds,
1253330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                java.awt.geom.Rectangle2D     userBounds,
12645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                java.awt.geom.AffineTransform xform,
1273330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                java.awt.RenderingHints       hints) {
12845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            precomputeGradientColors();
129d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet
130d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            java.awt.geom.AffineTransform canvasMatrix;
131d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet            try {
132d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                canvasMatrix = xform.createInverse();
133d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            } catch (java.awt.geom.NoninvertibleTransformException e) {
134918aaa5717fce6081557c82ce1c439b6922737d5Xavier Ducrohet                Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
13551a7e5447de94791c464cda5cc6ebbf616d73c80Xavier Ducrohet                        "Unable to inverse matrix in RadialGradient", e, null /*data*/);
136d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                canvasMatrix = new java.awt.geom.AffineTransform();
137d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet            }
138d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet
139d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
140d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet            try {
141d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                localMatrix = localMatrix.createInverse();
142d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            } catch (java.awt.geom.NoninvertibleTransformException e) {
143918aaa5717fce6081557c82ce1c439b6922737d5Xavier Ducrohet                Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
14451a7e5447de94791c464cda5cc6ebbf616d73c80Xavier Ducrohet                        "Unable to inverse matrix in RadialGradient", e, null /*data*/);
145d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                localMatrix = new java.awt.geom.AffineTransform();
146d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet            }
147d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet
148d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet            return new RadialGradientPaintContext(canvasMatrix, localMatrix, colorModel);
14945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
15045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
15145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private class RadialGradientPaintContext implements java.awt.PaintContext {
15245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
153d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            private final java.awt.geom.AffineTransform mCanvasMatrix;
154d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            private final java.awt.geom.AffineTransform mLocalMatrix;
15545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            private final java.awt.image.ColorModel mColorModel;
15645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
157d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet            public RadialGradientPaintContext(
158d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    java.awt.geom.AffineTransform canvasMatrix,
159d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    java.awt.geom.AffineTransform localMatrix,
160d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet                    java.awt.image.ColorModel colorModel) {
161d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                mCanvasMatrix = canvasMatrix;
162d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                mLocalMatrix = localMatrix;
16345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                mColorModel = colorModel;
16445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            }
16545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
16646d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet            @Override
16745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            public void dispose() {
16845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            }
16945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
17046d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet            @Override
17145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            public java.awt.image.ColorModel getColorModel() {
17245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                return mColorModel;
17345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            }
17445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
17546d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet            @Override
17645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
17745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
17845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                        java.awt.image.BufferedImage.TYPE_INT_ARGB);
17945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
18045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                int[] data = new int[w*h];
18145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
18245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                // compute distance from each point to the center, and figure out the distance from
18345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                // it.
18445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                int index = 0;
185d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                float[] pt1 = new float[2];
186d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                float[] pt2 = new float[2];
18745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                for (int iy = 0 ; iy < h ; iy++) {
18845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    for (int ix = 0 ; ix < w ; ix++) {
189d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        // handle the canvas transform
190d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        pt1[0] = x + ix;
191d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        pt1[1] = y + iy;
192d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
193d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet
194d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        // handle the local matrix
195d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        pt1[0] = pt2[0] - mX;
196d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        pt1[1] = pt2[1] - mY;
197d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
198d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet
199d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        float _x = pt2[0];
200d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                        float _y = pt2[1];
20145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                        float distance = (float) Math.sqrt(_x * _x + _y * _y);
20245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
20345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                        data[index++] = getGradientColor(distance / mRadius);
20445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    }
20545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                }
20645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
20745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
20845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
20945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                return image.getRaster();
21045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            }
21145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
21245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
21345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    }
21445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
21545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet}
216