Commit Graph

11797 Commits

Author SHA1 Message Date
Alex Dvornikov 2f952fbaac Initial implementation of multiple RAM bundles registry
Differential Revision: D5850963

fbshipit-source-id: e1bd6d74953872d38e73a20f6d054905a7e4c80c
2017-09-21 08:51:00 -07:00
Alex Dvornikov da2ea2601b Allow "nativeRequire" to accept "bundleId" and "moduleId" values
Differential Revision: D5850960

fbshipit-source-id: 4d7aa0ed7542181861649a2089d90c3cf98723e9
2017-09-21 08:51:00 -07:00
Alexey Lang b9be9a01a9 Break down PRE_REACT_CONTEXT
Reviewed By: cwdick

Differential Revision: D5874529

fbshipit-source-id: 0ee9d740b4445419e3143942514475751763520d
2017-09-21 08:04:08 -07:00
Mingwei Pan 67d0cc5c08 Improve formatting of YogaNode.print() on Android
Reviewed By: emilsjolander

Differential Revision: D5842889

fbshipit-source-id: 8ecc829dc43614934c47fd3a68317259e403325a
2017-09-21 07:50:57 -07:00
Emil Sjolander 244045edea Revert D5874862: [yoga][PR] Fix shrinking in non strech alignments
Differential Revision: D5874862

fbshipit-source-id: 24517d26b18c11fb9f75c6d3b5faae360711ea9e
2017-09-21 03:50:11 -07:00
Adam Miskiewicz 26133beda9 Add closed-form damped harmonic oscillator algorithm to Animated.spring
Summary:
As I was working on mimicking iOS animations for my ongoing work with `react-navigation`, one task I had was to match the "push from right" animation that is common in UINavigationController.

I was able to grab the exact animation values for this animation with some LLDB magic, and found that the screen is animated using a `CASpringAnimation` with the parameters:

- stiffness: 1000
- damping: 500
- mass: 3

After spending a considerable amount of time attempting to replicate the spring created with these values by CASpringAnimation by specifying values for tension and friction in the current `Animated.spring` implementation, I was unable to come up with mathematically equivalent values that could replicate the spring _exactly_.

After doing some research, I ended up disassembling the QuartzCore framework, reading the assembly, and determined that Apple's implementation of `CASpringAnimation` does not use an integrated, numerical animation model as we do in Animated.spring, but instead solved for the closed form of the equations that govern damped harmonic oscillation (the differential equations themselves are [here](https://en.wikipedia.org/wiki/Harmonic_oscillator#Damped_harmonic_oscillator), and a paper describing the math to arrive at the closed-form solution to the second-order ODE that describes the DHO is [here](http://planetmath.org/sites/default/files/texpdf/39745.pdf)).

Though we can get the currently implemented RK4 integration close by tweaking some values, it is, the current model is at it's core, an approximation. It seemed that if I wanted to implement the `CASpringAnimation` behavior _exactly_, I needed to implement the analytical model (as is implemented in `CASpringAnimation`) in `Animated`.

We add three new optional parameters to `Animated.spring` (to both the JS and native implementations):

- `stiffness`, a value describing the spring's stiffness coefficient
- `damping`, a value defining how the spring's motion should be damped due to the forces of friction (technically called the _viscous damping coefficient_).
- `mass`, a value describing the mass of the object attached to the end of the simulated spring

Just like if a developer were to specify `bounciness`/`speed` and `tension`/`friction` in the same config, specifying any of these new parameters while also specifying the aforementioned config values will cause an error to be thrown.

~Defaults for `Animated.spring` across all three implementations (JS/iOS/Android) stay the same, so this is intended to be *a non-breaking change*.~

~If `stiffness`, `damping`, or `mass` are provided in the config, we switch to animating the spring with the new damped harmonic oscillator model (`DHO` as described in the code).~

We replace the old RK4 integration implementation with our new analytic implementation. Tension/friction nicely correspond directly to stiffness/damping with the mass of the spring locked at 1. This is intended to be *a non-breaking change*, but there may be very slight differences in people's springs (maybe not even noticeable to the naked eye), given the fact that this implementation is more accurate.

The DHO animation algorithm will calculate the _position_ of the spring at time _t_ explicitly and in an analytical fashion, and use this calculation to update the animation's value. It will also analytically calculate the velocity at time _t_, so as to allow animated value tracking to continue to work as expected.

Also, docs have been updated to cover the new configuration options (and also I added docs for Animated configuration options that were missing, such as `restDisplacementThreshold`, etc).

Run tests. Run "Animated Gratuitous App" and "NativeAnimation" example in RNTester.
Closes https://github.com/facebook/react-native/pull/15322

Differential Revision: D5794791

Pulled By: hramos

fbshipit-source-id: 58ed9e134a097e321c85c417a142576f6a8952f8
2017-09-20 23:38:16 -07:00
Adam King 4d54b48167 Fix onSubmitEditing dispatch behavior with blurOnSubmit/multiline combinations.
Summary:
Fixes https://github.com/facebook/react-native/issues/15863 on master. Behavior of `onSubmitEditing` is now consistent between iOS and Android. Tapping the submit button in a TextInput dispatches the event precisely when doing so does not make a newline (when blurOnSubmit is true or multiline is false).

1. Run this app on iOS and Android:
```
// flow

import React, { Component } from 'react';
import {
  StyleSheet,
  TextInput,
  View
} from 'react-native';

type State = {
  toggled: boolean
};

type Props = {
  blurOnSubmit: boolean,
  multiline: boolean
};

class ToggleColorInput extends Component<Props, State> {
  state: State = {
    toggled: false
  };

  props: Props;

  toggle = () => {
    this.setState({
      toggled: !this.state.toggled
    });
  }

  render() {
    return (
      <TextInput
        blurOnSubmit={this.props.blurOnSubmit}
        multiline={this.props.multiline}
        onSubmitEditing={this.toggle}
        style={[styles.textInput, {backgroundColor: this.state.toggled ? 'blue' : 'azure'}]}
        underlineColorAndroid='transparent'
      />
    )
  }
}

export default class App extends Component<{}> {
  render() {
    return (
      <View>
        <ToggleColorInput blurOnSubmit={true} multiline={true} />
        <ToggleColorInput blurOnSubmit={true} multiline={false} />
        <ToggleColorInput blurOnSubmit={false} multiline={true} />
        <ToggleColorInput blurOnSubmit={false} multiline={false} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  textInput: {
    height: 75,
    borderWidth: 1,
    borderColor: 'black'
  }
});
```
2. You see four TextInputs, with each combination of the `blurOnSubmit` and `multiline` properties. For each TextInput, type some text and tap the submit button.
3. The TextInputs in this test will toggle background color when they emit an `onSubmitEditing` event. Verify the following behavior on each platform:
 * blurOnSubmit && isMultiline => Submit event emitted, blurred, no newline inserted
 * blurOnSubmit && !isMultiline => Submit event emitted, blurred
 * !blurOnSubmit && isMultiline => Submit event emitted, newline inserted
 * !blurOnSubmit && !isMultiline => Submit event emitted
Closes https://github.com/facebook/react-native/pull/16040

Differential Revision: D5877401

Pulled By: shergin

fbshipit-source-id: 741bcc06d8b69d7025f2cb42dd0bee4fa01cd88e
2017-09-20 16:33:14 -07:00
Lukas Wöhrl aa8eb806ca Fix shrinking in non strech alignments
Summary:
This fixes shrinking of elements which are in a non stretch alignment

Fixes #633
Closes https://github.com/facebook/yoga/pull/634

Differential Revision: D5874862

Pulled By: emilsjolander

fbshipit-source-id: 1426aa6b60f6ba42c2be702e6f24cea935ab7acb
2017-09-20 13:31:11 -07:00
Aaron Chiu 565a24140b add Native Module init
Reviewed By: achen1

Differential Revision: D5740540

fbshipit-source-id: 9989424812fdcfd0a54c2ccf1e973aa7cc2a1f67
2017-09-20 10:57:12 -07:00
Andrew Chen (Eng) 08befb730b Add interface for ReactShadowNode
Reviewed By: AaaChiuuu

Differential Revision: D5871546

fbshipit-source-id: 7c338fe3b747a79377a54867c789028d221b3dd5
2017-09-20 08:47:32 -07:00
Kathy Gray 6334ed2ff3 Detangle destroy and create accesses
Differential Revision: D5823786

fbshipit-source-id: d6a6e29b856361a6b1d5ab48397607a844b5ab53
2017-09-20 05:08:03 -07:00
Lee Byron 628cbe170b Synchronize all relay packages
Reviewed By: mjmahone

Differential Revision: D5842774

fbshipit-source-id: 40c57619901e15b0baa62c59837fc887c100652b
2017-09-19 22:50:29 -07:00
Justin Reynolds 3ae45d5cb8 Fix Content-Type header checking of React/RCTJavascriptLoader.mm #15791
Summary:
To fix this issue: https://github.com/facebook/react-native/issues/15791
Closes https://github.com/facebook/react-native/pull/15792

Differential Revision: D5813101

Pulled By: shergin

fbshipit-source-id: fd3eb6f1d9ccdeb5373d1ba2b2df173ff7a8e986
2017-09-19 19:50:07 -07:00
Naman Goel 11963d824d Fix Flow errors in ListViewData source.
Differential Revision: D5839414

fbshipit-source-id: 7a0c7b3d27be728c74e08d3a8209deb3ca68dd63
2017-09-19 16:57:41 -07:00
Christian Brevik f426a83d1b Add props for overriding native component
Summary:
Opening a new PR for #10946 (see discussion there).

This PR builds upon #14775 (iOS ViewManager inheritance) and #14261 (more extensible Android WebView).

**Motivation**
When `WebView.android.js` and `WebView.ios.js` use `requireNativeComponent`, they are hard-coded to require `RCTWebView`. This means if you want to re-use the same JS-logic, but require a custom native WebView-implementation, you have to duplicate the entire JS-code files.

The same is true if you want to pass through any custom events or props, which you want to set on the custom native `WebView`.

What I'm trying to solve with this PR is to able to extend native WebView logic, and being able to re-use and extend existing WebView JS-logic.

This is done by adding a new `nativeConfig` prop on WebView. I've also moved the  extra `requireNativeComponent` config to `WebView.extraNativeComponentConfig` for easier re-use.

**Test plan**
jacobp100 has been kind enough to help me with docs for this new feature. So that is part of the PR and can be read for some information.

I've also created an example app which demonstrates how to use this functionality: https://github.com/cbrevik/webview-native-config-example

If you've implemented the native side as in the example repo above, it should be fairly easy to use from JavaScript like this:
```javascript
import React, { Component, PropTypes } from 'react';
import { WebView, requireNativeComponent, NativeModules } from 'react-native';
const { CustomWebViewManager } = NativeModules;

export default class CustomWebView extends Component {
  static propTypes = {
    ...WebView.propTypes,
    finalUrl: PropTypes.string,
    onNavigationCompleted: PropTypes.func,
  };

  _onNavigationCompleted = (event) => {
    const { onNavigationCompleted } = this.props;
    onNavigationCompleted && onNavigationCompleted(event);
  }

  render() {
    return (
      <WebView
        {...this.props}
        nativeConfig={{
          component: RCTCustomWebView,
          props: {
            finalUrl: this.props.finalUrl,
            onNavigationCompleted: this._onNavigationCompleted,
          },
          viewManager: CustomWebViewManager
        }}
      />
    );
  }
}

const RCTCustomWebView = requireNativeComponent(
  'RCTCustomWebView',
  CustomWebView,
  WebView.extraNativeComponentConfig
);
```

As you see, you require the custom native implementation at the bottom, and send in that along with any custom props with the `nativeConfig` prop on the `WebView`. You also send in the `viewManager` since iOS requires that for `startLoadWithResult`.

**Discussion**
As noted in the original PR, this could in principle be done with more React Native components, to make it easier for the community to re-use and extend native components.
Closes https://github.com/facebook/react-native/pull/15016

Differential Revision: D5701280

Pulled By: hramos

fbshipit-source-id: 6c3702654339b037ee81d190c623b8857550e972
2017-09-19 16:01:02 -07:00
Brian Vaughn ed77dbb5ae Fixed package.json peerDependencies
Reviewed By: sophiebits

Differential Revision: D5860751

fbshipit-source-id: 634ccf22d40bf80eabed467cb1c874f5b02c4f8d
2017-09-19 15:46:14 -07:00
Drew Smith c25a3db662 Revert faulty change to HelloWorld demo in docs
Summary:
Related to commit/diff:
6e99e314b2 (diff-692279cda23c48738b9688454811448a)

The above change breaks "HelloWorld" demo in docs, as you can see at the bottom of the below screenshot:
![image](https://user-images.githubusercontent.com/5363847/30427914-9477d4ee-9949-11e7-8be6-3d6990d6e267.png)

This pull request reverts things just enough to get the demo working correctly again.

I'm new to react-native so I'm not sure if there is another (read: better) solution but by accepting this pull request it would prevent noobs like myself from falling at the first hurdle!
Closes https://github.com/facebook/react-native/pull/15947

Differential Revision: D5866110

Pulled By: hramos

fbshipit-source-id: a453e4373b8af528e3ef2fa6a5a029ff398b0398
2017-09-19 15:46:14 -07:00
Trevor Brindle e99fbfcfa9 add node/npm version to ISSUE_TEMPLATE.md
Summary:
A huge number of Issues are opened with some key information about node/npm versions missing. Adding this information as a required part of the ISSUE_TEMPLATE may help issues get closed faster.

Once merged in, check ISSUE_TEMPLATE by opening new issue, verify new line is there.
Closes https://github.com/facebook/react-native/pull/14422

Differential Revision: D5865411

Pulled By: hramos

fbshipit-source-id: 70e776c8635de38fb149471656e6d260f9eb2537
2017-09-19 15:05:35 -07:00
Valentin Shergin 6b11259c46 Fixed issue with measuring text with NaN width
Summary:
Looks like `-[NSLayoutManager ensureLayoutForTextContainer:textContainer]` has a bug that cause infinite loop inside this method
during measuring some special characters AND when specified `width` equals NaN (which is useless anyways).

So, we cover this case in this diff.

Reviewed By: javache

Differential Revision: D5859767

fbshipit-source-id: 58a5910f21f282bf5b82494916b5b02ad72d357f
2017-09-19 14:16:41 -07:00
Chris Lewis a43a988128 Document Android native communication
Summary:
Native communication is documented for iOS but not Android. Typically pages in Guides (IOS) and Guides (Android) share a common structure/content but provide language specific examples.

I followed this pattern with the Android native communication documentation. It is missing some content that the iOS documentation contains, such as the layout computation flow. But provides a solid base for future efforts.

Ran local instance of React Native website. Went to http://localhost:8079 and read through the new page (react-native/docs/communication-android.html). Also tested links two/from the page.

As a result of this link testing, I updated the Native Modules Android documentation to link to the Apple TV documentation, as it is now the previous page on the navigation sidebar.
Closes https://github.com/facebook/react-native/pull/14316

Differential Revision: D5865137

Pulled By: hramos

fbshipit-source-id: 10ec7d2b08667e70bc38576ecc56da457859e8b1
2017-09-19 14:16:41 -07:00
Aaron Chiu 12f123d3e4 add JS->Java Bridge traffic
Reviewed By: achen1

Differential Revision: D5740501

fbshipit-source-id: 3a88cd95d3a58aac24968e577f4eb3096d47d4ec
2017-09-19 12:03:15 -07:00
Dmitry Zakharov 4fc9e20fce Untangle NativeAnimatedNodesManager from UIManager internals.
Reviewed By: AaaChiuuu

Differential Revision: D5861523

fbshipit-source-id: 39eb79b91d4d5e2295d03369f1be585ae7836c75
2017-09-19 10:00:52 -07:00
David Vacca 5180995666 Fix setBackground for Android sdk version 15 and below
Reviewed By: achen1

Differential Revision: D5854430

fbshipit-source-id: 1276f3d7e94b757f9a9dd412a2ef8b72e8427ffb
2017-09-19 09:39:45 -07:00
Kang Zhang 87a1dc4b76 rename catalyst animations
Reviewed By: achen1

Differential Revision: D5855613

fbshipit-source-id: 2eac7ba6a9d95f6cd3a58a1df4ec0b170f34d6ed
2017-09-19 07:33:42 -07:00
Alex Dvornikov 01bcbd44e7 Unbreak ReactLegacy project
Reviewed By: shergin

Differential Revision: D5854859

fbshipit-source-id: 96d4ced9f5481ae1df8741f9d09da4bc939e8ed8
2017-09-19 03:30:05 -07:00
Brian Vaughn ccddbf82d7 Fixed runtime error with ProgressBarAndroid
Reviewed By: yungsters

Differential Revision: D5857305

fbshipit-source-id: 2fc20a848fa4dce5c1ac3fb7e986536618e25548
2017-09-19 00:01:00 -07:00
Tomas Reimers 9e373529f3 Backed out D5792012.
Reviewed By: AaaChiuuu

Differential Revision: D5855139

fbshipit-source-id: 3837769a4da90d9752de75669c6395fabcd3b18b
2017-09-18 21:37:54 -07:00
Max Sherman e764361f93 Add getter for JS Executor Factory
Reviewed By: mhorowitz

Differential Revision: D5857012

fbshipit-source-id: 8c9fc0095c512325968234f48d6728b63d61913d
2017-09-18 21:18:24 -07:00
Michał Gregorczyk 0ee502d125 More useful utilities in jschelpers
Reviewed By: mhorowitz

Differential Revision: D5785204

fbshipit-source-id: 4c5240f24c6a69bb781896d3af32d4d16fc2387c
2017-09-18 18:45:27 -07:00
Michał Gregorczyk d6c519bc96 Base class for all object private data passed to JSC
Reviewed By: amnn

Differential Revision: D5761937

fbshipit-source-id: de88cf8b959fc855c3c0786f817bb6032491c819
2017-09-18 18:45:27 -07:00
Brian Vaughn 8bf8b21613 React sync for revisions abce30f...b5ac963
Reviewed By: sophiebits

Differential Revision: D5853012

fbshipit-source-id: d0ebf12d2c801dc3e232fe18f9cc25e477812350
2017-09-18 16:45:26 -07:00
Valentin Shergin 9d9e250d28 Using `indexOfObjectIdenticalTo` instead of `indexOfObject` in RCTUIManager
Summary:
This should be much more performant (and it better illustrates the intension of the code).
The fix was suggested by Adlai-Holler.

Reviewed By: mmmulani

Differential Revision: D5851595

fbshipit-source-id: 45d172a5fa796549c6dcea8f35c5cbb2a4c2d2e0
2017-09-18 15:46:11 -07:00
Valentin Shergin d7f6208649 Fixing clowntown in RCTUIManager
Reviewed By: mmmulani

Differential Revision: D5851596

fbshipit-source-id: 952dc8af4ee2af4522725873187b6281b62642cc
2017-09-18 15:46:11 -07:00
Valentin Shergin 38c8b6dd42 Using mutex inside RCTUIManagerObserverCoordinator instead of GCD
Reviewed By: javache

Differential Revision: D5843832

fbshipit-source-id: f4051755a5de83431f8bed1b765b5d8118b5ab88
2017-09-18 13:46:10 -07:00
Paco Estevez Garcia 6b733a4fe7 Force local builds to use regular JS bundles
Reviewed By: dcaspi

Differential Revision: D5824552

fbshipit-source-id: a435fc0ad5b43a8bd3c6a873a4147c4d92190f4e
2017-09-18 08:00:33 -07:00
Alex Dvornikov 6e281798e8 Refactored executeApplicationScript in RCTCxxBridge
Reviewed By: dcaspi

Differential Revision: D5850957

fbshipit-source-id: d2cacfd99fd7ffca70b0dcf0bf252ea160268c05
2017-09-18 06:45:38 -07:00
Ori Harel 795370789b re #15915 HeadlessJsTaskService is expected to run on UI thread
Summary:
<!--
Thank you for sending the PR! We appreciate you spending the time to work on these changes.

Help us understand your motivation by explaining why you decided to make this change.

You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html

Happy contributing!

-->

Headless tasks are required to run in the main thread, however due to the nature of the React context creation flow, the handler may be returned outside of the main thread, causing the HeadlessJsTaskContext to throw an exception.

Swipe out the app. send push notification from a server that starts a HeadlessJsTaskService
Closes https://github.com/facebook/react-native/pull/15940

Differential Revision: D5852448

Pulled By: foghina

fbshipit-source-id: 54c58a1eb7434dd5de5c39c28f6e068ed15ead9d
2017-09-18 05:30:50 -07:00
Andrew Hansen df8d0d1db9 use `uniqBy` for iteratee support
Summary:
I noticed `uniq` does not take a second parameter the way it's being used here. I think the function what was intended is [uniqBy](https://lodash.com/docs/4.17.4#uniqBy)
Closes https://github.com/facebook/react-native/pull/15615

Differential Revision: D5852155

Pulled By: hramos

fbshipit-source-id: 892d0bf7f24d30c24620350f698ffb416907ccc5
2017-09-18 02:45:32 -07:00
Valentin Shergin 7efd4fabfd Text to Spannable conversion is now using PRIORITY flag to enforce the order of spans
Summary:
When we convert nested <Text> components to Spannable object we must enforce the order of spans somehow,
otherwise we will have Spannable object with unpredictable order of spans, which will produce unpredictalbe text layout.
We can do it only using `Spannable.SPAN_PRIORITY` feature because Spannable objects do not maintain the order of spans internally.

We also have to fix this to implement autoexpandable <TextInput>.

Reviewed By: achen1

Differential Revision: D5811172

fbshipit-source-id: 5bc68b869e58aba27d6986581af9fe3343d116a7
2017-09-17 22:00:16 -07:00
Valentin Shergin 3ff463f6a0 BREAKING: Removed support of nested content inside <Image> on Android
Summary: Use <ImageBackground> instead.

Reviewed By: yungsters

Differential Revision: D5190170

fbshipit-source-id: 29acf99db9a31351dbfe8eeefa61abd439f8618c
2017-09-17 21:34:28 -07:00
Brian Vaughn d1372faeb5 Re-added global event-type Map to UIManager constants
Reviewed By: sophiebits

Differential Revision: D5846806

fbshipit-source-id: 7b0a54bd5a4b877f0c5915f11392ee0d34718dbe
2017-09-15 16:47:16 -07:00
Brian Vaughn 11b40845b0 Added Flow types for React Native host components
Reviewed By: calebmer

Differential Revision: D5844473

fbshipit-source-id: 2893e5a5ee58d147a2f7d351143a7ce0eb8eebe3
2017-09-15 16:22:04 -07:00
Oleksandr Sokolov 2cb87dfacd Bump react/jsx-no-undef (undefined require) from warning to error
Reviewed By: weicool

Differential Revision: D5843154

fbshipit-source-id: 0729cb19e3b3664a235320e908af51b2f56cc4ae
2017-09-15 12:01:04 -07:00
Mingwei Pan d0f36d7a68 Zero out all fields in YGZeroOutLayoutRecursivly using memset
Reviewed By: emilsjolander

Differential Revision: D5842351

fbshipit-source-id: d2c2b6f829588a200525b7ccbdb63003cb4dcc4e
2017-09-15 08:34:26 -07:00
Kathy Gray cf2ef84b16 Move destroy threads in catalystinstance off the UI thread
Reviewed By: cwdick

Differential Revision: D5842135

fbshipit-source-id: e9c44c4129d4d10da8781798df121f5c676766f8
2017-09-15 05:48:57 -07:00
Christoph Nakazawa 2f78d19df2 Use the Config type from Metro
Reviewed By: davidaurelio

Differential Revision: D5832633

fbshipit-source-id: 8e4e0e6a2907e485a5627c87161af2d0672b4f56
2017-09-15 05:00:10 -07:00
Christoph Nakazawa 327a0dd84e Bump metro-bundler dependency to 0.17
Reviewed By: davidaurelio

Differential Revision: D5834180

fbshipit-source-id: 121efc7000bff7aff121d44e6b0b8eed1d4e81ae
2017-09-14 22:16:30 -07:00
Brian Vaughn 75c94a8907 Native view manager event types exposed to JS via view config
Differential Revision: D5814210

fbshipit-source-id: 41291f0d6b39af77f66173f6a699d88f9f4ccc74
2017-09-14 18:17:17 -07:00
Brian Vaughn e9780bdc0f ReactNative sync (c3718c4...abce30f): the one about the Prepack optimizations
Reviewed By: sophiebits

Differential Revision: D5626312

fbshipit-source-id: f8158ccb14f991b681fba34fb23933042266939d
2017-09-14 18:17:17 -07:00
Aaron Chiu 6c2c2ecd8c add some RN Core markers
Reviewed By: achen1

Differential Revision: D5740438

fbshipit-source-id: eca6160e0ff9089e1f70ead0f2269ce152258c19
2017-09-14 12:02:29 -07:00