toaster » (the universe lets me win) 2013-01-08 07:21:32

January 8th, 2013
The non-baby-related excitement in my life is that I bought a new bike. It's a Novara Transfer, a "european-style" bike, the dude in the shop said, which I think means that it's the kind of bike you enjoy if you like trundling around the city on a nice sunny day and not if you like to weave in and out of traffic at forty miles an hour while wearing lycra. Since I'm firmly in the first camp, I think I'm going to love it. It's the kind of bike that should have a basket, and ideally the basket will have a baguette sticking out of it, but a bag of bagels and a travel mug of coffee probably works too.

It arrives next weekend. I can't wait.

Here's a review: http://open.salon.com/blog/familyonbikes/2011/05/08/rei_novara_transfer_a_review

toaster » (the universe lets me win) 2013-01-08 06:42:48

January 8th, 2013
Our baby's a month old! At this time on December 7th, my water had broken while I was coding[1] and I was wondering whether I'd have time to submit a half-working version of the project before we had to go to the hospital. Nope! At midnight the contractions started and eight hours later we had a little Gollum lookalike of our very own, all covered in birth-goop and yelling the place down.

A month already. Without unusual events or notable weekends to demarcate time, it doesn't feel like weeks are passing. We feed and clean the baby. We do small recreational things that don't take a lot of brain power. We go out for breakfast. We marvel at how much we adore this small person and discuss minute changes in her abilities. I pump milk. Joel does laundry. He introduces her to Dave Brubeck ("Listen for the change in time signature here"). I take her for walks around the neighbourhood and tell her about being a New Yorker ("Don't make unnecessary eye contact, but it's always ok to compliment people's dogs"). We've figured out a pretty good schedule which gives both of us some time off. It'll get much harder once work and real life come back into play, but for now it's fantastic to just watch her booting up.

Babies don't change that much in the first month and at the same time the difference is remarkable. She's growing rapidly, which is a relief. She no longer feels fragile. She reacts to sounds and she now sometimes looks at things and can track slow-moving objects. She grips my finger while I'm feeding her and makes me feel like the best person in the world. She sprawls out on her belly on Joel's chest, arms and legs hugged around him, and falls into her most contented sleep. Humans are her favourite furniture.

She searches her surroundings for sources of milk, mouth open to the air like a baby bird. I hold her upright to make her burp and she flails a little sticky, milky face against my collarbone in case I'm hiding a spare nipple there. She doesn't cry yet, but she makes furious frustrated animal sounds when we're slow about feeding her. She has feeding frenzies. We call her Captain Sharky.

We swaddle her in a sheet and it looks like a toga and she throws one arm above her head (about an inch above her head: she has stubby arms) and we make impassioned speeches to the Roman senate on her behalf ("Friends, Romans, fellow babies. How long must we wait for the milk we have been promised?"). Music makes her calm. She likes voices. I've discovered that I like reading out loud (it's likely correlated with a love for the sound of one's own voice) and she and I read classics like The Great Railway Bazaar and Happy Pig Day.

It's _lovely_. I like it so much. Part of me can't wait for major developmental milestones -- all of the smiling and gurgling and moving around -- but mostly I don't want this time to end. Real life can back off for another few weeks.

If you like baby pictures, here's an album of the first month in chronological order:
Photo & Video Sharing by SmugMug
Elizabeth First Month


[1] Approximate next thoughts: "oh god, the new sofa!... oh, come on, I _just_ figured out how to write this, can't it wait half an hour?... I should call the doctor".

cammy » Happy New Year 2013!

December 31st, 2012

While struggling with a bit of a cold, did a little sketch before the end of the year. Happy New Year!
DSC_0276

Related Posts:

toaster » (the universe lets me win) 2012-12-15 01:36:37

December 15th, 2012
Last night I read kidface her first book, Owl Moon by Jane Yolen. It's a beautiful story about a little girl going out at night with her dad to look for owls. The writing perfectly evokes the stillness of a snowy night and the companionable silence between two people who understand each other, and the pictures are gorgeous too: it won the Caldecott medal for children's book art in 1988. It's a delight to read out loud. It may also be nice to listen to, but Elizabeth's opinions on it are hard to interpret. She mostly stayed awake.

The other first for yesterday evening was our first time giving her a sponge bath. Afterwards I wrapped her up in her towel-with-a-hood (grr.. it has trains on it, so the label describes it as "boy towel"; how the hell can a towel be gendered?) and put her to bed, whereupon she explosively crapped, chucked milk down her front and into her neck folds, and then peed over any parts of her that she'd inadvertently missed. She was clean for two whole minutes. Because we are ridiculously enchanted by everything this kid does, it was more endearing than anything else, but I bet that changes over time :-)

Today I achieved the ambitious two-part goal I'd set for myself: 1) I wore clothes that weren't pyjamas. 2) I left the house. We're definitely making progress! Tomorrow I'd like to do those things again and also brush my teeth before 5pm, but this may be trying for too much.

It's surprisingly easy to be contented with this lifestyle. I mean, not forever -- I hope we'll get some structure soon and that I'll do non-baby things again -- but there's something nice about having a single, well-defined goal and working towards it. I'm enjoying getting to know this excellent small person.

cambo » Adding Custom Message Headers to a WCF Service using Inspectors & Behaviors

December 14th, 2012
WCF Header Man

He has a WCF Header… Get it !

Often, you’ll need to pass some piece of information on some or all of your  WCF Service operations. For my team, we had recently exposed some functionality in an old WCF Endpoint via a Web Front End and wanted to log some auditing information on each and every Service Call. Obviously modifying every single method signature to accept the new parameters would be a pretty significant breaking change to all the consumers so instead we looked at passing this information as a Custom WCF Message Header. WCF exposes a number of interfaces which you can leverage to inspect & modify messages  on the fly and to add customer behaviors to service endpoints. In the following demo, we’ll go through the process of building a Custom Header for our WCF Service & subsequently passing that information from the Consumer Client back to the service. In our contrived example I’ll be attempting to pass 3 pieces of information to the WCF Service as part off every message call.

  • The username of the currently logged in web front-end user
  • Since our website is deployed across multiple nodes, the id of the web node
  • The “Special Session Guid” of the current users Session

Important!

The completed solution can be found on GitHub at https://github.com/eoincampbell/wcf-custom-headers-demo 
This scenario could apply to a number of other real world situations. Perhaps the service is secured and called using a single WS Security Account, but we need to log the user who’s session, the service call originated from on every service call. Or perhaps you’re exposing your service to the public and as well as providing a username & password to authenticate, the caller also needs to provide some sort of “Subscription Account Number” in addition to their Credentials. Any of these scenarios are candidates for adding a custom header to a WCF Service.

The Quick & Dirty Solution

Of course I could just edit method signatures of each service call to accept this additional information as additional parameters but this causes a number of other problems. This might be feasible for a small in-house service, or dummy application but it causes a number of issues in reality.
  • I need to add additional parameters to every service call which isn’t a particularly elegant solution
  • If I need to add more information in the future, I must edit every service call signature which at worst is a breaking change for every client and at best, a significant amount of work & re-factoring.
  • Depending on the scenario, I’m potentially intermingling Business Logic with Authentication/Authorization or some other sort of Service Wide Validation logic which is going to increase the complexity of any future re-factoring.

Operation Context & Custom Message Headers

A better solution would be to “tag” each service call with some sort of header information. In this way, we could piggy-back our additional data along without interfering with the individual method signatures of each service call. Thankfully WCF includes built-in support for MessageHeaders. The services OperationContext includes Incoming & Outgoing Message Header collections.

//Service Contract
    [ServiceContract]
    public interface ISimpleCustomHeaderService
    {
        [OperationContract]
        void DoWork();
    }

//Client Code
    using (var client = new SimpleCustomHeaderServiceClient())
    using (var scope = new OperationContextScope(client.InnerChannel))
    {
        var webUser = new MessageHeader("joe.bloggs");
        var webUserHeader = webUser.GetUntypedHeader("web-user", "ns");
        OperationContext.Current.OutgoingMessageHeaders.Add(webUserHeader);

        client.DoWork();
    }

For now I’ve created a very simple Service Contract which has a single void method on it called DoWork(). Adding a custom header to this service call is relatively trivial. First we instantiate a new instance of our WCF Client Proxy. We also nee to create an OperationContextScope using the WCF client channel. Since the OperationContext is accessed, via the static Current property, instantiating this scoping object, stores the current context & the OperationContext of the current Clients IContextChannel becomes that returned by the Current Property. This allows us to modify the OutgoingMessageHeaders collection of the clients channel. Once disposed the state of the original Current OperationContext is restored. MessageHeaders are passed as untyped data as they travel on the wire. In the example above I’ve created a strongly typed .NET object. That is then converted to an untyped header; keyed by name & namespace for transmission in the OutgoingMessageHeaders Collection. If we observe the data that travels across the wire using fiddler, we can see our Custom Header Data has been appended to the soap header section of the message.

Fiddler WCF Headers

Fiddler WCF Headers

Finally, these Header values can be retrieved from the IncomingMessageHeader Collection as part of the service call processing. Since we’re already in the scope the Current OperationContext, we can just directly access that context’s header collection to read our headers. I’ve added a simple generic helper method to test to see if the Header can first be found and if so, will be returned.

public class SimpleCustomHeaderService : ISimpleCustomHeaderService
{
    public string DoWork()
    {
        //Do Work
        //...

        //Capture Headers
        var userName = GetHeader("web-user", "ns");
        var webNodeId = GetHeader("web-node-id", "ns");
        var webSessionId = GetHeader("web-session-id", "ns");

        Debug.WriteLine("User: {0} / Node: {1} / Session: {2}", userName, webNodeId, webSessionId);
        var s = string.Format("HeaderInfo: {0}, {1}, {2}",
            userName,
            webNodeId,
            webSessionId);

        return s;
    }

    private static T GetHeader(string name, string ns)
    {
        return OperationContext.Current.IncomingMessageHeaders.FindHeader(name, ns) > -1
            ? OperationContext.Current.IncomingMessageHeaders.GetHeader(name, ns)
            : default(T);
    }
}

Leveraging Client & Dispatch Message Inspectors

The above solution comes with some pros and cons. On the plus side headers can be added in an adhoc manner with little friction to existing code. On the downside, it’s not really ideal from a code maintenance/organization point of view. Header Data is relatively unstructured and disparate. We also end up with a lot of touch-points. Adding headers requires creating an OperationContextScope in close proximity to every service call… similarly, accessing the resultant header values must be done in the Service Methods… Imagine our WCF Service had 100 service methods, and all we wanted to do was send a single additional header to be logged on the server. That results in 100′s of lines of additional code.

A better solution would be to use the built in message inspector interfaces in WCF. Message Inspectors provide you with a way to plug directly into the WCF Communications Pipeline on both the client or server side of the communication Channel. The IDispatcherMessageInspector allows us to affect messages either just after the request has arrives on the server (AfterReceiveRequest) or just before the response leaves the server (BeforeSendReply) The IClientMessageInspector allows us to affect messages either just before the request leaves the client  (BeforeSendRequest) or just after the response is received by the client (AfterReceiveReply)


public class CustomInspectorBehavior : IDispatchMessageInspector, IClientMessageInspector
{
    #region IDispatchMessageInspector

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    { ... }
    #endregion

    #region IClientMessageInspector
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    { ... }
    #endregion
}

Injecting ourselves into the message pipeline like this serves a number of advantages, We now have the opportunity to add our messages to the outbound client request in a single place. We also have a single touch point for capturing the request on the server side. If this was a licence-code validation check, this would save us from peppering every single service call with the validation check code.

In the following sections we’ll look at creating a custom data header object, creating a message inspector implementation to manage injecting and extracting this data from our WCF Service, creating Client & Service Behaviors to attach our Message Inspectors and creating a behavior extension to allow these behaviors to be applied to our service through configuration.

Solution Organisation

Since both our Web Application (which will host the Web Services) and the Console Application will have some common dependencies, I’ve split out the majority of the code in these next sections and stored them in Common Class Library folder which both Applications can then reference.

Solution Organisation

Solution Organisation

Custom Header Data Contract

The first thing I’ll create is a simple data contract object to represent our custom header information. This POCO Data Contract provides a simple way for us to encapsulate our header information into a single payload which will be transmitted with our Service Calls.

    [DataContract]
    public class CustomHeader
    {
        [DataMember]
        public string WebUserId { get; set; }
        [DataMember]
        public int WebNodeId { get; set; }
        [DataMember]
        public Guid WebSessionId { get; set; }
    }

Message Inspectors

Next I create our Message Inspectors. The two interfaces that are required are the System.ServiceModel.Dispatcher.IDispatchMessageInspector (which hooks into our pipeline on the service side) and the  System.ServiceModel.Dispatcher.IClientMessageInspector (which hooks into our pipeline on the consumer side). Within these two interfaces the two methods I’m most interested in are the IClientMessageInspector.BeforeSendRequest which allows me to modify the outgoing header collection on the client and the IDispatchMessageInspector.AfterReceiveRequest which allows me to retrieve the data on the service side.

    #region IDispatchMessageInspector
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        //Retrieve Inbound Object from Request
        var header = request.Headers.GetHeader("custom-header", "s");
        if (header != null)
        {
            OperationContext.Current.IncomingMessageProperties.Add("CustomHeader", header);
        }
        return null;
    }
    #endregion

    #region IClientMessageInspector
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        //Instantiate new HeaderObject with values from ClientContext;
        var dataToSend = new CustomHeader
            {
                WebNodeId = ClientCustomHeaderContext.HeaderInformation.WebNodeId,
                WebSessionId = ClientCustomHeaderContext.HeaderInformation.WebSessionId,
                WebUserId = ClientCustomHeaderContext.HeaderInformation.WebUserId
            };

        var typedHeader = new MessageHeader(dataToSend);
        var untypedHeader = typedHeader.GetUntypedHeader("custom-header", "s");

        request.Headers.Add(untypedHeader);
        return null;
    }
    #endregion

I’ll also need to create a simple static Client Context class which will provide the conduit for the Consumer Application to set header values to be picked up inside the message inspector methods.

    public static class ClientCustomHeaderContext
    {
        public static CustomHeader HeaderInformation;

        static ClientCustomHeaderContext()
        {
            HeaderInformation = new CustomHeader();
        }
    }

WCF Custom Behaviors

WCF Service Behaviors define how the endpoint (the actual service instance) interacts with its clients. Attributes like security, concurrency, caching, logging, and attached message inspectors – those are all part of the behavior. We’re going to implement a new custom behavior for both the Service side and the Client side of this interaction. Since these are still just interface implementations, there’s no need to create a new class to implement them. We can add this functionality to the same class which contains our Message Inspector functionality. Of course if you wanted to be a purist about it, there’s nothing to stop you implementing the two message inspectors and two service behaviors in four completely separate classes.

The two behavior contracts I’m interested in here are the System.ServiceModel.Description.IEndpointBehavior, which is responsible for the client side behavior and the System.ServiceModel.Description.IServiceBehavior which is responsible for the service side behavior. Implementing these interfaces allows me to add an instance of the Message Inspectors to the service.

#region IEndpointBehavior
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
    var channelDispatcher = endpointDispatcher.ChannelDispatcher;
    if (channelDispatcher == null) return;
    foreach (var ed in channelDispatcher.Endpoints)
    {
        var inspector = new CustomInspectorBehavior();
        ed.DispatchRuntime.MessageInspectors.Add(inspector);
    }
}

public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
    var inspector = new CustomInspectorBehavior();
    clientRuntime.MessageInspectors.Add(inspector);
}
#endregion

#region IServiceBehaviour
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
    foreach (ChannelDispatcher cDispatcher in serviceHostBase.ChannelDispatchers)
    {
        foreach (var eDispatcher in cDispatcher.Endpoints)
        {
            eDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomInspectorBehavior());
        }
    }
}

#endregion

Adding the Custom Behavior to a WCF Service

Behaviors can be applied to services using a special Service Behavior attribute which decorates the ServiceContract. The last step is to extend the Attribute class in our CustomHeaderInspectorBehavior class and then to decorate each of services with that attribute.

[AttributeUsage(AttributeTargets.Class)]
public class CustomInspectorBehavior : Attribute, ... { ... }

[CustomInspectorBehavior]
public class ComplexCustomHeaderService : IComplexCustomHeaderService { ... }

Configuring a WCF Client to use a specific behavior

On the client side, I need to do a tiny bit more work. I can manually configure the Behavior on the WcfClientProxy every time I instantiate it but this is extra bloat and eventually I’ll forget to set it somewhere and lose my behavior functionality.

using(var client = new ComplexCustomHeaderServiceClient()) {
    client.ChannelFactory.Endpoint.Behaviors.Add(new CustomHeaderInspectorBehavior());
}

Instead I’d prefer to be able to set this once in configuration and never have to worry about it again. I can achieve this by using a BehaviorExtension Element as follows and adding it to my application configuraiton file.

public class CustomInspectorBehaviorExtension : BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        return new CustomInspectorBehavior();
    }
    public override Type BehaviorType
    {
        get { return typeof (CustomInspectorBehavior); }
    }
}

And below is the equivalent configuration file.

    <system.serviceModel>
      <behaviors>
        <endpointBehaviors>
          <behavior name="CustomInspectorBehavior">
            <CustomInspectorBehavior />
          </behavior>
        </endpointBehaviors>
      </behaviors>
      <extensions>
        <behaviorExtensions>
          <add name="CustomInspectorBehavior"
               type="WCFCustomHeaderDemo.Lib.Extensions.CustomInspectorBehaviorExtension,WCFCustomHeaderDemo.Lib" />
        </behaviorExtensions>
      </extensions>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_ISimpleCustomHeaderService" />
                <binding name="BasicHttpBinding_IComplexCustomHeaderService" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost/TestService/ComplexCustomHeaderService.svc"
                behaviorConfiguration="CustomInspectorBehavior"
				binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IComplexCustomHeaderService"
                contract="ComplexCustomHeaderService.IComplexCustomHeaderService"
                name="BasicHttpBinding_IComplexCustomHeaderService" />
        </client>
    </system.serviceModel>

Calling our Client

Finally, we can call our client and test to see if our Server side application can see the headers being submitted and echo them back.

using(var client = new ComplexCustomHeaderServiceClient())
{
    ClientCustomHeaderContext.HeaderInformation.WebNodeId = 465;
    ClientCustomHeaderContext.HeaderInformation.WebSessionId = Guid.NewGuid();
    ClientCustomHeaderContext.HeaderInformation.WebUserId = "joe.bloggs";
    System.Console.WriteLine(client.DoWork());
}
Wcf Header Demo Result

WCF Header Demo Result

Excellent.

~Eoin C

toaster » (the universe lets me win) 2012-12-12 18:33:10

December 12th, 2012
Well, we made a baby and she is fantastic. Elizabeth James Votaw was born at 08:28 on Saturday, December 8th, 2012 and came home to Brooklyn on Monday evening. I've been waiting for ten uninterrupted minutes to write about her here, but it's looking like she'll be in college before that happens, so I'll link to the gplus post I wrote during the last uninterrupted ten minutes and leave it at that for now :-)

elizabeth

PS: parenthood is terrifying and also the happiest thing ever.

toaster » (the universe lets me win) 2012-12-04 17:00:53

December 4th, 2012
We have no hospital! As I mentioned before, NYU flooded and they moved us to Mount Sinai. That filled up, so we moved again to Downtown. And now Downtown is overcrowded, so we're getting bumped again. Our doctor says that the Manhattan hospitals are not exactly throwing their doors open to refugees, and we may end up somewhere in Brooklyn. That would suck terribly for the NJ patients, but it might be ok for us. The other way around would be less ok: my kid is not getting born in Jersey. (Sorry, Jersey.)

It's funny that I spent so much time comparing hospital philosophies and facilities at the start -- I picked our doctor based on her connection to NYU Langone, not the other way around -- and at this point we'll be happy if we don't have to present ourselves to A&E at grubby LICH.

cambo » Unexpected Variable Behaviour in DOS Batch and Delayed Expansion

December 4th, 2012

What would you expect the following piece of Code to print. if the directory ‘A’ doesn’t exist

@ECHO OFF
IF '1'=='1' (
        CD a
        ECHO %ERRORLEVEL%
)

CD a
ECHO %ERRORLEVEL%

Not very intuitive right?

This is because the DOS batch processor treats the whole if statement as one command, expanding the variables only once, before it executes the conditional block. So you end up with %ERRORLEVEL% being expanded to its value, which is 0, before you start the block, You can get around this by enabling Delayed Expansion. As the name suggests this forces the the Batch Processor to only expand variables once required to do so in the middle of execution.
To enable this behavior you need to do 2 things.
  1. SET ENABLEDELAYEDEXPANSION at the top of your script.
  2. Replace % delimited variables with an Exclamation. i.e. %ERRORLEVEL% becomes !ERRORLEVEL!

Now our script looks like this, and behaves as expected.

Working Script

@ECHO OFF
REM Enable Delayed Expansion
setlocal enabledelayedexpansion
IF '1'=='1' (
        CD a
        REM Use Exclamations instead of percentages
        ECHO !ERRORLEVEL!
)

CD a
ECHO %ERRORLEVEL%
For when powershell just isn’t retro enough ;-)
~Eoin C

toaster » (the universe lets me win) 2012-12-02 16:55:56

December 2nd, 2012
Fifteen more hours of on call and then I'm on maternity leave! I waver between finding this ridiculous and feeling that it's actually about time: on one hand, I'm still chipper and energetic most of the time and The Company could get another couple of weeks' work out of me; on the other, I'd prefer to spend these days walking a lot and taking naps instead of sitting in an office chair and defending my belly on the subway at rush hour. On the other other hand, I have to go find food for myself now? What do people eat when they don't have five Google cafeterias and a coffee bar catering to their every whole-food-organic culinary notion? Do I know how to cook anything that isn't breakfast? I don't have the right life skills for a staycation.

This part of Brooklyn is baby-oriented enough to be able to support a new pregnancy mailing list every month. December2012babies is full of activity right now, with a few early babies, a lot of anxiety and tons of exhausted teachers and hairdressers and other doers of real jobs who'll be working right up until their due dates and even afterwards. I'm staying quiet: I can't really admit that "Yeah, we get four weeks off in advance, but I was really enjoying my project so I only took three", can I? Poor teachers, especially. I can't imagine.

Anyway, on call ends at 1am and the kid can come when she wants after that... though we do have Billy Connolly tickets for Thursday, so no rush.

Of course we're likely still weeks away, but things are definitely shifting around in there and every day brings new and exciting phenomena. I can mostly tie my own shoelaces again! Sometimes I snore while awake! It's a time of great indignity. Strange biology too: at 2am I was losing at Go against my phone and wondering whether this new kind of intermittent twitchy back pain that had arrived was going to develop into something interesting. Spoiler: it didn't and my secondary on call didn't get a late night "tag, you're it!" phone call. So a regular Sunday morning it is.

toaster » (the universe lets me win) 2012-11-29 06:06:22

November 29th, 2012
What a cranky and difficult day. Nothing was good today and everything went wrong and there was no obvious reason for any of it. Joel says "It's because you didn't light box yesterday" and I say "No, it's because every goddamn thing is stupid." I'm medicating with Bach, a purring cat and a lot of pillows. (Joel: "the Pillow Of The Month Club called; they wondered if you meant to take out that third subscription.". Oh, Joel's on a roll today.)

Today was a day of technological failure, hanging browsers, crashing IM clients, wedged phones, laggy infrastructure, upgrades that didn't and -- really, this seemed a bit unnecessary -- an adjustable desk that chose today to stop adjusting. Seriously, desk? You too? That said, the fax I needed to send this evening went out on the first attempt, so maybe this was some sort of technological karma: you need to build up a lot of broken crap to balance out a fax machine that does what you want it to do.

But even the reason for the fax was annoying! Our baby-delivering hospital, the sleek, modern NYU Langone, got flooded in the storm, and we've been bumped to the less salubrious NY Downtown. Right, lots of people had actually bad storm outcomes and we're going to not whine about it (apart from right now, when I'm absolutely going to whine about it, but then it'll be out of my system I promise), but it does seem to be a step down in terms of facilities and attitude. It'll be more 'hospitally', I think. Well, we'll know more when we take a tour, but for now the most visible impact is that we change from sending off crisp downloadable pdfs to badly photocopied faxes. I filled out the labour and delivery admission form today and was bemused to note that after the blurry lines for "Name", "Address", "Date of birth", "Race" and "Gender" (which, in itself, is an interesting question to see on a maternity form), the next question was "Mother". What? Whose? I added a cover sheet to the fax, like it was 1994 or something, and included my email address for any followup questions.