Summary:
The `UIManager` already has a lot of responsibilities and is deeply
tied with React Native's view architecture. This diff separates out a
`DeviceInfo` native module to provide information about screen dimensions and
font scale, etc.
Reviewed By: fkgozali
Differential Revision: D4713834
fbshipit-source-id: f2ee93acf876a4221c29a8c731f5abeffbb97974
Summary:
Moving setting `availableSize` for `RCTRootShadowView` on earlier stage allows to prevent situations where `availableSize` is not specified yet, but Yoga layout is already happening.
Because `availableSize` equals {infinity, infinity} by default (in this case), Yoga returns a lot of nodes with infinit metrics, which confises UIKit.
Reviewed By: mmmulani
Differential Revision: D4672170
fbshipit-source-id: f9d8c84799dcbdb6b9230ddef6284d84df268833
Summary:
A related Android PR is #11008.
Font scale was exposed through:
- The `getContentSizeMultiplier` method
- The `didUpdateContentSizeMultiplier` event
These are now deprecated. The reason is that there was already an API that exposed font scale. However, it was Android only. We now expose font scale through that API on iOS as well. Specifically:
- Font scale is now available as `PixelRatio.getFontScale()`.
- The `change` event on the `Dimensions` object now fires when font scale changes.
This change also adds support for `Dimensions.get('screen')` on iOS. Previously, only `Dimensions.get('window')` was available on iOS. The motivation is that, [according to this comment](https://github.com/facebook/react-native/pull/11008#issuecomment-275123609), we'd like to deprecate `window` dimensions in favor of `screen` dimensions in the future.
**Test plan (required)**
Verified that `PixelRatio.getFontScale()` and the `change` event work properly in a test app.
Adam Comella
Microsoft Corp.
Closes https://github.com/facebook/react-native/pull/12268
Differential Revision: D4673642
Pulled By: mkonicek
fbshipit-source-id: 2602204da6998a96216e06f5321f28f6603e4972
Summary: RCTDevSettings incorrectly assigned "bad" executor-override class to the executor instead of checking if the class exists before assigning it. It should really check if the class exists, and fallback to defaults otherwise.
Reviewed By: mmmulani, yungsters
Differential Revision: D4655926
fbshipit-source-id: 48c8fe28f22aaa8430752411ce5e6e858dbd4b32
Summary:
* The dev support code moved into a `DevSupport` subspec, meaning that only if the subspec is specified in the user’s Podfile will the packager client, dev menu, etc be included. This is mainly done through checks for header availability.
It also improves the weird situation where you had to specify the `RCTWebSocket` subspec if you wanted to be able to use the packager client during development.
* I removed hardcoding the release version in the podspec on release, because the podspec still relies on `package.json` when evaluating, so there’s no real point in not also getting the version number from there. This should remove any requirement to perform maintenance of the OSS release script regarding the podspec.
Closes https://github.com/facebook/react-native/pull/12602
Differential Revision: D4621021
Pulled By: ericvicenti
fbshipit-source-id: 6c208371fc40ea607809a6ab05dd3714ed9980cf
Summary:
Nothing actually changed except the deprecation.
Existed `intrinsicSize` was already implemented as `intrinsicContentSize` and this change only removes redundancy.
Moreover, we do not need `rootViewDidChangeIntrinsicSize` delegate method anymore; this is now mentioned in its description.
Depends on D4577890
Reviewed By: mmmulani
Differential Revision: D4589344
fbshipit-source-id: 16ed62cbf6bf72678bd7f7c11d4812c5aa36c743
Summary:
This decouples non-UI logic from RCTDevMenu into a new module RCTDevSettings.
**Motivation**: This allows developers to change dev settings without depending on the built-in dev menu, e.g. if they want to introduce their own UI, or have other devtools logic that doesn't depend on an action sheet.
It also introduces the RCTDevSettingsDataSource protocol for storing dev tools preferences. This could allow a developer to implement alternative behaviors, e.g. loading the settings from some other config, changing settings based on the user, deciding not to persist some settings, or something else.
The included data source implementation, RCTDevSettingsUserDefaultsDataSource, uses NSUserDefaults and is backwards compatible with the older implementation, so **no workflows or dependent code will break, and old saved settings will persist.**
The RCTDevMenu interface has not changed and is therefore also backwards-compatible, though
some methods are now deprecated.
In order to ensure that RCTDevSettings
Closes https://github.com/facebook/react-native/pull/11613
Reviewed By: mmmulani
Differential Revision: D4571773
Pulled By: javache
fbshipit-source-id: 25555d0a6eaa81f694343e079ed02439e5845fbc
Summary:
Now things look much more clear, I hope.
This diff:
* Introduces new property of `RCTRootShadowView` `availableSize` which represents exactly what we transmit to layout engine;
* Illuminates conflict between logical `availableSize` and explicitly specified size of DOM node (current `size`);
* Splits overcomplicated `setSize:forView:` method into two unrelated ones;
* Changes actual values of `RCTRootViewSizeFlexibility` enum constants for simpler usage;
* Completely removes `sizeFlexibility` concept from `RCTRootShadowView` (in favor of special values of `availableSize`);
* Makes the code clearer finally.
This is beginning of big effort to improve `RCTRootView` and co.
Reviewed By: mmmulani
Differential Revision: D4562834
fbshipit-source-id: f5baaf2859ea430d44645a6b5d35f222f15a668e
Summary:
Motivation:
* `RCTShadowView`'s `frame` property actually represents computed layout of the view. We must not use it as a setter for yoga node styles;
* Using `frame` and `setLeftTop` in existing way actually works only for view with absolute positioning, so it is super rare and special case;
* Internally, setting `frame` only make sense to `RootView`, and in that case there we always must not change `origin` we are introducing `setSize` method.
Changes:
* `[-RCTShadowView setFrame:]` was removed, `frame` property is readonly now;
* `[-RCTShadowView setLeftTop:]` was removed; no replacement provided;
* `[-RCTShadowView size]` read-write property was added;
* `[-RCTUIManager setFrame:forView:]` was deprecated, use (just introduced) `setSize:forView:` instead;
* `[-RCTUIManager setSize:forView:]` was added.
If you are still need some of removed methods, you are probably doing something wrong. Consider using `setIntrinsicContentSize`-family methods,
`setSize`-family methods, or (in the worst case) accessing `yogaNode` directly.
Reviewed By: javache
Differential Revision: D4491384
fbshipit-source-id: 56dd84567324c5a86e4c870a41c38322dc1224d2
Summary:
In theory, we should be able to animate any non-layout property, including custom ones. While there is still work to be done on the native side to fully enable this, we should start by dropping the prop whitelist.
Closes https://github.com/facebook/react-native/pull/10658
Differential Revision: D4379031
Pulled By: ericvicenti
fbshipit-source-id: fe9c30ea101e93a8b260d7d09a909fafbb82fee6
Summary:
Following the PR https://github.com/facebook/react-native/pull/6195, this adds a `HEIGHT` constant on `StatusBar` for iOS.
Combined with `statusBarFrameDidChange` and `statusBarFrameWillChange` StatusBar native events, it solves various problems with In-Call cellar bar / Location bar / others 40pt status bars, and offers a correct `keyboardVerticalOffset` value for the KeyboardAvoidingView component.
Closes https://github.com/facebook/react-native/pull/12041
Differential Revision: D4450924
Pulled By: hramos
fbshipit-source-id: 664798260f4226140f3fa3f9222a415a305d0d78
Summary:
Add one more parameter which can specify the keyboard type of first text input(if exists) to AlertIOS.prompt().
Example usage:
`AlertIOS.prompt('Type a phone number', null, null, 'plain-text', undefined, 'phone-pad')`
Closes https://github.com/facebook/react-native/pull/8781
Differential Revision: D4437900
Pulled By: hramos
fbshipit-source-id: 8141cc0d7c70d13603cd5a1d5ea3f1ab1ce437a6
Summary: Switch to using IS_TESTING on the Platform module. While IS_TESTING has to be explicitly set in the test harness, this makes it more usable and stops people from relying on brittle variables in the (larger) environment.
Reviewed By: fkgozali
Differential Revision: D4423661
fbshipit-source-id: 27a80867778b9374bcba67b69f9c93d32c0a74b0
Summary:
Right now from JS there's no way to see the environment variables or arguments that the application was started with.
The main use case for this is to help enable/disable features when being run in a testing environment (as environment variables are the easiest way to communicate).
javache is it okay to reference these constants from JS at startup time? I am planning to disable yellow boxes via an environment variable.
achen1 how easy is it expose these two things for Android as well?
Reviewed By: achen1
Differential Revision: D4395091
fbshipit-source-id: fc318e6a60b8829f7eb4491ea8f3258f68f59c8c
Summary:
Fixes the build warning:
```react-native/React/Modules/RCTRedBox.m:406:58: Conversion from value of type 'NSArray<RCTJSStackFrame *> *' to incompatible type 'NSArray<NSDictionary *> *```
This appears because the compiler is left to infer the type of `stack`, and it does so as `NSArray<RCTJSStackFrame *>` based on [RCTRedBox.m#L390](https://github.com/facebook/react-native/blob/master/React/Modules/RCTRedBox.m#L390). In reality `stack` may be either of two types and the function body deals with normalisation.
Mark the stack as explicitly `NSArray<id>` to prevent inference so we're free to make the decision to cast to more specific types.
Closes https://github.com/facebook/react-native/pull/11807
Differential Revision: D4402916
fbshipit-source-id: 356343f244af7638b9b9e91c2c5b7e68de0cbd33
Summary:
Motivation: reduce build noise that might worry new users or hide real problems.
This deals with four of the warnings currently in the iOS build. The `__unused` additions are standard and self-explanatory, following the style used elsewhere in RN. I've used `#pragma unused` to deal with parameters named by macros.
Tested by building and running the `UIExplorer` example app in XCode 8.2
Closes https://github.com/facebook/react-native/pull/11797
Differential Revision: D4396611
fbshipit-source-id: 728e9ebb94d147f7a2cbc674a25fe67e66e2e8b2
Summary:
On certain devices (in my case, any iPad Pro model), listening to `DeviceEventEmitter.didUpdateDimensions` would call back *before* the interface change takes places (i.e. calling `Dimensions.get()` in this callback would return wrong values). Turns out that we were listening for the wrong native event.
Edit to add: now using `[RCTSharedApplication() statusBarOrientation]` to get the current orientation. Not yet sure why, but the `userInfo` provided by the notification was returning the wrong orientation *only* on the first time you rotate the device.
This fixes the open issue: https://github.com/facebook/react-native/issues/7340
Closes https://github.com/facebook/react-native/pull/11350
Differential Revision: D4348186
Pulled By: javache
fbshipit-source-id: cb2cfb9cccfc459ad4b46a5af2bec4c973132ae8
Summary: No need to have two files; merge it into one and give it an appropriate name.
Reviewed By: javache
Differential Revision: D4296716
fbshipit-source-id: 904d13c23bb8d403b8efcb60f9a4aa5df5b08972
Summary: This singleton was unnecessary and can be implemented with a single `static` in `RCTDevMenu`. In another diff, I will rename `RCTWebSocketManager.{h,m}` to reflect the only class that remains.
Reviewed By: javache
Differential Revision: D4296551
fbshipit-source-id: 653971dfb31de5b0a161b531eed82a067f536ce3
Summary:
To make React Native play nicely with our internal build infrastructure we need to properly namespace all of our header includes.
Where previously you could do `#import "RCTBridge.h"`, you must now write this as `#import <React/RCTBridge.h>`. If your xcode project still has a custom header include path, both variants will likely continue to work, but for new projects, we're defaulting the header include path to `$(BUILT_PRODUCTS_DIR)/usr/local/include`, where the React and CSSLayout targets will copy a subset of headers too. To make Xcode copy headers phase work properly, you may need to add React as an explicit dependency to your app's scheme and disable "parallelize build".
Reviewed By: mmmulani
Differential Revision: D4213120
fbshipit-source-id: 84a32a4b250c27699e6795f43584f13d594a9a82
Summary: Correct header import paths, update podspec so we point at the copy in ReactCommon (and can eventually remove the copy under React)
Reviewed By: astreet
Differential Revision: D4204501
fbshipit-source-id: e979a010092f025b2cdc289e1e5f22fc7b65a8d1
Summary:
Corresponding Android PR: https://github.com/facebook/react-native/pull/11008
This gives apps the ability to find out the current scaling factor for fonts on the device. An event was also added so that apps can find out when this value changes.
**Test plan (required)**
Verified that the getter and the event work properly in a test app. Also, this change is used in my team's app.
Adam Comella
Microsoft Corp.
Closes https://github.com/facebook/react-native/pull/11010
Differential Revision: D4207620
Pulled By: ericvicenti
fbshipit-source-id: b3f6f4a412557ba97e1f5fb63446c7ff9a2ff753
Summary:
The various RCTLog macros (`RCTLogWarn`, `RCTLogError`, etc..) are based on the `_RCTLog` macro, which, in its expanded form, has a semi-colon in DEV mode (i.e., when `RCTLOG_ENABLED` is set to 1), and doesn't have one when `RCTLOG_ENABLED` is set to 0.
This could lead to a situation where code will compile in DEV but will fail to compile for prod.
Fixing this by removing the semicolon from the DEV version (as should).
Reviewed By: javache
Differential Revision: D4189133
fbshipit-source-id: 54cb4e2c96d1e48d9df88464aa58b13af432c2bd
Summary:
1. Using weak container to hold the currently opened alerts.
2. Using weak reference to alertController in action handler block.
3. BTW, remove the unused vars: _alertCallbacks, _alertButtonKeys.
Test plan (required)
```
- (void)invalidate
{
for (UIAlertController *alertController in _alertControllers) {
[alertController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
}
```
Since we use weak container, _alertControllers should only contains the currently opened alerts.
I test this way: Put a breakpoint in invalidate, open the UIExplorer play with the 'Alert' & 'AlertIOS' examples, then fire a reload and see if _alertControllers contains the expected values.
Closes https://github.com/facebook/react-native/pull/10407
Differential Revision: D4078649
Pulled By: lacker
fbshipit-source-id: 8509e7e7142379a81d5b28c9067c085bad8bb5cb
Summary:
- Consolidate common code in iOS and tvOS test scripts
- Start the packager before starting tests, to improve reliability
- Increase timeout value in RCTTestRunner.m
Closes https://github.com/facebook/react-native/pull/10378
Differential Revision: D4028364
Pulled By: bestander
fbshipit-source-id: 24c2124a1c62643a02f0668b60a67b971e08d1a3
Summary:
This fixes the following problem on iPad (happens when trying to show the devmenu ActionSheet):
> Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController () of style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem. If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'
I see 2 ways of fixing the issue: falling back to Alert (always displayed in the center) or adding a fake view somewhere on the screen to display the ActionSheet.
Reviewed By: mmmulani
Differential Revision: D3989672
fbshipit-source-id: 59fabc50ec1aac3ae6ddd7ecf4d8e8e5b9586dba
Summary:
* Motivation *
Second PR for Apple TV support.
* Test plan *
Apple TV tests have been added to scripts/objc-test.sh
Closes https://github.com/facebook/react-native/pull/10227
Differential Revision: D3974064
Pulled By: javache
fbshipit-source-id: 36dffb4517efa489e40fa713a30655d1d76ef646
Summary:
Android (starting from API 23) supports "light status bar", thus it is possible to extend StatusBar and make `barStyle` property work not only for iOS, but also for Android.
This PR introduces one more `barStyle` option `dark-content` in addition to two existing ones (`default` and `light-content`).
Why there are 3 options instead of 2?
Two simple reasons:
1) to make all existing applications fully compatible with these changes;
2) the default status bar on Android is dark with white text and icons, while on iOS it is light with black text and icons on it. Thus the `default` option means something like "I don't really care, just apply the default color for this platform", while two other options (`light-content` and `dark-content`) allow to accurately specify the required result.
Closes https://github.com/facebook/react-native/pull/10185
Differential Revision: D3952346
fbshipit-source-id: 999a67614abff52321fbeb06298ebf1946c3f1d1
Summary:
First commit for Apple TV support: changes to existing Objective-C code so that it will compile correctly for tvOS.
Closes https://github.com/facebook/react-native/pull/9649
Differential Revision: D3916021
Pulled By: javache
fbshipit-source-id: 34acc9daf3efff835ffe38c43ba5d4098a02c830
Summary:
Explain the **motivation** for making this change. What existing problem does the pull request solve?
- Being able to call these from JS is really useful in envs where action sheets are not available (eg: App Extensions). I made the functions act as explicit toggles, this way it's easy to set the wanted behavior.
**Test plan (required)**
- I tested the functions manually.
![Remote debug from an iMessage Application](https://cloud.githubusercontent.com/assets/4422516/17445198/976ebfe0-5af8-11e6-885f-1b40f9518aab.png)
Closes https://github.com/facebook/react-native/pull/9242
Differential Revision: D3749568
fbshipit-source-id: 2cea1d609dc792aec73d4bcf1eae07575725b4b7
Summary:
At the moment, posting RCTReloadNotification in any circumstance causes all RCTBridge instances to reload. This change scopes the notification to the bridge for which it was intended.
Closes https://github.com/facebook/react-native/pull/8762
Differential Revision: D3831914
fbshipit-source-id: ff29574f574ecd1a403057ddd0458dea38f0136e
Summary:
Include CSSLayout headers in the same way as other project headers, ie `#import <CSSLayout/CSSLayout.h>` becomes `#import "CSSLayout.h"`. CSSLayout is not a framework or system dependency, so shouldn't (AFAIK) be included with angle brackets. Doing so breaks framework builds, such as when RN is used as a pod in a swift project.
In combination with https://github.com/facebook/css-layout/pull/217 this fixes https://github.com/facebook/react-native/issues/9014 (specifically swift cocoapods projects). There is then no need for a separate CSSLayout pod subspec.
Tests run on the RN project in isolation (with changes inside `CSSLayout` itself also applied) and against a dummy swift project with RN included as a pod.
NB: This effectively reverts https://github.com/facebook/react-native/pull/9015 and may break non-swift cocoapods projects unless https://github.com/facebook/css-layout/pull/217 is merged and synced first.
Update: As discussed with alloy and emilsjolander, wrap these imports in a preprocess
Closes https://github.com/facebook/react-native/pull/9544
Differential Revision: D3821791
Pulled By: javache
fbshipit-source-id: d27ac8be9ce560d03479b43d3db740cd196c24da
Summary: added API to in UIManager to find the rootTag/View of any reactTag based on its layout (shadow views) hierarchy (not to be used by JS)
Reviewed By: javache
Differential Revision: D3750410
fbshipit-source-id: 68611e39930d53ece478f25245ddc7f7838daaa6
Summary:
1. Provide forceRTL function for developer to test RTL layout in LTR language bundle in I18nUtil and expose it in I18nManager.
2. Rename `allowRTL` and `setAllowRTL` functions
Reviewed By: fkgozali
Differential Revision: D3663693
fbshipit-source-id: 3db13a44c069ae73d1728c211306422db5dd8122
Summary:
When call `[RCTDevMenu invalidate]`, it will cancel updateTask. But in fact, after the `[updateTask cancel]`, the updateTask's completionHandler will call `checkForUpdates` again, so it will create a new updateTask.
Closes https://github.com/facebook/react-native/pull/6165
Differential Revision: D3669576
Pulled By: javache
fbshipit-source-id: 443924b7f4be1716797fc5690e90d962cf31b923
Summary:
Sometimes is handy to check if a React node is a descendant of another node or not. For instance, I want to check if the focused `TextInput` is descendant of an specific `ScrollView`:
```js
const currentlyFocusedField = TextInput.State.currentlyFocusedField()
UIManager.viewIsAncestorOf(
currentlyFocusedField,
this.getInnerViewNode(),
(isAncestor) => {
if (isAncestor) {
console.log('The focused field is a descendant of this ScrollView!')
}
}
)
```
This function uses the same strategy as the `measureLayout` method to check if one node is an ancestor of other node. As the `measureLayout` method, this is performed outside the main thread.
By now I've only implemented the iOS version and its tests, but if this function is going to be merged I'll implement the Android version too. I have objc experience but no Java or Android, so I prefer to validate this functionality before jumping into developing the Android part.
Closes https://github.com/facebook/react-native/pull/7876
Differential Revision: D3662045
Pulled By: javache
fbshipit-source-id: b9668e8ea94fd01db76651f16243926cf9c2566f
Summary:
As per javache comments in #8734.
Also removes now useless feature detection check.
**Test plan**
Tested that rIC still works in UIExplorer example.
Closes https://github.com/facebook/react-native/pull/8795
Differential Revision: D3572566
Pulled By: javache
fbshipit-source-id: 261d13d8b03898313f8b4184d634c70f81a61b62
Summary:
iOS follow up to #8569. This currently depends on the Android PR since it contains the JS implementation, only review the last commit. Just putting this out here for visibility, don't merge this before the Android PR.
**Test plan**
Tested by running a background task that burns all remaining idle time (see UIExplorer example).
Tested that native only calls into JS when there are pending idle callbacks.
Tested that timers are executed before idle callback.
Closes https://github.com/facebook/react-native/pull/8734
Differential Revision: D3560818
fbshipit-source-id: a28d3092377a7fd4331647148d40fe69e4198c7e
Summary:
Attempt to fix#7919.
Currently, if the app is launched into the background and you read `AppState.currentState` too soon, you will see the value `'active'` instead of `'background'`. This is because the default value of `AppState.currentState` is hardcoded to be `'active'` and it is initialized with the actual value asynchronously.
This attempts to fix the bug by having the `RCTAppState` module provide the initial state as a module constant.
As noted in #7919, it looks like this fix was already tried and reverted with 0fb3d8de83. zjj010104, hedgerwang, nicklockwood -- can you explain why? I would very much like to get this bug fixed. Nobody has followed up on the issue I filed so I decided to just go ahead and make a PR with my best guess at a fix.
**Test plan (required)**
Built a small app as described in the repro steps for #7919 and verified that, when the app is launched into the background, `init currentState: background` is printed. Also verified that `i
Closes https://github.com/facebook/react-native/pull/8058
Differential Revision: D3554619
fbshipit-source-id: 5d950b85e335765552bbd3cf6ed91534062e35a1
Summary:
By default we run the the JS display link, even if there are no modules listening. Given that most listeners will be lazily constructed, let's make it paused by default.
Since RCTTiming almost never unpauses due to some long-lived timers, implement a sleep timer that pauses the displaylink but uses an NSTimer to wake up in time.
Reviewed By: mhorowitz
Differential Revision: D3235044
fbshipit-source-id: 4a340fea552ada1bd8bc0d83b596a7df6f992387
Summary:
Currently React Native codebase treats JS stack traces as array of dictionaries.
This diff switches the Red Box to use new `RCTJSStackFrame` for internal data representation, while keeping the exposed API unchanged. The next step would be to replace the rest of manual parsing and usage of dictionaries.
The new class has ability to parse the stack from raw strings or dictionaries.
Depends on D3429031
Reviewed By: javache
Differential Revision: D3473199
fbshipit-source-id: 90d2a4f5e8e054b75c99905f35c2ee54927bb311
Summary:
Delete the bridge functions(isRTL, allowRTL()) in internal module and move to OSS.
Create bridge for RCTI18nUtil
Reviewed By: fkgozali
Differential Revision: D3519224
fbshipit-source-id: 3853edcfcc78777d957874448117de72ae0700b5
Summary: Rename the forceRTL to allowRTL so that make it much clear to read. And change a typo.
Reviewed By: fkgozali
Differential Revision: D3489235
fbshipit-source-id: b9803dfbcda2f764b7e752c9810cfc7a0b9fe39b
Summary: Provide function that could read the language currently used in the app, so the isRTL is using the app current using language to set isRTL.
Reviewed By: fkgozali
Differential Revision: D3480654
fbshipit-source-id: dea3ef4769296f594f7f32da2961b4fec1b99a7a
Summary: Create isDeviceLanguageRTL function to connect the OS language with isRTL. Now even if a new app could support RTL language, without setting forceRTL at JS side it won't directly change into RTL layout.
Reviewed By: fkgozali
Differential Revision: D3473109
fbshipit-source-id: ac1410c910e980d44750bb88cad7615febb9e076
Summary: Create a module for React Native to get IsRTL information and set ForceRTL function.
Reviewed By: fkgozali
Differential Revision: D3446871
fbshipit-source-id: 736edf138a89d222818071370ac49dc54bda63b7