void BuddyModel::addBuddy(Vreen::Buddy *contact) { if (!checkContact(contact)) return; int index = Vreen::lowerBound(m_buddyList, contact, m_buddyComparator); beginInsertRows(QModelIndex(), index, index); m_buddyList.insert(index, contact); endInsertRows(); }
void BuddyModel::addFriend(Vreen::Buddy *contact) { if (!checkContact(contact)) return; int index = m_buddyList.count(); beginInsertRows(QModelIndex(), index, index); m_buddyList.insert(index, contact); endInsertRows(); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); }
void BuddyModel::setFilterByName(const QString &filter) { m_filterByName = filter; emit filterByNameChanged(filter); Vreen::BuddyList list; foreach (auto buddy, m_roster->buddies()) { if (checkContact(buddy)) { auto it = qLowerBound(list.begin(), list.end(), buddy, m_buddyComparator); list.insert(it, buddy); } } setBuddies(list); }
void DisplayContestContact::processMinosStanza( const std::string &methodName, MinosTestImport * const mt ) { std::string updtg; int itemp; if ( mt->getStructArgMemberValue( "lseq", itemp ) ) // should already be done... logSequence = ( unsigned long ) itemp; mt->getStructArgMemberValueDTG( "uDTG", updtg ); if ( methodName == "MinosLogComment" ) { std::string ctime; mt->getStructArgMemberValueDTG( "logTime", ctime ); time.setIsoDTG( ctime ); bool btemp = false; unsigned short cf = contactFlags.getValue(); if ( mt->getStructArgMemberValue( "LocalComment", btemp ) ) mt->setBit( cf, LOCAL_COMMENT, btemp ); if ( mt->getStructArgMemberValue( "dontPrint", btemp ) ) mt->setBit( cf, DONT_PRINT, btemp ); contactFlags.setInitialValue( cf ); mt->getStructArgMemberValue( "comment", comments ); } else if ( methodName == "MinosLogQSO" ) { modificationCount++; updtime.setIsoDTG( updtg ); std::string ctime; if ( mt->getStructArgMemberValueDTG( "logTime", ctime ) ) time.setIsoDTG( ctime ); unsigned short cf = contactFlags.getValue(); bool btemp = false; if ( mt->getStructArgMemberValue( "validDistrict", btemp ) ) mt->setBit( cf, VALID_DISTRICT, btemp ); mt->setBit( cf, VALID_DISTRICT, btemp ); if ( mt->getStructArgMemberValue( "countryForced", btemp ) ) mt->setBit( cf, COUNTRY_FORCED, btemp ); if ( mt->getStructArgMemberValue( "unknownCountry", btemp ) ) mt->setBit( cf, UNKNOWN_COUNTRY, btemp ); if ( mt->getStructArgMemberValue( "nonScoring", btemp ) ) mt->setBit( cf, NON_SCORING, btemp ); if ( mt->getStructArgMemberValue( "manualScore", btemp ) ) mt->setBit( cf, MANUAL_SCORE, btemp ); if ( mt->getStructArgMemberValue( "dontPrint", btemp ) ) mt->setBit( cf, DONT_PRINT, btemp ); if ( mt->getStructArgMemberValue( "validDuplicate", btemp ) ) mt->setBit( cf, VALID_DUPLICATE, btemp ); if ( mt->getStructArgMemberValue( "toBeEntered", btemp ) ) mt->setBit( cf, TO_BE_ENTERED, btemp ); if ( mt->getStructArgMemberValue( "xBand", btemp ) ) mt->setBit( cf, XBAND, btemp ); if ( mt->getStructArgMemberValue( "Forced", btemp ) ) mt->setBit( cf, FORCE_LOG, btemp ); contactFlags.setInitialValue( cf ); mt->getStructArgMemberValue( "modeTx", mode ); mt->getStructArgMemberValue( "rstTx", reps ); mt->getStructArgMemberValue( "serialTx", serials ); mt->getStructArgMemberValue( "exchangeTx", contest->location ); mt->getStructArgMemberValue( "modeRx", mode ); mt->getStructArgMemberValue( "callRx", cs.fullCall ); mt->getStructArgMemberValue( "rstRx", repr ); mt->getStructArgMemberValue( "serialRx", serialr ); mt->getStructArgMemberValue( "exchangeRx", extraText ); if ( mt->getStructArgMemberValue( "locRx", loc.loc ) ) loc.validate(); mt->getStructArgMemberValue( "commentsTx", comments ); mt->getStructArgMemberValue( "commentsRx", comments ); mt->getStructArgMemberValue( "power", contest->power ); mt->getStructArgMemberValue( "band", contest->band ); mt->getStructArgMemberValue( "claimedScore", contactScore ); mt->getStructArgMemberValue( "forcedMult", forcedMult ); mt->getStructArgMemberValue( "op1", op1 ); mt->getStructArgMemberValue( "op2", op2 ); int maxct = atoi( serials.getValue().c_str() ); if ( maxct > contest->maxSerial ) contest->maxSerial = maxct; contest->validationPoint = this; checkContact(); // processMinosStanza - Do we need to? scanContest will repeat it. Except we push the contact in it's current state into history BaseContact bc( *this ); // this should get it now?? getHistory().push_back( bc ); } }
void FootBumperStateProvider::update(FootBumperState& footBumperState) { // Check, if any bumper is pressed const bool leftFootLeft = !theDamageConfigurationBody.sides[Legs::left].footBumperDefect && checkContact(KeyStates::leftFootLeft, leftFootLeftDuration); const bool leftFootRight = !theDamageConfigurationBody.sides[Legs::left].footBumperDefect && checkContact(KeyStates::leftFootRight, leftFootRightDuration); const bool rightFootLeft = !theDamageConfigurationBody.sides[Legs::right].footBumperDefect && checkContact(KeyStates::rightFootLeft, rightFootLeftDuration); const bool rightFootRight = !theDamageConfigurationBody.sides[Legs::right].footBumperDefect && checkContact(KeyStates::rightFootRight, rightFootRightDuration); const bool contactLeftFoot = leftFootLeft || leftFootRight; const bool contactRightFoot = rightFootLeft || rightFootRight; // Update statistics if(contactLeftFoot) { contactBufferLeft.push_front(1); contactDurationLeft++; } else { contactBufferLeft.push_front(0); contactDurationLeft = 0; } if(contactRightFoot) { contactBufferRight.push_front(1); contactDurationRight++; } else { contactBufferRight.push_front(0); contactDurationRight = 0; } // Generate model if((theMotionInfo.motion == MotionInfo::stand || theMotionInfo.motion == MotionInfo::walk) && (theGameInfo.state == STATE_READY || theGameInfo.state == STATE_SET || theGameInfo.state == STATE_PLAYING) && //The bumper is used for configuration in initial (theFallDownState.state == FallDownState::upright)) { if(contactBufferLeft.sum() > contactThreshold) { footBumperState.status[Legs::left].contact = true; footBumperState.status[Legs::left].contactDuration = contactDurationLeft; if(contactLeftFoot) footBumperState.status[Legs::left].lastContact = theFrameInfo.time; } else { footBumperState.status[Legs::left].contact = false; footBumperState.status[Legs::left].contactDuration = 0; } if(contactBufferRight.sum() > contactThreshold) { footBumperState.status[Legs::right].contact = true; footBumperState.status[Legs::right].contactDuration = contactDurationRight; if(contactRightFoot) footBumperState.status[Legs::right].lastContact = theFrameInfo.time; } else { footBumperState.status[Legs::right].contact = false; footBumperState.status[Legs::right].contactDuration = 0; } } else { footBumperState.status[Legs::left].contact = false; footBumperState.status[Legs::right].contact = false; footBumperState.status[Legs::left].contactDuration = 0; footBumperState.status[Legs::right].contactDuration = 0; } // Debugging stuff: if(debug && theFrameInfo.getTimeSince(lastSoundTime) > (int)soundDelay && (footBumperState.status[Legs::left].contact || footBumperState.status[Legs::right].contact)) { lastSoundTime = theFrameInfo.time; SystemCall::playSound("jump.wav"); } PLOT("module:FootBumperStateProvider:sumLeft", contactBufferLeft.sum()); PLOT("module:FootBumperStateProvider:durationLeft", contactDurationLeft); PLOT("module:FootBumperStateProvider:sumRight", contactBufferRight.sum()); PLOT("module:FootBumperStateProvider:durationRight", contactDurationRight); PLOT("module:FootBumperStateProvider:contactLeft", footBumperState.status[Legs::left].contact ? 10 : 0); PLOT("module:FootBumperStateProvider:contactRight", footBumperState.status[Legs::right].contact ? 10 : 0); PLOT("module:FootBumperStateProvider:leftFootLeft", leftFootLeft ? 10 : 0); PLOT("module:FootBumperStateProvider:leftFootRight", leftFootRight ? 10 : 0); PLOT("module:FootBumperStateProvider:rightFootLeft", rightFootLeft ? 10 : 0); PLOT("module:FootBumperStateProvider:rightFootRight", rightFootRight ? 10 : 0); }
void FootContactModelProvider::update(FootContactModel& model) { MODIFY("module:FootContactModelProvider:parameters", p); // Check, if any bumper is pressed bool leftFootLeft = checkContact(KeyStates::leftFootLeft, leftFootLeftDuration); bool leftFootRight = checkContact(KeyStates::leftFootRight, leftFootRightDuration); bool rightFootLeft = checkContact(KeyStates::rightFootLeft, rightFootLeftDuration); bool rightFootRight = checkContact(KeyStates::rightFootRight, rightFootRightDuration); // Update statistics if (leftFootLeft || leftFootRight) { contactBufferLeft.add(1); contactDurationLeft++; } else { contactBufferLeft.add(0); contactDurationLeft = 0; } if (rightFootLeft || rightFootRight) { contactBufferRight.add(1); contactDurationRight++; } else { contactBufferRight.add(0); contactDurationRight = 0; } // Generate model if ((theMotionInfo.motion == MotionInfo::stand || theMotionInfo.motion == MotionInfo::walk) && (theGameInfo.state == STATE_READY || theGameInfo.state == STATE_SET || theGameInfo.state == STATE_PLAYING) && //The bumper is used for configuration in initial (theFallDownState.state == FallDownState::upright)) { if(contactBufferLeft.getSum() > p.contactThreshold) { model.contactLeft = true; model.contactDurationLeft = contactDurationLeft; model.lastContactLeft = theFrameInfo.time; } else { model.contactLeft = false; model.contactDurationLeft = 0; } if(contactBufferRight.getSum() > p.contactThreshold) { model.contactRight = true; model.contactDurationRight = contactDurationRight; model.lastContactRight = theFrameInfo.time; } else { model.contactRight = false; model.contactDurationRight = 0; } } else { model.contactLeft = false; model.contactRight = false; model.contactDurationLeft = 0; model.contactDurationRight = 0; } // Debugging stuff: if(p.debug && theFrameInfo.getTimeSince(lastSoundTime) > (int)p.soundDelay && (model.contactLeft || model.contactRight)) { lastSoundTime = theFrameInfo.time; SoundPlayer::play("doh.wav"); } DECLARE_PLOT("module:FootContactModelProvider:sumLeft"); DECLARE_PLOT("module:FootContactModelProvider:durationLeft"); DECLARE_PLOT("module:FootContactModelProvider:contactLeft"); DECLARE_PLOT("module:FootContactModelProvider:sumRight"); DECLARE_PLOT("module:FootContactModelProvider:durationRight"); DECLARE_PLOT("module:FootContactModelProvider:contactRight"); DECLARE_PLOT("module:FootContactModelProvider:leftFootLeft"); DECLARE_PLOT("module:FootContactModelProvider:leftFootRight"); DECLARE_PLOT("module:FootContactModelProvider:rightFootLeft"); DECLARE_PLOT("module:FootContactModelProvider:rightFootRight"); PLOT("module:FootContactModelProvider:sumLeft", contactBufferLeft.getSum()); PLOT("module:FootContactModelProvider:durationLeft", contactDurationLeft); PLOT("module:FootContactModelProvider:sumRight", contactBufferRight.getSum()); PLOT("module:FootContactModelProvider:durationRight", contactDurationRight); PLOT("module:FootContactModelProvider:contactLeft", model.contactLeft ? 10 : 0); PLOT("module:FootContactModelProvider:contactRight", model.contactRight ? 10 : 0); PLOT("module:FootContactModelProvider:leftFootLeft", leftFootLeft ? 10 : 0); PLOT("module:FootContactModelProvider:leftFootRight", leftFootRight ? 10 : 0); PLOT("module:FootContactModelProvider:rightFootLeft", rightFootLeft ? 10 : 0); PLOT("module:FootContactModelProvider:rightFootRight", rightFootRight ? 10 : 0); }
int main( int argc, char* args[] ) { SDL_Color BACKGROUND_COLOR = SDL_Color(); BACKGROUND_COLOR.r = 0; BACKGROUND_COLOR.g = 0; BACKGROUND_COLOR.b = 0; BACKGROUND_COLOR.a = 255; SDL_Color HUNTER_COLOR = SDL_Color(); HUNTER_COLOR.r = 255; HUNTER_COLOR.g = 0; HUNTER_COLOR.b = 0; HUNTER_COLOR.a = 255; SDL_Color BOUND_COLOR = SDL_Color(); BOUND_COLOR.r = 0; BOUND_COLOR.g = 255; BOUND_COLOR.b = 0; BOUND_COLOR.a = 255; SDL_Color PREY_COLOR = SDL_Color(); PREY_COLOR.r = 0; PREY_COLOR.g = 0; PREY_COLOR.b = 255; PREY_COLOR.a = 255; // Init GUI SDL_Window *screen = NULL; if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) { std::cout << "Error on SDL_Init:" << std::endl << SDL_GetError() << std::endl; return 1; } screen = SDL_CreateWindow(WINDOW_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0); if( screen == NULL ) { std::cout << "Error on SDL_CreateWindow:" << std::endl << SDL_GetError() << std::endl; return 1; } SDL_Renderer* bgRenderer = NULL; bgRenderer = SDL_CreateRenderer( screen, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if( bgRenderer == NULL ) { std::cout << "Error on SDL_CreateRenderer:" << std::endl << SDL_GetError() << std::endl; return 1; } // Define QLAgent QLAgent<QLAction,QLState>::qlt table; if(std::ifstream(FILENAME)) { loadQLTable(table,FILENAME); } const std::vector<QLAction> actionVec { Entity::UP, Entity::DOWN, Entity::LEFT, Entity::RIGHT, Entity::IDLE }; QLAgent<QLAction,QLState> preyAgent = QLAgent<QLAction,QLState>([&actionVec](QLState u){return actionVec;} , table); preyAgent.setQLParameters(CAP, LR, DF, GVR); // Inizialization SDL_Rect bounds = SDL_Rect(); bounds.x = BOUND_MIN_X; bounds.y = BOUND_MIN_Y; bounds.w = BOUND_MAX_X - BOUND_MIN_X; bounds.h = BOUND_MAX_Y - BOUND_MIN_Y; Entity hunter = Entity( HUNTER_WIDTH, HUNTER_HEIGHT, HUNTER_SPEED, HUNTER_START_X, HUNTER_START_Y, bounds, HUNTER_COLOR ); Entity prey = Entity( PREY_WIDTH, PREY_HEIGHT, PREY_SPEED, PREY_START_X, PREY_START_Y, bounds, PREY_COLOR ); preyAgent.setCurrentState(dataToQLState(hunter,prey)); // Render clr(bgRenderer,BACKGROUND_COLOR); renderRect(bounds, BOUND_COLOR, bgRenderer, false); renderEntity(hunter, bgRenderer); renderEntity(prey, bgRenderer); SDL_RenderPresent(bgRenderer); // TIMERS SDL_TimerID renderTimerId = SDL_AddTimer(TIME_GAP_RENDER, render_callback, NULL); if( renderTimerId == 0 ) { std::cout << "Error on SDL_AddTimer:" << std::endl << SDL_GetError() << std::endl; return 1; } SDL_TimerID movementTimerId = SDL_AddTimer(TIME_GAP_MOVEMENT, movement_callback, NULL); if( movementTimerId == 0 ) { std::cout << "Error on SDL_AddTimer:" << std::endl << SDL_GetError() << std::endl; return 1; } // main cycle //// structure to read user events SDL_Event event; //// to check when the key is pressed or released bool isKeyPressed[4] = { false, false, false, false }; bool quit = false; int matchCounter = 0; while( quit == false ) { bool matchIsOver = false; matchCounter++; // int moveCounter = 0; // int succesCounter = 0; while(!matchIsOver) { // event handling while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_QUIT: quit = true; break; case SDL_KEYDOWN: // Keyboard input handling - keydown checkKeyPressed( event.key.keysym.sym, isKeyPressed, true ); break; case SDL_KEYUP: // Keyboard input handling - keyup checkKeyPressed( event.key.keysym.sym, isKeyPressed, false ); break; case SDL_USEREVENT: switch(event.user.code) { case RENDER_CB: // Render clr(bgRenderer,BACKGROUND_COLOR); renderRect(bounds, BOUND_COLOR, bgRenderer, false); renderEntity(hunter, bgRenderer); renderEntity(prey, bgRenderer); SDL_RenderPresent(bgRenderer); break; case MOVEMENT_CB: // Entities movement hunter.move( actHunter(hunter,prey) ); //userMovement(prey, isKeyPressed); prey.move( preyAgent.chooseAction() ); // check contact if( checkContact( hunter, prey ) ) { hunter.reset(); prey.reset(); preyAgent.update(dataToQLState(hunter,prey), CATCH_REWARD); matchIsOver = true; } else { preyAgent.update(dataToQLState(hunter,prey), SURVIVE_REWARD); } break; } break; default: break; } } // // moveCounter++; // // hunter.move( actHunter(hunter,prey) ); // //userMovement(prey, isKeyPressed); // // prey.move( preyAgent.chooseAction() ); // // // check contact // if( checkContact( hunter, prey ) ) { // hunter.reset(); // prey.reset(); // preyAgent.update(dataToQLState(hunter,prey), CATCH_REWARD); // matchIsOver = true; // } // else { // preyAgent.update(dataToQLState(hunter,prey), SURVIVE_REWARD); // } // // if(matchCounter%10000 == 0) { std::cout << matchCounter << std::endl; } // if(matchCounter%100000 == 0) { quit = true; } // if(moveCounter == 1000) { succesCounter++; matchIsOver = true; } // if(succesCounter == 100) { std::cout << "SUCCESS!!!" << std::endl; } } } std::cout << "states in table: " << table.size() << std::endl; saveQLTable(table,FILENAME); SDL_Quit(); return 0; }
int main( int argc, char* args[] ) { SDL_Color BACKGROUND_COLOR = SDL_Color(); BACKGROUND_COLOR.r = 0; BACKGROUND_COLOR.g = 0; BACKGROUND_COLOR.b = 0; BACKGROUND_COLOR.a = 255; SDL_Color HUNTER_COLOR = SDL_Color(); HUNTER_COLOR.r = 255; HUNTER_COLOR.g = 0; HUNTER_COLOR.b = 0; HUNTER_COLOR.a = 255; SDL_Color BOUND_COLOR = SDL_Color(); BOUND_COLOR.r = 0; BOUND_COLOR.g = 255; BOUND_COLOR.b = 0; BOUND_COLOR.a = 255; SDL_Color PREY_COLOR = SDL_Color(); PREY_COLOR.r = 0; PREY_COLOR.g = 0; PREY_COLOR.b = 255; PREY_COLOR.a = 255; // Init GUI SDL_Window *screen = NULL; if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) { std::cout << "Error on SDL_Init:" << std::endl << SDL_GetError() << std::endl; return 1; } screen = SDL_CreateWindow(WINDOW_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0); if( screen == NULL ) { std::cout << "Error on SDL_CreateWindow:" << std::endl << SDL_GetError() << std::endl; return 1; } SDL_Renderer* bgRenderer = NULL; bgRenderer = SDL_CreateRenderer( screen, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if( bgRenderer == NULL ) { std::cout << "Error on SDL_CreateRenderer:" << std::endl << SDL_GetError() << std::endl; return 1; } // Define neural network LinearNeuralNetwork nn = LinearNeuralNetwork( 0, { 1 }, NULL, NULL ); if(std::ifstream(FILENAME)) { nn = LinearNeuralNetwork( FILENAME, Neuron::SIGMOID, Neuron::SIGMOID_DER ); } else { nn = LinearNeuralNetwork( ALPHA, NEURAL_NETWORK_DESCRIPTOR, Neuron::SIGMOID, Neuron::SIGMOID_DER ); } // Inizialization SDL_Rect bounds = SDL_Rect(); bounds.x = BOUND_MIN_X; bounds.y = BOUND_MIN_Y; bounds.w = BOUND_MAX_X - BOUND_MIN_X; bounds.h = BOUND_MAX_Y - BOUND_MIN_Y; Entity hunter = Entity( HUNTER_WIDTH, HUNTER_HEIGHT, HUNTER_SPEED, HUNTER_START_X, HUNTER_START_Y, bounds, HUNTER_COLOR ); Entity prey = Entity( PREY_WIDTH, PREY_HEIGHT, PREY_SPEED, PREY_START_X, PREY_START_Y, bounds, PREY_COLOR ); // Render clr(bgRenderer,BACKGROUND_COLOR); renderRect(bounds, BOUND_COLOR, bgRenderer, false); renderEntity(hunter, bgRenderer); renderEntity(prey, bgRenderer); SDL_RenderPresent(bgRenderer); // TIMERS SDL_TimerID renderTimerId = SDL_AddTimer(TIME_GAP_RENDER, render_callback, NULL); if( renderTimerId == 0 ) { std::cout << "Error on SDL_AddTimer:" << std::endl << SDL_GetError() << std::endl; return 1; } SDL_TimerID movementTimerId = SDL_AddTimer(TIME_GAP_MOVEMENT, movement_callback, NULL); if( movementTimerId == 0 ) { std::cout << "Error on SDL_AddTimer:" << std::endl << SDL_GetError() << std::endl; return 1; } // main cycle //// structure to read user events SDL_Event event; //// to check when the key is pressed or released bool isKeyPressed[4] = { false, false, false, false }; bool quit = false; while( quit == false ) { bool matchIsOver = false; while(!matchIsOver) { // event handling while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_QUIT: quit = true; break; case SDL_KEYDOWN: // Keyboard input handling - keydown checkKeyPressed( event.key.keysym.sym, isKeyPressed, true ); break; case SDL_KEYUP: // Keyboard input handling - keyup checkKeyPressed( event.key.keysym.sym, isKeyPressed, false ); break; case SDL_USEREVENT: switch(event.user.code) { case RENDER_CB: // Render clr(bgRenderer,BACKGROUND_COLOR); renderRect(bounds, BOUND_COLOR, bgRenderer, false); renderEntity(hunter, bgRenderer); renderEntity(prey, bgRenderer); SDL_RenderPresent(bgRenderer); break; case MOVEMENT_CB: int initialDistance = dist(hunter,prey); // Entities movement hunter.move( actHunter(hunter,prey) ); //userMovement(prey, isKeyPressed); // DEBUG std::vector<float> outputNn = outPrey( hunter, prey, nn ); Entity::Action preyAction = actPrey( outputNn ); prey.move( preyAction ); // check contact if( checkContact( hunter, prey ) ) { std::vector<float> err (5, 0); err[preyAction] = - REWARD_CAPTURE * outputNn[preyAction]; nn.learn( err ); matchIsOver = true; } else { int distance = dist(hunter, prey); // std::cout << "distances" << distance << " " << initialDistance << std::endl; std::vector<float> err (5, 0); if( distance > initialDistance ) { err[preyAction] = ( 1 - outputNn[preyAction] ) * REWARD_DISTANCE; } else if( distance < initialDistance ) { err[preyAction] = - outputNn[preyAction] * REWARD_DISTANCE; } nn.learn( err ); } break; // default: // std::cout << "!!! UserEvent code not defined!!!" << std::endl; // return 1; //break; } break; default: break; } } } hunter.reset(); prey.reset(); } SDL_Quit(); return 0; }