| Index: lib/filterStorage.js | 
| =================================================================== | 
| --- a/lib/filterStorage.js | 
| +++ b/lib/filterStorage.js | 
| @@ -192,20 +192,25 @@ | 
|  | 
| /** | 
| * Replaces the list of filters in a subscription with a new list. | 
| * @param {Subscription} subscription The subscription to be updated. | 
| * @param {Array.<Filter>} filters The new list of filters. | 
| */ | 
| updateSubscriptionFilters(subscription, filters) | 
| { | 
| -    disconnectSubscriptionFilters(subscription); | 
| -    let oldFilters = subscription.filters; | 
| -    subscription.filters = filters; | 
| -    connectSubscriptionFilters(subscription); | 
| +    let oldFilters = [...subscription.filters()]; | 
| +    disconnectSubscriptionFilters(subscription, oldFilters); | 
| +    subscription.clearFilters(); | 
| + | 
| +    for (let filter of filters) | 
| +      subscription.addFilter(filter); | 
| + | 
| +    connectSubscriptionFilters(subscription, filters); | 
| + | 
| filterNotifier.emit("subscription.updated", subscription, oldFilters); | 
| } | 
|  | 
| /** | 
| * Adds a user-defined filter to the storage. | 
| * @param {Filter} filter | 
| * @param {?SpecialSubscription} [subscription] The subscription that the | 
| *   filter should be added to. | 
| @@ -231,20 +236,20 @@ | 
| { | 
| // No group for this filter exists, create one | 
| subscription = SpecialSubscription.createForFilter(filter); | 
| this.addSubscription(subscription); | 
| return; | 
| } | 
|  | 
| if (typeof position == "undefined") | 
| -      position = subscription.filters.length; | 
| +      position = subscription.filterCount; | 
|  | 
| filter.addSubscription(subscription); | 
| -    subscription.filters.splice(position, 0, filter); | 
| +    subscription.insertFilterAt(filter, position); | 
| filterNotifier.emit("filter.added", filter, subscription, position); | 
| } | 
|  | 
| /** | 
| * Removes a user-defined filter from the storage. | 
| * @param {Filter} filter | 
| * @param {?SpecialSubscription} [subscription] The subscription that the | 
| *   filter should be removed from. If not specified, the filter will be | 
| @@ -263,31 +268,32 @@ | 
| if (currentSubscription instanceof SpecialSubscription) | 
| { | 
| let positions = []; | 
| if (typeof position == "undefined") | 
| { | 
| let index = -1; | 
| do | 
| { | 
| -            index = currentSubscription.filters.indexOf(filter, index + 1); | 
| +            index = currentSubscription.searchFilter(filter, index + 1); | 
| if (index >= 0) | 
| positions.push(index); | 
| } while (index >= 0); | 
| } | 
| else | 
| positions.push(position); | 
|  | 
| for (let j = positions.length - 1; j >= 0; j--) | 
| { | 
| let currentPosition = positions[j]; | 
| -          if (currentSubscription.filters[currentPosition] == filter) | 
| +          let currentFilter = currentSubscription.filterAt(currentPosition); | 
| +          if (currentFilter && currentFilter.text == filter.text) | 
| { | 
| -            currentSubscription.filters.splice(currentPosition, 1); | 
| -            if (currentSubscription.filters.indexOf(filter) < 0) | 
| +            currentSubscription.deleteFilterAt(currentPosition); | 
| +            if (currentSubscription.searchFilter(filter) < 0) | 
| filter.removeSubscription(currentSubscription); | 
| filterNotifier.emit("filter.removed", filter, currentSubscription, | 
| currentPosition); | 
| } | 
| } | 
| } | 
| } | 
| } | 
| @@ -297,29 +303,30 @@ | 
| * @param {Filter} filter | 
| * @param {SpecialSubscription} subscription The subscription where the | 
| *   filter is located. | 
| * @param {number} oldPosition The current position of the filter. | 
| * @param {number} newPosition The new position of the filter. | 
| */ | 
| moveFilter(filter, subscription, oldPosition, newPosition) | 
| { | 
| -    if (!(subscription instanceof SpecialSubscription) || | 
| -        subscription.filters[oldPosition] != filter) | 
| -    { | 
| +    if (!(subscription instanceof SpecialSubscription)) | 
| return; | 
| -    } | 
| + | 
| +    let currentFilter = subscription.filterAt(oldPosition); | 
| +    if (!currentFilter || currentFilter.text != filter.text) | 
| +      return; | 
|  | 
| newPosition = Math.min(Math.max(newPosition, 0), | 
| -                           subscription.filters.length - 1); | 
| +                           subscription.filterCount - 1); | 
| if (oldPosition == newPosition) | 
| return; | 
|  | 
| -    subscription.filters.splice(oldPosition, 1); | 
| -    subscription.filters.splice(newPosition, 0, filter); | 
| +    subscription.deleteFilterAt(oldPosition); | 
| +    subscription.insertFilterAt(filter, newPosition); | 
| filterNotifier.emit("filter.moved", filter, subscription, oldPosition, | 
| newPosition); | 
| } | 
|  | 
| /** | 
| * Increases the hit count for a filter by one. | 
| * @param {Filter} filter | 
| */ | 
| @@ -471,17 +478,17 @@ | 
| *exportData() | 
| { | 
| // Do not persist external subscriptions | 
| let subscriptions = []; | 
| for (let subscription of this.subscriptions()) | 
| { | 
| if (!(subscription instanceof ExternalSubscription) && | 
| !(subscription instanceof SpecialSubscription && | 
| -            subscription.filters.length == 0)) | 
| +            subscription.filterCount == 0)) | 
| { | 
| subscriptions.push(subscription); | 
| } | 
| } | 
|  | 
| yield "# Adblock Plus preferences"; | 
| yield "version=" + this.formatVersion; | 
|  | 
| @@ -492,17 +499,17 @@ | 
| { | 
| yield* subscription.serialize(); | 
| yield* subscription.serializeFilters(); | 
| } | 
|  | 
| // Save filter data | 
| for (let subscription of subscriptions) | 
| { | 
| -      for (let filter of subscription.filters) | 
| +      for (let filter of subscription.filters()) | 
| { | 
| if (!saved.has(filter.text)) | 
| { | 
| yield* filter.serialize(); | 
| saved.add(filter.text); | 
| } | 
| } | 
| } | 
| @@ -642,31 +649,37 @@ | 
| let filterStorage = new FilterStorage(); | 
|  | 
| exports.filterStorage = filterStorage; | 
|  | 
| /** | 
| * Connects a subscription to its filters without any notifications. | 
| * @param {Subscription} subscription The subscription that should be | 
| *   connected to its filters. | 
| + * @param {?Array.<Filter>} [filters] A list of filters to which the | 
| + *   subscription should be connected. If this is not given, the subscription | 
| + *   is connected to its own filters. | 
| */ | 
| -function connectSubscriptionFilters(subscription) | 
| +function connectSubscriptionFilters(subscription, filters) | 
| { | 
| if (!filterStorage.knownSubscriptions.has(subscription.url)) | 
| return; | 
|  | 
| -  for (let filter of subscription.filters) | 
| +  for (let filter of filters || subscription.filters()) | 
| filter.addSubscription(subscription); | 
| } | 
|  | 
| /** | 
| * Disconnects a subscription from its filters without any notifications. | 
| * @param {Subscription} subscription The subscription that should be | 
| *   disconnected from its filters. | 
| + * @param {?Array.<Filter>} [filters] A list of filters from which the | 
| + *   subscription should be disconnected. If this is not given, the | 
| + *   subscription is disconnected from its own filters. | 
| */ | 
| -function disconnectSubscriptionFilters(subscription) | 
| +function disconnectSubscriptionFilters(subscription, filters) | 
| { | 
| if (!filterStorage.knownSubscriptions.has(subscription.url)) | 
| return; | 
|  | 
| -  for (let filter of subscription.filters) | 
| +  for (let filter of filters || subscription.filters()) | 
| filter.removeSubscription(subscription); | 
| } | 
|  |