Adobe Creative Cloud: Adobe Application Manager

image

 

Being a card carrying member of the To-The-Cloud camp, anything that uses the cloud gets my attention.

Creative Cloud is pure dead brilliant. Not to mention affordable. Its definitely the way forward for Adobe.

However, my gripe is with the Adobe Application Manager. As lofty as the name sounds, mission control a la Adobe its not. There definitely is room for more functionality.

Now, being on the far end of a bad broadband line, I rely on Download Managers more often than not. Being able to reliably pause and restart downloads is key when you’ve got to ration bandwidth.

Firstly: Do you see a pause button in that screen shot? Nope.  There is only a cancel button. When you’re 60% of the way through a multi-gigabyte download, that’s the last thing you want to do. So a way to a pause the downloads and restart would be nice.

Secondly, having two computers means I want CS6 installed on both of them. The Application Manager, as far as I can tell, does not cache the installer files at all. And I’ve really gone looking for them. So it requires a separate download on the laptop. This does not please me. Its a hassle. Its very un-user friendly. A fix would be nice – or at least THE OPTION of keeping the files.

If there is already a  cache – a link to it would be helpful.

There are basic features that are lacking. And its disappointing that they’re missing.

But looking at the application as a whole, it is Spartan – there is a certain lack of features. Yes I’m sure we’re supposed to use the website for all the other management tasks.

But, for example, installing language packs. Now this is not a problem for me. English is fine. Or even Pirate. But its a bit of a convoluted process switching language and getting it to download the correct language packs.

What about an auto uploader to the Creative Cloud storage? A Dropbox for Designers anyone? 

So a little love and attention would be nice to complete the experience.

I suppose the point to my little rant here is that as great as CS6 and Creative cloud are, the Application Manager is somewhat lacking in comparison.

Codeplex Projects of the Week.

Two Codeplex projects have come in quite handy for  me this week and I thought I’d pass them on.

 

WSUS 3.0 – WSUS Smart Approve

I installed Windows Server Update Services on my Windows Home Server 2011 this week.

As usual, I was in a bit over my head. I hit the Approve All Updates nuclear option. Knowledgeable sysadmins are possibly cringing or screaming at me (or both). By the time i figured out that approving updates puts them in the download queue, 4 and a half gigabytes were in the queue. Ordinarily this wouldn’t be a problem. But my broadband has had issues and it’s ridiculously slow (0.85 MBPS) and WSUS was eating up all the bandwidth.

So this was a problem. The solution was, of course to approve and download only needed updates. Amazingly, WSUS has no way of automatically approving needed updates (even as a checkbox buried five or six option screens down and off by default).

So, Codeplex to the rescue!

WSUS Smart Approve does exactly what it says on the tin – automatically approving updates according to certain rules. One of those is, of course, to approve needed updates automatically.

 

MetaWeblogAPI – ooMetaWeblog

One of the nice things about the MetaWeblogAPI is that almost everyone supports it. One of those is, of course, Windows Live Writer 2011.

Using Windows Live Writer as a WYSIWYG editor would be convenient.

There are a number of options to implement a server-side MetaWeblogAPI endpoint. Scott Hanselman has one approach.

I used another approach  – the Matlus.MetaWeblogAPI.

The corresponding Codeplex project is ooMetaWeblog.

 

Hope they come in helpful for somebody.

Why Silverlight Should Stay

Mary Jo Foley just published a post discussing the future of Silverlight.

I’m not a Silverlight Developer by any stretch of the imagination. I never played with it. Never touched it at all.

Then, for the Flying Shakes website,  I had to have the control below in a web form. Naturally I turned to Silverlight.

image

 

With no knowledge or experience of Silverlight it took me 90 minutes from idea to working control.

And yes, I realise that I could write a HTML5 version of that now. But it would probably take much, much longer (don’t nobody suggest Flash).

Silverlight is good, not just for rich client experiences it allows us to build, but also because its part and parcel of the tools we Visual Studio devs work with every day.

The flip side to this, of course is the user perspective.

Here in the UK we have Sky satellite television. The reason why I like them so much is that they are fairly technology friendly. Besides streaming on the go (iPad, iPhone, etc), you can log on to their Sky Go website to stream on-demand or download and watch on your desktop offline.

This experience is delivered by, wait for it, Silverlight. The impressive part of this whole thing was the Sky Go Desktop Client. Its an offline Silverlight application, popping straight out of the browser and installed silently.  Was downloading from my queue 10 seconds after hitting the download button.

Satisfied does not even begin to describe it.

I HTML 5 may be the bees knees, but there is still a business case for keeping Silverlight around.

I’ll consider HTML 5 a contender when we have the same level of support and tooling for it as we have now for Silverlight.

LINQ + Google Charts + MVC : Pie Chart

A couple of weeks ago, I pointed out a LINQ snippet that was running against the Google Charts API.

This week, I’m back with my implementation of  the Pie Chart.

I’ve started with the Pie chart because its relatively simple and will lay the foundation for dealing with the complexities of the other charts.

Building Blocks

Since this is MVC, I created a new ChartsService class in the Services namespace of the project.

If you look at the snippets in the original ACM article, you’ll notice an extension method called “SeparatedBy”. So our first task is to create this extension method.

There are, of course, a number of ways to concatenate a list of string with a separator. This being an exercise in LINQ, we are going to use the LINQ Aggregate method.

   
public static string SeparatedBy(this List<String> list, string seperator)
{ 
return list.Aggregate((current, next) => current + seperator + next); 
}

 

I’m sure that you’ll agree with me when i say that it’s a nice and clean approach to what could be a messy block of code.

However, that extension method will only concatenate the list of strings passed to it. Why is this a problem? Because we are going to want to concatenate lists of int objects as well. So that extension method will just not do. We  could do some fancy work with generics, but the simplest thing to do is to supply to an overloaded method that accepts lists of type int.

public static string SeparatedBy(this List<int> list, string seperator)

List<string> thelist = list.ConvertAll<string>(x => x.ToString());

 return thelist.Aggregate((current, next) => current + seperator + next); 
}

There is one additional difference between these and our original method – the call to ConvertAll. Rather than have a foreach loop that does the conversation, we simply supply an inline lambda function that gets executed against each item  in the list and returns a list of the desired type. Again, very clean.

 

So, armed with these extension methods, we can now declare our classes.

Data

Google charts offers a wide range of functionality and many different kinds of charts. Each chart has a host of differing options and settings available to it. So when creating classes to represting thse charts kinds we have to bear in mind that there will be unique functionality not common to other charts that will come up.

Charts logically are made up of a number of  smaller complements:  bar charts have columns, pie charts have slices and so on and so forth. So we’ll represent these first.


public class Slice
{
public int Value { get; private set; }
public string Legend { get; private set; }

public Slice(int value, string legend)
 this.Value = value;
this.Legend = legend;
}

} 

Lets first look at the Pie class itself now.

Pie Class


public List<Slice> Slices { get; set; }
public string Title { get; private set; 
public Double Height { get; private set; }
public Double Width { get; private set; }

public Pie(string title, double height, double width)
{
this.Slices = new List<Slice>();
this.Title = title;
this.Height = height;
this.Width= width;
}

We start by declaring a number of properties and a constructor. In the constructor we initialize our list of Slices. This is where we see a departure from the snippets of he ACM article.  We do not pass the slices into the constructor. Of course, this is an issue of style over substance. There is no reason why we could not have generated the slices before the creating the chart and then passed the slices.


public string Compile()
{
var tt = Title.Split(' ').ToList().SeparatedBy(' ');
var p = new List<string>(){
this.Slices.Select(slice =>slice.Legend).ToList().SeparatedBy("|"),
this.Slices.Select(slice =>slice.Value).ToList().SeparatedBy(",")};

return string.Format(@"http://chart.googleapis.com/chart?cht=p&chtt={0}&chs={3}x{4}&chl={1}&chd=t:{2}", tt, p.ElementAt(0), p.ElementAt(1), this.Width, this.Height)
}

This is where all the important stuff happens.

Line 3 properly formats the title by putting a + sign to signify spaces between words. Note that we are using the extension method we wrote earlier.

Line 4 creates a new list of strings, each string being the comma or | delimited list of values and legends. Using a List gives us greater flexibility later on when our implementation will handle multiple data series and legends

Line 8 uses String.Format to merge all this data into a url that we can use to call the Google Charts API with. For an explanation of what each of these parameters mean, see the Google Charts API Parameter List

 

ViewModel

Now, this being MVC, the way to display stuff is by using a ViewModel. So lets create one:


public class MonthlyReportsViewModel
{
public MonthlyReports Details { get; set; }
public Pie Chart { get; set; }
 }

The one property we are interested in here is the Chart Property.

Now that we have our ViewModel, we have to populate it. So, in our ActionResult method:


<pre>Pie chart = new Pie("This is my chart",200);
chart.Slices.Add(new Slice(25, “Slice 1”));
chart.Slices.Add(new Slice(25, “Slice 2”));
chart.Slices.Add(new Slice(25, “Slice 3”));
chart.Slices.Add(new Slice(25, “Slice 4”));
model.Chart = chart;
return View(model);

 

View

In our View itself, we’re going to have to render out the chart. Since the call to Google Charts API will return an image, we can simply do the following:


<img src = "@Model.Chart.Compile()" alt ="">

 

What one could do is to put the actual rendering code in a Helper Method and call the Helper Method from your view, like so:


@GoogleCharts.PieChart(@Model.Chart)

That, of course, further abstracts the code. It does have the advantage of being much cleaner and easier to do.

 

Conclusion

As you can see, using LINQ to abstract away the complexity of what your code is actually doing is not just the province of database code. One thing what I’ve enjoyed about working with LINQ is how code always comes out looking fresh, clean and crisp. Having worked extensively with LINQ and Lambda expressions, using foreach loops  to process Lists looks so much messier.

Next time, we’ll take a look at the somewhat more complicated Bar Chart. I’ll not cover every single possible piece of functionality, but I’ll cover the basics. All I want to show is how the foundation laid down today can easily translate over. My current implementation of bar charts is sufficient only for the limited functionality the app needs and nothing more. 

At some point in the future, I’d also like to implement Line charts.

 

Postscript

I must say that apart from working with LINQ, its been a very satisfying experience for me to implement a C# version of a web API.

There is GoogleChartsSharp on Codeplex that Implements a whole lot more of the functionality of Google Charts. I did indeed use it for a while before implementing it on my own.

So its been a satisfying experience for me to implement an API that allows me to work the way I want to work. Not only did I write something simpler and easier to work with, but I dropped a dependency in the process and that made me happier than I think its safe to admit. 

Writing against something requires you, the writer, to pay extra attention to the small details. It requires you to think of the relationship between your code,the web API  calls and the documentation that supports it. When one uses an already baked implementation such as GoogleChartSharp, its like working with a giant black box  you have no idea what goes on inside. And you really don’t want to know the finer details. But writing the API, you create a white box. And you HAVE to understand those finer details.

So while the LINQ is nothing special in and of itself,nothing earth shattering or ground-breaking, it is the experience and the satisfaction gained from it that makes this a worthwhile post to write.

The iPhone 4S: A Rose by any Other Name (a Response to Dan Gillour)

Dan Gilmour thinks Apple made a bit of a blunder by calling it the iPhone 4S rather than the iPhone 5 .

Sorry Dan, But I disagree completely.

On Google Plus I put the following argument forward:

I want to mention that Apple always thinks long term. They called it the 4S because:

  • Its convention – the minor versions (yes, this is minor, or we would have got a form factor change) always have a S appended to the name of the last major release.
  • Apple have something big on the horizon. They have big plans for the next major release of the iPhone. They want to reserve the "iPhone 5" name for that release.

The iPhone, the iPhone 3G and the iPhone 4 have all been major releases and have all sported form factor redesigns.

The iPhone 4S specs may seem to be major (in a parallel universe where all phone manufacturers but Apple went bankrupt in 2007), but they merely bring Apple to PARITY with Android.

The iPhone 5 is going to be the release that makes Android play some serious catchup.

Another important thing to note is that Apple would never every call it the iPhone 5 just because people want it to be the iPhone 5. I’m sure it was Steve Jobs himself who said something along the lines of “People don’t know what they want, they just think they do”, or words to that effect. People have no idea what they want out of an iPhone 5. People don’t know what they want until Apple shows it off to them and they go, “Yeah, I want that”.

Everyone is acting like Steve Jobs’ influence has gone. Nonsense. I think even Leo Laporte said yesterday that he got the impression that the reality distortion field was no longer there. What other company spends 53 minutes repeating what it announced at it’s last press conference and then spend half an hour on a new iPhone and Siri? Oh yeah, then announce as an after thought, “Yeah, we’re on Sprint”. That’s a Steve Jobs keynote if there ever was one,only without Steve. The only thing that changed was that we noticed it.

My bet is that’s it’s the same reason why Steve jobs wasn’t there: not major enough.

When there’s a One More Thing to announce, he’ll be there.

 

PS – Pardon the Shakespeare reference.

One of the things that makes Google+ so great

I’ve been thinking about this for a few weeks, and never really got a handle on how to articulate it.

Till today.

 

I was commenting on Scoble’s post. He says in the post  that importing tweets into Google+ is a very bad idea.

Now, apart from being very pleased that me and him see eye to eye on this, I commented:

Agree with you +Robert Scoble No tweets in here.
Keeping Google + free of imported stuff has encouraged/forced people to post original material rather than reuse from twitter, facebook, friendfeed, flickr, etc.
Its one of those things that make Google+ interesting and different from all the other social networks around. Its made google + a destination in and of itself, rather than simply a portal or an aggregator (like Friendfeed is)

 

This is part of, shall we say, a philosophy around which Google+ is built. A philosophy which, dare i say it, is socially engineering us.

 

For example, the fact that comments and posts are not limited to 140 characters and allow rich formatting actually encourages people to comment. And not just comment – to comment substantially.  That is why Google+ has such a great reputation (already) for interaction.

 

Google has taken a very different approach to the other social networks. It is attempting to fulfil a very different version of what a social network should be.

And so far, its succeeding.

WCF Chat Update: Long Polling

Updating WCF chat continues slowly but surely. I have not made any commits yet, so you’ll have to wait to see the changes.

In addition to the changes to Authentication, there are changes to the callback mechanism that I originally wrote.

 

When i originally wrote the chat application, the callback was one of the first pieces of code that i wrote. The fact of the matter is, the the only requirement for it was to work across the local network (or even simply between instances on the local machine). So when I wrote the Cloud version, suddenly callbacks had to work across NAT to let the application function across the internet.

 

Now, there are a number of possible design patterns that would allow the server to execute a callback on a remote client. 

 

The first is ,indeed, the design pattern we use at the moment. Where we actually have a callback. the enabler for this is actually found in WCF. The wsHTTPDuplexBinding allows for dual HTTP connections – one in each direction. This allows you to invoke an operation on the client. However, in order for this to work, you need to have an instance of WCF server on a per-instance basis. So. Every new client session will spawn a new instance of the server. This means that you are going to end up with dozens ( or hundreds etc) of long-lived instances. The question here is scalability. Is this scalable?

It might seem somewhat arrogant to talk about scalability, but if you design with scalability in mind, you’re not going to end up dealing with it later.

 

The other is something that, while not new, really hit the big-time after Friendfeed released its Tornado server. Tornado supports long polling http connections. Long polling is not in and of itself new. The basic design pattern involves a client making a call ( http or otherwise) to a server. The server receives the connection and keeps it open until it has something to return. Some long polled connections eventually time out and this is the implicit signal for the client to immediately open another connection. Others, such as the Friendfeed implementation, keep them open indefinitely.

 

There are probably more that you can think of, but these are the two that I considered for the Chat Application. As with most things, the choice is between a Push model (where notifications are pushed to the client) and the Pull model (where information, Notifications or otherwise, is pulled from the server by the client).

 

The fact of the matter is that I like both. Both are Cool. And both are supported intrinsically by WCF – no coding voodoo to make thins work.

Of the two, I’ve begun implementing the long polling method. Although it s radical departure, it will allow the overall design of to server-side to remain the same. The WCF server remains as a Single Instance service, and so the implementation remains the same.

The WCF stack is written in such a way that when you mark a OperationContract as needing the Async Pattern, WCF with start the Asyc operation and then go off and handle another request until that method returns. The End method that receives the results then returns the data to the client. In other words, its non-blocking.

I’ve not sorted out the exact specifics of implementation, but there will be changes to both the server and the client to accommodate  this. In saying that, I’m doing  a lot of simplification to the class structure. So hopefully what emerges from all these changes will be better than the current setup. Even I had to go back and follow the inheritance tree to figure things out.

These changes are happening in parallel with the changes to the authentication scheme.

 

So, while I’ve got no code, I leave you with this MSDN blog post on Async programming with WCF and this post that adapts it to long-polling specifically.

From the Department of MVC useful goodies (and sponsored by the department of Stackoverflow saved my butt)

I use the ipinfodb.com API in my app a lot to do geolocation. Well, as such things are wont to do, it went down for about an hour today. Curiously, the production site wasn’t affected at all, but my dev work was. So, in panic mode  I needed to add a country selector so that the rest of the site would have  the country information it needed. Now the reason there wasn’t one already was a deliberate design choice. So, i needed a backup plan for the next time ipinfodb went down.

As usual, Stackoverflow saved my butt (again). There’s a great answer that explains the way to do things in MVC using Razor.

Rather than steal the guys thunder, I’m just going to add one recommendation. In the body of the javascript function add the following:

location.reload();

And the page refreshes, including any changes triggered by the selection.

Go on and read the answer here.

Sitemaps in ASP.Net MVC: Icing on the Cake

This is short simple and sweet (forgive the pun).  The reason why i say that is that you have two options when doing a sitemap in MVC (actually, you have more, but whatever).

The first is using a Library. There’s a MVC Sitemap provider on Codeplex that you can download and install. It involves some XML configuration and attributes on all the actions you want to include in your sitemap.

The fact is, I don’t have time to fiddle around with configurations. I just want a simple sitemap file with a handful of products, categories and one or two other links. If the site was larger and more complex I might consider it.

So, we come to the second, DIY way. Now, this is not entirely my idea. I just repurposed it to pull the correct URL parameters out of the db. The original code is found on Codeplex.

Firstly, we have to register a new route to www.example.com/sitemap.xml. Go to Global.asax and put the following in your RegisterRoutes() method. I put mine after the call to IgnoreRoute.

routes.MapRoute("Sitemap", "sitemap.xml", new { controller = "Home", action = "Sitemap", id = UrlParameter.Optional });

Now, you can use any default routing you want with this. As you can see above, the route is pointing to the Sitemap action of the Home controller.

Then we have to actually populate our Action with some code.

  protected string GetUrl(object routeValues)
        {
            RouteValueDictionary values = new RouteValueDictionary(routeValues);
            RequestContext context = new RequestContext(HttpContext, RouteData);

            string url = RouteTable.Routes.GetVirtualPath(context, values).VirtualPath;

            return new Uri(Request.Url, url).AbsoluteUri;
        }
        [OutputCache (Duration=3600)]
        public ContentResult Sitemap()
        {
            var categories = storeDB.Categories.Include("Products").Where(g => g.Id != 8); //some filtering of categories
            XNamespace xmlns = "http://www.sitemaps.org/schemas/sitemap/0.9";
            XElement root = new XElement(xmlns + "urlset");

            List<string> urlList = new List<string>();
            urlList.Add(GetUrl(new { controller = "Home", action = "Index" }));
            urlList.Add(GetUrl(new { controller = "Home", action = "Terms" }));
            urlList.Add(GetUrl(new { controller = "Home", action = "ShippingFAQ" }));
            urlList.Add(GetUrl(new { controller = "Home", action = "Testimonials" }));
            foreach (var item in categories)
            {
                urlList.Add(string.Format("{0}?{1}={2}",GetUrl(new { controller = "Store", action = "BrowseProducts"}),"category",item.Name));

                foreach (var product in item.Products)
                {
                    urlList.Add(string.Format("{0}/{1}", GetUrl(new { controller = "Store", action = "ProductDetails" }), product.Id));
                }
            }

            foreach (var item in urlList)
            {
                root.Add(
                new XElement("url", 
                new XElement("loc", item), 
                new XElement("changefreq", "daily")));
            }

            using (MemoryStream ms = new MemoryStream())
            {
                using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8))
                {
                    root.Save(writer);
                }

                return Content(Encoding.UTF8.GetString(ms.ToArray()), "text/xml", Encoding.UTF8);
            }
        }

Essentially, we’re just outputting an xml file with the correct format and structure.  This gives us a file that looks like:

<?xml version="1.0" encoding="utf-8"?>

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

  <url xmlns="">

    <loc>http://localhost:26641/</loc>

    <changefreq>daily</changefreq>

  </url>

  <url xmlns="">

    <loc>http://localhost:26641/Home/Terms</loc>

    <changefreq>daily</changefreq>

  </url>

  <url xmlns="">

    <loc>http://localhost:26641/Home/ShippingFAQ</loc>

    <changefreq>daily</changefreq>

  </url>

You get the idea.

The above code is using Entity Framework 4.1, so you can replace the line that declares  “var categories” with whatever data source you have. And you’ll have to reformat the url strings to conform to your parameter format.

Now I’m not suggesting this for any large MVC deployment. The code could get rather messy.

 

But for something simple, it works like a dream.

Getting your News Manually Blows: A Reply

Last night Holden Page wrote a pretty good blog post entitled: Getting Your News Manually Blows (http://pagesaresocial.com/2011/04/05/getting-your-news-manually-blows/).

It was late, so I thought I’d reply now when I’m fully awake :).

Holden’s point was that when you use a service like my6thsense that auto-curates the news and presents this to you, it’s much easier than using Twitter (and by extension Google Reader etc) to get your news. Essentially, it’s easier to have the news pushed to you rather than to have to go off and pull it from various services.

Essentially, Holden is arguing for the curation model rather than e co sunroom model. This is infect something that I’ve noticed myself. There is consistent lack of content, even using Feedly and Twitter and Friendfeed to get my news.

Now I got an iPad about 2 months ago. And promptly installed Flipboard. I mention this because the experience is as important, if not more so, as the content in that experience. This rapidly warmed me to the iPad as a digital newspaper, complete with page turns and layout. Now it’s blatantly obvious, but the iPads ability to BECOME the app that’s running is a singular experience. As a dead tree newspaper reader, the fuss of a broadsheet just melts away on the iPad. Turning pages on a broadsheet can be a torturous experience. Flipboard showed me how that just melts away.

Thus I went off to seek actual newspaper apps to use.

Now before you groan and call newspapers dead tree media of the past, sit down and think about it. Newspapers were the my6thsense of the dead tree media (albeit it political persuasions, rivalries and narcissistic owners took thee place of algorithms). Decades worth of experience curating the news still produces some damn fine newspapers.

That’s a fact. Take the Times of London. I’ve been a Times Reader for years, even though it is a Tory paper. The iPad apps for the Times and the Sunday Times are incredibly good. They preserve the newspaper’s look and feel whilst incorporating video and some innovative layouts. I like it so much I signed up for the monthly subscription.

Here’s the scary bit: I open up The Times app and read it before I open up Feedly. No kidding. It’s curated news that covers a wide variety of topics succinctly. It’s quick and easy to browse through.

“Hang on a minute” I hear you say, “there’s no sharing or linking or liking or anything! It’s a Walled Garden”. And that’s the truly scary part: I don’t care.

Now i’m not at all suggesting that we abandon our feed readers and start reading digital newspapers. Quite the opposite. I’m saying that if we’re looking for sources of curated news, digital newspapers had better be one of those sources. Indeed, Feedly still gets used everyday. It’s invaluable to me. (Today, for example, the Falcon 9 Heavy story is nowhere to be found in The Times).

There other good newspaper app I found was the USA Today app. It’s nice and clean, with a simple interface that focusses on content. As a bonus, you can share articles to your hearts content. Plus, it’s US centric for the Americans among us 😉

I mentioned above that looking through my feeds for good content or through Twitter and Friendfeed was/is becoming a it of a chore. I’m finding more and more time where i’m looking at absolutely nothing. I probably need to subscribe to better feeds or better people. I probably need to reorganise my feeds to better layout content, and cull the boring ones. But here’s the thing, I don’t have the time to do all that.

As Apple would say, There’s an App For That!