Esempio n. 1
0
//  ... Tick off delta time and run timeout routines as needed
static int serviceTimers (int ifProcessExpiredTimers)
{
    ULONG   numberOfTicks, smallestDelta;

    // is this the first time?
    if (timerList->lastTick == 0ULL)
    {
        timerList->lastTick = radTimeGetMSSinceEpoch ();
    }

    numberOfTicks = (ULONG)(radTimeGetMSSinceEpoch () - timerList->lastTick);
    timerList->lastTick = radTimeGetMSSinceEpoch ();

    // update timers with number of expired ticks
    smallestDelta = updateTimers (numberOfTicks);
    if (ifProcessExpiredTimers && smallestDelta == 0)
    {
        // process expired timer(s)
        processExpiredTimers ();

        // re-process timers with zero ticks to get smallest delta value
        smallestDelta = updateTimers (0);
    }

    return smallestDelta;
}
Esempio n. 2
0
void emulate(void)
{
	_u8 i;
	
	//Execute several instructions to boost performance
	for (i = 0; i < 64; i++)
	{
		updateTimers(TLCS900h_interpret());
		if (Z80ACTIVE) Z80EMULATE
		updateTimers(TLCS900h_interpret());
	}
}
Esempio n. 3
0
EXPORT void FrameAdvance(MyFrameInfo* frame)
{
	lagged = true;
	bool MeowMeow = 0;
	MDFN_Surface surface;
	surface.pixels = frame->VideoBuffer;
	surface.pitch32 = 160;
	frame->Width = 160;
	frame->Height = 152;
	frontend_time = frame->FrontendTime;
	storeB(0x6f82, frame->Buttons);

	ngpc_soundTS = 0;
	NGPFrameSkip = frame->SkipRendering;

	do
	{
		int32 timetime = (uint8)TLCS900h_interpret(); // This is sooo not right, but it's replicating the old behavior(which is necessary
													  // now since I've fixed the TLCS900h core and other places not to truncate cycle counts
													  // internally to 8-bits).  Switch to the #if 0'd block of code once we fix cycle counts in the
													  // TLCS900h core(they're all sorts of messed up), and investigate if certain long
													  // instructions are interruptable(by interrupts) and later resumable, RE Rockman Battle
		// & Fighters voice sample playback.

		//if(timetime > 255)
		// printf("%d\n", timetime);

		// Note: Don't call updateTimers with a time/tick/cycle/whatever count greater than 255.
		MeowMeow |= updateTimers(&surface, timetime);

		z80_runtime += timetime;

		while (z80_runtime > 0)
		{
			int z80rantime = Z80_RunOP();

			if (z80rantime < 0) // Z80 inactive, so take up all run time!
			{
				z80_runtime = 0;
				break;
			}

			z80_runtime -= z80rantime << 1;
		}
	} while (!MeowMeow);

	frame->Cycles = ngpc_soundTS;
	frame->Samples = MDFNNGPCSOUND_Flush(frame->SoundBuffer, 8192);
	frame->Lagged = lagged;
}
RegularBattleScene::RegularBattleScene(battledata_ptr dat, BattleDefaultTheme *theme, bool logNames) : mData(dat), unpausing(false),
    pauseCount(0), info(dat->numberOfSlots()), mLogNames(logNames)
{
    gui.theme = theme;

    /* Sets the bar in non-percentage mode for players */
    for (int i = 0; i < data()->numberOfSlots(); i++) {
        if (isPlayer(i)) {
            info.percentage[i] = false;
        }
    }

    setupGui();
    updateTimers();
}
Esempio n. 5
0
 /* FIXME, change to take TimeRecords ?? or not*/
void ClockDisplay::setTimeInfo(int btime, int bstones_periods, int wtime, int wstones_periods)
{
	/* FIXME DOUBLECHECK if this is allowed.  We want to be able
	 * to pass empty records but, this may not be the way to
	 * do it */
	if(wtime != 0 || wstones_periods != -1)
	{
		w_time = wtime;
		w_stones_periods = wstones_periods; 
	}
	if(btime != 0 || bstones_periods != -1)
	{ 
		b_time = btime;
		b_stones_periods = bstones_periods;
	}
	//printf("wb %d %d %d %d\n", w_time, b_time, w_stones_periods, b_stones_periods);
	updateTimers();
}
Esempio n. 6
0
void ClockDisplay::makeMove(bool black)
{
	if (black)
	{
		if(timeSystem == canadian && b_stones_periods != -1)
		{
			b_stones_periods--;
		}
	}
	else
	{
		if(timeSystem == canadian && w_stones_periods != -1)
		{
			w_stones_periods--;
		}
	}
	
	updateTimers();
}
Esempio n. 7
0
void ClockDisplay::rerackTime(bool black)
{
	if (black)
	{
		if(timeSystem == canadian && b_stones_periods == 0)
		{
			b_time = periodtime;
			b_stones_periods = periods;
		}
		else if(timeSystem == byoyomi && b_stones_periods != -1)
		{
			b_time = periodtime;
			//b_stones_periods = periods;
		}
		else if(timeSystem == tvasia)
		{
			b_time = maintime;
			b_stones_periods = -1;
		}
	}
	else
	{
		if(timeSystem == canadian && w_stones_periods == 0)
		{
			w_time = periodtime;
			w_stones_periods = periods;
		}
		else if(timeSystem == byoyomi && w_stones_periods != -1)
		{
			w_time = periodtime;
			//w_stones_periods = periods;
		}
		else if(timeSystem == tvasia)
		{
			w_time = maintime;
			w_stones_periods = -1;
		}
	}
	
	updateTimers();	
}
void RegularBattleScene::setupGui()
{
    int nslots = data()->numberOfSlots();

    gui.nick.resize(nslots);
    gui.level.resize(nslots);
    gui.gender.resize(nslots);
    gui.bars.resize(nslots);
    gui.status.resize(nslots);

    QVBoxLayout *l=  new QVBoxLayout(this);
    l->setMargin(0);

    /* As anyway the GraphicsZone is a fixed size, it's useless to
       resize that part, might as well let  the chat be resized */
    l->setSizeConstraint(QLayout::SetFixedSize);

    QHBoxLayout *firstLine = new QHBoxLayout();
    l->addLayout(firstLine);

    QHBoxLayout *midzone = new QHBoxLayout();
    l->addLayout(midzone);

    QHBoxLayout *lastLine = new QHBoxLayout();
    l->addLayout(lastLine);

    QVBoxLayout *teamAndName[2];

    for (int i = 0; i < 2; i++) {
        teamAndName[i] = new QVBoxLayout();
        teamAndName[i]->addLayout(createTeamLayout(gui.pokeballs[i]));
        teamAndName[i]->addWidget(gui.trainers[i] = new QLabel(data()->name(i)),0, Qt::AlignRight);
        gui.trainers[i]->setObjectName("TrainerNick");
    }

    firstLine->addWidget(gui.fullBars[opponent()] = createFullBarLayout(nslots, opponent()));
    firstLine->addLayout(teamAndName[opponent()]);

    gui.zone = new GraphicsZone(data(), gui.theme);

    /* Make the code below more generic? */
    QVBoxLayout *midme = new QVBoxLayout();
    midzone->addLayout(midme);
    midme->addStretch(100);
    gui.timers[myself()] = new QProgressBar();
    gui.timers[myself()]->setObjectName("TimeOut"); //for style sheets
    gui.timers[myself()]->setRange(0,300);
    QLabel *mybox = new QLabel();
    mybox->setObjectName("MyTrainerBox");
    mybox->setFixedSize(82,82);
    mybox->setPixmap(gui.theme->trainerSprite(data()->avatar(myself())));
    midme->addWidget(gui.timers[myself()]);
    midme->addWidget(mybox);

    midzone->addWidget(gui.zone);

    QVBoxLayout *midopp = new QVBoxLayout();
    midzone->addLayout(midopp);
    midopp->addStretch(100);
    gui.timers[opponent()] = new QProgressBar();
    gui.timers[opponent()]->setObjectName("TimeOut"); //for style sheets
    gui.timers[opponent()]->setRange(0,300);
    QLabel *oppbox = new QLabel();
    oppbox->setPixmap(gui.theme->trainerSprite(data()->avatar(opponent())));
    oppbox->setObjectName("OppTrainerBox");
    oppbox->setFixedSize(82,82);
    midopp->addWidget(oppbox);
    midopp->addWidget(gui.timers[opponent()]);

    lastLine->addLayout(teamAndName[myself()]);
    lastLine->addWidget(gui.fullBars[myself()] = createFullBarLayout(nslots, myself()));

    QTimer *t = new QTimer (this);
    t->start(200);
    connect(t, SIGNAL(timeout()), SLOT(updateTimers()));
}
Esempio n. 9
0
	void update()
	{
		updateTimers();
	}
Esempio n. 10
0
static void Emulate(EmulateSpecStruct *espec)
{
	bool MeowMeow = 0;

	espec->DisplayRect.x = 0;
	espec->DisplayRect.y = 0;
	espec->DisplayRect.w = 160;
	espec->DisplayRect.h = 152;

	if(espec->VideoFormatChanged)
	 NGPGfx->set_pixel_format(espec->surface->format);

	if(espec->SoundFormatChanged)
	 MDFNNGPC_SetSoundRate(espec->SoundRate);


	NGPJoyLatch = *chee;
	storeB(0x6F82, *chee);

	MDFNMP_ApplyPeriodicCheats();

	ngpc_soundTS = 0;
	NGPFrameSkip = espec->skip;

	do
	{
#if 0
         int32 timetime;

	 if(main_timeaccum == 0)
	 {
	  main_timeaccum = TLCS900h_interpret();
          if(main_timeaccum > 255)
	  {
	   main_timeaccum = 255;
           printf("%d\n", main_timeaccum);
	  }
	 }

	 timetime = std::min<int32>(main_timeaccum, 24);
	 main_timeaccum -= timetime;
#else
#if 0
	 uint32 old_pc = pc;
	 {
	  uint32 xix = gpr[0];
	  uint32 xiz = gpr[2];
	  printf("%08x %08x --- %s\n", xix, xiz, TLCS900h_disassemble());
	 }
	 pc = old_pc;
#endif

	 int32 timetime = (uint8)TLCS900h_interpret();	// This is sooo not right, but it's replicating the old behavior(which is necessary
							// now since I've fixed the TLCS900h core and other places not to truncate cycle counts
							// internally to 8-bits).  Switch to the #if 0'd block of code once we fix cycle counts in the
							// TLCS900h core(they're all sorts of messed up), and investigate if certain long
							// instructions are interruptable(by interrupts) and later resumable, RE Rockman Battle
							// & Fighters voice sample playback.
#endif
	 //if(timetime > 255)
	 // printf("%d\n", timetime);

	 // Note: Don't call updateTimers with a time/tick/cycle/whatever count greater than 255.
	 MeowMeow |= updateTimers(espec->surface, timetime);

	 z80_runtime += timetime;

         while(z80_runtime > 0)
	 {
	  int z80rantime = Z80_RunOP();

	  if(z80rantime < 0) // Z80 inactive, so take up all run time!
	  {
	   z80_runtime = 0;
	   break;
	  }

	  z80_runtime -= z80rantime << 1;

	 }
	} while(!MeowMeow);


	espec->MasterCycles = ngpc_soundTS;
	espec->SoundBufSize = MDFNNGPCSOUND_Flush(espec->SoundBuf, espec->SoundBufMaxSize);
}
Esempio n. 11
0
void emulate_debug(BOOL dis_TLCS900h, BOOL dis_Z80)
{
	_u32 storePC = pc;

	debug_abort_memory = FALSE;
	debug_abort_instruction = FALSE;

	system_debug_history_add();		//For the debugger

	if (dis_TLCS900h)
	{
		char* s;

		//Disassemble TLCS-900h
		_u32 oldpc = pc;
		s = disassemble();
		system_debug_message(s);
		system_debug_message_associate_address(oldpc);
		free(s);
		pc = oldpc;
	}

	if (dis_Z80)
	{
		//Disassemble Z80
		if (Z80ACTIVE)
		{
			char* s;
			_u16 pc = Z80_getReg(Z80_REG_PC);
			_u16 store_pc = pc;

			//Disassemble
			s = Z80_disassemble(&pc);
			system_debug_message(s);
			system_debug_message_associate_address(store_pc + 0x7000);
			free(s);
		}
	}

	debug_abort_memory = FALSE;
	debug_abort_instruction = FALSE;

	//==================
	// EMULATE
	//==================
	{
		//TLCS900h instruction
		updateTimers(TLCS900h_interpret());

		//Z80 Instruction
		if (Z80ACTIVE) Z80EMULATE;
	}
	
	//Check register code error
	if (rErr != RERR_VALUE)
		instruction_error("Invalid register code used.");

	//Memory Exception
	if (debug_abort_memory && filter_mem)
	{
		_u32 oldpc = pc;
		char* s;

		debug_abort_memory = FALSE;

		//Try to disassemble the erroneous instruction
		pc = storePC;
		debug_mask_memory_error_messages = TRUE;
		s = disassemble();
		debug_mask_memory_error_messages = FALSE;

		if (debug_abort_memory == FALSE)
		{
			system_debug_message("Stopped due to memory exception caused by");
			system_debug_message("     %s", s);
			system_debug_message_associate_address(storePC);
			system_debug_message("\n");
		}
		else
		{
			system_debug_message("Stopped due to memory exception caused at %06X", storePC);
			system_debug_message_associate_address(storePC);
		}
		free(s);
		pc = oldpc;
		
		system_debug_stop();
		system_debug_refresh();
		return;
	}

	//Unimplemented Instruction
	if (debug_abort_instruction)
	{
		_u32 oldpc = pc;
		char* s;

		debug_abort_memory = FALSE;

		//Try to disassemble the erroneous instruction
		pc = storePC;
		debug_mask_memory_error_messages = TRUE;
		s = disassemble();
		debug_mask_memory_error_messages = FALSE;

		if (debug_abort_memory == FALSE)
		{
			system_debug_message("Stopped due to instruction");
			system_debug_message("     %s", s);
			system_debug_message_associate_address(storePC);
			system_debug_message("\n");
		}
		else
		{
			system_debug_message("Stopped due to instruction at %06X", storePC);
			system_debug_message_associate_address(storePC);
		}
		free(s);
		pc = oldpc;
		
		system_debug_stop();
		system_debug_refresh();
		return;
	}
}
Esempio n. 12
0
void RegularBattleScene::setupGui()
{
    int nslots = data()->numberOfSlots();

    gui.nick.resize(nslots);
    gui.level.resize(nslots);
    gui.gender.resize(nslots);
    gui.bars.resize(nslots);
    gui.status.resize(nslots);

    QGridLayout *window = new QGridLayout(this);
    window->setSizeConstraint(QLayout::SetFixedSize);

    QVBoxLayout *team[2];
    QVBoxLayout *name[2];

    for (int i = 0; i < 2; i++) {
        team[i] = new QVBoxLayout();
        team[i]->addLayout(createTeamLayout(gui.pokeballs[i]));
        name[i] = new QVBoxLayout();
        name[i]->addWidget(gui.trainers[i] = new QLabel(data()->name(i)),0, Qt::AlignRight);
        gui.trainers[i]->setObjectName("TrainerNick");
    }

    gui.zone = new GraphicsZone(data(), gui.theme);

    /* Set up our data */
    QVBoxLayout *midme = new QVBoxLayout();
    gui.timers[myself()] = new QProgressBar();
    gui.timers[myself()]->setObjectName("TimeOut"); //for style sheets
    gui.timers[myself()]->setRange(0, data()->rated() ? ratedTime : unratedTime);
    QLabel *mybox = new QLabel();
    mybox->setObjectName("MyTrainerBox");
    mybox->setFixedSize(82,82);
    mybox->setPixmap(gui.theme->trainerSprite(data()->avatar(myself())));
    midme->addLayout(team[myself()]);    
    midme->addWidget(gui.timers[myself()]);
    midme->addWidget(mybox);
    midme->addLayout(name[myself()]);

    /* Set up Opponent's data */
    QVBoxLayout *midopp = new QVBoxLayout();
    gui.timers[opponent()] = new QProgressBar();
    gui.timers[opponent()]->setObjectName("TimeOut"); //for style sheets
    gui.timers[opponent()]->setRange(0, data()->rated() ? ratedTime : unratedTime);
    QLabel *oppbox = new QLabel();
    oppbox->setPixmap(gui.theme->trainerSprite(data()->avatar(opponent())));
    oppbox->setObjectName("OppTrainerBox");
    oppbox->setFixedSize(82,82);
    midopp->addLayout(name[opponent()]);
    midopp->addWidget(oppbox);    
    midopp->addWidget(gui.timers[opponent()]);
    midopp->addLayout(team[opponent()]);

    /* Field must be at least 215 pixels tall otherwise the side elements will collide, causing display issues */
    gui.zone->setMinimumSize(400,240);
    gui.zone->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    gui.zone->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    /* Arrange everything */
    window->addLayout(midopp,0,4,3,1,Qt::AlignTop);
    window->addWidget(gui.fullBars[opponent()] = createFullBarLayout(nslots, opponent()),0,1,1,3,Qt::AlignRight);
    window->addWidget(gui.zone,1,1,2,3);
    window->addWidget(gui.fullBars[myself()] = createFullBarLayout(nslots, myself()),3,1,1,3,Qt::AlignLeft);
    window->addLayout(midme,1,0,3,1,Qt::AlignBottom);

    QTimer *t = new QTimer (this);
    t->start(200);
    connect(t, SIGNAL(timeout()), SLOT(updateTimers()));
}
Esempio n. 13
0
/*
 * decrease the timer info according to the step, and updates the clocks
 */
void ClockDisplay::setTimeStep(bool black)
{
	if (black)
	{
		b_time--;
		if(b_time == 0 && b_stones_periods != 0)
		{
			/* FIXME, maybe we should have one clock and subclass
			 * the time system for different clocks??*/
			if(timeSystem == byoyomi || (timeSystem == tvasia && b_stones_periods != -1))
			{
				//printf("b by: %d %d %d %d\n", b_time, b_stones_periods, periodtime, periods);
				if(b_stones_periods > -1 || timeSystem == tvasia)
					b_stones_periods--;
				else
					b_stones_periods = periods;
				if(b_stones_periods != 0)
					b_time = periodtime;
			}
			else if(b_stones_periods == -1)
			{
				if(timeSystem == canadian)
				{
					b_time = periodtime;
					b_stones_periods = periods;
				}
				else if(timeSystem == tvasia)
				{
					b_time = periodtime;
					b_stones_periods = periods - 1;
				}
			}
			else
				printf("other timesystem\n");
			/* IGS gets here a lot due to lag.  I.e., canadian time steps down to 0 with stones
			 * still remainaining to be played, then opponent plays and turns out they have five
			 * seconds left or something.  Would be neat to adjust for lag or something. FIXME */
		}
		/* FIXME
		 * major thing, we need to get time to switch
		 * over into byoyomi time on IGS 
		 * I think the issue was that IGS sends a byoyomi entering
		 * message... */
	}
	else
	{
		w_time--;
		if(w_time == 0 && w_stones_periods != 0)
		{
			if(timeSystem == byoyomi || (timeSystem == tvasia && w_stones_periods != -1))
			{
				//printf("w by: %d %d %d %d\n", w_time, w_stones_periods, periodtime, periods);
				if(w_stones_periods > -1 || timeSystem == tvasia)
					w_stones_periods--;
				else
					w_stones_periods = periods;
				if(w_stones_periods != 0)
					w_time = periodtime;
			}
			else if(w_stones_periods == -1)
			{
				if(timeSystem == canadian)
				{
					w_time = periodtime;
					w_stones_periods = periods;
				}
				else if(timeSystem == tvasia)
				{
					w_time = periodtime;
					w_stones_periods = periods - 1;
				}
			}
			else
				printf("other timesystem\n");
		}
	}
	
	updateTimers();
}
// This function determines which command to issue next based on our
// policy decisions.
void policyManager(FILE *ofile)
{	
	command chosenCommand = WAIT;
	command nextCommand;
	bool isLegal = TRUE;
	int chosenPriority = -2;
	int comparePriority = 0;
	int chosenIndex;
	int queueIndex;
	
	// Check for a starving command and give it priority if it is legal.
	int starveCheck = findStarvation();
	if (starveCheck != -1)
	{
		chosenIndex = starveCheck;
		chosenCommand = findNextCommand(starveCheck);
		chosenPriority = 10;
		
		// Update starving struct with info
		starvationStatus.isCommandStarving = TRUE;
		starvationStatus.name = chosenCommand;
		starvationStatus.bank = requestQueue[chosenIndex].bank;
		
		// Determine and store window that is locked out to other banks
		calculateWindow(starvationStatus.name, starvationStatus.bank, &starvationStatus.lowerWindow, &starvationStatus.upperWindow);
		
		// If command is not legal assign a WAIT command and low priority.
		if (!isCommandLegal(chosenCommand, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].row, chosenIndex, TRUE))
		{
			chosenCommand = WAIT;
			chosenPriority = -1;
		}
	}
	else
	{
		// No starving requests.
		starvationStatus.isCommandStarving = FALSE;
	}
	
	// Look through queue and find highest priority legal commands.
	for (queueIndex = 0; queueIndex < 16; ++queueIndex)
	{
		// Array element must be valid and not the most starving request.
		if (requestQueue[queueIndex].occupied && 
			!requestQueue[queueIndex].finished && 
			queueIndex != starveCheck)
		{
			nextCommand = findNextCommand(queueIndex);
			
			isLegal = isCommandLegal(nextCommand, 
				requestQueue[queueIndex].bank, 
				requestQueue[queueIndex].row,
				queueIndex, FALSE);
				
			// Skip illegal commands.
			if (!isLegal)
				continue;
				
			// Assign priority based on command.
			switch(nextCommand)
			{
				case PRE :
					comparePriority = prechargePriority(queueIndex);
					break;
					
				case ACT :
					comparePriority = 2;
					break;
				
				case RD :
					comparePriority = 4;
					break;
					
				case WR :
					comparePriority = 4;
					break;
					
				case WAIT:
					comparePriority = -1;
					
				default :
				printf("\nERROR: Unknown Command\n");
			}

			// Keep highest priority command.
			if (comparePriority > chosenPriority)
			{
				chosenPriority = comparePriority;
				chosenIndex = queueIndex;
				chosenCommand = nextCommand;
			}
			// The oldest request wins if priority tie.
			else if (comparePriority == chosenPriority)
			{
				if (requestQueue[queueIndex].timeIssued < 
					requestQueue[chosenIndex].timeIssued)
				{
					chosenIndex = queueIndex;
					chosenCommand = nextCommand;
				}
			}		
		}
	}
	
	// Print the correct output based on command chosen.
	switch (chosenCommand)
	{
		case PRE:
			fprintf(ofile, "%llu\tPRE\t%d\n", currentCPUTick, requestQueue[chosenIndex].bank);
			updateDimmStatus(chosenCommand, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].row);
			updateTimers(chosenCommand, requestQueue[chosenIndex].bank);
		break;
		
		case ACT:
			fprintf(ofile, "%llu\tACT\t%d\t%d\n", currentCPUTick, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].row);
			updateDimmStatus(chosenCommand, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].row);
			updateTimers(chosenCommand, requestQueue[chosenIndex].bank);
		break;
		
		case RD:
			fprintf(ofile, "%llu\tRD\t%d\t%d\n", currentCPUTick, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].column);
			requestQueue[chosenIndex].finished = TRUE;
			// Read requests will stay until data is finished.
			requestQueue[chosenIndex].timeRemaining = tCAS + tBURST;
			updateDimmStatus(chosenCommand, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].row);
			updateTimers(chosenCommand, requestQueue[chosenIndex].bank);
		break;
		
		case WR:
			fprintf(ofile, "%llu\tWR\t%d\t%d\n", currentCPUTick, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].column);
			requestQueue[chosenIndex].finished = TRUE;
			requestQueue[chosenIndex].occupied = FALSE;
			countSlotsOccupied -= 1;
			updateDimmStatus(chosenCommand, requestQueue[chosenIndex].bank, requestQueue[chosenIndex].row);
			updateTimers(chosenCommand, requestQueue[chosenIndex].bank);
		break;
			
		default:
			//printf("CPU:%llu ---\n", currentCPUTick);
			incrementTimers(1);
		break;
	}
	
}