Tuesday, June 05, 2007
by Nik Kalyani
Tuesday, June 05, 2007 8:52:46 AM (Pacific Standard Time, UTC-08:00)

When opening an HTML file that sits on your desktop, IE will throw a security warning which you must click before the page is rendered. This is annoying, especially when the file is your own creation and there is no security risk. You can suppress the security warning by adding the "Mark Of The Web" (MOTW) to the top of your HTML document:

<!-- saved from url=(0014)about:internet -->

After adding this, you can launch the HTML file locally without any annoying warnings.

 Thursday, February 08, 2007
by Nik Kalyani
Thursday, February 08, 2007 6:49:51 PM (Pacific Standard Time, UTC-08:00)

As AJAX and Javascript widgets get more popular, it is not unusual to see Javascript from multiple parties running on the same page. This greatly increases the chances of collisions in variable and function names. For instance, two unrelated scripts might define the function “modifySomething()”. In this case, the last definition of “modifySomething()” on the page will be the one called. This is an invitation to disaster.

One way to prevent this is to practice defensive Javascript coding through the use of namespaces. In .Net and Java, the use of namespaces clearly delineates classes and prevents collisions. While Javascript does not have a built-in mechanism for using namespaces, it is relatively easy to implement them. In fact, just about every library such as Dojo Toolkit, Yahoo UI and ASP.Net AJAX provides a mechanism for registering and using namespaces in Javascript. This is fine if you are using one of the libraries, but if you are not, then how do you go about creating namespaces in your Javascript code. Read on.

Let’s create a simple “Cube” class with properties of Width, Height, Depth and methods grow() and shrink(). This class must reside in the “Speerio.Web.Solids” namespace.

If we try something like this: 

Speerio.Web.Solids.Cube = function(width, height, depth)
{
      this.width = width;
      this.height = height;
      this.depth = depth;
}

…we get an error. This is because Javascript expects to find an object “Speerio”, with a child object “Web”, which has a child object “Solids”. To make this work, we will first need to define a way to tell Javascript that the “Speerio.Web.Solids” hierarchy exists. We can do this by creating a function to create the hierarchy like this:

function $register(ns)
{
    var segs = ns.split(".");
    var namespace = window;
    for(var s = 0; s < segs.length; s++)
    {
        var seg = segs[s];
        if (typeof(namespace[seg]) == "undefined")
            namespace[seg] = new Object();
            
        namespace = namespace[seg];
    }
}

This function adds our namespace as a hierarchy of objects that are children of the top-level “window” object. It only works if the object has not already been defined, so it’s OK to register the same or similar namespaces multiple times. Now, it’s a simple matter of calling the function:

$register(“Speerio.Web.Solids”);

Once the namespace is registered, we can use it in our code as we would any other object. Since we are talking about defensive coding, let’s go further and define the “Cube” class.

Speerio.Web.Solids.Cube = function(width, height, depth)
{
       this.__width = width;
       this.__height = height;
       this.__depth = depth;
}
 
Speerio.Web.Solids.Cube.prototype =
{
       shrink : $Speerio_Web_Solids_Cube_Shrink,
       grow : $Speerio_Web_Solids_Cube_Grow,
       getWidth : $Speerio_Web_Solids_Cube_GetWidth,
       setWidth : $Speerio_Web_Solids_Cube_SetWidth
}

We start by defining the Cube class whose constructor takes three parameters — width, height and depth. In the definition of the class, these parameters are used to initialize properties __width, __height and __depth respectively. Why the underscores you ask? Mainly to discourage them from being directly modified. Javascript does not provide a set/get mechanism so to protect properties from being set directly, a small layer of obfuscation is necessary. It is not fool-proof…anyone studying your code will see this right away. However, it should be obvious that the intent is to protect the integrity of the data and prevent it from being modified directly.

Next, we define the various methods for the Cube class. For each method, the “public” method name is clear and simple. The actual method that does the work has a longer name. I used the following convention:

  • prefix all class methods with $
  • append the namespace and class name, replacing periods with underscores
  • append the name of the method, prefixed with “Get” or “Set” if the method is intended to be a property getter/setter

Now, we can define the actual methods:

function $Speerio_Web_Solids_Cube_Shrink()
{
    if ((this.__width > 1) && (this.__height > 1) && (this.__depth > 1))
    {
        this.__width--;
        this.__height--;
        this.__depth--;
    }
}
 
function $Speerio_Web_Solids_Cube_Grow()
{
    this.__width++;
    this.__height++;
    this.__depth++;
}
 
function $Speerio_Web_Solids_Cube_GetWidth()
{
    return(this.__width);
}
 
function $Speerio_Web_Solids_Cube_SetWidth(w)
{
    if (w > 0)
       this.__width = w;
}

And finally, some code to test the class:

var cube = new Speerio.Web.Solids.Cube(10, 10, 10);
cube.grow();
cube.grow();
cube.shrink();
alert("The cube width should be 11; the actual value is " + cube.getWidth());
cube.setWidth(100);
alert("The cube width should be 100; the actual value is " + cube.getWidth());

The above namespace-based class definition protects your code when it is running on a page where code from other parties is also executing. In addition the code is readable and likely easy to manage, even if months have elapsed since you last took a look at it. There may be a small performance hit the first time the script file is downloaded to the user’s browser due to the verbosity, but I’ll take verbose code that works over concise code that breaks the page any day.

#    Comments [2] - Trackback    

 Tuesday, February 06, 2007
by Nik Kalyani
Tuesday, February 06, 2007 7:56:25 PM (Pacific Standard Time, UTC-08:00)

Steve Jobs' rather unassumingly titled Thoughts on Music packs quite a punch. In what is surely going to be one of the most linked-to URL’s on the Internet, Jobs openly advocates an end to DRM-crippled music. Reactions from bloggers such as Don Dodge and Fred Wilson are positive and commend Jobs on this move.

Until now, it has been generally accepted that Apple uses DRM on iTunes tracks to protect its control on online digital music distribution. Turns out that Apple’s research data shows the average iPod has only 22 songs or 3% of music that comes from the iTunes store. So while iTunes and iPod appear to have been mega successes, it’s only the tip of the iceberg. The music companies require Applie to DRM-protect iTunes music and this constrains the market to those willing to live with DRM, liberal as the iTunes DRM policy may seem.

Jobs does a great job of educating us on how completely unbalanced and illogical the music industry’s approach is to online music distribution:

Why would the big four music companies agree to let Apple and others distribute their music without using DRM systems to protect it? The simplest answer is because DRMs haven’t worked, and may never work, to halt music piracy. Though the big four music companies require that all their music sold online be protected with DRMs, these same music companies continue to sell billions of CDs a year which contain completely unprotected music. That’s right! No DRM system was ever developed for the CD, so all the music distributed on CDs can be easily uploaded to the Internet, then (illegally) downloaded and played on any computer or player.

He takes a jab at European countries such as France who have legislation requiring companies to make DRM-enabled music playable on any device: 

Much of the concern over DRM systems has arisen in European countries.  Perhaps those unhappy with the current situation should redirect their energies towards persuading the music companies to sell their music DRM-free.  For Europeans, two and a half of the big four music companies are located right in their backyard.  

Overall, this is an excellent P.R. tactic by Jobs. With this one post, adverse public opinion will shift away from Apple and on to the music industry. Of course, this will not make much of a difference since the dinosaurs running  industry are too fixated on the old to look at the huge opportunities that await a music industry that is free.

Under a free and fair system, there will be no incentive for most people to download sub-standard quality music from questionable sources with embedded junk in the files. The pace of innovation in the music player business will increase as the market size increases. Artists will be fairly compensated for their work and the music industry will get fairly compensated for its marketing efforts. To make this happen, all the industry has to do is build on Apple’s successful 99 cent model and either remove DRM completely, or include DRM in such a way that from the perspective of the purchaser, the DRM does not exist. Another way to look at it is to change the positioning altogether — instead of Digital Rights Management, which serves to limit and take away rights, it should be DRG – Digital Rights Grant. By purchasing a piece of content, you are effectively granted the right to play it on any device that you have in your control.

This is not a very difficult technical problem. Most digital devices today have a configuration function which can be used by the consumer to customize various aspects of its operation. Why not allow the consumer to enter in a “key” of their choice. (Something akin to a password, but with limitations on the characters and the length allowed.) The consumer would enter the same key on every device or media playing software in her/his household. When purchasing digital content (the scheme can be applied to music, video, eBooks), the consumer provides the same key to the online store which locks the content with that key before allowing the consumer to download it. The content can then only be played on any device programmed with that key. This is the essence of DRG — the consumer is freely able to play the content he/she purchased on ANY device under her/his control. If he chooses to illegally share the content, he will also need to also share his key, and the other person(s) will need to configure his devices to use that key. It is certainly conceivable that those intent on stealing music will collude and share keys, but this can be mitigated by retiring keys that are known to be on illegal sharing sites. The music pirates are then left with a static collection of content. That should get boring very quickly.

I realize this is a gross over-simplification of the cryptographic controls that would be necessary to implement such content protection, but the main point I’m trying to make is that a simple and elegant system is possible if all the players cooperate. Device manufacturers and digital content distributors need to agree on a system that is easy for consumers to use. By focusing on “granting” rights for those who want to have legal content, instead of “restricting” rights for those bent on abusing the system, the industry can gradually change the game. If it has the will, there are plenty of super-smart people out there that can create a system that really works.

I truly believe that consumers will be quick to vote with their wallets for any system that makes content available under a fair pricing scheme and without limitations on playback on their devices. Jobs knows this and although it’s an uphill task, this open letter is a great first step in getting the music industry to wake-up to the realities of content distribution in a digital world. Whether the outcome is totally DRM-free music or music with real “fair play” rights, anything is better than the status quo.

#    Comments [0] - Trackback    

by Nik Kalyani
Tuesday, February 06, 2007 7:34:44 AM (Pacific Standard Time, UTC-08:00)

The GoDaddy-MySpace fiasco appears to have run its course. As I read blog posts and news stories, one thing that stood out was the intense focus on the legal and business implications of GoDaddy’s actions. I do not know the exact details, but I can speculate that “business” folks at MySpace contacted “business” folks at GoDaddy who then directed technical folks to act on the request to shut-down Seclists.org. GoDaddy and MySpace (but mostly GoDaddy) has been at the receiving end of a fair amount of negative P.R. as a result. Let’s put our business hats aside for a moment and put on our technical hats (after all this is a technology blog).

I think that if the folks at MySpace or GoDaddy had consulted with their in-house technical and information security resources a much simpler and effective solution could have been employed. It’s a big assumption on my part that in-house technical resources were not consulted going by the sheer stupidity of the public actions (or perhaps they were, and subsequently ignored, which is often the case).

Any sane information security person would have informed them of two very important things:

  • On the Internet there is no “unpublish” feature. Once information is out there, you have to assume that it is there in perpetuity.
  • Usernames and passwords, once compromised must be changed as the associated accounts are no longer secure.

The course of action that MySpace took was the exact opposite of what they could and should have done — run a script on the published list of usernames to permanently disable each one and contact the account owners about what they need to do to regain access. This would have been terribly inconvenient for all the users involved, but it would have made the leaked usernames inconsequential.

GoDaddy simply compounded things for itself by not pushing back on this and instead shutting down the domain at MySpace’s request.

There have been many blog posts asking people to reconsider using GoDaddy as a registrar, including this one by fellow LinkedIn blogger Marc Freedman. I thought about this and decided against it. First of all, it’s a huge pain to move active domains and even with careful planning there will likely be some site down time during the switch. Secondly, there is a cost associated with it.

I would switch if GoDaddy did this sort of thing repeatedly and blatantly. However I am not convinced this is the case. While it is more fun and buzz-worthy to bash GoDaddy on this issue from the grandiose perspective of freedom and laws, the truth of the matter is that this episode highlights one commonality between GoDaddy and MySpace — incompetent people. I somehow doubt switching registrars is going to provide any measure of protection.  

#    Comments [1] - Trackback    

 Wednesday, January 31, 2007
by Nik Kalyani
Wednesday, January 31, 2007 10:54:34 AM (Pacific Standard Time, UTC-08:00)

In a previous post DotNetNuke Module Settings Made Simple, I had shared some code to make DotNetNuke module settings easier to manage. One of the methods in an included class permitted the use of tokens in stored settings values. This allows for many possibilities that are user-, tab- or portal-driven. In that post, I had omitted the code for token substitution because it is a bit lengthy. Here, then, is code for substituting string tokens with portal values.

Although the intended use is for module settings, there’s no reason this code cannot be used for just about any scenario where tokens need to be injected. 

using System;
using System.Web;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Reflection;
using DotNetNuke;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Users;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Security;
using DotNetNuke.Security.Roles;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.Localization;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Modules.Actions;
using DotNetNuke.Services.Personalization;
using DotNetNuke.Modules.HTMLEditorProvider;
using DotNetNuke.Framework.Providers;
/* Copyright (c) 2007, Speerio, Inc. This notice may not be removed. */
namespace Speerio.DNN.Common
{
    /// <summary>
    /// Summary description for PortalTokens.
    /// </summary>
    public class PortalTokens
    {
        public const string UnknownUser = "~Public";
 
        public static string Replace(string source)
        {
            return(Replace(source, UnknownUser, null));
        }
 
        public static string Replace(string source, ModuleInfo moduleConfig)
        {
            return(Replace(source, UnknownUser, moduleConfig));
        }
 
        public static string Replace(string source, string unknownUserText, ModuleInfo moduleConfig)
        {
            PortalSettings portalSettings = (PortalSettings) HttpContext.Current.Items["PortalSettings"];
 
            // PORTALSETTINGS tokens
            source = PortalTokens.ReplacePortalTokens(source, portalSettings);
 
            // USERINFO tokens
            source = PortalTokens.ReplaceUserTokens(source, unknownUserText);
 
            // ROLEMEMBER tokens
            source = PortalTokens.ReplaceRoleTokens(source);
 
            // TABSETTINGS tokens
            source = PortalTokens.ReplaceTabTokens(source, portalSettings.ActiveTab);
 
            // MODULESETTINGS tokens
            if (moduleConfig != null)
                source = PortalTokens.ReplaceModuleTokens(source, moduleConfig);
 
            // USERPROFILE tokens
            source = PortalTokens.ReplaceProfileTokens(source);
 
            // REGEX tokens
            source = PortalTokens.ReplaceRegExTokens(source);
 
            return(source);
        }
 
        private static string ReplaceRegExTokens(string source)
        {
            // REGEX tokens
            if (source.IndexOf("<REGEX:") > -1)
            {
                int reToken = source.IndexOf ("<");
                if (reToken > -1)
                {
                    try
                    {
                        string rePair = source.Substring(reToken+1);
                        int term = rePair.IndexOf(">");
                        if (term > -1)
                        {
                            rePair = rePair.Substring(0,term);
                            string[] reParams = rePair.Split(',');
                            if (reParams.Length == 2)
                            {
                                source = source.Replace("<" + reParams[0] + "," + reParams[1] + ">","");
                                reParams[0] = reParams[0].Replace("REGEX:","");
                                source = Regex.Replace(source, reParams[0], reParams[1], RegexOptions.IgnoreCase);
                            }
                        }
                    }
                    catch
                    {
                    }
                }
            }
            return(source);
        }
                        
        private static string ReplacePortalTokens(string source, PortalSettings portalSettings)
        {
            if (source.IndexOf("[PORTALSETTINGS:") > -1)
            {
                try { source = source.Replace("[PORTALSETTINGS:PortalId]",portalSettings.PortalId.ToString()); } catch {}
                try { source = source.Replace("[PORTALSETTINGS:UploadDirectory]",portalSettings.HomeDirectory); } catch {}
                try { source = source.Replace("[PORTALSETTINGS:HomeDirectory]",portalSettings.HomeDirectory); } catch {}
                try { source = source.Replace("[PORTALSETTINGS:PortalName]",portalSettings.PortalName); } catch {}
                try { source = source.Replace("[PORTALSETTINGS:AdministratorId]",portalSettings.AdministratorId.ToString()); } catch {}
                try { source = source.Replace("[PORTALSETTINGS:AdministratorRoleId]",portalSettings.AdministratorRoleId.ToString()); } catch {}
                try { source = source.Replace("[PORTALSETTINGS:DefaultLanguage]",portalSettings.DefaultLanguage); } catch {}
            }
            return(source);
        }
 
        private static string ReplaceUserTokens(string source, string unknownUserText)
        {
            if (source.IndexOf("[USERINFO:") > -1)                        
            {
                try
                {
                    bool auth = HttpContext.Current.Request.IsAuthenticated;
                    UserInfo userInfo = null;
                    if (auth)
                        userInfo = (UserInfo) HttpContext.Current.Items["UserInfo"];
 
                    try { source = source.Replace("[USERINFO:UserID]",(auth ? userInfo.UserID.ToString() : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:FullName]",(auth ? userInfo.FirstName + " " + userInfo.LastName : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:FirstName]",(auth ? userInfo.FirstName : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:LastName]",(auth ? userInfo.LastName : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Street]",(auth ? userInfo.Profile.Street : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:City]",(auth ? userInfo.Profile.City : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Region]",(auth ? userInfo.Profile.Region : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:PostalCode]",(auth ? userInfo.Profile.PostalCode : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Country]",(auth ? userInfo.Profile.Country : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Password]",(auth ? userInfo.Membership.Password : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Email]",(auth ? userInfo.Membership.Email : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Unit]",(auth ? userInfo.Profile.Unit : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Telephone]",(auth ? userInfo.Profile.Telephone : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Username]",(auth ? userInfo.Username : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:IsSuperUser]",(auth ? userInfo.IsSuperUser.ToString() : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:AffiliateID]",(auth ? userInfo.AffiliateID.ToString() : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Website]",(auth ? userInfo.Profile.Website : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:TimeZone]",(auth ? userInfo.Profile.TimeZone.ToString() : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:IM]",(auth ? userInfo.Profile.IM : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Fax]",(auth ? userInfo.Profile.Fax : unknownUserText)); } catch {}
                    try { source = source.Replace("[USERINFO:Cell]",(auth ? userInfo.Profile.Cell : unknownUserText)); } catch {}
 
                }
                catch
                {
                }
            }
            return(source);
        }
 
 
        private static string ReplaceRoleTokens(string source)
        {
            string tmp = source;
 
            if (source.IndexOf("<ROLEMEMBER:") > -1)
            {
                try
                {
                    string pattern = "(?<token>\\<ROLEMEMBER:(?<roles>.*?)\\|(?<unknown>.*?)\\>)";
                    Regex r = new Regex(pattern, RegexOptions.IgnoreCase );
 
                    ArrayList tokens = new ArrayList(10);
                    ArrayList roles = new ArrayList(10);
                    ArrayList unknowns = new ArrayList(10);
                    Match m;                           
                    for (m = r.Match(source); m.Success; m = m.NextMatch())
                    {
                        tokens.Add(m.Groups["token"].ToString());
                        roles.Add(m.Groups["roles"].ToString().Trim());
                        unknowns.Add(m.Groups["unknown"].ToString().Trim());
                    }
 
                    RoleController roleController = new RoleController();
                    bool auth = HttpContext.Current.Request.IsAuthenticated;
                    UserInfo userInfo = null;
                    string[] userRoles = {};
                    if (auth)
                    {
                        userInfo = (UserInfo) HttpContext.Current.Items["UserInfo"];
                        userRoles = roleController.GetPortalRolesByUser(userInfo.UserID, userInfo.PortalID);
                        if (userRoles != null)
                        {
                            for(int u=0;u<userRoles.Length;u++)
                                userRoles[u] = userRoles[u].ToLower();
                        }
                    }
                    for(int idx=0;idx<tokens.Count;idx++)
                    {
                        string token = tokens[idx].ToString();
                        string defaultValue = unknowns[idx].ToString();
                        string[] roleList = roles[idx].ToString().Split(',');
                        string selectedRole = "";
                        for(int l=0;l<roleList.Length;l++)
                        {
                            for(int u=0;u<userRoles.Length;u++)
                            {
                                if (roleList[l].ToLower() == userRoles[u])
                                {
                                    selectedRole = roleList[l];
                                    break;
                                }
                            }
                            if (selectedRole != "")
                                break;
                        }
 
                        try { source = source.Replace(tokens[idx].ToString(), (selectedRole == "" ? defaultValue : selectedRole));  } 
                        catch {}
                    }
                    return(source);
                }
                catch
                {              
                }
            }
            return(source);
        }
 
 
        private static string ReplaceProfileTokens(string source)
        {
            string tmp = source;
 
            if (source.IndexOf("<USERPROFILE:") > -1)
            {
                try
                {
                    string pattern = "(?<token><USERPROFILE:(?<container>.*?),(?<key>.*?),(?<unknown>.*?)>)";
                    Regex r = new Regex(pattern, RegexOptions.IgnoreCase );
 
                    ArrayList tokens = new ArrayList(10);
                    ArrayList containers = new ArrayList(10);
                    ArrayList keys = new ArrayList(10);
                    ArrayList unknowns = new ArrayList(10);
                    Match m;                           
                    for (m = r.Match(source); m.Success; m = m.NextMatch())
                    {
                        tokens.Add(m.Groups["token"].ToString());
                        containers.Add(m.Groups["container"].ToString().Trim());
                        keys.Add(m.Groups["key"].ToString().Trim());
                        unknowns.Add(m.Groups["unknown"].ToString().Trim());
                    }
                    for(int idx=0;idx<tokens.Count;idx++)
                    {
                        object keyObject = Personalization.GetProfile(containers[idx].ToString(),keys[idx].ToString());
                        string keyValue = "";
                        if (keyObject != null)
                            keyValue = keyObject.ToString();
                        try { source = source.Replace(tokens[idx].ToString(), (keyValue == "" ? unknowns[idx].ToString() : keyValue));  } catch {}
                    }
                    return(source);
                }
                catch
                {              
                }
            }
            return(source);
        }
 
        private static string ReplaceTabTokens(string source, TabInfo tabSettings)
        {
            if (source.IndexOf("[TABSETTINGS:") > -1)
            {
                try
                {
                    try { source = source.Replace("[TABSETTINGS:PortalId]",tabSettings.PortalID.ToString()); } catch {}
                    try { source = source.Replace("[TABSETTINGS:TabId]",tabSettings.TabID.ToString()); } catch {}
                    try { source = source.Replace("[TABSETTINGS:TabName]",tabSettings.TabName); } catch {}
                    try { source = source.Replace("[TABSETTINGS:Title]",tabSettings.Title); } catch {}
                    try { source = source.Replace("[TABSETTINGS:AuthorizedRoles]",tabSettings.AuthorizedRoles); } catch {}
                    try { source = source.Replace("[TABSETTINGS:AdministratorRoles]",tabSettings.AdministratorRoles); } catch {}
                    try { source = source.Replace("[TABSETTINGS:ParentId]",tabSettings.ParentId.ToString()); } catch {}
                    try { source = source.Replace("[TABSETTINGS:Level]",tabSettings.Level.ToString()); } catch {}
                    try { source = source.Replace("[TABSETTINGS:Skinsource]",tabSettings.SkinPath); } catch {}
                    try { source = source.Replace("[TABSETTINGS:SkinSrc]",tabSettings.SkinSrc); } catch {}
                }
                catch
                {
                }
            }
            return(source);
        }
 
        private static string ReplaceModuleTokens(string source, ModuleInfo moduleConfig)
        {
            if (source.IndexOf("[MODULESETTINGS:") > -1)
            {
                try
                {
                    try { source = source.Replace("[MODULESETTINGS:ModuleId]",moduleConfig.ModuleID.ToString()); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:TabId]",moduleConfig.TabID.ToString()); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:ModuleDefId]",moduleConfig.ModuleDefID.ToString()); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:ModuleOrder]",moduleConfig.ModuleOrder.ToString()); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:PaneName]",moduleConfig.PaneName); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:ModuleTitle]",moduleConfig.ModuleTitle); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:AuthorizedEditRoles]",moduleConfig.AuthorizedEditRoles); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:AuthorizedViewRoles]",moduleConfig.AuthorizedViewRoles); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:ControlSrc]",moduleConfig.ControlSrc); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:ControlTitle]",moduleConfig.ControlTitle); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:DesktopModuleId]",moduleConfig.DesktopModuleID.ToString()); } catch {}
                    try { source = source.Replace("[MODULESETTINGS:FriendlyName]",moduleConfig.FriendlyName); } catch {}
 
                }
                catch
                {
                }
            }
            return(source);
        }
 
    }
}
#    Comments [1] - Trackback    

RSS feed
Search and Links
Bling

View Nik Kalyani's profile on LinkedIn

Contact me: nik*kalyani.com (replace "*")

TechBubble
www.flickr.com
This is a Flickr badge showing public photos from techbubble. Make your own badge here.
Statistics
Total Posts: 214
This Year: 32
This Month: 0
This Week: 0
Comments: 238
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008
Nik Kalyani
Sign In
All Content © 2008, Nik Kalyani