Bill Blogs in C# -- C# General

Bill Blogs in C# -- C# General

Created: 9/30/2009 11:32:00 PM

I love it when I find those small new bits of functionality in the .NET framework. It’s all the big items that get all the love at conferences and in magazines.

Lazy<T> is one of those items.

Let’s imagine you’re writing an application and in some scenarios, but not others,  you need a particular object. Furthermore, suppose that object you need is very expensive to create and use. You don’t want to create it everytime your application runs. You only want to create it when you need it.

Sure, you could manage all that yourself, but Lazy<T> makes it easy.  You just create a lazy wrapper on the expensive object:

Lazy<ExpensiveResource> ownedResource = new Lazy<ExpensiveResource>();

You can simply reference ‘ownedResource.Value’ to get at the expensive object. The first time you access ownedResource.Value, the expensive resource will get allocated, but not before.

Lazy<T> also has a boolean propoerty, named IsValueCreated, that you can check to see if the value has been created. That would be useful when you need to store information from the expensive resource, but only if it’s been used.

Supporting Types without default constructors

Lazy<T> does not enforce the new() constraint. You can use Lazy<T> for types that must be instantiated using a different constructor, or even a factory method. A second constructor specifies a Func<T> that returns the new expensive resource:

Lazy<ExpensiveResource> ownedResource = new Lazy<ExpensiveResource>(
    () => new ExpensiveResource("filename.data"));

You can use this second constructor to better control what code creates the expensive resource. I’ve used a different constructor here, but you could use a factory method, an IOC container, or any method.

We’re living in a Multi Core World

There are two other constructors in Lazy<T>:

public Lazy(bool isThreadSafe);
public Lazy(Func<T> valueFactory, bool isThreadSafe);

 

These two constructors indicate that you are running in a multi-threaded envrionment, and the lazy construction of of the owned object must be synchronized. (After all, it’s an expensive resource. You don’t want two of them.)

It’s a simple type, but it’s one of those types you’ll find yourself reaching for over and over again.

I’m glad it’s been added.

Created: 8/26/2009 3:15:30 AM

Well, it’s been a long time since I’ve taken the time to solve and blog about one of the Euler problems.  It was time to pick this up again.

Problem 13 says:

Work out the first 10 digits of the sum of the following one-hundred 50-digit numbers. <long list of numbers elided>

The key here is that you only need the first 10 digits of the answer. Therefore, you only need to add the first 11 digits for each of the 100 numbers. Here’s why:  These numbers do not contain any 0’s in the first position.  Therefore, the sum of all the first digits is at least 100. The first digit contributes at least 3 digits in the final answer. Once you get to the 11th digit, that number can’t be great than 900. (100 9’s).  It won’t affect anything in the first 10 digits.  That’s the end of the work.

That makes the final answer one LINQ query:

             1:
          static
          void Main(string[] args)
             2: {
             3:     var finalAnswer = (from index in Enumerable.Range(0, 11)
             4:                        from s in listOfDigits
             5:                        select int.Parse(s[index].ToString()) * 
             6:                        (long)Math.Pow(10, 11 - index)).
             7:                        Sum();
             8:     Console.WriteLine(finalAnswer);
             9: }

listOfDigits (elided) is a list of strings where each string contains the digits for one number.

The first line of the query creates an enumeration for the first 11 digits.

The next two lines select a single character from each string, parsing that character to create an integer.

Next, do a little math to move that single digit into the correct column for the sum.

Finally, sum all the integers.

Sweet, huh?

Created: 8/19/2009 12:29:16 PM

Chris Marinos started Elevate as a learning time project at SRT Solutions.  It’s still very young, but it’s already very useful to me.

Chris wrote a great introductory post on the library, which is hosted on CodePlex.

Elevate contains methods we use, usually based on LINQ queries, or otherwise built on top of the .NET BCL.  There are methods to build sequences, sub-divide very large sequences into chunks, perform pattern matching on sequences, and some general purpose composable APIs.

It’s still a very young project, and we’re adding functionality on a regular basis. We’re also actively seeking other community members’ input and contribution. Please visit the project, join and submit ideas. Or, just download it, try it, and suggest ideas on the CodePlex pages.

Created: 7/13/2009 3:08:52 PM

During my recent vacation, I read the final print version of Essential LINQ, by Charlie Calvert and Dinesh Kulkarni.

Normally, I try to answer the question, “Who should read this book?” That answer eluded me on this book, due to the thorough treatment Charlie and Dinesh give the subject. Essential LINQ is approachable by developers that have minimal experience with LINQ, and yet those developers that have been using LINQ since day one will learn something from this book.

The Essence of LINQ and LINQ Patterns and Practices

Everyone will learn something from two chapters in this book. “The Essence of LINQ” describes the principles behind the LINQ libraries and language enhancements. By understanding the goals of LINQ, you’ll immediately gain insight that will make LINQ more approachable and more productive for you.

In chapter 16, toward the end of book, Charlie and Dinesh discuss some patterns you’ll run into while developing with LINQ. You’ll learn how to use LINQ to SQL entities as part of a large multi-tier application. You’ll learn how to improve performance in LINQ applications. You’ll learn how to separate concerns in LINQ based applicaitons. LINQ is too new to be considered complete in terms of ‘best practices’, and thankfully neither Charlie nor Dinesh approach this subject with that kind of arrogance. Instead, they offer their recommendations, and invite discussion on the subject.

A catalog of LINQ Functionality

Throughout the rest of the book, Charlie and Dinesh explain LINQ to Objects and LINQ to SQL from a usage standpoint, and from an internal design standpoint. In other chapters, LINQ to XML is discussed. The authors provide examples of transforming data between XML and relational storage models as well. In every section, they tie together those features with the concepts discussed in “The Essence of LINQ”. That continuity helps to reinforce your understanding of LINQ through its design concepts.

After reading this book, you’ll be able to leverage LINQ in all your regular coding tasks. You’ll have a much better understanding of how LINQ works, and when you’ll encounter subtle differences in how different LINQ providers may behave.

LINQ to SQL vs. Entity Framework

It seems you can’t discuss LINQ without at least wading into the controversy of LINQ to SQL vs. Entity Framework. This book wades there as well (It was finished about the time the first EF release was made). More time is spent on LINQ to SQL, as it is more approachable from an internal design perspective. However, the chapters that cover EF build on that knowledge to help you understand how the two database LINQ technologies are more complementary adversarial. In addition, they touch on when you should consider one over the other in your application.

A look at providers

This section is the least complete, but the most useful to look into the future of the LINQ universe. It’s too easy to view LINQ as LINQ to Objects, LINQ to SQL, and LINQ to XML, and nothing more. This chapter gives you a brief view some of the other providers people have created for other types of data stores. Looking at some of those providers (especially the IQToolkit) will give you a greater appreciation for how LINQ can be used with a wider variety of data sources than you ever imagined.

So, is this book for you?

If you are interested in being more productive with LINQ, you should read this book. You’ll probably thumb through it again and again as you search for better ways to solve different problems.

Created: 5/26/2009 9:25:05 PM

I’m just going to assume that all readers of my blog know that Visual Studio 2010 Beta one has been released.

I’ve been running it almost exclusively since I downloaded and installed it. There’s a lot to like. For this first post, I’m going to limit my discussion to a very small set of IDE features that thrill me in the new release.

Tear away editor and tool windows

This is a neat feature for single monitor work, but is absolutely wonderful in a multi-monitor scenario.  In VS2010, you can grab the title tab in an editor window (design or code window) and move it out of the VS IDE frame window. It’s wonderful when you’re trying to do some work that requires examining more than one code file at a time.

The fact is that this feature works for tool windows as well as editor windows.  In my setup, I’ve tried to maximize my main code window in the main monitor.  Properties, Solution Explorer, and the build output windows are on the secondary monitor. I’ll pull editor windows out when I need to see multiple code (or designer) files for a particular task.

PascalCased IntelliSense

Love this for discovering classes or methods in the .NET Base Class Libraries. Intellisense now picks up targets that contain the words you type, even if they are not at the beginning. For example, if you type ‘enumer’ in a code window, Intellisense will (as always) contain Enumerable. It will also contain IEnumerable, IOrderedEnumerable, and ParallelEnumerable.

It’s a great way to discover something that might be the solution to your current coding problems.

Real TDD Support: Generate From Usage

Create From Usage means you can really follow a TDD methodology. You can right test scenarios that describe how you want to use a class. Once you’ve written the test, you have a test that doesn’t compile (like now). Right click on each item with red squiggles and select “Generate”.  Types allow you to generate a new class (quick default), or “Generate Other” which displays a dialog that lets you select a class, interface, enum, or struct. Furthermore, that dialog lets you select the access modifiers on the type, select a destination project (if you have multiple projects in your solution).  You can follow the same workflow to generate methods or properties once you’ve created the types.

The IDE will create members that throw NotImplementedExceptions, so all your tests will fail. But, isn’t that the point of TDD?  Once you have those failing tests, you have a task list to make them green.

In future posts, I’ll touch on more of the major features in VS 2010. I wanted to start with these hidden gems because they can be so easily overlooked if you just start using the new version with your old work patterns.

Created: 5/11/2009 5:54:09 PM

My last post (which was too long ago), generated question on whether I prefer the query language or the method notation for LINQ queries.

The answer is ‘yes’.  Jon Skeet mentioned this as well last January, but anything you can do with query syntax can be accomplished with method calls. (Item 36 of More Effective C# discusses is some detail how the query language operators map to method calls.)

From the standpoint of correctness, you can use either construct with no differences. That means it is a matter of style whether you choose the query expressions or the method calls.

My own preference is to use the method call syntax for simpler queries, and use the query syntax for more complex query operations.

For example, I would use the method call syntax below over the query syntax:

             1:
          int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
             2: var smallNumbers = from n in numbers
             3:
          where n < 5
             4:                    select n;
             5:  
             6: var smallNumbers2 = numbers.Where((n) => n < 5);

However, once a query gets sufficiently complex, I believe the query syntax is more readable:

             1:
          int[] odds = { 1, 3, 5, 7 };
             2:
          int[] evens = { 2, 4, 6, 8 };
             3: var values = from oddNumber in odds
             4:             from evenNumber in evens
             5:
          where oddNumber > evenNumber
             6:             select new { oddNumber, evenNumber, 
             7:             Sum = oddNumber + evenNumber };
             8:  
             9: var values2 = odds.SelectMany(oddNumber => evens,
            10:     (oddNumber, evenNumber) =>
            11:
          new { oddNumber, evenNumber })
            12:     .Where(pair => pair.oddNumber > pair.evenNumber).
            13:     Select(pair => new { 
            14:         pair.oddNumber, 
            15:         pair.evenNumber, 
            16:         Sum = pair.oddNumber + pair.evenNumber });

In my opinion, for more complex queries, the query language produces a much more readable construct. However, on simpler queries, the method calls are easier to understand.

I like Jon’s comment: “next time you’re writing a query expression, take a look at it afterwards – it it’s simple, try writing it without the extra syntactic sugar.” (from the post referenced above).

Created: 4/17/2009 2:57:25 AM

I was involved in an interesting discussion about how the C# language has evolved, and how it’s getting harder and harder to teach developers to be proficient in the language with each passing version.

I think that’s our fault.

As leaders and experienced C# developers, we too often teach and explain from our perspective: We learned C# 1.0, learned the new features in 2.0. Then, we learned LINQ and the other syntax additions in 3.0. Now, we’re looking at adding the new 4.0 features to our repertoire of techniques. It makes sense to us, because that’s how we learned.

But we are not them.

That’s an inefficient way for someone approaching C# now to learn the language. Instead, we should explain these new concepts based on how one should learn now, not how we learned. I wish I could take credit for this amazing insight, but I must credit Bjarne Stroustrup. He wrote an essay for C++ Users Journal back in 1999 asserting that the C++ community must change how they taught developers C++.  Back then, everyone teaching C++ just assumed that every novice C++ developer was a veteran C developer. And that’s how they taught. Stroustrup instead claimed that developers should learn the best C++ idioms, rather than be taught C, then how to move to C++.

Lambda Expressions as Example

Explaining Lambda expressions is a great example of what I mean in C# today.

When I explain lambda expressions to a novice C# developer, I use this example:

             1: var someNumbers = new List<int>(Enumerable.Range(-20, 200));
             2: someNumbers.RemoveAll(n => n > 30);
             3:  
             4:
          bool assertion = someNumbers.TrueForAll(n => n < 40);

Line 1 creates a collection with a bunch of numbers.

Line 2 introduces a lambda. It removes all numbers greater than 30 from the collection. The lambda expression “n => n > 30” describes the condition for all elements to be removed from the list. A lambda expression is a short hand description of a method: n is the parameter. The expression returns a boolean, the result of the test ‘n > 30’.

At this point, I’ll often get a few questions:

‘what type is n"?’

That’s easy: the compiler infers types for the parameters to lambda expressions. Here, the compiler infers that n must be integer, because the collection someNumbers contains integers.

‘there’s no return value’

Yes, I know that’s not a question. But it does express the confusion, and that’s how it’s often stated. I say that the compiler infers the return type. List.RemoveAll() takes a Predicate<T> as its parameter, and Predicate<T> returns a bool. therefore, the expression ‘n > 30’ must be a boolean expression. To illustrate this, I’ll modify the code to show how the compiler checks the type. The lambda expression ‘n => n.ToString()’ doesn’t compile, because n.ToString() evaluates to a string, not a boolean.

Then, I go on to the concept: a lambda expression is a mechanism that enables you to pass code (in the form of a lambda) to another method for execution later. Internally, List.RemoveAll() evaluates the lambda expression parameter for every element in the list. All elements that return true are removed.

I follow the same process to explain the TrueForAll() method call.

Yeah, but what about delegates, anonymous delegates and expression trees?

Those of you that are experienced C# developers are probably concerned: I didn’t mention that lambdas are implemented like anonymous delegates. I didn’t drill down further to state that anonymous delegates are just like delegates.

In short, I didn’t work back from a lambda expression to the equivalent C# 1.0 syntax. But, that’s the point. Unless you have been working with C# since the beginning, those concepts don’t help you. Someone starting to learn C# now doesn’t have that prior knowledge about C# 1.0, or C# 2.0.

Read my explanations above again.  They don’t dive into great detail about how a lambda expression is interpreted by the compiler. Rather, they give you a good description of how you would write code using lambda expressions, and what they do for you.

Nothing I said is wrong, but a lot of details are left out.  That’s ok, hiding details helps novices get started.  We can fill in those holes as these new C# developers develop a greater understanding, and want a deeper understanding.

At that point, they are ready for a different explanation.

Until then, we are better off explaining concepts using explanations that help them, even if those explanations are different than how we learned.

Created: 4/10/2009 2:13:36 AM

I’ll start this post with a couple caveats. I’m learning the Live Framework SDK, just everyone else. This (and upcoming) blog posts on the Live Framework are based on my initial learning on Live Framework. All the usual disclaimers apply.

My plan is to work through some of the Live Framework SDK samples. As I’m doing that, my normal work pattern is to take lots of notes on what I’m learning. My blog seems as good a place as any. Unlike posts on technologies where I’ve spent lots of time, I’m a noob on the Live Framework too. But, there’s only one way to learn.

The Project Manager Sample

I decided to start with the WPF Project Manager sample. It’s a WPF application that lets you create projects. You can add milestones to those projects. Obviously, you can edit both projects and milestones. The projects are stored as MeshObjects. The milestones are stored as DataEntries in the MeshObjects (representing projects).

This first post is mostly looking at the application, with a small look at the code.

I ran the code, created a project and some milestones.  Cool enough.

Then, I went to the developer mesh website, and looked at my mesh desktop. I expected to see new folders, or something that showed the projects and milestones I created. I was surprised that nothing was there.

The answer was in the code. Remember from my first post on the Live Framework that the MyPhotos application used resource types of LiveMeshFolder, and LiveMeshFiles. That makes objects that are visible in the mesh, obviously as folders and files.

This sample uses different resources types. The sample defines a “Project” resource type for the project, and a “Milestone” type for the milestones.

Both Project and Milestone are C# classes. They are (more or less) POCO objects. They are decorated with the DataContract attribute (and their properties are decorated with the DataMember attribute).

Here’s the Project type:

             1: [DataContract(Namespace = "Microsoft.Samples.Workflow.ProjectManagerWPF")]
             2:
          public
          class Project
             3: {
             4:
          /// <summary>
        
             5:
          /// UUID of the parent MeshObject
        
             6:
          /// </summary>
        
             7:     [DataMember]
             8:
          public
          string MOID { get; set; }
             9:
          /// <summary>
        
            10:
          /// Title of the milestone (during save/update, this matches MeshObject.Resource.Title, 
        
            11:
          /// but is stored here when the custom object is databound instead of the resource)
        
            12:
          /// </summary>
        
            13:     [DataMember]
            14:
          public
          string Title { get; set; }
            15:
          /// <summary>
        
            16:
          /// Date when project will be started
        
            17:
          /// </summary>
        
            18:     [DataMember]
            19:
          public DateTime KickOffDate {get; set;}
            20:
          /// <summary>
        
            21:
          /// Estimated Date for Completion
        
            22:
          /// </summary>
        
            23:     [DataMember]
            24:
          public DateTime CompletionDate {get; set;}
            25:
          /// <summary>
        
            26:
          /// Date when project was shipped
        
            27:
          /// </summary>
        
            28:     [DataMember]
            29:
          public DateTime ShippedDate {get; set;}
            30:
          /// <summary>
        
            31:
          /// Description of Project
        
            32:
          /// </summary>
        
            33:     [DataMember]
            34:
          public
          string Description {get; set;}
            35: }

Storing and retrieving the Project type from the Mesh is straightforward Live Framework code. Here’s the code to read a project:

 

             1:
          //grab the Project Instance object from the mesh object and populate an instance of our Project Domain Class
        
             2: Library.Project SaveProject = this.ExistingProjectMeshObject.Resource.GetUserData<Library.Project>();

You simply convert the Resource to the POCO type, using the GetUserData<T> method to convert the resource. Cool. Saving it back is just as easy:

             1: MO = ExistingProjectMeshObject;
             2: SaveProject = ExistingProjectMeshObject.Resource.GetUserData<Library.Project>();
             3: MO.Resource.Title = tbTitle.Text;
             4:  
             5:
          //Set the custom attributes of the mesh object to the values from the library/domain class, 
        
             6:
          //this will popualte the userfield data with the deserialized content from the Project object created above
        
             7: MO.Resource.SetUserData<Library.Project>(SaveProject);
             8:  
             9:
          //Set the type of the mesh object's resource to PRoject
        
            10: MO.Resource.Type = "Project";
            11:  
            12:
          //Update the object in the cloud.
        
            13: MO.Update();

The SetUserData<T> call converts the POCO Project object to a mesh resource. Then, you just need to send the data to the cloud.

Future posts will dive into the code in more detail, and start on some other mesh style programming. Just this little dive makes me think more about what I can build with this.

Created: 3/23/2009 5:18:00 PM

It’s been a long time since I have worked on any of the Euler problems.  I simply haven’t had time.  Well, it was time to spend a bit of time just exercising the math part of my mind, and solve another problem.

Problem 12 asks you to find the first triangle number that has more than 500 divisors.

Like my other C# solutions, it makes sense to decompose this problem into smaller sets. First, figure out how to generate the triangle numbers. Then, figure out the simplest way to determine how many divisors a number has.

Let’s start with the triangle numbers. The nth triangle number is the sum of all natural numbers less than or equal to N. You can think of them like the number of balls in a billiard rack with N rows:  1, (1+2), (1+2+3), (1+2+3+4), or, 1,3,6,10,15…

A little bit of math (or a quick search) will tell you that the Nth triangle number is [N * (N+1)]/2.

Now, all we need to do is compute the total number of divisors for each of these numbers. One simple answer is to take all number less than or equal to the triangle number. Any of those that divide into the triangle number is a divisor. But, that’s incredibly inefficient. Instead, you can stop at Sqrt(Number). That will give you exactly 1/2 the number of divisors. For example, if 128 is divisible by 2, you’ve found two divisors: 2, and 64. Therefore, this method tells me quickly how many divisors a number has:

   1: static int CountDivisors(int n)
   2: {
   3:     var divisors = from val in Enumerable.Range(1, (int)Math.Sqrt(n))
   4:                    where n % val == 0
   5:                    select val;
   6:  
   7:     return divisors.Count()*2;
   8: }

This query (written in two parts) finds the answer. Remember that one of the keys to LINQ is deferred execution. Only the triangle numbers up to and including the answer are generated.  The entire program runs in a few seconds:

 

   1: var triangleNumbers = from n in Enumerable.Range(1, 100000)
   2:                       let Value = (n * (n + 1)) / 2
   3:                       select new
   4:                       {
   5:                           Number = Value,
   6:                           NumDivisors = CountDivisors(Value)
   7:                       };
   8: var answer = (from vals in triangleNumbers
   9:              where vals.NumDivisors > 500
  10:                   select vals).First();

It feels good to stretch the math muscles again.

Created: 3/20/2009 2:21:00 AM

Yesterday, a number of community leaders and Microsoft employees gave a series of presentations for developers working for the State of MI.

We spent the better part of the day discussing the current and future trends for developers on the .NET framework.

My talk was on leveraging tools to improve the quality and timeliness of your work.

You can get the slides here. And the samples here.

 

Created: 1/19/2009 11:03:46 PM

There is still time to register for the MSDN Developer Conference in Detroit, this coming Thursday.

If you missed PDC, this is a chance to get a look at the major content announcements from that conference.  You’ll get sessions on the Azure Services Platform for Cloud Computing, Client and Presentation Technologies, and Tools, Languages and Platforms.  You’ll learn how to build applications for Azure the Live Platform, and Live Mesh Services, and how to use SQL Data Services for storage in the cloud. You’ll see what’s next in ASP.NET, WPF, and Silverlight. You’ll learn what’s next for C# and VB.NET, what is Oslo, what’s the F# buzz about, and what’s coming in VSTS 2010.

That’s in addition to side events like the Community Courtyard, and Women Build.

I’m giving the talk on the future of C# and Visual Basic, and I’m thrilled with the content.  You can register here: http://www.msdndevcon.com/Pages/Detroit.aspx

Created: 1/12/2009 4:04:55 PM

I’ve just uploaded my code and slides from both talks at CodeMash.

I was somehow lucky enough to have two talks at CodeMash:

Extending and modeling the type system using Extension Methods.

Slides

CodeSamples

Understanding Query Comprehensions

Slides

CodeSamples

 

The talk on understanding Query Comprehensions was recorded.  When the CoeeMash tribe posts the recording, I’ll post a link to that as well.

Created: 12/12/2008 8:57:00 PM

More Effective C# was one of the better selling books at PDC, which triggered Alan Ashcraft to sit down and chat with me about C#, writing, helping customers, and being a general nerdy person.

The full interview is here: http://dotnet.dzone.com/articles/net-author-qa-bill-wagner-more

And, the interview contains links for a download of a portion of Chapter 3 in More Effective C#.

Created: 12/1/2008 4:31:31 PM

This month’s VSM has a pair of articles by me and Kathleen Dollard that were great fun to write, and I believe they’ll be useful to a wide audience.

My regular C# corner column discusses what every VB Developer should know about C#. Kathleen’s column discusses what C# developers should know about VB.  The bottom line is that all .NET developers will learn something from how a different language leverages the platform.  Take the time and read both, and learn something new about your favorite platform.

But, whatever you do, leave your bad attitude about another language, or their community, behind.

Created: 11/23/2008 9:12:24 PM

Matt Warren has put the IQueryable toolkit on CodePlex.  I’m excited about this for a number of reasons.

I’ve commented before about how much I’ve learned reading Matt’s posts about building an IQueryProvider. That makes LINQ much more powerful.  However, building an IQueryProvider from scratch is a difficult and lengthy task. Without any jump-start, creating an IQueryProvider is almost always more work than it’s worth. (The counter-examples are those providers for very broad use sources like SQL, XML, or Amazon).

Adding Matt’s sample code gives you the jumpstart you need to create a reasonable Query Provider. My hope is that enough people find the IQueryable toolkit useful, and it finds its way into the .NET BCL in some future version.

In the meantime, it’s a great way to get started creating your IQueryProvider.

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.