-->

2013年7月14日 星期日

Python - Auto Completion under Interaction Mode

在 Expert Python Programming 看到,在 Python Interactive Mode 裡,如何產生 auto-completion 的功能。

在未介紹之前,我們在 command-line 打上 python,會看到類似的 interactive mode

$ python
Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
Display all 174 possibilities? (y or n)

例如在 import os,但可能突然忘了某個語法怎麼下的時候,這時候就可以透過 auto-completion 的功能,方便查詢。

在 Linux (CentOS) 可以用下面的方法來添加:

  1. 首先,在你的 HOME 目錄,加入 .pythonstartup 這個檔案
    $ vim ~/.pythonstartup

    import readline
    import rlcompleter
    import atexit
    import os
    
    # tab completion
    readline.parse_and_bind('tab: complete')
    # history file
    histfile = os.path.join(os.environ['HOME'], '.pythonhistory')
    try:
      readline.read_history_file(histfile)
    except IOError:
      pass
    
    atexit.register(readline.write_history_file, histfile)
    del os, histfile, readline, rlcompleter
    
    
  2. 接著在你的環境變數增加 PYTHONSTARTUP 這個變數
    $ vim ~/.bash_profile

    在最後面加上
    export PYTHONSTARTUP=~/.pythonstartup
  3. 最後做重讀設定的動作
    $ source ~/.bash_profile
這樣就完成了,我們此時可以重新進入 python 的 interactive mode 去看結果:
$ python
Python 2.6.6 (r266:84292, Jul 10 2013, 22:48:45)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os. # ← 我們打完 os. 之後按下 tab 鍵
Display all 244 possibilities? (y or n) # ← 然後輸入 y,接下來會看到所有的成員
os.EX_CANTCREAT
os.WIFEXITED(
os.execle(
os.popen(
os.EX_CONFIG
os.WIFSIGNALED(
os.execlp(
os.popen2(
...

這樣就大功告成了。

2012年12月8日 星期六

透過 Putty + XMing,在 Windows 下執行遠端 Linux 上的 GUI 程式


  • 前言
    在 Linux 裡,可以透過 X Window (簡稱 X11) 來處理圖形介面。
    往往有時候我們希望可以直接透過遠端存取的方式在 Linux 上處理相關作業。例如:透過 Putty (Telnet/SSH) 來連遠端的 Linux。然後開始修改文件,例如用 vim 修改檔案內容。但是,有時想要能透過滑鼠來快速移到某行時,只能透過鍵盤來操作,會不會覺得很麻煩、很不方便?
  • 這時候,就可以採取 Putty + XMing 的方案了。

先登入到你的遠端 Linux
  • 先安裝 openssh,在 CentOS 下可以用下面的指令
    yum install openssh
  • 編輯 /etc/ssh/sshd_config
  • 加入三行
    X11Forwarding yes
    X11DisplayOffset 10
    X11UseLocalhost yes
  • 然後儲存
  • 重新啟動 sshd,指令如下
    service sshd restart

下載並安裝 XMing (http://sourceforge.net/projects/xming/) for Windows。



執行 XLanuch


 





設定 Putty 的 SSH > X11 forwarding


之後執行 Putty 的 SSH 連線
輸入 xclock 以及 gvim,可以看到從 Linux 來的 GUI 視窗



2012年1月1日 星期日

[gcov] Coverage testing tool

在 GNU 有一套 gcov 可以輔助我們計算 code coverage 的工具

我們在這裡以一個 max(a, b, c) 的 C++ 程式為例,從 compile、test、最後透過 gcov 跑出 gcov 的結果。

下面的程式,為了展示效果,所以將 max 以比較直觀的 if 來判斷大小,用意是為了測試 gcov 的效果。

首先,先編輯一個 max3.cpp 的檔案
# vim max3.cpp


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
#include <stdlib.h>
 
template <typename T>
T max(T a, T b, T c)
{
  if (a > b)
  {
    if (a > c)
    {
      return a;
    }
    else
    {
      return c;
    }
  }
  else
  {
    if (b > c)
    {
      return b;
    }
    else
    {
      return c;
    }
  }
}
 
void show_usage(void)
{
  fprintf(stderr, "Please input arguments with thress numbers!\n");
}
 
int main(int argc, char **argv)
{
  if (argc < 4)
  {
    show_usage();
    return EXIT_FAILURE;
  }
 
 
  int a = atoi(argv[1]);
  int b = atoi(argv[2]);
  int c = atoi(argv[3]);
  printf(
    "Max number (%d, %d, %d) is %d\n",
    a, b, c,
    max(a, b, c)
  );
 
  return EXIT_SUCCESS;
}
 


若不加 gcov,我們可以用
# g++ max3.cpp -o max3
來編譯我們的程式,接著用

# ./max3
就可以簡單的跑我們的程式,結果如下:

Please input arguments with thress numbers!
因為我們沒有輸入任何數字,所以程式會執行到 show_usage,印出錯誤訊息後,結束程式。

 
void show_usage(void)
{
  fprintf(stderr, "Please input arguments with thress numbers!\n");
}
 
int main(int argc, char **argv)
{
  if (argc < 4)
  {
    show_usage();
    return EXIT_FAILURE;
  }
 
我們可以在 compile 的時候,加上分析 coverage 的選項

# g++ max3.cpp -o max3 -fprofile-arcs -ftest-coverage
編譯完後,用 ls 查詢多了一個 max3.gcno 的檔案
# ls
max3  max3.cpp  max3.gcno
接著我們就可以跟平常一樣,開始測試我們的程式

./max3
只要有執行過 binary,就會在該目錄下發現多了 .gcda 的檔案

# ls
max3  max3.cpp  max3.gcda  max3.gcno
測試完以後,用 gcov,參數給 source files

# gcov max3.cpp
File 'max3.cpp'
Lines executed:35.00% of 20
max3.cpp:creating 'max3.cpp.gcov'
然後 ls 就會看到多了 .gcov 的檔案

# ls
max3  max3.cpp  max3.cpp.gcov  max3.gcda  max3.gcno
 這個 .gcov 的檔案就是 coverage 的結果

        -:    0:Source:max3.cpp
        -:    0:Graph:max3.gcno
        -:    0:Data:max3.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:#include <stdlib.h>
        -:    3:
        -:    4:template <typename T>
    #####:    5:T max(T a, T b, T c)
        -:    6:{
    #####:    7:  if (a > b)
        -:    8:  {
    #####:    9:    if (a > c)
        -:   10:    {
    #####:   11:      return a;
        -:   12:    }
        -:   13:    else
        -:   14:    {
    #####:   15:      return c;
        -:   16:    }
        -:   17:  }
        -:   18:  else
        -:   19:  {
    #####:   20:    if (b > c)
        -:   21:    {
    #####:   22:      return b;
        -:   23:    }
        -:   24:    else
        -:   25:    {
    #####:   26:      return c;
        -:   27:    }
        -:   28:  }
        -:   29:}
        -:   30:
        1:   31:void show_usage(void)
        -:   32:{
        1:   33:  fprintf(stderr, "Please input arguments with thress numbers!\n");
        1:   34:}
        -:   35:
        1:   36:int main(int argc, char **argv)
        -:   37:{
        1:   38:  if (argc < 4)
 
        -:   39:  {
        1:   40:    show_usage();
        1:   41:    return EXIT_FAILURE;
        -:   42:  }
        -:   43:
    #####:   44:  int a = atoi(argv[1]);
    #####:   45:  int b = atoi(argv[2]);
    #####:   46:  int c = atoi(argv[3]);
        -:   47:  printf(
        -:   48:    "Max number (%d, %d, %d) is %d\n",
        -:   49:    a, b, c,
        -:   50:    max(a, b, c)
    #####:   51:  );
        -:   52:
    #####:   53:  return EXIT_SUCCESS;
        -:   54:}
        -:   55:
左邊欄有看到 1 代表該 line 被執行了 1 次、##### 代表沒有執行

此時我們可以繼續執行我們的測試,coverage 會繼續的累積

# ./max3 1 3 5
Max number (1, 3, 5) is 5

# gcov max3.cpp
File 'max3.cpp'
Lines executed:80.00% of 20
max3.cpp:creating 'max3.cpp.gcov'

# cat max3.cpp.gcov
        -:    0:Source:max3.cpp
        -:    0:Graph:max3.gcno
        -:    0:Data:max3.gcda
        -:    0:Runs:2
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:#include <stdlib.h>
        -:    3:
        -:    4:template <typename T>
        1:    5:T max(T a, T b, T c)
        -:    6:{
        1:    7:  if (a > b)
        -:    8:  {
    #####:    9:    if (a > c)
        -:   10:    {
    #####:   11:      return a;
        -:   12:    }
        -:   13:    else
        -:   14:    {
    #####:   15:      return c;
        -:   16:    }
        -:   17:  }
        -:   18:  else
        -:   19:  {
        1:   20:    if (b > c)
        -:   21:    {
    #####:   22:      return b;
        -:   23:    }
        -:   24:    else
        -:   25:    {
        1:   26:      return c;
        -:   27:    }
        -:   28:  }
        -:   29:}
        -:   30:
        1:   31:void show_usage(void)
        -:   32:{
        1:   33:  fprintf(stderr, "Please input arguments with thress numbers!\n");
        1:   34:}
        -:   35:
        2:   36:int main(int argc, char **argv)
        -:   37:{
        2:   38:  if (argc < 4)
        -:   39:  {
        1:   40:    show_usage();
        1:   41:    return EXIT_FAILURE;
        -:   42:  }
        -:   43:
        1:   44:  int a = atoi(argv[1]);
        1:   45:  int b = atoi(argv[2]);
        1:   46:  int c = atoi(argv[3]);
        -:   47:  printf(
        -:   48:    "Max number (%d, %d, %d) is %d\n",
        -:   49:    a, b, c,
        -:   50:    max(a, b, c)
        1:   51:  );
        -:   52:
        1:   53:  return EXIT_SUCCESS;
        -:   54:}
        -:   55:
測試 code coverage 的好處,可以幫我們檢查我們的 test case 只能跑那些部分,還有那些部分是無法被執行的。於是開 test case 的時候,我們就不用一直增加重複跑到的部分,如果測試你開了 100 個 test cases,和開了 10000 個 test cases,結果跑出來的 coverage rate 沒有因此而提昇的話,那這樣是很沒有效率的。

因為我們現在的 coverage rate 只有 80%,代表我們還有一些 code 沒有被測試,我們就可以繼續開 test case。

./max3 6 4 2
./max3 6 2 4
./max3 2 6 4

# gcov max3.cpp
File 'max3.cpp'
Lines executed:95.00% of 20
max3.cpp:creating 'max3.cpp.gcov'

        -:    4:template <typename T>
        4:    5:T max(T a, T b, T c)
        -:    6:{
        4:    7:  if (a > b)
        -:    8:  {
        2:    9:    if (a > c)
        -:   10:    {
        2:   11:      return a;
        -:   12:    }
        -:   13:    else
        -:   14:    {
    #####:   15:      return c;
        -:   16:    }
        -:   17:  }
        -:   18:  else
        -:   19:  {
        2:   20:    if (b > c)
        -:   21:    {
        1:   22:      return b;
        -:   23:    }
        -:   24:    else
        -:   25:    {
        1:   26:      return c;
        -:   27:    }
        -:   28:  }
        -:   29:}
多了三個 test cases 以後,我們 coverage rate 已經提昇到 95%,還剩下 line 15 沒有被執行到,我們就只要開

# ./max3 6 4 8
Max number (6, 4, 8) is 8
# gcov max3.cpp
File 'max3.cpp'
Lines executed:100.00% of 20
max3.cpp:creating 'max3.cpp.gcov'
最後終於到達 100%,也就是我們的程式碼,都被執行過至少一次了。

2011年12月29日 星期四

Build STLPort on Ubuntu


Download site: http://sourceforge.net/projects/stlport/

# tar jxvf STLport-5.2.1.tar.bz2 STLport-5.2.1/
# cd STLport-5.2.1/
# sudo apt-get install g++
# ./configure --use-static-gcc --enable-static --with-cc=gcc --with-cxx=g++
# make

# cd build/lib/obj/gcc/so_stlg

Then, you can find out library files.

2011年10月15日 星期六

[教學] 下載 Android Source (2.3)


kernel.org hacked workaround 下載 source 方法:

安裝 Cygwin:

套件要裝
git
git-completion
git-gui
gitk
git-oodiff
libiconv
python
readline (libreadline5libreadline6libreadline7)
wget

之後的流程:

執行 Cygwin
mkdir ./bin

由於 kernel.org hacked,改用下面的方法抓 repo
(原本官方的方法:curl http://android.git.kernel.org/repo > ~/bin/repo)

chmod a+x ./bin/repo
export PATH=~/bin:$PATH
.bash_profile 加入 export PATH=~/bin:$PATH

mkdir gingerbread
cd gingerbread 

下載 2.2
repo init -u git://codeaurora.org/platform/manifest.git -b froyo
(原本官方的方法:repo init -u git://android.gt.kernel.org/platform/manifest.git -b froyo)

下載 2.3
repo init -u git://codeaurora.org/platform/manifest.git -b gingerbread
(原本官方的方法:repo init -u git://android.kernel.org/platform/manifest.git -b gingerbread)
repo sync


Android 的版本代號
1.5
cupcake
1.6
donut
2.0/2.1
eclair
2.2
froyo
2.3
gingerbread


如果出現下面的錯誤

$ repo init -u git://android.gt.kernel.org/platform/manifest.git -b ginerbread
      0 [main] python 3232 C:\cygwin\bin\python.exe: *** fatal error - unable to
ent: 0x3A0000 != 0x3D0000
Stack trace:
Frame     Function  Args
0028A6A8  6102796B  (0028A6A8, 00000000, 00000000, 7594D3FB)
0028A998  6102796B  (6117EC60, 00008000, 00000000, 61180977)
0028B9C8  61004F1B  (611A7FAC, 6124D78C, 003A0000, 003D0000)
End of stack trace
      0 [main] python 8048 fork: child 3232 - died waiting for dll loading, errno 11
Traceback (most recent call last):
  File "/home/Joybo/bin/repo", line 685, in <module>
    main(sys.argv[1:])
  File "/home/Joybo/bin/repo", line 652, in main
    _Init(args)
  File "/home/Joybo/bin/repo", line 184, in _Init
    _CheckGitVersion()
  File "/home/Joybo/bin/repo", line 209, in _CheckGitVersion
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
  File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
    errread, errwrite)
  File "/usr/lib/python2.6/subprocess.py", line 1049, in _execute_child
    self.pid = os.fork()
OSError: [Errno 11] Resource temporarily unavailable

解決方法:
cd c:\cygwin\bin
修改 rebaseall 的第 110 行
sed -e '/cygwin1\.dll$/d' -e '/cyglsa.*\.dll$/d' -e 's/^/\//' >"$TmpFile"
改成
sed -e '/cygwin1\.dll$/d' -e '/cyglsa.*\.dll$/d' -e 's/^/\//' -e '/\/sys-root\/mingw\/bin/d' >"$TmpFile"
然後執行
ash /usr/bin/rebaseall




2011年6月18日 星期六

INFO: Design Issues When Using IOCP in a Winsock Server

Link: http://support.microsoft.com/kb/192800


INFO: Design Issues When Using IOCP in a Winsock Server

  • Summary
    This article assumes you already understand the I/O model of the Windows NT I/O Completion Port (IOCP) and are familiar with the related APIs. If you want to learn IOCP, please see Advanced Windows (3rd edition) by Jeffery Richter, chapter 15 Device I/O for an excellent discussion on IOCP implementation and the APIs you need to use it. 

    An IOCP provides a model for developing very high performance and very scalable server programs. Direct IOCP support was added to Winsock2 and is fully implemented on the Windows NT platform. However, IOCP is the hardest to understand and implement among all Windows NT I/O models. To help you design a better socket server using IOCP, a number of tips are provided in this article.
  • More Information
    TIP 1: Use Winsock2 IOCP-capable functions, such as WSASend and WSARecv, over Win32 file I/O functions, such as WriteFile and ReadFile. 

    Socket handles from Microsoft-based protocol providers are IFS handles so you can use Win32 file I/O calls with the handle. However, the interactions between the provider and file system involve many kernel/user mode transition, thread context switches, and parameter marshals that result in a significant performance penalty. You should use only Winsock2 IOCP- capable functions with IOCP. 

    The additional parameter marshals and mode transitions in ReadFile and WriteFile only occur if the provider does not have XP1_IFS_HANDLES bit set in dwServiceFlags1 of its WSAPROTOCOL_INFO structure. 

    NOTE: These providers have an unavoidable additional mode transition, even in the case of WSASend and WSARecv, although ReadFile and WriteFile will have more of them. 

    TIP 2: Choose the number of the concurrent worker threads allowed and the total number of the worker threads to spawn. 

    The number of worker threads and the number of concurrent threads that the IOCP uses are not the same thing. You can decide to have a maximum of 2 concurrent threads used by the IOCP and a pool of 10 worker threads. You have a pool of worker threads greater than or equal to the number of concurrent threads used by the IOCP so that a worker thread handling a dequeued completion packet can call one of the Win32 "wait" functions without delaying the handling of other queued I/O packets. 

    If there are completion packets waiting to be dequeued, the system will wake up another worker thread. Eventually, the first thread satisfies it's Wait and it can be run again. When this happens, the number of the threads that can be run is higher than the concurrency allowed on the IOCP (for example, NumberOfConcurrentThreads). However, when next worker thread calls GetQueueCompletionStatus and enters wait status, the system does not wake it up. In other words, the system tries to keep your requested number of concurrent worker threads. 

    Typically, you only need one concurrent worker thread per CPU for IOCP. To do this, enter 0 for NumberOfConcurrentThreads in the CreateIoCompletionPort call when you first create the IOCP. 

    TIP 3: Associate a posted I/O operation with a dequeued completion packet. 

    GetQueuedCompletionStatus returns a completion key and an overlapped structure for the I/O when dequeuing a completion packet. You should use these two structures to return per handle and per I/O operation information, respectively. You can use your socket handle as the completion key when you register the socket with the IOCP to provide per handle information. To provide per I/O operation "extend" the overlapped structure to contain your application-specific I/O-state information. Also, make sure you provide a unique overlapped structure for each overlapped I/O. When an I/O completes, the same pointer to the overlapped I/O structure is returned. 

    TIP 4: I/O completion packet queuing behavior. 

    The order in which I/O completion packets are queued in the IOCP is not necessarily the same order the Winsock2 I/O calls were made. Additionally, if a Winsock2 I/O call returns SUCCESS or IO_PENDING, it is guaranteed that a completion packet will be queued to the IOCP when the I/O completes, regardless of whether the socket handle is closed. After you close a socket handle, future calls to WSASend, WSASendTo, WSARecv, or WSARecvFrom will fail with a return code other than SUCCESS or IO_PENDING, which will not generate a completion packet. The status of the completion packet retrieved by GetQueuedCompletionStatus for I/O previously posted could indicate a failure in this case. 

    If you delete the IOCP itself, no more I/O can be posted to the IOCP because the IOCP handle itself is invalid. However, the system's underlying IOCP kernel structures do not go away until all successfully posted I/Os are completed. 

    TIP 5: IOCP cleanup. 

    The most important thing to remember when performing ICOP cleanup is the same when using overlapped I/O: do not free an overlapped structure if the I/O for it has not yet completed. The HasOverlappedIoCompleted macro allows you to detect if an I/O has completed from its overlapped structure. 

    There are typically two scenarios for shutting down a server. In the first scenario, you do not care about the completion status of outstanding I/Os and you just want to shut down as fast as you can. In the second scenario, you want to shut down the server, but you do need to know the completion status of each outstanding I/O. 

    In the first scenario, you can call PostQueueCompletionStatus (N times, where N is the number of worker threads) to post a special completion packet that informs the worker thread to exit immediately, close all socket handles and their associated overlapped structures, and then close the completion port. Again, make sure you use HasOverlappedIoCompleted to check the completion status of an overlapped structure before you free it. If a socket is closed, all outstanding I/O on the socket eventually complete quickly. 

    In the second scenario, you can delay exiting worker threads so that all completion packets can be properly dequeued. You can start by closing all socket handles and the IOCP. However, you need to maintain a count of the number of outstanding I/Os so that your worker thread can know when it is safe to exit the thread. The performance penalty of having a global I/O counter protected with a critical section for an IOCP server is not as bad as might be expected because the active worker thread does not switch out if there are more completion packets waiting in the queue.

2011年6月11日 星期六

Build SWIG on Windows


Build SWIG on Windows
相關檔案下載 Link: http://sourceforge.net/projects/mingw/files/

1. 下載 MinGW、MSYS (直接下載 mingw-get-inst-20110530.exe 並選 MinGW 和 MSYS)
   安裝至 C:\MinGW
          C:\MinGW\msys\1.0
       
2. 下載 automake-1.11.1-1-msys-1.0.13-bin.tar
        autoconf-2.67-1-msys-1.0.15-bin.tar
        bison-2.4.2-1-msys-1.0.13-bin.tar
   將這三個檔案表複製到 C:\MinGW\msys\1.0,並直接解壓縮
 
3. 執行 C:\MinGW\msys\1.0\msys.bat
mkdir /usr/src
cd /usr/src
svn co https://swig.svn.sourceforge.net/svnroot/swig/trunk swig

4. Build SWIG
cd /usr/src/swig
./autogen.sh
./configure --without-pcre
make

之後就會產生 swig.exe

5. 若要使用 swig.exe 有兩種方法:
第一種:透過 C:\MinGW\msys\1.0\msys.bat 執行
第二種:環境變數 Path 設定 C:\MinGW\bin

2010年10月3日 星期日

[轉載][文章] 善於表達 懂得反擊

作者: spinpop (大晴天) 看板: share
標題: [文章] 善於表達 懂得反擊
時間: Sat Aug 28 21:13:06 2010


現代人生活富裕了,教育程度也比較高,也漸漸開始懂得爭取自己的權益,


當然在爭取權利之前提,就是要知道是誰佔了你便宜,你覺得不舒服所以才要據理力爭。


覺得我們中國人不知道是怕麻煩還是覺得吃虧就是佔便宜是種美德,


遇見不公平時總是想:啊!算了,搞不好說了別人覺得我討厭,


或是怕大家目光集中在他身上而放棄為自己伸張正義,


結果事情也不會變得更好,不懂爭取的人,只會讓自己更委屈,而且沒有人會同情你。


像我有一個朋友有一次在公車上被一個色狼摸了屁股,


我朋友瞪了他一眼,那個色狼還若無其事地回看他,


如果是妳,妳會怎麼做呢?


大聲說出來?怕大家看妳?不說話?結果就像我那位朋友一樣,氣了好幾天。


有一次我在台中一家飯店點了一客豬排,結果送上來時是一塊疑似隔夜的炸豬排,


企圖用很多黑胡椒醬來掩飾,咬下去裡面還是涼的,


我覺得蠻生氣的,一客600元的食物,這樣是有欺騙之嫌,


正想找經理理論,我朋友說:「誰叫你要點這個,算妳倒楣。」


那我就忍了下來,


結果等我點的咖啡上來,竟然是三合一的即溶咖啡,


我想至少我要向這家店表達我的不滿,


我同桌的三位朋友竟然一起對我說:「妳真的很麻煩耶!」


這次經驗讓我蠻傷心,也讓我有點混淆,難道自認倒楣真的比較好嗎?


外國人就不一樣了,他們勇於表達,而且懂得反擊。


有一次我跟外國朋友約在義大利碰面,我坐的是義航,


等我到了羅馬機場,行李卻找不到,問櫃臺,說不知道而且態度惡劣。


弄了大半天,櫃臺才告訴我因為某些原因,所以行李明天才會到,要我明天再來領。


所以我在沒有任何換洗衣服的情況下在旅館度過一夜。


第二天一早再趕到機場,只看見我那一班飛機的行李被堆在機場一角,


有很多人包括我的行李被翻開過,現場一片狼籍,


而義航沒有任何人在現場指揮或表示歉意,


當然我也是一副可憐相的提著我的行李,氣歸氣,也只是在嘴裡碎碎念。


你知道我的外國友人為我做了什麼嗎?


他先把我的行李拿去車上,然後到櫃臺告訴他們行李找不到,於是我得到了200元美金
的補償費,


我這時反倒覺得心虛,問他會不會太過份了,


我朋友說還不夠,他到了義航的辦公室指控他們這一次的失責,


這些職員們當然是互相推卸責任,一問三不知,


因為我們沒有許多時間耗在這裡,


於是在我們旅途中的每站旅館,我朋友就FAX一封英打信函,表達他非常不高興,


有必要的話,他會控訴這家失職而又不肯善後的高姿態航空公司,


雖然他只是一個小小的報社記者……(當然這是騙人的)。


等我們回到羅馬,義航的經理很主動地跟我們聯絡,


而且為了表達歉意,還送了我一張羅馬到香港的來回機票,


我朋友說,一個人旅行是很寂寞的,你應該給二張才對!


於是我拿到了二張羅馬到香港的免費來回機票。


有時我猜如果跟我同行的朋友跟我一樣是中國人,或許這件事就這樣過去了,


我們旅行了、回來了,罵罵他們,而義航也不會覺得自己有任何不妥。


但我朋友選擇了據理力爭,雖然花了很多時間跟力氣,但是最後得到對方道歉與尊重(還
有補償),


那感覺卻是很好的。

--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.127.73.61
 [1;37m推  [33mkgi          [m [33m:推~                                                [m 08/29 09:54