Saturday, May 8, 2010

Extract File Extension and Check Image Format

[ Intention | Requirements | Discussion and Implementation | Final Code Snippets ]

Intention [top]

Once in a while, we all may need to extract the file extension from a file name. In the past, when I was doing it in Java, I used to use the String.lastIndexOf() to search for the last period in the filename and then extract the rest of the substring. We can apply the same idea in .NET using String.LastIndexOf() as well. However, .NET provides a single static method call; it makes everything a lot easier. However, this static method internal implementation is not using regular expression to extract the file extension. Yesterday, I was browsing around my old code and thinking that I would like to use regular expression to capture the file extension. Thus, I pick the portion of my file upload program for conversion. First, I will start with the requirements for this file upload portion and then go into the detail discussion. Finally I will present the complete code snippets. In this exercise, I will also show you how to check the image format.

Requirements [top]

  1. Use regular expression to capture or extract the file extension from the file name but the leading period (.) of the resulted file extension must be trimmed off. For example, .txt becomes txt.
  2. A file extension cannot contain spaces.
  3. Save the uploaded file if only if the file extension is one of the listed extensions (see the list below) and the file must be one of the supported image formats.
  4. Supported file extensions are BMP, GIF, PNG, TIFF, JPG, and JPEG.
  5. Supported image formats are BMP, GIF, PNG, TIFF and JPEG. They are also corresponding to the above file extensions

Discussion and Implementation [top]

There are a few ways to extract a file extension from a file name. One of the simple ways is to use System.IO.Path.GetExtension() method by passing the file name as a parameter, e.g.,

   System.IO.Path.GetExtension("abc.txt")

In this example, .txt is the extracted file extension and it always comes with a leading period (.). In order to fit our 1st requirement, we could remove the leading period from the resulted file extension. Unfortunately, the requirement binds us to use regular expression. Thus, the regular expression should look like the following (non-named capturing):

      \.([^.]+)$

According to the 2nd requirement (the extension cannot contain spaces), the previous regular expression is revised and becomes:

      \.([^(\s|.)]+)$

In C#, we can do the following to fulfill the #1 and the #2 requirements:

      String pattern = @"\.([^(\s|.)]+)$";        
      String fileExt = null;

      Regex r = new Regex(pattern);
      Match m = r.Match(filename);
      if (m.Success) {
        fileExt = m.Groups[1].Value;
      }

As we can see, the captured text is always placed inside the group 1 (at index 1), not 0. What if we have many captured groups? It could be hard to remember which one is what. Luckily, .NET supports name capturing. It greatly helps in coding and back-reference. In this example, the requirement is simple and we don't have to use named capture. But to exercise this named capture feature, we could revise the regular expression a bit and then reference the name in our code. Let's say that the captured text name is called ext. The revised code snippet becomes:

      String pattern = @"\.(?<ext>[^(\s|.)]+)$";        
      String fileExt = null;

      Regex r = new Regex(pattern);
      Match m = r.Match(filename);
      if (m.Success) {
        fileExt = m.Groups["ext"].Value; 
      }

A part of the third requirement is to check the resulted file extension against our supported file extension list. We can continuously get help from regular expression. Let's define our pattern for matching. In C#, we can write this:

      String SupportedImageExtPatterns = "^(BMP|GIF|PNG|TIFF|JPE?G)$";

To check the resulted file extension against the list, in C#, we can implement this way:

      Match m1 = Regex.Match(fileExt, 
                             SupportedImageExtPatterns,
                             RegexOptions.IgnoreCase);
      if (m1.Success) {
        ...
      }
or using one single statement,
      if (Regex.Match(fileExt, 
                      SupportedImageExtPatterns,
                      RegexOptions.IgnoreCase).Success) {  
          ...
      }

How to check the file is one of the supported image format? Since the file is uploaded via HTTP, the file could be anything. For this matter, we first need to confirm if the file is an image by referencing to the file's Stream object and then try to convert it to an image. If we get an ArgumentException, it is not an image. Let's say the file upload object is called FileUpload1. In C#, we can write the following to execute the idea.

      System.Drawing.Image theImage = null;
      try {
        theImage = System.Drawing.Image.FromStream(FileUpload1.PostedFile.InputStream);
      }
      catch (System.ArgumentException) {  // not an image
        ...
      }
After we've confirmed that the file is an image, we can go ahead to check the image format against our list with the help of the Equals() method of System.Drawing.Imaging.ImageFormat. For convenience, I group all the required System.Drawing.Imaging.ImageFormat objects together in an array so that I can iterate through the array for checking.
       System.Drawing.Imaging.ImageFormat[] SupportedImageFormats = { 
             System.Drawing.Imaging.ImageFormat.Bmp,      
             System.Drawing.Imaging.ImageFormat.Gif,      
             System.Drawing.Imaging.ImageFormat.Png,
             System.Drawing.Imaging.ImageFormat.Tiff,
             System.Drawing.Imaging.ImageFormat.Jpeg      
       };

The code snippet for checking image format in C# is illustrated below:
       System.Drawing.Imaging.ImageFormat[] SupportedImageFormats = { 
         System.Drawing.Imaging.ImageFormat.Bmp,      
         System.Drawing.Imaging.ImageFormat.Gif,      
         System.Drawing.Imaging.ImageFormat.Png,
         System.Drawing.Imaging.ImageFormat.Tiff,
         System.Drawing.Imaging.ImageFormat.Jpeg      
       };

       System.Drawing.Image theImage = null;
       try {
         theImage = System.Drawing.Image.FromStream(FileUpload1.PostedFile.InputStream);

         for (int i=0; i < SupportedImageFormats.Length; i++) {        
           if (theImage.RawFormat.Equals(SupportedImageFormats[i])) {
             ...
             break;
           }
         }
         ...

       }
       catch (System.ArgumentException) {  // not an image
         ...
       }

As soon as we confirm that the file is an image and it is also one of our expected formats, we can simply use the FileUpload object SaveAs() method by passing the absolute pathname. Let's say the directory to save is called Uploads. The statement may look something like below:

   FileUpload1.SaveAs(Server.MapPath("~/Uploads/") + FileUpload1.FileName);
Up to here, our mission is accomplished from extracting the file extension, checking image format to saving the file. The complete code snippets are presented in the next section.

Final Code Snippets [top]

The followings are two pieces of code snippets summarized for the above discussions. The difference between these two pieces of code is: one is using non-named capture to extract the file extension while the other is named capture. Other than that, everything is identical.

Using non-named capture to extract the file name [ Final Code Snippets | top ]

Note that
  1. the file upload control object is called FileUpload1, and
  2. the save directory is called Uploads and located at the root directory.
// declare the pattern for Requirement #1 and #2 to capture the file extension.
// the following pattern is using non-named capture.
String pattern = @"\.([^(\s|.)]+)$";        
String fileExt = null;

Regex r = new Regex(pattern);
Match m = r.Match(FileUpload1.PostedFile.FileName); 
if (m.Success) {
  // capture the file extension without the period
  // here we use non-named capture group
  fileExt = m.Groups[1].Value;

  // Requirement #4 - the supported file extensions
  String SupportedImageExtPatterns = "^(BMP|GIF|PNG|TIFF|JPE?G)$";

  if (Regex.Match(fileExt, 
                  SupportedImageExtPatterns,
                  RegexOptions.IgnoreCase).Success) {

    // Requirement #5 - the supported image formats 
    System.Drawing.Imaging.ImageFormat[] SupportedImageFormats = { 
          System.Drawing.Imaging.ImageFormat.Bmp,      
          System.Drawing.Imaging.ImageFormat.Gif,      
          System.Drawing.Imaging.ImageFormat.Png,
          System.Drawing.Imaging.ImageFormat.Tiff,
          System.Drawing.Imaging.ImageFormat.Jpeg      
    };

    System.Drawing.Image theImage = null;
    try {
      theImage = System.Drawing.Image.FromStream(FileUpload1.PostedFile.InputStream);
    
      for (int i=0; i < SupportedImageFormats.Length; i++) {        
        if (theImage.RawFormat.Equals(SupportedImageFormats[i])) {
           // Requirement #3 - save the file only if it is our expected image format.
           FileUpload1.SaveAs(Server.MapPath("~/Uploads/") + FileUpload1.FileName);
           break;
        }
      }      
    }
    catch (System.ArgumentException) {  // not an image
      ...  
    }
  }
}

Using named capture to extract the file name [ Final Code Snippets | top ]

Note that
  1. the file upload object is called FileUpload1, and
  2. the save directory is called Uploads and located at the root directory.
// declare the pattern for Requirement #1 and #2 to capture the file extension.
// the following pattern is using named capture.
String pattern = @"\.(?<ext>[^(\s|.)]+)$";        
String fileExt = null;

Regex r = new Regex(pattern);
Match m = r.Match(FileUpload1.PostedFile.FileName);
if (m.Success) {
  // capture the file extension without the period
  // here we use named capture group
  fileExt = m.Groups["ext"].Value;

  // Requirement #4 - the supported file extensions
  String SupportedImageExtPatterns = "^(BMP|GIF|PNG|TIFF|JPE?G)$";

  if (Regex.Match(fileExt, 
                  SupportedImageExtPatterns,
                  RegexOptions.IgnoreCase).Success) {

    // Requirement #5 - the supported image formats 
    System.Drawing.Imaging.ImageFormat[] SupportedImageFormats = { 
          System.Drawing.Imaging.ImageFormat.Bmp,      
          System.Drawing.Imaging.ImageFormat.Gif,      
          System.Drawing.Imaging.ImageFormat.Png,
          System.Drawing.Imaging.ImageFormat.Tiff,
          System.Drawing.Imaging.ImageFormat.Jpeg      
    };

    System.Drawing.Image theImage = null;
    try {
      theImage = System.Drawing.Image.FromStream(FileUpload1.PostedFile.InputStream);
    
      for (int i=0; i < SupportedImageFormats.Length; i++) {        
        if (theImage.RawFormat.Equals(SupportedImageFormats[i])) {
           // Requirement #3 - save the file only if it is our expected image format.
           FileUpload1.SaveAs(Server.MapPath("~/Uploads/") + FileUpload1.FileName);
           break;
        }
      }      
    }
    catch (System.ArgumentException) {  // not an image
      ...  
    }
  }
}

Wednesday, April 7, 2010

Facebook Privacy Setting for Wall Posts by Friends

Also see the update on Jan 5, 2011.


Facebook has been changing a lot since this March and they still keep changing. Have you ever noticed the above setting in the red box?

You can find this setting at your personal profile page. Go to your profile, locate the "Share" button. Right below it, click on "Settings," you will find the above settings circling by the red box.

If you change the setting for "Who can see posts made by friends?" to "Only Me," the check box for "Posting Ability" will be grayed out and become unchecked. It means no one or application can post anything to your wall. Unfortunately you won't notice this change unless you immediately refresh the page and then go back to the same location to check on it. Or you may know this problem when someone notifies you.

These above two settings are supposedly corresponding to the settings at your privacy settings page. Again, it is confusing. After the changes made from your profile page, if you go and check your privacy settings page, you will find this confusing settings as shown in the following picture.


The check box for "Friends can post on my Wall" is still on (checked) while "Posts by Friends - Control who can see posts by your friends on your profile" is set to "Only Me."

Because the second setting is set to "Only Me," no one but you can post to your wall. Thus, if you allow your friends to post something to your wall, please make sure "... [W|w]ho can see posts made by ... friends... " is set appropriate in your profile page or your privacy settings page.

I personally don't understand why Facebook still doesn't want to change or amend this wording "... who can see posts made by ... friends?" to make things clear.

Thursday, March 25, 2010

How to make UTF-8 as default encoding in Notepad++ manually

The following information applies to version 5.1 up to the current latest version 5.6.8. It may apply to the future versions. However, if you're using the latest one (5.6.8), the GUI now provides a nice setting for you to change (Settings -> Preferences -> New Document/Default Directory). If you use the GUI to change the settings, the following manual method may not work. I don't know where another configuration files are stored.

Important: Don't use the same version of Notepad++ to edit any its configuration files. Otherwise, all your changes or modifications will be lost when you exit.

Note that I use Notepad++ zip version and do the manual installation instead of using the executable installer. Thus, your installed file structure may be different from mine if you're using installer.

  • Go to the location where you install your Notepad++ and you should see two folders, ansi and unicode.

    Each folder represents a distinct version. The Unicode version is mainly to support Unicode characters in paths. Please see here to learn more about these two versions.
  • Go in either ANSI or Unicode version folder where you may use to launch your Notepad++.
  • Open the file called config.xml. For the newest version, this file doesn't exist at the beginning but config.model.xml is provided. Make a copy from config.model.xml and then rename it to config.xml.
  • Locate the following line:
    <GUIConfig name="NewDocDefaultSettings" format="0" encoding="1" lang="0" openAnsiAsUTF8="no" />
    
  • Set encoding to 4 for UTF-8. For other encodings, see the table below or the comment inside the file.
    <GUIConfig name="NewDocDefaultSettings" format="0" encoding="4" lang="0" openAnsiAsUTF8="no" />
    
    0ANSI
    1UCS2 BIG
    2UCS2 SMALL
    3UTF 8
    4UTF 8 without BOM
  • Relaunch the Notepad++.

Monday, January 11, 2010

Thinking to extend my MagicJack service to 5 years

magic jack I have been using MagicJack almost for a year. I am thinking to extend the service to 5 years. Unfortunately, the charge of 5-year service plan has been increased from $59.99 to $69.99. If I have have know this, I could have extended it earlier to save my $10.00. Still, this 5-year plan deal is better than the one provided by AT&T, Time Warner or other phone service companies. The most importance is that I am satisfied with their phone quality but I have to bear with their poor support service including Web one.


Note that beginning of this post, I switched to use the image hosting service from ImageShack instead of PhotoBucket because PhotoBucket has imposted a storage limit to free accounts.

Monday, October 26, 2009

Why inner DIV doesn't inherit background color

What situation will make an inner DIV not inherit the background color of the outer DIV? It usually happens when CSS or HTML style's float attribute exists. Considering the following HTML,
<html>
<body style="background-color:#F8E0EC;">
<div style="background-color:#fff;padding:20px;border:10px solid blue;">        
  <div style="float:left;width:330px;border: 1px dotted red;">
      <p>
        <strong>When:</strong>          
        12/5/2009        
        <strong>@</strong>
        3:30 PM
      </p>
      <p>
        <strong>Where:</strong>
        5 main street
        USA
      </p>
      <p>
        <strong>Description:</strong>
        test
      </p>
      <p>
        <strong>Contact:</strong>
        425-555-1212
      </p>   
  </div>   
</div> 
</body>
</html>
The picture will look like this:
inner div floats outside
As you can see, most inner DIV text are sitting outside the blue box (outer DIV). If you take out the float attribute, everything will work fine. The reason of using float attribute is that you may want to have another DIV sit side-by-side together. In this situation, you need to put
   <div style="clear:both"></div> 
at the end of the inner DIV, just before closing the outer DIV. In my example, I will continue to use only one inner DIV. You can test it yourself with two.
<html>
<body style="background-color:#F8E0EC;">
<div style="background-color:#fff;padding:20px;border:10px solid blue;">        
  <div style="float:left;width:330px;border: 1px dotted red;">
      <p>
        <strong>When:</strong>          
        12/5/2009       
        <strong>@</strong>
        3:30 PM
      </p>
      <p>
        <strong>Where:</strong>
        5 main street
        USA
      </p>
      <p>
        <strong>Description:</strong>
        test
      </p>
      <p>
        <strong>Contact:</strong>
        425-555-1212
      </p>   
  </div>

  <div style="clear:both"></div>
   
</div> 
</body>
</html>

inner div floats outside
Now the problem is fixed.

Saturday, October 24, 2009

Key Notes for Complie, Install, and Using OpenSSL on Windows

Ref Docs: Generate Private Key | Generate Certificate | config | openssl | openssl req | openssl ca

I downloaded three versions of OpenSSL and have successfully compiled both versions 0.9.8h and 0.9.8k. But the compilation failed on the latest beta version 1.0.0-beta3. In this document, I will describe how I compile, install and use OpenSSL into IIS on Windows. Note that the part using/configure OpenSSL is missing in this article. I haven't completed it in my writing. I was distracted by something else while I was working on this article. All my notes are still in my local computer. After a while, I completely forget about it. Since it is just for my own notes or references, I decide to leave it as-is. If I upgrade my OpenSSL, I may update this info as needed.

Tools needed:
  • Cygwin, or GNU tar and gzip: If you don't have cygwin, I would recommend to install it. You will find a lot of useful UNIX utilities such as tar and gzip. For openssl purpose, you need both tar and gzip to unpack the openssl-<version>.tar.gz file. Don't use WinZip, WinRAR or similar to uncompress the file. Or most likely you will have problems in compilation. You can use GNU tar and gzip instead if you have them. But I have some troubles using them.
  • MinGW: It is optional unless you compile openssl under cygwin with error(s). MinGW can compile source under a DOS command prompt. For a unknown reason, I cannot compile openssl under cygwin but I can compile it under DOS with MinGW. I also cannot compile it with VC++ either.

Compilation

The followings are the steps I was taking to get the job done and MinGW is the compiler.
  1. Uncompress the file using tar and gzip. You can do it under either DOS or Cygwin Bash Shell enviornment.
    tar zxvf openssl-x.x.x.tar.gz

    With the z option, tar will automatically involve gzip to work together. Thus you must have gzip around and they both must sit in the same directory.
  2. After the file extraction, look for INSTALL.W32 file for the detailed Windows compilation instructions
  3. Ensure MinGW's bin directory is in the PATH environment. Or you can do the following at the command prompt, assuming your MinGW installation directory is at c:\mingw.
    set PATH=c:\mingw\bin;%PATH%"
  4. Change directory into OpenSSL-x.x.x directory, for example,
    cd c:\openssl-0.9.8k
  5. Type the following command to compile:
    ms\mingw32
  6. The compilation will take a while. When it is done successfully, it will end with the following two lines:
    Generating the DLLs and input libraries
    Done compiling OpenSSL
  7. Two DLL's files ( libeay32.dll and libssl32.dll ) are found in the root directory (e.g., c:\openssl-0.9.8k). MinGW also produced two additional directories: out and outinc.

    openssl.exe and other executable files are found in out.

    outinc contains all the headers files.

After Compilation

There is no actual openssl installation. As openssl claims, if you compile it under cygwin, the compiled version will be placed under cygwin directory at /usr/local/ssl. In my case (because I use MinGW for compilation) , I have to repackage the files and the directories myself.
  • Create the following directory tree:
    openssl dir
  • Copy files (assuming the above step is created at c:\):
         copy out\*  c:\openssl\bin
         copy outinc\openssl\*  c:\openssl\include\openssl
         copy out32dll\libeay32.dll c:\openssl\lib
         copy out32dll\libssl32.dll c:\openssl\lib
         copy apps\openssl.cnf  c:\openssl\config
    

Master Configuration File Location

The master openssl.cnf is located inside the apps directory.

The openssl configuration file name is openssl.cnf, which is expected to be found at /usr/local/ssl/ (unix file path style). If you are using cygwin, this ( /usr/local/ssl/openssl.cnf) should be under your cygwin directory. Unfortunately, I cannot compile it under cygwin. Again, I am using mingw as my compiler. With it, the master configuration file is located inside the apps directory.

Possible Issue

When you answer Y to sign the certificate/request again, you may have the following error:
Sign the certificate? [y/n]:y
failed to update database
TXT_DB error number 2

Solution: You cannot have two certificates that look the same. To fix this, there are two options:
  1. You can remove the line in the database (index.txt) or replace the index.txt with an empty one. Or
  2. you can revoke the previous certificate, e.g, openssl ca -revoke myCA.cer

Friday, October 23, 2009

DOS to UNIX

When you are running a script or compiling a program in a Cygwin Bash Shell, you may encounter the following error:
\r command not found

To handle it, you need to convert this DOS ending character \r at the end of each line to UNIX format.

In Cygwin or UNIX, you can convert an input file (INFILE) in DOS format to an output file (OUTFILE) in Unix format by calling:

> tr -d '\15' < INFILE > OUTFILE
Or you can run this command:
> d2u --safe *
Here --safe mean not touching any binary files. The * is wild card for all files in the current directory. You can type d2u --help in bash for help.

Similarly, you can use u2d to convert UNIX ending line character to DOS format.

Monday, October 19, 2009

Free long distance calls including International calls

Free International Long Distance Calls Talkster or FreeRinger

Note that Talkster is no longer free beginning of the year of 2010.

Talkster provides free International phone-to-phone calls including landlines and mobile phones. As of today, it supports 38 countries. I have been using it for a year already. You don't have to sign up before use. Simply go register your phone and your callee number in exchange for talkster numbers and then you both are ready to call each other.

Each call seems to be limited to 2 hours.

If you don't use the talkster number for a while, you may not be able to use it and call. In this case, you may get a busy signal saying the line is not available or something. Simply go to Talkster again and re-input the numbers; the problem should be cleared itself.

FreeRinger uses Talkster service to provide free calls. With FreeRinger, you don't have to use a physical phone to make calls. You can make calls via Computer-Phone and send/receive calls via your SIP phone. There is absolutely no software download and it is completely online. However, you have to create an account with them first. This feature is great for off-country traveling, or you don't want to use a physical phone to make calls.

Free Fax: Please see my another post

Free WiFi Locator: JiWire
It lists all available free WiFi hot pots in 140 countries. The service will be no use if you don't have an Internet to access it first. Thus, you would be better to do the research of the location while you are being connected.

Saturday, October 17, 2009

Free Fax

Oh, no, I cannot send fax. I did in the past when I still had my land line. Not any more now. Traditional fax can't work well with VoIP. Why? See this for why faxing over IP network doesn't work. I am currently using MagicJack which sends data/voice via VoIP protocols. What can I do?

I tried quite a few products but there is only one which actually works. The service can send fax internationally. I also tested this out and it worked like a charm. The other important thing is that it is free!

You can use their service either by your mobile phone or directly at their site : qipit
  • You need to create an account with them first.
  • All documents must be in picture format, not PDF or any other kinds of format. Apparently, the service only operates on pictures. It will convert a picture file into a PDF file for email or fax.
  • You can upload pictures to your account by MMS or email to either copy@qipit.com or color@qipit.com.
  • The detail instructions could be found here.
  • It supports a multiple-page document.
  • For free service, the fax limit is 5 per week counting from each Sunday at 12:01 am in Paris, France.

Tuesday, September 22, 2009

Changing account info with yahoo is difficult

I have seldom used yahoo email account since they no longer support POP. Recently, I have logged on to it and was forced to add new security questions due to their new design and interface. Then I found that there is an error in my birthday and would like to amend it. Unfortunately the field is not available. I sent them a question asking about how to update it.

The answer is that I have to wait for 35 days in order to edit the field since my security questions are newly added/updated. The other ridiculous thing is that this field will be public by default (see the email exception below). I can't hide it until 35 days. How difficult to make the personal account information becomes editable immediately since they have already had the interface? Why do I have to wait 35 days? Anyway, I simply hide my entire profile since I am not using it for connections.

The following is excerpted from the email answered by Yahoo:

"Once the 35 days has passed, you will be able to edit your age from the "Edit Profile" link in your Yahoo! Profile. Edit fields for your birth date will be available on that page after the 35 day period. You will also be provided a field that will allow you the ability to hide your age from other users."

September 28, 2009
The 35 days have already passed. I still don't see that there is a field for age or birthday available at the Edit Profile page. Everything is the same as before only showing Full Name, Display Name, Location, Verify and two buttons (Save and Cancel) - that's! The page with the birthday info I found is only available at Account Info page. Unfortunately it is not editable at that page. I have never seen Age field that Yahoo keeps mentioning. They should have posted the screenshot at their support page to guide people. Such a question has been asked several times if you do a search on Google, but no one is fond of their answer. I have been talking to Yahoo back and forth 4 times. I can see that it is wasting time. Wait for 35 days? Then what? The information is still unavailable. Yahoo support just wants to dismiss you ASAP regardless of your satisfaction with their answer. Luckily, I don't subscribe their pay service. It is totally not worth it! Although it is free, Users should have the right to make corrections on their personal data. It seems to me that Yahoo promotes false information and discourages users to make amendments!

Side note:
  • A few years ago, a friend of mine's email accounts were hacked. She successfully had her Hotmail back but not Yahoo. She was extremely furious with Yahoo and advised everyone to reconsider if he or she chooses Yahoo's service while there are better services in somewhere else.
  • If you lose your password, you probably will be out of luck to get your account back from yahoo. I lost once in the past but luckily I remember it a month later to have it back. Their service support is very poor regardless of how much information you provide them. Their answer is always the same, "Sorry, your data doesn't match with their file." So the case is closed.

Thursday, September 3, 2009

Your Facebook photo alumn is never private

Regardless of your permission setting on your Facebook photo albums, they are all considered public. Each album is assigned an unique access link. It can be found at the bottom of the album page (the link is only visible to you). Don't think you set the photos are only viewed by you; then the rest of the world can't see it. Facebook has explicitly said in every album that "Share this album with anyone by sending them this public link: ...." Obviously your photos are viewable to non-facebook users, which means everyone. The link will look like this:

    http://www.facebook.com/album.php?aid=12345&id=123456789&l=abcdefghij

In the above example, l=abcdefghij, I believe, is sort of the public access ID. Without it, non-Facebook users cannot go in the album or see the photo. Therefore, don't casually distribute your album link to anyone. Without it, the link is difficult for human educated guess; possibly a hack program can. If you have ever published the link to someone else, you may consider to create a new album by transferring the existing photos to the new one and then delete the old album. The new album will be assigned a new public access ID. Such a way it may keep your photos more safer. As of this writing, there is still no guarantee to keep your photo on Facebook 100% private.

Blogger fails to identify users

Some people are unable to provide comments with their own identities using their Google accounts, because blogger always mistakenly tags them with someone else. Clearing cookies and cache for the browser won't make a difference. I am one of them. Thus, I won't comment friends' blogs with my Google Account identity because it will never be me. Luckily most of them allow visitors to sign with Name/URL.

I just did a little bit experience using a public computer where I have never been before by posting a comment back to my own blog. When I posted a comment, I logged in with my Google account, hoping my name will show up correctly. No, never! Instead, I became someone else. The worst is that I don't even know who that person is. Obviously, it is not the issue of you possessing many Google accounts as blogger claims. Unfortunately, blogger has never admitted the fault and has no plan to fix it. In looking back the complaints posted to the blogger user communities/forums, this problem has existed for a few years already. To be safe, if you have already experienced this problem, it would better not use Google account when you post a comment to blogger, use OpenID if you have another identity with some other sites, or use Name/URL if the blog allows anonymous posting.

Blogger cannot correctly handle their own Google account for comment posting. Why not put Google account under OpenID category and handle it the same way as other OpenIDs? This problem discourages people using (or signing up) Google accounts and also degrades user experience.

Monday, August 31, 2009

How to make your Facebook note visible to everyone?

[Update on Oct 1, 2010]

Facebook has changed a lot since March 2010. This post previously is no longer valid. In the past, Facebook Notes privacy setting possessed its own rules and settings which were different from other applications. Nowadays everything has been migrated. Notes acts like other applications and its privacy permission setting also follows the norms.

There are 4 categories in permissions: Everyone, Friends of Friends, Friends Only and Customize. The privacy permission is a lot of simpler. For example,

Setting permission to Everyone on a note means that this note is visible to everyone on Facebook, no matter if your wall is closed or the wall is visible only to yourself. However, if your personal profile is closed or only visible to certain people, the Facebook community may not see your note via your profile page unless they have your note URL, e.g. http://www.facebook.com/note.php?note_id=[your_note_id].

Unlike the past, the default setting of Notes application has no additional control on permissions. It will be applied to a note when published only when you don't make any permission change individually.

There are two areas to control if your Facebook note is visible to everyone.

First, you have to open your application permission door to the Facebook public. This application permission acts like a gatekeeper to control who can get in the Notes door and see your notes. The default permission is Everyone. Each individual note can be associated or applied by different permissions as needed. The default is still Everyone. If you set your Notes application permission to something else other than Everyone, and then you set your individual note to Everyone, your note will not be visible to everyone on Facebook. For example, if you set the Notes application permission to Only Friends, and you set your note to Everyone, it means that only everyone of your friends will see that note. In other words, the permissions for both the application and the note itself must be set to Everyone in order to share that note with the Facebook public. The following table could provides you some illustration.

Notes Application Permission Individual Note Permission Who can see the note
Everyone Everyone Everyone on the Facebook this is the default.
Only Friends Everyone Everyone of your friends on Facebook
All combination permission sets are not shown in this table. There are only two examples as discussed.

For me, I set my Notes application permission to Everyone; then I use the individual note permission to control who can see my notes. Some notes will be shared with the entire Facebook community, some with my friends, some with certain people and some even only for myself. If you are sure that you won't share anything to the Facebook public, you can just simply to close the door by setting the application permission to something else other than Everyone. Then the unwanted guests won't be able to get into your Notes territory.

How and where to set the application permission settings

Here is one of the ways to do it.
  • Navigate to your Notes page, and then at the top of the page (blue bar), mouse over Settings. you will see something similar as below.
    locate application settings
  • Select Notes Settings if it exists; otherwise, select Application Settings.
  • If you select Application Settings, locate the application called Notes and then click on Edit Settings.
  • Notes application settings
  • Now you're at the application setting control box where you can change the permission. permissions dropdown box


Individual Note Permission

In each note, you should find something similar to the following at the bottom of the note when you compose it. Set or change the permission as needed.
individual notes permissions box



One more thing, Setting Everyone permission to both the application and the note will not make it to be visible to non-Facebook users. All users have to log in onto Facebook in order to see your note.

Thursday, August 27, 2009

Location of IsolatedStorageFile

An IsolatedStorageFile is always persisted to a dedicated location by .NET isolated storage API. Each file, when it is first created, will be granted access at least to the current logged-on user plus other requirements. In other words, an IsolatedStorageFile is created based on isolated requirements called IsolatedStorageScope, for example,

  • User + Assembly
  • User + Assembly + Domain
  • Roaming + User + Assembly
  • Roaming + User + Assembly + Domain
  • ...
  • Machine + Assembly +
  • Machine + Assembly + Domain
  • ...
Note that you cannot initialize a storage with IsolatedStorageScope.User and IsolatedStorageScope.Machine together because IsolatedStorageScope.Machine represents All Users which include the current user. But either one of them must be present in the IsolatedStorageScope with others. In addition, you cannot use IsolatedStorageScope.Application if the application is not configured or running as a ClickOnce application, which implies you can only use either IsolatedStorageFile.GetUserStoreForApplication() or IsolatedStorageFile.GetMachineStoreForApplication() for store initialization only when the application is NOT a ClickOnce application.

The exact location to represent the isolated storage "file system" varies from operating systems.

For user scope (IsolatedStorageScope.User) related, the isolated storage is located at

   XP: %USERPROFILE%\Local Settings\Application Data\IsolatedStorage\
Vista: %USERPROFILE%\App Data\Local\IsolatedStorage\ 
For machine or all users scope (IsolatedStorageScope.Machine) related, the isolated storage is located at
   XP: %ALLUSERSPROFILE%\Local Settings\Application Data\IsolatedStorage\
Vista: %ALLUSERSPROFILE%\App Data\Local\IsolatedStorage\ 
All storage entry points (folders) will be placed under the above location(s). Each of entry point or folder represents a store assigned or automatically created by .NET when an IsolatedStorageFile is first created. Then you can create folders or sub-folders relative to that store location. After that, you can even create another IsolatedStorageFiles under those sub-folders.

Monday, August 24, 2009

Disappointed Again

Yesterday I spoke with my brother about my friend's condition, who is currently fighting for the fatal disease, brain cancer. I am extremely worry about him, especially I can't pay him a visit due to geographical living locations. His radiation therapy is not doing well and he could lose his battle.

My brother immediate reaction makes me even sadder. He shows no compassion. Instead he said, I should prepare to deal with this thing to happen in my life when I get older. Who doesn't know this? No one needs him to remind of this. A person will leave the world eventually. Especially when we get older, such a sad story will echo to our ears and/or surround us more often. However, could he pretend to show some sympathy by simply saying "I am sorry to hear this"? He is disappointed me again!

I've seldom shared any feeling of mine with my family although we try to remain a good relation. Unfortunately, none of my family members understand me or even know what I will feel and think. Since a friend always encourages me to try/share my feeling with my family, it still fails and makes me even more upset. It was not the first time, the second time or the third. I can't remember how many times my families did to me. This episode is just a simpe example from my brother. I am not going to try again. They always hurt my feelings. I would rather keep all to myself or share with strangers who don't know me. Speaking to no one here, I will at least feel a lot better inside.

Health or Job?

I have felt extremely sad lately. But there is nothing I can do. A friend of mine passed out and rushed into the hospital in March. Then he had a brain surgery almost immediately next day and was diagnostics to brain cancer stage 4. The recent radiation seems not helping. According to a friend's messages, he also loses his confidence to survive. Right now, he cuts off people contact or visiting. Since we both are not living in the same country, I am unable to visit him. Instead I am thinking him a lot daily. I am afraid of losing him soon. He is one of my best friends I've ever had. His patient, listening, caring and consideration manner makes me/everyone feel comfortable to stay with him all times. He was "never" sick; he was very health conscious and always kept his health in a good shape. I can't imagine he ran into this fatal disease. Can he survive through this? No one is sure to tell. I cannot deny that the chance is less (although there are plenty of successful stories), especially when he loses his own confidence to fight this. I am not a Christian but I would like to pray for him to re-get his health over. Please, God bless and help him!

For those people who are currently losing jobs, please don't give up. You all definitely will receive a second chance (and more chances) to start your career and life again, and then stay happy. Remember, your life is much, much better than someone's, who is fighting for a fatal disease, losing health or life. No health means no life and no second chance. Please precious what you have now and make wise use of your free time to prepare yourself for your next career.

I also wish everyone healthy and no worry of sickness or disease.

Again, God, if you can hear me, please help and save my friend. Show me your mercy and the miracle. Thank you.

Wednesday, August 19, 2009

Cyberbully and MySpace

MySpace Mom:
The first felong charge case in Missouri. A 49 years old woman Lori Drew posing as a 16-year-old boy on MySpace befriended with a 13-year-old girl Megan Meier first, and then suddenly sent Meier hateful messages and even published her private messages online that led Meier who had a history of depression commite a suicide. Drew was found quilty of three misdemeanors by criminal laws, which have been recently overturned by arguing that violating a Website's terms of service (TOS) is not a federal crime. Although Drew's actions or motives disgust me, I don't agree that violating TOS constitued "unauthorized access" that induces violating federal anti-hacking laws. Harassment may be a better term. Missouri has changed its anti-harassment laws to cover cyberbully.

Craigslist's Casual Encounters:
A 40-year-old woman Elizabeth Thrasher posted a fake "Casual Encounter" ad on Craigslist for a 17-year-old girl with whom Thrasher argued over the Internet (MySpace again). Thrasher was currently out of jail on a $10,000 bond and prohibited from accessing to the Internet. She could face 4 years in state prision in addition to $5000 fine maximum if she was convicted.

Two cases are done by women. What was in those two women's minds? Are they sick or full of retaliation?

Moreover, two cases are somehow related to MySpace, one of popular social networks. Nowadays, the social network gathering has become "real" although we are not physically face-to-face. Conversations and/or arguments without geographical barriers happen every minute or any moment. These two cases are just a simple reflection of real-life scenarios. Whenever there are humans group together in a place, there may be a crime or evil thing to be conducted somehow.

Tuesday, August 18, 2009

Annoying JavaScript Error on IE7

There is nothing wrong with IE. It is the bad work done by the Web developers who did a very bad job. Even Google is not doing a good job either. See its blogger.com and most sites where installed Google Ads.

Since using IE 7, I keep getting javascript pop-up errors all the time. It is very annoying. "Disable Script Debugging" on your IE Internet settings doesn't mean you can eliminate all JavaScript errors. Some errors still continue popping up without your consent. I wish I simply put IE to retire but IE is still one of the popular browsers. I still have to use it for testing.

I am not a IE lover. I personally like to use Mozilla or now called Sea Monkey instead. Unfortunately, most sites don't support Mozilla but IE. Somehow I believe that IE popularity is related to its default distribution by the OSs. It induces users using it regardless of things users dislike.

Would this JavaScript problem be fixed soon? Unlikely, I think. IE 8 has already in the market. Later maybe IE 9, 10, ... Most sites focus on the latest technologies and have never bothered to fix things for the old browsers. Too bad for you if you're still using it! So don't count on them fixing it. Instead, users have to find their ways to deal with it.

Friday, August 14, 2009

Share or Trade?

I am reading news about "Rhapsody connects to Facebook, Twitter." You go and listen to a song you like at Rhapsody, then you post a link into your Facebook profile for sharing. Your friends see it and click on it; the link will bring them to Rhapsody site for further exploration.

Actually you're helping them to do advertisement for free and helping them to get more exposure in public - similar to the effect of "the word of mouth." The more people visit their sites, the more chances for them do business. It is just a marketing tactic. It looks like more and more business going to this direction.

Nowadays, sharing has another meaning attached to it - free advertisement - yeah, you share their content and they will make profit from your "sharing" - fair deal, huh? Or it may be called a trade!

Wednesday, July 22, 2009

Data Binding Expressions and Their Symbols

All data Binding Expressions are evaluated at runtime. There are three ways I know to include data binding expressions in ASP.NET. I don't find that Microsoft has defined any specific terms to distinguish them. For clarify and easy discussion, I would define ones here so that I can discuss and compare them.

These three (3) ways data binding expressions are:


Page-Level Data Binding
<%#  ...  %>

Example:

 <%# Request.MapPath("mytext.txt") %>
 <%# GetUserName() %>
 <%# MyAddress %>
 <%# 1 + 2 * 3 %>

The expression will be evaluated when you call DataBind() of the Page class or any other controls that support it such as the GridView, DetailsView, and FormView.  This expression can be applied to a reference to another control's property, a value of an object property, a member variable or a return value of a function. It can be placed anywhere in the ASPX file whenever it fits. For example,

  <title>
    <%# PageTitle %>
  </title>

  <img src="<%# GetImageFile() %>" alt="" />

  <asp:TextBox ID="txtFirstName" 
               runat="server" Text="<%# GetFirstName() %>" />

  <asp:HyperLink ID="lnkExample" 
                 NavigateUrl="<%# Example.Link.Value %>" 
                 Text="Example" runat="server" />

Page-level data binding is very common and easy to use. It also comes with two methods Eval and Bind. Eval provides readonly capability on data while data with Bind is updatable.

 <%# Eval("LastName") %>
 <%# Bind("FirstName") %>

For the detail how to use them, you can read more on your own.

Control-Level Data Binding
<%$  ...  %>

Example:

 <%$ ConnectionStrings:Northwind %>
 <%$ AppSettings:MyVariable %>

The expression will be evaluated when the page is rendered. There is no need to call DataBind(), unlike the page-level.

In addition, control-level data binding cannot be placed anywhere in the page by itself. Instead, it must be wrapped inside a control tag. The result of the expression is used to set that control's property. For example,

  <asp:SqlDataSource ConnectionString="<%$ ConnectionStrings:Northwind %>"  ... /%>
where the <%$ and %> is used to extract the custom connection string from web.config.

Currently, there are only two build-in expressions available. One is to extract connection string from the web.config (see the above example) and the other is to extract application settings from web.config.

  <asp:Literal Text="<%$ AppSettings:MyVariable %>"  ... /%>

Although you can always make your own custom expressions through CodeDOM (Code Document Object Model), creating a custom expression to use is not an easy task.

Script-Level Data Binding
<%=  ...  %>

Example:

 <%= Request.MapPath("mytext.txt") %>
 <%= GetUserName() %>
 <%= MyAddress %>
 <%= 1 + 2 * 3 %>
 <%= myClass.Name %>
 <%= myClass.Execute %>

  <script language="javascript">
     location.href = <%= MyForwardPageUrl %>;
     ...
  </script>

Similar to the control-level, the expression will be evaluated when the page is rendered. Then, ASP.NET automatically inserts the value of the expression. There is no need to make any call to any DataBind() method either including Page.DataBind(). Similar to page-level, it can be placed anywhere in the markup page.