gruvin / gruvin9x

Automatically exported from code.google.com/p/gruvin9x
6 stars 6 forks source link

SIMU hangs when trying to format virtual EEPROM #94

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
As at r1480, SIMU doesn't respond to arrow keys/home/end any more. These used 
to be mapped to [UP] [DOWN] [LEFT] [RIGHT] (arrows)  and [MENU] [EXIT] (Home & 
End).

Were the key assignments changed to something else?

I changed one line in r1480 to removed a compiler warning I was getting. It 
happens to be in the key input routine. Maybe this is the cause? ...

gruvin9x.cpp diff...

475     - in = (~PIND & 0b11000000) >> 5;
    475 + in = (~PIND & 0xc0/*0b11000000*/) >> 5;

Original issue reported on code.google.com by gru...@gmail.com on 14 Feb 2012 at 12:39

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
This is weird ...

I changed the line back to use the 0b11000000 instead of 0xc0. Now I don't get 
the compiler warning I was getting before (bad suffix) (huh?!!) and the keys 
work again. BUT ...

Now when I press any key to get past the Alarms warning, Simu enters into 
"EEPROM Formatting" and hangs (crashes.)

None of this is making any sense to me. :/ Can you figure it out?

Also, Simu started up with the back light on already, whereas previously it 
started without. WEIRD.

Oh and, this is on my console ...

$ ./simu
bad eeFs.version
: Undefined error: 0
bad eeFs.mySize
: Undefined error: 0

Original comment by gru...@gmail.com on 14 Feb 2012 at 12:48

GoogleCodeExporter commented 9 years ago
That's weird, indeed.
I tried here without any problem.
What is your make command for simu?

Original comment by bson...@gmail.com on 20 Feb 2012 at 10:12

GoogleCodeExporter commented 9 years ago

bryan:src$ make DSM2=NO simu
g++ simu.cpp -gdwarf-2 -DF_CPU=16000000UL -DPCBV3 -DFRSKY -DFRSKY_HUB 
-DWS_HOW_HIGH -DTELEMLOGS -DPCBV4 -DBEEPSPKR -DTRANSLATIONS -DTEMPLATES -Os 
-Wall -Wno-strict-aliasing  -I../gtest-1.6.0//include gruvin9x.cpp pulses.cpp 
stamp.cpp menus.cpp model_menus.cpp general_menus.cpp main_views.cpp 
statistics_views.cpp pers.cpp file.cpp lcd.cpp drivers.cpp  gtime.cpp rtc.cpp 
ff.cpp diskio.cpp frsky.cpp logs.cpp templates.cpp simpgmspace.cpp -arch x86_64 
-o simu -I/usr/local/include/fox-1.6 -I/usr/include/fox-1.6 -I/include 
-I/opt/local/include/fox-1.6 -L/usr/local/lib -L/src/.libs -L/opt/local/lib 
-lFOX-1.6 -Wl,-rpath,/src/.libs -MD -DSIMU
ld: warning: directory not found for option '-L/src/.libs'
bryan:src$ ./simu
bad eeFs.version
: Undefined error: 0
bad eeFs.mySize
: Undefined error: 0
bryan:src$ svn up
At revision 1505.

Locks up on the screen shown in attachment.

Original comment by gru...@gmail.com on 22 Feb 2012 at 5:21

Attachments:

GoogleCodeExporter commented 9 years ago
The problem is solved here. Could you tell me if it works for you?

Original comment by bson...@gmail.com on 23 Feb 2012 at 1:34

GoogleCodeExporter commented 9 years ago
Unfortunately, no. It seems still exactly the same here.

[trunk/firmware/src]

$ make clean

-------- begin --------

Cleaning project:
rm -f simu
rm -f gtests
rm -f gtest.a
rm -f gtest_main.a
rm -f gruvin9x.hex
rm -f gruvin9x.eep
rm -f gruvin9x.cof
rm -f gruvin9x.elf
rm -f gruvin9x.map
rm -f gruvin9x.sym
rm -f gruvin9x.lss
rm -rf obj
rm -f 
rm -f *.o
rm -f *.d
rm -rf .dep
-------- end --------

$ make DSM2=NO simu
g++ simu.cpp -gdwarf-2 -DF_CPU=16000000UL -DPCBV3 -DFRSKY -DFRSKY_HUB 
-DWS_HOW_HIGH -DTELEMLOGS -DPCBV4 -DBEEPSPKR -DTRANSLATIONS -DTEMPLATES -Os 
-Wall -Wno-strict-aliasing  -I../gtest-1.6.0//include gruvin9x.cpp pulses.cpp 
stamp.cpp menus.cpp model_menus.cpp general_menus.cpp main_views.cpp 
statistics_views.cpp pers.cpp file.cpp lcd.cpp drivers.cpp  gtime.cpp rtc.cpp 
ff.cpp diskio.cpp frsky.cpp logs.cpp templates.cpp simpgmspace.cpp -arch x86_64 
-o simu -I/usr/local/include/fox-1.6 -I/usr/include/fox-1.6 -I/include 
-I/opt/local/include/fox-1.6 -L/usr/local/lib -L/src/.libs -L/opt/local/lib 
-lFOX-1.6 -Wl,-rpath,/src/.libs -MD -DSIMU
ld: warning: directory not found for option '-L/src/.libs'
bryan:src$ ls *.bin
eeprom.bin    gruvin9x.bin  models.bin
bryan:src$ rm eeprom.bin
bryan:src$ ./simu
error in fopen: No such file or directory
bad eeFs.version
: No such file or directory
bad eeFs.mySize
: No such file or directory
$ svn info
Path: .
URL: https://gruvin9x.googlecode.com/svn/trunk/firmware/src
Repository Root: https://gruvin9x.googlecode.com/svn
Repository UUID: f6e3ec8c-4711-3139-51d9-7b347ef5a272
Revision: 1506
Node Kind: directory
Schedule: normal
Last Changed Author: bsongis
Last Changed Rev: 1506
Last Changed Date: 2012-02-23 23:53:28 +1300 (Thu, 23 Feb 2012)

Original comment by gru...@gmail.com on 23 Feb 2012 at 10:12

GoogleCodeExporter commented 9 years ago
How is it possible? You are blocked during this "Formating..." screen? Right?
Could you tell me what gdb says?

These logs are normal:

bad eeFs.version
: Undefined error: 0
bad eeFs.mySize
: Undefined error: 0

Original comment by bson...@gmail.com on 23 Feb 2012 at 10:17

GoogleCodeExporter commented 9 years ago
I forgot to mention that eeprom.bin was not re-created when simu was run.

I don't know how it possible. It's weird.

How do I use gdb for that? I know what gdb is and roughly how it works. But 
I've never really worked with it.

I am able to quit simu normally, while it is hung up. 

Original comment by gru...@gmail.com on 23 Feb 2012 at 10:22

GoogleCodeExporter commented 9 years ago
You start with "gdb ./simu"
When it's blocked you Ctrl+C and enter bt, you will have the stack

Original comment by bson...@gmail.com on 23 Feb 2012 at 10:25

GoogleCodeExporter commented 9 years ago
Easier than I thought ...

Basically though, it say nothing at all. There is no additional output from gdb 
after 'press any key' at the 'ALERT -- Bad EEPROM' screen. 

$ gdb simu
GNU gdb 6.3.50-20050815 (Apple version gdb-1705) (Fri Jul  1 10:50:06 UTC 2011)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared 
libraries .... done

(gdb) run
Starting program: /Users/bryan/g9x/trunk/firmware/src/simu 
Reading symbols for shared libraries +++...........warning: Could not find 
object file 
"/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.or
g_release_ports_archivers_bzip2/bzip2/work/bzip2-1.0.6/blocksort.o" - no debug 
information available for "blocksort.c".

warning: Could not find object file 
"/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.or
g_release_ports_archivers_bzip2/bzip2/work/bzip2-1.0.6/huffman.o" - no debug 
information available for "huffman.c".

.... more similar warnings ....

warning: Could not find object file 
"/opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.or
g_release_ports_x11_mesa/mesa/work/Mesa-7.11/src/glx/apple/../../../src/mapi/gla
pi/libglapi.a(u_thread.o)" - no debug information available for "u_thread.c".

................................................................................
................................................... done
error in fopen: No such file or directory
bad eeFs.version
: No such file or directory
bad eeFs.mySize
: No such file or directory

Original comment by gru...@gmail.com on 23 Feb 2012 at 10:25

GoogleCodeExporter commented 9 years ago
Oh! Right. Here's the output (thanks) ...

^C
Program received signal SIGINT, Interrupt.
0x00007fff911e3df2 in select$DARWIN_EXTSN ()
(gdb) bt
#0  0x00007fff911e3df2 in select$DARWIN_EXTSN ()
#1  0x00000001000442e3 in FX::FXApp::getNextEvent ()
#2  0x00000001000436d4 in FX::FXApp::run ()
#3  0x0000000100002364 in main (argc=1, argv=0x7fff5fbffae0) at simu.cpp:417
(gdb)

Original comment by gru...@gmail.com on 23 Feb 2012 at 11:11

GoogleCodeExporter commented 9 years ago
info threads
thread 1
bt
thread 2
bt
I need to know what the eeprom thread does! Pretty sure it is in an infinite 
loop for a reason I need to know...

Original comment by bson...@gmail.com on 23 Feb 2012 at 11:21

GoogleCodeExporter commented 9 years ago
Wow. Never knew gdb could do this kind of stuff. Here's those results ...

^C
Program received signal SIGINT, Interrupt.
0x00007fff911e3df2 in select$DARWIN_EXTSN ()
(gdb) info threads
  2                         eeWriteBlockCmp (i_pointer_ram=0x9, size=18446744073709551615, i_pointer_eeprom=64) at drivers.cpp:82
* 1 "com.apple.main-thread" 0x00007fff911e3df2 in select$DARWIN_EXTSN ()
(gdb) thread 1
[Switching to thread 1 (process 49861), "com.apple.main-thread"]
0x00007fff911e3df2 in select$DARWIN_EXTSN ()
(gdb) bt
#0  0x00007fff911e3df2 in select$DARWIN_EXTSN ()
#1  0x00000001000442e3 in FX::FXApp::getNextEvent ()
#2  0x00000001000436d4 in FX::FXApp::run ()
#3  0x0000000100002364 in main (argc=1, argv=0x7fff5fbffae0) at simu.cpp:417
(gdb) thread 2
[Switching to thread 2 (process 49861)]
eeWriteBlockCmp (i_pointer_ram=0x9, size=18446744073709551615, 
i_pointer_eeprom=64) at drivers.cpp:82
82      while (eeprom_buffer_size > 0) wdt_reset();
(gdb) bt
#0  eeWriteBlockCmp (i_pointer_ram=0x9, size=18446744073709551615, 
i_pointer_eeprom=64) at drivers.cpp:82
#1  0x0000000100010507 in EeFsSetLink [inlined] () at 
/Users/bryan/g9x/trunk/firmware/src/file.cpp:66
#2  0x0000000100010507 in EeFsFormat () at file.cpp:171
#3  0x000000010000f700 in eeReadAll () at pers.cpp:352
#4  0x0000000100018539 in main_thread (unnamed_arg=0x9) at simpgmspace.cpp:108
#5  0x00007fff8ef828bf in _pthread_start ()
#6  0x00007fff8ef85b75 in thread_start ()

Original comment by gru...@gmail.com on 23 Feb 2012 at 11:34

GoogleCodeExporter commented 9 years ago
Ok I have everything needed. These parameters on eeWriteBlockCmp are completely 
wrong. Oh, but you are on a 64bits arch, right?

Original comment by bson...@gmail.com on 23 Feb 2012 at 11:39

GoogleCodeExporter commented 9 years ago
that's correct. 64-bit. 

(I keep forgetting about that myself. But then, I seem to forget everything 
these days, don't I! 'Gruvin the forgetful'. I could be in an adventure movie 
-- perhaps as some comic relief.)

Original comment by gru...@gmail.com on 24 Feb 2012 at 12:36

GoogleCodeExporter commented 9 years ago
I don't understand. How is it possible that EeFsSetLink call eeWriteBlockCmp 
with this size, when in file.cpp:66 the parameter is 1!!!

Could you set a breakpoint there?

break file.cpp:66
run

Original comment by bson...@gmail.com on 24 Feb 2012 at 9:24

GoogleCodeExporter commented 9 years ago
Oh yes. I see! (I'm not used to reading this data. It's starting to make sense.)

The breakpoint reveals that the large number is being computed from (blk*BS). I 
tried to inspect the value of blk but it seems I don't understand how to do it 
...

Breakpoint 7, EeFsSetLink [inlined] () at 
/Users/bryan/g9x/trunk/firmware/src/file.cpp:66
66    eeWriteBlockCmp(&s_link, (blk*BS), 1);
(gdb) p blk
No symbol "blk" in current context.
(gdb) p BS
No symbol "BS" in current context.
(gdb)

Original comment by gru...@gmail.com on 25 Feb 2012 at 9:36

GoogleCodeExporter commented 9 years ago
that's because this function is inlined and BS is a define!
next to reach the next line, what receives eeWriteBlockCmp?

Original comment by bson...@gmail.com on 25 Feb 2012 at 9:40

GoogleCodeExporter commented 9 years ago
Hmmm.  next hangs. Does not return to (gdb) prompt. I Googled to find 'step' 
command, which seems to do what we wanted. But I see no problem here (unless 
i_pinter_ram is off. No way to know) ... (read below for next step) ...

Breakpoint 7, EeFsSetLink [inlined] () at 
/Users/bryan/g9x/trunk/firmware/src/file.cpp:66
66    eeWriteBlockCmp(&s_link, (blk*BS), 1);
(gdb) step
eeWriteBlockCmp (i_pointer_ram=0x10001f760, size=1, i_pointer_eeprom=64) at 
drivers.cpp:67
67    assert(!eeprom_buffer_size);

Continuing ...

(gdb) next
67    assert(!eeprom_buffer_size);
(gdb) next
69    eeprom_pointer = i_pointer_eeprom;
(gdb) n
70    eeprom_buffer_data = (const char*)i_pointer_ram;
(gdb) n
71    eeprom_buffer_size = size+1;
(gdb) n
74    sem_post(&eeprom_write_sem);
(gdb) n
81    if (s_sync_write) {
(gdb) n 
82      while (eeprom_buffer_size > 0) wdt_reset();
(gdb) n
hangs here

Correct me if I'm wrong, but this would appear to be using async EERPOM writes, 
which surely wouldn't work with simu? I cannot see anything in Makefile to 
force the old synchronous mode. Perhaps another ifdef(SIMU) is required 
somewhere?

(I have to sleep now. We can pick this over later. Thanks.)

Original comment by gru...@gmail.com on 25 Feb 2012 at 9:52

GoogleCodeExporter commented 9 years ago
Yes it should work, the other thread (which writes the eeprom), what does it 
do, it should write a byte, then decrement eeprom_size until 0. Then the main 
thread continues.

Perhaps the infinite loop uses too much CPU. Would it help if in simpgmspace.h 
wdt_reset was defined as sleep(1)?

Original comment by bson...@gmail.com on 26 Feb 2012 at 10:56

GoogleCodeExporter commented 9 years ago
Hmmm. OK. I dunno. It used to work no problem. It was working fine before I 
changed that 0b00000 whatever to a hex and back again. WEIRD. 

Well, I changed the line to ...

    while (eeprom_buffer_size > 0) { wdt_reset(); sleep(100); }

... as a test. No change. There's no CPU load registering for the app when it's 
hung, either.

By the way ... the above gdb session changed to drivers.cpp (from file.cpp) 
without saying so, it seems. The loop line in question is in fact 
drivers.cpp:82 ... no the one in file.cpp:flush().

My only other guess it that maybe the variable being checked in the while loop 
is not getting updated in scope, perhaps doe to optimization. Perhaps we/I 
should make it volatile? But now it's 4:30am and I'm about dead. I'll try to 
pick this up again later, if you haven't had a brain wave and figured it out by 
then.

Thanks.

Original comment by gru...@gmail.com on 26 Feb 2012 at 3:30

GoogleCodeExporter commented 9 years ago
But it is already volatile!

Original comment by bson...@gmail.com on 26 Feb 2012 at 5:04

GoogleCodeExporter commented 9 years ago
So it is. Well then WTF? I don't know. 

How do I check what the other thread is doing? I mean -- I know how to switch 
threads in gdb from earlier ... but how.where would I monitor what it is 
supposed to be doing while the file.cpp thread is in the while loop?

Original comment by gru...@gmail.com on 28 Feb 2012 at 1:30

GoogleCodeExporter commented 9 years ago
You stop it with Ctrl-C. Then you enter "thread xx" and "bt" so that you know 
the stack. From there you may use the "next" and "step" commands as well.

Original comment by bson...@gmail.com on 28 Feb 2012 at 8:15

GoogleCodeExporter commented 9 years ago
Well I tried that. The output is just noise to my eyes. Can't make any sense of 
it. Here's what I saw though, in case you can make something of it ...

(gdb) info threads
  2                         eeWriteBlockCmp (i_pointer_ram=0x9, size=18446744073709551615, i_pointer_eeprom=64) at drivers.cpp:82
* 1 "com.apple.main-thread" 0x00007fff911e3df2 in select$DARWIN_EXTSN ()
(gdb) thread 2
[Switching to thread 2 (process 86331)]
eeWriteBlockCmp (i_pointer_ram=0x9, size=18446744073709551615, 
i_pointer_eeprom=64) at drivers.cpp:82
82      while (eeprom_buffer_size > 0) wdt_reset();
(gdb) bt
#0  eeWriteBlockCmp (i_pointer_ram=0x9, size=18446744073709551615, 
i_pointer_eeprom=64) at drivers.cpp:82
#1  0x0000000100010507 in EeFsSetLink [inlined] () at 
/Users/bryan/g9x/trunk/firmware/src/file.cpp:66
#2  0x0000000100010507 in EeFsFormat () at file.cpp:171
#3  0x000000010000f700 in eeReadAll () at pers.cpp:352
#4  0x0000000100018539 in main_thread (unnamed_arg=0x9) at simpgmspace.cpp:108
#5  0x00007fff8ef828bf in _pthread_start ()
#6  0x00007fff8ef85b75 in thread_start ()
(gdb) thread 1
[Switching to thread 1 (process 86331), "com.apple.main-thread"]
0x00007fff911e3df2 in select$DARWIN_EXTSN ()
(gdb) bt
#0  0x00007fff911e3df2 in select$DARWIN_EXTSN ()
#1  0x00000001000442e3 in FX::FXApp::getNextEvent ()
#2  0x00000001000436d4 in FX::FXApp::run ()
#3  0x0000000100002348 in main (argc=1, argv=0x7fff5fbffae0) at simu.cpp:417
(gdb) n
Single stepping until exit from function select$DARWIN_EXTSN, 
which has no line number information.
0x00007fff911e4ffc in cerror ()
(gdb) n
Single stepping until exit from function cerror, 
which has no line number information.
0x00007fff911ce386 in cthread_set_errno_self ()
(gdb) n
Single stepping until exit from function cthread_set_errno_self, 
which has no line number information.
0x00007fff8ef3a1df in cthread_set_errno_self ()
(gdb) n
Single stepping until exit from function cthread_set_errno_self, 
which has no line number information.
0x00007fff911e501d in cerror ()
(gdb) n
Single stepping until exit from function cerror, 
which has no line number information.
0x00000001000442e3 in FX::FXApp::getNextEvent ()
(gdb) n
Single stepping until exit from function _ZN2FX5FXApp12getNextEventER7_XEventb, 
which has no line number information.
0x00000001000436d4 in FX::FXApp::run ()
(gdb) n
Single stepping until exit from function _ZN2FX5FXApp3runEv, 
which has no line number information.

--- at this point, the gbd prompt does not return, thus requiring Ctrl-C again

^C
Program received signal SIGINT, Interrupt.
0x00007fff911e3df2 in select$DARWIN_EXTSN ()
(gdb) bt
#0  0x00007fff911e3df2 in select$DARWIN_EXTSN ()
#1  0x00000001000442e3 in FX::FXApp::getNextEvent ()
#2  0x00000001000436d4 in FX::FXApp::run ()
#3  0x0000000100002348 in main (argc=1, argv=0x7fff5fbffae0) at simu.cpp:417
(gdb) 

Some kind of looping, through what exactly, I can only guess. To me, it just 
looks like background user interface and screen output handling. I don't see 
anything remotely to do with the problem at hand. *shrug*

Bryan.

Original comment by gru...@gmail.com on 1 Mar 2012 at 1:57

GoogleCodeExporter commented 9 years ago
Bertrand -- I can't really understand the multi-threading code for this. For 
example, the hang being experienced is to do with EEPROM writing -- yet there 
there appears to be no thread control mutex scheme in place for writing, at 
all. In fact, I cannot see any thread running anywhere that has anything to do 
with EEPROM writing. Thus, there's no code anywhere that I can see that would 
ever unlock the thread mutex or otherwise allow the wait loop to exit. Thus, I 
can't see how this could be working for ANYBODY. I don't believe it's only a 
fault for me, on my Mac. But I don't know enough about SIMU to fix it and have 
again had to give up.

Can you please try deleting the eeprom.bin file and running through a format 
yourself, to confirm that it does NOT work for you either? 

If it does work for you -- then HOW? Where exactly in SIMU is the code that 
even updates eeprom_buffer_size for the while loop at drivers.cpp:87. The only 
place I can see is drivers:49 -- an AVR interrupt routine, presumably not 
handled by SIMU at all. Therefore, there's no way the async. EEPROM writes can 
work at all in SIMU, far as I can tell.

I really need SIMU fixed, so we can work on documentation, etc.

Thanks.

Original comment by gru...@gmail.com on 1 Apr 2012 at 3:56

GoogleCodeExporter commented 9 years ago
I just got the 'brilliant' idea of using companion9x to create a valid 
eeprom.bin file. This has avoided the 'Bad EEPROM' and 'Formatting...' hang 
issue, for now.

However, SIMU just hangs at a later point now. See the attached image for what 
I see.

Clearly, something is wrong with the multi-threading, somehow. This all used to 
work fine -- before the EEPROM async code was added, as far as I can recall. 
The option to run synchronous EEPROM write only has been removed from Makefile, 
so I'm not able to easily test that scenario, sorry.

Original comment by gru...@gmail.com on 1 Apr 2012 at 4:28

Attachments:

GoogleCodeExporter commented 9 years ago
The code for the EEPROM write is in simpgmspace.cpp
I even checked on a 64bits platform and it works perfectly
I really can't find the reason of the problem, I am afraid of files not 
compiled correctly? Makefile problem? Does companion9x simulator runs on your 
platform? 

Original comment by bson...@gmail.com on 2 Apr 2012 at 8:11

GoogleCodeExporter commented 9 years ago
I should note that ...

make PCB=STD DSM2=NO

... does still work. For the life of me, I'm not sure why I didn't try that 
earlier. :/

I thought simu was now able to run with v4 board code. (It does compile OK, 
where it didn't use to.) But perhaps not the case?

Reverted to Priority-Medium, since PCB=STD is just fine for doing documentation.

Original comment by gru...@gmail.com on 3 Apr 2012 at 7:21

GoogleCodeExporter commented 9 years ago
Yes, it should work. At least here it does (32 bits platform and 64bits 
platform). 
In the case the problem would come from the infinite loop when the EEPROM write 
should occur, would you try with this code in simpgmspace.h:274 
#define wdt_reset() sleep(1/*ms*/)

Original comment by bson...@gmail.com on 3 Apr 2012 at 8:08

GoogleCodeExporter commented 9 years ago
OK. So it should work and does for you. Hmmm.

I tried the wdt_reset define. It made no difference. (Still hangs on the 
formatting EEPROM) message. (I tried sleep(100) too, just to see. No change.)

The problem must surely be something to do with the way my Mac is handling the 
threads. But I have no idea how to even start investigating that.

Original comment by gru...@gmail.com on 3 Apr 2012 at 8:29

GoogleCodeExporter commented 9 years ago
Should be solved now!

Original comment by bson...@gmail.com on 26 May 2012 at 7:12

GoogleCodeExporter commented 9 years ago
Nope. Sorry. No change in behaviour, at all.

Original comment by gru...@gmail.com on 26 May 2012 at 7:19