Tuesday, April 15, 2014

Private domain SSL setup on Winodws Azure VM

Nine years of programming life, and finally I got the chance to setup the domain & SSL on my own. Usually I work in enterprises, this will be done by MIS guy and programmer will be shut-off from production environment. With the new job and as a new back-end department pioneer, here comes the opportunities.

For the first few steps, I'll show more on hosting with Windows Azure, if any other hosting company, the steps will be roughly the same.

1) Hosting with Windows Azure: You have to purchase a cloud server. My case I use: http://azure.microsoft.com/en-us/. You can start with trial plan but it will not last long, at most few days only. Here're the few links you can start with:


It's highly recommended that you use new IE (I use IE9) for accessing Windows Azure, even for service payment. Most of the standard browsers do not work well with IE-only Windows Azure.

2) Hosting with Windows Azure: Your web binary files can be deployed through FTP, and this is the steps: http://www.intstrings.com/ramivemula/articles/enable-ftp-access-on-windows-azure-vm/

3) Hosting with Windows Azure: Remember to open the Azure HTTPS endpoints (usually is port 443) of the server:


4) Domain with GoDaddy: For hosting with Azure server, you'll get a sub-domain that looks like this: xxx.cloudapp.net. But for a HTTPS to be worked, you need your own private domain. No choice but have to buy one. My company bought one at: http://my.godaddy.com/. Mind you, there's no such thing called customer service in GoDaddy, everything is on your own. When you get the domain, go to: https://mya.godaddy.com/default.aspx?prog_id=GoDaddy&.


Click on the "Launch" near the domain and you will see the domain you purchased.


5) Domain with GoDaddy: For hooking up the domain and the Windows Azure server, some details is on here: http://blog.smarx.com/posts/custom-domain-names-in-windows-azure. The latest GoDaddy site might looks like this. Click on the "Manage" near the "Forwarding".


Add one entry of your domain here.



Click on the "DNS Zone". Change the Host,"@" to Windows Azure Virtual IP & CName,"www" to Azure DNS name. You can get this from Windows Azure Dashboard.





6) Domain & Hosting: After the TTL period, you can go to the website through the domain. You will get the standard IIS welcome page that looks like this:


7) Domain & Hosting: You have to go back to Azure IIS and add this domain to the website. Click "Add Web Site".


On the new website added, click "Bindings" and key-in the domain info.

And your website should be browsable by now.


8) SSL with GoDaddy: Now we come to final part, which is SSL. Purchase the SSL from GoDaddy. Create the certificate by following this link: http://azure.codegrains.com/2013/07/step-by-step-guide-for-implementing.html (until step 8). It takes only few minutes for SSL to be signed.


Install the SSL certificate by following this link: [To Install an SSL Certificate in Microsoft IIS 7] http://support.godaddy.com/help/article/4801/installing-an-ssl-certificate-in-microsoft-iis-7?locale=en&countrysite=my&pc_split_value=4

9) SSL: Do not forget the HTTPS binding in the new website.


And your site should be browsable through HTTPS by now.


10) SSL: After the SSL is setup, you can check your SSL security level on your server. Here're the few websites that you can check:

  1. https://sslcheck.casecurity.org/en_US (you might need to clear your cache after your first run)
  2. https://www.ssllabs.com/ssltest/analyze.html
  3. http://foundeo.com/products/iis-weak-ssl-ciphers/test.cfm

11) SSL: With default settings on Windows Server 2008 R2, most probably you'll be getting an "F".


it's because of SSL version 2 is not disabled on server. Here're the links that you can refer to.
  1. http://support.microsoft.com/kb/187498
  2. http://hosting.com/support/pci-security-scan/disable-sslv2-for-microsoft-iis7-under-windows-server-2008-64bit/
  3. http://blogs.msdn.com/b/httpcontext/archive/2012/02/17/how-to-disable-ssl-2-0-on-windows-server-2008-r2.aspx
12) SSL: After adding new entries on registry and restart the server, I got this, a "B".


13) Done! Phew, what a long way.

Thursday, January 2, 2014

Developing a FPS game with Unity3D

Almost after 10-year ago I developed some basic stuffs on OpenGL, I manage to regain some interests on developing a FPS (First-person shooter) game again. I have to admit I am not an avid-gamer, and just a casual gamer, but it's kinda fun to work on it.

There're couples of top-notch free 3D game engines in the markets, ie:
  1. Unity
  2. CryEngine
  3. Unreal Development Kit (UDK)
and many more. By starting with the game engine, you focus your work on game itself, and not the engine.

After some tries-and-errors, I chose to start with Unity. Its UI looks simple and the requirement on hardware spec is low, if compare with CryEngine & UDK. The ability to export to multiple platforms, likes Apple's iOS & Google's Android, is also another reason I choose it.


For those FPS lover, I highly-recommend to try the Unity3D with this book: "Beginning 3D Game Development with Unity 4", by Sue Blackman.


Not only it guides you with some basic concept, it also comes with chapters on building a FPS game on one of the level from scratch. And for the past few months, I was following all the chapters closely and it's quite fun.

Here are some of the screenshots from the sample of the book (credit to the author)




Impressive with the graphics, huh? Why waits then? :)

You can reach the author here, and sometimes she is at Unity forum as well.
You can read some free excerption from Google Books too.

Two things bear in mind:
  • Unity is getting updated frequently, some of the old features might not available (or even works, a.k.a bugs) in new version. To follow the chapters in this book, please download a suitable version 4.2.X from here.
  • There're couple of erratas in the book, my suggestion is: please open the finished chapter along with you own project, side-by-side, to compare whenever something's wrong.

Tuesday, November 12, 2013

Access Denied: XXX needs the following permission(s) to perform this action: View collection-level information

Due to some mis-understanding, my windows account in server that hosts TFS 2010 was deleted, thru 'Computer Management->System Tools->Local Users & Groups'. Then I found I got problem to log-in.


After I added my account back, I encountered this error message when connect to VS2010:

Access Denied: 'XXX\gan' needs the following permission(s) to perform this action: View collection-level information.


At the TFS server, I launched the "Team Foundation Server Administration Console", I found my windows account is still there. I know my account is not associated with TFS properly anymore.


From MSDN: Team Foundation Server Permissions, it got something to do with 'Project-Level Permissions':

Permission Name
Name at Command Line
Description
Create test runs
PUBLISH_TEST_RESULTS
Users who have this permission can add and remove test results and add or modify test runs for the team project.
Delete team project
DELETE
Users who have this permission can delete the project for which they have this permission from Team Foundation Server.
Delete test runs
DELETE_TEST_RESULTS
Users who have this permission can delete a scheduled test for this team project.
Edit project-level information
GENERIC_WRITE
Users who have this permission can edit project-level permissions for users and groups on Team Foundation Server.
Manage test configurations
MANAGE_TEST_CONFIGURATIONS
Users who have this permission can create and delete test configurations for this team project.
Manage test environments
MANAGE_TEST_ENVIRONMENTS
Users who have this permission can create and delete test environments for this team project.
View project-level information
GENERIC_READ
Users who have this permission can view project-level group membership and the permissions of those project users.
View test runs
VIEW_TEST_RESULTS
Users who have this permission can view test plans in this node.


Browsing from 'Source Control Explorer', I really got no idea whether is my account still there. Can you tell??



No choice, I have to remove and re-add. After adding my windows account in the "Team Foundation Server Administration Console->Administration Console Users-Add", no error logged but my windows account is not there.


I opened the log, and found there's an error.
[Info   @01:36:05.790] -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
[Info   @01:36:05.790] Running Readiness Checks ...

[Info   @01:36:05.790] -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

[Info   @01:36:05.791] 

[Info   @01:36:05.791] -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

[Info   @01:36:05.791] Activity.Verify

[Info   @01:36:05.792] -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

[Info   @01:36:05.797] Verify: AccountsChecks(VCONTAINER): Starting Verification

[Info   @01:36:05.797] A generic container node that does not contribute to results

[Info   @01:36:05.797] "Verify: AccountsChecks(VCONTAINER): Exiting Verification with state Ignore and result Ignore"

[Info   @01:36:05.798] Verify: AccountsChecks\Verify Accounts Feature(VCHANGEFEATURE): Starting Verification
[Info   @01:36:05.798] Verifies a condition
[Info   @01:36:05.798] "Verify: AccountsChecks\Verify Accounts Feature(VCHANGEFEATURE): Exiting Verification with state Completed and result Success"

[Info   @01:36:05.798] Verify: AccountsChecks\Verify Accounts Account(VACCOUNTVALID): Starting Verification

[Info   @01:36:05.798] Verifies the account is a valid account

[Info   @01:36:05.799] "Verify: AccountsChecks\Verify Accounts Account(VACCOUNTVALID): Exiting Verification with state Completed and result Success"

[Info   @01:36:05.799] Verify: AccountsChecks\SqlLogin(VSQLLOGIN): Starting Verification

[Info   @01:36:05.799] Verifies the given account does not already have a SQL login that is denied access or with the wrong SID

[Info   @01:36:05.801] Verifying SQL login of account XXX\gan does not exist on XXX\SqlExpress, or if it exists, it does not have a different SID and it is not denied access to the server.

[Error  @01:36:05.805] The login for the given account has the wrong SID.

[Error  @01:36:05.805] !Verify Error!: TF255441: An orphaned SQL Server login is associated with the following account: XXX\gan. The login has an incorrect security identifier (SID). The server selected to host the databases for Team Foundation Server is: XXX SqlExpress. You must delete the login from the SQL Server instance on that server.

[Info   @01:36:05.805] "Verify: AccountsChecks\SqlLogin(VSQLLOGIN): Exiting Verification with state Completed and result Error"

[Info   @01:36:05.805] Verify: AccountsChecks\DBExists(VDBEXISTS): Starting Verification

[Info   @01:36:05.805] Sql Database Existance Verification

[Info   @01:36:05.809] "Verify: AccountsChecks\DBExists(VDBEXISTS): Exiting Verification with state Completed and result Success"

[Info   @01:36:05.809] !Verify Result!: 4 Completed, 0 Skipped: 3 Success, 1 Errors, 0 Warning
Looks like TFS only cater an account when it does not exist, but it cannot re-create the account due to security issue.

So, I have to go to MSSQL-Express and remove my windows account.


You can check the DB used in 'Data Tier Summary' at "Team Foundation Server Administration Console" (more info at 'Team Foundation Server Databases'):


After adding my windows account again in the "Team Foundation Server Administration Console->Administration Console Users-Add", everything is ok!
[Info   @01:51:33.399] -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
[Info   @01:51:33.399] Adding account to collection databases ...

[Info   @01:51:33.399] -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

[Info   @01:51:33.400] Getting collections...
[Info   @01:51:33.401] Changing collection: DefaultCollection
[Info   @01:51:33.403] ConnectionString: Data Source=XXX\SqlExpress;Initial Catalog=Tfs_DefaultCollection;Integrated Security=True

[Info   @01:51:33.405] ModifyExecRole: Add:XXX\gan

[Info   @01:51:34.498] result: Success

[Info   @01:51:34.499] Added XXX\gan to Tfs_DefaultCollection (XXX\SqlExpress)

[Info   @01:51:34.499] Changing collection: YYY

[Info   @01:51:34.502] ConnectionString: Data Source=XXX\SqlExpress;Initial Catalog=Tfs_YYY;Integrated Security=True

[Info   @01:51:34.503] ModifyExecRole: Add:XXX\gan

[Info   @01:51:35.381] result: Success

[Info   @01:51:35.381] Added XXX\gan to Tfs_YYY (XXX\SqlExpress)

[Info   @01:51:35.388] ADDCOLLACCOUNT Completed.

[Info   @01:51:35.389] Starting Node: ADDSYSTEMDBACCOUNT

[Info   @01:51:35.389] Add account to system dbs

Done. (You might need to re-map your work-space after this)

Thursday, September 26, 2013

Create failed for User 'XXX' when restoring a database

Recently I was doing the database (let's say: 'restoreTest') migration in MSSQL 2008 from one instance to another.


There's an existing login (let's say: 'restore' in picture below) that I need to bring along with this 'restoreTest' database migration.


1) When I went to create a new login and assign the access-right of the newly-created 'restore' account to the new 'restoreTest' database restored in the new instance,


2) I encounter this error message:

Create failed for User 'XXX'
User, group, or role 'XXX' already exists in the current database. (Microsoft SQL Server, Error: 15023)


3) The new 'restore' user is created but it's not associated with  'restoreTest' database.
I was so curious what went wrong. After a check, I  found the user 'restore' was backed-up along with the database.


4) After I deleted the user 'restore' that comes in the newly-restored 'restoreTest' database & , and re-assign it, then everything is OK.

Monday, August 26, 2013

Web-based Javascript Interactive map makes easy with SVG

Recently I was thinking what else can i come up with, after seeing the successful story of the Waze, by using the world map. With the advancement of the html5, it can be done easily with canvas and SVG.

Of course, there's a lot of ready-made powerful tile-based detailed map API, eg.
1) Google Maps JavaScript API v3.
2) jquerygeo
3) leafletjs

However, the subtleness of them is beyond comparable with svg path-based map, with the aid of GPS and millions of dollars pumps by them.

Few of the prominent sites in Javascript svg path-based interactive map are:
1) jvectormap
2) amMap

So sad that my country of origin, Malaysia, is too small to be included by them. "Hey, why don't I create my own Interactive map", struck my mind.

Let's get started.
1) I need a map of my country. With the help of Google Image Search, there's plenty of them. Any image format will do, the important thing is the plain background. Beware of the infringement of the propriety though.

2) Once you find the proper image, you can using all sorts of image converting software to turn it into a .svg file. One option is Adobe Illustrator, if you are a designer. If you are just some independent programmer, online tool like Vector Magic, might be a good friend of you. Choose high-resolution when you do conversion.



3) Verify the newly generated .svg file if all the details are there. If not, you can use SVG-edit to add/remove the detail accordingly. Click on the particular svg-path and give a meaningful id to it. Click  twice will allow you to twist the svg-path, that something similar to spline.


4) Embed the svg element in the html page. This can be done easily.
*You might need to set/clip the width and height on the svg element, due to browser compatibility. See more here.

5) However, there's no element of interactive there. So we're gonna add it now. What we need are:

  • display the name of the region when mouse hovers
  • able to zoom
  • able to pan

6) To display the name of the region when mouse hovers, we use jquery and can be achieved easily through following code:

$(function() {
  $(".icon svg path").bind("mouseover", function( evt ) {
    var currentMap = evt.target.getAttributeNS(null,'id');
    if(currentMap != "background" 
        && currentMap != "KualaLumpur_border" 
        && currentMap != "Putrajaya_border"){
   //$(this).css('fill','blue');                            
   //$("#" + currentMap).removeAttr("fill");
   $("#" + currentMap).css('fill','blue');
   //evt.target from viewbox; text.text1 from diff cooor; need to offset
   // more complicated at: http://msdn.microsoft.com/en-us/library/ie/hh535760(v=vs.85).aspx
   var targetedPath = evt.target.getBBox();
   $(".icon svg text.text1").css('display','block')
                            .text(currentMap)
                            .attr( "x", targetedPath.x + targetedPath.width / 2)
                            .attr( "y", targetedPath.y + targetedPath.height / 2);
    }
  })
  .bind("mouseleave", function( evt ) {
    //IE9 & FF not supported
    //var currentMap = evt.target.getAttributeNS(null,'id');
    //console.log("mouseleave:" + currentMap);
  })
  .bind("mouseout", function( evt ) {
    var currentMap = evt.target.getAttributeNS(null,'id');
    if(currentMap != "background" &&
        currentMap != "KualaLumpur_border" &&
        currentMap != "Putrajaya_border"){
      //$(this).css('fill','c9c9c9');//IE9 & FF not supported
      //$("#" + currentMap).css('fill','c9c9c9');//IE9 & FF not supported
      var theCurrentMap = document.getElementById(currentMap);
      theCurrentMap.setAttribute('style', '');
      $(".icon svg text").css('display','none');
    }
  });
 });

*FireFox & IE9 does not fire 'mouseleave' event in the event bubling, so have to bind at 'mouseout' event. See more here.

7) What it does is loop through all the svg-paths, and bind the mouseover & mouseleave events. When mouse hovers, change the current element's css, then display the id of the region using a svg text on cursor's tip, with the help of  the current box selection, getBBox(), . What mouse leaves does is restoring whatever you've done on mouseover event. You might need to append this svg text programmatically though.


8) To enable the zooming capability, we use the following codes when DOM body's loads:
// Must be greater than 1. Increase this value for faster zooming (i.e., less granularity).
var zoomRate         = 1.1; 

function zoom(zoomType)
    {
  var theSvgElement = document.getElementById('svgElement');
  var viewBox = theSvgElement.getAttribute('viewBox'); // Grab the object representing the SVG element's viewBox attribute.
  var viewBoxValues = viewBox.split(' ');    // Create an array and insert each individual view box attribute value (assume they're seperated by a single whitespace character).

  viewBoxValues[2] = parseFloat(viewBoxValues[2]);  // Convert string "numeric" values to actual numeric values.
  viewBoxValues[3] = parseFloat(viewBoxValues[3]);
      
  if (zoomType == 'zoomIn')
  {
   viewBoxValues[2] /= zoomRate; // Decrease the width and height attributes of the viewBox attribute to zoom in.
   viewBoxValues[3] /= zoomRate; 
  }
  else if (zoomType == 'zoomOut')
  {
   viewBoxValues[2] *= zoomRate; // Increase the width and height attributes of the viewBox attribute to zoom out.
   viewBoxValues[3] *= zoomRate; 
  }
  else
   alert("function zoom(zoomType) given invalid zoomType parameter.");
      
  // Convert the viewBoxValues array into a string with a white space character between the given values.
  theSvgElement.setAttribute('viewBox', viewBoxValues.join(' '));
    }
        
    function zoomViaMouseWheel(mouseWheelEvent)
    {      
      //check for detail first so Opera uses that instead of wheelDelta 
      var delta=mouseWheelEvent.detail? mouseWheelEvent.detail*(-120) : mouseWheelEvent.wheelDelta 
      //if (mouseWheelEvent.wheelDelta > 0)
        zoom('zoomIn');
      else
        zoom('zoomOut');
        
      /* When the mouse is over the webpage, don't let the mouse wheel scroll the entire webpage: */
      mouseWheelEvent.cancelBubble = true; 
      return false;       
    }

 function initialize()
    {        
      /* Add event listeners: */
      // Don't let the mousewheel event bubble up to stop native browser window scrolling.
      //window.addEventListener('mousewheel', zoomViaMouseWheel, false);
      
      //FF doesn't recognize mousewheel as of FF3.x
      var mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel" 
 
      if (document.attachEvent) //if IE (and Opera depending on user setting)
        document.attachEvent("on"+mousewheelevt, zoomViaMouseWheel)
      else if (document.addEventListener) //WC3 browsers
        document.addEventListener(mousewheelevt, zoomViaMouseWheel, false)
    }

9) What it does is hooking-up the mousewheel event, and change the svg viewbox properties.
*Due to FireFox & Safari handles mousewheel event differently, we have to cater as well. See more here.

10) To enable panning, it needs a little more treatment.

// Number of pixels to pan per key press.  
var panRate          = 10;   

 var isDragging = false;
 var mouseCoords = { x: 0, y: 0 };

function hookEvent(element, eventName, callback)
    {
        if(typeof(element) == "string")
           element = document.getElementById(element);
        if(element == null)
           return;
        if(eventName == 'mousewheel')
        {
           element.addEventListener('DOMMouseScroll', callback, false); 
        }
        else
         {
           element.addEventListener(eventName, callback, false);
        }
    }
  
 function onMouseDown(e)
    {
        isDragging = true;
    }
        
    function onMouseUp(e)
    {
        isDragging = false;
    }
        
    function onMouseOver(e)
    {
        mouseCoords = {x: e.clientX, y: e.clientY};
    }
  
  function onMouseMove(e)
    {
        if(isDragging == true)
        {
           var xd = (e.clientX - mouseCoords.x);
           var yd = (e.clientY - mouseCoords.y);
           pan(xd, yd)
        }
            
        mouseCoords = {x: e.clientX, y: e.clientY};
            
        return cancelEvent(e);
   }
  
  function pan(x, y)
  {
   var theSvgElement = document.getElementById('svgElement');
   var viewBox = theSvgElement.getAttribute('viewBox'); // Grab the object representing the SVG element's viewBox attribute.
   var viewBoxValues = viewBox.split(' ');    // Create an array and insert each individual view box attribute value (assume they're seperated by a single whitespace character).

   viewBoxValues[0] = parseFloat(viewBoxValues[0]);  // Convert string "numeric" values to actual numeric values.
   viewBoxValues[1] = parseFloat(viewBoxValues[1]);
    
   viewBoxValues[0] -= x;//panRate; // Increase the x-coordinate value of the viewBox attribute to pan right.
   viewBoxValues[1] -= y;//panRate; // Increase the y-coordinate value of the viewBox attribute to pan down.
    
   theSvgElement.setAttribute('viewBox', viewBoxValues.join(' ')); // Convert the viewBoxValues array into a string with a white space character between the given values.
  }

 
  function cancelEvent(e)
     {
        e = e ? e : window.event;
        if(e.stopPropagation)
           e.stopPropagation();
        if(e.preventDefault)
           e.preventDefault();
        e.cancelBubble = true;
        e.cancel = true;
        e.returnValue = false;
        return false;
     }

function initialize()
    {        
        hookEvent('svgElement', 'mousedown', onMouseDown);
        hookEvent('svgElement', 'mouseup', onMouseUp);
        hookEvent('svgElement', 'mousemove', onMouseMove);
    }

11) What it does is quite similar to mousewheel event. The different is now it uses global variable to check the mouse-down and the distance of mouse move, and eventually apply that to svg viewbox properties.

12) That's it. Now a javascript  interactive map is created. Full codes here.