Thursday, December 29, 2011

jQuery Mobile swiperight too sensitive

While adding functionalities that triggers when the jQuery Mobile swiperight event is fired, I met the same problem as ade_cd, where the swiperight event gets triggered even when I am scrolling a page. On examining the jQuery Mobile 1.0 source code, I realized that the jQuery Mobile team has taken his suggestion and made the previously hardcoded values into parameters.

The parameters should be changed after the jQuery Mobile script has loaded. Here is the _Layout.cshtml file I’m using for my ASP.NET MVC 3 project.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1.0, width=device-width" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/themes/red-blue/RedBlue.min.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/themes/red-blue/jquery.mobile.structure-1.0.min.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.mobile-1.0.min.js")" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {             // huan086: Swipe right is way too sensitive on iPhone 4S and gets triggered even when scrolling vertically.
            // Set the horizontalDistanceThreshold to 50% of screen to make sure that it does not get triggered accidentally.
            $.event.special.swipe.horizontalDistanceThreshold = Math.min($(document).width() / 2, 160);         });     </script>
</head>
<body>
    @RenderBody()
</body>
</html>

Thursday, December 08, 2011

Getting the DayOfWeek in Linq to Entities

Entity Framework has several pros and cons. The pros of strongly typed objects and shorter code compared to the equivalent SQL kept me from going back to using SqlCommand directly. However, I met another cons of Entity Framework today — that is the lack of support for DateTime.DayOfWeek.

I have a table [Booking] with a column [StartDateTime]. Using the following code results in an error.

var bookings = from b in this.db.Bookings
               where b.StartDateTime.DayOfWeek == DayOfWeek.Monday
               select b;

The yellow screen of death says

The specified type member 'DayOfWeek' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

The solution I found on MSDN forums is to use SqlFunctions.DatePart. However, it is a suboptimal solution, as I’ll be effectively tying myself to using MS SQL only. Even worse is the fact that the return value of the weekday (dw) date part depends on the value that is set by SET DATEFIRST. To get a value regardless of the DATEFIRST settings, I’ll have to use (@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7, which is a statement that cannot be translated to Linq to Entities.

Luckily, Curt’s answer at StackOverflow inspired me. Instead of using DatePart, I can count the number of days from a base date which I know the day of week. Getting the remainder after dividing by 7 would then give me the day of week. So the final code looks like

DateTime firstSunday = new DateTime(1753, 1, 7);
var bookings = from b in this.db.Bookings
               where EntityFunctions.DiffDays(firstSunday, b.StartDateTime) % 7 == 1
               select b;

I have chosen the year 1753 because that is the earliest that the datetime datatype in MS SQL supports, and is way earlier than any dates that I will be using.

Tuesday, November 22, 2011

Enkompass 11.30 unfit for ASP.NET hosting

After facing various issues with Enkompass, I’m giving up on it and moving to Plesk. I shall document the issues to remind myself not to go back to Enkompass until the issues are resolved. Hopefully, this also serves as a guide to those evaluating whether Enkompass caters to their needs.

  1. Enkompass supports only one ASP.NET application. There is no way to configure virtual directories or new ASP.NET application in subdirectories. This is a blocker if you wish to have a different application, say landing page on www.example.com, and a separate blog application on www.example.com/blog.
  2. The workaround for the one ASP.NET application limitation is to use subdomains. Each subdomain supports one ASP.NET application. So you can have a landing page on www.example.com and your blog on blog.example.com.
  3. However, I need to secure all communications, so I had to install an SSL certificate to enable HTTPS. SSL works on a per IP basis. There are two types of SSL – one which secures one domain only, and another called a wildcard certificate that secures multiple domains. Enkompass supports only one dedicated IP per account, so getting many one domain certificates is not an option.
  4. As for getting a wildcard certificate, Enkompass does not allow me to change the host field of the CSR to *.example.com, so wildcard certificate can’t be used as well. Moreover, there are reports that even if you are successful in generating a wildcard CSR using WHM, when accessing the HTTPS subdomain, web pages from the main domain get served out instead.

Enough of Enkompass. Simple interface, crippled internals.

Tuesday, May 10, 2011

Recovering DotNetNuke Host menu after unchecking Include in Menu

The Admin and Host pages in DotNetNuke can be hidden from the menu, just like other pages. However, a bug in DotNetNuke causes the Host page to lose its connection to its subpages. Luckily, it is reversible, as mentioned in http://www.dnncreative.com/Forum/tabid/88/aft/31023/Default.aspx. Just type the following

UPDATE {databaseOwner}[{objectQualifier}Tabs] SET PortalID = NULL WHERE TabID = 7

in /Host/SQL/tabid/21/portalid/0/Default.aspx, check Run as Script and execute.

For those who check Include in Menu after unchecking it, there will be a red admin border saying Visible By Administrators Only on the Host page. To remove it, run the following script

DELETE FROM {databaseOwner}[{objectQualifier}TabPermission] WHERE TabID = 7

Wednesday, April 20, 2011

Prevent getting disconnected/blocked from school network when running virtual machine

In Nanyang Technological University’s (NTU) Local Area Network (LAN), whenever one plugs a personal router into a LAN port, the port will be blocked for 10 minutes. If the router is still present after 10 minutes, it gets blocked again. This is probably to ensure that nobody connects a wireless router/access point and turn the non-password secured physical port into a wireless one.

However, this security measure interferes with virtual machines as well. Whenever I start XP Mode, VirtualPC or VirtualBox, I get disconnected from the network. This is probably due to virtualization turning my network card into a Network Address Translation (NAT) device, thus appearing as a router from the outside.

The solution is to connect to NTU Virtual Private Network (VPN) first. Instructions can be found at http://www.ntu.edu.sg/cits/itnetworking/remoteaccess/Pages/quickstartguide.aspx#sslvpn. By doing so, I can access the Internet both from my host and guest OS without getting blocked.

Sunday, February 27, 2011

Bing Maps 7 API bug in MouseEventArgs.getX and getY

The new Bing Maps is a lot more lightweight, and the changes in event handling makes more sense. For example, it is now possible to detect viewchangeend event instead of using an assortment of onendpan, timers and getCenter to detect whether the view has changed.

However, I ran into the same problem mentioned here http://www.ms-windows.info/Help/map-control-v7-mouse-wheel-double-29660.aspx. The mouse wheel and double click do not zoom at the location of the mouse. Worse still, adding a pushpin when the user clicked on the map results in the pushpin being placed too high up on the map. How much higher the pushpin is placed also depends on the browser used.

Upon investigating the MouseEventArgs.getX and getY functions, I found that they depended on getViewportX and getViewportY functions. By replacing the getViewportY function with one that uses jQuery to calculate the correct offset, I managed to get the mouse wheel, double click and pushpins to all work correctly.

var map = new Microsoft.Maps.Map($("#map")[0],

{

    credentials: "",

    center: new Microsoft.Maps.Location(1.35, 103.82),

    zoom: 11,

    showDashboard: false

});

 

map.getViewportY = function () {

    return $("#map").offset().top + $("#map").height() / 2;

};

However, it does introduce a problem whereby the dashboards navigations no longer work correctly and the view type menu displays too far down. It thus necessitates writing my own dashboard.

Tuesday, February 08, 2011

Oddities of Facebook events API

Using the the Graph API of https://graph.facebook.com/[userId]/events, one can retrieve the events that the user is attending. The same applies to page, using https://graph.facebook.com/[pageId]/events. However, what does it mean by the event attended by a page? It is not the same as the events created by the page, as the API returns less results that what you would see in the events tab of the page. The result return from FQL and REST API are similar.

After spending an entire day figuring out what happens behind the scene, I came to the following conclusion:

  1. User A creates Page P.
  2. User A makes User B also the admin of Page P.

During creation of event:

  1. If User A creates event on Page P, Page P will be attending the event.
  2. If User B creates event on Page P, Page P will not be attending the event.

Unfortunately, as FQL does not allow querying the event by its creator, there is hence no way to fool-proof way to get the events that a page has created.

Monday, February 07, 2011

Oddities of Facebook event date/time

Facebook is very popular globally, crossing several time zones. Yet to my surprise, it has no concept of time zones. Quote from the Legacy REST API

Note that the start_time and end_time are the times that were inputted by the event creator. Facebook Events have no concept of timezone, so, in general, you can should not treat the value returned as occurring at any particular absolute time. When an event is displayed on facebook, no timezone is specified or implied.

However, using the Graph API to retrieve events of a page, I got the following:

{
  "data":
  [
    {
      "name":"Event Name",
      "start_time":"2010-11-20T02:30:00+0000",
      "end_time":"2010-11-20T03:00:00+0000",
      "location":"5th Street",
      "id":"1234"
    }
  ],
  "paging":
  {
    "previous":"https:\/\/graph.facebook.com\/11\/events?access_token=15\u00257&limit=5000&since=2010-11-20T02\u00253A30\u00253A00\u00252B0000",
    "next":"https:\/\/graph.facebook.com\/11\/events?access_token=15\u00257&limit=5000&until=2010-09-22T01\u00253A29\u00253A59\u00252B0000"
  }
}

The start_time and end_time are displayed as GMT+0. These times are 8 hours late. On some other events, they are 7 hours late. Clearly, Facebook is trying to store the time in GMT, but isn’t using the correct time zone where I am at.

According to http://www.webos-internals.org/wiki/Facebook_timezone_issue, Facebook assumes all time to be in Pacific Time. Thus the GMT-8 during Standard Time and GMT-7 during Daylight Savings.

In order to use the time from the Graph API, I used the TimeZoneInfo to convert the time from GMT to Pacific Time. Code as follows

private static PacificDateTime StringToDate(string value)
{
    DateTime fakeUtc = DateTime.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
 
    // See http://www.webos-internals.org/wiki/Facebook_timezone_issue.
    // Facebook assumes all time in events to be in Pacific Time.
    const string pacificTimeZoneId = "Pacific Standard Time";
    TimeZoneInfo pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById(pacificTimeZoneId);
    DateTime pacificTime = TimeZoneInfo.ConvertTimeFromUtc(fakeUtc, pacificTimeZone);
 
    return new PacificDateTime(pacificTime, pacificTimeZone.IsAmbiguousTime(pacificTime));
}

By treating all times as Pacific Time, Facebook introduced oddities to places that do not practise daylight savings, or that has daylight savings on a different schedule. Effectively, there is no way for me to meet on 13 March 2011 at 2.30am. Since daylight savings starts at 2am on the 2nd Sunday of March, and it adjusts the clock to 3am, 2.30am is an invalid time in Pacific Time. Events specified as 2.30am becomes 3.30am.

On the 6 November 2011, daylight savings ends and the clock jumps back an hour. This creates ambiguous time between 1am and 2am, which Facebook behaves in a very weird way when creating events that are at that time. Try it for yourself.