text:
PlantUML Editor, built using WPF and .NET 3.5, is an IDE for drawing UML diagrams using the amazing PlantUML tool. If you have used PlantUML before, you know you can code UML diagrams super fast without struggling with a designer environment. Especially those who use Visio to draw UML diagrams (God forbid!), you will be in heaven. This is a super fast way to get your diagrams up and ready for show. You can *write* UML diagrams in plain English, following a simple syntax and get diagrams generated on-the-fly.
This editor really saves time designing UML diagrams. I have to produce quick diagrams to convey ideas quickly to Architects, Designers and Developers everyday. So, I use this tool to write some quick diagrams at the speed of coding, and the diagrams get generated on the fly. Instead of writing a long mail explaining some complex operation or some business process in English, I can quickly write it in the editor in almost plain English, and get a nice looking activity/sequence diagram generated instantly. Making major changes is also as easy as doing search-replace and copy-pasting blocks here and there. You don't get such agility in any conventional mouse-based UML designers.
Here's a quick screencast of how it works:
First install GraphViz. Then create an environment variable named GRAPHVIZ_DOT that points to the location where GraphViz has stored the dot.exe. For example, C:\Program Files (x86)\Graphviz2.26.3\bin\dot.exe.
Graphviz is used by plantuml to render the diagrams.
Then you can just download the installer that I made and install it. It has plantuml Java jar embedded as well.
It's a single WPF project with some utility classes that you can reuse in your projects. The Utilities has a BackgroundWork class which is used to perform background tasks in WPF. It's more powerful than .NET's default BackgroundWorker component or Dispatcher because you can get more control over how the background tasks run, wait until all background work is finished, abort a work, etc. I will write about the BackgroundWork library separately.
The MainWindow.xaml is the main window that you see on screenshot. It hosts the left side file list and the right side welcome panel. The editor and the diagram image is in the DiagramViewControl.xaml that takes care of showing and editing of a particular diagram.
This is my second WPF app I ever made, so have mercy.
Let's look at the cool stuff to take out from the code.
You must be salivating to get your hands on the theme for this project. I was too. :) I must say I have taken a lot of inspiration (and code copy and paste) from the famous Family.Show project and tailored it to fit the need. Then I got the background image from some example of Expression Blend.
You should look at the Skins\Black\BlackResource.xaml to get an idea of how such custom themes are built. The amount of wisdom in this file is mind boggling.
The left side listbox shows a preview of content from the actual file and the generated diagram. First, you have to define a custom template for ListBox items:
<ListBox Grid.Row="1" Width="Auto" ItemContainerStyle="{DynamicResource ListBoxItemStyle1}" SelectionMode="Extended" Background="#64404040" ItemsSource="{StaticResource DesignTimeDiagramFiles}" x:Name="DiagramFileListBox" SelectedValuePath="DiagramFilePath" IsSynchronizedWithCurrentItem="True" HorizontalContentAlignment="Stretch" Foreground="Ivory" BorderBrush="{x:Null}" Margin="0,0,0,10" ScrollViewer.CanContentScroll="True" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" VerticalAlignment="Stretch" MouseDoubleClick="DiagramFileListBox_MouseDoubleClick" SelectionChanged="DiagramFileListBox_SelectionChanged" > <ListBox.ItemTemplate> <DataTemplate> <DataTemplate.Resources> </DataTemplate.Resources> <Border Padding="0,2,0,2" CornerRadius="2" x:Name="DiagramItem" HorizontalAlignment="Stretch" VerticalAlignment="Top"> <StackPanel> <WrapPanel HorizontalAlignment="Stretch" Margin="0,0,10,0"> <Image MaxWidth="64" MaxHeight="100" Source="{Binding Path=ImageFilePath, Converter={StaticResource uriToImageConverter}}" Margin="3, 5, 10, 0" VerticalAlignment="Top"></Image> <StackPanel> <TextBlock Text= "{Binding Path=DiagramFileNameOnly}" /> <TextBlock Foreground="White" TextWrapping="WrapWithOverflow" Text="{Binding Path=Preview}" TextTrimming="CharacterEllipsis" MaxHeight="100" ClipToBounds="True" VerticalAlignment="Top" /> </StackPanel> </WrapPanel> <Separator Foreground="Green" Opacity="0.5" /> </StackPanel> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Here the ListBox's ItemSource attribute is bound to a design time data source that I will talk about soon. Basically it is bound to a collection of DiagramFile class which holds information about a diagram file - the path, path to the diagram image, preview of the actual content, etc.
The Image is bound to the path of the diagram image. In order to preview the diagram, I had to create a custom converter. Otherwise the Image holds a lock on the image file and does not allow it to be changed. Here's the code of the converter:
public class UriToCachedImageConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value == null) return null; if (!string.IsNullOrEmpty(value.ToString())) { BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.UriSource = new Uri(value.ToString()); // OMAR: Trick #6 // Unless we use this option, the image file is locked and cannot be modified. // Looks like WPF holds read lock on the images. Very bad. bi.CacheOption = BitmapCacheOption.OnLoad; // Unless we use this option, an image cannot be refrehsed. It loads from // cache. Looks like WPF caches every image it loads in memory. Very bad. bi.CreateOptions = BitmapCreateOptions.IgnoreImageCache; try { bi.EndInit(); return bi; } catch { return default(BitmapImage); } } return null; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException("Two way conversion is not supported."); } }
It solves two problems. First, it does not hold a lock on the file so that the file can be changed while you edit the diagram. Secondly, it looks like WPF has some kind of internal cache and it holds the image in the cache. You cannot refresh the image and make it load from source. So, you have to do the BitmapCreateOptions.IgnoreImageCache trick to make it work.
On the code behind, the grid is loaded in a background thread when the application starts. Also when you change the path in the top-left corner location box, the grid is refreshed. It looks for all the text files in the given folder and checks if any of the text files is in plantuml format. If it is, then it loads it in the list.
private void LoadDiagramFiles(string path, Action loaded) { _DiagramFiles.Clear(); this.StartProgress("Loading diagrams..."); BackgroundWork.DoWork<list><diagramfile>>( () => { var diagrams = new List<diagramfile>(); foreach (string file in Directory.GetFiles(path)) { string content = File.ReadAllText(file); if (content.Length > 0) { string firstLine = content.Substring(0, content.IndexOf(Environment.NewLine[0])); if (firstLine.StartsWith("@startuml")) { string imageFileName = firstLine.Substring (content.IndexOf(' ') + 1) .TrimStart('"').TrimEnd('"'); diagrams.Add(new DiagramFile{ Content = content, DiagramFilePath = file, ImageFilePath = System.IO.Path.IsPathRooted(imageFileName) ? System.IO.Path.GetFullPath(imageFileName) : System.IO.Path.GetFullPath( System.IO.Path.Combine (path, imageFileName)) }); } } } return diagrams; }, (diagrams) => { this._DiagramFiles = new ObservableCollection<diagramfile>(diagrams); this.DiagramFileListBox.ItemsSource = this._DiagramFiles; this.StopProgress("Diagrams loaded."); loaded(); }, (exception) => { MessageBox.Show(this, exception.Message, "Error loading files", MessageBoxButton.OK, MessageBoxImage.Error); this.StopProgress(exception.Message); }); }
Here you will see one use of my BackgroundWork class. I am using it to load the files from the given path in a separate thread so the UI remains responsive. The first callback is for doing the work on a separate thread. Here I am building a new collection of diagram files. I cannot change the existing collection which is already bound to the ListBox because that would trigger an update on the ListBox and .NET would not allow that to happen from a seaprate thread. So, once the new collection is built, the second callback is fired which is the onSuccess callback. It executes on the UI thread and here I can re-bind the ListBox.
Here's the DiagramFile class which holds information about each diagram:
public class DiagramFile { public string DiagramFilePath { get; set; } public string ImageFilePath { get; set; } public string Content { get; set; } public string Preview { get { // Ignore first @startuml line and select non-empty lines return Content.Length > 100 ? Content.Substring(0, 100) : Content; } } public string DiagramFileNameOnly { get { return Path.GetFileName(this.DiagramFilePath); } } public string ImageFileNameOnly { get { return Path.GetFileName(this.ImageFilePath); } } public override bool Equals(object obj) { var diagram = obj as DiagramFile; return diagram.DiagramFilePath == this.DiagramFilePath; } public override int GetHashCode() { return this.DiagramFilePath.GetHashCode(); } }
It's a simple entity class to hold information about a plantuml formatted diagram. For example, a diagram in plantuml would look like this:
@startuml img/sequence_img014.png participant User User -> A: DoWork activate A A -> A: Internal call activate A A -> B: << createRequest >> activate B B --> A: RequestCreated deactivate B deactivate A A -> User: Done deactivate A @enduml
When you render it using plantuml, it looks like this:
Now this is loaded at run time. How does the design time environment show realistic data in the ListBox?
In WPF, you have to create a ObservableCollection<YourClass> and then create a StaticResource out of it to show the result of binding at design time. For example, here I am showing the result of binding diagrams to the ListBox and the tabs:
Here's how you do it. First create an ObservableCollection out of your entity class and in the constructor, populate it with dummy data.
public class DiagramFiles : ObservableCollection<DiagramFile> { public DiagramFiles() { this.Add(new DiagramFile() { Content = @"@startuml cpe.png actor EndUser participant SaaS participant CPE . . . @enduml", DiagramFilePath = "test.txt", ImageFilePath = "http://plantuml.sourceforge.net/img/sequence_img009.png" }); this.Add(new DiagramFile() { Content = @"@startuml btconnectjourney.png actor User participant AOOJ participant SaaS participant DnP . . . @enduml", DiagramFilePath = "test2.txt", ImageFilePath = "http://plantuml.sourceforge.net/img/activity_img06.png" }); } }
Then you build it and you need to create a static resource for it. First you need to add a namespace reference inside the <Window> decalaration.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" x:Class="PlantUmlEditor.MainWindow" xmlns:plantuml="clr-namespace:PlantUmlEditor" xmlns:DesignTimeData="clr-namespace:PlantUmlEditor.DesignTimeData"
Then inside the ResourceDictionary of the Window, you create a tag to declare a static resource:
<Window.Resources> <ResourceDictionary> <DesignTimeData:DiagramFiles x:Key="DesignTimeDiagramFiles" />
That's it. You can then bind ItemSource attribute of controls to this static resource.
You might have noticed that when you go into editing mode by clicking on the diagram text box, the left column smoothly collapses to give you more editing space. You can do this by using a custom animation to reduce the width of the left column.
First name the column so that you can refer to it from animation:
<Grid.ColumnDefinitions> <ColumnDefinition Width="300" x:Name="LeftColumn" /> <ColumnDefinition Width="Auto" MinWidth="10" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>
Then create two Storyboards, one for collapsing and one for expanding. You will have to create a custom animation here because by default there's no animation class available to animate a Grid's Width or Height property which are of GridLength data type. I have used the great example from this article, which saved a lot of time.
Here's how the animation class looks like:
// Source: http://www.codeproject.com/KB/WPF/GridLengthAnimation.aspx using System; using System.Collections.Generic; using System.Text; using System.Windows.Media.Animation; using System.Windows; using System.Diagnostics; namespace PlantUmlEditor.CustomAnimation { internal class GridLengthAnimation : AnimationTimeline { static GridLengthAnimation() { FromProperty = DependencyProperty.Register("From", typeof(GridLength), typeof(GridLengthAnimation)); ToProperty = DependencyProperty.Register("To", typeof(GridLength), typeof(GridLengthAnimation)); } public override Type TargetPropertyType { get { return typeof(GridLength); } } protected override System.Windows.Freezable CreateInstanceCore() { return new GridLengthAnimation(); } public static readonly DependencyProperty FromProperty; public GridLength From { get { return (GridLength)GetValue(GridLengthAnimation.FromProperty); } set { SetValue(GridLengthAnimation.FromProperty, value); } } public static readonly DependencyProperty ToProperty; public GridLength To { get { return (GridLength)GetValue(GridLengthAnimation.ToProperty); } set { SetValue(GridLengthAnimation.ToProperty, value); } } public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) { double fromVal = ((GridLength)GetValue (GridLengthAnimation.FromProperty)).Value; double toVal = ((GridLength)GetValue(GridLengthAnimation.ToProperty)).Value; if (fromVal > toVal) { return new GridLength((1 - animationClock.CurrentProgress.Value) * (fromVal - toVal) + toVal, GridUnitType.Pixel); } else return new GridLength(animationClock.CurrentProgress.Value * (toVal - fromVal) + fromVal, GridUnitType.Pixel); } } }
Once the class is compiled, add a reference to the namespace inside <Window> tag and then you can use it inside storyboards.
<Storyboard x:Key="CollapseTheDiagramListBox"> <customAnimation:GridLengthAnimation Storyboard.TargetProperty="Width" Storyboard.TargetName="LeftColumn" From="{Binding Path=Width, ElementName=LeftColumn}" To="120" Duration="0:0:0.5" AutoReverse="False" AccelerationRatio="0.8"/> </Storyboard> <Storyboard x:Key="ExpandTheDiagramListBox" > <customAnimation:GridLengthAnimation Storyboard.TargetProperty="Width" Storyboard.TargetName="LeftColumn" From="{Binding Path=Width, ElementName=LeftColumn}" Duration="0:0:0.5" AutoReverse="False" AccelerationRatio="0.8"/> </Storyboard>
These animations are triggered from the code. Whenever you click on the editor text box, the GotFocus event gets fired on the usercontrol that wraps the text box. On the event, I start the animation. Similarly when you leave the editing environment and click on the ListBox, the LostFocus event is fired and I run the Expand animation.
private void DiagramView_GotFocus(object sender, RoutedEventArgs e) { if (this.LeftColumn.ActualWidth > this.LeftColumnLastWidthBeforeAnimation.Value) this.LeftColumnLastWidthBeforeAnimation = new GridLength(this.LeftColumn.ActualWidth); ((Storyboard)this.Resources["CollapseTheDiagramListBox"]).Begin(this, true); } private void DiagramView_LostFocus(object sender, RoutedEventArgs e) { var storyboard = ((Storyboard)this.Resources["ExpandTheDiagramListBox"]); (storyboard.Children[0] as GridLengthAnimation).To = this.LeftColumnLastWidthBeforeAnimation; storyboard.Begin(this, true); }
As you see, it's not straightforward. When the column is collapsed, you need to remember the Width of the column before you start collapsing, so that you can restore it to its original width when it is expanded.
The default tabs in WPF are so uncool. As soon as you put the TabControl on your form, your hard effort in making amazing UI goes to the drain. So, I have customized the appearance of the tabs using custom templates.
<Style TargetType="{x:Type TabItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabItem}"> <Grid> <Border Name="Border" Background="Gray" BorderBrush="Black" BorderThickness="1,1,1,1" CornerRadius="6,6,0,0" > <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2"/> </Border> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="Border" Property="Background" Value="black" /> <Setter Property="Foreground" Value="White" /> <Setter TargetName="Border" Property="BorderThickness" Value="4,4,4,1" /> </Trigger> <Trigger Property="IsSelected" Value="False"> <Setter TargetName="Border" Property="Background" Value="gray" /> <Setter Property="Foreground" Value="black" /> <Setter TargetName="Border" Property="Opacity" Value="0.4" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
Next, like the ListBox, the TabControl is bound to the same design time collection, so that you can see how the tabs look like on the design view. Inside the TabControl, the DiagramViewControl is hosted, which delivers the editing and preview features for a single diagram. The DataContext property of the DiagramViewControl is mapped to the SelectedItem property of the tabs so that it gets the active tab's associated DiagramFile object. So, if you change tab, the DataContext property of DiagramViewControl changes as well to show the correct tab's data.
<TabControl Grid.Column="2" Name="DiagramTabs" Background="{x:Null}" Visibility="Hidden" ItemsSource="{StaticResource DesignTimeDiagramFiles}"> <TabControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Path=DiagramFileNameOnly}" /> </DataTemplate> </TabControl.ItemTemplate> <TabControl.ContentTemplate> <DataTemplate> <plantuml:DiagramViewControl x:Name="DiagramView" DataContext="{Binding Path=SelectedItem, ElementName=DiagramTabs, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" OnAfterSave="DiagramViewControl_OnAfterSave" OnBeforeSave="DiagramViewControl_OnBeforeSave" OnClose="DiagramViewControl_OnClose" GotFocus="DiagramView_GotFocus" LostFocus="DiagramView_LostFocus"> </plantuml:DiagramViewControl> </DataTemplate> </TabControl.ContentTemplate> </TabControl>
Notice the two way binding. It's because any changes made inside the DiagramViewControl on the content is reflected to the associated DiagramFile object as well.
Now you will notice, when you double click a file on the ListBox, a new tab is created dynamically to show that particular diagram. At run time, the TabControl is attached to another ObservableCollection<DiagramFile> called OpenDiagrams. All you need to do is, add a DiagramFile object to this collection and a new tab pops up. Joy of data binding!
private void DiagramFileListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e) { var diagramFile = this.DiagramFileListBox.SelectedItem as DiagramFile; this.OpenDiagramFile(diagramFile); } private void OpenDiagramFile(DiagramFile diagramFile) { if (!_OpenDiagrams.Contains(diagramFile)) { _OpenDiagrams.Add(diagramFile); this.DiagramTabs.ItemsSource = _OpenDiagrams; this.DiagramTabs.Visibility = Visibility.Visible; this.WelcomePanel.Visibility = Visibility.Hidden; } this.DiagramTabs.SelectedItem = diagramFile; }
That's it!
The code editor uses the ICSharpCode.AvalonEdit control, mostly because it supports block indenting, which is not available in WPF's default text editors. Using this control is pretty straightforward. Add the reference to the DLL, declare the namespace inside <UserControl> tag and then use it like this:
<avalonEdit:TextEditor x:Name="ContentEditor" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontFamily="Consolas" FontSize="11pt" Background="Black" Foreground="LightYellow" Opacity="0.8" Text="" Padding="10" TextChanged="ContentEditor_TextChanged"> </avalonEdit:TextEditor>
That's it. The only caveat is it does not support binding the Text property to a string. So, I could not find it to the DiagramFile.Content property to show and reflect changes in the text. So, I did this from the DataContextChanged event of the UserControl, which gets fired whenever the DataContext is changed to some other object.
private void UserControl_DataContextChanged (object sender, DependencyPropertyChangedEventArgs e) { if (e.NewValue != null) { var newDiagram = (e.NewValue as DiagramFile); ContentEditor.Text = newDiagram.Content; ContentEditor.Tag = newDiagram.DiagramFilePath; } }
This keeps the DataContext of the text editor control in sync with the DataContext of the usercontrol.
You can use the Image control in WPF to show an image from a local file, from a URL or from a MemoryStream. The Image control is super powerful. It has complex transformation support. You can zoom, twist, transform images many ways. You can also bind the transformation to other WPF controls. For example, you can bind a Scaling transformation to a slider, so that when you slide the slider up and down, the image zooms in and out.
<Image.ContextMenu> <ContextMenu x:Name="ImageContextMenu" Style="{DynamicResource ContextMenuStyle}"> <MenuItem Style="{DynamicResource MenuItemStyle}" Header="Copy to Clipboard" Click="CopyToClipboard_Click"></MenuItem> <MenuItem Style="{DynamicResource MenuItemStyle}" Header="Open in explorer" Click="OpenInExplorer_Click"></MenuItem> </ContextMenu> </Image.ContextMenu> <Image.RenderTransform> <TransformGroup> <ScaleTransform ScaleX="{Binding ElementName=ZoomSlider, Path=Value}" ScaleY="{Binding ElementName=ZoomSlider, Path=Value}"/> </TransformGroup> </Image.RenderTransform> </Image>
Here you see, I have bound the ScaleTransform to the ZoomSlider control's value.
Whenever you save the diagram, it's generated again using plantuml and then the diagram image is refreshed. Since we have to use a custom value converter to bind the image to a path, we miss the auto refresh ability. The Image control no longer listens on the file for change. So, we have to force a refresh on the image using custom code:
BindingOperations.GetBindingExpression (DiagramImage, Image.SourceProperty).UpdateTarget();
However, doing this only does not refresh the Image. WPF has its internal cache where it remembers the images based on Uri. So, the custom value converter has to be changed to stop caching:
public class UriToCachedImageConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value == null) return null; if (!string.IsNullOrEmpty(value.ToString())) { BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.UriSource = new Uri(value.ToString()); // OMAR: Trick #6 // Unless we use this option, the image file is locked and cannot be modified. // Looks like WPF holds read lock on the images. Very bad. bi.CacheOption = BitmapCacheOption.OnLoad; // Unless we use this option, an image cannot be refrehsed. It loads from // cache. Looks like WPF caches every image it loads in memory. Very bad. bi.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
You can read the comments to understand the pain I went through and you won't have to go through it anymore.
Since it is a simple trick, but worth mentioning. You can right click on the image and select "Show in explorer" which would launch Windows Explorer where the image is already selected. You can immediately copy and paste the file or do any other file operations. This is done by this:
private void OpenInExplorer_Click(object sender, RoutedEventArgs e) { Process .Start("explorer.exe","/select," + this.CurrentDiagram.ImageFilePath) .Dispose(); }
Simple but handy feature.
When you keep typing on the code editor, it keeps refreshing the diagram every 10 seconds. This is where my BackgroundWork class comes handy. I can check if any background work is already running. If not, I can queue a work to happen after 10 seconds, in a separate thread.
private void ContentEditor_TextChanged(object sender, EventArgs e) { if (AutoRefreshCheckbox.IsChecked.Value) { if (!BackgroundWork.IsWorkQueued()) { BackgroundWork.DoWorkAfter(SaveAndRefreshDiagram, TimeSpan.FromSeconds( int.Parse(RefreshSecondsTextBox.Text))); } } }
This prevents multiple diagram generation request from getting queued and running into race conditions.
The diagram is generated by running the plantuml command line program. It takes the path of a diagram text file and generates the diagram image specified inside the diagram text file.
BackgroundWork.WaitForAllWork(TimeSpan.FromSeconds(20)); BackgroundWork.DoWork( () => { // Save the diagram content File.WriteAllText(diagramFileName, content); // Use plantuml to generate the graph again using (var process = new Process()) { var startInfo = new ProcessStartInfo(); startInfo.FileName = plantUmlPath; startInfo.Arguments = "\"" + diagramFileName + "\""; startInfo.WindowStyle = ProcessWindowStyle.Hidden; // OMAR: Trick #5 startInfo.CreateNoWindow = true; // OMAR: Trick #5 process.StartInfo = startInfo; if (process.Start()) { process.WaitForExit(10000); } } }, () => { BindingOperations.GetBindingExpression (DiagramImage, Image.SourceProperty).UpdateTarget(); OnAfterSave(this.CurrentDiagram); }, (exception) => { OnAfterSave(this.CurrentDiagram); MessageBox.Show(Window.GetWindow(this), exception.Message, "Error running PlantUml", MessageBoxButton.OK, MessageBoxImage.Error); });
First it waits for all background work to complete. Then it starts running the planuml process in a separate thread. The program is run without any window so that it does not take the focus away from your code editor. When the diagram is successfully generated, the diagram image is refreshed.
I have used the fantastic JSmooth utility to create an EXE out of the plantuml jar. It has sophisticated JVM detection ability built-in. The EXE wrapper it creates detects the right JVM and then runs the jar.
You can embed the jar inside the generated EXE to create a single EXE file that automatically extracts and runs the jar.
There's a "Add" button which, when clicked, shows a context menu programmatically.
That's not it. It also remembers which submenu you clicked the last time and it automatically opens that submenu saving you one click. When you are on a use case diagram and adding use case elements, it's likely you will keep on adding use case items. Clicking on "use case" and then selecting an item from it is cumbersome. The intelligent context menu saves you from making that unnecessary click.
private void AddStuff_Click(object sender, RoutedEventArgs e) { // Trick: Open the context menu automatically whenever user // clicks the "Add" button AddContextMenu.IsOpen = true; // If user last added a particular diagram items, say Use case // item, then auto open the usecase menu so that user does not // have to click on use case again. Saves time when you are adding // a lot of items for the same diagram if (_LastMenuItemClicked != default(WeakReference<MenuItem>)) { MenuItem parentMenu = (_LastMenuItemClicked.Target.Parent as MenuItem); parentMenu.IsSubmenuOpen = true; } }
Here the context menu is programmatically opened by using IsOpen property. However, right after opening it, I am checking what was the last submenu item that was clicked and I open that automatically as well.
If you look at the XAML for the button, you would notice, there's no click handler. There are so many submenus and grand-child menus that it's hard to add a event handler from the markup.
<Button Style="{DynamicResource RedButtonStyle}" Height="Auto" x:Name="AddStuff" Width="Auto" Padding="20, 0, 20, 0" Click="AddStuff_Click" Content="_Add..." > <Button.ContextMenu> <ContextMenu x:Name="AddContextMenu" Style="{DynamicResource ContextMenuStyle}"> <MenuItem Style="{DynamicResource MenuItemStyle}" Header="Use Case"> <MenuItem Style="{DynamicResource MenuItemStyle}" Header="Actor"> <MenuItem.Tag> <![CDATA[ actor :Last actor: as Men << Human >> ]]> </MenuItem.Tag> </MenuItem>
Instead I programmatically traverse the menu hierarchy and add a click handler to it.
public DiagramViewControl() { InitializeComponent(); foreach (MenuItem topLevelMenu in AddContextMenu.Items) { foreach (MenuItem itemMenu in topLevelMenu.Items) { itemMenu.Click += new RoutedEventHandler(MenuItem_Click); } } }
Inside the menu click handler, I have set the LastMenuItemClicked variable to remember which menu item was last clicked.
private void MenuItem_Click(object sender, RoutedEventArgs e) { this._LastMenuItemClicked = e.Source as MenuItem; this.AddCode((e.Source as MenuItem).Tag as string); }
Now those who know me, you know very well that I am careful about strong refs and memory leaks. I would not do such nasty things like holding reference to an UI element in a private variable, or trying to access controls at parent scope from anonmous delegates. That's evil! So, I use strongly typed WeakReference<T> class to hold reference to UI elements and pass the weak refs to the delegates.
For example, you can see use of weak reference to anonymous delegates:
WeakReference<ListBox> listbox = this.DiagramFileListBox; this.LoadDiagramFiles(this.DiagramLocationTextBox.Text, () => { var diagramOnList = this._DiagramFiles.First (d => d.DiagramFilePath == diagramFileName); ListBox diagramListBox = listbox; diagramListBox.SelectedItem = diagramOnList; this.OpenDiagramFile(diagramOnList); });
I have a handy WeakReference<T> class at my disposal which supports implicit conversion to and from any class. It makes it easy to use the reference as if it can take any class and can become any class. As you see in the above code example, there's no cast to ListBox data type anywhere. It behaves almost like an implicit pointer.
So, here it is...
I have taken this from the great Damien's blog and made some enhancements to it:
using System; using System.Runtime.InteropServices; public class WeakReference<T> : IDisposable { private GCHandle handle; private bool trackResurrection; public WeakReference(T target) : this(target, false) { } public WeakReference(T target, bool trackResurrection) { this.trackResurrection = trackResurrection; this.Target = target; } ~WeakReference() { Dispose(); } public void Dispose() { handle.Free(); GC.SuppressFinalize(this); } public virtual bool IsAlive { get { return (handle.Target != null); } } public virtual bool TrackResurrection { get { return this.trackResurrection; } } public virtual T Target { get { object o = handle.Target; if ((o == null) || (!(o is T))) return default(T); else return (T)o; } set { handle = GCHandle.Alloc(value, this.trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak); } } public static implicit operator WeakReference<T>(T obj) { return new WeakReference<T>(obj); } public static implicit operator T(WeakReference<T> weakRef) { return weakRef.Target; } }
I have added the implicit operator conversions to make use of WeakReference<T> more convenient.
You must have noticed my clever use of Tag property? If not, then here it is again. I am storing the UML snippet inside the Tag of each menu item this way:
<MenuItem Style="{DynamicResource MenuItemStyle}" Header="Note beside usecase"> <MenuItem.Tag> <![CDATA[ note right of (Use)\r A note can also\r be on several lines\r end note ]]> </MenuItem.Tag> </MenuItem>
When a menu item is clicked, I can read the UML snippet from the Tag and then use it to inject into the code editor. I am using Clipboard to copy the UML snippet and then paste it inside the editor. This way, it preserves the indenting.
private void MenuItem_Click(object sender, RoutedEventArgs e) { this._LastMenuItemClicked = e.Source as MenuItem; this.AddCode((e.Source as MenuItem).Tag as string); } private void AddCode(string code) { ContentEditor.SelectionLength = 0; var formattedCode = code.Replace("\\r", Environment.NewLine) + Environment.NewLine + Environment.NewLine; Clipboard.SetText(formattedCode); ContentEditor.Paste(); this.SaveAndRefreshDiagram(); }
Anyone know a better way to do this?
What's a smart client without an auto updater? When you launch this app, it starts a background thread to check if there's any update submitted for this app. Now this application is uploaded into Google Code site. So, I need to check if there's a newer version of the installer file. I do this by making a Web Request to the download URL and check the Last-Modified response header. Then I compare it with the last modification date of the EXE running on your computer. If they are off by one day, then we have an update.
public static bool HasUpdate(string downloadUrl) { HttpWebRequest request = WebRequest.Create(downloadUrl) as HttpWebRequest; using (var response = request.GetResponse()) { var lastModifiedDate = default(DateTime); if (DateTime.TryParse(response.Headers["Last-Modified"], out lastModifiedDate)) { var path = System.Reflection.Assembly.GetExecutingAssembly().Location; var localFileDateTime = File.GetLastWriteTime(path); return (localFileDateTime < lastModifiedDate.AddDays(-1)); } } return false; }
When there's a new update available, the following function downloads the latest file and stores in a local file to run it.
public static void DownloadLatestUpdate(string downloadUrl, string localPath) { DownloadedLocation = localPath; using (WebClient client = new WebClient()) { client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler (client_DownloadFileCompleted); client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged); client.DownloadFileAsync(new Uri(downloadUrl), localPath); } }
The WebClient class has an asynchronous version of DownloadFile to download files in a separate thread and the notification of progress and download complete/cancel is given via the event handlers.
You will find this code in UpdateChecker which is a reusable class that you can use in your projects too. The way I use it from the MainWindow is:
// Check if there's a newer version of the app BackgroundWork.DoWork<bool>(() => { return UpdateChecker.HasUpdate(Settings.Default.DownloadUrl); }, (hasUpdate) => { if (hasUpdate) { if (MessageBox.Show(Window.GetWindow(me), "There's a newer version available. Do you want to download and install?", "New version available", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) { BackgroundWork.DoWork(() => { var tempPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Settings.Default.SetupExeName); UpdateChecker.DownloadLatestUpdate (Settings.Default.DownloadUrl, tempPath); }, () => { }, (x) => { MessageBox.Show(Window.GetWindow(me), "Download failed. When you run next time, it will try downloading again.", "Download failed", MessageBoxButton.OK, MessageBoxImage.Warning); }); } } }, (x) => { });
When the download is in progress, the DownloadProgressChanged event is fired and when the download completes/cancels, it fires the DownloadCompleted event. The completed event handler takes care of finishing the installation.
UpdateChecker.DownloadCompleted = new Action<AsyncCompletedEventArgs>((e) => { Dispatcher.BeginInvoke(new Action(() => { if (e.Cancelled || e.Error != default(Exception)) { MessageBox.Show(Window.GetWindow(me), "Download failed. When you run next time, it will try downloading again.", "Download failed", MessageBoxButton.OK, MessageBoxImage.Warning); } else { Process.Start(UpdateChecker.DownloadedLocation).Dispose(); this.Close(); } })); }); UpdateChecker.DownloadProgressChanged = new Action<DownloadProgressChangedEventArgs>((e) => { Dispatcher.BeginInvoke(new Action(() => { this.StartProgress("New version downloaded " + e.ProgressPercentage + "%"); })); });
When the download completes, it runs the installer and quits the application so that the installer can install the latest version over it.
Visual Studio still does not offer creating setup projects which produces a single EXE or MSI file which has a bootstrapper to detect .NET Framework version, download and install if needed and then run the real MSI. So, I had to use the famous dotnetInstaller. But getting it to detect .NET Framework 3.5 was a challenge. It does not come with built-in support. Moreover, creating a single EXE with self-extracting installer is not so straighforward. Here's my take.
First you have to add a custom component to your configuration file in order to get .NET Framework detected. The solution is given here.
Then you have to add an MSI component that points to the MSI file. But there's a trick to the file path.
You have to provide the path in this format. And you have to add an Embed File underneath the .msi component you added and set the path exactly like this:
Notice the targetfilepath is blank.
Then you need to create a folder, where you will copy the dotnetinstaller.exe file, the .msi file. Both of the files need to be in the same folder. And then make the project to prepare the single installer.
This editor really saves time designing UML diagrams. I have to produce quick diagrams to convey ideas quickly to Architects, Designers and Developers everyday. So, I use this tool to write some quick diagrams at the speed of coding, and the diagrams get generated on the fly. Instead of writing a long mail explaining some operations or some process in English, I can quickly write the text in the editor and get a nice looking activity/sequence diagram produced. Making major changes is also as easy as doing search replace and copy-pasting blocks here and there. You don't get such agility in any conventional mouse-based UML designers. Hope you find this tool useful and if you do, please spread the love.
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
+------------------------------------------+ |Error loading files | +------------------------------------------+ | | | \/ Length cannot be less than zero. | | /\ Parmeter name: length | | | | [ OK ] | | | +------------------------------------------+
Length cannot be less than zero. Parameter name: length
The process cannot access the file 'C:\pagefile.sys' because it is being used by another process.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith
As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
@startuml "Test UML.png" Alice -> Bob: Kjøp melk! Bob --> Alice: Jeg vil ikke kjøpe melk! Alice --> Bob: Does Norwegian characters work? ÆØÅæøå @enduml
General News Suggestion Question Bug Answer Joke Praise Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.


text:
You will visit the following 5 places:
San Francisco
San Francisco, officially the City and County of San Francisco, is the financial, cultural, and transportation center of the San Francisco Bay Area, a region of 7.5 million people which includes San Jose and Oakland. The only consolidated city-county in California, it encompasses a land area of about 46.9 square miles (121 km2) on the northern end of the San Francisco Peninsula, giving it a density of about 17,179 people per square mile (6,632 people per km2). It is the most densely settled large city (population greater than 200,000) in the state of California and the second-most densely populated large city in the United States after New York City. San Francisco is the fourth most populous city in California and the 13th most populous city in the United States, with a population of 805,235 as of the 2010 Census. The San Francisco-Oakland-Fremont metropolitan area has a population of 4,335,391.
Santa Barbara
Santa Barbara is the county seat of Santa Barbara County, California, United States. Located on an east-west trending section of coastline, the longest such section on the West Coast of the United States, the city lies between the steeply-rising Santa Ynez Mountains and the Pacific Ocean. Santa Barbara's climate is often described as Mediterranean, and the city is sometimes referred to as the "American Riviera." In addition to being a popular tourist and resort destination, the city economy includes a large service sector, education, technology, health care, finance, agriculture, manufacturing, and local government. In 2004, the service sector accounted for fully 35% of local employment. Education in particular is well represented, with five institutions of higher learning on the south coast (the University of California, Santa Barbara, Santa Barbara City College, Westmont College, Antioch University, and the Brooks Institute of Photography).
Victoria, capital of British Columbia, is located near the southern tip of Vancouver Island. With abundant parkland, it's known for outdoor activities. Named after Queen Victoria of the United Kingdom and, at the time, British North America, Victoria is one of the oldest cities in the Pacific Northwest, with British settlement beginning in 1843. Known as the "The Garden City", Victoria is also an attractive city and a popular tourism destination with a thriving technology sector that has risen to be its largest revenue-generating private industry.
Seattle is the northernmost major city in the contiguous United States, and the largest city in the Pacific Northwest and in the state of Washington. A seaport situated on a narrow isthmus between Puget Sound (an arm of the Pacific Ocean) and Lake Washington, about 100 miles (160 km) south of the Canada – United States border, it is named after Chief Sealth "Seattle", of the Duwamish and Suquamish native tribes. Seattle is the center of the Seattle–Tacoma–Bellevue metropolitan statistical area, the 15th largest in the United States, and the largest in the northwestern United States. Seattle is the county seat of King County and is the major economic, cultural and educational center in the region. The 2010 census found that Seattle is home to 630,320 residents within a metropolitan area of some 3.4 million inhabitants. The Port of Seattle and Seattle–Tacoma International Airport are major gateways to Asia, Alaska, and the rest of the world.

subset: commoncrawl


text:
According to story, the Ancient Greek philosopher Diogenes of Sinope rejected the customs and beliefs of his day, made a vow of poverty and took up residence in a large jar or barrel, where he subsisted on onions. Diogenes is also remembered for scorning Plato and for carrying a lantern in the daytime in a fruitless search for an honest man.
John Gray is something of a Diogenes, albeit without the barrel and the onions. His new book challenges what he sees as some of the most cherished beliefs of our times, asserting that humanism and faith in progress are facile and even dangerous. Gray scorns much of the Western tradition of thought stemming from Plato and Christianity which place their faith in reason or in redemption to overcome tragedy. In their place, he counsels "godless mysticism", a stance that has something in common with negative theology, Zen Buddhism or Taoism.
Gray's fans should find much here to please them. The range of literary, historical and philosophical extracts – from Conrad and Zweig to Borges and John Ashbery, and from Nietzsche and Freud to Robinson Jeffers and Czeslaw Milosz, to name only a few – is broad and deep. Gray's own utterances are by turns characteristically dark, audacious and outrageous. "If there is anything unique about the human animal," he writes, "it is that it has the ability to grow knowledge at an accelerating rate while being chronically incapable of learning from experience"; "The crisis today resembles that of the Thirties in this respect: it cannot be overcome by collective action"; "Health may be the natural condition of other species, but in humans it is sickness that is normal."
The riches also include fascinating passages from neglected classics such as Naples '44, Norman Lewis's account of the turmoil at the time of the Allied liberation of that city. There are historical nuggets such as the likely actual source (in Soviet collectivisation) of the equation "2 + 2 = 5" made infamous in George Orwell's 1984. And lyrical, visionary passages by some of the finest English nature writers of the mid-20th century are cited in support of Gray's low-comfort conclusion.
But despite its merits, The Silence of Animals is flawed and unsatisfactory: it both ignores too much and doesn't go far enough.
The book is divided into three sections. In the first and longest, Gray assembles instances to support his almost unremitting scepticism about the power of reason, and his pessimism about human affairs. His account is excessively narrow to the point of distortion.
No one would deny that the 20th century, especially its first half from which most of his material is drawn, is full of catastrophes; but Gray ignores too much, both then and since, that offers grounds for hope.
For a compelling view of the whole, see Steven Pinker's The Better Angels of Our Nature, a huge and carefully argued work that uses detailed historical analysis, ample statistics and close reasoning to make a case for a reduction in violence over time as people become better educated and create smarter systems and more effective institutions. History contains Gandhi and Martin Luther King as well as Stalin and Mao.
In the second section, Gray dwells on the tragic vision of Sigmund Freud, who, he says, "reformulated one of the central insights of religion: humans are cracked vessels". But Gray's direction of travel is summarised in a line from Wallace Stevens: "Beyond humanism and something else it might be possible to create an acceptable fiction," where fiction is taken to mean not falsehood but, as in the meaning of the Latin verb from which it is derived, making or forming: the fabrication of a new myth to live by.
The third section steps into that mythic territory. For Gray it is glimpsed in the moments of epiphany described by two great observers of and writers about the natural world: Llewelyn Powys, the youngest of three literary brothers whose short life was overshadowed by death from an early age, and JA Baker, whose vigil with peregrine falcons in his native Essex occasioned some of the most extraordinary nature writing of the 20th century.
It is in this final section that the title of this book comes into view. The silence of animals is not, says Gray, a literal silence, for many if not most sentient animals inhabit vivid sound worlds. It is, however, a world without the kinds of turmoil and torment that humans experience. Is he right about that? Clearly, animals often suffer even if the suffering is not mentalised to the degree it can be in humans.
Where Gray surely is on the right track is in drawing attention to the vibrancy of non-verbalised experience. Where he doesn't go far enough, however (at least in my view), is in being ready to celebrate the living world as a whole, and the many ways and levels in which humans can come to know it. But the most important shortcomings of this book are excessive scepticism about our potential to use reason to wise ends, and political quietism.
Mathematics and scientific laws do not and perhaps never will explain everything, but the explanations we construct with those symbols are a lot more than "a scattering of dust spread over a world that is beyond understanding". Without them we would never have experienced a deep field photograph taken by the Hubble telescope, in which a patch of sky the size of a grain of sand held at arm's length may show 10,000 galaxies, all containing billions of stars and quite possibly other life.
And when Gray writes of contemplation as "an activity that aims not to change the world or to understand it but simply to let it be", I disagree. Contemplation, truly lived, leads to compassion. We need to be mindful of our terrific capability to harm other humans and other life on this planet and, despite devastating and irreparable losses, organise to mitigate future harms, however poor the odds sometimes appear to be. Tragedy is not final because there are future generations to hope for. The possibilities of life, wedded to increasing knowledge, may be endless.
John Gray
Allen Lane, £16.99, 240pp
Read on
1 Straw Dogs by John Gray (2002).
2 The Better Angels of Our Nature by Steven Pinker (2011).
3 The Peregrine by JA Baker (1967).


text:
- Upper : 100% leather
- Lining: 100% leather
- Insole: 100% leather
- Outsole: 100% elastomer
- Heel height: between 4 and 4.5 cm
- Upper height: 11.5 cm
- Made in Portugal
- Delivered with a travel pouch in a 100% recyclable box
Put them on with a shoe horn to avoid treading down the backs or harming any embellishments, especially if the back has any sequins or embroidery.
Use a shoe tree or stuff newspaper into the toes when you are not wearing them to help keep their original shape.
If you have worn them out in the rain, let them air-dry away from any heat sources.
Machine-wash your laces regularly, using a washing net.
Leather advice
Whatever your shoes are made from, always start by removing the laces if they have any, and dusting with a clean cloth or brush. You can use a shoe tree or newspaper in the toes to help.
Be careful not to damage the embroidery, patches or sequins on your shoes when cleaning.
Smooth leather
Smooth leather does not need to be waterproofed.
To care for your smooth leather shoes, dust with a clean cloth or brush.
Clean with a sheer cleaning cream and a clean cloth using circular movements, then leave to dry for half an hour before buffing with a clean cloth.
We have retained the fur on this leather and printed it with an animal motif.
There is no need to waterproof ponyskin. It can be brushed clean and any marks removed with a damp cloth.
Suede is more fragile than smooth leather.
Waterproof your suede shoes before wearing them for the first time.
A suede brush or gentle regular brush can be used to remove any marks.
Velvet or satin
Velvet and satin are delciate materials that do not tolerate contact with rain or snow very well, so be sure to wear your velvet or satin shoes in dry weather only. You can also use a protective spray. Avoid machine washing as it will damage the soles.
Waterproof your sequinned shoes before you wear them for the first time.
Look after them by rubbing gently with a clean cloth or a brush, being careful not to damage the sequins.
Delivery is free for orders of €100 and over.
For orders under €100, below is the shipping cost per country:
Belgium, Luxembourg and Spain | €4.90 |
France | €7.90 |
Austria and Germany | €8.90 |
Switzerland | €20.00 |
Rest of Europe | €12.90 |
Any packages sent back because of an erroneous or incomplete delivery address will be sent back out at the customer's charge.
We accept returns within 15 days of delivery, with postage & packing at the customer's charge unless the items are defective or were sent in error. Once we have accepted your return, we will refund you within 15 days.
To find out more, click here.


text:
Bitdefender Total Security 2021 [3-PC, 2-YR]
Bitdefender Total Security 2021 is the company's full-strength, no-compromise security suite, a powerful mix of antivirus, firewall, browsing protection, parental controls, anti-theft system, file encryption and 2GB of secure online backup space. It's a long list of features, but don't be put off: the new release is all about convenience, and making them as easy to use as possible.
A revamped interface means common tasks (Quick Scan, Update, Safepay, Optimize) are now available with a single click, while other functions are accessible via three main tiles (Protection, Privacy, Tools). Even first-time users will quickly find what they need.
Bitdefender Safepay, the suite's secure browser, is now integrated with Wallet for safer online transactions. Better still, it can now automatically fill in user names, passwords and credit card details, too, often allowing you to pay online in a single step.
Bitdefender's Vulnerability Scanner not only finds missing patches on your PC, it now provides links to help you download and install them.
A new Activity Profiles feature sees the suite automatically optimise your system for different situations. Play a game and BitDefender enables the Game Profile, disabling unnecessary services and working to speed up your PC. The Movie Profile kicks in when you're watching a movie, optimising the suite's settings and enhancing visual effects. And if your battery is running low, the Battery Mode Profile optimises Total Security and Windows settings to save energy.
If you're still worried about performance, the Tuneup section (Tools > Tuneup) provides six new modules to help: Boot Optimizer, PC Clean-Up, Disk Defragmenter, Registry Cleaner, Registry Recovery and Duplicate Finder. Or, if exploring all those sounds too complicated, the new One-Click Optimizer will clean up your PC all on its own.
There are smaller improvements dotted around the suite: better reports, enhanced parental controls, and a more capable desktop widget, while the spam filter is now entirely cloud-based, improving accuracy and making it more responsive to the latest threats.
Bitdefender's real strength comes in the protection it provides, though. The independent labs typically give it very high marks, and as we write, AV-Comparatives' May 2014 Real-World Protection Test found Bitdefender's package blocked 100% of threats. Only Panda, out of 21 other entrants, could match them.
Note that this version includes a 3-PC, 2-Year license. You can use this license to activate three PCs for two years.
Technical Specification
Product: Bitdefender Total Security 2021 [3-PC, 2-YR]
Version: 2021
Manufacturer: Bitdefender
RSS Feed: http://feeds2.feedburner.com/uk/bitdefender-latestnews
Twitter : http://twitter.com/bitdefender
Languages: English, German, French, Dutch, Romanian, Portuguese, Italian, Spanish, Russian, Traditional Chinese, Arabic, Indian-English
Download Information
Installing Bitdefender Software
You cannot install a brand new security suite such as this Bitdefender product, unless you've removed your previous security suite, even in trial mode. You may need to the official removal tool for your previous security software to make sure it's fully removed from your system.
As an alternative download, you can install the 'offline' version of your Bitdefender software from the Bitdefender forum.
Uninstalling Bitdefender Software
You can uninstall your Bitdefender software using Add/Remove Programs in your Windows Control Panel.
If this fails for any reason, use the official Bitdefender Removal Tool to fully remove the security suite from your computer. Go to the official Removal Tool download page to download.


text:
NEW ORLEANS -- There are several ingredients that go into creating a championship football team. Good coaching, strong quarterback play and explosive playmakers have been essential elements of every recent Super Bowl-winning squad. This Baltimore Ravens team was rich in all three of those areas but there were two other ingredients that made them a special group: mental and physical toughness.
The Ravens battled through a tremendous amount of adversity during the regular season, playoffs and the Super Bowl itself. They battled numerous injuries to key players during the regular season, won difficult road contests over two future Hall of Fame quarterbacks during the postseason and survived a fierce comeback from the San Francisco 49ers in Super Bowl XLVII.
The Ravens' roster is littered with tough-minded players who enjoy playing a physical brand of football. Joe Flacco is one, but we'll get to him in a minute. Let's focus on two players who deserve special mention for their performances Sunday evening:
Anquan Boldin
The veteran wide receiver might be the NFL's most physical pass catcher. He overpowered defenders throughout the game, hauling in six balls for 104 yards and one touchdown. Boldin operated fearlessly in the middle of the 49ers' defense and he also was effective making plays on deep crossers. His arrival in Baltimore added toughness to the receiving corps that had been sorely lacking and it paid off in the form of a Super Bowl title.
Paul Kruger
The Ravens' defense is loaded with big-name superstars. However, it was the lesser-known Kruger who made some of the biggest plays on the Super Bowl stage. With Terrell Suggs' pass rush ability greatly limited due to injury, Kruger filled the void with two huge sacks of 49ers quarterback Colin Kaepernick. Kruger's explosive first step and effective hand usage gave right tackle Anthony Davis fits all game long. Kruger is set to be a free agent and he drove up the price tag with his performance in Super Bowl XLVII.
And about that Joe guy...
Flacco capped off an incredible postseason run with an MVP performance in Super Bowl XLVII. While watching this game, there were three aspects of the Baltimore Ravens quarterback's play that continued to stand out:
Poise. Flacco looked very comfortable all night long. Offensive coordinator Jim Caldwell did an excellent job of dialing up an easy throw to start the game and that helped quickly get Flacco into a rhythm. He never looked frazzled and he quickly managed his way through his progressions to find the open receiver. He didn't force balls into coverage but he also didn't refrain from taking shots down the field.
Pocket movement. We heard all week about the athleticism of San Francisco 49ers quarterback Colin Kaepernick. That was well-deserved praise but we might have short-changed Flacco's mobility. Flacco didn't pop any long runs but he did put on a clinic on how to successfully navigate his way around pressure. He avoided three potential first-half sacks by bailing out of the pocket and he successfully climbed up in the pocket to connect on a 56-yard touchdown toss to Jacoby Jones. That play was eerily similar to the tying touchdown pass late in the playoff game against the Broncos.
Play-making. Every time a play needed to be made, Flacco delivered. He set the tone with his touchdown strike to Anquan Boldin during the Ravens' first drive and he produced two scoring drives (two field goals) in the fourth quarter as the game was beginning to slip away from the Ravens. One key to the game was the third-down disparity. Thanks to Flacco, the Ravens were 9-of-16 while the 49ers converted just twice in nine chances.
Follow Daniel Jeremiah on Twitter @MoveTheSticks


text:
photograph by Christine Chitnis
For the last few months, I've enjoyed working with Squam Art Workshops on a special limited edition offering for their store this summer. We came up with the Sweet Forest Sachet sets...
Each sachet has an original painting of my feather trees printed onto kona cotton fabric on one side and soft and nubby burlap on the other along with an inpiring word hand stamped onto a muslin patch. They are filled with balsam pine that I sourced from a lovely company in Maine. The pine is pesticide and chemical free. Each sachet measures just over 4x4 inches and can be ordered in sets of two or three. They are now available here.
Happy Summer!


text:
I'm picturing some poor schmuck at Microsoft accounts getting a bill for the Xbox One's launch event in NYC tonight in a few months' time, looking at it, then jumping straight out a window.
The company is going to ridiculous lengths tonight, not only taking over Times Square but doing stuff like having zombies shamble all over the Brooklyn Bridge, fancy sports cars racing through Manhattan and giving out green beanies.
Some of team Kotaku will be heading down to check it out; expect more coverage from them through the night.


text:
What makes places like Silicon Valley tick?
Can we replicate that magic in other places?
Discover the answers in this groundbreaking book that proposes a radical new theory to explain the phenomenon of innovation ecosystems—social networks that generate extraordinary creativity and output. The authors challenge basic assumptions that economists have held for over a century. The Rainforest will transform the way you think about technology, business, and leadership.
free preview
To read a free preview of the book, click here.
To learn about the ideas in The Rainforest, read the official White Paper presented at the University of Chicago for the book's publication on February 21, 2012.
What reviewers say about The Rainforest…


text:
Romain Jerome is probably best known for making watches out of the actual materials recovered from the sunken Titanic. Since 2004, this exotic watch brand has been offering unique and unmistakable timepieces that are both instantly recognizable and highly desirable. At its inception, the brand's founders developed the "Hole in One Golf Counter", a world-first in timepiece-based golf-score trackers. Following the tremendous success of this watch, the brand embarked on an entire collection which today includes TITANIC-DNA, MOON-DNA and EYJAFJALLAJOKULL-DNA, watches forged respectively from parts of the storied luxury ship, the moon and the active Icelandic volcano.
This watch is guaranteed 100% authentic, has original serial numbers and is shipped in factory-fresh,
brand new, unworn condition with all manufacturer documentation and packaging.
Package contains watch manufacturer's certificate of authenticity (if such certificate is applicable,
and provided by the manufacturer), tags, stickers, boxes, and user manuals.
We will gladly accept returns within 30 days of receipt of delivery. Watches must be returned to us in brand new, unworn and undamaged condition. All domestic purchases showing as "In Stock" under $3000 will receive a full refund minus shipping fees. A 10% restocking fee will apply on all other orders. Read more.
Gemnation ships your domestic order free via FedEx/UPS Insured Standard Delivery (3-5 days) after your order has been processed. Please read the additional information section next to the watch to determine processing times. Watches that cost less than $200, will be shipped via FedEx/UPS Ground. Read more.
We sell luxury timepieces at considerably lower prices than the manufacturers list price. Gemnation is not
an Authorized Romain Jerome Watch Dealer and is not affiliated with Romain Jerome. Authorized dealers are not permitted
to discount or sell watches on the Internet. For this reason, we choose not to be authorized watch dealers
for many of the brands that we sell.
Since we are not authorized dealers for many of the watch manufacturers, we may be unable to ship the original
watch manufacturers warranty. In all cases, however, we provide a Two Year Gemnation Warranty (active from the
date of purchase).
Gemnation utilizes a full-time Swiss-trained watchmaker who is licensed and trained to repair every brand and model of watch that we sell. If we can supply the original warranty we provide this information in the individual watch description. Read More.
Mon - Thur 10 a.m.- 5 p.m.
Fri 10 a.m.-1 p.m. (ET)


text:
During my research on my husband's family, it seemed as if the Sons of the Republic of Texas membership was quickly slipping through his hands. Everyone was from some place other than Texas, and I had yet to discover any evidence that his family arrived in Texas before the late 1800's, well past the Republic of Texas' time frame.
For those of you not familiar with the Republic of Texas, the Republic was an independent nation in North America, bordering the United States and Mexico between the years 1836 and 1846. It encompassed what is today Texas, as well as smaller parts of Oklahoma, New Mexico, Colorado, Wyoming and Kansas. In fact, then President Andrew Jackson even sent diplomatic agents to the Republic, thereby recognizing it as an independent and sovereign nation.
Map of the Republic of Texas, ca. 1836 |
Remember the Alamo? That battle, in which famous men such as Jim Bowie and Davy Crockett died at the hands of the Santa Anna and his Mexican Army, was fought right after Texas became a Republic (in fact, the Republic of Texas was officially declared on March 2, 1836, and the Alamo fell four days later).
Now, we've all seen the images from that famous John Wayne western, The Alamo, in which gloriously brave men fought the evil invading army, holding onto their new Republic until the bitter end. Who wouldn't want to be a part, at least through family history, of that event? I believe it is equal to the American Revolution for images of drama and glory and courage.
So imagine the surprise and jubilation when I did discover a family link to the Republic of Texas. Oh, happy day! Cautiously (and after many hours of shouting from the rooftops over this illustrious event) I double checked my research to ensure that I had not overstated my husband's connection.
My research appeared as if it was holding. And while my husband's connection to the Republic of Texas does not involve the Alamo, it seemed as if I was able to establish a connection nonetheless. My husband's fifth great-grandfather, Benoni Middleton, settled in Texas, dying there in 1842.
Benoni Middleton, originally named Benjamin Middleton, was probably born in Kentucky about 1776 (why he changed his name from "Benjamin" to "Benoni" is unknown; he may have been wanting something with a more international flair). Using a United States Land Grant for his service in the War of 1812, he and his family moved to Illinois around 1820, where he purchased 160 acres for $1.25 per acre in 1830.
Not all of Benoni's family moved to Texas with him. Many of his daughters had already married and stayed behind in Illinois. Hannah Elizabeth Middleton, identified as one of Benoni's daughter's, and my husband's 4th great-grandmother, did indeed stay in Crawford County, Illinois with her husband Ithra Brashear, dying there in 1846.
Around 1837, the opportunity to own more land, specifically 1,280 under a Republic of Texas Land Act, probably pushed Benoni and many of his family south, into what is today Leon County, Texas. There he settled with his wife and children near Fort Boggy. The Fort was established in 1840 by President Lamar and built by the Texas Rangers to protect the local white settlers from Kikapoo and Kichai Indian attacks. Benoni did not get to enjoy his new home for long as he died in January 1842, allegedly from an Indian attack.
Benoni's three sons, William, Thomas and Benoni, Jr. went on to participate in the Mier Expedition, in an effort to defend Texas from the invading Mexican Army. All three men were imprisoned by the Mexicans and sentenced to death by the Mexican dictator Antonio Lopez de Santa Anna. Deciding to make the idea of execution more interesting, Santa Anna instituted death-by-lottery. The prisoners selected beans out of a jar and those selecting black beans were blindfolded and shot. The three brothers were spared from death by the lottery and were taken to Mexico City as prisoners. William and Thomas eventually made it back to Texas, but Benoni, Jr. died in prison in Mexico City.
Now, as with many great stories, the ending is not one that ends in triumph, but in great tragedy and disappointment. I am not referring here to Benoni, Jr. dying in prison, but something that hits much closer to home. So eager was I to discover a Texas connection, that I didn't look as carefully as I should at the evidence. Oftentimes in the pursuit of an exciting connection in family history, we overlook details that should be the very first thing that we verify.
The birth date of Benoni and his alleged daughter, Hannah Elizabeth Middleton, who married Ithra Brashear, didn't add up. Benoni would have been 8 years old when Hannah was born, which, even back then, is nearly impossible to believe. The evidence points instead to Hannah being Benoni's sister, making Benoni Middleton my husband's 4th great-granduncle.
Obviously, I am disappointed with the outcome, but my husband can still be proud of the adventurous and courageous spirit that Benoni and his family had. And although my husband may never be a member of the Sons of the Republic of Texas, he may be assured that the same brave spirit that ran through their blood runs through his as well, just slightly more diluted.