Snapshot idea/135.1286 from git://git.jetbrains.org/idea/community.git

a223e43: fixed ideaIC mac sit and dmg
fc7066d: fixed issue with mac launcher location and classpath
4c0f217: IDEA-128247 Make sure OS X Developer ID signature is made on OS X 10.9
53ea02e: Gradle: use application level for gradle system setting related issue: IDEA-128535 Global Gradle Settings aren't global (cherry picked from commit 4e894cc)
5fbdf04: external system: add system.settings title (e.g. Global Gradle settings) only if the external system provides system level settings (cherry picked from commit 98ce798)

Change-Id: I84bf0124f530a3c34667e0a5d2bee1a322e7d9f8
diff --git a/build/conf/mac/Contents/Info.plist b/build/conf/mac/Contents/Info.plist
index d7a1a70..acb80d4 100644
--- a/build/conf/mac/Contents/Info.plist
+++ b/build/conf/mac/Contents/Info.plist
@@ -75,13 +75,15 @@
         <key>idea.java.redist</key>
         <string>NoJavaDistribution</string>
 
+        <key>idea.home.path</key>
+        <string>$APP_PACKAGE/Contents</string>
       </dict>
 
       <key>VMOptions</key>
       <string>@@vmoptions@@ -Xbootclasspath/a:../lib/boot.jar</string>
 
       <key>WorkingDirectory</key>
-      <string>$APP_PACKAGE/bin</string>
+      <string>$APP_PACKAGE/Contents/bin</string>
     </dict>
   </dict>
 </plist>
diff --git a/build/conf/mac/Contents/MacOS/idea b/build/conf/mac/Contents/MacOS/idea
index 1089d07..6ba553f 100755
--- a/build/conf/mac/Contents/MacOS/idea
+++ b/build/conf/mac/Contents/MacOS/idea
Binary files differ
diff --git a/build/scripts/dist.gant b/build/scripts/dist.gant
index b4ae079..36595f6 100644
--- a/build/scripts/dist.gant
+++ b/build/scripts/dist.gant
@@ -126,8 +126,8 @@
   buildWinZip("$paths.artifacts/idea${args.buildNumber}.win.zip", [paths.distAll, paths.distWin])
 
   def macAppRoot = isEap() ?
-                   "IntelliJ IDEA ${p("component.version.major")} CE EAP.app" :
-                   "IntelliJ IDEA ${p("component.version.major")} CE.app"
+                   "IntelliJ IDEA ${p("component.version.major")} CE EAP.app/Contents" :
+                   "IntelliJ IDEA ${p("component.version.major")} CE.app/Contents"
 
   String macZip = "$paths.artifacts/idea${args.buildNumber}.mac.zip"
   buildMacZip(macAppRoot, macZip, [paths.distAll], paths.distMac)
diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant
index b584b51..7df4bb2 100644
--- a/build/scripts/utils.gant
+++ b/build/scripts/utils.gant
@@ -306,7 +306,7 @@
   }
 
   ant.copy(todir: path) {
-    fileset(dir: "$ch/build/conf/mac")
+    fileset(dir: "$ch/build/conf/mac/Contents")
   }
 
   ant.tstamp() {
@@ -316,14 +316,14 @@
   String executable = args.executable != null ? args.executable : p("component.names.product").toLowerCase()
   String helpId = args.help_id != null ? args.help_id : "IJ"
   String icns = "idea.icns"
-  String helpIcns = "$path/Contents/Resources/${helpId}.help/Contents/Resources/Shared/product.icns"
+  String helpIcns = "$path/Resources/${helpId}.help/Contents/Resources/Shared/product.icns"
   if (args.icns != null) {
-    ant.delete(file: "$path/Contents/Resources/idea.icns")
-    ant.copy(file: args.icns, todir: "$path/Contents/Resources")
+    ant.delete(file: "$path/Resources/idea.icns")
+    ant.copy(file: args.icns, todir: "$path/Resources")
     ant.copy(file: args.icns, tofile: helpIcns)
     icns = new File((String)args.icns).getName();
   } else {
-    ant.copy(file: "$path/Contents/Resources/idea.icns", tofile: helpIcns)
+    ant.copy(file: "$path/Resources/idea.icns", tofile: helpIcns)
   }
 
   String fullName = args.fullName != null ? args.fullName : p("component.names.fullname")
@@ -352,7 +352,7 @@
   new File("$path/bin/idea.properties").text = effectiveProperties.toString()
   new File("$path/bin/idea.vmoptions").text = "$mem64 -XX:+UseCompressedOops".split(" ").join("\n")
 
-  String classPath = classPathLibs.collect {"\$APP_PACKAGE/lib/${it}" }.join(":")
+  String classPath = classPathLibs.collect {"\$APP_PACKAGE/Contents/lib/${it}" }.join(":")
 
   String archs = """
     <key>LSArchitecturePriority</key>
@@ -385,7 +385,7 @@
 """
   }
 
-  ant.replace(file: "$path/Contents/Info.plist") {
+  ant.replace(file: "$path/Info.plist") {
     replacefilter(token: "@@build@@", value: args.buildNumber)
     replacefilter(token: "@@doc_types@@", value: ifNull(args.doc_types, ""))
     replacefilter(token: "@@executable@@", value: executable)
@@ -403,7 +403,7 @@
   }
 
   if (executable != "idea") {
-    ant.move(file: "$path/Contents/MacOS/idea", tofile: "$path/Contents/MacOS/$executable")
+    ant.move(file: "$path/MacOS/idea", tofile: "$path/MacOS/$executable")
   }
 
   ant.replace(file: "$path/bin/inspect.sh") {
@@ -705,7 +705,7 @@
         exclude(name: "bin/*.py")
         exclude(name: "bin/fsnotifier")
         exclude(name: "bin/restarter")
-        exclude(name: "Contents/MacOS/*")
+        exclude(name: "MacOS/*")
         extraBins.each {
           exclude(name: it)
         }
@@ -719,7 +719,7 @@
         include(name: "bin/*.py")
         include(name: "bin/fsnotifier")
         include(name: "bin/restarter")
-        include(name: "Contents/MacOS/*")
+        include(name: "MacOS/*")
         extraBins.each {
           include(name: it)
         }
diff --git a/native/MacLauncher/Launcher.m b/native/MacLauncher/Launcher.m
index e16e6b5..51dbe47 100644
--- a/native/MacLauncher/Launcher.m
+++ b/native/MacLauncher/Launcher.m
@@ -92,13 +92,23 @@
     NSString *explicit = [[[NSProcessInfo processInfo] environment] objectForKey:@"IDEA_JDK"];
 
     if (explicit != nil) {
-        appendBundle(explicit, jvmBundlePaths);
+        // check if IDEA_JDK value corresponds  with JVMVersion from Info.plist
+        NSLog(@"value of IDEA_JDK: %@", explicit);
+        NSBundle *jdkBundle = [NSBundle bundleWithPath:explicit];
+        NSString *required = requiredJvmVersion();
+        if (jdkBundle != nil && required != NULL) {
+            if (satisfies(jvmVersion(jdkBundle), required)) {
+                appendBundle(explicit, jvmBundlePaths);
+                debugLog(@"User VM:");
+                debugLog([jdkBundle bundlePath]);
+            }
+        }
     }
-    else {
+    if (! jvmBundlePaths.count > 0 ) {
         NSBundle *bundle = [NSBundle mainBundle];
-        NSString *appDir = bundle.bundlePath;
+        NSString *appDir = [bundle.bundlePath stringByAppendingPathComponent:@"Contents"];
 
-        appendJvmBundlesAt([appDir stringByAppendingPathComponent:@"jre"], jvmBundlePaths);
+        appendJvmBundlesAt([appDir stringByAppendingPathComponent:@"/jre"], jvmBundlePaths);
         if (jvmBundlePaths.count > 0) return jvmBundlePaths;
 
         appendJvmBundlesAt([NSHomeDirectory() stringByAppendingPathComponent:@"Library/Java/JavaVirtualMachines"], jvmBundlePaths);
@@ -147,6 +157,7 @@
     NSString *required = requiredJvmVersion();
     debugLog([NSString stringWithFormat:@"Required VM: %@", required]);
 
+    if (required != nil && required != NULL) {
     for (NSBundle *vm in vmBundles) {
         if (satisfies(jvmVersion(vm), required)) {
             debugLog(@"Chosen VM:");
@@ -154,9 +165,11 @@
             return vm;
         }
     }
-
-    debugLog(@"No matching VM found");
-
+    } else {
+        NSLog(@"Info.plist is corrupted, Absent JVMOptios key.");
+        exit(-1);
+    }
+    NSLog(@"No matching VM found.");
     return nil;
 }
 
@@ -174,14 +187,21 @@
 - (NSMutableString *)buildClasspath:(NSBundle *)jvm {
     NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:JVMOptions];
     NSMutableString *classpathOption = [NSMutableString stringWithString:@"-Djava.class.path="];
-    [classpathOption appendString:[jvmInfo objectForKey:@"ClassPath"]];
-
-    NSString *toolsJar = [[jvm bundlePath] stringByAppendingString:@"/Contents/Home/lib/tools.jar"];
-    if ([[NSFileManager defaultManager] fileExistsAtPath:toolsJar]) {
+    NSString *classPath = [jvmInfo objectForKey:@"ClassPath"];
+    if (classPath != nil && classPath != NULL) {
+      [classpathOption appendString:[jvmInfo objectForKey:@"ClassPath"]];
+      NSString *toolsJar = [[jvm bundlePath] stringByAppendingString:@"/Contents/Home/lib/tools.jar"];
+      if ([[NSFileManager defaultManager] fileExistsAtPath:toolsJar]) {
         [classpathOption appendString:@":"];
         [classpathOption appendString:toolsJar];
     }
-    return classpathOption;
+
+    } else {
+        NSLog(@"Info.plist is corrupted, Absent ClassPath key.");
+        exit(-1);
+    }
+        
+  return classpathOption;
 }
 
 
@@ -206,8 +226,20 @@
     return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/bin/idea.properties"];
 }
 
-NSString *getDefaultVMOptionsFilePath() {
-    return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/bin/idea.vmoptions"];
+// NSString *getDefaultVMOptionsFilePath() {
+//    return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@fileName];
+
+NSString *getDefaultFilePath(NSString *fileName) {
+    NSString *fullFileName = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/Contents"];
+    fullFileName = [fullFileName stringByAppendingString:fileName];
+    NSLog(@"fullFileName is: %@", fullFileName);
+    if ([[NSFileManager defaultManager] fileExistsAtPath:fullFileName]) {
+      NSLog(@"fullFileName exists: %@", fullFileName);
+    } else{
+      fullFileName = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:fileName];
+      NSLog(@"fullFileName exists: %@", fullFileName);
+    }
+    return fullFileName;
 }
 
 NSString *getVMOptionsFilePath() {
@@ -217,7 +249,8 @@
 NSArray *parseVMOptions() {
     NSArray *inConfig=[VMOptionsReader readFile:getVMOptionsFilePath()];
     if (inConfig) return inConfig;
-    return [VMOptionsReader readFile:getDefaultVMOptionsFilePath()];
+    //return [VMOptionsReader readFile:getDefaultVMOptionsFilePath()];
+    return [VMOptionsReader readFile:getDefaultFilePath(@"/bin/idea.vmoptions")];
 }
 
 NSDictionary *parseProperties() {
@@ -263,6 +296,13 @@
 
 - (const char *)mainClassName {
     NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:JVMOptions];
+    
+    NSString *mainClass = [jvmInfo objectForKey:@"MainClass"];
+    if (mainClass == nil || mainClass == NULL) {
+        NSLog(@"Info.plist is corrupted, Absent MainClass key.");
+        exit(-1);
+    }
+    
     char *answer = strdup([[jvmInfo objectForKey:@"MainClass"] UTF8String]);
     
     char *cur = answer;
@@ -279,11 +319,14 @@
 - (void)process_cwd {
     NSDictionary *jvmInfo = [[NSBundle mainBundle] objectForInfoDictionaryKey:JVMOptions];
     NSString *cwd = [jvmInfo objectForKey:@"WorkingDirectory"];
-    if (cwd != nil) {
+    if (cwd != nil && cwd != NULL) {
         cwd = [self expandMacros:cwd];
         if (chdir([cwd UTF8String]) != 0) {
             NSLog(@"Cannot chdir to working directory at %@", cwd);
         }
+    } else {
+        NSLog(@"Info.plist is corrupted, Absent WorkingDirectory key.");
+        exit(-1);
     }
 }
 
diff --git a/native/MacLauncher/MacLauncher.xcodeproj/project.pbxproj b/native/MacLauncher/MacLauncher.xcodeproj/project.pbxproj
index a9bd2b6..10c71f4 100644
--- a/native/MacLauncher/MacLauncher.xcodeproj/project.pbxproj
+++ b/native/MacLauncher/MacLauncher.xcodeproj/project.pbxproj
@@ -164,7 +164,7 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.5;
 				ONLY_ACTIVE_ARCH = NO;
 				PRODUCT_NAME = "$(TARGET_NAME)";
-				SDKROOT = macosx;
+				SDKROOT = macosx10.8;
 				WRAPPER_EXTENSION = app;
 			};
 			name = Release;
@@ -182,7 +182,7 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.5;
 				ONLY_ACTIVE_ARCH = NO;
 				PRODUCT_NAME = "$(TARGET_NAME)";
-				SDKROOT = macosx;
+				SDKROOT = macosx10.8;
 				WRAPPER_EXTENSION = app;
 			};
 			name = Debug;
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalSystemConfigurable.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalSystemConfigurable.java
index 59b1e5f..5a933ab 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalSystemConfigurable.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/settings/AbstractExternalSystemConfigurable.java
@@ -166,7 +166,6 @@
 
     
     if (!myProjectsModel.isEmpty()) {
-      addTitle(ExternalSystemBundle.message("settings.title.system.settings", myExternalSystemId.getReadableName()));
       myProjectsList.setSelectedIndex(0);
     }
   }
@@ -196,6 +195,7 @@
   private void prepareSystemSettings(@NotNull SystemSettings s) {
     mySystemSettingsControl = createSystemSettingsControl(s);
     if (mySystemSettingsControl != null) {
+      addTitle(ExternalSystemBundle.message("settings.title.system.settings", myExternalSystemId.getReadableName()));
       mySystemSettingsControl.fillUi(myComponent, 1);
     }
   }
diff --git a/platform/util/src/com/intellij/util/Restarter.java b/platform/util/src/com/intellij/util/Restarter.java
index 4c3450b..7f1584d 100644
--- a/platform/util/src/com/intellij/util/Restarter.java
+++ b/platform/util/src/com/intellij/util/Restarter.java
@@ -133,7 +133,7 @@
   }
 
   private static void restartOnMac(@NotNull final String... beforeRestart) throws IOException {
-    final String homePath = PathManager.getHomePath();
+    final String homePath = PathManager.getHomePath().substring(0, PathManager.getHomePath().indexOf( ".app" ) + 4);
     if (!StringUtil.endsWithIgnoreCase(homePath, ".app")) throw new IOException("Application bundle not found: " + homePath);
 
     doScheduleRestart(new File(PathManager.getBinPath(), "restarter"), new Consumer<List<String>>() {
diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml
index e2ea6e2..d4f85f6 100644
--- a/plugins/gradle/src/META-INF/plugin.xml
+++ b/plugins/gradle/src/META-INF/plugin.xml
@@ -91,6 +91,7 @@
 
     <applicationService serviceImplementation="org.jetbrains.plugins.gradle.service.GradleInstallationManager"/>
 
+    <applicationService serviceImplementation="org.jetbrains.plugins.gradle.settings.GradleSystemSettings"/>
     <projectService serviceImplementation="org.jetbrains.plugins.gradle.settings.GradleSettings"/>
     <projectService serviceImplementation="org.jetbrains.plugins.gradle.settings.GradleLocalSettings"/>
     <projectService serviceImplementation="org.jetbrains.plugins.gradle.service.project.GradleNotification"/>
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java
index d85e6cf..db15699 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSettings.java
@@ -30,26 +30,24 @@
 
 /**
  * Holds shared project-level gradle-related settings (should be kept at the '*.ipr' or under '.idea').
- * 
+ *
  * @author peter
  */
 @State(
-    name = "GradleSettings",
-    storages = {
-      @Storage(file = StoragePathMacros.PROJECT_FILE),
-      @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/gradle.xml", scheme = StorageScheme.DIRECTORY_BASED)
-    }
+  name = "GradleSettings",
+  storages = {
+    @Storage(file = StoragePathMacros.PROJECT_FILE),
+    @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/gradle.xml", scheme = StorageScheme.DIRECTORY_BASED)
+  }
 )
 public class GradleSettings extends AbstractExternalSystemSettings<GradleSettings, GradleProjectSettings, GradleSettingsListener>
-  implements PersistentStateComponent<GradleSettings.MyState>
-{
+  implements PersistentStateComponent<GradleSettings.MyState> {
 
-  @Nullable private String myServiceDirectoryPath;
-  @Nullable private String myGradleVmOptions;
-  private boolean myIsOfflineWork;
+  private final GradleSystemSettings mySystemSettings;
 
   public GradleSettings(@NotNull Project project) {
     super(GradleSettingsListener.TOPIC, project);
+    mySystemSettings = GradleSystemSettings.getInstance();
   }
 
   @NotNull
@@ -65,9 +63,6 @@
 
   @Override
   protected void copyExtraSettingsFrom(@NotNull GradleSettings settings) {
-    myServiceDirectoryPath = settings.getServiceDirectoryPath();
-    myGradleVmOptions = settings.getGradleVmOptions();
-    myIsOfflineWork = settings.isOfflineWork();
   }
 
   @SuppressWarnings("unchecked")
@@ -76,58 +71,52 @@
   public GradleSettings.MyState getState() {
     MyState state = new MyState();
     fillState(state);
-    state.serviceDirectoryPath = myServiceDirectoryPath;
-    state.gradleVmOptions = myGradleVmOptions;
-    state.offlineWork = myIsOfflineWork;
     return state;
   }
 
   @Override
   public void loadState(MyState state) {
     super.loadState(state);
-    myServiceDirectoryPath = state.serviceDirectoryPath;
-    myGradleVmOptions = state.gradleVmOptions;
-    myIsOfflineWork = state.offlineWork;
   }
 
   /**
    * @return service directory path (if defined). 'Service directory' is a directory which is used internally by gradle during
-   *         calls to the tooling api. E.g. it holds downloaded binaries (dependency jars). We allow to define it because there
-   *         is a possible situation when a user wants to configure particular directory to be excluded from anti-virus protection
-   *         in order to increase performance
+   * calls to the tooling api. E.g. it holds downloaded binaries (dependency jars). We allow to define it because there
+   * is a possible situation when a user wants to configure particular directory to be excluded from anti-virus protection
+   * in order to increase performance
    */
   @Nullable
   public String getServiceDirectoryPath() {
-    return myServiceDirectoryPath;
+    return mySystemSettings.getServiceDirectoryPath();
   }
 
   public void setServiceDirectoryPath(@Nullable String newPath) {
+    String myServiceDirectoryPath = mySystemSettings.getServiceDirectoryPath();
     if (!Comparing.equal(myServiceDirectoryPath, newPath)) {
-      String oldPath = myServiceDirectoryPath;
-      myServiceDirectoryPath = newPath;
-      getPublisher().onServiceDirectoryPathChange(oldPath, newPath);
-    } 
+      mySystemSettings.setServiceDirectoryPath(newPath);
+      getPublisher().onServiceDirectoryPathChange(myServiceDirectoryPath, newPath);
+    }
   }
 
   @Nullable
   public String getGradleVmOptions() {
-    return myGradleVmOptions;
+    return mySystemSettings.getGradleVmOptions();
   }
-  
+
   public void setGradleVmOptions(@Nullable String gradleVmOptions) {
+    String myGradleVmOptions = mySystemSettings.getGradleVmOptions();
     if (!Comparing.equal(myGradleVmOptions, gradleVmOptions)) {
-      String old = myGradleVmOptions;
-      myGradleVmOptions = gradleVmOptions;
-      getPublisher().onGradleVmOptionsChange(old, gradleVmOptions);
+      mySystemSettings.setGradleVmOptions(gradleVmOptions);
+      getPublisher().onGradleVmOptionsChange(myGradleVmOptions, gradleVmOptions);
     }
   }
 
   public boolean isOfflineWork() {
-    return myIsOfflineWork;
+    return mySystemSettings.isOfflineWork();
   }
 
   public void setOfflineWork(boolean isOfflineWork) {
-    myIsOfflineWork = isOfflineWork;
+    mySystemSettings.setOfflineWork(isOfflineWork);
   }
 
   @Override
@@ -143,9 +132,6 @@
   public static class MyState implements State<GradleProjectSettings> {
 
     private Set<GradleProjectSettings> myProjectSettings = ContainerUtilRt.newTreeSet();
-    public String serviceDirectoryPath;
-    public String gradleVmOptions;
-    public boolean offlineWork;
 
     @AbstractCollection(surroundWithTag = false, elementTypes = {GradleProjectSettings.class})
     public Set<GradleProjectSettings> getLinkedExternalProjectsSettings() {
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSystemSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSystemSettings.java
new file mode 100644
index 0000000..b24bd24
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/settings/GradleSystemSettings.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed 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.
+ */
+package org.jetbrains.plugins.gradle.settings;
+
+import com.intellij.openapi.components.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Vladislav.Soroka
+ * @since 14/8/2014
+ */
+@State(
+  name = "GradleSystemSettings",
+  storages = {
+    @Storage(file = StoragePathMacros.APP_CONFIG + "/gradle.settings.xml")
+  }
+)
+public class GradleSystemSettings implements PersistentStateComponent<GradleSystemSettings.MyState> {
+
+  @Nullable private String myServiceDirectoryPath;
+  @Nullable private String myGradleVmOptions;
+  private boolean myIsOfflineWork;
+
+  @NotNull
+  public static GradleSystemSettings getInstance() {
+    return ServiceManager.getService(GradleSystemSettings.class);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Nullable
+  @Override
+  public GradleSystemSettings.MyState getState() {
+    MyState state = new MyState();
+    state.serviceDirectoryPath = myServiceDirectoryPath;
+    state.gradleVmOptions = myGradleVmOptions;
+    state.offlineWork = myIsOfflineWork;
+    return state;
+  }
+
+  @Override
+  public void loadState(MyState state) {
+    myServiceDirectoryPath = state.serviceDirectoryPath;
+    myGradleVmOptions = state.gradleVmOptions;
+    myIsOfflineWork = state.offlineWork;
+  }
+
+  @Nullable
+  public String getServiceDirectoryPath() {
+    return myServiceDirectoryPath;
+  }
+
+  public void setServiceDirectoryPath(@Nullable String newPath) {
+    myServiceDirectoryPath = newPath;
+  }
+
+  @Nullable
+  public String getGradleVmOptions() {
+    return myGradleVmOptions;
+  }
+
+  public void setGradleVmOptions(@Nullable String gradleVmOptions) {
+    myGradleVmOptions = gradleVmOptions;
+  }
+
+  public boolean isOfflineWork() {
+    return myIsOfflineWork;
+  }
+
+  public void setOfflineWork(boolean isOfflineWork) {
+    myIsOfflineWork = isOfflineWork;
+  }
+
+  public static class MyState {
+    public String serviceDirectoryPath;
+    public String gradleVmOptions;
+    public boolean offlineWork;
+  }
+}
\ No newline at end of file
diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant
index 7efb4e3..7e8f669 100644
--- a/python/build/pycharm_community_build.gant
+++ b/python/build/pycharm_community_build.gant
@@ -173,7 +173,7 @@
   String tarRoot = isEap() ? "pycharm-community-$buildNumber" : "pycharm-community-${p("component.version.major")}.${p("component.version.minor")}"
   buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}.tar", [paths.distAll, paths.distUnix])
 
-  String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app" : "PyCharm CE.app"
+  String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm CE.app/Contents"
   buildMacZip(macAppRoot, "${paths.artifacts}/pycharmPC-${buildNumber}.sit", [paths.distAll], paths.distMac)
 }