Platforms > Implementations
I recently read an insightful post about how being a developer is less about coding and more about tooling, and while I do not agree with all of the post, the fact we as developers are tool obsessed rings very true. This obsession with tools becomes a white hot rage when our favourite tool is threated with extinction or causes a world of panic when a competing tool is proposed without enough information on it.
Let’s look at two key examples of that:
- WinForms was very popular and when Microsoft brought us WPF, there was major push back from those who did not want to change and learn a new tool. If you reading this, then you are thinking well time solved that, I disagree. This very week I was asked about WinForms vs. WPF again. Time doesn’t heal all wounds, it just gives some of us time to move on.
- To illustrate the world of panic I can use a more recent issue – Windows 8! Remember all the discussion before //Build about the death of <insert your favourite tool here>? The confusion caused by incomplete discussions around tools we love caused panic.
So what is the solution to this? I think simply a mind set change would be enough. The mind set change needed is to remember that a platform is more important/powerful/useful than a tool. I would like to take credit for this idea, but the first time I heard anyone mention this was a few years back and it was Scott Hanselman talking on MVC almost three years ago to the day. He mentioned that ASP.NET > ASP.NET Web Forms and ASP.NET > ASP.NET MVC. In short he was saying that the core understanding of ASP.NET, the core features and the core uses of the platform are bigger than a single implementation (tool) could be. Sure, you need to learn a new tool, but you aren’t starting at zero if you know the platform.
Why I am bringing this up? It is because of the discussions I have been having about another tool recently: Silverlight. We are approaching the panic stage on this tool due to rumours of it’s demise. However it is VERY important to take a step back and see what the platform is and how knowing the platform means that a tool can move along and we are still able to work/code/make money etc…
The platform Silverlight uses is XAML based UI technologies, a core set of how we can layout UI components using an XML dialect called XAML. This platform also has lots of options for things like binding, the MVVM patterns and so on that are either difficult or impossible to do with other UI technologies (like WinForms for example).
XAML based UI technologies started with a single tool: WPF – an implementation of the platform designed to run on top of the .NET Framework. A second tool, Silverlight, later appeared – this is an implementation of the platform designed to run as a plugin in a browser. A third tool, Silverlight for Windows Phone 7, came next and while very close to Silverlight it had it’s differences as it was an implementation of the platform for the phone. In the last few months we have had the forth implementation of the XAML based UI technologies appear: WinRT. This is the Windows Runtime in Windows 8 and when you develop with C#, VB.NET or C++ your UI technology is just another implementation of the platform.
Every implementation of the platform has been different, some in big ways and some in smaller ways but the core of the XAML based UI technology platform hasn’t changed and there is not a single rumour, plan, or hint that we are even close to seeing the end of XAML based UI technologies. We may see a tool end of life and die (like some rumours say about Silverlight) or other tools just find completeness and not need new work done (like WPF if) but the platform remains and grows and learning a platform is always more important/powerful/useful.
TCP servers with .NET: Scenario 4 & Non-blocking servers with .NET 4.5
This post is part of a series, to see the other posts in the series go to the series index.
Scenario 3 is a great solution to the problem, but the problem with it was the complexity of the code is way higher than in scenario 1 or scenario 2. We are calling to other methods, using recursive like behaviours and all kinds of things that are not obvious or easy to grasp.
Thankfully Microsoft has identified this issue and in .NET 4.5 we will be getting some help with this thanks to the new ASYNC features, in particular the async & await keywords.
In short async provides information to the compiler that this method will spawn off an asynchronous process and will return to the caller at some point while the await points out the line of code that line asynchronously.
So using this allowed me to modify the code back to pretty close to the scenario 1 code (I even have the Boolean continue running server flag). However the two methods are enhanced with the async keyword and in there the await keyword is used with AcceptTcpClientAsync and ReadAsync – these are new methods in the TCP stack which return Task<T>, a fundamental requirement of calls that work with async.
I think this is a fantastic improvement, and I cannot wait for .NET 4.5 to ship
class Program { private const int BufferSize = 4096; private static bool ServerRunning = true; static void Main(string[] args) { var tcpServer = new TcpListener(IPAddress.Any, 9000); try { tcpServer.Start(); ListenForClients(tcpServer); Console.WriteLine("Press enter to shutdown"); Console.ReadLine(); } finally { tcpServer.Stop(); } } private static async void ListenForClients(TcpListener tcpServer) { while (ServerRunning) { var tcpClient = await tcpServer.AcceptTcpClientAsync(); Console.WriteLine("Connected"); ProcessClient(tcpClient); } } private static async void ProcessClient(TcpClient tcpClient) { while (ServerRunning) { var stream = tcpClient.GetStream(); var buffer = new byte[BufferSize]; var amountRead = await stream.ReadAsync(buffer, 0, BufferSize); var message = Encoding.ASCII.GetString(buffer, 0, amountRead); Console.WriteLine("Client sent: {0}", message); } } }
TCP servers with .NET: Scenario 3 & Non-blocking (Async) optimistic servers
This post is part of a series, to see the other posts in the series go to the series index.
The first two posts (post 1, post 2) in this series were really to just set the stage and help explain problems with TCP servers that do blocking. The code and method is not wrong, they are okay for some scenarios, but if you want a really robust model, a model that fixes the issues with them without any extra technical issues being added you need to use a non-blocking server.
We start the server the same way, however instead of using the blocking AcceptTcpClient method we use the non-blocking method BeginAcceptTcpClient which implements the async or begin/end (I’ll call it async from here on) pattern. Mark Pearl has a great post explaining the async pattern.
When a client connects, it runs the code associated when we setup the async and in there we call the EndAcceptTcpClient to end the async process and get the TcpClient implementation.
We repeat this process with reading from the client by switching from Read to BeginRead.
The advantage of this model is the only blocking point is the Readline so shutting the server is very easy, we have no thread management to worry about (it is using threads under the covers, but we do not need to care), and clients can connect now and send data at any time – it doesn’t matter!
This pattern does require a lot more code and it is more complex to setup, but once you understand the async pattern (call begin > pass the info we need in state > call end to get more info we need) it is pretty easy
class Program { private const int BufferSize = 4096; static void Main(string[] args) { var tcpServer = new TcpListener(IPAddress.Any, 9000); try { tcpServer.Start(); tcpServer.BeginAcceptTcpClient(ClientConnection, tcpServer); Console.WriteLine("Press enter to shutdown"); Console.ReadLine(); } finally { tcpServer.Stop(); } } private static void ClientConnection(IAsyncResult asyncResult) { Console.WriteLine("Client connection"); var tcpServer = asyncResult.AsyncState as TcpListener; var tcpClientConnection = tcpServer.EndAcceptTcpClient(asyncResult); tcpServer.BeginAcceptTcpClient(ClientConnection, tcpServer); var stream = tcpClientConnection.GetStream(); var buffer = new byte[BufferSize]; var clientData = new ClientReadData() { Buffer = buffer, Stream = stream }; stream.BeginRead(buffer, 0, BufferSize, ClientRead, clientData); } private class ClientReadData { public byte[] Buffer { get; set; } public NetworkStream Stream { get; set; } } private static void ClientRead(IAsyncResult asyncResult) { var clientReadData = asyncResult.AsyncState as ClientReadData; var amountRead = clientReadData.Stream.EndRead(asyncResult); var buffer = new byte[BufferSize]; var clientData = new ClientReadData() { Buffer = buffer, Stream = clientReadData.Stream }; clientReadData.Stream.BeginRead(buffer, 0, BufferSize, ClientRead, clientData); var message = Encoding.ASCII.GetString(clientReadData.Buffer, 0, amountRead); Console.WriteLine("Client sent: {0}", message); } }
TCP servers with .NET: Scenario 2 - Optimistic Blocking Servers
This post is part of a series, to see the other posts in the series go to the series index.
In the previous post we looked at the simplest of all TCP server scenarios, but what about the third issue highlighted in the post: It assumes your clients will connect, pass data and disconnect. What about for clients the connect optimistically so that they can send data at some point in the future?
This is very common for games, where the client connection process is very slow or where even smallest of overhead should be eliminated.
In this mode rather than read data and disconnect we add a loop on the reading and read until we get a end of message notice and will then end the connection.
The problem with extending the simple model to this, is that we now have a blocking action, i.e. code can not continue until something happens, in both the server thread and in all the client connection threads. So now shutting down the server is not just related to the server, we need clients to disconnect properly first.
What is common here, is to send a message to all clients saying it will shutdown and then having them do that. That assumes we have pretty smart clients and/or control them and in scenarios you do not control the TCP clients it could be a bit problem. We will look at a way to solve this in the next post, but for now the code below shows how this is done, and compared to scenario 1 it contains one small change:
class Program { private const int BufferSize = 4096; private static bool ServerRunning = true; static void Main(string[] args) { new Thread(RunTCPServer).Start(); Console.WriteLine("Press enter to shutdown"); Console.ReadLine(); ServerRunning = false; } private static void RunTCPServer() { var tcpServer = new TcpListener(IPAddress.Any, 9000); try { tcpServer.Start(); while (ServerRunning) { var tcpClientConnection = tcpServer.AcceptTcpClient(); Console.WriteLine("Client connection"); // spawn thread to deal with it new Thread(ClientConnection).Start(tcpClientConnection); } } finally { tcpServer.Stop(); } } private static void ClientConnection(object state) { var tcpClientConnection = state as TcpClient; var stream = tcpClientConnection.GetStream(); var buffer = new byte[BufferSize]; while (ServerRunning) // new in scenario 2 { var amountRead = stream.Read(buffer, 0, BufferSize); var message = Encoding.ASCII.GetString(buffer, 0, amountRead); Console.WriteLine("Client sent: {0}", message); } } }
TCP servers with .NET: Scenario 1 - Simple TCP servers
This post is part of a series, to see the other posts in the series go to the series index.
Writing a TCP server is something that modern business .NET developers do not need to worry about, we have WCF which has abstracted us from understanding TCP servers & clients for business apps – but for some systems we still need to write a TCP server or client.
Microsoft has optimised the .NET framework for common scenarios – for example doing something like SMTP where a server where it is always running and clients connect when they have data, provide the data and disconnect. So what you may do is start a server (in it’s own thread so you can still do other things in the app), and wait for client connections. At this point you are blocking processing until a client connects. When a client connects, you get the data and process it (in a new thread, so you can allow more clients to connect).
The advantage of this is this is a simple model and is fairly easy to setup, but there is a few problems with this:
- You have this blocking point while you wait for clients, so trying to shut it down is difficult. As the view of a server is that it should always be up, this is not an optimised path so there is no way. Basically you will need to deal with task manager to kill the process.
- You have lots of threading and you must handle threads. Threads are hard to understand and easy to fail so we are opening up potential for problems.
- You assume the client will connect and send data at once and will go away. Once again this is the “normal” scenario (think HTTP or SMTP) but there are scenarios where this is not possible.
Below is the sample to do this in a console application.
class Program { private const int BufferSize = 4096; private static bool ServerRunning = true; static void Main(string[] args) { new Thread(RunTCPServer).Start(); Console.WriteLine("Press enter to shutdown"); Console.ReadLine(); ServerRunning = false; } private static void RunTCPServer() { var tcpServer = new TcpListener(IPAddress.Any, 9000); try { tcpServer.Start(); while (ServerRunning) { var tcpClientConnection = tcpServer.AcceptTcpClient(); Console.WriteLine("Client connection"); // spawn thread to deal with it new Thread(ClientConnection).Start(tcpClientConnection); } } finally { tcpServer.Stop(); } } private static void ClientConnection(object state) { var tcpClientConnection = state as TcpClient; var stream = tcpClientConnection.GetStream(); var buffer = new byte[BufferSize]; var amountRead = stream.Read(buffer, 0, BufferSize); var message = Encoding.ASCII.GetString(buffer, 0, amountRead); Console.WriteLine("Client sent: {0}", message); } }
TCP servers with .NET: Series Index
This page provides links to each of the posts in this series. If the post is not linked yet, check back in a few days as they will be all up soon!
Tech·Ed Africa: Slides, Scripts & Thoughts
WOW! I am sitting here under s a fake tree in a fake city that is Micropolis (also known as the Tech·Ed Africa 2011 expo, and it is AMAZING!). I have just finished my third and final presentation at Tech·Ed Africa 2011 and I just wanted to say THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU THANK YOU to all the people who attended my talks!
This year not only has an amazing expo, but the audiences have been by far the BEST EVER! A special thanks to those who braved 8am to see my .NET 4 talk – 2min before I started I thought “I need sleep”, 2min after the energy from the audience was flowing and I never looked back at what I felt was a great talk, so thank you!
A special work of thanks to Suliman and DPE (it is their fake tree I am sitting under) for arranging this and the opportunity to present! I also want to say thanks to the technical team at the event, without who you would not see or hear me, and they were fantastic this year!
For those who attended my talks, or those who couldn’t below are the slides, scripts and misc files used in the talks!
(for those in an RSS reader or on the home page, click read more)
Power features in .NET 4: Investigating the features of .NET 4 which you don’t know about
File downloads
Extend Visual Studio 2010
File downloads
Building Business Applications with Microsoft Visual Studio LightSwitch
File downloads
SharePoint Saturday: Lab Rooms
Next weekend (15th Oct) Cape Town is hosting the SharePoint Saturday conference and myself and fellow BBDer Rudi Grobler will be there and will be and we are running a very special event in conjunction with the main event: Lab Rooms!
There will be two special rooms available and in one Rudi will presenting and training on Windows Phone 7 and in the other I will be presenting and training on the Windows Azure Platform!
The cost for this? FREE! It is being sponsored by BBD & the SharePoint Saturday event
Space in both rooms is VERY VERY limited, so you need to register NOW!
Windows Phone Registration: http://wp7camp.eventbrite.com/
Windows Azure Registration: http://windowsazurecpt.eventbrite.com/
Windows 8: How to get it working
(Update 1) Note: This relates to the Windows 8 Developer Preview, your mileage may vary and this may change.
This post is here to help you, and me, by sharing solutions that I am finding while trying to get Windows 8 running for a professional developer. I am using a HP 8510w laptop so some things maybe specific. This will be updated randomly and will be more like a live blog than a polished post.
(Update 1) As I update this I will prefix new content with (Update #) where # is the update number. The latest ones will be in bold.
Problems & Solutions
Graphics
I have a NVidia Quatro graphics card and to get it working correctly with Win8 (rather than the basic graphic driver) I needed to use the BETA driver from: Beta and Older Driver Versions – I used the Verde 285.27 Driver and that worked just fine, everything else was broken in one way or another.
(Update 5) This just worked with the Windows 8 Community Preview
.NET 3.5
A bunch of apps use .NET 3.5 or earlier so I needed that. To install it you must install it via the Turn Windows Features On/Off option in the control panel (it’s under Programs). I had a BUNCH of issues (error 0x800F0906) getting it to work as it needs to download it which I think are proxy related. Once I downloaded via 3g it finally came down (took an hour
).
(UPDATE 2) Tried this via a transparent proxy and it worked too. Seems it is related to proxy servers that require basic authentication.
(UPDATE 4) Finally found a solution Thanks to Zayd Kara for helping me with this:
Copy the SXS folder from the Windows 8 ISO to the C:\Temp folder.
Then run: dism.exe /online /enable-feature /featurename:NetFX3 /All /Source:c:\temp\sxs /LimitAccess
Metro Style Apps Don’t Run
(Update 1) Found the error message in the Event Log (Application and Services Logs –> Microsoft –> Windows –> WwaHost –> Admin)
Windows Web Application Host has encountered an unexpected exception. The error is number 0x8007000E.
(UPDATE 2) One of the best new features in Windows 8 is the ability to reset your machine without affecting your files. I did this and this solved all my issues
(UPDATE 4) The cause of this is the DLink modem software for my 3G modem. It is screwing up com. No idea why, and no way around it. That’ll teach me to use a 3g modem that doesn’t work with the natively Windows 7/8 mobile internet support.
Windows Phone Developer Tools
The 7.0 RTM release will NOT install at all. The 7.1 RC will install so you may need to get that one.
YOU MUST install .NET 3.5 first (see above). Once installed I didn’t have any emulator options and trying to run it would cause: HRESULT: 0x89721800
I resolved this by deleting “%LOCALAPPDATA%\Microsoft\Phone Tools\CoreCon\10.0” (source for that App Hub Forums)
The emulator option appeared but now when I try to run it, it crashes Windows 8 with a BSOD related to vmm.sys – no solution yet.
(UPDATE 2) I have tried everything and nothing seems to help. Resorted to using a Windows 7 boot from VHD to be able to run these tools
(Update 5) Solved: http://sadev.co.za/content/installing-windows-phone-developer-tools-windows-8
Microsoft Security Essentials
It would not install because of a compatibility issue Downloaded it again from the website, which doesn’t tell you version numbers and the file size looked the same, but this newer one did work fine.
(UPDATE 2) Paul Adare pointed out on the forums that this is included now out of the box, so not needed
Switch to Live ID
Not working, error 0xD00000072 – suspecting proxy again.
Install of Visual Studio 2010 Offline Documentation
Completely failed, no idea why.
D-Link 3G Modem
It could not find the drivers, so I had to go to device manager, select the unknown devices –> Right click –> Update Driver –> Browse my computer –> C:\Program Files (x86)\D-Link Connection Manager\drivers\64bit\WIN7
Then it found and installed the drivers for the 3G modem
(Update 1) Visual Studio 11 Express for Windows Developer Preview
Cannot build or run Metro Style apps.
Designer is failing with Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE))
And running them fails with Unable to activate Windows Tailored application
I suspect this is related to the Metro app issue above.
(Update 1) Internet Explorer 10
Two interesting issues, one browsing our intranet which runs on HTTPS any content from HTTP fails to load and there is NO option to allow it.
Second issue is in the IE desktop mode there is no tooltips
However the solution is to run the Metro Style Internet Explorer, and it shows tooltips… and they are LOVELY:
(Update 3) SharePoint
I am referring to connecting to SharePoint server using IE 10, in short – it is horrid for anything other than basic browsing. I have installed Chrome to get around this.
(Update 3) Windows Server AppFabric
I needed Windows Server AppFabric installed so I could do development, however AppFabric does not install on Windows 8
To work around this I waited for the error to appear, then browsed to the extracted files (the moment you click ok on the error it cleans itself up) and used the expand command to extract the msu file which you can find in the packages folder.
That gets me a cab file which I extract again and that produces another 1 996 files. In there I used the file search to find the assemblies I needed to get the code to build, won’t run but at least I can code
(Update 4) HP LaserJet 4250 Printer
I have this printer on the network but it was horrid trying to get Windows to see and work with it. The trick was to download the actual PCL6 drivers from the HP website. This has all the options to set it up and it works fine now
(Update 5) This just worked with the Windows 8 Community Preview
Things that just worked
For balance here are application that have been installed with no issue.
- Visual Studio 2010 + SP1
- Firefox 6
- Chrome (what ever the latest is)
- Windows Live Writer
- TweetDeck
- Office 2010 + SP 1
- (Update 1) VLC
- (Update 3) Pull
There is also some more info in the comments!
.NET 4, do you know the new features? - Top 10 most useful features
More in this series can be found in the introduction.
In the past two posts we have looked at the negative (top 10 least known, top 12 most useless) so lets switch to the positive side and see what is on the list for top 10 most useful features.
This is worked out by those who knew the feature and indicated it was useful using the same ratio as explained in the in top 12 most useless post.
CLR/BCL: IsNullOrWhiteSpace
Useful Ratio: 21 : 1
Introduction: We have had IsNullOrEmpty on string for a while but in .NET 4 we have the added IsNullOrWhiteSpace which checks for Nulls, empty strings or strings of just white space.
Thoughts: Easy to see why this is useful, it covers more scenarios than the old one, it is easily discoverable and it solves a difficult problem (I do not think many people understand all the white space charters).
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-ii-string
CLR/BCL: Stream.CopyTo
Useful Ratio: 19 : 1
Introduction: You have two streams, you want to copy from one stream to another one, which previously took 6 lines of code, a loop and 3 variables now uses 1 line of code and always works.
Thoughts: A common problem and a great solution and is easily discoverable because the method name is exactly what you would be looking for.
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-ix-stream
CLR/BCL: Enum.HasFlag
Useful Ratio: 17 : 1
Introduction: Enumerator has support for bitwise operations but previously has involved a fairly unintuitive calculation. I think that it was so unintuitive that some people have never even realised bitwise operations were supported. Now we have a single method which makes it VERY easy.
Thoughts: Making the hard easy and making it very discoverable – the factors of all these top useful functions!
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-iii-enum
CLR/BCL: Enum.TryParse
Useful Ratio: 7.6 : 1
Introduction: Going from a string to an enum has been possible in the past but it has never been a fluid experience. No support for generics and not easy to to handle bad data easily. TryParse solves those by brining generics into it and providing a response to tell you if it succeeds.
Thoughts: I think this is a BIG problem for many developers and this is a great and useful solution.
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-iii-enum
CLR/BCL: TimeSpan parsing improvements
Useful Ratio: 5.7 : 1
Introduction: Parsing strings into timespans is not easy, there is many ways to type in time ranges and it has been difficult for people to get right constantly… until .NET 4!
Thoughts: I am surprised at how highly this is up the list, it is useful but ranked this high surprises me as I do not think many people use TimeSpan’s in business systems.
Update: Mark Stacey on Twitter provided some good business use cases I didn't think of (Tweet 1, Tweet 2): "Absolutely. Business process stuff ~ loan applications, time since call was logged, tons of others. Especially where multiple applications work in process."
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-i-timespan
CLR/BCL: MemoryCache
Useful Ratio: 5 : 1
Introduction: MemoryCache is a per process in memory cache for your application which is VERY easy to use regardless of application type – prior to .NET 4 only ASP.NET had an in memory cache. There is also some low plumbing that makes it possible to have the cache stored to other locations, like files or SQL.
Thoughts: This is one of only two features in this list that also appeared in another list, in both cases the top 10 unknown features. This brings joy to me since it means that the issue here is discoverability because once you know it – you find big value in it
More Info: http://www.sadev.co.za/content/net-baby-steps-part-vii-caching
CLR/BCL: string.Join
Useful Ratio: 4.7 : 1
Introduction: Join allows us to concatenate an array of strings together with a specific separator character in place.
Thoughts: This is very useful, as there is often times you need to loop over strings and build up another string. Think of in line SQL generation with a WHERE clause! Very useful stuff.
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-ii-string
Parallel: Parallel Extensions
Useful Ratio: 3.7 : 1
Introduction: Writing code that runs across cores has not been easy and the parallel extensions make it easy to understand how when thinking about normal for or foreach looping structures as it provides implementations of those looping structures which do run across multiple cores.
Thoughts: A fantastic edition to the framework and a much needed one to help solve the issue of having multi-core machines but the complexity of threading not being worth the effort. Why this is came in so high compared to the other two new additions in parallel (TPL was ranked 14th most useful & PLINQ 22nd) is odd but maybe because this is the easiest of the three to understand.
As a side not this is the only one of the most useful top 11 that I didn’t cover in my .NET 4 Baby Steps series which really makes me proud since it shows I was on target for that series.
More Info: http://www.sadev.co.za/content/pulled-apart-part-vii-plinq-not-easy-first-assumed
CLR/BCL: 64bit identification on Environment class
Useful Ratio: 3.5 : 1
Introduction: The environment class has been enhanced to have two new properties which help if the OS is 64bit and the process running is 64bit.
Thoughts: This also appeared on the top 10 unknown feature list, so really highlights that developers are either not thinking about 64bit at all but when they do, the tools they need are available.
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-xiii-tiny-steps
CLR/BCL: Lazy
Useful Ratio: 3.2 : 1
Introduction: Lazy allows you to wrap a class (target class) in another class (Lazy<T> class) and gain lazy constructor calling on the target class.
Thoughts: Very nice feature, but I am surprised it did this well on the useful list as I see this as a bandage to a bad design solution. Proper use of patterns and planning in code should prevent usage – but I’ve been known to be wrong so tell me in the comments why you see this as useful!
More Info: http://www.sadev.co.za/content/net-4-baby-steps-part-v-lazy