Home > Workshops >

Test-Driven Development

James Grenning - Watch Now - Duration: 01:18:26

Test-Driven Development is a technical practice that supports Agile's iterative and incremental development cycle. TDD helps you quickly discover mistakes, preventing defects. You weave a test safety net as you grow your product's behavior one test at a time. This safety net supports you now and in the future to help you keep code working as you change it. Oh yeah, don't let me forget to tell you it's fun and once you learn it, you save time and money.

Maybe you have heard of Test-Driven Development but don't quite get it. A good way to understand TDD is to pair program with an experienced practitioner. We will start with a brief overview and demo of Test-Driven Development. In this interactive workshop, you can practice TDD in C. You don't need to install any tools for this workshop. You'll run the exercise on my exercise server. You will know what TDD is after this session. We'll conclude the workshop with a debrief on your experience.

Before attending this workshop, it is highly recommended that you watch this talk from the 2020 Embedded Online Conference.

M↓ MARKDOWN HELP
italicssurround text with
*asterisks*
boldsurround text with
**two asterisks**
hyperlink
[hyperlink](https://example.com)
or just a bare URL
code
surround text with
`backticks`
strikethroughsurround text with
~~two tilde characters~~
quote
prefix with
>

jkennedy
Score: 1 | 7 months ago | no reply

I'm not sure what changed between last year and this year, but navigating the recordings was a lot smoother last year. I really enjoy watching Mr. Grenning speak, so hopefully this recording will be made available.

Stephen
Score: 1 | 7 months ago | no reply

I can't play the video, it says it is not available.

Jay
Score: 3 | 7 months ago | no reply

When will the replay be available?

Marko
Score: 1 | 7 months ago | no reply

Hello James,

I have one question for you that I was not able to ask in the workshop.
I work in a IoT company as an embedded programmer, we manly write code for Zephyr and NRF5 SDK based products. We are usually dealing with trackers and systems that have BLE, LoRa, LTE, GPS connectivity, plus usually tons of sensors.

With my coworkers we were watching your last years talk. Our major concern is that faking (through the mocks) all the connectivity part of the products would be slow and would add an overhead which would put us behind in the deadlines. Plus they did not like the steps of the mini test cycle, which I can understand as they could not see the full benefit from ouor short presentation. Can you give some thoughts on mocking hardware and networking depended parts of the ssystems?

SeanIson
Score: 0 | 7 months ago | 1 reply

My computer froze and I had to restart, how do I get back into the session?

Stephane.Boucher
Score: 0 | 7 months ago | 1 reply

Try now

SeanIson
Score: 0 | 7 months ago | no reply

Thank you!

j_apolo
Score: 0 | 7 months ago | 2 replies

(sigh) Missed the window... Thankfully there will be a recording of it.

nathancharlesjones
Score: 0 | 7 months ago | 1 reply

Same problem! My audio stopped working so I left to try and reset. But I'm also getting the "Live session has ended" message. Any chance I can join back in??

Stephane.Boucher
Score: 0 | 7 months ago | 1 reply

Please try now.

nathancharlesjones
Score: 0 | 7 months ago | no reply

Yes! Thank you!!

Stephane.Boucher
Score: 0 | 7 months ago | 1 reply

There will be! You can still join though, we're not that far yet...

burak.seker
Score: 0 | 7 months ago | 3 replies

How exactly, pls? I am looking a way to join you but I cannot find how to do it.

Stephane.Boucher
Score: 0 | 7 months ago | 1 reply

Click on the video image at the top.

burak.seker
Score: 0 | 7 months ago | 1 reply

It says "This Live Session has Ended. A recording will be provided here soon."

Stephane.Boucher
Score: 1 | 7 months ago | 1 reply

Try again, I just changed a setting

burak.seker
Score: 0 | 7 months ago | no reply

Thanks a lot, it works now!!

Stephane.Boucher
Score: 0 | 7 months ago | no reply

Should work now

Stephane.Boucher
Score: 0 | 7 months ago | no reply

The red play button...

Teadotjay
Score: 0 | 7 months ago | no reply

I just got in.

Teadotjay
Score: 0 | 7 months ago | no reply

Looks like they fixed it.

Cezar
Score: 0 | 7 months ago | no reply

This is definitely most popular talk

Stephane.Boucher
Score: 0 | 7 months ago | no reply

Should work now

Dale_Walter
Score: 0 | 7 months ago | no reply

Max capacity for me too. :(

Teadotjay
Score: 0 | 7 months ago | no reply

Max capacity 100. Can’t join.

Naveen_Shankar
Score: 2 | 7 months ago | 5 replies

Already reach max capacity and I am not able to join the Zoom meet.

jgaitan
Score: 0 | 7 months ago | 2 replies

Same problem for me

Rene Ayoroa
Score: 0 | 7 months ago | no reply

Me too

andrei
Score: 0 | 7 months ago | no reply

Same here

Theophile
Score: 0 | 7 months ago | no reply

Same

Jay
Score: 0 | 7 months ago | no reply

same. disappointing.

minky
Score: 0 | 7 months ago | no reply

+1

DaveK
Score: 0 | 7 months ago | no reply

Me too.

maj
Score: 0 | 7 months ago | no reply

Yeah, same here

Fulgo
Score: 0 | 7 months ago | no reply

I cannot join due to the capacity limit... :/

Marko
Score: 0 | 7 months ago | no reply

Same here problem here

Vlad
Score: 0 | 7 months ago | no reply

Me too!

Wayne_F
Score: 0 | 7 months ago | no reply

I'm having the same maximum capacity Zoom meeting problem.
"Meeting capacity has been reached
You cannot join this meeting because it has reached the maximum number of participant allowed."

14:02:56	 From  Michael Kirkhart : @ James Grenning: I like the shirt in your picture: "The code does not work - why?"
14:03:40	 From  Michael Kirkhart : LOL
14:04:22	 From  busa2191 : Is there audio?
14:05:00	 From  Derek Konigsberg : There’s a “Join With Computer Audio” option when connecting to Zoom.  Its easy to miss it.
14:05:06	 From  Will Hsiung : Hi James, great to see you again!
14:05:13	 From  Ira Wolf : yes
14:05:14	 From  Carlos : YES
14:05:15	 From  Clayton Pannell : yes
14:05:15	 From  Diogo Freitas : yes
14:05:16	 From  Raul Pando : Yep
14:05:17	 From  JackW : yep!
14:05:18	 From  Paul Malcolm : audio is great
14:05:19	 From  Gerhard : yes
14:05:21	 From  David C : Yep!
14:05:45	 From  Keith J : Hey James - looking forward to the "refresher"
14:06:28	 From  Iván GB : People is having problems to join due to the capacity limit of the ZOOM
14:07:00	 From  afwaanquadri : Where are these instructions?
14:07:23	 From  Gerhard : Will be published in a few moments.
14:08:18	 From  Leandro Pérez : HI everyone from Colombia :)
14:08:49	 From  Piotr Zdunek : How can we open the exercises?
14:08:58	 From  Benny : Hello :)
14:09:04	 From  René Andrés Ayoroa : Hi from Paraguay
14:09:10	 From  gatoAlfa : Hi Leandro! ??
14:09:15	 From  jvillasante : And I thought TDD wasn’t that popular anymore :)
14:09:49	 From  René Andrés Ayoroa : How can we open the exercises?
14:10:00	 From  Jeremy Schreiber : You can't yet
14:10:17	 From  enrico : good book
14:10:25	 From  Naveen Shankar : Fantastic book!
14:12:20	 From  enrico : whats c ?
14:12:43	 From  Piotr Zdunek : high level framework for assembly
14:12:51	 From  enrico : lol im jk
14:13:00	 From  Piotr Zdunek : me too :D
14:13:15	 From  Iván GB : Debug later programming :D
14:13:53	 From  Michael Kirkhart : LOL - definition of debugging!
14:14:00	 From  Leandro Pérez : Great definition
14:14:11	 From  David : I'm a programmer and I (try not to) write bugs
14:17:45	 From  jvillasante : I’m a programmer and even my tests are buggy
14:17:59	 From  enrico : lol
14:18:20	 From  David Campelo : :)
14:19:15	 From  Benny : I'm a bug and I write programs ;)
14:19:34	 From  jvillasante : LOL
14:21:39	 From  Piotr Zdunek : Encapsulation is king
14:22:02	 From  António Carvalho (Bosch) : int is too large
14:22:26	 From  Benny : 128 bit?
14:22:26	 From  jvillasante : If you are using malloc kind of functions why not go all the way and use C++?
14:22:43	 From  Piotr Zdunek : Not many embedded systems use cpp
14:22:59	 From  Benny : exactly
14:23:04	 From  Gerhard : Arduino?
14:23:04	 From  mdohring : empty
14:23:09	 From  jvillasante : Those aren’t allowed to use malloc either, I guess.
14:23:14	 From  David Campelo : after creating it's empty
14:23:45	 From  Iván GB : Dynamic allocation is "dangerous" and many embedded systems do not have an MMU to avoid mem fragmentation
14:24:05	 From  enrico : its only dangerous if you need to free()
14:24:12	 From  António Carvalho (Bosch) : if you can run Linux on an embedded system, you can run whatever
14:24:12	 From  enrico : no free...no problem
14:24:16	 From  Hariharan G : More like free causes fragmentation
14:24:26	 From  Piotr Zdunek : if you don't need to free(), then why do you need dynamic allocation?
14:24:29	 From  patelk5 : https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code
14:24:45	 From  patelk5 : if you are writing safety crticial code, it is good to avoid dynamic allocation
14:24:46	 From  jvillasante : Allocate at initialization and do not free until shutdown… kind of an arena
14:24:49	 From  Derek Konigsberg : I do wish static allocation and data structure encapsulation didn’t often feel mutually exclusive.
14:25:52	 From  Iván GB : If you do not use free, better use static
14:26:44	 From  Piotr Zdunek : I think there is no point in freeing before shutdown, but I don't know all the requirements and constraints :)
14:27:57	 From  Andrei : warning unused self
14:28:20	 From  Iván GB : Well, another issue could be the space assigned to the heap. I think the decission depends on the memory constraints you have
14:28:51	 From  jvillasante : Did I miss the link to the playground?
14:28:57	 From  jvillasante : Or haven’t been posted yet?
14:29:04	 From  afwaanquadri : Its not yet posted
14:29:06	 From  António Carvalho (Bosch) : hasn't been posted yet
14:29:18	 From  jvillasante : Ok, thanks @afwan!
14:29:52	 From  Iván GB : And malloc is not deterministic in time. I stop here :P
14:30:17	 From  afwaanquadri : Why can't we just write up the source code first and then start writing the test cases?
14:30:33	 From  Jason Cose : there is a vid from 2020 that tells why
14:30:45	 From  Jason Cose : check the notes for this meeting
14:30:47	 From  António Carvalho (Bosch) : you can. but this way you're defining the behavior before the implemetation
14:30:47	 From  Jason Cose : there is a link
14:30:48	 From  Piotr Zdunek : Technically if you follow TDD you will write a better code with less bugs if you start with tests
14:31:09	 From  Andrei : In theory, you define the API, write the test and implement the code
14:32:01	 From  Keith J : @Afwan - in order to create test coverage, there shouldn't be code that isn't tested so tests drive code... otherwise you don't have complete coverage (and know the tests work)
14:32:02	 From  jvillasante : I don’t know if a real Red/Green/Refactor workflow will work in an embedded situation, you need those tests to run fast, otherwise it will just slow you down
14:32:20	 From  Iván GB : The point is that if you start coding trying to cause the fails, you Will write better code. That is why he starts doing the test fail I guess
14:32:57	 From  Anthony : It also means you write the minimum code necessary to pas the tests.
14:32:59	 From  Hariharan G : Also it affects the design since you are thinking about the modules testability first
14:33:57	 From  Sean : In an ideal world you will write most of your tests off target
14:34:29	 From  mdohring : test name typo?
14:34:32	 From  jvillasante : So, I’m getting ahead of myself… what do you guys think about mocking and test doubles?
14:34:44	 From  Ben Sweet : is_not_empty_after_push?
14:34:57	 From  enrico : mocking is good...never used test doubles
14:35:06	 From  enrico : that's when you link fom a lib right ?
14:35:25	 From  António Carvalho (Bosch) : if you can prove with tets that your code is correct off target then it will let you be a little more confident about it being correct when running on the device
14:35:28	 From  jvillasante : It’s kind of mocking but without the recording
14:36:39	 From  Anthony : Mocking is good, fakes and shims are not so much.  I don't know how that maps to test doubles.  I usually will create test classes which inherit from the class under test just to expose privates or other inconvenient things.
14:36:40	 From  jvillasante : BOOM… a test that depends on a hidden side effect?
14:36:47	 From  Piotr Zdunek : I personally prefer to avoid any mathematical operations in return statement.
14:37:37	 From  António Carvalho (Bosch) : ah, forget C. just use LISP
14:38:31	 From  jvillasante : Did somebody mention Rust already? :)
14:39:33	 From  Clayton Pannell : ?
14:40:00	 From  Benny : rust is too complicated for me
14:40:13	 From  Andrei : compile error in get
14:40:16	 From  Benny : C es btter:)
14:40:20	 From  jvillasante : @Benny, look into zig then
14:40:26	 From  Benny : *fills
14:40:50	 From  Iván GB : Rust? It should be easier, avoiding many of the hard parts of C/C++
14:41:11	 From  Benny : put borrow checker in c!
14:41:22	 From  gatoAlfa : I think the parameter name in the .h file helps the user understand the usage of the parameter, the type doesn’t help much. Any particular reason to omit the name in the .h
14:41:35	 From  Gerhard : LONGS_EQUAL
14:41:41	 From  jvillasante : Zig has a very interested design on which everything that allocates needs to explicitly be passed an allocator
14:41:53	 From  jvillasante : And unlike Rust, it’s trying to compete with C, not with C++
14:42:16	 From  Benny : interesting...
14:42:40	 From  Benny : first time I hear about zig
14:42:54	 From  António Carvalho (Bosch) : nothing can compete with the behemoth that is C++ unless it can also get 40+ years of adding complexity
14:42:55	 From  jvillasante : Pretty interesting, still not 1.0 yet…
14:43:10	 From  Piotr Zdunek : I'm not sure if anything takes over C in embedded systems, there is simply too much legacy code and compilers, it would be a lot of effort to move to anything else
14:44:28	 From  Nathan Jones : If anyone is wondering how James is coming up with all these great tests, I found this blog post on his website to be very useful: https://blog.wingman-sw.com/tdd-guided-by-zombies.
14:44:32	 From  Benny : I do BSP so only C for me ;)
14:44:59	 From  afwaanquadri : Need to add a check for overflow. It can keep incrementing the values
14:45:14	 From  Andrei : You need to C it to believe it :D
14:46:04	 From  António Carvalho (Bosch) : here it comes
14:46:14	 From  Steve Wheeler : I once had to find a bug in circular buffer code that was written as a state machine with 64 states. This looks a bit more straightforward.
14:46:18	 From  Nathan Jones : Starting to look like an intentional DDoS
14:46:26	 From  afwaanquadri : :D
14:46:32	 From  James Grenning : https://wingman-sw.com/exercises/emb2021
14:46:50	 From  Gustavo : I don't think C will ever be taken over on bare-metal

But what I think will happen is that more and more projects will be developed with "virtual machines", like micropython, and we are the guys who will support these BSPs :)
14:46:50	 From  Kurtovic Tarik, Omerbegovic Adna (1.59) : _sound of the universe imploding_
14:47:36	 From  Tom.Davies : boom
14:49:22	 From  Jón Hákon Richter : is there a finite amount of people that can join the servers?
14:50:22	 From  DMI: Franco MASSARO : Sorry I have to leave
14:51:31	 From  Clayton Pannell : it feels weird not using vim
14:51:35	 From  gatoAlfa : How I reset, I lost all the content in my CircularBufferTest.cpp
14:51:39	 From  Benny : should I add additional variable in the struct?
14:52:41	 From  Stephane Boucher   to   James Grenning(Direct Message) : We need to make sure to wrap up the session by about 2:50, so I can start Jacob's workshop in time
14:53:40	 From  gatoAlfa : Yes revert works. (lost code)
14:54:55	 From  Arjun N A : Hi can you repeat what is that we have to do. I missed out a couple of minutes during your presentation. Sorry.
14:56:30	 From  Arjun N A : Should we create the circular buffer?
14:57:18	 From  Arjun N A : ooh okay, I think we should replicate what you did for the previous 10 mins?
14:58:00	 From  António Carvalho (Bosch) : how do I run the tests?
14:58:56	 From  Shaun Hayward : sorry but I unfortunately have to drop. Thank you for a good workshop (and July "bat" avatar is free if anyone wants it :) )
15:00:23	 From  António Carvalho (Bosch) : for some reason it was not working on Firefox. I had to move to Edge
15:00:59	 From  Arjun N A : Hi, Can you please share where I should start in the TDD
15:01:24	 From  Arjun N A : Yes
15:01:24	 From  gatoAlfa : Thanks everyone, have to leave. I will keep open and will try to finish later today.
15:01:33	 From  Peter Jamrozinski : Will you have this code skeleton available elsewhere via GitHub?

15:01:37	 From  James Grenning : https://wingman-sw.com/exercises/emb2021
15:01:52	 From  Marinna Martini : I was locked out and just got in - is there a way to catch up?
15:02:16	 From  Leandro Pérez : I have learned TDD in the past 10 minutes... lol
15:02:23	 From  Burak ŞEKER : Can we reach to this link later on to do the exercise via recording? I was too late due to zoom limitation and I would like to do it later
15:03:56	 From  Tony Arkles : James, when I reached the dynamic memory portion here, I got that lovely memory leak error. Is that something that is included “for free” in CppUTest?! Because it’s awesome!
15:04:19	 From  Leandro Pérez : How can test many condition at the same time? What is the syntaxis?
15:04:57	 From  Leandro Pérez : I got it
15:05:23	 From  S : I'm unable to connect on Firefox or Chrome. Timed out.
15:05:43	 From  Paul : OpenDNS is now classifying emb-1a.wingman-sw.com as a security threat
15:05:57	 From  Yuriy Kozhynov : Will the link will work later?
15:06:20	 From  Rocco Brandi : TEST(CircularBuffer, report_capacity)
{
    LONGS_EQUAL(100, CircularBuffer_Capacity(buffer));
}
15:06:26	 From  Rocco Brandi : is passing always
15:06:44	 From  Rocco Brandi : even if the function CircularBuffer_Capacity
 doesn't exists
15:07:29	 From  Rocco Brandi : opps!
15:08:50	 From  Iain Chalmers : Q: At what point in the cycle would you typically do your commits to source control? Immediately on writing a test that fails, or as a full test + passing code?
15:08:55	 From  Miehl : If you want to practice TDD with a template after this exercise is over, you can use this one: https://github.com/makomi/tdd_templates/tree/master/C_CppUTest

It is a template for a code kata, i.e. everything is set up - you just need to write your tests and code
15:09:42	 From  Leandro Pérez : Interesting TDD
15:09:53	 From  Marinna Martini : @Miehl thanks
15:09:56	 From  patelk5 : CircularBufferTest.cpp:100: error: Failure in TEST(CircularBuffer, put_get_is_fifo)
	Memory leak(s) found.
15:10:04	 From  S : No idea what happened, but I put in http://wingman-sw.com and went to the website, then typed in the rest and it connected.
15:10:55	 From  patelk5 : do we have to call free somewhere if we used calloc to allocate buffer array?
15:11:37	 From  patelk5 : I am getting memory leaks
15:11:44	 From  Peter Jamrozinski : If we want to come back later, will our progress still be saved under our "avatar"?
15:11:59	 From  patelk5 : never mind
15:12:00	 From  James Grenning : https://linoit.com/users/jwgrenning/canvases/emb-1-parking-lot
15:15:25	 From  Clayton Pannell : d'oh
15:16:05	 From  Nathan Jones : What is meant by "Don't forget to update CircularBuffer_Create() in setup()!" in CircularBufferTest.cpp?
15:16:14	 From  Stephane Boucher   to   Michael Kirkhart(Direct Message) : Michael, I just noticed your raised hand.  Do you have a question or did you simply forget to bring your hand down?
15:16:17	 From  Leandro Pérez : Yes I know
15:16:26	 From  Leandro Pérez : Is my first time with TDD
15:17:07	 From  Scott K. : If the build env were a docker image, we could work on this on our own at our leisure.
15:17:07	 From  S : I DO like your book thus far...only part way in. I've been in test for about 10 years and this opened my eyes. Thank you!
15:17:19	 From  JackW : I especially appreciate that CPPuTest can detect memory corruption and leaks so effortlessly... I am only familiar with Ceedling/Unity and it doesn't have this functionality
15:19:19	 From  Juan : James, in your book you use Unity and CppUnit, would you have picked those today?
15:22:07	 From  James Grenning : https://wingman-sw.com/exercises/emb2021-debrief
15:22:15	 From  Ben Sweet : What is the difference between "checks" and "tests"?
"checks" is always one greater than "tests" (when all tests pass.)
15:23:12	 From  Frederic : google docs is blocked by firewall
15:23:22	 From  Tony Arkles : yeah I’m encountering that too
15:23:31	 From  Stefan Petersen : The tests are number of TEST and checks are CHECK*
15:24:26	 From  James Grenning : if you cannot get to the google doc, add a postit, what did you like? what concerns you?
15:25:03	 From  Scott K. : What/where is the parking lot?
15:25:34	 From  James Grenning : https://linoit.com/users/jwgrenning/canvases/emb-1-parking-lot
15:25:46	 From  James Grenning : https://wingman-sw.com/exercises/emb2021-debrief
15:28:00	 From  Ben Sweet : "Sorry about that Chief!"
15:28:49	 From  Kurtovic Tarik, Omerbegovic Adna (1.59) : the message "You got ahead of your tests" is cute :D
15:30:03	 From  Marinna Martini : Ahhh - the error messages instruct you how to write the code.
15:31:43	 From  patelk5 : Well done presentation!
15:36:41	 From  Jeremy Overesch : CppUTest does work on most ARM based systems.  I've been using it on a range of STM32 processors.
15:37:38	 From  afwaanquadri : What are your suggestions about mocks and fakes?
15:39:38	 From  Yan S. : Compare to Boost test CPP test , which is better?
15:43:15	 From  Ben Sweet : In "Test-Driven Development for Embedded C" you mention both CppUTest and Unity.  Aside from CppUTest being applicable to both C and C++, are there other advantages of CppUTest in general?
15:44:28	 From  Miehl : https://martinfowler.com/articles/is-quality-worth-cost.html
15:44:39	 From  Jeremy Overesch : @Ben, I'm unsure about Unity, but CppUTest can be run on actual hardware. I'm using it on multiple STM32 cores right now.
15:44:57	 From  Jeremy Overesch : with IAR
15:47:06	 From  Peter Sik : How would you go about adding tests to a legacy codebase without them? Start from beginning or adding them gradually?
15:47:42	 From  Miehl : James wrote an article on this topic: https://wingman-sw.com/articles/tdd-legacy-c
15:48:29	 From  Miehl : I am collecting information like that in this Telegram channel: https://t.me/embedded_sw_quality
15:48:39	 From  Piotr Zdunek : How long will the server be up for us to play around?
15:50:28	 From  Frederic : thanks a lot, it was great!
15:50:30	 From  Tom.Davies : Thanks James
15:50:33	 From  Jason Cose : Thanks!
15:50:35	 From  Piotr Zdunek : Thanks!
15:50:35	 From  Andrew Murray : Thank James :)
15:50:36	 From  Rocco Brandi : thank you very much!
15:50:37	 From  Brian : Thank you!
15:50:38	 From  Jeremy Schreiber : Thank you!!
15:50:38	 From  Carlos : Thank you!
15:50:39	 From  James G : thank you! 
15:50:39	 From  Arjun N A : Thank you
15:50:39	 From  dayolawa : Thanks you!
15:50:40	 From  Grant : Thanks!
15:50:43	 From  Gerhard : Thanks!
15:50:43	 From  Peter Sik : Thank you!
15:50:43	 From  JackW : thanks!
15:50:44	 From  Iván GB : Thanks
15:50:44	 From  Tony Arkles : thanks! yeah that was awesome!
15:50:44	 From  S : than kyou
15:50:46	 From  Stefan Petersen : Thank you!
15:50:46	 From  Jón Hákon Richter : Thanks for the lecture!
15:50:48	 From  Leandro Pérez : Thanks
15:50:49	 From  René Andrés Ayoroa : Thank you!
15:50:49	 From  navin : Thanks James!
15:50:49	 From  Yuriy Kozhynov : Thanks
15:50:49	 From  Douglas UTFPR : thanks a lot
15:50:52	 From  Mark J : Thank you
15:50:52	 From  Ben Sweet : Thanks for the great TDD experience!
15:50:55	 From  Steve Wheeler : Thank you. Very informative.
15:50:55	 From  Sergii Akhinko : Thanks a lot it was very nice !
15:50:56	 From  sleung : Thanks again!  Awesome.
15:50:57	 From  Aditya S : Thank you very much, this was an interesting intro
15:51:01	 From  HarriR : Thank you James!
15:51:01	 From  Miehl : Thank you - especially for your book!
15:51:06	 From  Peter Jamrozinski : Thank you!
15:51:07	 From  Dale Walter : Thank you!
15:51:12	 From  Thomas : Thanks - bye
15:51:14	 From  ITP1CA : Thanks everyone!
15:51:17	 From  Mustafa Caliskan : Thanks

OUR SPONSORS