diff --git a/community-resources/intellij.idea.community.customization.iml b/community-resources/intellij.idea.community.customization.iml
index a73828cc90ad..c1f7e4424e98 100644
--- a/community-resources/intellij.idea.community.customization.iml
+++ b/community-resources/intellij.idea.community.customization.iml
@@ -26,5 +26,6 @@
+
\ No newline at end of file
diff --git a/community-resources/resources/META-INF/IdeaPlugin.xml b/community-resources/resources/META-INF/IdeaPlugin.xml
index 4efc3c962494..70fbbb494bf1 100644
--- a/community-resources/resources/META-INF/IdeaPlugin.xml
+++ b/community-resources/resources/META-INF/IdeaPlugin.xml
@@ -16,6 +16,7 @@
+
diff --git a/platform/experiment/intellij.platform.experiment.iml b/platform/experiment/intellij.platform.experiment.iml
new file mode 100644
index 000000000000..bdb38f7d8f4e
--- /dev/null
+++ b/platform/experiment/intellij.platform.experiment.iml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/platform/experiment/resources/intellij.platform.experiment.xml b/platform/experiment/resources/intellij.platform.experiment.xml
new file mode 100644
index 000000000000..81058a8fd026
--- /dev/null
+++ b/platform/experiment/resources/intellij.platform.experiment.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/platform/experiment/src/com/intellij/platform/experiment/ab/ABExperiment.kt b/platform/experiment/src/com/intellij/platform/experiment/ab/ABExperiment.kt
new file mode 100644
index 000000000000..d9671cecf81e
--- /dev/null
+++ b/platform/experiment/src/com/intellij/platform/experiment/ab/ABExperiment.kt
@@ -0,0 +1,69 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.platform.experiment.ab
+
+import com.intellij.internal.statistic.eventLog.EventLogConfiguration
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.util.PlatformUtils
+
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+abstract class ABExperiment {
+
+ abstract val id: String
+
+ protected abstract val experimentConfig: T
+
+ protected abstract val testRegistryKey: String
+
+ fun isExperimentEnabled(): Boolean {
+ return getUserGroupKind() == GroupKind.Experimental
+ }
+
+ fun getUserGroupNumber(): Int {
+ val testRegistryExperimentGroup = Registry.intValue(testRegistryKey, -1, -1, experimentConfig.totalNumberOfBuckets - 1)
+ if (testRegistryExperimentGroup >= 0) return testRegistryExperimentGroup
+
+ val bucket = getBucket()
+ val experimentGroup = bucket % getTotalNumberOfGroups()
+ return experimentGroup
+ }
+
+ fun getUserGroupKind(): GroupKind {
+ val groupNumber = getUserGroupNumber()
+ return if (isPopularIDE()) {
+ when (groupNumber) {
+ in experimentConfig.experimentalGroupNumbersForPopularIde -> GroupKind.Experimental
+ in experimentConfig.controlGroupNumbersForPopularIde -> GroupKind.Control
+ else -> GroupKind.Experimental
+ }
+ }
+ else {
+ when (groupNumber) {
+ in experimentConfig.experimentalGroupNumbersForRegularIde -> GroupKind.Experimental
+ in experimentConfig.controlGroupNumbersForRegularIde -> GroupKind.Control
+ else -> GroupKind.Experimental
+ }
+ }
+ }
+
+ private fun getTotalNumberOfGroups(): Int {
+ return if (isPopularIDE()) {
+ experimentConfig.experimentalGroupNumbersForPopularIde.size + experimentConfig.controlGroupNumbersForPopularIde.size
+ }
+ else {
+ experimentConfig.experimentalGroupNumbersForRegularIde.size + experimentConfig.controlGroupNumbersForRegularIde.size
+ }
+ }
+
+ private fun getBucket(): Int {
+ val eventLogConfiguration = EventLogConfiguration.getInstance()
+ return eventLogConfiguration.bucket % experimentConfig.totalNumberOfBuckets
+ }
+
+ private fun isPopularIDE() = PlatformUtils.isIdeaUltimate() || PlatformUtils.isPyCharmPro()
+
+
+ enum class GroupKind {
+ Experimental,
+ Control
+ }
+}
\ No newline at end of file
diff --git a/platform/experiment/src/com/intellij/platform/experiment/ab/ABExperimentConfigBase.kt b/platform/experiment/src/com/intellij/platform/experiment/ab/ABExperimentConfigBase.kt
new file mode 100644
index 000000000000..78557b36712f
--- /dev/null
+++ b/platform/experiment/src/com/intellij/platform/experiment/ab/ABExperimentConfigBase.kt
@@ -0,0 +1,10 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.platform.experiment.ab
+
+abstract class ABExperimentConfigBase {
+ open val experimentalGroupNumbersForPopularIde = (0..7).toList()
+ open val controlGroupNumbersForPopularIde = listOf(8, 9)
+ open val experimentalGroupNumbersForRegularIde = listOf(0, 1)
+ open val controlGroupNumbersForRegularIde = listOf(2)
+ open val totalNumberOfBuckets = 256
+}
diff --git a/platform/experiment/src/com/intellij/platform/experiment/demo/DemoABExperiment.kt b/platform/experiment/src/com/intellij/platform/experiment/demo/DemoABExperiment.kt
new file mode 100644
index 000000000000..8140da85f99b
--- /dev/null
+++ b/platform/experiment/src/com/intellij/platform/experiment/demo/DemoABExperiment.kt
@@ -0,0 +1,24 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.platform.experiment.demo
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import com.intellij.platform.experiment.ab.ABExperiment
+import com.intellij.platform.experiment.ab.ABExperimentConfigBase
+
+fun getInstance(): DemoABExperiment {
+ return ApplicationManager.getApplication().service()
+}
+
+
+@Service
+class DemoABExperiment : ABExperiment() {
+
+ override val id: String = "demo.ab_experiment"
+
+ override val experimentConfig: ABExperimentConfigBase = object : ABExperimentConfigBase() {}
+
+ override val testRegistryKey: String = "demo.ab_experiment"
+
+}
\ No newline at end of file
diff --git a/platform/experiment/src/com/intellij/platform/experiment/demo/DemoABExperimentAction.kt b/platform/experiment/src/com/intellij/platform/experiment/demo/DemoABExperimentAction.kt
new file mode 100644
index 000000000000..c37322543bad
--- /dev/null
+++ b/platform/experiment/src/com/intellij/platform/experiment/demo/DemoABExperimentAction.kt
@@ -0,0 +1,13 @@
+// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.platform.experiment.demo
+
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+
+class DemoABExperimentAction : AnAction("Aaaaaaa test") {
+ override fun actionPerformed(e: AnActionEvent) {
+ println(getInstance().isExperimentEnabled())
+ println(getInstance().getUserGroupKind())
+ println(getInstance().getUserGroupNumber())
+ }
+}
\ No newline at end of file