| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701 | 
							- /**
 -  * Copyright (c) 2018-present, Infinite Red, Inc.
 -  *
 -  * This source code is licensed under the MIT license found in the
 -  * LICENSE file in the root directory of this source tree.
 -  *
 -  * @format
 -  * @noflow
 -  */
 - 
 - 'use strict';
 - 
 - import React from 'react';
 - import PropTypes from 'prop-types';
 - 
 - import ReactNative from 'react-native'
 - import {
 -   ActivityIndicator,
 -   EdgeInsetsPropType,
 -   Linking,
 -   StyleSheet,
 -   Text,
 -   UIManager,
 -   View,
 -   ViewPropTypes,
 -   requireNativeComponent,
 -   NativeModules,
 -   Image
 - } from 'react-native';
 - 
 - import invariant from 'fbjs/lib/invariant';
 - import keyMirror from 'fbjs/lib/keyMirror';
 - 
 - import deprecatedPropType from 'deprecated-prop-type';
 - 
 - import WebViewShared from './WebViewShared';
 - 
 - const resolveAssetSource = Image.resolveAssetSource;
 - 
 - // Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
 - function processDecelerationRate(decelerationRate) {
 -   if (decelerationRate === 'normal') {
 -     decelerationRate = 0.998;
 -   } else if (decelerationRate === 'fast') {
 -     decelerationRate = 0.99;
 -   }
 -   return decelerationRate;
 - }
 - 
 - 
 - const RNCWebViewManager = NativeModules.WebViewManager;
 - 
 - const BGWASH = 'rgba(255,255,255,0.8)';
 - const RCT_WEBVIEW_REF = 'webview';
 - 
 - const WebViewState = keyMirror({
 -   IDLE: null,
 -   LOADING: null,
 -   ERROR: null,
 - });
 - 
 - const NavigationType = keyMirror({
 -   click: true,
 -   formsubmit: true,
 -   backforward: true,
 -   reload: true,
 -   formresubmit: true,
 -   other: true,
 - });
 - 
 - const JSNavigationScheme = 'react-js-navigation';
 - 
 - // type ErrorEvent = {
 - //   domain: any,
 - //   code: any,
 - //   description: any,
 - // };
 - 
 - // type Event = Object;
 - 
 - const DataDetectorTypes = [
 -   'phoneNumber',
 -   'link',
 -   'address',
 -   'calendarEvent',
 -   'none',
 -   'all',
 - ];
 - 
 - const defaultRenderLoading = () => (
 -   <View style={styles.loadingView}>
 -     <ActivityIndicator />
 -   </View>
 - );
 - const defaultRenderError = (errorDomain, errorCode, errorDesc) => (
 -   <View style={styles.errorContainer}>
 -     <Text style={styles.errorTextTitle}>Error loading page</Text>
 -     <Text style={styles.errorText}>{'Domain: ' + errorDomain}</Text>
 -     <Text style={styles.errorText}>{'Error Code: ' + errorCode}</Text>
 -     <Text style={styles.errorText}>{'Description: ' + errorDesc}</Text>
 -   </View>
 - );
 - 
 - /**
 -  * `WebView` renders web content in a native view.
 -  *
 -  *```
 -  * import React, { Component } from 'react';
 -  * import { WebView } from 'react-native';
 -  *
 -  * class MyWeb extends Component {
 -  *   render() {
 -  *     return (
 -  *       <WebView
 -  *         source={{uri: 'https://github.com/facebook/react-native'}}
 -  *         style={{marginTop: 20}}
 -  *       />
 -  *     );
 -  *   }
 -  * }
 -  *```
 -  *
 -  * You can use this component to navigate back and forth in the web view's
 -  * history and configure various properties for the web content.
 -  */
 - class WebView extends React.Component {
 -   static JSNavigationScheme = JSNavigationScheme;
 -   static NavigationType = NavigationType;
 -   static propTypes = {
 -     ...ViewPropTypes,
 - 
 -     html: deprecatedPropType(
 -       PropTypes.string,
 -       'Use the `source` prop instead.',
 -     ),
 - 
 -     url: deprecatedPropType(PropTypes.string, 'Use the `source` prop instead.'),
 - 
 -     /**
 -      * Loads static html or a uri (with optional headers) in the WebView.
 -      */
 -     source: PropTypes.oneOfType([
 -       PropTypes.shape({
 -         /*
 -          * The URI to load in the `WebView`. Can be a local or remote file.
 -          */
 -         uri: PropTypes.string,
 -         /*
 -          * The HTTP Method to use. Defaults to GET if not specified.
 -          * NOTE: On Android, only GET and POST are supported.
 -          */
 -         method: PropTypes.string,
 -         /*
 -          * Additional HTTP headers to send with the request.
 -          * NOTE: On Android, this can only be used with GET requests.
 -          */
 -         headers: PropTypes.object,
 -         /*
 -          * The HTTP body to send with the request. This must be a valid
 -          * UTF-8 string, and will be sent exactly as specified, with no
 -          * additional encoding (e.g. URL-escaping or base64) applied.
 -          * NOTE: On Android, this can only be used with POST requests.
 -          */
 -         body: PropTypes.string,
 -       }),
 -       PropTypes.shape({
 -         /*
 -          * A static HTML page to display in the WebView.
 -          */
 -         html: PropTypes.string,
 -         /*
 -          * The base URL to be used for any relative links in the HTML.
 -          */
 -         baseUrl: PropTypes.string,
 -       }),
 -       /*
 -        * Used internally by packager.
 -        */
 -       PropTypes.number,
 -     ]),
 - 
 -     /**
 -      * Function that returns a view to show if there's an error.
 -      */
 -     renderError: PropTypes.func, // view to show if there's an error
 -     /**
 -      * Function that returns a loading indicator.
 -      */
 -     renderLoading: PropTypes.func,
 -     /**
 -      * Function that is invoked when the `WebView` has finished loading.
 -      */
 -     onLoad: PropTypes.func,
 -     /**
 -      * Function that is invoked when the `WebView` load succeeds or fails.
 -      */
 -     onLoadEnd: PropTypes.func,
 -     /**
 -      * Function that is invoked when the `WebView` starts loading.
 -      */
 -     onLoadStart: PropTypes.func,
 -     /**
 -      * Function that is invoked when the `WebView` load fails.
 -      */
 -     onError: PropTypes.func,
 -     /**
 -      * Boolean value that determines whether the web view bounces
 -      * when it reaches the edge of the content. The default value is `true`.
 -      * @platform ios
 -      */
 -     bounces: PropTypes.bool,
 -     /**
 -      * A floating-point number that determines how quickly the scroll view
 -      * decelerates after the user lifts their finger. You may also use the
 -      * string shortcuts `"normal"` and `"fast"` which match the underlying iOS
 -      * settings for `UIScrollViewDecelerationRateNormal` and
 -      * `UIScrollViewDecelerationRateFast` respectively:
 -      *
 -      *   - normal: 0.998
 -      *   - fast: 0.99 (the default for iOS web view)
 -      * @platform ios
 -      */
 -     decelerationRate: PropTypes.oneOfType([
 -       PropTypes.oneOf(['fast', 'normal']),
 -       PropTypes.number,
 -     ]),
 -     /**
 -      * Boolean value that determines whether scrolling is enabled in the
 -      * `WebView`. The default value is `true`.
 -      * @platform ios
 -      */
 -     scrollEnabled: PropTypes.bool,
 -     /**
 -      * Controls whether to adjust the content inset for web views that are
 -      * placed behind a navigation bar, tab bar, or toolbar. The default value
 -      * is `true`.
 -      */
 -     automaticallyAdjustContentInsets: PropTypes.bool,
 -     /**
 -      * The amount by which the web view content is inset from the edges of
 -      * the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}.
 -      * @platform ios
 -      */
 -     contentInset: EdgeInsetsPropType,
 -     /**
 -      * Function that is invoked when the `WebView` loading starts or ends.
 -      */
 -     onNavigationStateChange: PropTypes.func,
 -     /**
 -      * A function that is invoked when the webview calls `window.postMessage`.
 -      * Setting this property will inject a `postMessage` global into your
 -      * webview, but will still call pre-existing values of `postMessage`.
 -      *
 -      * `window.postMessage` accepts one argument, `data`, which will be
 -      * available on the event object, `event.nativeEvent.data`. `data`
 -      * must be a string.
 -      */
 -     onMessage: PropTypes.func,
 -     /**
 -      * Boolean value that forces the `WebView` to show the loading view
 -      * on the first load.
 -      */
 -     startInLoadingState: PropTypes.bool,
 -     /**
 -      * The style to apply to the `WebView`.
 -      */
 -     style: ViewPropTypes.style,
 - 
 -     /**
 -      * Determines the types of data converted to clickable URLs in the web view's content.
 -      * By default only phone numbers are detected.
 -      *
 -      * You can provide one type or an array of many types.
 -      *
 -      * Possible values for `dataDetectorTypes` are:
 -      *
 -      * - `'phoneNumber'`
 -      * - `'link'`
 -      * - `'address'`
 -      * - `'calendarEvent'`
 -      * - `'none'`
 -      * - `'all'`
 -      *
 -      * @platform ios
 -      */
 -     dataDetectorTypes: PropTypes.oneOfType([
 -       PropTypes.oneOf(DataDetectorTypes),
 -       PropTypes.arrayOf(PropTypes.oneOf(DataDetectorTypes)),
 -     ]),
 - 
 -     /**
 -      * Boolean value to enable JavaScript in the `WebView`. Used on Android only
 -      * as JavaScript is enabled by default on iOS. The default value is `true`.
 -      * @platform android
 -      */
 -     javaScriptEnabled: PropTypes.bool,
 - 
 -     /**
 -      * Boolean value to enable third party cookies in the `WebView`. Used on
 -      * Android Lollipop and above only as third party cookies are enabled by
 -      * default on Android Kitkat and below and on iOS. The default value is `true`.
 -      * @platform android
 -      */
 -     thirdPartyCookiesEnabled: PropTypes.bool,
 - 
 -     /**
 -      * Boolean value to control whether DOM Storage is enabled. Used only in
 -      * Android.
 -      * @platform android
 -      */
 -     domStorageEnabled: PropTypes.bool,
 - 
 -     /**
 -      * Set this to provide JavaScript that will be injected into the web page
 -      * when the view loads.
 -      */
 -     injectedJavaScript: PropTypes.string,
 - 
 -     /**
 -      * Sets the user-agent for the `WebView`.
 -      * @platform android
 -      */
 -     userAgent: PropTypes.string,
 - 
 -     /**
 -      * Boolean that controls whether the web content is scaled to fit
 -      * the view and enables the user to change the scale. The default value
 -      * is `true`.
 -      */
 -     scalesPageToFit: PropTypes.bool,
 - 
 -     /**
 -      * Function that allows custom handling of any web view requests. Return
 -      * `true` from the function to continue loading the request and `false`
 -      * to stop loading.
 -      * @platform ios
 -      */
 -     onShouldStartLoadWithRequest: PropTypes.func,
 - 
 -     /**
 -      * Boolean that determines whether HTML5 videos play inline or use the
 -      * native full-screen controller. The default value is `false`.
 -      *
 -      * **NOTE** : In order for video to play inline, not only does this
 -      * property need to be set to `true`, but the video element in the HTML
 -      * document must also include the `webkit-playsinline` attribute.
 -      * @platform ios
 -      */
 -     allowsInlineMediaPlayback: PropTypes.bool,
 - 
 -     /**
 -      * Boolean that determines whether HTML5 audio and video requires the user
 -      * to tap them before they start playing. The default value is `true`.
 -      */
 -     mediaPlaybackRequiresUserAction: PropTypes.bool,
 - 
 -     /**
 -      * List of origin strings to allow being navigated to. The strings allow
 -      * wildcards and get matched against *just* the origin (not the full URL).
 -      * If the user taps to navigate to a new page but the new page is not in
 -      * this whitelist, we will open the URL in Safari.
 -      * The default whitelisted origins are "http://*" and "https://*".
 -      */
 -     originWhitelist: PropTypes.arrayOf(PropTypes.string),
 - 
 -     /**
 -      * Function that accepts a string that will be passed to the WebView and
 -      * executed immediately as JavaScript.
 -      */
 -     injectJavaScript: PropTypes.func,
 - 
 -     /**
 -      * Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin.
 -      *
 -      * Possible values for `mixedContentMode` are:
 -      *
 -      * - `'never'` (default) - WebView will not allow a secure origin to load content from an insecure origin.
 -      * - `'always'` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
 -      * - `'compatibility'` -  WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
 -      * @platform android
 -      */
 -     mixedContentMode: PropTypes.oneOf(['never', 'always', 'compatibility']),
 - 
 -     /**
 -      * Override the native component used to render the WebView. Enables a custom native
 -      * WebView which uses the same JavaScript as the original WebView.
 -      */
 -     nativeConfig: PropTypes.shape({
 -       /*
 -        * The native component used to render the WebView.
 -        */
 -       component: PropTypes.any,
 -       /*
 -        * Set props directly on the native component WebView. Enables custom props which the
 -        * original WebView doesn't pass through.
 -        */
 -       props: PropTypes.object,
 -       /*
 -        * Set the ViewManager to use for communication with the native side.
 -        * @platform ios
 -        */
 -       viewManager: PropTypes.object,
 -     }),
 -   };
 - 
 -   static defaultProps = {
 -     originWhitelist: WebViewShared.defaultOriginWhitelist,
 -     scalesPageToFit: true,
 -   };
 - 
 -   state = {
 -     viewState: WebViewState.IDLE,
 -     lastErrorEvent: null,
 -     startInLoadingState: true,
 -   };
 - 
 -   UNSAFE_componentWillMount() {
 -     if (this.props.startInLoadingState) {
 -       this.setState({ viewState: WebViewState.LOADING });
 -     }
 -   }
 - 
 -   render() {
 -     let otherView = null;
 - 
 -     if (this.state.viewState === WebViewState.LOADING) {
 -       otherView = (this.props.renderLoading || defaultRenderLoading)();
 -     } else if (this.state.viewState === WebViewState.ERROR) {
 -       const errorEvent = this.state.lastErrorEvent;
 -       invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
 -       otherView = (this.props.renderError || defaultRenderError)(
 -         errorEvent.domain,
 -         errorEvent.code,
 -         errorEvent.description,
 -       );
 -     } else if (this.state.viewState !== WebViewState.IDLE) {
 -       console.error(
 -         'RNCWebView invalid state encountered: ' + this.state.loading,
 -       );
 -     }
 - 
 -     const webViewStyles = [styles.container, styles.webView, this.props.style];
 -     if (
 -       this.state.viewState === WebViewState.LOADING ||
 -       this.state.viewState === WebViewState.ERROR
 -     ) {
 -       // if we're in either LOADING or ERROR states, don't show the webView
 -       webViewStyles.push(styles.hidden);
 -     }
 - 
 -     const nativeConfig = this.props.nativeConfig || {};
 - 
 -     const viewManager = nativeConfig.viewManager || RNCWebViewManager;
 - 
 -     const compiledWhitelist = (this.props.originWhitelist || []).map(
 -       WebViewShared.originWhitelistToRegex,
 -     );
 -     const onShouldStartLoadWithRequest = (event) => {
 -       let shouldStart = true;
 -       const { url } = event.nativeEvent;
 -       const origin = WebViewShared.extractOrigin(url);
 -       const passesWhitelist = compiledWhitelist.some(x =>
 -         new RegExp(x).test(origin),
 -       );
 -       shouldStart = shouldStart && passesWhitelist;
 -       if (!passesWhitelist) {
 -         Linking.openURL(url);
 -       }
 -       if (this.props.onShouldStartLoadWithRequest) {
 -         shouldStart =
 -           shouldStart &&
 -           this.props.onShouldStartLoadWithRequest(event.nativeEvent);
 -       }
 -       viewManager.startLoadWithResult(
 -         !!shouldStart,
 -         event.nativeEvent.lockIdentifier,
 -       );
 -     };
 - 
 -     const decelerationRate = processDecelerationRate(
 -       this.props.decelerationRate,
 -     );
 - 
 -     const source = this.props.source || {};
 -     if (this.props.html) {
 -       source.html = this.props.html;
 -     } else if (this.props.url) {
 -       source.uri = this.props.url;
 -     }
 - 
 -     const messagingEnabled = typeof this.props.onMessage === 'function';
 - 
 -     const NativeWebView = nativeConfig.component || RNCWebView;
 - 
 -     const webView = (
 -       <NativeWebView
 -         ref={RCT_WEBVIEW_REF}
 -         key="webViewKey"
 -         style={webViewStyles}
 -         source={resolveAssetSource(source)}
 -         injectedJavaScript={this.props.injectedJavaScript}
 -         bounces={this.props.bounces}
 -         scrollEnabled={this.props.scrollEnabled}
 -         decelerationRate={decelerationRate}
 -         contentInset={this.props.contentInset}
 -         automaticallyAdjustContentInsets={
 -           this.props.automaticallyAdjustContentInsets
 -         }
 -         onLoadingStart={this._onLoadingStart}
 -         onLoadingFinish={this._onLoadingFinish}
 -         onLoadingError={this._onLoadingError}
 -         messagingEnabled={messagingEnabled}
 -         onMessage={this._onMessage}
 -         onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
 -         scalesPageToFit={this.props.scalesPageToFit}
 -         allowsInlineMediaPlayback={this.props.allowsInlineMediaPlayback}
 -         mediaPlaybackRequiresUserAction={
 -           this.props.mediaPlaybackRequiresUserAction
 -         }
 -         dataDetectorTypes={this.props.dataDetectorTypes}
 -         {...nativeConfig.props}
 -       />
 -     );
 - 
 -     return (
 -       <View style={styles.container}>
 -         {webView}
 -         {otherView}
 -       </View>
 -     );
 -   }
 - 
 -   /**
 -    * Go forward one page in the web view's history.
 -    */
 -   goForward = () => {
 -     UIManager.dispatchViewManagerCommand(
 -       this.getWebViewHandle(),
 -       UIManager.RNCWebView.Commands.goForward,
 -       null,
 -     );
 -   };
 - 
 -   /**
 -    * Go back one page in the web view's history.
 -    */
 -   goBack = () => {
 -     UIManager.dispatchViewManagerCommand(
 -       this.getWebViewHandle(),
 -       UIManager.RNCWebView.Commands.goBack,
 -       null,
 -     );
 -   };
 - 
 -   /**
 -    * Reloads the current page.
 -    */
 -   reload = () => {
 -     this.setState({ viewState: WebViewState.LOADING });
 -     UIManager.dispatchViewManagerCommand(
 -       this.getWebViewHandle(),
 -       UIManager.RNCWebView.Commands.reload,
 -       null,
 -     );
 -   };
 - 
 -   /**
 -    * Stop loading the current page.
 -    */
 -   stopLoading = () => {
 -     UIManager.dispatchViewManagerCommand(
 -       this.getWebViewHandle(),
 -       UIManager.RNCWebView.Commands.stopLoading,
 -       null,
 -     );
 -   };
 - 
 -   /**
 -    * Posts a message to the web view, which will emit a `message` event.
 -    * Accepts one argument, `data`, which must be a string.
 -    *
 -    * In your webview, you'll need to something like the following.
 -    *
 -    * ```js
 -    * document.addEventListener('message', e => { document.title = e.data; });
 -    * ```
 -    */
 -   postMessage = data => {
 -     UIManager.dispatchViewManagerCommand(
 -       this.getWebViewHandle(),
 -       UIManager.RNCWebView.Commands.postMessage,
 -       [String(data)],
 -     );
 -   };
 - 
 -   /**
 -    * Injects a javascript string into the referenced WebView. Deliberately does not
 -    * return a response because using eval() to return a response breaks this method
 -    * on pages with a Content Security Policy that disallows eval(). If you need that
 -    * functionality, look into postMessage/onMessage.
 -    */
 -   injectJavaScript = data => {
 -     UIManager.dispatchViewManagerCommand(
 -       this.getWebViewHandle(),
 -       UIManager.RNCWebView.Commands.injectJavaScript,
 -       [data],
 -     );
 -   };
 - 
 -   /**
 -    * We return an event with a bunch of fields including:
 -    *  url, title, loading, canGoBack, canGoForward
 -    */
 -   _updateNavigationState = (event) => {
 -     if (this.props.onNavigationStateChange) {
 -       this.props.onNavigationStateChange(event.nativeEvent);
 -     }
 -   };
 - 
 -   /**
 -    * Returns the native `WebView` node.
 -    */
 -   getWebViewHandle = () => {
 -     return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
 -   };
 - 
 -   _onLoadingStart = (event) => {
 -     const onLoadStart = this.props.onLoadStart;
 -     onLoadStart && onLoadStart(event);
 -     this._updateNavigationState(event);
 -   };
 - 
 -   _onLoadingError = (event) => {
 -     event.persist(); // persist this event because we need to store it
 -     const { onError, onLoadEnd } = this.props;
 -     onError && onError(event);
 -     onLoadEnd && onLoadEnd(event);
 -     console.warn('Encountered an error loading page', event.nativeEvent);
 - 
 -     this.setState({
 -       lastErrorEvent: event.nativeEvent,
 -       viewState: WebViewState.ERROR,
 -     });
 -   };
 - 
 -   _onLoadingFinish = (event) => {
 -     const { onLoad, onLoadEnd } = this.props;
 -     onLoad && onLoad(event);
 -     onLoadEnd && onLoadEnd(event);
 -     this.setState({
 -       viewState: WebViewState.IDLE,
 -     });
 -     this._updateNavigationState(event);
 -   };
 - 
 -   _onMessage = (event) => {
 -     const { onMessage } = this.props;
 -     onMessage && onMessage(event);
 -   };
 - }
 - 
 - const RNCWebView = requireNativeComponent('RNCWebView');
 - 
 - const styles = StyleSheet.create({
 -   container: {
 -     flex: 1,
 -   },
 -   errorContainer: {
 -     flex: 1,
 -     justifyContent: 'center',
 -     alignItems: 'center',
 -     backgroundColor: BGWASH,
 -   },
 -   errorText: {
 -     fontSize: 14,
 -     textAlign: 'center',
 -     marginBottom: 2,
 -   },
 -   errorTextTitle: {
 -     fontSize: 15,
 -     fontWeight: '500',
 -     marginBottom: 10,
 -   },
 -   hidden: {
 -     height: 0,
 -     flex: 0, // disable 'flex:1' when hiding a View
 -   },
 -   loadingView: {
 -     backgroundColor: BGWASH,
 -     flex: 1,
 -     justifyContent: 'center',
 -     alignItems: 'center',
 -     height: 100,
 -   },
 -   webView: {
 -     backgroundColor: '#ffffff',
 -   },
 - });
 - 
 - module.exports = WebView;
 
 
  |