Posts
  • Eric Gunnerson's Compendium

    Looj Review

    • 1 Comments

    As many of you know, we have lived with a Roomba for a few years. He's been a faithful servent, though our cleaning people sometimes unplug the charger and don't plug it back in.

    A while back I got an email that said "Looj on Woot!". Woot!, as many of you know, is a website that specializes in selling something different every day. And Looj is a gutter-cleaning robot from iRobot, the maker of the Roomba. A week or so later, the Looj showed up at my door, but I only got around to reviewing it today.

    Unlike the Roomba, the Luje is not authonomous. So, strictly speaking, it's a radio-controlled gutter cleaner rather than a robotic one, but I'm willing to cut them so slack on this. It has two parts - there's the main body of the robot, which is about 12" long, 2" wide, and perhaps an inch and a half tall. On the front is the cleaning part, which has rubber flaps and some strong brushes.

    Attached to the top is the handle/remote control.

    I got up on my roof today to try it out. I have a few leaves, a few needles, a bit of moss, and a whole lot of maple tree seeds (aka "helicopters"). It's all fairly dry because of the time of the year.

    To use it, you set it in the gutter, turn it on, and detach the handle. Turn on the auger, and then you just drive it forwards and backwards like an RC car. In most cases, it will clear all the debris in the first pass, but sometimes there's enough that it climbs on top a bit, and you have to reverse and then move forward to clean it all out. Or, you can drive forwards in spurts when you hit a lot of debris.

    It works really well. I only ran into two problems. In one of my gutters, the Looj rolled over on its back, but since the tread design is symmetrical, it works fine on the back as well. The second problem I had was when I drove it over a short maple tree which got tangled in the auger and the auger clutch released (this doesn't damage the Looj). I untangled it, pulled out the tree, and finished that section of the gutter (the Looj manual tells you not to try to remove trees...)

    So, I did all the gutters - perhaps 120' - in about 15 minutes. Now, I did it from the roof, so I didn't have to move the ladder, but it was still remarkably painless. And it's pretty cheap for what it does - about $100 for the basic model.

    Recommended.

  • Eric Gunnerson's Compendium

    Again

    • 2 Comments

    I was really just trying to get people to smile when they read about it.

    Last Sunday night (the 9th), I played another game of indoor. I felt pretty good, and though I got run into fairly hard at one point, I thought that the guy who ran into me came away worse than I did. At the end of the game my right ankle was sore, but everything else was fine.

    Tuesday morning, I woke up, and my side hurt. I tried to deny it, but by Thursday morning, it was clear. The guy who hit me must have run into me with a knee, because I have another hurt rib (on the lower-left quadrant - one of the short ribs, another new spot for me). I'm not sure whether it's bruised or cracked, but I do know that it's pretty painful. The 30 miles I did on the bike on Sunday were about as pleasant as 7 hills was (ie not much), and I skipped this Sunday's soccer game (it's better to spread the injuries out rather than enjoy them all at once). So, it's another 2-3 weeks of pain, though the only really bad time is when I first get up in the morning and stretch.

    The only upside for this is that I've been looking for a good excuse to skip RAMROD this year, and I figure the double-rib qualifies.

  • Eric Gunnerson's Compendium

    Conference wrap-up...

    • 3 Comments

    After a bit of time to recover from my back-to-back conferences (TechEd 2008 in Orlando and the 2008 HealthVault Solutions Conference in Bellevue), I have a few thoughts to share.

    I haven't been to TechEd for a few years, but TechEd is still TechEd. The developer division, however, has seen a lot of turnover, and I was surprised to find how few Microsoft people that I knew were in attendence. I did two "lunch talks", which is code for "we don't know what track to put you in...". You only get 45 minutes for your talk (after which they come in and tell you to get off the stage), but on the plus side, you don't have to go through any slide review process. I did a HealthVault introduction that went relatively well, and a "write lots of code" talk that went well except for some demo slowness (more on that later). There were about 50 attendees in each session, which is pretty good for a lunch session because of the hassle of attending them.

    I'm disappointed that TechEd no longer devotes a night to "ask the experts". Instead, the MS people have to do "booth duty", which means you stand at your designated section for hours and hope that somebody will come by to talk to you. From watching and talking with a few MS people, that meant a lot of hours where you just stand around, and even when people come by to talk, the MS person who is best equipped to answer the question may not be there.  

    I talked with developers at all the meals, and had some good conversations. I ran into 3 developers who worked in the Health area but had never heard of HealthVault. It means we have some work to do to find out why those developers don't know about us, but it also means that we have some nice opportunities to reach a new audience.

    Splitting the conference into two sections (dev for 4 days, IT for 4 days) was a positive move for the people I talked to, and made it a bit more intimate (if you can properly apply that term in a conference that big).

    Two things I suggest not doing at a conference:

    First, don't try to write a presentation for a second conference while you are at a conference. It's really hard to do well.

    Second, don't check your bag at the conference center, unless you want to spend 35 minutes to do what will take you 5 minutes at the airport. The shuttles to the airport were nice, however.

    After the week at TechEd, I headed back for the

    HealthVault Solutions Conference

    Which was held Mon/Tue of the next week in picturesque downtown Bellevue (come see our construction) at the Hyatt Hotel. This was a great conference - everybody was uniformly friendly, and because of the partner approach the conference is as much about partner <-> partner interaction as it is about Microsoft <-> partner interaction. Monday featured a keynote and then a very complex demo involving live code from lots of different partners working together, put on by my team (but with very little effort on my part). The demo was nearly flawless, and if anything, they made it look a little too effortless. It was very compelling.

    Tuesday started with a keynote by Dr. Oz, a cardiac surgeon and gifted speaker. After a product roadmap talk (that I skipped to get set up for our technical track), we had the following talks:

    • An architecture talk by Bert and Sean
    • A data type talk by Tim and Eric
    • (lunch)
    • A development talk (same talk I did at TechEd) by Eric
    • A third-party-library and other topics talk by Chris
    • A Patient Connect talk by Kalpita

    The talks all went well, with the exception of Eric's. Apparently he forgot to modify his proxy settings to be used outside the firewall, so everytime he made a request it had to time out finding the proxy server before it completed. He is disappointed that he didn't figure this out before the talk, and apologizes to all those who put up with the slowness.  

    Our goal is to re-use the slides and get them on MSDN in some form. I'm probably going to take the development talk about make a tutorial out of it.

  • Eric Gunnerson's Compendium

    Answering a question nobody asked...

    • 1 Comments

    I'm on a break between sessions at TechEd, downstairs in one of the cavernous halls. Something like 400 yards from from to back (yes, I paced it off). I was looking for a comfortable place to sit for a few minutes, and found that the MSDN Zone has a big space with about 20 bean-bag chairs in it. I walk around the side, and am surprised to find that there are a few empty ones. I gracefully lower myself - as gracefully as my middle-aged body will let me right now - and settle in.

    Disappointed! 

    Apparently, somebody thought it was important to answer the question "what if I made something that looked like a bean-bag chair but stuffed it with cheap fiberfill instead?", and somebody else thought it was a good idea to answer the question "will people like these better than bean-bag chairs?"

    Questions that nobody had every really asked before, but for good reason. The whole point of a bean-bag chair is that the user gets to modify the chair to their own personal support requirements. If you want to flop out, you mush it out flat. If you want to sit up - and perhaps use your laptop - you smush it so that it provides good support.

    This "chair" is okay for flopping on, but despite a bit of swelling at one end, provides little in the way of support. After trying a few positions, I'm writing this while I'm in "street luge" position - my legs stretched out in front of me and my head just slightly raised up - which manages to look fairly relaxing without being relaxing at all.

  • Eric Gunnerson's Compendium

    Meet me at TechEd...

    • 1 Comments

    If you're at TechEd this week and are bored Tuesday afternoon, I'll be hanging out in the community lounge (in the basement near the online labs area) during the afternoon.

    I'll try to make the 3-mile walk to the back of the basement room worth your while.

  • Eric Gunnerson's Compendium

    Indoor

    • 4 Comments

    This spring I decided to start playing indoor soccer. I had played in the informal Microsoft outdoor lunchtime games a few years ago, but decided to do something different because a) it's hard to find time in the middle of the day, b) my group ride is Tue/Thu evenings, and iii) I might get wet and stuff.

    I needed to do something other than cycling because cycling specialists have trouble running to save their lives and have the bone density of 75 year old grandmothers.

    So, I signed up for the "over 40" league at Arena Sports in Redmond. We play on Sunday nights.

    The first few weeks were hard. My atrophied soccer skills were complimented by my disused running muscles and my untrained anaerobic system, but over time I started to make progress in all those areas, and the day at which I could actually walk without wincing became Monday rather than Thursday. I did get a rather spectacular skinned knee, and have therefore become a devotee of Tegaderm, a truly wondrous wound dressing (Seriously, it's great stuff).

    About 10 days ago, I scored two goals (one floater, one hard shot with a move before hand (I played defender for years, and my skill with "moves" is fairly limited)). I also left the field with Grade 1 Turf Toe, which was notably painful at the time. By Sunday, it was healed well enough that I could show with only a moderate lack of judgement, to play a double header. The games have blurred together, but both were against the top teams in the league and both featured some pretty skillfull players. Playing defense, I blocked one shot with my left leg, leaving a nice imprint of the ball across my knee. And I blocked another killer hard shot with my upper right chest, leaving me with...

    Longtime readers (Hi George and Fred) have probably figured it out already...

    Cracked rib.

    To go with #2 and #3. #1 is not chronicled yet, but involves people asking me if I was alright from a chairlift and lots of animated waving by me.

    This one - which I'm considering naming "Stanley" - is still in the "hurting more each day" phase, so it's not clear how it will compare to the others in terms of overall pain. Given how much it hurt to get out of bed today, I'd have to say I fancy its chances. I am happy that this is in a different place than the last two so the experience will be different.

    The *real* question is whether this is the "reason" (ie "excuse") I drop off of the waiting list for RAMROD.

    I'm going to ride 7 hills on Monday, doing a distant but undoubtably far whinier imitation of Tyler Hamilton in the 2003 Tour. The smart money is on the "7 hills" variant rather than the "11 hills" version, though some savvy betters have chosen "4 hills".

    To make it easier to track my rib-cracking antics (a pretty good name for a rock band), I've added the "CrackedRib" tag to my blog.

    Enjoy.

  • Eric Gunnerson's Compendium

    My TechEd Presentations...

    • 0 Comments

    I've been working on my TechEd HealthVault development slides for the past week or so. I'm taking the "build an application from scratch" approach, which I think will work well but has a lot of interesting challenges.

    If you want to show up on Friday to shout helpful suggestions like "you forgot the semicolon" (ie "heckle"), here's the information:
     

    Dev Conference LUN05 Developing Microsoft HealthVault Applications
    Session Day/Time: 6/6/2008 12:00PM-12:45PM
    Room: S220 A
     
    Dev Conference LUN06 Introduction to Microsoft HealthVault
    Session Day/Time: 6/4/2008 12:00PM-12:45PM
    Room: S230 E (DEV)

    Note that LUN06 happens on Wednesday, and LUN05 happens on Friday, for a reason that I know better than to ask for.

    I will be there from Tuesday-Friday, so if you want to catch up and complain about how I don't write anything useful any more, let me know.

     

     

  • Eric Gunnerson's Compendium

    Individual Empowerment and agile...

    • 1 Comments

    (Interestingly, I find myself writing more about agile and team stuff now that I'm not on a development team....)

     

    This is in response to a question about how you balance individual empowerment with the collaborative approach on a agile tem... 

     

    *** 

     

    Agile is all about the team, and being on an agile team requires participants to give up some autonomy towards the team. The team is empowered to do what they need to do to reach their goal. If there are issues around how things should be done or what decision is right, the team needs to come to a decision, and I would encourage management to let the team try to do it.  Further, the team needs to “meta rules” around how to make decisions, and they also need to develop those.

     

    This is very different than the “alpha geek” culture that exists in some groups, where a small number of developers are interested in wielding power. There are some individuals who just aren’t willing/able to work collaboratively – I’ve worked with a few, and if you are trying to run an agile team, they are likely better in a different position.

     

    One of the teams I was on basically came to this agreement:

     

    Developers are expected to use their best judgement when deciding what advice to seek when they are doing development.   There are no rules around when you should seek advice, but as a rough guideline, extending functionality under existing patterns is something you can safely do on your own, and big refactorings or new components are areas when you should definitely seek advice. In between, think about the implications of any design choices you might make, and act accordingly.

     

    The other approach is to adopt pair programming, which is a bigger cultural change, but generally if you get two people thinking about decisions they usually make the right decision about involving others.

  • Eric Gunnerson's Compendium

    HealthVault Vocabulary Browser

    • 1 Comments

    I wrote a little utility to browse vocabularies that I thought you might be interested in.

    It uses the HelloWorld app id, so you should just be able to dump it to a directory and run it.

    If you just want to browser, you can do it on the labs vocabulary page, or the vocabulary browser on Get Real's Developer's x-ray tool.

  • Eric Gunnerson's Compendium

    Being greener

    • 8 Comments

    For most of my life, I've been a "small e" environmentalist. I'm not outspoken on my views, but I really hate to see needless waste. For me, that's meant keeping cars for a long time rather than replacing them, spending a little more on stuff that will last so I don't need to throw as much stuff away, and getting books at the library. Stuff like that.

    I haven't, however, put as much effort into applying the same principles to my profession, and over the past few months, I've been working to be more reasonable in that area as well.

    I've come up with a few practices that I thought I'd pass along, as part of what I'm calling "Green Programming - Simple practices to make the world a better place..."

    Practice #1:

    Consider the following code:

        if (x > 5)
        {
            i++;
        }

    Now, if I need to change it so that 2 is added to the value of i rather than one, I would probably do the following:

    First, I'd select the line with the increment:

        if (x > 5)
        {
            i++;
        }

    hit "delete":

        if (x > 5)
        {
        }

    and then type in the new line:

        if (x > 5)
        {
            i = i + 2;
        }

    I've done that sort of thing millions of times in my career. But not any more. Here's what I do now:

    First, delete the characters that I no longer need. In this case, it's just the second "+" sign:

        if (x > 5)
        {
            i+;
        }

     then, insert " = i "

        if (x > 5)
        {
            i = i +;
        }

     and finally, " 2":

        if (x > 5)
        {
            i = i + 2;
        }

    In my first version, I deleted 12 characters (plus a carriage return and linefeed), and then added 20 new characters. With my new approach, I deleted 1 character and added 7 characters. That small change reduced my deletion percentage by 91.67%, and my new character percentage by a less impressive but still impactful 65.00%.

    Practice #2:

    The first practice made some great improvements, but I thought there was more to be had. I found that I could keep open a session of notepad, and rather than deleting the characters from my code, I would copy them to notepad, for possible reuse later. Unfortunately, since I write a lot of new code, I tended to exhaust this resource fairly quickly, and was forced to fall back on typing new characters.

    Practice #3:

    To give me a better source of recycled characters, I came up with a new approach. Not only do I copy characters to notepad before deleting them, when I need to delete a source file, I copy *all* of it's contents to my notepad buffer before deleting the file.

    I am proud to report that I now am justified in believing that I am "character neutral" in all of my coding. That made me quite happy, until I realized that I still had a problem.

    It was my blogging. I tend to write a fair bit on my blogs (3-5 depending on how you count them), but because of my natural eloquence and low quality standards, I rarely delete stuff, and therefore keeping a buffer for my blog writing was problematic. I tried using my programming one - it certainly is sufficiently full that it won't run out quickly - but I found that I tended to have some problems with expression ("I regret I have but one life to give foreach my country"), not to mention developing having to write lines like this:

    (){=();="");(<,>){=.;=..;=..;<>=<>();(());(..()){=;}}

    to use up some of the excess punctuation.

    So, that clearly wasn't workable, but just yesterday I came up with a great idea. I'm now recycling all the contact spam that is *already generated* by my blog into my blog buffer, and I'm considering re-using the splog links I keep getting, which would be especially convenient as they already have the words that I like to use.

    So, that's my little contribution, because as I like to say, if you're not part of the solution, you're part of the problem. Or the precipitate.

    Future Ideas:

    I haven't thought all of these through fully, but here's a list of other ways you might "recycle and reuse":

    • Don't throw away that command window you're using and create a new one. Reuse the existing one.
    • Keep old classes around to use as the starting point for new ones.
    • As some believe in "Peak Oil", I fear that we've already reached "Peak Guid", and that the days of $4 guids are in sight. I therefore recommend that you save all of the guids that you generate. Sure, it may be 15 years before the software that you used them in is gone and you're free to reuse them, but if you're the guy with 500 guids in your pocket during the Guid crisis of 2025, you're going to be sitting pretty.

    What practices can you add?

    (composed of 100% post-consumer characters)

  • Eric Gunnerson's Compendium

    Uncanny valley

    • 0 Comments

    Try this on your second monitor...

    (yes, I know it's not fully rendered, but "Ew")

  • Eric Gunnerson's Compendium

    International Dance Party

    • 1 Comments

    What a nice build. Make sure to watch the video:

    International Dance Party

     and you might want to take a look at the manual...

  • Eric Gunnerson's Compendium

    Project managers for agile teams...

    • 1 Comments

    A recent question about skill requirements for project managers of agile teams led me to write this:

    In traditional project management, “project manager” means “person who is in charge”. In other words, that person makes the decisions, with varying degrees of depth (sometimes it’s high-level, sometimes it’s micro-management).

     

    Agile doesn’t have somebody in change – inherent in the concept of agile is that the group is responsible and the group decides.

     

    There *is* somebody who facilates (scrummaster in scrum, coach in XP), but their job is very explicitly not to make decisions. That means that the person who takes that role needs to be mindful of that and willing to push any decisions that rise up back down to the time. If the person has previous experience (and a preference) for “being in charge”, they are unlikely to do a good job in that role. If they aren’t thoughful about group dynamics in general, they may not do a good job in that role.

     

    Double that comment if the group is not experienced with making decisions together. If they tend to defer upwards and the facilitator is used to making decisions, you probably won’t get a good result.

     

  • Eric Gunnerson's Compendium

    Job openings in the HealthVault team...

    • 1 Comments

    Long-time readers (who I like to refer to as "those three guys") know that I rarely blog about job openings, but I've decided to make an exception.

    The HealthVault team is building a platform to solve "real important" HealthCare problems that affect the lives of "real people". We're a small but growing group that still has that "new group" smell to it, and we're looking for people who would do well in that sort of environment.

    If you want to find out more information, you can find it at the Microsoft Career site (choose "Health Solutions Group" as the product). If you don't want to find out more information, you can find it at the bottom of a locked filing cabinet stuck in a discused lavatory with a sign on the door saying "Beware of the Leopard".

    Or so I'm told.

     

  • Eric Gunnerson's Compendium

    Scheming for Schema

    • 3 Comments

    As many of you know, we already provide access to the schema for the healthvault types through the Type Schema Browser and the Raw XML API reference page.

    If those pages don't do exactly what you want - say, you want to look at all the schemas together in a tool - you can access the schemas programmatically. The schema for a data type is built on some lower-level schemas (or types, if you wish):

    The first one can be fetched programmatically, and the second and third you will need to download directly from the links I provided.

    Access to the schema is provided through the ItemTypeManager class. You can call GetBaseHealthRecordItemTypeDefinition() to get the base schema (base.xsd), and then use GetHealthRecordItemTypeDefinition() to get the xsd for a specific type.

    And, you can get a list of all the types from the "thing-types" vocabulary, thusly:

    Vocabulary thingTypes = ApplicationConnection.GetVocabulary("thing-types");

    Here's a bit of code that I wrote to fetch all of the schemas and store them in separate files:

        protected void Page_Load(object sender, EventArgs e)
        {
            HealthRecordItemTypeDefinition baseTypes = ItemTypeManager.GetBaseHealthRecordItemTypeDefinition(ApplicationConnection);
            SaveTypeXSD(baseTypes, "base");
            Vocabulary thingTypes = ApplicationConnection.GetVocabulary("thing-types");
            foreach (KeyValuePair<string, VocabularyItem> item in thingTypes)
            {
                Guid thingType = new Guid(item.Key);
                HealthRecordItemTypeDefinition definition = ItemTypeManager.GetHealthRecordItemTypeDefinition(thingType, ApplicationConnection);
                SaveTypeXSD(definition, definition.Name);
            }
            int k = 12;
        }
        void SaveTypeXSD(HealthRecordItemTypeDefinition definition, string name)
        {
            string directoryName = MapPath("platform");
            Directory.CreateDirectory(directoryName).CreateSubdirectory("web").CreateSubdirectory("xsd");
            string filename = MapPath(@"platform\web\xsd\" + name + ".xsd");
            using (StreamWriter writer = System.IO.File.CreateText(filename))
            {
                string schema = definition.XmlSchemaDefinition;
                writer.Write(schema);
            }
        }
    Note that it puts the schema definitions in a directory named platform\web\xsd. This is the same structure that the schemas use in our source tree, and this makes sure things work correctly
  • Eric Gunnerson's Compendium

    Work on your Vocabulary. The word for today is "CodableValue"

    • 1 Comments

    Vocabulary and CodableValue are two of the somewhat interesting types in the HealthVault platform, and I thought I'd spend a little time discussing them.

    So, here's the problem they're designed to solve.

    In medicine, there are sometimes long lists. The kinds of lab tests you can order, the kinds of medication that can be prescribed, or the specialties of physicians. Unfortunately, the actual names can be a bit unwieldy. For the last example, you see things like:

    • Medical Toxicology - Emergency Medicine
    • Neurodevelopmental Disabilities (Pediatrics)
    • Adult Reconstructive Orthopedics

    So, to make things simpler, there are a set of codes - using one to three letters in this case - that are the "standard" ways of encoding the longer string (what I'll call the "Display Text"). Take that code, put it together with the display text (and sometimes an abbreviation), and you get a Vocabulary item. Create a list of a bunch of VocabularyItems (along with some other information I'll talk about in a minute), and you get a Vocabulary, which defines both a list of possible options and the accepted way of encoding them (the key).

    To be a bit more concrete, here's how we can fetch a vocabulary describing the different kinds of aerobic activities:

    Vocabulary vocabulary = ApplicationConnection.GetVocabulary("aerobic-activites");

    foreach (KeyValuePair<string, VocabularyItem> item in vocabulary)
    {
        string key = item.Key;
        string displayText = item.Value.DisplayText;
        string abbreviation = item.Value.AbbreviationText;
    }

    If you looked closely at the foreach part, you noticed that item.Value is really a VocabularyItem, and that's where DisplayText and AbbreviationText came from.

    Here's what I got back from executing that code:

     

    Key DisplayText AbbreviationText
    run running run
    jog jogging jog
    hike hiking hike
    bike bicycling bike
    spin spinning spin
    swim swimming swim
    walk walking walk
    row rowing row

     

    In addition to the information on a specific vocabulary item, there is some general information on the Vocabulary type.

    Culture

    The culture tells you the culture of the vocabulary. When you fetch a vocabulary, it comes back for the current Culture, and you can control whether there is a fallback to other culture's if there's not one specific to the current culture. Note that the key is culture-invariant, and therefore may not make sense to users in your current culture.

    Family

    Family defines the overall source for the vocabulary. If it's from HL7, this would presumably be for that. Or perhaps it might say "AMA", or something else. The family lets you understand where the vocabulary came from.  If it's something the HealthVault team defined, the family is "wc".

    Name

    The name of the vocabulary. Together with the family, that should fully identify the source

    Version

    A string defining a version of the vocabulary.  

     

    Coded and Codable Values

    How is a reference to a specific vocabulary item stored in HealthVault?

    It is done through the CodedValue type. A quick look at the type shows the following properties:

    • Family
    • Value
    • Version
    • VocabularyName

    As you probably figured out, Family, Version, and VocabularyName are used to indicate what vocabulary we are using, and Value is used to store the key for the specific vocabulary item. An application can figure out exactly you mean by looking at the CodedValue.

    That works well when we have a vocabulary and we know exactly what code to use. But there are two more scenarios we need to support.

    First, we might have an item to store, and it's either not in the vocabulary or we don't know what the appropriate vocabulary is. I might want to store my juggling exercise data, but that's not part of aerobic-activities vocabulary. Or, I'm adding the over-the-counter allergy medicine I take, and all I know is the name on the box.

    In other words, sometimes we have very precise information, and sometimes it's less precise, but in both cases the platform and the applications that use the platform need to handle it well.

    The second scenario - and this one's rarer - is that there are times where a single entry might need to store multiple values.

    Both of these scenarios are supported through the CodableValue type, and that's the type that you'll see used in the data types.  It provides a Text property and a way of having multiple coded values.

    CodableValue.Text is always set for all codable values, and that's the one that you display when you're showing that value to a user. Any underlying CodedValue instances are of a "more information" category - the application can use them to find out more information about that Text.

    All Vocabularies

    You can fetch the list of all vocabularies with the following:

    ReadOnlyCollection<VocabularyKey> keys = ApplicationConnection.GetVocabularyKeys();

    Why would you want to do this? Well, it's useful for browsing to see if the vocabularly that you want is currently defined in the system. If there's one that's not in the system, you can request a new vocabulary using the same process you'd use to request a new data type.

    Best Practices

    1. Always set the Text property on the Codable value, even if there are CodedValues underneath.
    2. Always display the Text property as the high-level summary of the CodableValue.
    3. Be thoughtful about displaying the key to a vocabulary item to the user. It might be a number - in which case it is probably okay - but it also might be a string that only works well in one locale.  

    Translation

    One of the nice things about vocabularies is that there is are so many to choose from. There are several different coding systems - and therefore possible vocabularies - for medication. We've talked about providing translation services between different vocabularies - so that an application could easily get hte information in the vocabulary it understands best.

    Would you find that to be a useful feature?

  • Eric Gunnerson's Compendium

    Dealing with PersonalImage

    • 2 Comments

    PersonalImage is a type that encapsulates the picture that shows up for a person in the health record.

    My current image is this:

    With the power to... Melt!

    (those interested into why that is my current image should post the results of their research in the comments)

    PersonalImage is what is called a Singleton type, which - as you've probably already figured out - means that there can only be one of them. But, there might be none of them, so code needs to handle this case as well.

    Here's some code you might find useful.

            using (Stream imageStream = System.IO.File.OpenRead(@"C:\Documents and Settings\ericgu\My Documents\My Pictures\213.jpg"))
            {
                HealthRecordItemCollection collection = PersonInfo.SelectedRecord.GetItemsByType(PersonalImage.TypeId, HealthRecordItemSections.All);
    
                PersonalImage image = null;
    
                if (collection.Count != 0)
                {
                    image = collection[0] as PersonalImage;
    
                    using (Stream currentImageStream = image.ReadImage())
                    {
                        byte[] imageBytes = new byte[currentImageStream.Length];
                        currentImageStream.Read(imageBytes, 0, (int)currentImageStream.Length);
    
                        using (FileStream outputImage = System.IO.File.OpenWrite(@"g:\213.jpg"))
                        {
                            outputImage.Write(imageBytes, 0, imageBytes.Length);
                        }
                    }
                }
    
    
                if (image == null)
                {
                    image = new PersonalImage();
                    image.WriteImage(imageStream, "image/jpg");
                    PersonInfo.SelectedRecord.NewItem(image);
                }
                else
                {
                    image.WriteImage(imageStream, "image/jpg");
                    PersonInfo.SelectedRecord.UpdateItem(image);
                }
            }
    
    
  • Eric Gunnerson's Compendium

    HealthVault and openness

    • 1 Comments

    Yesterday - while I was taking a day off skiing with my wife and daughter - we announced our plans around openness and interoperabiity for HealthVault.

    I'm pretty excited about this. I'm especially excited about making the current .NET client library available under the Microsoft reference license, as I remember how useful it was to step through the MFC or ATL source when I was trying to figure out how things worked (or, more usually, what I had done wrong).

  • Eric Gunnerson's Compendium

    Uploading a file to HealthVault

    • 1 Comments

    I came across a question asking how to upload a file to HealthVault, and decided to write a quick example.

    Files, like everything else in HealthVault, are stored in XML, and in fact, the File class is really a pretty thin wrapper over the underlying type. The File type stores the name of the file, the size, and the type of the content in the file.  The contents of the file is then stored in the "OtherData" member as a base-64 encoded string.

    Here's some code:

    FileInfo fileInfo = new FileInfo(@"C:\Documents and Settings\ericgu\My Documents\My Pictures\lame.jpg");
    using (FileStream stream = System.IO.File.OpenRead(fileInfo.FullName))
    {
       
    BinaryReader reader = new BinaryReader(stream);
        byte[] fileContents = reader.ReadBytes((int) fileInfo.Length);
        string encodedString = Convert.ToBase64String(fileContents);

        Microsoft.Health.ItemTypes.File file = new Microsoft.Health.ItemTypes.File();
        file.Name = fileInfo.Name;
        file.Size = fileInfo.Length;
        file.ContentType =
    new CodableValue("image/jpg");
        file.OtherData =
    new OtherItemData();
        file.OtherData.ContentEncoding =
    "base-64";
       
    file.OtherData.ContentType = @"image/jpg";

        file.OtherData.Data = encodedString;

        PersonInfo.SelectedRecord.NewItem(file);
    }

    That will get the data up into HealthVault. Remember that the OtherData section doesn't come down by default, so if you want to get the contents of the file back, you'll need to specify:

    filter.View.Sections = HealthRecordItemSections.All;

    (or another version of the Sections mask that includes HealthRecordItems.OtherData).

  • Eric Gunnerson's Compendium

    Build a 3D XNA game from scratch - webcast series

    • 0 Comments

    This came highly recommended...

    Build a 3D XNA game from scratch - webcast series

  • Eric Gunnerson's Compendium

    The correct answer is "snowblower"

    • 2 Comments

    As some guessed, a snowblower.

    More specifically, an Ariens 824E snowblower, from SnowblowersDirect.com.

    Some of you know that I ski in the winter, and keep a ski cabin to make ski mornings much nicer. The ski cabin is at about 1000', and traditionally, there really isn't that much snow at that elevation around here - it tends to snow a bit, and then warm up.

    But - as we've found over the last few years - if you have a house that sits on the north side of a hill, you don't get any solar radiation at all, and any snow that you do get is amazingly resilient - it will stick around for months. Though I can usually push the outback into our driveway with the new snow, it doesn't really work on deep slop, unless you're fond of severe drivetrain abuse and the smell of burning clutch(es).

    So, we park at a small spot on the road to our lot. If it's snowed, I have to either move the plowed snow to the side before we park, or just muscle over it. And I need to cut a path through the snow to the cabin so we don't slip and fall over.

    We've had this tentative plan to get an ATV and put a small plow on it, but I pretty much just lazed on that one. And then it started snowing, and snowing, and snowing around here, and I started thinking in terms of snowpack. We've probably had a good 4-5 feet of snow fall, and the snowpack is around 24-30" right now (it was a bit higher a week or so ago). I'm tired of digging.

    Hence the snowblower. I couldn't find any stock here or close on the east side of cascades, so I ended up buying online, which was surprisingly easy. The blower showed up on Friday, we took it up Saturday, and found that it's a nice machine. And, amazingly, it started on the first pull in 20 degree weather, which shows that small engines have improved a bit since the lawn-mowing days of my youth.

    It made quick work of the top 8" of snow, which was still sort of powderly. I had little luck at all with what was underneath, but given the fact that the blower doesn't sink into the snowpack, I'm not surprised. It would have been fine if I could have attacked it incrementally, and I'm hopeful that when it warms up a bit, the pack will soften and I'll be able to get back into the driveway.

    Or, I could try to borrow one of these...

  • Eric Gunnerson's Compendium

    Ninja Warrior

    • 8 Comments

    My daughter found some broadcasts of a show named "Ninja Warrior" (originally named Sasuke in its Japanese broadcast), which is currently running on G4TV. It's an elaborate obstacle course show, with an English voiceover on top of the Japanese commentary.

    Not only do you get to see some really talented athletes, you also get to see ordinary people crash and burn on the first stage, falling into the muddy water.

    Recommended.

  • Eric Gunnerson's Compendium

    What did Eric buy?

    • 5 Comments
    • 228 pound
    • 6 speeds
    • 318cc
  • Eric Gunnerson's Compendium

    Users, records, and multi-record applications

    • 2 Comments

    A topic came up yesterday in the forums, and I thought it was of general interest.

    HealthVault is different from a lot of information systems - at least the ones I've worked with - in that there is a break between the concept of "user" - the person who authenticates into the application - and "record" - the thing that holds information about specific individual.

    This is to support two scenarios.

    The first one is for parents, who want to track the health information of their children. They can create a separate record (that they have access to) for the child.

    The second one is when an adult is managing the health of another adult - that adult can be granted access to another adult's record.

    If you are writing an application, this is something that you need to deal with. If I'm using an application and then I come back to it after I've gotten access to another record, I need to provide the following:

    1. A way to authorize the application to access the new record. This is done through the shell and a redirect, similar to how normal authorization is done.
    2. Some UI to allow the user to switch between records.

    For an example of how to do this, take a look at the HealthAndFitness application.

    The existence of multiple records explains why you need to use PersonInfo.SelectedRecord to access the data - it belongs to the current record, not to the current user.

    That's the overview. The specific point that came up yesterday was around the ids for users and records. An application can access PersonInfo.PersonId and SelectedRecord.Id, and use those to uniquely identify that user and record.

    But, to make it harder to correlate information between applications, the same person using two separate applications is going to have two different values of PersonInfo.PersonId and SelectedRecord.Id, and, in fact, the record ID will change if the application is de-authorized and then re-authorized.

    So, you may need to keep this in mind if you are doing anything with those IDs...

  • Eric Gunnerson's Compendium

    Family Health Guy

    • 1 Comments
    Sean Nolan, my second-level (aka my manager's manager) and chief HealthVault architect, has started a blog named FamilyHealthGuy (no relation, AFAIK, to Family Guy), where his initial post, after dealing with matters mursine, talks a bit about why he's excited about HealthVault.
Page 5 of 46 (1,137 items) «34567»