500 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			500 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Id: tridentdraw.c,v 1.1 1999/11/02 03:54:47 keithp Exp $
 | 
						|
 *
 | 
						|
 * Copyright © 1999 Keith Packard
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that
 | 
						|
 * copyright notice and this permission notice appear in supporting
 | 
						|
 * documentation, and that the name of Keith Packard not be used in
 | 
						|
 * advertising or publicity pertaining to distribution of the software without
 | 
						|
 * specific, written prior permission.  Keith Packard makes no
 | 
						|
 * representations about the suitability of this software for any purpose.  It
 | 
						|
 * is provided "as is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
						|
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
						|
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
						|
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | 
						|
 * PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
/* $RCSId: xc/programs/Xserver/hw/kdrive/trident/tridentdraw.c,v 1.10 2001/06/03 18:48:19 keithp Exp $ */
 | 
						|
 | 
						|
#ifdef HAVE_CONFIG_H
 | 
						|
#include <config.h>
 | 
						|
#endif
 | 
						|
#include "trident.h"
 | 
						|
#include "tridentdraw.h"
 | 
						|
 | 
						|
#include	"Xmd.h"
 | 
						|
#include	"gcstruct.h"
 | 
						|
#include	"scrnintstr.h"
 | 
						|
#include	"pixmapstr.h"
 | 
						|
#include	"regionstr.h"
 | 
						|
#include	"mistruct.h"
 | 
						|
#include	"fontstruct.h"
 | 
						|
#include	"dixfontstr.h"
 | 
						|
#include	"fb.h"
 | 
						|
#include	"migc.h"
 | 
						|
#include	"miline.h"
 | 
						|
#include	"picturestr.h"
 | 
						|
 | 
						|
CARD8 tridentRop[16] = {
 | 
						|
    /* GXclear      */      0x00,         /* 0 */
 | 
						|
    /* GXand        */      0x88,         /* src AND dst */
 | 
						|
    /* GXandReverse */      0x44,         /* src AND NOT dst */
 | 
						|
    /* GXcopy       */      0xcc,         /* src */
 | 
						|
    /* GXandInverted*/      0x22,         /* NOT src AND dst */
 | 
						|
    /* GXnoop       */      0xaa,         /* dst */
 | 
						|
    /* GXxor        */      0x66,         /* src XOR dst */
 | 
						|
    /* GXor         */      0xee,         /* src OR dst */
 | 
						|
    /* GXnor        */      0x11,         /* NOT src AND NOT dst */
 | 
						|
    /* GXequiv      */      0x99,         /* NOT src XOR dst */
 | 
						|
    /* GXinvert     */      0x55,         /* NOT dst */
 | 
						|
    /* GXorReverse  */      0xdd,         /* src OR NOT dst */
 | 
						|
    /* GXcopyInverted*/     0x33,         /* NOT src */
 | 
						|
    /* GXorInverted */      0xbb,         /* NOT src OR dst */
 | 
						|
    /* GXnand       */      0x77,         /* NOT src OR NOT dst */
 | 
						|
    /* GXset        */      0xff,         /* 1 */
 | 
						|
};
 | 
						|
 | 
						|
#define tridentFillPix(bpp,pixel) {\
 | 
						|
    if (bpp == 8) \
 | 
						|
    { \
 | 
						|
	pixel = pixel & 0xff; \
 | 
						|
	pixel = pixel | pixel << 8; \
 | 
						|
    } \
 | 
						|
    if (bpp <= 16) \
 | 
						|
    { \
 | 
						|
	pixel = pixel & 0xffff; \
 | 
						|
	pixel = pixel | pixel << 16; \
 | 
						|
    } \
 | 
						|
}
 | 
						|
 | 
						|
static Cop	*cop;
 | 
						|
static CARD32	cmd;
 | 
						|
 | 
						|
Bool
 | 
						|
tridentPrepareSolid (DrawablePtr    pDrawable,
 | 
						|
		     int	    alu,
 | 
						|
		     Pixel	    pm,
 | 
						|
		     Pixel	    fg)
 | 
						|
{
 | 
						|
    FbBits  depthMask = FbFullMask(pDrawable->depth);
 | 
						|
    
 | 
						|
    if ((pm & depthMask) != depthMask)
 | 
						|
	return FALSE;
 | 
						|
    else
 | 
						|
    {
 | 
						|
	KdScreenPriv(pDrawable->pScreen);
 | 
						|
	tridentCardInfo(pScreenPriv);
 | 
						|
	cop = tridentc->cop;
 | 
						|
	
 | 
						|
	tridentFillPix(pDrawable->bitsPerPixel,fg);
 | 
						|
	_tridentInit(cop,tridentc);
 | 
						|
	_tridentSetSolidRect(cop,fg,alu,cmd);
 | 
						|
	return TRUE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentSolid (int x1, int y1, int x2, int y2)
 | 
						|
{
 | 
						|
    _tridentRect (cop, x1, y1, x2 - 1, y2 - 1, cmd);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentDoneSolid (void)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
tridentPrepareCopy (DrawablePtr	pSrcDrawable,
 | 
						|
		    DrawablePtr	pDstDrawable,
 | 
						|
		    int		dx,
 | 
						|
		    int		dy,
 | 
						|
		    int		alu,
 | 
						|
		    Pixel	pm)
 | 
						|
{
 | 
						|
    FbBits  depthMask = FbFullMask(pDstDrawable->depth);
 | 
						|
    
 | 
						|
    if ((pm & depthMask) == depthMask)
 | 
						|
    {
 | 
						|
	KdScreenPriv(pDstDrawable->pScreen);
 | 
						|
	tridentCardInfo(pScreenPriv);
 | 
						|
	cop = tridentc->cop;
 | 
						|
	_tridentInit(cop,tridentc);
 | 
						|
	cop->multi = COP_MULTI_PATTERN;
 | 
						|
	cop->multi = COP_MULTI_ROP | tridentRop[alu];
 | 
						|
	cmd = COP_OP_BLT | COP_SCL_OPAQUE | COP_OP_ROP | COP_OP_FB;
 | 
						|
	if (dx < 0 || dy < 0)
 | 
						|
	    cmd |= COP_X_REVERSE;
 | 
						|
	return TRUE;
 | 
						|
    }
 | 
						|
    else
 | 
						|
	return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentCopy (int srcX,
 | 
						|
	     int srcY,
 | 
						|
	     int dstX,
 | 
						|
	     int dstY,
 | 
						|
	     int w,
 | 
						|
	     int h)
 | 
						|
{
 | 
						|
    if (cmd & COP_X_REVERSE)
 | 
						|
    {
 | 
						|
	cop->src_start_xy = TRI_XY (srcX + w - 1, srcY + h - 1);
 | 
						|
	cop->src_end_xy   = TRI_XY (srcX, srcY);
 | 
						|
	cop->dst_start_xy = TRI_XY (dstX + w - 1, dstY + h - 1);
 | 
						|
	cop->dst_end_xy   = TRI_XY (dstX, dstY);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	cop->src_start_xy   = TRI_XY (srcX, srcY);
 | 
						|
	cop->src_end_xy	    = TRI_XY (srcX + w - 1, srcY + h - 1);
 | 
						|
	cop->dst_start_xy   = TRI_XY (dstX, dstY);
 | 
						|
	cop->dst_end_xy	    = TRI_XY (dstX + w - 1, dstY + h - 1);
 | 
						|
    }
 | 
						|
    _tridentWaitDone (cop);
 | 
						|
    cop->command = cmd;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentDoneCopy (void)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentComposite (CARD8      op,
 | 
						|
		  PicturePtr pSrc,
 | 
						|
		  PicturePtr pMask,
 | 
						|
		  PicturePtr pDst,
 | 
						|
		  INT16      xSrc,
 | 
						|
		  INT16      ySrc,
 | 
						|
		  INT16      xMask,
 | 
						|
		  INT16      yMask,
 | 
						|
		  INT16      xDst,
 | 
						|
		  INT16      yDst,
 | 
						|
		  CARD16     width,
 | 
						|
		  CARD16     height)
 | 
						|
{
 | 
						|
    SetupTrident (pDst->pDrawable->pScreen);
 | 
						|
    tridentScreenInfo(pScreenPriv);
 | 
						|
    RegionRec	region;
 | 
						|
    int		n;
 | 
						|
    BoxPtr	pbox;
 | 
						|
    CARD32	rgb;
 | 
						|
    CARD8	*msk, *mskLine;
 | 
						|
    FbBits	*mskBits;
 | 
						|
    FbStride	mskStride;
 | 
						|
    int		mskBpp;
 | 
						|
    int		mskXoff, mskYoff;
 | 
						|
    CARD32	*src, *srcLine;
 | 
						|
    CARD32	*off, *offLine;
 | 
						|
    FbBits	*srcBits;
 | 
						|
    FbStride	srcStride;
 | 
						|
    int		srcXoff, srcYoff;
 | 
						|
    FbStride	offStride;
 | 
						|
    int		srcBpp;
 | 
						|
    int		x_msk, y_msk, x_src, y_src, x_dst, y_dst;
 | 
						|
    int		x2;
 | 
						|
    int		w, h, w_this, h_this, w_remain;
 | 
						|
    CARD32	*off_screen;
 | 
						|
    int		off_size = tridents->off_screen_size >> 2;
 | 
						|
    int		off_width, off_height;
 | 
						|
    int		stride = pScreenPriv->screen->fb[0].pixelStride;
 | 
						|
    int		mskExtra;
 | 
						|
    CARD32	off_screen_offset = tridents->off_screen - tridents->screen;
 | 
						|
    int		mode;
 | 
						|
    
 | 
						|
#define MODE_NONE   0
 | 
						|
#define MODE_IMAGE  1
 | 
						|
#define MODE_MASK   2
 | 
						|
    
 | 
						|
    rgb = *((CARD32 *) ((PixmapPtr) (pSrc->pDrawable))->devPrivate.ptr);
 | 
						|
    if (pMask && 
 | 
						|
	!pMask->repeat &&
 | 
						|
	pMask->format == PICT_a8 &&
 | 
						|
        op == PictOpOver &&
 | 
						|
	pSrc->repeat &&
 | 
						|
	pSrc->pDrawable->width == 1 &&
 | 
						|
	pSrc->pDrawable->height == 1 &&
 | 
						|
	PICT_FORMAT_BPP(pSrc->format) == 32 &&
 | 
						|
	(PICT_FORMAT_A(pSrc->format) == 0 ||
 | 
						|
	 (rgb & 0xff000000) == 0xff000000) &&
 | 
						|
	pDst->pDrawable->bitsPerPixel == 32 &&
 | 
						|
	pDst->pDrawable->type == DRAWABLE_WINDOW)
 | 
						|
    {
 | 
						|
	mode = MODE_MASK;
 | 
						|
    }
 | 
						|
    else if (!pMask &&
 | 
						|
	     op == PictOpOver &&
 | 
						|
	     !pSrc->repeat &&
 | 
						|
	     PICT_FORMAT_A(pSrc->format) == 8 &&
 | 
						|
	     PICT_FORMAT_BPP(pSrc->format) == 32 &&
 | 
						|
	     pDst->pDrawable->bitsPerPixel == 32 &&
 | 
						|
	     pDst->pDrawable->type == DRAWABLE_WINDOW)
 | 
						|
    {
 | 
						|
	mode = MODE_IMAGE;
 | 
						|
    }
 | 
						|
    else
 | 
						|
	mode = MODE_NONE;
 | 
						|
    
 | 
						|
    if (mode != MODE_NONE)
 | 
						|
    {
 | 
						|
	xDst += pDst->pDrawable->x;
 | 
						|
	yDst += pDst->pDrawable->y;
 | 
						|
	xSrc += pSrc->pDrawable->x;
 | 
						|
	ySrc += pSrc->pDrawable->y;
 | 
						|
	
 | 
						|
	fbGetDrawable (pSrc->pDrawable, srcBits, srcStride, srcBpp, srcXoff, srcYoff);
 | 
						|
	
 | 
						|
	if (pMask)
 | 
						|
	{
 | 
						|
	    xMask += pMask->pDrawable->x;
 | 
						|
	    yMask += pMask->pDrawable->y;
 | 
						|
	    fbGetDrawable (pMask->pDrawable, mskBits, mskStride, mskBpp, mskXoff, mskYoff);
 | 
						|
	    mskStride = mskStride * sizeof (FbBits) / sizeof (CARD8);
 | 
						|
	}
 | 
						|
	
 | 
						|
	if (!miComputeCompositeRegion (®ion,
 | 
						|
				       pSrc,
 | 
						|
				       pMask,
 | 
						|
				       pDst,
 | 
						|
				       xSrc,
 | 
						|
				       ySrc,
 | 
						|
				       xMask,
 | 
						|
				       yMask,
 | 
						|
				       xDst,
 | 
						|
				       yDst,
 | 
						|
				       width,
 | 
						|
				       height))
 | 
						|
	    return;
 | 
						|
	
 | 
						|
	_tridentInit(cop,tridentc);
 | 
						|
	
 | 
						|
	cop->multi = COP_MULTI_PATTERN;
 | 
						|
	cop->src_offset = off_screen_offset;
 | 
						|
	
 | 
						|
	if (mode == MODE_IMAGE)
 | 
						|
	{
 | 
						|
	    cop->multi = (COP_MULTI_ALPHA |
 | 
						|
			  COP_ALPHA_BLEND_ENABLE |
 | 
						|
			  COP_ALPHA_WRITE_ENABLE |
 | 
						|
			  0x7 << 16 |
 | 
						|
			  COP_ALPHA_DST_BLEND_1_SRC_A |
 | 
						|
			  COP_ALPHA_SRC_BLEND_1);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
	    rgb &= 0xffffff;
 | 
						|
	    cop->multi = (COP_MULTI_ALPHA |
 | 
						|
			  COP_ALPHA_BLEND_ENABLE |
 | 
						|
			  COP_ALPHA_WRITE_ENABLE |
 | 
						|
			  0x7 << 16 |
 | 
						|
			  COP_ALPHA_DST_BLEND_1_SRC_A |
 | 
						|
			  COP_ALPHA_SRC_BLEND_SRC_A);
 | 
						|
	}
 | 
						|
	
 | 
						|
	n = REGION_NUM_RECTS (®ion);
 | 
						|
	pbox = REGION_RECTS (®ion);
 | 
						|
	
 | 
						|
	while (n--)
 | 
						|
	{
 | 
						|
	    h = pbox->y2 - pbox->y1;
 | 
						|
	    w = pbox->x2 - pbox->x1;
 | 
						|
	    
 | 
						|
	    offStride = (w + 7) & ~7;
 | 
						|
	    off_height = off_size / offStride;
 | 
						|
	    if (off_height > h)
 | 
						|
		off_height = h;
 | 
						|
	    
 | 
						|
	    cop->multi = COP_MULTI_STRIDE | (stride << 16) | offStride;
 | 
						|
	    
 | 
						|
	    y_dst = pbox->y1;
 | 
						|
	    y_src = y_dst - yDst + ySrc;
 | 
						|
	    y_msk = y_dst - yDst + yMask;
 | 
						|
	    
 | 
						|
	    x_dst = pbox->x1;
 | 
						|
	    x_src = x_dst - xDst + xSrc;
 | 
						|
	    x_msk = x_dst - xDst + xMask;
 | 
						|
	
 | 
						|
	    if (mode == MODE_IMAGE)
 | 
						|
		srcLine = (CARD32 *) srcBits + (y_src - srcYoff) * srcStride + (x_src - srcXoff);
 | 
						|
	    else
 | 
						|
		mskLine = (CARD8 *) mskBits + (y_msk - mskYoff) * mskStride + (x_msk - mskXoff);
 | 
						|
 | 
						|
	    while (h)
 | 
						|
	    {
 | 
						|
		h_this = h;
 | 
						|
		if (h_this > off_height)
 | 
						|
		    h_this = off_height;
 | 
						|
		h -= h_this;
 | 
						|
		
 | 
						|
		offLine = (CARD32 *) tridents->off_screen;
 | 
						|
		
 | 
						|
		_tridentWaitDone(cop);
 | 
						|
		
 | 
						|
		cop->dst_start_xy = TRI_XY(x_dst, y_dst);
 | 
						|
		cop->dst_end_xy = TRI_XY(x_dst + w - 1, y_dst + h_this - 1);
 | 
						|
		cop->src_start_xy = TRI_XY(0,0);
 | 
						|
		cop->src_end_xy = TRI_XY(w - 1, h_this - 1);
 | 
						|
					 
 | 
						|
		if (mode == MODE_IMAGE)
 | 
						|
		{
 | 
						|
		    while (h_this--)
 | 
						|
		    {
 | 
						|
			w_remain = w;
 | 
						|
			src = srcLine;
 | 
						|
			srcLine += srcStride;
 | 
						|
			off = offLine;
 | 
						|
			offLine += offStride;
 | 
						|
			while (w_remain--)
 | 
						|
			    *off++ = *src++;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
		    while (h_this--)
 | 
						|
		    {
 | 
						|
			w_remain = w;
 | 
						|
			msk = mskLine;
 | 
						|
			mskLine += mskStride;
 | 
						|
			off = offLine;
 | 
						|
			offLine += offStride;
 | 
						|
			while (w_remain--)
 | 
						|
			    *off++ = rgb | (*msk++ << 24);
 | 
						|
		    }
 | 
						|
		}
 | 
						|
		
 | 
						|
		cop->command = (COP_OP_BLT |
 | 
						|
				COP_SCL_OPAQUE |
 | 
						|
				COP_OP_FB);
 | 
						|
	    }
 | 
						|
	    pbox++;
 | 
						|
	}
 | 
						|
	cop->src_offset = 0;
 | 
						|
	
 | 
						|
	KdMarkSync (pDst->pDrawable->pScreen);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	KdCheckComposite (op,
 | 
						|
			  pSrc,
 | 
						|
			  pMask,
 | 
						|
			  pDst,
 | 
						|
			  xSrc,
 | 
						|
			  ySrc,
 | 
						|
			  xMask,
 | 
						|
			  yMask,
 | 
						|
			  xDst,
 | 
						|
			  yDst,
 | 
						|
			  width,
 | 
						|
			  height);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
KaaScreenPrivRec    tridentKaa = {
 | 
						|
    tridentPrepareSolid,
 | 
						|
    tridentSolid,
 | 
						|
    tridentDoneSolid,
 | 
						|
 | 
						|
    tridentPrepareCopy,
 | 
						|
    tridentCopy,
 | 
						|
    tridentDoneCopy,
 | 
						|
};
 | 
						|
 | 
						|
Bool
 | 
						|
tridentDrawInit (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    SetupTrident(pScreen);
 | 
						|
    tridentScreenInfo(pScreenPriv);
 | 
						|
    PictureScreenPtr    ps = GetPictureScreen(pScreen);
 | 
						|
    
 | 
						|
    if (!kaaDrawInit (pScreen, &tridentKaa))
 | 
						|
	return FALSE;
 | 
						|
 | 
						|
    if (ps && tridents->off_screen)
 | 
						|
	ps->Composite = tridentComposite;
 | 
						|
    
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentDrawEnable (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    SetupTrident(pScreen);
 | 
						|
    CARD32  cmd;
 | 
						|
    CARD32  base;
 | 
						|
    CARD16  stride;
 | 
						|
    CARD32  format;
 | 
						|
    CARD32  alpha;
 | 
						|
    int	    tries;
 | 
						|
    int	    nwrite;
 | 
						|
    
 | 
						|
    stride = pScreenPriv->screen->fb[0].pixelStride;
 | 
						|
    switch (pScreenPriv->screen->fb[0].bitsPerPixel) {
 | 
						|
    case 8:
 | 
						|
	format = COP_DEPTH_8;
 | 
						|
	break;
 | 
						|
    case 16:
 | 
						|
	format = COP_DEPTH_16;
 | 
						|
	break;
 | 
						|
    case 24:
 | 
						|
	format = COP_DEPTH_24_32;
 | 
						|
	break;
 | 
						|
    case 32:
 | 
						|
	format = COP_DEPTH_24_32;
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    /* 
 | 
						|
     * compute a few things which will be set every time the
 | 
						|
     * accelerator is used; this avoids problems with APM
 | 
						|
     */
 | 
						|
    tridentc->cop_depth = COP_MULTI_DEPTH | format;
 | 
						|
    tridentc->cop_stride = COP_MULTI_STRIDE | (stride << 16) | (stride);
 | 
						|
    
 | 
						|
#define NUM_TRIES   100000
 | 
						|
    for (tries = 0; tries < NUM_TRIES; tries++)
 | 
						|
	if (!(cop->status & COP_STATUS_BUSY))
 | 
						|
	    break;
 | 
						|
    if (cop->status & COP_STATUS_BUSY)
 | 
						|
	FatalError ("Can't initialize graphics coprocessor");
 | 
						|
    cop->multi = COP_MULTI_CLIP_TOP_LEFT;
 | 
						|
    cop->multi = COP_MULTI_MASK | 0;
 | 
						|
    cop->src_offset = 0;
 | 
						|
    cop->dst_offset = 0;
 | 
						|
    cop->z_offset = 0;
 | 
						|
    cop->clip_bottom_right = 0x0fff0fff;
 | 
						|
    
 | 
						|
    _tridentInit(cop,tridentc);
 | 
						|
    _tridentSetSolidRect(cop, pScreen->blackPixel, GXcopy, cmd);
 | 
						|
    _tridentRect (cop, 0, 0, 
 | 
						|
		  pScreenPriv->screen->width, pScreenPriv->screen->height,
 | 
						|
		  cmd);
 | 
						|
    KdMarkSync (pScreen);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentDrawDisable (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentDrawFini (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
tridentDrawSync (ScreenPtr pScreen)
 | 
						|
{
 | 
						|
    SetupTrident(pScreen);
 | 
						|
    
 | 
						|
    _tridentWaitIdleEmpty(cop);
 | 
						|
}
 |