Tuesday, January 27, 2009

Accessing images from Google Sites

I recently wanted to modify my blog template a bit and had to create my own images and use them. I decided to upload the images to Google sites, where I have kept a bunch of my other files and preferred to maintain them all in one single location.

I uploaded the .gif images which had transparent areas in them and I copied the link and added to my harness blog and tested. I noticed that it displayed fine in Chrome, Firefox, Opera and Safari, but not really so in IE 6.

The transparent areas of the file were filled with a light blue color which was sufficient enough to mangle the appearance of the page.

The problem was with the URL I had used. The actual URL from the Google Sites was:
http://sites.google.com/site/codingpassion/Home/rails_main.gif?attredirects=0

For some reason, I found that query at the end of the URL to be unnecessary and removed it and hence faced this error.

This is what you see when accessing this link in IE6 (notice the blue/gray area? That is supposed to be transparent)
http://sites.google.com/site/codingpassion/Home/rails_main.gif


This is what you see when accessing this link in IE6 (notice the ?attredirects=0 query string)
http://sites.google.com/site/codingpassion/Home/rails_main.gif?attredirects=0


Fiddling with this further showed that when the attredirects=0 query string is passed along, Google appends the URL with an “auth” key value which in turn redirects to a more messy URL. Not sure what happens internally, probably they extract it from some location and authenticate if the file is available to all users, but adding that query string value back to the URL fixed things.

Update 1
Apparently there has been some issues with accessing images from Google sites:
http://groups.google.com/group/sites-help-somethingisbroken/browse_thread/thread/ec167ad76b4ea267/170c3709074f2bf6?lnk=gst&q=

Not sure what exactly Google does to fetch the image and why it would behave differently without the query string input.

Modifying Blogger Template – Resizing main Blog Area

The Google blogger has a decent bunch of templates to choose from and when I had to choose one I took a couple of minutes to think.

I would be posting code snippets and occasionally diagrams or images, maybe screen captures to explain something. But primarily the content will mostly be text with a lot of code.

I did not want a dark background with white fonts – I think no one will ever want to use that for writing technical content. Somehow I did not like the fully white templates as well. Most of the templates offered looked too simple and without many colors.

I finally chose the Rounders-3 (Green version) because it was simple and slick and the colors were fine and looked professional. However there was one drawback with it which I noticed as I started to post. The space reserved for the main blog was too little and any post that I did looked obtrusively lengthy. The code snippets that I posted had to be broken down to multiple lines despite using a smaller font. Making the fonts any smaller would be make it impossible to read.

So the only options I had were to either expand the main blog area or choose another template. But then, since I liked the template and also because did not want to perform a huge face-lift to a blog with steady traffic, I chose option A.

The change, I presumed, should not be difficult to make and it was not that difficult at all.

The default template was done to fit 800x600 resolutions and hence the max size of the title and footer was at 740 px. I am not sure if there are any more people using such low resolutions, but anyways I had my Google analytics stats to answer my question. There was less than 1% of the total visitors in that screen resolution.

Convinced that it would not affect the majority of the users, and even for those affected, they only have to scroll to see the profiles section, I proceeded to make the change.
Just wanted to jot down the exact changes made, as a ready reckoning for myself and others:
1. CSS properties had to be changed for the main blog area and the Title
2. Noticed that the rounded corners were not images for just the corners, but were a strip, hence had to modify the images and adjust it to the new width

That was all that needed to be done.

I used Google sites to upload my modified images. There was a snag in accessing the images from Google sites. Read more about it here.

Actual CSS Changes

#outer-wrapper
width:940px;
change image – used
http://sites.google.com/site/codingpassion/Home/corners_main_bot.gif?attredirects=0

#main-wrap2
change image – used
http://sites.google.com/site/codingpassion/Home/corners_main_top.gif?attredirects=0

#main
change image – used
http://sites.google.com/site/codingpassion/Home/rails_main.gif?attredirects=0

.main .widget
width: 668px;

.main .Blog
width: 684px;

#header-wrapper
change image – used
http://sites.google.com/site/codingpassion/Home/corners_cap_top.gif?attredirects=0

#header
change image – used
http://sites.google.com/site/codingpassion/Home/corners_cap_bot.gif?attredirects=0

#footer-wrap2
change image – used
http://sites.google.com/site/codingpassion/Home/corners_cap_top.gif?attredirects=0

#footer
change image – used
http://sites.google.com/site/codingpassion/Home/corners_cap_bot.gif?attredirects=0

Before


After

Tuesday, January 13, 2009

Fixing Corrupt Fonts Windows XP

Recently while I uninstalled a Game I was playing, it corrupted my Windows XP fonts. It had a copy of it taken from the Windows directory and when it prompted to delete some files, it showed the path of the game directory, and I thought it was safe to delete. But it totally messed up things and left my PC with bloated fonts.

A little bit of googling and quite a few options were suggested including reinstalling the OS (Nah, I was not planning to do that though). But this solution saved my day:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes]
"MS Shell Dlg 2"="Tahoma"
"MS Shell Dlg"="Tahoma"

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
"NoSaveSettings"=dword:00000000

Copy the above content into a text editor and save it with some name and make the extension as .reg - you can then double click this to set Tahoma back as the default font and get back the original Windows XP settings.

Or you can download the one I created from here.

Be careful with editing the registry, if you are not sure of what you are doing, i would advise you to take a backup of the registry before proceeding.

Sybase Stored procedure error Select permission denied on object

Yesterday we finally resolved a strange issue which was troubling us for a few hours.
We had a web page which was calling a newly created stored procedure. This stored procedure was returning results, but most fields of the result set were NULLS.

While we know that there is no chance for the data to go missing, we were left with the following options:
  1. Execute just the query used inside the stored procedure
  2. See the IO statistics to see if the correct tables are internally mapped (we had faced a similar issue a few weeks back, Check it here)

On running the IO statistics, we found that there was a warning - Server Error Number 10330, Severity 14. Select permission denied on object dbName..tableName.

We were logged into the database with very limited access and permissions and so after getting a login which had sufficient Select and Exec permissions, we proceeded to find out and fix the issue.

  1. There were two databases involved. Let us call it db1 and db2
  2. Stored procedure created in db1, selects from a table in db2 (db2..tablename)
  3. The db1 stored procedure was granted exec permissions to user group Group1
  4. The login used from the UI connection string belonged to the db1..group1 but did not belong to db2..group1
  5. The reason why the old stored procedure worked was because – that procedure was created by a user who had sa rights – and Sybase applies the rights of the owner to the queries inside it

Adding the login user (from the UI connection string) to db2..Group1 resolved this issue.

Thursday, December 18, 2008

SqlDbx - Really Cool

I was asked to work in a project migrating from classic ASP to .Net and the database used was Sybase ASE. The only option for DB coding, was to use the pre-installed SQLAdvantage.

The first thing I did was to search for a better tool and after getting SqlDbx I knew, I've got the best.

Guys in my team were thrilled at this product. I have recommended this one to my company's IT Tools department and I am sure each one of us would get the professional edition real soon.

Wednesday, December 17, 2008

Building a simple Dirty State Page in .Net with AJAX

I was building a small internal application for my company as a pilot application that tests the Business Object framework we had just built. This web application could well serve as a useful too.

And now I wanted to try out a simple dirty state page – a page that tracks any changes made to it and notifies accordingly to the user. With AJAX extensions, I know it was possible, there are options to extend and create your own control - like a DirtyStateUpdatePanel or something. Anyways, I just wanted to try a basic version - so here is the simple version that I came up with. Consider this as a work done for a proof of concept.

DISPLAY
We need something to notify that the page has become dirty – even a div tag should be suffice
<div id="DirtyStateNotifyDivCtl" class="dirtyPanel" runat="server">div>

CONTROLS AND EVENTS
We need to notify if any of the bound controls have changed – we should be fine with each control’s changed event. Additionally we need them all to perform one common function – notify a dirty state change. So we can have our own event declared

Public Event DirtyStateChangedEvent(ByVal getDirtyStateMethod As IDirtyPage.GetDirtyState) Implements IDirtyPage.DirtyStateChangedEvent

And its handler:

    Protected Sub ValueChanged(ByVal getDirtySateMethod As IDirtyPage.GetDirtyState) Handles Me.DirtyStateChangedEvent

        With Me.DirtyStateNotifyDivCtl

            If getDirtySateMethod.Invoke() Then

                .InnerText = "*Unsaved Changes"

            Else

                .InnerText = " "

            End If

        End With

    End Sub

And a cheeky way to expose the raise event from Master Page:

    Public Sub RaiseDirtyStateEvent(ByVal getDirtyStateMethod As IDirtyPage.GetDirtyState)

        RaiseEvent DirtyStateChangedEvent(getDirtyStateMethod)

    End Sub

POSTBACK
We need to get all our controls wrapped into an UpdatePanel to “Ajaxify” things.

DETERMINE IF DIRTY
We can wire up the page controls to one common event handler (you can have as many event handlers). And pass in a delegate of a GetDirtyState method and let the Master page take care of the display of the Unsaved change text – or clear the unsaved change text.

    Protected Sub Page_DirtyStateChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles EndDateTxtCtl.TextChanged, StartDateTxtCtl.TextChanged

        Me.MasterPage.RaiseDirtyStateEvent(AddressOf Me.GetDirtyState)

    End Sub

 

    Public Function GetDirtyState() As Boolean

        ' TODOK: loop through your controls and find out if the page has become dirty by any chance

        If Me.EndDateTxtCtl.Text <> Me.TeamProject.EndDate Then

            Return True

        Else

            Return False

        End If

 

    End Function

And the icing on the cake would be the following:
<script language="javascript" type="text/javascript">

window.onbeforeunload = confirmIfDirty;

function confirmIfDirty(){

    if(document.getElementById('ctl00_DirtyStateUpdatePanelCtl').innerText > "")    {

        event.returnValue = "There are some unsaved changes. Navigating away from this page would cause such data to be lost.";

    }

}

script>

The slick onbeforeunload event pops up every time the user tries to navigate away from the page leaving it dirty.

You can find the sample files here.

 

Questions… Projects… - my two cents

A few years back, I happened to hear a glorified programmer advising his self-proclaimed sidekick how important it is to ask lesser questions to technical stakeholders/business users about the project or technology that they are working on.

I couldn’t disagree more! He was arguing that one should ask “smart” questions and should never let the other person think we do not know anything about the business by asking "stupid" questions.

Let me put this straight - There is nothing called as a stupid question. People get annoyed only when they get repeat questions. It would make them nervous on whether you are really on top of things.

For the benefit of the developer and for the benefit of the project, one should ask as many questions as possible. I am sure that clients who want the project done successfully would love to give you the answers. Even if they don’t have it with them immediately, it would kick start the thinking process and will make them revisit the requirements.

It helps to clarify a lot of things and verifies your assumptions. I strongly believe in this – “Assumption is the mother of all mess-ups”. It is wise to put forward your assumptions and sort it out. Nothing wrong in asking something basic about the business, after all you are going to be held responsible for the project you are build, aren’t you? The client would also be expecting you to know what you are doing.

Asking a lot of questions make you smart.
Asking only smart questions could leave even you in a lot of doubt.

Sybase stored procedure bug!?! Due to renamed table

We were investigating an issue with a web page – that displays data from a Sybase database. The problem was simple – the data was not as expected. The values were missing.

When we queried the actual table (say TableA) from which the stored procedure selects, the information was there. But on running the stored procedure, there would be no results.

We first suspected the parameters that were being passed in – but they were fine.

We then ran the stored procedure with IO statistics On and traced the culprit. The stored procedure was selecting records from a totally different table (TableA_old). The logical explanation is this:

Somebody renamed TableA to TableA_old. Thereby breaking all stored procedures, views depending on it. Later this somebody made another table by the same name TableA. But that does not fix the things that were broken earlier by the renaming.

The stored procedure (which is precompiled) was still pointing to the old table since it was referencing the table using id’s used internally by the database.

We saw if there was an option to recompile as I remembered that there was a sp_recompile, but that did not help. I played around with sp_recompile and it did mark the table to cause all associated sp’s to be recompiled the next time it was run. But when I ran the stored procedure again, it recompiled (there were 2 IO Stats entry), but both were pointing to the old (renamed) table only.

We then dropped and re-created the stored procedure and that fixed it all.

Tthe Sybase version I was working on was quite an old one:
“Adaptive Server Enterprise/12.5.3/EBF”

Here is a quick way to find out what version you are in. SELECT @@version
To just give some code examples to reproduce this error, try this on some old version of Sybase:

CREATE TABLE tbl1
(
name VARCHAR(10)
)

CREATE PROCEDURE sp_tbl1
AS
SELECT name FROM tbl1

SET STATISTICS IO ON
EXEC sp_tbl1

/*
**RESULT WOULD BE:
Table: tbl1 scan count 1, logical reads: (regular=1 apf=0 total=1),
physical reads: (regular=1 apf=0 total=1), apf IOs used=0
**/

SET STATISTICS IO OFF
sp_rename 'tbl1','tbl1_old'

CREATE TABLE tbl1
(
name VARCHAR(10)
)

SET STATISTICS IO ON
EXEC sp_tbl1
/*
**RESULT WOULD BE:
Table: tbl1_old scan count 1, logical reads: (regular=1 apf=0 total=1),
physical reads: (regular=0 apf=0 total=0), apf IOs used=0
**/

DROP PROCEDURE sp_tbl1
DROP TABLE tbl1
DROP TABLE tbl1_old

Sunday, December 14, 2008

How to extract contents from .msi files - Windows XP

My company’s strange “security” policy granted me administrator rights ONLY on my PC, but did not add me up to the administrators group of the domain to which my user account belonged to. That gave me kind of mixed permissions – and often caused some annoying “You do not have permissions” error. One such thing was - running an .msi file. I was installing AJAX Extensions when this one popped up again.

I have done some workarounds before for normal executables (.exe), with my handy WinRar, which would extract all contents of a setup package. But I was dealing with this Microsoft Installer, which was a bit tricky. But surfing through MSDN helps, as always! Learnt how to do it the black & white way:

Run the following on command prompt:
msiexec /a “the msi file with path” /qb TARGETDIR=”the path where you want the contents to be extracted”

Example:
msiexec /a “D:\Installers\AJAXExtensions.msi” /qb TARGETDIR=”C:\AjaxExtensionsExtracted”

Since I was an administrator on my local machine, I knew I had the rights to run the contents from the extracted folder. Well, at least I did not sweat much on it.

Release Process !?!

Two days back, my teammate had to release to production a minor code change he made to one of the web modules. Since we both were new to the release process followed by the client, we were given a small briefing about it.

We first have to release the change to a common dev environment, where it will reside till the peer review and internal testing is completed. Then we had 3 documents to be meticulously filled up for the UAT (User Acceptance Testing). One of the documents gives a clear step by step instruction on how to release to the QA environment, explaining like it is being told to a 4 year old. Once the UAT release is done, the development team we would get an email notification and after the user test it, there would be yet another email notification giving a sign-off for a production release.

We then have to prepare another bunch of documents, add with that the UAT sign-off email and the UAT release notification email and send it across to the deployment and maintenance team at the client side, who would take care of the release. They follow a semi-automated release process whereby the release manager would just specify the steps to be executed and the scheduled deployment runs once every 3 hours.

On the release date, if you never hear back from the release manager, things are good. But if you get an email with a high alert… you probably woke up on the wrong side of the bed that day.
Well, apparently that’s what my teammate would have possibly done, because he had just received such an email. He had a senior colleague to help him figure out the problem. So I decided to keep away from it, after just telling to compare the code changes in source control and holler if he needs any assistance. I decided to stay out of it partly because I did not want to jeopardize the senior colleague’s approach and also because I myself had a couple of burning issues, to attend to.

While I was keeping busy, later that evening I heard from this teammate that they had to rollback the changes after trying a couple of things and that this has been escalated and needs to be re-released the next day. They had identified that a few things were not matching up with the QA and Production environment. But they had figured out what the problem was and they were prepared for the next day’s release. While he was explaining I asked a few questions for which he either had no answers or was not confident of them, which made me a bit nervous for him.
Well, it was the next day - same time, and sadly the same story. It was a Friday and people were all the more frustrated and this colleague of mine was being made responsible and he had no clue what was going on. When things were going towards yet another rollback, I decided to jump in, invited or not.

They had this published website which was released to UAT – which worked fine, but when released to production, it failed to even load the default page and redirected to an authentication failed error page. The “fix” after the first rollback was this – they had compared the config file and found some application specific Role-id’s to be different and assumed that this must have been the issue and prepared themselves to give another shot, which eventually failed – miserably.

The code version in the source control looked intact, leaving me no other option but to decompile. Reflector, my favorite tool in many instances came to the rescue and I decompiled the app code binary of the current version in production with ours. When I saw the decompiled login related method, it seemed to contain quite a lot of additional changes – changes that were not present in source control!

We then figured out a way to get this work by making a few changes in the configuration file. Call it a tweak or a hack but it saved the day and the weekend, but I made it aware to all the people involved in this including the client who got an emergency regression test run and also promptly created another request to get this mess cleaned up.

I have worked quite a bit in this onsite/offshore setup and have my own experiences to recon. But almost no client I have worked with before had such an elaborate documentation process. So at first I appreciated this way of working, but this incident clearly proved that no system or process is invincible to errors, not when people have the audacity to bypass certain rules.
This whole thing was obviously caused due to someone who had been here long enough and knew how to sidestep a few landmines, but unfortunately did not know or care about the consequences and complications it would create to the next bunch of people who would work on it. The blame game had started, and something tells me that whoever did this must have been long gone.

Even though I come from a background where documentation was not so much patronized, I still could suggest on maintaining a “deviation log” which can be mainly used to record any such deviations, in any step of the development life cycle.

The bottom line is this - 
Even though there are a lot of steps to streamline any work process – nothing could change unless people learn to respect it and follow it.