Vkontakte additional links

By elamskoy Last update Jul 19, 2009 — Installed 7,610 times. Daily Installs: 17, 9, 12, 13, 12, 11, 9, 15, 12, 11, 10, 10, 12, 7, 15, 8, 19, 11, 10, 10, 9, 15, 16, 3, 8, 3, 3, 6, 9, 4, 9, 7

There are 36 previous versions of this script.

Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

// ==UserScript==
// @name           Vkontakte additional links
// @author         Eugene Lamskoy
// @description    Additional links and features for Vkontakte.ru
// @include        http://vkontakte.ru/*
// ==/UserScript==

/**
 * Thanks for regizz for ukrainian translation (http://userscripts.org/users/100131)
 * Script uses next 3d party components:
 * 1. adopted each() function from jquery library 
 */

(function(){
    /**
     * Constants
     */
    Const = {
        'version' : '0.190',
        'consoleEnabled' : false,
        'homepage' : 'http://userscripts.org/scripts/show/43183',
        'scriptSource' : 'http://userscripts.org/scripts/source/43183.user.js',
        'author' : 'http://vkontakte.ru/id3095966',
        'groupPage' : 'http://vkontakte.ru/club9266497'
    };

    /**
     * Multilanguage translations
     */
    Lang = {
        'en' : {
            'update' : {
                'confirm' : "Vkontakte Additional Links Updater \n\nNew version is available: {0}\nYour current version is: {1}\n\nDo you want to upgrade?",
                'menuTitle' : "Vkontakte Additional Links - Check for updates",
                'noUpdates' : "No updates found. Wait a little bit while author make upgrade :)"
            },
            'links' : {
                'homepageTitle' : '[ Homepage ]',
                'authorTitle' : '[ Author ]',
                'groupTitle' : '[ VK Group ]',
                'downloadVideo' : 'Download video',
                'downloadAudio' : 'Download'
            },
            'search': {
                'photosLink': 'Photos',
                'photosWithLink': 'Photos with user',
                'notesLink': 'Notes',
                'questionsLink': 'Questions',
                'audioLink': 'Audio',
                'videoLink': 'Video',
                'groupsLink': 'Groups',
                'wallLink': 'Wall',
                'friendsLink' : 'Friends',
                'sendLink' : 'Send message'
            },
            'groups': {
                'photosLink': 'Photos',
                'audioLink': 'Audio',
                'videoLink': 'Video',
                'boardsLink': 'Boards',
                'wallLink': 'Wall',
                'membersLink': 'Members'
            },
            'favourites' : {
                'addLink' : 'Add to favourites',
                'delLink' : 'Remove from favourites'
            },
            'settings' : {
                'title' : 'Additional links settings',
                'myFriends' : 'Show additional links on "My friends", "Friends of user" pages',
                'favouritesLinks': 'Show additional links on  "My Bookmarks" (add/delete) ',
                'favouritesOnline': 'Show all users on "My bookmarks" in one table with status icon (online/offline)',
                'searchMode' : 'Show links on "Members search"',
                'inviteToGroup' : 'Show links in extended "Invite to group" mode',
                'deletedPages' : 'Show links on pages of deleted members',
                'groups' : 'Show links on "Search groups", "Groups of user" pages',
                'awayLinks' : 'Don\'t show redirect page while opening external links',
                'favouritesEnlarge' : 'Increase width of "My bookmarks" users list',
                'eraseAds' : 'Erase banners on all pages',
                'sidebarOneWord' : 'Erase "My" prefixes in left sidebar',
                'onlineTextToImage' : 'Replace "Online" text with image',
                'videoLinks' : 'Display "Download video" links',
                'audioLinks' : 'Display "Download audio" links',
                'albumsFlashUpload' : 'Use "Flash uploader" for photos by default',
                'appendUploadPhotos' : 'Enlarge upload files count to 6 in default images uploader'
            }
        },
        'ru' : {
            'update' : {
                'confirm' : "Обновление Vkontakte Additional Links\n\nДоступна новая версия: {0}\nВаша текущая версия: {1}\n\nХотите обновиться?",
                'menuTitle' : "Vkontakte Additional Links - Проверить наличие обновлений",
                'noUpdates' : "Обновления не найдены. Подождите пока автор не выпустит очередную версию :)"
            },
            'links' : {
                'homepageTitle' : '[ Домашняя страница ]',
                'authorTitle' : '[ Автор скрипта  ]',
                'groupTitle' : '[ Группа Вконтакте ]',
                'downloadVideo' : 'Скачать видео',
                'downloadAudio' : 'Скачать'
            },
            'search': {
                'photosLink': 'Фотографии',
                'photosWithLink': 'Фото с пользователем',
                'notesLink': 'Заметки',
                'questionsLink': 'Вопросы',
                'audioLink': 'Аудио',
                'videoLink': 'Видео',
                'groupsLink': 'Группы',
                'wallLink': 'Стена',
                'friendsLink' : 'Друзья пользователя',
                'sendLink' : 'Отправить сообщение'
            },
            'groups': {
                'photosLink': 'Фотографии',
                'audioLink': 'Аудио',
                'videoLink': 'Видео',
                'boardsLink': 'Обсуждения',
                'wallLink': 'Стена',
                'membersLink': 'Члены группы'
            },
            'favourites' : {
                'addLink' : 'Добавить в закладки',
                'delLink' : 'Удалить из закладок'
            },
            'settings' : {
                'title' : 'Настройки дополнительных ссылок',
                'myFriends' : 'Отображать дополнительные ссылки на странице "Мои друзья", "Друзья пользователя"',
                'favouritesLinks': 'Отображать дополнительные ссылки на странице "Мои закладки" (удалить/добавить) ',
                'favouritesOnline': 'Отображать всех пользователей в закладках в одной таблице с иконкой статуса (онлайн/оффлайн)',
                'searchMode' : 'Отображать ссылки в режиме "Поиск пользователей"',
                'inviteToGroup' : 'Отображать ссылки в режиме расширенного приглашения в группу',
                'deletedPages' : 'Отображать ссылки на страницах удаленных пользователей',
                'groups' : 'Отображать ссылки при поиске групп и в "Друзьях пользователя"',
                'awayLinks' : 'Не показывать страницу переадресации при переходе по внешней ссылке',
                'favouritesEnlarge' : 'Увеличить ширину блока с пользователями в "Моих закладках"',
                'eraseAds' : 'Удалить баннеры на всех страницах',
                'sidebarOneWord' : 'Удалить префиксы "Моя/мои" в панели ссылок',
                'onlineTextToImage' : 'Заменить текст "Online" на картинку',
                'videoLinks' : 'Отображать ссылки "Скачать видео"',
                'audioLinks' : 'Отображать ссылки "Скачать аудио"',
                'albumsFlashUpload' : 'Использовать флеш-загрузчик фотографий по умолчанию',
                'appendUploadPhotos' : 'Расширить количество файлов до 6 в обычном загрузчике фотографий'
            }
        },
        // Перевод на украинский by regizz (http://userscripts.org/users/100131)
        'ua' : {
          'update' : {
              'confirm' : "Оновлення Vkontakte Additional Links\n\nДоступна нова версія: {0}\nВаша поточна версія: {1}\n\nХочете поновити?",
              'menuTitle' : "Vkontakte Additional Links - Перевірити наявність оновлень",
              'noUpdates' : "Обновленя відсутні. Зачекайте доки автор напише нову версію :)"
              
          },
          'links' : {
              'homepageTitle' : '[ Домашня сторінка ]',
              'authorTitle' : '[ Автор скрипту  ]',
              'groupTitle' : '[ Група Вконтакті ]',
              'downloadVideo' : 'Скачати відео',
              'downloadAudio' : 'Скачати'
          },
          'search': {
              'photosLink': 'Фотографії',
              'photosWithLink': 'Фото з користувачем',
              'notesLink': 'Нотатки',
              'questionsLink': 'Питання',
              'audioLink': 'Аудіо',
              'videoLink': 'Відео',
              'groupsLink': 'Групи',
              'wallLink': 'Стіна',
              'friendsLink' : 'Друзі користувача',
              'sendLink' : 'Відправити повідомлення'
          },
          'groups': {
              'photosLink': 'Фотографії',
              'audioLink': 'Аудіо',
              'videoLink': 'Відео',
              'boardsLink': 'Обговорення',
              'wallLink': 'Стіна',
              'membersLink': 'Члени групи'
          },
          'favourites' : {
              'addLink' : 'Додати в закладки',
              'delLink' : 'Втидалити з закладок'
          },
          'settings' : {
              'title' : 'Налаштування додаткових посиланнь',
              'myFriends' : 'Показувати додаткові посилання на сторінці "Мої друзі", "Друзі користувача"',
              'favouritesLinks': 'Показувати додаткові посілання на сторінці "Мої закладки" (видалити/додати) ',
              'favouritesOnline': 'Показувати усіх користувачів у закладках в одній таблиці з іконкою статусу (онлайн/оффлайн)',
              'searchMode' : 'Показувати посилання в режимі "Пошук користувачів"',
              'inviteToGroup' : 'Показувати посилання в режимі розширеного запрошення в групу',
              'deletedPages' : 'Показувати посилання на сторінках видалених користувачів',
              'groups' : 'Показувати посилання при пошуку груп і у "Друзях користувача"',
              'awayLinks' : 'Не показувати сторінку переадресації при переході за зовнішнім посиланням',
              'favouritesEnlarge' : 'Збільшити ширину блоку з користувачами у "Моїх закладках"',
              'eraseAds' : 'Прибрати банери на всіх сторінках',
              'sidebarOneWord' : 'Прибрати префікси "Моя/мої" на панелі посиланнь',
              'onlineTextToImage' : 'Замінювати текст "Online" на картинку',
              'videoLinks' : 'Показувати посилання "Скачати відео"',
              'audioLinks' : 'Показувати посилання "Скачати аудіо"',
              'albumsFlashUpload' : 'Використовувати флеш-завантажувач фотографій за замовчуванням',
              'appendUploadPhotos' : 'Розширити кількість файлів до 6 у звичайному завантажувачі фотографій'
          }
        },        
        getLanguage : function() {
            var cookie = parseInt(Cookie.get('remixlang')) 
            var defaultLang = "ru"
            var cases = {0:'ru', 1:'ua', 3:'en'}
            for (i in cases) {
                if(i == cookie) {
                    return cases[i]
                }
            }            
            return defaultLang
        },
        text : function(section, val) {
             var code = Lang.getLanguage();
             if(typeof(Lang[code][section][val]) != 'undefined') {
                return Lang[code][section][val];
             }
             return '%%'+section+'.'+val+'%%';
        }
    };

    /**
     * Wrapper for cookies
     * @param {Object} check_name
     */
    Cookie = {
        get : function ( check_name ) {
            var a_all_cookies = document.cookie.split( ';' );
            var a_temp_cookie = '';
            var cookie_name = '';
            var cookie_value = '';
            for ( var i = 0; i < a_all_cookies.length; i++ ) {
                a_temp_cookie = a_all_cookies[i].split( '=' );
                cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
                if ( cookie_name == check_name ) {
                    if ( a_temp_cookie.length > 1 ) {
                        cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
                    }
                    return cookie_value;
                }
            }
            return null;
        }
    };

    /**
     * Settings wrapper
     */
    Settings = {
        store: function(name, value){
            return GM_setValue(name, value);
        },
        load: function(name, defaultVal){
            return GM_getValue(name, defaultVal);
        },
        kill: function(name){
            return GM_deleteValue(name);
        },
        list: function(){
            return GM_listValues();
        }
    };

    Settings.list = {
        update : {
            'internal' : true,
            'key' : 'update_lastChecked',
            'defaultVal' : 0
        },
        updateDelta : {
            'internal' : true,
            'key': 'update_period',
            'defaultVal' : 3600 * 12
        },
        myFriends : {
            'description': Lang.text('settings', 'myFriends'),
            'defaultVal' : true,
            'key' : 'show_myFriends'
        } ,
        favouritesLinks : {
            'description': Lang.text('settings', 'favouritesLinks'),
            'key': 'show_myFavourites',
            'defaultVal' : true
        } ,
        favouritesOnline : {
            'description': Lang.text('settings', 'favouritesOnline'),
            'key': 'online_myFavourtites',
            'defaultVal' : true
        },
        videoLinks : {
            'description': Lang.text('settings', 'videoLinks'),
            'key': 'show_downloadVideo',
            'defaultVal' : true
        },        
        audioLinks : {
            'description': Lang.text('settings', 'audioLinks'),
            'key': 'show_downloadAudio',
            'defaultVal' : true
        },        

        onlineTextToImage : {
            'description': Lang.text('settings', 'onlineTextToImage'),
            'key': 'online_textToImage',
            'defaultVal' : true    
        },
        favEnlarge : {
            'description': Lang.text('settings', 'favouritesEnlarge'),
            'key': 'enlarge_myFavUsers',
            'defaultVal' : false
        } ,
        searchMode    : {
            'description': Lang.text('settings', 'searchMode'),
            'key': 'show_searchMode',
            'defaultVal' : true
        } ,
        inviteToGroup : {
            'description': Lang.text('settings', 'inviteToGroup'),
            'key': 'show_inviteMode',
            'defaultVal' : true
        } ,
        deletedPages : {
            'description': Lang.text('settings', 'deletedPages'),
            'key': 'show_deletedPage',
            'defaultVal' : true
        } ,
        groups : {
            'description': Lang.text('settings', 'groups'),
            'key': 'show_groups',
            'defaultVal' : true
        } ,
        awayLinks : {
            'description': Lang.text('settings', 'awayLinks'),
            'key': 'erase_awayLinks',
            'defaultVal' : false
        } ,
        eraseAds : {
            'description': Lang.text('settings', 'eraseAds'),
            'key': 'erase_advertisements',
            'defaultVal' : true
        },
/*        sidebarOneWord : {
            'description': Lang.text('settings', 'sidebarOneWord'),
            'key': 'split_sidebarLinksTitles',
            'defaultVal' : false        
        },*/
        albumsFlashUpload : {
            'description': Lang.text('settings', 'albumsFlashUpload'),
            'key': 'flash_uploaderByDefault',
            'defaultVal' : false        
        },
        appendUploadPhotos: {
            'description': Lang.text('settings', 'appendUploadPhotos'),
            'key': 'flash_appendUploadPhotos',
            'defaultVal' : false                    
        }

    };

    Settings.autoLoad = function(index) {
        return Settings.load(Settings.list[index].key, Settings.list[index].defaultVal);
    };

    function jeach( object, callback, args ) {
        var name, i = 0;
        if ( args ) {
            if ( typeof(object.length) == 'undefined' ) {
                for ( name in object )
                    if ( callback.apply( object[ name ], args ) === false )
                        break;
            } else
                for ( ; i < object.length; )
                    if ( callback.apply( object[ i++ ], args ) === false )
                        break;
        } else {
            if ( typeof(object.length) == 'undefined' ) {
                for (name in object) {
                     if (callback.call(object[name], name, object[name]) === false) {
                        break;
                    }
                }
            } else
                for ( var value = object[0];
                    i < object.length && callback.call( value, i, value ) !== false; value = object[++i] ){}
        }
        return object;
    };

    

    VersionControl = {
        timestamp : function() {
            return parseInt(new Date().getTime().toString().substring(0, 10))
        },
        init: function() {
            var title = Lang.text('update', 'menuTitle')
            GM_registerMenuCommand(title, VersionControl.check);
            var now = VersionControl.timestamp();
            var lastCheck = parseInt(Settings.autoLoad('update'));
            // Allow update each 12 hours
            var timeDelta = parseInt(Settings.autoLoad('updateDelta'));
            if(lastCheck == 0 || now >= lastCheck + timeDelta) {
                VersionControl.check(true);
            }
        },
        check: function(suppressNoUpdatesMessage) {
            GM_xmlhttpRequest({
              method : "GET",
              url : Const.homepage,
              headers:{
                "User-Agent": navigator.userAgent,
                "Accept": "text/xml"
              },
              onload: function(response) {
                var version = response.responseText.match(/<span>([0-9]+\.[0-9]+)<\/span>/i);
                if( typeof(version[1]) == 'undefined') {
                    return;
                }
                var siteVer = parseFloat(version[1]);
                Settings.store(Settings.list.update.key, VersionControl.timestamp());
                if( parseFloat(siteVer) <= parseFloat(Const.version)) {
                    if( ! suppressNoUpdatesMessage ) {                        
                        alert(Lang.text('update', 'noUpdates')) 
                    }
                    return
                }
                if(confirm(StringsHelper.format(Lang.text('update', 'confirm'), siteVer, Const.version))) {
                    window.location.href = Const.scriptSource;
                }
              }
              });
        }
    }

    /**
     * Vkontakte request map
     */


    Vkontakte = {
        makeRequest : function(options) {
            var args = {
                method: 'POST',
                url: 'http://vkontakte.ru',
                headers: {'Content-type': 'application/x-www-form-urlencoded'}
            };

            if(typeof(options.method) == 'string') {
                args.method = options.method;
            }
            if(typeof(options.url) == 'string') {
                args.url = options.url;
            }
            if(typeof(options.onload) == 'function') {
                args.onload = options.onload;
            }
            if(typeof(options.onerror) == 'function') {
                args.onload = options.onerror;
            }
            if(typeof(options.path) == 'string') {
                args.url += options.path;
            }
            if(typeof(options.params) == 'object') {
                args.data = StringsHelper.http_build_query(options.params);
            } else if(typeof(options.params) == 'string') {
                args.data = options.params;
            }
            //console.log(args)
            GM_xmlhttpRequest(args);
        },

        addPersonToFavourites : function(options) {
            options.path = '/fave.php';
            options.params = {'act':'addPerson', 'mid':options.id};
            Vkontakte.makeRequest(options);
        },
        addGroupToFavourites : function(options) {
            options.path = '/fave.php';
            options.params = {'act':'addGroup', 'gid':options.id};
            Vkontakte.makeRequest(options);
        },
        deletePersonFromFavourites : function(options) {
            options.path = '/fave.php';
            options.params = {'act':'deletePerson', 'mid':options.id};
            Vkontakte.makeRequest(options);
        },
        deleteGroupFromFavourites : function(options) {
            options.path = '/fave.php';
            options.params = {'act':'deleteGroup', 'gid':options.id};
            Vkontakte.makeRequest(options);
        },
        addDelFavouritesCombined : function(options) {
            var gMode = typeof(options.groupMode) != 'undefined' ? options.groupMode : false;
            var aMode = typeof(options.addMode) != 'undefined' ? options.addMode : true;
            var processors = {
                'add' :  {'group' : Vkontakte.addGroupToFavourites, 'person' : Vkontakte.addPersonToFavourites},
                'del' :  {'group' : Vkontakte.deleteGroupFromFavourites, 'person' : Vkontakte.deletePersonFromFavourites},
            };
            gMode = gMode == true ? 'group' : 'person';
            aMode = aMode == true ? 'add' : 'del';
            //Console.log(aMode, gMode);
            return (processors[aMode][gMode])(options);
        }
    };



    /**
     * FavouritesInnerObj
     * @param {Object} options
     */
    FavouritesInnerObj = function(options) {
        this.obj = null;
        this.images = {};
        this.text = {};
        this.init(options);
    };
    FavouritesInnerObj.prototype = {
        init: function(options) {
            this.images.add = options.addImage ? options.addImage : false;
            this.images.del = options.delImage ? options.delImage : false;
            this.images.load = options.loadImage ? options.loadImage : false;
            this.text.add = options.addText ? options.addText : false;
            this.text.del = options.delText ? options.delText : false;
        },
        addRenderer: function() {
            var out = [];
            if(this.images.add) {
                var img = document.createElement('img');
                img.setAttribute('src', this.images.add);
                out.push(img);
            }
            if(this.text.add) {
                out.push(this.text.add);
            }
            return out;
        },
        delRenderer: function() {
            var out = [];
            if(this.images.del) {
                var img = document.createElement('img');
                img.setAttribute('src', this.images.del);
                out.push(img);
            }
            if(this.text.del) {
                out.push(this.text.del);
            }
            return out;
        },
        loadRenderer: function() {
            var img = document.createElement('img');
            img.setAttribute('src', this.images.load);
            return [img];
        }
    };


    /**
     * Favourites Link object
     * @param {Object} options
     */
    function FavouritesLink(options){
        this.obj = null;
        this.pictureMode = false;
        this.addMode = false;
        this.section = '';
        this.id = 0;
        this.img = null;
        this.renderer = null;
        this.loadMode = false;
        this.init(options);
        return this.obj;
    }
    FavouritesLink.prototype = {
        objToHtml : function(arg) {
            var div = document.createElement('div');
            jeach(arg, function(key, obj) {
                if(typeof(obj) != 'string') {
                    div.appendChild(obj);
                } else {
                    div.innerHTML += obj;
                }
            });

            return div.innerHTML;
        },
        render : function() {
            this.obj.href = 'javascript:void(0);';
            var rObj = null;
            if(this.loadMode) {
                rObj = this.renderer.loadRenderer();
                this.loadMode = false;
            } else {
                rObj = this.addMode ? this.renderer.addRenderer() : this.renderer.delRenderer();
            }
            this.obj.innerHTML = this.objToHtml(rObj);
        },
        init : function(options) {
            this.pictureMode = typeof(options.pictureMode) != 'undefined' ? options.pictureMode : false;
            this.obj = document.createElement('a');
            this.addMode = typeof(options.addMode) != 'undefined' ? options.addMode : true;
            this.groupMode = typeof(options.groupMode) != 'undefined' ? options.groupMode : false;
            this.section = options.section;
            this.id = options.id;
            this.loadMode = false;
            var picRender = {'addImage': Images['add'], 'delImage' : Images['delete'], 'loadImage': Images['loader'] };
            var txtRender = {'addText' : Lang.text('favourites', 'addLink'), 'delText' : Lang.text('favourites', 'delLink'),  'loadImage': Images['loader'] };
            var rOptions = this.pictureMode ? picRender : txtRender;
            this.renderer = new FavouritesInnerObj(rOptions);
            this.render();

            // Трюк для замыкания
            var self = this;
            this.obj.addEventListener('click', function() {
                self.loadMode = true;
                self.render();
                Vkontakte.addDelFavouritesCombined({
                    'id' : self.id,
                    'addMode' : self.addMode,
                    'groupMode' : self.groupMode,
                    'onload' : function(response) {
                        if(response.status != 200) {
                            alert('Error while sending request to server!');
                        } else {
                            self.addMode =! self.addMode;
                        }
                        self.render();
                    }
                });
                return false;
            }, false);
        }
    };

    /**
     * SettingsCheck
     * @param {Object} options
     */
    function SettingsCheck (options) {
        this.obj = null;
        this.settingsKey = '';
        this.checked = false;
        this.init(options);
        return this.obj;
    };
    SettingsCheck.prototype = {
        init: function(options) {
        this.settingsKey = options.key;
        this.checked = Settings.autoLoad(this.settingsKey);
        //console.log('Checked :', this.checked, ', ', options.key);
        this.obj = document.createElement('input');
        this.obj.setAttribute('type', 'checkbox');

        if(options.id) {
            this.obj.setAttribute('id', options.id);
        }
        if(this.checked) {
            this.obj.setAttribute('checked', 'checked');
        }
        var self = this;
        this.obj.addEventListener('change',
            function() {
                self.checked =! self.checked;
                Settings.store(Settings.list[self.settingsKey].key, self.checked);
            },
            false);
        }
    };


    SettingsTable = function(options) {
        this.obj = null;
        this.init(options);
        return this.obj;

    };
    SettingsTable.prototype = {
        init : function (options) {
            var table = document.createElement('table');
            table.setAttribute('cellspacing', 0);
            table.setAttribute('cellpadding', 0);
            table.setAttribute('class', 'editor');
            table.style.width = '420px';
            table.style.margin = '0px';
            var t = document.createElement('tbody');
            table.appendChild(t);

            this.obj = document.createElement('form');
            this.obj.appendChild(table);

            if(typeof(options.checkboxes) != 'undefined') {
                jeach(options.checkboxes, function(key, c) {
                    var tr = document.createElement('tr');

                    var td = document.createElement('td');
                    td.setAttribute('class', 'servCheck');
                    td.appendChild(c.checkbox);
                    tr.appendChild(td);

                    var td = document.createElement('td');
                    td.setAttribute('class', 'servDesc');
                    td.innerHTML = c.description;

                    tr.appendChild(td);
                    t.appendChild(tr);
                });
            }
        },
    };



    /**
     * PHP-like func_get_args()
     */
    function func_get_args(){
        return Array.prototype.slice.call(arguments.callee.caller.arguments);
    }

    /**
     * Links helper
     */
    LinksHelper = {
        /**
         * Create user links set
         * @param {Object} id
         */
        getUserLinks: function(id, params){
            if(!params) {
                params = {};
            }
            var out = [];
            var noSend = false;
            var noFriends = false;
            if(typeof(params.noSend) != 'undefined') {
                noSend = params.noSend;
            }
            if(typeof(params.noFriends) != 'undefined') {
                noFriends = params.noFriends;
            }

            if (!noSend) {
                out.push(createLink('/mail.php?act=write&to=' + id, Lang.text('search', 'sendLink')));
            }
            if (!noFriends) {
                out.push(createLink('/friends.php?id=' + id, Lang.text('search', 'friendsLink')));
            }
            out.push(document.createElement('br'));
            out.push(createLink("/photos.php?id=" + id, Lang.text('search', 'photosLink')));
            out.push(createLink("/photos.php?act=user&id=" + id, Lang.text('search', 'photosWithLink')));
            out.push(createLink("/notes.php?id=" + id, Lang.text('search', 'notesLink')));
            out.push(createLink("/questions.php?mid=" + id, Lang.text('search', 'questionsLink')));
            out.push(createLink("/video.php?id=" + id, Lang.text('search', 'videoLink')));
            out.push(createLink("/audio.php?id=" + id, Lang.text('search', 'audioLink')));
            out.push(createLink("/groups.php?id=" + id, Lang.text('search', 'groupsLink')));
            out.push(createLink("/wall.php?id=" + id, Lang.text('search', 'wallLink')));
            out.push(document.createElement('br'));
            return out;
        },
        /**
         * Create group links set
         * @param {Object} id
         */
        getGroupLinks: function(id){
            var out = [];
            out.push(document.createElement('br'));
            out.push(createLink("/search.php?group=" + id, Lang.text('groups', 'membersLink')));
            out.push(createLink("/video.php?gid=" + id, Lang.text('groups', 'videoLink')))
            out.push(createLink("/audio.php?gid=" + id, Lang.text('groups', 'audioLink')));
            out.push(createLink("/photos.php?gid=" + id, Lang.text('groups', 'photosLink')));
            out.push(createLink("/board.php?act=topics&id=" + id, Lang.text('groups', 'boardsLink')));
            out.push(createLink("/wall.php?gid=" + id,Lang.text('groups', 'wallLink')));
            out.push(document.createElement('br'));
            return out;

        }
    };

    /**
     * Strings helper
     */
    StringsHelper = {
        format : function( text ) {
            //check if there are two arguments in the arguments list
            if ( arguments.length <= 1 ) {
                return text;
            }
            //decrement to move to the second argument in the array
            var tokenCount = arguments.length - 2;

            for( var token = 0; token <= tokenCount; token++ ) {
                text = text.replace( new RegExp( "\\{" + token + "\\}", "gi" ), arguments[ token + 1 ] );

            }
            return text;
        },


        /**
         * PHP-like urlencode
         * @param {Object} str
         */
        urlencode: function(str){

            var histogram = {}, tmp_arr = [];
            var ret = str.toString();

            var replacer = function(search, replace, str){
                var tmp_arr = [];
                tmp_arr = str.split(search);
                return tmp_arr.join(replace);
            };

            // The histogram is identical to the one in urldecode.
            histogram["'"] = '%27';
            histogram['('] = '%28';
            histogram[')'] = '%29';
            histogram['*'] = '%2A';
            histogram['~'] = '%7E';
            histogram['!'] = '%21';
            histogram['%20'] = '+';

            // Begin with encodeURIComponent, which most resembles PHP's encoding functions
            ret = encodeURIComponent(ret);

            for (search in histogram) {
                replace = histogram[search];
                ret = replacer(search, replace, ret) // Custom replace. No regexing
            }

            // Uppercase for full PHP compatibility
            return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2){
                return "%" + m2.toUpperCase();
            });

            return ret;
        },

        /**
         * PHP-like http_build_query
         * @param {Object} formdata
         * @param {Object} numeric_prefix
         * @param {Object} arg_separator
         */
        http_build_query: function(formdata, numeric_prefix, arg_separator){
            var key, use_val, use_key, i = 0, j = 0, tmp_arr = [];

            if (!arg_separator) {
                arg_separator = '&';
            }

            for (key in formdata) {
                use_val = this.urlencode(formdata[key].toString());
                use_key = this.urlencode(key);

                if (numeric_prefix && !isNaN(key)) {
                    use_key = numeric_prefix + j;
                    j++;
                }
                tmp_arr[i++] = use_key + '=' + use_val;
            }

            return tmp_arr.join(arg_separator);
        }


    }

    /**
     * Safe console wrapper
     */
    Console = {
        /**
         * console.log wrapper
         * @see func_get_args()
         */
        log: function(){

            if (!Const.consoleEnabled) {
                return false;
            }
            if (typeof(console) !== 'undefined') {
                return console.log.apply(null, func_get_args());
            }
            return false;
        }

    }

    /**
     * Xpath iteration wrapper
     */
    Xpath = {
        /**
         * Iterate
         * @param {String} xPath
         * @param {Function} callback
         * @param {Object} obj
         */
        iterate: function(xPath, callback, obj, evalCaller){
            if (!obj) {
                obj = document;
            }
            if (!evalCaller) {
                evalCaller = document;
            }
            var query = evalCaller.evaluate(xPath, obj, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            for (var i = 0, length = query.snapshotLength; i < length; i++) {
                var item = query.snapshotItem(i);
                var res = callback(item);
                if (typeof(res) == 'boolean' && res == false) {
                    break;
                }
            }
            return this;
        },
        count : function(xPath, obj) {
            if(!obj) {
                obj = document;
            }
            return document.evaluate('count('+xPath+')', obj, null, XPathResult.ANY_TYPE, null).numberValue;
        }
    };

    /**
     * Append object
     */
    Append = {
        /**
         * Append elements to UL wrapped in LI
         * @param {Object} element
         * @param {Array} childs
         */
        appendToUl: function(element, childs){
            for (j in childs) {
                var t = childs[j];
                var tmp = document.createElement("li");
                if (typeof(t) == 'object') {
                    tmp.appendChild(t);
                }
                else {
                    tmp.innerHTML = t;
                }
                element.appendChild(tmp);
            }
        }
    };



    // HTML: construct link
    function createLink (href, inner, onclick){
        var addon = document.createElement("a");
        addon.setAttribute("href", href);
        addon.innerHTML = inner;
        if (onclick) {
            addon.addEventListener('click', onclick, false);
        }
        return addon;
    };

    /**
     * http://vkontakte.ru/fave.php processor
     */
    function faveProcessor(){
        var faves = [{
            'xpath': "//div[@id='Information'][1]//td/a[starts-with(@href, '/id')]",
            'regex': /id([0-9]+)/i,
            'type' : 'people'
        }, {
            'xpath': "//li//a[starts-with(@href, '/club')]",
            'regex': /club([0-9]+)/i,
            'type' : 'groups'
        }, {
            'xpath': "//li//a[starts-with(@href, 'events.php?act=')]",
            'regex': /gid=([0-9]+)/i,
            'type' : 'groups'
        }];

        var useLinks = Settings.autoLoad('favouritesLinks');
        var useOnline = Settings.autoLoad('favouritesOnline');
        var useEnlarge = Settings.autoLoad('favEnlarge');

        if (useEnlarge) {
            GM_addStyle("#leftColumn { width: 470px;}");
            GM_addStyle("#pageLayout { width: 891px }");
            GM_addStyle("#pageBody { width: 732px }");
            //        GM_addStyle ("#pageHeader { width: 800px; background-color: #FFFFFF;}");
            //        GM_addStyle ("#topNav { position: relative; left:-100px}");
            //        GM_addStyle ("div#quickSearch {position: relative; left:20px}");
            GM_addStyle("#pageHeader { margin-left: 50px;}");
        }

        if (useOnline) {
            Xpath.iterate("//div[@id='Information'][2]", function(link){
                link.style.display = 'none';
            });
            var onlinePeople = {};
            Xpath.iterate("//div[@id='Information'][2]//td/a[starts-with(@href, '/id')]", function(link){
                var id = parseInt(link.href.match(faves[0].regex)[1]);
                onlinePeople[id] = true;
            });
        }

        jeach (faves, function(key, j) {
            Xpath.iterate(j.xpath, function(link){

                var id = link.getAttribute('href').toString().match(j.regex)[1];
                //Console.log('Id = ' + id);

                if (useLinks) {
                    var element = new FavouritesLink({
                        'id': id,
                        'addMode': false,
                        'pictureMode': j.type == 'people',
                        'groupMode': j.type != 'people'
                    });
                    element.style.color = '#FF0000';
                    element.style.padding = "0px 0px 0px 4px";
                }
                //Console.log('type = ' + j.type);

                if(j.type == 'people' && useOnline) {
                    var div = document.createElement("div");
                    var img = document.createElement("img");

                    img.src = onlinePeople[id] ? Images.online : Images.offline;
                    img.style.padding = '0px';
                    div.appendChild(img);

                    if (useLinks) {
                        element.style.padding = '0px';
                        div.appendChild(element);
                    }

                    link.parentNode.appendChild (document.createElement("br"));
                    link.parentNode.appendChild (div);
                } else if(useLinks) {
                    link.parentNode.appendChild (document.createElement("br"));
                    link.parentNode.appendChild (element);
                }

                if(!link.innerHTML) {
                    link.innerHTML = 'No title';
                }
            });
        } );
    }

    
    function newSearchProcessor() {
        
        searchMode = Settings.autoLoad('searchMode')  
        allowAudio = Settings.autoLoad('audioLinks') 
        groupsMode = Settings.autoLoad('groups')
        document.addEventListener('DOMNodeInserted', function(event) {
            var div = e = event.target
            if (!typeof(e) == 'object' || !e.tagName || e.tagName.toUpperCase() != 'DIV' || !e.hasAttribute('class')) {
                return;
            }

            elementClass = e.getAttribute('class').match(/(result|audioRow)/i)
            if (!elementClass) {
                return
            }

            appendUserLinks = function(id) {
                var id = 0
                Xpath.iterate("*//a[starts-with(@href, 'mail.php?')]", function(row) {
                    id = row.getAttribute('href').match(/mail.php\?act=write&to=([0-9]+)/i)[1];
                    return false;
                }, div);
                if (!id) {
                    return
                }
                var isDeleted = Xpath.count("*//span[@class='bbb']", div) != 0;
                var noItems = Xpath.count("*//ul/li", div) == 0;
                var hasWriteTo = Xpath.count("*//a[starts-with(@href, 'mail.php?act=write')]", div) != 0
                var hasFriendsOf = Xpath.count("*//a[contains(@href, 'friend')]", div) != 0;
                var hasFavLink = Xpath.count("*//a[starts-with(@href, 'fave.php?act=')]", div) != 0;
                Xpath.iterate('*//ul', function(ul) {
                    var links = LinksHelper.getUserLinks(id, {'noSend': hasWriteTo, 'noFriends' : hasFriendsOf});
                    var t = [];
                    links = t.concat(links);
                    if (!hasFavLink) {
                        links.push(new FavouritesLink({
                            'id': id,
                            'addMode': true,
                            'pictureMode': false
                        }));
                    } else {
                        links.pop();
                    }
                    Append.appendToUl(ul, links);
                }, div);
            }            
            appendClubLinks = function() {
                Xpath.iterate("*//li/a[starts-with(@href, 'club')]", function(link){
                    var idGroup = link.getAttribute('href').match(/club(\d+)/i)[1];
                    var element = link.parentNode.parentNode;
                    var l = LinksHelper.getGroupLinks(idGroup);
                    l.push(new FavouritesLink({'id':idGroup, 'groupMode': true, 'addMode': true, 'pictureMode': false}));
                    Append.appendToUl(element, l);
                }, div);
            }
            
            if ( searchMode ) {
                appendUserLinks()
            } 
            if ( groupsMode ) {
                appendClubLinks()
            }
            if ( allowAudio ) {
                Xpath.iterate("*//img[starts-with(@id, 'imgbutton')]", processSoundLink, div)
            }

        }, false);
    }
    
    function searchProcessor(){
        var useSearch = Settings.autoLoad('searchMode');
        var useInvite = Settings.autoLoad('inviteToGroup');
        var inviteMode = Xpath.count("//a[starts-with(@href, 'javascript: inviteMemberToGroup')]") != 0;
        
        /*
        if(inviteMode) {
            Xpath.iterate("//a[starts-with(@href, 'javascript: inviteMemberToGroup')]", function(a) {
                console.log(a);
                //var evt = document.createEvent("HTMLEvents");
                //evt.initEvent("click", true, true);
                //a.dispatchEvent(evt);
                location.href = a.href;
                alert('yes');
            });
        }
        */
    
        var xpath = "//div[starts-with(@class, 'result clearFix')]";

        
        Xpath.iterate(xpath, function(div) {
            var id = 0;
            Xpath.iterate("*//div[starts-with(@id, 'row')]", function(row) {
                id = row.getAttribute('id').match(/row2([0-9]+)/i)[1];
                return false;
            }, div);

            if(!id) { return true;}

            var isDeleted = Xpath.count("*//span[@class='bbb']", div) != 0;
            var noItems = Xpath.count("*//ul/li", div) == 0;
            var hasWriteTo = Xpath.count("*//a[starts-with(@href, 'mail.php?act=write')]", div) != 0
            var hasFriendsOf = Xpath.count("*//a[contains(@href, 'friend')]", div) != 0;
            var hasFavLink = Xpath.count("*//a[starts-with(@href, 'fave.php?act=')]", div) != 0;

            Xpath.iterate('*//ul', function(ul) {
                var links = LinksHelper.getUserLinks(id, {'noSend': hasWriteTo, 'noFriends' : hasFriendsOf});
                var t = [];
                links = t.concat(links);
                if (!hasFavLink) {
                    links.push(new FavouritesLink({
                        'id': id,
                        'addMode': true,
                        'pictureMode': false
                    }));
                } else {
                    links.pop();
                }
                if( (useSearch && !inviteMode) || (useInvite && inviteMode) ) {
                    Append.appendToUl(ul, links);
                }
            }, div);
        });
    }

    // Groups
    function browseProcessor(){
        if(false == Settings.autoLoad('groups')) {
            return;
        }
        Xpath.iterate("//li/a[starts-with(@href, '/club')]", function(link){
            var idGroup = link.getAttribute('href').match(/club(\d+)/i)[1];
            var element = link.parentNode.parentNode;
            var l = LinksHelper.getGroupLinks(idGroup);
            l.push(new FavouritesLink({'id':idGroup, 'groupMode': true, 'addMode': true, 'pictureMode': false}));
            Append.appendToUl(element, l);
        });
    }

    /**
     * Profile page processor
     */
    function profileProcessor(){
        //Console.log('Profile processor');
        if(false == Settings.autoLoad('deletedPages')) {
            return;
        }
        var rightCol = document.getElementById('rightColumn');
        if (rightCol) {
            return;
        }
        /**
         *  When it's user's deleted profile, do our job
         */
        var idUser = location.href.match(/id[=]?([\d]+)/i)[1];
        var element = document.createElement("ul");
        element.id = 'nav';
        var l = LinksHelper.getUserLinks(idUser);
        l.push(new FavouritesLink({'id':idUser, 'addMode': true, 'pictureMode': false}));
        Append.appendToUl(element, l);
        document.getElementById('header').appendChild(element);
    }

    /**
     * Settings processor
     */
    function settingsProcessor() {
        var e = document.createElement('div');
        e.setAttribute('id', 'vkadd_settings');
        e.setAttribute('class', 'settingsPanel');
        var header = document.createElement('h4');
        header.innerHTML = Lang.text('settings', 'title');
        e.appendChild(header);
        var boxes = [];
        jeach(Settings.list, function(key, val) {
            if(typeof(val.internal) == 'undefined') {
                boxes.push( {
                    'description' :val.description,
                    'checkbox': (new SettingsCheck({'key': key}))
                });
            }
        });

        e.appendChild(new SettingsTable({'checkboxes':boxes}));
        
        jeach([
            { 'href' : Const.groupPage, 'title' : Lang.text('links', 'groupTitle') },
            { 'href' : Const.homepage, 'title' : Lang.text('links', 'homepageTitle') },
            { 'href' : Const.author, 'title' : Lang.text('links', 'authorTitle') }    
        ], function(k, val) {
            var link = createLink(val.href, val.title);
            link.style.padding = '4px';
            e.appendChild(link);        
        });
        
        Xpath.iterate("//div[@id='content']/div[@class='editorPanel clearFix']", function(o) {
            o.insertBefore(e, o.hasChildNodes() ? o.childNodes[0] : null);
        });
    }

    Images = {
        'online': 'data:image/gif;base64,R0lGODlhDwAPAPcAAAAAAAAAALVCShAACFIxQhgAEEIAOWsAa1IAUjEAMVopWhAIEIR7hHtze8aEzloAcxgAOQAAMQAAIYyl3gAQMWN7nGOczgAQEAAICITvnHPnhEJ7SmvOcwAxAAAYAAAIAEJKQggYABg5CBAhCEprOSFKCBgxCCFCCAgQABAYCAgIAIyMKZSUMZSUOf//a///c///e///hP//jL29a/f3jP//lKWlY+fnjP//nP//rdbWlP//tf//vf//xv//zv//1v//3t7WObWtMf/3St7WQtbOQv/3Ut7WSu/nUtbOSv/3Wt7WUv/3Y97WWv/3a//3c//3e//vOf/vQpSMKZSMMb21Su/ne//nGHNrGGtjGIR7IdbGOXNrIf/vUvfvpefOCN7GCM61CMatCL2lCN7GEGNaGP/eCPfWCOfGCLWcCP/eEPfWEP/eGO/OGP/WCPfOCHtjEMZSGFoYCIwpELUxGFoQCLUpGIxCOYQYEPcxKQgAAFoICIQQEP8hIe8hIa0YGOchIbUhIf9ra/97e9Zzc4RaWv+1te/v7+fn597e3tbW1sbGxrW1taWlpZycnJSUlISEhGtrayEhIRgYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAJQALAAAAAAPAA8ABwhqACkJpLShIEGDAwduyJCBw8KGGxIKXKjBYYaKERUWvGgRo8GHGTZghMjQoUgNKDc47OiRg0uXG1yofOnwYMGYLmTejAgSokyGJTeiXLmQYkuYJEO+5Cm0o8mMEzlSrClx5kqYEid+RCgwIAA7',
        'offline': 'data:image/gif;base64,R0lGODlhDwAPAPcAAAAAAP///7VCShAACFIxQhgAEEIAOWsAa1IAUjEAMVopWhAIEIR7hHtze8aEzloAcxgAOQAAMQAAIYyl3gAQMWN7nGOczgAQEAAICITvnHPnhEJ7SmvOcwAxAAAYAAAIAEJKQggYABg5CBAhCEprOSFKCBgxCCFCCAgQABAYCAgIAIyMKZSUMZSUOf//a///c///e///hP//jL29a/f3jP//lKWlY+fnjP//nP//rdbWlP//tf//vf//xv//zv//1v//3t7WObWtMf/3St7WQtbOQv/3Ut7WSu/nUtbOSv/3Wt7WUv/3Y97WWv/3a//3c//3e//vOf/vQpSMKZSMMb21Su/ne//nGHNrGGtjGIR7IdbGOXNrIf/vUvfvpefOCN7GCM61CMatCL2lCN7GEGNaGP/eCPfWCOfGCLWcCP/eEPfWEP/eGO/OGP/WCPfOCHtjEMZSGFoYCIwpELUxGFoQCLUpGIxCOYQYEPcxKQgAAFoICIQQEP8hIe8hIa0YGOchIbUhIf9ra/97e9Zzc4RaWv+1te/v7+fn597e3tbW1sbGxrW1taWlpZycnJSUlISEhGtrayEhIRgYGP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAPAA8ABwhoACkJpFSoIEGDAwcWMsRwYcOEAhcOIiSRYsKCFTMadGhoIUVDHxtKHNSR4sdBEwsSWrmykItCLFsexOiiJsaNDBlSfJkTZEFDKE0uHEkRZkufPlkWmgn0ZNGlCptmhEhQqVKqM7MODAgAOw==',
        'delete' : 'data:image/gif;base64,R0lGODlhDwAPAKIFAP///8zMzGZmZpmZmTMzM////wAAAAAAACH5BAEAAAUALAAAAAAPAA8AAAM2WLrcTtApSGtcJOgw+hAEY40NAWge+ABDIAyEWrIuLIv0G4dzq9+YnI2H8w1XqA5wMrpInoUEADs=',
        'add'    : 'data:image/gif;base64,R0lGODlhDwAPAPcAAAQCBCyKBJzehGy+PGTCTAxGBGyqTNz2xHzWJJTeTAweBESeFMzupCR6BITWbGzSPAQOBLTuhITCXCRaDHSuXOz63EyuLESaDLTmlGTCPBxCFKTiZAwqBEyeHIzeRAQKBDSKDKTejHTOVGyqVOT21ITaNEyeFMzyrDx6JHTSRAQWBIzGXHSuZPT67GzCPCRKHKTqZBQmDIB3AAAAAAAA2AAA6QAAFwAAAID/4JH/7Xf/7wAAdkgAgAEAO3IA1gAAAACoRQADAAAAAAAAANhXeB8B3ngBdQABAACMAADmAHIXcgAAAAjeAADOAADTAAh1AABkAAD7AAAXcgEAAIB4EHAc7X/5dQB2AIDxAHBSAH/wAAB2AJj+nyX/y3f/DAD/dgiXYQC3AADwAAB2AAD4ZACy6SDwFwB2AAAARQAAAHIAAAAAAADgwAAfbgB4RgAAAGzgAOcfABd4AAAAAKuQALbvAPDvAHZ2ADA0gQEAtXIA8ADAdpeoTrfn2/AX03YAdV0ZuyjMjBfTFwB1AAAAAAAAAAByAAAAAAAABwAAAHIAAAAAAODYAB8fAHh4AAAAANgAAKUAYHwAdgAAAADKAABCAADUAAB1AAAAAAABAAAAAAAAAAvcAADnAAAXAAAAAFcAAAAAAAAAAAAAAHgAWwEBv3IA0wAAdUjK/tRC/3fU/wB1/0jcTgHn23IX0wAAdQBQFQBHAADVAAB1AAAAFQDoAHIXAAAAAEgA0AEB7XIAFwAAAOjK/ztC/4DU/wB1/4AAAJEAAHcAAAAAAEgYCAEA6XIAFwAAAAJcBgBDnQDUTAJ1AAAA6AAA6AAAFwAAAI0EdwDpcAAXT40AAHWXHABD6QDUFwB1ABxEXOaNQxdP1AAAdQBgsQKY6gBPFwAAAAMA6QAB/wAA/wAAf3gAnBzo6vkXF3YAAIAAAAABAAAAAAAAAA24XABDQwDU1AB1dZcBALcAAPAAAHYAAPEABx4wjQAAF+92AHXwKAClZwAMdgB2AOgYgTvoRYAXSAAAACH5BAEAAAAALAAAAAAPAA8ABwh3AAEIHEiwoMGDByHEWAgBoUANIhwQ0OAQwAsBFUZwSPjiBQoBBwxMKPCi4cAYIkKEwMBAwoAHFhQQjOGgBYkTETZ4QBBAxcwBLEasgDFgwYUGPgdC0MBhgosEHQpw2HjwxYMSC6gifGEhQAOtCRVASFqxrFkAAQEAOw==',
        'loader' : 'data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=='        
    };

     function eraseRedirectionLinks() {
        var prefix = "http://vkontakte.ru/away.php?to=";
        var path = "//a[starts-with(@href, '" + prefix + "')]";
        Xpath.iterate(path, function(link) {
            var encodedHref = link.href.substr(prefix.length);
            link.href = unescape(encodedHref.replace(/\+/g, " "));
            link.target = "";
        });
    }

    function eraseAdvertisement() {
        jeach([
        "//a[starts-with(@href, '/ads.php')]",
        "//a[starts-with(@href, 'help.php?page=target')]",
        "//iframe", "//div[starts-with(@id, 'banner')]"
        ], function(key,val) {
            Xpath.iterate(val, function(link) {
                if(link.getAttribute('id') != 'editFrame') {
                    link.style.display = 'none';
                }
            });
        });
    }
    
    
    function appendWallpost (e) {
        if(e.innerHTML.match(/online/i)) {                
            e.innerHTML = '<div style="margin-left:17px;padding-top:2px;">Online</div>';
            e.style.margin = '0px';
            e.style.height = '16px';
            e.style.background = 'url('+Images['online']+') bottom left no-repeat';
        }
    }

    function appendWallpost2 (e) {
        if(e.innerHTML.match(/online/i)) {                
            e.innerHTML = '<img src="'+Images['online']+'"/>';
        }
    }

    function appendOnlineProfile(e) {
        e.innerHTML = '';
        e.setAttribute('align', 'right');                
        var img = document.createElement('img');
        img.src = Images['online'];
        e.appendChild(img);                
    }
        
    function onlineText() {
        Xpath.iterate('//*[@class="messageFrom"]//div', appendWallpost);
        Xpath.iterate('//span[@class="bbb"]', appendWallpost2);
        Xpath.iterate('//div[@id="wrapHI"]//div[@id="header"]//h1//b', appendOnlineProfile);
        Xpath.iterate('//table[@class="wallpost"]//td[@class="image"]//div', appendWallpost);
    }
    
    function domTest(event) {
        var element = event.target;
        try {
            if(!element.getAttribute('id').match(/wPostContainer/i)) {
                return;
            }
        } catch (ex) {
            return;
        } finally {
            
        }
        Xpath.iterate('//td[@class="image"]//div', appendWallpost, element);
    }

    function cleanSidebar() {
        Xpath.iterate( '//*[@id="sideBar"]//li//a', function(link) {
            var html = link.innerHTML.split(' ');
            if(html.length > 3) {
                link.innerHTML = html.slice(1).join(' ');
            }
        });        
    }
    
    function checkCommonGroups() {
        Xpath.iterate('//[@id="groups"]//*[@class="flexBox clearFix aPad"]//a', function(link) {
            //console.log(link);
        });
    }
    function albumProcessor() {
        if(!Settings.autoLoad('albumsFlashUpload')) {
            return;
        }
        Xpath.iterate("//a[starts-with(@href, 'photos.php?act=add')]", function(link) {
           link.href = link.href.replace('act=add&', 'act=add_flash&').replace('gid=', 'oid=-')
        });
    }
    
    function videoProcessor() {
        if(!Settings.autoLoad('videoLinks')) {
            return;
        }
        var t = document.getElementsByTagName('script');
        jeach(t, function(key, k) {
            var m = k.innerHTML.match(/vtag:'(.*?)',/);
            if(m) {
                var vtag = m[1];
                var vkid = k.innerHTML.match(/vkid:'(.*?)',/)[1];
                var host = k.innerHTML.match(/host:'(.*?)',/)[1];
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: "http://vkadre.ru/get_video?version=1&vtag="+vtag+"&vkid="+vkid,
                    onload: function(resp) {
                            try {
                                var XMLResponce = (new DOMParser()).parseFromString(resp.responseText, "text/xml");
                                var link = XMLResponce.getElementsByTagName('location')[0].firstChild.nodeValue;
                            } catch (ex) {
                            
                            } finally {
                                var e = document.createElement("a");
                                e.href = link;
                                e.innerHTML = Lang.text('links', 'downloadVideo');
                                e.style.fontWeight = 'bold';
                                document.getElementById("videoactions").appendChild(e);     
                            }
                    }
                });
                return false;
            }
        });

    }
    function processSoundLink(link) {
        var data = link.getAttribute('id').match(/(imgbutton|imgbuttonWall)(\d+)/i)
        var id = data[2]
          var str = link.getAttribute("onclick");
        var re=/(operate|operateWall)\((\d+)[^0-9]+(\d+)[^0-9]+(\d+),[^0-9a-zA-Z]+([0-9a-zA-Z]+)/;
        var arr=re.exec(str);
        var user=arr[4];
        if (user<100000) {
            user=parseInt(user)+100000;
            user=(user.toString()).substr(1);
        }
        var newHref = "http://cs"+arr[3]+".vkontakte.ru/u"+user+"/audio/"+arr[5]+".mp3"
        var key = data[1] == 'imgbutton' ? 'title' : 'titleWall'
        var node = document.getElementById(key+id).parentNode
        var linkTitle = Lang.text('links', 'downloadAudio')
        node.innerHTML += " | <a target='_blank' href='"+newHref+"'>"+linkTitle+"</a>"
    }
    function soundLinks() {
        Xpath.iterate("*//img[starts-with(@id, 'imgbutton')]", function(link) {
            processSoundLink(link)
        })   
    }
    function friendsProcessDiv(e) {
            var data = e.getAttribute('id').toString().match(/fr_res([\d]+)/i);
            if (!data) {
                return;
            }
            var alreadyDone = Xpath.count("*//a[contains(@href, 'photos.php?')]", e) != 0;
            if (alreadyDone) {
                return
            }
            var idUser = data[1];
            var l = LinksHelper.getUserLinks(idUser, {'noSend': true, 'noFriends' : true});
            l.push(new FavouritesLink({'id':idUser,  'addMode': true, 'pictureMode': false}));
            Append.appendToUl(e.getElementsByTagName('ul')[0], l);
    }
	
    function friendsProcessor() {
		if (! Settings.autoLoad('myFriends') ) {
			return
		}
        Xpath.iterate("*//div[starts-with(@id, 'fr_res')]", friendsProcessDiv);
        domProc = function (event) {
            var e = event.target;
            if (!typeof(e) == 'object' || !e.tagName || e.tagName.toUpperCase() != 'DIV' || !e.hasAttribute('id')) {
                return;
            }
            friendsProcessDiv(e)
        }
        document.addEventListener('DOMNodeInserted', domProc, false);
    }
    
    function uploadPhotosProcessor() {
        if (! Settings.autoLoad('appendUploadPhotos') ) {
            return
        }
        Xpath.iterate("*//table[@class = 'formTable']/tbody/tr[@class = 'tallRow']/td[2]", function(e) {
            e.innerHTML += '<input type="file" name="file4" id="file4" size="22" class="upload"/>'
            e.innerHTML += '<input type="file" name="file5" id="file5" size="22" class="upload"/>'
            e.innerHTML += '<input type="file" name="file6" id="file6" size="22" class="upload"/>'
        })
    
    }
    
    // Entry function. Detects page by regex and calls appropriate processor
    function run() {
        VersionControl.init();
        if(Settings.autoLoad('awayLinks')) {
            eraseRedirectionLinks();
        }
        if(Settings.autoLoad('eraseAds')) {
            eraseAdvertisement();
        }
        /*if(Settings.autoLoad('sidebarOneWord')) {
            cleanSidebar();
        }*/
        if(Settings.autoLoad('onlineTextToImage')) {
            document.addEventListener('DOMNodeInserted', domTest, false);
            onlineText();    
        }
        if(Settings.autoLoad('audioLinks')) {
            soundLinks();
        }
        jeach ([
        {
            // Album | photos processor
            'regex': /\/(album|photos)/i,
            'processor': albumProcessor
        }, {
            // Favourites processor
            'regex': /\/fave.php/i,
            'processor': faveProcessor
        }, {
            // Extended "invite to group" mode
            'regex': /\/search.php/i,
            'processor': searchProcessor
        } , {
            // New-style "friends page" processor
            'regex': /\/(friends).php/i,
            'processor': friendsProcessor
        }, {
            // New-style "search" page processor
            'regex': /\/gsearch.php/i,
            'processor': newSearchProcessor
        }, {
            // Groups processors
            'regex': /\/(browse|groups).php/i,
            'processor': browseProcessor
        }, {
            // Profile processor
            'regex': /\/(profile.php|id[0-9]+)/i,
            'processor': profileProcessor
        }, {
            // Settings page processor
            'regex': /\/settings.php($|\?[0-9]+|\?m=[0-9]+)/i,
            'processor': settingsProcessor
        }, {
            // Video page processor
            'regex': /\/(video|video-)(\d+)_(\d+)/i,
            'processor': videoProcessor
        }, {
            'regex': /\/photos.php\?act=add/i,
            'processor' : uploadPhotosProcessor
        
        }], function(key, val) {
            var match =    location.href.match(val.regex);
            if (match) {
                return (val.processor)(match);
            }
        });
    }

    
    /**
     * Entry Point :)
     */
    //GM_addStyle('.mailbox table tr.newRow { background-color: #DEE1E3; }');
    run();

})();