Miscellaneous - Random knowledge that won't fit any other category


Expertise levels

Asking about people's expertise level is a common question in professional interviews. You're expected to rate yourself on a 4 levels scale, typically :
  1. Novice
  2. Beginner
  3. Advanced (or "Intermediate")
  4. Expert
This raises some extra questions :
Level Knowledge Skills Experience
Novice none has never used it
  • know a few options and features
  • can do some basic tasks
has used it :
  • once
  • on a single project
  • know the "typical" options and features
  • can do some not-so-basic tasks
  • can fix some errors / failures
  • can answer some questions (and many of them with a quick googling)
has used it :
  • a few times
  • in a few different contexts (teams / projects / companies)
  • know most of options and features (beyond the "typical" ones)
  • know hacks / bugs about some of them
  • can teach it
  • can give valuable advice and good practices about it
  • can answer most questions without googling them first
  • can fix most errors / failures
has used it :
  • many times
  • daily for months / years (and still does)
  • in numerous different contexts (teams / projects / companies)
  • know all options and features
  • know hacks / bugs about all of them
  • can do everything about it :
    • setup
    • fix
    • improve
    • teach
  • and do it :
    • right now
    • quickly
    • without googling
    • without notes
  • has built it
  • has deployed / installed / improved it for years (and still does)
  • has used it daily for years (and still does)
Jedis exist but :
  • very few people actually qualify as Jedis
  • with hard work, it's possible to become Jedi on a specific topic, but nobody can be a Jedi in everything
  • it's easier to be a Jedi in something if you made it yourself
  • many so-called Jedis are actual rockstars ... and "rockstars" are often assholes
  • when companies open positions to Jedis only :
    • do they really need them ?
    • can they actually afford them ? (does the job offer suggest it ?)
  • It's nice to be important, but it's more important to be nice.
    What matters most is teamwork, not individuals.

Comments in programming, scripts, ...

Context Single line Multiple lines Notes
Starts with ... Until ... Starts with ... Until ...
ASP ' end of line
Awk # end of line source
Bash, MySQL query # end of line
C, PHP, Javascript // end of line /* */
CSS /* */ /* */
HTML <!-- --> <!-- -->
LATEX % end of line
MS-Dos Batch (.bat, .cmd) REM end of line
Oracle query -- end of line
PERL # end of line


Must include blank lines before and after the comment tag
Python # end of line
  • '''
  • """
  • '''
  • """
VBA, VBS ' end of line
YAML (.yml) # end of line
  • a comment can start anywhere on the line
  • no support for block comments
  • source

ANSI escape sequences

ANSI escape sequences define functions that :

They are made of a sequence of ASCII characters, the first two of which are the ASCII Escape character 27 (1Bh) and the left-bracket character [ (5Bh). The character(s) following the escape and left-bracket characters specify an alphanumeric code that controls a keyboard or display function.


Configuration of the Technicolor TG788vn V2 ADSL modem / router

Before starting playing with your router, you should consider making a backup of all its settings from the web interface.

Start a Telnet session :

  1. telnet
  2. login / pass : Administrator /
  3. Disable the Telnet session timeout : env set var=SESSIONTIMEOUT value=0
  4. Apply changes : saveall

Change the LAN IP of a connected device, i.e. static DHCP (source) :

  1. Start a Telnet session to your modem / router
  2. List current DHCP leases and devices :
    dhcp server lease list
    Lease			Pool		TTL		State	Clientid
    1	LAN_private	13:44:55	USED	[01] 91:d8:32:8f:31:04
    3	LAN_private	23:45:37	USED	[01] 3d:c5:14:7d:14:f0
    0	LAN_private	16:27:32	USED	[01] 12:34:56:ab:cd:ef
  3. Based on its MAC address or current IP address, identify the device which you want to get a permanent IP address. Unregister it from the DHCP server by ending its current lease :
    dhcp server lease delete clientid=12:34:56:ab:cd:ef
  4. Assign it a fixed IP address :
    dhcp server lease add clientid=12:34:56:ab:cd:ef pool=LAN_private addr= leasetime=0
    • the chosen IP address must be in the range
    • leasetime=0 requests an infinite lease time
  5. Save changes : saveall
  6. Reboot the modem / router : system reboot
  7. Then request a new IP address from the client side.

If the interface getting a static DHCP address is actually a bridge interface, its MAC address may change, nulling this setting. Indeed, by default in Linux, bridge interfaces use, for their MAC address, the lowest MAC address among the enslaved interfaces (source). But there is a workaround...

List existing NAT rules (source) :

nat maplist
Idx	Type	Interface	Outside Address				Inside Address			Use
1	NAT	Internet	my.public.IP.address:8			18
2	NAT	Internet	my.public.IP.address			0
3	NAPT	Internet	my.public.IP.address:6346		0
4	NAPT	Internet	my.public.IP.address:[6881-6889][6881-6889]	0
5	NAPT	Internet	my.public.IP.address:51005			0
6	NAPT	Internet	my.public.IP.address:5060		my.public.IP.address:5060	0
7	NAT	Internet	my.public.IP.address			0
8	NAPT	Internet	my.public.IP.address			unmapped			9

Create a new NAT rule :

There is an "easy" way of configuring NAT on this device : just Create a new game or application, then Assign a game or application to a local network device. On my side, this worked only ~5 minutes after creating a new NAT rule, then the incoming traffic to the specified port was dropped until the next stream of outbound traffic (even a "ping" was enough to re-allow the incoming traffic to go through. ), hence this guide
  1. Start a Telnet session to your modem / router
  2. Check the existing NAT rules
  3. List the available interfaces :
    nat iflist
    Interface	NAT
    loop		disabled
    Internet	enabled
    LocalNetwork	transparent
  4. Then create a new rule (here, we're opening HTTPS traffic) :
    nat mapadd intf Internet outside_addr my.public.IP.address outside_port 443 inside_addr inside_port 443
    • _WAY_ more options can be specified here : ports ranges, protocol, ...
    • Looks like the = signs shown in the documentation between parameters and values are optional
  5. Should you made an error while adding a rule, to fix it, you have to :
    1. List the existing rules and get the index number (Idx column) and interface of the faulty one
    2. Delete it :
      nat mapdelete index=indexNumber intf=Internet
  6. Then save changes :

Miscellaneous commands :

Reboot the router
system reboot
Check which devices are connected
hostmgr list

Technicolor TG788vn Telnet reference guide (source) :


How to plug a Suunto watch into a Debian host ?

Spoiler : you can't .


the device communication lib : libambit

==> http://www.movescount.com/fr/groups/group5135-Linux_User_Group
http://sourceforge.net/projects/openambit/ (source : http://forum.ubuntu-fr.org/viewtopic.php?id=1211421)
==> DEBIAN : https://tracker.debian.org/pkg/openambit

Writing a simple Operating system from scratch

Here are my notes / work in progress while reading and trying things with Writing a simple Operating system from scratch.pdf (originally found here, looks like there are some nice docs there).

Create a blank disk image :

  1. dd if=/dev/zero of=./01_boot.img bs=1 count=1024
  2. Boot it : qemu -curses -k fr -hda 01_boot.img
  3. It tries all devices, and ends on : No bootable device.
  4. To leave : killall -1 qemu

Edit the image file with Emacs :

  1. within Emacs : Alt-x hexl-find-file, then (source) :
    • Ctrl-Alt-d : insert a byte with a code typed in decimal
    • Ctrl-Alt-o : insert a byte with a code typed in octal
    • Ctrl-Alt-x : insert a byte with a code typed in hex
  2. Start with (hex values): e9 fd ff
  3. End (512 bytes chunk, MBR) : 55 aa
  4. The final result should look like :
    e9 fd ff 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
  5. Then boot : Booting from Hard Disk...

Boot sector re-visited :

  1. apt install nasm
  2. edit 02_boot_sect.asm :
    ; A simple boot sector program that loops forever.
    loop:			; Define a label, "loop", that will allow
    			; us to jump back to it, forever.
    jmp loop		; Use a simple CPU instruction that jumps
    			; to a new memory address to continue execution.
    			; In our case, jump to the address of the current
    			; instruction.
    times 510 -($-$$) db 0	; When compiled, our program must fit into 512 bytes,
    			; with the last two bytes being the magic number,
    			; so here, tell our assembly compiler to pad out our
    			; program with enough zero bytes ( db 0) to bring us to the
    			; 510th byte.
    dw 0xaa55		; Last two bytes ( one word ) form the magic number,
    			; so BIOS knows we are a boot sector.
  3. compile : nasm 02_boot_sect.asm -f bin -o 02_boot_sect.bin
  4. then boot : qemu -curses -k fr 02_boot_sect.bin
  5. result is the same as above : Booting from Hard Disk...
  6. let's have a look INSIDE 02_boot_sect.bin : od -t x1 -A n 02_boot_sect.bin
    eb fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
    e9 fd ff changed into eb fe ? Maybe this is just a "jump" destination and doesn't really matter (?)

16-bit real mode :

16-bit real mode is opposed to 32/64-bit protected mode where the OS can restrict a user process to access kernel memory.

CPU registers :

x86 processors have 4 16-bit registers : ax, bx, cx, dx (details) :

To store a value in a register, we "move" it : mov register, value
It's also possible to address either the high byte or the low byte of a register : ah, al, ...
  1. Let's edit 03_boot_sect_hello.asm :
    ; A simple boot sector that prints a message to the screen using a BIOS routine.
    mov ah, 0x0e		; int 10/ah = 0eh -> scrolling teletype BIOS routine
    mov al, 'H'		; char to display into al
    int 0x10		; call the display routine
    mov al, 'e'
    int 0x10
    mov al, 'l'
    int 0x10
    mov al, 'l'
    int 0x10
    mov al, 'o'
    int 0x10
    jmp $			; Jump to the current address ( i.e. forever ).
    ; Padding and magic BIOS number.
    times 510 -($-$$ ) db 0	; Pad the boot sector out with zeros
    dw 0xaa55		; Last two bytes form the magic number,
    			; so BIOS knows we are a boot sector.
  2. compile : nasm 03_boot_sect_hello.asm -f bin -o 03_boot_sect_hello.bin
  3. boot :
    qemu -curses -k fr 03_boot_sect_hello.bin
    qemu 03_boot_sect_hello.bin
  4. it says :
    Booting from Hard Disk...
  5. let's have a look into 03_boot_sect_hello.bin : hd 03_boot_sect_hello.bin
    00000000	b4 0e b0 48 cd 10 b0 65		cd 10 b0 6c cd 10 b0 6c		|...H...e...l...l|
    00000010	cd 10 b0 6f cd 10 eb fe		00 00 00 00 00 00 00 00		|...o............|
    00000020	00 00 00 00 00 00 00 00		00 00 00 00 00 00 00 00		|................|
    000001f0	00 00 00 00 00 00 00 00		00 00 00 00 00 00 55 aa		|..............U.|

Memory, addresses and labels :

BIOS loads the boot sector to the address 0x7c00.

X marks the spot :

  1. let's edit 04_boot_sect_X.asm :
    ; A simple boot sector program that demonstrates addressing.
    mov ah, 0x0e		; int 10/ah = 0eh -> scrolling teletype BIOS routine
    ; First attempt
    mov al, the_secret	; copy the value of 'the_secret' into al
    int 0x10		; Does this print an X?
    ; Second attempt
    mov al, [the_secret]	; copy the contents of address 'the_secret' into al
    int 0x10		; Does this print an X?
    ; Third attempt
    mov bx, the_secret
    add bx, 0x7c00
    mov al, [bx]
    int 0x10		; Does this print an X?
    ; Fourth attempt
    ;mov al, [0x7c1e]
    mov al, [0x7c1d]
    int 0x10		; Does this print an X?
    jmp $			; Jump forever.
    the_secret:		; this is just a label to mark the offset of 'X' since the beginning of this program
    			; this label will be removed by nasm, and every reference to it will be replaced by its actual value
    db "X"			; 'db' : 'declare byte(s) of data'. The quotes instruct the assembler to replace each character with its ASCII value
    			; if the data has several characters, the label will point to the first of them
    times 510-($-$$ ) db 0	; Padding
    dw 0xaa55		; magic BIOS number
  2. nasm 04_boot_sect_X.asm -f bin -o 04_boot_sect_X.bin
  3. hd 04_boot_sect_X.bin outputs :
    00000000	b4 0e b0 1d cd 10 a0 1d		00 cd 10 bb 1d 00 81 c3		|................|
    00000010	00 7c 8a 07 cd 10 a0 1e		7c cd 10 eb fe 58 00 00		|.|......|....X..|
    00000020	00 00 00 00 00 00 00 00		00 00 00 00 00 00 00 00		|................|
    000001f0	00 00 00 00 00 00 00 00		00 00 00 00 00 00 55 aa		|..............U.|
    In my case, the offset of 'X' is 0x1d.
  4. Then boot : qemu -curses -k fr 04_boot_sect_X.bin
    Booting from Hard Disk...
    "?" is actually a non-ASCII character
  5. With [org 0x7c00] at the very beginning of the program, the display becomes :
    Booting from Hard Disk...
    X X

Using the stack :

push / pop : in 16-bit mode, the stack works only on 16-bit boundaries, we cannot work with single bytes.
The stack is implemented by two special CPU registers (remember the x86 registers ?) :
  • bp : address of the stack base (i.e. bottom, actually : base pointer)
  • sp : address of the stack top (i.e. summit, actually : stack pointer)

The stack grows downwards from the base pointer. So when we issue a push, the value actually gets stored below --- and not above --- the address of bp, and sp is decremented by the value's size.

  1. Let's edit 05_boot_sect_stack.asm :
    ; A simple boot sector program that demonstrates the stack.
    mov ah, 0x0e		; int 10/ah = 0eh -> scrolling teletype BIOS routine
    mov bp, 0x8000		; Set the base of the stack a little above where BIOS
    mov sp, bp		; loads our boot sector - so it won't overwrite us.
    push 'A'		; Push some characters on the stack for later retrieval.
    push 'B'		; Note, these are pushed on as 16-bit values, so the
    push 'C'		; most significant byte will be added by our assembler as 0x00.
    pop bx			; Note, we can only pop 16-bits, so pop to bx
    mov al, bl		; then copy bl (i.e. 8-bit char) to al
    int 0x10		; print (al)
    pop bx			; Pop the next value
    mov al, bl
    int 0x10		; print (al)
    mov al, [0x7ffe]	; To prove our stack grows downwards from bp,
    			; fetch the char at 0x8000 - 0x2 (i.e. 16-bits)
    int 0x10		; print (al)
    jmp $			; Jump forever. '$' is the address of the current instruction (?)
    times 510-($-$$) db 0	; Padding
    dw 0xaa55		; magic BIOS number
  2. compile : nasm 05_boot_sect_stack.asm -f bin -o 05_boot_sect_stack.bin
  3. then boot : qemu -curses -k fr 05_boot_sect_stack.bin
  4. which outputs :
    Booting from Hard Disk...

Question 3 :

  1. ;
    ; EXERCISE : code this
    mov bx, 30
    if (bx <= 4) {
    	mov al, 'A '
    else if (bx < 40) {
    	mov al, 'B '
    else {
    	mov al, 'C '
  2. 06_boot_sect_jump.asm :
    mov bx, 30	; should display 'B'
    ;mov bx, 3	; should display 'A'
    ;mov bx, 50	; should display 'C'
    cmp bx, 4
    jle lessOrEqualThan4
    cmp bx, 40
    jl lessThan40
    mov al, 'C'
    jmp theEnd
    mov al, 'A'
    jmp theEnd
    mov al, 'B'
    jmp theEnd
    mov ah, 0x0e	; int=10/ah=0x0e -> BIOS tele-type output
    int 0x10		; print the character in al
    jmp $
    ; Padding and magic number.
    times 510-($-$$) db 0
    dw 0xaa55
  3. compile then boot : nasm 06_boot_sect_jump.asm -f bin -o 06_boot_sect_jump.bin && qemu -curses -k fr 06_boot_sect_jump.bin
  4. try it with different values in bx

Question 4 :

  1. Given :
    ; EXERCISE : A boot sector that prints a string using our function.
    [org 0x7c00]		; Tell the assembler where this code will be loaded
    mov bx, HELLO_MSG	; Use bx as a parameter to our function, so
    call print_string	; we can specify the address of a string.
    mov bx, GOODBYE_MSG
    call print_string
    jmp $			; Hang
    %include "print_string.asm"
    ; Data
    db 'Hello, World !', 0	; <-- The zero on the end tells our routine
    			; when to stop printing characters.
    db 'Goodbye !', 0
    ; Padding and magic number.
    times 510-($-$$) db 0
    dw 0xaa55
    Write print_string.asm
  2. ;
    ; MY ANSWER : print_string.asm
    ; arg :		BX, start of the string to print
    ; return :	nothing
    	cmp byte[bx], 0
    	je leave_print_string_function
    	mov al, [bx]
    	call print_character
    ;	add bx, 0x01		; jump to the next character of the string to display
    	inc bx			; same as above, different syntax
    	jmp print_string_start
    	mov al, 0x0d		; bonus : add a carriage return
    	call print_character
    	mov al, 0x0a		; ... and a line feed
    	call print_character
    ; arg :		AL, character to print
    ; return :	nothing
    	mov ah, 0x0e		; int=10/ah=0x0e -> BIOS tele-type output
    	int 0x10		; print the character in al
  3. compile and boot : nasm 07_boot_sect_print_string.asm -f bin -o 07_boot_sect_print_string.bin && qemu -curses -k fr 07_boot_sect_print_string.bin

For reference, x86 assembly guides : 1, 2.

Question 5 :

  1. Code this :
    mov dx, 0x1fb6	; store the value to print in dx
    call print_hex	; call the function
    ; prints the value of DX as hex.
    	; TO DO: manipulate chars at HEX_OUT to reflect DX
    	mov bx, HEX_OUT		; print the string pointed to
    	call print_string	; by BX
    ; global variables
    HEX_OUT: db '0x0000', 0
  2. some intermediate notes :
    • mov [HEX_OUT+5], 3 : square brackets mean that the operand points to a memory location (source)
    • mov [HEX_OUT+5], 3 : nasm will complain operation size not specified because it has no idea whether this value should be sorted as a single-byte (8 bits) value ("byte"), 2-byte (16 bits) value ("word"), 4-byte (32 bits) value ("double word"), or 8-byte (64 bits) value ("quad word").
      To fix it, be more explicit : mov byte[HEX_OUT+5], 3
    • mov byte[HEX_OUT+5], 42 : will store the decimal value 42 (the ASCII character *) into the specified address.
      To store a B (42h), be explicit : mov byte[HEX_OUT+5], 42h, or mov byte[HEX_OUT+5], 0x42
    • Don't systematically pusha / popa when creating a function, or popa will overwrite changes made to registers by the function, and the returned value(s) will be the function parameter(s) (i.e. unchanged value(s))
    • If you want to shr register, n, n being a variable number of bits, this can only work if n is stored in cl. (WHY?)
  3. 08_boot_sect_print_hex.asm :
    ; EXERCISE : Print an hexadecimal value.
    [org 0x7c00]		; Tell the assembler where this code will be loaded
    mov dx, 0x1fb6		; store the value to print in dx
    call print_hex		; call the function
    mov dx, 0x1234		; store the value to print in dx
    call print_hex		; call the function
    mov dx, 0xcaca		; store the value to print in dx
    call print_hex		; call the function
    jmp $			; Hang
    ; arg :		DX, the hex value to print
    ; return :	nothing
    ; the idea is to convert the value to print into characters, then insert those into HEX_OUT
    	; 1st digit from the right
    	mov cx, dx
    	; nothing to shift here
    	and cx, 0x000f		; select 1 digit with a logical AND, store result in cx
    	call changeHexDigitIntoAscii
    	mov byte[HEX_OUT+5], cl	; store the converted char as the rightmost char of HEX_OUT :
    				; HEX_OUT : '0x....'
    				; offset : 012345
    	; 2nd digit from the right
    	mov cx, dx
    	shr cx, 4
    	and cx, 0x000f
    	call changeHexDigitIntoAscii
    	mov byte[HEX_OUT+4], cl	; store the converted char as the 2nd char from the right of HEX_OUT
    	; 3rd digit from the right
    	mov cx, dx
    	shr cx, 8
    	and cx, 0x000f
    	call changeHexDigitIntoAscii
    	mov byte[HEX_OUT+3], cl	; store the converted char as the 3rd char from the right of HEX_OUT
    	; 4th digit from the right
    	mov cx, dx
    	shr cx, 12
    	and cx, 0x000f
    	call changeHexDigitIntoAscii
    	mov byte[HEX_OUT+2], cl	; store the converted char as the 4th char from the right of HEX_OUT
    	; Done converting. Let's print the result
    	mov bx, HEX_OUT		; print the string pointed to
    	call print_string	; by BX
    ; arg :	CX, single digit
    ; return :	CX, corresponding ASCII value
    	cmp cl, 0xa
    	jl digitValueIsLessThanA
    	; the current hex digit is within [a-f]
    	add cx, 0x57		; convert hex value 0xa into ASCII value 'a'
    	digitValueIsLessThanA:	; the current hex digit is within [0-9]
    				; let's add 0x30 to change it into its ASCII value
    	add cx, 0x30
    %include "print_string.asm"
    ; global variables
    HEX_OUT: db '0x1234', 0
    ; Padding and magic number.
    times 510-($-$$) db 0
    dw 0xaa55
    I'm not completely satisfied with this solution : too much copy-pasted code. I've tried (but not succeeded yet) to write a function taking dx and the right shift offset as parameters... (I'm open to suggestions
  4. compile and boot : nasm 08_boot_sect_print_hex.asm -f bin -o 08_boot_sect_print_hex.bin && qemu -curses -k fr 08_boot_sect_print_hex.bin

Extended Memory Access Using Segments :

  1. Let's edit 09_boot_sect_segment_offsetting.asm :

    0x7c0 refers to 0x7c00 : to calculate the absolute address, the CPU multiplies the value in the segment register by 16 and then adds your offset address

    ; A simple boot sector program that demonstrates segment offsetting
    mov ah, 0x0e			; int 10/ ah = 0 eh -> scrolling teletype BIOS routine
    mov al, [the_secret]
    int 0x10			; Does this print an X ?
    mov bx, 0x7c0			; Can't set ds directly, so set bx
    mov ds, bx			; then copy bx to ds.
    mov al, [the_secret]
    int 0x10			; Does this print an X ?
    mov al, [es:the_secret]		; Tell the CPU to use the 'es' (not 'ds') segment.
    int 0x10			; Does this print an X ?
    mov bx, 0x7c0
    mov es, bx
    mov al, [es:the_secret]
    int 0x10			; Does this print an X ?
    jmp $				; Jump forever.
    db "X"
    times 510-($-$$) db 0		; Padding.
    dw 0xaa55			; magic BIOS number.
  2. compile and boot : programName='09_boot_sect_segment_offsetting'; nasm "$programName.asm" -f bin -o "$programName.bin" && qemu -curses -k fr "$programName.bin"
  3. Booting from Hard Disk...
    Doesn't help much understanding what's happening
  4. Let's edit 09_boot_sect_segment_offsetting.asm again :
    ; A simple boot sector program that demonstrates segment offsetting
    mov ah, 0x0e			; int 10/ ah = 0 eh -> scrolling teletype BIOS routine
    mov al, [the_secret_a]
    int 0x10			; Does this print an 'A' ?
    mov bx, 0x7c0			; Can't set ds directly, so set bx
    mov ds, bx			; then copy bx to ds.
    mov al, [the_secret_b]
    int 0x10			; Does this print a 'B' ?
    mov al, [es:the_secret_c]	; Tell the CPU to use the 'es' (not 'ds') segment.
    int 0x10			; Does this print a 'C' ?
    mov bx, 0x7c0
    mov es, bx
    mov al, [es:the_secret_d]
    int 0x10			; Does this print a 'D' ?
    jmp $				; Jump forever.
    db "A"
    db "B"
    db "C"
    db "D"
    times 510-($-$$) db 0		; Padding.
    dw 0xaa55			; magic BIOS number.
  5. Booting from Hard Disk...
    B D
  6. (to be continued ...)

How to swap 2 variables without using a 3rd variable ?

Method :

step x y
0 a b
1 = x0 - y0
= a - b
= y0
= b
2 = x1
= a - b
= x1 + y1
= a - b + b
= a
3 = y2 - x2
= a - (a - b)
= a - a + b
= b
= y2
= a

Try it :

x=123; y=456; echo "BEFORE : x=$x, y=$y"; x=$((x-y)); y=$((x+y)); x=$((y-x)); echo "AFTER : x=$x, y=$y"

NetApp SnapShot

1. A snapshot is taken. 2. Changed data is written to a new block and the pointer is updated, but the snapshot pointer still points to the old block, giving you a live view of the data and an historical view. 3. Another snapshot is taken and you now have access to 3 generations of your data without taking up the disk space that 3 unique copies would require : live, snapshot 2 and snapshot 1 in order of age.

How to type special characters ?

Character Windows Linux
¡ AltGr-!
¼ ALT + 172
½ ALT + 171
¾ ALT + 243
¿ AltGr-?
À ALT + 183
  • CAPS LOCK then type the lowercase é/è/ê/ç/whatever...

  • ALT Gr. - SHIFT - then type the é/è/ê/ç/whatever...
 ALT + 182
Ç ALT + 128
È ALT + 200
É ALT + 144
Ê ALT + 210
Ô ALT + 226
ñ AltGr-~, n AltGr-^, n

Regular Expressions, a.k.a RegExp

BRE vs ERE (source 1, 2, 3) :

There are 2 flavors of regular expressions : basic (BRE) and extended (ERE). The main difference is that, in basic regular expressions :
  • characters such as ?, +, {, |, ( and ) have no special meaning
  • they must be escaped with \ to have a special meaning
literal ( ( \(
grouping character \( (
  • echo -e "a\nb\nc" | /bin/grep 'b' returns b. Don't know whether this is BRE or ERE.
  • echo -e "a\nb\nc" | /bin/grep 'b+' returns (nothing). This + was not so special : BRE.
  • echo -e "a\nb\nc" | /bin/grep 'b\+', as well as echo -e "a\nb\nc" | /bin/grep -E 'b+', returns b. + has become "special" : ERE.

In these examples, we're using /bin/grep instead of just grep to make sure we're calling the grep binary itself rather than any local alias.

Special characters :

Expression Matches Example Details
. any single character dot / point / period .
+ the preceding item (expression or character) repeated at least 1 time + sign
* the preceding item repeated 0 or more times asterisk *
| either what's on the left or what's on the right alternation |
? 2 usages :
  1. optional-mode : the preceding item repeated either 0 or 1 time (=it becomes optional)
  2. lazy-mode : forces minimal matching when an expression can match a longer string.
    To perform its "minimal" match, a "closing" character is expected after the ? to instruct where matching stops.
    This also works in Emacs .
^foo nothing before foo, ^ = beginning of string beginning of string
foo$ nothing after foo, $ = end of string end of string
[a-z], [A-Z], [0-9] any single character in the range a-z, A-Z, 0-9 character lists
[12345] or [1-5] any single character in the list : 1, 2, 3, 4, 5
[^A-Z] any single character NOT in the list : everything except capital letters
expression{n} expression repeated n times interval expressions
(expression) + \n "what was matched by the nth (expression)"
echo '123-abc-4567' | sed -r 's/^([0-9]+)-([a-z]+)-(.*)$/\3+\1+\2/'
alias (aka callback) used by sed and by Emacs (in replace regexp mode)
parenthesis have different meanings depending on the context (BRE vs ERE), Emacs requires escaping them : \( and \)
character classes
[:alpha:] alphabetic characters, same as A-Za-z
  • echo -e 'a\n1\nb\n2' | grep '[[:alpha:]]'
  • echo -e 'a\n1\nb\n2' | sed -n '/[[:alpha:]]/p'
Character classes are pre-defined lists of characters (i.e. [:digit:] translates into 0123456789). As such, they have to be enclosed between [ and ] brackets :
[:blank:] blank characters : space and tab
  • echo -e 'ab\na b\na\tb' | grep '[[:blank:]]'
  • echo -e 'ab\na b\na\tb' | sed -n '/[[:blank:]]/p'
regular expression extensions
  • \b (perl + sed)
  • \y (awk)
word boundary (because not all words are separated by space or blank characters)
  • echo 'hello, world' | perl -pe 's/.*?(.)\b/\1/g'
    o d
    Had to use perl for this example because sed is greedy (.* matches the longest string it can find). In this example, I wanted to print several matches from the same line (source)
  • echo -e 'foo\nfoo1\nfoo2' | awk '/foo\y/'
\s whitespace characters : space and tab

Examples :

Bash snippet to play with regular expressions :

wordList='t 1 t1 1t test test1 1test test+ +test test+1 1+test te-1-st'; regExp='([A-Za-z].*[0-9])|([0-9].*[A-Za-z])'; for word in $wordList; do echo $word | grep -E "$regExp" || { echo "$word : no match"; }; done

y = ax + b

Getting a and b :

y = ax + b

y1 = ax1 + b
y2 = ax2 + b

b = y1 - ax1

y2 = ax2 + y1 - ax1
y2 = a(x2 - x1) + y1

a(x2 - x1) = y2 - y1

a = ( y2 - y1 ) / ( x2 - x1 )

y1 = ax1 + b

b = y1 - ax1

b = y1 - x1 * ( y2 - y1 ) / ( x2 - x1 )

Getting x such as y = n :

y = ax + b

ax + b = n
ax = n - b

x = ( n - b ) / a

Behavioral techniques


It is close to impossible to say "No" after you said "Yes" first. With this "Yes", you are committed to act according to the decision you just made.
  • Would you mind looking at my luggage just for a minute ? (Then stop a thief)
  • What time is it, please ? (...) Do you have a quarter, I need to make an important phone call ?

The freeze effect

People tend to stick to decisions they consider as theirs (even though that decision was made by a group, or suggested by previous assertions).
After making a decision, people tend to comply with their decisions, even though it appears they made a mistake. New facts are not considered as they should be : help making the opposite (and right !) decision.
"A decision is forever".

The sunk cost

This happens when you persist on a decision / strategy / plan on which you already and massively invested (time / money / effort), even though you can switch to more affordable / valuable / cost-effective solutions.
  • Even though the movie is bad, you watch it until the end because you PAID for it.
  • Drinking a bad wine just because it is a famous (and expensive) bottle.

Entrapment ( + escalation of commitment)

Somewhat similar to the sunk cost, this one means several rounds of investment (time / money / effort), rather than changing one's mind. This happens when you persist on the same original plan, even though it's becoming over-expensive and can't work anymore
Escaping such a trap can be done by :
  • deciding it with a "STOP" decision. But such traps work so well because of the freeze effect.
  • setting a stop threshold before entering such a trap : wait n minutes only, spend at most n €, ...
  • The bus is late. Miss a first taxi, believing the bus will arrive soon. Miss another taxi. No bus. No more taxi. Walk back home. Waiting + walking was longer than taking the 1st taxi, or walk without waiting.
  • The Vietnam war, for the USA.

Breaking passwords

The basics

Here are some basic methods to get your password :
  1. Just ask ! Sounds stupid, but this often works between colleagues in a rush, or before holidays. Consider social engineering methods.
  2. Guess ! Birthday, kid's 1st name, pet name, car plate number, loved person nickname, favorite football team, ... Consider the most famous passwords in the world : love, secret, god, password, 123456, qwerty, letmein, 123123, ... (list)
  3. Steal it ! It may be noted on a Post-it™ note under the keyboard, or stored in a passwords.xls on a USB key.
  4. Break it with a dictionary attack.
  5. Break it with a brute force attack.


When it comes to crackers —skilled people with heavy machinery who break passwords— things are a little bit different : their target is not to break specifically YOUR password, but to break as many passwords as possible (the lowest hanging fruits first) from the dump they have.
Knowing where the DB dump comes from (website, company) is very informative :
  • the "subscribe" form / corporate rules list the passwords requirements
  • it gives a hint on the type of users : gender, age, education, business, interests, ...
  • it gives a hint on the lexical field users may pick words from

Their methods

Crackers won't obviously ask, try to guess or steal your password as said above (which is what people you physically know / meet may do). They'll try various methods, starting from the most efficient (as for the number of passwords they can break) to the most complex (source) :
  • brute-force on all 6-character passwords
  • hybrid attack by testing passwords made of a dictionary word + 2 characters (digits / "special"), then 3, ...
  • Markov chain attack : since passwords have "patterns" (like "string-digits", "uppercase-lowercase-digit", "string-special-string", ...) it is possible to reduce the number of values to test
  • mask attack : like brute-force but more specific, based on patterns. This allows breaking, for instance, Julia1984 : this is a name, starting with an uppercase letter and followed by a year. Here come common symbol substitutions : 0 for o, | for l, $ for s, ... (which is why P@$$w0rd is plain sh*t )
  • combinator attack : each word of a dictionary is appended to each word in a dictionary. This is an answer to the correct horse battery staple thing.

Last minute thoughts

  • No password is safe forever : make it an habit of changing passwords before they become crackable (i.e. if a given password is assumed to take 2 years to be brute-forced, change it after 1 year : whenever it's cracked, you changed it anyway)
  • Use distinct passwords across sites : in a users database, your password is linked to your email address, and your email address is present in all sites you have an account on. If your password is discovered, it becomes very easy to gain access to your other accounts
  • Any string that was once someone's password may be in a cracker's personal dictionary : momof3g8kids was broken thanks to momof3g and 8kids (which were probably previously broken via brute-force). So if your password is made of
    • concatenation of strings anybody may have used as password
    • or such a string + digits or "specials"
    you're in trouble
  • Patterns suck :
    • qeadzcwrsfxv1331 looks long and solid, but it's actually a keyboard pattern on a QWERTY keyboard. Crackers have methods to test these too.
    • When generating passwords, any kind of pattern or rule decreases security. Strength comes from randomness (and we —humans— suck at this) : let a computer do the job for you !.
  • Making a password out of 7 random words from a "large" list is considered safe.

Social Engineering


Here are described some techniques to get "what you want" from somebody not willing to give it to you (and even without asking !)
Goal Target people Method
Get admin rights on a workstation Helpdesk
  1. Wait for a moment at which helpdesk technicians can not spend too much time with you (at lunch time when most of them have already left the office or are not back yet, during an issue occurring somewhere else (server crash, virus attack), during holidays/epidemic, or anytime they're not numerous enough)
  2. Ask the technician to perform some operation for which he has to log onto the target workstation with admin rights
  3. Ask him to launch any operation taking some time to perform, like defragmenting an HDD.
  4. If he's busy enough, he won't have time to wait until the defragmentation is done, so he may tell you : "Just log out when it's finished and enjoy."
  5. That's it : you have admin rights on your machine. You can now create a local administrator account for future use.

Other Strategies

The F.U.D. strategy
  • Fear : Gather facts / data / statistics so that the target people sees everybody has something to fear, and that "feeling safe" is different from "being safe"
  • Uncertainty : Everything has an uncertain side, just because some facts are unknown to everybody, things don't always behave as expected, and the future is unknown until it happens.
  • Doubt : Make the target people doubt about what they know (or think they know). Show them their understanding has (or can have) failures.
Changing one's mind
Statistically, when people make a decision which appears to be wrong afterwards, they often stick to their initial decision anyway. It seems that admitting one's made a mistake is more difficult than persevere in a wrong way. This works even better when occurring in public.
The "Tell a friend" strategy
Good friends are known to share secrets. Let's imagine you have something "hard" to say to Alice but you have no idea on how to let her know without hurting her feelings. Well, just tell it to Bob, who is Alice's best friend. Say it as a secret, and ask Bob never to repeat this to anyone. Bob's first thought will be to let Alice know.
The "SEsGI" strategy
The Someone Else's Good Idea. Some ideas can not be "good" ideas just because they are yours. (But your boss's ideas are always good). If you want an idea to be thought as "good", just go to people saying "Hey, I just remember the idea you told me about few days ago, and (blah blah blah...)". Very few people are honest enough to answer "Sorry, this wasn't my idea".

Syntax of Windows network shares

\\host\directory is what's called a UNC path. Such paths are not case-sensitive.