*]7Z!OG' 7bRbSbTbUbVbWbXbYbZb[b^b_b`babblcldlelflglhliljlk+++Z[}}     NoneCount CanPerformGetItem HtmlEncode ShowPageAdd WebIncludeMapIsChanging AccessDenied ShowMessage FindTagIdGetTag StatusErrorCore XWebAdminSystem FindByName InsertAt SaveAdminsRemoveGetGetPrivsTable StatusOk NextPrivNoneQuery MapTitle HyperLink CopyFromId AddMessage FixPrivs MakeMenuRowEngineDeleteElement FindItemId ShowFrameServerChangeMapReloadExcludeMapsNone MoveFromId ContainsNoneGenerateMapListSelectCanManageUserAddSortedElement ValidNameNone SetGamePIReset UsedMutators NextMessage ValidPass DefaultPage AddGroupFindPlayingBotQueryRestartPageReloadIncludeMapsTitleSayConsoleInit GetMapListGenerateGameTypeOptions MoveFrom ShiftStrictFormatMessageSetAt ArrayItem HasURLOptionGenerateMapListOptions ApplyMapList LoadMutatorsQuerySubmitRestartPageQueryHeaderPageQueryRootFrameLoadQueryHandlers ValidMaskQueryDefaultsIPPolicyQueryDefaultsRulesQueryDefaultsMapsQueryDefaultsMenuQueryDefaults GetTeamName GetTeamColorQueryCurrentBotsQueryCurrentMutatorsQueryCurrentConsoleSendQueryCurrentConsoleLogQueryCurrentConsoleQueryCurrentGameQueryCurrentPlayersQueryCurrentMenuQueryCurrentFrameGetGroupOptionsMakePrivsTable ManagedUsers GetPrivsItemGetPrivsHeaderGetGroupsForBrowseGetHumanReadableNameGetUsersForBrowseQueryGroupsEditPageQueryGroupsAddPageQueryGroupsBrowsePageQueryUsersMGroupsPageQueryUsersGroupsPageQueryUsersEditPageQueryUsersAddPageQueryUsersBrowsePageQueryUserAccountPageQueryUsersHomePageQueryAdminsMenuQueryAdminsFrameDump CopyFrom LastMessageNoneUTServerAdminLoadGameTypesUWeb MaxSecLevelCanManageGroup RemoveGroup ServerTravelSetSizeGetUser AdminLogout CopyItemToRunTestMoveElementDownMoveElementUp FindItem AddElement Checkbox StatusReport Destroyed PreBeginPlayUserMainPadLefthtmHighlightedBG DefaultBG RestartPage MessagePage HeaderPage RootFrameQueryHandlerClassesSpectatorType AdminRealmNotePolicyPageNoteRulesPage NoteMapsPageDefaultsRestartPageDefaultsIPPolicyPageDefaultsRulesPageDefaultsMapsPage AdminLoginNoneDefaultsIndexPageConsoleCommandKickBanPlayerGetLoggedAdmin NoteBotsPageNoteMutatorsPageNoteConsolePageNotePlayersPage AllowPriv NoteGamePageDefaultSendTextCurrentRestartPageCurrentBotsPageCurrentMutatorsPageCurrentConsoleSendPageCurrentConsoleLogPageCurrentConsolePageCurrentGamePage GameHasEndedClientGameEndedCurrentPlayersPageClientVoiceMessageCurrentIndexPage GetItemName TeamMessageTeamSayCopyToNoteMGroupAccessPageNoteGroupAccessPageNoteGroupsBrowsePageNoteGroupEditPageNoteGroupAddPageNoteUsersBrowsePageNoteUserEditPageNoteUserAddPageNoteAccountPageNoteUserHomePageGroupsEditPageGroupsBrowsePageGroupsAddPageUsersMGroupsPageUsersGroupsPageUsersEditPageUsersBrowsePage UsersAddPageUsersAccountPageUsersHomePageAdminsIndexPage RowGroupbLocalizedMessagesbTeamMessagesbClientMessagesReceivedMsgMax SetPrivsPlayerMessagexWebQueryDefaults UnlinkUsers HasPrivilege CreateGroupReceiveLocalizedMessageClientMessage BroadcastxWebQueryCurrentxWebQueryHandlerxWebQueryAdminsxWebAdminCommandLetAddManagedGroupRedoMergedPrivsUTServerAdminSpectatorUTImageServer StringArraySortedStringArraySortedObjectArray UnlinkGroupsCreate ObjectArray listitem AddNamedBotMatchInProgress ForceAddBot PostQuery PreQueryFailAuthenticationSendCachedFile ImageServer WebServerRequest Response ListenPortNoneURISubst ClearSubst IncludeUHTMLoadParsedUHTMWebApplication WebRequestNone GetVariableGetVariableCountGetVariableNumber WebResponseNone Messages Spectator UnrealGame DeathMatchUnrealMPGameInfo MinPlayersGameReplicationInfo bTournamentkTagsXGame SpeciesTypexUtilxBotMutatorRecord PlayerRecord DefaultNameSpeciesPlayerRecords SpeciesNameRowsServergnamePage bReadOnlyTest ControllerSortContent SubPrivs moveCountNoneBotListNonePlayerController TeamInfo AllMutatorsbSaveCanEdit BaseMutatorNoneMutator MainPrivsMapsupassPlayerReplicationInfo GameInfo GameName PlayerIDM LevelInfoManagedGroups MergedPrivsPRINumBotsprivsNextMsgLastMsg bMasterAdmin GameSecLevel PrivilegesbVoiceMessagesPrev NumPlayers MapPrefixLevelNone ReturnValuePawn NeededPrivsbotnameParamblogfilter PlayerListstrSplitStringToArrayNoneNoneNonebGlobal SecLevel ExtraPriv Grouping RenderType DisplayName SettingName PlayInfoDataNoneMin bCheckedMenubEnableStatLoggingfirst GameTypeIPScorePinguprivsugrpErrMsg PlayerNameValue GrpNames GroupRowsGrpNamebModifyDataMaxPgprivsgsecNoneTextOutStr CanDeleteNextOptionalObjectcondNone RelatedPRI_2 RelatedPRI_1NonePMbNoEditNonemaxcolsNoneNoneNoneNoneNone bCanEdit PlayInfoPlayer oldprivsmyprivs GetNextIntgrpselGetPlayerNetworkAddress MessageIDIdTargetnextController bIsPlayer bEnabled messagetype RecipientNonepriv ScriptTextMaskunameIndex SpeciesNamesMapNamepos GetUrlOptionPlayerListSubstTempStrTempTag TempDataKickButtonText TableHeadersCols bCanKickbCanBan UpdateURL ExcludeMaps IncludeMaps MovedMaps NewGameTypeSwitchButtonName bMakeChanges GroupNameSendStr bUserAdded LogSubstLogStrGroup bDeleteMeNoneselectedmutes lastgroup nextgroup thisgroupNoneGroupedMutatorsURLNone BotCountmaxbots oldstate bInMatchDMActorxPrivilegeBasexAdminUserList Password UsernameB IPPolicies AllPrivs PrivManagersGroupsUsers IsDemoBuild xAdminUserPageStrxAdminGroupListPath xAdminGroup XAdminBasebMarkedMarkMapList policies LocalMessageNextURLControllerListGameQueryHandlers CurAdminGamePI AGameType AExcMutators AIncMutatorsRespEngineVersionNoneNone bReadyToPlay bIsSpectatorNone ShortNameMessagingSpectatorQHQHCAccessControl GroupPageParmsDis CurPageTitleNoneDynamicLoadObject ClassName bConflict Conflicts Settingssmap Commandlet Descriptionfile NewStateNoneNone GameClassNoneSrcNoneOptionsAMaps ColorNamesMessageExMaps TeamIndexTagCurrentGameType SelectedStr OptionStrjNoneNoneNoneNone ResponseStrOuteri ParamNameClassPackageSwitchNone FriendlyName NextMutator ErrorMessageSuccessMessage TextBufferObject FunctionhlinkStructNoneNoneNoneTeam StrProperty bJustMovedType NewElement TempItemStructProperty FirstElementMsg SearchDataArrayPropertySender MoveItem TempCountCNoneNone AllItemsNoneSClassPropertyNewSize NamePropertyObjectPropertyFloatProperty bTeamGameArrItemszbUniqueNetConnection BoolProperty IntPropertynewid BytePropertyNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneRemoveManagedGroupNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNone SubmitButton CurrentLinksSelect RadioButtonTextBox ValidOctetNoneCreateFullMutatorListNone NoneTextNone AddUserTitleAcceptCustomDeny GroupRemovedPasswordErrorYouMustSelectAdminNotFoundInsufficientPrivsPlayerListLinkedHeaderAddGroupTitleConsoleRefreshTag BadGameTypeModifyUserGroup SwitchTextInvalidCharactersSelectInclude UserRemoved PrivTitle DeleteTextRadioButtonIncludeUpdateRemovedBrowseGroupsTitleSubmitButtonIncludeMutatorGroupTitleTextboxIncludeSecurityLevel CellColSpanEditGroupButton PickMutators NowrapRight NoneItemTextCannotAssignPrivs NowrapCenterErrorAuthenticatingModifySingleBotStatus NowrapLeftAdminPageTitleGameTypeUnsupportedCannotAssignHigherMutatorTablePageDefaultsMapsLink CellRight RowCenterAdded BotStatusInactiveMapNotFoundShowFramedMessage CellCenterCouldNotCreateSelectedMutatorsDefaultsRowPage NameExistsDefaultsIPPolicyLinkDefaultsRestartLinkIDBanNoPlayersConnectedAccessDeniedText WaitTitle SiteCSSFileCheckboxIncludeFramedMessagePageNoPrivsNoBotsGroupNotFoundPlayerListHeader CannotModifyNonePlayerListMinPlayersRowLeftAddGroupButtonManagedAdminHomeTitleMapChangingToBrowseUsersTitleActiveMapNotFoundEditUserButtonEditGroupTitleModifyMUserGroupEditUserTitleErrorAddUserButton NoBotsTitle MapChanging CellLeftMutatorGroupMember Deleting NegSecLevel DoesNotExist InvalidItemOctets DefaultValueNonetmpVtmpNGetPlayerIDHashSizeChecked ServerNameNone BannedIDs Mutators bDisabledNoneSelectOptions bSelected SelectName GameState MaxLength SkinPathSubmitButtonValue bIsErrorMsgNone TextName SoloMutatorsNoneOpNone bBanByIDNoneNewMapGrouped GroupsOnlybIpBanZNone PolicyTypeNonetmpSubmitButtonNameNoneNoneNone IsBeforeCodedPlain CleanupQuery HandleHTM ToggleSortApplySkinSettingsCheckPrivilegeGroupHandleMessagePage HtmlDecodeValidMaskOctetHandleWebIncludeHandleSpecialQuery PadRightCleanup LoadSkinsHandleFrameMessageGenerateSkinSelect SetSortOrderStatusOKColor SpecialCharsSiteBGSkinSelectIncludeNoneResetButtonIncludeHiddenIncludeNone HtmlChar NameText UT2K3SkinHiddenWebSkinSkinCSSDefaultBGColorAdminAccountTitle ResetButtonTimerNonePrivilegeTableStatusErrorColor StatTableRow CleanupAppEatStr StatTableTeamPlayerReplicationInfo bIsErrormlength WebAdmin SpecialQuerybShowPrivGroupSubPath Suicides SkinClassbResultxPlayerOrderSpreesselectedstringResetButtonNameSkinsCurCol CurrentSkin PrivStringLastDeaths IsHanging PrivHeaderResetButtonValueNoneNoneSPrivSubStr MainPrivSpree WebSkinsNone ReverseSortMainStrbDelayCleanupNone FilenameReverse ConnectionWebConnection bCanKickBots PrivItems MultiKills ActiveSkinKills bHasPrivxp TagIndexNoneNone GetGameIndexNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNone ValidMapNoneNoneNoneUpdateCustomMapListNoneNoneNoneAddMapNoneNone RemoveMapNoneNoneNoneNone RemoveListGetActiveListNoneFormatMapNameDefaultWebSkinClassNoneNoneNoneConsoleUserlistNoneNonePauseNone SetPauseNoneNonebPauseidxNewName CurrentListNone selectedExtPauser ListNameCustomMapSelectNoneNoneNoneNoneNoneResultNoneNoneNoneNoneNoneNone FullNameAr GameIndexNoneNoneGetMapListTitleNone ShiftMapAddListGetMapListNames RenameList ClearList SaveMapList ResetListNoneNone MapListIndexNoneActiveNoneNextPNoneNoneNoneNoneMutsNoneNone InfoClassesNoneNone CacheManager TmpClassInfoDebug GameRecordNoneGetConfigArrayColumnTitleGenerateMutatorOptionsQueryVotingGameConfigUpdateConfigArrayItem ServerPauseDeleteConfigArrayItem ClassicUTUArrayPropertyGetConfigArrayDataAddConfigArrayItemUnrealAdminPageNewTextDefaultsVotingGameConfigPageDefaultsVotingGameConfigLink UT2K3StatsGetConfigArrayItemCountNoteVotingGameConfigPage KickPlayer bRegLineParts bAltLinexUserbStructcolumnsMaplistHandlerVotingHandler MutatorList ThisPropxGroup Property bRuleQueryMaplistManagerBasebFullGameConfigData bMutQuery PageTextxGroupsSortedMutatorList ArrayDimNoneGetBaseMapName LoadMapsGetGameCacheIndex InitializedEdit LoadingMaps LoadingGames DumpMaplistscntAllMapsMaplistRecord MapRecordMapURL PadString AllGames ReplaceText RightTablebDebug MaxWidth LeftTable MapRecords Col1CountX ColumnTitleGameConfigIndex bNoMutatorsNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNoneNone jf⯅@EUW U lyة4@Eة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4ة4UUUU/UU UUGUUz@UX UUU(UUUU#UU@U\ UwUUWUUQUUAUUUUV@UX U"UUUUzUQ P_qEY'Ck!oUUUAUKUUuUU]@Up U$@UU~UUF@UUfUUUUUUxUUSUU4UU@@UUF@@UU~ @UUj@UUWUUkUUUW bk,eM@E,eM,eMUUUUtUUhUUCUUcUUbUUnUUUUaUU} @UUU@UU@Ud U>UUWUU@U` \ g=q<UUL UU[@UUBU\ Td 6Aw6bt3}Zs3}Zs!#oKyHoKyH3}Zs!#⯘zVGBzVGBoKyH!JT SRQUUpUULUUfUUgUUJUUsUUpUU\@UU\ UU?UUH@UU-UU7@UU@UUUU)UUS@UU@UUzUUxUUqUUFUU@Ux U[UUq@Us UlUUc@UU@UUIUUb UUEUUrUUwUUi@UUr@UU@UUW@UUUUU} p v6_oKyHgk3}Zs±֧O3}⯜܄mBcmBcmBcmBcmBc3}3}Zs- =13}3}3}⯉3}mBc⯉3}Zs!#؉3}Zs!#⯊3}3}Zs֧OqEY'qEY'qEY'qEY'qEY'qEY'qEY'qEY'- =1FF3}Zs±qEY'FF3}mBcmBcmBcmBcqEY'3}3}Zs3}3}Aw6lj3}Zs±3}Zs±3}Zs±qEY'qEY'3}Zs!#؉3}Zs!#؉3}Zs!#؉3}Zs!#؉3}Zs!#؉3}в3}вв3}вввввввв3}3}mBcmBc3}⯉3}mBc3}⯉3}Zs!#؜⯉3}Zs⯉3}Zs3}Zs3}Zs3}Zs±⯑вqEY'qEY'3}⯉3}ZsjWjWjWjWjW⯜ډ3}3}Aw6RяxTYUXWebAdmin.xWebQueryCurrentXWebAdmin.xWebQueryDefaultsXWebAdmin.xWebQueryAdminsUA| ~R Y@ ]& ]&U@ ]" ]"U@ ]  ] U@ ]< ]<U@ ]> ]>U@ ] ]©U@ ] ] ™U@ ] ]®UO] #aaaaaaN] #3a7c8cS] rootframeR] mainmenuQ] messagev ]frame_messagePMserver_restartM].htmV]UT Remote Admin Servert = ut2003.cssS ] #243954Q ] #33cc66e ]YellowM ] cell_lefti ] cell_centerc = cell_rightS ] cell_colspan] ]cell_left_nowrapY ]cell_center_nowrapV ]cell_right_nowrap~ ] row_leftd = row_centeru ] checkboxQ ] textboxO ]submit_buttonK ] radio_buttonG ]selectV ] reset_buttonW ]hiddenT Mmainmenu_itemsx ]Acceptz ]DenyL ]Updatey ]CustomI ]Erroru ]NoneE ]SwitchJ ]DeleteN]Newo]Edits ] Please WaitL ]a_The server is now switching maps. Please allow 10 - 15 seconds while the server changes maps.B ]omThe server is now switching to map '%MapName%'. Please allow 10-15 seconds while the server changes maps.r ]Access DeniedZ ]+*Exception Occurred During Authentication!w ]76Your privileges are not sufficient to view this page.q]Loading Game Typesp]Loading Available Mapsn]$#%class% Initialized on port %port%UUW@UUPUU[UUUU}@UU| UUI@UJ UD@UUUU{UU{UUTUUUUi UU@UUUUO@@UU}UUR@UU UU@UUl@@UU]@UU5UUCUUQUUh@UU|UUUU@UU}UUUUUU;UUI@UUf UUPUUUUu@UUeUU<@UUq@UUUUUUx @UUUUc@UUkUUM@@UUJ UUrUUd@@UU@UUzUUQ@UU^ @UU`UU{@@UUC@@UUVUU[UU]@UU\@@UUUU2UUUUJ@UUR@UU6UUk@@UU~@@UU]@@UUnUU@UU}@UUUUa@UUJUU{@UU3UUUUUUk@UU_@UU@UUA@UUEUU@UUnUULUUq UUkUU@UUUUmUU_@@UUmUUnUUUUUU@UUAUUM UUUUOUUcUUO@UUZ UUUU~UUGUUZ@@UUUU|UUAU,UBUUI@UU*@UUO@@UUl@UUUUc@@UUUU]vAUB@UUyUUDUUI@UUn@UUUU@UUS@UUJUUgUU^@@UUiU,Uu@@UU`@@UU@@UU!UU@UU@UUd@UUe@UUfUUo@@UUC@UUi@UUs@@UUjUUP UUUUUUAUUv@UUr@UUsUUpUUUUUUMUUM@UUm@UUU@UUUUd@UUUUO @UUnUU@UU`UUsUU]@UUpUUR UU@UUNUUyUUX@UUSUUz@UU@UU[@UUKUU@UUTUUqUUUUI@UUz UUUUUU_UoU@@@UUUU|@UU}@UUhUUh@UU@UULUUx UUHUU|@UUb@UUUUEUUXUUhUU%@@UUM@@UUW@UU@UUiUUUUS @@UUwUUmUUlUUUU@UUDUUc@UUA UU|UU}@UUN UULUUUUUUl m G( GUUUM@UUb@UU@UUS@UUh@@UUW@UU@UUgUUU@@UUx@UUJ@@UUn UUfUUUUQ@UUz@@UUy @UUC UUF UUGUUZ@UUKUU_ @UUr @UUpUUuUUNUUG @UUGUUj @UUN@UUHUUT@UUQ@UUnUU@UUO@UUy@UU@UUQ@UUF@UU1UUA@UU@UUg@UUeUUYUUp@UUZUU_UUo@UUxUUUUT@UU@@veU@UUb @UUMUUu @@UUkUUZ UUJUUVUV Z`6I^]qEY' ⯠ *j *j⯓֧O3}Zs±֧O3}Zs±3}Zs±(ͥߵ(ͥߵ(ͥߵ(ͥ߄֧O3}Zs±֧O *jMKh*jMKh,eM,eM֧O֧O3}Zs±֧O  *j*j*j*j*j,eM,eM,eM֧O֧O֧O֧O֧O֧O3}Zs± ֧O*j*j*j3}Zs± *j*j*j*j3}Zs±*j*j*j*j3}Zs± ֧O3}Zs± ֧O3}Zs± 3}Zs±3}Zs± ֧O*j*j3}Zs± 3}Zs±3}Zs±MKh֧O֧O3}Zs±֧O ⯠ *j *j⯠ ֧O ֧O֧O֧O 3}Zs±֧O֧O3}Zs±MKh֧O֧O3}Zs±֧O ⯠ *j *j⯠ ֧O ֧O֧O֧O 3}Zs±֧O֧O3}Zs±֧O֧O֧O֧O3}Zs±֧O֧O֧O֧O֧O֧O֧O3}Zs±֧O֧O֧O֧O3}Zs±֧O ֧O3}Zs±MKh֧O3}Zs±MKh֧O3}Zs±MKh3}Zs±3}Zs±MKh֧O֧O֧O3}Zs±MKh3}Zs±֧O֧O֧O֧O֧O3}Zs±֧O֧O֧O!oO] admins_menuN] admins_homeMMadmins_accountL] users_addK] users_browseJ= users_editI] users_groupsH]users_mgroupsG= groups_addF]groups_browseE] groups_editd ]admins_priv_tableD]+*Welcome to Admins & Groups ManagementC]ywHere you can change your password if required. You can also see which privileges were assigned to you by your manager.B]WAs an Admin of this server you can add new Admins and give them privileges. Make sure that the password assigned to the new Admin is not easy to hack.A]nlAs an Admin of this server you can modify information and privileges for another Admin that you can manage.@]fdHere you can see other Admins that you can manage and modify their privilege and groups assignment.]FYou can create new groups which will have a common set of privileges. Groups are used to give the same privileges to multiple Admins.~]~You can modify which privileges were assigned to this group. Note that you can only change privileges that you have yourself.}][YHere you can see all the groups that you can manage, click on a group name to modify it.|]EHere you can decide in which groups the selected admin will be part of. This will decide which base privileges this admin will have.{]|zHere you can decide which groups this admin will be able to manage. He will be able to assign other admins to this group.Z ]NameO ] deletingz]groupS]GroupsJ]user[ ]modify@ ] Managed C= PrivilegesR MSecurity Level^ ]Users & Groups ManagementA ]Admin Home Page` ] AccountC ]Browse Available UsersN ]Browse Available Groupsw ]Add a New AdministratorJ ] Add AdminA ]Add New Administration Group ] Add GroupH ]Modify an AdministratorE ] Modify AdminF ] Modify an Administration GroupT ] Modify GroupD ]Modify Groups forG ]Modify Managed Groups forH ] User '%UserName%' was removed!{ ]"!Group '%GroupName%' was removed!~ ]Admin Not Foundy ]Group Not FoundI ]Insufficient Privilegesu ] *** None ***W ]$#** There are no %Item%s to list **| ]HFInvalid characters in password or password not at least 6 characters. ]87Your privileges prevent you from %Action% this %Item%.R ] Invalid %Item% name specified!F ]$#Invalid characters in %Item% name!m ] Must specify a unique name for} ]You must select aQ ]%$The selected %Item% does not exist!j ] Exceptional error creating newP ]%$Negative security level is invalid!` ]65You cannot assign a security level higher than yoursX ]You cannot assign privileges5] adminsframe:]Admins & GroupsL]A|G|Al|Aa|Ae|Ag|Am|Gl|Ga|GeUUI @UUD @UU@ UU} UUV@@UUv @UUu UUe@UUo d \+Jp%Ap77|6<pdpp GUq @UUUUi @UUj@UUd @UUl@UU^ UUL@UUr E+-p_ L+_%_7rL GUeD[ K ^6RuëqEY'JJJJ3},e[zVGB,e3}3}Zsuu/$⯜!!⯜!⯉3}Zsuuuuuuu⯊⯩uuu[uuuu⯄⯄⯄[zVGB[zVGB⯄⯊⯊⯄⯄⯄⯄⯄3}Zs- =13}Aw6Aw6Aw6DŽ3}Zs3}3}Aw6lj3}Aw6NJ3}Aw6DŽ3}3}Zs3}Zs3}Zs!#؉3}Zs!#؉3}Zs3},eݝҳݝҳݝҳ8f8f8f8f8f8f,e3}Zs⯄3}ZsJJ⯉3},e,e u,ezVGB3}Zs±,ezVGB3}Zs±,e,ezVGB,e3}Zs- =13}Zs±3}вв֧O3}3}WSF3}Zs3}WSF3},e,e,e,e,ezVGB,ezVGB3}3}u,ezVGB,ezVGB u3}Zs± u,ezVGB3}Zs,ezVGB,ezVGBJJ,ezVGBJ,ezVGBJ,ezVGB,ezVGB,ezVGB3}Zs±,ezVGBJ,ezVGBJ,ezVGB,ezVGB,ezVGB,ezVGB,ezVGB⯗,e⯄3}WSF!ov] current_menut]current_playersq] current_gamep]current_consoleo]current_console_logn]current_console_sendm]current_mutatorsl] current_botsk]current_restartj]say i ]current_game_stat_tablef ]current_game_stat_table_rowz ]current_players_list_head@ ] current_players_list_head_link} ]current_players_minpB ]-,V  @@W GUG kx_ !-Ykid GU@@UUl Ff.ON7Gm2SectionlcF editwc* zc^{F modJFGroupNameRFcb9JFGameSec%,{Jcc .Jr J*cJIR%Item%rIS%Item%r^zI{Rcc URc9=b{I 2I2.NameValuec2%PrivTablec2$GameSecValue9Rc2PostActiono2SubmitNamemod2SubmitValueu2PageHelp@2oIw %Action%GII%Item%r 2TI4 2Q %Item%rK 2 GU] deW^-JAa[`[%d#Content%Item%`d/RowContent{ ^dContentjr{ dContentErpr{ dContent r-Jpr{ rdRowContentrj^X%UX[i.[ XdUsernamepp?edit=iiAe|Aad PrivilegesidhGroupsAgppC?edit=is'dpManagedAmpp\?edit=ipDs'dfDelete-Jpp`?delete=iJ'aBjusers_rowXj GUh KQ_Q a0K2GameType9VcK PageMt{KGameTypeSetQKGameTypeSelecta|QaaQ6@GameTypeButtonl GameTypeSet~6CGameTypeSelectn GameType?a66GameTypeSelect6DefaultBGLM 6ppa&Page=L_H%H7MpM 6ppppa&Page=k&Filter=HHHaBM 6ppa&Page=sBaBM 6ppa&Page=zKaBMp
 6ppa&Page=d\6ContentM6'FilterKFilter6Pagec6PostAction6  GUQT F[{ge \ T F gec%c7F_ʚcI selectedaB|ppppppc_| GU[@UUc@UU_ H qH%URIpp?GameType=N HURITextK defaults_menu_row GU^ ]c]C-DGd-A Ge-ww5w%]#Content%Item%r]/RowContent{ ^]Contentjn{ ]ContentEnpn{ ]ContentWnpn{ ]Content n-Dpn{ n]RowContentnS^P%:Pwlw P]lGroupnameppo?edit=ll'] Privilegesl]Gamesec9Rl]fDelete-Dpph?delete=lJ'aBSgroups_rowPS GUl@UUVUUo ZRN IfZ2GameType9VeZPageLd{ZFilterp&Filter=ZFiltergBIndexURIppppp ?GameType=f&Page=edg0MainURIpppe?GameType=fd$g GUUUV UU` }+lriJC}%}%A}}7h }  }Sw`*'` }  }%S selectedTpppppppT}JT GUz bg\:G{Ga{baddnewBbGroupName]bD9JbGameSec .BxS%Item%r[w B*xpRr![.D%xg[[Dyxv!%NameValueB!PrivTable]!GameSecValue9SDzxxZB]9=Dwx* bx xxp@r!{x !x!PrivTablewx*!PostActiono!SubmitNamemod!SubmitValueu!PageHelp@!Sectionl_!PostActionU!SubmitNameaddnew!SubmitValuei!Sectiona!PageHelpD!o ! GUj UU}@UUNlA6mA(@A& \RA@' v QA@' LPA@' kOA@' sNA@' 7d58A@' ezcEA@' ( GUR j9H (M* @>KJV%DV7@n kV@pnV@n'-EpppppAdding map entry to include list Item 'nV@' Tag 'n'@j  n:@j @VG GUh H 0fMzH %VH 9VUH rU*Error loading gametypeH !m %VUr** w*&Vz[BU69JB [ wwU*7VVU VH  GU@UUU@UUs F EĒlwF E'O~w.-O%EwwO& e w{e GU@UUUUwUUn ah4BybGl|GefSectionL{adeleteradeletewr* zrf[%GroupName%rrX rOw %Action%oOO%Item%r fO fF%Item%rfBrowseListcffPageHelpyfhv f GUNtFCA(F& H]FJ' bt\FJ' %[FJ' FZFJ' OYFJ' ]XFJ' 4uWFJ' bM`VFJ' ~UFJ' {8FJ' ( GUV'oW|%N|7t''6d|t6e|t|' G UU_U|@UUL@@UU} UUA E $y^+wl*lB E D 'E %ppppu /D O' GUd P  Ml?GameType~ \ ?jMapListNum{jW9JjW y ~[c~W+&?9+~WQ* =jMoveMap* {j[ListName[j  > <>AExcludeMapsSelectA&9%/+%mExcludeMapsSelectd  km;@+d;%Q;p ~Wpdm/pRExcludeMapsSelect!m  * D < <IncludeMapsSelect%AIncludeMapsSelectA&%mIncludeMapsSelectd  km%;+@d;%Q+;s ~WpdmpYIncludeMapsSelect!m * >>+%;(++&;%Q;$p ~W ;* 7<<4%;+(&1;%Q+;i~W* Up[9D9LMoveMapCountAIncludeMapsSelect%AQ2sIncludeMapsSelect[[%Q# %)e~W [A[* ' Down[9D9LMoveMapCountAIncludeMapsSelect%hAQ2sIncludeMapsSelect&$ % Q# %)e~W [A[*  { Save[ListName[l ~W[*  { New7p%% 7pp   k~WW.f?ListName[p+&?9+~W* Z { Use[ListName[l ~W[G~W* * {DeleteWx ~W[c~W+&?9+~WRF?WKGameType?KSessionSessionKMapListName[KMapListOptionsRK3ExcludeMapsOptions++QK3IncludeMapsOptions+QKSection_KPostActionLKPageHelpG KKL  K GUUUA f zz|:wl*lB fC f'f%ppppu /C Of' GU@UUW V \ -h*V X  GUUUE B {jzc&@cc&B @Statusppppc
 GUK@UUU gSQ{!rg*gd GUI @ p|H@ <Statuspppp GUe {b;Zc/SCheckboxFv~pp|{|pp|v|-u/Textyprivs_header GUOUUL hG#(}<zGh}/ hGzG GU@UUUUr ~&&p$+z~~9Vym~y訨Could not load gametype~for maplist.~~* =~6yh c%l~O%O7l}h 6OlM-EppppAdding entry to exclude maplist Item '9SO' Tag '6Ol'~'6Ol6Ol'O~ GUUUO F -~0wl*lF F|z FSection|FMessagezF%ppppu /cO GUo mTzNrm*Am,mm#CCCCCC GUUUd YBtwY*9q!; rYKglq!;KppY: gq!yKppp[Y]: gKppp(9Wq) gq!<KWebAdmin:gKppp(9Wq) gK GUg x ] xrt GU+class UTImageServer extends ImageServer; UF vhwz-Zuppiui GUb PUUU{ j] wjPageF|&IndexURIppt?Page=w|MainURIw$| GUu@UUPUU@Uo Ub@UUb r_r----Begin Dump----?r*NO PLAYER REPLICATION INFOUr*NO PAWNNextMsg:9RqLastMsg:9RPReceivedMsgMax:9RQMsg[0]%]Msg[1]&]Msg[2],]Msg[3],]Msg[4],]Msg[5],] GUZpFJ6/CheckNamep/#Checked-n checked/%Disabled-D disabledb GUC TO\.x .Ms  0TGameTypeQTFilter-n{TSaveOBdefaults_markSectionQFilterQ% 7~ z6Q?9:6y]z6266$-6/6a/!J~ 79%hG T*6-n/bh6-}-}$-6Mark-}BAHintText6DDisplayText6I-9R67SecLevelp     I6 $ $78w{6O6;7} 9} :w76W9J7,(} 79&} pppp (%9 - &9)Contentpp 69SW9S9J76} /FormObjectCa $-n'z6 b9T(ContentF6|69T'{6/FormObjectCa ^ $7096;W%W&79aB7ppW, EContentn 67/FormObjectCa aBO`b zOOOTableContentOPostActionkGameType!SubmitValueHPageHelpI k GUSHLCrVz|| bHF}bAbp|b bA GU@UU@UUv uݓ`q~u|(q%q}uAuqW{uuu&A GU_@UUq@UUY Bi9AmfB editwf*d ,f-ppj-I{Bsubmitl* =c%cpl@p cp cc9c%(clil cyp i-L{B i-Icf )y`-Lf ] y-Lf byDGroupNameiCf )yC checkedDCheckedCaBjusers_groups_rowc[-IDManagedDD.NameValuefDGroupRowsjDPostAction\D3SectionBfDPageHelpvDCCw %Action%GCC%Item%` DTC D[ %Item%` D GUR l7yPwP*n.Pjwn*jznlnPP* GUk lzQlu{Qa hQ YQ'Ql( GUd@UUQUUiq 2i`dB1{LaBL,aBL69JB dL GU@ @UUf&// ==================================================================== // Class: xWebAdmin.SortedObjectArray // Parent: xWebAdmin.ObjectArray // // Sorted list - sorts by tag // ==================================================================== class SortedObjectArray extends ObjectArray; var const bool debug; function Add(object item, string tag) { local int pos; if (debug) { for (pos = 0; pos < AllItems.Length; pos++) log(" Member"@pos@AllItems[pos].Tag); } pos = FindTagId(tag); if (pos < 0) InsertAt(-pos-1, item, tag); else InsertAt(pos, item, tag); if (debug) { log("~~Inserting new member at"@pos@tag); for (pos = 0; pos < AllItems.Length; pos++) log(" Member"@pos@AllItems[pos].Tag); } } function int FindTagId(string Tag) { local int sz, min, max, pos; sz = AllItems.Length - 1; if (sz < 0 || IsBefore(Tag, AllItems[0].tag)) { if (debug) log(tag@"was before first member, so returning -1"); return -1; } if (Tag ~= AllItems[0].Tag) return 0; if (Tag ~= AllItems[sz].Tag) return sz; if (sz == 1) return -3; // Add tag to end of list if (!IsBefore(Tag,AllItems[sz].tag)) { if (debug) log(tag@"was after last member, so returning"@(-(sz+1))-1); return (-(sz+1))-1; } // Find the position of insertion max = sz; pos = sz; do { if (tag ~= AllItems[pos].tag) return pos; if (IsBefore(Tag,AllItems[pos].tag)) max = pos; else min = pos; if (debug) log("Min:"$Min@"Max:"$Max@"Pos:"$((Min + Max)/2)); pos = (min + max)/2; } until (max-min < 2); // Min = 1 and Max = 2, return 1 if (pos == 0) { if (debug) log(tag@"wanted to be added at 0, so adding at 1 instead"); return 1; } if (debug) log(tag@"will be inserted at position"@-pos-2); return -pos-2; } /* singular function ToggleSort() { ReverseSort = !ReverseSort; log("ToggleSort. ReverseSort is now:"$ReverseSort); } */ function bool IsBefore(string test, string tag) { local bool b; if (debug) { b = ((!ReverseSort && test < tag) || (ReverseSort && test > tag)); log("IsBefore"); log(" ReverseSort:"$ReverseSort); log(" "$Test@"is before"@Tag$":"@b); log(""); return ((!ReverseSort && test < tag) || (ReverseSort && test > tag)); } return Super.IsBefore(test,tag); } Ut UUM gaCwd-a-a~pp|g|pp|{|{g -a'mgzm{&-a(</2CheckboxF{-a-T/Textbprivs_element GUUUyE(mi2wi*iiiyy iy* GU{ OH#w@* B* =2  c)C%C7@9SC6CCJOtwO*]O-L@ 9VO*L%B*@ L6L]Unknown Mutator in use: 9VO!m OO GUOcwI!m V* = c$hc%|c7hV&6ch6chc3 GUy o-nU-oRw-*x-(N(r-*-NN -N*R;;t-(N(r- *oN- NN - N-- NR--  GU@//============================================================================== // Web Application to handle remote administration of server // // Revised by Micheal Comeau // Revised by Ron Prestenback // 1998-2004, Epic Games, Inc. All Rights Reserved //============================================================================== class UTServerAdmin extends WebApplication config; // TODO: // Do something with colspan.inc var config string ActiveSkin; // Each query handler represents a section in webadmin var() config array QueryHandlerClasses; var array QueryHandlers; // Global Objects var() array > WebSkins; // array of webadmin skins var() class SpectatorType; var() class DefaultWebSkinClass; var WebSkin CurrentSkin;// Currently loaded webadmin skin var UTServerAdminSpectator Spectator; // Used to get console messages var xAdminUser CurAdmin; // Currently logged admin (not thread safe) var PlayInfo GamePI; // Contains all confiurable variables var WebResponse Resp; // Non-thread safe reference to a WebResponse object // Lists var array AllGames; var array AllMaps; var array AllMutators; // All mutators as determined by .int entries var StringArray AGameType; // All available Game Types var StringArray AExcMutators; // All available Mutators (Excluded) var StringArray AIncMutators; // All Mutators currently in play var StringArray Skins; // All Webadmin custom skins // Characters which aren't rendered correctly in HTML struct HtmlChar { var string Plain; var string Coded; }; var array SpecialChars; var config string DefaultBG; // Non-highlighted items var config string HighlightedBG; // Active links // Pages var config string RootFrame; // This is the master frame divided in 2: Top = Header, bottom = frame page var config string HeaderPage; // This is the header menu var config string MessagePage; // Name of the file containing the message template var config string FramedMessagePage; // Name of file containing message template for sub-frames var config string RestartPage; // This is the page that users will be transferred to when restarting the server var string htm; var config string AdminRealm; // Used by browsers to cache login information // HTML variables used for skins var string SkinPath; // Path to use for .htm and .inc content var string SiteCSSFile; // CSS file to use var string SiteBG; // Background color for this skin var string StatusOKColor; // Color of status ok messages var string StatusErrorColor; // Color of status error messages // Table cells var config string CellLeft; // Table cell, left justified var config string CellCenter; // Table cell, center justified var config string CellRight; // Table cell, right justified var config string CellColSpan; // Spanned table cell var config string NowrapLeft; // Nowrap table cell, left justified var config string NowrapCenter; // Nowrap table cell, center justified var config string NowrapRight; // Nowrap table cell, right justified var config string RowLeft; // Table row, left justified var config string RowCenter; // Table row, center justified // Form objects var config string CheckboxInclude; var config string TextboxInclude; var config string SubmitButtonInclude; var config string RadioButtonInclude; var config string SelectInclude; var config string ResetButtonInclude; var config string HiddenInclude; var config string SkinSelectInclude; // Global localization var localized string Accept; var localized string Deny; var localized string Update; var localized string Custom; var localized string Error; var localized string NoneText; var localized string SwitchText; var localized string DeleteText; var localized string NewText; var localized string Edit; var localized string WaitTitle; var localized string MapChanging; var localized string MapChangingTo; var localized string AccessDeniedText; var localized string ErrorAuthenticating; var localized string NoPrivs; var localized string LoadingGames, LoadingMaps, Initialized; var bool bDebug; // ===================================================================================================================== // ===================================================================================================================== // Initialization // ===================================================================================================================== // ===================================================================================================================== event Init() { Super.Init(); if (SpectatorType != None) Spectator = Level.Spawn(SpectatorType); else Spectator = Level.Spawn(class'UTServerAdminSpectator'); if (Spectator != None) Spectator.Server = self; // won't change as long as the server is up and the map hasnt changed LoadMaps(); LoadGameTypes(); LoadMutators(); LoadQueryHandlers(); ReplaceText( Initialized, "%class%", string(Class) ); ReplaceText( Initialized, "%port%", string(WebServer.ListenPort) ); Log(Initialized,'WebAdmin'); } function LoadMaps() { log(LoadingMaps,'WebAdmin'); class'CacheManager'.static.GetMaplist(AllMaps); } function LoadGameTypes() { local int i; Log(LoadingGames,'WebAdmin'); // reinitialize list if needed AGameType = New(None) class'SortedStringArray'; class'CacheManager'.static.GetGameTypeList(AllGames); for (i = 0; i < AllGames.Length; i++) AGameType.Add( AllGames[i].ClassName, AllGames[i].GameName ); } function LoadMutators() { local Mutator M; local int i, id; AExcMutators = New(None) class'StringArray'; AIncMutators = New(None) class'SortedStringArray'; if ( Level.IsDemoBuild() ) return; // Load All mutators class'CacheManager'.static.GetMutatorList(AllMutators); for (i = 0; i= 0) AIncMutators.Add(AExcMutators.GetItem(id), AllMutators[id].FriendlyName); else log("Unknown Mutator in use: "@M.Class,'WebAdmin'); } } } function LoadQueryHandlers() { local int i, j; local xWebQueryHandler QH; local class QHC; LoadSkins(); for (i=0; i(DynamicLoadObject(QueryHandlerClasses[i],class'Class')); // skip invalid classes if (QHC != None) { // Make sure we dont have duplicate instance of the same class for (j=0;j TmpClass; local array > InfoClasses; local int i; if (GameType == "") { InfoClasses[0] = Level.Game.Class; GameType = string(Level.Game.Class); } else { TmpClass = class(DynamicLoadObject(GameType, class'Class')); if (TmpClass == None) { Log("Error loading gametype"@GameType,'WebAdmin'); return ""; } InfoClasses[0] = TmpClass; } if (GamePI == None) GamePI = new(None) class'PlayInfo'; if (Level.Game.AccessControl != None) InfoClasses[1] = Level.Game.AccessControl.Class; while (i < AIncMutators.Count()) { TmpClass = class(DynamicLoadObject(AllMutators[int(AIncMutators.GetItem(i++))].ClassName, class'Class')); if (TmpClass != None) InfoClasses[InfoClasses.Length] = TmpClass; } GamePI.Init( InfoClasses ); return GameType; } // ===================================================================================================================== // ===================================================================================================================== // List Initialization & Generation // ===================================================================================================================== // ===================================================================================================================== // Returns a list of all maps for this gametype function StringArray ReloadExcludeMaps(String GameType) { local int i, GameIndex; local string MapPrefix; local StringArray AMaps; local array MapRecords; if ( GameType == "" ) GameType = string(Level.Game.Class); GameIndex = GetGameCacheIndex(GameType); if ( GameIndex == -1 ) { Warn("Could not load gametype"@GameType@"for maplist."); return AMaps; } AMaps = New(None) class'SortedStringArray'; MapPrefix = AllGames[GameIndex].MapPrefix; class'CacheManager'.static.GetMapList(MapRecords, MapPrefix); for ( i = 0; i < MapRecords.Length; i++ ) if ( ValidMap(MapRecords[i].MapName) ) { if ( bDebug ) log("Adding entry to exclude maplist Item '"$i$"' Tag '"$MapRecords[i].MapName$"'"); AMaps.Add(MapRecords[i].MapName, MapRecords[i].MapName, True); } return AMaps; } // Returns a list of active maps for this gametype function StringArray ReloadIncludeMaps(StringArray ExMaps, int GameIndex, int MapListIndex) { local int i, id; local string MapName; local array Maps; local StringArray Arr; Arr = new(None) class'StringArray'; Maps = Level.Game.MaplistHandler.GetMapList(GameIndex, MapListIndex); for ( i = 0; i < Maps.Length; i++ ) { MapName = class'MaplistRecord'.static.GetBaseMapName(Maps[i]); Arr.Add( MapName $ Maps[i], MapName, True ); if ( bDebug ) log("Adding map entry to include list Item '"$MapName $ Maps[i]$"' Tag '"$MapName$"'"); // Always add the maps that are in the existing maplist, even if they aren't valid maps id = ExMaps.FindTagId(MapName); if ( id != -1 ) ExMaps.Remove(id); } return Arr; } // Only 'Mutators' has value when function is called function CreateFullMutatorList(out StringArray Mutators, out StringArray GroupsOnly) { local StringArray Grouped; local int i,j,z; local string GrpName; local string thisgroup, nextgroup; // This class provides a specialized sorting function // since mutators may be grouped - mutators in the same groups // are not allowed to be selected together Grouped = new(None) class'SortedStringArray'; // Create array sorted on GroupName...this allows to flag // the mutator for a different .inc file (radio instead of checkbox) for (i = 0; i < Mutators.Count(); i++) { j = int(Mutators.GetItem(i)); // If the mutator author forgot to configure a group name for the mutator, // generate a groupname "Z" + number, so that every mutator without group name // has its own group, and isn't grouped together if (AllMutators[j].GroupName == "") GrpName = "Z" $ string (z++); else GrpName = AllMutators[j].GroupName; Grouped.Add(string(j),GrpName $ "." $ AllMutators[j].FriendlyName $ AllMutators[j].ClassName); } // Move all grouped mutators to GroupsOnly StringArray for sorting by friendly name for (i = 0; i < Grouped.Count(); i++) { thisgroup = AllMutators[int(Grouped.GetItem(i))].GroupName; nextgroup = ""; if (thisgroup == "") continue; if (i+1 < Grouped.Count()) nextgroup = AllMutators[int(Grouped.GetItem(i+1))].GroupName; if (thisgroup ~= nextgroup) { j=i; while(nextgroup ~= thisgroup && j < Grouped.Count()) { GroupsOnly.MoveFromId(Grouped, Grouped.FindItemId(Grouped.GetItem(j))); thisgroup = nextgroup; if (j+1 == Grouped.Count()) nextgroup=""; else nextgroup = AllMutators[int(Grouped.GetItem(j+1))].GroupName; } if (j < Grouped.Count()) GroupsOnly.MoveFromId(Grouped,Grouped.FindItemId(Grouped.GetItem(j))); i=-1; } } // Move all non-grouped mutators back to Mutators StringArray // for re-sorting by Friendly Name Mutators.Reset(); for (i=0;i SkinClass; Skins = new(None) class'StringArray'; S = Level.GetNextInt("XWebAdmin.WebSkin", i++); while (S != "") { SkinClass = class(DynamicLoadObject(S, class'Class')); if (SkinClass != None) { Skins.Add(Level.GetItemName(string(SkinClass)), SkinClass.default.DisplayName); WebSkins[WebSkins.Length] = SkinClass; } S = Level.GetNextInt("XWebAdmin.WebSkin", i++); } ApplySkinSettings(); } function ApplySkinSettings() { local int i; if (Skins == None) return; if (CurrentSkin != None && Level.GetItemName(string(CurrentSkin.Class)) ~= ActiveSkin) return; i = Skins.FindItemId(ActiveSkin); if (i < 0) CurrentSkin = new(None) class'XWebAdmin.UT2K3Skin'; else CurrentSkin = new(None) WebSkins[i]; if (CurrentSkin != None) CurrentSkin.Init(Self); } function ServerChangeMap(WebRequest Request, WebResponse Response, string MapName, string GameType) { local int i; local bool bConflict; local string Conflicts, Str, ShortName, Muts; if (Level.NextURL != "") { ShowMessage(Response, WaitTitle, MapChanging); } if (Request.GetVariable("Save", "") != "") { // All we need to do is override settings as required for (i = 0; i 0) { for (i = 0; i < CurrentSkin.SpecialQuery.Length; i++) { if (CurrentSkin.SpecialQuery[i] ~= Mid(Request.URI,1)) { if (CurrentSkin.HandleSpecialQuery(Request, Response)) return; break; } } } // Check whether we're supposed to handle this query switch (Mid(Request.URI, 1)) { case "": case RootFrame: QueryRootFrame(Request, Response); return; case HeaderPage: QueryHeaderPage(Request, Response); return; case RestartPage: if (!MapIsChanging()) QuerySubmitRestartPage(Request, Response); return; case SiteCSSFile: Response.SendCachedFile( Path $ SkinPath $ "/" $ Mid(Request.URI, 1), "text/css"); return; } // If not, allow each query handler a chance to process this query. Show error message if no query handlers // were able to handle the query for (i=0; i 0) GroupPage = QueryHandlers[0].DefaultPage; if (Request.GetVariable("ChangeSkin") != "") { ActiveSkin = Request.GetVariable("WebSkin", ActiveSkin); ApplySkinSettings(); SaveConfig(); } GroupPage = Request.GetVariable("Group", GroupPage); Response.Subst("HeaderURI", HeaderPage$"?Group="$GroupPage); Response.Subst("BottomURI", GroupPage); Response.Subst("ServerName", class'GameReplicationInfo'.default.ServerName); ShowFrame(Response, RootFrame); } // Generates the HTML for the top frame, which displays the available areas of webadmin and webadmin skin selector function QueryHeaderPage(WebRequest Request, WebResponse Response) { local int i; local string menu, GroupPage, Dis, CurPageTitle; Response.Subst("AdminName", CurAdmin.UserName); Response.Subst("HeaderColSpan", "2"); if (QueryHandlers.Length > 0) { GroupPage = Request.GetVariable("Group", QueryHandlers[0].DefaultPage); // We build a multi-column table for each QueryHandler menu = ""; CurPageTitle = ""; for (i=0; i"$AGameType.GetTag(i)$""; } return OptionStr; } // HTML for active mutator selection list function string GenerateMutatorOptions(String SelectedMutators) { local int i, j; local string SelectedStr, OptionStr; local array MutatorList; local StringArray SortedMutatorList; local bool bNoMutators; Split( SelectedMutators, ",", MutatorList); SortedMutatorList = new(None) class'SortedStringArray'; for(i=0; i < AllMutators.Length; i++) SortedMutatorList.Add(AllMutators[i].ClassName,AllMutators[i].FriendlyName); // Search mutator list for NONE, if found then no other mutators can be selected. SelectedStr = ""; for( j=0; j < MutatorList.Length; j++) { if( MutatorList[j] ~= "NONE" ) { SelectedStr = " selected"; bNoMutators = true; break; } } // add None options - for unloading all mutators OptionStr = ""; for(i=0; i < SortedMutatorList.Count(); i++) { SelectedStr = ""; if( !bNoMutators ) // dont select other mutators if none selected { for( j=0; j < MutatorList.Length; j++) { if( MutatorList[j] ~= SortedMutatorList.GetItem(i) ) { SelectedStr = " selected"; break; } } } OptionStr $= ""; } SortedMutatorList.Reset(); return OptionStr; } // HTML for maplist selection options function string GenerateMapListOptions(string GameType, int Active) { local int i, idx; local array Ar; local string Result, selected; idx = Level.Game.MaplistHandler.GetGameIndex(GameType); Ar = Level.Game.MaplistHandler.GetMapListNames(idx); for (i = 0; i < Ar.Length; i++) { selected =Eval(i == Active, " selected", ""); Result $= ""; } return Result; } // HTML for the dual map selection lists function string GenerateMapListSelect(StringArray MapList, StringArray MovedMaps) { local int i; local String ResponseStr, SelectedStr; if (MapList.Count() == 0) return ""; for (i = 0; i= 0) SelectedStr = " selected"; ResponseStr = ResponseStr$""; } } return ResponseStr; } // HTML for webadmin skin options function string GenerateSkinSelect() { local string S, selectedstring; local int i; if (Skins.Count() == 0) return ""; for (i = 0; i < Skins.Count(); i++) { SelectedString = Eval(CurrentSkin != None && Level.GetItemName(string(CurrentSkin.Class)) ~= Skins.GetItem(i), " selected", ""); S = S $ ""; } return S; } // ===================================================================================================================== // ===================================================================================================================== // HTML helpers // ===================================================================================================================== // ===================================================================================================================== // Replaces special characters in a regular string with HTML static function string HtmlEncode(string src) { local int i; for (i = 0; i < default.SpecialChars.Length; i++) src = Repl(src, default.SpecialChars[i].Plain, default.SpecialChars[i].Coded); return src; } // Replaces HTML special characters with regular text static function string HtmlDecode(string src) { local int i; for (i = 0; i < default.SpecialChars.Length; i++) src = Repl(src, default.SpecialChars[i].Coded, default.SpecialChars[i].Plain); return src; } // Make the specified string's length equal to MaxWidth by adding PadString to the beginning of the string function string PadLeft( string Text, int MaxWidth, optional string PadString) { local String OutStr; if (PadString == "") PadString = " "; for (OutStr = Text; Len(OutStr) < MaxWidth; OutStr = PadString $ OutStr); return Right(OutStr, MaxWidth); // in case PadStr is more than one character } // Make the specified string's length equal to MaxWidth by adding PadString to the end of the string function string PadRight(string Text, int MaxWidth, optional string PadString) { local string OutStr; if (PadString == "") PadString = " "; for (OutStr = Text; Len(OutStr) < MaxWidth; OutStr $= PadString); return Left(OutStr, MaxWidth); } // Adds the HTML necessary for showing the current map's name function MapTitle(WebResponse Response) { local string str, smap; str = Level.Game.GameReplicationInfo.GameName$" in "; if (Level.Title ~= "untitled") { smap = Level.GetURLMap(); if (Right(smap, 4) ~= ".ut2") str $= Left(smap, Len(smap) - 4); else str $= smap; } else str $= Level.Title; Response.Subst("SubTitle", str); } function bool MapIsChanging() { if (Level.NextURL != "") { ShowMessage(Resp, WaitTitle, MapChanging); return true; } return false; } // Converts the specified text into a hyperlink function string HyperLink(string url, string text, bool bEnabled, optional string target) { local string hlink; if (bEnabled) { hlink = ""$text$""; return hlink; } return text; } // Loads an .inc file into the current WebResponse object function string WebInclude(string file) { local string S; if (CurrentSkin != None) { S = CurrentSkin.HandleWebInclude(Resp, file); if (S != "") return S; } return Resp.LoadParsedUHTM(Path $ SkinPath $ "/" $ file $ ".inc"); } function bool ShowFrame(WebResponse Response, string Page) { if (CurrentSkin != None && CurrentSkin.HandleHTM(Response, Page)) return true; Response.IncludeUHTM( Path $ SkinPath $ "/" $ Page $ htm); return true; } function bool ShowPage(WebResponse Response, string Page) { if (CurrentSkin != None && CurrentSkin.HandleHTM(Response, Page)) { Response.ClearSubst(); return true; } Response.IncludeUHTM( Path $ SkinPath $ "/" $ Page $ htm); Response.ClearSubst(); return true; } function StatusError(WebResponse Response, string Message) { if (Left(Message,1) == "@") Message = Mid(Message,1); Response.Subst("Status", ""$Message$"
"); } function StatusOk(WebResponse Response, string Message) { Response.Subst("Status", ""$Message$""); } function bool StatusReport(WebResponse Response, string ErrorMessage, string SuccessMessage) { if (ErrorMessage == "") StatusOk(Response, SuccessMessage); else StatusError(Response, ErrorMessage); return ErrorMessage==""; } function ShowMessage(WebResponse Response, string Title, string Message) { if (CurrentSkin != None && CurrentSkin.HandleMessagePage(Response, Title, Message)) return; Response.Subst("Section", Title); Response.Subst("Message", Message); Response.IncludeUHTM(Path $ SkinPath $ "/" $ MessagePage $ htm); } // Framed message page (eliminates double headers) function ShowFramedMessage(WebResponse Response, string Message, bool bIsErrorMsg) { if (CurrentSkin != None && CurrentSkin.HandleFrameMessage(Response, Message, bIsErrorMsg)) return; if (bIsErrorMsg) StatusError(Response,Message); else Response.Subst("Message", Message); Response.IncludeUHTM(Path $ SkinPath $ "/" $ FramedMessagePage $ htm); } // ===================================================================================================================== // ===================================================================================================================== // Form control HTML helpers // ===================================================================================================================== // ===================================================================================================================== // Creates a checkbox, optionally greying it out (disabled) function string Checkbox(string tag, bool bChecked, optional bool bDisabled) { Resp.Subst("CheckName", tag); Resp.Subst("Checked", Eval(bChecked, " checked", "")); Resp.Subst("Disabled", Eval(bDisabled, " disabled", "")); return WebInclude(CheckboxInclude); } function string Hidden(string Tag, string Value) { Resp.Subst("HiddenName", Tag); Resp.Subst("HiddenValue", Value); return WebInclude(HiddenInclude); } // Creates a submit button function string SubmitButton(string SubmitButtonName, string SubmitButtonValue) { Resp.Subst("SubmitName", SubmitButtonName); Resp.Subst("SubmitValue", SubmitButtonValue); return WebInclude(SubmitButtonInclude); } function string ResetButton(string ResetButtonName, string ResetButtonValue) { Resp.Subst("ResetName", ResetButtonName); Resp.Subst("ResetValue", ResetButtonValue); return WebInclude(ResetButtonInclude); } // Creates a textbox, optionally providing a default value function string TextBox(string TextName, coerce string Size, coerce string MaxLength, optional string DefaultValue) { Resp.Subst("TextName", TextName); if (int(Size) > 0) Resp.Subst("TextSize", "size=\""$Size$"\""); else Resp.Subst("TextSize", ""); if (int(MaxLength) > 0) Resp.Subst("TextLength", "maxlength=\""$MaxLength$"\""); else Resp.Subst("TextLength", ""); Resp.Subst("TextValue", DefaultValue); return WebInclude(TextboxInclude); } function string RadioButton(string Group, string Value, bool bSelected) { Resp.Subst("RadioGroup", Group); Resp.Subst("RadioValue", Value); Resp.Subst("Selected", Eval(bSelected, " checked", "")); return WebInclude(RadioButtonInclude); } function string Select(string SelectName, string SelectOptions) { Resp.Subst("SelectName", SelectName); Resp.Subst("ListOptions", SelectOptions); return WebInclude(SelectInclude); } // ===================================================================================================================== // ===================================================================================================================== // Accessor / Utility Functions // ===================================================================================================================== // ===================================================================================================================== function int GetGameCacheIndex( string GameClass ) { local int i; for ( i = 0; i < AllGames.Length; i++ ) if ( AllGames[i].ClassName ~= GameClass ) return i; return -1; } // Returns whether this map is a valid map function bool ValidMap(string MapURL) { local int i; local string MapName; if ( Left(Caps(MapName),4) ~= "TUT-" ) return false; MapName = class'MaplistRecord'.static.GetBaseMapName(MapURL); for ( i = 0; i < AllMaps.Length; i++ ) { if ( AllMaps[i].MapName ~= MapName ) return true; } return false; } function FormatMapName(out string FullName, out string ShortName) { local string ext; ext = ".ut2"; if (FullName == "" && ShortName == "") return; if (FullName != "" && ShortName == "") { if (Right(FullName, 4) ~= ext) ShortName = Left(FullName, Len(FullName) - 4); else { ShortName = FullName; FullName = FullName $ ext; } } else if (FullName == "" && ShortName != "") { if (Right(ShortName,4) ~= ext) { FullName = ShortName; ShortName = Left(ShortName, Len(ShortName) - 4); } else FullName = ShortName $ ext; } else { if (!(Right(FullName,4) ~= ext)) FullName = FullName $ ext; ShortName = Left(FullName, Len(FullName) - 4); } } function String UsedMutators() { local int i; local String OutStr; while (i < AIncMutators.Count()) { if (OutStr != "") OutStr $= ","; OutStr $= AllMutators[int(AIncMutators.GetItem(i++))].ClassName; } return OutStr; } function bool HasURLOption(string ParamName, out string Value) { local string Param; local int i; Param = ParamName; while (true) { i = Instr(Param, "."); if (i < 0) break; Param = Mid(Param, i+1); } Value = Level.GetUrlOption(Param); return Value != ""; } function string NextPriv(out string PrivString) { local int pos; local string Priv; pos = Instr(PrivString, "|"); if (pos < 0) pos = Len(PrivString); EatStr(Priv, PrivString, Pos); if (PrivString != "") // Remove leading pipe char PrivString = Mid(PrivString, 1); return Priv; } function bool CanPerform(string privs) { local string priv; priv = NextPriv(privs); while (priv != "") { if (Level.Game.AccessControl.AllowPriv(priv) && CurAdmin.HasPrivilege(priv)) return true; priv = NextPriv(privs); } return false; } U[@UU| ]D9LhGwh*0|hj]hhh* GUZ ^xo<wl*[lI /^<{[[/&ppppu /^.inc GUhUU^ [\!~[PageFDefaultBGLPlayersBGLGameBGLConsoleBGL MutatorsBGLRestartBGL~ H%PlayersBGl xFGameBGl OConsoleBGl M MutatorsBGl {RestartBGl (PlayersURIpp?Page=%%GameURIpp?Page=F(ConsoleURIpp?Page=O)MutatorsURIpp?Page=M%BotsURIpp?Page=~(RestartURIpp?Page={GameLink%r PlayerLink&r ConsoleLink,r MutatorLink,r BotsLink,r RestartLink,r t GU@ u"EF =w *&| jp zpr ur  *u wu*u *w  *   w *      * *=    GUUUX E Lv1,{ /Ji'( GU UUUUD rCb HEwG*ws3w%wG *hG G h wG *G GhGwh*h hGhh G)rhrrGwssw GU@UUH @UU[ N uW  GUK K% GUT UUI yBz HEwH*xp3x%wH*XHHXwH*H HX H wX *X XH XXH)rHyyXxppx GUQ =' GU_ // ==================================================================== // Class: XWebAdmin.xWebQueryHandler // Parent: Engine.xAdminBase // // // ==================================================================== class xWebQueryHandler extends xAdminBase Within UTServerAdmin; var string DefaultPage; var string Title; var string NeededPrivs; function bool Init() {return true;} function bool PreQuery(WebRequest Request, WebResponse Response) { return true; } function bool Query(WebRequest Request, WebResponse Response) { return false; } function bool PostQuery(WebRequest Request, WebResponse Response) { return true; } // Called at end of match function Cleanup(); UU JU0#d .Mb  .r* uk%GameType%9V -% sj Nr\* b2w\* = % 7w\96 w6 w' %7[\ %N 7w#\ 6 w#%r#[*#[* =#[&6 w6 w -pa!n&{Jaddbotnum49JJaddnum0|JBotActionAddn, 44%n %M 4o %4% 0K%Action%g4& 1w%Action%g 9S4K%Action%g##|JBotActionRemove44%44% 0K%Action%e#4& 1w%Action%e# 9S4K%Action%e{Jselectbots-p % \#%# [-}{J%pppBotX9S .9S#-m{J$pppBot9S .9S#R [ #-}-m-}G7RwG*&Ga mR#| \ w\*4% %N \4 [  % \I 'SpeciesName\  Ip~_species#% # [ BotChecked %BotIndexpp9S .9S# )BotName [ #G7 [ # DisabledBots-p DisabledBots DISABLED wG* -BotColorTG 0BotTeamNameSGaBIp~_row_sel aBIp~_row# BotListIW u [4,tu [aB}p~_species_group  uttt [aB}p~_species_group aBDp~_species_groupu [ U LeftBotTable} RightBotTableD DisabledBots -p DisabledBots DISABLED  PageHelpM  Section,r  ~ GUD//============================================================================== // WebAdmin handler for modifying default game settings // // Written by Michael Comeau // Revised by Ron Prestenback // 2003,2004 Epic Games, Inc. All Rights Reserved //============================================================================== class xWebQueryDefaults extends xWebQueryHandler config; var config string DefaultsIndexPage; // Defaults Menu Page var config string DefaultsMapsPage; var config string DefaultsRulesPage; var config string DefaultsIPPolicyPage; // Special Case of Multi-part list page var config string DefaultsRestartPage; var config string DefaultsVotingGameConfigPage; // Custom Skin Support var config string DefaultsRowPage; var localized string DefaultsMapsLink; var localized string DefaultsIPPolicyLink; var localized string DefaultsRestartLink; var localized string IDBan; var localized string DefaultsVotingGameConfigLink; // Error messages var localized string ActiveMapNotFound; var localized string InactiveMapNotFound; var localized string CannotModify; var localized string NoteMapsPage; var localized string NoteRulesPage; var localized string NotePolicyPage; var localized string NoteVotingGameConfigPage; function bool Init() { local int i; if (GamePI == None) SetGamePI(""); for (i = 0; i < GamePI.Settings.Length; i++) if (GamePI.Settings[i].ExtraPriv != "" && InStr(NeededPrivs, GamePI.Settings[i].ExtraPriv) == -1) NeededPrivs = NeededPrivs $ "|" $ GamePI.Settings[i].ExtraPriv; return true; } function bool Query(WebRequest Request, WebResponse Response) { if (!CanPerform(NeededPrivs)) return false; MapTitle(Response); switch (Mid(Request.URI, 1)) { case DefaultPage: QueryDefaults(Request, Response); return true; // Done : General case DefaultsIndexPage: QueryDefaultsMenu(Request, Response); return true;// Done : General case DefaultsMapsPage: if (!MapIsChanging()) QueryDefaultsMaps(Request, Response); return true; case DefaultsRulesPage: if (!MapIsChanging()) QueryDefaultsRules(Request, Response); return true; case DefaultsIPPolicyPage: if (!MapIsChanging()) QueryDefaultsIPPolicy(Request, Response); return true; case DefaultsRestartPage: if (!MapIsChanging()) QueryRestartPage(Request, Response); return true; case DefaultsVotingGameConfigPage: if (!MapIsChanging()) QueryVotingGameConfig(Request, Response); return true; } return false; } //***************************************************************************** function QueryDefaults(WebRequest Request, WebResponse Response) { local String GameType, PageStr, Filter; // if no gametype specified use the first one in the list GameType = Request.GetVariable("GameType", String(Level.Game.Class)); // if no page specified, use the first one PageStr = Request.GetVariable("Page", DefaultsMapsPage); Filter = Eval(Request.GetVariable("Filter") != "", "&Filter="$ Request.GetVariable("Filter"), ""); Response.Subst("IndexURI", DefaultsIndexPage $ "?GameType=" $ GameType $ "&Page=" $ PageStr $ Filter); Response.Subst("MainURI", PageStr $ "?GameType=" $GameType $ Filter); ShowFrame(Response, DefaultPage); } function QueryDefaultsMenu(WebRequest Request, WebResponse Response) { local string GameType, Page, TempStr, Content; local int i; GameType = SetGamePI(Request.GetVariable("GameType", string(Level.Game.Class))); Page = Request.GetVariable("Page"); // set currently active page if (CanPerform("Mt")) { if (Request.GetVariable("GameTypeSet", "") != "") { TempStr = Request.GetVariable("GameTypeSelect", GameType); if (!(TempStr ~= GameType)) GameType = TempStr; } Response.Subst("GameTypeButton", SubmitButton("GameTypeSet", Update)); Response.Subst("GameTypeSelect", Select("GameType", GenerateGameTypeOptions(GameType))); } else Response.Subst("GameTypeSelect", Level.Game.Default.GameName); // set background colors Response.Subst("DefaultBG", DefaultBG); // for unused tabs // Set URIs Content = MakeMenuRow(Response, GameType $ "&Page=" $ DefaultsMapsPage, DefaultsMapsLink); for (i = 0; i" $ MakeMenuRow(Response, GameType $ "&Page=" $ DefaultsRestartPage, DefaultsRestartLink); Response.Subst("Content", Content); Response.Subst("Filter", Request.GetVariable("Filter", "")); Response.Subst("Page", Page); Response.Subst("PostAction", DefaultPage); ShowPage(Response, DefaultsIndexPage); } // TODO: add highlight code function string MakeMenuRow(WebResponse Response, string URI, string Title) { Response.Subst("URI", DefaultPage $ "?GameType=" $ URI); Response.Subst("URIText", Title); return WebInclude("defaults_menu_row"); } function QueryDefaultsMaps(WebRequest Request, WebResponse Response) { local String GameType, ListName, Tmp, MapName, MapURL; // Strings containing generated html (possibly move to .inc?) local string CustomMapSelect; local StringArray ExcludeMaps, IncludeMaps, MovedMaps; local int i, Count, MoveCount, id, CurrentList, Index; local array Arr; if (CanPerform("Ml")) { Request.Dump(); GameType = Request.GetVariable("GameType"); // provided by index page Index = Level.Game.MaplistHandler.GetGameIndex(GameType); // Get index of maplist from select Tmp = Request.GetVariable("MapListNum"); // Maybe viewing a non-active list if (Tmp != "") CurrentList = int(Tmp); else CurrentList = Level.Game.MaplistHandler.GetActiveList(Index); ListName = Level.Game.MaplistHandler.GetMapListTitle(Index, CurrentList); // Available maplists ExcludeMaps = ReloadExcludeMaps(GameType); IncludeMaps = ReloadIncludeMaps(ExcludeMaps, Index, CurrentList); MovedMaps = New(None) class'SortedStringArray'; Tmp = Request.GetVariable("MoveMap",""); // If name in textbox isn't the same as the name of the active list, // and we're moving maps, should track of name until we either save or cancel if (Tmp != "") { ListName = Request.GetVariable("ListName", ListName); switch (Tmp) { case " > ": case ">": Count = Request.GetVariableCount("ExcludeMapsSelect"); for (i = Count - 1; i >= 0; i--) { if (ExcludeMaps.Count() > 0) { MapURL = Request.GetVariableNumber("ExcludeMapsSelect", i); MapName = class'MaplistRecord'.static.GetBaseMapName(MapURL); id = IncludeMaps.MoveFrom(ExcludeMaps, MapName); if (id >= 0) { MovedMaps.CopyFromId(IncludeMaps, id); Level.Game.MaplistHandler.AddMap(Index, CurrentList, MapName $ MapURL); } else Log(InactiveMapNotFound$Request.GetVariableNumber("ExcludeMapsSelect", i),'WebAdmin'); } } break; case " < ": case "<": if (Request.GetVariableCount("IncludeMapsSelect") > 0) { Count = Request.GetVariableCount("IncludeMapsSelect"); for (i = Count-1; i >= 0; i--) { MapURL = Request.GetVariableNumber("IncludeMapsSelect", i); MapName = class'MaplistRecord'.static.GetBaseMapName(MapURL); if (IncludeMaps.Count() > 0) { id = ExcludeMaps.MoveFrom(IncludeMaps, MapName); if (id >= 0) { MovedMaps.CopyFromId(ExcludeMaps, id); Level.Game.MaplistHandler.RemoveMap(Index, CurrentList, MapName $ MapURL); } else Log(ActiveMapNotFound $ Request.GetVariableNumber("IncludeMapsSelect", i),'WebAdmin'); } } } break; case ">>": while (ExcludeMaps.Count() > 0) { id = IncludeMaps.MoveFromId(ExcludeMaps, ExcludeMaps.Count()-1); if (id >= 0) { MovedMaps.CopyFromId(IncludeMaps, id); Level.Game.MaplistHandler.AddMap(Index, CurrentList, IncludeMaps.GetItem(id)); } } break; case "<<": while (IncludeMaps.Count() > 0) { id = ExcludeMaps.MoveFromId(IncludeMaps, IncludeMaps.Count()-1); if (id >= 0) { MovedMaps.CopyFromId(ExcludeMaps, id); Level.Game.MaplistHandler.ClearList(Index, CurrentList); } } break; case "Up": MoveCount = int(Abs(float(Request.GetVariable("MoveMapCount")))); Count = Request.GetVariableCount("IncludeMapsSelect"); for (i = 0; i= 0) { Level.Game.MaplistHandler.ShiftMap(Index, CurrentList, IncludeMaps.GetItem(i), MoveCount); IncludeMaps.ShiftStrict(i, MoveCount); } } break; case "Down": MoveCount = int(Abs(float(Request.GetVariable("MoveMapCount")))); Count = Request.GetVariableCount("IncludeMapsSelect"); for (i = 0; i= 0; i--) { if (MovedMaps.FindItemId(IncludeMaps.GetItem(i)) >= 0) { Level.Game.MaplistHandler.ShiftMap(Index, CurrentList, IncludeMaps.GetItem(i), MoveCount); IncludeMaps.ShiftStrict(i, MoveCount); } } break; } } if (Request.GetVariable("Save") != "") { ListName = Request.GetVariable("ListName", ListName); UpdateCustomMapList(Index, CurrentList, ListName); } else if (Request.GetVariable("New") != "") { Arr.Length = 0; for (i = 0; i < IncludeMaps.Count(); i++) Arr[Arr.Length] = IncludeMaps.GetTag(i); Level.Game.MaplistHandler.ResetList(Index, CurrentList); CurrentList = Level.Game.MaplistHandler.AddList(GameType, Request.GetVariable("ListName", ListName), Arr); ExcludeMaps = ReloadExcludeMaps(GameType); IncludeMaps = ReloadIncludeMaps(ExcludeMaps, Index, CurrentList); } else if (Request.GetVariable("Use") != "") { ListName = Request.GetVariable("ListName", ListName); UpdateCustomMaplist(Index, CurrentList, ListName); Level.Game.MaplistHandler.ApplyMapList(Index, CurrentList); } else if (Request.GetVariable("Delete") != "") { CurrentList = Level.Game.MaplistHandler.RemoveList(Index, CurrentList); ListName = Level.Game.MaplistHandler.GetMapListTitle(Index, CurrentList); ExcludeMaps = ReloadExcludeMaps(GameType); IncludeMaps = ReloadIncludeMaps(ExcludeMaps, Index, CurrentList); } CustomMapSelect = GenerateMapListOptions(GameType, CurrentList); // Fill response values Response.Subst("GameType", GameType); Response.Subst("Session", "Session"); Response.Subst("MapListName", ListName); Response.Subst("MapListOptions", CustomMapSelect); Response.Subst("ExcludeMapsOptions", GenerateMapListSelect(ExcludeMaps, MovedMaps)); Response.Subst("IncludeMapsOptions", GenerateMapListSelect(IncludeMaps, MovedMaps)); Response.Subst("Section", DefaultsMapsLink); Response.Subst("PostAction", DefaultsMapsPage); Response.Subst("PageHelp", NoteMapsPage); Response.Dump(); ShowPage(Response, DefaultsMapsPage); } else AccessDenied(Response); } function QueryDefaultsRules(WebRequest Request, WebResponse Response) { local int i, j; local bool bMarked, bSave; local String GameType, Content, Data, Op, Mark, Filter, SecLevel, TempStr; local array Options; if (!CanPerform("Ms")) { AccessDenied(Response); return; } GameType = SetGamePI(Request.GetVariable("GameType")); Filter = Request.GetVariable("Filter"); bSave = Request.GetVariable("Save", "") != ""; Content = ""; Mark = WebInclude("defaults_mark"); Response.Subst("Section", Filter); Response.Subst("Filter", Filter); for (i = 0; i 1) Op = " ("$Options[0]$" - "$Options[1]$")"; Response.Subst("Content", Textbox(GamePI.Settings[i].SettingName, j, int(Data), HtmlEncode(GamePI.Settings[i].Value)) $ Op); Response.Subst("FormObject", WebInclude(NowrapLeft)); break; case PIT_Check: if (bSave && GamePI.Settings[i].Value == "") GamePI.StoreSetting(i, false); Response.Subst("Content", Checkbox(GamePI.Settings[i].SettingName, GamePI.Settings[i].Value ~= string(true), GamePI.Settings[i].Data != "")); Response.Subst("FormObject", WebInclude(NowrapLeft)); break; case PIT_Select: Data = ""; // Build a set of options from PID.Data GamePI.SplitStringToArray(Options, GamePI.Settings[i].Data, ";"); for (j = 0; (j+1)"$HtmlEncode(Options[j+1])$""); } Response.Subst("Content", Select(GamePI.Settings[i].SettingName, Data)); Response.Subst("FormObject", WebInclude(NowrapLeft)); break; } Content $= WebInclude(DefaultsRowPage); } } GamePI.SaveSettings(); if (Content == "") Content = CannotModify; Response.Subst("TableContent", Content); Response.Subst("PostAction", DefaultsRulesPage); Response.Subst("GameType", GameType); Response.Subst("SubmitValue", Accept); Response.Subst("PageHelp", NoteRulesPage); ShowPage(Response, DefaultsRulesPage); } function QueryDefaultsIPPolicy(WebRequest Request, WebResponse Response) { local int i, j; local bool bIpBan; local string policies, tmpN, tmpV; local string PolicyType; if (CanPerform("Xi")) { Response.Subst("Section", DefaultsIPPolicyLink); if (Request.GetVariable("Update") != "") { i = int(Request.GetVariable("IpNo", "-1")); if(i > -1 && ValidMask(Request.GetVariable("IPMask"))) { if (i >= Level.Game.AccessControl.IPPolicies.Length) { i = Level.Game.AccessControl.IPPolicies.Length; Level.Game.AccessControl.IPPolicies.Length = i+1; } Level.Game.AccessControl.IPPolicies[i] = Request.GetVariable("AcceptDeny")$";"$Request.GetVariable("IPMask"); Level.Game.AccessControl.SaveConfig(); } } if(Request.GetVariable("Delete") != "") { i = int(Request.GetVariable("IdNo", "-1")); if (i == -1) { bIpBan = True; i = int(Request.GetVariable("IpNo", "-1")); } if (i > -1) { if ( bIpBan && i < Level.Game.AccessControl.IPPolicies.Length ) { Level.Game.AccessControl.IPPolicies.Remove(i,1); Level.Game.AccessControl.SaveConfig(); } if ( !bIpBan && i < Level.Game.AccessControl.BannedIDs.Length ) { Level.Game.AccessControl.BannedIDs.Remove(i,1); Level.Game.AccessControl.SaveConfig(); } } } Policies = ""; if (Level.Game.AccessControl.bBanById) { for (i = 0; i < Level.Game.AccessControl.BannedIds.Length; i++) { j = InStr(Level.Game.AccessControl.BannedIDs[i], " "); tmpN = Mid(Level.Game.AccessControl.BannedIDs[i], j + 1); tmpV = Left(Level.Game.AccessControl.BannedIDs[i], j); Response.Subst("PolicyType", IDBan); Response.Subst("PolicyCell", tmpN $ ":" @ tmpV $ "  "); Response.Subst("PostAction", DefaultsIPPolicyPage $ "?IDNo="$string(i)); Response.Subst("UpdateButton", ""); Policies = Policies $ WebInclude(DefaultsIPPolicyPage $ "_row"); } } for(i=0; i"; PolicyType = PolicyType $ RadioButton("AcceptDeny", "DENY", tmpN ~= "DENY") @ Deny; Response.Subst("PolicyType", PolicyType); Response.Subst("PolicyCell", Textbox("IPMask", 15, 25, tmpV) $ "  "); Response.Subst("PostAction", DefaultsIPPolicyPage $ "?IpNo="$string(i)); Response.Subst("UpdateButton", SubmitButton("Update", Update)); Policies = Policies $ WebInclude(DefaultsIPPolicyPage $ "_row"); } Response.Subst("Policies", policies); Response.Subst("PostAction", DefaultsIPPolicyPage$"?IpNo="$string(i)); Response.Subst("PageHelp", NotePolicyPage); ShowPage(Response, DefaultsIPPolicyPage); } else AccessDenied(Response); } function QueryVotingGameConfig(WebRequest Request, WebResponse Response) { local int i, j, k, x, columns, count, GameConfigIndex; local string PageText, GameConfigData, ColumnTitle, Value; local array Parts; local array MutatorList; if (CanPerform("Ms")) { Response.Subst("Section", DefaultsVotingGameConfigLink); PageText = ""; // make headers i=0; while( Level.Game.VotingHandler.GetConfigArrayColumnTitle("GameConfig",i) != "" ) { PageText = PageText $ "" $ Level.Game.VotingHandler.GetConfigArrayColumnTitle("GameConfig",i) $ ""; i++; } columns = i; Response.Subst("ColumnTitles", PageText); GameConfigIndex = int(Request.GetVariable("GameConfigIndex", "-1")); if (Request.GetVariable("Update") != "") { if( GameConfigIndex > -1 ) { for( j=0; j < columns; j++ ) { ColumnTitle = Level.Game.VotingHandler.GetConfigArrayColumnTitle("GameConfig",j); Value = ""; if ( j == 4 ) // Mutators - retrieve all selected mutators { count = Request.GetVariableCount(ColumnTitle); for ( k = 0; k < count; k++ ) { if( Request.GetVariableNumber(ColumnTitle, k) ~= "NONE" ) { Value = "NONE"; // dont allow any other mutators if none break; } if ( Value != "" ) Value $= ","; Value $= Request.GetVariableNumber(ColumnTitle, k); } } else Value = Request.GetVariable(ColumnTitle); Level.Game.VotingHandler.UpdateConfigArrayItem("GameConfig", GameConfigIndex, j, Value); } Level.Game.VotingHandler.SaveConfig(); GameConfigIndex = -1; } } if(Request.GetVariable("Delete") != "") { if (GameConfigIndex > -1) { Level.Game.VotingHandler.DeleteConfigArrayItem("GameConfig", GameConfigIndex); Level.Game.VotingHandler.SaveConfig(); GameConfigIndex = -1; } } if(Request.GetVariable("New") != "") { Level.Game.VotingHandler.AddConfigArrayItem("GameConfig"); Level.Game.VotingHandler.SaveConfig(); } PageText = ""; for( i=0; i"; for( j=0; j < columns; j++) { PageText $= ""; GameConfigData = Level.Game.VotingHandler.GetConfigArrayData("GameConfig", i, j); Split(GameConfigData, ";", Parts); // split "type;maxlength;value" // 0 1 2 if( i == GameConfigIndex ) { switch( Caps(Parts[0]) ) // type { case "TEXT": //TextBox(string TextName, coerce string Size, coerce string MaxLength, optional string DefaultValue) PageText $= Textbox(Level.Game.VotingHandler.GetConfigArrayColumnTitle("GameConfig",j), 15, int(Parts[1]), Parts[2]); break; case "GAMETYPE": PageText $= Select(Level.Game.VotingHandler.GetConfigArrayColumnTitle("GameConfig",j), GenerateGameTypeOptions(Parts[2])); break; case "MUTATORS": PageText $= ""; break; } } else { switch( Caps(Parts[0]) ) // type { case "TEXT": PageText $= Parts[2]; break; case "GAMETYPE": // translate game class name to friendly name for(k=0; k < AllGames.Length; k++) { if( Parts[2] ~= AllGames[k].ClassName ) { PageText $= AllGames[k].GameName; break; } } break; case "MUTATORS": // translate mutator class names to friendly names for display Split( Parts[2], ",", MutatorList); for(x=0; x < MutatorList.Length; x++) { for(k=0; k < AllMutators.Length; k++) { if( MutatorList[x] ~= AllMutators[k].ClassName ) { PageText $= AllMutators[k].FriendlyName; if( x < MutatorList.Length - 1 ) PageText $= ","; break; } } } break; } } PageText $= ""; } PageText $= ""; if( i == GameConfigIndex ) { PageText $= SubmitButton("Update", Update); PageText $= SubmitButton("Delete", DeleteText); } else PageText $= SubmitButton("Edit",Edit); PageText $= ""; } PageText $= "
"; PageText $= SubmitButton("New", NewText); PageText $= "
"; Response.Subst("GameConfigs", PageText); Response.Subst("PageHelp", NoteVotingGameConfigPage); ShowPage(Response, DefaultsVotingGameConfigPage); } else AccessDenied(Response); } // evo --- function bool ValidMask(string mask) { local int i; local string Octets[4]; local string tmp; // First check each octet to make sure it's a byte while (mask != "") { if (Left(mask,1) == ".") { if (!ValidOctet(tmp)) return false; Octets[i++] = tmp; Mask = Mid(Mask,1); tmp = ""; } EatStr(tmp, Mask, 1); } if (!ValidOctet(tmp)) return false; Octets[i++] = tmp; // Check to make sure we only have 4 valid bytes if (i > 4) return false; return true; } function bool ValidOctet(string tmp) { local int i; if (tmp == "") return false; if (ValidMaskOctet(tmp)) return true; i = int(tmp); if (i == 0 && tmp != "0") return false; if (i < 0 || i > 255) return false; return true; } function bool ValidMaskOctet(string tmp) { local string s; if (tmp == "" || len(tmp) > 3 || right(tmp,1) != "*") return false; while (tmp != "") { s = left(tmp,1); if (s == "*") break; if (s < "0" || s > "9") return false; tmp = mid(tmp,1); } return true; } // --- evo Uf UUO ANaTest: Init 'B' *  (B jBp => Test=9V * (AjATest: AddSort 'A' - p => Test=9V  Vw*ppppp => Tag=( Prev=9V  Next=9V* (DjDTest: AddSort 'D' - p => Test=9V  Pw*ppppp => Tag=( Prev=9V  Next=9V* (CjCTest: AddSort 'C' - p => Test=9V  Jw*ppppp => Tag=( Prev=9V  Next=9VTest: Delete 'C' " Cp => Test=9V  w*ppppp => Tag=( Prev=9V  Next=9VTest: Delete 'D' " Dp => Test=9V  w*ppppp => Tag=( Prev=9V  Next=9V_Test: Delete 'A' " Ap => Test=9V  w*ppppp => Tag=( Prev=9V  Next=9V#Test: Delete 'B' " Bp => Test=9V  ^w*ppppp => Tag=( Prev=9V  Next=9V GY eV x$xUUp*// ==================================================================== // Class: xWebAdmin.ObjectArray // Parent: Core.Object // // // ==================================================================== class ObjectArray extends Object; struct ArrayItem { var object item; var string tag; }; var protected array AllItems; var protected bool ReverseSort; // ObjectArray members must always be unique function Add(object item, string tag) { InsertAt(AllItems.Length, item, tag); } protected function SetAt(int pos, object item, string tag) { // Increase array if necessary if (AllItems.Length <= pos) AllItems.Length = (pos+1); AllItems[pos].item = item; AllItems[pos].tag = tag; } protected function InsertAt(int pos, object item, string tag) { // See if need to insert or increase length if (pos < AllItems.Length) AllItems.Insert(pos, 1); else AllItems.Length = (pos+1); AllItems[pos].item = item; AllItems[pos].tag = tag; } // User Prepare if you know the number of items that will be inserted function SetSize(int NewSize) { // HACK: This is to pre-allocate the space in the FArray // It should prevent a bunch of Realloc() AllItems.Length = NewSize; AllItems.Length = 0; } function Reset() { AllItems.Length = 0; } function int Count() { return AllItems.Length; } function int FindItemId(object item) { local int i; for (i=0; i= AllItems.Length) return false; AllItems.Remove(index, 1); return true; } function object GetItem(int index) { return AllItems[index].item; } function string GetTag(int index) { return AllItems[index].tag; } function int CopyTo(ObjectArray arr, string Tag) { local int i; i = FindTagId(Tag); if (i >= 0) arr.Add(AllItems[i].item, AllItems[i].tag); return i; } function int CopyItemTo(ObjectArray arr, object item) { local int i; i = FindItemId(item); if (i >= 0) arr.Add(AllItems[i].item, AllItems[i].tag); return i; } // 0 = Sort lowest to highest (A first, Z last) // 1 = Reverse sort (Z first, A last) singular function SetSortOrder(bool Order) { ReverseSort = Order; } singular function ToggleSort() { ReverseSort = !ReverseSort; } function bool IsBefore(string test, string tag) { return ((!ReverseSort && Caps(test) < Caps(tag)) || (ReverseSort && Caps(test) > Caps(tag))); } U^Xuip in |untitledib#|i,.ut2aBii}i,aBiiaBiXSubTitlei GUC oj0Aggo editwg*G ,g-mms-z{osubmitt* =W%Wmt@m Wm WW9W%(Wtrt Wvm r-{o r-zcg )v`-g {v-g 6vEGroupNamervg )vv checkedECheckedvaBsusers_groups_rowW[-zE.NameValuegEGroupRowssEPostActionCE3SectionAgEPageHelpwECvw %Action%Gvv%Item%` ETv E[ %Item%` E GU` @UU`//============================================================================== // WebAdmin handler for activities related to the game currently in // progress on the server // // Written by Michael Comeau // Revised by Ron Prestenback // 2003,2004 Epic Games, Inc. All Rights Reserved //============================================================================== class xWebQueryCurrent extends xWebQueryHandler config; var config string CurrentIndexPage; // This is the page with the Menu var config string CurrentPlayersPage; var config string CurrentGamePage; var config string CurrentConsolePage; var config string CurrentConsoleLogPage; var config string CurrentConsoleSendPage; var config string CurrentMutatorsPage; var config string CurrentBotsPage; var config string CurrentRestartPage; var config string DefaultSendText; var config string StatTable; var config string StatTableRow; // Custom Skin Support var config string PlayerListHeader; var config string PlayerListLinkedHeader; var config string PlayerListMinPlayers; var config string ConsoleRefreshTag; var config string MutatorTablePage; var config string MutatorGroupTitle; var config string MutatorGroupMember; // Localization // Sections & Titles var localized string BadGameType; var localized string CurrentLinks[6]; var localized string NoBotsTitle; // Labels var localized string KickButtonText[3]; var localized string NoPlayersConnected; var localized string SelectedMutators; var localized string PickMutators; var localized string GameTypeUnsupported; var localized string NoBots; var localized string Added; var localized string Removed; var localized string BotStatus; var localized string SingleBotStatus; var localized string ConsoleUserlist; // Help messages var localized string NoteGamePage; var localized string NotePlayersPage; var localized string NoteConsolePage; var localized string NoteMutatorsPage; var localized string NoteBotsPage; var StringArray SpeciesNames; var array BotList; // Sorted bot list by species function bool Query(WebRequest Request, WebResponse Response) { if (!CanPerform(NeededPrivs)) return false; switch (Mid(Request.URI, 1)) { case DefaultPage: QueryCurrentFrame(Request, Response); return true; case CurrentIndexPage: QueryCurrentMenu(Request, Response); return true; case CurrentPlayersPage: if (!MapIsChanging()) QueryCurrentPlayers(Request, Response); return true; case CurrentGamePage: if (!MapIsChanging()) QueryCurrentGame(Request, Response); return true; case CurrentConsolePage: if (!MapIsChanging()) QueryCurrentConsole(Request, Response); return true; case CurrentConsoleLogPage: if (!MapIsChanging()) QueryCurrentConsoleLog(Request, Response); return true; case CurrentConsoleSendPage: QueryCurrentConsoleSend(Request, Response); return true; case CurrentMutatorsPage: if (!MapIsChanging()) QueryCurrentMutators(Request, Response); return true; case CurrentBotsPage: if (!MapIsChanging()) QueryCurrentBots(Request, Response); return true; case CurrentRestartPage: if (!MapIsChanging()) QueryRestartPage(Request, Response); return true; } return false; } //***************************************************************************** function QueryCurrentFrame(WebRequest Request, WebResponse Response) { local String Page; // if no page specified, use the default Page = Request.GetVariable("Page", CurrentGamePage); Response.Subst("IndexURI", CurrentIndexPage$"?Page="$Page); Response.Subst("MainURI", Page); ShowFrame(Response, DefaultPage); } function QueryCurrentMenu(WebRequest Request, WebResponse Response) { local String Page; Page = Request.GetVariable("Page", CurrentGamePage); // set background colors Response.Subst("DefaultBG", DefaultBG); // for unused tabs Response.Subst("PlayersBG", DefaultBG); Response.Subst("GameBG", DefaultBG); Response.Subst("ConsoleBG", DefaultBG); Response.Subst("MutatorsBG",DefaultBG); Response.Subst("RestartBG", DefaultBG); switch(Page) { case CurrentPlayersPage: Response.Subst("PlayersBG", HighlightedBG); break; case CurrentGamePage: Response.Subst("GameBG", HighlightedBG); break; case CurrentConsolePage: Response.Subst("ConsoleBG", HighlightedBG); break; case CurrentMutatorsPage: Response.Subst("MutatorsBG",HighlightedBG); break; case CurrentRestartPage: Response.Subst("RestartBG", HighlightedBG); break; } // Set URIs Response.Subst("PlayersURI", DefaultPage$"?Page="$CurrentPlayersPage); Response.Subst("GameURI", DefaultPage$"?Page="$CurrentGamePage); Response.Subst("ConsoleURI", DefaultPage$"?Page="$CurrentConsolePage); Response.Subst("MutatorsURI", DefaultPage$"?Page="$CurrentMutatorsPage); Response.Subst("BotsURI", DefaultPage$"?Page="$CurrentBotsPage); Response.Subst("RestartURI", DefaultPage$"?Page="$CurrentRestartPage); // Set link text Response.Subst("GameLink", CurrentLinks[0]); Response.Subst("PlayerLink", CurrentLinks[1]); Response.Subst("ConsoleLink", CurrentLinks[2]); Response.Subst("MutatorLink", CurrentLinks[3]); Response.Subst("BotsLink", CurrentLinks[4]); Response.Subst("RestartLink", CurrentLinks[5]); ShowPage(Response, CurrentIndexPage); } function QueryCurrentPlayers(WebRequest Request, WebResponse Response) { local string Sort, PlayerListSubst, TempStr, TempTag, TempData; local string TableHeaders, GameType, Reverse, ColorNames[2], Last; local StringArray PlayerList; local Controller P, NextP; local int i, Cols, mlength; local string IP, ID; local bool bCanKick, bCanBan, bCanKickBots; Response.Subst("Section", CurrentLinks[1]); Response.Subst("PostAction", CurrentPlayersPage); ColorNames[0] = class'TeamInfo'.default.ColorNames[0]; ColorNames[1] = class'TeamInfo'.default.ColorNames[1]; MLength = int(Eval(Len(ColorNames[0]) > Len(ColorNames[1]), string(Len(ColorNames[0])), string(Len(ColorNames[1])))); if (CanPerform("Xp|Kp|Kb|Ko")) { PlayerList = new(None) class'SortedStringArray'; Sort = Request.GetVariable("Sort", "Name"); Last = Request.GetVariable("Last"); Response.Subst("Sort", Sort); Cols = 0; bCanKick = CanPerform("Kp"); bCanBan = CanPerform("Kb"); bCanKickBots = CanPerform("Ko|Mb"); if (Last == Sort && Request.GetVariable("ReverseSort") == "") { PlayerList.ToggleSort(); Reverse = "?ReverseSort=True"; } else Reverse = ""; // Count the number of Columns allowed if (bCanKick || bCanBan || bCanKickBots) { // Use 'do-while' to avoid access-none when destroying Controllers within the loop P = Level.ControllerList; if (P != None) { do { NextP = P.NextController; if( PlayerController(P) != None && P.PlayerReplicationInfo != None && NetConnection(PlayerController(P).Player) != None) { if ( bCanBan && Request.GetVariable("Ban" $ string(P.PlayerReplicationInfo.PlayerID)) != "" ) Level.Game.AccessControl.KickBanPlayer(PlayerController(P)); else if ( bCanKick && Request.GetVariable("Kick" $ string(P.PlayerReplicationInfo.PlayerID)) != "" ) Level.Game.AccessControl.KickPlayer(PlayerController(P)); } else if ( PlayerController(P) == None && bCanKickBots && P.PlayerReplicationInfo != None && Request.GetVariable("Kick" $ string(P.PlayerReplicationInfo.PlayerID)) != "") { // Kick Bots P.Destroy(); } P = NextP; } until (P == None); } if (bCanKick || bCanKickBots) Cols += 1; if (bCanBan) Cols += 2; Response.Subst("KickButton", SubmitButton("Kick", KickButtonText[Cols-1])); // Build of valid TableHeaders TableHeaders = ""; if (bCanKick || bCanKickBots) { Response.Subst("HeadTitle", "Kick"); TableHeaders $= WebInclude(PlayerListHeader); } if (bCanBan) { Response.Subst("HeadTitle", "Ban"); TableHeaders $= WebInclude(PlayerListHeader); } if (Sort ~= "Name") Response.Subst("ReverseSort", Reverse); else Response.Subst("ReverseSort", ""); Response.Subst("HeadTitle", "Name"); TableHeaders $= WebInclude(PlayerListLinkedHeader); if (Level.Game.GameReplicationInfo.bTeamGame) { if (Sort ~= "Team") Response.Subst("ReverseSort", Reverse); else Response.Subst("ReverseSort", ""); Response.Subst("HeadTitle", "Team"); TableHeaders $= WebInclude(PlayerListLinkedHeader); } if (Sort ~= "Ping") Response.Subst("ReverseSort", Reverse); else Response.Subst("ReverseSort", ""); Response.Subst("HeadTitle", "Ping"); TableHeaders $= WebInclude(PlayerListLinkedHeader); if (Sort ~= "Score") Response.Subst("ReverseSort", Reverse); else Response.Subst("ReverseSort", ""); Response.Subst("HeadTitle", "Score"); TableHeaders $= WebInclude(PlayerListLinkedHeader); Response.Subst("HeadTitle", "IP"); TableHeaders $= WebInclude(PlayerListHeader); // evo --- if (Level.Game.AccessControl.bBanbyID) { Response.Subst("HeadTitle", "Global ID"); TableHeaders $= WebInclude(PlayerListHeader); } // --- evo Response.Subst("TableHeaders", TableHeaders); } if (CanPerform("Ms")) { GameType = Level.GetItemName(SetGamePI(GameType)); if (GamePI != None && GamePI.Settings[GamePI.FindIndex(GameType$".MinPlayers")].SecLevel <= CurAdmin.MaxSecLevel()) { if ((Request.GetVariable("SetMinPlayers", "") != "") && UnrealMPGameInfo(Level.Game) != None) { UnrealMPGameInfo(Level.Game).MinPlayers = Min(Max(int(Request.GetVariable("MinPlayers", String(0))), 0), 32); Level.Game.SaveConfig(); } Response.Subst("MinPlayers", string(UnrealMPGameInfo(Level.Game).MinPlayers)); Response.Subst("MinPlayerPart", WebInclude(PlayerListMinPlayers)); } else { Response.Subst("MinPlayers", ""); Response.Subst("MinPlayersPart", ""); } } for (P=Level.ControllerList; P!=None; P=P.NextController) { TempData = ""; if (!P.bDeleteMe && P.bIsPlayer && P.PlayerReplicationInfo != None) { Response.Subst("Content", CheckBox("Kick" $ string(P.PlayerReplicationInfo.PlayerID), False)); if (CanPerform("Kp")) TempData $= WebInclude(CellCenter); if (CanPerform("Kb")) { if ( PlayerController(P) != None ) Response.Subst("Content", Checkbox("Ban" $ string(P.PlayerReplicationInfo.PlayerID), False)); else Response.Subst("Content", ""); TempData $= WebInclude(CellCenter); } TempStr = ""; if (DeathMatch(Level.Game) != None && DeathMatch(Level.Game).bTournament && P.PlayerReplicationInfo.bReadyToPlay) TempStr = " (Ready) "; else if (P.PlayerReplicationInfo.bIsSpectator) TempStr = " (Spectator) "; else if (PlayerController(P) == None) TempStr = " (Bot) "; if( PlayerController(P) != None ) { IP = PlayerController(P).GetPlayerNetworkAddress(); IP = HtmlEncode(" " $ Left(IP, InStr(IP, ":"))); // evo --- ID = HtmlEncode(" " $ Eval(Level.Game.AccessControl.bBanbyID, PlayerController(P).GetPlayerIDHash(), " ")); // --- evo } else { IP = HtmlEncode(" "); ID = HtmlEncode(" "); } Response.Subst("Content", HtmlEncode(P.PlayerReplicationInfo.PlayerName $ TempStr)); TempData $= WebInclude(NowrapLeft); if (Level.Game.bTeamGame) { if (P.PlayerReplicationInfo.Team != None && P.PlayerReplicationInfo.Team.TeamIndex < 4) Response.Subst("Content", ""$HtmlEncode(" ")$""$HtmlEncode(P.PlayerReplicationInfo.Team.GetHumanReadableName())); else if (P.PlayerReplicationInfo.bIsSpectator) Response.Subst("Content", HtmlEncode(" ")); TempData $= WebInclude(NowrapCenter); } Response.Subst("Content", string(P.PlayerReplicationInfo.Ping*4)); TempData $= WebInclude(CellCenter); Response.Subst("Content", string(int(P.PlayerReplicationInfo.Score))); TempData $= WebInclude(CellCenter); Response.Subst("Content", IP); TempData $= WebInclude(CellCenter); if (Level.Game.AccessControl.bBanbyID) { Response.Subst("Content", ID); TempData $= WebInclude(CellCenter); } switch (Sort) { case "Name": TempTag = P.PlayerReplicationInfo.PlayerName; break; case "Team": // Ordered by Team, then subordered by last selected sort method TempTag = PadRight(class'TeamInfo'.default.ColorNames[P.PlayerReplicationInfo.Team.TeamIndex],MLength,"0"); switch (Last) { case "Name": TempTag $= P.PlayerReplicationInfo.PlayerName; break; case "Ping": TempTag $= PadLeft(string(P.PlayerReplicationInfo.Ping*4), 5, "0"); break; default: TempTag $= PadLeft(string(int(P.PlayerReplicationInfo.Score)), 4, "0"); break; } break; case "Ping": TempTag = PadLeft(string(P.PlayerReplicationInfo.Ping*4), 5, "0"); break; default: TempTag = PadLeft(string(int(P.PlayerReplicationInfo.Score)), 4, "0"); break; } Response.Subst("RowContent", TempData); PlayerList.Add( WebInclude(RowLeft), TempTag); } } PlayerListSubst = ""; if (PlayerList.Count() > 0) { for ( i=0; i GameClass; local string NewGameType, SwitchButtonName, GameState, NewMap; local bool bMakeChanges; local Controller C; local xPlayer XP; local TeamPlayerReplicationInfo PRI; local int i, MultiKills, Sprees, GameIndex; if (CanPerform("Mt|Mm")) { if (Request.GetVariable("SwitchGameTypeAndMap", "") != "") { if (CanPerform("Mt")) ServerChangeMap(Request, Response, Request.GetVariable("MapSelect"), Request.GetVariable("GameTypeSelect")); else AccessDenied(Response); return; } else if (Request.GetVariable("SwitchMap", "") != "") { if (CanPerform("Mm|Mt")) { NewMap = Request.GetVariable("MapSelect"); Level.ServerTravel(NewMap$"?game="$Level.Game.Class$"?mutator="$UsedMutators(), false); ShowMessage(Response, WaitTitle, Repl(MapChangingTo, "%MapName%", NewMap)); } else AccessDenied(Response); return; } bMakeChanges = (Request.GetVariable("ApplySettings", "") != ""); if (CanPerform("Mt") && (bMakeChanges || Request.GetVariable("SwitchGameType", "") != "")) { NewGameType = Request.GetVariable("GameTypeSelect"); GameClass = class(DynamicLoadObject(NewGameType, class'Class')); } else GameClass = None; if (GameClass == None) { GameClass = Level.Game.Class; NewGameType = String(GameClass); } GameIndex = Level.Game.MaplistHandler.GetGameIndex(NewGameType); ExcludeMaps = ReloadExcludeMaps(NewGameType); IncludeMaps = ReloadIncludeMaps(ExcludeMaps, GameIndex, Level.Game.MaplistHandler.GetActiveList(GameIndex)); GameState = ""; // Show game status if admin has necessary privs if (CanPerform("Ma")) { if (Level.Game.NumPlayers > 0) { for (C = Level.ControllerList; C != None; C = C.NextController) { MultiKills = 0; Sprees = 0; PRI = None; XP = xPlayer(C); if (XP != None && !XP.bDeleteMe) { if (TeamPlayerReplicationInfo(XP.PlayerReplicationInfo) != None) PRI = TeamPlayerReplicationInfo(XP.PlayerReplicationInfo); if (PRI != None) { Response.Subst("PlayerName", HtmlEncode(PRI.PlayerName)); Response.Subst("Kills", string(PRI.Kills)); Response.Subst("Deaths", string(PRI.Deaths)); Response.Subst("Suicides",string(PRI.Suicides)); for (i = 0; i < 7; i++) MultiKills += PRI.MultiKills[i]; Response.Subst("MultiKills", string(MultiKills)); for (i = 0; i < 6; i++) Sprees += PRI.Spree[i]; Response.Subst("Sprees", string(Sprees)); GameState $= WebInclude(StatTableRow); } } } } else GameState = ""@NoPlayersConnected@""; Response.Subst("StatRows", GameState); Response.Subst("GameState", WebInclude(StatTable)); } if (GameClass == Level.Game.Class) { SwitchButtonName="SwitchMap"; MovedMaps = New(None) Class'SortedStringArray'; MovedMaps.CopyFromId(IncludeMaps, IncludeMaps.FindTagId(Left(string(Level), InStr(string(Level), ".")))); } else SwitchButtonName="SwitchGameTypeAndMap"; if (CanPerform("Mt")) { Response.Subst("Content", Select("GameTypeSelect", GenerateGameTypeOptions(NewGameType))); Response.Subst("GameTypeButton", SubmitButton("SwitchGameType", SwitchText)); } else Response.Subst("Content", Level.Game.Default.GameName); Response.Subst("GameTypeSelect", WebInclude(CellLeft)); Response.Subst("Content", Select("MapSelect", GenerateMapListSelect(IncludeMaps, MovedMaps))); Response.Subst("MapSelect", WebInclude(CellLeft)); Response.Subst("MapButton", SubmitButton(SwitchButtonName, SwitchText)); Response.Subst("PostAction", CurrentGamePage); Response.Subst("Section", CurrentLinks[0]); Response.Subst("PageHelp", NoteGamePage); MapTitle(Response); ShowPage(Response, CurrentGamePage); } else AccessDenied(Response); } function QueryCurrentConsole(WebRequest Request, WebResponse Response) { local String SendStr, OutStr; if (CanPerform("Xc")) { SendStr = Request.GetVariable("SendText", ""); if (SendStr != "" && !(Left(SendStr, 6) ~= "debug " || SendStr ~= "debug")) { if (Left(SendStr, 4) ~= "say ") Level.Game.Broadcast(Spectator, Mid(SendStr, 4), 'Say'); else if (SendStr ~= "pause") { if (Level.Pauser == None) Level.Pauser = Spectator.PlayerReplicationInfo; else Level.Pauser = None; } else if (SendStr ~= "dump") Spectator.Dump(); else if ((Left(SendStr, 4) ~= "get " || Left(SendStr,4) ~= "set ") && (InStr(Caps(SendStr), "XADMINCONFIG") != -1 || !CanPerform("Ms")) ) { if ( InStr(Caps(SendStr), "XADMINCONFIG") != -1 ) { StatusError(Response, ConsoleUserlist); ShowMessage(Response, Error, ""); log("User attempted to modify or enumerate admin account information illegally using the webadmin console. User:"$Request.Username$".",'WebAdmin'); } else if ( !CanPerform("Ms") ) AccessDenied(Response); } else { OutStr = Level.ConsoleCommand(SendStr); if (OutStr != "") Spectator.AddMessage(None, OutStr, 'Console'); } } Response.Subst("LogURI", CurrentConsoleLogPage); Response.Subst("SayURI", CurrentConsoleSendPage); ShowPage(Response, CurrentConsolePage); } else AccessDenied(Response); } function QueryCurrentConsoleLog(WebRequest Request, WebResponse Response) { local String LogSubst, LogStr; local int i; if (CanPerform("Xc")) { Response.Subst("Section", CurrentLinks[2]); Response.Subst("SubTitle", Level.Game.GameReplicationInfo.GameName$" in "$Level.Title); i = Spectator.LastMessage(); LogStr = HtmlEncode(Spectator.NextMessage(i)); while (LogStr != "") { LogSubst = LogSubst$"> "$LogStr$"
"; LogStr = HtmlEncode(Spectator.NextMessage(i)); } Response.Subst("RefreshMeta", ConsoleRefreshTag $ CurrentConsoleLogPage $ "#END\">"); Response.Subst("LogText", LogSubst); Response.Subst("PageHelp", NoteConsolePage); MapTitle(Response); ShowPage(Response, CurrentConsoleLogPage); } else AccessDenied(Response); } function QueryCurrentConsoleSend(WebRequest Request, WebResponse Response) { if (CanPerform("Xc")) { Response.Subst("DefaultSendText", DefaultSendText); Response.Subst("PostAction", CurrentConsolePage); ShowPage(Response, CurrentConsoleSendPage); } else AccessDenied(Response); } function QueryCurrentMutators(WebRequest Request, WebResponse Response) { local int i, j, k, z; local string selectedmutes, lastgroup, nextgroup, thisgroup, Checked, tmp; local StringArray GroupedMutators, SoloMutators; if (CanPerform("Mu")) { SoloMutators = new(None) class'SortedStringArray'; GroupedMutators = new(None) class'StringArray'; if (Request.GetVariable("SetMutes", "") != "") { AIncMutators.Reset(); lastgroup = ""; for (i = 0; i= 0, " checked", ""); Response.Subst("Checked", Checked); selectedmutes $= WebInclude(MutatorGroupMember); lastgroup = thisgroup; } for (i = 0; i < SoloMutators.Count(); i++) { tmp = ""; // Some sort of bug in WebInclude...must empty this var each time I use it j = int(SoloMutators.GetItem(i)); Response.Subst("Content", CheckBox(AllMutators[j].ClassName, AIncMutators.FindItemId(string(j)) >= 0) $ " " $ AllMutators[j].FriendlyName); tmp = WebInclude(NowrapLeft); Response.Subst("Content", AllMutators[j].Description); Response.Subst("RowContent", tmp $ WebInclude(CellLeft)); selectedmutes $= WebInclude(RowLeft); } Response.Subst("TableTitle", PickMutators); Response.Subst("TableRows", selectedmutes); Response.Subst("ChooseTable", WebInclude(MutatorTablePage)); MapTitle(Response); Response.Subst("Section", CurrentLinks[3]); Response.Subst("PageHelp", NoteMutatorsPage); Response.Subst("PostAction", CurrentMutatorsPage); ShowPage(Response, CurrentMutatorsPage); } else AccessDenied(Response); } function QueryCurrentBots(WebRequest Request, WebResponse Response) { local array PlayerRecords; local string OutStr, BotName, LeftTable, RightTable; local int i, j, BotCount, maxbots, cnt, Col1Count; local xBot B; local bool oldstate, newstate, bInMatch; local DeathMatch DM; if (!CanPerform("Mb")) { AccessDenied(Response); return; } DM = DeathMatch(Level.Game); if (DM == None) { ShowMessage(Response, BadGameType, Repl(GameTypeUnsupported, "%GameType%", string(Level.Game.Class))); return; } // Disable any type of Bots controls when stats are on if (DM.bEnableStatLogging && DM.NumBots == 0) { ShowMessage(Response, NoBotsTitle, NoBots); return; } // Make a sorted list of all species and group bots if (SpeciesNames == None) { class'xUtil'.static.GetPlayerList(PlayerRecords); SpeciesNames = new(None) class'SortedStringArray'; for (i = 0; i= 0 && BotList[j] == None) BotList[j] = new(None) class'SortedStringArray'; // Add the player record to the BotList BotList[j].Add(PlayerRecords[i].DefaultName, PlayerRecords[i].DefaultName); } } bInMatch = Level.Game.IsInState('MatchInProgress'); if (Request.GetVariable("addbotnum", "") != "") { BotCount = int(Request.GetVariable("addnum", "0")); if (Request.GetVariable("BotAction", "") ~= "Add") { maxbots = 32-(DM.NumPlayers + DM.NumBots); BotCount = Clamp(BotCount, 0, maxbots); for (i=0;i Col1Count ) { // Account for any species that contained a large number of bots by adding smaller // species to the first column Col1Count += Botlist[i].Count(); LeftTable $= WebInclude(CurrentBotsPage $ "_species_group"); } else RightTable $= WebInclude(CurrentBotsPage $ "_species_group"); } cnt += BotList[i].Count(); } } Response.Subst("LeftBotTable", LeftTable); Response.Subst("RightBotTable", RightTable); // If not in match, make sure that the bots selection button is disabled Response.Subst("DisabledBots", ""); if (!bInMatch) Response.Subst("DisabledBots", " DISABLED"); MapTitle(Response); Response.Subst("PageHelp", NoteBotsPage); Response.Subst("Section", CurrentLinks[4]); ShowPage(Response, CurrentBotsPage); } function xBot FindPlayingBot(string BotName) // Returns -1 on failure, or index for team/color { local Controller C; local xBot B; for (C = Level.ControllerList; C != None; C = C.NextController) { B = xBot(C); if (B != None) if (B.PlayerReplicationInfo.PlayerName == BotName) return B; } return None; } function string GetTeamColor(TeamInfo Team) { if (Team == None) return ""; if (Team.TeamIndex < 4) return Team.ColorNames[Team.TeamIndex]; return "#CCCCCC"; } function string GetTeamName(TeamInfo Team) { if (Team == None) return ""; return Team.GetHumanReadableName(); } U@UWUm@UU| ^Ws=%ppS* =_%_S@ _ __SS%ppl_%_SWS _lpppl_ l GU`@UUQyCN7 y7 y&6_y M6Py K GUt SP}9:q]BSUfqE9:q9:Qq$_9:q9:PPz9:P9:QP$ GUhD%?9*{ 1Ji{DSave*%*7|w6*{D!6*%|6*(*O-k(HF0F*%*7E6*l#|6*l;{6*GameReplicationInfo.AdminName1,SettingName6*1,SettingText6*1'DefVal6*1URLVall1MapNameC1GameTypeFHpHpG_row-k'**-k1ConflictsH1PostActionG1"SectionRestart Conflicts1SubmitValueH1G Q2{QQp?Mutator=Q$|pppC?Game=FQ( 1Ji GU@UUa V&{]V7 @ V&.7 V&6_V J6PV G GUw UUh iI[`]Mr|Mt|Mm|Ms|Mu|Ml%iLiMapNameiGameType GU} H8[TQMr|Mt|Mm|Ms|Mu|Ml%HIb#9V GUe F}47 F7 % GUg NN<Q:Xi5SectionB{NUpdate9JNIpNo-1MNIPMask:777&ppNAcceptDeny;NIPMaskb~{NDelete9JNIdNo-1A-h'9JNIpNo-1~-h27A&b~-h27A&bN-%7f~ Bf&Ef5PolicyTypeZ53PolicyCellppB:E  5*PostActionpps?IDNo=9S5UpdateButtonNpNps_row%7;BEDpo AcceptDenyACCEPT|BACCEPTH
DpDo AcceptDenyDENY|BDENYh5PolicyTypeD5FPolicyCellpp IPMask9S,9S,E  5*PostActionpps?IpNo=9S59UpdateButtonl Update~NpNps_row5PoliciesN5*PostActionpps?IpNo=9S5PageHelpJ 5sN 5 GUi 1:< 7 % GUk m ?q 7  GUUUl E#FIZ%@ZZ6r6_Z EZZ GU@UUZUUH@UUw z `[lfXC* Z\-@y@A%OA@G@ A%EG{G ;C #{%C{{AC GUW@ M\k{@ Wz@ &..q v (XGv @ @ &v v @ &}q v (XGv X,(' GUYUUC `[kSection&r PostAction%%w% &w& n9Jʗ}%w}&w9S}%w9S}&wTXp|Kp|Kb|KoT* =z`SortNameQ` LastSortzE%-rKp-rKb-AKo|MbzQz!z`ReverseSortTC y?ReverseSort=TrueyE-r-r-Aw*Gxw.*w*w..*-r4{`&pBan9Sb.uu-r5{`'pKick9ST.r.*-Aw*5{`'pKick9SaG-r* -r-AE&2-rE,5KickButtonl KickE&p$-r-AHeadTitleKickaB$N-rHeadTitleBanaB$NB|zNameReverseSorty`ReverseSortHeadTitleNameaB$MY-|zTeamReverseSortyReverseSortHeadTitleTeamaB$M|zPingReverseSortyReverseSortHeadTitlePingaB$M|zScoreReverseSorty;ReverseSortHeadTitleScoreaB$MHeadTitleIPaB$N#-HeadTitleGlobal IDaB$NTableHeaders$s Ms@w0@5 w*c9:6bp@.MinPlayersy {`SetMinPlayers w.*.9J`MinPlayers9S%%, b9MinPlayers9S.)MinPlayerPart}s MinPlayersMinPlayersPartnw*W--w*@ContentFpKick9S(f KpaBx  Kb w.*?ContentFpBan9S( ContentaBx ] w.*'.--] (Ready)   -] (Spectator)   r.*] (Bot)  w.*l.lp l~l:cp -.  l c <Contentp]aBC-pw*%,Contentppppp d-"Content aB].Content9S9:,aBx *Content9S9DaBx ContentlaBx E-ContentcaBx z uName_ Team_K  n0Q NameaB_ EPingaB_L9S9:,,0 aB_L9S9D,0 Ping_L9S9:,,0 _L9S9D,0RowContentT(^_ M T%a%aT|zScoreMpT aMaBMT aaSpanContentoSpanLength6/RowContentZM{PlayerListM9MinPlayers9S.PageHelpQ %h  GUCjZ0j%j7 (A j&' GUUUUUv Aaj6_A  GUCU,UUUy  b6P  GUE @JXVbAdminNamebHeaderColSpan2 7%I@Group%Ehe%e7zeIheFg-{eAeAgdb6MenuLinkpp_?Group=eb%MenuTitleeFEpEppJ_itemgebLocationhbHeaderMenuEXsbHeaderColSpan3b'SkinSelectn WebSkinO b WebSkinSelectzbJ GU@UU| ~zhTZ }KZ%~&6_Z 6PZ Z GUA @UUXUUZUUQ Xk;'Aa|Aeb3Sectionxb~X editcwb*  ,b{X modWXUsername{XPasswordmXb{Wbb .Wr ~W*bWbR`bS%Item%`1zbz{b&b 4{b{1bWzzb{mbbmbczb{b 3b3.NameValueb3.PassValueb3%PrivTableb3PostAction3SubmitNamemod3SubmitValuev3PageHelpw3`bw %Action%Gbb%Item%` 3Tb 3[ %Item%` 3 GU {@sT[#zK[%{&6_[ 6P[ [ GU`|KVS"7%q%p{|ChangeSkinD|WebSkinDD bq|GroupqY(HeaderURIppJ?Group=qYBottomURIqY ServerName $Y_ GUr u_si;TuTU%X,F&2{TBTIu-`E BI-kB -oSSbOUu-kB{IJI-PJ-k-o-PzJ&B-`-PFXF&aBRaBRaOUu'J-kF/-`/PrivilegeRowsRTppTSM2T GU[UUQTJ P-T}%P}7 稨 Member9S}6P} }} e}%}&Je}Je-T稨~~Inserting new member at9S}e}%}7 稨 Member9S}6P} } GUW r*GAME HAS ENDED!< GUL L [n  GUN UUCI D )Uh7 &xh%~ D6P% r-TDwas before first member, so returning -1|D6P% %|D6Ph hh&7~ D6Ph )-T稨Dwas after last member, so returning9Sh&&h&&mhmhm|D6Pm m~ D6Pm mmkm-TpppMin:9SkMax:9SmPos:9Skm,mkm,Mmk,dm%b-TDwanted to be added at 0, so adding at 1 instead&-T稨Dwill be inserted at position9Sm,m, GUB UUhUU] zwK={BBugAddressppwebadminbugs@epicgames.com{CSSX{BODYBGZwl*7l^%{%{7l^ |{l^z& lJ z{ {z& / I_Kz{ cJJz{ GIz{ X{4spppu /z&text/css {%{7 {z{ { {IPage not found!  GUa jl)Aac-}}{jaddnew`jUsernameAjPassworddj|jUsergroupF} |h .`US%Item%`6w `*UR`6 4AUW6z|UpSr!66rF*U %Item%r%NameValue`PassValueAPrivTabledzUuj`Adwu*u 6F uUp@`!{U UPrivTablewu*PostActionSubmitNameaddnewSubmitValuevSectionxPageHelpwGroups^}|PostAction^SubmitNameaddnewSubmitValueNSectionKPageHelp\^  GUc UUR UUP S p&Qc %_c 7Uc pS R R -'c |R  A  GUs bVS  Mu| * =v* {bSetMutesB1U%@"9J@ "%u6"{b%@  0zb u6"B<@ 6"}%G@"9J@ "%=| &9S"6"8%Bz "9JB "%7Content6"z { 7Content6"6RowContentpz { aB8^VB{8TableTitlenTableRows8)SelectedTableps | vU8%Uv"9Jv "%Kz6"upZ9S| u6"2&vaS9Jv&_S%Kz6SapZ9S|a6SGroupNameu-MutatorClass6",MutatorName6",MutatorDesc6"{Uu zuaCheckedcheckedaB8x}ʙB #9S"% checkedChecked}aB8wUur%| z "9J| ~ContentppF6"B #9S"% 6"z C(Content6"6RowContentpz { aB8^\TableTitlemTableRows8'ChooseTablepSection,r PageHelpO PostActionMM   GUH//============================================================================== // WebAdmin handler for activities related to managing the users / groups // that are allowed to log into the server // // Written by Michael Comeau // Revised by Ron Prestenback // 2003,2004 Epic Games, Inc. All Rights Reserved //============================================================================== class xWebQueryAdmins extends xWebQueryHandler config; // TODO: // Fix log spam in adding groups function struct RowGroup { var array rows; }; var config string AdminsIndexPage; var config string UsersHomePage; var config string UsersAccountPage; var config string UsersAddPage; var config string UsersBrowsePage; var config string UsersEditPage; var config string UsersGroupsPage; var config string UsersMGroupsPage; var config string GroupsAddPage; var config string GroupsBrowsePage; var config string GroupsEditPage; var config string PrivilegeTable; // Localization var localized string NoteUserHomePage; var localized string NoteAccountPage; var localized string NoteUserAddPage; var localized string NoteUserEditPage; var localized string NoteUsersBrowsePage; var localized string NoteGroupAddPage; var localized string NoteGroupEditPage; var localized string NoteGroupsBrowsePage; var localized string NoteGroupAccessPage; var localized string NoteMGroupAccessPage; // Single words var localized string NameText; var localized string Deleting; var localized string Group; var localized string Groups; var localized string User; var localized string Modify; var localized string Managed; var localized string Privileges; var localized string SecurityLevel; // Title & Section Names var localized string AdminPageTitle; var localized string AdminHomeTitle; var localized string AdminAccountTitle; var localized string BrowseUsersTitle; var localized string BrowseGroupsTitle; var localized string AddUserTitle; var localized string AddUserButton; var localized string AddGroupTitle; var localized string AddGroupButton; var localized string EditUserTitle; var localized string EditUserButton; var localized string EditGroupTitle; var localized string EditGroupButton; var localized string ModifyUserGroup; var localized string ModifyMUserGroup; // Status messages var localized string UserRemoved; var localized string GroupRemoved; // Error Messages var localized string AdminNotFound; var localized string GroupNotFound; var localized string PrivTitle; var localized string NoneText; var localized string NoneItemText; var localized string PasswordError; var localized string InsufficientPrivs; var localized string InvalidItem; var localized string InvalidCharacters; var localized string NameExists; var localized string YouMustSelect; var localized string DoesNotExist; var localized string CouldNotCreate; var localized string NegSecLevel; var localized string CannotAssignHigher; var localized string CannotAssignPrivs; function bool Query(WebRequest Request, WebResponse Response) { if (!CanPerform(NeededPrivs)) return false; switch (Mid(Request.URI, 1)) { case DefaultPage: QueryAdminsFrame(Request, Response); return true; case AdminsIndexPage: QueryAdminsMenu(Request, Response); return true; case UsersHomePage: if (!MapIsChanging()) QueryUsersHomePage(Request, Response); return true; case UsersAccountPage: if (!MapIsChanging()) QueryUserAccountPage(Request, Response); return true; case UsersBrowsePage: if (!MapIsChanging()) QueryUsersBrowsePage(Request, Response); return true; case UsersAddPage: if (!MapIsChanging()) QueryUsersAddPage(Request, Response); return true; case UsersEditPage: if (!MapIsChanging()) QueryUsersEditPage(Request, Response); return true; case UsersGroupsPage: if (!MapIsChanging()) QueryUsersGroupsPage(Request, Response); return true; case UsersMGroupsPage: if (!MapIsChanging()) QueryUsersMGroupsPage(Request, Response); return true; case GroupsBrowsePage: if (!MapIsChanging()) QueryGroupsBrowsePage(Request, Response); return true; case GroupsAddPage: if (!MapIsChanging()) QueryGroupsAddPage(Request, Response); return true; case GroupsEditPage: if (!MapIsChanging()) QueryGroupsEditPage(Request, Response); return true; } return false; } function QueryAdminsFrame(WebRequest Request, WebResponse Response) { local String Page; // if no page specified, use the default Page = Request.GetVariable("Page", UsersHomePage); Response.Subst("IndexURI", AdminsIndexPage$"?Page="$Page); Response.Subst("MainURI", Page); ShowPage(Response, DefaultPage); } function QueryAdminsMenu(WebRequest Request, WebResponse Response) { Response.Subst("Title", AdminPageTitle); Response.Subst("UsersHomeURI", UsersHomePage); Response.Subst("UserAccountURI", UsersAccountPage); Response.Subst("UsersAddURI", UsersAddPage); Response.Subst("GroupsAddURI", GroupsAddPage); Response.Subst("UsersBrowseURI", UsersBrowsePage); Response.Subst("GroupsBrowseURI", GroupsBrowsePage); ShowPage(Response, AdminsIndexPage); } function QueryUsersHomePage(WebRequest Request, WebResponse Response) { Response.Subst("AdminName", CurAdmin.UserName); Response.Subst("Section", AdminHomeTitle); Response.Subst("PageHelp", NoteUserHomePage); ShowPage(Response, UsersHomePage); } function QueryUserAccountPage(WebRequest Request, WebResponse Response) { local string upass; Response.Subst("NameValue", HtmlEncode(CurAdmin.UserName)); if (Request.GetVariable("edit", "") != "") { // Can only change his password upass = Request.GetVariable("Password", CurAdmin.Password); if (!CurAdmin.ValidPass(upass)) StatusError(Response, PasswordError); else if (upass != CurAdmin.Password) { CurAdmin.Password = upass; Level.Game.AccessControl.SaveAdmins(); } } Response.Subst("PassValue", CurAdmin.Password); Response.Subst("PrivTable", GetPrivsTable(CurAdmin.Privileges, true)); Response.Subst("GroupLinks", ""); Response.Subst("SubmitValue", Accept); Response.Subst("PostAction", UsersAccountPage); Response.Subst("Section", AdminAccountTitle); Response.Subst("PageHelp", NoteAccountPage); ShowPage(Response, UsersAccountPage); } function QueryUsersBrowsePage(WebRequest Request, WebResponse Response) { local xAdminUser xUser; local string tmp; if (CanPerform("Al|Aa|Ae|Ag|Am")) { // Delete an Admin if (Request.GetVariable("delete") != "") { // Delete specified Admin Group xUser = Level.Game.AccessControl.Users.FindByName(Request.GetVariable("delete")); if (xUser != None) { if (CurAdmin.CanManageUser(xUser)) { StatusOk(Response, Repl(UserRemoved, "%UserName%", HtmlEncode(xUser.UserName))); // Remove xUser xUser.UnlinkGroups(); Level.Game.AccessControl.Users.Remove(xUser); Level.Game.AccessControl.SaveAdmins(); } else { tmp = Repl(InsufficientPrivs, "%Action%", Deleting); tmp = Repl(tmp, "%Item%", Group); StatusError(Response, tmp); } } else StatusError(Response, Repl(InvalidItem, "%Item%", Group)); } // Show the list Response.Subst("BrowseList", GetUsersForBrowse(Response)); Response.Subst("Section", BrowseUsersTitle); Response.Subst("PageHelp", NoteUsersBrowsePage); ShowPage(Response, UsersBrowsePage); } else AccessDenied(Response); } function QueryUsersAddPage(WebRequest Request, WebResponse Response) { local xAdminUser xUser; local xAdminGroup xGroup; local xAdminGroupList xGroups; local string uname, upass, uprivs, ugrp, ErrMsg; if (CanPerform("Aa")) { if (CurAdmin.bMasterAdmin) xGroups = Level.Game.AccessControl.Groups; else xGroups = CurAdmin.ManagedGroups; if (Request.GetVariable("addnew") != "") { // Humm .. AddNew uname = Request.GetVariable("Username"); upass = Request.GetVariable("Password"); uprivs = FixPrivs(Request, ""); ugrp = Request.GetVariable("Usergroup"); xGroup = xGroups.FindByName(ugrp); if (!CurAdmin.ValidName(uname)) ErrMsg = Repl(InvalidCharacters, "%Item%", User); else if (Level.Game.AccessControl.Users.FindByName(uname) != None) ErrMsg = NameExists@User; else if (!CurAdmin.ValidPass(upass)) ErrMsg = PasswordError; else if (ugrp == "") ErrMsg = YouMustSelect@Group$"!"; else if (xGroup == None) ErrMsg = Repl(DoesNotExist, "%Item%", Group); Response.Subst("NameValue", HtmlEncode(uname)); Response.Subst("PassValue", upass); Response.Subst("PrivTable", GetPrivsTable(uprivs)); if (ErrMsg == "") { // All settings are fine, create the new Group. xUser = Level.Game.AccessControl.Users.Create(uname, upass, uprivs); if (xUser != None) { xUser.AddGroup(xGroup); Level.Game.AccessControl.Users.Add(xUser); Level.Game.AccessControl.SaveAdmins(); } else { // Only re-add the DDL if there was a problem. ErrMsg = CouldNotCreate@User$"!"; } } if (ErrMsg != "") StatusError(Response, ErrMsg); } else Response.Subst("PrivTable", GetPrivsTable("")); if (xUser != None) { Response.Subst("PostAction", UsersEditPage); Response.Subst("SubmitName", "addnew"); Response.Subst("SubmitValue", EditUserButton); Response.Subst("Section", EditUserTitle); Response.Subst("PageHelp", NoteUserEditPage); ShowPage(Response, UsersEditPage); } else { Response.Subst("Groups", GetGroupOptions(xGroups, ugrp)); Response.Subst("PostAction", UsersAddPage); Response.Subst("SubmitName", "addnew"); Response.Subst("SubmitValue", AddUserButton); Response.Subst("Section", AddUserTitle); Response.Subst("PageHelp", NoteUserAddPage); ShowPage(Response, UsersAddPage); } } else AccessDenied(Response); } function QueryUsersEditPage(WebRequest Request, WebResponse Response) { local xAdminUser xUser; local string uname, upass, privs, ErrMsg; if (CanPerform("Aa|Ae")) { ErrMsg = ""; Response.Subst("Section", EditUserTitle); xUser = Level.Game.AccessControl.GetUser(Request.GetVariable("edit")); if (xUser != None) { if (CurAdmin.CanManageUser(xUser)) { // Operations if (Request.GetVariable("mod") != "") { // Validate the changes and modify the user information uname = Request.GetVariable("Username"); upass = Request.GetVariable("Password"); privs = FixPrivs(Request, xUser.Privileges); if (uname != xUser.UserName) { if (xUser.ValidName(uname)) { if (Level.Game.AccessControl.GetUser(uname) == None) xUser.UserName = uname; else ErrMsg = NameExists@User; } else ErrMsg = Repl(InvalidCharacters, "%Item%", User); } if (ErrMsg == "" && !(upass == xUser.Password)) { if (xUser.ValidPass(upass)) xUser.Password = upass; else ErrMsg = PasswordError; } if (ErrMsg == "" && privs != xUser.Privileges) { xUser.Privileges = privs; xUser.RedoMergedPrivs(); } if (ErrMsg == "") Level.Game.AccessControl.SaveAdmins(); } if (ErrMsg != "") StatusError(Response, ErrMsg); Response.Subst("NameValue", HtmlEncode(xUser.UserName)); Response.Subst("PassValue", HtmlEncode(xUser.Password)); Response.Subst("PrivTable", GetPrivsTable(xUser.Privileges)); Response.Subst("PostAction", UsersEditPage); Response.Subst("SubmitName", "mod"); Response.Subst("SubmitValue", EditUserButton); Response.Subst("PageHelp", NoteUserEditPage); ShowPage(Response, UsersEditPage); } else { ErrMsg = Repl(InsufficientPrivs, "%Action%", Modify); ErrMsg = Repl(ErrMsg, "%Item%", User); ShowMessage(Response, PrivTitle, ErrMsg); } } else ShowMessage(Response, AdminNotFound, Repl(DoesNotExist, "%Item%", User)); } else AccessDenied(Response); } function QueryUsersGroupsPage(WebRequest Request, WebResponse Response) { local xAdminUser xUser; local xAdminGroupList xGroups; local xAdminGroup xGroup; local StringArray GrpNames; local string GroupRows, GrpName, Str; local int i; local bool bModify, bChecked; if (CanPerform("Ag")) { xUser = Level.Game.AccessControl.Users.FindByName(Request.GetVariable("edit")); if (xUser != None) { if (CurAdmin.CanManageUser(xUser)) { if (CurAdmin.bMasterAdmin) xGroups = Level.Game.AccessControl.Groups; else xGroups = CurAdmin.ManagedGroups; // Work with a table of checkboxes now GroupRows = ""; bModify = (Request.GetVariable("submit") != ""); // Make a sorted list of Groups GrpNames = new(None)class'SortedStringArray'; for (i=0; i CurAdmin.MaxSecLevel()) ErrMsg = CannotAssignHigher; Response.Subst("NameValue", HtmlEncode(gname)); Response.Subst("PrivTable", GetPrivsTable(gprivs)); Response.Subst("GameSecValue", string(gsec)); if (ErrMsg == "") { // All settings are fine, create the new Group. xGroup = Level.Game.AccessControl.Groups.CreateGroup(gname, gprivs, byte(gsec)); if (xGroup != None) { CurAdmin.AddManagedGroup(xGroup); Level.Game.AccessControl.Groups.Add(xGroup); Level.Game.AccessControl.SaveAdmins(); } else ErrMsg = CouldNotCreate@Group$"!"; } if (ErrMsg != "") StatusError(Response, ErrMsg); } else Response.Subst("PrivTable", GetPrivsTable("")); if (xGroup != None) { Response.Subst("PostAction", GroupsEditPage); Response.Subst("SubmitName", "mod"); Response.Subst("SubmitValue", EditGroupButton); Response.Subst("PageHelp", NoteGroupEditPage); Response.Subst("Section", EditGroupTitle); } else { Response.Subst("PostAction", GroupsAddPage); Response.Subst("SubmitName", "addnew"); Response.Subst("SubmitValue", AddGroupButton); Response.Subst("Section", AddGroupTitle); Response.Subst("PageHelp", NoteGroupAddPage); } ShowPage(Response, GroupsEditPage); } else AccessDenied(Response); } function QueryGroupsEditPage(WebRequest Request, WebResponse Response) { local xAdminGroup xGroup; local string ErrMsg, gname, gprivs; local int gsec; if (CanPerform("Gm")) { Response.Subst("Section", EditGroupTitle); xGroup = Level.Game.AccessControl.Groups.FindByName(Request.GetVariable("edit")); if (xGroup != None) // Do not let admins fake the system. { if (CurAdmin.CanManageGroup(xGroup)) { if (Request.GetVariable("mod") != "") { // Save the changes gname = Request.GetVariable("GroupName"); gprivs = FixPrivs(Request, xGroup.Privileges); gsec = Clamp(int(Request.GetVariable("GameSec")), 0, 255); if (gname != xGroup.GroupName) { if (xGroup.ValidName(gname)) { if (Level.Game.AccessControl.Groups.FindByName(gname) == None) xGroup.GroupName = gname; else ErrMsg = Repl(NameExists, "%Item%", Group); } else ErrMsg = Repl(InvalidCharacters, "%Item%", Group); } if (ErrMsg == "") { if (gprivs != xGroup.Privileges) xGroup.SetPrivs(gprivs); xGroup.GameSecLevel = gsec; Level.Game.AccessControl.SaveAdmins(); } } if (ErrMsg != "") StatusError(Response, ErrMsg); Response.Subst("NameValue", HtmlEncode(xGroup.GroupName)); Response.Subst("PrivTable", GetPrivsTable(xGroup.Privileges)); Response.Subst("GameSecValue", string(xGroup.GameSecLevel)); Response.Subst("PostAction", GroupsEditPage); Response.Subst("SubmitName", "mod"); Response.Subst("SubmitValue", EditGroupButton); Response.Subst("PageHelp", NoteGroupEditPage); ShowPage(Response, GroupsEditPage); } else { ErrMsg = Repl(InsufficientPrivs, "%Action%", Modify); ErrMsg = Repl(ErrMsg, "%Item%", Group); ShowMessage(Response, PrivTitle, ErrMsg); } } else ShowMessage(Response, GroupNotFound, Repl(DoesNotExist, "%Item%", Group)); } else AccessDenied(Response); } // Must not forget to show only the Users from groups that the admin can manage function string GetUsersForBrowse(WebResponse Response) { local ObjectArray Users; local xAdminUser xUser; local string OutStr, Tmp; local int i; local bool CanDelete; CanDelete = CanPerform("Aa"); Users = ManagedUsers(); // Now, just make the users list a bunch of Rows if (Users.Count() == 0) { Response.Subst("Content", Repl(NoneItemText, "%Item%", User)); Response.Subst("RowContent", WebInclude(CellLeft)); return WebInclude(RowLeft); } Response.Subst("Content", NameText); Tmp = WebInclude(CellLeft); Response.Subst("Content", Privileges); Tmp = Tmp $ WebInclude(CellLeft); Response.Subst("Content", " "); Tmp = Eval(CanDelete, Tmp $ WebInclude(CellLeft), Tmp); Response.Subst("RowContent", Tmp); OutStr = WebInclude(RowLeft); for (i = 0; i maxcols) { CurCol = 1; PrivItems $= ""; } PrivItems $= GetPrivsItem(privs, PM.Tags[TagIndex++], true, SPriv, bCanEdit); CurCol++; } } if (bShowPrivGroup) { Resp.Subst("PrivilegeRows", PrivItems); OutStr = OutStr $ PrivHeader $ WebInclude(PrivilegeTable); } } return OutStr; } function string GetPrivsTable(string privs, optional bool bNoEdit) { local string str; local int i; // Start by getting all rows for known privilege groups str = ""; for (i=0; i"$NoneText$""; // Step 1: Sort the groups GrpNames = new(None) class'SortedStringArray'; for (i=0; i" $ NoneText $ ""; // Step 2: Build the group list OutStr = ""; for (i=0; i"$HtmlEncode(GrpName)$""; } return OutStr; } // Returns true if we have any of the privilege from this priv group function bool CheckPrivilegeGroup(string MainPriv, string SubPrivs) { local string Tmp; if (CanPerform(MainPriv)) return true; while (SubPrivs != "") { Tmp = NextPriv(SubPrivs); if (CanPerform(Tmp)) return true; } return false; } UoYclass ListItem extends Object; var ListItem Next; var ListItem Prev; var String Tag; // sorted element var String Data; // saved data var bool bJustMoved; // if the map was just moved, keep it selected function AddElement(ListItem NewElement) { local ListItem TempItem; for (TempItem = self; TempItem.Next != None; TempItem = TempItem.Next); TempItem.Next = NewElement; NewElement.Prev = TempItem; NewElement.Next = None; } function AddSortedElement(out ListItem FirstElement, ListItem NewElement) { local ListItem TempItem; // find item which new should be inserted after TempItem = FirstElement; while (TempItem != None) { // if current is less or equal than new, but is at the end if (Caps(TempItem.Tag) <= Caps(NewElement.Tag) && TempItem.Next == None) { TempItem.Next = NewElement; NewElement.Prev = TempItem; NewElement.Next = None; break; } // else if current is greater than new else if (Caps(TempItem.Tag) > Caps(NewElement.Tag)) { // if current.prev == none, then make it the new first element if (TempItem.Prev == None) FirstElement = NewElement; else TempItem.Prev.Next = NewElement; NewElement.Prev = TempItem.Prev; NewElement.Next = TempItem; TempItem.Prev = NewElement; break; } TempItem = TempItem.Next; } } function ListItem FindItem(String SearchData) { local ListItem TempItem; for (TempItem = self; TempItem != None; TempItem = TempItem.Next) { if (TempItem.Data ~= SearchData) return TempItem; } return None; } function ListItem DeleteElement(out ListItem First, optional String SearchData) { local ListItem TempItem; for (TempItem = self; TempItem != None; TempItem = TempItem.Next) { if (TempItem.Data ~= SearchData || SearchData == "") { // if no prev, assume this is the first element if (TempItem == First || TempItem.Prev == None) { First = TempItem.Next; if (First != None) First.Prev = None; } else { // close the links around TempItem if (TempItem.Prev != None) TempItem.Prev.Next = TempItem.Next; if (TempItem.Next != None) TempItem.Next.Prev = TempItem.Prev; } TempItem.Prev = None; TempItem.Next = None; break; } } return TempItem; } function MoveElementUp(out ListItem First, ListItem MoveItem, out int Count) { local ListItem TempItem; local int TempCount; if (MoveItem != None) { for (TempCount = Count; TempCount > 0 && MoveItem.Prev != None; TempCount--) { TempItem = MoveItem.Prev; MoveItem.Prev = TempItem.Prev; if (MoveItem.Prev != None) MoveItem.Prev.Next = MoveItem; TempItem.Next = MoveItem.Next; if (TempItem.Next != None) TempItem.Next.Prev = TempItem; MoveItem.Next = TempItem; TempItem.Prev = MoveItem; if (TempItem == First) First = MoveItem; } Count = Count - TempCount; } } function MoveElementDown(out ListItem First, ListItem MoveItem, out int Count) { local ListItem TempItem; local int TempCount; if (MoveItem != None) { for (TempCount = Count; TempCount > 0 && MoveItem.Next != None; TempCount--) { TempItem = MoveItem.Next; MoveItem.Next = TempItem.Next; if (MoveItem.Next != None) MoveItem.Next.Prev = MoveItem; TempItem.Prev = MoveItem.Prev; if (TempItem.Prev != None) TempItem.Prev.Next = TempItem; MoveItem.Prev = TempItem; TempItem.Next = MoveItem; if (MoveItem == First) First = TempItem; } Count = Count - TempCount; } } function RunTest() { local ListItem Test, TempItem; Log("Test: Init 'B'"); Test = new(None) class'ListItem'; Test.Tag = "B"; Test.Data = "B"; Log(" => Test="$Test); TempItem = new(None) class'ListItem'; TempItem.Tag = "A"; TempItem.Data = "A"; Log("Test: AddSort 'A'"); Test.AddSortedElement(Test, TempItem); Log(" => Test="$Test); for (TempItem = Test; TempItem != None; TempItem = TempItem.Next) Log(" => Tag="$TempItem.Tag$" Prev="$TempItem.Prev$" Next="$TempItem.Next); TempItem = new(None) class'ListItem'; TempItem.Tag = "D"; TempItem.Data = "D"; Log("Test: AddSort 'D'"); Test.AddSortedElement(Test, TempItem); Log(" => Test="$Test); for (TempItem = Test; TempItem != None; TempItem = TempItem.Next) Log(" => Tag="$TempItem.Tag$" Prev="$TempItem.Prev$" Next="$TempItem.Next); TempItem = new(None) class'ListItem'; TempItem.Tag = "C"; TempItem.Data = "C"; Log("Test: AddSort 'C'"); Test.AddSortedElement(Test, TempItem); Log(" => Test="$Test); for (TempItem = Test; TempItem != None; TempItem = TempItem.Next) Log(" => Tag="$TempItem.Tag$" Prev="$TempItem.Prev$" Next="$TempItem.Next); Log(""); Log("Test: Delete 'C'"); Test.DeleteElement(Test, "C"); Log(" => Test="$Test); for (TempItem = Test; TempItem != None; TempItem = TempItem.Next) Log(" => Tag="$TempItem.Tag$" Prev="$TempItem.Prev$" Next="$TempItem.Next); Log("Test: Delete 'D'"); Test.DeleteElement(Test, "D"); Log(" => Test="$Test); for (TempItem = Test; TempItem != None; TempItem = TempItem.Next) Log(" => Tag="$TempItem.Tag$" Prev="$TempItem.Prev$" Next="$TempItem.Next); Log("Test: Delete 'A'"); Test.DeleteElement(Test, "A"); Log(" => Test="$Test); for (TempItem = Test; TempItem != None; TempItem = TempItem.Next) Log(" => Tag="$TempItem.Tag$" Prev="$TempItem.Prev$" Next="$TempItem.Next); Log("Test: Delete 'B'"); Test.DeleteElement(Test, "B"); Log(" => Test="$Test); for (TempItem = Test; TempItem != None; TempItem = TempItem.Next) Log(" => Tag="$TempItem.Tag$" Prev="$TempItem.Prev$" Next="$TempItem.Next); } U@UtUMUUU@UUiDclass UTServerAdminSpectator extends MessagingSpectator config; struct PlayerMessage { var PlayerReplicationInfo PRI; var String Text; var Name Type; var PlayerMessage Next; // pointer to next message }; var array Messages; var byte NextMsg, LastMsg; var config byte ReceivedMsgMax; var config bool bClientMessages; var config bool bTeamMessages; var config bool bVoiceMessages; var config bool bLocalizedMessages; var UTServerAdmin Server; function bool SetPause( BOOL bPause ) { log("Webadmin spectator executing SetPause:"$bPause); return Super.SetPause(bPause); } /* Pause() Command to try to pause the game. */ function ServerPause() { log("Webadmin spectator executing pause command!"); Super.Pause(); } event Destroyed() { Server.Spectator = None; Super.Destroyed(); } event PreBeginPlay() { Super.PreBeginPlay(); NextMsg = 0; LastMsg = 0; if (ReceivedMsgMax < 10) ReceivedMsgMax = 10; Messages.Length = ReceivedMsgMax; } function int LastMessage() { return LastMsg; } function string NextMessage(out int msg) { local string str; if (msg == NextMsg) return ""; str = Messages[msg]; msg++; if (msg >= ReceivedMsgMax) msg = 0; return str; } // Implemented Rotating function AddMessage(PlayerReplicationInfo PRI, String S, name Type) { // Add the message to the array Messages[NextMsg] = FormatMessage(PRI, S, Type); NextMsg++; if (NextMsg >= ReceivedMsgMax) NextMsg = 0; if (NextMsg == LastMsg) LastMsg++; if (LastMsg >= ReceivedMsgMax) LastMsg = 0; } function Dump() { Log("----Begin Dump----"); if (PlayerReplicationInfo == None) Log("NO PLAYER REPLICATION INFO"); if (Pawn == None) Log("NO PAWN"); Log("NextMsg:"@NextMsg); Log("LastMsg:"@LastMsg); Log("ReceivedMsgMax:"@ReceivedMsgMax); Log("Msg[0]"@Messages[0]); Log("Msg[1]"@Messages[1]); Log("Msg[2]"@Messages[2]); Log("Msg[3]"@Messages[3]); Log("Msg[4]"@Messages[4]); Log("Msg[5]"@Messages[5]); } function String FormatMessage(PlayerReplicationInfo PRI, String Text, name Type) { local String Message; // format Say and TeamSay messages if (PRI != None) { if (Type == 'Say' && PRI == PlayerReplicationInfo) Message = Text; else if (Type == 'Say') Message = PRI.PlayerName$": "$Text; else if (Type == 'TeamSay') Message = "["$PRI.PlayerName$"]: "$Text; else Message = "("$Type$") "$Text; } else if (Type == 'Console') Message = "WebAdmin:"@Text; else Message = "("$Type$") "$Text; return Message; } event ClientMessage( coerce string S, optional Name Type ) { //Log("Admin Received a ClientMessage"); if (bClientMessages) AddMessage(None, S, Type); } function TeamMessage( PlayerReplicationInfo PRI, coerce string S, name Type) { //Log("Admin Received a TeamMessage"); if (bTeamMessages) AddMessage(PRI, S, Type); } function ClientVoiceMessage(PlayerReplicationInfo Sender, PlayerReplicationInfo Recipient, name messagetype, byte messageID) { //Log("Admin Received a ClientVoiceMessage"); // do nothing? } function ReceiveLocalizedMessage( class Message, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject ) { //Log("Admin Received a LocalizedMessage"); // do nothing? } // A couple of functions that should not do anything function ClientGameEnded() {} // Report end game in log function GameHasEnded() { AddMessage(None, "GAME HAS ENDED", 'Console'); } exec function DumpMaplists( string GameType ) { local int i; local int GameIndex; local StringArray ExcludeMaps, IncludeMaps; if ( GameType == "" ) GameType = string(Level.Game.Class); GameIndex = Level.Game.MaplistHandler.GetGameIndex(GameType); ExcludeMaps = Server.ReloadExcludeMaps(GameType); IncludeMaps = Server.ReloadIncludeMaps(ExcludeMaps, GameIndex, Level.Game.MaplistHandler.GetActiveList(GameIndex)); for ( i = 0; i < ExcludeMaps.Count(); i++ ) { log(" ExcludeMaps["$i$"]: Item '"$ExcludeMaps.GetItem(i)$"' Tag '"$ExcludeMaps.GetTag(i)$"'"); } for ( i = 0; i < IncludeMaps.Count(); i++ ) { log(" IncludeMaps["$i$"]: Item '"$IncludeMaps.GetItem(i)$"' Tag '"$IncludeMaps.GetTag(i)$"'"); } } UdQq>vF'Wr*r*r* xIk(hw/*A r*wM*aMa Aw*`r* xIk(I'^QQx rX( cr* xIk (/x-M'd %d 7d qQx-M(d -M GU_UUCUUsnC#T7n7n&6enn6<nln GUw Km;jAl|Aa|Ae|Ag|Am{KdeleteqKdeletewq*s ,qYH%UserName%qqi qPw %Action%oPP%Item%r YP YF%Item%rYBrowseListeYYSectionMYPageHelpNY`~ Y GUI@UUUU` n/ cn7@n&.7n&6enk6<njn GUNa:b* 6A(:& Hq:>' bap:>' @o:>' Zn:>' `m:>' ^l:>' HFk:>' vCtj:>' \i:>' hh:>' Ug:>' .o,f:>' ( GUF fn\I%I7\p\_If-eIz\\@\ GUz DL:M D%D7T~DT 2w~*B%B7rB~~*BP/w~*| ~/w|*|=77&7&|/稨WebQueryHandler:9V~could not be initialized!m ppInvalid QueryHandlerClass:DT. Removing invalid entry.!m ATD&bD  GUUUe i}?7i7% GUL=x+wM*aMBa A]w*`lwHL%class%9V%port%9S!m  GUj 1E 7% GUl n J 7 GUUUm h#QJo%Ao77|6eohoo GUUUr UUoUUN _ WUQwXcCDefaultSendTextS CPostActionOCu C GUT e3@Me9:qHe]eDe9:Qe%H GU\@UUpUUK MnaZ7NameValue:{MeditFM'Password 4F ZW::{FFZ(PassValueZ/PrivTable'ZGroupLinksZ!SubmitValueHZPostActionZZSectionHZPageHelp`ZZ GUg\e0\%\7(A\&' GUu SZ9  Mt|Mm{SSwitchGameTypeAndMapMt%S)SMapSelectSGameTypeSelect ) {SSwitchMapMm|Mt`SMapSelectX|pppp`?game=9V?mutator=2( )Jq%MapName%` ) -U{SApplySettingsMt1-U&{SSwitchGameTypezSGameTypeSelectyz y*ry*yz9VyE \ zW&zM9WE y EzMa%@ w@*X%Y%o*~.@w~*~-kw.~*o.~wo*)/PlayerNameo)Kills9So)Deaths9Uo) Suicides9Soq%^q,X9:qoq+)MultiKills9SXq%q,Y9:qoq)Sprees9SYaBzy@@Ozo)StatRowsz)%GameStatex2ryQSwitchMapN* =NAMM- 9V~9V.NQSwitchGameTypeAndMapMt)BContentn GameTypeSelect?z)CGameTypeButtonl SwitchGameTypeq6)/Content)3GameTypeSelect{ )BContentn MapSelect+MN).MapSelect{ )3MapButtonl Qq)PostActionF)Section%r )PageHelpW ))F  ) GUUUx blJ6eb GUg ]oM-\j\I{VkV~pp|\|pp|k|{IaBI|aBIkr{\k\{] k+~pp|I|pp|k&|s{IaBI|aBIkI GU@UU{ a m6<a GU{A// ==================================================================== // Class: XAdmin.StringArray // Parent: Core.Object // // // ==================================================================== class StringArray extends Object; struct ArrayItem { var string item; var string tag; }; var protected array AllItems; var protected bool ReverseSort; function int Add(coerce string item, coerce string tag, optional bool bUnique) { local int pos; if (bUnique) { pos = FindTagId(tag); if (pos >= 0) return pos; } return InsertAt(AllItems.Length, item, tag); } protected function int SetAt(int pos, coerce string item, coerce string tag) { // Increase array if necessary if (AllItems.Length <= pos) AllItems.Length = (pos+1); AllItems[pos].item = item; AllItems[pos].tag = tag; return pos; } protected function int InsertAt(int pos, coerce string item, coerce string tag) { // See if need to insert or increase length if (pos < AllItems.Length) AllItems.Insert(pos, 1); else AllItems.Length = (pos+1); AllItems[pos].item = item; AllItems[pos].tag = tag; return pos; } // User Prepare if you know the number of items that will be inserted function SetSize(int NewSize) { // HACK: This is to pre-allocate the space in the FArray // It should prevent a bunch of Realloc() AllItems.Length = NewSize; AllItems.Length = 0; } function Reset() { AllItems.Length = 0; } function int Count() { return AllItems.Length; } function int FindItemId(coerce string item, optional bool bLog) { local int i; for (i=0; i= AllItems.Length) return false; AllItems.Remove(index, 1); return true; } function string GetItem(int index) { return AllItems[index].item; } function string GetTag(int index) { return AllItems[index].tag; } function int CopyFrom(StringArray arr, coerce string Tag) { local int id; id = arr.FindTagId(Tag); if (id >= 0 && id < arr.Count()) id = Add(arr.GetItem(id), arr.GetTag(id)); return id; } function int MoveFrom(StringArray arr, coerce string Tag) { return MoveFromId(arr, arr.FindTagId(Tag)); } function int MoveFromId(StringArray arr, int id) { local int newid; if (id >= 0 && id < arr.Count()) { newid = Add(arr.GetItem(id), arr.GetTag(id)); arr.Remove(id); return newid; } return -1; } function int CopyFromId(StringArray arr, int id) { if (id >= 0 && id < arr.Count()) return Add(arr.GetItem(id), arr.GetTag(id)); return -1; } function ShiftStrict(int id, out int Count) { if (Count == 0 || id<0 || id >= AllItems.Length) return; if (Count < 0) { // Move items toward 0 if (id + Count < 0) Count = -id; InsertAt(id + Count, AllItems[id].item, AllItems[id].Tag); Remove(id+1); } else { if ((id + Count + 1) >= AllItems.Length) Count = AllItems.Length - id - 1; InsertAt(id + Count + 1, AllItems[id].item, AllItems[id].Tag); Remove(id); } } // 0 = Sort lowest to highest (A first, Z last) // 1 = Reverse sort (Z first, A last) // Thread safe singular function SetSortOrder(bool Order) { ReverseSort = Order; } singular function ToggleSort() { ReverseSort = !ReverseSort; } function bool IsBefore(string test, string tag) { local bool bResult; bResult = Strcmp(Test,Tag,,True) < 0; if ( ReverseSort ) return !bResult; else return bResult; } /* function int CopyTo(ObjectArray arr, string Tag) { local int i; i = FindTagId(Tag); if (i >= 0 && id < arr.Count()) arr.Add(AllItems[i].item, AllItems[i].tag); return i; } function int CopyItemTo(ObjectArray arr, string item) { local int i; i = FindItemId(item); if (i >= 0 && id < arr.Count()) arr.Add(AllItems[i].item, AllItems[i].tag); return i; } */ U@UU~ Gss }BG  `tB%BGBG BG  BB GUP UU_H(&`* GUBUUZUUA N@| #(NN  _ GUsUUC I.t=q$P$,9:Q, Q$ 7]9:Q GUUUF H(: }ts%sHRH sH  sH sR GU[ E oZ(AdminNameZSectionPZPageHelpmZ@ GUUURUU] G XdNXcsSection,r sZSubTitlepp in ]tI 3]M{I[ppp[> I
I 3]s)RefreshMetappz]#END">sLogText[sPageHelpP ss] s GUJ V ^UK%KVV KV  K GU_ UUyUUUUO .A ,t% .%.7 t%V.t%t..t6e.6<..& .t&7t7.&.t&6e.6<.. GUH Y t9' 9:P GUC // ==================================================================== // Class: xWebAdmin.xWebAdminCommandLet // Parent: Core.Commandlet // // // ==================================================================== class xWebAdminCommandLet extends Commandlet; event int Main( string Parms ) { // local class Tmp; // local int i; // for (i = 0; i < class'XWebAdmin.UTServerAdmin'.default.QueryHandlerClasses.Length;i++) // { // Tmp = class(DynamicLoadObject(class'xWebAdmin.UTServerAdmin'.default.QueryHandlerClasses[i],class'Class')); // if (Tmp != None) // Tmp.static.StaticSaveConfig(); // } return 0; } UsSbt T:t%t&STII-[ttST GUK s  GU@UUUUtUUa Q p yTitleTyUsersHomeURI@yUserAccountURIZyUsersAddURI^yGroupsAddURIUyUsersBrowseURI`yGroupsBrowseURIhya GUgV { Xj7&<j%~ {6<%T|{6<%%t|{6<jj~ {6<jj&&cjnj|{6<nn~ {6<ncnvnnvc,cv,In%n, GUy \YMHXcp\SendText>{p)|p,debug |pdebug|p,say "]p,!;>@|ppause$r*=*>k|pdumpr>|p,get |p,set 9~pXADMINCONFIGMs~pXADMINCONFIG Jm JIppUser attempted to modify or enumerate admin account information illegally using the webadmin console. User:\.!m Ms J>W ap>{W*W!<JLogURI]JSayURIuJO J GUjUUUU|// ==================================================================== // Class: XAdmin.SortedStringArray // Parent: XAdmin.StringArray // // Sorted list - sorts based on tag // ==================================================================== class SortedStringArray extends StringArray; function int Add(coerce string item, coerce string tag, optional bool bUnique) { local int pos; pos = FindTagId(tag); if (pos < 0) return InsertAt(-pos-1, item, tag); else if (bUnique) return pos; return InsertAt(pos, item, tag); } function int FindTagId(coerce string Tag) { local int Last, Min, Max, Pos; Last = AllItems.Length - 1; if ( Last < 0 || IsBefore(Tag,AllItems[0].Tag) ) return -1; if (Tag ~= AllItems[0].Tag) return 0; if (Tag ~= AllItems[Last].Tag) return Last; // if (Last == 0) // return -2; // Add tag to end of list if (!IsBefore(Tag,AllItems[Last].tag)) return (-(Last+1))-1; // Find the position of insertion max = Last; pos = Last; do { if (tag ~= AllItems[pos].tag) return pos; if (IsBefore(Tag,AllItems[pos].tag)) max = pos; else min = pos; pos = (min + max)/2; } until (max-min < 2); if (pos == 0) return -2; return -pos-2; } Uf tq}StPage@P&IndexURIppa?Page=SPMainURISP GU M a:b ]tzUUUUUUUUk UUh UUi UUUUNg p' GUe UUP f q' GUq UU|UUp UUs@UU@UUI@UUX@UU@UUF@UUd@@UUv@UUx @@UUUUB@UUs @UU@@UUy@UUE@UU@UUD@UUUUD@UUh@UUl@UUi@UUw@UU}@@UUM@@UU@UU@UUnUUS@UUR@UUH@UUw @UUGUUh@UUC@@UUQ@UU{@@UUU@UUr@UUyUUK@UU~ @UUe@UUNUUq@UUt@UUu@UUo UUr@UUx@@UUJ@UUs@UU`@UUA@UUl@UUm@UUv@UUC@UU`@UU8UUz @UUt @UUW@UUg@UU\@UU]@@UUE@UUW@UUS@UUv @UU@UUh@UUO@UUN@UUK@UUL@UUa@UUG @UUH@UUT@UUO@UU @UUP@UUG@@UUT@UUZ@UUR@UUK@UU[@UUZ@UUa@@UUB@UU_@@UUi@UUc@@UUd@@UUe@@UUf@@UUC@@UUv@UU~@UUx@UUg@UUj@UUq@UUk@UUm@UUn@UUo@UUr@UUk@UUp@UUI@UUr @UU@@UUu@@UUw@@UUp@@UUb@@UUfUUz@@UU[ @UUB@UUH@UUUUi UUG@UUX@UU[@UUW@UUK@UUL@UUM@UUU@UUI@UUSUUQ@UUO@UUVPo yψ|/RadioGroupP/RadioValueQ/$Selected-O checkede GU@UURNn ĉP/SelectNameN/ListOptionsIf GU@UUXJp m+/TextNameJ[9JK%/$TextSizeppsize="K"v/TextSize9JL%/+TextLengthppmaxlength="L"/TextLength/TextValueMc GU@UU@UUTFl \ P/SubmitNameF/SubmitValueGd GUT dh 81wl* lN dy-C M-C dyjdMessageyd%ppppu /VO GUp Qs h+Mo * =q %q Qp 9JQ q yz6p fpZ9S|f6p o ;9Sp pppf.6p 6p q q %q o ~ 69Jo q s ;z~ q &o s 69Jo q &|~ s p q [|s ~ p o n.(o o #o p ~ s .p &o s Xs 69Jo p &p o n.(o o #o p q q Q1q %;q o p 9Jo q Q9Sp 6p q o 1 GUG@UU^@@UUZ@@UU@UUFUUs Yq ^gzY(H Y'F9JYGF% {Y0(bF% F,(' GUUmNG] 3mBc@EoKyHoKyHoKyH\] SomeSkin^ = ut2003.css_ ] #243954UUP@UUqUUtUUXUUX@UUt@UUL@UpUm @UUUUQ@UUUUw@UUtUUUUUU@UUoUUWUU~UUUUJ@UUUmUT@@UU@UUXUUC@UUB@UUT@UUUUUUd UUUoUkUUT@UU`@UUR@UUI@UUFUUl@UUQ@UUYUUEUUG@UU@UUM@voU@UsUUoUPUUe@UUe@UU@UU^@UUf@UU9@UUo@UUm@UUx@UU@UUlUU[ UUc@UUk@UUHUUb@UU@UUUUy@@UUN@@UUH@@UUUUq@UmRL[ 2~L6=mBcoKyHoKyHoKyH\MStandard UT2K4UUz@@UU[@UUA@UU@@@UUW@UUD@UU{ @UUF@UUM@UUJ@UUg@UUI_=#D_u p/I_Zf_Xg GUDdY Um@@UUz//----------------------------------------------------------- // //----------------------------------------------------------- class WebSkin extends Object abstract notplaceable; var string SubPath; var localized string DisplayName; // Name to use in skin select box var string SkinCSS; // CSS file associated with this skin var string DefaultBGColor; // Color for webadmin backgrounds // Array containing any pages you'd like to handle a query for var array SpecialQuery; function Init(UTServerAdmin WebAdmin) { WebAdmin.SkinPath = "/" $ SubPath; WebAdmin.SiteBG = DefaultBGColor; WebAdmin.SiteCSSFile = SkinCSS; } // Add additional values to WebResponse object // Return true to cancel normal handling of query // Return false to allow UTServerAdmin to continue processing query function bool HandleSpecialQuery(WebRequest Request, WebResponse Response) { return false; } // Hook for overriding VariableMap values before tokens in .htm or .inc files are replaced with values // Return false to allow query processing to continue function string HandleWebInclude(WebResponse Response, string filename) { return ""; } function bool HandleHTM(WebResponse Response, string filename) { return false; } function bool HandleMessagePage(WebResponse Response, string Title, string Message) { return false; } function bool HandleFrameMessage(WebResponse Response, string Message, bool bIsError) { return false; } Uj L  GU{@UUv//----------------------------------------------------------- // //----------------------------------------------------------- class UT2K3Skin extends WebSkin; function Init(UTServerAdmin WebAdmin) { WebAdmin.SkinPath = ""; WebAdmin.SiteBG = DefaultBGColor; WebAdmin.SiteCSSFile = SkinCSS; } U| WG pW{%N{7tWW6e{t6d{t{W G Uf E\ S-P/HiddenNameE/HiddenValueD@ GUV@UUk UO k5Cp%x%,xplʂwl*6|w9Vlp x selectedVpppppppVxJV GU@UUYBa dN/ResetNameB/ResetValueAC GU}@UU_ }E v`}'[{qvqXv'( GU@UUh KK sRz{{ }KB}}BaB}{ }B GUD {P ~ --{ G"UT A Rw@w/*//b /**  GU_C -- G"Uat~ K A-stb-ttb GUvUU`Kg &Bbw**K%HK7KL KYw/*A  GUUUS wP -z-w G"UkLD &7 rp* Ewl*'|w9VlD Lp #D|L%l* ~l* L]wl*l= GUgC -z-z G"Uir~ 7-~rk '%--z-~4-~ GU_sM K5p* H XWebAdmin.WebSkins{HCmH wC*p* w9VCCJ7]]CH XWebAdmin.WebSkins>D  GUP  n=*3&r*0v%v7{6v1~A6vAppA|6vv-' GU~UUvUUUmU@ULUisH _0zs }s,{s&*({sEs&ZzE*xsE0 tE9(ss&0' GU@UUEUUKwJ ( GUxUUyUUUUv{I  GU|UU}@UU@UUzB ( GU@UUA@UUUU~CF 9( GUDUUE@UUF@UUUUBHN !( GUIUUJ@UUKUUUUKN=<Nu NZfNXg GUU@UU]@UU~UUj@UU@UUeUUm@UUFUUd@UU@U\UXUU_@UU~@UUUU@UvUWUU+@UUOUU@UU@UU@UUW @UU]VEDpWebadmin spectator executing SetPause:9T-V-V GUUU@UUlvmUc Al KAmzcALWLhALW y ALGALjAL GUNLh t|X,TUT-(X  kLu%ou7ze|6uzX'u9( GUuUUeR{ :].ut2(zR zU {R zUp|R,]UR}R,URRpR]7zR {U|U,]RUUU}U,RpU]7|R,]RpR]UR}R, GU@UUpUULUUUU|@UNUaUUc UUg UUJUU@UU@UUUUVUU[@U^UX@UU]@UUUUUUZUUUUbM W~ gg-T-Z- sWX- tWXIsBeforep ReverseSort:9T-pp Wis beforeX:9T-Z- sWX- tWXbWX GUL@UUdUUWUUIUUfUUAUUpUUmUUUUjUUa@UUFUUwUUvUUaUUhUUyUUPUUOUUw@USUnUUFUUtUUSUUBUUlUU`@@UU@UUCUU`UUjUUVUUUUCUUHUUI@UUk@URUBUU}UU{UUoUUD@UUe@UUY@UUp@UU\UUX@UUJ@UU@UUZ ND)%bN,Dk* =e%ne7k&6e6ee%CA%A7D|ADNONEC selected-F'A}Ippppe%ekC-FA%A7D|ADk eC selectedA?aBIppppppe k1I GU@UU@UUEUUZ//----------------------------------------------------------- // SampleSkin.ClassicUT // // Example class to demonstrate how to create a customized skin // for webadmin using unrealscript. //----------------------------------------------------------- class ClassicUT extends WebSkin; // Name of class will be used for name of SkinPath mYM2V=EmBcp ]UnrealAdminPage\]the Unreal Admin Page^ ]UnrealAdminPage.css_ ] #FFFFFFUUj tEH  MsnSectionK`a%{CGameConfiga`ppp`CGameConfigaaB|anColumnTitles`i9JtGameConfigIndex-1${tUpdate$id%d|pCGameConfigdkd,Ct pf%fCB|tpfNONEkNONEZ{kaBk,aBktpffkt p!FGameConfigidkd{bi{tDeleteiHGameConfigibi6{t NewLGameConfigb`a% aRGameConfigaB`pppp
d%d|aB`LKGameConfigadL;sai%s TEXTaB`p CGameConfigd9S,9S9J&s,s lGAMETYPEaB`n CGameConfigd?,s MUTATORSaB`pppp %s <TEXTaB`,s GAMETYPEf%f7h|,s6fhaB`6fhfP MUTATORS,s,wr%r7wf%f7|rw6faB`6fr7w&aB`,fr aB`daB`5 aiaB`l Update~aB`l DeleteJa aB`l EditJaB`
aEaB`pppppp
aB`l NewOaB`
nGameConfigs`nPageHelpPnz  n GUe@UUG//============================================================================== // the Unreal Admin page webadmin skin (UT2004 edition) // used with permission // // Written by Michiel Hendriks //============================================================================== class UnrealAdminPage extends WebSkin; UvTMJ A[-EzM&current_mutators-BzM&defaults_rules( GmdbQ2[3mBcp = UT2K3Stats\] UT2K3 Stats^ ]ut2003stats.cssn Y#current_mutatorsdefaults_rulesUU]UUUUzZ~I  -E -B{j,cell_ {jcurrent_mutators_group${jcurrent_mutators_group_row{jdefaults_row{zjcurrent_mutators_group$zjcurrent_mutators_group_rowzjdefaults_row6-H-h(-o(~CellClassnf-h'-o'~CellClassnabg-H-H-o~CellClassn-h-h(-o(~CellClassnabg-h-o'-h' GUMG"8Webadmin spectator executing pause command! GmUI2`[mBcp ] ClassicUT\= Classic UT^ ]classicut.css_ ] #000000UU@UU~^cB F\7|Jcurrent_mutators-E(-o(-h(WW|Jdefaults_row-B(( GUJUUg//----------------------------------------------------------- // //----------------------------------------------------------- class UT2K3Stats extends WebSkin; var int i; var bool bMutQuery, bRuleQuery, bFull, bRegLine, bAltLine; function bool HandleSpecialQuery(WebRequest Request, WebResponse Response) { bMutQuery = Mid(Request.URI,1) == "current_mutators"; bRuleQuery = Mid(Request.URI,1) == "defaults_rules"; return false; } function string HandleWebInclude(WebResponse Response, string Page) { if (!bMutQuery && !bRuleQuery) return ""; if (Left(Page,5) != "cell_" && Page != "current_mutators_group" && Page != "current_mutators_group_row" && Page != "defaults_row") return ""; if (Page == "current_mutators_group" || Page == "current_mutators_group_row"|| Page == "defaults_row") { if (bFull) { bAltLine = False; bRegLine = False; Response.Subst("CellClass", "n"); } else { bAltLine = True; bRegLine = True; Response.Subst("CellClass", "nabg"); } bFull = !bFull; return ""; } else { if (bRegLine) { Response.Subst("CellClass", "n"); if (bAltLine) bAltLine = False; else bRegLine = False; } else { Response.Subst("CellClass", "nabg"); if (bAltLine) bRegLine = True; else bAltLine = True; } } return ""; } function bool HandleHTM(WebResponse Response, string Page) { if (Page ~= "current_mutators") { bMutQuery = False; bRegLine = False; bAltLine = False; } else if (Page ~= "defaults_row") bRuleQuery = False; return false; } UUUrUUxUUz@URU`UUvUUs@UU@UUUR@UU@@UUsUUk@UUUU|UUUUGUUtUUg@UU@USUoUU~UU@UQUY@UUc @UUD@UUUUE@UUnUU|UU{UUiUU @UUUUUU@UUA@UUG@UUJ@UUB@UUg@UUP@UUTMmJq%Aq7h7|6qhMqq GUk l; G!m  c%z GUqUU@UU@UU@UUJ vr+zvv9Vx \ vo` &vs`69ox y xg%Egopppppp ExcludeMaps[9Sg]: Item 'o g' Tag 'o  g'gg%gspppppp IncludeMaps[9Sg]: Item 's g' Tag 's  g'gL GU@U__!_x^E^gE [^oh{^y^@^u^E ^h^E H^N ^LE c^VhB^u^M ^a^tE u^Z^}^^_Ixj^^XE tjU^j_Q^bE [^i^x^J^fB ^oN^\E \ou^KE S^j ouob^Ko]^Mo|^J^t^B ^LhDxPoz^p^u^S^TE TjAM AE zoloM^Q E nomjvx] oroYN L^RN }^D jVoChC^t oYh{obN P^jN wN FoMh}E P E boCE V^P ^M o P ho:^AE HP BF gxSB XP XE MoBo|E OoZhHovhEM oovhg h=hzo\hh oNoah|h ^uoW^t^r^[hPM {xRhSxPhIovE TE SM WE Ko{hnM G oQoqodhdh=hrN ihsM WE MP [M L hX N {xhU^`hRh[h~hrhKoZoMoBokh\hrM wE uE cE ^hxhqhhp^L F ~ hGE nP G P T N q M cM NM G hCM n^`oGhuo[ M YN V fIZlMcspof{Nt]moe~EM`\\k,ywJ\Zpi\ywHokW\hwvwE_aUoHvvFwVodfhwwE5U\dIssBlwQUaUpj~tMU|I\Qk9wz\JoYkohsWSTfojuUwE]wUweEuwD_wSrc}rKA&vQT`Qog]}&wZejohyd`Ioii\ywHwX{vhzxzH<~X{wgwwU_cFrUcdQrq@U9vOy^kmU\{sJ!wZ7wjgzaJAGZU\kU_ezkI\W^wf\vzwEUsURe^yt<\CyQ c`\cnva>|]v]AlUNw|SL@ZBiYylkJ[wYvhwxUk\H(tWUowgovwATGUUUqUOdUyuvDNSoOaepvxNA@_AToUOQNUog]UmU\|\JeX'RfewuUI EvUdwsUUI CUxQs`sor~KMf[U%cjEyUqHlW[fUiuUUU9GC9rT\QcUk^rlBJQZ\`ol]~IMlv\U]vjU_\y]kG]]V_ve]tmCUpR|a\qMnNU~]cl_{vJU\Y\g<OufDUgS_a\py\sM\\4vkUU J z@IvW `foNu sD cS/\b\pv~mLJT[VcjBx\`HvNWwfUU\v(sDUUUTNc\r(UATP(\`boe~oPL~['\joRxUTGoUU_g\ve\EPTUeycvrUp\ApP^\_|nM~^TMUo]LlUK{UlvJNYhPghWuheDhwSFcproA\Pn_noOUHOc]plo{nJdZU{j{xcFbUsdjs cBUUUsPU3w_ Qnk}7sLAH ZJH jNyz]wIOTYyh9pv9qFoMVawe9suUa^DVQRUOH a]yqEwNKw^Nxm8`|N\KUcYA\gOxvGUiV QeUtxCyRv``p}RN~]llv{KUUZvinwRF^UUrcqskBwQGaLpa@U\Nv\Rlez{UwJdZdwiqy^zHUaVU%dv\IU_fW]ufkSukZCGRZSaZTpUUhv~UHNlu]UoSlkq{zvK]v[_^iZxvmGwVnfwvxFpOUUe~tDCFRuawqUd@UUUQPA_UdnUQ~qM\\^key~HLW]ebtvCU:RU4Ravo I ~!vNQ^7vmFH }~MUv\JO lVI zoTI9tY<Nh9owoVGUXVVK e]vt<vD`oaTFQCAQR>`a;`poQQN'C]'~l U{/I P*C _%Qm%I | QKU I ZUK iUI xMGDT^WZm{D|SU}bI qH AvQQaH p`@vO`_Qn, V}SI bC rQ@vNw^I mQ}wKI Z@jQyI G,.WWs=E|x_HA WQf,DuwNAR^,h^mvKBZwiCxAVGC`}ox~\M[q[Uqi~wASF[A Uvd[|tMDDSabUQqUUUav@}PC_Uwnx}NL~Z:iexeGNVwdemtwB^R^awpv]@YOre^XmW|d:KUdZdziexfGgVUje`etUA CiRqaZRoo?G~Ax:EZJfw Ne@ EQG EoFZLU^Jf`Ju zDcj ~eJhpJwR_GoJfwto+gDgn kvYkJiN^xo9YVUo0|o]GkrJyUoErHdJz[gHvJWhcfNcIoYl{E|JU`dqso$hBUPM'jJwo~EJCA\8QJIo {WJRSU,DKSOJ^,-lJYJi, -xoJZeJ,zWM^dJsJBky Q,@WJoKya_{ZJUUQzdAr:^A['X NC P Q `a JpoXljWwAvQopEaV[f]4UA]4{YVQUJaJpA]4uDoqZtJN3v]CVmmlC<JoU J~_LNSkb~oLe`%JE}0So=kC1'n'U-J|#VJd`/Oo/J~WIMA3YV'JoJ~nWMDdZUh8J}-KPx;JH ,V]4GBB>JIswW @NAH3^AJQKv`@8pNvhAIPxFJH(xVoCN&JQJJ_XRnd@ d[vtOJDAGRAt*Yb]4O Cs=cRAs&uk[TJjVJxpoGg= PvY} F\JC |R=]4HaqEia`n\N\\lJjlvxjvHjwXjJhp&vlw\q&lUUr RUb\qm @Ooy ]of ly { Ioi XUy goM vk Em T@cQ reAUW PUw _V m)\|[ Jox YoI hos wf FU@ Uz dzRs!y A^ Om _F nI }UU| L\[)y joS y~ HUUo~ WU9q fUUTuwDM Tpce rt AoL PUoZ _F nUs }O Ma \oE kzzSIUT XE g\ vH ENT9d cUu rZ @oL OW ^j mUn |o] K@ ZCiR xS Gu VXeoJ tw CN RC aJ p{ A Ny ]g l} {^ JUov YR hot wD Fp U{ do soY BUb Ql `A oou ~oQ MoO \oK koG zP Ioz X gx v_ Eou TU ck rq AiPoB _or nK }ow LC [` jN yP HUB Wod fu u} DUUX SD bG qh @_ NUz ]g lH {a Jj YY he wT Fc Ub dzsmBoo @QJQon \_J{op qIJzJHol \Voh TrUUUUos g FJmoV |UUoc KTZUU)Jhq vwUUo{ m] f}ey c9|roy B9\R^y ay poR | P\_Mm\|O JJ Y\h|\vyD9X R,J c9|rR BKPr _oU pA z MUA \E kD z\I\Ws em tUW D} SS b@ qK @Y OA ^Im9T |9v KoS ZA iUoH w-n Hm Xo hUQwU@ F U-_ c-^ rfAUZ OQ^w mA |l J_YUdh`w\F`UUy du ri @f OoT ^u mUF {m[ QJUoW [A jx yoV HmWQfoe uoQ D` S-p b-\q-=R@oY Rd l-]4F{UL #AJd~]4BsoG ^uo\ \SJooO Y~JWoa ZeJE eNJsUUoK _A,P -`oA rM,C .,~ VmJCog gRJyUP -GoD dtC .X~ LFoM SRP =IeJnJ}]H L4R ]H YmU^n FJTU-J &cvIwYJi-I 'ww^N nJ}-B &KwqN AJP-F &^wD:TNcJr-N &@wfNvk EJTK~=LbUUUUUi^nUUiq}UKLUUUP[UiNjUUUUU`\xbG`IVUUUUy eUUUUUH tUUUUe\DUUUUUU`WSUGbpH qpr@UUUUUUUUUUU``QUUUUUQ`UUUMHn`J}ebKUUUUUU`MYUUUUUUUUUUUUU@gUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUAEbvUMJXUUUUUUUUUUUUH fo| tUUol IFUUUUoh {OUeJJUo{ UYUUUUUUUUUUUUrnUUUUUUU`|UU``KUUU9`Z`_hryU`pIpnXp`gUU_vUUwDUU@Rr~`rzr`CQRUOar\oUJ}zLb~ c]f@\OX^]_nU~\MX\XlW|^XJ^Zhie_ygIwYUigx!XHz_XVhvyXI_Yegil_y_IOYXhZxgGwWgggwUFaUSd]seD_S_ccsTB^QP`dov~k NoN]SloD|z]vVD\R]4famMuGEs!|Jo]4S~vJ oQmQr@wrJBzI bPAGYrmI]KJh~B rvwh]4sxJkOy\HoyWCh\} wmFUwepbtoCBS\bApp@Ns]el]{`K`ZotixyxH~Ws fontpTC}R}ap{o|MD[opixxoqGooVxeewtGComYRol7kJbtqyA]QArH_g