You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/01/24 19:41:51 UTC

[3/3] ios commit: Fix CB-2271 - Multiple Cordova Views.

Updated Branches:
  refs/heads/master 41955f942 -> be6e4d3cc


Fix CB-2271 - Multiple Cordova Views.

The problem was that multiple views loading at the same time would end
up with the same User-Agent. This change adds a locking mechanism around
User-Agent setting, so that multiple views will load in serial instead
at the same time.

Adds a unit test that failed before the fix, but now passes consistently

https://issues.apache.org/jira/browse/CB-2271


Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/be6e4d3c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/be6e4d3c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/be6e4d3c

Branch: refs/heads/master
Commit: be6e4d3cce3b5d3d5682b62a63d0e402a059e7a8
Parents: b8f7515
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Jan 24 10:55:55 2013 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Thu Jan 24 13:40:48 2013 -0500

----------------------------------------------------------------------
 CordovaLib/Classes/CDVInAppBrowser.h               |    3 +-
 CordovaLib/Classes/CDVInAppBrowser.m               |   57 +++++----
 CordovaLib/Classes/CDVUserAgentUtil.h              |    4 +-
 CordovaLib/Classes/CDVUserAgentUtil.m              |   64 ++++++++--
 CordovaLib/Classes/CDVViewController.m             |   35 ++++--
 CordovaLibTests/CDVUserAgentTest.m                 |   93 +++++++++++++++
 .../CordovaTests.xcodeproj/project.pbxproj         |    4 +
 7 files changed, 211 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVInAppBrowser.h b/CordovaLib/Classes/CDVInAppBrowser.h
index a36a62a..9ff460a 100644
--- a/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/CordovaLib/Classes/CDVInAppBrowser.h
@@ -31,7 +31,7 @@
 
 @end
 
-@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>{}
+@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>
 
 @property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
 @property (nonatomic, copy) NSString* callbackId;
@@ -46,6 +46,7 @@
     NSURL* _requestedURL;
     NSString* _userAgent;
     NSString* _prevUserAgent;
+    NSInteger _userAgentLockToken;
 }
 
 @property (nonatomic, strong) IBOutlet UIWebView* webView;

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVInAppBrowser.m b/CordovaLib/Classes/CDVInAppBrowser.m
index fde68b8..45bf705 100644
--- a/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/CordovaLib/Classes/CDVInAppBrowser.m
@@ -235,27 +235,23 @@
 
     webViewBounds.size.height -= FOOTER_HEIGHT;
 
-    if (!self.webView) {
-        [CDVUserAgentUtil setUserAgent:_userAgent];
-
-        self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
-        self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
-
-        [self.view addSubview:self.webView];
-        [self.view sendSubviewToBack:self.webView];
-
-        self.webView.delegate = self;
-        self.webView.backgroundColor = [UIColor whiteColor];
-
-        self.webView.clearsContextBeforeDrawing = YES;
-        self.webView.clipsToBounds = YES;
-        self.webView.contentMode = UIViewContentModeScaleToFill;
-        self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
-        self.webView.multipleTouchEnabled = YES;
-        self.webView.opaque = YES;
-        self.webView.scalesPageToFit = NO;
-        self.webView.userInteractionEnabled = YES;
-    }
+    self.webView = [[UIWebView alloc] initWithFrame:webViewBounds];
+    self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
+
+    [self.view addSubview:self.webView];
+    [self.view sendSubviewToBack:self.webView];
+
+    self.webView.delegate = self;
+    self.webView.backgroundColor = [UIColor whiteColor];
+
+    self.webView.clearsContextBeforeDrawing = YES;
+    self.webView.clipsToBounds = YES;
+    self.webView.contentMode = UIViewContentModeScaleToFill;
+    self.webView.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+    self.webView.multipleTouchEnabled = YES;
+    self.webView.opaque = YES;
+    self.webView.scalesPageToFit = NO;
+    self.webView.userInteractionEnabled = YES;
 
     self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
     self.spinner.alpha = 1.000;
@@ -383,6 +379,11 @@
 
 - (void)close
 {
+    if (_userAgentLockToken != 0) {
+        [CDVUserAgentUtil releaseLock:_userAgentLockToken];
+        _userAgentLockToken = 0;
+    }
+
     if ([self respondsToSelector:@selector(presentingViewController)]) {
         [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
     } else {
@@ -397,9 +398,17 @@
 - (void)navigateTo:(NSURL*)url
 {
     NSURLRequest* request = [NSURLRequest requestWithURL:url];
-
-    [self.webView loadRequest:request];
     _requestedURL = url;
+
+    if (_userAgentLockToken != 0) {
+        [self.webView loadRequest:request];
+    } else {
+        [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
+                _userAgentLockToken = lockToken;
+                [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
+                [self.webView loadRequest:request];
+            }];
+    }
 }
 
 - (void)goBack:(id)sender
@@ -456,7 +465,7 @@
     // More info at https://issues.apache.org/jira/browse/CB-2225
     BOOL isPDF = [@"true" isEqualToString:[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]];
     if (isPDF) {
-        [CDVUserAgentUtil setUserAgent:_prevUserAgent];
+        [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
     }
 
     if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStop:)]) {

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVUserAgentUtil.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUserAgentUtil.h b/CordovaLib/Classes/CDVUserAgentUtil.h
index fdea596..662b674 100644
--- a/CordovaLib/Classes/CDVUserAgentUtil.h
+++ b/CordovaLib/Classes/CDVUserAgentUtil.h
@@ -21,5 +21,7 @@
 
 @interface CDVUserAgentUtil : NSObject
 + (NSString*)originalUserAgent;
-+ (void)setUserAgent:(NSString*)newValue;
++ (void)acquireLock:(void (^)(NSInteger lockToken))block;
++ (void)releaseLock:(NSInteger)lockToken;
++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken;
 @end

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVUserAgentUtil.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVUserAgentUtil.m b/CordovaLib/Classes/CDVUserAgentUtil.m
index ac5c994..e2baef0 100644
--- a/CordovaLib/Classes/CDVUserAgentUtil.m
+++ b/CordovaLib/Classes/CDVUserAgentUtil.m
@@ -21,9 +21,16 @@
 
 #import <UIKit/UIKit.h>
 
+// #define VerboseLog NSLog
+#define VerboseLog(...) do {} while (0)
+
+static NSString* const kCdvUserAgentKey = @"Cordova-User-Agent";
+static NSString* const kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
+
 static NSString* gOriginalUserAgent = nil;
-static NSString* kCdvUserAgentKey = @"Cordova-User-Agent";
-static NSString* kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
+static NSInteger gNextLockToken = 0;
+static NSInteger gCurrentLockToken = 0;
+static NSMutableArray* gPendingSetUserAgentBlocks = nil;
 
 @implementation CDVUserAgentUtil
 
@@ -55,22 +62,55 @@ static NSString* kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version";
     return gOriginalUserAgent;
 }
 
-+ (void)setUserAgent:(NSString*)newValue
++ (void)onAppLocaleDidChange:(NSNotification*)notification
+{
+    // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens.
+    // Maybe use the PDF bug (noted in setUserAgent:).
+    gOriginalUserAgent = nil;
+}
+
++ (void)acquireLock:(void (^)(NSInteger lockToken))block
+{
+    if (gCurrentLockToken == 0) {
+        gCurrentLockToken = ++gNextLockToken;
+        VerboseLog(@"Gave lock %d", gCurrentLockToken);
+        block(gCurrentLockToken);
+    } else {
+        if (gPendingSetUserAgentBlocks == nil) {
+            gPendingSetUserAgentBlocks = [[NSMutableArray alloc] initWithCapacity:4];
+        }
+        VerboseLog(@"Waiting for lock");
+        [gPendingSetUserAgentBlocks addObject:block];
+    }
+}
+
++ (void)releaseLock:(NSInteger)lockToken
 {
+    NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken);
+
+    VerboseLog(@"Released lock %d", lockToken);
+    if ([gPendingSetUserAgentBlocks count] > 0) {
+        void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0];
+        [gPendingSetUserAgentBlocks removeObjectAtIndex:0];
+        gCurrentLockToken = ++gNextLockToken;
+        NSLog (@"Gave lock %d", gCurrentLockToken);
+        block(gCurrentLockToken);
+    } else {
+        gCurrentLockToken = 0;
+    }
+}
+
++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken
+{
+    NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken);
+    VerboseLog(@"User-Agent set to: %@", value);
+
     // Setting the UserAgent must occur before a UIWebView is instantiated.
     // It is read per instantiation, so it does not affect previously created views.
     // Except! When a PDF is loaded, all currently active UIWebViews reload their
     // User-Agent from the NSUserDefaults some time after the DidFinishLoad of the PDF bah!
-    NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:newValue, @"UserAgent", nil];
-
+    NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:value, @"UserAgent", nil];
     [[NSUserDefaults standardUserDefaults] registerDefaults:dict];
 }
 
-+ (void)onAppLocaleDidChange:(NSNotification*)notification
-{
-    // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens.
-    // Maybe use the PDF bug (noted in setUserAgent:).
-    gOriginalUserAgent = nil;
-}
-
 @end

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVViewController.m b/CordovaLib/Classes/CDVViewController.m
index ef91f5f..36ae785 100644
--- a/CordovaLib/Classes/CDVViewController.m
+++ b/CordovaLib/Classes/CDVViewController.m
@@ -26,7 +26,9 @@
 
 #define degreesToRadian(x) (M_PI * (x) / 180.0)
 
-@interface CDVViewController ()
+@interface CDVViewController () {
+    NSInteger _userAgentLockToken;
+}
 
 @property (nonatomic, readwrite, strong) NSXMLParser* configParser;
 @property (nonatomic, readwrite, strong) NSDictionary* settings;
@@ -303,14 +305,17 @@
     }
 
     // /////////////////
-
-    if (!loadErr) {
-        NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
-        [self.webView loadRequest:appReq];
-    } else {
-        NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
-        [self.webView loadHTMLString:html baseURL:nil];
-    }
+    [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
+            _userAgentLockToken = lockToken;
+            [CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken];
+            if (!loadErr) {
+                NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
+                [self.webView loadRequest:appReq];
+            } else {
+                NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
+                [self.webView loadHTMLString:html baseURL:nil];
+            }
+        }];
 }
 
 - (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
@@ -430,8 +435,6 @@
     webViewBounds.origin = self.view.bounds.origin;
 
     if (!self.webView) {
-        [CDVUserAgentUtil setUserAgent:self.userAgent];
-
         self.webView = [self newCordovaViewWithFrame:webViewBounds];
         self.webView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
 
@@ -496,6 +499,11 @@
  */
 - (void)webViewDidFinishLoad:(UIWebView*)theWebView
 {
+    if (_userAgentLockToken != 0) {
+        [CDVUserAgentUtil releaseLock:_userAgentLockToken];
+        _userAgentLockToken = 0;
+    }
+
     /*
      * Hide the Top Activity THROBBER in the Battery Bar
      */
@@ -521,6 +529,11 @@
 
 - (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
 {
+    if (_userAgentLockToken != 0) {
+        [CDVUserAgentUtil releaseLock:_userAgentLockToken];
+        _userAgentLockToken = 0;
+    }
+
     NSLog(@"Failed to load webpage with error: %@", [error localizedDescription]);
 
     /*

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLibTests/CDVUserAgentTest.m
----------------------------------------------------------------------
diff --git a/CordovaLibTests/CDVUserAgentTest.m b/CordovaLibTests/CDVUserAgentTest.m
new file mode 100644
index 0000000..dcbf30a
--- /dev/null
+++ b/CordovaLibTests/CDVUserAgentTest.m
@@ -0,0 +1,93 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <SenTestingKit/SenTestingKit.h>
+
+#import "CDVWebViewTest.h"
+#import "CDVViewController.h"
+#import "AppDelegate.h"
+
+@interface CDVUserAgentTestViewController : UIViewController
+@property (nonatomic) CDVViewController* vc1;
+@property (nonatomic) CDVViewController* vc2;
+@end
+
+@implementation CDVUserAgentTestViewController
+@synthesize vc1 = _vc1, vc2 = _vc2;
+
+- (void)loadView
+{
+    _vc1 = [[CDVViewController alloc] init];
+    _vc1.wwwFolderName = @"www";
+    _vc1.startPage = @"index.html";
+    [self addChildViewController:_vc1];
+
+    _vc2 = [[CDVViewController alloc] init];
+    _vc2.wwwFolderName = @"www";
+    _vc2.startPage = @"index.html";
+    [self addChildViewController:_vc2];
+
+    CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
+    UIView* contentView = [[UIView alloc] initWithFrame:applicationFrame];
+
+    CGRect sub1, sub2;
+    CGRectDivide(applicationFrame, &sub1, &sub2, applicationFrame.size.height / 2, CGRectMinYEdge);
+    [_vc1.view setBounds:sub1];
+    [_vc2.view setBounds:sub2];
+
+    [contentView addSubview:_vc1.view];
+    [contentView addSubview:_vc2.view];
+
+    self.view = contentView;
+}
+
+@end
+
+@interface CDVUserAgentTest : CDVWebViewTest
+@end
+
+@implementation CDVUserAgentTest
+
+- (void)setUp
+{
+    [super setUp];
+}
+
+- (void)tearDown
+{
+    [super tearDown];
+}
+
+- (void)testMultipleViews
+{
+    CDVUserAgentTestViewController* rootVc = [[CDVUserAgentTestViewController alloc] init];
+
+    self.appDelegate.window.rootViewController = rootVc;
+
+    NSString* getUserAgentCode = @"navigator.userAgent";
+    [self waitForConditionName:@"getting user-agents" block:^{
+            return (BOOL)(rootVc.vc1.webView.request != nil && rootVc.vc2.webView.request != nil);
+        }];
+    NSString* ua1 = [rootVc.vc1.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
+    NSString* ua2 = [rootVc.vc2.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
+
+    STAssertFalse([ua1 isEqual:ua2], @"User-Agents should be different.");
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/be6e4d3c/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj b/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
index 02490b5..f29ac11 100644
--- a/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
+++ b/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
@@ -43,6 +43,7 @@
 		68A32D7F141030F3006B237C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AC141002F100DF4CF2 /* Foundation.framework */; };
 		EB3B34E9161B5532003DBE7D /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3B34E6161B5454003DBE7D /* libCordova.a */; };
 		EB89634A15FE66EA00E12277 /* CDVInvokedUrlCommandTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */; };
+		EB96677216ADBCF500D86CDF /* CDVUserAgentTest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */; };
 		EBA3554615A731F100F4DE24 /* CDVFakeFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA3554515A731F100F4DE24 /* CDVFakeFileManager.m */; };
 		EBA3556F15ABD0C900F4DE24 /* CDVFileTransferTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA3556E15ABD0C900F4DE24 /* CDVFileTransferTests.m */; };
 		F8EB14D1165FFD3200616F39 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = F8EB14D0165FFD3200616F39 /* config.xml */; };
@@ -105,6 +106,7 @@
 		68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
 		EB37018115D18B2D00BEBC43 /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = ../CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
 		EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVInvokedUrlCommandTests.m; sourceTree = "<group>"; };
+		EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUserAgentTest.m; sourceTree = "<group>"; };
 		EBA3550F15A5F18900F4DE24 /* CDVWebViewTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDVWebViewTest.h; sourceTree = "<group>"; };
 		EBA3554415A731F100F4DE24 /* CDVFakeFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVFakeFileManager.h; sourceTree = "<group>"; };
 		EBA3554515A731F100F4DE24 /* CDVFakeFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVFakeFileManager.m; sourceTree = "<group>"; };
@@ -237,6 +239,7 @@
 		EB3B34F4161B585D003DBE7D /* CordovaLibTests */ = {
 			isa = PBXGroup;
 			children = (
+				EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */,
 				EBA3554415A731F100F4DE24 /* CDVFakeFileManager.h */,
 				EBA3554515A731F100F4DE24 /* CDVFakeFileManager.m */,
 				EBA3550F15A5F18900F4DE24 /* CDVWebViewTest.h */,
@@ -417,6 +420,7 @@
 				EBA3554615A731F100F4DE24 /* CDVFakeFileManager.m in Sources */,
 				EBA3556F15ABD0C900F4DE24 /* CDVFileTransferTests.m in Sources */,
 				EB89634A15FE66EA00E12277 /* CDVInvokedUrlCommandTests.m in Sources */,
+				EB96677216ADBCF500D86CDF /* CDVUserAgentTest.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};