Brion VIBBER has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/181675

Change subject: Update DataHousekeeping for post-CoreData world
......................................................................

Update DataHousekeeping for post-CoreData world

Change-Id: I86d6a4ae85c5491e6d0db51aed0cc4e7a87ee427
---
M MediaWikiKit/MediaWikiKit/MWKDataStore.h
M MediaWikiKit/MediaWikiKit/MWKDataStore.m
M MediaWikiKit/MediaWikiKit/MWKHistoryList.h
M MediaWikiKit/MediaWikiKit/MWKHistoryList.m
M MediaWikiKit/MediaWikiKit/MWKSavedPageList.h
M MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
M Wikipedia.xcodeproj/project.pbxproj
D wikipedia/Housekeeping/CoreDataHousekeeping.m
R wikipedia/Housekeeping/DataHousekeeping.h
A wikipedia/Housekeeping/DataHousekeeping.m
M wikipedia/View Controllers/History/HistoryViewController.m
M wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
M wikipedia/View Controllers/WebView/WebViewController.m
13 files changed, 142 insertions(+), 96 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia 
refs/changes/75/181675/1

diff --git a/MediaWikiKit/MediaWikiKit/MWKDataStore.h 
b/MediaWikiKit/MediaWikiKit/MWKDataStore.h
index 711de67..f4ce2de 100644
--- a/MediaWikiKit/MediaWikiKit/MWKDataStore.h
+++ b/MediaWikiKit/MediaWikiKit/MWKDataStore.h
@@ -63,4 +63,6 @@
 
 -(MWKImageList *)imageListWithArticle:(MWKArticle *)article 
section:(MWKSection *)section;
 
+-(void)iterateOverArticles:(void(^)(MWKArticle *))block;
+
 @end
diff --git a/MediaWikiKit/MediaWikiKit/MWKDataStore.m 
b/MediaWikiKit/MediaWikiKit/MWKDataStore.m
index 05a8476..51b78f2 100644
--- a/MediaWikiKit/MediaWikiKit/MWKDataStore.m
+++ b/MediaWikiKit/MediaWikiKit/MWKDataStore.m
@@ -104,6 +104,11 @@
     return encodedStr;
 }
 
+-(NSString *)stringWithSafeFilename:(NSString *)str
+{
+    return [str 
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+}
+
 -(NSString *)safeFilenameWithImageURL:(NSString *)str
 {
     if ([str hasPrefix:@"http:"]) {
@@ -407,4 +412,28 @@
     }
 }
 
+-(void)iterateOverArticles:(void(^)(MWKArticle *))block
+{
+    NSFileManager *fm = [NSFileManager defaultManager];
+    NSString *articlePath = [self pathForSites];
+    for (NSString *path in [fm enumeratorAtPath:articlePath]) {
+        NSArray *components = [path pathComponents];
+        NSUInteger count = [components count];
+        NSString *filename = components[count - 1];
+        if ([filename isEqualToString:@"Article.plist"]) {
+            NSString *dirname = components[count - 2];
+            NSString *titleText = [self stringWithSafeFilename:dirname];
+
+            NSString *language = components[count - 4];
+            NSString *domain = components[count - 5];
+            
+            MWKSite *site = [[MWKSite alloc] initWithDomain:domain 
language:language];
+            MWKTitle *title = [site titleWithString:titleText];
+            
+            MWKArticle *article = [self articleWithTitle:title];
+            block(article);
+        }
+    }
+}
+
 @end
diff --git a/MediaWikiKit/MediaWikiKit/MWKHistoryList.h 
b/MediaWikiKit/MediaWikiKit/MWKHistoryList.h
index 36606df..4423c85 100644
--- a/MediaWikiKit/MediaWikiKit/MWKHistoryList.h
+++ b/MediaWikiKit/MediaWikiKit/MWKHistoryList.h
@@ -11,7 +11,7 @@
 @class MWKTitle;
 @class MWKHistoryEntry;
 
-@interface MWKHistoryList : MWKDataObject
+@interface MWKHistoryList : MWKDataObject <NSFastEnumeration>
 
 @property (readonly) NSUInteger length;
 @property (readwrite) BOOL dirty;
diff --git a/MediaWikiKit/MediaWikiKit/MWKHistoryList.m 
b/MediaWikiKit/MediaWikiKit/MWKHistoryList.m
index 272effb..fc277fa 100644
--- a/MediaWikiKit/MediaWikiKit/MWKHistoryList.m
+++ b/MediaWikiKit/MediaWikiKit/MWKHistoryList.m
@@ -127,5 +127,12 @@
     return @{@"entries": [NSArray arrayWithArray:array]};
 }
 
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
+                                  objects:(__unsafe_unretained id [])stackbuf
+                                    count:(NSUInteger)len
+{
+    return [entries countByEnumeratingWithState:state objects:stackbuf 
count:len];
+}
+
 
 @end
diff --git a/MediaWikiKit/MediaWikiKit/MWKSavedPageList.h 
b/MediaWikiKit/MediaWikiKit/MWKSavedPageList.h
index 5c81b42..9ec6438 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSavedPageList.h
+++ b/MediaWikiKit/MediaWikiKit/MWKSavedPageList.h
@@ -11,7 +11,7 @@
 @class MWKTitle;
 @class MWKSavedPageEntry;
 
-@interface MWKSavedPageList : MWKDataObject
+@interface MWKSavedPageList : MWKDataObject <NSFastEnumeration>
 
 @property (readonly) NSUInteger length;
 @property (readonly) BOOL dirty;
diff --git a/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m 
b/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
index db4d682..e13e9a1 100644
--- a/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
+++ b/MediaWikiKit/MediaWikiKit/MWKSavedPageList.m
@@ -105,4 +105,11 @@
 }
 
 
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
+                                  objects:(__unsafe_unretained id [])stackbuf
+                                    count:(NSUInteger)len
+{
+    return [entries countByEnumeratingWithState:state objects:stackbuf 
count:len];
+}
+
 @end
diff --git a/Wikipedia.xcodeproj/project.pbxproj 
b/Wikipedia.xcodeproj/project.pbxproj
index 25664e8..b5a0093 100644
--- a/Wikipedia.xcodeproj/project.pbxproj
+++ b/Wikipedia.xcodeproj/project.pbxproj
@@ -106,7 +106,7 @@
                0487048F19F8262600B7D307 /* WikiTextSectionFetcher.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 0487047B19F8262600B7D307 /* 
WikiTextSectionFetcher.m */; };
                0487049019F8262600B7D307 /* WikiTextSectionUploader.m in 
Sources */ = {isa = PBXBuildFile; fileRef = 0487047D19F8262600B7D307 /* 
WikiTextSectionUploader.m */; };
                048A26771906268100395F53 /* PaddedLabel.m in Sources */ = {isa 
= PBXBuildFile; fileRef = 048A26761906268100395F53 /* PaddedLabel.m */; };
-               0493C2CC1952373100EBB973 /* CoreDataHousekeeping.m in Sources 
*/ = {isa = PBXBuildFile; fileRef = 0493C2CB1952373100EBB973 /* 
CoreDataHousekeeping.m */; };
+               0493C2CC1952373100EBB973 /* DataHousekeeping.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 0493C2CB1952373100EBB973 /* DataHousekeeping.m 
*/; };
                0493C2D419526A0100EBB973 /* WikiFont-Glyphs.ttf in Resources */ 
= {isa = PBXBuildFile; fileRef = 0493C2D319526A0100EBB973 /* 
WikiFont-Glyphs.ttf */; };
                0493C2D619526FFE00EBB973 /* WikiFont-Glyphs-iOS.ttf in 
Resources */ = {isa = PBXBuildFile; fileRef = 0493C2D519526FFE00EBB973 /* 
WikiFont-Glyphs-iOS.ttf */; };
                049566C218F5F4CB0058EA12 /* ZeroConfigState.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 049566C118F5F4CB0058EA12 /* ZeroConfigState.m 
*/; };
@@ -462,8 +462,8 @@
                0487047D19F8262600B7D307 /* WikiTextSectionUploader.m */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; 
path = WikiTextSectionUploader.m; sourceTree = "<group>"; };
                048A26751906268100395F53 /* PaddedLabel.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
PaddedLabel.h; sourceTree = "<group>"; };
                048A26761906268100395F53 /* PaddedLabel.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; 
lineEnding = 0; path = PaddedLabel.m; sourceTree = "<group>"; 
xcLanguageSpecificationIdentifier = xcode.lang.objc; };
-               0493C2CA1952373100EBB973 /* CoreDataHousekeeping.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
CoreDataHousekeeping.h; sourceTree = "<group>"; };
-               0493C2CB1952373100EBB973 /* CoreDataHousekeeping.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= CoreDataHousekeeping.m; sourceTree = "<group>"; };
+               0493C2CA1952373100EBB973 /* DataHousekeeping.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
DataHousekeeping.h; sourceTree = "<group>"; };
+               0493C2CB1952373100EBB973 /* DataHousekeeping.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= DataHousekeeping.m; sourceTree = "<group>"; };
                0493C2D219525F8E00EBB973 /* WikiGlyph_Chars_iOS.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WikiGlyph_Chars_iOS.h; sourceTree = "<group>"; };
                0493C2D319526A0100EBB973 /* WikiFont-Glyphs.ttf */ = {isa = 
PBXFileReference; lastKnownFileType = file; path = "WikiFont-Glyphs.ttf"; 
sourceTree = "<group>"; };
                0493C2D519526FFE00EBB973 /* WikiFont-Glyphs-iOS.ttf */ = {isa = 
PBXFileReference; lastKnownFileType = file; path = "WikiFont-Glyphs-iOS.ttf"; 
sourceTree = "<group>"; };
@@ -1225,8 +1225,8 @@
                0493C2C91952373100EBB973 /* Housekeeping */ = {
                        isa = PBXGroup;
                        children = (
-                               0493C2CA1952373100EBB973 /* 
CoreDataHousekeeping.h */,
-                               0493C2CB1952373100EBB973 /* 
CoreDataHousekeeping.m */,
+                               0493C2CA1952373100EBB973 /* DataHousekeeping.h 
*/,
+                               0493C2CB1952373100EBB973 /* DataHousekeeping.m 
*/,
                        );
                        path = Housekeeping;
                        sourceTree = "<group>";
@@ -2189,7 +2189,7 @@
                                0487048D19F8262600B7D307 /* ThumbnailFetcher.m 
in Sources */,
                                04530AF51935BF4D00022512 /* 
ModalMenuAndContentViewController.m in Sources */,
                                041A3B6218E11ED90079FF1C /* 
LanguagesViewController.m in Sources */,
-                               0493C2CC1952373100EBB973 /* 
CoreDataHousekeeping.m in Sources */,
+                               0493C2CC1952373100EBB973 /* DataHousekeeping.m 
in Sources */,
                                043F18E118D9691D00D8489A /* 
TopActionSheetLabel.m in Sources */,
                                0412CC621925366C0010E616 /* 
RootViewController.m in Sources */,
                                04272E7B1940EEBC00CC682F /* AssetsFile.m in 
Sources */,
diff --git a/wikipedia/Housekeeping/CoreDataHousekeeping.m 
b/wikipedia/Housekeeping/CoreDataHousekeeping.m
deleted file mode 100644
index 1f468c5..0000000
--- a/wikipedia/Housekeeping/CoreDataHousekeeping.m
+++ /dev/null
@@ -1,70 +0,0 @@
-//  Created by Monte Hurd on 6/18/14.
-//  Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
-
-#import "CoreDataHousekeeping.h"
-#import "NSDate-Utilities.h"
-
-@interface CoreDataHousekeeping (){
-}
-
-@end
-
-@implementation CoreDataHousekeeping
-
-- (instancetype)init
-{
-    self = [super init];
-    if (self) {
-    }
-    return self;
-}
-
--(void)performHouseKeeping
-{
-    /*
-    [context_ performBlockAndWait:^(){
-        
-        [self removeUnsavedUnhistoriedArticles];
-        [self removeUnsavedArticleSections];
-
-        NSError *error = nil;
-        [context_ save:&error];
-        if (error){
-            NSLog(@"ImageHousekeeping error = %@", error);
-        }else{
-            [self removeUnusedImages];
-            
-            error = nil;
-            [context_ save:&error];
-            if (error) NSLog(@"ImageHousekeeping error = %@", error);
-        }
-
-    }];
-     */
-}
-
--(void)removeUnsavedUnhistoriedArticles
-{
-    /*
-    // Removes articles which have neither saved nor history records.
-    // The user can remove items from both saved pages and history.
-    // If they've removed this article from both, not need to keep its
-    // data.
-
-    NSEntityDescription *entity = [NSEntityDescription entityForName: 
@"Article" inManagedObjectContext: context_];
-    
-    NSFetchRequest *request = [[NSFetchRequest alloc] init];
-    [request setEntity:entity];
-    // To-many query: http://stackoverflow.com/a/1195519
-    [request setPredicate:[NSPredicate predicateWithFormat:@"history.@count == 
0 AND saved.@count == 0"]];
-    
-    NSError *error = nil;
-    NSArray *articles = [context_ executeFetchRequest:request error:&error];
-    for (Article *article in articles) {
-        NSLog(@"removing article w/o history or save records = %@", 
article.title);
-        if (article) [context_ deleteObject:article];
-    }
-     */
-}
-
-@end
diff --git a/wikipedia/Housekeeping/CoreDataHousekeeping.h 
b/wikipedia/Housekeeping/DataHousekeeping.h
similarity index 83%
rename from wikipedia/Housekeeping/CoreDataHousekeeping.h
rename to wikipedia/Housekeeping/DataHousekeeping.h
index e933a4c..c1074aa 100644
--- a/wikipedia/Housekeeping/CoreDataHousekeeping.h
+++ b/wikipedia/Housekeeping/DataHousekeeping.h
@@ -3,7 +3,7 @@
 
 #import <Foundation/Foundation.h>
 
-@interface CoreDataHousekeeping : NSObject
+@interface DataHousekeeping : NSObject
 
 -(void)performHouseKeeping;
 
diff --git a/wikipedia/Housekeeping/DataHousekeeping.m 
b/wikipedia/Housekeeping/DataHousekeeping.m
new file mode 100644
index 0000000..f227a8a
--- /dev/null
+++ b/wikipedia/Housekeeping/DataHousekeeping.m
@@ -0,0 +1,71 @@
+//  Created by Monte Hurd on 6/18/14.
+//  Copyright (c) 2014 Wikimedia Foundation. Provided under MIT-style license; 
please copy and modify!
+
+#import "DataHousekeeping.h"
+#import "NSDate-Utilities.h"
+
+#import "SessionSingleton.h"
+
+#define MAX_HISTORY_ENTRIES 100
+
+@interface DataHousekeeping (){
+}
+
+@end
+
+@implementation DataHousekeeping
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+    }
+    return self;
+}
+
+-(void)performHouseKeeping
+{
+    
+    SessionSingleton *session = [SessionSingleton sharedInstance];
+    MWKDataStore *dataStore = session.dataStore;
+    MWKUserDataStore *userDataStore = session.userDataStore;
+    MWKHistoryList *historyList = userDataStore.historyList;
+    MWKSavedPageList *savedPageList = userDataStore.savedPageList;
+    
+    
+    NSMutableDictionary *articlesToSave = [@{} mutableCopy];
+
+    // Keep all saved pages
+    for (MWKSavedPageEntry *entry in savedPageList) {
+        articlesToSave[entry.title] = entry.title;
+    }
+    
+    // Keep most recent MAX_HISTORY_ENTRIES history entries
+    NSMutableArray *historyEntriesToPrune = [@[] mutableCopy];
+    int n = 0;
+    for (MWKHistoryEntry *entry in historyList) {
+        if (n++ < MAX_HISTORY_ENTRIES) {
+            // save!
+            articlesToSave[entry.title] = entry.title;
+        } else {
+            // prune!
+            [historyEntriesToPrune addObject:entry];
+        }
+    }
+    for (MWKHistoryEntry *entry in historyEntriesToPrune) {
+        [historyList removeEntry:entry];
+    }
+    [userDataStore save];
+    
+    // Iterate through all articles and de-cache the ones that aren't on the 
keep list
+    // Cached metadata, section text, and images will be removed along with 
their articles.
+    [dataStore iterateOverArticles:^(MWKArticle *article) {
+        if (articlesToSave[article.title]) {
+            // don't kill it!
+        } else {
+            NSLog(@"Pruning unsaved article %@ %@", 
article.title.site.language, article.title.prefixedText);
+            [article remove];
+        }
+    }];
+}
+@end
diff --git a/wikipedia/View Controllers/History/HistoryViewController.m 
b/wikipedia/View Controllers/History/HistoryViewController.m
index f813b08..e3f6b30 100644
--- a/wikipedia/View Controllers/History/HistoryViewController.m
+++ b/wikipedia/View Controllers/History/HistoryViewController.m
@@ -17,7 +17,7 @@
 #import "PaddedLabel.h"
 #import "MenuButton.h"
 #import "TopMenuViewController.h"
-#import "CoreDataHousekeeping.h"
+#import "DataHousekeeping.h"
 #import "NSObject+ConstraintsScale.h"
 #import "SessionSingleton.h"
 
@@ -249,8 +249,8 @@
     [userDataStore save];
 
     // Remove any orphaned images.
-    CoreDataHousekeeping *imageHousekeeping = [[CoreDataHousekeeping alloc] 
init];
-    [imageHousekeeping performHouseKeeping];
+    DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
+    [dataHouseKeeping performHouseKeeping];
     
     [NAV loadTodaysArticleIfNoCoreDataForCurrentArticle];
 }
@@ -477,8 +477,8 @@
     }
 
     // Remove any orphaned images.
-    CoreDataHousekeeping *imageHousekeeping = [[CoreDataHousekeeping alloc] 
init];
-    [imageHousekeeping performHouseKeeping];
+    DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
+    [dataHouseKeeping performHouseKeeping];
     
     [NAV loadTodaysArticleIfNoCoreDataForCurrentArticle];
 }
@@ -519,8 +519,8 @@
     [userDataStore save];
 
     // Remove any orphaned images.
-    CoreDataHousekeeping *imageHousekeeping = [[CoreDataHousekeeping alloc] 
init];
-    [imageHousekeeping performHouseKeeping];
+    DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
+    [dataHouseKeeping performHouseKeeping];
     
     [self.historyDataArray removeAllObjects];
     [self.tableView reloadData];
diff --git a/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m 
b/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
index 5db89ce..eb45318 100644
--- a/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
+++ b/wikipedia/View Controllers/SavedPages/SavedPagesViewController.m
@@ -14,7 +14,7 @@
 #import "UIViewController+ModalPop.h"
 #import "MenuButton.h"
 #import "TopMenuViewController.h"
-#import "CoreDataHousekeeping.h"
+#import "DataHousekeeping.h"
 #import "SavedPagesFunnel.h"
 #import "NSObject+ConstraintsScale.h"
 #import "PaddedLabel.h"
@@ -272,8 +272,8 @@
     }
 
     // Remove any orphaned images.
-    CoreDataHousekeeping *imageHousekeeping = [[CoreDataHousekeeping alloc] 
init];
-    [imageHousekeeping performHouseKeeping];
+    DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
+    [dataHouseKeeping performHouseKeeping];
     
     [NAV loadTodaysArticleIfNoCoreDataForCurrentArticle];
 }
@@ -284,8 +284,8 @@
     [userDataStore save];
 
     // Remove any orphaned images.
-    CoreDataHousekeeping *imageHousekeeping = [[CoreDataHousekeeping alloc] 
init];
-    [imageHousekeeping performHouseKeeping];
+    DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
+    [dataHouseKeeping performHouseKeeping];
     
     [self.tableView reloadData];
     
diff --git a/wikipedia/View Controllers/WebView/WebViewController.m 
b/wikipedia/View Controllers/WebView/WebViewController.m
index 8437f63..1df537e 100644
--- a/wikipedia/View Controllers/WebView/WebViewController.m
+++ b/wikipedia/View Controllers/WebView/WebViewController.m
@@ -35,7 +35,7 @@
 #import "MWKSection+DisplayHtml.h"
 #import "EditFunnel.h"
 #import "ProtectedEditAttemptFunnel.h"
-#import "CoreDataHousekeeping.h"
+#import "DataHousekeeping.h"
 #import "NSDate-Utilities.h"
 #import "AccountCreationViewController.h"
 #import "OnboardingViewController.h"
@@ -345,8 +345,8 @@
     NSLog(@"daysSinceLastHouseKeeping = %ld", (long)daysSinceLastHouseKeeping);
     if (daysSinceLastHouseKeeping > 1) {
         NSLog(@"Performing housekeeping...");
-        CoreDataHousekeeping *imageHousekeeping = [[CoreDataHousekeeping 
alloc] init];
-        [imageHousekeeping performHouseKeeping];
+        DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
+        [dataHouseKeeping performHouseKeeping];
         [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] 
forKey:@"LastHousekeepingDate"];
         [[NSUserDefaults standardUserDefaults] synchronize];
     }
@@ -1294,8 +1294,8 @@
     [ROOT pushViewController:createAcctVC animated:YES];
     */
     
-    //CoreDataHousekeeping *imageHousekeeping = [[CoreDataHousekeeping alloc] 
init];
-    //[imageHousekeeping performHouseKeeping];
+    //DataHousekeeping *dataHouseKeeping = [[DataHousekeeping alloc] init];
+    //[dataHouseKeeping performHouseKeeping];
     
     // Do not remove the following commented toggle. It's for testing W0 stuff.
     //[session.zeroConfigState toggleFakeZeroOn];

-- 
To view, visit https://gerrit.wikimedia.org/r/181675
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I86d6a4ae85c5491e6d0db51aed0cc4e7a87ee427
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Brion VIBBER <br...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to