text:
Kent Boogaart
My sliding window.
Wednesday, September 24, 2014
Saturday, February 16, 2013
Replacing Synology's Data Replicator with Powershell and Robocopy
I recently upgraded (for some definition of "upgraded") from Windows 7 to Windows 8. I had been using Data Replicator 3 to keep my machine backed up to my Synology server. However, I was keen to be rid of it because it is awfully slow and cumbersome. So I set out to do exactly that by leveraging Powershell and Robocopy, both of which are installed by default on Windows 8.
It's important to note that the solution I provide here isn't a like-for-like replacement of Data Replicator. It doesn't provide any help restoring data – you would have to either do that manually or write another script to reverse the robocopy from server to client. But on the plus side, there's nothing Synology-specific here either, so you can use this regardless of your server technology.
So here's the powershell script I concocted (obviously you'll need to tweak the $Server and $PathsToBackup properties for your setup):
# Incrementally backs up files on a client to a server # the name of your server $Server = "SERVER_NAME" # the local paths to back up to your server. All paths must be fully-qualified $PathsToBackup = @("C:\Users", "C:\SOME_OTHER_PATH") $ScriptPath = $MyInvocation.MyCommand.Path $ScriptDir = Split-Path $ScriptPath $Client = [System.Net.Dns]::GetHostName() $LogPath = "$ScriptDir\BackupLog.txt" if (Test-Path -path $LogPath) { Remove-Item $LogPath } New-Item $LogPath -type file foreach ($PathToBackup in $PathsToBackup) { $PathQualifier = Split-Path -Qualifier $PathToBackup $PathQualifier = $PathQualifier.Replace(":", "") $PathToBackupWithoutQualifier = Split-Path -NoQualifier $PathToBackup $Command = "robocopy $PathToBackup \\$Server\Backups\$Client\$PathQualifier\$PathToBackupWithoutQualifier /FFT /MIR /NP /W:0.5 /R:0 >> $LogPath" Invoke-Expression $Command }
I placed this script in my home directory with a name of Backup.ps1.
Next, I set up a scheduled task to run this script every day. Open the Task Scheduler and select the Task Scheduler Library. Right-click in the list of tasks and select Create New Task… Use the following screenshots to guide you configuring the task. I've also listed the changes textually in case the images stop working (or are blocked for you):
Click OK to create the task. You will be prompted for a password, so enter that. Now you've got a scheduled task that will incrementally back up whatever local files you like to your server. Finally, note that the script produces a log (truncated on each run) called BackupLog.txt in the same directory as Backup.ps1, so this may come in handy if something isn't backing up as expected.
Monday, December 24, 2012
WPF Splash Screens
It may seem odd to blog about something as mundane as WPF splash screens. After all, it's a solved problem, right? Wrong. I think there are various problems that come about by using standard splash screen helpers, and I want to address those here.
First though, we need to get back to basics by discussing what the purpose of a splash screen is. Contrary to many a splash you may have been subjected to, the purpose of a splash screen is not to annoy users or to wow business folks. To quote the repository of all knowledge:
Splash screens are typically used by particularly large applications to notify the user that the program is in the process of loading. They provide feedback that a lengthy process is underway.
So a splash screen's primary goal is to reassure the user that their choice of software is, indeed, loading. That implies that the splash screen must appear quickly, otherwise the user won't feel reassured at all and may end up launching the software a second time. A splash screen might also provide some additional pieces of information about the software (such as the version number).
With those points in mind, it's time to move onto specifics.
WPF provides a SplashScreen class. It is simple by design and addresses the main goal of splash screens: immediate feedback. By virtue of forgoing the WPF stack and instead relying on Windows Imaging Component (WIC) to display images, it provides the quickest path to getting a splash on the screen short of writing your own native bootstrapper.
Of course, it has limitations, otherwise this blog post wouldn't have much meat on it. We'll get to those shortly...
Disabling the Splash
Within mere minutes of adding a splash to your application, you'll be sick of seeing it, especially if your artistic skills are on par with mine. And when the debugger breaks with the splash screen superimposed over it, you'll be screaming abuse at Thaygorn (the god of splash screens, as ordained by me, just now).
So the first thing you should do is provide a command-line switch to disable the splash screen. I like -thaybegorn, but heathens may prefer -nosplash. For WPF applications, this means forgoing the generated entry point and providing your own. For any non-trivial application, you'll likely want your own entry point anyway, so that you can bootstrap logging and hook into unhandled exception events as early as possible.
In your entry code, you can have something like this:
internal static void Main(string[] args) { var showSplash = !args.Any(x => string.Equals("-nosplash", x, StringComparison.OrdinalIgnoreCase)); if (showSplashScreen) { ShowSplashScreen(); } } private static void ShowSplashScreen() { splashScreen = new SplashScreen("Splash.png"); splashScreen.Show(true, true); }
Now developers can simply configure their IDE to pass in this command line argument when starting the application. Most of the time, they can live in blissful ignorance of there even being a splash screen.
Regaining some Dynamism
One of the biggest things you give up by using SplashScreen is dynamic content. No animations (not even animated GIFs), no progress information, no nothing. If you're like me, you'd at least like the version number of the product in the splash screen. But that means you have to modify your splash image every time your version changes. Rather than doing this manually (ugh!), you should look to your build process to do it for you. I assume you already have a shared assembly info file with the version of your product in it? If not, go do that right now.
Once your build has access to a well-defined version number, you can use a custom task to modify a base splash image on the fly. Here's one I wrote (MSBuild):
<UsingTask TaskName="AddTextToImage" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll"> <ParameterGroup> <InputPath ParameterType="System.String" Required="true" /> <TopRightPoint ParameterType="System.String" Required="true" /> <OutputPath ParameterType="System.String" Required="true" /> <IsBitmap ParameterType="System.Boolean" Required="false" /> <Text ParameterType="System.String" Required="true" /> </ParameterGroup> <Task> <Reference Include="WindowsBase"/> <Reference Include="PresentationCore"/> <Reference Include="PresentationFramework"/> <Reference Include="System.Xaml"/> <Using Namespace="System" /> <Using Namespace="System.Globalization" /> <Using Namespace="System.IO" /> <Using Namespace="System.Windows" /> <Using Namespace="System.Windows.Media" /> <Using Namespace="System.Windows.Media.Imaging" /> <Code Type="Fragment" Language="cs"><![CDATA[ var originalImageSource = BitmapFrame.Create(new Uri(InputPath)); var visual = new DrawingVisual(); using (var drawingContext = visual.RenderOpen()) { drawingContext.DrawImage(originalImageSource, new Rect(0, 0, originalImageSource.PixelWidth, originalImageSource.PixelHeight)); var typeFace = new Typeface(new FontFamily("Century Gothic"), FontStyles.Normal, FontWeights.Bold, FontStretches.Normal); var formattedText = new FormattedText(Text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeFace, 8, Brushes.White); var topRightPoint = Point.Parse(TopRightPoint); var point = new Point(topRightPoint.X - formattedText.Width, topRightPoint.Y); drawingContext.DrawText(formattedText, point); } var renderTargetBitmap = new RenderTargetBitmap(originalImageSource.PixelWidth, originalImageSource.PixelHeight, originalImageSource.DpiX, originalImageSource.DpiY, PixelFormats.Pbgra32); renderTargetBitmap.Render(visual); var bitmapFrame = BitmapFrame.Create(renderTargetBitmap); BitmapEncoder encoder = null; if (IsBitmap) { encoder = new BmpBitmapEncoder(); } else { encoder = new PngBitmapEncoder(); } encoder.Frames.Add(bitmapFrame); using (var stream = File.OpenWrite(OutputPath)) { encoder.Save(stream); } ]]> </Code> </Task> </UsingTask>
In my case, I need to ensure the text within the splash image is right-aligned, so I have a TopRightPoint property. I use it like this:
<AddTextToImage InputPath="$(ResourcesPath)/SplashTemplate.png" OutputPath="$(ResourcesPath)/Splash.png" TopRightPoint="350,115" Text="$(Version)"/>
This takes the SplashTemplate.png image, adds the contents of the Version property at the location specified, then saves it to Splash.png. Easy. This step, of course, happens before I build the application, so that the modified Splash.png is included in the executable as a resource. I also check in a copy of the splash template as Splash.png so that developers don't run into missing file issues if they compile without the splash generation step having been executed. I then set up my source control to ignore any changes to that file.
I use the same technique to add version numbers to my setup images. You could take it a lot further (add other text, flexible fonts, superimpose other images), of course, but I haven't had any need.
Postponing Closure
The SplashScreen class supports an auto-close function, which will start closing the splash screen as soon as the application is loaded (ie. the dispatcher is processing messages with a priority of DispatcherPriority.Loaded). It also allows you to close the splash screen yourself, via its Close method.
In my experience, a splash screen closing as soon as the application is loaded can be a jarring experience. The application being loaded does not imply that all windows have been initialized and displayed. You may have some background process initializing services or connections or whatever, with UI initializing asynchronously in respect to that.
I much prefer to have explicit control over when the splash screen closes. I like to have it wait a couple of seconds after the application has loaded before fading out the splash screen. And sometimes I need even more control than that, such as waiting for some specific UI initialization event.
Simply starting a timer in our entry code does not suffice, because it will start before the application has loaded. Indeed, if the application takes more than a couple of seconds to load, the splash may close before the UI even appears! And since the entry code is the main UI thread, we can't just block until the application initializes, because then it never will!
One approach might be to spin off another thread or task to periodically check whether the application is loaded. However, there's a cleaner way via WPF's DispatcherFrame mechanism. What we can do is pump the dispatcher until the application is loaded:
private static void PumpDispatcherUntilPriority(DispatcherPriority dispatcherPriority) { var dispatcherFrame = new DispatcherFrame(); Dispatcher.CurrentDispatcher.BeginInvoke((ThreadStart)(() => dispatcherFrame.Continue = false), dispatcherPriority); Dispatcher.PushFrame(dispatcherFrame); }
We can use that method like this:
if (showSplash) { // pump until loaded PumpDispatcherUntilPriority(DispatcherPriority.Loaded); // start a timer, after which the splash can be closed var splashTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) }; splashTimer.Tick += (s, e) => { splashTimer.Stop(); CloseSplashScreen(); }; splashTimer.Start(); }
Great! Now we have a splash that closes two seconds after the application loads. You could also pump the dispatcher until some other criteria is met. Notice, however, that you need to be careful. If the user has sufficient time to open a dialog window within the application, this can preclude the closure of the splash screen (until the dialog is dismissed). That's because opening the dialog will result in a new dispatcher frame that pumps until the dialog is closed. That's precisely why I used a timer above instead of just pumping for a fixed period of time.
Fixing the Activation Issue
Now that our splash closes some time after the application appears, another problem has surfaced. When our splash screen fades, it temporarily becomes activated. That's weird. And rather ugly.
After perusing the source for SplashScreen, I found the reason for this jarring activation. This code is in the fade logic:
// by default close gets called as soon as the first application window is created // since it will have become the active window we need to steal back the active window // status so that the fade out animation is visible. IntPtr prevHwnd = UnsafeNativeMethods.SetActiveWindow(new HandleRef(null, _hwnd));
The comment seems to suggest that the window is being activated only to ensure it is visible. Nasty.
So where does this discovery leave us? We must either put up with the activation of the fading splash screen, or forgo the fade logic in SplashScreen and write our own. I did the latter, and it looks like this:
private static void CloseSplashScreen(TimeSpan fadeDuration) { var fadeDurationTicks = fadeDuration.Ticks; var remainingTicks = fadeDurationTicks; var lastCheckTicks = DateTime.UtcNow.Ticks; var dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal) { // 60fps Interval = TimeSpan.FromMilliseconds(1000 / 60d) }; var opacity = 1d; dispatcherTimer.Tick += (s, e) => { var tickChange = DateTime.UtcNow.Ticks - lastCheckTicks; lastCheckTicks = DateTime.UtcNow.Ticks; remainingTicks -= tickChange; remainingTicks = Math.Max(0, remainingTicks); opacity = (double)remainingTicks / fadeDurationTicks; if (remainingTicks == 0) { // finished fading splashScreen.Close(TimeSpan.Zero); dispatcherTimer.Stop(); splashForegroundTimer.Stop(); splashScreen = null; splashForegroundTimer = null; } else { // still fading blendFunction.SourceConstantAlpha = (byte)(255 * opacity); SafeNativeMethods.UpdateLayeredWindow(splashScreen.GetHandle(), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, ref blendFunction, SafeNativeMethods.ULW_ALPHA); } }; dispatcherTimer.Start(); }
As you can see, I set up a timer that continuously fades the splash screen until it is no longer visible, at which point I close it. At no point do I activate the splash screen.
Notice the call to splashScreen.GetHandle()? That's where things have gotten a bit ugly. SplashScreen does not expose its window handle to us, so I wrote an extension method to obtain it via reflection:
internal static class SplashScreenExtensions { public static IntPtr GetHandle(this SplashScreen @this) { return (IntPtr)typeof(SplashScreen).GetField("_hwnd", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(@this); } }
Not ideal, but it works. We can now fade our splash screen ourselves without it being activated.
Taming the Z-order
There's nothing more obnoxious that a splash screen that insists on covering other applications. OK, apart from Ken Ham that is. So when we show our splash screen, we should pass false for the topmost parameter (or don't specify the parameter at all, since false is the default value):
splashScreen.Show(autoClose: false, topMost: false);
However, doing so presents another issue. Other windows within our application can obstruct the splash screen. As we discovered in the last section, this is why WPF's SplashScreen calls SetActiveWindow. But SetActiveWindow's primary purpose is to activate a window – bringing the window to the top of the stack is just a side-effect of that. We would like to bring our splash to the top of the window stack without activating it. Moreover, we need to ensure it remains at the top of the stack regardless of how many application windows happens to come (and maybe even go) during the time the splash is on-screen or fading away.
The first issue can be addressed by using SetWindowPos instead of SetActiveWindow. It allows us to pull a window in our application to the top of the stack without activating it.
The second issue – ensuring our splash stays on top even as application windows come and go – is trickier. I considered many approaches, including setting the splash window to be a child of the application window (but what if there are multiple application windows?), detecting the activation of new windows so I can call SetActiveWindow again on the splash, and hooking into message queues.
Ultimately I settled on the simplest possible thing I could get to work:
splashForegroundTimer = new DispatcherTimer(DispatcherPriority.Normal); splashForegroundTimer.Interval = TimeSpan.FromMilliseconds(10); splashForegroundTimer.Tick += delegate { SafeNativeMethods.SetWindowPos(splashScreen.GetHandle(), SafeNativeMethods.HWND_TOP, 0, 0, 0, 0, SafeNativeMethods.SetWindowPosFlags.SWP_NOMOVE | SafeNativeMethods.SetWindowPosFlags.SWP_NOSIZE | SafeNativeMethods.SetWindowPosFlags.SWP_NOACTIVATE); }; splashForegroundTimer.Start();
I have a timer that brings the splash screen to the top of the z-order every 10ms (I didn't experiment too much with this interval, so it may be possible to lengthen it). Notice that I use SWP_NOACTIVATE to ensure the splash isn't activated. Notice also that this isn't a perfect solution. There is still a 10ms (give or take) window wherein the splash may be underneath application windows. In practice, however, I have found this to work satisfactorily. If anyone has any other ideas on how to achieve this more cleanly and simply then I'd love to hear them.
What we end up with when applying all the above changes is something rather more complicated than one might expect. Indeed, it makes me wonder whether I should forgo WPF's SplashScreen class altogether and create my own. However, I have avoided doing so for a couple of reasons:
- SplashScreen has quite a bit of complexity in it.
- SplashScreen is in WindowsBase.dll, which is used by any WPF application, and is NGEN'd. Consequently, it's more likely to load faster than my own assembly.
I did, however, create my own wrapper around WPF's SplashScreen class. To confuse matters, I called mine SplashScreen too. Its API is very similar to that provided by WPF's SplashScreen.
Attached is a sample project showing all these techniques combining to result in a splash screen I (and my users) can live with.
Saturday, September 08, 2012
And then there was Then
In his excellent post Processing Sequences of Asynchronous Operations with Tasks, Stephen Toub discusses how a series of asynchronous operations can be run one after the other in a pre-.NET 4.5 world (a world in which I currently reside, both at work and at home). I won't go into the details here - you should just read his post - but suffice to say that an implementation of a set of Then extension methods is desirable as a functional equivalent to the await keyword. This allows us to chain together asynchronous operations with ease and with better performance than that attainable with ContinueWith on its own:
DownloadImageAsync() .Then(x => SearchForAliensAsync()) .Then(x => DistributeResultsAsync());
Stephen provides an implementation of Then and hints at the usefulness of further overloads. In this post, I provide my own implementation of Then that includes all overloads that I think are useful.
Firstly, here are the signatures for my overloads of Then:
public static Task Then(this Task antecedent, Func<Task, Task> getSuccessor) public static Task Then(this Task antecedent, Action<Task> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null) public static Task<TSuccessor> Then<TSuccessor>(this Task antecedent, Func<Task, Task<TSuccessor>> getSuccessor) public static Task<TSuccessor> Then<TSuccessor>(this Task antecedent, Func<Task, TSuccessor> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null) public static Task Then<TAntecedent>(this Task<TAntecedent> antecedent, Func<Task<TAntecedent>, Task> getSuccessor) public static Task Then<TAntecedent>(this Task<TAntecedent> antecedent, Action<Task<TAntecedent>> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null) public static Task<TSuccessor> Then<TAntecedent, TSuccessor>(this Task<TAntecedent> antecedent, Func<Task<TAntecedent>, Task<TSuccessor>> getSuccessor) public static Task<TSuccessor> Then<TAntecedent, TSuccessor>(this Task<TAntecedent> antecedent, Func<Task<TAntecedent>, TSuccessor> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null)Note that due to the use of optional arguments, there are more overload permutations here than apparent at first glance. Broadly, there are four supported scenarios:
- A non-generic antecedent task THEN a non-generic successor task.
- A non-generic antecedent task THEN a generic successor task.
- A generic antecedent task THEN a non-generic successor task.
- A generic antecedent task THEN a generic successor task.
Each scenario comes in two "flavours". The first flavour requires that the caller provide a Func that returns the successor Task. The second flavour allows you to specify the task logic in an Action or Func, which will be automatically wrapped in a Task for you.
Four scenarios and two flavours means eight overloads, many of which include optional arguments. The result is a great deal of flexibility in how you use Then:
InitializeAsync() .Then(x => Console.WriteLine("Initialize step done.")) // an action that is wrapped in a Task for us .Then(x => DownloadDataAsync()) // a method that returns a Task .Then( // a func that is wrapped in a Task for us x => { Console.WriteLine("Download step done: " + x.Result); return x.Result; }) .Then(x => // a func that returns the Task with which to continue { if (x.Result.Contains("MAGIC")) { return ProcessMagicAsync(); } else { return ProcessNonMagicAsync(); } }) .Then(x => Console.WriteLine("Processing step done: " + x.Result)); // another action
Right, on to the implementation then. To improve maintainability, I really wanted to ensure I had only a single implementation of the core Then logic, no matter the number of overloads I made available. This presented a problem in that the core implementation would need to be generic, but then the non-generic overloads would not be able to call it (because their Task instances are not generic). To that end, I created a simple method that takes a non-generic Task and wraps it as a Task<bool>:
public static Task<bool> ToBooleanTask(this Task task) { var taskCompletionSource = new TaskCompletionSource<bool>(); task.ContinueWith(t => taskCompletionSource.TrySetException(t.Exception.GetBaseException()), TaskContinuationOptions.OnlyOnFaulted); task.ContinueWith(t => taskCompletionSource.TrySetCanceled(), TaskContinuationOptions.OnlyOnCanceled); task.ContinueWith(t => taskCompletionSource.TrySetResult(true), TaskContinuationOptions.OnlyOnRanToCompletion); return taskCompletionSource.Task; }
If and when the non-generic Task succeeds, the wrapper Task<bool> assumes a result of true. If it is cancelled or fails, that cancellation or failure propagates to the wrapper Task<bool> too. So now any Task can be treated as a Task<bool>, thus allowing our non-generic overloads to call into our generic core implementation.
With that in place, I could create the core implementation:
private static Task<TSuccessor> ThenImpl<TAntecedent, TSuccessor>(Task<TAntecedent> antecedent, Func<Task<TAntecedent>, Task<TSuccessor>> getSuccessor) { antecedent.AssertNotNull("antecedent"); getSuccessor.AssertNotNull("getSuccessor"); var taskCompletionSource = new TaskCompletionSource<TSuccessor>(); antecedent.ContinueWith( delegate { if (antecedent.IsFaulted) { taskCompletionSource.TrySetException(antecedent.Exception.InnerExceptions); } else if (antecedent.IsCanceled) { taskCompletionSource.TrySetCanceled(); } else { try { var successorTask = getSuccessor(antecedent); if (successorTask == null) { taskCompletionSource.TrySetCanceled(); } else { successorTask.ContinueWith( delegate { if (successorTask.IsFaulted) { taskCompletionSource.TrySetException(successorTask.Exception.InnerExceptions); } else if (successorTask.IsCanceled) { taskCompletionSource.TrySetCanceled(); } else { taskCompletionSource.TrySetResult(successorTask.Result); } }, TaskContinuationOptions.ExecuteSynchronously); } } catch (Exception ex) { taskCompletionSource.TrySetException(ex); } } }, TaskContinuationOptions.ExecuteSynchronously); return taskCompletionSource.Task; }
This is very similar to the implementation provided on Stephen's blog, since I used his solution as a starting point.
With these two pieces in place, I could add all the overloads I required:
public static Task Then(this Task antecedent, Func<Task, Task> getSuccessor) { Func<Task<bool>, Task<bool>> getSuccessorAsBoolean = x => { var successiveTask = getSuccessor(x); return successiveTask == null ? null : successiveTask.ToBooleanTask(); }; return ThenImpl<bool, bool>(antecedent.ToBooleanTask(), getSuccessorAsBoolean); } public static Task Then(this Task antecedent, Action<Task> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null) { successor.AssertNotNull("successor"); Func<Task<bool>, Task<bool>> getSuccessor = x => { var successiveTask = new Task(() => successor(antecedent), taskCreationOptions); successiveTask.Start(scheduler ?? TaskScheduler.Default); return successiveTask.ToBooleanTask(); }; return ThenImpl<bool, bool>(antecedent.ToBooleanTask(), getSuccessor); } public static Task<TSuccessor> Then<TSuccessor>(this Task antecedent, Func<Task, Task<TSuccessor>> getSuccessor) { return ThenImpl<bool, TSuccessor>(antecedent.ToBooleanTask(), getSuccessor); } public static Task<TSuccessor> Then<TSuccessor>(this Task antecedent, Func<Task, TSuccessor> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null) { successor.AssertNotNull("successor"); Func<Task<bool>, Task<TSuccessor>> getSuccessor = x => { var successiveTask = new Task<TSuccessor>(() => successor(antecedent), taskCreationOptions); successiveTask.Start(scheduler ?? TaskScheduler.Default); return successiveTask; }; return ThenImpl<bool, TSuccessor>(antecedent.ToBooleanTask(), getSuccessor); } public static Task Then<TAntecedent>(this Task<TAntecedent> antecedent, Func<Task<TAntecedent>, Task> getSuccessor) { Func<Task<TAntecedent>, Task<bool>> getSuccessorAsBoolean = x => { var successiveTask = getSuccessor(x); return successiveTask == null ? null : successiveTask.ToBooleanTask(); }; return ThenImpl<TAntecedent, bool>(antecedent, getSuccessorAsBoolean); } public static Task Then<TAntecedent>(this Task<TAntecedent> antecedent, Action<Task<TAntecedent>> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null) { successor.AssertNotNull("successor"); Func<Task<TAntecedent>, Task<bool>> getSuccessor = x => { var successiveTask = new Task(() => successor(antecedent), taskCreationOptions); successiveTask.Start(scheduler ?? TaskScheduler.Default); return successiveTask.ToBooleanTask(); }; return ThenImpl<TAntecedent, bool>(antecedent, getSuccessor); } public static Task<TSuccessor> Then<TAntecedent, TSuccessor>(this Task<TAntecedent> antecedent, Func<Task<TAntecedent>, Task<TSuccessor>> getSuccessor) { return ThenImpl<TAntecedent, TSuccessor>(antecedent, getSuccessor); } public static Task<TSuccessor> Then<TAntecedent, TSuccessor>(this Task<TAntecedent> antecedent, Func<Task<TAntecedent>, TSuccessor> successor, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler scheduler = null) { successor.AssertNotNull("successor"); Func<Task<TAntecedent>, Task<TSuccessor>> getSuccessor = x => { var successiveTask = new Task<TSuccessor>(() => successor(antecedent), taskCreationOptions); successiveTask.Start(scheduler ?? TaskScheduler.Default); return successiveTask; }; return ThenImpl<TAntecedent, TSuccessor>(antecedent, getSuccessor); }
Each of these overloads directly calls the core ThenImpl implementation, massaging any parameters as necessary. It's all reasonably straightforward, so I won't elaborate too much here.
In the interests of completeness, I also wrote these unit tests to validate the implementation:
[Fact] public void to_boolean_task_propagates_failures() { var task = Task.Factory.StartNew(() => { throw new InvalidOperationException("Testing."); }); var booleanTask = task.ToBooleanTask(); var ex = Assert.Throws<AggregateException>(() => booleanTask.Wait(TimeSpan.FromSeconds(1))); Assert.Equal(1, ex.InnerExceptions.Count); Assert.IsType<InvalidOperationException>(ex.InnerExceptions[0]); Assert.Equal("Testing.", ex.InnerExceptions[0].Message); } [Fact] public void to_boolean_task_propagates_cancellation() { var cancellationTokenSource = new CancellationTokenSource(); cancellationTokenSource.Cancel(); var task = Task.Factory.StartNew(() => cancellationTokenSource.Token.ThrowIfCancellationRequested(), cancellationTokenSource.Token); var booleanTask = task.ToBooleanTask(); var ex = Assert.Throws<AggregateException>(() => booleanTask.Wait(TimeSpan.FromSeconds(1))); Assert.Equal(1, ex.InnerExceptions.Count); Assert.IsType<TaskCanceledException>(ex.InnerExceptions[0]); } [Fact] public void to_boolean_task_propagates_success() { var task = Task.Factory.StartNew(() => { }); var booleanTask = task.ToBooleanTask(); Assert.True(booleanTask.Wait(TimeSpan.FromSeconds(1))); } [Fact] public void then_non_generic_second_task_does_not_start_until_first_is_finished() { var executed = false; var task = Task.Factory .StartNew( () => { Thread.Sleep(100); executed = true; }) .Then( x => { Assert.True(executed); }); Assert.True(task.Wait(TimeSpan.FromSeconds(3))); } [Fact] public void then_non_generic_fault_in_first_task_prevents_second_task_from_running() { var executed = false; var task = Task.Factory .StartNew( () => { throw new InvalidOperationException("Failure"); }) .Then( x => { executed = true; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Faulted, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } [Fact] public void then_non_generic_fault_in_second_task_results_in_faulted_overall_task() { var executed = false; var task = Task.Factory .StartNew(() => { }) .Then( x => { throw new InvalidOperationException("Failure"); }) .Then( x => { executed = true; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Faulted, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } [Fact] public void then_non_generic_cancellation_in_first_task_prevents_second_task_from_running() { var executed = false; using (var cancellationTokenSource = new CancellationTokenSource()) { // cancel up-front cancellationTokenSource.Cancel(); var cancellationToken = cancellationTokenSource.Token; var task = Task.Factory .StartNew( () => { cancellationToken.ThrowIfCancellationRequested(); }, cancellationToken) .Then( x => { executed = true; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Canceled, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } } [Fact] public void then_non_generic_cancellation_in_second_task_results_in_overall_canceled_task() { var executed = false; using (var cancellationTokenSource = new CancellationTokenSource()) { // cancel up-front cancellationTokenSource.Cancel(); var cancellationToken = cancellationTokenSource.Token; var task = Task.Factory .StartNew(() => { }, cancellationToken) .Then( x => { cancellationToken.ThrowIfCancellationRequested(); }) .Then( x => { executed = true; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Canceled, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } } [Fact] public void then_non_generic_cancellation_is_automatic_if_next_task_is_null() { var task = Task.Factory .StartNew(() => { }) .Then(x => null); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.Equal(TaskStatus.Canceled, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } [Fact] public void then_non_generic_antecedent_task_is_passed_through() { var task1 = Task.Factory .StartNew(() => { }); var task2 = task1 .Then(x => Assert.Same(task1, x)); var task3 = task2 .Then(x => Assert.Same(task2, x)); Assert.True(task3.Wait(TimeSpan.FromSeconds(2))); } [Fact] public void then_generic_second_task_does_not_start_until_first_is_finished() { var executed = false; var task = Task.Factory .StartNew( () => { Thread.Sleep(100); executed = true; return "result 1"; }) .Then( x => { Assert.True(executed); return "result 2"; }); Assert.True(task.Wait(TimeSpan.FromSeconds(3))); Assert.Equal("result 2", task.Result); } [Fact] public void then_generic_fault_in_first_task_prevents_second_task_from_running() { var executed = false; var task = Task.Factory .StartNew<string>( () => { throw new InvalidOperationException("Failure"); }) .Then( x => { executed = true; return "result 2"; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Faulted, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } [Fact] public void then_generic_fault_in_second_task_results_in_faulted_overall_task() { var executed = false; var task = Task.Factory .StartNew(() => "result 1") .Then( x => { // dummy test to appease compiler if (!executed != executed) { throw new InvalidOperationException("Failure"); } return "result 2"; }) .Then( x => { executed = true; return "result 3"; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Faulted, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } [Fact] public void then_generic_cancellation_in_first_task_prevents_second_task_from_running() { var executed = false; using (var cancellationTokenSource = new CancellationTokenSource()) { // cancel up-front cancellationTokenSource.Cancel(); var cancellationToken = cancellationTokenSource.Token; var task = Task.Factory .StartNew( () => { cancellationToken.ThrowIfCancellationRequested(); return "result 1"; }, cancellationToken) .Then( x => { executed = true; return "result 2"; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Canceled, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } } [Fact] public void then_generic_cancellation_in_second_task_results_in_overall_canceled_task() { var executed = false; using (var cancellationTokenSource = new CancellationTokenSource()) { // cancel up-front cancellationTokenSource.Cancel(); var cancellationToken = cancellationTokenSource.Token; var task = Task.Factory .StartNew(() => "result 1", cancellationToken) .Then( x => { cancellationToken.ThrowIfCancellationRequested(); return "result "; }) .Then( x => { executed = true; return "result 3"; }); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.False(executed); Assert.Equal(TaskStatus.Canceled, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } } [Fact] public void then_generic_cancellation_is_automatic_if_next_task_is_null() { var task = Task.Factory .StartNew(() => "result 1") .Then<string, string>((Func<Task<string>, Task<string>>)(x => null)); try { task.Wait(TimeSpan.FromSeconds(3)); Assert.True(false); } catch (AggregateException ex) { Assert.Equal(TaskStatus.Canceled, task.Status); Assert.Equal(1, ex.InnerExceptions.Count); } } [Fact] public void then_generic_antecedent_task_is_passed_through() { var task1 = Task.Factory .StartNew(() => "One"); var task2 = task1 .Then( x => { Assert.Same(task1, x); return "Two"; }); var task3 = task2 .Then( x => { Assert.Same(task2, x); return "Three"; }); Assert.True(task3.Wait(TimeSpan.FromSeconds(2))); } [Fact] public void then_generic_tasks_can_change_type() { var task = Task.Factory .StartNew(() => "One") .Then( x => { Assert.Equal("One", x.Result); return 2; }) .Then( x => { Assert.Equal(2, x.Result); return 3d; }, TaskCreationOptions.None) .Then( x => { Assert.Equal(3d, x.Result); }); Assert.True(task.Wait(TimeSpan.FromSeconds(2))); }
Alright, that about wraps it up. I hope it is of use to some of you.
Tuesday, March 13, 2012
Debugging Failed, Unobserved TPL Tasks
I've been doing some work with the task parallel library (TPL) of late. For the most part, I've found it a joy to work with, despite the fact that I'm using .NET 4.0 with VS2010 and am thus unable to leverage the async / await keywords in C# 5. However, I found that complex composition of tasks could lead to difficulty in debugging the inevitable failures you will encounter throughout development. Specifically, one might see an exception similar to this:
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
As suggested by the exception message, this occurs when a task has failed but nothing has observed its failure. This is a good thing - it would be awful if the TPL silently swallowed these problems and left it to the developer to suss out what was going on. It's important to note that the TPL uses a finalizer to notify you of such problems. Therefore, you aren't likely to see the exception immediately when your task fails. Indeed, it may not appear for some time after the offending task completes, which can make debugging especially painful.
I found that even though I had access to the failing task, there wasn't enough contextual information for me to relate the task back to my source code. This is partly as a result of my complicated task composition and partly due to the fact that many of those tasks could result in the same generic exceptions.
To combat this problem, I decided it would be nice to attach a conceptual name to each task that I start. I could then retrieve that name when the failure occurs, and therefore be able to relate it back to a specific point in my code.
I defined a TaskExtensions class that allows me to associate names with tasks as follows:
var firstTask = Task.Factory .StartNew(...) .WithName("whatever I want to call this task"); var continuation = firstTask .ContinueWith(...) .WithName("my continuation");
I then added a handler for TaskScheduler.UnobservedTaskException that retrieved the conceptual name associated with the failing task.
Result! I was able to quickly determine which of my tasks was improperly observed and fix accordingly.
I have attached a sample project demonstrating this. If you run it, you'll see you can create successful or failing tasks and force garbage collection. If you create a failing task, you'll see a message output to the console, but no failure. If you then force garbage collection, you'll see an error message that includes the conceptual name of the task.
Note that in my real project, I limit the use of TaskExtensions to DEBUG builds only. This is just to avoid memory leaks (ie. holding onto a massive list of task names that never gets cleaned up). You could conceivably use a weak reference to the task as the key in the dictionary, but then you'll need to decide how and when expired entries are moved. It's a complication I just did not need to bother with, considering I did not want WithName() calls scattered about the source code anyway. In other words, the infrastructure I'm describing is, for me, a debug-only aid. Once debugged, I expect all calls to WithName() to be removed from the code.
In addition, my UnobservedTaskException handler is also DEBUG-only, and automatically breaks into the debugger:
#if DEBUG // this allows us to see tasks that were left unobserved TaskScheduler.UnobservedTaskException += delegate(object sender, UnobservedTaskExceptionEventArgs e) { var task = (Task)sender; var taskName = HSBC.TraderDesktop.Utility.Tasks.TaskExtensions.GetName(task); // if you break here, it's because you've left a TPL task unobserved // the task and any assigned name are given above // you can assign names to your tasks using the TaskExtensions class: task.WithName("...") Debugger.Break(); }; #endif
This will instantly get the developer's attention as soon as reasonably possible, and gives them the information they need to begin resolving the issue.
Saturday, November 19, 2011
The application I'm currently working on - top secret, mum's the word, your death for my indiscretion, you get the idea - includes a widget-style interface. In order to render these widgets, I use an ItemsControl and bind it to a collection of view models, each of which represents a widget. I use a Canvas to lay them out according to their XOffset and YOffset properties. Something like this:
<ItemsControl ItemsSource="{Binding Widgets}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style> <Setter Property="Canvas.Left" Value="{Binding XOffset}"/> <Setter Property="Canvas.Top" Value="{Binding YOffset}"/> </Style> </ItemsControl.ItemContainerStyle> <ItemsControl.ItemTemplate> <DataTemplate> <views:WidgetView/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
This all works fine and I'd even go so far as to say it's a beautiful thing. However, it is only a widget-style interface by virtue of some trickery on my part. Without said trickery, it would be more of an MDI interface.
With an MDI interface, multiple child windows are contained within a parent window – they cannot appear outside the bounds of the parent. Whilst my widgets look like windows, they aren't. They're just regular WPF user controls with some additional smarts to allow positioning and what-have-you. And whilst it looks like they're free to roam wherever they like on the desktop, they're not. They're all contained within the ItemsControl, which is within the only Window in my application. Thus, they cannot be positioned outside the area in which the Window resides. It just so happens that I've stretched that Window across the entire desktop and made it transparent. This gives the illusion that I have a widget interface and am thus as cool as The Dude himself, but I actually have an MDI interface which makes me more Napolean Dynamite than Lebowski. Before the dance, that is.
All this wouldn't concern me terribly (one learns to live with it) but my users are actually privy to more screen real estate than I. And when I say "more", I mean they have six screens whilst I have two, one of which I can't use for anything of import because it frequently distorts and shows other signs of discontent (no audible screams as yet). Because of this abundance of screen real estate, my Window has to to stretch across a huge expanse of pixels in order to keep up this illusion of cool. This has dire consequences for performance. You see, if one's Window size exceeds the maximum texture size of one's video card (I don't have one of course, but my users do) then the video card won't be able to accelerate rendering of said Window. The Window will be software-rendered instead, which is probably going to be a lot slower and less capable of Dude-worthy effects and animations.
No problem, you say. Just host your widgets inside windows instead and be done with it. And this is indeed what I am going to do.
But I want it to be seamless with respect to the current code base. I don't want to have to go hook up a bunch of event handlers to create/show/close windows when my widget collection changes. I don't want to have to change the way my view models keep track of widget positions and sizes (all persisted across application restarts, of course). All I want to do is change this:
<ItemsControl ItemsSource="{Binding Widgets}">
to this:
<WindowItemsControl ItemsSource="{Binding Widgets}">
But unfortunately WPF doesn't have a WindowItemsControl. Boo. And it doesn't seem as though anyone in the community has written one.
Obviously, then, I set out to write my own.
My initial approach failed, but it's worth discussing anyway. I tried to have my WindowItemsControl create Window instances as containers. This failed because internal WPF code was attempting to add these Windows as visual children of the ItemsControl, and Windows must be top-level visual items (makes sense). So I tried to hack around this because I really wanted the logical connection between the Window and the WindowItemsControl, much the same way there's a logical connection between a ListBoxItem and its containing ListBox. If I could trick WPF into forgoing the visual connection, I could then attempt the logical connection.
Well, I tried all sorts of nastiness, and ended up reflectively invoking an internal member to trick WPF into not including the Window as a visual child. Success! Right!? Alas, no, because when I then added the Window as a logical child of the WindowItemsControl, I got another similar error. I can't remember the details, nor can I explain why a Window cannot be a logical child of another control (it's only a logical connection, after all). But it didn't work and I gave up on this approach entirely.
My second approach is much more sane but gives up on creating a logical connection between the Windows and their host. But I don't really need that anyway – it was a nice-to-have.
What I did instead was had the WindowItemsControl create WindowItemsControlItem instances as containers. These containers are really just surrogates for the Window they represent. When they're initialized, they display the Window. When they're destroyed, they close the Window. In addition, if a Window is closed ahead of time, the corresponding data item is removed from the underlying collection and thus too the surrogate from the visual tree.
The code is actually quite neat and compact. Here is the code for WindowItemsControl:
public class WindowItemsControl : ItemsControl { public static readonly DependencyProperty ShowDialogProperty = DependencyProperty.Register( "ShowDialog", typeof(bool), typeof(WindowItemsControl)); public static readonly DependencyProperty OwnerProperty = DependencyProperty.Register( "Owner", typeof(Window), typeof(WindowItemsControl), new FrameworkPropertyMetadata(OnOwnerChanged)); public static readonly DependencyProperty WindowStartupLocationProperty = DependencyProperty.Register( "WindowStartupLocation", typeof(WindowStartupLocation), typeof(WindowItemsControl)); public static readonly DependencyProperty RemoveDataItemWhenWindowClosedProperty = DependencyProperty.Register( "RemoveDataItemWhenWindowClosed", typeof(bool), typeof(WindowItemsControl), new FrameworkPropertyMetadata(true)); static WindowItemsControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowItemsControl), new FrameworkPropertyMetadata(typeof(WindowItemsControl))); } public bool ShowDialog { get { return (bool)this.GetValue(ShowDialogProperty); } set { this.SetValue(ShowDialogProperty, value); } } public Window Owner { get { return this.GetValue(OwnerProperty) as Window; } set { this.SetValue(OwnerProperty, value); } } public WindowStartupLocation WindowStartupLocation { get { return (WindowStartupLocation)this.GetValue(WindowStartupLocationProperty); } set { this.SetValue(WindowStartupLocationProperty, value); } } public bool RemoveDataItemWhenWindowClosed { get { return (bool)this.GetValue(RemoveDataItemWhenWindowClosedProperty); } set { this.SetValue(RemoveDataItemWhenWindowClosedProperty, value); } } protected override DependencyObject GetContainerForItemOverride() { return new WindowItemsControlItem(this); } protected override bool IsItemItsOwnContainerOverride(object item) { return item is WindowItemsControlItem; } protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { (element as WindowItemsControlItem).Window.Content = item; } protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item) { // the item container style will be applied to the windows, not to the containers (which are surrogates for the window) return false; } private static void OnOwnerChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { var windowItemsControl = (WindowItemsControl)dependencyObject; var owner = (Window)e.NewValue; for (var i = 0; i < windowItemsControl.Items.Count; ++i) { var container = windowItemsControl.ItemContainerGenerator.ContainerFromIndex(i) as WindowItemsControlItem; if (container == null) { continue; } container.Window.Owner = owner; } } }
Pretty straightforward stuff. Note the following:
- it declares some properties (ShowDialog, Owner, WindowStartupLocation) that assist it in the display of child Windows
- it declares a RemoveDataItemWhenWindowClosed property that can be used to prevent the control from removing data items when a window is closed. This can be useful in shutdown or other situations where windows are being closed programmatically rather than by the user
- I don't apply the ItemContainerStyle to the containers themselves, but instead hold out so that I can apply them to the Windows they represent
- I also make sure that any change of Owner is applied to any existing Windows
- the default style is overridden to remove unnecessary stuff like the Border, because the WindowItemsControl will never actually be visible on screen
The WindowItemsControl works in conjunction with the WindowItemsControlItem, which looks like this:
public class WindowItemsControlItem : FrameworkElement { private readonly WindowItemsControl windowItemsControl; private readonly Window window; static WindowItemsControlItem() { // there is no need for these items to be visible as they are simply surrogates for the windows that they display VisibilityProperty.OverrideMetadata(typeof(WindowItemsControlItem), new FrameworkPropertyMetadata(Visibility.Collapsed)); } public WindowItemsControlItem(WindowItemsControl windowItemsControl) { windowItemsControl.AssertNotNull("windowItemsControl"); this.windowItemsControl = windowItemsControl; this.window = this.CreateWindow(windowItemsControl); this.Loaded += delegate { if (this.windowItemsControl.ShowDialog) { this.window.ShowDialog(); } else { this.window.Show(); } }; this.Unloaded += delegate { this.window.Close(); }; } public Window Window { get { return this.window; } } private Window CreateWindow(WindowItemsControl windowItemsControl) { var window = new Window { Owner = windowItemsControl.Owner, WindowStartupLocation = windowItemsControl.WindowStartupLocation }; BindingOperations.SetBinding(window, Window.DataContextProperty, new Binding("Content") { Source = window }); BindingOperations.SetBinding(window, Window.StyleProperty, new Binding("ItemContainerStyle") { Source = windowItemsControl }); BindingOperations.SetBinding(window, Window.ContentTemplateProperty, new Binding("ItemTemplate") { Source = windowItemsControl }); BindingOperations.SetBinding(window, Window.ContentTemplateSelectorProperty, new Binding("ItemTemplateSelector") { Source = windowItemsControl }); window.Closed += delegate { // orphan the content because it might be hosted somewhere else later (including in another window) window.Content = null; // if the window closes, attempt to remove the original item from the underlying collection, which will result in this surrogate being removed too if (windowItemsControl.RemoveDataItemWhenWindowClosed) { var editableItems = windowItemsControl.Items as IEditableCollectionView; if (editableItems != null && editableItems.CanRemove) { editableItems.Remove(this.DataContext); } } }; return window; } }
This is all pretty self-explanatory, too. The important points to note are:
- relevant properties on the WindowItemsControl are bound to the correct properties on the Windows themselves
- Windows are displayed when the surrogate is initialized, and closed when the surrogate is unloaded
- as mentioned earlier, Windows that are closed before the surrogate is destroyed (perhaps by the user clicking the close button) result in the related data item in the underlying collection being removed (unless the RemoveDataItemWhenWindowClosed property has been set to false). This, in turn, will cause the surrogate to be removed from the visual tree. In other words, if I close a widget Window, the corresponding WidgetViewModel will be removed from my collection of widget view models. Then, the ItemsControl will remove the related surrogate container from the visual tree.
Now, as I yearned for at the beginning of this post, I can simply change my ItemsControl to a WindowItemsControl, make minor adjustments to my ItemContainerStyle and it just magically works.
The Dude abides.
I created a little demo to show how it all works, which you can download below. Enjoy!
Saturday, November 12, 2011
We all know how important logging is to any non-trivial application, so it stands to reason that we should make it as pain free as possible to add logging to our application components. But at the same time, we don't want to sacrifice too much, such as having to deal with a sub-standard logging API, or with a logging infrastructure that doesn't log the obvious stuff on our behalf.
Wouldn't it be nice if logging were as simple as this:
namespace SomeNamespace { public class SomeClass { [ImportingConstructor] public SomeClass(ILoggerService loggerService) { loggerService.Debug("Created an instance of {0}.", GetType().Name); } } }
And, importantly, the resultant log entry looked something like this:
[2011-11-12 12:09:04,749] [1] [DEBUG] [SomeNamespace.SomeClass] Created an instance of SomeClass.
Prism ships with an ILoggerFacade interface that looks like this:
public interface ILoggerFacade { void Log(string message, Category category, Priority priority); }
This is obviously a very bare-bones interface. Every time you write a log statement you'll be forced to:
- Format any parameters yourself.
- Specify the category as a parameter (instead of having separate methods for each category)
- Choose and specify a priority, even if it makes no sense for your code.
- Incur the cost of any preparation for the log statement even if the pertinent log level is disabled because you have no way to check whether it is or not.
This is not very consumer-friendly at all, and you'll more than likely begin to find logging a more onerous task than it should be.
Another problem with using ILoggerFacade in Prism is the lack of any originating source in the output. There is nothing intrinsic to differentiate log statements from different components. If two components log the same message ("Initialized", for example), you will have no way to tell which component was initialized!
These problems forced me to come up with a custom solution. I wanted my logging to be based on log4net, and I wanted MEF to provide my components with a logging service instance. Moreover, that service must produce log entries that are specific to my component.
The first problem (poor API) was easiest to solve. I defined my own interface as follows:
public interface ILoggerService { bool IsVerboseEnabled { get; } bool IsDebugEnabled { get; } bool IsInfoEnabled { get; } bool IsWarnEnabled { get; } bool IsErrorEnabled { get; } bool IsPerfEnabled { get; } void Verbose(string message); void Verbose(string message, Exception exception); void Verbose(string message, params object[] args); void Debug(string message); void Debug(string message, Exception exception); void Debug(string message, params object[] args); void Info(string message); void Info(string message, Exception exception); void Info(string message, params object[] args); void Warn(string message); void Warn(string message, Exception exception); void Warn(string message, params object[] args); void Error(string message); void Error(string message, Exception exception); void Error(string message, params object[] args); IDisposable Perf(string message); IDisposable Perf(string message, params object[] args); }
As you can see, this interface provides many overloads for all the relevant combinations of parameters you might need. This saves you, the caller, from having to deal with the annoyance of formatting messages or exceptions. There are also properties that can be used to check whether a given log level is enabled, which can be crucial in performance-critical paths. Finally, notice the handy Perf overloads which can be used to measure the performance of a block of code like this:
using (loggerService.Perf("Authenticating the user")) { // do authentication here }
The only thing I haven't included (because I haven't needed it) are generic Write methods that take the log level as a parameter instead of inferring the log level from the method name. Such methods can be useful in dynamic logging scenarios, so you may want to add your own.
With the API defined, it was time to write an implementation:
public sealed class Log4NetLoggerService : ILoggerService { private static readonly Level perfLevel = new Level(35000, "PERF"); private readonly ILog log; public Log4NetLoggerService(ILog log) { log.AssertNotNull("log"); this.log = log; } public bool IsVerboseEnabled { get { return this.log.Logger.IsEnabledFor(Level.Verbose); } } public bool IsDebugEnabled { get { return this.log.IsDebugEnabled; } } public bool IsInfoEnabled { get { return this.log.IsInfoEnabled; } } public bool IsWarnEnabled { get { return this.log.IsWarnEnabled; } } public bool IsErrorEnabled { get { return this.log.IsErrorEnabled; } } public bool IsPerfEnabled { get { return this.log.Logger.IsEnabledFor(perfLevel); } } public void Verbose(string message) { this.log.Logger.Log(typeof(Log4NetLoggerService), Level.Verbose, message, null); } public void Verbose(string message, Exception exception) { this.log.Logger.Log(typeof(Log4NetLoggerService), Level.Verbose, message, exception); } public void Verbose(string message, params object[] args) { this.log.Logger.Log(typeof(Log4NetLoggerService), Level.Verbose, new SystemStringFormat(CultureInfo.InvariantCulture, message, args), null); } public void Debug(string message) { this.log.Debug(message); } public void Debug(string message, Exception exception) { this.log.Debug(message, exception); } public void Debug(string message, params object[] args) { this.log.DebugFormat(CultureInfo.InvariantCulture, message, args); } public void Info(string message) { this.log.Info(message); } public void Info(string message, Exception exception) { this.log.Info(message, exception); } public void Info(string message, params object[] args) { this.log.InfoFormat(CultureInfo.InvariantCulture, message, args); } public void Warn(string message) { this.log.Warn(message); } public void Warn(string message, Exception exception) { this.log.Warn(message, exception); } public void Warn(string message, params object[] args) { this.log.WarnFormat(CultureInfo.InvariantCulture, message, args); } public void Error(string message) { this.log.Error(message); } public void Error(string message, Exception exception) { this.log.Error(message, exception); } public void Error(string message, params object[] args) { this.log.ErrorFormat(CultureInfo.InvariantCulture, message, args); } public IDisposable Perf(string message) { message.AssertNotNull("message"); return new PerfBlock(this, message); } public IDisposable Perf(string message, params object[] args) { message.AssertNotNull("message"); args.AssertNotNull("args"); return new PerfBlock(this, string.Format(CultureInfo.InvariantCulture, message, args)); } private sealed class PerfBlock : IDisposable { private readonly Log4NetLoggerService owner; private readonly string message; private readonly Stopwatch stopwatch; private bool disposed; public PerfBlock(Log4NetLoggerService owner, string message) { this.owner = owner; this.message = message; this.stopwatch = Stopwatch.StartNew(); } public void Dispose() { if (!this.disposed) { this.disposed = true; this.stopwatch.Stop(); var messageWithTimingInfo = string.Format(CultureInfo.InvariantCulture, "{0} [{1}, {2}ms]", this.message, this.stopwatch.Elapsed, this.stopwatch.ElapsedMilliseconds); this.owner.log.Logger.Log(typeof(Log4NetLoggerService), perfLevel, messageWithTimingInfo, null); } } } }
It's all pretty straightforward - most of the code just delegates to log4net.
But notice how the constructor requires a log4net.ILog? Log4net provides various ways by which an ILog can be obtained, but we would like to use LogManager.GetLogger(Type ownerType), where ownerType is the type importing our service. How, then, can we expect MEF to provide instances of ILoggerService when our constructor has a dependency that it cannot satisfy?
MEF supports an abstraction called ExportProvider, which is an object that can dynamically provide exports to satisfy matching imports. The trick to making this all work seamlessly is a custom ExportProvider that creates instances of Log4NetLoggerService on the fly to satisfy imports of type ILoggerService. In order to create Log4NetLoggerService instances, the export provider must know the type of the object that is importing the service. Thankfully, MEF supports obtaining this information through its reflection services.
Here is the code for our custom ExportProvider:
public sealed class LoggerServiceExportProvider : ExportProvider { private static readonly ILoggerService log = new Log4NetLoggerService(LogManager.GetLogger(typeof(LoggerServiceExportProvider))); private readonly IDictionary<Type, ILoggerService> loggerServiceCache; public LoggerServiceExportProvider() { this.loggerServiceCache = new Dictionary<Type, ILoggerService>(); } protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) { var contractName = definition.ContractName; log.Verbose("Attempting to resolve contract name '{0}' to a log instance.", contractName); if (string.IsNullOrEmpty(contractName)) { log.Verbose("Contract name is null or empty - cannot resolve."); yield break; } if (!string.Equals(typeof(ILoggerService).FullName, contractName, StringComparison.Ordinal)) { log.Verbose("Incorrect contract - cannot resolve."); yield break; } if (definition.Cardinality != ImportCardinality.ExactlyOne) { log.Verbose("Cardinality is {0} - cannot resolve.", definition.Cardinality); yield break; } // in order to get a log4net logger, we need the type importing the logger facade Type ownerType = null; if (ReflectionModelServices.IsImportingParameter(definition)) { log.Verbose("Parameter import detected."); var importingParameter = ReflectionModelServices.GetImportingParameter(definition); ownerType = importingParameter.Value.Member.DeclaringType; } else { log.Verbose("Property import detected."); var setAccessor = ReflectionModelServices .GetImportingMember(definition) .GetAccessors() .Where(x => x is MethodInfo) .Select(x => x as MethodInfo) .FirstOrDefault(x => (x.Attributes & MethodAttributes.SpecialName) == MethodAttributes.SpecialName && x.Name.StartsWith("set_", StringComparison.Ordinal)); if (setAccessor == null) { log.Verbose("Set accessor for property not found - cannot resolve."); yield break; } ownerType = setAccessor.DeclaringType; } if (ownerType == null) { log.Verbose("Owner type could not be determined - cannot resolve."); yield break; } log.Verbose("Owner type is '{0}'.", ownerType.FullName); ILoggerService loggerService; if (!this.loggerServiceCache.TryGetValue(ownerType, out loggerService)) { log.Verbose("Logger facade for owner type '{0}' is not yet cached - creating it.", ownerType.FullName); var logInstance = LogManager.GetLogger(ownerType); loggerService = new Log4NetLoggerService(logInstance); this.loggerServiceCache[ownerType] = loggerService; } var export = new Export(contractName, () => loggerService); yield return export; } }
There are several things to note about this implementation:
- Log service instances are cached. This means that if different instances of the same type import a logger service, they will (quickly) get the exact same instance.
- Imports can be either via constructors or through properties. The export provider supports both.
- The export provider itself includes logging statements, but it must do so with an explicitly created ILog instance. Obviously the export provider cannot import an ILoggerService itself or we'd have a chicken and egg problem!
We can tell MEF to use our custom ExportProvider in the usual fashion:
var compositionContainer = new CompositionContainer(new LoggerServiceExportProvider());
With this infrastructure in place, we achieve our objectives entirely. The code I included right at the beginning of this post will work, and any log entries will include the details of the originating type. And it is ridiculously easy for us to imbue components created by MEF with logging statements. Simply add the import and then invoke the simple-to-use APIs.
For a working example, click below. Enjoy!


text: Actress Lindsay Lohan to appear in PlayboyBy the CNN Wire StaffUpdated 8:38 PM ET, Mon November 7, 2011The Playboy issue featuring actress Lindsay Lohan is expected to hit newsstands in late December.Story highlightsLohan will be featured in the January/February issue of the magazineThe 25-year-old actress was released from jail early MondayHer rocky personal life has overshadowed her career in recent yearsActress Lindsay Lohan will be featured in the January/February issue of Playboy, a spokeswoman for the magazine said Monday.The issue is expected to hit newsstands late December, Theresa Hennessey told CNN, declining to offer details.The 25-year-old actress and model shot to fame for her roles in kid-friendly flicks like "The Parent Trap." But her rocky personal life, which is standard fodder for tabloids, has overshadowed her career in recent years.Lohan was released from jail early Monday, just hours after she was booked in, authorities said.Last week, a Los Angeles County judge ordered Lohan to serve a 30-day jail term after she admitted she violated her probation on a necklace theft conviction.At the time, Los Angeles County Sheriff spokesman Steve Whitmore said it was likely Lohan could be booked in and booked out the same day. "It depends on the fluctuations of the day, what's going on in the jail," Whitmore said.The actress must work at least 12 days a month at the county morgue until she completes the 53 remaining days on her court-ordered community service, Judge Stephanie Sautner told her. Lohan must also attend 18 psychotherapy sessions.The actress also made headlines last month, when photographs surfaced showing Lohan with less-than-perfect teeth.Her representative, Steve Honig, shot back then, telling CNN: "Lindsay is widely recognized as one of the most beautiful women on the planet, and is regularly sought after by some of the top photographers in the world to appear on covers of magazines around the globe."More from showbizAnthony Bourdain previews new CNN showBourdain: I never thought I'd leave NYCDemi Lovato's plan to change the worldPowered by Livefyre

subset: commoncrawl


text:
byRob Wright on
More Heads Roll At Apple Over Maps Flap
Apple reportedly pushed out another executive this week following the heavy criticism of its new Maps app for iOS 6. Richard Williamson, senior director of iOS platform services and the lead on the Maps app development, was shown the door; his exit follows the high-profile dismissal of Scott Forstall, Apple's iOS software chief, who was pushed out for reportedly refusing to publicly apologize for the buggy app.
Live At XChange Solution Provider 2015
XChange Solution Provider 2015 is finally upon us and the timing couldn't be better. The premier channel event is happening March 1-3 in Dallas, bringing together 225 solution provider decision makers from across North America. CRN is at the event to provide news, analysis and a firsthand take from partners.
Here are 10 recent searches by CRN visitors.
Cloud 100


text:
Oldest practice in Logan County established 1955
2930 Hwy. 105 Guthrie, OK 73044 Phone Number: 405-282-4821 TRAVEL DIRECTIONS View MapQuest Map BUSINESS HOURS
ABOUT US We offer primary care services for a wide variety of animals. Our mission here at Veterinary Corner is to provide your pet with the best possible care. The veterinarians here at Veterinary Corner, working under Dr. JG Sewell, are highly skilled in diagnosis and are knowledgeable about the most advanced and best treatment methods available for your pet. Veterinary Corner was founded in 1955 here in Guthrie, and we have since then built our reputation as the finest veterinary clinic in the area. We know how much you care about your pet, because we care about them too. That is why we here at Veterinary Corner have always done our best to keep your pet healthy. ANIMALS TREATED Cats, Dogs, Horses, Cattle, Goats, Swine, Exotics, Pocket Pets |


text:
The School of Law Events Calendar has a complete listing of events at the School.
January 13, 2015
"First Tuesdays" Alumni Gathering in Holyoke, MA
Host: Cristina Ianello L'02
5:30-7:30 p.m.
Pic's Pub and Pizzeria, Holyoke
Please RSVP to Cristina Ianello L'02 at firstname.lastname@example.com.
January 24, 2015
University Alumni and Families Great Wolf Lodge Water Park Getaway
Fitchburg, MA
February 3, 2015
"First Tuesdays" Alumni Gathering in Boston
Host: Zach Ryan L'09
Boston Beer Works, 113 Canal St.
RSVP: firstname.lastname@example.com
February 10, 2015
President's Alumni Reception in Boca Raton, FL
Host: Trustee Peter Steingraber L'84
More info on the University Alumni Calendar.
February 11, 2015
President's Alumni Reception in Tampa, FL
Host: John Iwanicki '84
More info on the University Alumni Calendar.
February 12, 2015
President's Alumni Dinner in Naples, FL
Host: John Breck '83
More info on the University Alumni Calendar.
February 21, 2015
School of Law Invitational Basketball Tournament Alumni Event
Lunch, and possibly an "old-timers" game or skills contest
Noon-2:00 p.m.
Alumni Healthful Living Center
More info: email@example.com.
February 26, 2015
University President's Alumni Reception in Boston
Host: Roger Wade L'82
More info on the University Alumni Calendar.
March 3, 2015
"First Tuesdays" Alumni Gathering in Long Island
5:30-7:30 p.m.
Basil's Bistro at the Hilton
Melville, NY
Host: Michael Borg L'88
March 4, 2015
"Selma: Forgetting the Future"
Blake Law Commons
Presenter: Department of History Professor John Baick
Sponsored by The Institute for Legislative and Governmental Affairs
More info: news story and flyer.
April 7, 2015
"First Tuesdays" Alumni Gathering in Albany, NY
Host: Marcy Spratt G'09/L'02
May 17, 2015
Law Commencement Ceremony
June 13, 2015
Law Alumni Trip to Fenway Park
Boston Red Sox vs. Toronto Blue Jays, 7:10 p.m.
Current Events
"First Tuesdays" Alumni Gathering in Springfield - December 2, 2014
Springfield-area alumni (above) joined join Alumni Board member Bob Ward '82 for an evening at 350 Grill Steak House in Springfield.
15th Annual Dinner for Students and Alumni of Color - November 21, 2014
The Carriage House at the Barney Estate in Springfield's Forest Park was the setting for this highlight of the School's fall social calendar. The annual event, pictured above, allows students to network with each other and many of our distinguished alumni. The guest speaker was The Honorable Tina S. Page L'82, a judge in the Commonwealth of Massachusetts Superior Court. View the photo album/slide show.
Color of Law Roundtable - November 10, 2014
Hector Zavala L'12 (pictured above), an Assistant District Attorney with the Hampden County District Attorney's Office, discussed his career and the demands of working full-time as a victim/witness advocate while attending the School of Law's part-time evening program—and at the same time raising a child. At the event, held at the Blake Law Commons, the Springfield native discussed the value of networking, taking advantage of the School's skills courses, and "building your resume with experience, because grades will only take you so far."
Clason Speaker Series - November 3
Judy Rabinovitz, Deputy Director, ACLU Immigrants' Rights Project, gave a talk in the Blake Law Commons entitled The Surge of Central American Migrants at the Border and the Politics of Immigration Reform: Reflections from 25 Years of Fighting for Immigrants' Rights.
Senatorial Debate - October 28, 2014
The School of Law hosted a debate between two of the candidates running for the 1st Hampden and Hampshire state Senate seat. Democrat Eric Lesser and Republican Debra Boronski (pictured above) sparred over issues including tax reform, economic development, heroin epidemic, crime, and both candidates spoke at length about their personal qualifications for the Senate seat. Read more.
Clason Speaker Series - October 27, 2014
Phil Tegeler, Executive Director, PRRAC, discussed "50 Years After the Civil Rights Act: The Challenge of Ending Segregation in Housing and Education," in the Blake
Law Commons
Naturalization Ceremony - October 24, 2014
The School of Law hosted naturalization proceedings for the U.S. Citizenship and Immigration Services (USCIS) in the J. Gerard Pellegrini Moot Court Room. Nineteen immigrants from western Massachusetts took the Oath of Allegiance to the United States of America and were sworn in as U.S. citizens during the ceremony, including Silvia Pickrell, a housekeeper employed at the University The citizenship candidates include immigrants from Jamaica, Japan, Nepal, Pakistan, Myanmar, People's Republic of China, Ghana, Canada, Poland, Russia, South Korea, Ukraine, Germany, and Uzbekistan. Dean Eric Gouvin presented poignant welcoming remarks to the new citizens and their families. The Honorable Mark Mastroianni L'89, Federal District Court Judge, then ruled on the motion to accept the applications of the new citizens, while U.S. District Court Deputy Clerk, Theresa Pelegano administered the Oath of Allegiance to the applicants. Read more.
Ambulance Chase 5K Walk/Run - October 18, 2014
This year was the 10th year School of Law students have held the Ambulance Chase to raise funds for local Springfield charities. For the past several years, the proceeds have gone to the Ronald McDonald House in Springfield. Read more.
University Alumni Reception in Washington, DC - October 16, 2014
Alumni from the Washington, DC area (pictured above) met at the Dupont Circle Hotel on October 16. It was a unique opportunity to reconnect with some old friends and make some new ones—along with some new professional contacts. The event was hosted by Scott Lessne L'83. View the photo album/slide show.
19th Annual Supreme Court Review Conference - October 15 and 16, 2014
The U.S. Supreme Court Review Conference (the audience is pictured above) focused on several federal court decisions handed down this year, mostly concerning discrimination. Law Professor and Director of the Legislative Institute, Art Wolf, moderated the presentations. Read more.
1L Students' Lunch With Local Attorneys – September 19, 2014
As part of a continuation of their orientation, 1L students had lunch with local alumni attorneys, who followed with a question-and-answer session in which they discussed their experiences as attorneys, and advised students on succeeding in law school and starting their legal careers. This networking event included attorneys John Bandeian L'09, David Bartley L'05, Chris Erchull L'14, Talia Gee L'10/G'12, Kyle Guelcher L'02, Cristina Ianello '99/L'02, David McGuire L'06, Dan McKellick L'14, Kate Muratore L'06, Erika Scibelli L'12, Lynn Scull L'09, Cheryl Smith L'83, Kristin Sopet '08/L'10, Chris Todd L'00, Christina Turgeon '98/L'01, Angelina Stafford L'12, and Pat Newcombe L'01. Pictured with students above are Jeff Krok (third from left) L'10 and Dean Eric Gouvin. View the photo album/slide show.
Constitution Day - September 17, 2014
The School of Law celebrated Constitution Day with a panel discussion entitled "Ferguson and the US Constitution" in the Blake Law Center's Law Commons. University faculty explored the relevance of the US Constitution, and of our particular Constitutional history, to the fatal shooting of Michael Brown by an officer of the Ferguson, MO Police Department. They focused on the Constitution's treatment of race, both in the original text and post Civil War amendments, on the role of the US Supreme Court in establishing and perpetuating the "outsider" status of African-Americans, particularly young African-American males, and on the militarization of local police departments in the aftermath of the terrorist attacks on September 11, 2001. The moderator was Professor Bruce Miller (Law) and the featured panelists were Professors John Baick (History), Bridgette Baldwin (Law), and Matthew Charity (Law). The event was sponsored by the Institute for Legislative and Governmental Affairs.
Hampden County District Attorney Debate - August 28, 2014
The School of Law and the Hampden County Bar Association hosted a debate between the four candidates running for Hampden County District Attorney: Shawn Allyn, Hal Etkin, Anthony Gulluni '03/L'07, and Brett Vottero, in the Blake Law Center's Pellegrini Moot Court Room. The moderator was Holyoke City Councilor Anthony Soto. The debate aired on Ludlow and Wilbraham cable access channels, and was streamed live online.
Law Alumni Day at the Races: Saratoga Race Track - August 15, 2014
The Western New England Law Alumni Board members hosted this family-friendly gathering in Saratoga Springs, NY. Law alumni gathered with Dean Eric Gouvin at the Paddock Tent behind the clubhouse, adjacent to Saratoga's picturesque saddling area. Pictured above are Kathleen Porter '90 (second from right), her husband Jim McGlynn '90 (right), along with their daughter, Molly, and Kathleen's dad, Bob, at the Saratoga Race Track. View the photo album/slide show.
Reunion 2014 - June 7th at Basketball Hall of Fame, Springfield, MA
Boston Reception - May 21st at Robinson & Cole
Pictured above, Kendra Berardi, L'08, Dean Eric Gouvin and Kathy Porter, L'90
Springfield Reception - April 3rd at LaQuinta, Springfield
Hartford Reception - November 14th at Max Downtown
Hon. Evelyn Daly L'82 and Dean Eric Gouvin
Lisa Bongiovi L'94 and Larry Josiah L'93
Karen Lynch L'81 and Lynn Banis L'82
Max Downton - Hartford, CT
Dinner for Students and Alumni of Color - November 8th -
Barney House at Forest Park, Springfield
Dean Eric Gouvin and law student speaker AnnaMaria Kiaresh
Hon. Charles W. Groce, III, L'97
President's Reception - NYC - October 24th


text:
Tufts Animal Care and Condition Scales
The Tufts Animal Care and Condition (TACC) Scales were developed in 1997 by Dr. Gary Patronek, with assistance from Lori Donley, MS '97, the Fort Wayne Dept. of Animal Care and Control, and the Law Enforcement Division of the Massachusetts Society for the Prevention of Cruelty to Animals to help cruelty investigators and veterinarians assess cases of animal abuse or neglect that are primarily related to husbandry, as opposed to deliberate acts of cruelty.
That pooch in the pet-store window may be may alluring but buyer beware: you may be supporting a puppy mill.
July 1, 2014
Finding Homes for High-Energy Dogs
Connecting high-energy dogs with families interested in performance sports.
May 1, 2014
No Place Like Home
Advocates use prevention strategies and fair housing laws to keep owners and pets together.
March 1, 2014
Time, Space, and the Single Cat
Many adopters are looking to bring a second cat to their household, but what's the best way to turn a couple of swingin' single felines into a happy couple? And how do you know if a new friend would even be welcome? Shelters and rescues can help adopters find their way to a peacefully expanded kitty family.
November 1, 2013
Decoding Dog Play
Learning to read the signs of dog-to-dog interaction help shelters and rescues make more responsible placements.
September 1, 2013
Mouthpieces: Don't Leave Pets in Hot Cars
This reproducible poster reminds owners that, even after summer ends, warm weather still makes it dangerous to leave pets alone in parked cars.
July 1, 2013
No Fly Zone
Parrots are intelligent and social creatures whose most basic instincts are often denied when kept as pets. The complex needs of these birds often overwhelm their owners, fueling a crisis of abandonment and neglect.
May 1, 2013
Mouthpieces: Too Much of a Good Thing
This reproducible poster encourages pet owners to spay or neuter their feline companions.
March 1, 2013
Taking it to the Streets
The HSUS's Pets for Life program is bringing the human touch to neighborhoods where pet care services are scarce, but love for animals abounds. Learn how to implement this amazing and unique program in your community.


text:
Comment: Re:Even worse - extensions == "chmod +x" ?!? (Score 1) 561
Keep in mind a file with 755 will be examined and run based on the magic number at the front of the file.
Even shell scripts. #! is actually a 16-bit magic number, that also happens to be a comment in almost every scripting language.
Go ahead - chmod +x a random non-executable file and try to run it. You'll probably get something enligthening: "invalid file (bad magic number): Exec format error"


text:
Maybe you don't need another World War II shooter, but how about three? If recently spotted listings on GameStop and Amazon are accurate, a new Call of Duty compilation, dubbed Call of Duty: The War Collection, will be released next month.
The collection bundles together the three WWII-based games in the series available on Xbox 360: Call of Duty 2, Call of Duty 3 and Call of Duty: World at War -- all for $60. Given that Call of Duty 2 was never released on PS3, it seems unlikely that Sony's platform will receive this particular collection.
That's three (old) Call of Duty games for the price of one standard Xbox 360 game. Not a bad deal, especially for Modern Warfare players in need of a history lesson. According to GameStop and Amazon, The War Collection will be released this June.
[Thanks, Iain]
Source - Call of Duty: The War Collection at Amazon
Source - Call of Duty: The War Collection at GameStop
Featured Stories
Off the Grid: The Witcher Adventure Game and Star Wars Imperial Assault
Posted on Feb 3rd 2015 2:15PM


text:
This site uses cookies and similar technologies to customize and enhance your online experience. By using this site, you accept our use of these technologies. To learn more, please read our cookie policy.
Bucks vs. Lakers: First half
Kobe Bryant and Dwight Howard both have 16 points as the Lakers lead the Rockets by seven at the half.


text:
Home › Health & Behavior › Emotional Well-Being
By GreatSchools Staff
Successful kids and successful schools usually share a secret ingredient: supportive parents! This means the time you spend helping at school also boosts your child's chances for success.
Students and their schools both rely on parents to help them be their best. Students need a supportive atmosphere for learning at home and someone to advocate for them at school. In these days of shrinking budgets and increasing demands on teachers, many schools cannot provide everything students need without help from parents.
In today's busy world, it is easy for parents to focus their time and energy on activities that directly benefit their own kids, and avoid getting involved with larger school activities and issues. Luckily you do not need to make a choice between helping the school and helping your child. Recent studies show that the children of parents who are involved in schools do better academically.
Here are 10 ways you can be involved in your child's education. Some support your child directly and others benefit the whole school, including your child. Remember, you don't have to do everything! Choose the activities that fit your interests and schedule.
1. Make sure your children go to school ready to learn. In the morning scramble to get out the door on time, your children may skip breakfast or leave homework behind. The day gets off to a much better start if they pack their backpacks the night before, get plenty of rest and have a good breakfast.
2. Make time for homework. Set up a study area with good lighting and a dictionary, and limit television on weeknights to be certain homework gets done. Make reading an everyday habit. Children who have "no homework" can always review the day's lessons or read a book for fun.
You may also need to curtail extracurricular activities and, as your children grow older, limit part-time jobs. Children who take part in other nonacademic activities for 20 or more hours per week usually don't have enough energy to perform optimally in school.
3. Monitor your children's academic progress. Don't wait until report cards come out to check up on how your children are doing. Attend scheduled parent-teacher conferences to get acquainted with their teachers, and don't hesitate to contact teachers at other times to find out whether your children are keeping up with assignments.
4. When there's a problem, work with the school on your child's behalf. If your child starts to slip academically, make an appointment with the teacher to put together a plan for correcting the problem. Teachers appreciate parents who reinforce the importance of schoolwork, and your child will have a better chance of succeeding if you and the teacher agree on a strategy.
If your child has difficulties with a teacher, try to keep an open mind and find out all the facts before jumping to conclusions. It's always best to try to work out differences with teachers before going over their heads and complaining to the principal.
5. Attend school functions. Going to back-to-school night, the spring concert, school plays, talent shows and other school events shows your children that you value their schools. In a 10-year study of 20,000 teenagers, Laurence Steinberg found that only one-fifth of parents regularly attended school functions, and that those who did were much more likely to have high-achieving students.
In addition to communicating to children that school is important, Steinberg writes in Beyond the Classroom, "Attending school functions may be even more important for the message it communicates to teachers and other school personnel. Teachers cannot help but pay closer attention to students whose parents they encounter at school programs, for both positive and negative reasons. On the positive side, the added attention stems from a sort of halo effect — Susie's parents are interested in her education, so Susie must be, too. But the attention also stems from the teacher's knowledge that Susie's parents are the sort of parents who are more likely to take action if something in Susie's education is not going right."
6. Volunteer at the school. In the early grades, some parents like to volunteer at school so they can observe how their children interact with other kids. As your children grow older, they may tell you they don't want to be seen in public with you, but they definitely get the message that school is important when they see you helping on school projects.
No matter what age your child is, there are many opportunities to help at school, whether it's in the classroom, library, computer lab or on the playground. Parents who spend their days at work or tending younger children can help in the evenings by making phone calls, drafting newsletters or writing letters on behalf of the school.
You can join the school's parent-teacher association or organization (PTA or PTO) or volunteer to assist an individual teacher. PTAs have evolved beyond bake sales and other fundraisers. Today's parents are using their professional skills to bring substantive improvements to schools, such as upgrading computer labs, landscaping school grounds and introducing academic enrichment programs.
7. Take a leadership role at school. There are plenty of opportunities for parents to become decision makers at schools. In addition to the PTA or PTO, you can offer to serve on the school site council, which oversees academic planning for the school, or on a district-wide committee or task force. Schools and districts often have committees related to curriculum, student health, after school programs, technology and more. Taking on a leadership role will give you a better appreciation of the complexities of education and will help you be a more informed advocate for your child's school.
8. Evaluate your school's performance. More and more data is becoming available to parents to help them understand how their schools are performing. On GreatSchools.org, you can find out test scores and lots of other facts. Depending on which state you live in, the data offered may include enrollment, teacher experience, the student-teacher ratio, socioeconomic status or the number of students per computer. You can also compare your children's schools to other schools using the Compare Schools tool.
9. Help your school improve. Once you know where your school stands, you can play a part in helping all children succeed. Parents around the U.S. are having a direct impact on school success by organizing after-school tutoring programs, bringing in speakers for parent education programs, starting academic enrichment workshops and introducing other school improvement projects.
To get inspired, you can read about other parents who have made changes at their schools.
10. Get involved in politics. When budget cuts are threatened and valuable programs may be cut, you can help your school by writing to your local and state legislators.
Another important responsibility is understanding education issues and candidates on the ballot. If parents in your community don't understand the ballot measures, host a pre-election coffee to pool everyone's knowledge or schedule a debate for school board candidates. Make sure your voter registration is current by calling your county elections office. And don't forget to vote!
Cooperman, Saul. How Schools Really Work: Practical Advice for Parents From an Insider (Catfeet Press, 1996): This book is packed with tips on assessing schools, teachers, principals, superintendents and school boards and ends with a chapter called "How to Take Control of Your Schools." The author has 40 years of experience as a teacher, principal, superintendent and as the commissioner of education for the state of New Jersey.
Steinberg, Laurence. Beyond the Classroom: Why School Reform Has Failed and What Parents Need to Do ( Touchstone, 1996): Among Steinberg's findings during a 10-year study of 20,000 teens are that effective parents regularly attend school functions and teach their children to take responsibility for their own learning.
Sign up for our newsletter and we'll send you more
insights to help you help your child succeed.
Thank you! You will begin to receive newsletters from us shortly.
Great work! Only one more step. Now we just need you to verify your email address. Please click on the link in the email we just sent you to complete your registration.
Great work! Only one more step. Now we just need you to verify your email address. Please click on the link in the email we just sent you to submit your review.
Please click on the link in the verification email we just sent you to complete your change of email address.
Whoops! It looks like we still need to verify your email. To do so, please click on the link in the email we sent you. Can't find the e-mail? Click the button below and we'll send you a new one.
Thanks for registering. Welcome to GreatSchools, the largest online community committed to improving educational outcomes through parental involvement.
Thanks for verifying your updated email address.
Oops! You haven't verified your email address yet. To do so, please click on the link in the email we sent you. Can't find the email? Click the button below to receive a new one.
Oops! That email verification link has expired. Please click the button below to receive a new one.
Create an account to submit your answers.
Sign in with an existing GreatSchools account or using Facebook:
Your review has been posted to GreatSchools.
Share with friends! Post your opinion of on Facebook.
Welcome to GreatSchools!
For principals and school officials, we offer a special Enhanced School Profile (ESP) which allows you to update and add information about your school, as well as respond to reviews. If you are a school official, click Continue to start.
Please note that it can take up to 48 hours for your comment to be posted to our site. While you're here, we'd like to invite you to fill out a survey on your school's programs, activities, and extracurriculars. It only takes a few minutes and will help parents get a full picture of your school.
Continue to compare the schools you have already selected or Edit schools to change your selection.
Get started now! You have successfully registered and can now start updating your Official School Profile. The information you provide is extremely valuable in helping parents and students learn more about your school, so thanks for taking the time!
Thank you for registering as a school leader. We just need to verify your email address. We've sent you an email - please click on the link in that message to get started editing your school's information!
Thanks! We just sent you an email – please click on the link in the email to post your answers.
Get timely updates for , including performance data and recently posted user reviews.


text:
Anyone else here who can't pass up a good deal on Patriots stuff? Sometimes I think I'm addicted to it. I've got several jackets, fleece, gloves, hats, etc., etc. I need to stay off eBay -- tons of cheap new stuff there.
Thanks for reminding me. I decided to look around and just bought this fleece jacket For 22 bucks. Turns out I had a $12 balance on my Paypal account for something I sold and forgot about. So I'll have a nice new fleece jacket to wear to work for only 10 bucks. Oh yeah free shipping too. What a deal. :singing:


text:
"The Smithsonian Bird," a prehistoric porphyry granite birdstone that is considered the finest discovered thus far could sell for as much as $600,000 in a June 23, 2012 auction hosted by Dan Ripley. Its name is derived from the fact that it was once part of the permanent collection at the Smithsonian's National Museum of the American Indian in Washington, D.C. Read More +
Tag Archives: native american artifacts
Historic Pancho Villa saddle sets new auction record at $750K
Mexican revolutionary hero Pancho Villa's silver embroidered saddle – the last saddle he owned – sold for $750,000 at the High Noon Western Americana Auction Jan. 28, 2012, in Mesa, Ariz. Read More +
Butterfly bannerstone brings $245K in Native American artifact auction
INDIANAPOLIS, Ind. – Smashing auction records was the name of the game when Dan Ripley's Antique Helper Auctions offered Part I, approximately one quarter, of the Townsend collection of Native American artifacts for sale Dec. 3, 2011. Popeye birdstone. … Read More +
Auction offering impressive prehistoric Native American artifact collection
According to Artifact Consultant Larry Swann, the first auction session will feature approximately one quarter of Earl Townsend Jr.'s prestigious Native American artifact collection. Read More +


text:
Munster rd will be closed on the 25th and 31st of December-please note on the 26th and 1st of January we will be opening at the later time of 4pm
Fulham High Street will be closed on the 25th 26th 31st of December and the 1st of January open again on the 2nd of January at 10am
We are now delivering to SW15 while our new shop in Putney is under construction please call our Munster rd branch on 0207 384-1884 or order on line, Grazie
For the finest Italian food in London visit one of our Fulham Restaurants. Eat a meal at one of our restaurants to experience the best that Italy can offer. Whether its a Pizza from our hand built Pizza oven, one of our amazing pasta's or another of our tasty dishes you can be sure that you will want to come back again. We put our love, heart and soul in to our cooking and you can taste the difference.


text:
I wired me new temp controller to my old chest freezer and after figuring out why the dang thing kept tripping the breaker I had a question pop up. Nowhere in the literature could I find anything on the subject. The wiring did not appear to me to bypass the existing thermostat, so with that still in line of the wiring, what "temp" should it be set at? The freezer is a Gibson elite 8 that has a rotary style thermostat that goes from off to coldest with about 8 settings in between. I first attempted to just barely turn it on but it still froze solid. I set the temp controller to 64* with a high set point of 68* and a delay of 10 minutes. Anything else I should do??? Thank y'all for the help.
Generally the device should be turned to the MAX COOLING position. The reasoning is that you always want the device ready to turn on whenever the external controller turns it on. If it's turned down to far it might not kick on even when the external controller switches on. The Johnson is a bit hard to configure IMO, until you get a good understanding of how it works. There are 2 sets of jumpers. One switches it from HEAT mode to COOL mode. Obviously you want the COOL mode, so it know which direction the temperature is supposed to go when the setpoint or offset is reached. The other selects either CUT-IN or CUT-OFF. Cut-IN says that when the setpoint is reached, turn the relay on and start cooling (if you have it in cooling mode..) and keep cooling until the offset is reached. Cut-OFF says that when offset is reached, turn on the relay to start cooling until the Setpoint is reached. Remember that the cut mode matches the setpoint. So cut-in at the setpoint, or cut-off when the setpoint is reached. It sounds like it's not in cooling mode to me. Or the relay is defective.
Thanks Homer, I will try that.
Freezer operating temperatures are generally around 0 or less, so the factory control will probably always be calling for cooling if you're running the box in the 60's - but, yeah you might as well dial it to "MAX". Be aware also that if the freezer has a defrost timer (it probably does), eventually it's going to stop the compressor for a period of time even though your external controller is supplying power to the unit. After the defrost time period has elapsed it will then resume normal operation and cycle on the controller.