| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* |  | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, |  | 
| 3  * Copyright (C) 2006-2016 Eyeo GmbH |  | 
| 4  * |  | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify |  | 
| 6  * it under the terms of the GNU General Public License version 3 as |  | 
| 7  * published by the Free Software Foundation. |  | 
| 8  * |  | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, |  | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | 
| 12  * GNU General Public License for more details. |  | 
| 13  * |  | 
| 14  * You should have received a copy of the GNU General Public License |  | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |  | 
| 16  */ |  | 
| 17 |  | 
| 18 /** |  | 
| 19  * @fileOverview Definition of Subscription class and its subclasses. |  | 
| 20  */ |  | 
| 21 |  | 
| 22 Cu.import("resource://gre/modules/Services.jsm"); |  | 
| 23 |  | 
| 24 let {ActiveFilter, BlockingFilter, WhitelistFilter, ElemHideBase} = require("fil
     terClasses"); |  | 
| 25 let {FilterNotifier} = require("filterNotifier"); |  | 
| 26 |  | 
| 27 /** |  | 
| 28  * Abstract base class for filter subscriptions |  | 
| 29  * |  | 
| 30  * @param {String} url    download location of the subscription |  | 
| 31  * @param {String} [title]  title of the filter subscription |  | 
| 32  * @constructor |  | 
| 33  */ |  | 
| 34 function Subscription(url, title) |  | 
| 35 { |  | 
| 36   this.url = url; |  | 
| 37   this.filters = []; |  | 
| 38   if (title) |  | 
| 39     this._title = title; |  | 
| 40   else |  | 
| 41   { |  | 
| 42     let {Utils} = require("utils"); |  | 
| 43     this._title = Utils.getString("newGroup_title"); |  | 
| 44   } |  | 
| 45   Subscription.knownSubscriptions[url] = this; |  | 
| 46 } |  | 
| 47 exports.Subscription = Subscription; |  | 
| 48 |  | 
| 49 Subscription.prototype = |  | 
| 50 { |  | 
| 51   /** |  | 
| 52    * Download location of the subscription |  | 
| 53    * @type String |  | 
| 54    */ |  | 
| 55   url: null, |  | 
| 56 |  | 
| 57   /** |  | 
| 58    * Filters contained in the filter subscription |  | 
| 59    * @type Filter[] |  | 
| 60    */ |  | 
| 61   filters: null, |  | 
| 62 |  | 
| 63   _title: null, |  | 
| 64   _fixedTitle: false, |  | 
| 65   _disabled: false, |  | 
| 66 |  | 
| 67   /** |  | 
| 68    * Title of the filter subscription |  | 
| 69    * @type String |  | 
| 70    */ |  | 
| 71   get title() |  | 
| 72   { |  | 
| 73     return this._title; |  | 
| 74   }, |  | 
| 75   set title(value) |  | 
| 76   { |  | 
| 77     if (value != this._title) |  | 
| 78     { |  | 
| 79       let oldValue = this._title; |  | 
| 80       this._title = value; |  | 
| 81       FilterNotifier.triggerListeners("subscription.title", this, value, oldValu
     e); |  | 
| 82     } |  | 
| 83     return this._title; |  | 
| 84   }, |  | 
| 85 |  | 
| 86   /** |  | 
| 87    * Determines whether the title should be editable |  | 
| 88    * @type Boolean |  | 
| 89    */ |  | 
| 90   get fixedTitle() |  | 
| 91   { |  | 
| 92     return this._fixedTitle; |  | 
| 93   }, |  | 
| 94   set fixedTitle(value) |  | 
| 95   { |  | 
| 96     if (value != this._fixedTitle) |  | 
| 97     { |  | 
| 98       let oldValue = this._fixedTitle; |  | 
| 99       this._fixedTitle = value; |  | 
| 100       FilterNotifier.triggerListeners("subscription.fixedTitle", this, value, ol
     dValue); |  | 
| 101     } |  | 
| 102     return this._fixedTitle; |  | 
| 103   }, |  | 
| 104 |  | 
| 105   /** |  | 
| 106    * Defines whether the filters in the subscription should be disabled |  | 
| 107    * @type Boolean |  | 
| 108    */ |  | 
| 109   get disabled() |  | 
| 110   { |  | 
| 111     return this._disabled; |  | 
| 112   }, |  | 
| 113   set disabled(value) |  | 
| 114   { |  | 
| 115     if (value != this._disabled) |  | 
| 116     { |  | 
| 117       let oldValue = this._disabled; |  | 
| 118       this._disabled = value; |  | 
| 119       FilterNotifier.triggerListeners("subscription.disabled", this, value, oldV
     alue); |  | 
| 120     } |  | 
| 121     return this._disabled; |  | 
| 122   }, |  | 
| 123 |  | 
| 124   /** |  | 
| 125    * Serializes the subscription to an array of strings for writing out on the d
     isk. |  | 
| 126    * @param {string[]} buffer  buffer to push the serialization results into |  | 
| 127    */ |  | 
| 128   serialize: function(buffer) |  | 
| 129   { |  | 
| 130     buffer.push("[Subscription]"); |  | 
| 131     buffer.push("url=" + this.url); |  | 
| 132     buffer.push("title=" + this._title); |  | 
| 133     if (this._fixedTitle) |  | 
| 134       buffer.push("fixedTitle=true"); |  | 
| 135     if (this._disabled) |  | 
| 136       buffer.push("disabled=true"); |  | 
| 137   }, |  | 
| 138 |  | 
| 139   serializeFilters: function(buffer) |  | 
| 140   { |  | 
| 141     for (let filter of this.filters) |  | 
| 142       buffer.push(filter.text.replace(/\[/g, "\\[")); |  | 
| 143   }, |  | 
| 144 |  | 
| 145   toString: function() |  | 
| 146   { |  | 
| 147     let buffer = []; |  | 
| 148     this.serialize(buffer); |  | 
| 149     return buffer.join("\n"); |  | 
| 150   } |  | 
| 151 }; |  | 
| 152 |  | 
| 153 /** |  | 
| 154  * Cache for known filter subscriptions, maps URL to subscription objects. |  | 
| 155  * @type Object |  | 
| 156  */ |  | 
| 157 Subscription.knownSubscriptions = Object.create(null); |  | 
| 158 |  | 
| 159 /** |  | 
| 160  * Returns a subscription from its URL, creates a new one if necessary. |  | 
| 161  * @param {String} url  URL of the subscription |  | 
| 162  * @return {Subscription} subscription or null if the subscription couldn't be c
     reated |  | 
| 163  */ |  | 
| 164 Subscription.fromURL = function(url) |  | 
| 165 { |  | 
| 166   if (url in Subscription.knownSubscriptions) |  | 
| 167     return Subscription.knownSubscriptions[url]; |  | 
| 168 |  | 
| 169   try |  | 
| 170   { |  | 
| 171     // Test URL for validity |  | 
| 172     url = Services.io.newURI(url, null, null).spec; |  | 
| 173     return new DownloadableSubscription(url, null); |  | 
| 174   } |  | 
| 175   catch (e) |  | 
| 176   { |  | 
| 177     return new SpecialSubscription(url); |  | 
| 178   } |  | 
| 179 }; |  | 
| 180 |  | 
| 181 /** |  | 
| 182  * Deserializes a subscription |  | 
| 183  * |  | 
| 184  * @param {Object}  obj map of serialized properties and their values |  | 
| 185  * @return {Subscription} subscription or null if the subscription couldn't be c
     reated |  | 
| 186  */ |  | 
| 187 Subscription.fromObject = function(obj) |  | 
| 188 { |  | 
| 189   let result; |  | 
| 190   try |  | 
| 191   { |  | 
| 192     obj.url = Services.io.newURI(obj.url, null, null).spec; |  | 
| 193 |  | 
| 194     // URL is valid - this is a downloadable subscription |  | 
| 195     result = new DownloadableSubscription(obj.url, obj.title); |  | 
| 196     if ("downloadStatus" in obj) |  | 
| 197       result._downloadStatus = obj.downloadStatus; |  | 
| 198     if ("lastSuccess" in obj) |  | 
| 199       result.lastSuccess = parseInt(obj.lastSuccess, 10) || 0; |  | 
| 200     if ("lastCheck" in obj) |  | 
| 201       result._lastCheck = parseInt(obj.lastCheck, 10) || 0; |  | 
| 202     if ("expires" in obj) |  | 
| 203       result.expires = parseInt(obj.expires, 10) || 0; |  | 
| 204     if ("softExpiration" in obj) |  | 
| 205       result.softExpiration = parseInt(obj.softExpiration, 10) || 0; |  | 
| 206     if ("errors" in obj) |  | 
| 207       result._errors = parseInt(obj.errors, 10) || 0; |  | 
| 208     if ("version" in obj) |  | 
| 209       result.version = parseInt(obj.version, 10) || 0; |  | 
| 210     if ("requiredVersion" in obj) |  | 
| 211     { |  | 
| 212       let {addonVersion} = require("info"); |  | 
| 213       result.requiredVersion = obj.requiredVersion; |  | 
| 214       if (Services.vc.compare(result.requiredVersion, addonVersion) > 0) |  | 
| 215         result.upgradeRequired = true; |  | 
| 216     } |  | 
| 217     if ("homepage" in obj) |  | 
| 218       result._homepage = obj.homepage; |  | 
| 219     if ("lastDownload" in obj) |  | 
| 220       result._lastDownload = parseInt(obj.lastDownload, 10) || 0; |  | 
| 221     if ("downloadCount" in obj) |  | 
| 222       result.downloadCount = parseInt(obj.downloadCount, 10) || 0; |  | 
| 223   } |  | 
| 224   catch (e) |  | 
| 225   { |  | 
| 226     // Invalid URL - custom filter group |  | 
| 227     if (!("title" in obj)) |  | 
| 228     { |  | 
| 229       // Backwards compatibility - titles and filter types were originally |  | 
| 230       // determined by group identifier. |  | 
| 231       if (obj.url == "~wl~") |  | 
| 232         obj.defaults = "whitelist"; |  | 
| 233       else if (obj.url == "~fl~") |  | 
| 234         obj.defaults = "blocking"; |  | 
| 235       else if (obj.url == "~eh~") |  | 
| 236         obj.defaults = "elemhide"; |  | 
| 237       if ("defaults" in obj) |  | 
| 238       { |  | 
| 239         let {Utils} = require("utils"); |  | 
| 240         obj.title = Utils.getString(obj.defaults + "Group_title"); |  | 
| 241       } |  | 
| 242     } |  | 
| 243     result = new SpecialSubscription(obj.url, obj.title); |  | 
| 244     if ("defaults" in obj) |  | 
| 245       result.defaults = obj.defaults.split(" "); |  | 
| 246   } |  | 
| 247   if ("fixedTitle" in obj) |  | 
| 248     result._fixedTitle = (obj.fixedTitle == "true"); |  | 
| 249   if ("disabled" in obj) |  | 
| 250     result._disabled = (obj.disabled == "true"); |  | 
| 251 |  | 
| 252   return result; |  | 
| 253 }; |  | 
| 254 |  | 
| 255 /** |  | 
| 256  * Class for special filter subscriptions (user's filters) |  | 
| 257  * @param {String} url see Subscription() |  | 
| 258  * @param {String} [title]  see Subscription() |  | 
| 259  * @constructor |  | 
| 260  * @augments Subscription |  | 
| 261  */ |  | 
| 262 function SpecialSubscription(url, title) |  | 
| 263 { |  | 
| 264   Subscription.call(this, url, title); |  | 
| 265 } |  | 
| 266 exports.SpecialSubscription = SpecialSubscription; |  | 
| 267 |  | 
| 268 SpecialSubscription.prototype = |  | 
| 269 { |  | 
| 270   __proto__: Subscription.prototype, |  | 
| 271 |  | 
| 272   /** |  | 
| 273    * Filter types that should be added to this subscription by default |  | 
| 274    * (entries should correspond to keys in SpecialSubscription.defaultsMap). |  | 
| 275    * @type string[] |  | 
| 276    */ |  | 
| 277   defaults: null, |  | 
| 278 |  | 
| 279   /** |  | 
| 280    * Tests whether a filter should be added to this group by default |  | 
| 281    * @param {Filter} filter filter to be tested |  | 
| 282    * @return {Boolean} |  | 
| 283    */ |  | 
| 284   isDefaultFor: function(filter) |  | 
| 285   { |  | 
| 286     if (this.defaults && this.defaults.length) |  | 
| 287     { |  | 
| 288       for (let type of this.defaults) |  | 
| 289       { |  | 
| 290         if (filter instanceof SpecialSubscription.defaultsMap[type]) |  | 
| 291           return true; |  | 
| 292         if (!(filter instanceof ActiveFilter) && type == "blacklist") |  | 
| 293           return true; |  | 
| 294       } |  | 
| 295     } |  | 
| 296 |  | 
| 297     return false; |  | 
| 298   }, |  | 
| 299 |  | 
| 300   /** |  | 
| 301    * See Subscription.serialize() |  | 
| 302    */ |  | 
| 303   serialize: function(buffer) |  | 
| 304   { |  | 
| 305     Subscription.prototype.serialize.call(this, buffer); |  | 
| 306     if (this.defaults && this.defaults.length) |  | 
| 307       buffer.push("defaults=" + this.defaults.filter((type) => type in SpecialSu
     bscription.defaultsMap).join(" ")); |  | 
| 308     if (this._lastDownload) |  | 
| 309       buffer.push("lastDownload=" + this._lastDownload); |  | 
| 310   } |  | 
| 311 }; |  | 
| 312 |  | 
| 313 SpecialSubscription.defaultsMap = { |  | 
| 314   __proto__: null, |  | 
| 315   "whitelist": WhitelistFilter, |  | 
| 316   "blocking": BlockingFilter, |  | 
| 317   "elemhide": ElemHideBase |  | 
| 318 }; |  | 
| 319 |  | 
| 320 /** |  | 
| 321  * Creates a new user-defined filter group. |  | 
| 322  * @param {String} [title]  title of the new filter group |  | 
| 323  * @result {SpecialSubscription} |  | 
| 324  */ |  | 
| 325 SpecialSubscription.create = function(title) |  | 
| 326 { |  | 
| 327   let url; |  | 
| 328   do |  | 
| 329   { |  | 
| 330     url = "~user~" + Math.round(Math.random()*1000000); |  | 
| 331   } while (url in Subscription.knownSubscriptions); |  | 
| 332   return new SpecialSubscription(url, title); |  | 
| 333 }; |  | 
| 334 |  | 
| 335 /** |  | 
| 336  * Creates a new user-defined filter group and adds the given filter to it. |  | 
| 337  * This group will act as the default group for this filter type. |  | 
| 338  */ |  | 
| 339 SpecialSubscription.createForFilter = function(/**Filter*/ filter) /**SpecialSub
     scription*/ |  | 
| 340 { |  | 
| 341   let subscription = SpecialSubscription.create(); |  | 
| 342   subscription.filters.push(filter); |  | 
| 343   for (let type in SpecialSubscription.defaultsMap) |  | 
| 344   { |  | 
| 345     if (filter instanceof SpecialSubscription.defaultsMap[type]) |  | 
| 346       subscription.defaults = [type]; |  | 
| 347   } |  | 
| 348   if (!subscription.defaults) |  | 
| 349     subscription.defaults = ["blocking"]; |  | 
| 350 |  | 
| 351   let {Utils} = require("utils"); |  | 
| 352   subscription.title = Utils.getString(subscription.defaults[0] + "Group_title")
     ; |  | 
| 353   return subscription; |  | 
| 354 }; |  | 
| 355 |  | 
| 356 /** |  | 
| 357  * Abstract base class for regular filter subscriptions (both internally and ext
     ernally updated) |  | 
| 358  * @param {String} url    see Subscription() |  | 
| 359  * @param {String} [title]  see Subscription() |  | 
| 360  * @constructor |  | 
| 361  * @augments Subscription |  | 
| 362  */ |  | 
| 363 function RegularSubscription(url, title) |  | 
| 364 { |  | 
| 365   Subscription.call(this, url, title || url); |  | 
| 366 } |  | 
| 367 exports.RegularSubscription = RegularSubscription; |  | 
| 368 |  | 
| 369 RegularSubscription.prototype = |  | 
| 370 { |  | 
| 371   __proto__: Subscription.prototype, |  | 
| 372 |  | 
| 373   _homepage: null, |  | 
| 374   _lastDownload: 0, |  | 
| 375 |  | 
| 376   /** |  | 
| 377    * Filter subscription homepage if known |  | 
| 378    * @type String |  | 
| 379    */ |  | 
| 380   get homepage() |  | 
| 381   { |  | 
| 382     return this._homepage; |  | 
| 383   }, |  | 
| 384   set homepage(value) |  | 
| 385   { |  | 
| 386     if (value != this._homepage) |  | 
| 387     { |  | 
| 388       let oldValue = this._homepage; |  | 
| 389       this._homepage = value; |  | 
| 390       FilterNotifier.triggerListeners("subscription.homepage", this, value, oldV
     alue); |  | 
| 391     } |  | 
| 392     return this._homepage; |  | 
| 393   }, |  | 
| 394 |  | 
| 395   /** |  | 
| 396    * Time of the last subscription download (in seconds since the beginning of t
     he epoch) |  | 
| 397    * @type Number |  | 
| 398    */ |  | 
| 399   get lastDownload() |  | 
| 400   { |  | 
| 401     return this._lastDownload; |  | 
| 402   }, |  | 
| 403   set lastDownload(value) |  | 
| 404   { |  | 
| 405     if (value != this._lastDownload) |  | 
| 406     { |  | 
| 407       let oldValue = this._lastDownload; |  | 
| 408       this._lastDownload = value; |  | 
| 409       FilterNotifier.triggerListeners("subscription.lastDownload", this, value, 
     oldValue); |  | 
| 410     } |  | 
| 411     return this._lastDownload; |  | 
| 412   }, |  | 
| 413 |  | 
| 414   /** |  | 
| 415    * See Subscription.serialize() |  | 
| 416    */ |  | 
| 417   serialize: function(buffer) |  | 
| 418   { |  | 
| 419     Subscription.prototype.serialize.call(this, buffer); |  | 
| 420     if (this._homepage) |  | 
| 421       buffer.push("homepage=" + this._homepage); |  | 
| 422     if (this._lastDownload) |  | 
| 423       buffer.push("lastDownload=" + this._lastDownload); |  | 
| 424   } |  | 
| 425 }; |  | 
| 426 |  | 
| 427 /** |  | 
| 428  * Class for filter subscriptions updated externally (by other extension) |  | 
| 429  * @param {String} url    see Subscription() |  | 
| 430  * @param {String} [title]  see Subscription() |  | 
| 431  * @constructor |  | 
| 432  * @augments RegularSubscription |  | 
| 433  */ |  | 
| 434 function ExternalSubscription(url, title) |  | 
| 435 { |  | 
| 436   RegularSubscription.call(this, url, title); |  | 
| 437 } |  | 
| 438 exports.ExternalSubscription = ExternalSubscription; |  | 
| 439 |  | 
| 440 ExternalSubscription.prototype = |  | 
| 441 { |  | 
| 442   __proto__: RegularSubscription.prototype, |  | 
| 443 |  | 
| 444   /** |  | 
| 445    * See Subscription.serialize() |  | 
| 446    */ |  | 
| 447   serialize: function(buffer) |  | 
| 448   { |  | 
| 449     throw new Error("Unexpected call, external subscriptions should not be seria
     lized"); |  | 
| 450   } |  | 
| 451 }; |  | 
| 452 |  | 
| 453 /** |  | 
| 454  * Class for filter subscriptions updated externally (by other extension) |  | 
| 455  * @param {String} url  see Subscription() |  | 
| 456  * @param {String} [title]  see Subscription() |  | 
| 457  * @constructor |  | 
| 458  * @augments RegularSubscription |  | 
| 459  */ |  | 
| 460 function DownloadableSubscription(url, title) |  | 
| 461 { |  | 
| 462   RegularSubscription.call(this, url, title); |  | 
| 463 } |  | 
| 464 exports.DownloadableSubscription = DownloadableSubscription; |  | 
| 465 |  | 
| 466 DownloadableSubscription.prototype = |  | 
| 467 { |  | 
| 468   __proto__: RegularSubscription.prototype, |  | 
| 469 |  | 
| 470   _downloadStatus: null, |  | 
| 471   _lastCheck: 0, |  | 
| 472   _errors: 0, |  | 
| 473 |  | 
| 474   /** |  | 
| 475    * Status of the last download (ID of a string) |  | 
| 476    * @type String |  | 
| 477    */ |  | 
| 478   get downloadStatus() |  | 
| 479   { |  | 
| 480     return this._downloadStatus; |  | 
| 481   }, |  | 
| 482   set downloadStatus(value) |  | 
| 483   { |  | 
| 484     let oldValue = this._downloadStatus; |  | 
| 485     this._downloadStatus = value; |  | 
| 486     FilterNotifier.triggerListeners("subscription.downloadStatus", this, value, 
     oldValue); |  | 
| 487     return this._downloadStatus; |  | 
| 488   }, |  | 
| 489 |  | 
| 490   /** |  | 
| 491    * Time of the last successful download (in seconds since the beginning of the |  | 
| 492    * epoch). |  | 
| 493    */ |  | 
| 494   lastSuccess: 0, |  | 
| 495 |  | 
| 496   /** |  | 
| 497    * Time when the subscription was considered for an update last time (in secon
     ds |  | 
| 498    * since the beginning of the epoch). This will be used to increase softExpira
     tion |  | 
| 499    * if the user doesn't use Adblock Plus for some time. |  | 
| 500    * @type Number |  | 
| 501    */ |  | 
| 502   get lastCheck() |  | 
| 503   { |  | 
| 504     return this._lastCheck; |  | 
| 505   }, |  | 
| 506   set lastCheck(value) |  | 
| 507   { |  | 
| 508     if (value != this._lastCheck) |  | 
| 509     { |  | 
| 510       let oldValue = this._lastCheck; |  | 
| 511       this._lastCheck = value; |  | 
| 512       FilterNotifier.triggerListeners("subscription.lastCheck", this, value, old
     Value); |  | 
| 513     } |  | 
| 514     return this._lastCheck; |  | 
| 515   }, |  | 
| 516 |  | 
| 517   /** |  | 
| 518    * Hard expiration time of the filter subscription (in seconds since the begin
     ning of the epoch) |  | 
| 519    * @type Number |  | 
| 520    */ |  | 
| 521   expires: 0, |  | 
| 522 |  | 
| 523   /** |  | 
| 524    * Soft expiration time of the filter subscription (in seconds since the begin
     ning of the epoch) |  | 
| 525    * @type Number |  | 
| 526    */ |  | 
| 527   softExpiration: 0, |  | 
| 528 |  | 
| 529   /** |  | 
| 530    * Number of download failures since last success |  | 
| 531    * @type Number |  | 
| 532    */ |  | 
| 533   get errors() |  | 
| 534   { |  | 
| 535     return this._errors; |  | 
| 536   }, |  | 
| 537   set errors(value) |  | 
| 538   { |  | 
| 539     if (value != this._errors) |  | 
| 540     { |  | 
| 541       let oldValue = this._errors; |  | 
| 542       this._errors = value; |  | 
| 543       FilterNotifier.triggerListeners("subscription.errors", this, value, oldVal
     ue); |  | 
| 544     } |  | 
| 545     return this._errors; |  | 
| 546   }, |  | 
| 547 |  | 
| 548   /** |  | 
| 549    * Version of the subscription data retrieved on last successful download |  | 
| 550    * @type Number |  | 
| 551    */ |  | 
| 552   version: 0, |  | 
| 553 |  | 
| 554   /** |  | 
| 555    * Minimal Adblock Plus version required for this subscription |  | 
| 556    * @type String |  | 
| 557    */ |  | 
| 558   requiredVersion: null, |  | 
| 559 |  | 
| 560   /** |  | 
| 561    * Should be true if requiredVersion is higher than current Adblock Plus versi
     on |  | 
| 562    * @type Boolean |  | 
| 563    */ |  | 
| 564   upgradeRequired: false, |  | 
| 565 |  | 
| 566   /** |  | 
| 567    * Number indicating how often the object was downloaded. |  | 
| 568    * @type Number |  | 
| 569    */ |  | 
| 570   downloadCount: 0, |  | 
| 571 |  | 
| 572   /** |  | 
| 573    * See Subscription.serialize() |  | 
| 574    */ |  | 
| 575   serialize: function(buffer) |  | 
| 576   { |  | 
| 577     RegularSubscription.prototype.serialize.call(this, buffer); |  | 
| 578     if (this.downloadStatus) |  | 
| 579       buffer.push("downloadStatus=" + this.downloadStatus); |  | 
| 580     if (this.lastSuccess) |  | 
| 581       buffer.push("lastSuccess=" + this.lastSuccess); |  | 
| 582     if (this.lastCheck) |  | 
| 583       buffer.push("lastCheck=" + this.lastCheck); |  | 
| 584     if (this.expires) |  | 
| 585       buffer.push("expires=" + this.expires); |  | 
| 586     if (this.softExpiration) |  | 
| 587       buffer.push("softExpiration=" + this.softExpiration); |  | 
| 588     if (this.errors) |  | 
| 589       buffer.push("errors=" + this.errors); |  | 
| 590     if (this.version) |  | 
| 591       buffer.push("version=" + this.version); |  | 
| 592     if (this.requiredVersion) |  | 
| 593       buffer.push("requiredVersion=" + this.requiredVersion); |  | 
| 594     if (this.downloadCount) |  | 
| 595       buffer.push("downloadCount=" + this.downloadCount); |  | 
| 596   } |  | 
| 597 }; |  | 
| OLD | NEW | 
|---|