<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Sagecraft Studios</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/" />
    <link rel="self" type="application/atom+xml" href="http://www.sagecraft-studios.com/atom.xml" />
    <id>tag:www.sagecraft-studios.com,2008-09-05://1</id>
    <updated>2009-01-13T18:00:32Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>

<entry>
    <title>Drupal Event Calendar using Date, Calendar, Views, and CCK</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2009/01/drupal-event-calendar-using-date-calendar-views-and-cck.html" />
    <id>tag:www.sagecraft-studios.com,2009://1.14</id>

    <published>2009-01-13T17:32:33Z</published>
    <updated>2009-01-13T18:00:32Z</updated>

    <summary><![CDATA[I&#8217;ll admit it: I am a Drupal newbie. We chose it for our CMS last year, but we haven&#8217;t really been using it as a CMS as much as a place to dump and view our internal key indicator reports.&nbsp;...]]></summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="Drupal" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="calendar" label="calendar" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="cms" label="CMS" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="date" label="date" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="drupal" label="drupal" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="event" label="event" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[<p>I&#8217;ll admit it: I am a Drupal newbie.  We chose it for our CMS last year, but we haven&#8217;t really been using it as a CMS as much as a place to dump and view our internal key indicator reports.&nbsp; But finally!  Ah, yes&#8230; we finally have a feature request that is actual content management - <em>an event calendar</em>.</p>

<p>Imagine my surprise when I go looking for an event calendar module and find nothing.  How could such a huge CMS not have a simple event calendar?  A big part of this misunderstanding was that I didn&#8217;t understand Drupal - at all.  I still don&#8217;t really, but figuring this feature out has helped a lot.</p>

<p>One thing to realize is that Drupal is a <strong>content</strong> management system.  So (eventually) it would make sense to create event <strong>content</strong> and display that content in a specific way.  I surprisingly couldn&#8217;t find much documentation on this, so below are the steps I took to get my event calendar up and running.  They&#8217;re kind of abbreviated, so just ask if you need any clarification.  Keep in mind this was a learning experience, so if you have any tips for me, I would like those as well. ;)</p>

<ol>
<li>## Install Modules
<ul>
<li>View</li>
<li>Date</li>
<li>CCK</li>
<li>Calendar</li>
<li><em>Don&#8217;t forget to give yourself permissions to administer these modules and enable them!</em></li>
</ul></li>
<li>## Create Calendar Event Content Type
<ol>
<li>Name: Event</li>
<li>Type: event</li>
<li>Title Field Label: Event</li>
<li>Body Field Label: Details</li>
<li>Do not promote to front page.</li>
<li>Save</li>
<li>Go to Manage Fields for Event in the content type list</li>
<li>Add a field called Date of type field<em>event</em>date with a textfield/popup calendar+repeat selector.  Configure it to be required and blank by default, have a reasonable format, and to hide the repeat options by default.</li>
<li>Add a field called Location of type field_event_location that is a single-row text field.  Configure it to be 100 chars long and required.</li>
</ol></li>
<li>## Set up A Calendar View
<ol>
<li>Go to Administer > Views</li>
<li>Enable the default calendar view and clone it.
<ul>
<li>View Name: a_calendar</li>
<li>View Description:  Calendar</li>
</ul></li>
<li>Change the title to &#8220;Whatever you want Calendar&#8221;</li>
<li>Change Arguments > Date: Date (Node: Updated date) to Content: Date (field_event_date value)  Scroll down a bit to see the checkboxes (under Date fields)</li>
<li>Add a sort criterion for Content: Date (field_event_date value)</li>
<li>Add a filter for Node: Type is one of Event</li>
<li>Click the Calendar page side-tab and change the path to &#8220;a_calendar&#8221;</li>
<li>Click the Calendar block side-tab and change the block settings admin to &#8220;A Calendar&#8221;</li>
<li>Save the view.</li>
<li>Navigate to ?q=a_calendar to make sure it is working.</li>
</ol></li>
<li>## Set up Roles
<ol>
<li>Add a new role called Calendar_User and add the following permissions:
<ul>
<li>Edit/view field_event_*</li>
<li>(Create | delete own | edit own) event content</li>
</ul></li>
<li>Give this role to whoever you want to create event entries.  (Let&#8217;s call them <em>eventries</em> for fun)</li>
</ol></li>
<li>## Add a link somewhere and enjoy!</li>
</ol>
]]>
        

    </content>
</entry>

<entry>
    <title>Google driving directions in C# - Update</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/11/google-driving-directions-in-c---update.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.13</id>

    <published>2008-11-19T16:22:24Z</published>
    <updated>2008-11-19T16:32:02Z</updated>

    <summary><![CDATA[I've updated my GDirections C# class to allow for easier access to the actual driving directions.&nbsp; The code file can be found here.&nbsp; As usual, you will need your own Google Maps API key, which you can get for free...]]></summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="C#" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="c" label="C#" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="dotnet" label="dotNET" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="googlemaps" label="Google Maps" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="howto" label="howto" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[I've updated my GDirections C# class to allow for easier access to the actual driving directions.&nbsp; The code file can be found <a href="http://www.sagecraft-studios.com/dotnet/gdirections.cs">here</a>.&nbsp; As usual, you will need your own Google Maps API key, which you can get for free at <a href="http://code.google.com/apis/maps/signup.html">http://code.google.com/apis/maps/signup.html</a>.&nbsp; You will also need <a href="http://james.newtonking.com/pages/json-net.aspx">JSON.NET</a> to parse the JSON response from Google's service.<br /><br />Example code:<br /><blockquote><br /></blockquote><tt><span style="font-size: 10pt;">GDirections directions = new
GDirections(startAddress, endAddress);</span></tt><span style="font-size: 10pt; font-family: &quot;Courier New&quot;;"><br />
<br />
<tt>if (directions.IsValid)</tt><br />
<tt>&nbsp;&nbsp;&nbsp; Response.Write(directions.RoutesHtml[0]);</tt><br />
<tt>else</tt><br />
<tt>&nbsp;&nbsp;&nbsp; Response.Write("Route not valid.");</tt></span><br /><br />]]>
        
    </content>
</entry>

<entry>
    <title>ASP.NET MVC beta upgrade guide for the absent-minded developer.</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/10/aspnet-mvc-beta-upgrade-guide-for-the-absent-minded-developer.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.12</id>

    <published>2008-10-22T15:16:35Z</published>
    <updated>2008-10-22T15:32:12Z</updated>

    <summary><![CDATA[I've been using ASP.NET MVC since preview 1, and have loved every bit of it.&nbsp; Between preview releases, none of my code broke -- even between 2 and 3...&nbsp; Wait that can't be right...So when the MVC beta dropped recently,...]]></summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="ASP.NET MVC" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="aspnetmvc" label="ASP.NET MVC" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[I've been using ASP.NET MVC since preview 1, and have loved every bit of it.&nbsp; Between preview releases, none of my code broke -- even between 2 and 3...&nbsp; Wait that can't be right...<br /><br />So when the MVC beta dropped recently, I went ahead and upgraded my three projects.&nbsp; Little did I know that when I was upgrading all of those other times, I was forgetting to update my assembly references!&nbsp; Big d'oh!&nbsp; I had been using preview 2 this whole time!<br /><br />Upgrading from preview 2 to the beta can be a bit of a pain, so here are some hints to make the process easier, if anyone out there actually needs to do this.<br /><br /><ul><li><b>Update your strongly typed ViewData references to use ViewData.Model </b>- This one is pretty self-explanitory.&nbsp; If you have strongly typed ViewData (by typing ViewData&lt;Foo&gt; in your codebehind) you need to reference ViewData.Model in your views now.</li><li><b>ViewData is now ViewDataDictionary </b>- If you have custom ViewData-derived classes, you should change them to inherit ViewDataDictionary.&nbsp; I just got rid of mine completely and created some ViewInfo classes to pack up all the common data I needed to send over that wasn't my model object.</li><li><b>RenderView("Page") is now return View("Page")</b> - Much, much nicer.&nbsp; Make sure you change those public voids to public ActionResults as well.&nbsp; Good work on this change!<br /></li><li><b>Default.aspx has a codebehind page now - </b>If you're getting blank pages, you probably want to update your Default.aspx that is included in the project template.&nbsp; Just create a new MVC beta project and you should have it ready to copy into your old project.</li><li><b>Update your Web.config file</b> - There are a few new entries:</li></ul>In compilation/assemblies: &lt;add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/&gt;<br />In pages/namespaces: &lt;add namespace="System.Web.Mvc.Html" /&gt;<br /><br />Happy coding!<br /><br />]]>
        
    </content>
</entry>

<entry>
    <title>Visual Studio 2008 problems.  Breakpoints and crashes.</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/10/visual-studio-2008-problems-breakpoints-and-crashes.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.11</id>

    <published>2008-10-14T16:14:21Z</published>
    <updated>2008-10-14T16:22:58Z</updated>

    <summary><![CDATA[For the past week or so I've been getting weird problems with Visual Studio 2008."Could not load breakpoint" - This was a mere nuisance really.&nbsp; Just a few error dialogs when I loaded our solution.Completely locks up when closing solution,...]]></summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="net" label=".NET" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="visualstudio" label="Visual Studio" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[For the past week or so I've been getting weird problems with Visual Studio 2008.<br /><br /><ul><li>"Could not load breakpoint" - This was a mere nuisance really.&nbsp; Just a few error dialogs when I loaded our solution.</li><li>Completely locks up when closing solution, does not save environment - This started happening a few weeks after the breakpoint issue.&nbsp; Amazingly annoying, since every time I load Visual Studio, I have to set the right startup project, set breakpoints, etc...</li><li>Closes without an error message when starting 2nd debug session - This is when I got annoyed enough to try to figure out what was happening.&nbsp; I was losing productivity having to reload and reset my environment every time I wanted to start a new debug session.</li></ul>Luckily, I found a solution rather quickly.&nbsp; I don't have the link anymore unfortunately, but all of these problems were fixed by deleting the .suo file in my solution folder.&nbsp; That kind of a fix should have been obvious to me, but I'm just happy to be back to 100% productivity. :)<br /> ]]>
        
    </content>
</entry>

<entry>
    <title>Really slick PHP/Ajax FTP batch upload script</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/09/really-slick-phpajax-ftp-batch-upload-script.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.8</id>

    <published>2008-09-11T01:43:20Z</published>
    <updated>2008-09-11T02:37:36Z</updated>

    <summary><![CDATA[I like to keep a pretty efficient development environment.&nbsp; I have several projects I manage at work, and I have these projects all to myself for the most part.&nbsp; Regardless of whether you are working in a huge IT consulting...]]></summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="code" label="code" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="enviroment" label="enviroment" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="jquery" label="jQuery" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="php" label="PHP" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[I like to keep a pretty efficient development environment.&nbsp; I have several projects I manage at work, and I have these projects all to myself for the most part.&nbsp; Regardless of whether you are working in a huge IT consulting firm or in a basement by yourself, it's a great idea to automate as many mundane processes as possible.<br /><br />One of the tasks that annoys me most is moving my code to our production web servers.&nbsp; It's a royal pain the ass to fire up SmartFTP/FileZilla/whatever, navigate your folders, connect, and so on, especially if you are frequently publishing.&nbsp; On top of this, manual FTP uploading can also be error prone.&nbsp; I'd like a nickel for every time I've overwritten production-specific config files with development copies.<br /><br />The easiest way I could think to publish changes is to simply push a freaking button.&nbsp; So, a month or two back I found a simply FTP upload script.&nbsp; The script (I can't remember where I got it) often worked, but once my projects started growing in size, it would often time out and only a portion of my code would make it up.&nbsp; I figured the best solution would be to write my upload script that cycled through my project files and used a remote script to upload them one by one rather than in one big session.&nbsp; Sure, it's slower, but hey, it works and all I ever have to do is click one freaking button.<br /><br />Below are the spoils of my endeavor and some commenting:<br /><br />Grab the code <a href="http://www.sagecraft-studios.com/2008/09/10/ftp_upload.zip">here</a>.<br /><a href="http://www.sagecraft-studios.com/2008/09/10/ftp_tools.php.txt"><br /></a>ftp_tools.php: Utility functions.&nbsp; Nothing to change here.&nbsp; echo_jsarray() recursively browses a directory and prints a Javascript object containing information about the files in it.<br />ftp_upload.php: The script that actually handles uploading a file passed to it.&nbsp; Here you want to change the $ACCOUNTS variable to hold the FTP login info for your various projects.&nbsp; Also change the $FTPADDR string to hold your server's address.<br />SampleProject.migrate.php: The script that handles uploading your files, one by one.&nbsp; There are some variables up at the top you'll want to change such as file exceptions and the directory you want to upload from.&nbsp; In UploadFile() you'll also want to define the account you want to use.<br /><br />Setup:&nbsp; On our production FTP server, I have an account for each project.&nbsp; The root directory of each of these accounts is the project's root folder.&nbsp; Thus, I simply upload to the root folder for every project.&nbsp; Dump all of these files into a folder on your test server or something, grab <a href="http://jquery.com/">jQuery</a> 1.2.6 (minified) and add it to the mix, and you should be good to go.<br /><br />It's a pretty rough, environment-specific way to do this, but it should be no problem to adapt to your own development environment.&nbsp; Bonus points: Figure out which files have been changed and which have not, and upload only the changed files.&nbsp; Add some error handling for when files fail to upload mid-stream. ]]>
        
    </content>
</entry>

<entry>
    <title>Making checkboxes always post a value in an HTTP request</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/09/making-checkboxes-always-post-a-value-in-an-http-request.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.7</id>

    <published>2008-09-07T17:46:15Z</published>
    <updated>2008-09-07T17:49:09Z</updated>

    <summary>I&apos;ve been working on an ASP.NET MVC project with a nice and fancy model layer. My models have a nice&apos;n&apos;friendly UpdateFrom(NameValueCollection) method to bind HTTP request parameters to an object. The only problem is that sometimes, I don&apos;t want to...</summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="ASP.NET MVC" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="aspnetmvc" label="ASP.NET MVC" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="code" label="code" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="dotnet" label="dotNET" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[<p>I've been working on an ASP.NET MVC project with a nice and fancy model layer.  My models have a nice'n'friendly UpdateFrom(NameValueCollection) method to bind HTTP request parameters to an object.  The only problem is that sometimes, I don't want to have every column on a form, and some of the related database columns should remain unchanged.</p>

<p>In HTML forms, this presents a problem: checkboxes that are unchecked don't post anything.  How am I to tell if a field has been left off the form or if a field is unchecked?  After some aimless wanderings on the inter-tubes, I found <a href="http://blog.stochasticbytes.com/2008/03/html-checkbox-that-submits-when.html" target="_blank">this article</a> which documents a solution for Rails.</p>

<p>It's pretty simple, so I figured I would take this idea and wrap it up in a server control.  We have a small set of server WebControls that play nice with the rest of our code, so it was just a matter of adding a few lines of code.  You could also wrap this up in a helper method like in the rails version.</p>

<pre>
CheckBox checkbox = new CheckBox();
checkbox.InputAttributes.Add("class", CssClass);
checkbox.InputAttributes.Add("id", (string.IsNullOrEmpty(ID) ? (FieldName + "CheckBox") : ID));
checkbox.InputAttributes.Add("value", "true");
checkbox.InputAttributes.Add("onclick", 
    "document.getElementById(\"" + FieldName + "TextBox\").value = this.checked.toString()");
checkbox.Checked = Checked;
checkbox.RenderControl(writer);

TextBox textbox = new TextBox();
textbox.Attributes.Add("style", "display: none;");
textbox.Attributes.Add("id", FieldName + "TextBox");
textbox.Attributes.Add("name", FieldName);
textbox.Text = Checked ? "true" : "false";
textbox.RenderControl(writer);
</pre>

<p>Now I can tell if a checkbox field is truly meant to either just not be there or is false.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Goodbye Typo, hello Movable Type!</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/09/goodbye-typo-hello-movable-type.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.6</id>

    <published>2008-09-07T17:20:28Z</published>
    <updated>2008-09-07T17:29:50Z</updated>

    <summary><![CDATA[I finally got tired of typo dying on me.&nbsp; Sometimes after making a post, the entire app would just blank out and return no html at all.&nbsp; The cache seemed to act really weird at times as well.So, after looking...]]></summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="blogosphere" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="blogs" label="blogs" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="movabletype" label="movabletype" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="software" label="software" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="typo" label="typo" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[I finally got tired of typo dying on me.&nbsp; Sometimes after making a post, the entire app would just blank out and return no html at all.&nbsp; The cache seemed to act really weird at times as well.<br />So, after looking around for some new software, I decided on movable type.&nbsp; Wordpress was another big alternative, but I had used it on my now-defunct guild site (Retaliation-Skullcrusher) and wanted something a little different.<br /><br />Movable Type is amazing so far.&nbsp; The preinstalled themes are great, the admin GUI is intuitive, and the whole thing seems rock solid.&nbsp; Setup was a breeze as well. (I used <a href="http://www.superxm.com/2007/08/movable-type-4-installation-step-by-step-with-screenshots.html">this walkthrough</a>)&nbsp; No qualms so far.<br /><br />Migrating from typo to Movable Type was fairly easy too.&nbsp; I lost all of my post dates and images, (my fault, though) but re-entering my post content was a breeze.&nbsp; I just went into my typo database, went through the contents table, and copy/pasted the markup.&nbsp; Make sure you choose the "Markdown" format in MT's format selector.<br /><br />Anyway, time to draw up a design comp and stick it on here.<br /> ]]>
        
    </content>
</entry>

<entry>
    <title>jQuery wizard form</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/09/jquery-wizard-form.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.5</id>

    <published>2008-09-07T02:06:41Z</published>
    <updated>2008-09-07T17:32:39Z</updated>

    <summary>One of my projects needed a wizard form. Being the jQuery fanboy that I am and given that I couldn&apos;t find any existing wizard form plugins for jQuery, I made my own! You can check it out here: http://plugins.jquery.com/project/WizardForm It&apos;s...</summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="javascript" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="code" label="code" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="design" label="design" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="jquery" label="jQuery" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[<p>One of my projects needed a wizard form.  Being the jQuery fanboy that I am and given that I couldn't find any existing wizard form plugins for jQuery, I made my own!  You can check it out here: <a href="http://plugins.jquery.com/project/WizardForm" target="_blank">http://plugins.jquery.com/project/WizardForm</a></p>

<p>It's not what I would consider finished, but it works if you need a quick form and don't mind dealing with my markup choices.  It behaves sort of like the jQuery tabs plugin, so if you have used that, you should be able to get started fairly quickly.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Where&apos;s the love for conditional comments?</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/09/wheres-the-love-for-conditional-comments.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.4</id>

    <published>2008-09-07T02:05:21Z</published>
    <updated>2008-09-07T17:34:59Z</updated>

    <summary>I hate trying to resolve CSS and Javascript conflicts between web browsers. What I hate even worse is going about it in an &quot;unclean&quot; way. Conditional comments for IE have been around a long time and I haven&apos;t really seen...</summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="CSS" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="css" label="CSS" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="design" label="design" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="howto" label="howto" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[<p>I hate trying to resolve CSS and Javascript conflicts between web browsers.  What I hate even worse is going about it in an "unclean" way.</p>

<p>Conditional comments for IE have been around a long time and I haven't really seen too many people (if any) using them for resolving style bugs.  Check out what I do on every web site I build.</p>

<pre>
&lt;link href="/public/css/style.css" rel="stylesheet" type="text/css" />
&lt;!--[if lte IE 7]>
    &lt;link rel="stylesheet" type="text/css" href="/public/css/style-ie.css" />
&lt;![endif]-->
&lt;!--[if lt IE 7]>
    &lt;link rel="stylesheet" type="text/css" href="/public/css/style-ie6.css" />
&lt;![endif]-->
</pre>

<p>Note that I normally don't bother with IE 5.5, but this could work for that as well.  With these CSS links in place, I can simply expect a normal, sane style sheet to be included on well-behaved browsers, a special style sheet for IE7, and an even more "special" style sheet for IE6.  Since these are declared in order of insanity, (from least to greatest) I can simply copy style declarations from my original style sheet, override whatever I need to, and keep everything squeaky clean.</p>

<p>There's my solution.  If anyone reading still uses CSS hacks, I would love to know why.  It may be something I just don't "get."</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Google driving directions in C#</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/09/google-driving-directions-in-c.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.3</id>

    <published>2008-09-07T02:02:23Z</published>
    <updated>2008-12-03T04:23:19Z</updated>

    <summary>ALERT! A better, more complete version of this code can be found here: http://www.sagecraft-studios.com/2008/11/google-driving-directions-in-c---update.html This is something I&apos;ve been wanting to figure out for a while. What I&apos;ll be demonstrating in this post is how to get driving directions, distances,...</summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="C#" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="code" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="c" label="C#" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="dotnet" label="dotNET" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="googlemaps" label="Google Maps" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="howto" label="howto" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[<p><strong>ALERT! A better, more complete version of this code can be found here: <a href="http://www.sagecraft-studios.com/2008/11/google-driving-directions-in-c---update.html">http://www.sagecraft-studios.com/2008/11/google-driving-directions-in-c---update.html</a></strong></p>

<p>This is something I've been wanting to figure out for a while.  What I'll be demonstrating in this post is how to get driving directions, distances, and trip durations from Google's mapping service... without using Javascript!  The demonstration code below is just that - a demonstration.  It is your job, dear reader, to make a friendly, accessible interface out of the underlying code.  </p>

<p><em>Note: As far as I can tell, this is undocumented.  If you're using this in a production environment, I would advise writing some unit tests in case URLs change, parameters change, etc...</em></p>

<p>You will need <a href="http://james.newtonking.com/pages/json-net.aspx" target="_blank">JSON.NET</a> referenced to deserialize the data sent from Google.</p>

<pre>
using Newtonsoft.Json;

namespace xxxx
{
    public class GDirections
    {
        private string _key = "xxxx";
        private string _output = "js";
        private string _requestFormat = "http://maps.google.com/maps/nav?key={0}&output={1}&q={2}";
        private Hashtable _data = new Hashtable();
</pre>

<p>Our underlying data.  Yes, you could certainly use a generic Dictionary rather than a Hashtable.  In the code above, make sure to set _key to your Google Maps API key, which can be generated <a href="http://code.google.com/apis/maps/signup.html" target="_blank">here</a>.</p>

<pre>
        /// &lt;param name="path"&gt;A path in the format "From {a} to {b}".  Example: "From Lexington, KY to Bowling Green, KY"&lt;/param&gt;
public GDirections(string path)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(
                string.Format(_requestFormat, _key, _output, Uri.EscapeUriString(path)));
            request.Method = "GET";
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader reader = new StreamReader(response.GetResponseStream());
            string json = reader.ReadToEnd();

            _data = readJson(new JsonReader(new StringReader(json)));
        }
</pre>

<p>In our constructor, we basically just grab the response from a web page. (or in this case, JavaScript object)  Using Json.NET, we deserialize the object and somehow stick it in a Hashtable.</p>

<pre>
        private Hashtable readJson(JsonReader jreader)
        {
            Hashtable data = new Hashtable();
            while (jreader.Read() && jreader.TokenType != JsonToken.EndObject)
            {
                string key = null;
                object value = null;

                if (jreader.TokenType == JsonToken.PropertyName)
                {
                    key = (string)jreader.Value;
                    jreader.Read();
                    switch (jreader.TokenType)
                    {
                        case JsonToken.StartArray:
                            value = readJsonArray(jreader);
                            break;
                        case JsonToken.StartObject:
                            value = readJson(jreader);
                            break;
                        case JsonToken.Null:
                        case JsonToken.Undefined:
                            value = null;
                            break;
                        default:
                            value = jreader.Value;
                            break;
                    }
                }

                if (key != null)
                    data.Add(key, value);
            }
            return data;
        }

        private ArrayList readJsonArray(JsonReader jreader)
        {
            ArrayList value = new ArrayList();
            while (jreader.Read() && jreader.TokenType != JsonToken.EndArray)
            {
                switch (jreader.TokenType)
                {
                    case JsonToken.StartArray:
                        value.Add(readJsonArray(jreader));
                        break;
                    case JsonToken.StartObject:
                        value.Add(readJson(jreader));
                        break;
                    case JsonToken.Null:
                    case JsonToken.Undefined:
                        value.Add(null);
                        break;
                    default:
                        value.Add(jreader.Value);
                        break;
                }
            }
            return value;
        }
    }
}
</pre>

<p>This is the "somehow stick it in a Hashtable" (or Dictionary<string,object>) part.  The code really is pretty simple, but the resulting data structure is a <b>huge mess.</b>  We end up with a nested dictionary-style object with arrays thrown in there just to keep things fun and complicated.</p>

<p>IDEALLY, we would want to create classes for each kind of object we get in our response.  For example, Placemark, Status, Point, and Direction classes would need to be created.   If even this is too much work, (which it shouldn't be if you are serious about implementing and fully using this functionality!) some more friendly accessor methods/properties shouldn't be a huge chore to do.  For example, since we're using this thing just for driving time and duration, I implemented the following accessors</p>

<pre>
        public decimal DrivingMeters
        {
            get { return Convert.ToDecimal(((Hashtable)Directions["Distance"])["meters"]); }
        }

        public TimeSpan DrivingTime
        {
            get { return new TimeSpan(0, 0, Convert.ToInt32(((Hashtable)Directions["Duration"])["seconds"])); }
        }

        public decimal DrivingMiles
        {
            get { return Math.Round(DrivingMeters * (decimal)0.000621371192, 2); } // according to Google.
        }

        private Hashtable Directions
        {
            get { return (Hashtable)_data["Directions"]; }
        }
</pre>

<p>So yes, I'm basically saying take this foundation and make it your own.  Make it friendly and then give it back to me. :)</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Four simple techniques for improving your WoW interface</title>
    <link rel="alternate" type="text/html" href="http://www.sagecraft-studios.com/2008/09/four-simple-techniques-for-improving-your-wow-interface.html" />
    <id>tag:www.sagecraft-studios.com,2008://1.2</id>

    <published>2008-09-07T01:38:27Z</published>
    <updated>2008-09-07T17:35:58Z</updated>

    <summary><![CDATA[Hide unnecessary buttonsPractically everything I use is hotkeyed.&nbsp; The only primary buttons I show are spells with a range or cooldown.&nbsp; My buttons are set up to turn red when out of range (Bartender) and display a cooldown time. (OmniCC)&nbsp;...]]></summary>
    <author>
        <name>glompix</name>
        
    </author>
    
        <category term="UI" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="WoW" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="design" label="design" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ui" label="UI" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="wow" label="WoW" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en-US" xml:base="http://www.sagecraft-studios.com/">
        <![CDATA[<font style="font-size: 1.25em;"><b>Hide unnecessary buttons</b></font><br />Practically everything I use is hotkeyed.&nbsp; The only primary buttons I show are spells with a range or cooldown.&nbsp; My buttons are set up to turn red when out of range (<a href="http://www.wowace.com/wiki/Bartender3">Bartender</a>) and display a cooldown time. (<a href="http://wow.curse.com/downloads/details/2775/">OmniCC</a>)&nbsp; Thus, I don't need spells like arcane explosion or flamestrike on my bar.&nbsp; I also use only 1 button for shared ranges or cooldowns, such as only showing fire ward instead of both fire ward and frost ward.&nbsp; I also have a tiny, out-of-the-way secondary bar for common tasks like food and portals.&nbsp; Gems and potions I just open my bag for.&nbsp; It's not that much trouble, but a macro for using them would also be useful.<br /><br /><font style="font-size: 1.25em;"><b>Maximize readability</b></font><br />The best way to increase readability is to reduce clutter and strategically place your frames.&nbsp; Important stuff should be near the middle of the screen.&nbsp; The developers of <a href="http://www.wowwiki.com/BigWigs">Bigwigs</a> figured this out and implemented a way for incoming timers to pop into the middle of the screen.&nbsp; Blizzard apparently hasn't, though, and put their unit frames way up in the corner of the screen.&nbsp; Get some unit frames like <a href="http://www.wowace.com/wiki/PitBull">Pitbull</a> and move that to the center of the screen, or even use a <a href="http://wow.curse.com/downloads/search/?q=HUD&amp;g=1">HUD</a>.&nbsp; If you're a healer, it would be wise to have raid frames somewhere close as well.<br /><br />Another potential readability block I have found is error text.&nbsp; By error text, I mean the stuff you get from spamming spells or trying to take a portal while mounted.&nbsp; After starting from scratch on my UI a month ago, I realized how important <a href="http://www.wowace.com/wiki/ErrorMonster">ErrorMonster</a> is.&nbsp; My BigWigs warning text and Blizzard's error text are basically in the same place.&nbsp; Eliminating error text makes it easier to read whatever crap BigWigs is trying to tell you.<br /><br /><b><font style="font-size: 1.25em;">Use "conditional" buttons and frames</font></b><br />There isn't as much room for this since patch 2.0, but it is still possible.&nbsp; I have a giant empty button for macros I need on certain encounters.&nbsp; This includes targeting Spitfire Totem, using Tainted Cores, or equipping/using Staff of Disintegration.&nbsp; Before a fight, I just drag that macro into that hidden button slot and bam, I'm ready to fight.&nbsp; I also have a focus frame for sheeping.&nbsp; Combined with a /focus-ing sheep macro.&nbsp; This frame is basically just a big 3D portrait to monitor the status of my sheep.<br /><br /><font style="font-size: 1.25em;"><b>Avoid obstructing your view</b></font><br />&lt;p&gt;There are mods out there that intentionally do this and I have no idea why.&nbsp; Putting a giant frame behind huge blocks of addons does absolutely nothing.&nbsp; It doesn't even look good.&nbsp; If there is little margin, fine, but often addon package authors will overdo framing.&nbsp; Viewport modifiers are another horrible idea.&nbsp; Why INTENTIONALLY reduce your visibility?&nbsp; Having your game look "cinematic" benefits nothing.&nbsp; Unless one of those viewport mods increases your horizontal field of vision, you are simply losing visibility.&nbsp; <a href="http://211.206.120.44/upload/jukz_wow_addon_gallery/%2858%29WoWScrnShot_072906_221155.JPG">Photek</a> was famous for this back in the day. (the <a href="http://wow.curse.com/downloads/details/3459/">package</a> looks like it has gotten much more sensible since)&nbsp; It looked pretty when you zoomed in, but overall the loss wasn't worth it.<br /><br />edit: Since changing blog software, I have lost the screenshots for my old interface.&nbsp; Sorry.<br />]]>
        
    </content>
</entry>

</feed>
