detox 20.14.0-prerelease.0 → 20.14.0-prerelease.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. package/Detox-android/com/wix/detox/{20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar → 20.14.0-prerelease.2/detox-20.14.0-prerelease.2-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar → 20.14.0-prerelease.2/detox-20.14.0-prerelease.2-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.aar +0 -0
  12. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom → 20.14.0-prerelease.2/detox-20.14.0-prerelease.2.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.14.0-prerelease.2/detox-20.14.0-prerelease.2.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/android/detox/src/full/java/com/wix/detox/Detox.java +1 -7
  29. package/android/detox/src/full/java/com/wix/detox/DetoxMain.kt +48 -43
  30. package/android/detox/src/full/java/com/wix/detox/adapters/server/DetoxActionsDispatcher.kt +12 -6
  31. package/package.json +2 -2
  32. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.md5 +0 -1
  33. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.sha1 +0 -1
  34. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.sha256 +0 -1
  35. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-javadoc.jar.sha512 +0 -1
  36. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.md5 +0 -1
  37. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.sha1 +0 -1
  38. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.sha256 +0 -1
  39. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0-sources.jar.sha512 +0 -1
  40. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar +0 -0
  41. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.md5 +0 -1
  42. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha1 +0 -1
  43. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha256 +0 -1
  44. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.aar.sha512 +0 -1
  45. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.md5 +0 -1
  46. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha1 +0 -1
  47. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha256 +0 -1
  48. package/Detox-android/com/wix/detox/20.14.0-prerelease.0/detox-20.14.0-prerelease.0.pom.sha512 +0 -1
@@ -0,0 +1 @@
1
+ e0a1d1fbab61c5893fdb46e2235e1dc6965bd844
@@ -0,0 +1 @@
1
+ 6d2d413c447f14ec84981d3da97088eb6ead4abeeffab793c0e3807ba0ea0a20
@@ -0,0 +1 @@
1
+ f3d84c1967a303c3c707f7078767ef0296c9f7371f8357040f8fa42489e46686f79820c4da968a56ed5c0d6061595bc779960b8ceaf442025eb84781fd23a542
@@ -0,0 +1 @@
1
+ 66be2d4b4d91e76a8909fc7545fcf13a60eba43e
@@ -0,0 +1 @@
1
+ 13dea4a5f63caef936464c15a71159cde4bc2b0c80341428c3316e61bdff8acb
@@ -0,0 +1 @@
1
+ ef3ae29d6f7e051f506fd883f538bda1c818b2024e79cd06874a8dc315f136bfe64f9376b1dab7fc0cc95dda74d3fd69aab4788d87b6526793e85ee081b8018d
@@ -0,0 +1 @@
1
+ 8d86651a5283de3c9553a1c45ae34def
@@ -0,0 +1 @@
1
+ ee568f1ad8cdbb5d491fa566632d846fb9db0a80
@@ -0,0 +1 @@
1
+ 39db53cfe1ef966fb18c2dc4f30c56f1e6d9b63c393f114f63d51e9848bfc28a
@@ -0,0 +1 @@
1
+ 160c2f2c9d386372d094eb9c41b97007e61811f642d794298630f6b4af6db906f75d34da02afe86febcb2fe06baf32e3a9f5d68e018abab1299ca025974b1503
@@ -3,7 +3,7 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.wix</groupId>
5
5
  <artifactId>detox</artifactId>
6
- <version>20.14.0-prerelease.0</version>
6
+ <version>20.14.0-prerelease.2</version>
7
7
  <packaging>aar</packaging>
8
8
  <name>Detox</name>
9
9
  <description>Gray box end-to-end testing and automation library for mobile apps</description>
@@ -0,0 +1 @@
1
+ e973e8bfa03ed352cbbd3635a81a9e79
@@ -0,0 +1 @@
1
+ 5e0a40ff9b9798ca9e76525ada5bc3199f6c2517
@@ -0,0 +1 @@
1
+ 2156c5da6b37fc3bce8c585df1b1edba48f4794f00d5736a9055c1f425e5d60f
@@ -0,0 +1 @@
1
+ 9162d09b7e867b0ce6a1ebdfba18172824c29c7e7921dfcd0721b22f0549e115afef385167db7f7e443c80db2fb08066194aacb6c497774d1d79720592fd3f51
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox</artifactId>
5
5
  <versioning>
6
- <latest>20.14.0-prerelease.0</latest>
7
- <release>20.14.0-prerelease.0</release>
6
+ <latest>20.14.0-prerelease.2</latest>
7
+ <release>20.14.0-prerelease.2</release>
8
8
  <versions>
9
- <version>20.14.0-prerelease.0</version>
9
+ <version>20.14.0-prerelease.2</version>
10
10
  </versions>
11
- <lastUpdated>20231206150336</lastUpdated>
11
+ <lastUpdated>20231210110218</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 374b144f9306034184388c9579fcda60
1
+ 5eb089354bf7e6365077c660d176d63c
@@ -1 +1 @@
1
- aeb72dae3a76fd71e383c8b1bbc7871bf39b5424
1
+ 1dc810e178b23e373e4891b93830741d37f1df15
@@ -1 +1 @@
1
- 94e4275040ab622783723cea7783afc664a6b9759ea43e8d3c57b48e1eb34290
1
+ 6346b5dc9a255df56aea84bb619de85ebb65ee1982d0e8759c3be02fe6460f02
@@ -1 +1 @@
1
- 8ed181a738180833c36cf5066afb55082d4067c3924e5f240deef147ee818058a09ad14f3a2800cb46538e67872fd79b8437561b37eadd9e2f9f7d38b5454285
1
+ f86e5affbf923bef18101c744088e4fee87177ad0cf66bc72e9010bbab37ba9f9d1a99792e5031f76ca6d5c59029f7247ed380811eca80b523b519dd02d962cb
package/Detox-ios-src.tbz CHANGED
Binary file
package/Detox-ios.tbz CHANGED
Binary file
@@ -123,13 +123,7 @@ public final class Detox {
123
123
  DetoxConfig.CONFIG.apply();
124
124
 
125
125
  sActivityLaunchHelper = new ActivityLaunchHelper(activityTestRule);
126
-
127
- try {
128
- DetoxMain.run(context, sActivityLaunchHelper);
129
- } catch (Exception e) {
130
- Thread.currentThread().interrupt();
131
- throw new RuntimeException("Detox got interrupted prematurely", e);
132
- }
126
+ DetoxMain.run(context, sActivityLaunchHelper);
133
127
  }
134
128
 
135
129
  public static void launchMainActivity() {
@@ -13,40 +13,52 @@ import java.util.concurrent.CountDownLatch
13
13
  private const val TERMINATION_ACTION = "_terminate"
14
14
 
15
15
  object DetoxMain {
16
- private val loginMonitor = CountDownLatch(1)
16
+ private val handshakeLock = CountDownLatch(1)
17
17
 
18
18
  @JvmStatic
19
19
  fun run(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
20
20
  val detoxServerInfo = DetoxServerInfo()
21
21
  val testEngineFacade = TestEngineFacade()
22
22
  val actionsDispatcher = DetoxActionsDispatcher()
23
- val externalAdapter = DetoxServerAdapter(actionsDispatcher, detoxServerInfo, TERMINATION_ACTION)
24
-
25
- initActionHandlers(actionsDispatcher, externalAdapter, testEngineFacade, rnHostHolder)
26
- // actionsDispatcher.dispatchAction(INIT_ACTION, "", 0)
27
- init(externalAdapter)
28
- synchronized(this) {
29
- awaitHandshake()
30
- launchApp(rnHostHolder, activityLaunchHelper)
31
- }
32
- actionsDispatcher.join()
33
- }
23
+ val serverAdapter = DetoxServerAdapter(actionsDispatcher, detoxServerInfo, TERMINATION_ACTION)
34
24
 
35
- private fun init(externalAdapter: DetoxServerAdapter) {
36
- initCrashHandler(externalAdapter)
37
- initANRListener(externalAdapter)
25
+ initCrashHandler(serverAdapter)
26
+ initANRListener(serverAdapter)
38
27
  initEspresso()
39
28
  initReactNative()
40
29
 
41
- externalAdapter.connect()
30
+ setupActionHandlers(actionsDispatcher, serverAdapter, testEngineFacade, rnHostHolder)
31
+ serverAdapter.connect()
32
+
33
+ launchActivityOnCue(rnHostHolder, activityLaunchHelper)
34
+ actionsDispatcher.join()
35
+ }
36
+
37
+ /**
38
+ * Launch the tested activity "on cue", namely, right after a connection is established and the handshake
39
+ * completes successfully.
40
+ *
41
+ * This has to be synchronized so that an `isReady` isn't handled *before* the activity is launched (albeit not fully
42
+ * initialized - all native modules and everything) and a react context is available.
43
+ *
44
+ * As a better alternative, it would make sense to execute this as a simple action from within the actions
45
+ * dispatcher (i.e. handler of `loginSuccess`), in which case, no inter-thread locking would be required
46
+ * thanks to the usage of Handlers. However, in this type of a solution, errors / crashes would be reported
47
+ * not by instrumentation itself, but based on the `AppWillTerminateWithError` message; In it's own, it is a good
48
+ * thing, but for a reason we're not sure of yet, it is ignored by the test runner at this point in the flow.
49
+ */
50
+ @Synchronized
51
+ private fun launchActivityOnCue(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
52
+ awaitHandshake()
53
+ launchActivity(rnHostHolder, activityLaunchHelper)
42
54
  }
43
55
 
44
56
  private fun awaitHandshake() {
45
- loginMonitor.await()
57
+ handshakeLock.await()
46
58
  }
47
59
 
48
60
  private fun onLoginSuccess() {
49
- loginMonitor.countDown()
61
+ handshakeLock.countDown()
50
62
  }
51
63
 
52
64
  private fun doTeardown(serverAdapter: DetoxServerAdapter, actionsDispatcher: DetoxActionsDispatcher, testEngineFacade: TestEngineFacade) {
@@ -56,30 +68,28 @@ synchronized(this) {
56
68
  actionsDispatcher.teardown()
57
69
  }
58
70
 
59
- private fun initActionHandlers(actionsDispatcher: DetoxActionsDispatcher, serverAdapter: DetoxServerAdapter, testEngineFacade: TestEngineFacade, rnHostHolder: Context) {
60
- // Primary actions
61
- with(actionsDispatcher) {
62
- val readyHandler = ReadyActionHandler(serverAdapter, testEngineFacade)
63
- val rnReloadHandler = ReactNativeReloadActionHandler(rnHostHolder, serverAdapter, testEngineFacade)
64
-
65
- associateActionHandler("isReady") { params, messageId ->
71
+ private fun setupActionHandlers(actionsDispatcher: DetoxActionsDispatcher, serverAdapter: DetoxServerAdapter, testEngineFacade: TestEngineFacade, rnHostHolder: Context) {
72
+ class SynchronizedActionHandler(private val actionHandler: DetoxActionHandler): DetoxActionHandler {
73
+ override fun handle(params: String, messageId: Long) {
66
74
  synchronized(this@DetoxMain) {
67
- readyHandler.handle(params, messageId)
68
- }
69
- }
70
- associateActionHandler("loginSuccess") { _, _ -> this@DetoxMain.onLoginSuccess() }
71
- associateActionHandler("reactNativeReload") { params, messageId ->
72
- synchronized(this@DetoxMain) {
73
- rnReloadHandler.handle(params, messageId)
75
+ actionHandler.handle(params, messageId)
74
76
  }
75
77
  }
78
+ }
79
+
80
+ // Primary actions
81
+ with(actionsDispatcher) {
82
+ val readyHandler = SynchronizedActionHandler( ReadyActionHandler(serverAdapter, testEngineFacade) )
83
+ val rnReloadHandler = SynchronizedActionHandler( ReactNativeReloadActionHandler(rnHostHolder, serverAdapter, testEngineFacade) )
84
+
85
+ associateActionHandler("loginSuccess", ::onLoginSuccess)
86
+ associateActionHandler("isReady", readyHandler)
87
+ associateActionHandler("reactNativeReload", rnReloadHandler)
76
88
  associateActionHandler("invoke", InvokeActionHandler(MethodInvocation(), serverAdapter))
77
89
  associateActionHandler("cleanup", CleanupActionHandler(serverAdapter, testEngineFacade) {
78
90
  dispatchAction(TERMINATION_ACTION, "", 0)
79
91
  })
80
- associateActionHandler(TERMINATION_ACTION) { _, _ ->
81
- this@DetoxMain.doTeardown(serverAdapter, actionsDispatcher, testEngineFacade)
82
- }
92
+ associateActionHandler(TERMINATION_ACTION) { -> doTeardown(serverAdapter, actionsDispatcher, testEngineFacade) }
83
93
 
84
94
  if (DetoxInstrumentsManager.supports()) {
85
95
  val instrumentsManager = DetoxInstrumentsManager(rnHostHolder)
@@ -90,13 +100,8 @@ synchronized(this) {
90
100
 
91
101
  // Secondary actions
92
102
  with(actionsDispatcher) {
93
- val queryStatusHandler = QueryStatusActionHandler(serverAdapter, testEngineFacade)
94
- associateActionHandler("currentStatus", object: DetoxActionHandler {
95
- override fun handle(params: String, messageId: Long) =
96
- synchronized(this@DetoxMain) {
97
- queryStatusHandler.handle(params, messageId)
98
- }
99
- }, false)
103
+ val queryStatusHandler = SynchronizedActionHandler( QueryStatusActionHandler(serverAdapter, testEngineFacade) )
104
+ associateSecondaryActionHandler("currentStatus", queryStatusHandler)
100
105
  }
101
106
  }
102
107
 
@@ -116,7 +121,7 @@ synchronized(this) {
116
121
  ReactNativeExtension.initIfNeeded()
117
122
  }
118
123
 
119
- private fun launchApp(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
124
+ private fun launchActivity(rnHostHolder: Context, activityLaunchHelper: ActivityLaunchHelper) {
120
125
  Log.i(DetoxLog.LOG_TAG, "Launching the tested activity!")
121
126
  activityLaunchHelper.launchActivityUnderTest()
122
127
  ReactNativeExtension.waitForRNBootstrap(rnHostHolder)
@@ -11,17 +11,18 @@ class DetoxActionsDispatcher {
11
11
  private val primaryExec = ActionsExecutor("detox.primary")
12
12
  private val secondaryExec = ActionsExecutor("detox.secondary")
13
13
 
14
- fun associateActionHandler(type: String, actionHandler: DetoxActionHandler, isPrimary: Boolean = true) {
15
- val actionsExecutor = (if (isPrimary) primaryExec else secondaryExec)
16
- actionsExecutor.associateHandler(type, actionHandler)
17
- }
14
+ fun associateActionHandler(type: String, actionHandler: DetoxActionHandler) =
15
+ associateActionHandler(type, actionHandler, true)
18
16
 
19
- fun associateActionHandler(type: String, handlerFunc: (params: String, messageId: Long) -> Unit) {
17
+ fun associateActionHandler(type: String, handlerFunc: () -> Unit) {
20
18
  associateActionHandler(type, object: DetoxActionHandler {
21
- override fun handle(params: String, messageId: Long) = handlerFunc(params, messageId)
19
+ override fun handle(params: String, messageId: Long) = handlerFunc()
22
20
  })
23
21
  }
24
22
 
23
+ fun associateSecondaryActionHandler(type: String, actionHandler: DetoxActionHandler) =
24
+ associateActionHandler(type, actionHandler, false)
25
+
25
26
  fun dispatchAction(type: String, params: String, messageId: Long) {
26
27
  (primaryExec.executeAction(type, params, messageId) ||
27
28
  secondaryExec.executeAction(type, params, messageId))
@@ -39,6 +40,11 @@ class DetoxActionsDispatcher {
39
40
  primaryExec.join()
40
41
  secondaryExec.join()
41
42
  }
43
+
44
+ private fun associateActionHandler(type: String, actionHandler: DetoxActionHandler, isPrimary: Boolean = true) {
45
+ val actionsExecutor = (if (isPrimary) primaryExec else secondaryExec)
46
+ actionsExecutor.associateHandler(type, actionHandler)
47
+ }
42
48
  }
43
49
 
44
50
  private class ActionsExecutor(name: String) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "detox",
3
3
  "description": "E2E tests and automation for mobile",
4
- "version": "20.14.0-prerelease.0",
4
+ "version": "20.14.0-prerelease.2",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -109,5 +109,5 @@
109
109
  "browserslist": [
110
110
  "node 14"
111
111
  ],
112
- "gitHead": "4eb7e6729cf5bd3d30f720c40df316fdf38300df"
112
+ "gitHead": "1707cce5d1e9922af476f3a47d34e3abfa2f0615"
113
113
  }
@@ -1 +0,0 @@
1
- 3530c43ea00d627580747ee9f0d5863ca9813f37
@@ -1 +0,0 @@
1
- 8e1b2ec062f53625f04682a7680f945a735f5ce1398779fc75053e06552d1df5
@@ -1 +0,0 @@
1
- 609e6c6a9432b4e1ef6a4e0cce31001a69ea5fb95ea2396be34732e5e1cc80accb647c5c9003827cf69754918a3a814deb24d27f14047a3aa6297c92b764ef03
@@ -1 +0,0 @@
1
- c2dffdb56581b4c26ed98b6775e222e1a4486c5e
@@ -1 +0,0 @@
1
- c9a52d8a32ecbc37230bcdbb9a4aa67411ca950311e5de327ec44694d77c8872
@@ -1 +0,0 @@
1
- 402fd90cfcfc8ee4f7faa04e7915ab6f24580ef704dbe0b835bae434abe4bf749987cb7fcc52b6a1f7557275a3ca5e0205438aef2934966948dfdaa66335a162
@@ -1 +0,0 @@
1
- e4d79ca2a269e97059c4321c69b89508
@@ -1 +0,0 @@
1
- a5f8cbcf67d3d87d5036eb6f48372962c64dd12b
@@ -1 +0,0 @@
1
- b2459b4c1286baf4f608be3ec55a46688c92ab1a95d840769a3519b4f75c2ea4
@@ -1 +0,0 @@
1
- 60375b1df9ce89baea8fb435985d83d2fde2a8013f3b12fb1d3e3391ef7ac14e98d10eff9b27fd44acc753c7764244fcb0d9934ce97c4beb534102247a9962f0
@@ -1 +0,0 @@
1
- 1e365cca25c5a49f1bf610fd76df8ff0
@@ -1 +0,0 @@
1
- 6f1a93a3247a829d64f63a67830adc742dfef0b9
@@ -1 +0,0 @@
1
- c2745e1391bb64bed726bf43a1f624f79d13f0a2c7e4ccd9838b64df40d1e3ee
@@ -1 +0,0 @@
1
- ca4428ae0cdffbf5bb7967d24f29486735a29ee89bad794bfa451f12467744f48bab8a7adac1fdb73426951aec461ccf3bae0396994c6e4711d1ff347e85369b