#include"..\ucos-ii\includes.h" /* uC/OS interface *
#include "..\ucos-ii\add\osaddition.h"
#include "..\inc\drv.h"
#include "..\INC\DRV\zlg7289.h"
#include
#include
#include
#pragma import(__use_no_semihosting_swi) // ensure no functions that use semihosting
extern int Zlg7289SIOBand;
extern int Zlg7289SIOCtrl;
///******************任务定义***************///
OS_STK Main_Stack[STACKSIZE*8]={0, }; //Main_Test_Task堆栈
void Main_Task(void *Id); //Main_Test_Task
#define Main_Task_Prio 12
/**************已经定义的OS任务*************
tcp监控任务 11
以太网物理层监控任务 8
触摸屏任务 9
键盘任务 10
lcd刷新任务 59
系统任务 1
*****************************************************/
OS_STK Time_Stack[STACKSIZE*8]={0, }; //Time_Tsk堆栈
void Time_Task(void *Id); //Time_Task
#define Time_Task_Prio 13
OS_STK Uart_Stack[STACKSIZE*8]={0, }; //Uart_Task堆栈
void Uart_Task(void *Id); //Uart_Task
#define Uart_Task_Prio 14
#define OSM_TIME 4 //定时器消息
/*重画界面命令*/
#define OSM_DRAW 5
/*消去一个满行的命令*/
#define OSM_DELLINE 6
/*自动下移一行的命令*/
#define OSM_AOTODOWN 7
/*生产新的方块*/
#define OSM_GEN 8
/*向左移动的命令,以键盘上的7来控制*/
#define LEFTMOVE 11
/*向右移动的命令,以键盘上的9来控制*/
#define RINGHTMOVE 13
/*旋转方块的命令,以键盘上的5来控制*/
#define ROTATE 9
/*向下加速的命令,以键盘上的8来控制*/
#define DOWNMOVE 12
/*更新分数*/
#define OSM_SCORE 13
/*提示下一个方块*/
#define OSM_NEXT 14
/*串口消息*/
#define OSM_UART 15
/*下面定义了显示区域的位置*/
#define AREALEFT -125
#define AREATOP -100
#define AREARIGHT -25
#define AREABOTTOM 100
/*下面定义了显示下一个方块的位置*/
#define NEXTLEFT 50
#define NEXTTOP -100
#define NEXTRIGHT 90
#define NEXTBOTTOM -60
/*下面定义了显示区域的大小 10*20*/
#define MAXHEIGHT 20
#define MAXWIDTH 10
/*颜色*/
#define RED 0x00ff0000
#define GREEN 0x0000ff00
#define BLUE 0x000000ff
#define COLORNUM 3
U32 color[COLORNUM]={RED,GREEN,BLUE};
/*定义七种基本的方块形状*/
#define SHAPENUM 19
U16 BASICBOX[SHAPENUM][4][4]={
{{1,1,1,1},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}},
{{1,1,1,0},{1,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,0,0,0},{1,1,0,0},{0,0,0,0}},
{{1,1,0,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}},
{{0,0,1,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},
{{1,1,1,0},{0,0,1,0},{0,0,0,0},{0,0,0,0}},
{{0,1,0,0},{0,1,0,0},{1,1,0,0},{0,0,0,0}},
{{1,1,0,0},{1,0,0,0},{1,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,0,0},{1,0,0,0},{0,0,0,0}},
{{1,1,1,0},{0,1,0,0},{0,0,0,0},{0,0,0,0}},
{{0,1,0,0},{1,1,0,0},{0,1,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,0,0},{1,0,0,0},{0,0,0,0}},
{{0,1,0,0},{1,1,0,0},{0,1,0,0},{0,0,0,0}},
{{1,1,0,0},{0,1,1,0},{0,0,0,0},{0,0,0,0}},
{{0,1,0,0},{1,1,0,0},{1,0,0,0},{0,0,0,0}},
{{0,1,1,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,1,0,0},{0,1,0,0},{0,0,0,0}},
{{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}}
};
///*****************事件定义*****************///
OS_EVENT *Nand_Rw_Sem; //Nand_Flash读写控制权旗语
//and you can use it as folloeing:
// Nand_Rw_Sem=OSSemCreate(1); //创建Nand-Flash读写控制权旗语,初值为1满足互斥条件//
// OSSemPend(Nand_Rw_Sem,0,&err);
// OSSemPost(Nand_Rw_Sem);
OS_EVENT *Uart_Rw_Sem; //Uart读写控制权旗语
//and you can use it as folloeing:
// Uart_Rw_Sem=OSSemCreate(1); //创建Uart读写控制权旗语,初值为1满足互斥条件//
// OSSemPend(Uart_Rw_Sem,0,&err);
// OSSemPost(Uart_Rw_Sem);
//////////////////////////////////////////////////////////
int oldarea[MAXHEIGHT][MAXWIDTH];
int area[MAXHEIGHT][MAXWIDTH];
/*存储当前方块的数组*/
int box[4][4];
/*当前方块的位置*/
int curX;
int curY;
int curW;
int curH;
/*方块当前的状态*/
int active;
/*方块的新位置*/
int newX;
int newY;
int newW;
int newH;
/*需要改变的屏幕区域*/
int actX;
int actY;
int actW;
int actH;
/*分数*/
int score;
/*当前的方块*/
int curID;
/*下一个方块*/
int nextID;
/*当前方框的颜色*/
int curColor;
/*下一个方框的颜色*/
int nextColor;
/*得到方块的宽度,即从右向左第一个不空的列*/
int GetWidth()
{
int i,j;
for(i=3;i>0;i--)
{
for(j=0;j<4;j++)
{
if(box[j])
return i;
}
}
return 0;
}
/*得到方块的高度,从上往下第一个不空的行*/
int GetHeight()
{
U16 i,j;
for(j=3;j>0;j--)
{
for(i=0;i<4;i++)
{
if(box[j])
return j;
}
}
return 0;
}
/*填充指定空格的颜色*/
void setFrameColor(int row,int col,int flag)
{
int left,top,right,bottom;
PDC pdc;//定义绘图设备上下文结构
int oldx,oldy;
left = AREALEFT+col*10;
top = AREATOP+(MAXHEIGHT-row-1)*10;
right = left+10;
bottom = top+10;
pdc=CreateDC();//创建绘图设备上下文
SetDrawOrg(pdc, LCDWIDTH/2,LCDHEIGHT/2, &oldx, & oldy); //设置绘图原点为屏幕中心
if(flag)
{
DrawRectFrame(pdc,left,top,right,bottom);
FillRect(pdc,left+1,top+1,right-1,bottom-1,GRAPH_MODE_NORMAL,color[curColor]);
}
else
{
DrawRectFrame(pdc,left,top,right,bottom);
FillRect(pdc,left+1,top+1,right-1,bottom-1,GRAPH_MODE_NORMAL,0xffffff);
}
DestoryDC(pdc);//删除绘图设备上下文
}
void SetNextFrame(int row,int col,int flag)
{
int left,top,right,bottom;
PDC pdc;//定义绘图设备上下文结构
int oldx,oldy;
left = NEXTLEFT+col*10;
top = NEXTTOP+(3-row)*10;
right = left+10;
bottom = top+10;
pdc=CreateDC();//创建绘图设备上下文
SetDrawOrg(pdc, LCDWIDTH/2,LCDHEIGHT/2, &oldx, & oldy); //设置绘图原点为屏幕中心
if(flag)
{
DrawRectFrame(pdc,left,top,right,bottom);
FillRect(pdc,left+1,top+1,right-1,bottom-1,GRAPH_MODE_NORMAL,color[nextColor]);
}
else
{
DrawRectFrame(pdc,left,top,right,bottom);
FillRect(pdc,left+1,top+1,right-1,bottom-1,GRAPH_MODE_NORMAL,0xffffff);
}
DestoryDC(pdc);//删除绘图设备上下文
}
/*显示下一个方块*/
void DrawNext()
{
int nextbox[4][4];
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
SetNextFrame(i,j,BASICBOX[nextID][j]);
}
/*在LED上显示分数*/
void DisplayScore(int score)
{
Zlg7289_Reset();
if(score<=9)
{
ZLG7289_ENABLE();//使zlg7289占有同步串口
WriteSDIO(ZLG7289_CMD_DATA0|0);//数码管以方式0译码,第一个数码管亮
WriteSDIO(score);//显示个位
ZLG7289_DISABLE();//zlg7289放弃同步串口控制权
}
else if(score<=99)
{
ZLG7289_ENABLE();//使zlg7289占有同步串口
WriteSDIO(ZLG7289_CMD_DATA0|0);
WriteSDIO(score%10);//显示个位
Delay(1);
WriteSDIO(ZLG7289_CMD_DATA0|1);
WriteSDIO(score/10);//显示十位
WriteSDIO(ZLG7289_CMD_HIDE);//使一、二两位数码管显示
WriteSDIO(3);
ZLG7289_DISABLE();//zlg7289放弃同步串口控制权
}
else if(score<=999)
{
ZLG7289_ENABLE();//使zlg7289占有同步串口
WriteSDIO(ZLG7289_CMD_DATA0|0);
WriteSDIO(score%10);//显示个位
Delay(1);
WriteSDIO(ZLG7289_CMD_DATA0|1);
WriteSDIO(score/10%10);//显示十位
Delay(1);
WriteSDIO(ZLG7289_CMD_DATA0|2);
WriteSDIO(score/100);//显示百位
WriteSDIO(ZLG7289_CMD_HIDE);//使一、二两位数码管显示
WriteSDIO(7);
ZLG7289_DISABLE();//zlg7289放弃同步串口控制权
}
else if(score<=9999)
{
ZLG7289_ENABLE();//使zlg7289占有同步串口
WriteSDIO(ZLG7289_CMD_DATA0|0);
WriteSDIO(score%10);//显示个位
Delay(1);
WriteSDIO(ZLG7289_CMD_DATA0|1);
WriteSDIO(score/10%10);//显示十位
Delay(1);
WriteSDIO(ZLG7289_CMD_DATA0|2);
WriteSDIO(score/100%10);//显示百位
Delay(1);
WriteSDIO(ZLG7289_CMD_DATA0|3);
WriteSDIO(score/1000);//显示千位
WriteSDIO(ZLG7289_CMD_HIDE);//使一、二两位数码管显示
WriteSDIO(15);
ZLG7289_DISABLE();//zlg7289放弃同步串口控制权
}
else
{
ZLG7289_ENABLE();//使zlg7289占有同步串口
WriteSDIO(ZLG7289_CMD_DATA0|0);
WriteSDIO(0);//显示个位
WriteSDIO(ZLG7289_CMD_DATA0|1);
WriteSDIO(0);//显示十位
WriteSDIO(ZLG7289_CMD_DATA0|2);
WriteSDIO(0);//显示百位
WriteSDIO(ZLG7289_CMD_DATA0|3);
WriteSDIO(0);//显示千位
ZLG7289_DISABLE();//zlg7289放弃同步串口控制权
}
}
/*随机函数*/ /*seed<=120*/
int random(int seed)
{
int minute,second;
structTime time;
Get_Rtc(&time);
minute=(int)time.minute;
second=(int)time.second;
return (minute+second)%seed;
}
void initOSGUI() //初始化操作系统的图形界面
{
initOSMessage();
initOSList();
initOSDC();
initOSCtrl();
initOSFile();
InitRtc(); //初始化系统时间
}
void initGrame()
{
int i,j;
int oldx,oldy;//保存原来坐标系位置
PDC pdc;//定义绘图设备上下文结构
U16 ch[10];
char cmdArr1[20]="1--left";
char cmdArr2[20]="3--right";
char cmdArr3[20]="5--rotate";
char cmdArr4[20]="2--movedown";
//char *cmdArr[4]={"1--left","3--right","5--rotate","2--speed"};
curX=0;
curY=0;
curW=0;
curH=0;
active=0;
nextID=random(SHAPENUM);
nextColor=random(COLORNUM);
newX=0;
newY=0;
newW=0;
newH=0;
score=0;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
box[j]=0;
}
}
for(i=0;i
{
for(j=0;j
{
oldarea[j]=0;
area[j]=0;
}
}
actX=0;
actY=0;
actW=0;
actH=0;
ClearScreen();//清屏
pdc=CreateDC();//创建绘图设备上下文
SetDrawOrg(pdc, LCDWIDTH/2,LCDHEIGHT/2, &oldx, & oldy); //设置绘图原点为屏幕中心
DrawRectFrame(pdc,AREALEFT,AREATOP,AREARIGHT,AREABOTTOM);
DrawRectFrame(pdc,NEXTLEFT,NEXTTOP,NEXTRIGHT,NEXTBOTTOM);
for(i=0;i<10;i++)
{
MoveTo(pdc,-115+i*10,-100);
LineTo(pdc,-115+i*10,100);
}
for(i=0;i<20;i++)
{
MoveTo(pdc,-125,-90+i*10);
LineTo(pdc,-25,-90+i*10);
}
for(i=0;i<4;i++)
{
MoveTo(pdc,60+i*10,-100);
LineTo(pdc,60+i*10,-60);
}
for(i=0;i<4;i++)
{
MoveTo(pdc,50,-90+i*10);
LineTo(pdc,90,-90+i*10);
}
strChar2Unicode(ch,cmdArr1);//将兆址???葑??蒛nicode
TextOut(pdc, 40, -20, ch, TRUE, FONTSIZE_MIDDLE);//文本模式下显示文字
strChar2Unicode(ch,cmdArr2);//将兆址???葑??蒛nicode
TextOut(pdc, 40, 0, ch, TRUE, FONTSIZE_MIDDLE);//文本模式下显示文字
strChar2Unicode(ch,cmdArr3);//将兆址???葑??蒛nicode
TextOut(pdc, 40, 20, ch, TRUE, FONTSIZE_MIDDLE);//文本模式下显示文字
strChar2Unicode(ch,cmdArr4);//将兆址???葑??蒛nicode
TextOut(pdc, 40, 40, ch, TRUE, FONTSIZE_MIDDLE);//文本模式下显示文字
OSTimeDly(500);
DestoryDC(pdc);//删除绘图设备上下文
DisplayScore(score);
GenerateNewbox();
}
/*清楚原有方框占有的空间*/
void ClearOldspace()
{
int i,j;
for(j=0;j<=curH; j++)
{
for(i=0;i<=curW; i++)
{
if(box[j])
area[curY+j][curX+i]=0;
}
}
}
/*置位新方块的位置*/
void PutNewspace()
{
int i,j;
for(j=0;j<=newH;j++)
for(i=0;i<=newW;i++)
if(box[j])
area[newY+j][newX+i]=1;
}
/*重绘游戏区*/
void DrawSpace()
{
int row,col;
for(row=actY;row<=actY+actH;row++)
for(col=actX;col<=actX+actW;col++)
if(area[row][col]!=oldarea[row][col])
{
if(area[row][col]==0)
setFrameColor(row,col,0);
else
setFrameColor(row,col,1);
oldarea[row][col]=area[row][col];
}
}
/*产生新的方块*/
int GenerateNewbox()
{
int i,j;
POSMSG pMsg;
curID=nextID;
curColor=nextColor;
nextID=random(SHAPENUM);
nextColor=random(COLORNUM);
pMsg = OSCreateMessage(NULL,OSM_NEXT,0,0);
if(pMsg)
SendMessage(pMsg);
for(i=0;i<4;i++)
for(j=0;j<4;j++)
box[j]=BASICBOX[curID][j];
curW=GetWidth();
curH=GetHeight();
curX=MAXWIDTH/2-curW/2;
curY=MAXHEIGHT-curH-1;
active=1;
newX=curX;
newY=curY;
newH=curH;
newW=curW;
actX=curX;
actY=curY;
actH=curH;
actW=curW;
PutNewspace();
DrawSpace();
return 1;
}
/*判断方块的移动是否造成区域冲突*/
int MoveCollision(int box[][4])
{
int i,j;
if(newX<0) return 1;
if(newX+newW>=MAXWIDTH) return 1;
if(newY<0) return 1;
for(j=0;j<=newH;j++)
for(i=0;i<=newW;i++)
if(area[newY+j][newX+i]&&box[j]) return 1;
return 0;
}
/*判断翻转方块是否造成区域的冲突*/
int RotateBoxCollision(int box[][4])
{
int i,j;
if(newX+newW>=MAXWIDTH)
newX=MAXWIDTH-1-newW;
if(newY+newH>=MAXHEIGHT)
newY=MAXHEIGHT-1-newH;
if(MoveCollision(box))
return 1;
for(i=0;i<=newW;i++)
for(j=0;j<=newH;j++)
if(area[newY+j][newX+i])
{
newX-=newW-i+1; goto L;
}
L: return MoveCollision(box);
}
/*向左移动方块*/
int MoveLeft()
{
POSMSG pMsg;
newX=curX-1;
ClearOldspace();
if(MoveCollision(box))
{
newX=curX;
PutNewspace();
return 0;
}
PutNewspace();
actW=curW+1;
actX=curX=newX;
pMsg = OSCreateMessage(NULL,OSM_DRAW,0,0);
if(pMsg)
SendMessage(pMsg);
return 1;
}
/*向右移动方块*/
int MoveRight()
{
POSMSG pMsg;
newX=curX+1;
ClearOldspace();
if(MoveCollision(box))
{
newX=curX;
PutNewspace();
return 0;
}
PutNewspace();
actW=curW+1;
actX=curX;
curX=newX;
pMsg = OSCreateMessage(NULL,OSM_DRAW,0,0);
if(pMsg)
SendMessage(pMsg);
return 1;
}
/*向下移动方块*/
int MoveDown()
{
POSMSG pMsg;
newY=curY-1;
ClearOldspace();
if(MoveCollision(box))
{
newY=curY;
PutNewspace();
active=0;
pMsg = OSCreateMessage(NULL,OSM_DELLINE,0,0);
if(pMsg)
SendMessage(pMsg);
return 0;
}
PutNewspace();
actH=curH+1;
actY=newY;
curY=newY;
pMsg = OSCreateMessage(NULL,OSM_DRAW,0,0);
if(pMsg)
SendMessage(pMsg);
return 1;
}
/*翻转方块*/
int RotateBox()
{
int newBox[4][4];
int i,j;
POSMSG pMsg;
ClearOldspace();
for(j=0;j<4;j++)
for(i=0;i<4;i++)
newBox[j]=0;
for(j=0;j<4;j++)
for(i=0;i<4;i++)
newBox[curW-i][j]=box[j];
newW=curH;
newH=curW;
if(RotateBoxCollision(newBox))
{
newW=curW;
newH=curH;
newX=curX;
newY=curY;
PutNewspace();
return 0;
}
for(j=0;j<4;j++)
for(i=0;i<4;i++)
box[j]=newBox[j];
PutNewspace();
actH=newH>curH? newH:curH;
actW=curX+actH-newX;
actX=newX;
actY=newY;
curX=newX;
curY=newY;
curW=newW;
curH=newH;
pMsg = OSCreateMessage(NULL,OSM_DRAW,0,0);
if(pMsg)
SendMessage(pMsg);
return 1;
}
/*按加速键后方块迅速下落到底*/
void MoveBottom()
{
while(active)
{
MoveDown();
DrawSpace();
}
//CMD=CMDDELLINE;
}
void ClearFullline()
{
int row,col, rowEnd,full,i,j;
int scoreArr[5]={0,10,20,50,100};
int line;
POSMSG pMsg;
line=0;
rowEnd=newY+newH;
if(rowEnd>=MAXHEIGHT-1)
rowEnd=MAXHEIGHT-2;
for(row=newY; row<=rowEnd;) /*只可能是方框的高度消去*/
{
full=1;
for(col=0;col
if(!area[row][col])
{full=0; break;}
if(!full)
{
++row;
continue;
}
for(j=row; j
for(i=0;i
area[j]=area[j+1];
line++;
actX=0;
actY=row;
actW=MAXWIDTH-1;
actH=MAXHEIGHT-1-row;
DrawSpace();
rowEnd--;
}
score+=scoreArr[line];
if(line)
{
pMsg = OSCreateMessage(NULL,OSM_SCORE,0,0);
if(pMsg)
SendMessage(pMsg);
}
pMsg = OSCreateMessage(NULL,OSM_GEN,0,0);
if(pMsg)
SendMessage(pMsg);
}
/*游戏结束*/
int GameOver()
{
int i;
if(!active)
{
for(i=0;i
if(oldarea[MAXHEIGHT-1])
return 1;
}
else
return 0;
}
int main(void)
{
ARMTargetInit(); //开发板初始化
OSInit(); //操作系统初始化
uHALr_ResetMMU();//复位MMU
LCD_Init(); //初始化LCD模块
LCD_printf("LCD initialization is OK\n");//向液晶屏输出数据
LCD_printf("320 x 240 Text Mode\n");
initOSGUI();//初始化图形界面
LoadFont();//调Unicode字库
LoadConfigSys();//使用config.sys文件配置系统设置
LCD_printf("Create task on uCOS-II...\n");
OSTaskCreate(Main_Task, (void *)0, (OS_STK *)&Main_Stack[STACKSIZE*8-1], Main_Task_Prio);// 创建系统任务
OSTaskCreate(Time_Task, (void *)0, (OS_STK *)&Time_Stack[STACKSIZE*8-1], Time_Task_Prio); //定时任务
OSTaskCreate(Uart_Task, (void *)0, (OS_STK *)&Uart_Stack[STACKSIZE*8-1], Uart_Task_Prio); //定时任务
OSAddTask_Init();//创建系统附加任务
LCD_printf("Starting uCOS-II...\n");
LCD_printf("Entering graph mode...\n");
LCD_ChangeMode(DspGraMode);//变LCD显示模式为文本模式
InitRtc();//初始化系统时钟
Nand_Rw_Sem=OSSemCreate(1); //创建Nand-Flash读写控制权旗语,初值为1满足互斥条件//
OSStart();//操作系统任务调度开始
//不会执行到这里
return 0;
}
void Main_Task(void *Id) //Main_Test_Task
{
POSMSG pMsg=0;//创建消息
initGrame();
for(;;)
{
while(!GameOver()) /*主任务、不会结束*/
{
pMsg=WaitMessage(0); //等待消息
switch(pMsg->Message)
{
case OSM_KEY://键盘消息
switch(pMsg->WParam)
{
case LEFTMOVE:
if(active)
{
MoveLeft();
}
break;
case RINGHTMOVE:
if(active)
{
MoveRight();
}
break;
case ROTATE:
if(active)
{
RotateBox();
}
break;
case DOWNMOVE:
if(active)
{
MoveBottom();
}
break;
}
break;
case OSM_TIME:
MoveDown();
break;
case OSM_DELLINE:
ClearFullline();
break;
case OSM_GEN:
GenerateNewbox();
break;
case OSM_DRAW:
DrawSpace();
break;
case OSM_SCORE:
DisplayScore(score);
break;
case OSM_NEXT:
DrawNext();
break;
case OSM_UART:
switch(pMsg->WParam)
{
case '1':
if(active)
{
MoveLeft();
}
break;
case '3':
if(active)
{
MoveRight();
}
break;
case '5':
if(active)
{
RotateBox();
}
break;
case '2':
if(active)
{
MoveBottom();
}
break;
}
}
DeleteMessage(pMsg);//删除消息,释放资源
}
initOSMessage();
OSTimeDly(1000);
initGrame();
}
}
void Time_Task(void * Id)
{
POSMSG pMsg;
for(;;)
{
OSTimeDly(1000);
if(!GameOver())
{
pMsg = OSCreateMessage(NULL,OSM_TIME,0,0);
if(pMsg)
SendMessage(pMsg);
}
}
}
void Uart_Task(void *Id)
{
POSMSG pMsg;
char ch[1];
char err;
for(;;)
{
Uart_SendByte(0,0xa);//换行
Uart_SendByte(0,0xd);//回车
err=Uart_Getch(ch,0,0); //从串口采集数据
Uart_SendByte(0,ch[0]); //显示采集的数据
if(err==TRUE)
{
pMsg = OSCreateMessage(NULL,OSM_UART,ch[0],0);
if(pMsg)
SendMessage(pMsg);
}
}
}