home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / AIMP2 / aimp_2.61.583.exe / $TEMP / YandexPackSetup.msi / fil3346EA191FC9074B20FB5710D952C39C < prev    next >
Text File  |  2010-07-12  |  149KB  |  4,782 lines

  1. const Cc = Components.classes;
  2. const Ci = Components.interfaces;
  3. const Cr = Components.results;
  4. const Cu = Components.utils;
  5.  
  6. const EXT_ID = "yasearch@yandex.ru";
  7. const CHROME_IMAGES = "chrome://yasearch/skin/images/";
  8. const CHROME_CONTENT = "chrome://yasearch/content/";
  9.  
  10. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  11.  
  12. ["consts", "utils", "cache_wrapper",
  13.  "ya_auth", "ya_storage", "ya_installer", "ya_defence",
  14.  "ya_bookmarks", "ya_overlay", "ya_searchplugin",
  15.  "ya_uservices", "ya_partner", "ya_sshot", "ya_ftab",
  16.  "ya_mfd", "ya_geolocation"]
  17. .forEach(
  18.   function(aScriptName) {
  19.     this.loadSubScript(CHROME_CONTENT + "sub-scripts/" + aScriptName + ".js");
  20.   },
  21.   Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
  22. );
  23.  
  24. function nsIYaSearch() {
  25.   this.version = "201005180600";
  26.   this.versionBuild = "10272";
  27.   this.VERSION_BUILD = "";
  28.  
  29.   this.wrappedJSObject = this;
  30.   this.debug = false;
  31.   
  32.   this._inited = false;
  33.   
  34.   this.EXT_ID = EXT_ID;
  35.  
  36.   this.prefs = {
  37.     _showBloggersValuePrefName: "yasearch.general.ui.show.bloggers.value",
  38.  
  39.     get showBloggersValue() {
  40.       return gYaSearchService.getBoolPref(this._showBloggersValuePrefName);
  41.     },
  42.  
  43.     set showBloggersValue(val) {
  44.       gYaSearchService.setBoolPref(this._showBloggersValuePrefName, !!val);
  45.       return this.showBloggersValue;
  46.     },
  47.     
  48.     _showCyValuePrefName: "yasearch.general.ui.show.cy.value",
  49.  
  50.     get showCyValue() {
  51.       return gYaSearchService.getBoolPref(this._showCyValuePrefName);
  52.     },
  53.  
  54.     set showCyValue(val) {
  55.       gYaSearchService.setBoolPref(this._showCyValuePrefName, !!val);
  56.       return this.showCyValue;
  57.     },
  58.  
  59.     _highlighterEnabledPrefName: "yasearch.general.ui.highlighter.enabled",
  60.  
  61.     get highlighterEnabled() {
  62.       return gYaSearchService.getBoolPref(this._highlighterEnabledPrefName);
  63.     },
  64.  
  65.     set highlighterEnabled(val) {
  66.       gYaSearchService.setBoolPref(this._highlighterEnabledPrefName, !!val);
  67.       return this.highlighterEnabled;
  68.     },
  69.  
  70.     _showSiteSearchPrefName: "yasearch.general.ui.show.site.search",
  71.  
  72.     get showSiteSearch() {
  73.       return gYaSearchService.getBoolPref(this._showSiteSearchPrefName);
  74.     },
  75.  
  76.     set showSiteSearch(val) {
  77.       gYaSearchService.setBoolPref(this._showSiteSearchPrefName, !!val);
  78.       return this.showSiteSearch;
  79.     },
  80.  
  81.     _searchHistoryEnabledPrefName: "yasearch.general.ui.search.history.enabled",
  82.  
  83.     get searchHistoryEnabled() {
  84.       return gYaSearchService.getBoolPref(this._searchHistoryEnabledPrefName);
  85.     },
  86.  
  87.     set searchHistoryEnabled(val) {
  88.       gYaSearchService.setBoolPref(this._searchHistoryEnabledPrefName, !!val);
  89.       return this.searchHistoryEnabled;
  90.     },
  91.  
  92.     _commandOpenTabPrefName: "yasearch.general.ui.command.open.tab",
  93.  
  94.     get commandOpenTab() {
  95.       return gYaSearchService.getBoolPref(this._commandOpenTabPrefName);
  96.     }
  97.   };
  98.  
  99.   this.updateTimer = {
  100.     "_Guid": null,
  101.     "_GuidRefresh": null,
  102.     "_MailAndFeeds": null,
  103.     "_Bookmarks": null
  104.   };
  105.  
  106.   this.checkTimeOut = {
  107.     "_Guid": DAY_SECS,
  108.     "_GuidRefresh": 3600010,
  109.     "_MailAndFeeds": 0,
  110.     "_Bookmarks": DAY_SECS
  111.   };
  112.  
  113.   this.feedsCounter = 0;
  114.  
  115.   this._runnedNotifications = [];
  116.  
  117.   this.usersData = {};
  118.  
  119.   this.maxUnreadInXML = 30;
  120.  
  121.   this.showLocalWelcomePage = false;
  122.   this.checkKeywordURL = null;
  123. }
  124.  
  125. nsIYaSearch.prototype = {
  126.   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
  127.                                          Ci.nsIYaSearch,
  128.                                          Ci.nsIObserver,
  129.                                          Ci.nsISupportsWeakReference]),
  130.   
  131.   ASSERT: function() {},
  132.  
  133.   log: function(msg) {
  134.     if (!this.debug)
  135.       return;
  136.  
  137.     let date = new Date();
  138.     let time = [date.getHours(), date.getMinutes(), date.getSeconds()].join(":") + "." + date.getMilliseconds();
  139.  
  140.     msg = "[nsIYaSearch (" + time + ")]: " + msg + "\n";
  141.     CONSOLE_SERVICE.logStringMessage(msg);
  142.   },
  143.  
  144.   get tmpLogOutput() {
  145.     if (!this.__tmpLogOutput) {
  146.       let tmpFile = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
  147.  
  148.       tmpFile.append("!!_ya_searchlog_");
  149.  
  150.       let os = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
  151.       os.init(tmpFile, 0x02 | 0x08 | 0x20, 0755, 0);
  152.  
  153.       this.__tmpLogOutput = os;
  154.     }
  155.  
  156.     return this.__tmpLogOutput;
  157.   },
  158.   
  159.   isLogin: false,
  160.  
  161.   cookieManager: Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager),
  162.  
  163.   defaultSearchEngineId: "www",
  164.  
  165.   settingsFolderName: "yandex",
  166.   xmlServicesFileName: "services.data.xml",
  167.   xmlServicesFile: null,
  168.   xmlServices: null,
  169.   contentDir: null,
  170.  
  171.   _xsltemplates: {},
  172.   xsltImportRegExp: new RegExp(/<xsl:import href="chrome:\/\/yasearch\/content\/xsl\-templ\/xsl\-(.*)\.xsl"\/>/),
  173.  
  174.   domParser:        Cc["@mozilla.org/xmlextras/domparser;1"].getService(Ci.nsIDOMParser),
  175.   xmlSerializer:    Cc["@mozilla.org/xmlextras/xmlserializer;1"].getService(Ci.nsIDOMSerializer),
  176.   xPathEvaluator:   Cc["@mozilla.org/dom/xpath-evaluator;1"].getService(Ci.nsIDOMXPathEvaluator),
  177.   unSnapshotType:   Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  178.   orSnapshotType:   Ci.nsIDOMXPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  179.  
  180.   soundService:     Cc["@mozilla.org/sound;1"].createInstance(Ci.nsISound),
  181.  
  182.   windowMediator:   Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator),
  183.   windowWatcher:    Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher),
  184.   promptService:    Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService),
  185.   
  186.   isFirstDOMWinStuffDone: false,
  187.   
  188.   onBrowserUIStartupComplete: function() {
  189.     if (!this._inited || this.isFirstDOMWinStuffDone)
  190.       return;
  191.     
  192.     this.stringBundle = null;
  193.  
  194.     this.isFirstDOMWinStuffDone = true;
  195.  
  196.     if (this.checkKeywordURL) {
  197.       if (this.checkKeywordURL === "set") {
  198.         this._setKeywordUrl(true);
  199.       } else if (this.checkKeywordURL === "check") {
  200.         this._checkKeywordUrl();
  201.       }
  202.       
  203.       this.checkKeywordURL = null;
  204.     }
  205.     
  206.     if (typeof(gYaSearchPlugin) === "object" && "checkSearchPluginInstall" in gYaSearchPlugin)
  207.       gYaSearchPlugin.checkSearchPluginInstall();
  208.   },
  209.   
  210.   onSessionstoreWindowsRestored: function() {
  211.     if (!this._inited)
  212.       return;
  213.     
  214.     if (this.showLocalWelcomePage) {
  215.       this.showLocalWelcomePage = false;
  216.       new G_Timer(function(){
  217.         gYaSearchService.loadURI("chrome://yasearch/locale/first-start/welcome.html", "tab");
  218.       }, 500);
  219.     }
  220.     
  221.     if (typeof(gYaMFD) === "object" && "init" in gYaMFD)
  222.       gYaMFD.init();
  223.     
  224.     if (this.isLogin && this.isCountersAutoUpdateEnabled)
  225.       this.refreshHTTPData("mailAndFeeds");
  226.   },
  227.   
  228.   init: function() {
  229.     this.debug = this.getBoolPref("yasearch.general.debug.enabled");
  230.     
  231.     if (!this.getBoolPref("yasearch.license.accepted")) {
  232.       if (!this.getBoolPref("yasearch.license.show")) {
  233.         this.setBoolPref("yasearch.license.accepted", true);
  234.       } else {
  235.         try {
  236.           let setupWin = this.windowWatcher.openWindow(null, "chrome://yasearch/content/first-start/wizard.xul",
  237.                                                        null, "centerscreen,modal", null);
  238.           
  239.           if (!this.getBoolPref("yasearch.license.accepted")) {
  240.             let refuseWin = this.windowWatcher.openWindow(null, "chrome://yasearch/content/first-start/license-refuse.xul",
  241.                                                           null, "centerscreen,modal", null);
  242.             Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager).disableItem(EXT_ID);
  243.             return;
  244.           }
  245.           
  246.         } catch(e) {
  247.           this.log(e);
  248.           return;
  249.         }
  250.       }  
  251.       
  252.       this.resetPref("yasearch.license.hidden");
  253.       
  254.       try {
  255.         let prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
  256.         prefService.savePrefFile(null);
  257.       } catch(e) {
  258.         this.log(e);
  259.       }
  260.     }
  261.     
  262.     this._inited = true;
  263.     
  264.     ["cookie-changed",
  265.      "http-on-modify-request",
  266.      "http-on-examine-response"]
  267.     .forEach(function(aTopicName) {
  268.       OBSERVER_SERVICE.addObserver(this, aTopicName, true);
  269.     }, this);
  270.     
  271.     if (typeof(gYaStorage) === "object" && "init" in gYaStorage)
  272.       gYaStorage.init();
  273.     
  274.     if (typeof(gYaInstaller) === "object" && "init" in gYaInstaller)
  275.       gYaInstaller.init();
  276.     
  277.     if (typeof(gYaOverlay) === "object" && "init" in gYaOverlay)
  278.       gYaOverlay.init();
  279.     
  280.     if (typeof(gYaGeolocation) === "object" && "init" in gYaGeolocation)
  281.       gYaGeolocation.init();
  282.     
  283.     this.checkTimeOut._MailAndFeeds = this.isCountersAutoUpdateEnabled ?
  284.                                           (this.getIntPref("yasearch.http.update.interval") * MIN_SEC || 0) : 0;
  285.     
  286.     this.appendUserSessionData("data");
  287.  
  288.     this.yaAuth.Cookies.checkAuthOnStart();
  289.  
  290.     this.hackKnownSkins();
  291.   },
  292.  
  293.   get buttonsInfo() {
  294.     let enumerator = this.windowMediator.getEnumerator("navigator:browser");
  295.     if (enumerator.hasMoreElements()) {
  296.       try {
  297.         let browser = enumerator.getNext();
  298.         return browser.Ya.buttonsObject;
  299.       } catch(e) {}
  300.     }
  301.     return null;
  302.   },
  303.   
  304.   get username() {
  305.     return this.yaAuth.username;
  306.   },
  307.   
  308.   set username(val) {
  309.     return this.yaAuth.username = val;
  310.   },
  311.   
  312.   get isLogin() {
  313.     return this.yaAuth.isLogin;
  314.   },
  315.   
  316.   set isLogin(val) {
  317.     this.yaAuth.isLogin = val;
  318.   },
  319.   
  320.   onYandexLogin: function() {
  321.     this.clearAllTimers();
  322.     
  323.     if (this.isCountersAutoUpdateEnabled)
  324.       this.refreshHTTPData("mailAndFeeds", {forceRequest: true});
  325.  
  326.     if (this.bookmarksIsOutOfDate)
  327.       this.refreshHTTPData("bookmarks");
  328.   },
  329.  
  330.   onYandexLogout: function(aClearCookies, aForgetLogin) {
  331.     this.clearAllTimers();
  332.  
  333.     let enumerator = this.windowMediator.getEnumerator("Yasearch:AddDialog");
  334.     if (enumerator.hasMoreElements()) {
  335.       while (enumerator.hasMoreElements())
  336.         enumerator.getNext().document.documentElement.cancelDialog();
  337.     }
  338.   },
  339.  
  340.   clearAllTimers: function() {
  341.     this.clearTimer("_MailAndFeeds");
  342.     this.clearTimer("_Bookmarks");
  343.  
  344.     this.setNotifyTimer("cancel");
  345.   },
  346.  
  347.   clearTimer: function(type) {
  348.     if (type && this.updateTimer[type]) {
  349.       this.updateTimer[type].cancel();
  350.       this.updateTimer[type] = null;
  351.     }
  352.   },
  353.  
  354.   setTimer: function(aType, aTimeout) {
  355.     if (!aType)
  356.       throw "nsIYaSearch::setTimer -- no type";
  357.  
  358.     aTimeout = aTimeout || this.checkTimeOut[aType] || 0;
  359.  
  360.     if (this.updateTimer[aType])
  361.       this.updateTimer[aType].cancel();
  362.     else
  363.       this.updateTimer[aType] = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  364.  
  365.     if (aTimeout > 0)
  366.       this.updateTimer[aType].initWithCallback(this._TimerCallbacks[aType], aTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
  367.   },
  368.   
  369.   _TimerCallbacks: {
  370.     _Login: {
  371.       notify: function() gYaSearchService.startLoginConnection()
  372.     },
  373.     
  374.     _MailAndFeeds: {
  375.       notify: function() gYaSearchService.refreshHTTPData("mailAndFeeds")
  376.     },
  377.     
  378.     _Bookmarks: {
  379.       notify: function() gYaSearchService.refreshHTTPData("bookmarks")
  380.     },
  381.  
  382.     _Guid: {
  383.       notify: function() gYaSearchService.refreshHTTPData("guid")
  384.     },
  385.  
  386.     _GuidRefresh: {
  387.       notify: function() gYaSearchService.clearTimer("_GuidRefresh")
  388.     }
  389.   },
  390.   
  391.   HTTPDataRequests: {
  392.     _data: {},
  393.     
  394.     add: function(aURL, aType, aRequest) {
  395.       this._data[aURL] = {
  396.         requestSimpleURL: aURL,
  397.  
  398.         request: aRequest,
  399.         requestTime: Date.now(),
  400.         
  401.         isRequestPending: function() {
  402.           return !!(this.request && this.request.channel.isPending());
  403.         },
  404.         
  405.         cancelRequest: function() {
  406.           this.request.channel.cancel(Cr.NS_BINDING_ABORTED);
  407.         },
  408.  
  409.         responseTime: 0,
  410.         responseIsOK: null,
  411.  
  412.         types: {}
  413.       }
  414.  
  415.       this._data[aURL].types[aType] = true;
  416.     },
  417.  
  418.     removeRequest: function(aRequest) {
  419.       for each (let data in this._data) {
  420.         if (data.request === aRequest) {
  421.           data.request = null;
  422.           return data;
  423.         }
  424.       }
  425.     },
  426.  
  427.     canResendRequest: function(aURL, aType, aData) {
  428.       if (aType == "allServices" || (aData && aData.forceRequest))
  429.         return true;
  430.  
  431.       let data = this._data[aURL];
  432.  
  433.       if (data) {
  434.         let requestTimeDelta = Math.abs(Date.now() - data.requestTime);
  435.  
  436.         if (data.isRequestPending()) {
  437.           if (requestTimeDelta > 30000) {
  438.             data.cancelRequest();
  439.             return true;
  440.           }
  441.  
  442.           data.types[aType] = true;
  443.           return false;
  444.         }
  445.  
  446.         let responseTimeDelta = Math.abs(Date.now() - data.responseTime);
  447.  
  448.         if (data.types[aType] && (requestTimeDelta < 1000 || (data.responseIsOK && responseTimeDelta < 5000)))
  449.           return false;
  450.  
  451.         data.responseIsOK = null;
  452.         data.responseTime = 0;
  453.       }
  454.  
  455.       return true;
  456.     },
  457.  
  458.     processDataFromCache: function(aURL, aType, aData) {
  459.       if (aData && aData.forceRequest) {
  460.         G_CacheWrapper.writeData(aURL, null);
  461.         return false;
  462.       }
  463.       
  464.       let lastDataFromCache = G_CacheWrapper.readData(aURL);
  465.       
  466.       if (lastDataFromCache) {
  467.         gYaSearchService.processHTTPDataResponse(lastDataFromCache, aType, aData);
  468.         return true;
  469.       }
  470.       
  471.       return false;
  472.     }
  473.   },
  474.  
  475.   manualRefreshHTTPData: function(aType, aData, aCallerElementId) {
  476.     if (!aData)
  477.       aData = {};
  478.  
  479.     aData.manual = true;
  480.     aData.callerElementId = aCallerElementId || ("yasearch-" + aType);
  481.  
  482.     this.refreshHTTPData(aType, aData);
  483.   },
  484.  
  485.   refreshHTTPData: function(aType, aData, aDelay) {
  486.     if (!aData)
  487.       aData = {};
  488.  
  489.     new G_Timer(
  490.       function() {
  491.         gYaSearchService.__refreshHTTPData(aType, aData);
  492.       }, aDelay || 10
  493.     )
  494.   },
  495.  
  496.   __refreshHTTPData: function(aType, aData) {
  497.     if (!aType || typeof(aType) != "string")
  498.       throw "No type given in refreshHTTPData";
  499.  
  500.     var url,
  501.         appendTimestamp = false;
  502.  
  503.     aData.isCounters = false;
  504.  
  505.     switch (aType) {
  506.       case "allServices":
  507.         url = this.Counters.getURLForSID("allServices");
  508.  
  509.         if (!url)
  510.           return;
  511.  
  512.         aData.isCounters = true;
  513.  
  514.         appendTimestamp = true;
  515.  
  516.         break;
  517.  
  518.       case "mailAndFeeds":
  519.         this.setTimer("_MailAndFeeds");
  520.  
  521.         url = this.Counters.getURLForSID("allCounters");
  522.  
  523.         if (!url)
  524.           return;
  525.  
  526.         aData.isCounters = true;
  527.  
  528.         break;
  529.  
  530.       case "mail":
  531.         if (aData.manual && this.yaMFD)
  532.           this.yaMFD.updateDataForAllAccounts();
  533.       
  534.       case "lenta":
  535.       case "money":
  536.       case "fotki":
  537.       case "yaru":
  538.       case "moikrug":
  539.         url = this.Counters.getURLForSID([aType]);
  540.  
  541.         if (!url)
  542.           return;
  543.  
  544.         aData.isCounters = true;
  545.  
  546.         break;
  547.  
  548.       case "mailList":
  549.         url = "http://mail.yandex.ru/api/barlist";
  550.         break;
  551.       
  552.       case "mfd-counter":
  553.       case "mfd-list":
  554.         url = aData.url;
  555.         appendTimestamp = true;
  556.         break;
  557.       
  558.       case "bookmarks":
  559.         url = "http://zakladki.yandex.ru/bar/index.xml?newdescr=true";
  560.         appendTimestamp = true;
  561.  
  562.         break;
  563.  
  564.       case "guid":
  565.         url = this.generateGUIDStatusURL + this.generateGUIDData;
  566.         break;
  567.       
  568.       default:
  569.         break;
  570.     }
  571.  
  572.     if (!url)
  573.       throw new Error("Bad type given in refreshHTTPData");
  574.  
  575.     this.notifyBusyStateOfRequest(aType, true, !!(aData && aData.manual), aData.callerElementId);
  576.  
  577.     if (this.HTTPDataRequests.canResendRequest(url, aType, aData)) {
  578.       var fullUrl = url;
  579.  
  580.       if (appendTimestamp)
  581.         fullUrl += (/\?/.test(fullUrl) ? "&":"?") + "ts=" + Date.now();
  582.  
  583.       if (!!(aData && aData.manual))
  584.         fullUrl = this.appendStatData2Url(fullUrl, {});
  585.  
  586.       this.HTTPDataRequests.add(url, aType, this.xmlHttpRequest(fullUrl,
  587.                                                  {callbackFunc: this.refreshHTTPDataCallback.bind(this, aData)} ));
  588.     } else {
  589.       this.notifyBusyStateOfRequest(aType, false, !!(aData && aData.manual), aData.callerElementId);
  590.     }
  591.   },
  592.  
  593.   refreshHTTPDataCallback: function(aReq, aData) {
  594.     var data = this.HTTPDataRequests.removeRequest(aReq.target);
  595.  
  596.     if (!data)
  597.       return;
  598.  
  599.     data.responseTime = Date.now();
  600.  
  601.     var aType = data.types;
  602.  
  603.     if (!aType)
  604.       throw new Error("No type given in refreshHTTPDataCallback");
  605.  
  606.     var isCounters = aData.isCounters;
  607.  
  608.     if (this.isReqError(aReq)) {
  609.       if ("guid" in aType) {
  610.         this.clearTimer("_GuidRefresh");
  611.       }
  612.       
  613.       data.responseIsOK = false;
  614.  
  615.     } else {
  616.       G_DateUtils.updateServerTimeValue(aReq);
  617.  
  618.       var text = this.safeUnicode(aReq.target.responseText);
  619.  
  620.       if (!("guid" in aType))
  621.         this.checkNeedSendGuid();
  622.  
  623.       var noAuthError = false;
  624.  
  625.       if (isCounters) {
  626.         let countersError = this.Counters.getErrorFromInboxString(text);
  627.         if (countersError) {
  628.           if (countersError.type == "noauth") {
  629.             noAuthError = true;
  630.           } else {
  631.             return;
  632.           }
  633.         }
  634.       }
  635.  
  636.       if (noAuthError) {
  637.         data.responseIsOK = false;
  638.         this.yaAuth.fireAfterLogout();
  639.         
  640.       } else {
  641.         data.responseIsOK = true;
  642.         
  643.         if (isCounters)
  644.           this.Counters.setDataFromInboxString(aType, text);
  645.         
  646.         for (let typeStr in aType)
  647.           this.processHTTPDataResponse(text, typeStr, aData);
  648.       }
  649.     }
  650.  
  651.     if (data.responseIsOK == false && ("allServices" in aType))
  652.       this.Counters.setAllServicesError(true);
  653.  
  654.     if (aData && aData.manual) {
  655.       for (let typeStr in aType)
  656.         this.notifyBusyStateOfRequest(typeStr, false, true, aData.callerElementId);
  657.     }
  658.   },
  659.  
  660.   notifyBusyStateOfRequest: function(aType, aState, aIsManualRequest, aCallerElementId) {
  661.     if (aIsManualRequest)
  662.       OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Busy-State", aState + ":" + aCallerElementId);
  663.   },
  664.  
  665.   processHTTPDataResponse: function(aText, aTypeStr, aData) {
  666.     var isManualRequest = !!(aData && aData.manual);
  667.  
  668.     switch (aTypeStr) {
  669.       case "guid":
  670.         this.timeGuid = true;
  671.  
  672.         OBSERVER_SERVICE.notifyObservers(null, "Ya-GUID-Response", "SENDED");
  673.  
  674.         var msg = new XML(this.xmlSerializer.serializeToString(this.domParser.parseFromString(aText.replace(/<\?xml .+\?>[\r\n]*/,"").replace(/(<\/page>)[\r\n]*$/, '$1'), "text/xml")));
  675.         var showAlert = false, msgTime = msg.@time.toString(), version = msg.@version.toString();
  676.  
  677.         var output = { title: msg.title.toString(),
  678.                         description: msg.description.toString(),
  679.                         icon: msg.icon.toString() };
  680.  
  681.         if (version != "") {
  682.           if (version > this.barExtensionVersion && Math.abs(this.guidUpdateDS - (Date.now() / DAY_SECS)) > 6) {
  683.             msgTime = "error";
  684.             showAlert = true;
  685.           } else if (msgTime != "" && msgTime != this.guidMessageTS && msg.addDescription.toString() != "") {
  686.             output = { title: msg.addTitle.toString(),
  687.                        description: msg.addDescription.toString(),
  688.                        icon: msg.addIcon.toString() };
  689.             showAlert = true;
  690.           }
  691.         } else if (msgTime != "" && msgTime != this.guidMessageTS) {
  692.           showAlert = true;
  693.         }
  694.  
  695.         if (showAlert)
  696.           this.showPermanentAlert(output.title, output.description, output.icon, msgTime);
  697.  
  698.         return;
  699.  
  700.       case "bookmarks":
  701.         var bookmarksResponse = this.yaBookmarks.getServerResponse(aText);
  702.         if (!bookmarksResponse.error)
  703.           this.bookmarksDOMMenu = bookmarksResponse.xml;
  704.         break;
  705.  
  706.       case "allServices":
  707.         this.Counters.setDataFromInboxString({"allServices": true}, aText);
  708.  
  709.       case "mailAndFeeds":
  710.         if (this.Counters.error) {
  711.           if (aTypeStr == "mailAndFeeds")
  712.             this.setTimer("_MailAndFeeds", this.Counters.errorTimeout);
  713.           this.Counters.handleError();
  714.         }
  715.  
  716.       case "yaru":
  717.         if (aTypeStr == "yaru") break;
  718.  
  719.       case "fotki":
  720.         if (aTypeStr == "fotki") break;
  721.  
  722.       case "money":
  723.         if (aTypeStr == "money") break;
  724.  
  725.       case "lenta":
  726.         if (aTypeStr == "lenta") break;
  727.  
  728.       case "moikrug":
  729.         if (aTypeStr == "moikrug") break;
  730.  
  731.       case "mail":
  732.         var mCount = this.Counters.getCount("mail");
  733.  
  734.         if (mCount && (mCount != this.mailCounter || (mCount > 0 && this.mailLastCheckIsOutOfDate))) {
  735.           this.mailCounter = mCount;
  736.           this.refreshHTTPData("mailList", aData);
  737.         } else if (!mCount && mCount != this.mailCounter) {
  738.           this.mailCounter = mCount;
  739.           this.mailDOMMenuDoc = false;
  740.           OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "mailList");
  741.         }
  742.         break;
  743.  
  744.       case "mailList":
  745.         this.mailLastCheckIsOutOfDate = false;
  746.         
  747.         var msgURLPrefix = "http://" + this.getLocaleDependedUrl("MailHost") + "/message?ids=";
  748.         var listData = this.parseMailListXMLString(aText, this.mailLastMaxId, msgURLPrefix);
  749.         
  750.         if (!listData)
  751.           return;
  752.         
  753.         if (listData == "No Auth") {
  754.           this.yaAuth.fireAfterLogout();
  755.           return;
  756.         }
  757.         
  758.         this.mailDOMMenuDoc = listData.list;
  759.         
  760.         if (listData.newLastMaxId)
  761.           this.mailLastMaxId = listData.newLastMaxId;
  762.         
  763.         if (listData.newMailCounter > 0) {
  764.           if (listData.newMailCounter == gYaSearchService.maxUnreadInXML) {
  765.             let tmp = this.mailCounter - this.mailPermCounter;
  766.             listData.newMailCounter = tmp >= gYaSearchService.maxUnreadInXML ? tmp : 0;
  767.           }
  768.           
  769.           this.notifyAboutNewItems(aTypeStr, listData.newMailCounter,
  770.                                    { from: listData.newLastItem.@from.toString(),
  771.                                      title: listData.newLastItem.@title.toString() });
  772.         }
  773.         
  774.         this.mailPermCounter = this.mailCounter;
  775.         
  776.         break;
  777.       
  778.       case "mfd-counter":
  779.         this.yaMFD.onResponse("mfd-counter", aText, aData);
  780.         break;
  781.       
  782.       case "mfd-list":
  783.         this.yaMFD.onResponse("mfd-list", aText, aData);
  784.         break;
  785.     }
  786.  
  787.     OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", aTypeStr);
  788.   },
  789.   
  790.   parseMailListXMLString: function(aMailListXMLString, aLastMaxId, aMsgURLPrefix) {
  791.     let barlist = this.safeE4Xml(aMailListXMLString, null, ["yandexmenu", "auther"]);
  792.     if (!barlist)
  793.       return false;
  794.     
  795.     if (barlist..error.(@reason == "not authenticated").length() > 0)
  796.       return "No Auth";
  797.     
  798.     let list = <list/>;
  799.     
  800.     let newMailCounter = 0,
  801.         newLastItem,
  802.         newLastMaxId;
  803.     
  804.     var increaseNewMailCounter = true;
  805.     
  806.     let i = 0;
  807.     
  808.     for each (let folder in barlist.item) {
  809.       for each (let message in folder.item) {
  810.         let id = /\?mesid=(\d+)/.exec(message.@url.toString())[1];
  811.         message.@url = aMsgURLPrefix + id;
  812.         
  813.         if (increaseNewMailCounter) {
  814.           if (i == 0)
  815.             newLastMaxId = "" + id;
  816.           
  817.           if (id > aLastMaxId) {
  818.             newMailCounter++;
  819.             newLastItem = newLastItem || message;
  820.           } else {
  821.             increaseNewMailCounter = false;
  822.           }
  823.         }
  824.         
  825.         i++;
  826.       }
  827.       
  828.       list.appendChild(folder);
  829.     }
  830.     
  831.     return {
  832.       list: list,
  833.       newLastItem: newLastItem,
  834.       newMailCounter: newMailCounter,
  835.       newLastMaxId: newLastMaxId
  836.     };
  837.   },
  838.   
  839.   xmlHttpRequest: function(aUrl, aDetails) {
  840.     var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
  841.     
  842.     if (aDetails.background)
  843.       req.mozBackgroundRequest = true;
  844.     
  845.     req.open(aDetails.data ? "POST" : "GET", aUrl, true);
  846.     req.setRequestHeader("Cache-Control", "no-cache");
  847.  
  848.     if (aDetails.data) {
  849.       req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
  850.       req.setRequestHeader("Connection", "close");
  851.     }
  852.     
  853.     var target = req.QueryInterface(Ci.nsIDOMEventTarget);
  854.     if (aDetails.callbackFunc) {
  855.       target.addEventListener("load", aDetails.callbackFunc, false);
  856.       target.addEventListener("error", aDetails.callbackFunc, false);
  857.     }
  858.     
  859.     req.send(aDetails.data || null);
  860.     return req;
  861.   },
  862.  
  863.   isReqError: function(aReq) {
  864.     return !!(!aReq || aReq.type == "error" || !aReq.target || aReq.target.status != 200);
  865.   },
  866.   
  867.   get Counters() {
  868.     return gYaUServices;
  869.   },
  870.   
  871.   get yaPartner() {
  872.     return gYaPartner;
  873.   },
  874.   
  875.   get yaAuth() {
  876.     return gYaAuth;
  877.   },
  878.   
  879.   get yaMFD() {
  880.     return gYaMFD;
  881.   },
  882.   
  883.   get yaBookmarks() {
  884.     return gYaBookmarks;
  885.   },
  886.   
  887.   get yaOverlay() {
  888.     return gYaOverlay;
  889.   },
  890.   
  891.   get yaDefence() {
  892.     return gYaDefence;
  893.   },
  894.  
  895.   get yaFTab() {
  896.     return gYaFTab;
  897.   },
  898.   
  899.   get yaURLInfo() {
  900.     return gYaURLInfo;
  901.   },
  902.   
  903.   get yaGeolocation() {
  904.     return gYaGeolocation;
  905.   },
  906.   
  907.   getFeedsGroups: function(aCallback) {
  908.     this.xmlHttpRequest("http://lenta.yandex.ru/count.xml",
  909.                          { callbackFunc: this.getFeedsGroupsCallback.bind(this, aCallback) });
  910.   },
  911.  
  912.   getFeedsGroupsCallback: function(aReq, aCallback) {
  913.     var mlist = false,
  914.         doc = false;
  915.  
  916.     if (!this.isReqError(aReq))
  917.       doc = aReq.target.responseXML;
  918.  
  919.     if (doc) {
  920.       var _doc = this.domParser.parseFromString("<empty/>", "text/xml");
  921.       function createElement(aElementName) {
  922.         return _doc.createElementNS(XULNS, aElementName);
  923.       }
  924.  
  925.       var groups = doc.getElementsByTagName("group");
  926.       var mpopup = createElement("menupopup");
  927.  
  928.       var last_group_id = this.feedsLastGroupId;
  929.       var selected_item = 0;
  930.  
  931.       for (var i = 0; i < groups.length; i++) {
  932.         var mi = createElement("menuitem");
  933.         mi.setAttribute("label", groups.item(i).getAttribute("title"));
  934.         
  935.         var group_id = groups.item(i).getAttribute("id");
  936.         if (group_id == last_group_id)
  937.           selected_item = i;
  938.         
  939.         mi.setAttribute("group-id", group_id);
  940.         mpopup.appendChild(mi);
  941.       }
  942.  
  943.       mpopup.selectedIndex = selected_item;
  944.  
  945.       mlist = createElement("menulist");
  946.  
  947.       mlist.appendChild(mpopup);
  948.       mlist.setAttribute("id", "yasearch-feeds-select-group");
  949.  
  950.       if (groups.length == 0) {
  951.         mlist.setAttribute("disabled", "true");
  952.         mpopup.appendChild(createElement("menuitem"));
  953.       }
  954.     }
  955.  
  956.     if (aCallback)
  957.       aCallback(mlist);
  958.   },
  959.  
  960.   get feedsCounter() {
  961.     return this.isLogin ? (this.usersData[this.username]._feedsCounter || 0) : 0;
  962.   },
  963.  
  964.   set feedsCounter(val) {
  965.     if (this.isLogin)
  966.       this.usersData[this.username]._feedsCounter = Math.max(val, 0);
  967.   },
  968.  
  969.   get feedsLastGroupId() {
  970.     return this.isLogin ? (this.usersData[this.username]._feedsLastGroupId || 0) : 0;
  971.   },
  972.  
  973.   set feedsLastGroupId(val) {
  974.     if (this.isLogin)
  975.       this.usersData[this.username]._feedsLastGroupId = val;
  976.   },
  977.  
  978.   feedsInsertNewItem: function(aData) {
  979.     if (aData.group_id) {
  980.       this.feedsLastGroupId = aData.group_id;
  981.       this.xmlHttpRequest("http://lenta.yandex.ru/feed_add_url.xml",
  982.                           { callbackFunc: this.feedsInsertNewItemCallback.bind(this, aData),
  983.                             data: "url=" + encodeURIComponent(aData.url) + "&group_id=" +
  984.                                   aData.group_id + "&ajax=1" });
  985.     } else if (aData.title && aData.title != "") {
  986.       this.xmlHttpRequest("http://lenta.yandex.ru/feed_add_group_bar.xml",
  987.                           { callbackFunc: this.feedsInsertNewGroupCallback.bind(this, aData),
  988.                             data: "title=" + encodeURIComponent(aData.title) + "&ajax=1" });
  989.     }
  990.   },
  991.  
  992.   feedsInsertNewGroupCallback: function(aReq, aData) {
  993.     let error;
  994.     
  995.     if (this.isReqError(aReq)) {
  996.       error = "errorNewGroup1";
  997.     } else {
  998.       let group_id;
  999.       
  1000.       let pageXml = gYaSearchService.safeE4Xml(aReq.target.responseText, null, "page");
  1001.       if (pageXml)
  1002.         group_id = pageXml.status.added.@id.toString();
  1003.       
  1004.       if (group_id)
  1005.         aData.group_id = group_id;
  1006.       else
  1007.         error = "errorNewGroup2";
  1008.     }
  1009.  
  1010.     return error ? aData.callback(error) : this.feedsInsertNewItem(aData);
  1011.   },
  1012.  
  1013.   feedsInsertNewItemCallback: function(aReq, aData) {
  1014.     this.feedsLastGroupId = aData.group_id;
  1015.  
  1016.     var error;
  1017.  
  1018.     if (this.isReqError(aReq))
  1019.       error = "errorNewItem1";
  1020.     else if (aReq.target.responseText.indexOf("ok") != 0)
  1021.       error = "errorNewItem2";
  1022.  
  1023.     return aData.callback(error);
  1024.   },
  1025.  
  1026.   get moneyCounter() {
  1027.     return this.isLogin ? (this.usersData[this.username]._moneyCounter || 0) : 0;
  1028.   },
  1029.  
  1030.   set moneyCounter(val) {
  1031.     if (this.isLogin)
  1032.       this.usersData[this.username]._moneyCounter = Math.max(val, 0);
  1033.   },
  1034.  
  1035.   get guidMessageTS() {
  1036.     return this.isLogin && this.usersData[this.username]._guidLastMsgTs ?
  1037.                 this.usersData[this.username]._guidLastMsgTs :
  1038.                 (this.getCharPref("yasearch.guid.lastMsg") || "");
  1039.   },
  1040.  
  1041.   set guidMessageTS(val) {
  1042.     val = val.toString();
  1043.  
  1044.     if (this.isLogin)
  1045.       this.usersData[this.username]._guidLastMsgTs = val;
  1046.  
  1047.     this.setCharPref("yasearch.guid.lastMsg", val);
  1048.   },
  1049.  
  1050.   get guidUpdateDS() {
  1051.     return this.getIntPref("yasearch.guid.lastUpdate");
  1052.   },
  1053.  
  1054.   set guidUpdateDS(val) {
  1055.     val = val ? Math.abs(Date.now() / DAY_SECS) : 0;
  1056.     this.setIntPref("yasearch.guid.lastUpdate", val);
  1057.   },
  1058.  
  1059.   get mailCounter() {
  1060.     return this.isLogin ? (this.usersData[this.username]._mailCounter || 0) : 0;
  1061.   },
  1062.  
  1063.   set mailCounter(val) {
  1064.     if (this.isLogin)
  1065.       this.usersData[this.username]._mailCounter = Math.max(val, 0);
  1066.   },
  1067.  
  1068.   get newMailCounter() {
  1069.     return this.isLogin ? (this.usersData[this.username]._newMailCounter || 0) : 0;
  1070.   },
  1071.  
  1072.   set newMailCounter(val) {
  1073.     if (this.isLogin)
  1074.       this.usersData[this.username]._newMailCounter = Math.max(val, 0);
  1075.   },
  1076.  
  1077.   get mailPermCounter() {
  1078.     return this.isLogin ? (this.usersData[this.username]._mailPermCounter || 0) : 0;
  1079.   },
  1080.  
  1081.   set mailPermCounter(val) {
  1082.     if (this.isLogin)
  1083.       this.usersData[this.username]._mailPermCounter = Math.max(val, 0);
  1084.   },
  1085.  
  1086.   get mailDOMMenuDoc() {
  1087.     if (!this.isLogin)
  1088.       return false;
  1089.     
  1090.     let doc = this.usersData[this.username]._mailDOMMenuDoc;
  1091.     if (!doc) {
  1092.       doc = <list boxname={this.username + "@yandex.ru"} type="yandex"/>;
  1093.       this.usersData[this.username]._mailDOMMenuDoc = doc;
  1094.     }
  1095.     
  1096.     return this.usersData[this.username]._mailDOMMenuDoc;
  1097.   },
  1098.  
  1099.   set mailDOMMenuDoc(aXMLDoc) {
  1100.     if (this.isLogin) {
  1101.       let doc = this.usersData[this.username]._mailDOMMenuDoc = (aXMLDoc || <list/>);
  1102.       doc.@boxname = this.username + "@yandex.ru";
  1103.       doc.@type = "yandex";
  1104.     }
  1105.   },
  1106.  
  1107.   get mailData() {
  1108.     let xmlDataForAllAccounts = <lists/>;
  1109.     
  1110.     let yandexList = this.mailDOMMenuDoc;
  1111.     if (yandexList) {
  1112.       yandexList.@counter = this.mailCounter;
  1113.       xmlDataForAllAccounts.appendChild(yandexList);
  1114.     }
  1115.     
  1116.     let mfdData = this.yaMFD.getDataForAllUsers();
  1117.     for each (let list in mfdData.lists)
  1118.       xmlDataForAllAccounts.appendChild(list);
  1119.     
  1120.     let counterValue = this.mailCounter + mfdData.counter;
  1121.     let mfdListLength = mfdData.lists.list.length();
  1122.     
  1123.     let mfdWarning = !!(counterValue && this.isLogin && !this.mailCounter);
  1124.     let type = mfdWarning ? "mfd" : "yandex";
  1125.     
  1126.     return {
  1127.       "count": counterValue,
  1128.       "permCount": this.mailPermCounter,
  1129.       "nodes": this.getDOMDocContent2("xsl-templ/xsl-mail-items.xsl", xmlDataForAllAccounts),
  1130.       "lastmaxid": this.mailLastMaxId,
  1131.       "type": mfdWarning ? "mfd" : "yandex"
  1132.     };
  1133.   },
  1134.  
  1135.   get mailLastMaxId() {
  1136.     if (!this.isLogin || !this.usersData[this.username]._mailLastMaxId)
  1137.       return "0";
  1138.  
  1139.     return this.usersData[this.username]._mailLastMaxId;
  1140.   },
  1141.  
  1142.   set mailLastMaxId(id) {
  1143.     if (this.isLogin)
  1144.       this.usersData[this.username]._mailLastMaxId = id.toString();
  1145.   },
  1146.  
  1147.   get mailLastCheckIsOutOfDate() {
  1148.     if (!this.isLogin)
  1149.       return false;
  1150.  
  1151.     let lastCheckTime = this.usersData[this.username]._mailLastCheckTime || 0;
  1152.  
  1153.     return Math.abs(lastCheckTime - Date.now()) > (15 * MIN_SEC);
  1154.   },
  1155.  
  1156.   set mailLastCheckIsOutOfDate(val) {
  1157.     if (this.isLogin)
  1158.       this.usersData[this.username]._mailLastCheckTime = val ? 0 : Date.now();
  1159.   },
  1160.   
  1161.   bookmarksPrepeareDialog: function(aCallback) {
  1162.     this.xmlHttpRequest("http://zakladki.yandex.ru/bar/struct.xml?newdescr=true&" + getNCRndStr(),
  1163.                              { callbackFunc: this.bookmarksPrepeareDialogCallback.bind(this, aCallback) });
  1164.   },
  1165.  
  1166.   bookmarksPrepeareDialogCallback: function(aReq, aCallback) {
  1167.     var res;
  1168.  
  1169.     if (this.isReqError(aReq)) {
  1170.       res = "lost_connection";
  1171.     } else if (!this.isLogin) {
  1172.       res = "auth_required";
  1173.     } else {
  1174.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1175.       if (bookmarksResponse.error && bookmarksResponse.error !== "reg_required") {
  1176.         res = bookmarksResponse.error;
  1177.       } else {
  1178.         var data = bookmarksResponse.error ? "<err/>" : bookmarksResponse.xml.toString();
  1179.         if (res = this.getDOMDocContent("bar-bookmarks-folders", this.domParser.parseFromString(data, "text/xml")))
  1180.           res.setAttribute("disabled", "true");
  1181.         else
  1182.           res = "service";
  1183.       }
  1184.     }
  1185.  
  1186.     if (aCallback)
  1187.       aCallback(res);
  1188.   },
  1189.   
  1190.   bookmarksGetItemById: function(aId) {
  1191.     let item = this.bookmarksRawXml.bookmarks..*.(function::attribute("id") == aId)[0];
  1192.     
  1193.     return {
  1194.       id:       item.@id.toString(),
  1195.       type:     item.localName().toString(),
  1196.       url:      item.@url.toString(),
  1197.       name:     item.@name.toString(),
  1198.       descr:    item.descr.toString(),
  1199.       tags:     item.@tags.toString(),
  1200.       parentId: item.@folder_id.toString() || item.@parent_id.toString()
  1201.     };
  1202.   },
  1203.   
  1204.   bookmarksEditItem: function(aItem) {
  1205.     if (!aItem.id)
  1206.       throw "bookmarksEditItem: no ID";
  1207.  
  1208.     if (aItem.nfolder != "") {
  1209.       var url = "http://zakladki.yandex.ru/bar/addfolder.xml?" + getNCRndStr();
  1210.       url = this.appendStatData2Url(url,{});
  1211.  
  1212.       var data = "name=" + encodeURIComponent(aItem.nfolder) + "&parent_id=" + aItem.folder;
  1213.  
  1214.       this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksInsertNewFolderInXML.bind(this, aItem)});
  1215.  
  1216.     } else {
  1217.  
  1218.       var old = aItem._old_info;
  1219.  
  1220.       aItem.tags = this.yaBookmarks.formatTagsString(aItem.tags);
  1221.  
  1222.       if (old.name != aItem.name || old.descr != aItem.descr || old.url != aItem.url || old.tags != aItem.tags) {
  1223.  
  1224.         var type = aItem.type;
  1225.  
  1226.         var url = "http://zakladki.yandex.ru/bar/update" + type + ".xml?" + getNCRndStr();
  1227.         url = this.appendStatData2Url(url,{});
  1228.  
  1229.         var data = type + "_id=" + aItem.id +
  1230.                     "&name="  + encodeURIComponent(aItem.name) +
  1231.                     "&descr=" + encodeURIComponent(aItem.descr) +
  1232.                     "&tags="  + encodeURIComponent(aItem.tags);
  1233.  
  1234.         if (type == "link")
  1235.           data += "&url=" + encodeURIComponent(aItem.url);
  1236.  
  1237.         this.xmlHttpRequest(url, { data: data, callbackFunc: this.bookmarksEditItemInXML.bind(this, aItem) });
  1238.  
  1239.       } else if (aItem.folderOld != aItem.folder) {
  1240.         this.bookmarksMoveItem(aItem);
  1241.  
  1242.       } else {
  1243.         return aItem.callback();
  1244.       }
  1245.     }
  1246.   },
  1247.  
  1248.   bookmarksEditItemInXML: function(aReq, aItem) {
  1249.     var res;
  1250.  
  1251.     if (this.isReqError(aReq)) {
  1252.       res = "lost_connection";
  1253.     } else if (!this.isLogin) {
  1254.       res = "auth_required";
  1255.     } else {
  1256.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1257.       if (bookmarksResponse.error) {
  1258.         res = bookmarksResponse.error;
  1259.       } else {
  1260.         if (!bookmarksResponse.xml.ok.length()) {
  1261.           res = "service";
  1262.         } else {
  1263.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  1264.           var elem = (aItem.type == "folder" ? bookmarks..folder : bookmarks..link).(@id == aItem.id)[0];
  1265.  
  1266.           elem.@name  = aItem.name;
  1267.           elem.@url   = aItem.url;
  1268.           elem.descr  = aItem.descr;
  1269.           elem.@tags  = this.yaBookmarks.formatTagsString(aItem.tags);
  1270.  
  1271.           this.yaBookmarks.refreshBookmarksDOMMenu();
  1272.  
  1273.           if (aItem.folderOld != aItem.folder) {
  1274.             this.bookmarksMoveItem(aItem);
  1275.             return;
  1276.           }
  1277.         }
  1278.       }
  1279.     }
  1280.  
  1281.     return aItem.callback(res);
  1282.   },
  1283.  
  1284.   bookmarksMoveItem: function(aItem) {
  1285.     if (!aItem.id)
  1286.       throw "bookmarksMoveItem: no ID";
  1287.  
  1288.     var url = "http://zakladki.yandex.ru/bar/move.xml?" + getNCRndStr();
  1289.     url = this.appendStatData2Url(url,{});
  1290.  
  1291.     var data =  "folder_id=" + aItem.folder + "&" + (aItem.type == "folder" ? "fid" : "link_id") + "=" + aItem.id;
  1292.  
  1293.     this.xmlHttpRequest(url, { data: data, callbackFunc: this.bookmarksMoveItemInXML.bind(this, aItem) });
  1294.   },
  1295.  
  1296.   bookmarksMoveItemInXML: function(aReq, aItem) {
  1297.     var res;
  1298.  
  1299.     if (this.isReqError(aReq)) {
  1300.       res = "lost_connection";
  1301.     } else if (!this.isLogin) {
  1302.       res = "auth_required";
  1303.     } else {
  1304.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1305.       if (bookmarksResponse.error) {
  1306.         res = bookmarksResponse.error;
  1307.       } else {
  1308.         if (!bookmarksResponse.xml.ok.length()) {
  1309.           res = "service";
  1310.         } else {
  1311.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  1312.           var elem = (aItem.type == "folder" ? bookmarks..folder : bookmarks..link).(@id == aItem.id);
  1313.  
  1314.           if (elem[0]) {
  1315.             var clone = new XML(elem[0]);
  1316.             var inFolder = bookmarks..folder.(@id == aItem.folder), inFolderId = inFolder.@id.toString();
  1317.             if (inFolder.@id.toString() == "") {
  1318.               inFolder = bookmarks;
  1319.               inFolderId = "0";
  1320.             }
  1321.  
  1322.             var type = aItem.type;
  1323.  
  1324.             switch (type) {
  1325.               case "folder":
  1326.                 clone.@parent_id = inFolderId;
  1327.  
  1328.                 var len = inFolder.folder.(@name < aItem.name).length()-1;
  1329.                 if (len == -1)
  1330.                   inFolder.folder = clone + inFolder.folder;
  1331.                 else
  1332.                  inFolder.folder[len] += clone;
  1333.                 break;
  1334.  
  1335.               case "link":
  1336.                 clone.@folder_id = inFolderId;
  1337.  
  1338.                 var len = inFolder.links.link.(@name < aItem.name).length()-1;
  1339.                 if (len == -1)
  1340.                   inFolder.links.link = clone + inFolder.links.link;
  1341.                 else
  1342.                   inFolder.links.link[len] += clone;
  1343.                 break;
  1344.             }
  1345.  
  1346.             delete elem[0];
  1347.           }
  1348.         }
  1349.       }
  1350.     }
  1351.  
  1352.     this.yaBookmarks.refreshBookmarksDOMMenu();
  1353.  
  1354.     return aItem.callback(res);
  1355.   },
  1356.  
  1357.   bookmarksDeleteItem: function(aItem) {
  1358.     if (!aItem.id)
  1359.       throw "bookmarksDeleteItem: no ID";
  1360.  
  1361.     var url = "http://zakladki.yandex.ru/bar/del.xml?" + getNCRndStr();
  1362.     url = this.appendStatData2Url(url, {});
  1363.  
  1364.     var data = (aItem.type == "folder" ? "fid" : "link_id") + "=" + encodeURIComponent(aItem.id);
  1365.  
  1366.     this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksDeleteItemInXML.bind(this, aItem)});
  1367.   },
  1368.  
  1369.   bookmarksDeleteItemInXML: function(aReq, aItem) {
  1370.     var res;
  1371.  
  1372.     if (this.isReqError(aReq)) {
  1373.       res = "lost_connection";
  1374.     } else if (!this.isLogin) {
  1375.       res = "auth_required";
  1376.     } else {
  1377.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1378.       if (bookmarksResponse.error) {
  1379.         res = bookmarksResponse.error;
  1380.       } else {
  1381.         if (!bookmarksResponse.xml.ok.length()) {
  1382.           res = "service";
  1383.         } else {
  1384.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  1385.           var elem = (aItem.type == "folder" ? bookmarks..folder : bookmarks..link).(@id == aItem.id);
  1386.  
  1387.           if (elem[0]) {
  1388.             delete elem[0];
  1389.  
  1390.             this.yaBookmarks.refreshBookmarksDOMMenu();
  1391.           }
  1392.         }
  1393.       }
  1394.     }
  1395.  
  1396.     return aItem.callback(res);
  1397.   },
  1398.  
  1399.   bookmarksSubscribeCallback: function(aReq, aItem) {
  1400.     this.bookmarksInsertNewItem(aItem);
  1401.   },
  1402.  
  1403.   bookmarksInsertNewItem: function(aItem) {
  1404.     if (this.yaBookmarks.isRegRequired) {
  1405.       this.yaBookmarks.isRegRequired = null;
  1406.       if (!this.yaBookmarks.isRegRequired) {
  1407.         this.xmlHttpRequest("http://passport.yandex.ru/passport?mode=subscribe&from=zakladki",
  1408.                              { callbackFunc: this.bookmarksSubscribeCallback.bind(this, aItem) });
  1409.         return;
  1410.       }
  1411.     }
  1412.  
  1413.     if (aItem.nfolder) {
  1414.       var url = "http://zakladki.yandex.ru/bar/addfolder.xml?" + getNCRndStr();
  1415.       url = this.appendStatData2Url(url, {});
  1416.  
  1417.       var data = "name=" + encodeURIComponent(aItem.nfolder) + "&parent_id=" + aItem.folder;
  1418.  
  1419.       this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksInsertNewFolderInXML.bind(this, aItem)});
  1420.  
  1421.     } else {
  1422.       var url = "http://zakladki.yandex.ru/bar/addlink.xml?" + getNCRndStr();
  1423.       url = this.appendStatData2Url(url, {});
  1424.  
  1425.       var yaruDataAppend = (aItem.yaru && ("feed_id" in aItem.yaru) && ("status" in aItem.yaru)) ?
  1426.                                ("&feed_id=" + encodeURIComponent(aItem.yaru.feed_id) +
  1427.                                 "&status=" + encodeURIComponent(aItem.yaru.status)) : "";
  1428.  
  1429.       var data = "name="        + encodeURIComponent(aItem.name)  +
  1430.                   "&url="        + encodeURIComponent(aItem.url)   +
  1431.                   "&descr="      + encodeURIComponent(aItem.descr) +
  1432.                   "&tags="       + encodeURIComponent(aItem.tags)  +
  1433.                   "&folder_id="  + (aItem.folder || 0) +
  1434.                   "&newfolder="  +
  1435.                   yaruDataAppend +
  1436.                   "&from=barff";
  1437.  
  1438.       this.xmlHttpRequest(url, {data: data, callbackFunc: this.bookmarksInsertNewLinkInXML.bind(this, aItem)});
  1439.     }
  1440.   },
  1441.  
  1442.   bookmarksInsertNewFolderInXML: function(aReq, aItem) {
  1443.     var res;
  1444.  
  1445.     if (this.isReqError(aReq)) {
  1446.       res = "lost_connection";
  1447.     } else if (!this.isLogin) {
  1448.       res = "auth_required";
  1449.     } else {
  1450.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1451.       if (bookmarksResponse.error) {
  1452.         res = bookmarksResponse.error;
  1453.       } else {
  1454.         var newFolderId = bookmarksResponse.xml.ok[0].@id.toString();
  1455.         if (!newFolderId) {
  1456.           res = "service";
  1457.         } else {
  1458.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  1459.           var elem = bookmarks..folder.(@id == aItem.folder);
  1460.           var parent = elem.@id.toString() == "" ? bookmarks : elem;
  1461.  
  1462.           var parentId = parent.@id.toString() == "" ? "0" : parent.@id.toString();
  1463.  
  1464.           if (bookmarks..folder.(@id == newFolderId).length() == 0) {
  1465.             var newItem = new XML('<folder id="' + newFolderId + '" parent_id="' + parentId + '"><links/></folder>');
  1466.             newItem.@name = aItem.nfolder;
  1467.  
  1468.             var len = parent.folder.(@name < aItem.nfolder).length()-1;
  1469.             if (len == -1)
  1470.               parent.folder = newItem + parent.folder;
  1471.             else
  1472.               parent.folder[len] += newItem;
  1473.  
  1474.             this.yaBookmarks.refreshBookmarksDOMMenu();
  1475.           }
  1476.  
  1477.           aItem.nfolder = "";
  1478.           aItem.folder = newFolderId;
  1479.  
  1480.           this.yaBookmarks.lastUsedFolder = newFolderId;
  1481.  
  1482.           if (aItem.folderOld) {
  1483.             this.bookmarksEditItem(aItem);
  1484.           } else {
  1485.             this.bookmarksInsertNewItem(aItem);
  1486.           }
  1487.         }
  1488.       }
  1489.     }
  1490.  
  1491.     if (res)
  1492.       return aItem.callback(res);
  1493.   },
  1494.  
  1495.   bookmarksInsertNewLinkInXML: function(aReq, aItem) {
  1496.     var res;
  1497.  
  1498.     if (this.isReqError(aReq)) {
  1499.       res = "lost_connection";
  1500.     } else if (!this.isLogin) {
  1501.       res = "auth_required";
  1502.     } else {
  1503.       var bookmarksResponse = this.yaBookmarks.getServerResponse(aReq.target.responseText);
  1504.       if (bookmarksResponse.error) {
  1505.         res = bookmarksResponse.error;
  1506.       } else {
  1507.         var newLinkId = bookmarksResponse.xml.ok[0].@id.toString();
  1508.         if (!newLinkId || newLinkId == "0") {
  1509.           res = "service";
  1510.         } else {
  1511.           if (bookmarksResponse.xml.ok[0].@yaru_link.toString()) {
  1512.             res = this.getDOMDocContent2("bookmarks/xsl-yaru-post-props.xsl",
  1513.                                           this.domParser.parseFromString(bookmarksResponse.xml.toSource(), "text/xml"));
  1514.           } else {
  1515.             res = null;
  1516.           }
  1517.  
  1518.           try {
  1519.             var _uri = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newURI(aItem.url, null, null);
  1520.  
  1521.             aItem.url = "hostPort" in _uri ?
  1522.                         [_uri.scheme, "://", (_uri.scheme == "file" ? "/" : ""), _uri.hostPort, _uri.path].join("") :
  1523.                         _uri.spec;
  1524.           } catch(e) {
  1525.             aItem.url = "http://" + aItem.url;
  1526.           }
  1527.  
  1528.           var bookmarks = this.usersData[this.username]._bookmarksRawXml.bookmarks;
  1529.           var elem = bookmarks..folder.(@id == aItem.folder);
  1530.           var parent = (elem.@id.toString() == "" ? bookmarks : elem).links;
  1531.  
  1532.           var duplicate = !!(bookmarksResponse.xml.ok[0].@duplicate.toString() > "");
  1533.           duplicate = duplicate && parent.link.(@id == newLinkId).length();
  1534.  
  1535.           if (!duplicate) {
  1536.             var newItem = new XML('<link id="' + newLinkId + '" folder_id="' + aItem.folder + '"/>');
  1537.             newItem.@name  = aItem.name;
  1538.             newItem.@url   = aItem.url;
  1539.             newItem.descr = aItem.descr;
  1540.             newItem.@tags  = aItem.tags;
  1541.  
  1542.             var len = parent.link.(@name < aItem.name).length()-1;
  1543.             if (len == -1)
  1544.               parent.link = newItem + parent.link;
  1545.             else
  1546.               parent.link[len] += newItem;
  1547.           }
  1548.  
  1549.           this.yaBookmarks.refreshBookmarksDOMMenu();
  1550.         }
  1551.       }
  1552.     }
  1553.  
  1554.     return aItem.callback(res);
  1555.   },
  1556.  
  1557.   get bookmarksDOMMenu() {
  1558.     if (!this.isLogin)
  1559.       return this.bookmarksDOMMenuDefault;
  1560.  
  1561.     if (!this.usersData[this.username].bookmarksDOMMenu)
  1562.       this.bookmarksDOMMenu = false;
  1563.  
  1564.     return this.usersData[this.username].bookmarksDOMMenu.cloneNode(true);
  1565.   },
  1566.  
  1567.   get bookmarksDOMMenuDefault() {
  1568.     if (!this._bookmarksDOMMenuDefault)
  1569.       this._bookmarksDOMMenuDefault = this.getDOMDocContent("bar-bookmarks",
  1570.                                       this.domParser.parseFromString("<page><bookmarks/></page>", "text/xml"));
  1571.     
  1572.     return this._bookmarksDOMMenuDefault.cloneNode(true);
  1573.   },
  1574.  
  1575.   set bookmarksDOMMenu(aBookmarksXML) {
  1576.     if (!this.isLogin)
  1577.       return false;
  1578.  
  1579.     this.usersData[this.username]._bookmarksRawXml = aBookmarksXML || this.bookmarksRawXml;
  1580.  
  1581.     if (aBookmarksXML)
  1582.       this.usersData[this.username]._bookmarksRawXml.@ts = Date.now();
  1583.  
  1584.     this.usersData[this.username].bookmarksDOMMenu =
  1585.         this.getDOMDocContent2("xsl-templ/xsl-bar-bookmarks.xsl",
  1586.             this.domParser.parseFromString(this.usersData[this.username]._bookmarksRawXml, "text/xml"),
  1587.             { addToFolderOnTop: this.getBoolPref("yasearch.general.ui.bookmarks.showaddtofolderontop") });
  1588.  
  1589.     this.yaBookmarks.bookmarksCache.clear(true);
  1590.   },
  1591.  
  1592.   get bookmarksRawXml() {
  1593.     return (this.isLogin && this.usersData[this.username]._bookmarksRawXml) ?
  1594.                     this.usersData[this.username]._bookmarksRawXml :
  1595.                     new XML("<page><bookmarks/></page>");
  1596.   },
  1597.  
  1598.   bookmarksGetLinksInFolder: function(aFolderId) {
  1599.     let urlArray = [];
  1600.     let folder = aFolderId ? this.bookmarksRawXml.bookmarks..folder.(@id == aFolderId) : this.bookmarksRawXml.bookmarks;
  1601.     
  1602.     for each (var link in folder.links.link)
  1603.       urlArray.push(link.@url.toString());
  1604.  
  1605.     return urlArray;
  1606.   },
  1607.  
  1608.   get bookmarksIsOutOfDate() {
  1609.     if (this.isLogin && !this.usersData[this.username]._bookmarksRawXml)
  1610.       return true;
  1611.  
  1612.     let lastCheckTime = this.parseIntFromStr(this.bookmarksRawXml.@ts);
  1613.     return !!(lastCheckTime && (Math.abs(Date.now() - lastCheckTime) > DAY_SECS))
  1614.   },
  1615.  
  1616.   setNotifyTimer: function(cancel) {
  1617.     if (!this._notifyTimer) {
  1618.       this._notifyTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  1619.       this._notifyTimer.initWithCallback(this, 1000, Ci.nsITimer.TYPE_REPEATING_SLACK);
  1620.     } else if (cancel) {
  1621.       this._runnedNotifications = [];
  1622.       this._notifyTimer.cancel();
  1623.       this._notifyTimer = null;
  1624.     }
  1625.   },
  1626.  
  1627.   notify: function(aTimer) {
  1628.     if (!this._runnedNotifications || this._runnedNotifications.length < 1)
  1629.       return this.setNotifyTimer("cancel");
  1630.  
  1631.     var notif = this._runnedNotifications[0];
  1632.     if (notif.isShowing == true)
  1633.       return;
  1634.  
  1635.     if (this.getBoolPref("yasearch." + notif.type + ".ui.notification.enabled")) {
  1636.       notif.isShowing = true;
  1637.  
  1638.       var msg = [(notif.type == "mail" && notif.nmb == 0) ?
  1639.                    this.getFormattedString("mailNotificationMsgPlus", [this.maxUnreadInXML]) :
  1640.                    this.getFormattedStringL18End(notif.type + "NotificationMsg", [notif.nmb])];
  1641.       
  1642.       let typeData = { type: notif.type };
  1643.       
  1644.       if (notif.type == "mail") {
  1645.         if (notif.nmb != 1)
  1646.           msg[0] += this.getString("mailNotificationMsgLast");
  1647.  
  1648.         msg.push([notif.mdata.from, notif.mdata.title]);
  1649.         
  1650.         if (notif.mdata.mfdDomain)
  1651.           typeData.mfdDomain = notif.mdata.mfdDomain;
  1652.       }
  1653.  
  1654.       this.showAlert(this.getString(notif.type + "NotificationTitle"), msg, typeData);
  1655.     } else {
  1656.       this._runnedNotifications.shift();
  1657.     }
  1658.  
  1659.     if (this.getBoolPref("yasearch." + notif.type + ".ui.soundnotification.enabled"))
  1660.       this.playSoundURL(this.getComplexValue("yasearch." + notif.type + ".ui.soundnotification.uri"));
  1661.   },
  1662.  
  1663.   playSoundURL: function(aSoundUrl) {
  1664.     if (!aSoundUrl || !aSoundUrl.length)
  1665.       return;
  1666.  
  1667.     var uri;
  1668.  
  1669.     try {
  1670.       if (aSoundUrl.indexOf("file://") == -1) {
  1671.         var tempLocalFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  1672.         tempLocalFile.initWithPath(aSoundUrl);
  1673.         uri = this.makeFileURI(tempLocalFile);
  1674.       } else {
  1675.         uri = this.makeURI(aSoundUrl);
  1676.       }
  1677.  
  1678.       this.soundService.play(uri);
  1679.  
  1680.     } catch(e) {}
  1681.   },
  1682.  
  1683.   notifyAboutNewItems: function(aType, aNewNum, aMailData) {
  1684.     switch (aType) {
  1685.       case "lenta":
  1686.         aType = "feeds";
  1687.         break;
  1688.       
  1689.       case "mailList":
  1690.         aType = "mail";
  1691.         break;
  1692.       
  1693.       default:
  1694.         return;
  1695.     }
  1696.  
  1697.     if (this.getBoolPref("yasearch." + aType + ".ui.notification.enabled") ||
  1698.         this.getBoolPref("yasearch." + aType + ".ui.soundnotification.enabled")) {
  1699.       
  1700.       this._runnedNotifications.push({
  1701.         type: aType,
  1702.         nmb: aNewNum,
  1703.         mdata: aMailData,
  1704.         isShowing: false
  1705.       });
  1706.       
  1707.       this.setNotifyTimer();
  1708.     }
  1709.   },
  1710.  
  1711.   _showAlertWithGrowl: function(title, msg, aTypeData) {
  1712.     if (this.AppInfo.OS.isMacOS) {
  1713.       try {
  1714.         var listener = {
  1715.           observe: function(aSubject, aTopic, aData) {
  1716.               if (aTopic == "alertclickcallback") {
  1717.                 let action;
  1718.                 
  1719.                 switch (aData) {
  1720.                   case "mfd":
  1721.                   case "mail":
  1722.                     action = 1040;
  1723.                     break;
  1724.                   case "feeds":
  1725.                     action = 1120;
  1726.                     break;
  1727.                   default:
  1728.                     return;
  1729.                 }
  1730.                 
  1731.                 gYaSearchService.loadConditionalURI(this._condURIType, "tab", {action: action});
  1732.               }
  1733.           },
  1734.           
  1735.           _condURIType: aTypeData.mfdDomain || aTypeData.type
  1736.         }
  1737.  
  1738.           var alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
  1739.           
  1740.           alertsService.showAlertNotification(CHROME_IMAGES + "bar-logo.png",
  1741.             title.split(":")[0], msg, false,
  1742.             aTypeData.mfdDomain ? "mfd" : aTypeData.type,
  1743.             listener);
  1744.  
  1745.         return true;
  1746.  
  1747.       } catch(e) {}
  1748.     }
  1749.  
  1750.     return false;
  1751.   },
  1752.  
  1753.   showAlert: function(title, msg, aTypeData) {
  1754.       if (this._showAlertWithGrowl(title, msg, aTypeData)) {
  1755.       this._runnedNotifications.shift();
  1756.         return;
  1757.       }
  1758.     
  1759.     let flags = "chrome,popup=yes";
  1760.     if (!this.AppInfo.browser.isGreaterThenFx35)
  1761.       flags += ",titlebar=no";
  1762.     
  1763.     let url = (aTypeData && aTypeData.type) ?
  1764.                   CHROME_CONTENT + "alerts/timed.alert.xul" :
  1765.                   "chrome://global/content/alerts/alert.xul";
  1766.     
  1767.     var alertWin = this.windowWatcher.openWindow(null, url, "_blank", flags, null);
  1768.     alertWin.arguments = [CHROME_IMAGES + "bar-logo.png", title, msg, aTypeData, this.timedAlertListener];
  1769.   },
  1770.  
  1771.   showPermanentAlert: function(title, msg, image, cookie) {
  1772.     let flags = "chrome,popup=yes";
  1773.     
  1774.     if (!this.AppInfo.browser.isGreaterThenFx35)
  1775.       flags += ",titlebar=no";
  1776.     
  1777.     var alertWin = this.windowWatcher.openWindow(null, CHROME_CONTENT + "alerts/permanent.alert.xul",
  1778.                                                  "_blank", flags, null);
  1779.     
  1780.     alertWin.arguments = [image && image != "" ? image : CHROME_IMAGES + "bar-logo.png", title, msg,
  1781.                           (cookie||""), this.permanentAlertListener];
  1782.   },
  1783.  
  1784.   timedAlertListener: {
  1785.     observe: function(aSubject, aTopic, aData) {
  1786.       if (aTopic == "alertfinished" && gYaSearchService._runnedNotifications)
  1787.         gYaSearchService._runnedNotifications.shift();
  1788.     }
  1789.   },
  1790.  
  1791.   permanentAlertListener: {
  1792.     observe: function(aSubject, aTopic, aData) {
  1793.       if (aTopic == "alertfinished") {
  1794.         switch (aData) {
  1795.           case "":
  1796.           case "error":
  1797.           case "installed":
  1798.             break;
  1799.           case "cancelled":
  1800.             gYaSearchService.guidUpdateDS = true;
  1801.             break;
  1802.           default:
  1803.             gYaSearchService.guidMessageTS = aData;
  1804.         }
  1805.       }
  1806.     }
  1807.   },
  1808.  
  1809.   decMailCounter: function(aMailId) {
  1810.     let item = this.mailDOMMenuDoc ? this.mailDOMMenuDoc.item.item.(@url == aMailId)[0] : null;
  1811.     if (item) {
  1812.       let parent = item.parent();
  1813.       
  1814.       delete parent.item[item.childIndex()];
  1815.       
  1816.       if (!parent.item.length())
  1817.         delete parent.parent().item[parent.childIndex()];
  1818.       
  1819.       this.mailCounter--;
  1820.       this.mailPermCounter--;
  1821.       
  1822.       new G_Timer(function(){OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "mailList")}, 1);
  1823.       
  1824.       this.mailLastCheckIsOutOfDate = true;
  1825.       this.refreshHTTPData("mail", null, 10000);
  1826.     } else {
  1827.       this.yaMFD.decMailCounter(aMailId);
  1828.     }
  1829.   },
  1830.  
  1831.   KeyCorrector: {
  1832.     STATE_DISABLED: 0,
  1833.     STATE_RUNNED:   1,
  1834.     STATE_STOPPED:  2,
  1835.  
  1836.     _statePrefName: "yasearch.general.ui.urlbar.corrector.state",
  1837.  
  1838.     _checkStateValue: function(aValue) {
  1839.       if (aValue > this.STATE_STOPPED || aValue < this.STATE_DISABLED)
  1840.         aValue = this.STATE_STOPPED;
  1841.       return aValue;
  1842.     },
  1843.  
  1844.     get currentState() {
  1845.       return this._checkStateValue(gYaSearchService.getIntPref(this._statePrefName));
  1846.     },
  1847.  
  1848.     set currentState(val) {
  1849.       gYaSearchService.setIntPref(this._checkStateValue(this._statePrefName), val);
  1850.       return val;
  1851.     },
  1852.  
  1853.     get keyConvTable() {
  1854.       return gYaSearchService.windowsOS ?
  1855.         { withoutShift: { 192: 96, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57, 48: 48, 109: 45, 61: 61, 81: 113, 87: 119, 69: 101, 82: 114, 84: 116, 89: 121, 85: 117, 73: 105, 79: 111, 80: 112, 219: 91, 221: 93, 220: 92, 65: 97, 83: 115, 68: 100, 70: 102, 71: 103, 72: 104, 74: 106, 75: 107, 76: 108, 59: 59, 222: 39, 90: 122, 88: 120, 67: 99, 86: 118, 66: 98, 78: 110, 77: 109, 188: 44, 190: 46, 191: 47 },
  1856.           withShift: { 192: 126, 49: 33, 50: 64, 51: 35, 52: 36, 53: 37, 54: 94, 55: 38, 56: 42, 57: 40, 48: 41, 109: 95, 61: 43, 81: 81, 87: 87, 69: 69, 82: 82, 84: 84, 89: 89, 85: 85, 73: 73, 79: 79, 80: 80, 219: 123, 221: 125, 220: 124, 65: 65, 83: 83, 68: 68, 70: 70, 71: 71, 72: 72, 74: 74, 75: 75, 76: 76, 59: 58, 222: 34, 90: 90, 88: 88, 67: 67, 86: 86, 66: 66, 78: 78, 77: 77, 188: 60, 190: 62, 191: 63 }
  1857.         } : null
  1858.     },
  1859.  
  1860.     __charConvTable: null,
  1861.  
  1862.     get charConvTable() {
  1863.       if (!this.__charConvTable) {
  1864.         var withoutShift = {},
  1865.             withShift = {};
  1866.  
  1867.         var cirChars = UConverter.ConvertToUnicode(
  1868.                         "╨╣╤å╤â╨║╨╡╨╜╨│╤ê╤ë╨╖╤à╤è╤ä╤ï╨▓╨░╨┐╤Ç╨╛╨╗╨┤╨╢╤ì╤Å╤ç╤ü╨╝╨╕╤é╤î╨▒╤Ä╤æ╨Ö╨ª╨ú╨Ü╨ò╨¥╨ô╨¿╨⌐╨ù╨Ñ╨¬╨ñ╨½╨Æ╨É╨ƒ╨á╨₧╨¢╨ö╨û╨¡╨»╨º╨í╨£╨ÿ╨ó╨¼╨æ╨«╨ü╤û╨å");
  1869.         var latChars = "qwertyuiop[]asdfghjkl;'zxcvbnm,.`QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,.`sS";
  1870.  
  1871.         var cirCharsShift = UConverter.ConvertToUnicode('╤à╤è╨╢╤ì╨▒╤Ä╤æ"*,.;Γäû');
  1872.         var latCharsShift = '{}:"<>~@$^&*#';
  1873.  
  1874.         var i=0, ch;
  1875.         while ((ch = cirChars[i]))
  1876.           withoutShift[ch] = latChars[i++];
  1877.  
  1878.         i=0;
  1879.         while ((ch = cirCharsShift[i]))
  1880.           withShift[ch] = latCharsShift[i++];
  1881.  
  1882.         this.__charConvTable = { withoutShift: withoutShift, withShift: withShift };
  1883.       }
  1884.  
  1885.       return this.__charConvTable;
  1886.     }
  1887.   },
  1888.  
  1889.   Bloggers: {
  1890.     cachedTabs: {},
  1891.     
  1892.     _tabTimer: null,
  1893.     
  1894.     _setTimer: function(aTabData, aVal) {
  1895.       if (this._tabTimer)
  1896.         this._tabTimer.cancel();
  1897.       else if (aVal)
  1898.         this._tabTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  1899.  
  1900.       if (!aVal)
  1901.         return;
  1902.       
  1903.       this._tabTimer.initWithCallback({
  1904.         tab: aVal.tab,
  1905.         url: aVal.url,
  1906.         
  1907.         notify: function(aTimer) {
  1908.           let bloggers = gYaURLInfo.getBloggers(this.url);
  1909.           if (!bloggers)
  1910.             return;
  1911.           
  1912.           var _self = gYaSearchService.Bloggers;
  1913.           if (bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_TIMED_REQUEST) {
  1914.             bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_REQUEST;
  1915.             
  1916.             _self.setBloggersData(false, this.tab, this.url);
  1917.             
  1918.             let _url = "http://blogs.yandex.ru/bar.xml?text=" +
  1919.                         encodeURIComponent('!link="' + this.url + '"') +
  1920.                         "&count=" + bloggers.value +
  1921.                         (this.manual ? "&" + getNCRndStr() : "");
  1922.             
  1923.             gYaSearchService.xmlHttpRequest(
  1924.                 _url,
  1925.                 {callbackFunc: _self.setBloggersData.bind(_self, this.tab, this.url)}
  1926.             );
  1927.           }
  1928.         }
  1929.       }, aTabData._timeout, Ci.nsITimer.TYPE_ONE_SHOT);
  1930.     },
  1931.  
  1932.     clearTabData: function(aTabId) {
  1933.       delete this.cachedTabs[aTabId];
  1934.     },
  1935.     
  1936.     getBloggersData: function(aTab, aSkipCache, aTimeout, aManual) {
  1937.       if (!(aTab && aTab.selected))
  1938.         return;
  1939.       
  1940.       let bloggers = gYaURLInfo.getBloggers(aTab.linkedBrowser.currentURI);
  1941.       if (!bloggers)
  1942.         return;
  1943.       
  1944.       let url = bloggers.url,
  1945.           aTabId = aTab.linkedPanel,
  1946.           tData = this.cachedTabs[aTabId];
  1947.  
  1948.       if (!tData)
  1949.         tData = this.cachedTabs[aTabId] = { visible: false };
  1950.       
  1951.       tData.url = url;
  1952.       tData._timeout = aTimeout ? 5 : 5000;
  1953.  
  1954.       this._setTimer();
  1955.       
  1956.       if ((bloggers.buttonState === gYaURLInfo.BLOGGERS_STATE_UNKNOWN) ||
  1957.           (aSkipCache && !(bloggers.buttonState & gYaURLInfo.BLOGGERS_STATE_REQUEST)))
  1958.       {
  1959.         bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_UNKNOWN;
  1960.         
  1961.         if (aManual) {
  1962.           bloggers.manual = true;
  1963.           gYaSearchService.notifyBusyStateOfRequest(null, true, true, "yasearch-bloggers");
  1964.         }
  1965.         
  1966.         gYaSearchService.getCY(url, aTab.linkedBrowser.webProgress, false);
  1967.       
  1968.       } else if (bloggers.value > 0 && tData && this.isWindowVisible(aTab) &&
  1969.                   ((bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_UNKNOWN) ||
  1970.                    (bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_TIMED_REQUEST) ||
  1971.                   (aSkipCache && !(bloggers.windowState & gYaURLInfo.BLOGGERS_STATE_REQUEST))))
  1972.       {
  1973.         bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_TIMED_REQUEST;
  1974.         this._setTimer(tData, {tab: aTab, url: url});
  1975.       }
  1976.       
  1977.       this.setBloggersData(false, aTab, url);
  1978.     },
  1979.  
  1980.     persistScrollPosition: function(aURL, aYPos) {
  1981.       let bloggers = gYaURLInfo.getBloggers(aURL);
  1982.       if (bloggers)
  1983.         bloggers.scroll = aYPos;
  1984.     },
  1985.  
  1986.     switchWindowMode: function(aMode) {
  1987.       this._fullMode = aMode === null ? !this._fullMode : aMode;
  1988.       return this._fullMode;
  1989.     },
  1990.  
  1991.     hideTopModeWindow: function() {
  1992.       if (this._fullMode)
  1993.         for each (let tabData in this.cachedTabs)
  1994.           if (tabData.visible)
  1995.             tabData.visible = false;
  1996.     },
  1997.  
  1998.     persistWindowVisible: function(aTab, aVisible) {
  1999.       let tData = this.cachedTabs[aTab.linkedPanel];
  2000.       if (!tData)
  2001.         tData = this.cachedTabs[aTab.linkedPanel] = {};
  2002.       
  2003.       tData.visible = aVisible;
  2004.     },
  2005.  
  2006.     isWindowVisible: function(aTab) {
  2007.       if (this._fullMode)
  2008.         return true;
  2009.       
  2010.       if (!aTab.selected)
  2011.         return false;
  2012.       
  2013.       let tData = this.cachedTabs[aTab.linkedPanel];
  2014.       return !!(tData && tData.visible);
  2015.     },
  2016.  
  2017.     setBloggersData: function(aReq, aTab, aUrl) {
  2018.       let bloggers = gYaURLInfo.getBloggers(aUrl);
  2019.       if (!bloggers)
  2020.         return;
  2021.       
  2022.       if (bloggers.manual) {
  2023.         bloggers.manual = false;
  2024.         gYaSearchService.notifyBusyStateOfRequest(null, false, true, "yasearch-bloggers");
  2025.       }
  2026.       
  2027.       if (aReq != false) {
  2028.         bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_ERROR;
  2029.  
  2030.         if (!gYaSearchService.isReqError(aReq)) {
  2031.           let serverDate;
  2032.           
  2033.           try {
  2034.             serverDate = new Date(aReq.target.getResponseHeader("Date"));
  2035.  
  2036.             if (serverDate != "Invalid Date")
  2037.               serverDate = new Date(serverDate.getTime() +
  2038.                                     serverDate.getTimezoneOffset() * 60 * 1000 +
  2039.                                     3 * 60 * 60 * 1000);
  2040.  
  2041.             if (serverDate == "Invalid Date")
  2042.               serverDate = null;
  2043.           } catch(e) {}
  2044.           
  2045.           let doc = gYaSearchService.getDOMDocContent2("xsl-templ/xsl-bloggers-data.xsl",
  2046.                                      gYaSearchService.domParser.parseFromString(aReq.target.responseText, "text/xml"));
  2047.  
  2048.           if (doc && doc.localName == "vbox") {
  2049.             bloggers.windowState = gYaURLInfo.BLOGGERS_STATE_RESPONSE;
  2050.  
  2051.             doc.firstChild.setAttribute("location", bloggers.url);
  2052.  
  2053.             if (serverDate) {
  2054.               Array.forEach(doc.getElementsByTagName("label"), function(aLabel) {
  2055.                 if (aLabel.getAttribute("class") == "ya-blogger-time") {
  2056.                   var postDate = this.getDateDiffString(serverDate, this.getDateFromString(aLabel.getAttribute("value")));
  2057.                   if (postDate)
  2058.                     aLabel.setAttribute("value", postDate);
  2059.                 }
  2060.               }, this);
  2061.             }
  2062.  
  2063.             Array.forEach(doc.getElementsByTagName("description"), function(aDescription) {
  2064.               var node = aDescription.firstChild;
  2065.               if (node && node.nodeName == "#text")
  2066.                 node.nodeValue = node.nodeValue.replace(/([\/\-&\?\.])/g, "$1\u200B")
  2067.                                                .replace(/(\S{15})(\S{15})/g, "$1\u200B$2");
  2068.             })
  2069.             
  2070.             
  2071.             bloggers.content = doc;
  2072.           }
  2073.         } else {
  2074.           gYaSearchService.log("setBloggersData got bad request result");
  2075.         }
  2076.       }
  2077.       
  2078.       try {
  2079.         if (aTab.selected)
  2080.           aTab.ownerDocument.defaultView.Ya.Bloggers.setData(bloggers);
  2081.       } catch(e) {}
  2082.     },
  2083.  
  2084.     getDateFromString: function(aString) {
  2085.       let res = aString.match(/(\d{1,2})\.(\d{1,2})\.(\d{4})(?:\s+(\d{1,2})\:(\d{1,2}))?/) ?
  2086.                     new Date(RegExp.$3, (RegExp.$2 * 1) - 1, RegExp.$1, RegExp.$4, RegExp.$5) :
  2087.                     null;
  2088.  
  2089.       return (!res && res == "Invalid Date") ? null : res;
  2090.     },
  2091.  
  2092.     _getFormatedTime: function(aDate) {
  2093.       return [aDate.getHours(), ("0" + aDate.getMinutes()).slice(-2)].join(":");
  2094.     },
  2095.  
  2096.     getDateDiffString: function(aCurrentDate, aDate) {
  2097.       if (!(aCurrentDate instanceof Date) || !(aDate instanceof Date))
  2098.         return null;
  2099.  
  2100.       let diff = aCurrentDate.getTime() - aDate.getTime();
  2101.       if (diff < 0)
  2102.         return null;
  2103.  
  2104.       let res = [],
  2105.           strType = "year";
  2106.  
  2107.       if (diff < DAY_SECS)
  2108.         strType = "today";
  2109.  
  2110.       if (aCurrentDate.getDate() != aDate.getDate())
  2111.         strType = "yesterday";
  2112.  
  2113.       if (diff >= DAY_SECS * 2)
  2114.         strType = "month";
  2115.  
  2116.       if (aCurrentDate.getYear() != aDate.getYear())
  2117.         strType = "year";
  2118.  
  2119.       switch (strType) {
  2120.         case "year":
  2121.           res = [aDate.getDate(), this.dateStrings.months[aDate.getMonth()], aDate.getFullYear()];
  2122.           break;
  2123.  
  2124.         case "month":
  2125.           res = [aDate.getDate(), this.dateStrings.months[aDate.getMonth()]];
  2126.           res.push(this._getFormatedTime(aDate));
  2127.           break;
  2128.  
  2129.         case "today":
  2130.         case "yesterday":
  2131.           res = [this.dateStrings[strType]];
  2132.           res.push(this._getFormatedTime(aDate));
  2133.           break;
  2134.       }
  2135.  
  2136.       return res.join(" ");
  2137.     },
  2138.  
  2139.     _dateStrings: null,
  2140.  
  2141.     get dateStrings() {
  2142.       if (!this._dateStrings) {
  2143.         this._dateStrings = {
  2144.           months: gYaSearchService.getString("dateMonths").toLowerCase().split(","),
  2145.           today: gYaSearchService.getString("dateToday"),
  2146.           yesterday: gYaSearchService.getString("dateYesterday")
  2147.         }
  2148.       }
  2149.  
  2150.       return this._dateStrings;
  2151.     }
  2152.   },
  2153.   
  2154.   _browserButtons: null,
  2155.   
  2156.   get browserButtons() {
  2157.     if (!this._browserButtons)
  2158.       this._browserButtons = this.buttonsInfo || {};
  2159.     
  2160.     return this._browserButtons;
  2161.   },
  2162.   
  2163.   set browserButtons(val) {
  2164.     this._browserButtons = val;
  2165.   },
  2166.   
  2167.   webProgressListener: {
  2168.     _servicesRe: /^https?:\/\/(?:((?:web)?mail|lenta(?:\-ng)?|money|fotki)\.yandex|[^\/]*\.(ya)|(moikrug))\.(?:ru|ua|kz|by)\/(.*)/i,
  2169.  
  2170.     _checkNeedRefreshData: function(aURL, aButtons) {
  2171.       aURL = "" + aURL;
  2172.       
  2173.       if (!aURL.match(this._servicesRe))
  2174.         return;
  2175.       
  2176.       var service = (RegExp.$1 || RegExp.$2 || RegExp.$3).toLowerCase();
  2177.       var path    = RegExp.$4.toLowerCase();
  2178.       
  2179.       var timeoutDelay = 5000;
  2180.       
  2181.       if (service == "mail" && /^lenta/.test(path)) {
  2182.         service = "lenta";
  2183.         path = path.replace(/^lenta\/?/, "");
  2184.       }
  2185.       
  2186.       if (service == "mail") {
  2187.         timeoutDelay = 70000;
  2188.         
  2189.         if (aButtons.mail && /(^|\/)(modern|classic|neo)\/messages(\?|$)/.test(path)) {
  2190.           if (!gYaSearchService.yaMFD.checkNeedRefreshDataOnLocation(path, timeoutDelay)) {
  2191.             if (gYaSearchService.isLogin && gYaSearchService.Counters.getCount("mail") > 0)
  2192.               gYaSearchService.refreshHTTPData("mail", null, timeoutDelay);
  2193.           }
  2194.         }
  2195.         
  2196.         return;
  2197.       }
  2198.       
  2199.       if (!gYaSearchService.isLogin)
  2200.         return;
  2201.  
  2202.       switch (service) {
  2203.         case "lenta-ng":
  2204.         case "lenta":
  2205.           if (aButtons.lenta && /^(unread.xml|read)/.test(path) &&
  2206.               gYaSearchService.Counters.getCount("lenta") > 0)
  2207.             gYaSearchService.refreshHTTPData("lenta", null, timeoutDelay);
  2208.           
  2209.           break;
  2210.  
  2211.         case "fotki":
  2212.           if (aButtons.fotki) {
  2213.             var needRefresh = false;
  2214.  
  2215.             if (/\/favorites$/.test(path)) {
  2216.               if (gYaSearchService.Counters.getCount("fotki") > 0)
  2217.                 needRefresh = true;
  2218.             } else if (/\/comments$/.test(path)) {
  2219.               if (gYaSearchService.Counters.getCount("fotki", "comments") > 0)
  2220.                 needRefresh = true;
  2221.             }
  2222.  
  2223.             if (needRefresh)
  2224.               gYaSearchService.refreshHTTPData("fotki", null, timeoutDelay);
  2225.           }
  2226.           break;
  2227.  
  2228.         case "money":
  2229.           if (path == "" || path == "prepaid.xml" || path == "shops.xml")
  2230.             gYaSearchService.refreshHTTPData("money", null, timeoutDelay);
  2231.           break;
  2232.  
  2233.         case "ya":
  2234.           if (path && path.indexOf("replies_history_unread.xml") == 0)
  2235.             gYaSearchService.refreshHTTPData("yaru", null, timeoutDelay);
  2236.           break;
  2237.  
  2238.         case "moikrug":
  2239.           if (path && (/^threads\/?$/.test(path) || /^threads\/\?ncrnd/.test(path)) &&
  2240.               gYaSearchService.Counters.getCount("moikrug") > 0) {
  2241.             gYaSearchService.refreshHTTPData("moikrug", null, timeoutDelay);
  2242.           }
  2243.           break;
  2244.  
  2245.         default:
  2246.           break;
  2247.       }
  2248.     },
  2249.  
  2250.     _getUrlFromLocation: function(aLocation) {
  2251.       let url = gYaURLInfo.getURL(aLocation);
  2252.       return url ? url.toString() : false;
  2253.     },
  2254.  
  2255.     _checkIsTopWindowRequested: function(aWebProgress, aRequest) {
  2256.       let reqWindow = false,
  2257.           topWindow = false;
  2258.  
  2259.       try {
  2260.         reqWindow = aWebProgress.DOMWindow;
  2261.         topWindow = reqWindow.top;
  2262.       } catch(e) {}
  2263.  
  2264.       return (topWindow && topWindow === reqWindow &&
  2265.                (arguments.length == 1 || topWindow.location.toString() === aRequest.name.toString())
  2266.               );
  2267.     },
  2268.  
  2269.     _getDataSumm: function(aWebProgress) {
  2270.       let dataSumm = {};
  2271.  
  2272.       if (aWebProgress && !aWebProgress.isLoadingDocument) {
  2273.         let httpStatus = false;
  2274.         try {
  2275.           if ("currentDocumentChannel" in aWebProgress) {
  2276.             httpStatus = aWebProgress.currentDocumentChannel
  2277.                                      .QueryInterface(Ci.nsIHttpChannel)
  2278.                                      .responseStatus;
  2279.           }
  2280.         } catch(e) {}
  2281.  
  2282.         dataSumm = (aWebProgress.chromeEventHandler.yaSearchTHandler || {}).dataSumm || {};
  2283.         dataSumm.httpStatus = httpStatus;
  2284.       }
  2285.  
  2286.       return dataSumm;
  2287.     },
  2288.  
  2289.     onPageShowInBackground: function(aWebProgress, aButtons) {
  2290.       let url = this._getUrlFromLocation(aWebProgress.currentURI);
  2291.  
  2292.       if (url)
  2293.         this._checkNeedRefreshData(url, aButtons);
  2294.     },
  2295.  
  2296.     onLocationChange: function(aWebProgress, aButtons) {
  2297.       gYaSearchService.browserButtons = aButtons;
  2298.       
  2299.       if (!aButtons.navigElements)
  2300.         return;
  2301.       
  2302.       if (!this._checkIsTopWindowRequested(aWebProgress))
  2303.         return;
  2304.  
  2305.       let url = this._getUrlFromLocation(aWebProgress.currentURI);
  2306.       gYaSearchService.getCY(url, aWebProgress, true, null, this._getDataSumm(aWebProgress));
  2307.     },
  2308.  
  2309.     onPageStateStart: function(aWebProgress, aRequest) {
  2310.       if (!gYaSearchService.browserButtons.navigElements)
  2311.         return;
  2312.  
  2313.       let url = this._getUrlFromLocation(aRequest.URI);
  2314.  
  2315.       if (!url)
  2316.         return;
  2317.       
  2318.       let cyDataToSet = { post: aRequest.requestMethod === "POST" };
  2319.       
  2320.       let wpCurrentURI = aWebProgress.currentURI;
  2321.       if (aWebProgress.loadType & 0x800000 && wpCurrentURI && wpCurrentURI.spec && url != wpCurrentURI.spec) {
  2322.         cyDataToSet.original = this._getUrlFromLocation(aWebProgress.currentURI);
  2323.         cyDataToSet.referring = this._getUrlFromLocation(aWebProgress.referringURI);
  2324.       }
  2325.       
  2326.       gYaURLInfo.setCY(aRequest.URI, cyDataToSet);
  2327.     },
  2328.  
  2329.     onPageStateStop: function(aWebProgress, aRequest) {
  2330.       if (!this._checkIsTopWindowRequested(aWebProgress, aRequest))
  2331.         return;
  2332.  
  2333.       let url = this._getUrlFromLocation(aWebProgress.currentURI);
  2334.  
  2335.       if (!url)
  2336.         return;
  2337.  
  2338.       this._checkNeedRefreshData(url, gYaSearchService.browserButtons);
  2339.  
  2340.       if (!gYaSearchService.browserButtons.navigElements)
  2341.         return;
  2342.  
  2343.       let originalURL = this._getUrlFromLocation(aRequest.originalURI);
  2344.       try {
  2345.         if (originalURL == aRequest.URI.spec)
  2346.           originalURL = false;
  2347.       } catch(e) {}
  2348.  
  2349.       gYaSearchService.getCY(url, aWebProgress, false, originalURL, this._getDataSumm(aWebProgress));
  2350.     }
  2351.   },
  2352.  
  2353.   confirmCYSpam: function(aUrl, aElement) {
  2354.     this.xmlHttpRequest(this.appendStatData2Url(aUrl,{}),
  2355.                          { callbackFunc: this.confirmedCYSpam.bind(this, aUrl, aElement) });
  2356.   },
  2357.  
  2358.   confirmedCYSpam: function(aReq, aUrl, aElement) {
  2359.     let browser;
  2360.     
  2361.     if (aElement && aElement.localName) {
  2362.       if ("menuitem" == aElement.localName)
  2363.         aElement = aElement.parentNode.parentNode;
  2364.  
  2365.       if ("toolbarbutton" == aElement.localName && aElement.hasAttribute("oncommand"))
  2366.         browser = aElement.ownerDocument.defaultView;
  2367.     }
  2368.  
  2369.     if (!browser)
  2370.       return;
  2371.  
  2372.     if (this.isReqError(aReq)) {
  2373.       browser.alert(this.getString("spamError"));
  2374.     } else {
  2375.       var url = browser.gBrowser.selectedBrowser.currentURI.spec;
  2376.       if (url && url.length > 9
  2377.           && aElement.getAttribute("oncommand")
  2378.                      .indexOf("('http://bar-compl.yandex.ru/c?url=" + encodeURIComponent(url)) > 0) {
  2379.         
  2380.         let cy = gYaURLInfo.getCY(url);
  2381.         if (cy)
  2382.           cy.spam = false;
  2383.         
  2384.         aElement.disabled = true;
  2385.       }
  2386.     }
  2387.   },
  2388.   
  2389.   getCY: function(aURL, aWebProgress, aFromCache, aOriginalURL, aDataSumm) {
  2390.     let cy = gYaURLInfo.setCY(aURL);
  2391.     let bloggers = gYaURLInfo.setBloggers(aURL);
  2392.     
  2393.     aURL = aURL || "undefined";
  2394.     
  2395.     var originalURL = null;
  2396.     
  2397.     if (cy && cy.spam === null) {
  2398.       originalURL = aOriginalURL || cy.original || false;
  2399.       var referrer = aWebProgress.referringURI ? aWebProgress.referringURI.spec : (originalURL ? cy.referrer : null);
  2400.       
  2401.       cy.spam = (aURL == "undefined") ?
  2402.                     false :
  2403.                     "http://bar-compl.yandex.ru/c?url=" + encodeURIComponent(aURL) +
  2404.                     (referrer ? ("&referer=" + encodeURIComponent(referrer)) : "") +
  2405.                     (originalURL ? "&oldurl=" + encodeURIComponent(originalURL) : "") +
  2406.                     "&login=" + (encodeURIComponent(this.username || ""));
  2407.     }
  2408.     
  2409.     let browser = aWebProgress.chromeEventHandler;
  2410.     this.setCY(false, browser, aURL);
  2411.     
  2412.     if (!cy || (aFromCache && aWebProgress.isLoadingDocument))
  2413.       return;
  2414.     
  2415.     let urlinfo = 0;
  2416.     
  2417.     if (this.browserButtons.cy) {
  2418.       urlinfo |= 1;
  2419.     }
  2420.     
  2421.     if (this.browserButtons.bloggers) {
  2422.       urlinfo |= 2;
  2423.     }
  2424.     
  2425.     if (!urlinfo)
  2426.       return;
  2427.     
  2428.     if (
  2429.       !!((urlinfo & 1) && (cy.state & gYaURLInfo.CY_STATE_UNKNOWN)) ||
  2430.       !!((urlinfo & 2) && (bloggers.buttonState & gYaURLInfo.BLOGGERS_STATE_UNKNOWN)) ||
  2431.       !!(aDataSumm && (aDataSumm.time || aDataSumm.action)))
  2432.     {
  2433.       if (urlinfo & 1)
  2434.         cy.state = gYaURLInfo.CY_STATE_REQUEST;
  2435.       
  2436.       if (urlinfo & 2)
  2437.         bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_REQUEST;
  2438.       
  2439.       originalURL = originalURL || aOriginalURL || cy.original || false;
  2440.       
  2441.       var post = cy.post;
  2442.       
  2443.       let tSumm = "";
  2444.       
  2445.       if (aDataSumm) {
  2446.         if (aDataSumm.time) {
  2447.           tSumm += "&tv=" + aDataSumm.time.tv + "&t=" + aDataSumm.time.t;
  2448.           
  2449.           if (aDataSumm.time.yamm)
  2450.             tSumm += "&yamm=" + encodeURIComponent(aDataSumm.time.yamm);
  2451.         }
  2452.         
  2453.         if (aDataSumm.action)
  2454.           tSumm += "&action=" + aDataSumm.action;
  2455.         
  2456.         if (aDataSumm.httpStatus)
  2457.           tSumm += "&httpstatus=" + aDataSumm.httpStatus;
  2458.       }
  2459.       
  2460.       let ui = this.guidString;
  2461.       if (ui) {
  2462.         ui = "&ui=" + encodeURIComponent(ui.replace(/^\{/, "").replace(/\}$/, ""));
  2463.         let r1 = this.barnavigR1String;
  2464.         if (r1)
  2465.           ui += "&r1=" + encodeURIComponent(r1);
  2466.       }
  2467.       
  2468.       let params = ["ver=" + this.barExtensionVersionWithLocale +
  2469.                     tSumm + "&" + this.getAppendStatData2Url({clid:4}) +
  2470.                     (ui || "") +
  2471.                     "&urlinfo=" + urlinfo +
  2472.                     "&url=" + encodeURIComponent(aURL) +
  2473.                     "&show=1&post=" + (post ? 1 : 0) +
  2474.                     (aWebProgress.referringURI && aWebProgress.referringURI.userPass == "" ?
  2475.                     "&referer=" + encodeURIComponent(aWebProgress.referringURI.spec) : "") +
  2476.                     (originalURL ? "&oldurl=" + encodeURIComponent(originalURL) : ""),
  2477.                     "",
  2478.                     (browser.contentTitle ? ("&title=" + encodeURIComponent(("" + browser.contentTitle).substr(0,1000))) : "")
  2479.                    ];
  2480.       
  2481.       gYaURLInfo.asyncGetIPsForURL(aURL, this.sendCY.bind(this, params, browser, aURL, urlinfo));
  2482.     }
  2483.   },
  2484.   
  2485.   sendCY: function(aIPs, aParams, aBrowser, aURL, aUrlinfo) {
  2486.     if (aIPs) {
  2487.       aIPs.some(function(aIP) {
  2488.         let parts = aIP ? aIP.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) : null;
  2489.         if (!parts)
  2490.           return false;
  2491.         
  2492.         aParams[1] = "&hip=" + ((parts[1] * 16777216) + (parts[2] * 65536) + (parts[3] * 256) + (parts[4] * 1));
  2493.         return true;
  2494.       });
  2495.     }
  2496.     
  2497.     this.xmlHttpRequest("http://bar-navig.yandex.ru/u?" + aParams.join(""),
  2498.                         { callbackFunc: this.setCY.bind(this, aBrowser, aURL, aUrlinfo) });
  2499.   },
  2500.   
  2501.   setCY: function(aReq, aBrowser, aURL, aUrlinfo, aDontResend) {
  2502.     let [cy, bloggers] = gYaURLInfo.getCYAndBloggers(aURL);
  2503.     
  2504.     let checkBloggers = false;
  2505.     
  2506.     if (aReq) {
  2507.       if (!(cy && bloggers)) {
  2508.         this.log("No CY or Bloggers data");
  2509.         return;
  2510.       }
  2511.       
  2512.       if (this.isReqError(aReq)) {
  2513.         if (!aDontResend) {
  2514.           try {
  2515.             var reqURL = aReq.target.channel.name;
  2516.             var nameReg = /^(http:\/\/)(bar\-navig\.yandex\.ru)/;
  2517.             
  2518.             if (reqURL && nameReg.test(reqURL)) {
  2519.               var status = 0;
  2520.               try {
  2521.                 status = parseInt(aReq.target.status, 10) || 0;
  2522.               } catch(ex) {}
  2523.               
  2524.               if (status != 200) {
  2525.                 this.xmlHttpRequest(reqURL.replace(nameReg, "$1backup-$2") + "&pstatus=" + status,
  2526.                                    { callbackFunc: this.setCY.bind(this, aBrowser, aURL, aUrlinfo, true) });
  2527.                 return;
  2528.               }
  2529.             }
  2530.           } catch(e) {}
  2531.         }
  2532.         
  2533.         if (aUrlinfo & 1)
  2534.           cy.state = gYaURLInfo.CY_STATE_ERROR;
  2535.         
  2536.         if (aUrlinfo & 2)
  2537.           bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_ERROR;
  2538.         
  2539.       } else {
  2540.         this.checkNeedSendGuid();
  2541.         
  2542.         let urlinfoXml = this.safeE4Xml(aReq.target.responseText, null, "urlinfo");
  2543.         
  2544.         if (urlinfoXml) {
  2545.           if (aUrlinfo & 1) {
  2546.             cy.state = gYaURLInfo.CY_STATE_RESPONSE;
  2547.             
  2548.             const REGION_REG = new RegExp(UConverter.ConvertToUnicode("╨á╨╡╨│╨╕╨╛╨╜: (.*)"), "g");
  2549.             const THEME_REG = new RegExp(UConverter.ConvertToUnicode("^\\s*╨ó╨╡╨╝╨░:\\s*"), "");
  2550.             
  2551.             let cyData = {};
  2552.             cyData.domain = urlinfoXml.url.@domain.toString();
  2553.             cyData.value = parseInt(urlinfoXml.tcy.@value.toString(), 10) || 0;
  2554.             cyData.rang = parseInt(urlinfoXml.tcy.@rang.toString(), 10) || 0;
  2555.             
  2556.             let titles = [];
  2557.             for each (let topic in urlinfoXml.topics.topic) {
  2558.               let title = topic.@title.toString().replace(THEME_REG, "");
  2559.               if (title)
  2560.                 titles.push(title);
  2561.             }
  2562.             
  2563.             cyData.theme = titles.length ? titles.join(", ") : this.getString("cyNoTheme");
  2564.             
  2565.             let region = REGION_REG.exec(urlinfoXml.textinfo.toString());
  2566.             cyData.region = (region && region[1]) ? region[1] : this.getString("cyNoRegion");
  2567.             
  2568.             if (urlinfoXml.r1.length() == 1) {
  2569.               let r1 = urlinfoXml.r1.toString();
  2570.               if (r1) {
  2571.                 this.barnavigR1String = r1;
  2572.               }
  2573.             }
  2574.             
  2575.             gYaURLInfo.setCY(aURL, cyData);
  2576.           }
  2577.           
  2578.           if (aUrlinfo & 2) {
  2579.             if ((bloggers.buttonState & gYaURLInfo.BLOGGERS_STATE_REQUEST) || urlinfoXml.page.length() == 1) {
  2580.               bloggers.value = parseInt(urlinfoXml.page.@count, 10) || 0;
  2581.               if (bloggers.value)
  2582.                 checkBloggers = true;
  2583.             }
  2584.             
  2585.             bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_RESPONSE;
  2586.           }
  2587.         } else {
  2588.           if (aUrlinfo & 1)
  2589.             cy.state = gYaURLInfo.CY_STATE_ERROR;
  2590.           
  2591.           if (aUrlinfo & 2)
  2592.             bloggers.buttonState = gYaURLInfo.BLOGGERS_STATE_ERROR;
  2593.         }
  2594.       }
  2595.     }
  2596.     
  2597.     try {
  2598.       var browser = aBrowser.boxObject.element.ownerDocument.defaultView;
  2599.       if (aBrowser == browser.gBrowser.selectedBrowser &&
  2600.           ((aURL == "undefined") || (aBrowser.webProgress.currentURI.spec == aURL)))
  2601.       {
  2602.         if (!aUrlinfo || (aUrlinfo & 1))
  2603.           browser.Ya.setCY(cy);
  2604.         
  2605.         if (!aUrlinfo || (aUrlinfo & 2))
  2606.           browser.Ya.Bloggers.setData(bloggers, checkBloggers);
  2607.       }
  2608.     } catch(e) {}
  2609.   },
  2610.  
  2611.   refreshCYInAllBrowsers: function() {
  2612.     this.browserButtons = null;
  2613.     
  2614.     gYaURLInfo.clear();
  2615.     
  2616.     for each (let browser in this.getWindows("navigator:browser")) {
  2617.       try {
  2618.         var yaButtons = browser.Ya.buttonsObject;
  2619.  
  2620.         var webProgress = browser.gBrowser.selectedBrowser.webProgress;
  2621.         webProgress.QueryInterface(Ci.nsIWebNavigation);
  2622.         webProgress.QueryInterface(Ci.nsIDocShell);
  2623.  
  2624.         var me = this;
  2625.  
  2626.         new G_Timer(function() {
  2627.           me.webProgressListener.onLocationChange(webProgress, yaButtons);
  2628.         }, 0);
  2629.  
  2630.       } catch(e) {}
  2631.     }
  2632.   },
  2633.   
  2634.   getWindow: function(aWindowType) {
  2635.     return this.windowMediator.getMostRecentWindow(aWindowType);
  2636.   },
  2637.   
  2638.   getWindows: function(aWindowType) {
  2639.     let windows = [],
  2640.         enumerator = this.windowMediator.getEnumerator(aWindowType);
  2641.     
  2642.     while (enumerator.hasMoreElements())
  2643.       windows.push(enumerator.getNext());
  2644.     
  2645.     return windows;
  2646.   },
  2647.   
  2648.   getInstallDir: function() {
  2649.     return Cc["@mozilla.org/extensions/manager;1"]
  2650.                 .getService(Ci.nsIExtensionManager)
  2651.                 .getInstallLocation(EXT_ID)
  2652.                 .getItemLocation(EXT_ID);
  2653.   },
  2654.  
  2655.   getChromeDir: function() {
  2656.     var file = this.getInstallDir();
  2657.     file.append("chrome");
  2658.     return file;
  2659.   },
  2660.  
  2661.   getContentDir: function() {
  2662.     var file = this.getChromeDir();
  2663.     file.append("content");
  2664.     return file;
  2665.   },
  2666.  
  2667.   getYandexDir: function() {
  2668.     var file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
  2669.  
  2670.     file.append(this.settingsFolderName);
  2671.  
  2672.     if (!file.exists())
  2673.       file.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  2674.  
  2675.     if (!file.exists())
  2676.       throw "Can't create '" + this.settingsFolderName + "' folder in profile";
  2677.  
  2678.     return file;
  2679.   },
  2680.  
  2681.   getServicesDataFile: function() {
  2682.     if (!this.xmlServicesFile) {
  2683.       var file = this.getContentDir();
  2684.       file.append("services");
  2685.       file.append(this.xmlServicesFileName);
  2686.  
  2687.       if (!file.exists())
  2688.         throw this.xmlServicesFileName + " is missing";
  2689.  
  2690.       if (!file.isFile() || !file.isReadable())
  2691.         throw this.xmlServicesFileName + " has type or permission problems";
  2692.  
  2693.       this.xmlServicesFile = file;
  2694.     }
  2695.  
  2696.     return this.xmlServicesFile;
  2697.   },
  2698.   
  2699.   getServicesData: function() {
  2700.     return this.readFile(this.getServicesDataFile());
  2701.   },
  2702.  
  2703.   getUserDataFile: function() {
  2704.     var file = this.getYandexDir();
  2705.     file.append(this.xmlServicesFileName);
  2706.  
  2707.     if (!file.exists() || !file.isFile())
  2708.       file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0755);
  2709.  
  2710.     if (!file.exists() || !file.isFile())
  2711.       throw "Can't create '" + this.xmlServicesFileName + "' in profile";
  2712.  
  2713.     if (!file.isReadable())
  2714.       throw this.xmlServicesFileName + " has type or permission problems";
  2715.  
  2716.     return file;
  2717.   },
  2718.  
  2719.   refreshXmlServices: function() {
  2720.     if (this._xmlServices) {
  2721.       this._xmlServices = null;
  2722.       OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "services");
  2723.     }
  2724.   },
  2725.  
  2726.   get xmlServices() {
  2727.     if (!this._xmlServices) {
  2728.       this._xmlServices = this.domParser.parseFromString(this.getServicesData(), "text/xml");
  2729.       this.appendUserSessionData("services");
  2730.     }
  2731.     return this._xmlServices;
  2732.   },
  2733.  
  2734.   appendUserSessionData: function(aType) {
  2735.     var userDataFile = this.getUserDataFile();
  2736.     if (!userDataFile)
  2737.       return;
  2738.  
  2739.     try {
  2740.       var userData = new XML(this.readFile(userDataFile));
  2741.     } catch(e) {
  2742.       return;
  2743.     }
  2744.  
  2745.     switch (aType) {
  2746.       case "services":
  2747.         let desktop = this.getServiceById("desktop");
  2748.         if (desktop && !this.isYandeskInstalled)
  2749.           desktop.removeAttribute("search-url");
  2750.  
  2751.         var timeNow = Date.now();
  2752.         for each (var serv in userData.timestamps.serv) {
  2753.           let elem = this.getServiceById(serv.@id);
  2754.           if (elem)
  2755.             elem.setAttribute("service-timestamp", timeNow--);
  2756.         }
  2757.  
  2758.         break;
  2759.  
  2760.       case "data":
  2761.         for each (var user in userData.users.user) {
  2762.           if (user.@login && user.@login.toString() > "") {
  2763.             let login = user.@login.toString();
  2764.  
  2765.             if ("undefined" == typeof this.usersData[login])
  2766.               this.usersData[login] = {};
  2767.  
  2768.             this.usersData[login]._mailLastMaxId = user.mail.@last.toString().replace(/\D/g, "") || "0";
  2769.  
  2770.             this.usersData[login]._mailPermCounter = this.parseIntFromStr(user.mail.@counter.toString());
  2771.  
  2772.             this.Counters.appendUserSessionData(login, user.counters, user.yaru);
  2773.  
  2774.             this.usersData[login]._guidLastMsgTs = user.guid.@message_ts.toString().replace(/\D/g, "");
  2775.  
  2776.             this.usersData[login]._bookmarksRawXml = this.safeE4Xml(user.bookmarks.toString(), "<page><bookmarks/></page>", "page");
  2777.           }
  2778.         }
  2779.         
  2780.         if (this.yaMFD && userData.mfd.length() == 1) {
  2781.           this.yaMFD.appendSessionData(userData.mfd[0]);
  2782.         }
  2783.  
  2784.         break;
  2785.       
  2786.       default:
  2787.         break;
  2788.     }
  2789.   },
  2790.   
  2791.   flushUserData: function() {
  2792.     if (!(this.xmlServices && this.xmlServices.documentElement))
  2793.       return;
  2794.     
  2795.     var userDataFile = this.getUserDataFile();
  2796.     
  2797.     if (userDataFile && userDataFile.isWritable()) {
  2798.       var userData = new XML('<data><version value="' + this.version + '"/><timestamps/><users/><lastengine/></data>');
  2799.     
  2800.       let xpathStr = "//xul:toolbarbutton/xul:menupopup/xul:menuitem[starts-with(@id,'yasearchMenuIdPrefix-')]";
  2801.       let elems = this.xPathEvaluator.evaluate(xpathStr,
  2802.                                                this.getServicesDOMNode(),
  2803.                                                function() XULNS,
  2804.                                                this.orSnapshotType,
  2805.                                                null);
  2806.       
  2807.       for (let i = 0, obj; (obj = elems.snapshotItem(i)); i++) {
  2808.         let len = userData.timestamps.serv.length();
  2809.         let serv = userData.timestamps.serv[len] = <serv/>;
  2810.         serv.@id = obj.getAttribute("id").split("yasearchMenuIdPrefix-")[1];
  2811.       }
  2812.       
  2813.       for (var data in this.usersData) {
  2814.         let len = userData.users.user.length();
  2815.         
  2816.         let user = userData.users.user[len] = <user/>;
  2817.         user.@login = data;
  2818.         
  2819.         user.mail = <mail/>;
  2820.         
  2821.         if (this.usersData[data]._mailLastMaxId > "0")
  2822.           user.mail.@last = this.usersData[data]._mailLastMaxId;
  2823.         
  2824.         if (this.usersData[data]._mailPermCounter > 0)
  2825.           user.mail.@counter = this.usersData[data]._mailPermCounter;
  2826.         
  2827.         if (this.usersData[data]._guidLastMsgTs > "") {
  2828.           user.guid = <guid/>;
  2829.           user.guid.@message_ts = this.usersData[data]._guidLastMsgTs;
  2830.         }
  2831.         
  2832.         if (this.usersData[data]._bookmarksRawXml) {
  2833.           user.bookmarks = <bookmarks/>;
  2834.           user.bookmarks = this.usersData[data]._bookmarksRawXml.toString();
  2835.         }
  2836.         
  2837.         var [countersData, yaruData] = this.Counters.getUserSessionDataForFlush(data);
  2838.         user.counters = countersData;
  2839.         user.yaru = yaruData;
  2840.       }
  2841.       
  2842.       if (this.yaMFD) {
  2843.         userData.appendChild(this.yaMFD.getSessionDataForFlush());
  2844.       }
  2845.       
  2846.       this.writeFile(userDataFile, userData);
  2847.     }
  2848.   },
  2849.   
  2850.   getXSLTemplate: function(fName) {
  2851.     if (!this._xsltemplates[fName]) {
  2852.       let fullName = "xsl-" + fName + ".xsl";
  2853.  
  2854.       let file = this.getContentDir();
  2855.       file.append("xsl-templ");
  2856.       file.append(fullName);
  2857.  
  2858.       if (!file.exists())
  2859.         throw "getXSLTemplate -- " + fullName + " is missing";
  2860.  
  2861.       let content = this.readFile(file);
  2862.  
  2863.       let include = this.xsltImportRegExp.exec(content);
  2864.       if (include && include[1]) {
  2865.         include = this.getInludeXSLTemplate(include[1]);
  2866.         content = content.replace(this.xsltImportRegExp, include);
  2867.       }
  2868.       
  2869.       this._xsltemplates[fName] = this.domParser.parseFromString(content, "text/xml");
  2870.     }
  2871.  
  2872.     return this._xsltemplates[fName];
  2873.   },
  2874.   
  2875.   getInludeXSLTemplate: function(fName) {
  2876.     var incHashName = "include-" + fName;
  2877.     
  2878.     if (!this._xsltemplates[incHashName]) {
  2879.       var content = this.xmlSerializer.serializeToString(this.getXSLTemplate(fName));
  2880.       content = content.split("<xsl:output method=\"xml\" encoding=\"UTF-8\" indent=\"no\"/>")[1];
  2881.       content = content.split("</xsl:stylesheet>")[0];
  2882.       this._xsltemplates[incHashName] = content;
  2883.     }
  2884.     
  2885.     return this._xsltemplates[incHashName];
  2886.   },
  2887.  
  2888.   getDOMDocContent: function(xslName, aDataSource, aParameters) {
  2889.     if (aDataSource && aDataSource.firstChild.localName == "parsererror")
  2890.       return null;
  2891.     
  2892.     let parameters = aParameters || {};
  2893.     
  2894.     if (!("localeTld" in parameters))
  2895.       parameters.localeTld = this.localeTld;
  2896.     
  2897.     if (!("localeLang" in parameters))
  2898.       parameters.localeLang = this.localeLang;
  2899.     
  2900.     const xsltProcessor = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
  2901.     
  2902.     for (let [paramName, paramValue] in Iterator(parameters))
  2903.       xsltProcessor.setParameter(null, paramName, paramValue);
  2904.     
  2905.     xsltProcessor.importStylesheet(this.getXSLTemplate(xslName));
  2906.     
  2907.     return xsltProcessor.transformToDocument(aDataSource || this.xmlServices).firstChild;
  2908.   },
  2909.  
  2910.   getDOMDocContent2: function(xslFilePath, aDataSource, aParameters) {
  2911.     switch (typeof aDataSource) {
  2912.       case "string":
  2913.         aDataSource = this.getXSLTemplate2(aDataSource);
  2914.         break;
  2915.  
  2916.       case "xml":
  2917.         aDataSource = this.domParser.parseFromString(aDataSource.toXMLString(), "text/xml");
  2918.         if (aDataSource.firstChild.localName == "parsererror")
  2919.           return null;
  2920.         break;
  2921.  
  2922.       default:
  2923.         break;
  2924.     }
  2925.     
  2926.     let parameters = aParameters || {};
  2927.  
  2928.     if (!("localeTld" in parameters))
  2929.       parameters.localeTld = this.localeTld;
  2930.     
  2931.     if (!("localeLang" in parameters))
  2932.       parameters.localeLang = this.localeLang;
  2933.     
  2934.     const xsltProcessor = Cc["@mozilla.org/document-transformer;1?type=xslt"].createInstance(Ci.nsIXSLTProcessor);
  2935.     
  2936.     for (let [paramName, paramValue] in Iterator(parameters))
  2937.       xsltProcessor.setParameter(null, paramName, paramValue);
  2938.     
  2939.     xsltProcessor.importStylesheet(this.getXSLTemplate2(xslFilePath));
  2940.     
  2941.     return xsltProcessor.transformToDocument(aDataSource).firstChild;
  2942.   },
  2943.  
  2944.   getXSLTemplate2: function(aFilePath) {
  2945.     let file = this.getContentDir();
  2946.     aFilePath.split("/").forEach(function(fpath) file.append(fpath));
  2947.  
  2948.     if (!file.exists())
  2949.       throw new Error("getXSLTemplate2 -- " + aFilePath + " is missing");
  2950.  
  2951.     return this.domParser.parseFromString(this.readFile(file), "text/xml");
  2952.   },
  2953.   
  2954.   getServicesDOMNode: function() {
  2955.     return this.getDOMDocContent("bar-services", null,
  2956.                                  { homePageHost: this.getLocaleDependedUrl("YandexWwwHost") });
  2957.   },
  2958.   
  2959.   getServiceById: function(id) {
  2960.     function nsResolver() {
  2961.       return "urn:data";
  2962.     }
  2963.     
  2964.     let elem = this.xPathEvaluator.evaluate("//xmlns:*[@id='" + id + "']",
  2965.                                             this.xmlServices.documentElement,
  2966.                                             nsResolver,
  2967.                                             this.unSnapshotType,
  2968.                                             null);
  2969.  
  2970.     return elem && elem.snapshotLength ? elem.snapshotItem(0) : null;
  2971.   },
  2972.  
  2973.   setServiceTimestamp: function(id) {
  2974.     let elem = this.getServiceById(id);
  2975.     if (!elem)
  2976.       return null;
  2977.  
  2978.     elem.setAttribute("service-timestamp", Date.now());
  2979.     OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Services", false);
  2980.     
  2981.     return elem;
  2982.   },
  2983.  
  2984.   getDefaultSearchEngine: function() {
  2985.     function nsResolver() {
  2986.       return "urn:data";
  2987.     }
  2988.     
  2989.     let elem = this.xPathEvaluator.evaluate("//xmlns:*[@search-url]",
  2990.                                             this.xmlServices.documentElement,
  2991.                                             nsResolver,
  2992.                                             this.unSnapshotType,
  2993.                                             null);
  2994.  
  2995.     return elem && elem.snapshotLength ? elem.snapshotItem(0).getAttribute("id") : null;
  2996.   },
  2997.  
  2998.   get searchService() {
  2999.     if (!this._searchService)
  3000.       this._searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
  3001.  
  3002.     return this._searchService;
  3003.   },
  3004.   
  3005.   get searchEngineSuggestURL() {
  3006.     return this._searchEngineSuggestURL ||
  3007.            (this._searchEngineSuggestURL = "http://" + this.getLocaleDependedUrl("YandexSuggestHost") + "/suggest-ff.cgi?part=");
  3008.   },
  3009.   
  3010.   get defaultYandexSearchEngine() {
  3011.     return {
  3012.       _self: this,
  3013.       
  3014.       supportsResponseType: function(aType) {
  3015.         return aType == "application/x-suggestions+json";
  3016.       },
  3017.       
  3018.       getSubmission: function(aData, aResponseType) {
  3019.         return {
  3020.           postData: null,
  3021.           uri: this._self.makeURI(this._self.searchEngineSuggestURL + encodeURIComponent(aData))
  3022.         }
  3023.       }
  3024.     };
  3025.   },
  3026.   
  3027.   get currentSearchEngine() {
  3028.     if (!this._yaCurrentEngine.isYandex)
  3029.       return this.searchService.getEngineByName(this._yaCurrentEngine.name);
  3030.  
  3031.     return {
  3032.       _self: this,
  3033.  
  3034.       _currentEngine: this._yaCurrentEngine,
  3035.  
  3036.       name: "___ya___" + this._yaCurrentEngine.name,
  3037.  
  3038.       supportsResponseType: function(aType) {
  3039.         return aType == "application/x-suggestions+json";
  3040.       },
  3041.  
  3042.       getSubmission: function(aData, aResponseType) {
  3043.         return {
  3044.           postData: null,
  3045.           uri: this._self.makeURI(this._self.searchEngineSuggestURL + encodeURIComponent(aData))
  3046.         }
  3047.       }
  3048.     };
  3049.   },
  3050.  
  3051.   desktopPinger: {
  3052.     checkService: function() {
  3053.       if (this._desktopServicePath) {
  3054.         var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
  3055.         req.open("HEAD", this._desktopServicePath);
  3056.  
  3057.         var target = req.QueryInterface(Ci.nsIDOMEventTarget);
  3058.  
  3059.         if (this.__triesCount) {
  3060.           target.addEventListener("load", this._reloadSearchErrorPages.bind(this), false);
  3061.           target.addEventListener("error", this._startTimer.bind(this), false);
  3062.         } else {
  3063.           target.addEventListener("error", this._pingDesktopServiceCallback.bind(this), false);
  3064.         }
  3065.  
  3066.         try {
  3067.           req.send(null);
  3068.         } catch(e) {}
  3069.       }
  3070.     },
  3071.  
  3072.     __timer: null,
  3073.     __triesCount: 0,
  3074.  
  3075.     _reloadSearchErrorPages: function() {
  3076.       this._stop(true);
  3077.  
  3078.       var desktopServicePath = this._desktopServicePath;
  3079.  
  3080.       new G_Timer(function() {
  3081.         for each (var browser in gYaSearchService.getWindows("navigator:browser")) {
  3082.           var browserInstance = browser.getBrowser();
  3083.  
  3084.           var numTabs = browserInstance.tabContainer.childNodes.length;
  3085.           for (var index = 0; index < numTabs; index++) {
  3086.             var currentBrowser = browserInstance.getBrowserAtIndex(index);
  3087.             if (desktopServicePath == currentBrowser.currentURI.prePath &&
  3088.                 /^about\:neterror/.test(currentBrowser.contentDocument.documentURI) &&
  3089.                 !currentBrowser.hasAttribute("busy")) {
  3090.               currentBrowser.loadURI(currentBrowser.currentURI.spec);
  3091.             }
  3092.           }
  3093.         }
  3094.       }, 3000);
  3095.     },
  3096.  
  3097.     _stop: function(aDropCounter) {
  3098.       if (this.__timer)
  3099.         this.__timer.cancel();
  3100.  
  3101.       this.__timer = null;
  3102.  
  3103.       if (aDropCounter)
  3104.         this.__triesCount = 0;
  3105.     },
  3106.  
  3107.     _startTimer: function() {
  3108.       if (this.__triesCount++ < 10) {
  3109.         this._stop();
  3110.         this.__timer = new G_Timer(this.checkService.bind(this, true), 1000);
  3111.       } else {
  3112.         this._stop(true);
  3113.       }
  3114.     },
  3115.  
  3116.     __desktopServicePath: null,
  3117.  
  3118.     get _desktopServicePath() {
  3119.       if (this.__desktopServicePath === null) {
  3120.         this.__desktopServicePath = false;
  3121.  
  3122.         var desktopService = gYaSearchService.getServiceById("desktop");
  3123.         if (desktopService && desktopService.hasAttribute("search-url")) {
  3124.           var uri = gYaSearchService.makeURI(desktopService.getAttribute("search-url"));
  3125.           if (uri)
  3126.             this.__desktopServicePath = uri.prePath;
  3127.         }
  3128.       }
  3129.  
  3130.       return this.__desktopServicePath;
  3131.     },
  3132.  
  3133.     _pingDesktopServiceCallback: function(aReq) {
  3134.       var exePath = gYaSearchService.getYandeskProgramDir();
  3135.  
  3136.       if (exePath) {
  3137.         var desctopExeFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  3138.         desctopExeFile.initWithPath(exePath);
  3139.         desctopExeFile.append("yandesk.exe");
  3140.  
  3141.         if (desctopExeFile.exists() && desctopExeFile.isFile()) {
  3142.           desctopExeFile.launch();
  3143.           this._startTimer();
  3144.         }
  3145.       }
  3146.     }
  3147.   },
  3148.  
  3149.   getSearchEngineUrl: function(aId, aText, aHost, aStatData) {
  3150.     var engine,
  3151.         result = { isYandexSearch: false },
  3152.         id = aId.replace(/^__/, "");
  3153.  
  3154.     if (id == aId) {
  3155.       result.isYandexSearch = true;
  3156.  
  3157.       engine = this.getServiceById(aId);
  3158.  
  3159.       if (engine) {
  3160.  
  3161.         if (aId === "desktop" && this.isYandeskInstalled)
  3162.           this.desktopPinger.checkService();
  3163.  
  3164.         var appendix = aHost && engine.hasAttribute("search-site") ?
  3165.                            "&" + engine.getAttribute("search-site") + "=" + encodeURIComponent(aHost) :
  3166.                            "";
  3167.  
  3168.         var searchURL = engine.getAttribute("search-url") + (encodeURIComponent(aText)) + appendix;
  3169.  
  3170.         result.url = this.appendStatData2Url(searchURL, (typeof aStatData == "undefined") ? {clid:2} : aStatData);
  3171.  
  3172.         var action = engine.hasAttribute("search-action") ?
  3173.                          engine.getAttribute("search-action") :
  3174.                          (engine.hasAttribute("action") ? engine.getAttribute("action") : null);
  3175.         
  3176.         result.statData = action ? {action: action} : null;
  3177.         
  3178.         result.postData = null;
  3179.       }
  3180.     } else {
  3181.       engine = this.searchService.getEngineByName(id);
  3182.       if (engine) {
  3183.         var submission = engine.getSubmission(aText, null);
  3184.         if (submission) {
  3185.           result.url = submission.uri.spec;
  3186.           result.statData = {action: "4300"};
  3187.           result.postData = submission.postData;
  3188.         }
  3189.       }
  3190.     }
  3191.  
  3192.     return result.url ? result : null;
  3193.   },
  3194.  
  3195.   setCurrentSearchEngine: function(aId) {
  3196.     var elem, result = {}, id = aId.replace(/^__/, "");
  3197.  
  3198.     this._yaCurrentEngine = {isYandex: false, name: id};
  3199.  
  3200.     if (id == aId) {
  3201.       this._yaCurrentEngine.isYandex = true;
  3202.       
  3203.       function nsResolver() {
  3204.         return "urn:data";
  3205.       }
  3206.       
  3207.       var obj, elems = this.xPathEvaluator.evaluate("//xmlns:*[@last-engine]",
  3208.                                                  this.xmlServices.documentElement,
  3209.                                                  nsResolver,
  3210.                                                  this.unSnapshotType,
  3211.                                                  null);
  3212.  
  3213.       for (var i = 0; (obj = elems.snapshotItem(i)); i++)
  3214.         obj.removeAttribute("last-engine");
  3215.  
  3216.       elem = this.getServiceById(aId);
  3217.  
  3218.       if (elem) {
  3219.         elem.setAttribute("last-engine", "true");
  3220.         result.searchUrl = elem.getAttribute("search-url");
  3221.         result.searchSite = elem.getAttribute("search-site");
  3222.         result.label = elem.getAttribute("label2") || elem.getAttribute("label");
  3223.         result.image = CHROME_IMAGES + elem.getAttribute("image") + ".png";
  3224.       }
  3225.     } else {
  3226.       elem = this.searchService.getEngineByName(id);
  3227.       if (elem) {
  3228.         result.label = id;
  3229.         result.image = elem.iconURI ? elem.iconURI.spec : "";
  3230.         result.searchUrl = elem.uri;
  3231.       }
  3232.     }
  3233.  
  3234.     return result.label ? result : null;
  3235.   },
  3236.  
  3237.   getSearchSettingsForSlovari: function(aText, aEvent, aCallback) {
  3238.     this.xmlHttpRequest("http://export.yandex.ru/mycookie.xml",
  3239.                         {callbackFunc: this.getSearchSettingsForSlovariCallback.bind(this, aText, aEvent, aCallback)});
  3240.   },
  3241.  
  3242.   getSearchSettingsForSlovariCallback: function(aReq, aText, aEvent, aCallback) {
  3243.     let type = "slovari-services";
  3244.     if (!this.isReqError(aReq) && /<translate>1<\/translate>/.test(aReq.target.responseText))
  3245.       type = "lingvo";
  3246.     
  3247.     let engineData = this.getSearchEngineUrl(type, aText);
  3248.     aCallback(engineData.url, aEvent, engineData.statData);
  3249.   },
  3250.   
  3251.   uninit: function() {
  3252.     if (this._inited) {
  3253.       this._inited = false;
  3254.       
  3255.       ["cookie-changed",
  3256.        "http-on-modify-request",
  3257.        "http-on-examine-response"]
  3258.       .forEach(function(aTopicName) {
  3259.         OBSERVER_SERVICE.removeObserver(this, aTopicName, true);
  3260.       }, this);
  3261.       
  3262.       gYaAuth.shutdown();
  3263.       
  3264.       this.clearAllTimers();
  3265.       
  3266.       if (gYaInstaller && !gYaInstaller.isBarUninstalled)
  3267.         this.flushUserData();
  3268.       
  3269.       this._browserButtons = null;
  3270.     }
  3271.     
  3272.     this._searchService = null;
  3273.   },
  3274.  
  3275.   handlePrefChanges: function(aData) {
  3276.     switch (aData.split("yasearch.")[1]) {
  3277.       case "general.debug.enabled":
  3278.         this.debug = this.getBoolPref(aData);
  3279.         break;
  3280.  
  3281.       case "general.ui.show.cy.value":
  3282.         this.refreshCYInAllBrowsers();
  3283.         break;
  3284.  
  3285.       case "general.ui.urlbar.corrector.state":
  3286.         OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "urlbar-corrector");
  3287.         break;
  3288.  
  3289.       case "http.update.interval":
  3290.         this.updateHttpTimers("mailandfeeds");
  3291.         break;
  3292.  
  3293.       case "http.auto.enabled":
  3294.         this.updateHttpTimers();
  3295.         break;
  3296.  
  3297.       case "general.ui.mail.integration":
  3298.         OBSERVER_SERVICE.notifyObservers(null, "Ya-Refresh-Data", "mail-integration");
  3299.         break;
  3300.     }
  3301.   },
  3302.  
  3303.   get isCountersAutoUpdateEnabled() {
  3304.     return this.getBoolPref("yasearch.http.auto.enabled");
  3305.   },
  3306.  
  3307.   updateHttpTimers: function(aTimerType) {
  3308.     var autoUpdateEnabled = this.isCountersAutoUpdateEnabled;
  3309.  
  3310.     if (!aTimerType || aTimerType == "mailandfeeds") {
  3311.       this.checkTimeOut._MailAndFeeds = autoUpdateEnabled ? (this.getIntPref("yasearch.http.update.interval") * MIN_SEC || 0) : 0;
  3312.       this.isLogin && this.checkTimeOut._MailAndFeeds > 0 ?
  3313.           this.setTimer("_MailAndFeeds") : this.clearTimer("_MailAndFeeds");
  3314.     }
  3315.     
  3316.     if (this.yaMFD && (!aTimerType || aTimerType == "mailandfeeds"))
  3317.       this.yaMFD.setUpdateTimer();
  3318.   },
  3319.  
  3320.   get barPref() {
  3321.     if (!this._barPref)
  3322.       this._barPref = " YB/" + this.barExtensionVersionWithLocale;
  3323.  
  3324.     return this._barPref;
  3325.   },
  3326.  
  3327.   get barPrefReg() {
  3328.     if (!this._barPrefReg)
  3329.       this._barPrefReg = new RegExp(this.barPref.replace(/(\.|\-)/g, "\\\$1"));
  3330.  
  3331.     return this._barPrefReg;
  3332.   },
  3333.  
  3334.   __localeTld: null,
  3335.   get localeTld() {
  3336.     if (!this.__localeTld)
  3337.       this.__localeTld = this.getString("locale.tld");
  3338.  
  3339.     return this.__localeTld;
  3340.   },
  3341.   
  3342.   __localeLang: null,
  3343.   get localeLang() {
  3344.     if (!this.__localeLang)
  3345.       this.__localeLang = this.getString("locale.lang");
  3346.  
  3347.     return this.__localeLang;
  3348.   },
  3349.  
  3350.   isYandexHost: function(aHost) {
  3351.     return /(^|\.)(yandex\.(ru|ua|by|kz|net|com)|(ya|narod|moikrug)\.ru)$/i.test(aHost);
  3352.   },
  3353.  
  3354.   _getDOMWindowForRequest: function(aRequest) {
  3355.     try {
  3356.       return aRequest.loadGroup.groupObserver.QueryInterface(Ci.nsIWebProgress).DOMWindow;
  3357.     } catch(e) {}
  3358.  
  3359.     return null;
  3360.   },
  3361.  
  3362.   _getTabForDOMWindow: function(aDOMWindow) {
  3363.     var tab = null;
  3364.  
  3365.     var docShellTree = aDOMWindow.QueryInterface(Ci.nsIInterfaceRequestor)
  3366.                                  .getInterface(Ci.nsIWebNavigation)
  3367.                                  .QueryInterface(Ci.nsIDocShellTreeItem);
  3368.  
  3369.     if (docShellTree.itemType == Ci.nsIDocShellTreeItem.typeContent) {
  3370.       try {
  3371.         var chromeWindow = docShellTree.rootTreeItem
  3372.                           .QueryInterface(Ci.nsIInterfaceRequestor)
  3373.                           .getInterface(Ci.nsIDOMWindow)
  3374.                           .wrappedJSObject;
  3375.  
  3376.         if (!chromeWindow)
  3377.           return null;
  3378.  
  3379.         tab = chromeWindow.getBrowser()
  3380.                           .getBrowserForDocument(aDOMWindow.document);
  3381.  
  3382.         if (!tab)
  3383.           return null;
  3384.  
  3385.         if (!tab.yaSearchTHandler) {
  3386.           var YaProgressListener = chromeWindow.YaProgressListener;
  3387.           if (YaProgressListener)
  3388.             YaProgressListener.addTabListener(tab);
  3389.         }
  3390.  
  3391.         if (tab.yaSearchTHandler)
  3392.           return tab;
  3393.  
  3394.       } catch(e) {}
  3395.     }
  3396.  
  3397.     return null;
  3398.   },
  3399.  
  3400.   _getYaSearchTHandlerForRequest: function(aRequest) {
  3401.     var win = this._getDOMWindowForRequest(aRequest);
  3402.     if (win && win === win.parent) {
  3403.       var tab = this._getTabForDOMWindow(win);
  3404.  
  3405.       if (tab)
  3406.         return tab.yaSearchTHandler;
  3407.     }
  3408.  
  3409.     return null;
  3410.   },
  3411.  
  3412.   observe: function(aSubject, aTopic, aData) {
  3413.     switch (aTopic) {
  3414.       case "http-on-modify-request":
  3415.         aSubject.QueryInterface(Ci.nsIHttpChannel);
  3416.  
  3417.         if (this.isYandexHost(aSubject.URI.host)) {
  3418.           try {
  3419.             var ua = aSubject.getRequestHeader("User-Agent");
  3420.             if (!this.barPrefReg.test(ua))
  3421.               aSubject.setRequestHeader("User-Agent", ua + this.barPref, false);
  3422.           } catch(e) {}
  3423.         }
  3424.  
  3425.         try {
  3426.           if (aSubject.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI) {
  3427.             var tabHandler = this._getYaSearchTHandlerForRequest(aSubject);
  3428.             if (tabHandler)
  3429.               tabHandler.onTransferStart(aSubject.URI.spec);
  3430.           }
  3431.         } catch(e) {}
  3432.  
  3433.         break;
  3434.  
  3435.       case "http-on-examine-response":
  3436.         aSubject.QueryInterface(Ci.nsIHttpChannel);
  3437.  
  3438.         try {
  3439.           if (aSubject.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI) {
  3440.             var tabHandler = this._getYaSearchTHandlerForRequest(aSubject);
  3441.             if (tabHandler)
  3442.               tabHandler.onTransferStop();
  3443.           }
  3444.         } catch(e) {}
  3445.  
  3446.         break;
  3447.  
  3448.       case "cookie-changed":
  3449.         this.yaAuth.onCookieChanged(aSubject, aTopic, aData);
  3450.         break;
  3451.       
  3452.       case "nsPref:changed":
  3453.         this.handlePrefChanges(aData);
  3454.         break;
  3455.       
  3456.       case "profile-after-change":
  3457.         this.init();
  3458.         
  3459.         if (this._inited) {
  3460.           let prefInternal = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
  3461.           prefInternal.addObserver("yasearch", this, true);
  3462.         }
  3463.         break;
  3464.  
  3465.       case "profile-before-change":
  3466.         if (this._inited) {
  3467.           let prefInternal = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
  3468.           prefInternal.removeObserver("yasearch", this, true);
  3469.         }
  3470.         
  3471.         this.uninit();
  3472.         break;
  3473.   
  3474.       case "app-startup":
  3475.         OBSERVER_SERVICE.addObserver(this, "browser-ui-startup-complete", false);
  3476.         OBSERVER_SERVICE.addObserver(this, "sessionstore-windows-restored", false);
  3477.         
  3478.         ["profile-before-change",
  3479.          "profile-after-change",
  3480.          "quit-application"]
  3481.         .forEach(function(aTopicName) {
  3482.           OBSERVER_SERVICE.addObserver(this, aTopicName, true);
  3483.         }, this);
  3484.         
  3485.         break;
  3486.       
  3487.       case "browser-ui-startup-complete":
  3488.         OBSERVER_SERVICE.removeObserver(this, "browser-ui-startup-complete");
  3489.         this.onBrowserUIStartupComplete();
  3490.         break;
  3491.       
  3492.       case "sessionstore-windows-restored":
  3493.         OBSERVER_SERVICE.removeObserver(this, "sessionstore-windows-restored");
  3494.         this.onSessionstoreWindowsRestored();
  3495.         break;
  3496.         
  3497.       case "quit-application":
  3498.         break;
  3499.     }
  3500.   },
  3501.  
  3502.   loadUserSheet: function(aFile) {
  3503.     if (aFile && aFile.exists() && aFile.isFile() && aFile.isReadable()) {
  3504.       var sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService);
  3505.       var u = this.makeFileURI(aFile);
  3506.  
  3507.       if (sss.sheetRegistered(u, sss.USER_SHEET))
  3508.         sss.unregisterSheet(u, sss.USER_SHEET);
  3509.  
  3510.       sss.loadAndRegisterSheet(u, sss.USER_SHEET);
  3511.     }
  3512.   },
  3513.  
  3514.   hackKnownSkins: function() {
  3515.     var selectedSkin = this.getCharPref("extensions.lastSelectedSkin") || this.getCharPref("general.skins.selectedSkin");
  3516.  
  3517.     if (selectedSkin) {
  3518.       if (selectedSkin == "classic/1.0")
  3519.         selectedSkin = "classic";
  3520.  
  3521.       var cssFile = this.getChromeDir();
  3522.       cssFile.append("skin");
  3523.       cssFile.append("themes-hacks");
  3524.  
  3525.       var platformCssFile,
  3526.           platformName = this.AppInfo.OS.platformName;
  3527.  
  3528.       if (platformName) {
  3529.         platformCssFile = cssFile.clone();
  3530.         platformCssFile.append(platformName);
  3531.       }
  3532.  
  3533.       [cssFile, platformCssFile].forEach(function(cssFile) {
  3534.         if (cssFile) {
  3535.           try {
  3536.             cssFile.append(selectedSkin + ".css");
  3537.             if (cssFile.exists() && cssFile.isFile())
  3538.               this.loadUserSheet(cssFile);
  3539.           } catch(e) {}
  3540.         }
  3541.       }, this)
  3542.     }
  3543.  
  3544.     var extSheetsDir = this.getChromeDir();
  3545.     extSheetsDir.append("skin");
  3546.     extSheetsDir.append("extensions-hacks");
  3547.  
  3548.     if (extSheetsDir.exists() && extSheetsDir.isDirectory()) {
  3549.       var em = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
  3550.       var extSheetsDirEnumerator = extSheetsDir.directoryEntries;
  3551.       while (extSheetsDirEnumerator.hasMoreElements()) {
  3552.         var entry = extSheetsDirEnumerator.getNext().QueryInterface(Ci.nsIFile);
  3553.         if (entry.isFile()) {
  3554.           var name = entry.leafName;
  3555.           if (/.\.css$/.test(name)) {
  3556.             var emItem = em.getItemForID(name.slice(0, -4));
  3557.             if (emItem && emItem.type == Ci.nsIUpdateItem.TYPE_EXTENSION)
  3558.               this.loadUserSheet(entry);
  3559.           }
  3560.         }
  3561.       }
  3562.     }
  3563.  
  3564.   },
  3565.  
  3566.   parseIntFromStr: function(aStr) {
  3567.     var res = aStr ? parseInt(aStr.toString().replace(/\D/g,""), 10) : 0;
  3568.     return isNaN(res) ? 0 : res;
  3569.   },
  3570.  
  3571.   safeUnicode: function(aString) {
  3572.     if (!/[^\r\n\x9\xA\xD\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]/.test(aString))
  3573.       return aString;
  3574.     
  3575.     return aString.replace(/[^\r\n\x9\xA\xD\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]/g, "");
  3576.   },
  3577.  
  3578.   getStringBundle: function(aLocaleFilePath) {
  3579.     let strBundleService = Cc["@mozilla.org/intl/stringbundle;1"].createInstance(Ci.nsIStringBundleService);
  3580.     
  3581.     if (aLocaleFilePath)
  3582.       return strBundleService.createBundle("chrome://yasearch/locale/" + aLocaleFilePath);
  3583.     
  3584.     if (!this.stringBundle)
  3585.       this.stringBundle = strBundleService.createBundle("chrome://yasearch/locale/yasearch.properties");
  3586.     
  3587.     return this.stringBundle;
  3588.   },
  3589.  
  3590.   getString: function(aName) {
  3591.     return this.getStringBundle().GetStringFromName(aName);
  3592.   },
  3593.  
  3594.   getFormattedString: function(aName, aStrArray) {
  3595.     return this.getStringBundle().formatStringFromName(aName, aStrArray, aStrArray.length);
  3596.   },
  3597.  
  3598.   getFormattedStringL18End: function(aName, aStrArray) {
  3599.     var n = aStrArray[0], _cases = [2,0,1,1,1,2,2,2,2,2];
  3600.     var l18End = aName + "L18End" + ((n%100>10)&&(n%100<20) ? 2 : _cases[n%10]);
  3601.     return this.getFormattedString(aName, aStrArray) + this.getString(l18End);
  3602.   },
  3603.  
  3604.   __localeDependedStrBundleService: null,
  3605.   getLocaleDependedUrl: function(aUrl) {
  3606.     if (!this.__localeDependedStrBundleService) {
  3607.       var strBundleService = Cc["@mozilla.org/intl/stringbundle;1"].createInstance(Ci.nsIStringBundleService);
  3608.       this.__localeDependedStrBundleService = strBundleService.createBundle("chrome://yasearch/locale/links/links.properties");
  3609.     }
  3610.  
  3611.     return this.__localeDependedStrBundleService.GetStringFromName(aUrl);
  3612.   },
  3613.  
  3614.   utils: {
  3615.     get G_Timer() {
  3616.       return G_Timer;
  3617.     }
  3618.   },
  3619.  
  3620.   writeFile: function(aFile, aData) {
  3621.     try {
  3622.       var chunk = UConverter.ConvertFromUnicode(aData);
  3623.       
  3624.       var os = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
  3625.       os.init(aFile, 0x02 | 0x08 | 0x20, 0755, 0);
  3626.       
  3627.       var result = os.write(chunk, chunk.length);
  3628.       os.close();
  3629.     } catch(e) {}
  3630.   },
  3631.  
  3632.   readFile: function(aFile) {
  3633.     var fileContents = "";
  3634.     
  3635.     var is = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
  3636.     is.init(aFile, 0x01, 0, is.CLOSE_ON_EOF);
  3637.     
  3638.     var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
  3639.     sis.init(is);
  3640.     
  3641.     while(sis.available() > 0)
  3642.       fileContents += UConverter.ConvertToUnicode(sis.read(sis.available()));
  3643.     
  3644.     is.close();
  3645.     sis.close();
  3646.     
  3647.     return this.safeUnicode(fileContents);
  3648.   },
  3649.  
  3650.   prefBranchInternal: Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2),
  3651.   prefBranch:         Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch),
  3652.  
  3653.   setBoolPref: function(aName, aValue) {
  3654.     this.prefBranch.setBoolPref(aName, aValue);
  3655.   },
  3656.  
  3657.   getBoolPref: function(aName) {
  3658.     let rv = null;
  3659.     try {
  3660.       rv = this.prefBranch.getBoolPref(aName);
  3661.     } catch(e) {}
  3662.     
  3663.     return rv;
  3664.   },
  3665.  
  3666.   setIntPref: function(aName, aValue) {
  3667.     this.prefBranch.setIntPref(aName, aValue);
  3668.   },
  3669.  
  3670.   getIntPref: function(aName) {
  3671.     let rv = null;
  3672.     try {
  3673.       rv = this.prefBranch.getIntPref(aName);
  3674.       if (rv < 0)
  3675.         rv = 0;
  3676.     } catch(e) {}
  3677.     
  3678.     return rv;
  3679.   },
  3680.  
  3681.   setCharPref: function(aName, aValue) {
  3682.     this.prefBranch.setCharPref(aName, aValue);
  3683.   },
  3684.  
  3685.   getCharPref: function(aName) {
  3686.     let rv = null;
  3687.     try {
  3688.       rv = this.prefBranch.getCharPref(aName);
  3689.     } catch(e) {}
  3690.     
  3691.     return rv;
  3692.   },
  3693.  
  3694.   getComplexValue: function(aName) {
  3695.     let rv = null;
  3696.     try {
  3697.       rv = this.prefBranch.getComplexValue(aName, Ci.nsIPrefLocalizedString).data;
  3698.     } catch(e) {}
  3699.     
  3700.     return rv;
  3701.   },
  3702.  
  3703.   setComplexValue: function(aName, aValue) {
  3704.     try {
  3705.       let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
  3706.       str.data = aValue;
  3707.       this.prefBranch.setComplexValue(aName, Ci.nsISupportsString, str);
  3708.     } catch(e) {}
  3709.   },
  3710.   
  3711.   resetPrefBranch: function(aPrefBranchName) {
  3712.     if (!aPrefBranchName)
  3713.       return;
  3714.     
  3715.     if (!/\.$/.test(aPrefBranchName))
  3716.       aPrefBranchName += ".";
  3717.     
  3718.     this.prefBranch.getChildList(aPrefBranchName, {}).forEach(function(aPrefName) {
  3719.       try {
  3720.         this.resetPref(aPrefName);
  3721.       } catch(e) {}
  3722.     }, this);
  3723.   },
  3724.   
  3725.   resetPref: function(aPrefName) {
  3726.     try {
  3727.       this.prefBranch.clearUserPref(aPrefName);
  3728.     } catch(e) {}
  3729.   },
  3730.   
  3731.   getBrowserHomePage: function() {
  3732.     let url;
  3733.     try {
  3734.       url = this.getComplexValue("browser.startup.homepage");
  3735.     } catch(e) {}
  3736.  
  3737.     if (!url) {
  3738.       var SBS = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
  3739.       var configBundle = SBS.createBundle("resource:/browserconfig.properties");
  3740.       url = configBundle.GetStringFromName("browser.startup.homepage");
  3741.     }
  3742.  
  3743.     return url;
  3744.   },
  3745.  
  3746.   setBrowserHomePage: function(aValue) {
  3747.     if (this.yaDefence)
  3748.       this.yaDefence.protectedHomepage = aValue;
  3749.  
  3750.     this.setComplexValue("browser.startup.homepage", aValue);
  3751.   },
  3752.   
  3753.   getBrowserKeywordURL: function() {
  3754.     let url;
  3755.     try {
  3756.       url = this.getComplexValue("keyword.URL") || this.getCharPref("keyword.URL");
  3757.     } catch(e) {}
  3758.  
  3759.     if (!url) {
  3760.       const SBS = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
  3761.       let configBundle = SBS.createBundle("chrome://browser-region/locale/region.properties");
  3762.       url = configBundle.GetStringFromName("keyword.URL");
  3763.     }
  3764.  
  3765.     return url;
  3766.   },
  3767.  
  3768.   setBrowserKeywordURL: function(aValue) {
  3769.     this.setComplexValue("keyword.URL", aValue);
  3770.   },
  3771.   
  3772.   get appOS() {
  3773.     var gApp  = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime);
  3774.     return gApp.OS;
  3775.   },
  3776.  
  3777.   get windowsOS() {
  3778.     return ("nsIWindowsRegKey" in Ci) ? true : false;
  3779.   },
  3780.  
  3781.   getYandeskProgramDir: function() {
  3782.     return this.WinReg.read("HKCU", "Software\\Yandex\\Yandesk", "ProgramDir");
  3783.   },
  3784.  
  3785.   get isYandeskInstalled() {
  3786.     return !!this.getYandeskProgramDir();
  3787.   },
  3788.  
  3789.   getYaOnlineProgramDir: function() {
  3790.     return this.WinReg.read("HKCU", "Software\\Yandex\\Online", "ProgramDir");
  3791.   },
  3792.  
  3793.   get isYaOnlineInstalled() {
  3794.     return !!this.getYaOnlineProgramDir();
  3795.   },
  3796.  
  3797.   WinReg: {
  3798.     _convertName2Key: function(aKeyName) {
  3799.       aKeyName = aKeyName.replace(/^(HKEY_)/i, "").toUpperCase();
  3800.  
  3801.       var keyNamesHash = {
  3802.         "CURRENT_USER":  ["HKCU", "USER", "CURRENT_USER"],
  3803.         "CLASSES_ROOT":  ["HKCR", "ROOT", "CLASSES_ROOT"],
  3804.         "LOCAL_MACHINE": ["HKLM", "MACHINE", "LOCAL_MACHINE"]
  3805.       };
  3806.  
  3807.       var keyName;
  3808.       for (var kName in keyNamesHash) {
  3809.         if (keyNamesHash[kName].indexOf(aKeyName) !== -1) {
  3810.           keyName = kName;
  3811.           break;
  3812.         }
  3813.       }
  3814.  
  3815.       if (!keyName)
  3816.         throw new TypeError("nsIYaSearch.WinReg: wrong key name");
  3817.  
  3818.       return Ci.nsIWindowsRegKey["ROOT_KEY_" + keyName];
  3819.     },
  3820.  
  3821.     _readValue: function(wrk, value) {
  3822.       if (wrk.hasValue(value)) {
  3823.         switch (wrk.getValueType(value)) {
  3824.           case wrk.TYPE_STRING:
  3825.             return wrk.readStringValue(value);
  3826.           case wrk.TYPE_BINARY:
  3827.             return wrk.readBinaryValue(value);
  3828.           case wrk.TYPE_INT:
  3829.             return wrk.readIntValue(value);
  3830.           case wrk.TYPE_INT64:
  3831.             return wrk.readInt64Value(value);
  3832.           default:
  3833.             break;
  3834.         }
  3835.       }
  3836.       
  3837.       return null;
  3838.     },
  3839.  
  3840.     _writeValue: function(wrk, name, value, type) {
  3841.       type = type.toLowerCase();
  3842.  
  3843.       switch (type) {
  3844.         case "string":
  3845.           wrk.writeStringValue(name, value);
  3846.           break;
  3847.         case "binary":
  3848.           wrk.writeBinaryValue(name, value);
  3849.           break;
  3850.         case "int":
  3851.           wrk.writeIntValue(name, value);
  3852.           break;
  3853.         case "int64":
  3854.           wrk.writeInt64Value(name, value);
  3855.           break;
  3856.         default:
  3857.           throw new TypeError("nsIYaSearch.WinReg: wrong key type");
  3858.           break;
  3859.       }
  3860.     },
  3861.  
  3862.     _removeChildren: function(wrk) {
  3863.       for (var i = wrk.childCount - 1; i >= 0; i--) {
  3864.         var name = wrk.getChildName(i);
  3865.         var subkey = wrk.openChild(name, wrk.ACCESS_ALL);
  3866.         this._removeChildren(subkey);
  3867.         subkey.close();
  3868.         wrk.removeChild(name);
  3869.       }
  3870.     },
  3871.  
  3872.     _getWrk: function() {
  3873.       return Cc["@mozilla.org/windows-registry-key;1"].createInstance(Ci.nsIWindowsRegKey);
  3874.     },
  3875.  
  3876.     read: function(aKey, aPath, aName) {
  3877.       var result = null;
  3878.  
  3879.       if (gYaSearchService.windowsOS) {
  3880.         var key = this._convertName2Key(aKey);
  3881.  
  3882.         var wrk = this._getWrk();
  3883.         try {
  3884.           wrk.open(key, aPath, wrk.ACCESS_READ);
  3885.           result = this._readValue(wrk, aName);
  3886.         } catch(e) {}
  3887.         
  3888.         try {
  3889.           wrk.close();
  3890.         } catch(e) {}
  3891.       }
  3892.  
  3893.       return result;
  3894.     },
  3895.  
  3896.     write: function(aKey, aPath, aName, aValue, aValueType) {
  3897.       if (gYaSearchService.windowsOS) {
  3898.         var key = this._convertName2Key(aKey);
  3899.  
  3900.         var wrk = this._getWrk();
  3901.         try {
  3902.           wrk.create(key, aPath, wrk.ACCESS_WRITE);
  3903.           this._writeValue(wrk, aName, aValue, aValueType);
  3904.         } catch(e) {}
  3905.  
  3906.         try {
  3907.           wrk.close();
  3908.         } catch(e) {}
  3909.       }
  3910.     },
  3911.  
  3912.     remove: function(aKey, aPath, aName) {
  3913.     }
  3914.   },
  3915.  
  3916.   get barExtensionVersion() {
  3917.     if (!this._barExtensionVersion)
  3918.       this._barExtensionVersion = this.barExtensionMajorVersion + this.VERSION_BUILD;
  3919.     return this._barExtensionVersion;
  3920.   },
  3921.   
  3922.   get barExtensionMajorVersion() {
  3923.     if (!this._barExtensionMajorVersion)
  3924.       this._barExtensionMajorVersion = Cc["@mozilla.org/extensions/manager;1"]
  3925.                                            .getService(Ci.nsIExtensionManager)
  3926.                                            .getItemForID(EXT_ID).version;
  3927.     
  3928.     return this._barExtensionMajorVersion;
  3929.   },
  3930.   
  3931.   get barExtensionVersionWithLocale() {
  3932.     if (!this._barExtensionVersionWithLocale)
  3933.       this._barExtensionVersionWithLocale = this.barExtensionVersion + this.versionLocaleAppend;
  3934.  
  3935.     return this._barExtensionVersionWithLocale;
  3936.   },
  3937.  
  3938.   get versionLocaleAppend() {
  3939.     let verLocaleAppend = this.getString("locale.lang");
  3940.     return (verLocaleAppend && verLocaleAppend != "ru") ? ("-" + verLocaleAppend) : "";
  3941.   },
  3942.  
  3943.   get generateGUIDStatusURL() {
  3944.     if (!this._generateGUIDStatusURL) {
  3945.       try {
  3946.         var vendorURL = this.getCharPref("yasearch.vendor.guid.url");
  3947.         var URIFixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup);
  3948.         vendorURL = URIFixup.createFixupURI(vendorURL, Ci.nsIURIFixup.FIXUP_FLAG_NONE);
  3949.         if ((vendorURL.scheme == "http" || vendorURL.scheme == "https") && /yandex\.ru$/i.test(vendorURL.host)) {
  3950.           vendorURL = vendorURL.spec;
  3951.           vendorURL += /\?/.test(vendorURL) ? (/&$/.test(vendorURL) ? "" : "&") : "?";
  3952.           this._generateGUIDStatusURL = vendorURL;
  3953.         }
  3954.       } catch (ex) {}
  3955.  
  3956.       if (!this._generateGUIDStatusURL)
  3957.         this._generateGUIDStatusURL = "http://soft.export.yandex.ru/status.xml?";
  3958.     }
  3959.     return this._generateGUIDStatusURL;
  3960.   },
  3961.  
  3962.   get generateGUID() {
  3963.     return Cc["@mozilla.org/uuid-generator;1"].createInstance(Ci.nsIUUIDGenerator).generateUUID();
  3964.   },
  3965.  
  3966.   getYaAppDir: function() {
  3967.     var appDir;
  3968.     
  3969.     if (this.AppBarType == "barffport") {
  3970.       appDir = this.getPortableDir();
  3971.     } else {
  3972.       try {
  3973.         appDir = Cc["@mozilla.org/file/directory_service;1"]
  3974.                      .getService(Ci.nsIProperties)
  3975.                      .get(this.windowsOS ? "AppData" : "Home", Ci.nsIFile);
  3976.       } catch(e) {}
  3977.     }
  3978.     
  3979.     if (appDir && appDir.exists() && appDir.isDirectory()) {
  3980.       appDir.append(this.windowsOS ? "Yandex" : ".yandex");
  3981.  
  3982.       if (!appDir.exists() || !appDir.isDirectory()) {
  3983.         try {
  3984.           appDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  3985.         } catch(e) {}
  3986.       }
  3987.  
  3988.       if (appDir.exists() && appDir.isDirectory())
  3989.         return appDir;
  3990.     }
  3991.  
  3992.     return false;
  3993.   },
  3994.   
  3995.   getPortableDir: function() {
  3996.     let curProcDir,
  3997.         badStructure = true;
  3998.     
  3999.     try {
  4000.       curProcDir = Cc["@mozilla.org/file/directory_service;1"]
  4001.                        .getService(Ci.nsIProperties)
  4002.                        .get("CurProcD", Ci.nsIFile)
  4003.                        .parent;
  4004.       
  4005.       badStructure = ["AppInfo", "DefaultData", "Firefox"].some(function(aDirName) {
  4006.         let dir = curProcDir.clone();
  4007.         dir.append(aDirName);
  4008.         return !(dir.exists() && dir.isDirectory());
  4009.       });
  4010.       
  4011.     } catch(e) {}
  4012.     
  4013.     return badStructure ? null : curProcDir;
  4014.   },
  4015.   
  4016.   _AppBarType: null,
  4017.   get AppBarType() {
  4018.     if (!this._AppBarType) {
  4019.       let prefName = "yasearch.general.app.bar.type";
  4020.       let barType = this.getCharPref(prefName);
  4021.       
  4022.       switch (barType) {
  4023.         case "barff":
  4024.         case "barffport":
  4025.           break;
  4026.         
  4027.         default:
  4028.           barType = !!this.getPortableDir() ? "barffport" : "barff";
  4029.           this.setCharPref(prefName, barType);
  4030.           break;
  4031.       }
  4032.       
  4033.       this._AppBarType = barType;
  4034.     }
  4035.     
  4036.     return this._AppBarType;
  4037.   },
  4038.   
  4039.   get vendorFileName() {
  4040.     return "clids-" + this.AppBarType + ".xml";
  4041.   },
  4042.   
  4043.   getYaPrefsFile: function(aFileName, aCreate) {
  4044.     function _isFileExists(aFile) {
  4045.       return !!(aFile.exists() && aFile.isFile());
  4046.     }
  4047.     
  4048.     var appDir = this.getYaAppDir();
  4049.     if (appDir) {
  4050.       var file = appDir.clone();
  4051.       file.append(aFileName);
  4052.  
  4053.       if (aFileName == this.vendorFileName && !_isFileExists(file)) {
  4054.         var venFile = appDir.clone();
  4055.         venFile.append("clids-barie.xml");
  4056.         
  4057.         if (_isFileExists(venFile)) {
  4058.           try {
  4059.             venFile.copyTo(appDir, aFileName);
  4060.             venFile.permissions = 0755;
  4061.           } catch(e) {}
  4062.         }
  4063.         
  4064.         if (!_isFileExists(file)) {
  4065.           venFile = appDir.clone();
  4066.           venFile.append("vendor.xml");
  4067.           
  4068.           if (_isFileExists(venFile)) {
  4069.             try {
  4070.               venFile.copyTo(appDir, aFileName);
  4071.               venFile.permissions = 0755;
  4072.             } catch(e) {}
  4073.           }
  4074.           
  4075.           if (!_isFileExists(file)) {
  4076.             venFile = this.getContentDir();
  4077.             venFile.append("services");
  4078.             venFile.append("vendor.xml");
  4079.             
  4080.             if (_isFileExists(venFile)) {
  4081.               try {
  4082.                 venFile.copyTo(appDir, aFileName);
  4083.                 venFile.permissions = 0755;
  4084.               } catch(e) {}
  4085.             }
  4086.           }
  4087.         }
  4088.       }
  4089.  
  4090.       if (aCreate == true && !_isFileExists(file))
  4091.         file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0755);
  4092.  
  4093.       if (_isFileExists(file) && file.isReadable())
  4094.         return file;
  4095.     }
  4096.  
  4097.     return false;
  4098.   },
  4099.  
  4100.   getGuidDataFromString: function(aGuidStr) {
  4101.     var guid = aGuidStr ? aGuidStr.toString() : false;
  4102.     return guid && /^\{[0-9a-f]{2,8}\-[0-9a-f]{2,4}\-[0-9a-f]{2,4}\-[0-9a-f]{1,4}\-[0-9a-f]{2,12}\}$/i.test(guid) ? guid : false;
  4103.   },
  4104.  
  4105.   __guidString: null,
  4106.  
  4107.   get guidString() {
  4108.     if (this.__guidString === null) {
  4109.       var guidPrefName = "yasearch.guid.value",
  4110.           guidStr = "",
  4111.           uiFile = this.getYaPrefsFile("ui");
  4112.  
  4113.       if (uiFile) {
  4114.         guidStr = this.getGuidDataFromString(this.readFile(uiFile));
  4115.       } else {
  4116.         var uiWasCreated = false;
  4117.         
  4118.         var currentWinUser;
  4119.         if (this.AppBarType !== "barffport") {
  4120.           currentWinUser = this.WinReg.read("HKCU",
  4121.                            "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", "Logon User Name");
  4122.           
  4123.           if (currentWinUser) {
  4124.             uiWasCreated = !!this.WinReg.read("HKCU", "Software\\Yandex", "UICreated_" + currentWinUser);
  4125.           }
  4126.         }
  4127.         
  4128.         if (!uiWasCreated) {
  4129.           if (this.prefBranch.prefHasUserValue(guidPrefName)) {
  4130.             guidStr = this.getGuidDataFromString(this.getCharPref(guidPrefName));
  4131.           } else {
  4132.             guidStr = this.generateGUID;
  4133.             this.setCharPref(guidPrefName, guidStr);
  4134.           }
  4135.  
  4136.           if (guidStr) {
  4137.             uiFile = this.getYaPrefsFile("ui", true);
  4138.             
  4139.             if (!uiFile || !uiFile.isWritable()) {
  4140.               guidStr = "";
  4141.             
  4142.             } else {
  4143.               this.writeFile(uiFile, guidStr);
  4144.               
  4145.               if (currentWinUser) {
  4146.                 this.WinReg.write("HKCU", "Software\\Yandex", "UICreated_" + currentWinUser, 1, "int");
  4147.               }
  4148.             }
  4149.           }
  4150.         }
  4151.       }
  4152.  
  4153.       if (guidStr)
  4154.         this.setCharPref(guidPrefName, guidStr);
  4155.       else
  4156.         guidStr = "";
  4157.  
  4158.       this.__guidString = "" + (guidStr || "");
  4159.     }
  4160.  
  4161.     return this.__guidString;
  4162.   },
  4163.   
  4164.   __barnavigR1String: null,
  4165.  
  4166.   get barnavigR1String() {
  4167.     if (this.__barnavigR1String === null) {
  4168.       let r1 = "",
  4169.           r1File = this.getYaPrefsFile("r1-barff", false);
  4170.  
  4171.       if (r1File) {
  4172.         r1 = this.readFile(r1File);
  4173.       }
  4174.       
  4175.       this.__barnavigR1String = r1 || "";
  4176.     }
  4177.     
  4178.     return this.__barnavigR1String;
  4179.   },
  4180.   
  4181.   set barnavigR1String(val) {
  4182.     if (val !== this.barnavigR1String) {
  4183.       let r1File = this.getYaPrefsFile("r1-barff", true);
  4184.       if (r1File) {
  4185.         this.writeFile(r1File, val);
  4186.       }
  4187.       
  4188.       this.__barnavigR1String = null;
  4189.     }
  4190.     
  4191.     return this.barnavigR1String;
  4192.   },
  4193.   
  4194.   vendorDataMergeClids: function() {
  4195.     this.__vendorData = null;
  4196.     
  4197.     var installedFile = this.getYaPrefsFile(this.vendorFileName, false);
  4198.     if (!installedFile)
  4199.       return;
  4200.     
  4201.     try {
  4202.       installedFile.permissions = 0755;
  4203.     } catch(e) {}
  4204.     
  4205.     var installedXml = this.safeE4Xml(this.readFile(installedFile), null, "vendor");
  4206.     if (!installedXml) {
  4207.       try {
  4208.         installedFile.remove(true);
  4209.       } catch(e) {}
  4210.       
  4211.       return;
  4212.     }
  4213.     
  4214.     var distribFile = this.getContentDir();
  4215.     distribFile.append("services");
  4216.     distribFile.append("vendor.xml");
  4217.     
  4218.     if (!(distribFile.exists() && distribFile.isFile()))
  4219.       return;
  4220.     
  4221.     var distribXml = this.safeE4Xml(this.readFile(distribFile), null, "vendor");
  4222.     if (!distribXml)
  4223.       return;
  4224.     
  4225.     var writeNewData = false;
  4226.     for each (var clid in distribXml.*.(/^clid\d+$/.test(function::name()))) {
  4227.       var clidName = clid.name();
  4228.       var clidValue = this.parseIntFromStr(clid.toString());
  4229.       if (clidValue > 0 && (installedXml[clidName].length() === 0 ||
  4230.           !this.parseIntFromStr(installedXml[clidName].toString()))) {
  4231.         installedXml[clidName] = clidValue;
  4232.         writeNewData = true;
  4233.       }
  4234.     }
  4235.     
  4236.     if (writeNewData) {
  4237.       this.writeFile(installedFile, "<?xml version=\"1.0\" encoding=\"windows-1251\"?>\r\n" +
  4238.                                     installedXml.toXMLString());
  4239.     }
  4240.   },
  4241.  
  4242.   get vendorData() {
  4243.     if (!this.__vendorData) {
  4244.       var data = {};
  4245.       var vendorFile = this.getYaPrefsFile(this.vendorFileName, false);
  4246.       var vendorXml = this.safeE4Xml(vendorFile ? this.readFile(vendorFile) : "", "<vendor/>", "vendor");
  4247.       
  4248.       for (var i = 0; i <= 10; i++) {
  4249.         var clid = this.parseIntFromStr(vendorXml["clid" + i].toString());
  4250.         data["clid" + i] = clid > 0 ? clid.toString().substr(0, 10) : false;
  4251.       }
  4252.  
  4253.       this.__vendorData = data;
  4254.     }
  4255.  
  4256.     return this.__vendorData;
  4257.   },
  4258.  
  4259.   get yandexHomePageValue() {
  4260.     let clid5 = this.vendorData.clid5;
  4261.     return "http://" + this.getLocaleDependedUrl("YandexWwwHost") + "/" + (clid5 ? "?clid=" + clid5 : "");
  4262.   },
  4263.   
  4264.   isYandexHomePage: function(aHomepageURL) {
  4265.     let url = typeof aHomepageURL === "undefined" ? this.getBrowserHomePage() : aHomepageURL;
  4266.     
  4267.     return !!(url &&
  4268.               (/^http:\/\/(www\.)?yandex\.(ru|ua|kz|by|com)/i.test(url) ||
  4269.                /^http:\/\/ru\.start3\.mozilla\.com\/firefox/.test(url))
  4270.              );
  4271.   },
  4272.   
  4273.   setHomePageUrl: function(aOverrideYandex) {
  4274.     if (aOverrideYandex || !this.isYandexHomePage())
  4275.       this.setBrowserHomePage(this.yandexHomePageValue);
  4276.  
  4277.     if (this.getIntPref("browser.startup.page") === 0)
  4278.       this.setIntPref("browser.startup.page", 1);
  4279.   },
  4280.   
  4281.   _checkKeywordUrl: function() {
  4282.     if (this.getCharPref("app.distributor") != "yandex")
  4283.       return;
  4284.     
  4285.     let keywordURL = this.getBrowserKeywordURL();
  4286.     if (!keywordURL || this.prefBranch.prefHasUserValue("keyword.URL"))
  4287.       return;
  4288.     
  4289.     this._setKeywordUrl(false);
  4290.   },
  4291.   
  4292.   _setKeywordUrl: function(aSetEnabled) {
  4293.     let keywordURL = this.getBrowserKeywordURL();
  4294.     
  4295.     if (!(/[&?]clid=/.test(keywordURL) && /^http:\/\/yandex\.(ru|ua|kz|by|com)\/yandsearch\?/.test(keywordURL))) {
  4296.       let urlParams = [];
  4297.       
  4298.       let clid9 = this.vendorData.clid9;
  4299.       if (clid9)
  4300.         urlParams.push("clid=" + clid9);
  4301.       
  4302.       urlParams.push("yasoft=" + encodeURIComponent(this.AppInfo.yasoftStr));
  4303.       urlParams.push("text=");
  4304.       
  4305.       this.setBrowserKeywordURL(this.getLocaleDependedUrl("KeywordURL") + "?" + urlParams.join("&"));
  4306.     }
  4307.     
  4308.     if (aSetEnabled)
  4309.       this.setBoolPref("keyword.enabled", true);
  4310.   },
  4311.  
  4312.   appendStatData2Url: function(aURL, aStatData) {
  4313.     if (!aStatData || typeof(aStatData) !== "object" || !aURL)
  4314.       return aURL;
  4315.  
  4316.     if (/[&?]yasoft=/.test(aURL))
  4317.       aStatData.yasoft = false;
  4318.  
  4319.     if (/[&?]clid=/.test(aURL))
  4320.       aStatData.clid = false;
  4321.     
  4322.     let appendix = this.getAppendStatData2Url(aStatData);
  4323.     
  4324.     if (appendix == "")
  4325.       return aURL;
  4326.  
  4327.     let url = aURL.split("?");
  4328.     url = url[0] + "?" + appendix + (url[1] ? "&" + url[1] : "");
  4329.  
  4330.     return url;
  4331.   },
  4332.  
  4333.   getAppendStatData2Url: function(aStatData) {
  4334.     let res = [];
  4335.  
  4336.     if (aStatData && !(aStatData.action && !(aStatData.yasoft || aStatData.clid))) {
  4337.       if (aStatData.clid) {
  4338.         let clid = this.vendorData["clid" + (aStatData.clid || "")];
  4339.         if (clid)
  4340.           res.push("clid=" + clid);
  4341.       }
  4342.  
  4343.       if ((aStatData.yasoft || null) !== false)
  4344.         res.push("yasoft=" + encodeURIComponent(this.AppInfo.yasoftStr));
  4345.     }
  4346.  
  4347.     return res.join("&");
  4348.   },
  4349.   
  4350.   get versionData() {
  4351.     var gApp  = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime);
  4352.  
  4353.     var versionData = {
  4354.       ui: this.guidString,
  4355.       v: this.barExtensionVersionWithLocale,
  4356.       ver: this.barExtensionVersionWithLocale,
  4357.       bn: gApp.name,
  4358.       bv: gApp.version,
  4359.       os: gApp.OS,
  4360.       yasoft: this.AppInfo.yasoftStr,
  4361.       tl: this.timeGuid
  4362.     };
  4363.  
  4364.     if (this.vendorData.clid1)
  4365.       versionData.clid = this.vendorData.clid1;
  4366.  
  4367.     return versionData;
  4368.   },
  4369.  
  4370.   get generateGUIDData() {
  4371.     if (!this._generateGUIDData) {
  4372.       var versionData = this.versionData;
  4373.  
  4374.       var data2Server = [];
  4375.       for (let [propName, propValue] in Iterator(versionData))
  4376.         data2Server.push(propName + "=" + encodeURIComponent(propValue));
  4377.       
  4378.       this._generateGUIDData = data2Server.join("&");
  4379.     }
  4380.  
  4381.     var dynamicAppend = "";
  4382.     
  4383.     if (this.yaDefence) {
  4384.       var yaDefenceTimesData = this.yaDefence.changesTime;
  4385.       if (yaDefenceTimesData)
  4386.         dynamicAppend += yaDefenceTimesData;
  4387.  
  4388.       var yaFSearchData = this.yaDefence.fSearchStatData;
  4389.       if (yaFSearchData)
  4390.         dynamicAppend += yaFSearchData;
  4391.     }
  4392.     
  4393.     var _use = "&stat=dayuse";
  4394.     if (typeof(gYaInstaller) === "object" && "sttInstall" in gYaInstaller) {
  4395.       let stt = gYaInstaller.sttInstall;
  4396.       if (stt)
  4397.         _use = "&stat=install";
  4398.     }
  4399.     
  4400.     dynamicAppend += _use;
  4401.     
  4402.     return this._generateGUIDData + dynamicAppend;
  4403.   },
  4404.  
  4405.   __AppInfo: null,
  4406.   get AppInfo() {
  4407.     if (!this.__AppInfo) {
  4408.       var gApp  = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).QueryInterface(Ci.nsIXULRuntime);
  4409.       var os = gApp.OS;
  4410.  
  4411.       let verLocaleAppend = this.getString("locale.lang");
  4412.       verLocaleAppend = (verLocaleAppend && verLocaleAppend != "ru") ? ("." + verLocaleAppend) : "";
  4413.  
  4414.       this.__AppInfo = {
  4415.         yasoftStr: "barff" + verLocaleAppend,
  4416.  
  4417.         OS: {
  4418.           name: os,
  4419.           isWindows: /^win/i.test(os),
  4420.           isLinux:   /^linux/i.test(os),
  4421.           isMacOS:   /^darwin/i.test(os),
  4422.           get platformName() {
  4423.             if (this.isWindows) return "win";
  4424.             if (this.isLinux)   return "unix";
  4425.             if (this.isMacOS)   return "mac";
  4426.  
  4427.             return "";
  4428.           }
  4429.         },
  4430.  
  4431.         browser: {
  4432.           version: gApp.version,
  4433.           get isGreaterThenFx30() {
  4434.             return !!Ci.nsIWorker;
  4435.           },
  4436.           get isGreaterThenFx35() {
  4437.             return !!Ci.nsIDOMGeoPositionAddress;
  4438.           }
  4439.         }
  4440.       };
  4441.     }
  4442.     return this.__AppInfo;
  4443.   },
  4444.  
  4445.   get timeGuid() {
  4446.     return (new Date(parseInt(this.getCharPref("yasearch.guid.time"), 10))).valueOf() || 0;
  4447.   },
  4448.  
  4449.   set timeGuid(val) {
  4450.     this.setCharPref("yasearch.guid.time", val ? Date.now() : "0");
  4451.   },
  4452.  
  4453.   checkNeedSendGuid: function() {
  4454.     if (this.updateTimer._GuidRefresh)
  4455.       return;
  4456.  
  4457.     let timeNow = Date.now(),
  4458.         timeBefore = this.timeGuid;
  4459.     
  4460.     if (timeBefore < (timeNow - DAY_SECS) || timeBefore > timeNow)
  4461.       this.setTimer("_Guid", 10);
  4462.  
  4463.     this.setTimer("_GuidRefresh");
  4464.   },
  4465.  
  4466.   loadURI: function(aURL, aEvent, aClidType) {
  4467.     let browser = this.getWindow("navigator:browser");
  4468.     return (browser && browser.Ya) ? browser.Ya.loadURI(aURL, aEvent, aClidType) : false;
  4469.   },
  4470.  
  4471.   loadConditionalURI: function(aType, aEvent, aStatData) {
  4472.     let browser = this.getWindow("navigator:browser");
  4473.     return (browser && browser.Ya) ? browser.Ya.loadConditionalURI(aType, aEvent, aStatData) : false;
  4474.   },
  4475.  
  4476.   makeURI: function(aURLSpec, aCharset) {
  4477.     try {
  4478.       return IO_SERVICE.newURI(aURLSpec, aCharset, null);
  4479.     } catch(e) {}
  4480.     
  4481.     return null;
  4482.   },
  4483.  
  4484.   makeFileURI: function(aFile) {
  4485.     try {
  4486.       return IO_SERVICE.newFileURI(aFile);
  4487.     } catch(e) {}
  4488.     
  4489.     return null;
  4490.   },
  4491.  
  4492.   safeE4Xml: function(aStr, aDefaultStr, aRootNodeName) {
  4493.     if (aStr) {
  4494.       if (typeof aStr == "string") {
  4495.         aStr = this.safeUnicode(aStr);
  4496.       } else {
  4497.         if (aStr instanceof Ci.nsIDOMDocument || aStr instanceof Ci.nsIDOMElement)
  4498.           aStr = this.xmlSerializer.serializeToString(aStr);
  4499.         else if (typeof(aStr) === "xml")
  4500.           aStr = aStr.toString();
  4501.       }
  4502.     }
  4503.  
  4504.     if (!aStr || aStr == "")
  4505.       aStr = (aDefaultStr || "").toString();
  4506.  
  4507.     if (typeof(aStr) != "string")
  4508.       return null;
  4509.  
  4510.     aStr = aStr.replace(/<\?xml .+\?>[\r\n]*/, "")
  4511.                .replace(/(<!DOCTYPE ((.|\r|\n)*?)\]>)[\r\n]*/, "");
  4512.  
  4513.     var d, rootNodeName;
  4514.  
  4515.     try {
  4516.       d = new XML(aStr)[0];
  4517.       rootNodeName = d.name().localName.toString();
  4518.     } catch(e) {
  4519.       this.log("'safeE4Xml' error: " + e);
  4520.     }
  4521.     
  4522.     if (d && rootNodeName) {
  4523.       if (!aRootNodeName)
  4524.         aRootNodeName = rootNodeName;
  4525.  
  4526.       var namesArray = typeof(aRootNodeName) == "string" ? [aRootNodeName] : aRootNodeName;
  4527.       
  4528.       if (namesArray.length > 0)
  4529.         for each (var name in namesArray)
  4530.           if (name == rootNodeName)
  4531.             return d;
  4532.     }
  4533.  
  4534.     return aDefaultStr ? this.safeE4Xml(aDefaultStr) : null;
  4535.   },
  4536.  
  4537.   DOMUtils: {
  4538.     evaluateXPath: function(aNode, aExpr) {
  4539.       function nsResolver(aPrefix) {
  4540.         const ns = {
  4541.           "xul": "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
  4542.           "xhtml": "http://www.w3.org/1999/xhtml"
  4543.         };
  4544.         
  4545.         return ns[aPrefix] || null;
  4546.       }
  4547.       
  4548.       let xpEvaluator = Cc["@mozilla.org/dom/xpath-evaluator;1"].getService(Ci.nsIDOMXPathEvaluator);
  4549.       let xpathResult = xpEvaluator.evaluate(aExpr, aNode, nsResolver,
  4550.                                              Ci.nsIDOMXPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
  4551.       let nextElement,
  4552.           result = [];
  4553.       
  4554.       while ((nextElement = xpathResult.iterateNext()))
  4555.         result.push(nextElement);
  4556.       
  4557.       return result;
  4558.     },
  4559.     
  4560.     importAndRemoveNode: function(aNode, aDocument) {
  4561.       if (!aNode)
  4562.         return aNode;
  4563.  
  4564.       var node = aDocument.importNode(aNode, true);
  4565.  
  4566.       try {
  4567.         aNode.parentNode.removeChild(aNode);
  4568.       } catch(e) {}
  4569.  
  4570.       return node;
  4571.     },
  4572.  
  4573.     adoptNode: function(aNode, aDocument) {
  4574.       return this.importAndRemoveNode(aNode, aDocument);
  4575.     },
  4576.  
  4577.     appendNode: function(aNode, aTarget) {
  4578.       var node = this.importAndRemoveNode(aNode, aTarget.ownerDocument);
  4579.  
  4580.       if (node)
  4581.         aTarget.appendChild(node);
  4582.  
  4583.       return node;
  4584.     },
  4585.  
  4586.     replaceNode: function(aNewNode, aOldNode) {
  4587.       var fromDoc = aNewNode.ownerDocument,
  4588.           toDoc = aOldNode.ownerDocument;
  4589.  
  4590.       var node = (fromDoc === toDoc) ? aNewNode : this.importAndRemoveNode(aNewNode, toDoc);
  4591.  
  4592.       if (node)
  4593.         aOldNode.parentNode.replaceChild(node, aOldNode);
  4594.  
  4595.       return node;
  4596.     },
  4597.  
  4598.     replaceChildNodes: function(aNode, aTarget) {
  4599.       while (aTarget.hasChildNodes())
  4600.         aTarget.removeChild(aTarget.firstChild);
  4601.  
  4602.       return aNode ? this.appendNode(aNode, aTarget) : null;
  4603.     }
  4604.   },
  4605.  
  4606.   dumpIFaces: function(aObject) {
  4607.     if (!this.debug)
  4608.       return;
  4609.  
  4610.     var dumpTxt = ["Dump interfaces\r\n==============================================="];
  4611.     for (var iface in Ci) {
  4612.       try {
  4613.         aObject.QueryInterface(Ci[iface])
  4614.         dumpTxt.push(iface);
  4615.       } catch(e) {}
  4616.     }
  4617.  
  4618.     this.log(dumpTxt.join("\r\n"));
  4619.     return aObject;
  4620.   },
  4621.  
  4622.   dump: function(aObject) {
  4623.     if (!this.debug)
  4624.       return;
  4625.  
  4626.     var dumpTxt = ["Dump properties in Object\r\n==============================================="];
  4627.     for (var prop in aObject)
  4628.       try { dumpTxt.push(prop + " :: " + aObject[prop]); } catch(e) {}
  4629.  
  4630.     if (aObject instanceof Ci.nsIDOMEvent) {
  4631.       dumpTxt.push("================= nsIDOMEvent targets ======================================");
  4632.       ["target", "currentTarget", "originalTarget", "explicitOriginalTarget"].forEach(function(aType) {
  4633.         dumpTxt.push(aType + " :: " + aObject[aType] + " :: " + (aObject[aType] ? aObject[aType].localName : null))
  4634.       })
  4635.     }
  4636.  
  4637.     this.log(dumpTxt.join("\r\n"));
  4638.   },
  4639.  
  4640.   _getToolbarForNode: function(aNode) {
  4641.     let toolbar = false,
  4642.         node = aNode;
  4643.     
  4644.     while (node && !toolbar) {
  4645.       node = node.parentNode;
  4646.       if (node && node.localName == "toolbar")
  4647.         toolbar = node;
  4648.     }
  4649.     
  4650.     return toolbar;
  4651.   },
  4652.  
  4653.   _persistToolbarSet: function(aToolbar) {
  4654.     if (aToolbar && aToolbar.localName && aToolbar.localName == "toolbar") {
  4655.       aToolbar.setAttribute("currentset", aToolbar.currentSet);
  4656.       aToolbar.ownerDocument.persist(aToolbar.id, "currentset");
  4657.     }
  4658.   },
  4659.  
  4660.   checkToolbarSet: function(aNmb, aToolbar) {
  4661.     if (aNmb == this.barExtensionVersion)
  4662.       return;
  4663.  
  4664.     aToolbar.setAttribute("yaNmbSaved", this.barExtensionMajorVersion);
  4665.     aToolbar.ownerDocument.persist(aToolbar.id, "yaNmbSaved");
  4666.  
  4667.     if (!aNmb)
  4668.       return;
  4669.  
  4670.     let gDocument = aToolbar.ownerDocument,
  4671.         defaultSet = aToolbar.getAttribute("defaultset");
  4672.  
  4673.     let addDiff = {
  4674.       "3.5.0": [ ["yasearch-fotki", ",yasearch-mail", true],
  4675.                  ["yasearch-yaru", ",yasearch-lenta", false] ],
  4676.  
  4677.       "4.0.0": [ ["yasearch-spellchecker", ",yasearch-bloggers", true] ],
  4678.       
  4679.       "4.3.0": [ ["yasearch-translate", ",yasearch-spellchecker", true] ]
  4680.     };
  4681.  
  4682.     for (var nmb in addDiff) {
  4683.       if (aNmb <= nmb) {
  4684.         let i = -1,
  4685.             _d = addDiff[nmb];
  4686.         
  4687.         while (_d[++i]) {
  4688.           let beforeElt = null;
  4689.  
  4690.           if (_d[i][1]) {
  4691.             let defSetCute = (defaultSet.split(_d[i][1])[0] + _d[i][1]).split(","),
  4692.                 j = defSetCute.length;
  4693.             
  4694.             let found = false;
  4695.  
  4696.             while (defSetCute[--j] && !found)
  4697.               found = gDocument.getElementById(defSetCute[j]);
  4698.  
  4699.             if (found && found.nextSibling) {
  4700.               let check = true;
  4701.               
  4702.               while (check && found.nextSibling) {
  4703.                 switch ((_d[i][2] ? found : found.nextSibling).localName) {
  4704.                   case "toolbaritem":
  4705.                   case "toolbarbutton":
  4706.                     check = false;
  4707.                     break;
  4708.                   
  4709.                   default:
  4710.                     found = found.nextSibling;
  4711.                 }
  4712.               }
  4713.             }
  4714.  
  4715.             beforeElt = found ? (found.nextSibling ? found.nextSibling : null) :
  4716.                                  (aToolbar.firstChild ? aToolbar.firstChild : null);
  4717.           }
  4718.  
  4719.           for each (var newItemId in _d[i][0].split(",").reverse())
  4720.             if (!gDocument.getElementById(newItemId))
  4721.               beforeElt = aToolbar.insertItem(newItemId, beforeElt);
  4722.         }
  4723.       }
  4724.     }
  4725.     
  4726.     if (aNmb < "4.3.0") {
  4727.       aToolbar.insertItem("separator", null);
  4728.       aToolbar.insertItem("yasearch.cb-default-0", null);
  4729.       aToolbar.insertItem("yasearch.cb-default-1", null);
  4730.     }
  4731.     
  4732.     this._persistToolbarSet(aToolbar);
  4733.   },
  4734.  
  4735.   module: {
  4736.     registerSelf: function (compMgr, fileSpec, location, type) {
  4737.       var compReg = compMgr.QueryInterface( Ci.nsIComponentRegistrar );
  4738.       compReg.registerFactoryLocation(this.cid,
  4739.                                       "nsIYaSearch JS component",
  4740.                                       this.contractId,
  4741.                                       fileSpec, location, type);
  4742.       var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  4743.       catman.addCategoryEntry("app-startup", "nsIYaSearch", this.contractId, true, true);
  4744.     },
  4745.  
  4746.     unregisterSelf: function(compMgr, fileSpec, location) {
  4747.       compMgr = compMgr.QueryInterface( Ci.nsIComponentRegistrar );
  4748.       compMgr.unregisterFactoryLocation( this.cid, fileSpec );
  4749.       var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  4750.       catman.deleteCategoryEntry("app-startup", this.contractId, true);
  4751.     },
  4752.  
  4753.     getClassObject: function (compMgr, cid, iid) {
  4754.       if (!cid.equals(this.cid))
  4755.         throw Cr.NS_ERROR_NO_INTERFACE;
  4756.       if (!iid.equals(Ci.nsIFactory))
  4757.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  4758.       return this.factory;
  4759.     },
  4760.  
  4761.     cid: Components.ID("{3F79261A-508E-47a3-B61C-D1F29E2068F3}"),
  4762.  
  4763.     contractId: "@yandex.ru/yasearch;1",
  4764.  
  4765.     factory: {
  4766.       createInstance: function (outer, iid) {
  4767.         if (outer != null)
  4768.           throw Cr.NS_ERROR_NO_AGGREGATION;
  4769.         return gYaSearchService;
  4770.       }
  4771.     },
  4772.  
  4773.     canUnload: function(compMgr) {return true;}
  4774.   }
  4775. }
  4776.  
  4777. function NSGetModule(compMgr, fileSpec) {
  4778.   return nsIYaSearch.prototype.module;
  4779. }
  4780.  
  4781. var gYaSearchService = new nsIYaSearch();
  4782.