View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0000626 | FSSCP | gameplay | public | 2005-11-21 04:49 | 2006-06-01 05:16 |
| Reporter | Goober5000 | Assigned To | taylor | ||
| Priority | normal | Severity | block | Reproducibility | always |
| Status | resolved | Resolution | fixed | ||
| Summary | 0000626: "Timer Rolled" causes game lockup | ||||
| Description | It seems that the "Timer Rolled" code in timer.cpp causes the game to freeze. Commenting out the line "Timer_base = time_now" fixes it. With the line uncommented, FSO simply locks up and is completely unresponsive. The music keeps playing, but at the end of the current track it too stops. I'm able to force-close the game if I'm running it in a window, but if I'm running it full-screen I have to do a hard reboot. I'm surprised nobody else has reported it, since it's a rather severe error. Perhaps it's my system, although it hasn't popped up until recently. | ||||
| Additional Information | I'm guessing the TIMER ROLLED code was added to prevent clock rollovers at midnight, but it's just popping up at random times. I added a line to print the difference to fs.log, which I've attached. The difference by which time_now is behind Timer_last_value isn't very big, typically 1, but it's occasionally as high as 50ish. The fs.log was taken during a run-through of the second demo mission. Search for "TIMER ROLLED" to find the instances. | ||||
| Tags | No tags attached. | ||||
|
2005-11-21 04:49
|
|
|
|
timeGetTime() returns the Windows system time in milliseconds since the system started. It only wraps every 49 days or so, so you really shouldn't ever see it more than once during a single game much less one mission. The Timer_base variable is used to determine how much time the game has been running and always needs to be accurate to what timeGetTime() is going to give, hence the roll check. What is time_now actually coming out to be when it wraps? |
|
2005-11-21 06:07
|
|
|
|
Well I attached another fs.log with printouts of the three variables each time the roll event occurs. This is playing through both missions of the demo campaign. Time_now is around 40M, but earlier tonight it was around 38 or 39M. It doesn't actually "wrap" though; Timer_last_value just gets ahead of time_now for some reason. Incidentally, I kept getting "Assert: Mission_events[*e1 & 0xffff].born_on_date != 0" in the first mission of the campaign, after I had destroyed the first wing of fighters that comes after Command says "you might want to rearm". I'm wondering if it's related to the event directive bug. |
|
|
Hmm, a precision error perhaps? What's the return value of timeBeginPeriod() in timer_init()? It should return 0 if there was no problem. |
|
|
Well, this is interesting. It seems timeBeginPeriod is called twice. Both times it returns 0, but it really shouldn't be called twice, I'm guessing. :) Both times are in game_init. The first time it's called through timer_init, but the second time it's called near the end of the function, right before mprinting VALID or INVALID. Oh, and by the way, I encountered a problem in weapon_explosions::PageIn where i is not yet initialized. I'm assuming that should be idx? |
|
|
Well, unfortunately that didn't solve the problem. :( I'm still getting the timer rolls, they're still causing freezes, and now they're ranging all over the place. I've uploaded a third fs.log for you to look at if you want. edited on: 11-21-05 23:33 |
|
2005-11-22 04:32
|
|
|
|
It's ok to call timeBeginPeriod more than once, just so long as there is a corresponding EndPeriod call for each. I would have preferred to only use the one but I left room for the call in timer_init to have a different precision setting. The EndPeriod call has to match the same precision which is why I left it with the two sets. The set after the timer_init call could be removed I think, I didn't test it. MSDN said that was perfectly ok to leave it as is though. And the i thing is supposed to be idx. That's what I get for chaning how PageIn worked back to like WMC had it without testing that it still worked. Making that change now. :) |
|
|
Add something like this to timer_init(): TIMECAPS mtime; timeGetDevCaps(&mtime, sizeof(TIMECAPS)); and check the value of mtime.wPeriodMin to see what the minimum precision actually gets reported as. Might just have to adjust it to choose the best precision and compensate for that in later math. |
|
|
Who submitted the original code (CVS Logs)? Whoever it is should own this bug. edited on: 11-25-05 11:08 |
|
|
I changed the code. It was one of the very few ways that's safe on SMP and dual core machines so I'm hesitant to change it unless more people (so far only Goober) start reporting a similar problem. |
|
|
I'm home right now so I can't give any more updates, but I'll be able to resume testing on Monday. |
|
|
*bump* because I intend to get back to this bug this evening. :) BTW, the phrase "add something like this to timer_init" sounds dangerous. I can add *exactly* that code snippet to timer_init, but if that's not the proper code I won't know what to change it to. :p |
|
|
Those two lines should be exact, I just haven't tested it myself to know for sure if it's compilable as is in the current code. It won't interfere with any of the other timer code (so don't replace anything) but will just give you some extra info to debug with. The idea with that is to make sure what precision the computer is reporting. If it's 5 or even 10ms, and we are doing math as if it's 1ms, then that could cause the issue. We may just need to add some basic fudge support in there. |
|
|
K, I added it in the block where it says TIMER ROLLED. Here are the results: wPeriodMin 1 wPeriodMax 65535 |
|
|
*bump* :p |
|
|
I'm thinking... ;) |
|
|
Hello. i'm not a programmer, so this entire discussion is far beyond my head. i feel as if i'm cluttering Mantis just by posting... but here goes. i'm using Win98SE, DX8.1b, OpenAL 1.1, a Radeon 9200, Catalyst 6.2, 400MB RAM and a 1.2Ghz P3. Prior to using the 2/20/06 redmenace CVS build, i did not notice this timer bug. Upon using the build, i may have gotten the error, i don't recall. i stopped playing FS_Open entirely for some time, then very recently tried the karajorma CVS builds for April/May. All of them generate the timer bug within about 15 minutes of gameplay. If i wait about 20 minutes, the crash unfreezes and play can resume for another 15 minutes before another crash. After discovering all that, i went back to the 2/20/06 build. It doesn't generate the timer bug anywhere near as often as the karajorma builds; i get maybe one crash in 45 minutes. Edit 5/23/06: Several hours of testing seem to indicate that the bug does not occur if registry DWORD "MaxFPS" is set to >50. edited on: 05-23-06 03:23 |
|
2006-05-29 04:38
|
timer.cpp (11,901 bytes)
/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
/*
* $Logfile: /Freespace2/code/Io/Timer.cpp $
* $Revision: 2.14 $
* $Date: 2006/03/30 04:15:20 $
* $Author: Goober5000 $
*
* Include file for timer stuff
*
* $Log: timer.cpp,v $
* Revision 2.14 2006/03/30 04:15:20 Goober5000
* hehe, grammar
* --Goober5000
*
* Revision 2.13 2005/10/12 05:45:35 taylor
* new timer code that shouldn't suffer from multi-cpu (or dual core) systems
* clean out all old Windows timer code since that was just a mess at this point
*
* Revision 2.12 2005/05/26 09:21:28 taylor
* forgot to take into account F1_0 on timer_get_fixed_seconds(), remove those stupid CRs too
*
* Revision 2.11 2005/05/26 04:27:11 taylor
* timer changes to fix game_busy() on the loading screen and 100% incorrect values on some machines,
* don't know if this is going to work that great but it's more like the Linux SDL code now which
* has worked for years without major problems
*
* Revision 2.10 2005/04/11 10:15:11 taylor
* un-revert previous revert since it does apparently affect MinGW (Alpha0)
*
* Revision 2.9 2005/04/11 05:50:35 taylor
* some limits.h fixes to make GCC happier
* revert timer asm change since it doesn't even get used with Linux and couldn't have been the slowdown problem
*
* Revision 2.8 2005/03/27 08:57:52 taylor
* will hopefully fix the slowdown from mission to mission (thanks Alpha0)
*
* Revision 2.7 2005/03/03 16:18:19 taylor
* lockup fixes, and it's Linux friendly too :)
*
* Revision 2.6 2005/02/04 10:12:30 taylor
* merge with Linux/OSX tree - p0204
*
* Revision 2.5 2004/07/26 20:47:33 Kazan
* remove MCD complete
*
* Revision 2.4 2004/07/12 16:32:51 Kazan
* MCD - define _MCD_CHECK to use memory tracking
*
* Revision 2.3 2003/03/02 05:46:28 penguin
* Added gcc-compatible asm blocks
* - penguin
*
* Revision 2.2 2002/08/01 01:41:06 penguin
* The big include file move
*
* Revision 2.1 2002/07/07 19:55:59 penguin
* Back-port to MSVC
*
* Revision 2.0 2002/06/03 04:02:24 penguin
* Warpcore CVS sync
*
* Revision 1.4 2002/05/24 16:46:47 mharris
* Fixed stupid error I made in timer_get_fixed_seconds()
*
* Revision 1.3 2002/05/17 06:45:53 mharris
* More porting tweaks. It links! but segfaults...
*
* Revision 1.2 2002/05/09 13:50:50 mharris
* temporarily ifdef out asm
*
* Revision 1.1 2002/05/02 18:03:08 mharris
* Initial checkin - converted filenames and includes to lower case
*
*
* 4 5/26/99 3:19p Dave
* Fixed release build errors.
*
* 3 5/17/99 6:03p Dave
* Added new timing code. Put in code to allow camera speed zooming.
*
* 2 10/07/98 10:53a Dave
* Initial checkin.
*
* 1 10/07/98 10:49a Dave
*
* 14 4/13/98 10:16a John
* Switched gettime back to timer_get_milliseconds, which is now thread
* safe.
*
* 13 4/13/98 10:11a John
* Made timer functions thread safe. Made timer_init be called in all
* projects.
*
* 12 4/13/98 8:09a John
* Made timer_get functions thread safe.
*
* 11 12/02/97 3:56p John
* fixed a bug with timestamp_until, created one with it rolling over.
*
* 10 9/11/97 7:12p Hoffoss
* Added more functionality to training sexp handling code.
*
* 9 8/29/97 4:49p Allender
* added mprintf to check for wrap problems with timestamp ticker
*
* 8 8/28/97 1:38p Allender
* from John: changes to timer func to detect early rollever
*
* 7 7/29/97 5:30p Lawrance
* move gettime() from keyboard module to timer module
*
* 6 7/16/97 4:42p Mike
* Make afterburner shake viewer, not ship.
* Shake for limited time.
* Add timestamp_until() function to timer library.
*
* 5 2/17/97 5:18p John
* Added a bunch of RCS headers to a bunch of old files that don't have
* them.
*
* $NoKeywords: $
*/
#ifdef _WIN32
#include <windows.h>
#endif
#include <limits.h>
#include "globalincs/pstypes.h"
#include "io/timer.h"
#include "graphics/2d.h"
#include "globalincs/alphacolors.h"
#define THREADED // to use the proper set of macros
#include "osapi/osapi.h" // for multi-thread macros
#ifndef NDEBUG
#define USE_TIMING
#endif
#ifdef _WIN32
static longlong Timer_last_value = 0, Timer_base = 0, Timer_freq = 0;
static const int precision = 1;
#endif
static int Timer_inited = 0;
static CRITICAL_SECTION Timer_lock;
void timer_close()
{
if ( Timer_inited ) {
Timer_inited = 0;
#ifdef _WIN32
timeEndPeriod(precision);
#endif
DELETE_CRITICAL_SECTION( Timer_lock );
}
}
void timer_init()
{
if ( !Timer_inited ) {
INITIALIZE_CRITICAL_SECTION( Timer_lock );
#ifdef _WIN32
timeBeginPeriod(precision);
Timer_base = Timer_last_value = timeGetTime();
#endif
Timer_inited = 1;
atexit(timer_close);
}
}
static uint timer_get()
{
#ifdef _WIN32
longlong time_now;
time_now = timeGetTime();
ENTER_CRITICAL_SECTION( Timer_lock );
if ( time_now < Timer_last_value ) {
// the clock has rolled!
Timer_base = time_now;
mprintf(("TIMER ROLLED!\n"));
}
Timer_last_value = time_now;
LEAVE_CRITICAL_SECTION( Timer_lock );
return (uint)(time_now - Timer_base);
#else
return SDL_GetTicks();
#endif
}
fix timer_get_fixed_seconds()
{
if (!Timer_inited) {
Int3(); // Make sure you call timer_init before anything that uses timer functions!
return 0;
}
longlong a = timer_get();
a *= 65536;
return (fix)(a / 1000);
}
fix timer_get_fixed_secondsX()
{
return timer_get_fixed_seconds();
}
fix timer_get_approx_seconds()
{
return timer_get_fixed_seconds();
}
int timer_get_milliseconds()
{
if (!Timer_inited) {
Int3(); // Make sure you call timer_init before anything that uses timer functions!
return 0;
}
return timer_get();
}
int timer_get_microseconds()
{
if (!Timer_inited) {
Int3(); // Make sure you call timer_init before anything that uses timer functions!
return 0;
}
return timer_get() * 1000;
}
// 0 means invalid,
// 1 means always return true
// 2 and above actually check the time
int timestamp_ticker = 2;
void timestamp_reset()
{
timestamp_ticker = 2;
}
// Restrict all time values between 0 and MAX_TIME
// so we don't have to use UINTs to calculate rollover.
// For debugging & testing, you could set this to
// something like 1 minute (6000).
#define MAX_TIME (INT_MAX/2)
void timestamp_inc(float frametime)
{
timestamp_ticker += (int)(frametime*TIMESTAMP_FREQUENCY);
if ( timestamp_ticker > MAX_TIME ) {
timestamp_ticker = 2; // Roll!
}
if (timestamp_ticker < 2 ) {
mprintf(("Whoa!!! timestamp_ticker < 2 -- resetting to 2!!!\n"));
timestamp_ticker = 2;
}
}
int timestamp(int delta_ms )
{
int t2;
if (delta_ms < 0 ) return 0;
if (delta_ms == 0 ) return 1;
t2 = timestamp_ticker + delta_ms;
if ( t2 > MAX_TIME ) {
// wrap!!!
t2 = delta_ms - (MAX_TIME-timestamp_ticker);
}
if (t2 < 2 ) t2 = 2; // hack??
return t2;
}
// Returns milliseconds until timestamp will elapse.
// Negative value gives milliseconds ago that timestamp elapsed.
int timestamp_until(int stamp)
{
// JAS: FIX
// HACK!! This doesn't handle rollover!
// (Will it ever happen?)
return stamp - timestamp_ticker;
/*
uint delta;
delta = stamp - timestamp_ticker;
if (delta > UINT_MAX/2)
delta = UINT_MAX - delta + 1;
else if (delta < - ( (int) (UINT_MAX/2)))
delta = UINT_MAX + delta + 1;
return delta;
*/
}
// alternate timestamp functions. The way these work is you call xtimestamp() to get the
// current counter value, and then call
int timestamp()
{
return timestamp_ticker;
}
int timestamp_has_time_elapsed(int stamp, int time)
{
int t;
if (time <= 0)
return 1;
t = stamp + time;
if (t <= timestamp_ticker)
return 1; // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.
return 0;
}
// timing functions -------------------------------------------------------------------------------
#define MAX_TIMING_EVENTS 15
// timing struct
#ifdef USE_TIMING
typedef struct timing {
char name[64];
int microseconds_total;
int start;
int ref_count;
} timing;
timing Timing_frame;
timing Timing_events[MAX_TIMING_EVENTS];
int Timing_event_count = 0;
#endif
// lookup a timing event
int timing_event_lookup(char *event_name)
{
#ifndef USE_TIMING
return -1;
#else
int idx;
// sanity
if(event_name == NULL){
return -1;
}
// look through all events
for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
if(!stricmp(Timing_events[idx].name, event_name)){
return idx;
}
}
return -1;
#endif
}
// start timing frame stuff
void timing_frame_start()
{
#ifndef USE_TIMING
return;
#else
int idx;
// restart the frame
Timing_event_count = 0;
Timing_frame.start = timer_get_microseconds();
for(idx=0; idx<MAX_TIMING_EVENTS; idx++){
Timing_events[idx].microseconds_total = 0;
strcpy(Timing_events[idx].name, "");
Timing_events[idx].ref_count = 0;
}
#endif
}
// done timing the frame
void timing_frame_stop()
{
#ifndef USE_TIMING
return;
#else
int stop_time;
// stop time
stop_time = timer_get_microseconds();
// calc times
Timing_frame.microseconds_total = stop_time - Timing_frame.start;
#endif
}
// get the total frame time in microseconds
int timing_frame_total()
{
#ifndef USE_TIMING
return 0;
#else
return Timing_frame.microseconds_total;
#endif
}
// time an individual event
void timing_event_start(char *event_name)
{
#ifndef USE_TIMING
return;
#else
int event;
// sanity
if(event_name == NULL){
return;
}
// try and find the event
event = timing_event_lookup(event_name);
// if we already have one
if(event != -1){
Assert(Timing_events[event].ref_count == 0);
Timing_events[event].start = timer_get_microseconds();
Timing_events[event].ref_count++;
}
// if we need to add a new one
else {
if(Timing_event_count < MAX_TIMING_EVENTS){
strcpy(Timing_events[Timing_event_count].name, event_name);
Timing_events[Timing_event_count].start = timer_get_microseconds();
Timing_events[Timing_event_count++].ref_count++;
}
}
#endif
}
// stop timing an event
void timing_event_stop(char *event_name)
{
#ifndef USE_TIMING
return;
#else
int event;
// sanity
if(event_name == NULL){
return;
}
// try and find the event
event = timing_event_lookup(event_name);
// if we already have one
if(event != -1){
Assert(Timing_events[event].ref_count == 1);
Timing_events[event].microseconds_total += timer_get_microseconds() - Timing_events[event].start;
Timing_events[event].ref_count--;
}
#endif
}
// get the total time for an event in microseconds
int timing_event_total(char *event_name)
{
#ifndef USE_TIMING
return -1;
#else
int event;
// sanity
if(event_name == NULL){
return -1;
}
// try and find the event
event = timing_event_lookup(event_name);
if(event == -1){
return -1;
}
return Timing_events[event].microseconds_total;
#endif
}
// get the percentage of total frametime for the event (0.0 to 1.0)
float timing_event_pct(char *event_name)
{
#ifndef USE_TIMING
return 0.0f;
#else
int event;
// sanity
if(event_name == NULL){
return -1.0f;
}
// try and find the event
event = timing_event_lookup(event_name);
if(event == -1){
return -1.0f;
}
return (float)((double)Timing_events[event].microseconds_total / (double)Timing_frame.microseconds_total);
#endif
}
// display timing
void timing_display(int x, int y)
{
#ifndef USE_TIMING
return;
#else
int idx;
gr_set_color_fast(&Color_bright_blue);
// total time
gr_printf(x, y, "Total time %f\n", (float)timing_frame_total() / 1000000.0f);
y += 10;
// each event percentage
for(idx=0; idx<Timing_event_count; idx++){
gr_printf(x, y, "%s: %f\n", Timing_events[idx].name, timing_event_pct(Timing_events[idx].name));
y += 10;
}
#endif
}
|
|
|
Please check and see if the attacked timer.cpp file works any better. Not much is different, I just added an ENTER/LEAVE_CRITICAL_SECTION macro set in timer_get(). Not sure if that will do much, but I've exhausted pretty much every other idea. EDIT: Oh and the *_CRITICAL_SECTION calls were there originally. Not sure why I didn't add them back when I did the changes to fix the SMP issues. I'm also not sure why I didn't notice they were missing before :/. edited on: 05-29-06 00:43 |
|
|
Change is now in CVS too btw. |
|
|
[double-checking] Were you addressing me, taylor? If so, then i can't do anything with timer.cpp; i'm a worthless, groveling end-user with no knowledge of compilers. Everything i posted came of using binaries. If not, then 'oops' and just ignore this comment. |
|
|
I think the comment was addressed to me. I'll have to play a few missions before I know if it's fixed (been busy this weekend). |
|
|
It was addressed at Goober mostly. You'll get the change with the next build though (hence the CVS commit update) so keep that in mind when you're testing and if it's working now just let me know. If no one else puts up a build in the next day or two then I'll post one for you to play with. EDIT: Oops, should have refreshed before posting. :) edited on: 05-30-06 01:06 |
|
|
Ah, duly noted; sorry for the interruption. (And hello, Goober5000.) Though, i would like to remention the edit i added to my other post: setting the MaxFPS variable to >50 solves the problem for me completely, as i've been playing FS_Open without a single crash since then. Hence, i've been wondering if that information was/is relevant or useful to you? Edit: Doh--thanks for offering to make a binary, taylor; no hurry, only do it if you feel like it. edited on: 05-30-06 01:12 |
|
|
The MaxFPS thing is curious, but didn't really help me any. Actually I just sat down at my desk and thought "did mutex locking get put back on in that function?", at which point I looked, and it didn't. Oh well, whatever. ;) The MaxFPS thing does change how often it (the process) sleeps though, which may be why that works. Of course that's not really a fix and just hides the real problem. You would likely still get the hangs/crashes if you upgraded to a faster computer for instance, or used a slower one. |
|
|
[light bulb] Ahhh. It's a shame the math co-processor of my brain is defective; the whys and wherefores of bugs are so intriguing (plus i imagine you might not refuse another hand to help out?). At any rate, thanks again for humouring my curiosity. |
|
|
@Crusader: Try this build - http://fs2source.warpcore.org/exes/latest/May2006/FS2_Open_Kara_20060531.rar It has some reported problems, but it also has the timer fix (if it actually is a fix). Let me know whether that makes a difference with this lockup/crash issue. |
|
|
Indeed, taylor, i downloaded that build earlier today from the forums. i still appreciate you providing a link though. As may be inferred, i'm here to report my findings: i tested the build with 'MaxFPS' off, whereafter a half hour of gameplay yielded no crashes. i'd say, good work. (And i may know what you mean about 'reported problems', because at present OpenAL will not initialise at all in this build. i could only do my testing by disabling all sound and music. But, i digress.) |
|
|
Cool. Thanks. I'll go ahead and resolve this then, but if you get the same problem again (or if Goober can still recreate it) then just reopen and I'll take another shot at it. |
|
|
Fixered. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2005-11-21 04:49 | Goober5000 | New Issue | |
| 2005-11-21 04:49 | Goober5000 | File Added: fs.log | |
| 2005-11-21 05:05 | taylor | Note Added: 0003904 | |
| 2005-11-21 06:07 | Goober5000 | File Added: fs.log | |
| 2005-11-21 06:10 | Goober5000 | Note Added: 0003905 | |
| 2005-11-21 06:54 | taylor | Note Added: 0003907 | |
| 2005-11-22 03:37 | Goober5000 | Note Added: 0003911 | |
| 2005-11-22 04:32 | Goober5000 | Note Added: 0003912 | |
| 2005-11-22 04:32 | Goober5000 | File Added: fs.log | |
| 2005-11-22 04:33 | Goober5000 | Note Edited: 0003912 | |
| 2005-11-22 04:34 | taylor | Note Added: 0003913 | |
| 2005-11-22 04:44 | taylor | Note Added: 0003914 | |
| 2005-11-25 16:06 | Inquisitor | Note Added: 0003935 | |
| 2005-11-25 16:08 | Inquisitor | Note Edited: 0003935 | |
| 2005-11-25 16:47 | taylor | Status | new => assigned |
| 2005-11-25 16:47 | taylor | Assigned To | => taylor |
| 2005-11-25 17:28 | taylor | Note Added: 0003936 | |
| 2005-11-25 21:18 | Goober5000 | Note Added: 0003938 | |
| 2006-01-13 18:23 | Goober5000 | Note Added: 0004244 | |
| 2006-01-13 19:09 | taylor | Note Added: 0004248 | |
| 2006-01-14 06:44 | Goober5000 | Note Added: 0004263 | |
| 2006-02-23 18:26 | Goober5000 | Note Added: 0004903 | |
| 2006-02-23 19:36 | taylor | Note Added: 0004909 | |
| 2006-05-21 04:37 | Crusader | Note Added: 0005542 | |
| 2006-05-23 07:23 | Crusader | Note Edited: 0005542 | |
| 2006-05-29 04:38 | taylor | File Added: timer.cpp | |
| 2006-05-29 04:41 | taylor | Note Added: 0005665 | |
| 2006-05-29 04:43 | taylor | Note Edited: 0005665 | |
| 2006-05-30 03:14 | taylor | Note Added: 0005670 | |
| 2006-05-30 04:58 | Crusader | Note Added: 0005673 | |
| 2006-05-30 05:02 | Goober5000 | Note Added: 0005674 | |
| 2006-05-30 05:05 | taylor | Note Added: 0005675 | |
| 2006-05-30 05:06 | taylor | Note Edited: 0005675 | |
| 2006-05-30 05:09 | Crusader | Note Added: 0005676 | |
| 2006-05-30 05:12 | Crusader | Note Edited: 0005676 | |
| 2006-05-30 05:22 | taylor | Note Added: 0005677 | |
| 2006-05-30 05:29 | Crusader | Note Added: 0005678 | |
| 2006-06-01 04:12 | taylor | Note Added: 0005680 | |
| 2006-06-01 04:57 | Crusader | Note Added: 0005681 | |
| 2006-06-01 05:16 | taylor | Note Added: 0005682 | |
| 2006-06-01 05:16 | taylor | Status | assigned => resolved |
| 2006-06-01 05:16 | taylor | Resolution | open => fixed |
| 2006-06-01 05:16 | taylor | Note Added: 0005683 |