Monday, December 29, 2008

VM Ware Server 2.0 Experience

I have been doing a lot of virtualization in the past 2 months or so. The engine of choice so far is VM Ware. Microsoft also has a virtualization engine called Virtual PC - I have never used it, but a lot of people that I know use VM Ware, so basically I just follow suit. Maybe when I have a chance to play around with Virtual PC, I will write a blog post comparing them against each other.

What I want to highlight in this post is some of the tips and tricks that got mine to work as I needed. Your needs may differ, but hopefully some of these are generic enough that they can still be helpful.

VM Ware Server site: http://www.vmware.com/products/server/

When you click download, you will need to fill in a form to get your key. It is free, so go ahead and fill in the form and the instruction to get the key will be emailed to you. Once you get the downloaded file, run it to execute the installation procedure.

Installation is pretty straight forward - just follow the instruction provided by the installer. At some point, you will be required to enter a license key - this is the key you got from the registration process.

Once the installation is done, usually it will create a shortcut on your desktop called "VMWare Server Home Page". This is the main executable that will launch the interface for VMWare Infrastructure interface. When you run it (by double clicking it), it will open a browser (whatever browser set to be the default) and there are 3 things that you will typically see.

1. There is a problem with this website's security certificate.
If you get this screen/page, all you need to do is to click on the second link on the page that says "Continue to this website (not recommended). "
Then on the next screen you will get a login screen. This is a login to the VMWare Infrastructure interface - you can login using the username and password that you use to login to the computer. So if you login to the computer using "myname" and with password "mypassword", then you use the same username & password to login to this VMWare web interface.
If your machine is in the domain, you do not need to include your domain name in the login process. So instead of login with DOMAIN\username, just use "username".






2. Internet Explorer cannot display the webpage.
If you get this screen when you open the VMWare Server Home Page, I will check several things: a) Is the URL correct? b) Is the port number correct? c) Is VMWare Host Agent service running? You can check this in "Services", located in Administrator Tools under Control Panel. If this service does not exist, you will need to reinstall VMWare Server. If it is there and not running, you need to start it. Once it is started, close all browser with VMWare stuff in it, and try again.
Also keep in mind, in FireFox or other browsers, it may look different.

3. VM Ware also has this tool that's called VM Ware Converter 3.0. This is a very useful tool to convert your physical PC into a VM or vice versa. It also allows you tp change the configuration of your VM by cloning it. The free version has limited functionality, but it should be able to do the things I mentioned above. The paid version has more robust functionality.

Related Posts:
How to Increase HD Space in a VM
Win XP 64 bit and VMWare Server
-- read more and comment ...

Tuesday, December 16, 2008

CSLA & ASP.NET MVC (part 3: Adding)

As I have mentioned previously in the last post, editing and adding is not that much different - one pulls an existing one and modify it with incoming data, the other is just creating a new instance and filling it up with incoming data. We discussed "editing" in my last post, and now we are going elaborate on "adding".

First, let's take a look on the displaying of the empty form. This one is pretty easy, just get a new customer and bind it into the model as CurrentCustomer.


[AcceptVerbs(HttpVerbs.Get)]
public ActionResult New()
{

viewData.CurrentCustomer = Customer.NewCustomer();
viewData.CustomerList = CustomerInfoList.GetCustomerInfoList();
viewData.Titles = TitleInfoList.GetTitleInfoList();

return View("New", viewData);
}

We also want to bind the list of titles to be able to populate the drop down for title selection.

in handling the post, we are doing essentially the same thing as in edit, except this time we are mapping it to en empty object since it is a new one.
        [ActionName("New"), AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create()
{
try
{
Customer customer = Customer.NewCustomer();
UpdateModel(customer, new[]
{
"TitleId",
"FirstName",
"MiddleName",
"LastName",
"DOB"
});
customer.DateEntered = DateTime.Now;
customer.DateUpdated = DateTime.Now;

if (!customer.IsValid)
{
foreach (Csla.Validation.BrokenRule brokenRule in customer.BrokenRulesCollection)
{
ModelState.SetAttemptedValue(brokenRule.Property, brokenRule.Property);
ModelState.AddModelError(brokenRule.Property, brokenRule.Description);
}
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.CurrentCustomer = customer;
return View(viewData);
}
else {
customer.Save();
TempData["Message"] = "I saved " + customer.LastName + " to the database";
return RedirectToAction("List", "Customer");
}
catch (Exception ex)
{
TempData["ErrorMessage"] = ex.Message;
return RedirectToAction("New");
}
}

So upon save, we want to display the confirmation message whether there is an error or the record is saved successfully. In the code above we also utilize CSLA rules validation - this is really useful in a way that we have a central place to put our format rules, business rules, validation at. If there is an error, we want to redisplay the new customer screen and if save is successful, we want to update the list with the current data.


Related Posts:
ASP.NET MVC, AJAX, jQuery
CSLA & ASP.NET MVC (part 1)
CSLA & ASP.NET MVC (part 2)
-- read more and comment ...

Saturday, December 13, 2008

CSLA & ASP.NET MVC (part 2: Editing)

In the last post, we discussed about listing viewing detail for objects built with CSLA framework via ASP.NET MVC. Now in this post, I will show the editing and adding of the object - in our example here, using "Customer".

In essence, editing and adding is not that much different - one pulls an existing one and modify it with incoming data, the other is just creating a new instance and filling it up with incoming data. In our code, we try to leverage CSLA as much as possible, where the "Save" method is called only when the object is "dirty". Another thing is that we also want to get as much as data validation within the CSLA object as possible rather than manual/custom checking in our controller.

First, editing.

        [AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit(int id)
{
viewData.CurrentCustomer = Customer.GetCustomer(id);
viewData.Titles = TitleInfoList.GetTitleInfoList();
return View("~/Views/Customer/Controls/CustomerEdit.ascx", viewData);
}

The method Edit is tagged with "AcceptVerbs" attribute and scoped to only accept "Get" request. What this means is that this method can and will only be executed during a GET. Scott Guthrie has an excellent post regarding this attributes in his blog - I suggest for you to check it out.
The rest of the code is pretty simple, get the Customer record that is selected (passed in as a Id parameter in the method), put the customer instance into my viewData, get the list of titles to populate my Titles drop down, and then pass the view data into the viewer - pretty straight forward.

Now, let's take a look at the handler code for edit submission/post - for when somebody hit submit on our edit form.
        [ActionName("Edit"), AcceptVerbs(HttpVerbs.Post)]
public ActionResult Update(int id)
{
try
{
Customer customer = Customer.GetCustomer(id);
UpdateModel(customer, Request.Form.AllKeys);
if (!customer.IsValid)
{
foreach (Csla.Validation.BrokenRule brokenRule in customer.BrokenRulesCollection)
{
ModelState.SetAttemptedValue(brokenRule.Property, customer.GetType().GetProperty(brokenRule.Property).GetValue(customer, null).ToString());
ModelState.AddModelError(brokenRule.Property, brokenRule.Description);
}
viewData.CustomerList = CustomerInfoList.GetCustomerInfoList();
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.CurrentCustomer = customer;
viewData.ValidationErrorFlag = true;
return View("~/Views/Customer/Controls/CustomerEdit.ascx",viewData);
}
else
{
if (customer.IsDirty)
{
customer.DateUpdated = DateTime.Now;
customer.Save();
TempData["Message"] = "I saved " + customer.LastName + " to the database";
}
else
{
TempData["Message"] = "There were no changes to be made";
}
return null;
}
}
catch (Exception ex)
{
TempData["ErrorMessage"] = ex.Message;
return RedirectToAction("Edit", new { id = id });
}
}

OK, that seems long - so let's examine the code bit by bit so we can fully understand what is going on. If you notice, above the method name, there is also an "AcceptVerb" attribute, but this time it is set to "POST". Another thing is that it has ActionName("Edit") - which when combined with the AcceptVerb attribute, it will have the meaning that if there is an action "Edit" called on the controller with a POST, it will then get redirected into this method "Update".
        
try
{
Customer customer = Customer.GetCustomer(id);
UpdateModel(customer, Request.Form.AllKeys);
...

The 2 lines of code above, it is basically getting the Customer record being edited, and then call "UpdateModel" method, where it tries to match the instance of Customer called "customer" with the data submitted into the Request.Form.
                if (!customer.IsValid)
{
foreach (Csla.Validation.BrokenRule brokenRule in customer.BrokenRulesCollection)
{
ModelState.SetAttemptedValue(brokenRule.Property, customer.GetType().GetProperty(brokenRule.Property).GetValue(customer, null).ToString());
ModelState.AddModelError(brokenRule.Property, brokenRule.Description);
}
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.CurrentCustomer = customer;
viewData.ValidationErrorFlag = true;
return View("~/Views/Customer/Controls/CustomerEdit.ascx",viewData);
}
...

Here we check whether the instance filled with data from the form is valid based on the rules specified in the CSLA rules. If it is not valid then iterate the broken rules collection and set the model marked with error messages appropriately. Now after the model is marked with the error, we want to display back the form with the model so the error messages can be displayed accordingly field by field. To do this, we then populate the Titles field in our viewdata back with list of available titles, and also populating our CurrentCustomer property with the edited customer, set the error flag and return the viewer for "Edit".
                else
{
if (customer.IsDirty)
{
customer.DateUpdated = DateTime.Now;
customer.Save();
TempData["Message"] = "I saved " + customer.LastName + " to the database";
}
else
{
TempData["Message"] = "There were no changes to be made";
}
return null;
}
...

If the instance does not violate any rules, then we can save if necessary. Even though CSLA will detect automatically whether the instance is dirty or not before saving to the database, but we chose to check in our controller so we then can display whether there are data being saved or not. Since there is nothing else needed to be done after the saving, we then return null value.


Related Posts:
ASP.NET MVC, AJAX, jQuery
CSLA & ASP.NET MVC (part 1)
CSLA & ASP.NET MVC (part 3)
-- read more and comment ...

Thursday, December 11, 2008

Jonathan is 3 years old - time flies!

Three years ago, early December was nervous time for me. Helen, my wife, was pregnant and the baby is due anytime. Jonathan was born Dec 10th 2005, 7am, @ Riverside hospital - 51cm, 7lbs 8oz. There were no complications, the delivery was smooth, and we went home being proud parents.


The first couple of months were rough. Helen sister stayed with us for the rest of the year and went home end of December. My mom came after that and stayed for 2 months to help us along. Jonathan loves his milk and he had no problem with food or milk. He had eczema on his cheeks which worried us for a bit, but after the 1st year and a half it pretty much went away. He started eating solid food at 4 months, and by that time, Jon could hold his own bottle. He was huge fir his age at the time - I believed he was in the 70-90 percentile back then.
Another thing we worried about back then was that Jon threw up a lot, especially when he was crying. This led us to eventually not allowing him to sleep by himself in the crib until he was almost 2 years old. Putting a humidifier in his room helps a lot too.

Jon started walking on his own when he was 11 months. I remembered that his first attempt to walk across the room in our living room was during a OSU-Michigan game (OSU won 42-39 - GO BUCKS!!). He was a fast walker and he was the type that cannot stay still - so we installed gates in our house to prevent him from going too far or going into unsafe rooms. Grandma and grandpa came during Jon's 1st birthday and we threw a party. Since the Buckeyes were going to National Championship that year, the theme for the party was "Buckeyes". Everybody came wearing scarlet or grey apparels. Even though Jon has not understand football yet at the time, but he was able to respond to "O-H" with an "I-O"! I was soo proud ...

Jon 1st birthday party!


Jon and his first snow ...


Jon's first haircut - done by mommy and daddy!


Halloween!

By the time Jon was 2 years old, he was talking Indonesian and English, sleeping on his own bed, ate all kinds of food, understand that OSU is the best, what an email is, how to chat to daddy, etc etc.

Jon's 2nd birthday party - can't wait to eat cake!

Yesterday was Jon's 3rd birthday - o how time flies. He is wearing bigger clothes now, brushes hi own teeth, talks in full sentences, ask the most difficult question I can ever imagined ("Why daddy has to go to work?"), loves staying in a cabin, etc. Jon loves his train set (me too) and looking forward to have it expanded. Taking pictures of Jon regularly also pays off big time.


BTW, Jon now has his own blog, written by mommy - http://jonathansetiabudi.blogspot.com, check it out.
-- read more and comment ...

Wednesday, December 10, 2008

CSLA & ASP.NET MVC (part 1: listing & viewing detail)

The easiest implementation for ASP.NET MVC is usually via LINQ to SQL. Now, for larger projects that must be scalable, one will need object development framework that is also scalable and more robust. My framework of choice CSLA.NET. Assuming you have built your CSLA classes, wiring it in with MVC is a piece of cake.

I recommend to make your view to be strongly typed to the object of your controller. So in my example, I have a CSLA class for "Customer" and also its corresponding read-only list, read-only item, editable, etc. Hence, I name my controller to be "CustomerController". In it, I created a class to carry around stuff as a single object, instead of stuffing everything in ViewData and cast when needed.

    public class CustomerControllerViewData
{
// list of read-only customer available to me
public CustomerInfoList CustomerList { get; set; }
// current editable customer seleted
public Customer CurrentCustomer { get; set; }
// list read-only Title available to the Customer
public TitleInfoList Titles { get; set;}
}

Then in the controller class, I declared a global variable to hold the instance of the CustomerControllerViewData class. I initialized it right away.
    public class CustomerController : Controller
{
CustomerControllerViewData viewData = new CustomerControllerViewData();

public ActionResult Index()
{
return RedirectToAction("FullList");
}
...
}

During list, I put all the necessary data into CustomerControllerViewData class, rest the validation, and then I pass that instance into the viewer as a strongly typed model. I do not fill in the CurrentCustomer property nor the Titles - since I won't be needing those to display my list of customers.
        public ActionResult List()
{
viewData.CustomerList = CustomerInfoList.GetCustomerInfoList();
viewData.ValidationErrorFlag = false;
return View("~/Views/Customer/Controls/CustomerListing.ascx", viewData);
}

The viewer looks like this - it should be pretty simple with the exception that it is strongly typed. So in the code behind, I have to add the type in the generic constructor of the viewer:
    public partial class CustomerListing : System.Web.Mvc.ViewUserControl
{
...
}

Now for viewing detail if a customer, we also do not need to fill out CustomerList property, since at this point we only care about a specific customer. Titles is needed since to populate a look up/drop down field.
        public ActionResult Detail(int id)
{
viewData.CurrentCustomer = Customer.GetCustomer(id);
viewData.Titles = TitleInfoList.GetTitleInfoList();
viewData.ValidationErrorFlag = false;
return View("~/Views/Customer/Controls/CustomerDetail.ascx", viewData);
}

Do the same thing for the code behind of the viewer to make it strongly typed:
    public partial class CustomerDetail : System.Web.Mvc.ViewUserControl
{
...
}


Related Posts:
ASP.NET MVC, AJAX, jQuery
CSLA & ASP.NET MVC (part 2)
CSLA & ASP.NET MVC (part 3)
-- read more and comment ...

Wednesday, December 3, 2008

New Nikkor!

By getting Nikkor AF-S 24-70mm f/2.8G, I have completed my Nikkor lenses line up that covers 17-200mm for FX (full frame) and 10-200 for DX (crop format). So now, my lens line up is consisting of these lenses:

  • Nikkor AF-S 17-35 f/2.8
  • Nikkor AF-S 24-70 f/2.8G
  • Nikkor AF-S 70-200 f/2.8G

Nikon has come up with Nikkor AF-S 14-24 f/2.8G and some people say that this lens is suppose to replace AF-S 17-35. I am not sure whether that is true or not, but since I bought my 17-35 before 14-24 came out and it still performs its job exceptionally well - then I am keeping it. I also have not tried 14-24 in person other than reading some reviews and seeing sample photos. Most people agree that 14-24 is one of Nikon's best - to the point even Canon people are looking for converted to be able to use with Canon cameras.

This is not a full spec detail review, but rather an experience based narrative. So I am going to write about my experience in using 24-70 for the last 1 month or so (I had it since early November). For the last month, I can say I use this lens almost exclusively - not because all my other lenses are bad - but because I have done mostly indoor shooting/photography. I took a lot of pictures of my son, thanksgiving parties, etc - and I can say that 24-70 is perfect for indoors.

Previously I usually use my 50mm f/1.4 AF-D or AF-S 18-200. If I use my 50mm, I can set it to f/4 and set my camera to A mode and be happy. If I am using multiple flashes, I set my camera to M mode and adjust exposure accordingly. My gripe with the 50mm is that it is not a zoom and also the speed of focusing is rather slow - so as a result I often missed some critical shot of my son acting funny.

I was not expecting that this lens will be so much faster in focusing - but apparently it is faster enough that I have more keeper than before. This lens is also very very sharp - even with normal sharpening setting in my camera, it produce a very sharp image - I would say that it is comparable to 50mm prime.

Compared to 18-200 is like night and day. Although 18-200 has its place as a travel lens, compared to 24-70, its flaws and compromised got exposed. The 24-70 is sharp wide open and stay sharp throughout the aperture range. The 18-200 is soft wide open and sharpest at f/6.3 - but even its sharpest is not comparable to 24-70 wide open.

The zoom ring of the 24-70 is also consistent and balanced, making it easy to zoom and compose - where 18-200 has zoom creep and imbalance zoom ring stiffness.

All in all, I am extremely satisfied with this new lens, AF-S 24-70 f/2.8G - worth every penny that I put into it.

-- read more and comment ...

Monday, November 10, 2008

The Deli Boys

I have been working from a downtown location for more than a year. Located on High St., nearby the arena, I have plenty of lunch option everyday. When I started working here, my supervisor hooked me up to this sandwich place called "The Deli Boys". Ever since then, just like a sandwich addict, I keep coming back - at least once or twice a week.

The Deli Boys have been there since early 2006 - located @ 2 E Long St., Columbus, OH - 43215. Their phone number is 614-621-1444. You can call ahead for carry out order or for catering order.

The price is pretty good - ranging from $3.75 for an Italian sausage on a hoagie to $5.50 "Heavy-weight" - a big all meat hoagie sandwich. They also have some basic salad menu, thin pizzas, and soups/chili. You can get a combo with chips and soda - which they serve Pepsi products. There is a daily special everyday - and so far the best special for me is the portabella chicken sandwich.

After a while, they will get you know you (they take your name on every order) - which shows an honorable degree of hospitality. Overall, combined with their charming hospitality - their sandwich is also great, toasted perfectly every time and hand delivered to your table as soon as they are ready!

My favorite menu item is the "Chicken Philly" sandwich. It got a good amount of jalapeno peppers, delicious grilled chicken breast, bell peppers, cheese, and mayo. Combined with a side of Jalapeno chips - it gives you plenty of heat to keep you awake for the rest of the afternoon. The bun is toasted perfectly every time, fresh lettuce, peppers, and melting cheese - yuuuummmmyyy! Their thin pizza is also good - if you are into thin pizzas.

If I am not mistaken, now they also have cup cakes everyday. It used to be on some special days - but it is everyday now. Good cupcakes with nice icing! Also available is frozen yogurt - the lemonade flavor is awesome.

I have tried every single sandwich menu available @ The Deli Boys as well as their pizza menu - and I like all of them (I like some better than others - like the chicken philly) - but the point is that I have never had a bad lunch there. Well, if you are in the area, check them out - they are open @ 7am, M-F.

The Deli Boys
Monday - Friday @ 7am
2 E Long St.
Columbus, OH - 43215
614-621-1444
-- read more and comment ...

Open Source Family Tree Software: Family.Show

I stumbled on a free open-source software written on MS .Net (C#, WPF) that is really intriguing and cool. This software is a "family tree" software. It is a simple one - but for my use - it is more than sufficient.

The software itself is called Family.Show. It was mad by a company called "Vertigo". It is very user-friendly and easy to use. It came with a sample family; the Windsor (English Royal family).

Did I mention that it is also open source? Yes, so you can go to codeplex and download the source code for the app. You will need Visual Studio 2008 to be able to open the solution fully, but you can use any text editor to view the code in C#.

So OK, I downloaded it and started my family tree. I happen to keep most of my family members data in my Outlook, so I can enter them right away. After you enter a person, you can add related person to the existing one. So you cannot add somebody who is not related to anybody in the system. For example: once I added myself, I can only add person who is directly related to me: spouse; brother/sister; mom/dad; son/daughter. If I want to add my cousin then I have to add my mom, then add her sister, then add my cousin as my mom's sister's daughter.

The software is pretty intuitive to use and quite simple. You can drag photo to the edit pane to assign a photo to a person in the system. You can add "story" to a person - a free text format where you can have some kind of a biography for the person.

Another feature is that you can filter the family data to find certain family members easier. Clicking "Expand" button will expand the list of family members into a big table, where you can filter, sort, search, etc - as well as displaying stats about age distribution, birthdays, etc. Clicking on the age distribution chart will filter the list automatically by age.

A super cool feature is the time slider. You can slide the time slider to see people's age on certain year. For example: if you want to know the age of your dad when you were born, you can slide the age slider until your age reaches 0 (zero) and see your dad's age displayed appropriately under his name. When you slide the age slider closer to current year, you can see his age is increasing.

The data is saved in an XML format - so you can send it to your families and ask them to install the software and complete/add missing data and send the xml file back to you. You can also export it into a GEDCOM format - which is the "family tree" standard format for most "family tree" software.

Check it out!
-- read more and comment ...

Thursday, November 6, 2008

Using PageMethods & JSON to provide auto population

One of the problem that I have to solve in my recent project was to provide a look up for city, county, state based on a zip code. There are multiple ways of doing this - but in this exercise, I want to demonstrate using javascript (client-side) to call PageMethods (server-side) and then populate my fields.

1. Set EnablePageMethod to true in your script manager



2. Create your PageMethod


When the PageMethod returns its value, it will get serialized into JSON object. In my example above, I an returning a IEnumerable - but you can return any object, as long as it is serializable.

3. Create your javascript to call the PageMethod and callback handler
When you call a PageMethod, the result from the PageMethod is directly transfered into your callback function. In my example below - it is transfered into "result". You can also specify success path callback and failure path callback if you want.
function GetZip(zipBox) {
var zip = zipBox.value;
if (zip.toString().length >= 5) {
var x = PageMethods.GetCityCountyState(zip, GetCityCountyState_Callback);
}
function GetCityCountyState_Callback(result) {
cityDDL = document.getElementById("cityDDL");
cityDDL.options.length = 0;
var oldValue = "";
for (i = 0; i < result.length; i++) {
if (oldValue != result[i][1]) {
var newValue = result[i][1];
var newText = result[i][2];
var objOption = new Option(newText, newValue);
cityDDL.options.add(objOption);
oldValue = newValue;
}
}

countyDDL = document.getElementById("countyDDL");
countyDDL.options.length = 0;
oldValue = "";
for (i = 0; i < result.length; i++) {
if (oldValue != result[i][3]) {
var newValue = result[i][3];
var newText = result[i][4];
var objOption = new Option(newText, newValue);
countyDDL.options.add(objOption);
oldValue = newValue;
}
}

stateDDL = document.getElementById("stateDDL");
stateDDL.options.length = 0;
oldValue = "";
for (i = 0; i < result.length; i++) {
if (oldValue != result[i][5]) {
var newValue = result[i][5];
var newText = result[i][6];
var objOption = new Option(newText, newValue);
stateDDL.options.add(objOption);
oldValue = newValue;
}
}
}

So in my javascript above, I basically waiting until the textbox for zipcode is filled with 5 numbers before calling the PageMethod. Once I get the result back as JSON object, my callback function will take over and populate my drop down list for City, County, and State.

Additional readings:
1. ASP.net: Exposing WebServices To AJAX Tutorial
2. AJAX PageMethods, JSON Serialization, and a little bit of LINQ databinding
3. Passing JSON param

Related Posts:
ASP.NET MVC, AJAX, jQuery
-- read more and comment ...

Wednesday, November 5, 2008

SLANK CONCERT!

SLANK concert @ Columbus was awesome. It was a part of INDIGO - an annual celebration for Indonesian students in Columbus, OH. Ticket price was decent, $20 (or $25 at the door), you get plenty of Indonesian food, tons of drinks, a performance by Columbus band and of course, SLANK!



I was in charge of setting up the sound system. We rented our house and monitor equipment as well as some backline equipments. SLANK & crew brought their own guitar amp head - a Marshall JCM 2000 and their own Bass head - AMPEG. Bimbim is endorsed by PREMIER drum - but since we could not find a PREMIER kit locally, we compromised and use another brand - and instead of renting, we borrowed one - from ME! So YES, it was my drum kit that was used during the concert by SLANK! One of their guitarist, Ridho could not make it - somehow he could not get a visa by US embassy.

Between 1pm until 4pm, there was a lot going on. The food came in and there were several people arranging them, putting them into boxes, putting all the drinks in cooler to chill, etc. We prepared around 400 boxes of Indonesian meal - that is a lot of boxing! Our food is sponsored by an Indonesian restaurant in Columbus called TASTE OF BALI. They are located @ Carriage Place on Bethel Rd, next to the dollar theater. I tasted the food - it was awesome!

Preparing ourfood:


We picked up our drum kit from my house around 10am and went straight to SLANK's hotel. We met with SLANK's crews - Dado & Wahyu as well as Sonny - their sound engineer. We arrived at the concert hall @ Ohio Expo Center - Rhodes Hall by 11am and the FoH & monitor equipments are already arriving and being setup by our rental company. SLANK at this point stayed behind @ hotel and they were going to meet several friends in the soccer tournament.

We proceeded in setting up our equipment and by noon-ish, we are all set. We went to lunch, stopped by a guitar shop to get several guitar stands, and went back to the concert hall to do sound check. After an hour or so sound check - we are ready to ROCK!!!

SLANK's crews:


At 4pm-ish, our opening band showed up for sound check. They are doing 4 songs. SLANK was kind enough to let the opening band borrowed their equipment (guitar head & bass head & snare drum). These guy never sounded that good before - primarily because of the quality of the sound system equipment and the sound engineer we hired.

All of our crews are on location right now, arranging furniture, preparing tickets, finalizing food preps, etc. The door opens @ 5:30pm and opening band to get on the stage @ 7pm.

Our MCs - Bebe & Aree:


Openning band - Columbus band:


SLANK in the waiting room:


Jon & Helen:


After the concert, SLANK's crews and I cleaned up the stage, as well as the backline and FoH & monitor rental crews. SLANK was in their waiting room with fans taking pictures, singing autograph, etc. At around 10:30pm, everything was done, and we drove back to SLANK's hotel. I helped SLANK's crews packed their equipments for their next flight to NY. Sonny gave me a used snare and I got SLANK's autographs on it. We went to Raising Cane's for late late supper, had a great talk with Ivan outside, and rolled home @ around midnight.

Long live SLANK & SLANKERS!
-- read more and comment ...

Wednesday, October 29, 2008

Backlighting & Overpowering Ambient

Red Leaf
The shot above was taken on a sunny day light in my living room - how did I do it? Check out the rest of the post.

First of all - I backlit the leaf
What does that mean? It means I use a light source (a Nikon SB-600 flash) and that light source is located behind the object (the leaf). This means that the object is sandwiched between me (and the camera) and the light source. Your light source could be anything: the sun, desk lamp, flash light, TV, etc. I just happen to use my Nikon flash - plus it provides a strong enough light to overpower the ambient light - which brings us to the second point.

Secondly - overpowering the ambient
What is "ambient light"? It is the light that is around you in your current condition. So in this case, my ambient light was sun-light coming through from some windows in my house as well as the kitchen light from my left.

What does "over-powering" the ambient mean? It means that I use an external light source (my Nikon flash) to be the primary light source and rendering the ambient light to be secondary light source or to be non-existent. In this case - I want the light coming out of my flash to be the ONLY light captured by my camera in lighting the leaf and I want the background to be dark (black or close to it). So my flash needs to be my primary light source and I need to render the ambient light into close to non-existent in the final picture - thus "overpowering the ambient".

OK then - how do you overpower the ambient? It is actually quite simple: I close down the exposure enough so that when I take a picture without flash it becomes dark/black. There are a lot of combinations you can use to accomplish this among shutter speed, aperture, and ISO setting. I picked ISO 100, 1/320 and f/11. I want to close down the aperture enough to capture the detail of the leaf and since I am handholding a 200mm lens, I want high enough shutter speed (more than 1/200s) . So that means low ISO, high speed, and closed down aperture - hence I selection.

After that, I position my flash behind the leaf, put it into High-FP mode (which enable the flash to work with shutter speed higher than normal sync-speed) and put it in 1/4 power and do a test fire. Adjust the position of the flash and adjust power to 1/2 and VOILA!

I did some post-processing with the image produced: cropping (I actually captured the whole leaf), sharpening (to strengthen the detail), and manipulate the color of the leaf a little bit (it was originally yellow/orange).

I use Nikon D80 camera, Nikkor AF-S 70-200 f/2.8 VR lens, and SB-600 flash.
-- read more and comment ...

Tuesday, October 21, 2008

Pumpkin Patch!

Jon, Helen, and I went to the pumpkin patch last Saturday. It was fun - a bit cold and windy - but fun overall. Sky was gorgeously blue in the morning. The patch that we went to was at Dublin (take 33 west, exist @ Post) - so it was not that bad of a drive from our house. We went with a bunch of friends (and their kids) - so we have a big group.

Once we got there, we got several options ... we can walk on our own to the area (which is about 10 minutes walk - not bad at all) - OR we can take a hay-ride. Since Jon has never been on a hay-ride, so we opt for the hay-ride.

Here is Jon sitting on an unused tractor while waiting for our hay-ride:




This is inside the wagon - there were about 20-something people inside the wagon, so it was packed. I sat across Helen and Jon and able to get this shot.


Once we got to the area, it was a free for all ... we can pick any pumpkin we can find. Most of them are bad though or too big. After searching for about 45 minutes or so, we finally found one that is big but not too big and one that is small enough for Jon to hold.


On our walk back to the weighing area - there was an area where it was filled with small size pumpkins. So we played around a little bit there and try to find some small pumpkins for Jon - or he was trying to find for his own.


It was fun and we enjoyed it - although warmer weather is more desirable for next trip. We ended up going home with 4 pumpkins (1 large one and 3 small ones).
-- read more and comment ...

Monday, September 29, 2008

New Appliances

My electric range needs replacing ... Two of the ranges (the bigger ones) don't even work now and the rest are only working half the time. Oven still works great, but not the range. It is an old GE range and it is screaming for replacement.

My dishwasher is also broken. The water outlet is broken so sometimes there will be a "pool" of water on the bottom. If the water is left there, it will become a bacteria sweet spot - so we have to keep using the dishwasher periodically or cleaning the bottom and removing the water - which is a pain. We try to have it fixed but the parts are hard to find and expensive - almost as much as buying a new one.

So when the company I work for announce that we will be getting our bonuses, we are off to our search for new appliances: dishwasher, electric range, and a matching hood/vent.

Electric Range
For one reason and another, we decided to go with Whirlpool as our chosen brand of appliance. For our electric range, we wanted to go with "coil" instead of the ceramic glass cooktop - because we found that the coil "heats" better. Since we cook on regular basis, coil seems to be a better option. Plus, the ceramic glass is expensive to replace if it is damaged (could be $250 or more) - even though it is really really easy to clean and certainly looks better. The model that we went for is Whirlpool RF263LXS. We also got the vent/hood for it: RH3730XL

Dishwasher
For the dishwasher, we also went stainless to match with the range and the hood: DU1055XTS.

So what kind of "heavy duty" cooking are we doing on our range? Well, my wife cook almost everyday and about once a week we host a bible study group at our house on Saturday. So more often than not, the heaviest use of our range is on the weekend, where our friends and us must cook for our bible study group (abour 20 people).

We do not use the oven as much - which is why probably the oven is still in good shape. As Asians, most of our food are deep fried, stir-fry based or soup based - which means that almost all the cooking is happening on the cooktop instead of in the oven.

We ordered these last weekend and they will be shipped within this week. I hope they work as long as my old appliances are, for years and years and years.
-- read more and comment ...

Tuesday, September 23, 2008

Twitter Clients

Do you know what "twitter" is? If not, go check it out at http://www.twitter.com. It is basically a "micro-blogging" tool; where you can post 140 characters at a time about anything (from what you are doing now to anything you can think of). You can follow other people - meaning that everytime they "tweet" or post in their twitter account, you will get their post. People can also follow you - so anytime you post something, they will get it.

There are new outlets, engineers, gadgets reviewers, etc (including Barack Obama) that are in twitter - and you can follow them and get their posts.

Twitter.com provides a web interface where you can interact with your post (post new post, reply, direct message, etc). But, there are also several twitter clients out there that allow you to be twittering without opening up a web browser. I will review 2 of them in this post - which are ones I used the most.

1. Twhirl: http://www.twhirl.org
Twhirl has a nice UI, slim, almost YM/AIM/MSN like. It provides the basic Twitter functions such as: posting, replying, direct message, viewing particular people's tweet, fave-ing a tweet, shorten URL, etc.

It also has several things that are very appealing: changing colors, multiple twitter accounts, automatic checking for new version and upgrade, MSN like notifications for new tweets.

There are also several things that I wish were better in twhirl, such as: not limiting displayed tweets to 20 tweets, truncate/not display replies and direct messages from the past, and add functionality for "grouping" people.

2. TweetDeck: http://www.tweetdeck.com
Tweetdeck is not as pretty as Twhirl, but for what it can do, it does them well. Tweetdeck has this feature that allows you to create "groups" - so you can group people together. For example, you can group tweets from your work friends together in its own column and tweets from your family is a different column altogether.

Its notification system is only telling you how many tweet it got and belong to what group, so it is not as nice as Twhirl (which tells you the actual tweet). Tweetdeck is also capable to display more than your last 20 tweets and clean up past replies/directs nicely.

There you have it, the 2 client apps that I use for twittering and there are many more out there. If you do not know what Twitter is, I urge you to check it out and give it a try - and urge your friends to join as well. The more friends you have, the better and more fun it is.
-- read more and comment ...

Monday, September 15, 2008

C# Crap That Are New to Me ... and Maybe to You Too

I have been involved in software engineering for a while and have been using C# pretty much since it came out in .NET Framework. But every now and then, I encountered something that I have never seen before. This is my attempt to catalog them and share them.

I found some of these just by luck, some from books, some from my colleagues, some from the web sample codes, some from forums, etc etc. So, not everything in my list will be new for you ... but at least they were for (until 5 minutes ago).

If you have anything you want to add, post them in the comments and I will add them in the post with credits to you.

1. ?? (coalescing) operator
"??" (coalescing) operator is simplifying "?" (if-and-only-if) operator, but only for null checking. In "?" operator, you do this (with null):

string result = (x == null ? "no result" : x.ToString());
Now with "??" operator you can simply do this:
string result = x ?? "no result";

2. @ for string
Usually when you have a string assigned with some values, you will have to pay attention to escape characters, etc. With "@", you can literally use string as literals. See this example:
string result = @"c:\windows\my files\";
This line of code will actually produce the expected result "c:\windows\my files\". Without the "@", you will to write something like this:
string result = "c:\\windows\\my files\\";

3. @ for variable names that are also keywords
If you put "@" in front of your local variable, you can name it anything you want, including using keyword-like name, check this out:
string @string = "hello world";

4. C# property constructor initialization
So instead of doing this:
Person objPerson = new Person();
objPerson.Name = "Bob";
objPerson.Phone = "1-(800)-555-5555";
You can do this:
Person objPerson = new Person {Name = "Bob", Phone = "1-(800)-555-5555" };

5. yield
Look here for MSDN explanation.
-- read more and comment ...

Tuesday, September 9, 2008

Photography as a Hobby

I am a serious hobbyist in photography. From my days in high school with film, until now in the digital era - photography has been a nagging interest in my life. For a certain period of time, it's virtually missing in my life - because of a simple reason: my camera was stolen. Since that point, for about 4 years, I did not own a camera - until my dad bought my wife and I a Nikon D70.

Holding the camera and pressing the shutter button triggered the journalistic memory from my high school and early college days. My film camera was a Nikon and the D70 that we had still use the same lens mount (it is called F-mount for Nikon). When I got a chance, I took all my old lenses and tried it and they worked!

Nikon vs. Canon
I am a little bit biased to Nikon because I owned Nikon equipments, including some of my old gears from the film days. Ultimately, they are a matter of preferences and your legacy equipments. So when you are already invested in Canon gears, it makes sense to continue on that route, same thing if you are in Nikon. If you are already invested in a brand, it is quite costly to switch - and this alone (depending on your seriousness level in photography) will be a strong cause to NOT switch brand.

I like Nikon bodies, their ergonomics, single functioning dedicated buttons, sub-command dials, shutter placement, etc. On the other hand, Canon is a step ahead in lenses variety. For 70-200mm alone, Canon provides 4 varieties (70-200 f/2.8 L USM IS and non-IS, 70-200 f/4 L USM IS and non-IS) with their price differences while Nikon only provides 1 model (70-200 f/2.8 AF-S VR). Nikon on the other hand is way ahead on lighting/flash technology.

Each brand also has bodies that range from early beginner up to the pro model (from $450 to $8K). So take your pick and stick with it. People ask me all the time about this and usually my answer is for them to try them out and pick for themselves. One benefit if you going with Nikon if you are my closer friends is that you can borrow my lenses and other Nikon equipment.

Crop Sensor
Most digital SLR now have crop sensor. What that means is that the sensor area is smaller then the area of a regular 35mm film. If the sensor area is the same as 35mm film, we call it "full frame" sensor - this usually only applied in the highest model line (Nikon D3, Canon 1Ds, etc) or close to highest (Nikon D700, Canon 5D). The smaller sensor area means that there is a crop factor in comparison to the 35mm area. For Nikon, the crop factor is 1.5 and for Canon is 1.3 or 1.6 (depending on the model). Crop factor 1.5 means that the digital sensor is 1.5 times smaller in area compared to 35mm film.

There are several implications to this factor:


  • Wide is no longer wide. Since there is a crop, what used to be wide angle shot become not so wide anymore. Camera with crop sensor requires a WIDER lens to achive 35mm film/full-frame sensor width. So if you use a 20mm lens in a camera body with crop sensor, it will produce the similar result as if you are using a 35mm lens on a full-frame camera. 35mm = 1.5 * 20mm. To accommodate the need for wide angle shot, lens manufacturer create lenses especially for crop sensor that is super wide - but cannot be used in full-frame camera (or it will produce a fall-off or vignette).

  • On the other hand, a 200mm tele lens becomes a 300mm tele lens in a crop sensor camera! So in a way, crop sensor body provides more reach.
Lens line up
So what is a good lens line up that spans from wide angle to tele for hobbyist? There are virtually endless possibilities, but I will try to provide several options based on budget. A good line up usually spans from ultra-wide (20mm or wider) to tele (200mm). In daily usage, it is rare you will need beyond this range.

OK, here we go - I am going with Nikon in most cases btw, if you want Canon, there are equivalent lenses - Google it!
  1. Going SUPER EASY - crop factor (DX) - 1 lens fits all
    • Nikkor AF-S 18-200 f/3.5-5.6 VR - $650
  2. Going SUPER CHEAP (< $350) - crop factor (DX) - 2 lenses
    • Nikkor AF-S 18-55 f/3.5-5.6 DX - $110 ($170 if get the VR)
    • Nikkor AF-S 55-200 f/4.5-5.6 DX - $170 ($220 if VR)
  3. Going CHEAP (< $500) - crop factor (DX) - 2 lenses
    • Nikkor AF-S 18-70 f/3.5-5.6 DX - $250 (NO VR)
    • Nikkor AF-S 55-200 f/4.5-5.6 DX - $170 ($220 if VR)
  4. Going COMPROMISED (< $750) - crop factor (DX) - 2 lenses
    • Nikkor AF-S 16-85 f/3.5-5.6 DX VR - $580
    • Nikkor AF-S 55-200 f/4.5-5.6 DX VR - $220
  5. Going QUALITY (~ $1,000) - crop factor (DX) - 2 lenses
    • Nikkor AF-S 16-85 f/3.5-5.6 DX VR - $560
    • Nikkor AF-S 70-300 f/4.5-5.6 VR - $460
  6. Going PRO ($$$) - DX or FX - 3 lenses
    • Nikkor AF-S 14-24 f/2.8 - $1,600
    • Nikkor AF-S 24-70 f/2.8 - $1,600
    • Nikkor AF-S 70-200 f/2.8 VR - $1,600
Obviously, this list is not exhaustive. There are more possibilities out there. Configure your own from this list!

If you are into MACRO, you want to get a MACRO lens, OR ... a reversing ring, so that you can use your PRIME wide angle or normal lens in reverse to get a magnification close to a MACRO lens (or maybe more - depending on how you configure it).

Currently, have quite a line up:
  • Sigma 10-20 f/4-5.6 DX - since I am using a crop factor camera, this is my ultra wide angle lens (equiv to 15-35 in full frame or 35mm format)
  • Nikkor AF-S 17-35 f/2.8
  • AF-D 50mm f/1.4
  • AF-S 70-200 f/2.8 VR
  • AF-S 18-200 f/3.5-5.6 VR - my walkabout and daily lens
In this line up, I am still missing the normal zoom range - so I probably going to get AF-S 24-70 f/2.8 in the near future (or when I can finance it).

There you go! Photography hobby is not cheap - so buy only what is necessary and flee from trying acquiring the latest greatest every time, because it is a never-ending buying process if you allow it to be so. Photography can be very satisfying and if you are really good, you can make money of it too! Here are some of my photos:

-- read more and comment ...

Thursday, September 4, 2008

The Paradox of Egotism

“How can I find true happiness? / Abundant Life” Nothing is more “backward”/counter-intuitive that Jesus’ answer to this question. In fact, Jesus had a radically different answer.

During the last supper, Jesus knew that he was about to be betrayed, forsaken, arrested, unjustly condemned, beaten and killed. The room they were using for the last supper had no household slave to wash their feet. Jesus’ disciples were consumed with which one of them is the greatest, so none of them was about to admit he is lesser by assuming this role – and wash others’ feet.
Jesus eventually went down like a slave and washed their feet. After explaining that his action was a picture of his way of life, he said John 13:17

17 Now that you know these things, God will bless you for doing them.

This was not the first time Jesus tried to drive this point home to his disciples. He also taught it through a paradox that is the most frequently quoted of his paradoxes in the gospels, Matt 16:24-26

24 Then Jesus said to his disciples, “If any of you wants to be my follower, you must turn from your selfish ways, take up your cross, and follow me. 25 If you try to hang on to your life, you will lose it. But if you give up your life for my sake, you will save it. 26 And what do you benefit if you gain the whole world but lose your own soul? Is anything worth more than your soul?

This passage not only suggests that if you are willing to lose your life you will save it – it also strongly rejects the world’s culture of selfish living to achieve life-fulfillment (abundance) – by saying that selfish living will eventually destroy/lose one’s life.

Self-Centered Life Will Destroy Your Life

Consider this passage in 2 Tim 3:
1 You should know this, Timothy that in the last days there will be very difficult times. 2 For people will love only themselves and their money. They will be boastful and proud, scoffing at God, disobedient to their parents, and ungrateful. They will consider nothing sacred. 3 They will be unloving and unforgiving; they will slander others and have no self-control. They will be cruel and hate what is good. 4 They will betray their friends, be reckless, be puffed up with pride, and love pleasure rather than God. 5 They will act religious, but they will reject the power that could make them godly.

This passage teaches about the problems that will be developed when people are away from God – which is that people will focus on themselves (vs. 2, 4, and 5).
Living for self means several things according to this passage:
1. Loving money
2. Establishing a proud identity
3. Hedonism

When people are living for self, what we see above is quite reflective of what we see in 1 John 2 (lust of the eye, lust of the flesh, and the boastful pride of life) – there is no logical alternative that will make sense. Living for self means I must create my own sense of significance, satisfy my own needs, and make myself happy. The other problems are just some resulting damages that result from our selfishness.
-- read more and comment ...

Monday, August 25, 2008

Abundant Life?

Everybody wants to have an abundant life. Some people feel that they are entitled more to it than others, but essentially we all want to live abundantly. To each one the standard of abundance may differ, but it almost does not matter. We may be rich or poor, healthy or in sickness, but there is this gnawing thirst to be satisfied and be happy.

Living in abundance means that we are not in need. This does not mean having things in excess or insurmountable things, but simply living happily and satisfactorily.

Throughout the ages humanity has been trying endlessly to find the key to happiness/abundant living. Ranging from psychological manipulation, wealth accumulation, positive thinking movement, secret society, religion, drugs, alcohol, and sex – all are human attempts to make themselves “happy” and living abundantly – and all of them seems to not scratch where it itches, at least for long and permanently. People always invent new ways of doing those thing in a new light, with a new twist, combining recipes, etc – in hope to find the ultimate way (and easy) to find permanent happiness and abundant living.

If we filter down and try to find a silver lining among the approaches that human have tried to find abundance in their lives, typically they are all boiled down to self-centered. In hind sight, this totally makes sense – since we are in need (not abundance) and unhappy, therefore we must strive to satisfy ourselves by finding whatever that will make me happy and satisfy my desires.

To be wholesomely happy then, we need to apply this to all areas of our lives, such as monetary, relationship, technology, food, entertainment, etc. How does this work?
In financial/monetary, we then strive to accumulate money as much as possible, so then we can feel that we are secured and able to buy things that we desire – and therefore resulting in happiness.

In our relationship, we then try to find friends that are not in conflict with us and as much as possible to be compatible. This will reduce tendency to conflict and emotional baggage that will consume our lives mentally and introduce more needs – which leads to unhappiness.

In finding our soul-mate or spouse, we uphold high the compatibility factor, since the more compatible you are, the happier you will be.

It is quite safe to say that we often consider that selfishness is the key to success in attaining abundant life. Our culture certainly says so – with all the movies, reality shows, contests, game shows, video games, music, fashion, commercials, books, and punditry.

Is SELFISHNESS really the KEY to SUCCESS in finding abundant living?
-- read more and comment ...

Tuesday, August 19, 2008

ASP.NET 3.5 ListView Web Control & CSLA

In .NET Framework 3.5, there is this new web control called ListView. ListView has been there in WinForm development for a while, but now it is available for web development. You can think of ListView as like an upgrade to GridView - a super cool upgrade - although GridView is still there. In fact, many of the stuff that ListView has are quite similar to those in GridView.

If you have a DataSet, it is super easy to bind to a ListView - all the available methods will work out of the box. A lot of tutorials on the web are written against this type of example (ListView & DataSet). What if you are using your own collection or list? In this example, I am using a CSLA based list. Hopefully this will be helpful for you in your ASP.NET - CSLA coding endeavor.

Binding
I use a CSLA datasource object. If you are using CSLA in your web project, this should be available for you.

Select the CSLADataSource from the toolbox and drag it into your page/control. You can change its ID and set some properties. Go to the event and implement the onselectobject methods such as this:


protected void CslaDSMyClassList_SelectObject(object sender, Csla.Web.SelectObjectArgs e)
{
e.BusinessObject = GetMyClassList();
}

private Csla.SortedBindingList GetMyClassList()
{
object businessObject = Session[SessionKeys.CurrentObject];
if (businessObject == null || !(businessObject is Csla.SortedBindingList))
{
Csla.SortedBindingList temp = null;
temp = new Csla.SortedBindingList(MyClassList.GetMyClassList());

temp.ApplySort(SortByPropertyName, SortDirection);
businessObject = temp;
Session[SessionKeys.CurrentObject] = businessObject;
}
return (Csla.SortedBindingList)businessObject;
}

Those methods guarantee that your ListView will always binded to a Csla.SortableBindingList holding your list, therefore this will Sort a feasible feature in our ListView with just some simple minimal coding.

Next, select a ListView control in your toolbox and drag it into your page/control. Set the d"Choose Data Source" selection to your CSLADataSource object name. Click on "Configure Data Source" and set the "Business object type" to your CSLA list and that is it! At this point, if you want, you can configure your ListView to show/hide data, put themes, adjust colors, etc.

Insert, Update, and Delete
Since with CSLA list objects you cannot natively call Insert method or Update or Delete (and CSLA by default also does not have a default constructor), you have to implement the event handler for "updating", "inserting" and "deleting". So instead of using the default methods, you will actually use the standard CSLA methods for saving object (.Save()). In inserting, a factory method call New is made and then populate the object using the data mapper and Save() it. In updating, similar process, but instead of New, a call to Get is made, then populate and then Save(). Here is an example for updating (inserting and deleting should be pretty similar).

protected void ListView1_ItemInserting (object sender, ListViewInsertEventArgs e)
{
MyClass myObject = MyClass.GetMyClass((int)(e.Keys[0].ToString()));
Csla.Data.DataMapper.Map(e.NewValues, myObject);
myObject = myObject.Save();
e.Cancel = true;
ListView1.EditIndex = -1;
ReloadList();
}

Sorting
Since Sort does not work automatically like when you are binding a DataSet, so you have to do it a little manually, but it is not bad at all. First, you have to create your button for sorting, either it is a regular button or link button, etc - it does not matter. I use the column header and convert them into link buttons. Secondly, you will need to assign a CommandName and CommandArgument. Here is an example of mine:

Name

Now in the code behind, create a handler for the ItemCommand. You can actually customize your list view with all kinds of command and as along as you have a matching handler in this ItemCommand hook, then you should be good to go. There are several keywords that ListView by default has implemented: "Edit", "Insert", "Sort", "Delete". So apart from that, you can call your command anything you want.

protected void ListView1_ItemCommand (object sender, ListViewCommandEventArgs e)
{
if (e.CommandName == "CSLASort")
{
if (SortByPropertyName == e.CommandArgument.ToString())
{
if (SortDirection == System.ComponentModel.ListSortDirection.Ascending)
SortDirection = System.ComponentModel.ListSortDirection.Descending;
else
SortDirection = System.ComponentModel.ListSortDirection.Ascending;
}
else
{
SortByPropertyName = e.CommandArgument.ToString();
SortDirection = System.ComponentModel.ListSortDirection.Ascending;
}
}
}

SortDirection & SortByPropertyName are just properties of the page/control defined as such:

private string SortByPropertyName
{
get
{
if (ViewState["SortByPropertyName"] == null)
ViewState["SortByPropertyName"] = "FullName";
return (string)ViewState["SortByPropertyName"];
}
set { ViewState["SortByPropertyName"] = value; }
}

private System.ComponentModel.ListSortDirection SortDirection
{
get
{
if (ViewState["SortDirection"] == null)
ViewState["SortDirection"] = System.ComponentModel.ListSortDirection.Ascending;
return (System.ComponentModel.ListSortDirection)ViewState["SortDirection"];
}
set { ViewState["SortDirection"] = value; }
}

There you go. You can read more on ListView here.
-- read more and comment ...

Sunday, August 17, 2008

Indonesian Independence Day (63rd)

August 17th, 1945 - Indonesia declared its independence from the Japanese. Just several days after Hiroshima and Nagasaki were bombed, Japan called a retreat and removed themselves from their colonies, including Indonesia. Indonesian people took their chances and declared independence - where the forming and planning of the declaration itself was full of drama for nationalistic sake!

Here is the short text of the declaration itself:


Kami, bangsa Indonesia, dengan ini menjatakan kemerdekaan Indonesia.

Hal-hal jang mengenai pemindahan kekoeasaan d.l.l., diselenggarakan dengan tjara saksama dan dalam tempo jang sesingkat-singkatnja.

Djakarta, hari 17 boelan 8 tahoen 05

Atas nama bangsa Indonesia

Soekarno - Hatta

Read the short version of the history here.

It is even sweeter this time since Indonesia won gold medal in the Olympic for men's double badminton. We actually got several medals.

It is very tempting to actually disown Indonesia as my motherland, but I believe that I was born and raised in Indonesia for a reason - a divine reason. Indonesia is still my home, even though I have been away for a while. So one of my purpose in staying in US for a while is to absorb as much as possible so that I can use those in my country - as time goes by, the stronger the affections grow.

My vision for now is help other Indonesian Christians so that they have a vision and passion to make impact in their communities for Christ - while trying to bring an impact in the Indonesian community from US, and eventually be able to go home to Indonesia and have a direct involvement and impact over there.
-- read more and comment ...

Thursday, August 14, 2008

New computer

My home computer is old and since we bought a digital camera and a FLIP, disk space recently have started to become an issue. It is an Athlon XP 3200+ with around 200GB of space and 1 GB of RAM. It is old, noisy (since I have to put fans everywhere to cool it) and my case is also falling apart. It is 4 years old ... which in computer age is like decades ... So, I am looking into getting soe more disk space to back up my photos, videos, mps2, and other data - but knowing that it is getting unstable, I decided to go the whole nine yards and build a whole new computer altogether and use my old as a backup.


So, here is my new system (some of these components are recommended by my friend Shawn - so thanks Shawn!):

  • Cooler Master Centurion 5 case
    My old case is small and I still plan to use it to host my old computer to run back up/storage. So getting a new case that is sturdy, flexible, with good air flow, accessible, but not overly expensive is imperative - this case fits all the requirement. Thanks to elpiar to point this out.

  • Corsair CMPSU-520HX
    My MB have been fried twice in the past because of bad/malfunctioning PSU. So this time, I aim to get a decent one and the Corsair has flexibility that allows you to attach/detach cable according to your need. So it is a winner in my book- super recommended.

  • ASUS P5Q
    My friend Shawn who is also building his own system recommended MSI P6N - which is a stellar performer. I choose the ASUS P5Q because of several reasons: more max RAM, faster RAM DDR, more SATA, and my bias toward ASUS - all with the same price as the MSI. Since I am building a machine that will run 64 bit processor, may run VMs, and most of the time is used for image processing, I need god amount or RAM headroom - P5Q allows up to 16GB instead of 8GB.

  • Intel Core 2 Quad Q9300 2.5 GHz
    Last time I got an AMD, I have to put 3 extra fans to cool it down. So, I am going with Intel now. I went with Q9300 instead of Q6600 or Q6700 because of the newer technology (4.5nm) and also since that is the best I can get for the money.

  • G.SKILL 4GB (2 x 2GB) 240-Pin DDR2 SDRAM DDR2 1066 (PC2 8500)
    No brainer here, just the good, reliable, and compatible (this is important) memory according to the MB. I typically don't want to cut corners on RAM, since faulty RAM is really a PITA.

  • WD raptor X WD1500AHFD 150GB 10KRPM SATA
    OVerall, this is probably the killer buy right here. I am super happy with this drive. It is fast, quite and has a transparent cover too! My boot up time is reduced significantly because of this drive.

  • Seagate Barracude 7200.11 500GB 7200 RPM SATA
    Need huge storage to store all my media files? Get this HD. I was thinking about doing RAID etc, but in the end I just bought this HD and run a backup bimonthly to my old 200GB drive. I may get another one of this at some point. Plus this is probably the best bang for the buck HD you can get - $78 for 500GB!

  • Scythe SCNJ-1100P 120mm Sleeve CPU Cooler
    This is a bad-ass heat-sink right here. I don't have to use this since the Q9300 comes with a factory heat-sink. But it just looks awesome and people highly recommend this heat-sink if you are over-clocking the CPU - which I may do. So, I splurge a little here and got the bad-ass heat-sink.

  • SAPPHIRE 100218L Radeon HD 2600XT 512MB 128-bit GDDR3 PCI Express x16 HDCP Ready CrossFire Supported Video Card
    I won't be using this machine for gaming much and most of my games are RTS (like Warcraft III or AoE) - so I won't be needing the super-duper video card, but I do need a video card that can run dual DVI for my monitors. This card seems to be serving purpose - well balanced with power as well as simplicity and cheap ($35) - a good choice!


-- read more and comment ...

Monday, August 4, 2008

How to smoke ribs

Smoking ribs is not easy and I have done it several times now with progressing tastiness. So, hopefully this post will help you when you decided to smoke some ribs. When done right - it is super awesome!


My style is dry rubs and slow moist smoke. Others like wet-rub better, some like baking it in the oven for simplicity/speed, etc. Feel free to take my way and tune it to your liking.
Ingredients:

  • Baby back or loin pork ribs

  • Dry rub spices - you can get these from the store or make your own. I bought several from Sam's Club and combined them to form my own rub

  • BBQ Sauce - I bought mine from Sam's Club and modified it to create a spicy bbq sauce by adding some honey and chipotle tabasco


Tools:
  • A good charcoal grill - mine is like this and something like this would be better.

  • Hickory wood chunks (not chips)

  • Apple wood chips

  • Wood chips metal tray

  • chimney smoker - click here to see photo and video demo of using it

  • Hickory Charcoal - I use Kingsford Hickory charcoal

  • A bucket (13 gallons or larger - large enough to soak the wood chunks)

  • Ribs rack (if needed)

  • Vegetable oil (or any kind of cooking oil)

  • Oven/grill thermometer


Preparation: (do this in order to save time)
  1. Soak wood chunks in water for at least a day - so do this step a day of two before the actuall cooking/smoking

  2. Ribs must be close to room temperature as possible. If yours is frozen, let it thaw to room temperature.

  3. Brush your paper with some cooking oil and use that paper to light up your charcoal in your chimney smoker - and don't touch it again until the charcoal is ready (usually about 10-15 minutes)

  4. Rub the ribs and let rest for about 15 minutes at room temperature

  5. Put charcoal in grill, as far away as possible from where you're going to put the ribs. I usually put my ribs near the grill's chimney and put the charcoal on the other side.

  6. Arrange the charcoal to stay as close to each other as possible (not spread around like regular grilling)



Cooking/Smoking:
  1. Once the charcoal is set, start putting wood chunks on top of charcoal. At this point, you should not need any more charcoal - just keep adding wood chunks to maintain heat and smoke

  2. Don't put your ribs/meat yet. Put your thermometer in the grill at the area where you are going to put the meat and close the grill. After 2-3 minutes, get a reading. If you have somewhere between 160F to 190F, you are doing great. If you have less or more, you want to work up/down to that temperature.

  3. Once you have a consistent temperature, start putting your ribs. On my grill, I only use a half of the cooking surface and leaving the other half open (including the area directly on top of the fire. Since my ribs arrangement will make the ribs closer to the heat cooked faster, I plan to rotate them consistently during the smoking period.

  4. Put apple wood chips in your wood chip metal tray and put it directly on top or near by your heat source/fire. I usually put mine on the rack on top of the fire. This will put more smoke (and also combine apple wood with hickory) but since it is using DRY wood chips, it cannot touch fire directly, but it needs a strong heat source.

  5. Ribs in the grill, put thermometer on top of ribs, and make sure smoke are coming out from your wood chunks and no direct fire touching the ribs.

  6. Every 45 minutes, glaze your ribs with BBQ sauce and rotate them if necessary to ensure even distribution of heat to the ribs. Also replenishing wood chunks to maintain temperature. Check your wood chips, make sure they are not on fire but still smokey.

  7. After 4 hours, you should have a fairly good smoke flavor in your ribs. I usually go 5.5 hours - so at this point, you can proceed to the next step or wait another 1.5 hours. Most of the time, waiting is really worth it ... unless of course you are absolutely really hungry or pressed on time.

  8. Once the smoking is done (4 hours or more), place your ribs on top direct heat in your grill. In my case, I just put the rack back on on the fire side and move my ribs there. Do this for about 2 minutes on each side while glazing them back and forth on each side. Keep doing this for about 3 times to bring your ribs up to temperature.

  9. Next step is to consume your ribs! enjoy!


-- read more and comment ...

Thursday, July 31, 2008

ASP.NET MVC, AJAX, and JQuery

I have been developing asp.net application from .NET framework 1.0, 1.1, 2.0, 3.0 - so pretty much from the begining. Nowadays, what really excites me (as far as programming goes) is ASP.NET MVC. The MVC model has been out there for a while in the Java world or Ruby world (with rails). But it is only since .NET Framework 3.5 that Microsoft ASP.NET starts to pick it up.

One thing that I really like about MVC (compared to ASP.NET webform) is the ability to control your HTML directly. This therefore empowers you to create your own Javascript component easier. In a way, it is a bit more manual then webform, but the total control and flexibility really pays off.


AJAX therefore then can become TRUE AJAX, rather than "fake" AJAX like webform's UpdatePanel. Payload is much smaller between client and server - which makes MVC app super fast (if done right, especially with AJAX).

ASP.NET MVC also enables you to have a TDD (test driven development) approach to UI development. Since all "controls" or "pages" are rendered by invoking an "Action" methods - which is just a regular method - there those methods can be called by a Unit Test of your choice and checked.

.NET framework 3.5 allows you to have pretty URL too. Initially baked into MVC assemblies, but in SP1 it will be released as part of the framework itself.

So, how do you code MVC? Is it really any different than C# or VB? Well, here is the thing, MVC is not a language or third party tools. It is more of a UI development framework. So you still use the same language (like C#, VB, etc).

For me, development in MVC pattern have been quite an experience. It really brought back the true power of separation between your model to your view/presenter but in a very powerful manner. Having a strong tight and concise HTML combined with the ability to maximize your Javascript without the use of 3rd party controls really opens tons of possibilities - this is really where you can fully utilize AJAX, in which I choose to use JQuery.

JQuery is a javascript framework. It is really powerful because it has a superb selectors - therefore with concise code, you can really do a lot of stuff that normally will take tons of code. So, what does it look like?


Here is the code to do that (just 1 line):

$("#surprise").slideToggle();

In JQuery website, you can read about all the APIs and its capabilities. It is quite amazing and opens new possibilities for your UI development.

You can read more about ASP.NET MVC:
Code Plex
An Architectural View of the ASP.NET MVC Framework
ASP.NET page
Scott Gu's Blog

JQuery:
JQuery
-- read more and comment ...

Google Visualization

Google Visualization is an API where you can feed your data to it and it will produce for you a "visualization" of your data; such as in a pie-chart, bar-chart, line-chart, and even some more complex visualization rendering. In other words, if you have structured data (dynamic or static), you can let Google handle the rendering of its visualization for you (instead of making a screen capture/image in a desktop app and including it in your web app/site).


Here is an example (taken from Google pie-chart code example) on how to render a pie chart about daily activities. From this basic code, we can customize the code to our liking, including displaying dynamic data.


<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["piechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Task');
data.addColumn('number', 'Hours per Day');
data.addRows(5);
data.setValue(0, 0, 'Work');
data.setValue(0, 1, 11);
data.setValue(1, 0, 'Eat');
data.setValue(1, 1, 2);
data.setValue(2, 0, 'Commute');
data.setValue(2, 1, 2);
data.setValue(3, 0, 'Watch TV');
data.setValue(3, 1, 2);
data.setValue(4, 0, 'Sleep');
data.setValue(4, 1, 7);

var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(data, {width: 400, height: 240, is3D: true, title: 'My Daily Activities'});
}
</script>
</head>

<body>
<div id="chart_div"></div>
</body>
</html>

The result (you can click on the chart btw - and get some details):


As I mentioned above, customization is easy. With dynamic data that comes from the server, as long as you can form your data to conform with the javascript data.addColumn format, you are set! Here is an example using data coming from ASP.NET MVC ... (or using JSON is also very easy)

<script type="text/javascript">
google.load("visualization", "1", {packages:["piechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Task');
data.addColumn('number', 'Hours per Day');
data.addRows(<%=(ViewData["MyTasks"] as List<Task>).Count() %>);
<%
int i = 0;
foreach (var task in (ViewData["MyTasks"] as List<Task>))
{
int j = 0;
%>
data.setValue(<%=i %>, <%=j %>, "<%=task.TaskName.Length > 15 ? task.TaskName.Substring(0, 15) + " ..." : task.TaskName%>");
<%j++; %>
data.setValue(<%=i %>, <%=j %>, <%=task.Hours %>);
<%i++; %>
<%
}
%>
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(data, {width: 400, height: 240, is3D: true, title: 'My Daily Activities'});
}
</script>

Now, if you are using ASP.NET web-form, is it not that easy to get your data out from your code-behind and expose it to the javascript api of Google Visualization. In this case you may need to expose your object as a protected property of your control/page so it can be accessible.

Nevertheless, once you are at the point where your data is accessible, sending your data to Google and getting a visualization back is a breeze (and fast too).

Cool, huh? Now, let's look at the code in more detail:

<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
...
This part of the code is where you reference Google's API in your code. There is no javascript to download etc, and this is all you need to do to make the API available for you. Now, in a way this is cool, because you don't need to worry about the javascript itself, less file to maintain, etc. But, it also means that there is no intellisense. I don't think it is that big of a deal, since the code you are writting will be pretty concise anyway.


...
google.load("visualization", "1", {packages:["piechart"]});
google.setOnLoadCallback(drawChart);
...
This section of code is what telling the API about what visualization you want to use (such as "piechart") and instantiate it, then it calls the method "setOnLoadCallback" passing in a method "drawChart"; which that puts the data together send it to the API to be drawn. The method "drawChart" is not a Google method. It is a regular javascript method and you can call it whatever you want (such as "myMethod" or "whatever") and as long as it is consistent in its uses, you will be fine.


...
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Task');
data.addColumn('number', 'Hours per Day');
data.addRows(5);
data.setValue(0, 0, 'Work');
data.setValue(0, 1, 11);
...
The example we are looking at is using a "DataTable" type to hold our data. This is probably the simplest way of holding our data to be sent to the visualization engine. I am not sure if there are any other data structure available from Google, but so far I have not had any needs to go beyond what DataTable has been able to provide. Anyway, this section of code is basically for putting our data together into the DataTable object "data". DataTable is basically an array. So when we are setting the values using setValue method, we are setting the data based on a specifiec coordinate (row/column). The method setValue takes in these parameters: row, column, value. You can have as many columns as you want as long as you define them - using addColumn method - before putting data into the DataTable.

...
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
...
This code is pointing out to Google Visualization on where to draw the chart. I created a div space in my HTML and gave it an id ("chart_div").

Click here to go to Google Visualization Gallery.

-- read more and comment ...