Monday, December 14, 2009

RIP DVD or create ISO image of DVD in Linux

(Dec 13, 2009)

I tried to rip a DVD in Linux.  Mostly, I followed the instructions available at instructables.com.  There are notes I want to jot down here.
  1. We need dvd::rip, as instructed in the website.  Do not, however, bother with the dvd::rip's website.  Just grab it directly from Ubuntu's Synaptic package manager.  This is the easiest way to do.

  2. We probably still need mplayer and rar.  Get them from Synaptic again.

  3. At this point, we are ready to rip a DVD, as shown at instructables.com.

  4. If you want to transcode the vob files from dvd::rip, try using vlc.


If you want to create an ISO image of your DVD, using k3b or GnomeBaker is a way to go.

Friday, November 13, 2009

Fix Ubuntu ATI driver problem caused by kernel upgrade

(Nov 13, 2009)

Updating kernel can cause some headache to Ubuntu users who use a proprietary video driver.  In my case, I used ATI's driver and upgraded kernel from 2.6.26 to 2.6.28.  Once kernel upgrade was complete, a display screen became garbage.  The best way to solve this issue is probably purging the old driver and reinstall it from scratch.

The procedure is well described here.  I followed the procedure in Section 'Need to fully remove -fglrx and reinstall -ati from scratch'.  Note that when we have the driver problem, we cannot access X server and need to boot the Ubuntu into a recover mode to maintain the system.

If the process is successful, we will be able to boot to the X server again.  However, the proprietary ATI driver may not be fully reinstalled as we expect.  There is no critical problem here.  Just download and reinstall it again from its script.


sudo /usr/share/ati/fglrx-uninstall.sh # (if it exists)
sudo apt-get remove --purge fglrx*
sudo apt-get remove --purge xserver-xorg-video-ati xserver-xorg-video-radeon
sudo apt-get install xserver-xorg-video-ati
sudo apt-get install --reinstall libgl1-mesa-glx libgl1-mesa-dri xserver-xorg-core
sudo dpkg-reconfigure xserver-xorg


Pinyo Taeprasartsit

Saturday, September 19, 2009

GL_POINTS + Qt

GL_POINTS + Qt

There are a few ways to do 2D OpenGL: GL_POINTS, glDrawPixels/glPixelZoom, and 2D texture.

The strength of GL_POINTS is its simplicity, while its weakness is inability to scale in a way most people intend.
Basically, each point occupied exactly one pixel of the screen.  If a window size increase, the point is still drawn as a single pixel.
Therefore, some pixels in a window become background color.

Consequently, GL_POINTS can be a strong candidate for 2D graphics if the window will not be resized.

The following function shows the a call list function, as an example.

/// This example draw a red horizontal line made of individual points at
///   the very middle of its window.
GLuint GLPoint::makeCallList() {
    glClear(GL_COLOR_BUFFER_BIT);

    GLuint list = glGenLists(1);
    glNewList(list, GL_COMPILE);

    glColor3f(1.0f, 0.25f, 0.25f);
    glBegin(GL_POINTS);
    {
        int nRow = m_nHeight / 2;
        for (int i = 0; i < m_nWidth; ++i)
            glVertex2s(i, nRow);
    }
    glEnd();

    glEndList();

    return list;
}


Since we are doing 2D graphics, it is recommended to disable depth test, as shown in the following initialized function.

void GLPoint::initializeGL()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glDisable(GL_DEPTH_TEST);    // we are going to do 2D OpenGL
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);
    glMatrixMode(GL_MODELVIEW);

    callList = makeCallList();
}

An example Eclipse CDT / Qt project is stored at a public folder here.
The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.

Pinyo Taeprasartsit
August-September 2009

Thursday, July 02, 2009

เรื่องของนักเรียนทุน

(เรื่องนี้ผมเขียนตอบข้อความของเพื่อนที่ http://wizardme.spaces.live.com/blog/cns!59943C23FC60FF0B!1962.entry?wa=wsignin1.0&sa=780937976
เนื่องจากว่ามันยาวมาก และหวังว่าจะมีประโยชน์ต่อคนอื่นด้วย จึงนำมาเก็บไว้ในที่ส่วนตัว)

นี่ อย่าต่อว่าทาง สนร เกินกว่าเหตุสิ อย่าลืมว่าเรามาจากประเทศไทย เราก็เป็นเหมือนลูกคนจน จะทำอะไรตามใจชอบมากก็ไม่ได้
ก็เราบอกเองไม่ใช่เหรอว่าเรามจากครอบครัวคนจน เราก็น่าจะเข้าใจข้อจำกัดพวกนี้ดี

เราไม่ควรจะมัวแต่ไปมองพวกคนในฟากรัฐบาลที่ได้เงินมากแบบไม่สมควร เพราะเรื่องเลว ๆ มันก็มีอยู่ทุกวงการ
เป็นต้นว่าในสายทางเอกชน พวกผู้บริหารสถาบันการเงินก็อาจจะได้รายได้มากอย่างไร้ความละอายใจ

พูดง่าย ๆ ก็คือ การเปลี่ยนแปลงบางอย่าง ใช่ว่าจะเป็นไปได้ด้วยกำลังของ สนร แต่เพียงฝ่ายเดียว
อย่างเราตอนทำงานในบริษัท ก็อาจจะมีเรื่องที่เราไม่ชอบอยู่ เราก็อาจจะไม่สามารถเปลี่ยนมันได้

และถ้ามองย้อนกลับเข้ามาที่ตัว แม้แต่ตัวของเราเองก็ยังไม่อาจจะเปลี่ยนสิ่งที่เราไม่ชอบในตัวเราเองได้
ดังนั้นอย่าตำหนิโลกภายนอกเกินกว่าจำเป็นเลย

ส่วนทาง สนร ที่จริงโดยรวมเค้าก็ดำเนินการอย่างมีเหตุผลอยู่ ถึงจะมีอะไรที่ดูแปลก ๆ ในบางพื้นที่ แต่จะให้ถูกต้องหมดก็คงจะไม่ง่ายนัก
ถ้าเราเป็น สนร เอง เราก็อาจจะไม่รู้ว่าตรงไหนที่ไม่สมเหตุผล เพราะไม่รู้ว่าจะเอาข้อมูลที่เชื่อถือได้มาจากไหนดี ก็ต้องรอให้มีคนร้องทุกข์มาพอสมควรก่อน

อย่างเรื่องวีซ่าที่เราบ่นมา แท้ที่จริงไม่ว่าจะได้มาแบบ J1 หรือ F1 ก็จะตกอยู่ในสภาพที่คล้าย ๆ กันทั้งคู่
และที่จริงแบบ J1 ก็ดีกว่า F1 ในกรณีที่มีคู่สมรสมาอยู่ด้วย เพราะ J2 ที่ติดสอยห้อยตามมา สามารถทำงานได้อย่างเต็มรูปแบบ ส่วน F2 ทำงานไม่ได้

ผมเองก็เลี้ยงชีพด้วยตัวเอง ไม่ได้ขอเงินพ่อแม่มา ถ้าทาง กพ เค้าไม่เงินค่าตั๋วเครื่องบินมาเรียน ผมก็แทบจะไม่เงินซื้อตั๋วเครื่องบินมาที่นี่ด้วยซ้ำ เรียกได้ว่าก่อนมา ผมจนยิ่งกว่าวันเสียอีก และนักเรียนทุนที่นี่จำนวนมากก็อยู่ด้วยกำลังของตัวอง แม้แต่รูมเมตผมก็เป็น วันอย่าได้มองโลกในแง่ร้ายเกินกว่าเหตุเลย

ครอบครัวไทยบางกลุ่มอยากให้ลูกเป็นข้าราชการเพราะไม่อยากให้ลำบากก็มี อยากให้เป็นใหญ่เป็นโตเพื่อคอรับชันก็มี
แต่บางกลุ่มก็ไม่ได้เป็นอย่างนั้น กลุ่มที่ดี ๆ ก็มีอยู่ แต่เราไม่เจอเอง เพราะข้าราชการครูหรือแพทย์ในพื้นที่ห่างไกลก็มีอยู่ พ่อแม้เค้าก็คงไม่อยากจะให้ลูกทำงานแบบนี้สักเท่าไหร่ แต่ในเมื่อเค้าเห็นลูกเต็มไปด้วยจิตวิญญาณที่จะช่วยคนอื่น พร้อมที่จะเผชิญทุกข์น้อยใหญ่ เค้าจึงยอมให้ไปเป็นข้าราชการ ทั้ง ๆ ที่รู้ว่าจะต้องลำบาก

ผมจบมาจากวิศวะจุฬา โอกาสทางการเงินผมก็มีอยู่ไม่น้อย ยิ่งไปกว่านั้นทั้ง ๆ ที่ผมก็ไม่มีเงิน (พ่อแม่ไม่มีจะให้เหมือนกัน) แต่อยากจะช่วยเหลือพัฒนาคุณภาพการศึกษา จึงได้เลือกเดินทางนี้ พ่อแม่ผมก็ห่วงว่าจะลำบาก (ในดวงของผม พ่อบอกว่าผมจะต้องทำงานหนักไปจนแก่โน่นแหละ ไม่ได้สบายเหมือนคนอื่นเลย) แต่สุดท้ายเค้าก็ยอมให้มาทางนี้ เพราะไม่อาจจะขวางกั้นเจตนาในการทำความดีของคนอื่นได้ และได้แต่หวังว่าผมจะหาทางเอาตัวรอดได้ และไม่ต้องลำบากนัก

วันอาจจะหลงคิดว่า สมัครทุนนี้มาเป็นการขายจิตวิญญาณ แต่สำหรับผมมันไม่ได้เป็นอย่างนั้นเลย เพราะผมสมัครทุนเพื่อจิตวิญญาณของผมเองต่างหาก ผมเตรียมใจที่จะเผชิญทุกข์ไว้ก่อนล่วงหน้า มีความพร้อมที่จะสละความสุขส่วนตนออก แม้จะเป็นไปเพื่อคนจำนวนมากที่ผมไม่รู้จักก็ตามที

ทีนี้ถ้าวกกลับมาเรื่องของเงิน มาดูกันดีกว่าอะไรที่ทำให้มันเกิดความแตกต่างขึ้น เพราะผมก็อยู่อย่างมีความสุข
อันที่จริงผมก็ไม่ใช่คนประหยัด คือไม่ประหยัดในแง่ที่ว่าผมอยากได้อะไรผมก็ซื้อเหมือนกัน แต่มันต่างกันตรงที่ว่า ผมไม่ค่อยอยากได้อะไรต่างหาก

ผมสังเกตคนรอบข้าง เค้าก็ไปเที่ยวโน่นเที่ยวนี่บ่อย ๆ บางคนก็ต้องหาซื้อ smart phone ที่ราคาไม่ค่อยจะถูกเท่าไหร่มาใช้ ว่ากันตามเหตุนี้แล้ว นี่ไม่ใช่ความประพฤติของลูกคนจนเลย (คนจนในที่นี้หมายถึงประเทศไทย) แต่ผมพอใจในสิ่งที่ตนมีอยู่ ผมก็มีความสุขของผมได้ด้วยกำลังทรัพย์เพียงน้อยนิด

ผมไม่ต้องเสียเงินเดินทางไกล เพราะใจไม่เร่าร้อนด้วยการแสวงหาสิ่งภายนอก ผมไม่ต้องเสียเงินเล่นสกี เพราะใจไม่เร่าร้อนด้วยความกระหายที่จะเพลิดเพลินในกีฬา ผมไม่ต้องกระเสือกกระสนหาความรักความปรารถนานอกกายอะไรมาก จึงไม่ต้องเสียเงินเพียงเพื่อให้ได้พบให้ได้ปรนเปรอหญิงหรือชายที่เราพอใจ

เมื่อใจไม่เร่าร้อน กายก็ไม่เร่าร้อน เมื่อกายไม่เร่าร้อน ก็ไม่ต้องแสวงหา และก็ไม่ต้องมีค่าใช้จ่ายเพื่อปรนเปรอตนหรือคนที่เราหลงให้มากมายนัก

ผมมาที่นี่ เงินเก็บผมมีแต่จะเพิ่ม ทั้ง ๆ ที่ไม่ได้พยายามเก็บ เพราะในเมื่อใจไม่อยากได้ ก็ไม่ต้องอดกลั้นพยายามเก็บเงิน แต่เงินจะถูกเก็บขึ้นมาเรื่อย ๆ โดยอัตโนมัติ ด้วยเหตุอันแสนจะเข้าใจง่ายคือมันไม่ถูกเอาไปใช้ ผมที่ไม่เป็นหนี้มาก่อน ก็ไม่เป็นเป็นหนี้ต่อไป

"จิตเป็นาย กายเป็นบ่าว" นะ  ใจของเราจะต้องชุ่มโชกด้วยความอยากก่อน กายถึงจะหลงและเร่าร้อนด้วยความอยากได้

ปัญหาเรื่องค่ากินอยู่ แก้ได้เราก็แก้ แก้ไม่ได้ก็อย่าไปทุกข์ อย่าไปต่อว่าคนอื่นจนเกินเลย คนมีปัญญาเค้ากล่าวไว้ว่า "ปัญหาเป็นสิ่งที่ทุกคนต้องเผชิญ แต่ความทุกข์เป็นเพียงส่วนเกินของชีวิต"

ย้อนดูคนในอดีต แม้แต่พระพุทธเจ้า พระเยซู ก็ยังต้องเผชิญปัญหาจากสาวกที่ไม่รักดีของตัวเอง คนธรรมดาเดินดินกินข้าวแกงอย่างเราจะหลีกเร้นจากปัญหาก็คงไม่ได้ แต่จะทุกข์หรือเปล่าก็เป็นอีกเรื่องหนึ่ง

อย่าลืมที่ผมพูดไว้ตอนก่อนหน้านี้นะว่า แม้แต่นิสัยบางอย่างของเราที่เราไม่ชอบ เราก็อาจจะแก้ไม่ได้ ความเขลาบางอย่างที่เรามีอยู่ บางทีเราก็กำจัดออกไปไม่ได้เหมือนกัน เว้นแต่เราจะมีความเด็ดเดี่ยวอย่างต่อเนื่องและยาวนาน
เช่น คนติดเหล่า บุหรี่ วีดีโอเกม บางทีก็ติดอยู่นั่นแหละ เป็นสิบปีก็ยังติดอยู่ ทั้งที่รู้ว่าไม่ดีหรือไม่มีประโยชน์

บุคคลหรือหน่วยงานอื่น ๆ ก็อาจจะตกอยู่ในสภาพนี้ ปัญหาอันไหนที่เรามีกำลังพอแก้ได้ เราก็พยายามแก้ไป ไม่ปล่อยให้เวลาล่วงเลยไปเปล่า ๆ อะไรที่แก้ไม่ได้ก็ต้องยอมรับสภาพมัน เพราะรู้อยู่แก่ใจแล้วว่าได้ทำดีที่สุดแล้ว

ภิญโญ
กรกฎาคม 2552

Friday, June 26, 2009

Creating and using shared library in Linux

Creating a shared library is relatively easy.  We only need to set a compilation flat to -fPIC (Position Independent Code) to create a library that is usable by other programs.

To use the shared library, however, is quite tricky in Linux.  A shared library or dynamically linked library in Windows are easy to use.  We can just place a dll file to the same folder of an executable. 

In Linux, nonetheless, things are more complicated, because Linux will never try to search for a library in a current directory.  Thus, we have to add a library direction to a search path or install it to a standard place like /usr/lib.  The latter choice needs adminstrator priviledge and not suitable if only one or two programs are to use the library.  So, we should modify a search path.

Now, the question is 'Can we modify a search path, but cause no side effect to other programs at all?'.  We are curious about this since we may have multiple libraries of the same name during testing.  A debug program may call a debug library and a release program may call release library of the same name.  Fortunately, we can do that, as shown in http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html (Section 3.5. Installing and Using a Shared Library).

For example, if a shared library is in the same current directory of an executable my_program we can call
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH  ./my_program

If the library is in another folder, such as /home/my_name, the command will be
LD_LIBRARY_PATH=/home/my_name:$LD_LIBRARY_PATH  ./my_program

Next question is 'How can we do such thing in Eclipse?'. We can do this in 'Run Configurations...'. Once we finish common configuration, we need to set an environment variable in the 'Environment' tab.
Click on the 'New' button. Set Name = LD_LIBRARY_PATH and set the Value = my_lib_dir:$LD_LIBRARY_PATH (change 'my_lib_dir' to the library directory). This is enough for Eclipse settings.

Reference
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

Monday, June 01, 2009

Note on Boost's Multidimensional Array

Note on Boost's Multidimensional Array

(Jun 1, 2009)
(Last update: Mar 28, 2010)
(Last typo correction: Jan 6, 2024)

The Boost C++ library provides an elegant way to handle a multi-dimensional array.  We can access an array element in a compact way as usual (A[i][j][k], for example).  Boundary checking is performed by assertion which is typically disabled when NDEBUG flag is employed.   Because of the use of assertion mechanism, accessing elements outside the range of any dimension does not cause an exception, but a program will be terminated right away.  This makes sense because a program normally has no use to access an invalid entry and should be rewritten.  Plus, graceful stack unwinding and tracing for exception is not available as a standard way in C++ (there may be a better, standard solution about this in the future, however).  Thus, program halting is not a bad idea under a typical C++ circumstance. 

Moreover, we almost always prevent out-of-bound access explicitly in our code and there is little use to do boundary checking again, especially when speed is important.  Therefore, in a production release, we can remove the boundary checking to increase program speed by disabling assertion.  Note: Alternatively, we can disable this boundary checking by defining BOOST_DISABLE_ASSERTS.

Besides an example in Boost website, I want to add another example and more explanation that may be helpful for later reference (and people who stumble at this page).   In this example, I show that we need to pass boost::multi_array by reference explicitly.  Otherwise, modification in a called function will not have any effect (to see the difference, try removing & in a function signature of change).  Also, there is no exception thrown or caught at all.  The program will be terminated if assertion is enabled.

Another side note, but is important, about Boost's multidimensional array is that we cannot explicitly reallocate it by using = to an instance of the array.  Reassigning an array instance can be done only if both input and output arrays are of the same size.

For example, because we know only an array size during runtime, some may choose to declare a boost multidimensional array without any initial size.

boost::multi_array<double, 3> arrayTest;

Then, we know at runtime that the size is (size_x, size_y, size_z), so we reallocate the array variable by reassignment (using = ) as follows

arrayTest = boost::multi_array<double, 3>(boost::extents[size_x][size_y][size_z]);

This will not cause an error outright in a release mode without assertion, but a program is very likely to crash later on.  A correct way to dynamically reallocate the space for a multidimensional array is to use 'resize' function, as shown below.

arrayTest.resize(boost::extents[size_x][size_y][size_z]);

Notice that it is boost::extents (with s), not just boost::extent (without s).  There is boost::extent, but it is another thing.  Please don't get confused with this.

A correct way to copy contents from one array to another

As discussed earlier, reassigning Boost's multi-dimensional array may cause an error unless both input and output arrays are equal in size.  Thus, a proper way for reassignment is:

// Assume that the input array is of size: size_x, size_y, and size_z.
// 1. resize an output array
outArray.resize( boost::extents[size_x][size_y][size_z] );

// 2. now, we can copy contents of an input array by using =
outArray = inArray;

Side note: assigning initial contents of an array when it is declared.

Assigning contents to an array when it is declared is not considered reassignment.  Hence, such operation is correctly executed as long as the dimensionality is matched.

// This content assignment is correct, provided that the dimensionality of the input array is three in this case.
boost::multi_array<double, 3> outArray = inArray;

The above operation implicitly initialized the size of the outArray to be the same as that of inArray.  It is important to note that such implicit size initialization can be done at the declaration only.  If we do not assign any content to the array, the length of each dimension is zero.  Consequently, content assignment int the following example is an incorrect use.

boost::multi_array<double, 3> outArray;    // since we say nothing else here, the length of the array in each dimension is zero.
outArray = inArray;    // The assignment is not done at the declaration time.  Therefore, this is reassignment.
                       // If inArray size does not match with outArray, the error will occur.

How can we know the size of Boost's multi dimensional array

The size of the array comes in two folds: dimensionality and the array length of each dimension.

  • To obtain dimensionality
    int nNumDims = A.dimensionality;

  • Now, obtain the array length of the ith dimension
    int nLengh = A.shape()[i];

    The following example obtains and prints out dimensionality and lengths of an array

    int nNumDims = A.dimensionality;

    cout << "Dimensionality = " << nNumDims << endl;

    // Report size list
    for (int i = 0; i != nNumDims; ++i) {
         cout << "Size( " << i << " ) = " << A.shape()[i] << endl;
    }

Pitfall: Be careful when Boost's multi-dimensional array is a class member

Suppose class MyArray has a three dimensional array as a member.  Copying contents from one instance of MyArray to another implies copying Boost's multi-dimensional array, as well.
So, make sure that the dimensionalities of input and output arrays match before copying.  Alternatively, we need to copy the contents of MyArray instance at declaration.  See section 'A correct way to copy centents from one array to another' and its side note for detail.

Example:
MyArray outArray;
MyArray inArray;

// Do something with inArray
// ...

// Now, try to save the contents of inArray to outArray
outArray = inArray;  // Beware! There is reassignment of the array inside. 
                     // We have to make sure that all Boost's multi dimensional arrays inside inArray and outArray match in size.

As discussed in the side note above, however, the following code has no problem.
MyArray inArray;

// Do something with inArray
// ...

// Now, try to save the contents of inArray to outArray
MyArray outArray = inArray;  // Correct!  There is no array reassignment, but array initialization at declaration.


=============================================

The following code is an example about assertion and exception throw related to Boost's multi dimensional array.

#include "boost/multi_array.hpp"

using namespace std;

typedef boost::multi_array<double, 3> array3_double;

void change(array3_double& A);
void causeException(array3_double& A);    // In fact, it's not an exception.  Program will be aborted immediately if assertion is enabled.

int main() {
    // Notice that it is extents, not just extent.
    array3_double A(boost::extents[4][3][2]);

    int values = 0;
    for(int i = 0; i != 4; ++i)
        for(int j = 0; j != 3; ++j)
            for(int k = 0; k != 2; ++k)
                A[i][j][k] = values++;

    change(A);

    // Delete this block if you don't want a program to halt.
    // Note: there is no exception thrown.  Program will be just terminated.
    {
        try {
            causeException(A);
        } catch(std::exception ex) {
            cout << "Exception caught:" << endl;
            cout << ex.what() << endl;
        }
    }

    cout << A[3][2][1] << endl; // check this if you pass by value
    return 0;
}

// The parameter is passed by reference.  This is important as the change of A in this function
//   will not affect the
original copy if we pass by value (without using & in the parameter). 
// If we pass by value, the whole thing in
the original copy will be copied to a local copy of
//   this function.

void change(array3_double& A) {
    int nNumDims = A.dimensionality;
    cout << "Dimensionality = " << nNumDims << endl;

    // Report size list
    for (int i = 0; i != nNumDims; ++i) {
        cout << "Size( " << i << " ) = " << A.shape()[i] << endl;
    }

    // Report total size
    cout << "Total size = " << A.num_elements() << endl;

    A[3][2][1] = 99;

    return;
}

void causeException(array3_double& A) {
    int k = 7;

    A[5][5][k] = 9999;

    return;
}


=============================================

Pinyo Taeprasartsit

(This document can be viewed at my blog and Google docs)
(Feel free to leave comment or question in my blog.  Don't worry if it is an old post.  I get a notification of your comment in my mailbox and tend to answer questions from the reader.
Google docs version is better for printing.)

Monday, May 18, 2009

SetPixel in Vista 64 bits

(May 18, 2009)

SetPixel in Vista 64 bits is affected by Aero Glass capability. If we disable Aero Glass, SetPixel will work correctly only around half of the bitmap. For example, if our image is of size 512 x 512, only the first or the second half of the bitmap plane will work fine. In my machine, columns 257 and later will not get affected by SetPixel.

This is a long standing bug in Vista 64 bits, as discussed at http://social.msdn.microsoft.com/Forums/en-US/windowsuidevelopment/thread/4ac40f47-6b44-46c4-869d-38a594d9a4f3.

Workaround is just enabling the Aero Glass theme or use FillRect of size 1 pixel, as shown
http://social.msdn.microsoft.com/Forums/en-US/windowsuidevelopment/thread/9100f5cc-dbc9-4b4a-a46f-23c434d76e87/

Friday, March 13, 2009

Create Virtual Drive in Windows by Mounting Directory

(Mar 13, 2009)

To create a virtual drive in Windows from a directory, we can use the Command Prompt in Windows and input

subst drive_letter: folder_path


For example, if we want to create a virtual z drive from a directory d:\temp, we can issue a command

subst z: d:\temp

To remove the virtual drive, we can use

subst drive_letter: /D

For example subst z: /D


//=================================

More details are available from http://www.askvg.com/create-a-virtual-drive-for-your-desired-folder-in-my-computer-using-subst-command/

Monday, March 02, 2009

Using TortoiseSVN

Using TortoiseSVN

(Mar 2, 2009)

Although GUI of TortoiseSVN is very good, it may not be intuitive for some people.  Here, I discussed some aspects of TortoiseSVN that may be important to a beginner in a version control system.

  1. Repository and working files (files we are working with) are stored in different places.  This aspect will be obvious if we are working on other version control systems, such as MS SourceSafe, because server and client interfaces are separated in the first place.  In that case, we have to set up a server and then use a client interface to connect to the server.

    For TortoiseSVN, however, this may be a bit confusing since TortoiseSVN can act as both server and client at the same time and on the same machine . A place to store a repository and working files seem to be just a folder.  Nonetheless, the behavior of server-client is still preserved and the repository and working files must be in different places.

  2. TortoiseSVN integrates itself to a Windows Explorer.  There is nothing to call from Windows' start menu.  Its behavior is changed according to the items we are interacting with.  For example, if we right click in an empty area in a folder, its menu will allow us to 'Create repository here'.  If we click on a checked out file, its menu will allow us to update from or commit to a repository.

  3. Don't try to add files by going to a working folder.  This must be done in a repository folder.  Basically, a brand new file is not associated with any repositories.  TortoiseSVN will not know where the new file should go.  Thus, we have to call a repository first.  This can be done by going to a repository folder, right click on an empty space, choose 'TortoiseSVN=>Repo-browser'.  When we arrive there, right click on the file pane and choose 'Add file...'. Notice that TortoiseSVN is very obsessed with right clicking on something.

  4. Although a file is added, it remains a normal file in a normal folder.  TortoiseSVN does not associate any version-control features to the file directly. 

  5. Version-control features will be available to working folders only.  In addition, working folders can be created by checking out things from a repository.  Note that pre-existing files in the folder may be perished.  Make sure you copy the files to somewhere else before doing so.  Alternatively, just check out items to another folder, preferably a brand-new one.

  6. We use a version-control system because we want to track change and revert to previous files, if needed.  For TortoiseSVN, reverting can be done at a working folder, not a repository.  This makes sense because a single repository may be checked out to many places.  Going to the repository will give TortoiseSVN no information about a target place.  Note that reverting to a single target is reasonable.  Why?  This is because it is normal that we want to check if reverting will fix an issue.  If so, we can commit the reverted file to a repository again with some check-in note.

    To execute version reverting, go to a target item, right click on it, and choose 'TortoiseSVN=>Show log'.  Then find a desired revision in a log, right click on the revision, and choose 'Revert to this revision'.

  7. A checked out folder is equipped with version-control features.  When we create a new file in the folder, it will mark with '?' on its icon to indicate that it is not a repository.  If it is not supposed to be in a repository, you can tell TortoiseSVN to ignore it.  Otherwise, you can add it to the repository.  This time, we can do it directly by right clicking on the file and choose an appropriate command.  ( Now, you see that TortoiseSVN is 'right-clicking oriented', right? :P )


This document can be view in my blog or Google docs.
(Use my blog to comment and Google docs for printing)


Sunday, January 04, 2009

Compiler issue: Nested template specialization in GCC

(Jan 4, 2009)

I tried to declare a vector that has another container in it. For example,
vector<vector<int>> vecInt;

This syntax works within MS Visual C++, but not in GCC. In GCC, the compiler says
`>>' should be `> >' within a nested template

The above error message is clear. We just need to insert space between angle brackets to fix the issue and change the above statement to
vector< vector<int> > vectInt;

However,
if the inner container is more complicated, the compiler error message
may make you wonder what is happening. For example, if the inner
container is Boost's dynamic bitset:
vector<boost::dynamic_bitset<>> vecBsRoiData;

The error message will be
vecBsRoiData' was not declared in this scope
The
error message is very confusing, but can be handled in the same way by
inserting space between angle brackets and change it to
vector< boost::dynamic_bitset<> > vecBsRoiData;

Note: in reality, we only need to insert space to the closing bracket, but doing so may make the code looks strange. Therefore, I inserted space to both opening and closing brackets.