Friday, June 17, 2011

Edit Blogger HTML Settings

This is blog is technical detail I did in 2007. I wrote this technique long time ago. It is truth that this is only required to do only once. However, when I create another blogger account, I would like to repeat it again. Now I think it is better to take detail notes of steps so that I may need to reuse it again.

Here is the example I edited HTML for my Chinese blog.

Backup HTML


It is important to backup your Blogger HTML settings before doing any updates. Here is the place to find the HTML settings and make the complete copy of HTML before any updates.



Copy My CSS Settings


The following CSS codes are used by my blog. Insert the CSS definitions into header section. Here I copied it to end of </b:skin>

<b:skin><![CDATA[/*-----------------------------------------------
...
/* David Inserted styles */
/* Use these styles as class ID for a box for some blocks such as div, p */
.outlinebox {
  width: 435px;
  border-width: 1px;        /* sets border width on all sides */
  border-style: solid;
  border-color: #666666;
  padding: 5px
  }

.outlineterminalbox {
  width: 850px;
  border-width: 1px;        /* sets border width on all sides */
  border-style: solid;
  border-color: #C0C0C0;
  font-family:monospace, prestige;
  background-color: #080808;
  color: #FFFF00;
  padding: 5px
  }

.outlinebox4wrappercodes {
  width: 444px;
  border-width: 1px;        /* sets border width on all sides */
  border-style: solid;
  border-color: #666666;
  margin: 0px auto;
  }

.outlineboxterminal4wrappercodes {
  width: 444px;
  border-width: 1px;        /* sets border width on all sides */
  border-style: solid;
  border-color: #080808;
  color: yellow;
  margin: 0px auto;
  }

/* code settings with following 2 outline Withbackclr. Generated in VIM TOhtml cmd */
.Type { color: #60ff60; }
.Comment { color: #80a0ff; }
.Identifier { color: #40ffff; }
.PreProc { color: #ff80ff; }
.Constant { color: #ffa0a0; }
.Statement { color: #fbf204; }
.Special { color: #fb8000; }

.outlinebox4wrappercodesWithbackclr {
  width: 444px;
  border-width: 1px;        /* sets border width on all sides */
  border-style: solid;
  border-color: #666666;
  margin: 0px auto;
  background-color: #000000;
  color: #cccccc;
  }

.outlineboxterminal4wrappercodesWithbackclr {
  width: 444px;
  border-width: 1px;        /* sets border width on all sides */
  border-style: solid;
  border-color: #080808;
  color: yellow;
  margin: 0px auto;
  background-color: #000000;
  color: #cccccc;
  }
 
.wrappercodes {
  width: 435px;
  padding: 5px;
  overflow: auto;
  }
 
.wrappercodesWithHeight {
  width: 435px;
  height: 300px;
  padding: 5px;
  overflow: auto;
  }

.wrappercodesWithHeightNowrap {
  width: 435px;
  height: 300px;
  padding: 5px;
  overflow: auto;
  white-space:nowrap;
  }

.nowrappercodes {
  width: 435px;
  padding: 5px;
  overflow: auto;
  white-space:nowrap;
  }

.nowrappercodesinner {
  width: auto;
  padding: 5px;
  overflow: auto;
  white-space:nowrap;
  }

.nowrappercodesWithHeight {
  width: 435px;
  height: 300px;
  padding: 5px;
  overflow: auto;
  white-space:nowrap;
  }
 
/* code style */
span.kwrd {
  color: rbg(0, 0, 255);
  }

span.defType {
  color: rgb(43, 145, 175);
  }
 
span.errorcode {
  color: rbg(255, 0, 0);
  }
 
span.highlight
{
color: white;
background-color: rgb(0, 100, 200);
}

/* Code Colors copied ccs from http://forums.asp.net/utility/colorcode.css for code colors */
/* Use asp.net forums on-line post to generate codes with these ccs class */

.coloredcode .cmt      { color: #00D502; }
.coloredcode .cmtg      { color: #666; }
.coloredcode .st           { color: #f00; }
.coloredcode .kwdt      { color: #666; }
.coloredcode .kwd      { color: #00f; }
.coloredcode .attr      { color: #f00; }
.coloredcode .attrv      { color: #00f; }
.coloredcode .ec           { color: #00f; }
.coloredcode .tag      { color: #800000; }
.coloredcode .dir    { color: #000; background: #FEFF22; }
.coloredcode .sel    { color: #800000; }
.coloredcode .val    { color: #00f; }
.coloredcode .unit      { color: #800000; }
.coloredcode .sqlcmt { color: #008080; }
.coloredcode .sqlkwd { color: #00f; }
.coloredcode .sqlkwd2 { color: #f0f; }
.coloredcode .sqlkwd3 { color: #999; }
.coloredcode .sqlkwd4 { color: #800000; }
.coloredcode .num      { color: #00f; }
.coloredcode .sqlst  { color: #008000;}
.coloredcode .classInterface { color: #1E90FF;}
.coloredcode b      { font-weight: normal; color: #008080; }
.coloredcode          { font-size: small !important; }
.row-set-descriptor {
  border-bottom: 1px solid #F60;
  border-bottom-style: solid;
  border-bottom-width: 1px;
  border-bottom-color: #F60;
  clear: left;
  color: #E55C00;
  font-size: 140%;
  margin: 0px 20px 0.5em 0px;
  margin-top: 0px;
  margin-right: 20px;
  margin-bottom: 0.5em;
  margin-left: 0px;
  padding: 1em 0px 0.2em 0em;
  padding-top: 1em;
  padding-right: 0px;
  padding-bottom: 
}

 /* End of Code Colors */
 /* End of David inserted styles */

]] > </b:skin>


Copy Scripts


Immediately after about </b:skin>, add Javascript codes.

<b:skin>
  ...
]] > </b:skin>
<script type='text/javascript'>
function toggleIt(id) {
  var post = document.getElementById(id);
  if (post.style.display != &#39;none&#39;) {
    post.style.display = &#39;none&#39;;
  }
  else {
    post.style.display = &#39;&#39;;
  }
}

function showFullPost(id) {
  var post = document.getElementById(id);
  var spans = post.getElementsByTagName(&#39;span&#39;);
  for (var i = 0; i != spans.length; i++) {
    if (spans[i].id == &quot;fullpost&quot;)
      spans[i].style.display = &#39;inline&#39;;
    if (spans[i].id == &quot;readmore&quot;)
      spans[i].style.display = &#39;none&#39;;
  }
}

function showFull(id) {
  var post = document.getElementById(id);
  var spans = post.getElementsByTagName(&#39;span&#39;);
  for (var i = 0; i != spans.length; i++) {
    if (spans[i].id == &quot;fullpost&quot;)
    spans[i].style.display = &#39;inline&#39;;
    if (spans[i].id == &quot;showlink&quot;)
      spans[i].style.display = &#39;none&#39;;
    if (spans[i].id == &quot;hidelink&quot;)
      spans[i].style.display = &#39;inline&#39;;
  }
}

function hideFull(id) {
  var post = document.getElementById(id);
  var spans = post.getElementsByTagName(&#39;span&#39;);
  for (var i = 0; i != spans.length; i++) {
    if (spans[i].id == &quot;fullpost&quot;)
      spans[i].style.display = &#39;none&#39;;
    if (spans[i].id == &quot;showlink&quot;)
      spans[i].style.display = &#39;inline&#39;;
    if (spans[i].id == &quot;hidelink&quot;)
      spans[i].style.display = &#39;none&#39;;
  }
  post.scrollIntoView(true);
}

function checkFull(id) {
  var post = document.getElementById(id);
  var spans = post.getElementsByTagName(&#39;span&#39;);
  var found = 0;
  for (var i = 0; i != spans.length; i++) {
    if (spans[i].id == &quot;fullpost&quot;)
      found = 1;
    if (spans[i].id == &quot;showlink&quot;)
      if (found == 0)
        spans[i].style.display = &#39;none&#39;;
  }
}
</script>



Insert Script Function Calls in Body Section


MODIFYING BLOG POSTS CODES

First find the line: <div class='post-header-line-1'/>

Insert the following codes after it:

<div class='post-body'>
  <b:if cond='data:blog.pageType == &quot;item&quot;'>
    <p><data:post.body/></p>
    <div style='clear: both;'/>
  <b:else/>
    <style>#fullpost {display:none;}</style>
    <p><data:post.body/></p>
    <span id='showlink'>
      <p>
        <a expr:onclick='&quot;javascript:showFull(\&quot;post-&quot; + data:post.id + &quot;\&quot;);&quot;'
        href='javascript:void(0);'>读详细内容(Read More)...</a>
      </p>
    </span>
    <span id='hidelink' style='display:none'>
      <p>
        <a expr:onclick='&quot;javascript:hideFull(\&quot;post-&quot; + data:post.id + &quot;\&quot;);&quot;'
        href='javascript:void(0);'>Collapse...</a>
      </p>
    </span>
    <script type='text/javascript'>
      checkFull(&quot;post-&quot; + &quot;<data:post.id/>&quot;);
    </script>
  </b:if>
</div>



NOTE: I found there is a duplicate post when the title of the post is clicked. The reason is that there is another div after the above codes:

<div class='post-body entry-content' expr:id='&quot;post-body-&quot; + data:post.id'>
  <data:post.body/>
  <div style='clear: both;'/> <!-- clear for photos floats -->
</div>



delete this section of div to avoid duplications.

NOTE: remove two tags: <div class="post-header"> ... </div> to avoid the content of post content in grey.

CODE FOR THE INCLUDABLE

Find the code: <b:includable id='feedLinksBody' var='links'>
Insert the following codes above it:

<b:includable id='PeekABooPost' var='post'>
  <div class='post uncustomized-post-template'>
    <table><tbody>
      <tr><td>
        <h3 class='post-title'><a expr:href='data:post.url'
        title='View this post only (comments visible).'><data:post.title/></a></h3>
      </td></tr>
      <tr><td>
        <a expr:onclick='&quot;javascript:toggleIt(\&quot;&quot; + data:post.id + &quot;\&quot;);&quot;'
          href='javascript:void(0)'
          style='text-decoration:none'
          title='Expand/collapse this post (comments not visible)'>[+/-] 显示内容(Show/Hide This Post).</a><br/>
        <a expr:href='data:post.url' target='_blank'>
          <i><font size='-2'>See/leave comments for this post in another window/tab.</font></i></a>
      </td></tr>
    </tbody></table>
    <div class='post-body' expr:id='data:post.id' style='display:none'>
       <p><data:post.body/></p>
       <div style='clear: both;'/>
    </div>
  </div>
</b:includable>
<b:includable id='feedLinksBoday' var='links'>



INCLUDE THE INCLUDABLE IN THE POSTS WIDGET

Find the code: <b:includable id='main' var='top'>
In this section find: <b:include data='post' name='post'/>
Change it to:

<b:if cond='data:blog.homepageUrl == data:blog.url'>
  <b:if cond='data:blog.pageType != &quot;item&quot;'>
    <b:include data='post' name='PeekABooPost'/>
  <b:else/>
    <b:include data='post' name='post'/>
  </b:if>
<b:else/>
  <b:include data='post' name='post'/>
</b:if>



Copy HTML Back to Blogger HTML Settings


After the change, copy the content of HTML from your local file back to blogger HTML settings.

REFERENCE

This feature of shrink and expend bloggs is based on this blog.

Read More...

Saturday, June 11, 2011

My SQL Query Questions

Last Friday I posted a SQL query question to SO. It was about get records between boundaries. Quickly I got several good answers.

I noticed one comment about performance issue by Piotr Auguscik:

U can use max/min to get value u need. Order by +top 1 isnt best way to get max value, what i can see in ur querys. To sort n items its O(n to power 2), getting max should be only O(n)


This is very interesting comment. I think about it, and I realize it is true. To sort a list of n items, it will take about n power of 2 by using bubble sort algorithm; while just to find out the max, it will do one loop of n at most. This is a very simple computer science concept. However, if it is an index column in the query table, I think that it should have no difference between TOP 1 + ORDER BY and MAX + GROUP BY.

Today I raised another question related to this issue again to SO. I got a very nice explanation and a tip to optimize the query and tip on how to turn on statistics on IO and TIME.

Here are queries:

SELECT
dv1.timestamp, dv1.value
FROM
myTable AS dv1
WHERE
dv1.value = @value
dv1.timestamp
BETWEEN (
SELECT TOP 1 dv2.timestamp
FROM myTable AS dv2
WHERE dv2.value = @value AND
dv2.timestamp < '@START_DATE'
ORDER BY dv2.timestamp DESC
)
AND (
SELECT TOP 1 dv3.timestamp
FROM myTable AS dv3
WHERE dv3.value = @value AND
dv3.timestamp < '@END_DATE'
ORDER BY dv3.timestamp ASC
)
ORDER BY dv1.timestamp

-- alternative way

SELECT
dv1.timestamp, dv1.value
FROM
myTable AS dv1
WHERE
dv1.value = @value
dv1.timestamp
BETWEEN (
SELECT MAX(dv2.timestamp)
FROM myTable AS dv2
WHERE dv2.value = @value
GROUP BY dv2.value
)
AND (
SELECT MIN(dv3.timestamp)
FROM myTable AS dv3
WHERE dv3.value = @value
GROUP BY dv3.value
)
ORDER BY dv1.timestamp

Read More...

Thursday, June 02, 2011

Use NET USE Command to Map Network Drive

Here is one senario about using network shared folders. One application requires a configuration file. The application has been used in our intranet environment with many users. Many users use the same configuration. It is preferable to put the configuration file on a shared network folder. I need to find a efficient way to let user be able to access to the file.

I use the following DOS command NET USE to dynamically allocate a network drive for the share one:

@IF EXIST \\remoteMachine\sharedFolder GOTO EXIT
@NET USE * \\remotemachine\sharedFolder pwd /user:userName /PERSISTENT:NO
:EXIT


In above codes, * is used to get next available drive letter for mapping. The key option is /PERSISTENT:NO. With this setting, the mapped drive will be released or not persistent after logout or reboot.

The main reason I use dynamic mapping is that I am not sure what network drive is available. It hard to find one no body in use. Since my application does accept UNC network full name, I don't care what network letter being assigned. In the configuration file, I use UNC network full name. Since the UNC name has been authenticated, it is as same as a drive letter for fast access.

Read More...

Sunday, May 22, 2011

Create Shortcut in C#

Last week I was working on a case to provide support for an application users. The application has two executables: one is app's main exe like app.exe and another one is for app's update like appUpdate.exe. For this update, we need to add a shortcut on clients machine desktop pointed to appUpdate.exe.

Like a typical shortcut, the one I need to put on client PCs has several settings: target, start in, run mode, icon and comments.



I tried to create a shortcut on my box first. Aftert that, I tried to copy this shortcut file (lnk) to a remote PC. It did not work. It seems that the lnk file some information are embedded in the file. When it is not in the machine where it was created. The machine name appears in the target.

I need a way to create a shortcut on fly. That's why I went to .net to create a simple console app do the job. This time SO helped me with an excellent open source library from a QA: ShellLink.cs. Within the source codes, there are actually two files I need: ShellLink.cs and FileIcon.cs. The library contains a wrapper class for Windows APIs. It is very straight forward.

The only change I made is to add a class level flag for any changes in shortcut properties. If any setter changes a value, this flag is true. Then I'll only save chances for the shortcut if any of properties are changed.

public class ShellLink : IDisposable {
private bool mChanged = false;
....
public string Target {
get { .... }
set { if (!value.Equals(Target)) {
mChanged = true;
....
}
....
}

Read More...

Sunday, May 15, 2011

Evernote Shared Link

Evernote is one of my favourite web services. I have taken a lots of notes about my programming experience and snip of codes. Recently Evernote announced that it adds public link to any private notes, as well as public ones. That's nice feature.

Here is one note I made last week about my experience to use console command to make to a network shared folder. With this tip, I can control the accessibility of sub folders. This node is from my public notebook: .Net

To test sharing of private note, here is my private note about Mac OS tip: Fix Failed Install.

Read More...

Sunday, May 08, 2011

Sina Blog

Let me continue to explain the Chinese web services. Today it is about blog. Sina provides a wide range web services. Sina blog is one of the most popular blog services in China. From its blog main page, you will see rich contents. The most interest area in the main page is the rank of bloggers.

For example, the number 1 for the current time is Xu Xiao Ming. He is so hot that his visits and followers will blow you away comparing to most western bloggers:



and Hanhan was the number one for many years. He is the most controversial person in China. He is so popular is mainly for this critics and sharp thoughts about government and current issues. He is still 8th in the rank.

Those top ones have most influence in Chinese, especially in young people. In Chinese followers or fans are called as fensi, which is a new word based on phonetic. It is interesting to see so many new words coming out almost every day. For Chinese absence just one year, they will don't know many new words when they come back. Chinese fensi love to read their their favourite blogs. It is interesting to read a long list of comments. As well, Sina provides a list of statistics about each blog, such reads, comments, forwards (copy to bloggers' blog) and favourites.



Most people just jump to their accounts to write or view blogs. On the top of Sina blog, there are some convenient links or menu items for accessing other sina services, as well as blog settings:



There is a list of menu items for personal information:



Writing blog is also very convenient. The on-line blog has a rich list of formats, photos, and videos, as well other options:





For uploading photos, you can only upload up to 20 photos per blog. Photo and video insert tool icons have other options such as reuse previous ones and web links.

Read More...

Sunday, May 01, 2011

Web Services for Chinese Blog and Twitter

In the past couple months I have spent many hours and effort to write Chinese blogs and twitters. Chinese is my mother language so it is natural for me to write. I know there are many web services to provide features and services specially for Chinese years ago. I even registered my account in two most popular ones, creaders.net and sina.com. However, I have spent rarely much time there. The main reason to switch my attention to those Chinese web sites was the time I went back to China last Christmas time vacation.

One thing got my attention is that almost every one in China with mobile phones have QQ. QQ becomes an alternative way to communicate. QQ's provider is a company called Tencent. Like Google and Twitter, QQ was started as a hobby app for people to communicate based on MSN text message. Soon it got Chinese people attention, and it spread out allover China. With so much people on QQ everyday, now Tencent have already attract many investors and it has been doing very well financially as well.

When I was surprised by Tencent success, I was told that Tencent was actually losing market in the blogger and twitter services in Chinese. Sina was and now is the biggest blog and twitter, or weibo in Chinese, in China. Since I already had account at Sina, I gave it a try when I was in China. I have continued my blog and weibo since then. The market is so hot there. I see that many famous people like celebrities, politicians, economic scholars, popular public speakers, naming just a few of types of people, have millions followers. Each time when they post any blog, news or a phrase, they reach to people instantly. Several times of comments, forwards, and favourites happen afterwards. I was joke to one CNet tech person, who is very active in new tech review and podcasts. I told her that if she was in weibo, she would have 100 times of followers. Unfortunately, none of western hot-people know Chinese.

Anyway, the reason I write my Chinese blogs and weibos are my exploration of web in this global environment. Now the English is not dominate language on the web. Actually, if you know another or more languages, you have great advantages over other people. For example, my weibo followers are about 55, while my twitter (@chudq) has only 18. The visits to my sina blog up to today are 2494, creaders blog are 8174. I have my principle to join those services, not just to attract people or pursue number of followers. I want to write my own idea, experience and tips, in one word: sharing. The followers are actually the people have the similar interest.

In terms of features, all Chinese web services are pretty good. For example, all Chinese blog web providers have nice editors with tones of tools for layout format. One most nice feature is HTML source code editing. I can almost write any HTML codes in my blog. This makes my control much easier. Weibo is similar as twitter. You can forward tweet, comment tweet, and group your followers. You can write private messages. The most popular feature is to add pictures and videos with tweet.



As you can see, pictures worth thousand words. With this feature, you can do your message more effectively. There are so much there. Most westerns don't know what is happening in Chinese Web services. Many webs are blocked and that's reality. However, in terms of freedom and dynamics, people are more active and I can see that Chinese people are very happy with what they have now. The media is not the correct picture. Personally speaking, I think western media give westerns wrong picture about China.

Read More...

Tuesday, April 26, 2011

My StackOverflow Reputation Over 2K

Finally today My SO reputation points are over 2K, 2008. It is a lucky number. Actually, I have not actively raised or answered any questions recently. I just keep checking my SO site and watching some questions there. That's why my points grow very slow.



Another interesting feature of SO is that you can subscribe to some user's feed to see user's activity. It is specially beneficial to following some awesome gurus. For example, I subscribed to user bbum, who is very good in ObjC and iPhone development.

Read More...

Sunday, April 17, 2011

Why is DI important?

In the past week, I was asked by this question. Most people use OO strategy to write their codes. Each class or object has its encapsulated private data member and methods. They do try to separate business logic clear and narrow down only the jobs the class cares. What is Dependency Injection(DI) and why do we use DI?

I asked a similar question to another senior developer, "where do you use DI?" He told me that he only uses it in unit test as mocked objects to avoid real access to database. That's very common in unit tests. However, that's not enough. Actually DI is a very important concept and should be a common practice in our daily coding.

I recalled my previous projects and went through the pattern I used. Here is my further explanation. Take the following codes as example:

public class MyDataReader {
...

public bool ReadData() {
var dbService = new MyDbService();
....
var data = dbService.GetObject();
....
}
}


The question code is the place where dbService object is created. How many times we have seen this type creation in our classes. The class MyDataReader has dependency on MyDbService class. In other words, it knows what db service class to use. Does MyDataReader class need to know that? Isn't that better if separate this specific logic from MyDataReaer?

Now look at the following updated codes:

public class MyDataReader {
...

public bool ReadData() {
var dbService = DIContainer.GetInstance<IDBService>();
....
var data = dbService.GetObject();
....
}
}


The only change is that MyDataReader does not have knowledge of what concrete db service is any more. It passes the job to a container class to get an instance of db service which implements the interface of IDBService. If you make changes in the container, then the instance you want to be used will be able to inject to MyDataReader class. You don't need to change MyDataReader class at all. This is a typical case of DI.

By implement DI pattern, your class will be truly OO. Less coupling is a critical principle of OO. You should always to use DI container as much as possible to separate the relationship between concrete classes. To do DI coding, you do need to create your container class and following your pattern to register the relationship between interface and class.

Fortunately, there are many great DI patterns available. I wrote blogs on Structure Map and MEF. Those are great DI Containers. For sure, you need to learn those patterns and ways they require, but I think it is worthwhile. Write better and clean codes will benefit you and your applications.

Read More...

Sunday, April 10, 2011

Two Useful Excel Functions

I often use Excel as a tool for some tests or data analysis. For example, last week I tried to comparing two columns in data base to see their difference. I found out that I had an Excel as a tool to do that. This file contains some formula for column comparison. Here is summary what I did for my future reference.

First, I copied column from table 1 to a worksheet(table1), and another column from table 2 to another worksheet(table2). Then I added a formula like this in column B:

=MATCH(A2, Table1!A2:A2409, 0)


MATCH function is useful to find first parameter value from the second parameter array, and the third parameter 0 is used to find a match. The result will be the index in the array if item is found, or #NA if nothing is found.

The result will be index number or #NA. I prefer to view the result as true or false. ISNA() is a function for this purpose.







above are snapshots of NeoOffice at my iMac.

Read More...

Saturday, April 02, 2011

Broken MSCOMRT2.OCX Caused Excel Add-in Exception

Last week I spent almost two days to resolve one issue. Excel add-in throw exceptions after an enterprise application update was installed. This happened initially in a product our team supports. The product is from a third party application suite by company C, where one Excel add-in is part of.

The symptom of the issue is that when Excel is opened, an exception is displayed right away. This one is caused by an add-in provided by the company C.



I contacted with the company which provides support the product. What they did was to remove monthview control from the add-in. It did not cause Excel error after that, however, I realized that this was not the right way to resolve the issue. The monthview is a common control from VB 6.0 control. Soon I found this control is MSCOMRT2.OCX, and there are some plains about its broken.

Soon I got calls from other department about the similar exceptions in Excel. They use different add-in and I realized that the root is to fix the control. After many discussions with other team member, I narrowed my focus on this control. I was right on this issue. I found a fix from Microsoft support knowledge base. The fix contains a cab file with only those two files:

mscomct2.inf
mscomct2.ocx


What I did was unregister the ocx file in %systemroot%/system32 first,



Then I copy those files to the path and register the ocx:



The fix seems very simple. However, at first no one knows the root of the issue. The update deployment team was afraid of the update would cause many user apps not working. I think the team work and web search played important role to get down the solution. Based on our communications on the issues and information we got, I finally found the right package as a fix.

Read More...

Thursday, March 24, 2011

FireFox Update (4.0) and Vimperator 3.0

My favorite web browser Firefox has been updated to 4.0. I got it today. After the installation, I found that my must-have adding Vimperator has also been updated to 3.0. The new interface for Vimperator looks nice; however, my clean UI is changed. All the toolbar, navigation bar, bookmark bar and tags are visible. I would like only tabs visible.

The command to display UI bars is different. In its help page, it still says that the following command is for displaying UI bars:

  :set go+=mTB

I thought I could use it to disable UI bars. There is no go settings in this new version. What I found is that the following command can be used to hide all:

  :set gui=none
:set gui=tabs

The first one is to disable all UI bars and the next one is for displaying tabs bar.

Other than that, I have not found anything changed in terms of features, except some minor changes in UI. For example, the command line displays a triangle instead colon (:). Vimperator works great!

Read More...

Saturday, March 19, 2011

VIM Tip: Add Syntax file for svg graphics

Today I found a graphics from Wikipedia about stomach. The graphics is a svg file, which is actually in XML. I like this type of graphics since it is a graphics in XML format. It makes it very easy to change some parts, specially some words in the graphics. I use VIM to edit the file.

stomach diagram.svg

Get the Syntax File

However, my MacVIM does have syntax file. I quickly found it from VIM web site, svg.vim. I saved it to my Desktop.

Copy svg.vim to Syntax Directory

According to VIM web svg.vim instruction, this file should be copied to VIM syntax directory first. At my Mac, I open my Terminal and copy the file to my vim syntax directory. My VIM's syntax directory is at ~/.vim/syntax/, where some other syntax files are, such as ps1.vim for PowerShell scripts and m.vim for Objective-C.

MyMac:~ userMe$ cp ~/Desktop/svg.vim ~/.vim/syntax/


Add a Line to filetype.vim

The next step is to add a line to my VIM's filetype.vim file. This file is located at my local vim directory:

MyMac:~ userMe$ vi ~/.vim/filetype.vim

In my vi editor, a line is added:

" my filetype file
if exists("did_load_filetypes")
finish
endif
augroup filetypedetect
au! BufRead,BufNewFile *.ps1 setfiletype ps1
au! BufRead,BufNewFile *.m setfiletype objc
au! BufNewFile,BufRead *.svg setfiletype svg
augroup END

Load syntax file From .vimrc

The above change seems OK, but I found that I also have a line in my vim configuration file to load the syntax files. The configuration file is ~/.vimrc, where syntax files are loaded. I added a line for svg:

" Load syntax source from file
source ~/.vim/syntax/ps1.vim
source ~/.vim/syntax/svg.vim

After that, restart my VIM and I'll syntax for the svg file I want to edit:



I should say that I would not need to do above steps to edit svg files by using VIM. However, it would be nice to have correct syntax highlighting if it is available. Finally I used my VIM to edit the svg file and changed texts from English to Chinese:


Reference

See my previous blog on VIM Syntax Settings.

Read More...

Wednesday, March 09, 2011

XCODE4.0 is Out!

Two days before iPad 2 release, today Apple released iOS4.3 for iPhone4 & iPad, as well as massive updates(I wrote a blog today about those items). The most expected XCODE 4.0 is released. I can be purchased from Mac Apple Store at $4.99, unbelievable low price comparing to Microsoft Visual Studio ($799 from MSRP for Professional version to $3,799 for Ultimate). For registered Apple Developers($99 annual fee), it is FREE!

However, this is the first time Apple charges a fee for XCODE. Mac users get XCODE with Mac computer for free. By default is not installed. It is an optional item on CD for most Mac computers, except MacBook Air(with OS X on USB). I got Air last year and I installed XCODE from my iMac CD. It runs without any problems.

I have watched many WWDC 2011 videos from iTunes. I am very impressed by XCODE 4.0 architecture and development. This is the one I am going to get soon when I have time in coming weeks. Here are some pictures of XCODE 4.0







Read More...

Saturday, March 05, 2011

Migration of Web Sites from IIS6 to IIS7

This note is about my experience to move a web site project from IIS6 to IIS7. The project was developed in ASP.Net in VS 2005. The requirement is to move the web site from one Windows box to another one. The only difference is IIS.

At first, I just copied all the files from IIS6 box to another box. That's the way normally I deploy a web site. However, after the set up on the new box in the same file and web site configuration, the new web site got exception when I tried to access to it from IE. After about one hour exploration, I found that it was caused by a http setting in my web.config. Rick Strahl's blog has one comment on this issue: HttpModule and HttpHander Sections in IIS 7 web.config files.

As Rick said, "you've probably seen the IIS 7 Exception that lets you know that in Integrated mode in IIS 7 you are not supposed to have an httpModules or httpHandlers section", however, my case web.config is different. The following http section caused the exception:

<add path="Reserved.ReportViewerWebControl.axd" verb="*" 
type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
validate="false"/>


After I comment it out, the web site on IIS 7 is OK. This is my note on this issue. I think Rick's view is related to the migration from IIS 6 to IIS 7.

Read More...

Tuesday, February 15, 2011

Tip: Delay Seconds in Batch Script

I found this tip to delay batch progress by seconds. PING is a commonly used MS-DOS command for checking a TCP/IP client. By using PING's -n and -w options, it simulates a time delay for its running.


I created a batch file: DeleySeconds.bat:

IF %1.==. PING 1.1.1.1 -n 1 -w 60000 > NUL
IF NOT %1.==. PING 1.1.1.1 -n 1 -w %1 > NUL

If the call to the batch script does not have parameter, the default delay time is 60 seconds. A specific time can be passed in as parameter.


Reference: Batch file examples - Wait.

Read More...

Saturday, February 12, 2011

.Net Project to Copy Excel Data

In the past weeks, I have been working on a project to copy Excel data between worksheets. The source worksheet contains some formulas with links to other worksheets and add-ins. The problem is that the API functions defined in add-ins take long time to get data from a remote service. When there are hundreds and even thousands of rows in Excel, it will take to long time to refresh data. That's the reason to have a scheduled job to copy the daily data from source excel file to another one with only values. Since the output put excel file contains only values, the show time is much responsive.


The project was initially created in .Net by using Microsoft.Interop.Excel, which is a warper class for Excel COM components. This is the first time I saw this namespace and real case usage. Basically, with this namespace and classes there, you can create Excel application, open existing or create new workbook, create or get worksheet.

I found that it is very powerful and interesting to do almost the same work in .Net project as you do interactively with Excel in Windows. For example, if the source excel file contains some links, you can ignore those links and rebuild them in .Net. You can reset excel cell data value and simulate special copy and paste to copy only values to another worksheet.

I updated the project to move many hard-coded settings out to a configuration file so that the tool will be more generic. The goal of the tool is to copy values from an excel file to another one. The figuration contains those settings:
  • Input and output excel files;
  • The links in both input and output files to be rebuilt;
  • Data values to be set in input file. Those values are in range object of an excel worksheet object. The values are strings or Excel formulas;
  • The range of data to be copied in the input file and destination range in the output file;
  • Page layout settings: display grid lines, window display headings, page area and line breaks.
I found one setting is very helpful. You can set excel object visibility so that you can debug your codes by viewing Excel status. With this debug feature, I found many bugs or wrong settings in the existing codes.

The project is almost rewritten to become a more generic tool with configurable feature. I used this not only resolve the original required excel report issue, but it has been used in many other cases. However, personally, I don't think doing the excel work in .Net is a practicable. The excel classes are to easy to be broken. When the project becomes a more generic tool, many unseen issues have not been tested. I don't want to spend too much time to fix issues. The coupling data and report to Excel is too much pain.

Read More...

Thursday, February 03, 2011

My EverNote Entry: OpenRasta, OpenWrap, and OWIN

Today I listened to a podcast by Herding Code. The podcast on Jan 25, 2011 is a very interesting and informational one. It is a talk with Seb Lambla on OpenEverthing, which includes OpenRasta, OpenWrap, OWIN and many other related resources.

I have used EverNote for quite awhile. It is an excellent web service for quickly making any notes. I have created a .Net notebook as public shared one. Therefore, I add one note on this podcast and related links in the notebook. For more detail information about this podcast and the talk on three major Open projects, see my .Net notebook.

The public notebook provided by EverNote can be used as a RSS feed. That means public notebooks can be subscribed to. I use EverNote to make notes for important things such as events, thoughts, and interesting thinks I found on web. In a way, it is my alternative way to write blogs to record my life's journey, almost everything, or a supplementary to my blogs.

Read More...

Sunday, January 30, 2011

OWIN Framework as WebService in .Net

This blog is a late post. I was on vacation back to Beijing and Wuhan during the past Christmas time and came back on Jan 16, 2011. During my time in China, unfortunately, I could not write blog since Blogger is blocked. I knew this issue and I scheduled my posts before I left. I have been busy to pick up and organize my stuff in the past week. Now I am back to normal schedule, working, web learning, doing my project and enjoying my life.

This late post is on OWIN: Open Web Interface for .Net. I got this when I listened to Hanselminute podcast #244 one day before in last December. I wrote a note in my Evernote on this(my .Net notebook).

Afterwards, I tried Kayak, an example OWIN library. The result was very exiting. I spent about 1 hour time on a console project. With its running at work, I could access to the service from any box at my work to get HTML results. My box is Windows XP Prof, which suppose not having any IIS. To install a web server is very complicated. With OWIN or Kayak, based on this testing, I could create any web service. OWIN is a very simple framework. I'll further explorer its potentials. Most likely, I will use it as a REST based service to provide data. I have many projects or apps which depends on remote data such as SCADA historian data, SQL server or Oracle database. OWIN may be excellent solution as light weighted layer to provide data.

Read More...

Friday, January 21, 2011

Parse and Transform Text File by Using PowerShell (3)

In my previous blog, I described who I parsed the input text file from my debug result to generate the first report table. Now Let's continue to the second report.

Generate the Second Report

The second report is another summary report, based on the first report. It displays a list of methods and counts of their calls. In other words, it will list distinct method names in the first report, and take the max counter for each method as method call count.

I find out that to get the second report, it is not easy to use just one pipeline with a long chain of segment codes. Still, I'll continue to use pipelines with each one to generate temporary results. I'll use pipelines to get temporary results, and dynamically add properties to objects.

First, initialize some variables:

# second report
# initialize variables
$totalCount = 0
$i = 0
$ht=New-Object Collections.Hashtable

The first pipeline is used to pass the result of the above collection of objects ($results) as input. There will be no result out of the pipeline. Instead, I use the pipeline to update a hash table variable $ht, with the property of method name as its key.

The input objects are piped into the second segment which is a where clause to filter any object with its count property larger than zero.

# Filter out rows with count less or equals 0
$result | where { $_.$propertyNameForCount -gt 0 } `

Then the filtered object is passed to a block of codes, where the hash table variable $ht is updated with the object with the max count value:

| Select-Object -Property 'MethodName', $propertyNameForCount `
| %{
if ( $_ -ne $null ) {
$key1 = $_.'MethodName';
if ( $ht.ContainsKey($key1) -eq $false ) {
$ht.Add($key1, $_)
}
elseif ($_.$propertyNameForCount -gt $ht[$key1].$propertyNameForCount) {
$ht.Set_Item($key1, $_)
}
}
}

The values of the hash table $ht contain objects we need for the report. In addition to those objects, I need a total count of each method call count. This is done by a pipeline to update total count into the variable $totalCount:

$ht.Values `
| %{ `
if ( $_ -ne $null ) {
$totalCount += $_.$propertyNameForCount
}
}

After we get the total count, a new object is created in the same structure of properties as ones in the hash table, then add the new object to the hash table $ht:

# add total count to $ht1 table
$objValue = New-Object PSCustomObject
$objValue | Add-Member -type NoteProperty -Name 'MethodName' -Value '[Total count]'; # use XXX so that sorting to the last
$objValue | Add-Member -type NoteProperty -Name $propertyNameForCount -Value $totalCount;
$ht.Add("XXXX dummy key", $objValue);

Finally, the objects in the hash table are ready for the second report. The report is generated by the last pipeline: sorting by property 'MethodName', adding a sequence number as object property, and appending the table layout report to the output file:

# generate report
$ht.Values `
| Sort-Object -Property 'MethodName' `
| %{ # Add sequence column
$obj = $_;
$obj | Add-Member -type NoteProperty -Name 'No.' -Value $i;
$i++;
$obj;
} `
| ft -AutoSize -Property 'No.', 'MethodName', $propertyNameForCount >> $outputFile; # Format the result and out put to file

In summary, pipeline in PS is a nice-to-have feature. You may achieve the same result without using pipeline. I like PS pipeline's simple, fluent flow and powerful feature. As you can see, PS is also dynamic data type script language. Objects can be created on-fly and properties can be added or removed during the run-time. My parse script codes take the advantage of those two great features.

Here is the complete package(ParseDebugMsgs.zip) of the script codes.

Read More...

Friday, January 07, 2011

Parse and Transform Text File by Using PowerShell (2)

With the previous blog on the basic concepts and the project goals on your belt, now it is time to jump into the codes from 6000 feet height.

Define Input Variables
I could set some input parameters for my script module for easy use from command line. However, since my script is only for my own use and I have to update some values frequently when I use it, then I decided to just declare some variables with initial settings as a simple start:

$inputFile = 'C:\Tmp\test\fst_PO20100505.txt';
$outputFile = '{0}.txt' -f $inputFile;
[decimal]$durationLimit = -0.01;

Then some counter variables and a hash table variable $ht for later use are initialized:
$i = 0
$j = 1
$identityExPattern = "*duration: *" # expression pattern as a filter
$exPatternForCount = "*DAO::*" # epxression pattern for count
$identityPropertyName = "Duration"
$propertyNameForCount = "DAO count"
$ht = New-Object Collections.Hashtable;

Next I output a line a header to my output file:
# Output duration limit to the result file
'==== Result of "Duration > {0}" ====' -f $durationLimit >> $outputFile;

Those codes are straightforward. The duration limit is a filter, which is used to list only calls with duration larger than the filter value.

Generate the First Report


The first report is generated by one statement with a long list of chained segments of codes as a pipeline. The result is saved to variable $result.

The first segment in the chain is to get lines from input file:

$result = Get-Content $inputFile `

Then the second segment is a block of codes %{...}. This block takes the input to process and generate empty or a collection of objects as a result. The result can be piped to the next segment. The codes in the block is very simple, it updates the line number in a varable $i, and then takes the input object as it is. $_ is a special variable notation for the input object:

| %{ $i = $i + 1;
$_;
} `

Then each line is piped to the next where constrain statement:
| where {$_.trim().length -gt 0 -and ($_.trim().SubString(0,1) -eq "[") -and ($_.trim() -like $identityExPattern)} `

This constrain clause is like a filter to remove un-expected string lines. The result of this filter will be a line which is not empty, the first none-empty char is "[" and the content of the string contains a substring of "duration: ". The interested lines are then piped into the next code block %{...}.

This block contains a lot of codes. They can be divided in to two parts. The first part is to split a line into an array variable $row, and to acuminate count of each method:

$row = (-split $_ ); # split a line into array by space
$bCount = $false;
$method = $row[7]; # example: [ 5/5/2010 9:55:03 AM duration: 0.19 ] AppUserDAO::loginUser
if ( $method -like $exPatternForCount )
{
$c = 1;
# update method in hash table with count value
if ( $ht.ContainsKey($method) )
{
$c = $ht.Get_Item($method) + 1;
$ht.Set_Item($method, $c);
}
else
{
$ht.Add($method, $c);
}
$bCount = $true;
}

The second part is to create an object based on the result of the first part: $row. The object is created by using "Select ... -InputObject ... -Property" statement. The -InputObject take the array of $row as input, and -Property defines a list of properties:

# create an object with properties: sequence, datetime, duration, DAO count, and methodName
$obj = select-object -input $row -prop `
@{Name='No.'; expression={$i;}}, `
@{Name='DateTime'; expression={[DateTime]($row[1] + ' ' + $row[2] + ' ' + $row[3]);};} , `
@{Name=$identityPropertyName; expression={([decimal]$row[5]);} }, `
@{Name=$propertyNameForCount; expression={ `
if ($bCount) { `
$ht.Get_Item($method); `
} `
else { `
0; `
} `
}
}, `
@{Name='MethodName'; expression={($method);} };
$obj; #output object

The last line of $obj will pass the object to the next segment of the pipeline.

The segment is a simple where clause, which filters out any duration smaller than the expected value:

| where { $_.Duration -gt $durationLimit } `

The final pipe segment is to create another object based on input object. The purpose of this new object is for the first report, each property for a column in the report:

%{
$obj1 = Select-Object -Input $_ -Property `
@{Name='No.'; expression={$j;}}, `
@{Name='Org No.'; expression={$_.'No.';}}, `
@{Name='DateTime'; expression={$_.'DateTime';};} , `
@{Name=$identityPropertyName; expression={$_.$identityPropertyName;} }, `
@{Name=$propertyNameForCount; expression={$_.=$propertyNameForCount;} }, `
@{Name='MethodName'; expression={$_.'MethodName';} };
$j++;
$obj1; # output obj1
};

The result of the above chained segments is a collection of objects for the first report. The result is assigned to variable $result, and then is output to a file:

# get the reults to output file as formatted table
$result | ft -AutoSize >> $outputFile;

Read More...

Saturday, January 01, 2011

Parse and Transform Text File by Using PowerShell (1)

I have used my DebugLog class to investigate issues in Visual Studio projects. The debug messages are pushed to Visual Studio's output consol. The generated messages may be very extensive huge. For example, I had a case of a Windows application with performance issues of DAO calls. I got about 8233 lines of debug messages just from the start to the main window displayed. I copied the messages to a text file. It is 732K in size. I like to keep the raw messages there; however, it was hard to investigate issues with the extensive raw messages.

What I would like is to generate concise summary reports, for example, a list of method calls with durations in an order and a list of DAO calls with their counts. This is similar to the case to use XPath to parse and to transform an XML content to another format, such as a HTML table list.

PS came to my mind first. PS is a script based language; therefore, it is easy to give it a try. I am not an expert in PS. I just use it and learn it as I need. I spent some time to write codes and finally I completed a script module to get my expected result. Here is my review of the codes.

Basic Concepts

Before I jump deep into my PS codes, I would like to list brief explanations for some basic concepts.

Single value variables are dynamically declared in PS with prefix $. The data type can also be static in the format of [type]var.

Hashtable is a dictionary data type with a key and an associated value. The constant definition is @{[key1=value1,...]} or @{}.

# is used for comments.

Statements can be either separated by line break or terminated by ';' character. ` character is used as a continuing indicator.

Piping or pipeline is a very powerful feature in PS. By using |, twp segments of codes can be chained together, the output or results of the first segment being piped into the next segment of codes as an input. Not only strings can be piped, but objects can also be passed through the pipeline. You can write similar codes without pipelines, but by using it appropriately, your scripts may look much simple and easy to read, and you may like this unique and powerful feature of PS.

There are many great resources on web. For example, the first part of this blog tutorial on PS variables, arrays, and hashtables provides nice hands-on examples on PS basics.

The Goal of my Project

I call it as a project because I want to write script codes to reach my goal. Basically, I copy my debug messages from VS output console and save them to a text file. The goal of the project is to read the text file as input, parse each line and generate a list of reports, actually two reports in this project.

The first report is a table view of methods and their corresponding duration time. The second report is a table view of interested methods and their call counts.

Here is a partial section of the raw data:

[ 5/5/2010 3:12:58 PM ] MainSchedulingTool::posMenuItem_Click
[ 5/5/2010 3:12:58 PM ] POSelectionViewForm::POSelectionViewForm
[ 5/5/2010 3:12:58 PM ] POSelectionViewForm::poStartDateTimeFilterPicker_ValueChanged
[ 5/5/2010 3:12:58 PM duration: 0.00 ] POSelectionViewForm::poStartDateTimeFilterPicker_ValueChanged
[ 5/5/2010 3:12:58 PM ] POSelectionViewForm::poEndDateTimeFilterPicker_ValueChanged
[ 5/5/2010 3:12:58 PM duration: 0.00 ] POSelectionViewForm::poEndDateTimeFilterPicker_ValueChanged
[ 5/5/2010 3:12:58 PM ] PODAO::GetAllPOsByStatusAndOrderByEndDate
[ 5/5/2010 3:12:58 PM ] PODAO::GetPOs
[ 5/5/2010 3:12:59 PM ] PODAO::ReadPOData
[ 5/5/2010 3:12:59 PM duration: 0.00 ] PODAO::ReadPOData
[ 5/5/2010 3:12:59 PM ] PODAO::ReadPOData
[ 5/5/2010 3:12:59 PM duration: 0.00 ] PODAO::ReadPOData
[ 5/5/2010 3:12:59 PM ] PODAO::ReadPOData
[ 5/5/2010 3:12:59 PM duration: 0.00 ] PODAO::ReadPOData
[ 5/5/2010 3:12:59 PM ] PODAO::ReadPOData
[ 5/5/2010 3:12:59 PM duration: 0.00 ] PODAO::ReadPOData
...

Here an example of the first report:
No. Org No. DateTime            Duration DAO count MethodName
--- ------- -------- -------- --------- ----------
1 161 5/5/2010 3:12:59 PM 0.38 1 PODAO::GetPOs
2 162 5/5/2010 3:12:59 PM 0.38 1 PODAO::GetAllPOsByStatusAndOrderByEndDate
3 164 5/5/2010 3:12:59 PM 0.41 0 POSelectionViewForm::POSelection...
4 807 5/5/2010 3:13:00 PM 1.56 1 VendorDAO::GetVendorData
5 808 5/5/2010 3:13:00 PM 1.56 1 VendorDAO::GetVendors
6 1450 5/5/2010 3:13:02 PM 1.83 2 VendorDAO::GetVendorData
7 1451 5/5/2010 3:13:02 PM 1.84 2 VendorDAO::GetVendors
8 1452 5/5/2010 3:13:02 PM 1.84 0 POSelectionViewForm::setupSortedPOList
9 2575 5/5/2010 3:13:13 PM 14.13 0 POSelectionViewForm::PopulatePOData...
10 2576 5/5/2010 3:13:13 PM 14.13 0 POSelectionViewForm::POSelection...
11 2729 5/5/2010 3:13:14 PM 0.16 0 MainSchedulingTool::setupC......


The first column is a sequence number. It is a sequence line number in the report. The second is similar to the line number in the raw text file. The remaining columns are the information about each method such date time, duration value, count of DAO method calls, and method names.

The following is an example of the second report:
No. MethodName                                DAO count
--- ---------- ---------
0 [Total count] 6
1 PODAO::GetAllPOsByStatusAndOrderByEndDate 1
2 PODAO::GetPOs 1
3 VendorDAO::GetVendorData 2
4 VendorDAO::GetVendors 2
...

Read More...