Friday, 8 February 2008

Tkinter layout/alignment control

The following example uses packer management for the Tkinter layout.

Reference: http://docs.python.org/lib/node695.html


from Tkinter import *

root=Tk()

b3=Button(root, text='click me!!')
b3.pack(padx=10,pady=5)

b1=Button(root, text='click me',padx=10,pady=5)
b1.pack(side = "left")

b2=Button(root, text='click me',padx=10,pady=5)
b2.pack(side = 'right',expand = 1)

b4=Button(root, text='click me',padx=10,pady=5)
b4.pack()


root.mainloop()




Powered by ScribeFire.

Tuesday, 5 February 2008

VMware command

For VMware server, a free version of VMware family. It can run as a server, on which most of the OS can run well.

P.S.:
1. Preconfigure is essential, especially, VMware server is updated, you should run [vmware-config.pl] to reconfigure it.
2. Using vmware-cmd, you must provide the full path.

Now here is how it works.
1. With SSH, user can connect to that server.
2. vmware-cmd /the/full/path/of/vmx getstate
vmware-cmd /the/full/path/of/vmx start
When you first time run this command with such option- start, it will prompt you with such an error:
VMControl error -16: Virtual machine requires user input to continue.
To solve it, run this command to input your option:
vmware-cmd /the/full/path/of/vmx answer

vmware-cmd /the/full/path/of/vmx stop

Monday, 4 February 2008

vi configuration

~/.vimrc
is the place to store vi start options.

put such command in it:
syn on

This is used to turn on Syntax function, namely syntax color highlight.

vi shortcuts: autocomplete

Topics on this page in alphabetic order



Why use vi?

When I first tried using vi I thought that you could not have a more obscure and difficult-to-use text editor, but I found that after memorising half-a-dozen commands that it was really quite simple to use. And, quite powerful. For example, you can do something like "find all lines with 'swordfish' in them, and for those lines only, change 'cat' to 'dog'". Try doing that with your normal editor!

The other reason is you can usually find vi on almost any Unix installation. If you get used to "my favourite editor" - whatever that is - and connect to a different site for troubleshooting, you may well find it is not installed, or only runs under Xwindows, or some other such restriction.

Further, you can do quite fancy things (see below) like do a "make" from inside vi, and then with a single keystroke go to each error message (even in different files), with the cursor being placed on the line in error, so you can fix it. This is quite a time-saver. Similarly with doing "grep" on a group of files.


The basics

If you start doing something and change your mind you can generally press Ctrl+C to cancel it.

Edit a file, look at it, stop editing

Edit a file from command prompt vi
Edit a file from command prompt for reading only vi -R
Edit a file from within vi :e
Edit a new file from within vi, discard changes to current file :e!
Reload current file, discarding changes :e!
Go forwards a page Ctrl+F (or PgDn)
Go backwards a page Ctrl+B (or PgUp)
Move around single lines or characters Arrow keys
Save changes :w
Save changes and override protected (read-only) files :w!
Save changes and exit vi ZZ
Quit :q
Quit and discard changes :q!
Get general help :help
Get help on a command (eg. :set) :help set

Notes

  1. Whether keys like PgUp and PgDn work will depend on your keymappings. I find recently that they tend to work without needing to make any changes. In some cases you may need to type "vim (file)" at the command prompt rather than "vi (file)" if both are installed. Otherwise you may set up an alias (at your shell prompt) to equate vi to vim.
  2. Any command starting with these characters:
    • : (colon) - starts a command sequence
    • / (slash) - starts a forwards search
    • ? (question mark) - starts a backwards search
    needs you to press to execute them. Until you have done that you can backspace and make corrections.

    These commands are echoed on the bottom line of the screen, so you can see what you are typing. If you have started typing one of those, you see the command being echoed, and change your mind, press Ctrl+C to cancel the command.

Simple example

Let's edit comm.c and then exit ...


vi -R comm.c
(PgDn to look at file)
:q

If you are experimenting then it might be wise to either edit a file you don't care about (eg. a copy) or use the -R option (read-only).

Alternatively, set read-only mode once you have edited the file:

Set read-only mode :set ro

Go to lines, find matching text

Go to line 1234 (do not see typing) 1234G
Go to line 1234 (see typing) :1234
Go to start of file 1G
Go to end of file G
Find (forwards) a line containing "swordfish" /swordfish
Find (forwards) a line using a regular expression /you see .* here
Repeat last search n
Repeat last search in opposite direction N
Find (backwards) a line containing "swordfish" ?swordfish
Find (backwards) a line using a regular expression ?you see .* here
Search case insensitive (Ignore Case) :set ic
Search with case sensitivity :set noic
Wrap searches back to start of file :set wrapscan
Do not wrap searches :set nowrapscan

Notes - these are probably the most frequent things I do. 'Go to line number', especially if you have a compiler error which gives a line number is very handy. Type the line number directly followed by "G", and you are taken there. Or, if you don't know the line, type "/" followed by a word or regular expression you are looking for. The second way of going to a line number (:1234) is probably easier to use because you can see the number as you type it. If you type "1234G" the number (1234) is not echoed to the screen as you type.

Highlighting - searching with "/" or "?" normally highlights the found word. Sometimes this can be quite annoying, especially if you have searched for something which occurs frequently, like a space. You can turn this off:


:hi clear search

Case-sensitivity - using ":set ic" lets you search with or without matching the exact case of the word you are searching for (eg. if you search for "dog" do you want to match "DOG"?).

Simple example

Let's edit comm.c and go to line 5522. Then find "const".


vi comm.c
:5522
/const
:q

Line numbers

Sometimes it is handy to know what line you are at, or what each line number is.

Show line numbers on the left :set nu
Do not show line numbers on the left :set nonu
Show the current line number :.=
Show total lines in file :=
Show file name, total lines, and current line number Ctrl+G
Show line number of first matching pattern :/pattern/=

Notes - showing lines numbers is particularly useful when you are relating things like error messages (or instructions) to a line number. Also the Ctrl+G trick is useful to remind yourself of what file you are editing.

Simple example

Let's edit comm.c, show line numbers, find the first line with "const" in it (line 70) and go to it:


vi comm.c
:set nu
:/const/=
:70
:q

Changing text

OK, we can move around the file and find things. Let's start changing stuff ...

Undoing things

When you start going into "change things" mode you will probably need to undo your mistakes. Two useful commands:

Undo last change u
Undo all changes on current line U

If things get out of hand, remember:

Quit editor without saving changes :q!
Reload current file, discarding changes :e!

Insert text

All of the changing commands (except "replace next character") go into "insert mode" (usually shown by "-- INSERT --" or "-- REPLACE --" at the bottom of the screen). To exit from Insert Mode, press the Esc key.

Insert after cursor i
Insert before cursor a
Insert at beginning of line I
Insert at end of line (append) A
Open (start) new line below cursor o
Open (start) new line above cursor O

The last two are the letter "oh" not a zero. I use the "O" and "o" commands quite a bit to start entering a new line above or below where the cursor currently is.

Change existing text

Replace next character r
Type over following characters R
Replace to end of line C

Note - the "r" command is useful if you just want to make a minor correction (eg. change "A" to "B"). This does not go into Insert Mode, so you don't need to then cancel Insert Mode. To change the character under the cursor to a "B" you would just type "rB".

Delete text

Delete character under cursor x
Delete character to left of cursor X
Delete to end of line D
Delete entire line dd

These are your basic deletion commands. "x" to scrub out the character under the cursor, "dd" to delete the entire line.

Advanced deletion

Delete next 5 lines 5dd
Delete to end of line d$
Delete to start of line d0
Delete to word "swordfish" d/swordfish
Delete to the letter "x" dfx
Delete lines 10 to 20 :10,20d
Delete current line and another 5 lines :.,+5d
Delete all lines :%d
Delete current word dw
Find line containing pattern, delete it :/pattern/d
Find line containing "dog", delete until line containing "cat" :/dog/,/cat/d
Delete from current line to line containing "foo" :.,/foo/d

Copying, cutting and pasting

If you delete some text using the deletion commands described above you have "cut" the text. However it is saved in an internal buffer and can be pasted somewhere else. Simply move the cursor to where you want it and:

Paste after cursor p
Paste before cursor P

vi calls copying "yanking", and thus uses the letter Y.

To copy text without deleting it you need to "yank" it. The yank commands are similar to the deletion commands, like this:

Yank to end of line y$
Yank to start of line y0
Yank to word "swordfish" y/swordfish
Yank to letter "g" yfg
Yank entire line Y
Yank lines 5 to 10 5,10y

After yanking you can paste as described above (or there is no point to yanking in the first place).


Advanced movement commands

Go forwards a word w
Go backwards a word b
Go to end of word e
Go to start of line 0
Go to end of line $
Go to top of screen H
Go to middle of screen M
Go to bottom of screen L
Go (forwards) to letter "x" on current line fx
Go (backwards) to letter "x" on current line Fx
Go to next occurrence of word under cursor *
Go to previous occurrence of word under cursor #
Find a control character (eg. Tab) /(Ctrl+V)(Tab)
Go backwards a sentence (
Go forwards a sentence )
Go backwards a paragraph {
Go forwards a paragraph }

The command "go to start of line" is a zero, not an "oh". You can use Ctrl+V in insert or command mode to literally insert the next character.


Repeat counts

Most commands have a "repeat count" that you can optionally type first. To do a repeat count just type the number before the command. It will not be echoed, so type carefully!

For example:

Delete 5 lines 5dd
Delete 5 characters 5x
Delete 5 words 5dw
Replace next 5 characters 5r
Yank (copy) next 7 lines 7Y
Go to line 1000 1000G
Paste copy buffer 10 times 10p
Insert 40 hyphens 40i-
Insert the line "swordfish" 10 times 10oswordfish
Find the 5th occurrence of "swordfish" 5/swordfish

In the above examples means press the Esc key.


Splitting and joining lines

Split a line (insert a return) i
Join two lines (current and next) J
Join next 10 lines 10J
Join lines 10 to 20 :10,20j

Splitting is basically breaking a line into two by inserting a newline. Joining is reversing that process by removing the newline.


Search and replace

Change "nick" to "fred" on current line :s/nick/fred/
Change "nick" to "fred" on the next 5 lines :.,+4 s/nick/fred/
Change "nick" to "fred" on lines 100 to 200, all occurrences :100,200 s/nick/fred/g
Capitalise every word in the entire file :% s/\<./\u&/g
Insert ">" at the start of every line :% s/^/>/
Insert "// nick" at the end of every line :% s;$;// nick;

Special characters for line sequences:

  • . is the current line
  • $ is the last line
  • % is every line
  • +5 means 5 lines from current line
  • -5 means 5 lines before current line

Applying commands to certain lines

You can use the ":g" (global) command to find matching lines (using a regular expression) and then apply a command to those lines. For example:

Find lines containing "fruit" and change "apple" to "orange" on them :g/fruit/s/apple/orange/g
Delete all blank lines :g/^$/d
Find lines NOT containing "nick", append "oops" to them :g! /nick/normal A oops

The third example above shows you you can use the "normal" command inside a command, to tell vi to use a normal character (in this case A for append) as part of a command.


Shell and filter commands

List directory :! ls
See processes :! ps
Sort lines 20 to 30 :20,30 ! sort
Sort entire file !G sort
Translate next sentence to upper case !) tr '[a-z]' '[A-Z]'
Word count file (save first) :!wc %
Look up manual entry for strstr :!man strstr
Insert "ls" command output into window :r !ls

Tags

Tags let you go to the definition of a function (in C or C++) without having to scan lots of source files (with grep) and work out which ones contain the function and which merely refer to it.

First, make a tag file, like this:


ctags *.c *.cpp *.h

(In recent versions of Linux I have had to use gctags instead of ctags).

This should produce a file "tags" in the current directory.

Now you can go straight to a function, without knowing which file it is in, like this:


vi -t game_loop

Once inside vi you can put the cursor on a word and go to its definition:

Go to function under cursor Ctrl+]
Go back Ctrl+T
Go to function xyz :tag xyz

Automating things

Compiling from within vi and going to errors

You can save your changes, run "make" to compile, and view errors, very easily ...

Save file :w
Run "make" :make
Go to next error :cn
Go to previous error :cp

This is fabulously powerful. It lets you skim through all your errors, with vi opening the right file and positioning the cursor on the line in error.

See below for how to map actions (like ":cn") to function keys to speed up the process.

Mapping actions to function keys

Map the action :cnext to :map :cnext
Map the action :cprevious to :map :cprevious
Map the action :make to :map :make
Map the action :close to :map :close

After entering the above commands you could compile by simply hitting F8, then look at each error by hitting F6.


More useful tips for programmers

Go to definition of word under cursor gd
Go to global definition gD
Find matching bracket, brace, #if, #endif %
Do a grep :grep foo *.c
After grep, go to next occurrence :cn
Get a file (eg. an #include file) whose name is under cursor gf
Auto complete (in insert mode) - match forwards Ctrl+X Ctrl+N
Auto complete (in insert mode) - match previous Ctrl+X Ctrl+P
Make an abbreviation (eg. cca = "const char *") :ab cca const char *
Turn syntax colouring on :syntax on
Turn syntax colouring off :syntax off
Execute any shell command :! command
Indent selected lines with C-style indenting =

For formatting of C code there are also other options you can use like "autoindent", "smartindent", "cindent", and "indentexpr". (Use :help (topic) to see more about those options). You can turn these on (eg. :set cindent) to automatically indent your coding as you type. Also, in conjunction with syntax colouring, you can see if you have made a syntax error (eg. not closed a quote, left off a bracket), as the syntax colouring algorithm will highlight in red sequences that do not seem correct.


Spellcheck file

Save file first :w!
Spell check it :! ispell %
Edit fixed file :e %

Tab management

Tabs can be annoying in source files, as they do not necessarily line up when you use different value tab stops. You can manage them in vi like this:

Set tabs to every 4 characters :set ts=4
Convert tabs to spaces in future :set et
Do not expand tabs :set noet
Fix existing tabs (convert to spaces) :%retab
Show tabs visually, and end-of-lines :set list
Do not show tabs and end-of-lines :set nolist

Visual mode

vi can be a bit difficult to follow when you are trying to do something to a block of lines (for example, do I want line 8843 through to 8903 or 8904?), so vim has a "visual mode" where you can actually see lines highlighted in inverse.

First, "mark" a block of lines (or characters) by going to the start of the block, and then using one of the following:

Character mode v
Line mode V
Block mode Ctrl+V
Re-mark previous block gv

The differences are:

  • Character mode - from somewhere inside one line to somewhere inside another (ie. can be a part line)
  • Line mode - will be whole lines
  • Block mode - from (say) column 5 at line 10, to column 60 in line 20 (a square block of text)

Then use the cursor movement commands (search, arrow, go to line, whatever) to mark the other end of the block, and either:

Do some command (see below)
Cancel visual mode Esc
Go to other end of block o

Other ways of establishing a visual block

A word (with white space) vaw
Inner word viw
A WORD (with white space) vaW
Inner WORD viW
A sentence (with white space) vas
Inner sentence vis
A paragraph (with white space) vap
Inner paragraph vip
A ( ... ) block (includes brackets) vab
Inner ( ... ) block vib
A { ... } block (includes braces) vaB
Inner { ... } block viB

A "word" is a sequence of letters, numbers, underscores. A "WORD" is a sequence that is terminated by spaces. The difference would apply in cases like a(b) - if the cursor is on "a" a "word" is "a" however a "WORD" is "a(b)".

Here is an example, from C source code. Say you have the following code, and you want to select the code inside the inner { ... } characters. Put the cursor in the middle (eg. on CON_EDITING) and type "viB" and the "inner block" (text in bold) will be highlighted.


if ( d->pagepoint )
{
if ( !pager_output(d) )
{
if ( d->character
&& ( d->connected == CON_PLAYING
|| d->connected == CON_EDITING ) )
save_char_obj( d->character );
d->outtop = 0;
close_socket(d, FALSE);

}
}

Here is another method of selecting a visual block of C code. Say we have the following code and we want to highlight everything inside the "while" loop. Put the cursor on the first "{" and type "v%". That will go into visual mode and move to the end of the block. The highlighted code will be in bold.


while ( usecDelta >= 1000000 )
{
usecDelta -= 1000000;
secDelta += 1;
}

Visual mode commands

See below for meanings of notes in brackets.

Switch case ~
Delete d
Change (4) c
Yank y
Shift right (4) >
Shift left (4) <
Filter through external command (1) !
Filter through 'equalprg' option command (1) =
Format lines to 'textwidth' length (1) gq

You can also do the following on the selected block:

Start ex command for highlighted lines (1) :
Change (4) r
Change s
Change (2)(4) C
Change (2) S
Change (2) R
Delete x
Delete (3) D
Delete (2) X
Yank (2) Y
Join (1) J
Make uppercase U
Make lowercase u
Find tag Ctrl+]
Block insert I
Block append A

Notes

  1. Always whole lines
  2. Whole lines when not using CTRL-V.
  3. Whole lines when not using CTRL-V, delete until the end of the line when using CTRL-V.
  4. When using CTRL-V operates on the block only.

An example of visual mode?

OK, let's say we have a visual block highlighted. Try these:

Delete it d
Copy it Y
Change "apple" to "orange" in the block :s/apple/orange/g
Turn into C++ comments :s.^.//.
Turn into C comments :s-^.*$-/* & */-

Marking your work

If you need to jump backwards and forwards between a couple of places you can "mark" them ...

Mark current position as "x" mx
Go to position "x" `x
Show list of known marks :marks

That character before the "x" is a back-quote - on my keyboard on the top-left corner, under the tilde (~) symbol. Marks can be in a different file to the current one.


Recording commands

Finally, let's do an example of recording commands for repeating later.

Record a sequence q(letter)(commands)q
Play back sequence @(letter)
See what is in registers :reg

You record a sequence into a lower-case register (a-z), eg.


qa:s/fish/chips/q

The command above (starting and ending with "q") records into register "a" the sequence ":s/fish/chips/".

Then whenever you want to repeat that command you can type "@a".

Example of recording

Whilst writing this page I wanted to convert every second sequence of:


(something)

to:

(something)

Doing a "find and replace" would have been tedious, as I would have had to skip every second item found. I was able to do it quite quickly by recording a macro. To do this I typed:

qa
2/
:s///
:s$$
$
$
q

The sequence above did the following:

  1. Start recording (q) under register "a"
  2. Search for the second occurence of (hence the leading "2" on the line)
  3. Change "" to ""
  4. On the same line change "" to "
  5. ". I used a $ as the search delimiter because the character "/" was in the text to be searched for.
  6. Go to the end of the current line ($) so the next search would begin at the next
  7. Stop recording (q)

Then I moved to the start of the file (1G), turned search wrapping off (:set nowrapscan) and typed "999@a". This executed macro "a" 999 times. In fact, it stopped before 999 times because the search failed after it got to the end of file.


Setting up your personal favourite settings

If you have some personal favourite settings like:

  • Spaces for tabs
  • Whether searches are highlighted or not
  • Syntax colouring on or off
  • Mapping function keys to special functions

you can have them processed automatically by putting them into a file named ".vimrc" in your home directory (see ":help vimrc" inside vim for more details).

For example, your .vimrc file might have in it:


set ts=4 " tab stops every 4 characters
set expandtab " tabs to spaces

map :cnext " next error after a make or grep
map :cprevious " previous error
map :close " close current window (eg. help)

syntax on " syntax colouring on

hi clear search " do not highlight searched-for words


From: http://www.gammon.com.au/smaug/vi.htm

Saturday, 2 February 2008

howto use /usr/local/

Normally when I partition my hard disk for installation of Linux. I will make it like this:
1. 1.5G Swap
2. 10G /
3. 20G /home
4. <10G /usr/local/


/usr/local and its subdirectories are used for the installation of software and other files for use on the local machine. What this really means is that software that is not part of the official distribution (which usually goes in /usr/bin) goes here.


/usr/local/ is the item when I try to keep some partitions not to be formatted, the system prompted me, says some partitions must be formatted, such as /, while some like /home, /usr/local can be kept unformatted. From this on, I leave a partition of /usr/local there. More and more I realized that how to use it: 1. When you "make" program form src, most of the geeks use such a command: sudo ./configure [--prefix=/usr/loca/xxx ......]
This means the programs compiled by you will be kept here, no matter whether you reinstall your system or not, it will always be there. Comparisons with program from .deb, which brings standard destinations and parameters when you install it.
2. /usr/local/bin, where can be a place you put all your favorite "links" here.
3. Some huge programs with licenses, such as Matlab, which just need be installed once, can be stored here. /home can be the places for your documents, while /usl/local is for your programs. (And I found if Matlab is installed in /opt, some java classes compiled by yourself for Matlab will not run correctly, for example, I ever made a java class to be called by Matlab to get configurations from .conf files, when I reinstalled Matlab from /opt to /usr/local, it works correctly, quite weird.)

Friday, 1 February 2008

坏硬盘分区

一、用软件来解决


1.在天极网Ftp://ftp1.mydown.com/home1/soft34/fbdisk10.zip下载一个大小仅19.8KB的小软件
FBDISK(坏盘分区器)。它可将有坏磁道的硬盘自动重新分区,将坏磁道设为隐藏分区。在DOS下运行FBDISK,屏幕提示Start scan
hard disk?(Y/N),输入Y,开始扫描硬盘,并将坏道标出来,接着提示Write to disk?(Y/N),选Y。坏道就会被隔离。


2.用PartitionMagic对硬盘进行处理。先用PartitionMagic中的“Check”命令来扫描磁盘,大概找出坏簇所在的硬盘分区,
然后在Operations菜单下选择“Advanced/bad Sector Retest”。再通过Hide
Partition菜单把坏簇所在的分区隐藏起来,这样就可以避免对这个区域进行读写。如果系统提示“TRACK 0 BAD,DISK
UNUSABLE”,那么说明硬盘的零磁道出现坏道。这需要通过Pctools9.0等磁盘软件,把0扇区0磁道屏蔽起来,最后用1扇区取代它就能修复。



以Pctools9.0为例,运行Pctools9.0中的de.exe文件,接着选主菜单Select中的Drive,进去后在Drive
type项选Physical,按空格选中它,再按Tab键切换到Drives项,选中hard
disk,然后回到主菜单,打开Select菜单,在出现的Partition
Table中,选中硬盘分区表信息。找到C盘,该分区是从硬盘的0柱面开始的,那么,将1分区的Beginning
Cylinder的0改成1,保存后退出。重新启动后再重新分区、格式化即可 二、重新分区再隐藏

用Windows系统自带的Fdisk。如果硬盘存在物理坏道,通过Scandisk和Norton Disk
Doctor我们就可以估计出坏道大致所处位置,然后利用Fdisk分区时为这些坏道分别单独划出逻辑分区,所有分区步骤完成后再把含有坏道的逻辑分区删
除掉,余下的就是没有坏道的好盘了。





方法一:如一块4.3G硬盘在2G处有严重的物理坏道,用Format格式化进行不下去,Scandisk或NDD检测也通不过,但能正常分区。找来一款分区格式化软件Smart Fdisk,用启动盘启动电脑后,进入盘符A:,运行该软件的执行文件SFdisk.EXE;然后删掉(DEL)原有分区,算出坏道在硬盘上的所在位置。如本例中,先建立1990M的基本分区,快速格式化后并激活它,然后再把坏道处分出约50M的逻辑分区,再将所剩的硬盘空间作为一个逻辑区后用快速格式化功能将其快速格式化;最后再将那个约50M的坏道所在的区删除(DEL)掉就是了。然后重启,一个有严重物理坏道的硬盘就很快被修好了,以后磁头再也不会去读那些被删除了的坏道区了。



方法二:用Windows系统自带的Fdisk分区。例如一块1G的硬盘,在格式化到10%时不能顺利通过,这时按Ctrl+Break强行终止,运行 Fdisk建立一个90M的DOS分区为C盘,然后再建立一个20M逻辑盘D,再将余下的800余M建立一个逻辑盘E。退出Fdisk再运行Format E:,如果格到10%时又遇到阻碍,这时用Fdisk再建立一个88M的E盘、10M的F盘,余下的790M作为G盘。继续重复上面的操作,直到完成。然后,运行Fdisk将10M的D、F盘删除,这时余下的就是没有坏道的好盘了。



方法三:同理,用PartitionMagic、DiskManager等磁盘软件也可完成这样的工作。如PartitionMagic分区软件,先用 PartitionMagic4中的“check”命令或Windows中的磁盘扫描程序来扫描磁盘,算出坏簇在硬盘上的位置,然后在 Operations菜单下选择“Advanced/bad Sector Retest”;把坏簇所在硬盘分成多个区后,再把坏簇所在的分区隐藏,以免在Windows中误操作,这个功能是通过Hide Partition菜单项来实现的。这样也能保证有严重坏道的硬盘的正常使用,并免除系统频繁地去读写坏道从而扩展坏道的面积。



系统显示“TRACK 0 BAD,DISK UNUSABLE”,意思为“零磁道损坏,硬盘无法使用”或用磁盘扫描程序扫描其它硬盘时其0扇区出现红色“B”。硬盘0扇区损坏,是大家比较头痛的故障,一般人往往将出现这样故障的硬盘作报废处理。其实合理运用一些磁盘软件,把报废的0扇区屏蔽掉,而用1扇区取而代之就能起到起死回生的效果,这样的软件如Pctools9.0和NU8等。



方法一:我们就先以Pctools9.0为例来作说明。一块2.1G硬盘出现上述故障,用盘启动电脑后,运行Pctools9.0目录下的DE.EXE文件。接着选主菜单Select中的Drive,进去后在Drive type项选Physical,按空格选定,再按Tab键切换到Drives项,选中hard disk,然后OK回车后回到主菜单。打开Select菜单,这时会出现Partition Table,选中进入后出现硬盘分区表信息。该硬盘有两个分区,找到C区,该分区是从硬盘的0柱面开始的,那么,将1分区的Beginning Cylinder的0改成1就可以了,保存后退出。重新启动电脑后按Del键进入COMS设置,运行“IDE AUTO DETECT”,可以看到CYLS由782变成781。保存退出后重新分区格式化该硬盘,使其起死回生。



方法二:诺顿NU8.0也较好用。例如一块1.28G硬盘出现0磁道损坏故障,进入NU8工具包目录,运行其主程序NORTON.EXE,然后可先选“补救盘”RESCUE选项对该硬盘的引导区、分区表等信息进行备份。接着选择“磁盘编辑器DISKEDIT”,成功运行后选“对象OBJECT”,选“分区表”后可见本硬盘的参数如下:面SIDE为0-63,簇CYLINDER为0-255,扇区SECTOR为1-63,其主引导记录和分区表信息就应该在0 面0柱1扇区。我们要做的事就是把其C盘的起始扇区从0面0柱1扇区改为0面1柱1扇区,移动光标手工修改即可。另外需要说的就是,改动数值要根据具体情况而定。最后存盘后退出重启电脑,用Format命令格式化硬盘即可正常使用了。需要特别留意的是,修好后的硬盘一定不要再用DOS下的Fdisk等分区工具对其进行重新分区操作,以免其又改变硬盘的起始柱面。



Powered by ScribeFire.

Wednesday, 30 January 2008

keyboard shortcut reset

The following command list all the keyboard shortcuts under this category.
gconftool-2 --recursive-list /desktop/gnome

More options go to: http://www.gnome.org/learn/admin-guide/2.2/ch01s04.html

quote in Java

"3" is not a char literal. It uses double quotes, instead of single quotes. (Double quotes makes it a String which we'll discuss later).

'' is not a char literal. There isn't a character between the two single quotes. You need one character between the double quotes.

'ab' is not a char literal. There are two characters in between the single quotes. char literals only have one character in between.

Saturday, 26 January 2008

python workspace, a little bit global

a=100

def first():
b=a+1
c=a+2
return b,c

def second():
d=bb+11
e=cc+12
return d,e

class thirdC:
def fourth(self):
f=dd+101
g=ee+102
return f,g
def fifth():
h=ff+1001
i=gg+1002
(j,k)=second()
return h,i,j,k

if __name__=='__main__':
(bb,cc)=first()
(dd,ee)=second()
tc=thirdC()
(ff,gg)=tc.fourth()
(hh,ii,jj,kk)=fifth()

Friday, 25 January 2008

java Socket programming

DataInputStream和InputStreamReader都可以用一个InputStream类做为其参数,而且目的也是一样的,就是把字节级的读取转换为字符级的读取!


#### Basing on Byte stream
Socket Operations at Client Side
• create a client socket:
Socket (host, port)
s = new Socket (“java.sun.com”, 13)

• get input / output data streams out of the socket:
in = new DataInputStream(s.getInputStream ());
out = new DataOutputStream( s.getOutputStream());
out = new PrintStream( s.getOutputStream());

• read from input / write to output data streams:
String str = in.readLine();
out.println ( “Echo:” + str + “\r”);

• close the socket:
s.close();

Socket Operations at Server Side

A server is always waiting for being connected. It need not initiate a connection to a host. So a server socket need only specify its own port no.
• create a server socket:
ServerSocket (port)
ServerSocket s = new ServerSocket(8189);
• accept an incoming connection:
Socket snew = s.accept ();
• get input / output data streams out of the socket for the incoming client:
in = new DataInputStream(snew.getInputStream());
out = new PrintStream(snew.getOutputStream());
• close the socket for the incoming client:
snew.close();





#### Basing on Character strem
Socket Operations at Client Side
• create a client socket:
Socket echoSocket = new Socket(args[0],9999);
out = new PrintWriter(echoSocket.getOutputStream(),true);
in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
• read from input streams:

System.out.println("server: " + in.readLine());
• write to output streams:
String str = in.readLine();
out.println ( “Echo:” + str + “\r”);
• close the socket
echoSocket.close();


Socket Operations at Server Side
• create a client socket:
ServerSocket serviceSocket = new ServerSocket(9999);
r=new InputStreamReader(serviceSocket.getInputStream());
in=new BufferedReader(r);
out = new PrintWriter(serviceSocket.getOutputStream(),true);
• read from input streams:
String line=in.readLine()
System.out.println("Received from client "+line);
• write to output streams:

String str = in.readLine();
out.println("Server says: "+str);
• close the socket
serviceSocket.close();




Powered by ScribeFire.

Wednesday, 23 January 2008

HOWTO: listbox in Python Tkinter

alist=[' x ',' xin ','zhengxin',' shan ',' shanshan ','shanshan cheng ']
##aset=set(alist)
##b=set()
##
##for aitem in aset:
## if aitem.find('xi')!=-1:
## print aitem,':item will be removed'
## b.add(aitem)
##
##c=aset-b
##print aset
##print c

from Tkinter import *
class MyDialog:
def __init__(self,master):
MyDialog.removed=list()
Label(text="one").pack()
self.s = Frame()
self.s.pack()

self.listbox = Listbox(self.s,selectmode=EXTENDED)
self.listbox.pack()

for item in alist:
self.listbox.insert(END, item)

Label(text="two").pack()

self.b = Button(master, text="Delete",command = self.toremove)
## self.b = Button(master, text="Delete",command = lambda lb=lb: lb.delete(ANCHOR))
self.b.pack()

def toremove(self):
# Select what to remove and save them to the Class Variable MyDialog.removed
self.items = self.listbox.curselection()
for i in self.items:
MyDialog.removed.append(self.listbox.get(i))
print self.listbox.get(i)

# To sort the sequence,then reverse, then delete.
self.iitems=list()
for i in range(len(self.items)):
self.iitems.append(int(self.items[i]))
self.iitems.sort()
self.iitems.reverse()
for j in self.iitems:
self.listbox.delete(j)
## def toremove(self):
## self.listbox.delete(ANCHOR)


if __name__=='__main__':
root = Tk()
d = MyDialog(root)
root.mainloop()

HOWTO: lambda in Python

By popular demand, a few features commonly found in functional programming languages like Lisp have been added to Python. With the lambda keyword, small anonymous functions can be created. Here's a function that returns the sum of its two arguments: "lambda a, b: a+b". Lambda forms can be used wherever function objects are required. They are syntactically restricted to a single expression. Semantically, they are just syntactic sugar for a normal function definition. Like nested function definitions, lambda forms can reference variables from the containing scope:

>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43


lambda很灵活,可以用在任何需要函数的地方:

>>>def f(x):
… return x*2

>>> f(2)
4

定义一个函数f(x),f(x)=x*2. 用lambda来表达就是:

>>> f=lambda x: x*2
>>> f(2)
4

这个函数没有函数名,lambda的结果被赋值给变量f调用。

############################################
对于Tkinter,
可以直接用lambda直接设置一些简单callback:
b = Button(master, text="Delete",command = lambda listbox=listbox: listbox.delete(ANCHOR))
在这种情况下,需要设定返回值(listbox=),然后才是lambda的参数(listbox).

这种简写方式等效于:(如下code是在一个class内的代码)

self.b = Button(master, text="Delete",command = self.toremove)
##self.b = Button(master, text="Delete",command = lambda llb=lb: lb.delete(ANCHOR))
def toremove(self):
self.listbox.delete(ANCHOR)

Powered by ScribeFire.

Tuesday, 22 January 2008

Create class for GUI , Python

from Tkinter import *

class MyDialog:
def __init__(self, top):
Label(top, text="Value").pack()

self.e = Entry(top)
self.e.pack(padx=5)

b = Button(top, text="OK", command=self.ok)
b.pack(pady=5)

def ok(self):
print "value is", self.e.get()

root = Tk()
d = MyDialog(root)
root.mainloop()

Multiline Formulae in LaTeX and lyx

Cited from: http://www.maths.tcd.ie/~dwilkins/LaTeXPrimer/Multiline.html

Consider the problem of typesetting the formula

[GIF Image]
It is necessary to ensure that the = signs are aligned with one another. In LaTeX, such a formula is typeset using the eqnarray* environment. The above example was obtained by typing the lines
\begin{eqnarray*}
\cos 2\theta & = & \cos^2 \theta - \sin^2 \theta \\
& = & 2 \cos^2 \theta - 1.
\end{eqnarray*}
Note the use of the special character & as an alignment tab. When the formula is typeset, the part of the second line of the formula beginning with an occurrence of & will be placed immediately beneath that part of the first line of the formula which begins with the corresponding occurrence of &. Also \\ is used to separate the lines of the formula.

Although we have placed corresponding occurrences of & beneath one another in the above example, it is not necessary to do this in the input file. It was done in the above example merely to improve the appearance (and readability) of the input file.

The more complicated example

[GIF Image]
was obtained by typing
If $h \leq \frac{1}{2} |\zeta - z|$ then
\[ |\zeta - z - h| \geq \frac{1}{2} |\zeta - z|\]
and hence
\begin{eqnarray*}
\left| \frac{1}{\zeta - z - h} - \frac{1}{\zeta - z} \right|
& = & \left|
\frac{(\zeta - z) - (\zeta - z - h)}{(\zeta - z - h)(\zeta - z)}
\right| \\ & = &
\left| \frac{h}{(\zeta - z - h)(\zeta - z)} \right| \\
& \leq & \frac{2 |h|}{|\zeta - z|^2}.
\end{eqnarray*}

The asterisk in eqnarray* is put there to suppress the automatic equation numbering produced by LaTeX. If you wish for an automatically numbered multiline formula, you should use \begin{eqnarray} and \end{eqnarray}.


#############################################
For Lyx, in the menu of Insert > Math > Eqnarray Environment, here it's easy to input multiple-line equation.

Lyx: equation numbering ALT+M N

LATEX is at its best when handling mathematical equations. Using LyX, you can get those perfect
equations with relatively little effort. There are two ways of entering equations. The first is to
use the menus. The “math” submenu in the “insert” menu contains everything you need. The
only problem is that it is clumsy, and only suitable for very beginning users. Far better is to
use the keyboard. The Alt-m key sequence gives you pretty much everything you need to create
equations. Let us try to create the following equation:


1. First enter the “Descriptive Math Mode” by pressing Alt-m d which starts an equation on
a separate line.
2. The terms on the left side involve fractions. A fraction is entered by typing Alt-m f (“f”
for fraction). To enter the ¶ symbol, type Alt-m p (“p” for partial). So type
Alt-m d Alt-m f Alt-m p A Alt-m p z
The takes you to the denominator field, while the leaves the fraction
and allows you to enter the next term.
3. The second term involves a subscript. This is done by typing “_”. So the second term is
entered as:
+ v_G Alt-m f Alt-m p A Alt-m p t
5
The “v_G” entry creates vG.

4. The third term involves superscripts. This is done by typing “^”. So the third term is
entered as follows:
+ iD Alt-m f Alt-m p^2 A Alt-m p t^2
Notice the “Alt-m p^2” and the “t^2” entries. These create the second derivitives.
5. The term on the right involves a Greek letter and vertical bars. These are entered as follows:
= Alt-m g g |A|^2 A
Here the “Alt-m g” sequence selects the Greek keyboard, where “abcde. . . ” become
“abcde. . . ”. The vertical bar is just directly typed in as seen above.
6. Finally, we want to give the equation a num
ber. By default, LyX does not number equations.
If you want to add a number to an equation, just put the cursor into the equation
and type Alt-m n. The equation number is automatically generated, and is guaranteed to be
in proper sequence, with proper respect paid to style. If you want to remove an equation
number, just type Alt-m Shift-n.
However, the only real reason to number an equation such as Eq. (1) is to refer to it in the
text. In that case, we can’t just add a number, we have to give that number a meaningful

label. This is done by placing the cursor in the equation, and typing Alt-i l, which opens
up a dialog box where you can give the name of the label, say “eq:maineq” (by default,
LyX will put “eq:” as part of an equation label to keep it from being confused with a
section label or a figure label or any other labe
l). Once you have done that, you can refer
to that equation elsewhere by typing
Eq. Alt-i r and selecting “eq:maineq”

That is pretty much it. There is much more you can do, like creating matrices, integral signs etc.
But the essence of the math mode in LyX is what we just did. But look at the result (type Alt-x
p) and see the quality of the typesetting that we have painlessly obtained. The Alt-m keyboard is
summarized below for quick reference:



############################
Normally, equation with label will be numbered automatically.

Python Tkinter-Checkbutton

Cited from: http://effbot.org/tkinterbook/checkbutton.htm

To use a Checkbutton, you must create a Tkinter variable. To inspect the button state, query the variable.

from Tkinter import *

master = Tk()

var = IntVar()

c = Checkbutton(master, text="Expand", variable=var)
c.pack()

mainloop()

By default, the variable is set to 1 if the button is selected, and 0 otherwise. You can change these values using the onvalue and offvalue options. The variable doesn’t have to be an integer variable:

    var = StringVar()
c = Checkbutton(
master, text="Color image", variable=var,
onvalue="RGB", offvalue="L"
)

If you need to keep track of both the variable and the widget, you can simplify your code somewhat by attaching the variable to the widget reference object.

    v = IntVar()
c = Checkbutton(master, text="Don't show this again", variable=v)
c.var = v

If your Tkinter code is already placed in a class (as it should be), it is probably cleaner to store the variable in an attribute, and use a bound method as callback:

    def __init__(self, master):
self.var = IntVar()
c = Checkbutton(
master, text="Enable Tab",
variable=self.var,
command=self.cb)
c.pack()

def cb(self, event):
print "variable is", self.var.get()

Example:

from Tkinter import *

def cb1():
print 'use c.var.get() to check the checkbutton value'

master=Tk()
v = IntVar()
c = Checkbutton(master, text="Color Image", variable=v, command=cb1)
c.var=v
c.pack()
master.mainloop()

Saturday, 19 January 2008

simple python gui

from Tkinter import *
root = Tk()

w = Label(root, text="Hello, world!")
w.pack()

root.mainloop() # if runs in IDLE, comment this line, otherwise errors occur.

Friday, 18 January 2008

希望入英籍的朋友要严重关注的问题

关于双重国籍的问题, 很多朋友都要各种各样的疑问. 根据英国的制度, 在加入了英国国籍以后, 而你的中国护照又有效的话, 确实是可以保留两本护照的. 关于中国那边的法律在次不再赘述了, 我先来解释一下英国的制度对于这种双重国籍的便利. 英国法律允许双重国籍, 这自然是不消说了, 而很多朋友得以保留中国护照同时使用的原因, 主要是英国没有绿卡制度, 英国的'绿卡', 其实就是一个永久有效的签证'INDEFINATE LEAVE TO REMAIN', 根据以往的经验, 一般在取得了永久居留的签证以后, 下一步就是入籍, 而即使你成功加入了英国国籍, 这个在中国护照上的签证依然是有效的.而我们知道;, 要在加入了其他国籍之后, 保留中国护照的最大技术上的难度就是, 因为绿卡取消导致中国的出境困难. 在这里我来举一个例子来解释一下, 以便大家更好的理解这个CASE. 以加拿大为例, 申请永久居留其实就是申请'枫叶卡', 类似美国的绿卡制度, 而'枫叶卡'持有者申请了加拿大国籍之后, 这个'枫叶卡'就会被取消. 如果一个加拿大华人期望能够同时保留中国护照, 问题就来了, 假如他持中国护照入境中国, 出境的时候就会有麻烦, 因为他的'枫叶卡'被取消了, 所以他的中国护照上也就没有其他国家的签证了, 这样中国的海关是不会准许他出境的. 如果在英国, 就没有类似的麻烦, 即使你入籍了, 中国护照上还有那个证'INDEFINATE LEAVE TO REMAIN'签证, 这样你只要在出入中国口岸的时候单一使用中国护照就可以了. 但是目前, 有一个细微的变化, 很可能会对持有两本护照的朋友造成很大困扰, 虽然目前我还不能证实, 但确实是一个值得关注的问题.
'
英国除了'INDEFINATE LEAVE TO REMAIN', 还有一个签证叫做' certificate of entitlement to right of abode', 准确来说, 这个不是一个签证, 而只能称为'签注', 申请这个的人, 主要是拥有英国居留权, 但又没有英国护照的人士. 顾名思义, 这是英国居留权签注,本质上和ILR永久居留签证是不同的. 但是,在HOME OFFICE的网页上宣布, If you have a certificate that was issued after 21 December 2006, it can be withdrawn if we find out that you no longer qualify for one or if an official order is made to remove your right of abode. 也就是说, 任何人在06年12月21号之后取得居留权的签注, 如果在这之后被发现, 该人士已经持有了英国护照, 这个签注就会被取消. 而现在问题就来了, 那是不是06年12月21号以后, 取得永久居留签证ILR的人士,在取得了英国护照以后, 他们的ILR也会注销吗????虽然HOME OFFICE明确说明了在持有英国护照的前提条件下, 任何人如果在另外一个国籍的护照上签有的certificate of entitlement to right of abode'会被取消, 但是却没有提及如果是永久居留ILR是不是也会同样地被注销?? 但在另外一个方面, 有一些微小的细节值得关注, 英国有一种叫做NTLTOC的签证类别, 指的是, 一个人如果现在的护照过期了, 但在这本护照上的签证还有效, 可以通过申请这个NTLTOC把依旧有效的签证移到新护照上. 我的疑惑就来自NTLTOC申请表格上的一段话,
If you have become naturalised as a British citizen since
being granted indefinite leave to enter or remain in the
UK, you should not apply for a no time limit stamp in the
passport of your other nationality, as you have the right
of abode in the UK and are no longer subject to immigration
control. If you have retained your other nationality
and want your status confirmed in that passport or travel
document, and you do not hold a UK passport or identity
card describing you as a British citizen, you may
apply for a certificate of entitlement to the right of abode
in the UK.

这段话的意思是说, 如果你已经加入了英国籍, 将来你换护照的时候, 你就不能再申请更新ILR,因为你已经有了英国居留权, 这样你只能申请居留权签注Right of abode,但是我们在前面已经说过, 这个签注是给没有英国护照的人士的, 如果你已经有了英国护照, 你也不能申请这个了,如此一来问题就产生了, 如果在加入了英国籍以后, HOME OFFICE把你原来的ILR注销, 那保留两本护照的可能性也就没有了. 因为你的中国护照上没有了有效的他国签证了, 但现在的问题是, HOME OFFICE的网页上只涉及了RIGHT OF ABODE的取消, 却完全没有提到ILR的问题, 那么到底这个永久居留签证会不会随着你的入籍而被取消呢?????有哪位朋友是在06年12月21号以后申请入籍和护照的呢?请来分享一下你的经验. 叙述较繁琐, 请各位见谅, 但是问题确实复杂, 不得不详细叙述.

Powered by ScribeFire.

python arguments

What if you want to supply arguments to the Python script? The sys module contains a variable called argv. It is an array that contains the name of the Python file and any command line arguments that followed.

For example, let's define a file called show_args.py;

import sys
print sys.argv

Now when we evaluate show_args.py with Python, we'll simply see the arguments we entered on the command line, along with the filename of the script:

% python show_args.py 1 2 3 4 5
['show_args.py', '1', '2', '3', '4', '5']
%

Notice that sys.argv is an array, so you can refer to individual commands using the [] array element syntax. You can also use any array function on sys.argv or on a part of it (using the [:] syntax).

Here's file show_args_2.py that extracts elements from the sys.argv array:

import sys, string

print 'The arguments of %s are "%s"' % \
(sys.argv[0], string.join(sys.argv[1:]))

(The "\" character lets me continue the print command to the next line by nullifying the "newline" character that would otherwise create a new line.) We'll run this script with the same command-line arguments we used for show_args.py:

% python show_args_2.py 1 2 3 4 5
The arguments of show_args_2.py are "1 2 3 4 5"
%

The sys.argv array consists of strings, so you will need to convert number arguments to numbers using the conversion functions int or float. For example, let's make our pi multiplying script take an argument. We'll call it pi_mult.py:

import math, sys

def times_pi(value):
return math.pi * value

value = float(sys.argv[1])

print '%g times pi is %g' % (value, times_pi(value))

Now when we run it with a command-line argument, that argument is changed into a float before it is multiplied by math.pi:

% python pi_mult.py 2
2 times pi is 6.28319
%

But what if we forget to enter an argument on the command line? We'll get an error message (since there is no second element to the sys.argv array) and Python will stop evaluating the script file:

% python pi_mult.py
Traceback (most recent call last):
File ``pi_mult.py'', line 6, in ?
value = float(sys.argv[1])
IndexError: list index out of range
%

By convention, Unix commands will provide a ``usage'' message if the arguments are wrong. The usage message lists descriptions of the arguments (enclosed in "<" and ">" characters) so you know what kind of arguments the command requires. We can add a check for the right number of arguments to our command, and print out the usage message if the argument count is incorrect.

We'll make a new version, called pi_mult_2.py, in which we add the argument check and the usage message:

import math, sys

if len(sys.argv) != 2:
print 'Usage: pi_mult_2.py '
sys.exit(1)

def times_pi(value):
return math.pi * value

value = float(sys.argv[1])

print '%g times pi is %g' % (value, times_pi(value))

Now when we try to run pi_mult_2.py without arguments, the number of command line arguments is wrong; it should be 2: one for the script filename and one for the number to be multipled by pi. The usage message will be printed instead of causing a Python error:

% python pi_mult_2.py
Usage: pi_mult_2.py
%

Thursday, 17 January 2008

python read files

Doing it the usual way

The standard idiom consists of a an ‘endless’ while loop, in which we repeatedly call the file’s readline method. Here’s an example:

# File: readline-example-1.py

file = open("sample.txt")

while 1:
line = file.readline()
if not line:
break
pass # do something

This snippet reads the file line by line. If readline reaches the end of the file, it returns an empty string. Otherwise, it returns the line of text, including the trailing newline character.

On my test machine, using a 10 megabyte sample text file, this script reads about 32,000 lines per second.
Using the fileinput module

If you think the while loop is ugly, you can hide the readline call in a wrapper class. The standard fileinput module contains an input class which does exactly that.

# File: readline-example-2.py

import fileinput

for line in fileinput.input("sample.txt"):
pass

However, adding more layers of Python code doesn’t exactly help. For the same test setup, performance drops to 13,000 lines per second. That’s nearly two and half times slower!
Speeding up line reading

To speed things up, we obviously need to make sure we spend as little time on in Python code (running under the interpreter) as possible.

One way to do this is to tell the file object to read larger chunks of data. For example, if you have enough memory, you can slurp the entire file into memory, using the readlines method. Or you could even use the read method to read the entire file into a single memory block, and then use string.split to chop it up into individual lines.

However, if you’re processing really large files, it would be nice if you could limit the chunk size to something reasonable. For example, if you read a few thousand lines at a time, you probably won’t use up more than 100 kilobytes or so.

The following script uses a nested loop. The outer loop uses readlines to read about 100,000 bytes of text, and the inner loop processes those lines using a simple for-in loop:

# File: readline-example-3.py

file = open("sample.txt")

while 1:
lines = file.readlines(100000)
if not lines:
break
for line in lines:
pass # do something

Can this really be faster? You bet. With the same test data, we can now process 96,900 lines of text per second!

Or to put it another way, this solution is three times as fast as the standard solution, and over seven times faster than the fileinput version.

In Python 2.2 and later, you can loop over the file object itself. This works pretty much like readlines(N) under the covers, but looks much better:

# File: readline-example-5.py

file = open("sample.txt")

for line in file:
pass # do something

In Python 2.1, you have to use the xreadlines iterator factory instead:

# File: readline-example-4.py

file = open("sample.txt")

for line in file.xreadlines():
pass # do something

Copyright © 2000 Fredrik Lundh

Powered by ScribeFire.

My photo
London, United Kingdom
twitter.com/zhengxin

Facebook & Twitter