/*
    Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
    и других спецификаций для функционирования компактных приложений на языке
    Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

    Copyright © 2016–2017, 2019–2022 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package javax.microedition.lcdui;

import com.nokia.mid.ui.*;
import javax.microedition.lcdui.game.*;
import malik.emulator.media.graphics.*;

public class Graphics extends Object implements DirectGraphics
{
    private static class Line extends Object implements Drawable
    {
        public final int x1;
        public final int y1;
        public final int x2;
        public final int y2;

        public Line(int x1, int y1, int x2, int y2) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }

        public void draw(PrimitiveRender render) {
            Graphics.drawLine(render, x1, y1, x2, y2, true);
        }
    }

    private static abstract class Triangle extends Line
    {
        public final int x3;
        public final int y3;

        public Triangle(int x1, int y1, int x2, int y2, int x3, int y3) {
            super(x1, y1, x2, y2);
            this.x3 = x3;
            this.y3 = y3;
        }

        public abstract void draw(PrimitiveRender render);
    }

    private static abstract class Polygon extends Object implements Drawable
    {
        public final int length;
        public final int xOffset;
        public final int yOffset;
        public final int[] xCoords;
        public final int[] yCoords;

        public Polygon(int[] xCoords, int xOffset, int[] yCoords, int yOffset, int length) {
            this.length = length;
            this.xOffset = xOffset;
            this.yOffset = yOffset;
            this.xCoords = xCoords;
            this.yCoords = yCoords;
        }

        public abstract void draw(PrimitiveRender render);
    }

    private static abstract class Rectangle extends Object implements Drawable
    {
        public final int width;
        public final int height;

        public Rectangle(int width, int height) {
            this.width = width;
            this.height = height;
        }

        public abstract void draw(PrimitiveRender render);
    }

    private static abstract class RoundRect extends Rectangle
    {
        public final int arcWidth;
        public final int arcHeight;

        public RoundRect(int width, int height, int arcWidth, int arcHeight) {
            super(width, height);
            width >>= 1;
            height >>= 1;
            this.arcWidth = arcWidth < 0 ? 0 : arcWidth > width ? width : arcWidth;
            this.arcHeight = arcHeight < 0 ? 0 : arcHeight > height ? height : arcHeight;
        }

        public abstract void draw(PrimitiveRender render);
    }

    private static class FilledTriangle extends Triangle
    {
        public FilledTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
            super(x1, y1, x2, y2, x3, y3);
        }

        public void draw(PrimitiveRender render) {
            int x1 = this.x1;
            int x2 = this.x2;
            int x3 = this.x3;
            int y1 = this.y1;
            int y2 = this.y2;
            int y3 = this.y3;
            int ix;
            int id;
            int idx;
            int idy;
            int ixerr;
            int iyerr;
            int iincx;
            int iincy;
            int jx;
            int jd;
            int jdx;
            int jdy;
            int jxerr;
            int jyerr;
            int jincx;
            int jincy;
            int tmp;
            if(y1 > y3)
            {
                tmp = y1;
                y1 = y3;
                y3 = tmp;
                tmp = x1;
                x1 = x3;
                x3 = tmp;
            }
            if(y1 > y2)
            {
                tmp = y1;
                y1 = y2;
                y2 = tmp;
                tmp = x1;
                x1 = x2;
                x2 = tmp;
            }
            if(y2 > y3)
            {
                tmp = y2;
                y2 = y3;
                y3 = tmp;
                tmp = x2;
                x2 = x3;
                x3 = tmp;
            }
            ix = x1;
            ixerr = 0;
            iyerr = 0;
            iincx = (idx = x2 - x1) == 0 ? 0 : (idx < 0 ? -1 : 1);
            iincy = (idy = y2 - y1) == 0 ? 0 : (idy < 0 ? -1 : 1);
            id = (idx = idx < 0 ? -idx : idx) >= (idy = idy < 0 ? -idy : idy) ? idx : idy;
            jx = x1;
            jxerr = 0;
            jyerr = 0;
            jincx = (jdx = x3 - x1) == 0 ? 0 : (jdx < 0 ? -1 : 1);
            jincy = (jdy = y3 - y1) == 0 ? 0 : (jdy < 0 ? -1 : 1);
            jd = (jdx = jdx < 0 ? -jdx : jdx) >= (jdy = jdy < 0 ? -jdy : jdy) ? jdx : jdy;
            for(int y = y1; ; )
            {
                if(y == y2)
                {
                    ix = x2;
                    ixerr = 0;
                    iyerr = 0;
                    iincx = (idx = x3 - x2) == 0 ? 0 : (idx < 0 ? -1 : 1);
                    iincy = (idy = y3 - y2) == 0 ? 0 : (idy < 0 ? -1 : 1);
                    id = (idx = idx < 0 ? -idx : idx) >= (idy = idy < 0 ? -idy : idy) ? idx : idy;
                }
                if(ix <= jx)
                {
                    render.drawHorizontalLine(ix, y, jx - ix + 1);
                } else
                {
                    render.drawHorizontalLine(jx, y, ix - jx + 1);
                }
                if(++y > y3) break;
                while(iincy > 0)
                {
                    ixerr += idx;
                    iyerr += idy;
                    if(ixerr > id)
                    {
                        ixerr -= id;
                        ix += iincx;
                    }
                    if(iyerr > id)
                    {
                        iyerr -= id;
                        break;
                    }
                }
                while(jincy > 0)
                {
                    jxerr += jdx;
                    jyerr += jdy;
                    if(jxerr > jd)
                    {
                        jxerr -= jd;
                        jx += jincx;
                    }
                    if(jyerr > jd)
                    {
                        jyerr -= jd;
                        break;
                    }
                }
            }
        }
    }

    private static class FilledPolygon extends Polygon
    {
        public FilledPolygon(int[] xCoords, int xOffset, int[] yCoords, int yOffset, int length) {
            super(xCoords, xOffset, yCoords, yOffset, length);
        }

        public void draw(PrimitiveRender render) {
            int ymin;
            int ymax;
            int length;
            int xStart;
            int yStart = (xStart = (length = this.length) & (-2)) + length;
            int[] coords = new int[yStart + length];
            Array.copy(xCoords, xOffset, coords, xStart, length);
            Array.copy(yCoords, yOffset, coords, yStart, length);
            ymin = ymax = coords[yStart];
            for(int i = length; i-- > 1; )
            {
                int yi = coords[yStart + i];
                if(ymin > yi) ymin = yi;
                if(ymax < yi) ymax = yi;
            }
            for(int y = ymin; y < ymax; y++)
            {
                int ixsize = 0;
                for(int x1 = coords[xStart], y1 = coords[yStart], i = length; i-- > 0; )
                {
                    int x;
                    int x0;
                    int x2 = x1;
                    int y2 = y1;
                    x1 = coords[xStart + i];
                    y1 = coords[yStart + i];
                    if(y < (y1 <= y2 ? y1 : y2) || y >= (y1 >= y2 ? y1 : y2)) continue;
                    x = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
                    switch(ixsize)
                    {
                    default:
                        if(x >= coords[ixsize - 1])
                        {
                            coords[ixsize++] = x;
                            break;
                        }
                        for(int j = 0; j < ixsize; j++) if(x <= coords[j])
                        {
                            Array.copy(coords, j, coords, j + 1, ixsize++ - j);
                            coords[j] = x;
                            break;
                        }
                        break;
                    case 1:
                        if(x < (x0 = coords[0]))
                        {
                            coords[ixsize++] = x0;
                            coords[0] = x;
                            break;
                        }
                        /* fall through */
                    case 0:
                        coords[ixsize++] = x;
                        break;
                    }
                }
                for(int x1, x2, j = ixsize; (j -= 2) >= 0; ) if((x1 = coords[j]) < (x2 = coords[j + 1])) render.drawHorizontalLine(x1, y, x2 - x1);
            }
        }
    }

    private static class FilledRoundRect extends RoundRect
    {
        public FilledRoundRect(int width, int height, int arcWidth, int arcHeight) {
            super(width, height, arcWidth, arcHeight);
        }

        public strictfp void draw(PrimitiveRender render) {
            double ratio;
            int w = width;
            int h = height;
            int aw = arcWidth;
            int ah = arcHeight;
            long square;
            if(aw <= 0 || ah <= 0)
            {
                render.fillRectangle(0, 0, w, h);
                return;
            }
            render.fillRectangle(0, ah, w, --h - (ah << 1) + 1);
            ratio = (double) aw / (double) ah;
            square = (long) ah * (long) ah;
            for(int y = ah, i = 0; i < ah; h--, y--, i++)
            {
                int j = (int) Math.round((double) aw - ratio * Math.sqrt((double) (square - (long) y * (long) y))) + (i != 0 ? 1 : 0);
                int tmp1 = w - (j << 1);
                render.drawHorizontalLine(j, i, tmp1);
                render.drawHorizontalLine(j, h, tmp1);
            }
        }
    }

    private static class ClosedPolygon extends Polygon
    {
        public ClosedPolygon(int[] xCoords, int xOffset, int[] yCoords, int yOffset, int length) {
            super(xCoords, xOffset, yCoords, yOffset, length);
        }

        public void draw(PrimitiveRender render) {
            int length = this.length;
            int xStart = xOffset;
            int yStart = yOffset;
            int[] cx = xCoords;
            int[] cy = yCoords;
            for(int x1 = cx[xStart], y1 = cy[yStart], i = length; i-- > 0; )
            {
                int x2 = x1;
                int y2 = y1;
                x1 = cx[xStart + i];
                y1 = cy[yStart + i];
                Graphics.drawLine(render, x1, y1, x2, y2, true);
            }
        }
    }

    private static class OpenedPolygon extends Polygon
    {
        public OpenedPolygon(int[] xCoords, int xOffset, int[] yCoords, int yOffset, int length) {
            super(xCoords, xOffset, yCoords, yOffset, length);
        }

        public void draw(PrimitiveRender render) {
            int length = this.length;
            int xStart = xOffset;
            int yStart = yOffset;
            int[] cx = xCoords;
            int[] cy = yCoords;
            for(int x2 = cx[xStart], y2 = cy[yStart], i = 1; i < length; i++)
            {
                int x1 = x2;
                int y1 = y2;
                x2 = cx[xStart + i];
                y2 = cy[yStart + i];
                Graphics.drawLine(render, x1, y1, x2, y2, false);
            }
        }
    }

    private static class OutlinedTriangle extends Triangle
    {
        public OutlinedTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
            super(x1, y1, x2, y2, x3, y3);
        }

        public void draw(PrimitiveRender render) {
            int x1 = this.x1;
            int y1 = this.y1;
            int x2 = this.x2;
            int y2 = this.y2;
            int x3 = this.x3;
            int y3 = this.y3;
            Graphics.drawLine(render, x1, y1, x2, y2, true);
            Graphics.drawLine(render, x2, y2, x3, y3, true);
            Graphics.drawLine(render, x3, y3, x1, y1, true);
        }
    }

    private static class OutlinedRectangle extends Rectangle
    {
        public OutlinedRectangle(int width, int height) {
            super(width, height);
        }

        public void draw(PrimitiveRender render) {
            int w = width;
            int h = height;
            render.drawHorizontalLine(0, 0, w + 1);
            if(h > 0) render.drawHorizontalLine(0, h, w + 1);
            if(h > 1)
            {
                render.drawVerticalLine(0, 1, h - 1);
                if(w > 0) render.drawVerticalLine(w, 1, h - 1);
            }
        }
    }

    private static class OutlinedRoundRect extends RoundRect
    {
        public OutlinedRoundRect(int width, int height, int arcWidth, int arcHeight) {
            super(width, height, arcWidth, arcHeight);
        }

        public strictfp void draw(PrimitiveRender render) {
            double ratio;
            int w = width;
            int h = height;
            int aw = arcWidth;
            int ah = arcHeight;
            int tmp1;
            int tmp2;
            long square;
            if(aw <= 0 || ah <= 0)
            {
                render.drawHorizontalLine(0, 0, w + 1);
                if(h > 0) render.drawHorizontalLine(0, h, w + 1);
                if(h > 1)
                {
                    render.drawVerticalLine(0, 1, h - 1);
                    if(w > 0) render.drawVerticalLine(w, 1, h - 1);
                }
                return;
            }
            tmp1 = w - (aw << 1) + 1;
            tmp2 = h - (ah << 1) + 1;
            render.drawHorizontalLine(aw, 0, tmp1);
            render.drawHorizontalLine(aw, h, tmp1);
            render.drawVerticalLine(0, ah, tmp2);
            render.drawVerticalLine(w, ah, tmp2);
            ratio = (double) aw / (double) ah;
            square = (long) ah * (long) ah;
            for(int x = aw, y = ah, l, k, j, i = 1; i < ah; x = j, i++)
            {
                y--;
                j = (int) Math.intPart((double) aw - ratio * Math.sqrt((double) (square - (long) y * (long) y))) + 1;
                tmp1 = x == j ? 1 : x - j;
                k = h - i;
                l = w - j - tmp1 + 1;
                render.drawHorizontalLine(j, i, tmp1);
                render.drawHorizontalLine(j, k, tmp1);
                render.drawHorizontalLine(l, i, tmp1);
                render.drawHorizontalLine(l, k, tmp1);
            }
        }
    }

    public static final int SOLID = 0;
    public static final int DOTTED = 1;
    public static final int HCENTER = 0x01;
    public static final int VCENTER = 0x02;
    public static final int LEFT = 0x04;
    public static final int RIGHT = 0x08;
    public static final int TOP = 0x10;
    public static final int BOTTOM = 0x20;
    public static final int BASELINE = 0x40;
    private static final short[] XTABLE;
    private static final short[] YTABLE;

    static {
        short[] x = new short[360];
        short[] y = new short[360];
        init(x, y);
        XTABLE = x;
        YTABLE = y;
    }

    static void drawLine(PrimitiveRender render, int x1, int y1, int x2, int y2, boolean inclusive) {
        int x;
        int y;
        int d;
        int dx;
        int dy;
        int xerr;
        int yerr;
        int incx;
        int incy;
        int prevx;
        int prevy;
        xerr = 0;
        yerr = 0;
        prevx = x = x1;
        prevy = y = y1;
        incx = (dx = x2 - x1) == 0 ? 0 : (dx < 0 ? -1 : 1);
        incy = (dy = y2 - y1) == 0 ? 0 : (dy < 0 ? -1 : 1);
        d = (dx = dx < 0 ? -dx : dx) >= (dy = dy < 0 ? -dy : dy) ? dx : dy;
        if(inclusive)
        {
            dx++;
            dy++;
            d++;
        }
        for(int i = 0; i <= d; i++)
        {
            xerr += dx;
            yerr += dy;
            if(xerr > d)
            {
                xerr -= d;
                x += incx;
            }
            if(yerr > d)
            {
                yerr -= d;
                y += incy;
            }
            if(dx >= dy)
            {
                if(y != prevy || i == d)
                {
                    if(prevx <= x)
                    {
                        render.drawHorizontalLine(prevx, prevy, x - prevx);
                    } else
                    {
                        render.drawHorizontalLine(x + 1, prevy, prevx - x);
                    }
                    prevx = x;
                    prevy = y;
                }
            } else
            {
                if(x != prevx || i == d)
                {
                    if(prevy <= y)
                    {
                        render.drawVerticalLine(prevx, prevy, y - prevy);
                    } else
                    {
                        render.drawVerticalLine(prevx, y + 1, prevy - y);
                    }
                    prevx = x;
                    prevy = y;
                }
            }
        }
    }

    private static void init(short[] x, short[] y) {
        short[] sin = new short[] {
            0x0000, 0x011e, 0x023c, 0x0359, 0x0477, 0x0594, 0x06b1, 0x07cd, 0x08e8, 0x0a03, 0x0b1d, 0x0c36, 0x0d4e, 0x0e66, 0x0f7c, 0x1090, 0x11a4, 0x12b6, 0x13c7, 0x14d6,
            0x15e4, 0x16f0, 0x17f9, 0x1902, 0x1a08, 0x1b0c, 0x1c0e, 0x1d0e, 0x1e0c, 0x1f07, 0x2000, 0x20f6, 0x21ea, 0x22db, 0x23ca, 0x24b5, 0x259e, 0x2684, 0x2767, 0x2847,
            0x2923, 0x29fd, 0x2ad3, 0x2ba6, 0x2c75, 0x2d41, 0x2e0a, 0x2ece, 0x2f90, 0x304d, 0x3107, 0x31bd, 0x326f, 0x331d, 0x33c7, 0x346d, 0x350f, 0x35ad, 0x3646, 0x36dc,
            0x376d, 0x37fa, 0x3882, 0x3906, 0x3986, 0x3a01, 0x3a78, 0x3aea, 0x3b57, 0x3bc0, 0x3c24, 0x3c83, 0x3cde, 0x3d34, 0x3d85, 0x3dd2, 0x3e19, 0x3e5c, 0x3e9a, 0x3ed3,
            0x3f07, 0x3f36, 0x3f61, 0x3f86, 0x3fa6, 0x3fc2, 0x3fd8, 0x3fea, 0x3ff6, 0x3ffe, 0x4000
        };
        for(int a = 90; a-- > 0; )
        {
            x[a] = (short) sin[90 - a];
            x[a + 90] = (short) -sin[a];
            x[a + 180] = (short) -sin[90 - a];
            x[a + 270] = (short) sin[a];
            y[a] = (short) -sin[a];
            y[a + 90] = (short) -sin[90 - a];
            y[a + 180] = (short) sin[a];
            y[a + 270] = (short) sin[90 - a];
        }
    }

    private static int directGraphicsToRasterCanvasTransform(int transform) {
        switch(transform)
        {
        case 0:
        case FLIP_HORIZONTAL | FLIP_VERTICAL | ROTATE_180:
            return RasterCanvas.TRANSFORM_NONE;
        case ROTATE_270:
        case FLIP_HORIZONTAL | FLIP_VERTICAL | ROTATE_90:
            return RasterCanvas.TRANSFORM_ROTATE_90;
        case ROTATE_180:
        case FLIP_HORIZONTAL | FLIP_VERTICAL | 0:
            return RasterCanvas.TRANSFORM_ROTATE_180;
        case ROTATE_90:
        case FLIP_HORIZONTAL | FLIP_VERTICAL | ROTATE_270:
            return RasterCanvas.TRANSFORM_ROTATE_270;
        case FLIP_HORIZONTAL | 0:
        case FLIP_VERTICAL | ROTATE_180:
            return RasterCanvas.TRANSFORM_MIRROR;
        case FLIP_HORIZONTAL | ROTATE_90:
        case FLIP_VERTICAL | ROTATE_270:
            return RasterCanvas.TRANSFORM_MIRROR_ROTATE_90;
        case FLIP_HORIZONTAL | ROTATE_180:
        case FLIP_VERTICAL | 0:
            return RasterCanvas.TRANSFORM_MIRROR_ROTATE_180;
        case FLIP_HORIZONTAL | ROTATE_270:
        case FLIP_VERTICAL | ROTATE_90:
            return RasterCanvas.TRANSFORM_MIRROR_ROTATE_270;
        default:
            return -1;
        }
    }

    private static int spriteToRasterCanvasTransform(int transform) {
        switch(transform)
        {
        case Sprite.TRANS_NONE:
            return RasterCanvas.TRANSFORM_NONE;
        case Sprite.TRANS_ROT90:
            return RasterCanvas.TRANSFORM_ROTATE_90;
        case Sprite.TRANS_ROT180:
            return RasterCanvas.TRANSFORM_ROTATE_180;
        case Sprite.TRANS_ROT270:
            return RasterCanvas.TRANSFORM_ROTATE_270;
        case Sprite.TRANS_MIRROR:
            return RasterCanvas.TRANSFORM_MIRROR;
        case Sprite.TRANS_MIRROR_ROT90:
            return RasterCanvas.TRANSFORM_MIRROR_ROTATE_90;
        case Sprite.TRANS_MIRROR_ROT180:
            return RasterCanvas.TRANSFORM_MIRROR_ROTATE_180;
        case Sprite.TRANS_MIRROR_ROT270:
            return RasterCanvas.TRANSFORM_MIRROR_ROTATE_270;
        default:
            return -1;
        }
    }

    final int width;
    final int height;
    private int stroke;
    private Font font;
    private final TextPaint paint;
    private final RasterBuffer buffer;
    private final RasterCanvas canvas;

    Graphics(RasterBuffer buffer) {
        int width;
        int height;
        Font font;
        this.width = width = buffer.getWidth();
        this.height = height = buffer.getHeight();
        this.font = font = Font.getDefaultFont();
        this.paint = new TextPaint(width, height, 0xff000000, true, font.getSystemFont(), font.isUnderlined(), false);
        this.buffer = buffer;
        this.canvas = new RasterCanvas(buffer);
    }

    public void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, int colorARGB) {
        Paint p;
        if((p = paint).getColor() != colorARGB)
        {
            int tx;
            int ty;
            p = new Paint(tx = p.getTranslateX(), ty = p.getTranslateY(), p.getLeft() - tx, p.getTop() - ty, p.getWidth(), p.getHeight(), colorARGB, true);
        }
        canvas.drawCustom(new OutlinedTriangle(x1, y1, x2, y2, x3, y3), 0, 0, p);
    }

    public void drawPolygon(int[] xCoords, int xOffset, int[] yCoords, int yOffset, int length, int colorARGB) {
        Paint p;
        if(xCoords == null)
        {
            throw new NullPointerException("DirectGraphics.drawPolygon: аргумент xCoords равен нулевой ссылке.");
        }
        if(yCoords == null)
        {
            throw new NullPointerException("DirectGraphics.drawPolygon: аргумент yCoords равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.drawPolygon", xCoords.length, xOffset, length);
        Array.checkBound("DirectGraphics.drawPolygon", yCoords.length, yOffset, length);
        if(length > 0)
        {
            if((p = paint).getColor() != colorARGB)
            {
                int tx;
                int ty;
                p = new Paint(tx = p.getTranslateX(), ty = p.getTranslateY(), p.getLeft() - tx, p.getTop() - ty, p.getWidth(), p.getHeight(), colorARGB, true);
            }
            canvas.drawCustom(new ClosedPolygon(xCoords, xOffset, yCoords, yOffset, length), 0, 0, p);
        }
    }

    public void drawPixels(byte[] pixels, byte[] mask, int offset, int scanlength, int left, int top, int width, int height, int transform, int format) {
        int pixelsOffset;
        int pixelsLength;
        int[] pixelsNative;
        RasterBuffer buffer;
        switch(format)
        {
        case TYPE_BYTE_8_GRAY:
        case TYPE_BYTE_332_RGB:
            if(scanlength >= 0)
            {
                pixelsOffset = offset;
                pixelsLength = width + (height - 1) * scanlength;
            } else
            {
                pixelsOffset = offset + (height - 1) * scanlength;
                pixelsLength = width + offset - pixelsOffset;
            }
            break;
        case TYPE_BYTE_1_GRAY_VERTICAL:
        case TYPE_BYTE_1_GRAY:
        case TYPE_BYTE_2_GRAY:
        case TYPE_BYTE_4_GRAY:
            throw new IllegalArgumentException("DirectGraphics.drawPixels: форматы, у которых меньше 8 бит на пиксел, не поддерживаются.");
        default:
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент format имеет недопустимое значение.");
        }
        if((transform = directGraphicsToRasterCanvasTransform(transform)) < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент width не может быть отрицательным.");
        }
        if(height < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент height не может быть отрицательным.");
        }
        if(width == 0 || height == 0) return;
        if(pixels == null)
        {
            throw new NullPointerException("DirectGraphics.drawPixels: аргумент pixels равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.drawPixels", pixels.length, pixelsOffset, pixelsLength);
        if(mask != null) Array.checkBound("DirectGraphics.drawPixels", mask.length, pixelsOffset, pixelsLength);
        buffer = RasterBuffer.create(pixelsNative = new int[width * height], 0, width, width, height, false);
        switch(format)
        {
        case TYPE_BYTE_8_GRAY:
            /* pixel  :                               yyyy|yyyy */
            /* mask   :                               aaaa|aaaa */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            for(int i = 0, j = offset, dj = scanlength - width, cy = height; cy-- > 0; j += dj) for(int cx = width; cx-- > 0; i++, j++)
            {
                int y = pixels[j] & 0xff;
                int a = mask != null ? mask[j] & 0xff : 0xff;
                pixelsNative[i] = a << 24 | y << 16 | y << 8 | y;
            }
            break;
        case TYPE_BYTE_332_RGB:
            /* pixel  :                               rrrg|ggbb */
            /* mask   :                               aaaa|aaaa */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            for(int i = 0, j = offset, dj = scanlength - width, cy = height; cy-- > 0; j += dj) for(int cx = width; cx-- > 0; i++, j++)
            {
                int p = pixels[j];
                int a = mask != null ? mask[j] & 0xff : 0xff;
                int r = 0xe0 & p;
                int g = 0x1c & p;
                int b = 0x03 & p;
                pixelsNative[i] = a << 24 | r << 16 | r << 13 | (r & 0xc0) << 10 | g << 11 | g << 8 | (g & 0x18) << 5 | b << 6 | b << 4 | b << 2 | b;
            }
            break;
        }
        if((transform & 1) != 0)
        {
            canvas.drawPixels(buffer, transform, left, top, height, width, paint);
            return;
        }
        canvas.drawPixels(buffer, transform, left, top, width, height, paint);
    }

    public void drawPixels(short[] pixels, boolean transparency, int offset, int scanlength, int left, int top, int width, int height, int transform, int format) {
        int pixelsOffset;
        int pixelsLength;
        int[] pixelsNative;
        RasterBuffer buffer;
        switch(format)
        {
        case TYPE_USHORT_444_RGB:
        case TYPE_USHORT_555_RGB:
        case TYPE_USHORT_565_RGB:
        case TYPE_USHORT_1555_ARGB:
        case TYPE_USHORT_4444_ARGB:
            if(scanlength >= 0)
            {
                pixelsOffset = offset;
                pixelsLength = width + (height - 1) * scanlength;
            } else
            {
                pixelsOffset = offset + (height - 1) * scanlength;
                pixelsLength = width + offset - pixelsOffset;
            }
            break;
        default:
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент format имеет недопустимое значение.");
        }
        if((transform = directGraphicsToRasterCanvasTransform(transform)) < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент width не может быть отрицательным.");
        }
        if(height < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент height не может быть отрицательным.");
        }
        if(width == 0 || height == 0) return;
        if(pixels == null)
        {
            throw new NullPointerException("DirectGraphics.drawPixels: аргумент pixels равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.drawPixels", pixels.length, pixelsOffset, pixelsLength);
        buffer = RasterBuffer.create(pixelsNative = new int[width * height], 0, width, width, height, false);
        switch(format)
        {
        case TYPE_USHORT_444_RGB:
            /* pixel  :                     ****|rrrr|gggg|bbbb */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            for(int i = 0, j = offset, dj = scanlength - width, cy = height; cy-- > 0; j += dj) for(int cx = width; cx-- > 0; i++, j++)
            {
                int p = pixels[j];
                int r = 0x0f00 & p;
                int g = 0x00f0 & p;
                int b = 0x000f & p;
                pixelsNative[i] = 0xff000000 | r << 12 | r << 8 | g << 8 | g << 4 | b << 4 | b;
            }
            break;
        case TYPE_USHORT_555_RGB:
            /* pixel  :                     *rrr|rrgg|gggb|bbbb */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            for(int i = 0, j = offset, dj = scanlength - width, cy = height; cy-- > 0; j += dj) for(int cx = width; cx-- > 0; i++, j++)
            {
                int p = pixels[j];
                int r = 0x7c00 & p;
                int g = 0x03e0 & p;
                int b = 0x001f & p;
                pixelsNative[i] = 0xff000000 | r << 9 | (r & 0x7000) << 4 | g << 6 | (g & 0x0380) << 1 | b << 3 | (b & 0x001c) >> 2;
            }
            break;
        case TYPE_USHORT_565_RGB:
            /* pixel  :                     rrrr|rggg|gggb|bbbb */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            for(int i = 0, j = offset, dj = scanlength - width, cy = height; cy-- > 0; j += dj) for(int cx = width; cx-- > 0; i++, j++)
            {
                int p = pixels[j];
                int r = 0xf800 & p;
                int g = 0x07e0 & p;
                int b = 0x001f & p;
                pixelsNative[i] = 0xff000000 | r << 8 | (r & 0xe000) << 3 | g << 5 | (g & 0x0600) >> 1 | b << 3 | (b & 0x001c) >> 2;
            }
            break;
        case TYPE_USHORT_1555_ARGB:
            /* pixel  :                     arrr|rrgg|gggb|bbbb */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            for(int i = 0, j = offset, dj = scanlength - width, cy = height; cy-- > 0; j += dj) for(int cx = width; cx-- > 0; i++, j++)
            {
                int p = pixels[j];
                int a = 0x8000 & p;
                int r = 0x7c00 & p;
                int g = 0x03e0 & p;
                int b = 0x001f & p;
                pixelsNative[i] = a << 16 >> 7 | r << 9 | (r & 0x7000) << 4 | g << 6 | (g & 0x0380) << 1 | b << 3 | (b & 0x001c) >> 2;
            }
            break;
        case TYPE_USHORT_4444_ARGB:
            /* pixel  :                     aaaa|rrrr|gggg|bbbb */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            for(int i = 0, j = offset, dj = scanlength - width, cy = height; cy-- > 0; j += dj) for(int cx = width; cx-- > 0; i++, j++)
            {
                int p = pixels[j];
                int a = 0xf000 & p;
                int r = 0x0f00 & p;
                int g = 0x00f0 & p;
                int b = 0x000f & p;
                pixelsNative[i] = a << 16 | a << 12 | r << 12 | r << 8 | g << 8 | g << 4 | b << 4 | b;
            }
            break;
        }
        if((transform & 1) != 0)
        {
            if(transparency)
            {
                canvas.drawPixels(buffer, transform, left, top, height, width, paint);
                return;
            }
            canvas.copyPixels(buffer, transform, left, top, height, width, paint);
            return;
        }
        if(transparency)
        {
            canvas.drawPixels(buffer, transform, left, top, width, height, paint);
            return;
        }
        canvas.copyPixels(buffer, transform, left, top, width, height, paint);
    }

    public void drawPixels(int[] pixels, boolean transparency, int offset, int scanlength, int left, int top, int width, int height, int transform, int format) {
        int pixelsOffset;
        int pixelsLength;
        RasterBuffer buffer;
        switch(format)
        {
        case TYPE_INT_888_RGB:
        case TYPE_INT_8888_ARGB:
            if(scanlength >= 0)
            {
                pixelsOffset = offset;
                pixelsLength = width + (height - 1) * scanlength;
            } else
            {
                pixelsOffset = offset + (height - 1) * scanlength;
                pixelsLength = width + offset - pixelsOffset;
            }
            break;
        default:
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент format имеет недопустимое значение.");
        }
        if((transform = directGraphicsToRasterCanvasTransform(transform)) < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент transform имеет недопустимое значение.");
        }
        if(width < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент width не может быть отрицательным.");
        }
        if(height < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawPixels: аргумент height не может быть отрицательным.");
        }
        if(width == 0 || height == 0) return;
        if(pixels == null)
        {
            throw new NullPointerException("DirectGraphics.drawPixels: аргумент pixels равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.drawPixels", pixels.length, pixelsOffset, pixelsLength);
        buffer = RasterBuffer.create(pixels, offset, scanlength, width, height, format == TYPE_INT_888_RGB);
        if((transform & 1) != 0)
        {
            if(transparency)
            {
                canvas.drawPixels(buffer, transform, left, top, height, width, paint);
                return;
            }
            canvas.copyPixels(buffer, transform, left, top, height, width, paint);
            return;
        }
        if(transparency)
        {
            canvas.drawPixels(buffer, transform, left, top, width, height, paint);
            return;
        }
        canvas.copyPixels(buffer, transform, left, top, width, height, paint);
    }

    public void drawImage(Image image, int x, int y, int anchor, int transform) {
        int width;
        int height;
        if(image == null)
        {
            throw new NullPointerException("DirectGraphics.drawImage: аргумент image равен нулевой ссылке.");
        }
        if((transform = directGraphicsToRasterCanvasTransform(transform)) < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.drawImage: аргумент transform имеет недопустимое значение.");
        }
        if((transform & 1) != 0)
        {
            width = image.height;
            height = image.width;
        } else
        {
            width = image.width;
            height = image.height;
        }
        switch(anchor)
        {
        case 0:
        case TOP | LEFT:
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            break;
        case TOP | RIGHT:
            x -= width;
            break;
        case VCENTER | LEFT:
            y -= height >> 1;
            break;
        case VCENTER | HCENTER:
            x -= width >> 1;
            y -= height >> 1;
            break;
        case VCENTER | RIGHT:
            x -= width;
            y -= height >> 1;
            break;
        case BOTTOM | LEFT:
            y -= height;
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= height;
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= height;
            break;
        default:
            throw new IllegalArgumentException("DirectGraphics.drawImage: аргумент anchor имеет недопустимое значение.");
        }
        canvas.drawPixels(image.buffer, transform, x, y, width, height, paint);
    }

    public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, int colorARGB) {
        Paint p;
        if((p = paint).getColor() != colorARGB)
        {
            int tx;
            int ty;
            p = new Paint(tx = p.getTranslateX(), ty = p.getTranslateY(), p.getLeft() - tx, p.getTop() - ty, p.getWidth(), p.getHeight(), colorARGB, true);
        }
        canvas.drawCustom(new FilledTriangle(x1, y1, x2, y2, x3, y3), 0, 0, p);
    }

    public void fillPolygon(int[] xCoords, int xOffset, int[] yCoords, int yOffset, int length, int colorARGB) {
        Paint p;
        if(xCoords == null)
        {
            throw new NullPointerException("DirectGraphics.fillPolygon: аргумент xCoords равен нулевой ссылке.");
        }
        if(yCoords == null)
        {
            throw new NullPointerException("DirectGraphics.fillPolygon: аргумент yCoords равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.fillPolygon", xCoords.length, xOffset, length);
        Array.checkBound("DirectGraphics.fillPolygon", yCoords.length, yOffset, length);
        if(length > 0)
        {
            if((p = paint).getColor() != colorARGB)
            {
                int tx;
                int ty;
                p = new Paint(tx = p.getTranslateX(), ty = p.getTranslateY(), p.getLeft() - tx, p.getTop() - ty, p.getWidth(), p.getHeight(), colorARGB, true);
            }
            canvas.drawCustom(new FilledPolygon(xCoords, xOffset, yCoords, yOffset, length), 0, 0, p);
        }
    }

    public void setARGBColor(int colorARGB) {
        paint.setColor(colorARGB);
    }

    public void getPixels(byte[] pixels, byte[] mask, int offset, int scanlength, int left, int top, int width, int height, int format) {
        boolean srcOpaque;
        int pixelsOffset;
        int pixelsLength;
        int srcOffset;
        int srcScanln;
        int[] srcPixels;
        RasterBuffer srcBuffer;
        Clip clip;
        switch(format)
        {
        case TYPE_BYTE_8_GRAY:
        case TYPE_BYTE_332_RGB:
            if(scanlength >= 0)
            {
                pixelsOffset = offset;
                pixelsLength = width + (height - 1) * scanlength;
            } else
            {
                pixelsOffset = offset + (height - 1) * scanlength;
                pixelsLength = width + offset - pixelsOffset;
            }
            break;
        case TYPE_BYTE_1_GRAY_VERTICAL:
        case TYPE_BYTE_1_GRAY:
        case TYPE_BYTE_2_GRAY:
        case TYPE_BYTE_4_GRAY:
            throw new IllegalArgumentException("DirectGraphics.getPixels: форматы, у которых меньше 8 бит на пиксел, не поддерживаются.");
        default:
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент format имеет недопустимое значение.");
        }
        if(width < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент width не может быть отрицательным.");
        }
        if(height < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент height не может быть отрицательным.");
        }
        if(width == 0 || height == 0) return;
        if(pixels == null)
        {
            throw new NullPointerException("DirectGraphics.getPixels: аргумент pixels равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.getPixels", pixels.length, pixelsOffset, pixelsLength);
        if(mask != null) Array.checkBound("DirectGraphics.getPixels", mask.length, pixelsOffset, pixelsLength);
        check("DirectGraphics.getPixels", left += (clip = paint).getTranslateX(), top += clip.getTranslateY(), width, height);
        srcBuffer = buffer;
        srcOpaque = srcBuffer.isOpaque();
        srcPixels = srcBuffer.getPixels();
        srcOffset = srcBuffer.getOffset();
        srcScanln = srcBuffer.getScanlength();
        switch(format)
        {
        case TYPE_BYTE_8_GRAY:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  :                               yyyy|yyyy */
            /* mask   :                               aaaa|aaaa */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = (byte) ((76 * ((p >> 16) & 0xff) + 152 * ((p >> 8) & 0xff) + 28 * (p & 0xff)) >> 8);
                    if(mask != null) mask[i] = srcOpaque ? (byte) 0xff : (byte) (p >> 24);
                }
            }
            break;
        case TYPE_BYTE_332_RGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  :                               rrrg|ggbb */
            /* mask   :                               aaaa|aaaa */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = (byte) ((p >> 16) & 0xe0 | (p >> 11) & 0x1c | (p >> 6) & 0x03);
                    if(mask != null) mask[i] = srcOpaque ? (byte) 0xff : (byte) (p >> 24);
                }
            }
            break;
        }
    }

    public void getPixels(short[] pixels, int offset, int scanlength, int left, int top, int width, int height, int format) {
        boolean srcOpaque;
        int pixelsOffset;
        int pixelsLength;
        int srcOffset;
        int srcScanln;
        int[] srcPixels;
        RasterBuffer srcBuffer;
        Clip clip;
        switch(format)
        {
        case TYPE_USHORT_444_RGB:
        case TYPE_USHORT_555_RGB:
        case TYPE_USHORT_565_RGB:
        case TYPE_USHORT_1555_ARGB:
        case TYPE_USHORT_4444_ARGB:
            if(scanlength >= 0)
            {
                pixelsOffset = offset;
                pixelsLength = width + (height - 1) * scanlength;
            } else
            {
                pixelsOffset = offset + (height - 1) * scanlength;
                pixelsLength = width + offset - pixelsOffset;
            }
            break;
        default:
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент format имеет недопустимое значение.");
        }
        if(width < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент width не может быть отрицательным.");
        }
        if(height < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент height не может быть отрицательным.");
        }
        if(width == 0 || height == 0) return;
        if(pixels == null)
        {
            throw new NullPointerException("DirectGraphics.getPixels: аргумент pixels равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.getPixels", pixels.length, pixelsOffset, pixelsLength);
        check("DirectGraphics.getPixels", left += (clip = paint).getTranslateX(), top += clip.getTranslateY(), width, height);
        srcBuffer = buffer;
        srcOpaque = srcBuffer.isOpaque();
        srcPixels = srcBuffer.getPixels();
        srcOffset = srcBuffer.getOffset();
        srcScanln = srcBuffer.getScanlength();
        switch(format)
        {
        case TYPE_USHORT_444_RGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  :                     0000|rrrr|gggg|bbbb */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = (short) ((p >> 12) & 0x0f00 | (p >> 8) & 0x00f0 | (p >> 4) & 0x000f);
                }
            }
            break;
        case TYPE_USHORT_555_RGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  :                     0rrr|rrgg|gggb|bbbb */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = (short) ((p >> 9) & 0x7c00 | (p >> 6) & 0x03e0 | (p >> 3) & 0x001f);
                }
            }
            break;
        case TYPE_USHORT_565_RGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  :                     rrrr|rggg|gggb|bbbb */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = (short) ((p >> 8) & 0xf800 | (p >> 5) & 0x07e0 | (p >> 3) & 0x001f);
                }
            }
            break;
        case TYPE_USHORT_1555_ARGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  :                     arrr|rrgg|gggb|bbbb */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = (short) ((srcOpaque ? 0x8000 : (p >> 16) & 0x8000) | (p >> 9) & 0x7c00 | (p >> 6) & 0x03e0 | (p >> 3) & 0x001f);
                }
            }
            break;
        case TYPE_USHORT_4444_ARGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  :                     aaaa|rrrr|gggg|bbbb */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = (short) ((srcOpaque ? 0xf000 : (p >> 16) & 0xf000) | (p >> 12) & 0x0f00 | (p >> 8) & 0x00f0 | (p >> 4) & 0x000f);
                }
            }
            break;
        }
    }

    public void getPixels(int[] pixels, int offset, int scanlength, int left, int top, int width, int height, int format) {
        boolean srcOpaque;
        int pixelsOffset;
        int pixelsLength;
        int srcOffset;
        int srcScanln;
        int[] srcPixels;
        RasterBuffer srcBuffer;
        Clip clip;
        switch(format)
        {
        case TYPE_INT_888_RGB:
        case TYPE_INT_8888_ARGB:
            if(scanlength >= 0)
            {
                pixelsOffset = offset;
                pixelsLength = width + (height - 1) * scanlength;
            } else
            {
                pixelsOffset = offset + (height - 1) * scanlength;
                pixelsLength = width + offset - pixelsOffset;
            }
            break;
        default:
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент format имеет недопустимое значение.");
        }
        if(width < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент width не может быть отрицательным.");
        }
        if(height < 0)
        {
            throw new IllegalArgumentException("DirectGraphics.getPixels: аргумент height не может быть отрицательным.");
        }
        if(width == 0 || height == 0) return;
        if(pixels == null)
        {
            throw new NullPointerException("DirectGraphics.getPixels: аргумент pixels равен нулевой ссылке.");
        }
        Array.checkBound("DirectGraphics.getPixels", pixels.length, pixelsOffset, pixelsLength);
        check("DirectGraphics.getPixels", left += (clip = paint).getTranslateX(), top += clip.getTranslateY(), width, height);
        srcBuffer = buffer;
        srcOpaque = srcBuffer.isOpaque();
        srcPixels = srcBuffer.getPixels();
        srcOffset = srcBuffer.getOffset();
        srcScanln = srcBuffer.getScanlength();
        switch(format)
        {
        case TYPE_INT_888_RGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  : 0000|0000|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = p & 0x00ffffff;
                }
            }
            break;
        case TYPE_INT_8888_ARGB:
            /* bits   :   28|  24|  20|  16|  12|   8|   4|   0 */
            /* native : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            /* pixel  : aaaa|aaaa|rrrr|rrrr|gggg|gggg|bbbb|bbbb */
            for(int i = offset, di = scanlength - width, j = srcOffset + left + top * srcScanln, dj = srcScanln - width, cy = height; cy-- > 0; i += di, j += dj)
            {
                for(int cx = width; cx-- > 0; i++, j++)
                {
                    int p = srcPixels[j];
                    pixels[i] = srcOpaque ? p | 0xff000000 : p;
                }
            }
            break;
        }
    }

    public int getAlphaComponent() {
        return paint.getAlphaComponent();
    }

    public int getNativePixelFormat() {
        return buffer.isOpaque() ? TYPE_INT_888_RGB : TYPE_INT_8888_ARGB;
    }

    public void copyArea(int left, int top, int width, int height, int x, int y, int anchor) {
        Clip clip;
        check("Graphics.copyArea", left += (clip = paint).getTranslateX(), top += clip.getTranslateY(), width, height);
        switch(anchor)
        {
        case 0:
        case TOP | LEFT:
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            break;
        case TOP | RIGHT:
            x -= width;
            break;
        case VCENTER | LEFT:
            y -= height >> 1;
            break;
        case VCENTER | HCENTER:
            x -= width >> 1;
            y -= height >> 1;
            break;
        case VCENTER | RIGHT:
            x -= width;
            y -= height >> 1;
            break;
        case BOTTOM | LEFT:
            y -= height;
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= height;
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= height;
            break;
        default:
            throw new IllegalArgumentException("Graphics.copyArea: аргумент anchor имеет недопустимое значение.");
        }
        canvas.copyPixels(RasterBuffer.create(buffer, left, top, width, height), RasterCanvas.TRANSFORM_NONE, x, y, width, height, clip);
    }

    public void drawElement(int type, int subtype, int state, int left, int top, int width, int height) {
        canvas.drawGUIElement(type, subtype, state, left, top, width, height, paint);
    }

    public void drawLine(int x1, int y1, int x2, int y2) {
        if(x1 == x2 && y1 == y2)
        {
            canvas.drawPixel(x1, y1, paint);
            return;
        }
        canvas.drawCustom(new Line(x1, y1, x2, y2), 0, 0, paint);
    }

    public void drawArc(int left, int top, int width, int height, int startAngle, int arcAngle) {
        int angle;
        int stepAngle;
        int length;
        int yStart;
        long xnSize;
        long ynSize;
        long xmSize;
        long ymSize;
        int[] coords;
        if(width < 0 || height < 0) return;
        if(startAngle < 0) startAngle += 360 * (startAngle / (-360) + 1);
        startAngle %= 360;
        if(arcAngle > 360) arcAngle = 360;
        if(arcAngle < -360) arcAngle = -360;
        if(arcAngle < 0)
        {
            startAngle = (startAngle + arcAngle + 360) % 360;
            arcAngle = -arcAngle;
        }
        angle = startAngle;
        stepAngle = (stepAngle = width < height ? height + 1 : width + 1) >= 180 || stepAngle == Integer.MIN_VALUE ? 1 : 180 / stepAngle;
        length = arcAngle / stepAngle + 1;
        xnSize = (long) width;
        ynSize = (long) height;
        xmSize = xnSize << 14;
        ymSize = ynSize << 14;
        coords = new int[(yStart = length + 1) << 1];
        for(int x = 0, y = yStart; x < length; angle += stepAngle, x++, y++)
        {
            coords[x] = (int) (xmSize + xnSize * (long) XTABLE[angle % 360] + 0x4000L >> 15);
            coords[y] = (int) (ymSize + ynSize * (long) YTABLE[angle % 360] + 0x4000L >> 15);
        }
        if((angle - stepAngle) < (angle = startAngle + arcAngle))
        {
            coords[length] = (int) (xmSize + xnSize * (long) XTABLE[angle % 360] + 0x4000L >> 15);
            coords[length++ + yStart] = (int) (ymSize + ynSize * (long) YTABLE[angle % 360] + 0x4000L >> 15);
        }
        canvas.drawCustom(new OpenedPolygon(coords, 0, coords, yStart, length), left, top, paint);
    }

    public void drawRect(int left, int top, int width, int height) {
        if(width >= 0 && height >= 0) canvas.drawCustom(new OutlinedRectangle(width, height), left, top, paint);
    }

    public void drawRoundRect(int left, int top, int width, int height, int arcWidth, int arcHeight) {
        if(width >= 0 && height >= 0) canvas.drawCustom(new OutlinedRoundRect(width, height, arcWidth, arcHeight), left, top, paint);
    }

    public void drawRGB(int[] pixels, int offset, int scanlength, int left, int top, int width, int height, boolean alpha) {
        int pixelsOffset;
        int pixelsLength;
        RasterBuffer buffer;
        if(scanlength >= 0)
        {
            pixelsOffset = offset;
            pixelsLength = width + (height - 1) * scanlength;
        } else
        {
            pixelsOffset = offset + (height - 1) * scanlength;
            pixelsLength = width + offset - pixelsOffset;
        }
        if(width <= 0 || height <= 0) return;
        if(pixels == null)
        {
            throw new NullPointerException("Graphics.drawRGB: аргумент pixels равен нулевой ссылке.");
        }
        Array.checkBound("Graphics.drawRGB", pixels.length, pixelsOffset, pixelsLength);
        buffer = RasterBuffer.create(pixels, offset, scanlength, width, height, !alpha);
        canvas.drawPixels(buffer, RasterCanvas.TRANSFORM_NONE, left, top, width, height, paint);
    }

    public void drawImage(Image image, int x, int y, int anchor) {
        int width;
        int height;
        if(image == null)
        {
            throw new NullPointerException("Graphics.drawImage: аргумент image равен нулевой ссылке.");
        }
        width = image.width;
        height = image.height;
        switch(anchor)
        {
        case 0:
        case TOP | LEFT:
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            break;
        case TOP | RIGHT:
            x -= width;
            break;
        case VCENTER | LEFT:
            y -= height >> 1;
            break;
        case VCENTER | HCENTER:
            x -= width >> 1;
            y -= height >> 1;
            break;
        case VCENTER | RIGHT:
            x -= width;
            y -= height >> 1;
            break;
        case BOTTOM | LEFT:
            y -= height;
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= height;
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= height;
            break;
        default:
            throw new IllegalArgumentException("Graphics.drawImage: аргумент anchor имеет недопустимое значение.");
        }
        canvas.drawPixels(image.buffer, RasterCanvas.TRANSFORM_NONE, x, y, width, height, paint);
    }

    public void drawStretch(Image image, int x, int y, int width, int height, int anchor) {
        if(image == null)
        {
            throw new NullPointerException("Graphics.drawStretch: аргумент image равен нулевой ссылке.");
        }
        if(width <= 0 || height <= 0) return;
        switch(anchor)
        {
        case 0:
        case TOP | LEFT:
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            break;
        case TOP | RIGHT:
            x -= width;
            break;
        case VCENTER | LEFT:
            y -= height >> 1;
            break;
        case VCENTER | HCENTER:
            x -= width >> 1;
            y -= height >> 1;
            break;
        case VCENTER | RIGHT:
            x -= width;
            y -= height >> 1;
            break;
        case BOTTOM | LEFT:
            y -= height;
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= height;
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= height;
            break;
        default:
            throw new IllegalArgumentException("Graphics.drawStretch: аргумент anchor имеет недопустимое значение.");
        }
        canvas.drawPixels(image.buffer, RasterCanvas.TRANSFORM_NONE, x, y, width, height, paint);
    }

    public void drawRegion(Image image, int left, int top, int width, int height, int transform, int x, int y, int anchor) {
        int w;
        int h;
        int lim;
        int len;
        if(image == null)
        {
            throw new NullPointerException("Graphics.drawRegion: аргумент image равен нулевой ссылке.");
        }
        if((lim = left + width) > (len = image.width) || lim < left || left > len || left < 0 || (lim = top + height) > (len = image.height) || lim < top || top > len || top < 0)
        {
            throw new IllegalArgumentException("Graphics.drawRegion: заданный регион выходит за пределы изображения.");
        }
        if((transform = spriteToRasterCanvasTransform(transform)) < 0)
        {
            throw new IllegalArgumentException("Graphics.drawRegion: аргумент transform имеет недопустимое значение.");
        }
        if((transform & 1) != 0)
        {
            w = height;
            h = width;
        } else
        {
            w = width;
            h = height;
        }
        switch(anchor)
        {
        case 0:
        case TOP | LEFT:
            break;
        case TOP | HCENTER:
            x -= w >> 1;
            break;
        case TOP | RIGHT:
            x -= w;
            break;
        case VCENTER | LEFT:
            y -= h >> 1;
            break;
        case VCENTER | HCENTER:
            x -= w >> 1;
            y -= h >> 1;
            break;
        case VCENTER | RIGHT:
            x -= w;
            y -= h >> 1;
            break;
        case BOTTOM | LEFT:
            y -= h;
            break;
        case BOTTOM | HCENTER:
            x -= w >> 1;
            y -= h;
            break;
        case BOTTOM | RIGHT:
            x -= w;
            y -= h;
            break;
        default:
            throw new IllegalArgumentException("Graphics.drawRegion: аргумент anchor имеет недопустимое значение.");
        }
        if(w > 0 && h > 0) canvas.drawPixels(image.buffer, left, top, width, height, transform, x, y, w, h, paint);
    }

    public void drawChar(char character, int x, int y, int anchor) {
        int width;
        TextPaint p;
        SystemFont font;
        width = (font = (p = paint).getFont()).characterWidth(character);
        switch(anchor)
        {
        case BASELINE | LEFT:
            break;
        case BASELINE | HCENTER:
            x -= width >> 1;
            break;
        case BASELINE | RIGHT:
            x -= width;
            break;
        case 0:
        case TOP | LEFT:
            y += font.getBaselinePosition();
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            y += font.getBaselinePosition();
            break;
        case TOP | RIGHT:
            x -= width;
            y += font.getBaselinePosition();
            break;
        case BOTTOM | LEFT:
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= font.getBaselineHeight();
            break;
        default:
            throw new IllegalArgumentException("Graphics.drawChar: аргумент anchor имеет недопустимое значение.");
        }
        canvas.drawCharacter(character, x, y, p);
    }

    public void drawChars(char[] src, int offset, int length, int x, int y, int anchor) {
        int width;
        TextPaint p;
        SystemFont font;
        width = (font = (p = paint).getFont()).charactersWidth(src, offset, length);
        switch(anchor)
        {
        case BASELINE | LEFT:
            break;
        case BASELINE | HCENTER:
            x -= width >> 1;
            break;
        case BASELINE | RIGHT:
            x -= width;
            break;
        case 0:
        case TOP | LEFT:
            y += font.getBaselinePosition();
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            y += font.getBaselinePosition();
            break;
        case TOP | RIGHT:
            x -= width;
            y += font.getBaselinePosition();
            break;
        case BOTTOM | LEFT:
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= font.getBaselineHeight();
            break;
        default:
            throw new IllegalArgumentException("Graphics.drawChars: аргумент anchor имеет недопустимое значение.");
        }
        canvas.drawCharacters(src, offset, length, x, y, p);
    }

    public void drawString(String string, int x, int y, int anchor) {
        int width;
        TextPaint p;
        SystemFont font;
        width = (font = (p = paint).getFont()).stringWidth(string);
        switch(anchor)
        {
        case BASELINE | LEFT:
            break;
        case BASELINE | HCENTER:
            x -= width >> 1;
            break;
        case BASELINE | RIGHT:
            x -= width;
            break;
        case 0:
        case TOP | LEFT:
            y += font.getBaselinePosition();
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            y += font.getBaselinePosition();
            break;
        case TOP | RIGHT:
            x -= width;
            y += font.getBaselinePosition();
            break;
        case BOTTOM | LEFT:
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= font.getBaselineHeight();
            break;
        default:
            throw new IllegalArgumentException("Graphics.drawString: аргумент anchor имеет недопустимое значение.");
        }
        canvas.drawString(string, x, y, p);
    }

    public void drawSubstring(String string, int offset, int length, int x, int y, int anchor) {
        int width;
        TextPaint p;
        SystemFont font;
        width = (font = (p = paint).getFont()).substringWidth(string, offset, length);
        switch(anchor)
        {
        case BASELINE | LEFT:
            break;
        case BASELINE | HCENTER:
            x -= width >> 1;
            break;
        case BASELINE | RIGHT:
            x -= width;
            break;
        case 0:
        case TOP | LEFT:
            y += font.getBaselinePosition();
            break;
        case TOP | HCENTER:
            x -= width >> 1;
            y += font.getBaselinePosition();
            break;
        case TOP | RIGHT:
            x -= width;
            y += font.getBaselinePosition();
            break;
        case BOTTOM | LEFT:
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | HCENTER:
            x -= width >> 1;
            y -= font.getBaselineHeight();
            break;
        case BOTTOM | RIGHT:
            x -= width;
            y -= font.getBaselineHeight();
            break;
        default:
            throw new IllegalArgumentException("Graphics.drawSubstring: аргумент anchor имеет недопустимое значение.");
        }
        canvas.drawSubstring(string, offset, length, x, y, p);
    }

    public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
        canvas.drawCustom(new FilledTriangle(x1, y1, x2, y2, x3, y3), 0, 0, paint);
    }

    public void fillArc(int left, int top, int width, int height, int startAngle, int arcAngle) {
        int stepAngle;
        int length;
        int yStart;
        long xnSize;
        long ynSize;
        long xmSize;
        long ymSize;
        int[] coords;
        if(width <= 0 || height <= 0) return;
        if(startAngle < 0) startAngle += 360 * (startAngle / (-360) + 1);
        startAngle %= 360;
        if(arcAngle > 360) arcAngle = 360;
        if(arcAngle < -360) arcAngle = -360;
        if(arcAngle < 0)
        {
            startAngle = (startAngle + arcAngle + 360) % 360;
            arcAngle = -arcAngle;
        }
        stepAngle = (stepAngle = width < height ? height : width) >= 180 ? 1 : 180 / stepAngle;
        length = arcAngle / stepAngle + 2;
        xnSize = (long) width;
        ynSize = (long) height;
        xmSize = xnSize << 14;
        ymSize = ynSize << 14;
        coords = new int[length << 1];
        for(int a = startAngle, x = 0, y = yStart = length--; x < length; a = (a + stepAngle) % 360, x++, y++)
        {
            coords[x] = (int) (xmSize + xnSize * (long) XTABLE[a] + 0x4000L >> 15);
            coords[y] = (int) (ymSize + ynSize * (long) YTABLE[a] + 0x4000L >> 15);
        }
        if(arcAngle < 360)
        {
            coords[length] = (int) (xmSize + 0x4000L >> 15);
            coords[length++ + yStart] = (int) (ymSize + 0x4000L >> 15);
        }
        canvas.drawCustom(new FilledPolygon(coords, 0, coords, yStart, length), left, top, paint);
    }

    public void fillRect(int left, int top, int width, int height) {
        if(width > 0 && height > 0) canvas.fillRectangle(left, top, width, height, paint);
    }

    public void fillRoundRect(int left, int top, int width, int height, int arcWidth, int arcHeight) {
        if(width > 0 && height > 0) canvas.drawCustom(new FilledRoundRect(width, height, arcWidth, arcHeight), left, top, paint);
    }

    public void translate(int deltaX, int deltaY) {
        Clip c;
        synchronized(c = paint)
        {
            c.translate(deltaX, deltaY);
        }
    }

    public void clipRect(int left, int top, int width, int height) {
        Clip c;
        synchronized(c = paint)
        {
            c.clipRect(left, top, width, height);
        }
    }

    public void setClip(int left, int top, int width, int height) {
        Clip c;
        synchronized(c = paint)
        {
            c.setClip(left, top, width, height);
            bound(c);
        }
    }

    public void setColor(int colorRGB) {
        paint.setColor(colorRGB | 0xff000000);
    }

    public void setColor(int red, int green, int blue) {
        if((red & 0xffffff00) != 0)
        {
            throw new IllegalArgumentException("Graphics.setColor: аргумент red имеет недопустимое значение.");
        }
        if((green & 0xffffff00) != 0)
        {
            throw new IllegalArgumentException("Graphics.setColor: аргумент green имеет недопустимое значение.");
        }
        if((blue & 0xffffff00) != 0)
        {
            throw new IllegalArgumentException("Graphics.setColor: аргумент blue имеет недопустимое значение.");
        }
        paint.setColor(red << 0x10 | green << 0x08 | blue | 0xff000000);
    }

    public void setGrayScale(int gray) {
        if((gray & 0xffffff00) != 0)
        {
            throw new IllegalArgumentException("Graphics.setGrayScale: аргумент gray имеет недопустимое значение.");
        }
        paint.setColor(gray << 0x10 | gray << 0x08 | gray | 0xff000000);
    }

    public void setStrokeStyle(int stroke) {
        if(stroke < 0 || stroke > 1)
        {
            throw new IllegalArgumentException("Graphics.setStrokeStyle: аргумент stroke имеет недопустимое значение.");
        }
        this.stroke = stroke;
    }

    public void setFont(Font font) {
        if(font == null) font = Font.getDefaultFont();
        this.font = font;
        paint.setFont(font.getSystemFont(), font.isUnderlined(), false);
    }

    public int getTranslateX() {
        return paint.getTranslateX();
    }

    public int getTranslateY() {
        return paint.getTranslateY();
    }

    public int getClipX() {
        return paint.getClipLeft();
    }

    public int getClipY() {
        return paint.getClipTop();
    }

    public int getClipWidth() {
        return paint.getClipWidth();
    }

    public int getClipHeight() {
        return paint.getClipHeight();
    }

    public int getColor() {
        return paint.getColor() & 0x00ffffff;
    }

    public int getDisplayColor(int colorRGB) {
        return colorRGB & 0x00ffffff;
    }

    public int getRedComponent() {
        return paint.getRedComponent();
    }

    public int getGreenComponent() {
        return paint.getGreenComponent();
    }

    public int getBlueComponent() {
        return paint.getBlueComponent();
    }

    public int getGrayScale() {
        int c = paint.getColor();
        return (76 * ((c >> 0x10) & 0xff) + 152 * ((c >> 0x08) & 0xff) + 28 * (c & 0xff)) >> 8;
    }

    public int getStrokeStyle() {
        return stroke;
    }

    public Font getFont() {
        return font;
    }

    void reset() {
        Font f;
        TextPaint p = paint;
        stroke = SOLID;
        font = f = Font.getDefaultFont();
        p.setFont(f.getSystemFont(), f.isUnderlined(), false);
        p.setColor(0xff000000);
        synchronized(p)
        {
            p.translateReset();
            p.setClip(0, 0, width, height);
        }
    }

    void bound(Clip clip) {
        clip.clipRect(-clip.getTranslateX(), -clip.getTranslateY(), width, height);
    }

    void check(String method, int left, int top, int width, int height) throws IllegalArgumentException {
        int lim;
        int len;
        if((lim = left + width) > (len = this.width) || lim < left || left > len || left < 0 || (lim = top + height) > (len = this.height) || lim < top || top > len || top < 0)
        {
            throw new IllegalArgumentException(method.concat(": заданный регион выходит за пределы канвы."));
        }
    }
}

final class ScreenGraphics extends Graphics
{
    private int left;
    private int top;
    private int width;
    private int height;
    private int startX;
    private int startY;

    ScreenGraphics(RasterBuffer buffer) {
        super(buffer);
    }

    public void copyArea(int left, int top, int width, int height, int x, int y, int anchor) {
        throw new IllegalStateException("Graphics.copyArea: эта канва представляет собой экран устройства.");
    }

    public void reset() {
        left = 0;
        top = 0;
        width = super.width;
        height = super.height;
        startX = 0;
        startY = 0;
        super.reset();
    }

    public int getTranslateX() {
        return super.getTranslateX() - startX;
    }

    public int getTranslateY() {
        return super.getTranslateY() - startY;
    }

    public void restricts(int left, int top, int width, int height) {
        this.left = left;
        this.top = top;
        this.width = width;
        this.height = height;
    }

    public void setStartPoint(int startX, int startY) {
        this.startX = startX;
        this.startY = startY;
    }

    public int getRestrictedLeft() {
        return left;
    }

    public int getRestrictedTop() {
        return top;
    }

    public int getRestrictedWidth() {
        return width;
    }

    public int getRestrictedHeight() {
        return height;
    }

    public int getStartPointX() {
        return startX;
    }

    public int getStartPointY() {
        return startY;
    }

    void bound(Clip clip) {
        clip.clipRect(left - clip.getTranslateX(), top - clip.getTranslateY(), width, height);
    }

    void check(String method, int left, int top, int width, int height) throws IllegalArgumentException {
        int lim;
        int len;
        int min;
        if(
            (lim = left + width) > (len = (min = this.left) + this.width) || lim < left || left > len || left < min ||
            (lim = top + height) > (len = (min = this.top) + this.height) || lim < top || top > len || top < min
        )
        {
            throw new IllegalArgumentException(method.concat(": заданный регион выходит за пределы канвы."));
        }
    }
}
