Good Programming

To me, one of the hallmarks of good programming is that the code looks so simple that you are tempted to dismiss the skill of the author. Writing good clean understandable code is hard work whatever language you are using -- Francis Glassborow

Abundance of facts in the Computer Age

Too many facts are often as much of an obstacle to understanding as
too few. There is a sense in which we moderns are inundated with facts
to the detriment of understanding. - Mortimer Adler

Eric Schmidt, chief executive of Google, stated that "instantaneous
devices" and the abundance of information people are exposed to
through e-mail and other technology-based sources could be having an
impact on the thought process, obstructing deep thinking,
understanding, impedes the formation of memories and makes learning
more difficult. -Wikipedia

On communication skill.

The skill of communication is about comprehension as much as it is about explanation.
It depends neither on language, nor grammar, nor spelling, nor pronunciation, nor all combined.
It is beyond all these... they just help reducing the ambiguities!

Linux: behavior of symbolic link and argv[0]; busybox and multiarch_wrapper

~# cat a.c

#include <stdio.h>
int main(int argc, char** argv)
{
printf("%s\n", argv[0]);
}

~# gcc a.c
~# ln -s a.out kk
~# ./kk
./kk
~#

Program prints argv[0]. But we did kk -> a.out.
Notice that whe we execute ./kk,
argv[0] is not ./a.out, but ./kk !

This idea is used in busybox and
to call different architecture dependent binaries
depending on USE_ARCH environment variable.

http://www.embeddedlinux.org.cn/EmbeddedLinuxPrimer/0136130550/ch11lev1sec3.html
http://www.clfs.org/view/CLFS-3.0.0-SYSVINIT/x86_64/final-system/multiarch_wrapper.html

Linux: Erase/clean MBR(partition table included) of a (pen)drive/block device using dd command

MBR size is (in bytes): 446 + 64 + 2 = 512

446 bytes - Bootstrap code.
64 bytes - Partition table.
2 bytes - Signature.

So
# dd if=/dev/zero of=/dev/sdb bs=512 count=1
cleans everything in the MBR.

Dynamic programming Vs Divide and Conquer

Dynamic programming is a method for solving a bigger problem by breaking it down into smaller subproblems, solving each of those subproblems only once and storing their solutions. Next time the same subproblem occurs, instead of recomputing its solution, we simply look up the previously stored solution, hence saving computation time at the expense of some amount storage space. Each of the subproblem's solution is indexed/hashed in some way, normally based on the value of its input parameters, so as to facilitate lookup. The technique of storing solutions to subproblems instead of recomputing them is called "memoization". It is an optimization technique.

Divide and Conquer works in these steps.
Divide: Divide the main problem into small subproblems.
Conquer: Solve those subproblems recursively.
Combine: Combine results of subproblems to compute result of main problem.

Dynamic Programming is similar to Divide and Conquer when it comes to dividing bigger problems into smaller subproblems. But here, each subproblem is solved only once. In Divide and Conquer, the subproblems are independent of each other while in case of Dynamic Programming, subproblems are not independent of each other. Solution of one subproblem may be required to solve another subproblem. That is why in Dynamic programming solutions to subproblems are remembered. We store the result of subproblems in a table so that we don't have to compute the result of a subproblem again and again.

Divide and Conquer example: Merge Sort
Dynamic Programming example: Tower of Hanoi, Nth Fibonacci number
function fib(n)
if n <= 1 return n
return fib(n − 1) + fib(n − 2)

Jon Bentley on code correctness.

"If it doesn't have to be correct, I can make it as fast as you'd like it to be" - Jon Bentley

Big Omega, Big Theta and Big Omicron.

In code complexity measure,

Big Omega gives us asymptotic lower bound function g(n).
Big Theta gives us asymptotically tight bound function g(n), i.e. both lower and upper bound being c1.g(n) and c2.g(n) respectively.
Big Omicron gives us asymptotic upper bound function g(n).

Most of the time we talk about Big Oh. That is actually Big Omicron.
[The character O is the upper-case Greek letter Omicron, not English letter O]

And surprisingly, when we say, complexity of a code is O(N^2) etc,
we really mean Big Theta! We not only mean, N^2 being the upper bound,
but also we mean, N^2 is the lower bound too. Isn't it?

Ignorance is bliss...

"Where ignorance is bliss, 'tis folly to be wise." -Thomas Gray

Static:Dynamic and Strong:Weak Typing.

Static languages = statically typed language = type is known from program text.
Dynamic languages = dynamically typed language = type is known when program runs.

But, dynamic typing != weak typing.
And static typing != strong typing.

Strong typing = Variables have specific data types. Once you assign a variable to something, it is bound to that type.
Weak typing = Variables are not strictly bound to a given data type. Variable's value can be interpreted differently.

Static typing can also be weak, as in C.
Static typing can also be strong, as in Java.

Java is statically typed and strongly typed.
C is statically typed but weakly typed.
Python is dynamically typed and strongly typed.
PHP is dynamically typed but weakly typed.

A good read: https://prateekvjoshi.com/2014/10/03/static-vs-dynamic-typing/

Dynamically typed languages and maintenance of large code bases.

Dynamically typed languages make it more difficult to maintain large code bases.
Mostly because errors that are caught by a statically typed languages are now not available for free.
Programmer must write test cases to ensure correctness.

A good read: https://softwareengineering.stackexchange.com/questions/221615/why-do-dynamic-languages-make-it-more-difficult-to-maintain-large-codebases

Javascript hoisting

In JavaScript, a name enters a scope in one of four basic ways (and in this order):
1. Language-defined: All scopes are, by default, given the names 'this' and 'arguments'.
2. Formal parameters: Functions can have named formal parameters, which are scoped to the body of that function.
3. Function declarations: These are of the form function foo() {}.
4. Variable declarations: These take the form var foo;.


Function declarations and variable declarations are always moved ("hoisted") invisibly to the top of their containing scope by the JavaScript interpreter.

The assignment portion of the declarations were not hoisted. Only the name is hoisted. Actual assignment to the variable name waits at its own line. This is not the case with function declarations, where the entire function body will be hoisted as well.

While hoisting, if a function name has already been defined, it is never overridden by another variable of the same name. This means that a function declaration takes priority over a variable declaration. This does not mean that an assignment to that variable name will not work, just that the declaration portion will be ignored while hoisting takes place. Since actual assignment to the variable name waits at its own line, after assignment the variable name (and its behavior) hides/overrides the function name.

Example:

1.
function example()
{
foo(); // TypeError "foo is not a function"
bar(); // valid
baz(); // TypeError "baz is not a function"
spam(); // ReferenceError "spam is not defined"
var foo = function () {}; // anonymous function expression (only 'foo' gets hoisted)
function bar() {}; // function declaration ('bar' and the function body get hoisted)
var baz = function spam() {}; // named function expression (only 'baz' gets hoisted)
foo(); // valid
bar(); // valid
baz(); // valid
spam(); // ReferenceError "spam is not defined"
}

2.
<script type="text/javascript">
document.write( f(3) + "<br/>")
var f=function(x) { return x+1; }
function f(x) { return x+2; }
document.write( f(3) + "<br/>")
</script>

This code is equivalent to:

<script type="text/javascript">
function f(x) { return x+2; }
var f; //until assignment this declaration doesn't change behavior of f()
document.write( f(3) + "<br/>")
f=function(x) { return x+1; } //after this assignment, behavior of old f() gets lost
document.write( f(3) + "<br/>")
</script>


Source: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html

Create iso file from CD/DVD using Linux dd command

# isoinfo -d -i /dev/cdrom | grep -i -E 'block size|volume size'
Logical block size is: 2048
Volume size is: 327867

# dd if=/dev/cdrom of=/path/to/my.iso bs=<block size from above> count=<volume size from above>

Source: https://www.thomas-krenn.com/en/wiki/Create_an_ISO_Image_from_a_source_CD_or_DVD_under_Linux

Almost self printing Javascript program

<script type="text/javascript">
( function f() { document.write( f ) }() )
</script>

Virtualbox folder sharing

Here are the instructions:

When Guest and Host are Linux/Windows...
http://www.murga-linux.com/puppy/viewtopic.php?t=76061

When Guest and Host both are Linux...
http://www.murga-linux.com/puppy/viewtopic.php?t=110070

An Engineer and a Salesman

An Engineer is said to be a man who knows a great deal about a very little, and who goes around knowing more and more, about less and less, until finally, he practically knows everything about nothing; whereas, a Salesman, on the other hand, is a man who knows a very little about a great deal, and keeps on knowing less and less about more and more until finally he knows practically nothing, about everything. – from a newspaper in the 1930s

http://harry-lewis.blogspot.in/2016/12/classics-of-computer-science.html

LOC Produced

If we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent".

- Edsger Wybe Dijkstra

(in EWD 1036: On the cruelty of really teaching computing science)

Sync database with SJA (SQLyog Job Agent)

~# /opt/lampp/bin/mysql -u root -p -e "create database flog"
~# /opt/lampp/bin/mysqldump -d -u root -p blog > blog.sql
[-d means without data, that means only schema export]
~# /opt/lampp/bin/mysql -u root -p flog < /root/blog.sql
~# mkdir sja
~# cd sja
[download sja from https://code.google.com/p/sqlyog/wiki/Downloads]
~/sja# tar -xvzf sja1209.x86_64.tar.gz
~/sja# ./sja blog_to_flog_sync.xml
[if sja says, couldn't connect through /tmp/mysql.sock, ln -s /opt/lampp/var/mysql/mysql.sock /tmp/mysql.sock]
============

~/sja# cat blog_to_flog_sync.xml
<?xml version="1.0" encoding="UTF-8"?>
<job version="11.1">
<syncjob>
<fkcheck check="yes" />
<twowaysync twoway="no" />
<source>
<host>localhost</host>
<user>root</user>
<pwd></pwd>
<port>3306</port>
<compressed>1</compressed>
<cleartext>0</cleartext>
<sessiontimeout>28800</sessiontimeout>
<ssl>0</ssl>
<sslauth>0</sslauth>
<clientkey></clientkey>
<clientcert></clientcert>
<cacert></cacert>
<cipher></cipher>
<charset></charset>
<database>blog</database>
</source>
<target>
<host>localhost</host>
<user>root</user>
<pwd></pwd>
<port>3306</port>
<compressed>1</compressed>
<cleartext>0</cleartext>
<ssl>0</ssl>
<sslauth>0</sslauth>
<clientkey></clientkey>
<clientcert></clientcert>
<cacert></cacert>
<cipher></cipher>
<charset></charset>
<database>flog</database>
</target>
<tables all="yes" />
<sync_action type="directsync" />
<abortonerror abort="no" />
<sendreport send="no" /></syncjob>
</job>
~/sja#

How to run your own OS kernel

# prepare a disk image to boot
harddisk_image_size=$((4*1024*1024)) # 4 megabytes
harddisk_image="harddisk.img"
kernel_args=""
kernel_binary="bin/kernel.bin"
if [ ! -f $harddisk_image ]
then
# create image
dd if=/dev/zero of="$harddisk_image" bs=4k count=$((harddisk_image_size/4096)) 2>/dev/null
# format image
mkfs.vfat "$harddisk_image"
# install syslinux
syslinux "$harddisk_image"
# copy mboot.c32 (required for Multiboot)
mcopy -i "$harddisk_image" /usr/lib/syslinux/mboot.c32 ::mboot.c32
# create syslinux.cfg
echo '
TIMEOUT 1
DEFAULT mboot.c32 kernel.bin '$kernel_args'
' | mcopy -i "$harddisk_image" - ::syslinux.cfg
fi
# now copy your own OS kernel to it
mkdir -p /tmp/harddisk
mount -o loop "$harddisk_image" /tmp/harddisk
cp "$kernel_binary" /tmp/harddisk
umount /tmp/harddisk






# prepare another disk to store some data
if [ ! -f "harddisk2.img" ]
then
dd if=/dev/zero of=harddisk2.img bs=4096 count=2560 # 10 megabytes
mkfs.ext2 -F -N 4096 -b 4096 harddisk2.img 2560
fi
# copy data to it
mkdir -p /tmp/harddisk
mount -o loop harddisk2.img /tmp/harddisk
cp -r ../hdd/* /tmp/harddisk
umount /tmp/harddisk





# prepare yet another disk to use with virtio
cp harddisk2.img harddisk3.img





# now run quemu

# booting from bootable disk
#qemu-system-i386 -m 64 -vga vmware -serial stdio -hda ./harddisk.img

# booting kernel directly from binary
#qemu-system-i386 -m 64 -vga vmware -serial stdio -kernel "$kernel_binary"

# booting from virtio disk (bootable) - works!
#qemu-system-i386 -m 64 -vga vmware -serial stdio -drive file=harddisk.img,if=virtio

# all together: booting kernel.bin, hda with ext2 fs, another non-bootable ext2 disk connected through virtio interface
#qemu-system-i386 -m 64 -vga vmware -serial stdio -kernel "$kernel_binary" -hda ./harddisk2.img -drive file=harddisk3.img,if=virtio

A function and a macro with same name.

~# cat a.c
#include<stdio.h>
#define inc(a) inc(a,1)
int inc(int a, int b)
{
return a+b;
}
int main()
{
int k = 9;
k = inc(k);
printf("%d\n", k);
return 0;
}
~# gcc a.c
a.c:3:21: error: macro "inc" passed 2 arguments, but takes just 1
a.c:4:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
~#

Here both function and macro with same name can't co exist.
Preprocessor performs macro expansion at function definition as well (at line 3).
But we don't want preprocessor to perform macro expansion there.
So we simply enclose the function name with parentheses while defining the function.
And we are done.

~# cat a.c
#include<stdio.h>
#define inc(a) inc(a,1)
int (inc)(int a, int b)
{
return a+b;
}
int main()
{
int k = 9;
k = inc(k);
printf("%d\n", k);
return 0;
}
~# gcc a.c
~# ./a.out
10
~#