Dreaming after waking

A few weeks ago I had a disturbing and yet intriguing experience. I was having a pretty typical nightmare—being chased by monsters, unable to get away, that old chestnut—when I suddenly woke up… but could still see the dream continuing on. I've heard of sleep paralysis and false awakening, and having experienced both can say this was completely different.

I normally forget dreams pretty quickly, but luckily I jotted down as much information as I could as soon as I woke up…

How the dream started

(Not that this has anything to do with what I experienced, but I still want to include all that I remembered.)

I was running around the city streets, in some sort of race/fun-run. We were running laps around the city and each lap was taking me over an hour to complete. After each lap for some reason I had to go into an apartment and rest. I was annoyed because the next lap I'd finish would be around lunch time, and the elevators would be busy. I woke up after resting for half an hour, and quickly went to take the elevator down to keep running. But everyone was looking at me strangely. I realised I was still wearing pyjamas, but I was already falling behind in the race from resting too long, so I couldn't afford the time to change.

Back on the streets, I was trying to run quickly but couldn't (I'm sure most people have had that dream before, where no matter how hard you try to run you just can't!). Everyone kept overtaking me but there wasn't anything I could do about it.

While I was running I had an overhead view of the city that looked like old Google Maps. It looked like New York City, lower Manhattan. I was talking to my wife (not on the phone, but telepathically). She was telling me to look at some building I was passing, but I couldn't look at it. It was a Russian embassy or consulate or something, and it was blurred out, like what Google Street View does (I'm dreaming far too much about Google products).

I kept running, and was coming back around to finish a lap, so needed to head up to the apartment again. But now I was running on road (with traffic no less), and was in the wrong lane. I had to cut across traffic, but I missed my exit anyway and had to u-turn.

I finally made it to the apartment, and started to head up…

Uneasiness sets in

I was in the elevator with some other people. One of them was an ex-colleague from almost sixteen years ago, but we didn't acknowledge each other. I was going up to level fourteen, she got out at six. The elevator kept going, and something started to feel a bit wrong, but I couldn't put my finger on what. The doors opened at twelve, and for some reason I got off there.

The corridor was dimly lit, and while it wasn't dirty, it looked dated and old-fashioned. Pale apricot and burnt orange. I couldn't remember the apartment number I was supposed to go to (presumably to rest, but I think the running part of the dream was well and truly over). I knew it was an even number, but I was feeling lost. I was looking at the apartment numbers on the doors, and saw 1208, which seemed right. So I opened the door.

It was a big, empty apartment. Tiled floor. All the lights were out, and the light from the hallway quickly vanished into darkness. I could hear music and people talking, but off in the distance, like they were in a back room with the door closed. As the door opened further, a chime-bell rang, like those in small shops to alert the clerk someone has entered. I hear them call out wondering who is there. I shout an apology, close the door, and start to walk away quickly.

Someone came out of the apartment to see who was there. A girl. She looks the other way down the hall first, so I can't see her face, but I know I don't want her to see me, so I hide behind a pillar. Thankfully, she goes back inside.

I see another door: 1206. This door looks old and shabby, with peeling faded paint. It says "class" below the number, which is weird. I open the door, and it's a small janitorial closet.

And so begins the terror…

The nightmare begins

Inside the room/closet/cupboard is a school-boy, standing in a mop-bucket, wrapped in a plastic shower curtain covering his face and upper body. Just standing there. Motionless. Completely inanimate. He's wearing private school maroon uniform with gold trim, but it looks dirty and disheveled. I felt my body go cold, and my stomach start churning.

I could tell it was from a Korean urban legend (in the dream, anyway. I'm sure there are equally terrifying Korean stories in real life). I knew I had to get away before he woke up. I tried to backtrack as quickly as I could, but it was too late. He jerked into life, and threw the shower curtain off of him. He had a long matted fridge obscuring most of his face, but I could see his face was scarred with deep scratches that looked like old knife-slice wounds.

As I tried to retreat down the hallway, he came out of the room to chase me, but in a jerky, non-fluid motion, like a bad attempt to portray a zombie. He was swiping at me, trying to claw at my face.

And then I woke up.

Just a dream. It's over. Right?

I woke up in a sweat, I could still feel chills from being terrified. I knew I really was awake. I could hear my wife breathing next to me. I could feel my new watch slightly irritating my wrist, as I got used to wearing a watch at night (sleep tracking, shame it doesn't have in built HRM!). I could feel gravity pulling me into the mattress, hear traffic outside, and all that stuff that you just don't feel in a dream.

And then, as I started to open my eyes to think about what I'd just dreamt, I saw the hallway. I saw the school-boy/zombie/monster closing in on me. But I still saw my bedroom. It wasn't like I was hallucinating actually being in the hallway, or having the sensation of actually being in the dream again. I could just see it. It was like there was something projecting a faint image of the dream sequence in front of me. The image was about fist-sized if held out at arm's length, and the "playback" seemed grainy and stuttering along at about 10fps, and no sound. Almost like looking at Fry playing the holophonor from Futurama.

Fry from Futurama playing a holophonor, projecting a visual image to the audience
Like watching a nightmare through the holophonor…

It took me by surprise. I tried to see the image better, so closed my eyes. But alas, it vanished! I opened my eyes slightly, and it reappeared. Opening my eyes fully, I lost it in the relative brightness of the room. So keeping my eyes half open, I could see it best. I could see the boy swiping at me from my perspective (the me in the dream). Then "camera angle" changed and now I could see myself. But it didn't look exactly like me, like I was older and had a heavily weathered face, or wearing a poorly fitting rubber mask. I was mouthing something. Help me! Don't! Whatever it was, I could only guess. Even though it was my mind making all this stuff up, I didn't know what I was saying.

It cut back to the boy, getting closer, still swiping at me. Back to me. Back to him. I tried to "direct" the dream, but I couldn't.

After what seemed like a minute, maybe two, the dream started fading and eventually disappeared to nothing.

What does it all mean?

I have never experienced anything like this before, nor since. I've had sleep paralysis before which is pretty terrifying while it's happening, this wasn't terrifying once I had actually woken up. I felt uneasy, but more curious than anything.

I didn't find any similar experiences while researching (and by "research" I mean I ventured to page two of Google search results). Working on the basis that a lot of brain activity occurs during certain stages of sleep, and that some part(s) of the brain try to make sense of this activity, a dream is the result. Going with this, it seems like after I suddenly woke, whatever brain activity was resulting in that dream, or whatever process was responsible for generating the dream based on some such activity, was continuing. So I continued to experience the dream. Maybe whatever jolts your brain back to reality when you awaken didn't function properly this time.

I have no idea if that's even remotely plausible, or if it even means anything. But whatever the reason, I hope that it's not indicative of a deeper problem!

Turning 20

I recently turned 20; hooray for me! As nice as that would be, unfortunately it would only accurate in base 16.

Sigh. I'm actually 32.

Thirty-two is a power of two (that is, 25 = 32), so it stood out to me given my career in computer science (also the number of bits used to represent integer datatypes I typically have to deal with). It then dawned on me that the next 2n birthday I get to celebrate is, of course, another 32 years away. That's a long time to go; but given the life expectancy for Australian men is just over 80 at the moment, I should be able to see it through. I wonder though, what is the probability of actually surviving the next 32 years?

If I understand the life tables properly, and my memory from uni stats classes serves me correctly, multiplying the px values from 32 to 63 should give me the probability of surviving to 64 (since px is the probability of surviving to x+1 years old). That gives me 89.5%. Sounds reasonable, I'll take those odds.

Life Tables
Life Tables

On to something lighter, I did some really in depth research on fascinating facts about the number 32. And by "in depth research", I mean I skimmed the Wikipedia article while commuting to work. Here are the highlights:

  • Fifth power of two (25)
  • Is a Leyland number; a number that can be written as xy + yx (24 + 42 = 32)
  • Is a happy number, yay! (See below)
  • 11 + 22 + 33 = 32
  • Relating to chess, both black and white have 32 squares of their respective colour on the board; also the total number of pieces on the board. (Also, I suck at chess.)
  • Number of teeth in an adult human, including wisdom teeth. I've had three wisdom teeth removed, the fourth doesn't seem to exist (cue jokes about not being so wise)
  • As mentioned, number of bits commonly used to represent integer data type
  • Number of bits in an IPv4 address
  • Twice the number of kilometers I've ever run in a single effort (so far!)

I'm pretty sure happy numbers and Leyland numbers serve no purpose other than recreational mathematics, but like I said, skimming Wikipedia is about as far as I'm willing to go on this subject.

Here's how 32 breaks down as a happy number:

  • Start with 32
  • 32 + 22 = 9 + 4 = 13
  • 12 + 32 = 1 + 9 = 10
  • 12 + 02 = 1 + 0 = 1
  • 1 (happy!)

So that was a bit of useless fun :-)

Fix for SharePoint 2013 and anonymous RSS

I have previously written about an issue stopping anonymous users accessing RSS feeds with SharePoint 2013 when ViewFormPagesLockdown is enabled. While I managed to develop a work around for the client I was working with at the time, I completely neglected to write it up so others could benefit. What a rube.

I've put an example solution up on Github, hopefully someone will find that useful. Here's what it does:

As mentioned in the linked post, the problem stems from Microsoft changing the permissions on the RssXslt.RightsRequired property to include ViewFormPages in SP2013:


protected override SPBasePermissions RightsRequired {
    get {
        return SPBasePermissions.ViewFormPages | SPBasePermissions.Open;
    }
}

The basic workaround idea is this:

  1. Deploy a new layouts page that inherits from RssXsltPage and override the RightsRequired property to return an appropriate value (i.e. what SharePoint 2010 returns)
  2. Use IIS rewrite/redirect any calls to /_layouts/15/rssxslt.aspx to my layouts page instead

So I created a blank solution, added a mapped folder to Layouts and added an ASPX page RssXslt.aspx. I inherited from Microsoft.SharePoint.ApplicationPages.RssXsltPage, and overrode RightsRequired to return whatever the OOTB RssXsltPage class returns, except for ViewFormPages:


protected override SPBasePermissions RightsRequired
{
    get {
        return base.RightsRequired & ~SPBasePermissions.ViewFormPages;
    }
}

I could have just returned Open permissions, but on the off chance the base permissions ever change, this will allow those changes to flow through.

Now for the catch… the original RssXslt.aspx isn't just an empty ASPX file driven completely by codebehind—it contains a bunch of XSL and server controls that are required for the base class to function. There's probably a better way to do this, but I simply copied everything except the directives from the OOTB RssXslt.aspx into my RssXslt.aspx.

Deploying this to my test farm and confirmed anonymous users can in fact view my version of the ASPX, and yet still get challenged to authenticated for the OOTB ASPX. Score!

For the final touch—IIS rewrites. It's no good having an accessible stylesheet if the RSS feed is still pointing to the broken one. And unfortunately the feedlist.aspx code-behind isn't feasible to hack around. So IIS rewrites will have to do. I want to rewrite anything containing /_layouts/15/rssxslt.aspx to point to my page. The solution I built is named AnonymousRs, so it will need to rewrite to /_layouts/15/AnonymousRss/rssxslt.aspx:


<rule name="RssXslt For Anonymous Users">
    <match url="^(.*/_layouts/15/)(rssxslt.aspx)" />
    <action type="Redirect" url="{R:1}AnonymousRss/{R:2}" />
</rule>

You can use IIS management console to do this of course. One thing to be aware of: if you're running this on a farm with multiple web front ends, each WFE will need this configuration applied. The solution could be changed to use SPWebConfigModification to let SharePoint handle pushing the changes to all WFEs, but damned if I'm touching that mess of a process for a simple work around :)

Here's the before and after. In this case I've configured IIS to redirect rather than rewrite, just so it's easy to see IIS is actually doing something:

RssXslt.aspx auth challenged
RssXslt.aspx auth challenged
Redirected to fix RssXslt.aspx. All good!
Redirected to fix RssXslt.aspx. All good!

How LastPass autofills on Chrome for Android

I had never really thought too much about how LastPass autofills passwords on Chrome for Android, but I found out something a little interesting today.

There was something that always bugged me about pre-filling passwords in Chrome for Android that never seemed to occur when pre-filling in native apps; I'd always see my recent searches briefly pop-up underneath the LastPass overlay:

Search history showing up under the LastPass overlay
Search history showing up under the LastPass overlay

It got me thinking… if LastPass is causing my search history to appear, is it putting focus in the address bar? If so, why?

I then realised why you're asked to "Touch Go or ↵" to autofill: LastPass is loading JavaScript in the address bar, hiding it with the overlay, and essentially getting you to run the snippet by press Go/↵.

I was able to get my browser in to a bit of a funny state, such that the address bar was full of forward slashes:

Address bar in Chrome for Android showing all forward slashes
Address bar in Chrome for Android showing all forward slashes

That seems suspicious. I was able to copy/paste it elsewhere and take a peek.

Sure enough, it's JavaScript searching the DOM for appropriate fields to populate with credentials! Interestingly, it's not hard coding any field IDs, selectors, or anything that would prevent the form fill from working even if the site owners completely changed their site layout. Neat! I guess the stacks of trailing slashes were meant to make the address bar look innocuous enough, should someone manage to get their browser to this state, that it would be ignored.

I won't post the code. While it doesn't seem to contain anything overly secretive, it's still probably not something LastPass want readily available. Of course "readily available" probably isn't overly accurate on a site that gets about 2 visits per day ☺ (or rather, ☹).

Calendar Overlays with Managed Navigation

I'm currently doing some work for a client to implement an intranet using SharePoint 2013, and one of their requirements is a simple calendar using overlays to colour code events.

The short

Calendar overlays aren't listed on calendar views when accessing the view via managed navigation unless you explicitly include the view ID in the target URL of the navigation term settings.

The long

This should be pretty straight forward, and works well enough:

Directly loading calendar list view with overlays

They're also using Managed Navigation on their site. No worries, surely calendar overlays and managed navigation don't interfere with each other, right? Oh wait, this is SharePoint, of course something will go wrong!

The above screenshot was taken when accessing the actual URL (~sitecollection/Lists/Events/calendar.aspx), while the below screenshot was taken when accessing the managed navigation term which pointed to the aforementioned URL (i.e. ~sitecollection/events is configured to display ~sitecollection/Lists/Events/calendar.aspx):

Calendar list view via managed navigation (note lack of overlay list)

Where is the list of calendar overlays?! Everything else works as expected: the events are colour coded, you can add events, use the ribbon to switch views, use the side navigation to change the viewed month. Just the list of overlays is missing.

After poking around a bit (in none other than SPView.ServerRelativeUrl. As the request URL is a friendly URL from managed navigation, it doesn't match any view URLs. As no views are matched, the component can't determine it's looking at calendar view, so doesn't render.

Stepping through the code:


// Microsoft.SharePoint.ApplicationPages.WebControls.CalendarAggregationPanel
protected override void CreateChildControls()
{
    this.Visible = this.IsVisible();
    if (!this.Visible)
    {
        return;
    }
    // …
}

The CalendarAggregationPanel is just the list of overlays. The IsVisible method determines if the control should be visible (shocking! =P).


// Microsoft.SharePoint.ApplicationPages.WebControls.CalendarAggregationPanel
private bool IsVisible()
{
    // …
    SPView view = SPContext.Current.ViewContext.View;
    if (view == null || SPViewCollection.StringToSPViewType(view.Type) != SPViewCollection.SPViewType.Calendar)
    {
        return false;
    }
    // …
}

Ok, so it gets the view and determines the SPView.Type. But my SPView was coming back null, so let's look at the property definition:


// Microsoft.SharePoint.SPViewContext
public SPView View
{
    get
    {
        if (this.m_view == null && this.ParentContext.List != null && this.ViewId != Guid.Empty)
        {
            // …
        }
        return this.m_view;
    }
}

And ViewId was returning Guid.Empty. And herein lies the problem. Looking at that property:


// Microsoft.SharePoint.SPViewContext
public Guid ViewId
{
    get
    {
        if (!this.m_isViewIdSet)
        {
            string text = this.ParentContext.HttpRequestContext.Request.QueryString["View"];
            if (string.IsNullOrEmpty(text))
            {
                text = this.ParentContext.HttpRequestContext.Request.QueryString["ShowWebPart"];
            }
            if (!string.IsNullOrEmpty(text))
            {
                try
                {
                    this.m_viewId = new Guid(text);
                }
                // catches setting to Guid.Empty
            }
            if (this.m_viewId == Guid.Empty && this.ParentContext.ItemId == 0 && this.ParentContext.FormContext.FormMode == SPControlMode.Invalid)
            {
                SPList list = this.ParentContext.List;
                string originalServerRelativeRequestUrl = SPUtility.OriginalServerRelativeRequestUrl;
                if (list != null && originalServerRelativeRequestUrl != null)
                {
                    foreach (SPView sPView in list.LightweightViews)
                    {
                        if (originalServerRelativeRequestUrl.StartsWith(sPView.ServerRelativeUrl))
                        {
                            this.View = sPView;
                            break;
                        }
                    }
                }
            }
            this.m_isViewIdSet = true;
        }
        return this.m_viewId;
    }
}

This attempts to get the view ID from either query string parameters (which aren't set in any case, but we'll come back to that because it's useful to know), and then tries to figure it out based on the request URL. As SPView.ServerRelativeUrl is the actual SharePoint URL (e.g. ~sitecollection/Lists/Events/calendar.aspx), no view is matched.

To test this a bit more, I changed my browser to load http://servername/events?View={view-id} and like magic the calendar overlays were listed as expected.

We can use this to work around the problem. Having ~sitecollection/events?View={view-id} is pretty ugly, but we can actually include this is the target URL for the navigation term (e.g. ~sitecollection/Lists/Events/calendar.aspx?View={view-id}), and it will get included in the HttpRequest.QueryString collection. Brilliant! Of course, that means you need to hard-code a GUID in your term sets, which isn't ideal, but "ideal" and "SharePoint" don't mix!

Query string in navigation term target URL
Calendar view with overlay list via managed navigation