22.12.07

Serializing JavaScript objects

I once have written a JavaScript function that dumps a JavaScript object in a human readable format. It was something like JSON, but it also handled objects containing circular references shared object references. I must admit that it was written badly.

After reading this, I thought that maybe it's a good idea to change the previous code for serializing JavaScript objects. I also refactored the code. You can find it below. I didn't test it thoroughly, so be careful.

An example of what it can do:
var x = {};

x.foo  = new Object();
x.self = x;
x.arr  = [x.self];
x.bar  = x.foo;

var s = serialize(x);
var y = deserialize(s);
alert(y == y.self);    // true
alert(y == y.arr[0]);  // true
alert(y.foo == y.bar); // true

alert(s);
// {
//     'foo': {},
//     'self': { _root_: [  ] },
//     'arr': [
//         { _root_: [  ] }
//     ],
//     'bar': { _root_: [ "foo" ] }
// }
Addition: I think that I have to express that better: don't expect it to serialize functions, regular expressions, images (or any other browser object), etc. It's just something like JSON, but it also handles shared object references. Code:
//============================================================================//
//  JavaScript object de/serialization with circular references.              //
//                                                                            //
//  author: Mehmet Yavuz Selim Soyturk                                        //
//  e-mail: Mehmet dot Yavuz dot Selim at gmail dot com                       //
//============================================================================//

Array.prototype.findIf = function(predicate) {
    for(var i in this) {
        if (predicate(this[i]))
            return i;
    }
    return -1;
};
Array.prototype.map = function(func) {
    var len = this.length;
    var result = [];
    for (var i=0; i<len; i++) {
        result[i] = func(this[i]);
    }
    return result;
};
Array.prototype.appended = function(value) {
    var copy = this.slice(0);
    copy[copy.length] = value;
    return copy;
};

//============================================================================//
//  SERIALIZATION                                                             //
//============================================================================//

function indented(n) {
    var s = '';
    for(var i=0; i<n; i++) s += '    ';
    return s;
}

function serializePrimitive(value) {
    if (typeof value == 'string')
        return '"' + value + '"';
    else
        return '' + value;
}

function serializePrimitiveArray(arr) {
    var s = "[ ";
    s += arr.map(serializePrimitive).join(', ');
    s += " ]";
    return s;
}

function serializeArray(arr, seen, indices, depth) {
    if (arr.length == 0)
        return '[]';

    seen[seen.length] = {obj: arr, indices: indices};
    
    var result = '[\n';
    for (var i=0; i<arr.length; i++) {
        result += indented(depth + 1);
        result += serializeAny(arr[i], seen, indices.appended(i), depth + 1);
        result += (i == arr.length - 1) ? '' : ', ';
        result += '\n';
    }
    result += indented(depth) + ']';

    return result;
}

function serializeObject(obj, seen, indices, depth) {
    seen[seen.length] = {obj: obj, indices: indices};
    
    var result = '{\n';
    var count = 0;
    for (var i in obj) {
        if (typeof obj[i] != 'function') {
            count++;
            result += indented(depth+1);
            result += "'" + i + "': ";
            result += serializeAny(obj[i], seen, indices.appended(i), depth + 1);
            result += ", \n"; // bad hack, see next
        }
    }
    if (count > 0) {
        result = result.substring(0, result.length-3) + '\n'; // bad hack
        return result + indented(depth) + '}';
    }
    else {
        return '{}';
    }
}


function serializeAny(value, seen, indices, depth) {
    var t = typeof(value);
    var prevIndex;
    
    if (t == 'function') {
        throw new Error("Cannot serialize function. Keys from root: " + 
            serializePrimitiveArray(indices));
    }
    else if (t != 'object') {
        return serializePrimitive(value);
    }
    else if ( (prevIndex = seen.findIf
                    ( function(obj) { return obj.obj == value } )
              ) >= 0) {
        return '{ _root_: ' + serializePrimitiveArray(seen[prevIndex].indices) + ' }';
    }
    else if (value.constructor == Array) {
        return serializeArray(value, seen, indices, depth);
    }
    else {
        return serializeObject(value, seen, indices, depth);
    }
};

function serialize(obj) {
   return serializeAny(obj, [], [], 0);
}


//============================================================================//
//  DESERIALIZATION                                                           //
//============================================================================//

function followIndices(obj, indices) {
    for (var i=0; i<indices.length; i++)
        obj = obj[indices[i]];
        
    return obj;
}

function replaceRootRefs(obj, root) {
    if (typeof obj != 'object' || obj == null)
        return;
    
    for (var i in obj) {
        var prop = obj[i];
        if (typeof prop == 'object' && prop != null) {
            if ('_root_' in prop)
                obj[i] = followIndices(root, prop._root_);
            replaceRootRefs(prop, root);
        }
    }
}

function deserialize(str) {
    var obj = eval( '(' + str + ')' );
    if (str.indexOf('_root_') < 0)
        return obj;
    
    replaceRootRefs(obj, obj);
    return obj;
}

15.12.07

Kablosuz aglari dinlemek icin

Interface'i monitor moda getir:
$ sudo iwconfig eth1 mode monitor
Wireshark'i calistir:
$ sudo wireshark
Dinle ve interface'i eski haline getir:
$ sudo iwconfig eth1 mode managed

13.12.07

latex, html, plain text

Converting latex to html, if the tex file has utf8 encoding:
latex2html -html_version 4,unicode document.tex
If you want only one page:
latex2html -split 0 -html_version 4,unicode document.tex
Converting html to plain tex:
elinks -dump document.html

16.11.07

Output buffer unwinding for PHP?

PHP 5 supports exception handling. When an exception occurs, PHP does stack unwinding so that it restores the state of the script... does it? No. An important state of the script does not get restored: the output. Would it not be a good idea if PHP also did some sort of output buffer unwinding? That is the idea:
<?php

exceptional_ob_start();

echo "Begin\n";
try {
    echo "Exception\n";
    throw new Exception();
} catch (Exception $e) {}
echo "End\n";

exceptional_ob_end_flush();
    
?>
And that is the only output:
Begin
End
I am not a PHP (nor webscripting) guy so I may be wrong, but I think that something like that would be very useful. It is maybe even needed for making PHP exceptions useful.
 

18.8.07

Currying in JavaScript

We can make our functions curried in JavaScript:
function curry(f, needed_len) {
    if (needed_len == undefined)
        needed_len = f.length;
        
    var curried = function() {
        var curried_args = arguments;
        if (curried_args.length >= needed_len) {
            return f.apply(this, arguments);
        }
        else {
            var curry_result_function = function() {
                var args = [];
                for(var i=0; i<curried_args.length; i++)
                    args[args.length] = curried_args[i];
                
                for(var i=0; i<arguments.length; i++)
                    args[args.length] = arguments[i];

                return f.apply(this, args);
            };
            return curry(curry_result_function, needed_len-curried_args.length);
        }
    };
    return curried;
}
And usage:
var curried_add = curry(function (a, b, c) {
    return a + b + c;
});

print(curried_add(1)(2)(3));
print(curried_add(1)()(2)()(3));
print(curried_add(1,2,3));
print(curried_add(1)(2,3));
print(curried_add(1,2)(3));
See also next pages for other implementations: http://www.dustindiaz.com/javascript-curry http://www.svendtofte.com/code/curried_javascript/
 
Note: after some more googling about currying in JavaScript, it's very interesting to see that http://www.coryhudson.com/blog/2007/03/10/javascript-currying-redux/ contains an almost identical implementation.

30.7.07

JavaScript'de eval ve closure'un gucu

Kendi halinde basit bir fonksiyonumuz olsun:
function myEval(code) {
    return eval(code);
}
Simdi kendimize bir sayac yapalim:
var inject = 'var n=0; var f=function(){return n++}; f';
var sayac = myEval(inject);

alert(sayac()); // 0
alert(sayac()); // 1
alert(sayac()); // 2

5.6.07

vim ile dosya calistirmaca

bakiniz: http://blog.arsln.org/vim-icinden-python-kodu-calistirmak/ Simdi bunu F8'e basildiginda her dosyayi calistirir hale getirmek gerek. Bunu daha once emacs icin yapmistim, ancak isin mantigini da elisp ile yaptirmaya ugrastigim icin karman corman birsey olmustu ne yazik ki. Simdi aklim basima geldi, bu isi bir shell script'e yaptirmak gerek. Bu ~/bin/calistir dosyasinin icerigi:
#!/bin/bash

dosya=$1

case $dosya in

"")
   echo "Kullanim: $0 <dosya_ismi>"
   ;;
*.js)
   js $dosya
   ;;
*.py)
   python $dosya
   ;;
*.sh)
   /bin/bash $dosya
   ;;
*.rb)
   ruby $dosya
   ;;
*.c)
   gcc $dosya
   ./a.out
   ;;
*.cpp)
   g++ $dosya
   ./a.out
   ;;
/*)
   $dosya
   ;;
*)
   ./$dosya
   ;;

esac
Ve ~/.vimrc dosyasina su satiri ekliyoruz:
map <F8> :!/home/kullanici/bin/calistir % <ENTER>
Bu da ~/.emacs dosyasina:
(defun exec-file () 
  "Execute a file, if possible."
  (interactive)
  (let ((curr-buf (buffer-name))
        (exec-buffer "execute-buffer"))
    (if (get-buffer exec-buffer) 
    
      ;; su anda bir calistirma buffer'i acik, kapat
      (kill-buffer exec-buffer)
      
      ;; calistir
      (progn
        (call-process "/home/kullanici/bin/calistir" nil exec-buffer t curr-buf)
        (switch-to-buffer-other-window exec-buffer)
        (switch-to-buffer-other-window curr-buf)))))

(global-set-key [f12] 'exec-file)

22.5.07

En cok kullandigim linux komutlari

Burada en cok kullandiginiz linux komutlarini ogrenmek icin bir yontem gosterilmis. Ben de hemen denedim, sonuc soyle:
$ history|awk '{print $2}'|awk 'BEGIN {FS="|"} {print $1}'|sort|uniq -c|sort -rn|head -10
  77 ls
  76 make
  50 cd
  34 pjs
  31 nano
  20 parrot
  19 rm
  18 js
  17 new
  16 svn
ls'in en cok kullandigim komut olmasina sasirmamak gerek. Terminalde yaptigim her hareketten once cagiririm onu. parrot, pjs, js, make ve svn komutlari da yapmakta oldugum proje nedeniyle bolca kullandigim komutlar.

25.4.07

Nurikabe

Vakit oldurmek icin birebir. Sudoku bana pek eglenceli gelmemisti, ama nurikabe bayagi zevkli geldi. Biraz bilgi edindikten sonra oynamaya buradan baslayabilirsiniz.