text:
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.android_webview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.provider.Settings;
import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebSettings.ZoomDensity;

import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.content_public.browser.WebContents;

/**
 * Stores Android WebView specific settings that does not need to be synced to WebKit.
 *
 * Methods in this class can be called from any thread, including threads created by
 * the client of WebView.
 */
@JNINamespace("android_webview")
public class AwSettings {
    private static final String LOGTAG = AwSettings.class.getSimpleName();
    private static final boolean TRACE = false;

    // TODO(hush): Use android.webkit.WebSettings.MENU_ITEM_*. crbug.com/546762.
    private static final int MENU_ITEM_NONE = 0;

    private static final String TAG = "AwSettings";

    // This class must be created on the UI thread. Afterwards, it can be
    // used from any thread. Internally, the class uses a message queue
    // to call native code on the UI thread only.

    // Values passed in on construction.
    private final boolean mHasInternetPermission;

    private ZoomSupportChangeListener mZoomChangeListener;
    private double mDIPScale = 1.0;

    // Lock to protect all settings.
    private final Object mAwSettingsLock = new Object();

    private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
    private int mTextSizePercent = 100;
    private String mStandardFontFamily = "sans-serif";
    private String mFixedFontFamily = "monospace";
    private String mSansSerifFontFamily = "sans-serif";
    private String mSerifFontFamily = "serif";
    private String mCursiveFontFamily = "cursive";
    private String mFantasyFontFamily = "fantasy";
    private String mDefaultTextEncoding = "UTF-8";
    private String mUserAgent;
    private int mMinimumFontSize = 8;
    private int mMinimumLogicalFontSize = 8;
    private int mDefaultFontSize = 16;
    private int mDefaultFixedFontSize = 13;
    private boolean mLoadsImagesAutomatically = true;
    private boolean mImagesEnabled = true;
    private boolean mJavaScriptEnabled = false;
    private boolean mAllowUniversalAccessFromFileURLs = false;
    private boolean mAllowFileAccessFromFileURLs = false;
    private boolean mJavaScriptCanOpenWindowsAutomatically = false;
    private boolean mSupportMultipleWindows = false;
    private PluginState mPluginState = PluginState.OFF;
    private boolean mAppCacheEnabled = false;
    private boolean mDomStorageEnabled = false;
    private boolean mDatabaseEnabled = false;
    private boolean mUseWideViewport = false;
    private boolean mZeroLayoutHeightDisablesViewportQuirk = false;
    private boolean mForceZeroLayoutHeight = false;
    private boolean mLoadWithOverviewMode = false;
    private boolean mMediaPlaybackRequiresUserGesture = true;
    private String mDefaultVideoPosterURL;
    private float mInitialPageScalePercent = 0;
    private boolean mSpatialNavigationEnabled;  // Default depends on device features.
    private boolean mEnableSupportedHardwareAcceleratedFeatures = false;
    private int mMixedContentMode = WebSettings.MIXED_CONTENT_NEVER_ALLOW;
    private boolean mVideoOverlayForEmbeddedVideoEnabled = false;
    private boolean mForceVideoOverlayForTests = false;
    private boolean mOffscreenPreRaster = false;
    private int mDisabledMenuItems = MENU_ITEM_NONE;

    // Although this bit is stored on AwSettings it is actually controlled via the CookieManager.
    private boolean mAcceptThirdPartyCookies = false;

    private final boolean mSupportLegacyQuirks;
    private final boolean mAllowEmptyDocumentPersistence;
    private final boolean mAllowGeolocationOnInsecureOrigins;

    private final boolean mPasswordEchoEnabled;

    // Not accessed by the native side.
    private boolean mBlockNetworkLoads;  // Default depends on permission of embedding APK.
    private boolean mAllowContentUrlAccess = true;
    private boolean mAllowFileUrlAccess = true;
    private int mCacheMode = WebSettings.LOAD_DEFAULT;
    private boolean mShouldFocusFirstNode = true;
    private boolean mGeolocationEnabled = true;
    private boolean mAutoCompleteEnabled = true;
    private boolean mFullscreenSupported = false;
    private boolean mSupportZoom = true;
    private boolean mBuiltInZoomControls = false;
    private boolean mDisplayZoomControls = true;

    static class LazyDefaultUserAgent{
        // Lazy Holder pattern
        private static final String sInstance = nativeGetDefaultUserAgent();
    }

    // Protects access to settings global fields.
    private static final Object sGlobalContentSettingsLock = new Object();
    // For compatibility with the legacy WebView, we can only enable AppCache when the path is
    // provided. However, we don't use the path, so we just check if we have received it from the
    // client.
    private static boolean sAppCachePathIsSet = false;

    // The native side of this object. It's lifetime is bounded by the WebContent it is attached to.
    private long mNativeAwSettings = 0;

    // Custom handler that queues messages to call native code on the UI thread.
    private final EventHandler mEventHandler;

    private static final int MINIMUM_FONT_SIZE = 1;
    private static final int MAXIMUM_FONT_SIZE = 72;

    // Class to handle messages to be processed on the UI thread.
    private class EventHandler {
        // Message id for running a Runnable with mAwSettingsLock held.
        private static final int RUN_RUNNABLE_BLOCKING = 0;
        // Actual UI thread handler
        private Handler mHandler;
        // Synchronization flag.
        private boolean mSynchronizationPending = false;

        EventHandler() {
        }

        void bindUiThread() {
            if (mHandler != null) return;
            mHandler = new Handler(ThreadUtils.getUiThreadLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case RUN_RUNNABLE_BLOCKING:
                            synchronized (mAwSettingsLock) {
                                if (mNativeAwSettings != 0) {
                                    ((Runnable) msg.obj).run();
                                }
                                mSynchronizationPending = false;
                                mAwSettingsLock.notifyAll();
                            }
                            break;
                    }
                }
            };
        }

        void runOnUiThreadBlockingAndLocked(Runnable r) {
            assert Thread.holdsLock(mAwSettingsLock);
            if (mHandler == null) return;
            if (ThreadUtils.runningOnUiThread()) {
                r.run();
            } else {
                assert !mSynchronizationPending;
                mSynchronizationPending = true;
                mHandler.sendMessage(Message.obtain(null, RUN_RUNNABLE_BLOCKING, r));
                try {
                    while (mSynchronizationPending) {
                        mAwSettingsLock.wait();
                    }
                } catch (InterruptedException e) {
                    Log.e(TAG, "Interrupted waiting a Runnable to complete", e);
                    mSynchronizationPending = false;
                }
            }
        }

        void maybePostOnUiThread(Runnable r) {
            if (mHandler != null) {
                mHandler.post(r);
            }
        }

        void updateWebkitPreferencesLocked() {
            runOnUiThreadBlockingAndLocked(new Runnable() {
                @Override
                public void run() {
                    updateWebkitPreferencesOnUiThreadLocked();
                }
            });
        }
    }

    interface ZoomSupportChangeListener {
        public void onGestureZoomSupportChanged(
                boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom);
    }

    public AwSettings(Context context,
            boolean isAccessFromFileURLsGrantedByDefault,
            boolean supportsLegacyQuirks,
            boolean allowEmptyDocumentPersistence,
            boolean allowGeolocationOnInsecureOrigins) {
        boolean hasInternetPermission = context.checkPermission(
                android.Manifest.permission.INTERNET,
                Process.myPid(),
                Process.myUid()) == PackageManager.PERMISSION_GRANTED;
        synchronized (mAwSettingsLock) {
            mHasInternetPermission = hasInternetPermission;
            mBlockNetworkLoads = !hasInternetPermission;
            mEventHandler = new EventHandler();
            if (isAccessFromFileURLsGrantedByDefault) {
                mAllowUniversalAccessFromFileURLs = true;
                mAllowFileAccessFromFileURLs = true;
            }

            mUserAgent = LazyDefaultUserAgent.sInstance;

            // Best-guess a sensible initial value based on the features supported on the device.
            mSpatialNavigationEnabled = !context.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_TOUCHSCREEN);

            // Respect the system setting for password echoing.
            mPasswordEchoEnabled = Settings.System.getInt(context.getContentResolver(),
                    Settings.System.TEXT_SHOW_PASSWORD, 1) == 1;

            // By default, scale the text size by the system font scale factor. Embedders
            // may override this by invoking setTextZoom().
            mTextSizePercent *= context.getResources().getConfiguration().fontScale;

            mSupportLegacyQuirks = supportsLegacyQuirks;
            mAllowEmptyDocumentPersistence = allowEmptyDocumentPersistence;
            mAllowGeolocationOnInsecureOrigins = allowGeolocationOnInsecureOrigins;
        }
        // Defer initializing the native side until a native WebContents instance is set.
    }

    @CalledByNative
    private void nativeAwSettingsGone(long nativeAwSettings) {
        assert mNativeAwSettings != 0 && mNativeAwSettings == nativeAwSettings;
        mNativeAwSettings = 0;
    }

    @CalledByNative
    private double getDIPScaleLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mDIPScale;
    }

    void setDIPScale(double dipScale) {
        synchronized (mAwSettingsLock) {
            mDIPScale = dipScale;
            // TODO(joth): This should also be synced over to native side, but right now
            // the setDIPScale call is always followed by a setWebContents() which covers this.
        }
    }

    void setZoomListener(ZoomSupportChangeListener zoomChangeListener) {
        synchronized (mAwSettingsLock) {
            mZoomChangeListener = zoomChangeListener;
        }
    }

    void setWebContents(WebContents webContents) {
        synchronized (mAwSettingsLock) {
            if (mNativeAwSettings != 0) {
                nativeDestroy(mNativeAwSettings);
                assert mNativeAwSettings == 0;  // nativeAwSettingsGone should have been called.
            }
            if (webContents != null) {
                mEventHandler.bindUiThread();
                mNativeAwSettings = nativeInit(webContents);
                updateEverythingLocked();
            }
        }
    }

    private void updateEverythingLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        assert mNativeAwSettings != 0;
        nativeUpdateEverythingLocked(mNativeAwSettings);
        onGestureZoomSupportChanged(
                supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
    }

    /**
     * See {@link android.webkit.WebSettings#setBlockNetworkLoads}.
     */
    public void setBlockNetworkLoads(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setBlockNetworkLoads=" + flag);
        synchronized (mAwSettingsLock) {
            if (!flag && !mHasInternetPermission) {
                throw new SecurityException("Permission denied - "
                        + "application missing INTERNET permission");
            }
            mBlockNetworkLoads = flag;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getBlockNetworkLoads}.
     */
    public boolean getBlockNetworkLoads() {
        synchronized (mAwSettingsLock) {
            return mBlockNetworkLoads;
        }
    }

    /**
     * Enable/disable third party cookies for an AwContents
     * @param accept true if we should accept third party cookies
     */
    public void setAcceptThirdPartyCookies(boolean accept) {
        if (TRACE) Log.d(LOGTAG, "setAcceptThirdPartyCookies=" + accept);
        synchronized (mAwSettingsLock) {
            if (mAcceptThirdPartyCookies != accept) {
                mAcceptThirdPartyCookies = accept;
            }
        }
    }

    /**
     * Return whether third party cookies are enabled for an AwContents
     * @return true if accept third party cookies
     */
    public boolean getAcceptThirdPartyCookies() {
        synchronized (mAwSettingsLock) {
            return mAcceptThirdPartyCookies;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setAllowFileAccess}.
     */
    public void setAllowFileAccess(boolean allow) {
        if (TRACE) Log.d(LOGTAG, "setAllowFileAccess=" + allow);
        synchronized (mAwSettingsLock) {
            if (mAllowFileUrlAccess != allow) {
                mAllowFileUrlAccess = allow;
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getAllowFileAccess}.
     */
    public boolean getAllowFileAccess() {
        synchronized (mAwSettingsLock) {
            return mAllowFileUrlAccess;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setAllowContentAccess}.
     */
    public void setAllowContentAccess(boolean allow) {
        if (TRACE) Log.d(LOGTAG, "setAllowContentAccess=" + allow);
        synchronized (mAwSettingsLock) {
            if (mAllowContentUrlAccess != allow) {
                mAllowContentUrlAccess = allow;
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getAllowContentAccess}.
     */
    public boolean getAllowContentAccess() {
        synchronized (mAwSettingsLock) {
            return mAllowContentUrlAccess;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setCacheMode}.
     */
    public void setCacheMode(int mode) {
        if (TRACE) Log.d(LOGTAG, "setCacheMode=" + mode);
        synchronized (mAwSettingsLock) {
            if (mCacheMode != mode) {
                mCacheMode = mode;
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getCacheMode}.
     */
    public int getCacheMode() {
        synchronized (mAwSettingsLock) {
            return mCacheMode;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setNeedInitialFocus}.
     */
    public void setShouldFocusFirstNode(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setNeedInitialFocusNode=" + flag);
        synchronized (mAwSettingsLock) {
            mShouldFocusFirstNode = flag;
        }
    }

    /**
     * See {@link android.webkit.WebView#setInitialScale}.
     */
    public void setInitialPageScale(final float scaleInPercent) {
        if (TRACE) Log.d(LOGTAG, "setInitialScale=" + scaleInPercent);
        synchronized (mAwSettingsLock) {
            if (mInitialPageScalePercent != scaleInPercent) {
                mInitialPageScalePercent = scaleInPercent;
                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                    @Override
                    public void run() {
                        if (mNativeAwSettings != 0) {
                            nativeUpdateInitialPageScaleLocked(mNativeAwSettings);
                        }
                    }
                });
            }
        }
    }

    @CalledByNative
    private float getInitialPageScalePercentLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mInitialPageScalePercent;
    }

    void setSpatialNavigationEnabled(boolean enable) {
        synchronized (mAwSettingsLock) {
            if (mSpatialNavigationEnabled != enable) {
                mSpatialNavigationEnabled = enable;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    @CalledByNative
    private boolean getSpatialNavigationLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mSpatialNavigationEnabled;
    }

    void setEnableSupportedHardwareAcceleratedFeatures(boolean enable) {
        synchronized (mAwSettingsLock) {
            if (mEnableSupportedHardwareAcceleratedFeatures != enable) {
                mEnableSupportedHardwareAcceleratedFeatures = enable;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    @CalledByNative
    private boolean getEnableSupportedHardwareAcceleratedFeaturesLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mEnableSupportedHardwareAcceleratedFeatures;
    }

    public void setFullscreenSupported(boolean supported) {
        synchronized (mAwSettingsLock) {
            if (mFullscreenSupported != supported) {
                mFullscreenSupported = supported;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    @CalledByNative
    private boolean getFullscreenSupportedLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mFullscreenSupported;
    }

    /**
     * See {@link android.webkit.WebSettings#setNeedInitialFocus}.
     */
    public boolean shouldFocusFirstNode() {
        synchronized (mAwSettingsLock) {
            return mShouldFocusFirstNode;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setGeolocationEnabled}.
     */
    public void setGeolocationEnabled(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setGeolocationEnabled=" + flag);
        synchronized (mAwSettingsLock) {
            if (mGeolocationEnabled != flag) {
                mGeolocationEnabled = flag;
            }
        }
    }

    /**
     * @return Returns if geolocation is currently enabled.
     */
    boolean getGeolocationEnabled() {
        synchronized (mAwSettingsLock) {
            return mGeolocationEnabled;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setSaveFormData}.
     */
    public void setSaveFormData(final boolean enable) {
        if (TRACE) Log.d(LOGTAG, "setSaveFormData=" + enable);
        synchronized (mAwSettingsLock) {
            if (mAutoCompleteEnabled != enable) {
                mAutoCompleteEnabled = enable;
                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                    @Override
                    public void run() {
                        if (mNativeAwSettings != 0) {
                            nativeUpdateFormDataPreferencesLocked(mNativeAwSettings);
                        }
                    }
                });
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getSaveFormData}.
     */
    public boolean getSaveFormData() {
        synchronized (mAwSettingsLock) {
            return getSaveFormDataLocked();
        }
    }

    @CalledByNative
    private boolean getSaveFormDataLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mAutoCompleteEnabled;
    }

    public void setUserAgent(int ua) {
        // Minimal implementation for backwards compatibility: just supports resetting to default.
        if (ua == 0) {
            setUserAgentString(null);
        } else {
            Log.w(LOGTAG, "setUserAgent not supported, ua=" + ua);
        }
    }

    /**
     * @returns the default User-Agent used by each ContentViewCore instance, i.e. unless
     * overridden by {@link #setUserAgentString()}
     */
    public static String getDefaultUserAgent() {
        return LazyDefaultUserAgent.sInstance;
    }

    /**
     * See {@link android.webkit.WebSettings#setUserAgentString}.
     */
    public void setUserAgentString(String ua) {
        if (TRACE) Log.d(LOGTAG, "setUserAgentString=" + ua);
        synchronized (mAwSettingsLock) {
            final String oldUserAgent = mUserAgent;
            if (ua == null || ua.length() == 0) {
                mUserAgent = LazyDefaultUserAgent.sInstance;
            } else {
                mUserAgent = ua;
            }
            if (!oldUserAgent.equals(mUserAgent)) {
                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                    @Override
                    public void run() {
                        if (mNativeAwSettings != 0) {
                            nativeUpdateUserAgentLocked(mNativeAwSettings);
                        }
                    }
                });
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getUserAgentString}.
     */
    public String getUserAgentString() {
        synchronized (mAwSettingsLock) {
            return getUserAgentLocked();
        }
    }

    @CalledByNative
    private String getUserAgentLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mUserAgent;
    }

    /**
     * See {@link android.webkit.WebSettings#setLoadWithOverviewMode}.
     */
    public void setLoadWithOverviewMode(boolean overview) {
        if (TRACE) Log.d(LOGTAG, "setLoadWithOverviewMode=" + overview);
        synchronized (mAwSettingsLock) {
            if (mLoadWithOverviewMode != overview) {
                mLoadWithOverviewMode = overview;
                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                    @Override
                    public void run() {
                        if (mNativeAwSettings != 0) {
                            updateWebkitPreferencesOnUiThreadLocked();
                            nativeResetScrollAndScaleState(mNativeAwSettings);
                        }
                    }
                });
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getLoadWithOverviewMode}.
     */
    public boolean getLoadWithOverviewMode() {
        synchronized (mAwSettingsLock) {
            return getLoadWithOverviewModeLocked();
        }
    }

    @CalledByNative
    private boolean getLoadWithOverviewModeLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mLoadWithOverviewMode;
    }

    /**
     * See {@link android.webkit.WebSettings#setTextZoom}.
     */
    public void setTextZoom(final int textZoom) {
        if (TRACE) Log.d(LOGTAG, "setTextZoom=" + textZoom);
        synchronized (mAwSettingsLock) {
            if (mTextSizePercent != textZoom) {
                mTextSizePercent = textZoom;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getTextZoom}.
     */
    public int getTextZoom() {
        synchronized (mAwSettingsLock) {
            return getTextSizePercentLocked();
        }
    }

    public void setDefaultZoom(ZoomDensity zoom) {
        if (zoom != ZoomDensity.MEDIUM) {
            Log.w(LOGTAG, "setDefaultZoom not supported, zoom=" + zoom);
        }
    }

    public ZoomDensity getDefaultZoom() {
        // Intentional no-op.
        return ZoomDensity.MEDIUM;
    }

    @CalledByNative
    private int getTextSizePercentLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mTextSizePercent;
    }

    /**
     * See {@link android.webkit.WebSettings#setStandardFontFamily}.
     */
    public void setStandardFontFamily(String font) {
        if (TRACE) Log.d(LOGTAG, "setStandardFontFamily=" + font);
        synchronized (mAwSettingsLock) {
            if (font != null && !mStandardFontFamily.equals(font)) {
                mStandardFontFamily = font;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getStandardFontFamily}.
     */
    public String getStandardFontFamily() {
        synchronized (mAwSettingsLock) {
            return getStandardFontFamilyLocked();
        }
    }

    @CalledByNative
    private String getStandardFontFamilyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mStandardFontFamily;
    }

    /**
     * See {@link android.webkit.WebSettings#setFixedFontFamily}.
     */
    public void setFixedFontFamily(String font) {
        if (TRACE) Log.d(LOGTAG, "setFixedFontFamily=" + font);
        synchronized (mAwSettingsLock) {
            if (font != null && !mFixedFontFamily.equals(font)) {
                mFixedFontFamily = font;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getFixedFontFamily}.
     */
    public String getFixedFontFamily() {
        synchronized (mAwSettingsLock) {
            return getFixedFontFamilyLocked();
        }
    }

    @CalledByNative
    private String getFixedFontFamilyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mFixedFontFamily;
    }

    /**
     * See {@link android.webkit.WebSettings#setSansSerifFontFamily}.
     */
    public void setSansSerifFontFamily(String font) {
        if (TRACE) Log.d(LOGTAG, "setSansSerifFontFamily=" + font);
        synchronized (mAwSettingsLock) {
            if (font != null && !mSansSerifFontFamily.equals(font)) {
                mSansSerifFontFamily = font;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getSansSerifFontFamily}.
     */
    public String getSansSerifFontFamily() {
        synchronized (mAwSettingsLock) {
            return getSansSerifFontFamilyLocked();
        }
    }

    @CalledByNative
    private String getSansSerifFontFamilyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mSansSerifFontFamily;
    }

    /**
     * See {@link android.webkit.WebSettings#setSerifFontFamily}.
     */
    public void setSerifFontFamily(String font) {
        if (TRACE) Log.d(LOGTAG, "setSerifFontFamily=" + font);
        synchronized (mAwSettingsLock) {
            if (font != null && !mSerifFontFamily.equals(font)) {
                mSerifFontFamily = font;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getSerifFontFamily}.
     */
    public String getSerifFontFamily() {
        synchronized (mAwSettingsLock) {
            return getSerifFontFamilyLocked();
        }
    }

    @CalledByNative
    private String getSerifFontFamilyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mSerifFontFamily;
    }

    /**
     * See {@link android.webkit.WebSettings#setCursiveFontFamily}.
     */
    public void setCursiveFontFamily(String font) {
        if (TRACE) Log.d(LOGTAG, "setCursiveFontFamily=" + font);
        synchronized (mAwSettingsLock) {
            if (font != null && !mCursiveFontFamily.equals(font)) {
                mCursiveFontFamily = font;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getCursiveFontFamily}.
     */
    public String getCursiveFontFamily() {
        synchronized (mAwSettingsLock) {
            return getCursiveFontFamilyLocked();
        }
    }

    @CalledByNative
    private String getCursiveFontFamilyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mCursiveFontFamily;
    }

    /**
     * See {@link android.webkit.WebSettings#setFantasyFontFamily}.
     */
    public void setFantasyFontFamily(String font) {
        if (TRACE) Log.d(LOGTAG, "setFantasyFontFamily=" + font);
        synchronized (mAwSettingsLock) {
            if (font != null && !mFantasyFontFamily.equals(font)) {
                mFantasyFontFamily = font;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getFantasyFontFamily}.
     */
    public String getFantasyFontFamily() {
        synchronized (mAwSettingsLock) {
            return getFantasyFontFamilyLocked();
        }
    }

    @CalledByNative
    private String getFantasyFontFamilyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mFantasyFontFamily;
    }

    /**
     * See {@link android.webkit.WebSettings#setMinimumFontSize}.
     */
    public void setMinimumFontSize(int size) {
        if (TRACE) Log.d(LOGTAG, "setMinimumFontSize=" + size);
        synchronized (mAwSettingsLock) {
            size = clipFontSize(size);
            if (mMinimumFontSize != size) {
                mMinimumFontSize = size;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getMinimumFontSize}.
     */
    public int getMinimumFontSize() {
        synchronized (mAwSettingsLock) {
            return getMinimumFontSizeLocked();
        }
    }

    @CalledByNative
    private int getMinimumFontSizeLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mMinimumFontSize;
    }

    /**
     * See {@link android.webkit.WebSettings#setMinimumLogicalFontSize}.
     */
    public void setMinimumLogicalFontSize(int size) {
        if (TRACE) Log.d(LOGTAG, "setMinimumLogicalFontSize=" + size);
        synchronized (mAwSettingsLock) {
            size = clipFontSize(size);
            if (mMinimumLogicalFontSize != size) {
                mMinimumLogicalFontSize = size;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getMinimumLogicalFontSize}.
     */
    public int getMinimumLogicalFontSize() {
        synchronized (mAwSettingsLock) {
            return getMinimumLogicalFontSizeLocked();
        }
    }

    @CalledByNative
    private int getMinimumLogicalFontSizeLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mMinimumLogicalFontSize;
    }

    /**
     * See {@link android.webkit.WebSettings#setDefaultFontSize}.
     */
    public void setDefaultFontSize(int size) {
        if (TRACE) Log.d(LOGTAG, "setDefaultFontSize=" + size);
        synchronized (mAwSettingsLock) {
            size = clipFontSize(size);
            if (mDefaultFontSize != size) {
                mDefaultFontSize = size;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getDefaultFontSize}.
     */
    public int getDefaultFontSize() {
        synchronized (mAwSettingsLock) {
            return getDefaultFontSizeLocked();
        }
    }

    @CalledByNative
    private int getDefaultFontSizeLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mDefaultFontSize;
    }

    /**
     * See {@link android.webkit.WebSettings#setDefaultFixedFontSize}.
     */
    public void setDefaultFixedFontSize(int size) {
        if (TRACE) Log.d(LOGTAG, "setDefaultFixedFontSize=" + size);
        synchronized (mAwSettingsLock) {
            size = clipFontSize(size);
            if (mDefaultFixedFontSize != size) {
                mDefaultFixedFontSize = size;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getDefaultFixedFontSize}.
     */
    public int getDefaultFixedFontSize() {
        synchronized (mAwSettingsLock) {
            return getDefaultFixedFontSizeLocked();
        }
    }

    @CalledByNative
    private int getDefaultFixedFontSizeLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mDefaultFixedFontSize;
    }

    /**
     * See {@link android.webkit.WebSettings#setJavaScriptEnabled}.
     */
    public void setJavaScriptEnabled(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setJavaScriptEnabled=" + flag);
        synchronized (mAwSettingsLock) {
            if (mJavaScriptEnabled != flag) {
                mJavaScriptEnabled = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs}.
     */
    public void setAllowUniversalAccessFromFileURLs(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setAllowUniversalAccessFromFileURLs=" + flag);
        synchronized (mAwSettingsLock) {
            if (mAllowUniversalAccessFromFileURLs != flag) {
                mAllowUniversalAccessFromFileURLs = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setAllowFileAccessFromFileURLs}.
     */
    public void setAllowFileAccessFromFileURLs(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setAllowFileAccessFromFileURLs=" + flag);
        synchronized (mAwSettingsLock) {
            if (mAllowFileAccessFromFileURLs != flag) {
                mAllowFileAccessFromFileURLs = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setLoadsImagesAutomatically}.
     */
    public void setLoadsImagesAutomatically(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setLoadsImagesAutomatically=" + flag);
        synchronized (mAwSettingsLock) {
            if (mLoadsImagesAutomatically != flag) {
                mLoadsImagesAutomatically = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getLoadsImagesAutomatically}.
     */
    public boolean getLoadsImagesAutomatically() {
        synchronized (mAwSettingsLock) {
            return getLoadsImagesAutomaticallyLocked();
        }
    }

    @CalledByNative
    private boolean getLoadsImagesAutomaticallyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mLoadsImagesAutomatically;
    }

    /**
     * See {@link android.webkit.WebSettings#setImagesEnabled}.
     */
    public void setImagesEnabled(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setBlockNetworkImage=" + flag);
        synchronized (mAwSettingsLock) {
            if (mImagesEnabled != flag) {
                mImagesEnabled = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getImagesEnabled}.
     */
    public boolean getImagesEnabled() {
        synchronized (mAwSettingsLock) {
            return mImagesEnabled;
        }
    }

    @CalledByNative
    private boolean getImagesEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mImagesEnabled;
    }

    /**
     * See {@link android.webkit.WebSettings#getJavaScriptEnabled}.
     */
    public boolean getJavaScriptEnabled() {
        synchronized (mAwSettingsLock) {
            return mJavaScriptEnabled;
        }
    }

    @CalledByNative
    private boolean getJavaScriptEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mJavaScriptEnabled;
    }

    /**
     * See {@link android.webkit.WebSettings#getAllowUniversalAccessFromFileURLs}.
     */
    public boolean getAllowUniversalAccessFromFileURLs() {
        synchronized (mAwSettingsLock) {
            return getAllowUniversalAccessFromFileURLsLocked();
        }
    }

    @CalledByNative
    private boolean getAllowUniversalAccessFromFileURLsLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mAllowUniversalAccessFromFileURLs;
    }

    /**
     * See {@link android.webkit.WebSettings#getAllowFileAccessFromFileURLs}.
     */
    public boolean getAllowFileAccessFromFileURLs() {
        synchronized (mAwSettingsLock) {
            return getAllowFileAccessFromFileURLsLocked();
        }
    }

    @CalledByNative
    private boolean getAllowFileAccessFromFileURLsLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mAllowFileAccessFromFileURLs;
    }

    /**
     * See {@link android.webkit.WebSettings#setPluginsEnabled}.
     */
    public void setPluginsEnabled(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setPluginsEnabled=" + flag);
        setPluginState(flag ? PluginState.ON : PluginState.OFF);
    }

    /**
     * See {@link android.webkit.WebSettings#setPluginState}.
     */
    public void setPluginState(PluginState state) {
        if (TRACE) Log.d(LOGTAG, "setPluginState=" + state);
        synchronized (mAwSettingsLock) {
            if (mPluginState != state) {
                mPluginState = state;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getPluginsEnabled}.
     */
    public boolean getPluginsEnabled() {
        synchronized (mAwSettingsLock) {
            return mPluginState == PluginState.ON;
        }
    }

    /**
     * Return true if plugins are disabled.
     * @return True if plugins are disabled.
     */
    @CalledByNative
    private boolean getPluginsDisabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mPluginState == PluginState.OFF;
    }

    /**
     * See {@link android.webkit.WebSettings#getPluginState}.
     */
    public PluginState getPluginState() {
        synchronized (mAwSettingsLock) {
            return mPluginState;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically}.
     */
    public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setJavaScriptCanOpenWindowsAutomatically=" + flag);
        synchronized (mAwSettingsLock) {
            if (mJavaScriptCanOpenWindowsAutomatically != flag) {
                mJavaScriptCanOpenWindowsAutomatically = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically}.
     */
    public boolean getJavaScriptCanOpenWindowsAutomatically() {
        synchronized (mAwSettingsLock) {
            return getJavaScriptCanOpenWindowsAutomaticallyLocked();
        }
    }

    @CalledByNative
    private boolean getJavaScriptCanOpenWindowsAutomaticallyLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mJavaScriptCanOpenWindowsAutomatically;
    }

    /**
     * See {@link android.webkit.WebSettings#setLayoutAlgorithm}.
     */
    public void setLayoutAlgorithm(LayoutAlgorithm l) {
        if (TRACE) Log.d(LOGTAG, "setLayoutAlgorithm=" + l);
        synchronized (mAwSettingsLock) {
            if (mLayoutAlgorithm != l) {
                mLayoutAlgorithm = l;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getLayoutAlgorithm}.
     */
    public LayoutAlgorithm getLayoutAlgorithm() {
        synchronized (mAwSettingsLock) {
            return mLayoutAlgorithm;
        }
    }

    /**
     * Gets whether Text Auto-sizing layout algorithm is enabled.
     *
     * @return true if Text Auto-sizing layout algorithm is enabled
     */
    @SuppressLint("NewApi")  // WebSettings.LayoutAlgorithm#TEXT_AUTOSIZING requires API level 19.
    @CalledByNative
    private boolean getTextAutosizingEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mLayoutAlgorithm == LayoutAlgorithm.TEXT_AUTOSIZING;
    }

    /**
     * See {@link android.webkit.WebSettings#setSupportMultipleWindows}.
     */
    public void setSupportMultipleWindows(boolean support) {
        if (TRACE) Log.d(LOGTAG, "setSupportMultipleWindows=" + support);
        synchronized (mAwSettingsLock) {
            if (mSupportMultipleWindows != support) {
                mSupportMultipleWindows = support;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#supportMultipleWindows}.
     */
    public boolean supportMultipleWindows() {
        synchronized (mAwSettingsLock) {
            return mSupportMultipleWindows;
        }
    }

    @CalledByNative
    private boolean getSupportMultipleWindowsLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mSupportMultipleWindows;
    }

    @CalledByNative
    private boolean getSupportLegacyQuirksLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mSupportLegacyQuirks;
    }

    @CalledByNative
    private boolean getAllowEmptyDocumentPersistenceLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mAllowEmptyDocumentPersistence;
    }

    @CalledByNative
    private boolean getAllowGeolocationOnInsecureOrigins() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mAllowGeolocationOnInsecureOrigins;
    }

    /**
     * See {@link android.webkit.WebSettings#setUseWideViewPort}.
     */
    public void setUseWideViewPort(boolean use) {
        if (TRACE) Log.d(LOGTAG, "setUseWideViewPort=" + use);
        synchronized (mAwSettingsLock) {
            if (mUseWideViewport != use) {
                mUseWideViewport = use;
                onGestureZoomSupportChanged(
                        supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getUseWideViewPort}.
     */
    public boolean getUseWideViewPort() {
        synchronized (mAwSettingsLock) {
            return getUseWideViewportLocked();
        }
    }

    @CalledByNative
    private boolean getUseWideViewportLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mUseWideViewport;
    }

    public void setZeroLayoutHeightDisablesViewportQuirk(boolean enabled) {
        synchronized (mAwSettingsLock) {
            if (mZeroLayoutHeightDisablesViewportQuirk != enabled) {
                mZeroLayoutHeightDisablesViewportQuirk = enabled;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    public boolean getZeroLayoutHeightDisablesViewportQuirk() {
        synchronized (mAwSettingsLock) {
            return getZeroLayoutHeightDisablesViewportQuirkLocked();
        }
    }

    @CalledByNative
    private boolean getZeroLayoutHeightDisablesViewportQuirkLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mZeroLayoutHeightDisablesViewportQuirk;
    }

    public void setForceZeroLayoutHeight(boolean enabled) {
        synchronized (mAwSettingsLock) {
            if (mForceZeroLayoutHeight != enabled) {
                mForceZeroLayoutHeight = enabled;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    public boolean getForceZeroLayoutHeight() {
        synchronized (mAwSettingsLock) {
            return getForceZeroLayoutHeightLocked();
        }
    }

    @CalledByNative
    private boolean getForceZeroLayoutHeightLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mForceZeroLayoutHeight;
    }

    @CalledByNative
    private boolean getPasswordEchoEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mPasswordEchoEnabled;
    }

    /**
     * See {@link android.webkit.WebSettings#setAppCacheEnabled}.
     */
    public void setAppCacheEnabled(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setAppCacheEnabled=" + flag);
        synchronized (mAwSettingsLock) {
            if (mAppCacheEnabled != flag) {
                mAppCacheEnabled = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setAppCachePath}.
     */
    public void setAppCachePath(String path) {
        if (TRACE) Log.d(LOGTAG, "setAppCachePath=" + path);
        boolean needToSync = false;
        synchronized (sGlobalContentSettingsLock) {
            // AppCachePath can only be set once.
            if (!sAppCachePathIsSet && path != null && !path.isEmpty()) {
                sAppCachePathIsSet = true;
                needToSync = true;
            }
        }
        // The obvious problem here is that other WebViews will not be updated,
        // until they execute synchronization from Java to the native side.
        // But this is the same behaviour as it was in the legacy WebView.
        if (needToSync) {
            synchronized (mAwSettingsLock) {
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * Gets whether Application Cache is enabled.
     *
     * @return true if Application Cache is enabled
     */
    @CalledByNative
    private boolean getAppCacheEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        if (!mAppCacheEnabled) {
            return false;
        }
        synchronized (sGlobalContentSettingsLock) {
            return sAppCachePathIsSet;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setDomStorageEnabled}.
     */
    public void setDomStorageEnabled(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setDomStorageEnabled=" + flag);
        synchronized (mAwSettingsLock) {
            if (mDomStorageEnabled != flag) {
                mDomStorageEnabled = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getDomStorageEnabled}.
     */
    public boolean getDomStorageEnabled() {
        synchronized (mAwSettingsLock) {
            return mDomStorageEnabled;
        }
    }

    @CalledByNative
    private boolean getDomStorageEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mDomStorageEnabled;
    }

    /**
     * See {@link android.webkit.WebSettings#setDatabaseEnabled}.
     */
    public void setDatabaseEnabled(boolean flag) {
        if (TRACE) Log.d(LOGTAG, "setDatabaseEnabled=" + flag);
        synchronized (mAwSettingsLock) {
            if (mDatabaseEnabled != flag) {
                mDatabaseEnabled = flag;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getDatabaseEnabled}.
     */
    public boolean getDatabaseEnabled() {
        synchronized (mAwSettingsLock) {
            return mDatabaseEnabled;
        }
    }

    @CalledByNative
    private boolean getDatabaseEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mDatabaseEnabled;
    }

    /**
     * See {@link android.webkit.WebSettings#setDefaultTextEncodingName}.
     */
    public void setDefaultTextEncodingName(String encoding) {
        if (TRACE) Log.d(LOGTAG, "setDefaultTextEncodingName=" + encoding);
        synchronized (mAwSettingsLock) {
            if (encoding != null && !mDefaultTextEncoding.equals(encoding)) {
                mDefaultTextEncoding = encoding;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getDefaultTextEncodingName}.
     */
    public String getDefaultTextEncodingName() {
        synchronized (mAwSettingsLock) {
            return getDefaultTextEncodingLocked();
        }
    }

    @CalledByNative
    private String getDefaultTextEncodingLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mDefaultTextEncoding;
    }

    /**
     * See {@link android.webkit.WebSettings#setMediaPlaybackRequiresUserGesture}.
     */
    public void setMediaPlaybackRequiresUserGesture(boolean require) {
        if (TRACE) Log.d(LOGTAG, "setMediaPlaybackRequiresUserGesture=" + require);
        synchronized (mAwSettingsLock) {
            if (mMediaPlaybackRequiresUserGesture != require) {
                mMediaPlaybackRequiresUserGesture = require;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getMediaPlaybackRequiresUserGesture}.
     */
    public boolean getMediaPlaybackRequiresUserGesture() {
        synchronized (mAwSettingsLock) {
            return getMediaPlaybackRequiresUserGestureLocked();
        }
    }

    @CalledByNative
    private boolean getMediaPlaybackRequiresUserGestureLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mMediaPlaybackRequiresUserGesture;
    }

    /**
     * See {@link android.webkit.WebSettings#setDefaultVideoPosterURL}.
     */
    public void setDefaultVideoPosterURL(String url) {
        synchronized (mAwSettingsLock) {
            if (mDefaultVideoPosterURL != null && !mDefaultVideoPosterURL.equals(url)
                    || mDefaultVideoPosterURL == null && url != null) {
                mDefaultVideoPosterURL = url;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getDefaultVideoPosterURL}.
     */
    public String getDefaultVideoPosterURL() {
        synchronized (mAwSettingsLock) {
            return getDefaultVideoPosterURLLocked();
        }
    }

    @CalledByNative
    private String getDefaultVideoPosterURLLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mDefaultVideoPosterURL;
    }

    private void onGestureZoomSupportChanged(
            final boolean supportsDoubleTapZoom, final boolean supportsMultiTouchZoom) {
        // Always post asynchronously here, to avoid doubling back onto the caller.
        mEventHandler.maybePostOnUiThread(new Runnable() {
            @Override
            public void run() {
                synchronized (mAwSettingsLock) {
                    if (mZoomChangeListener != null) {
                        mZoomChangeListener.onGestureZoomSupportChanged(
                                supportsDoubleTapZoom, supportsMultiTouchZoom);
                    }
                }
            }
        });
    }

    /**
     * See {@link android.webkit.WebSettings#setSupportZoom}.
     */
    public void setSupportZoom(boolean support) {
        if (TRACE) Log.d(LOGTAG, "setSupportZoom=" + support);
        synchronized (mAwSettingsLock) {
            if (mSupportZoom != support) {
                mSupportZoom = support;
                onGestureZoomSupportChanged(
                        supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#supportZoom}.
     */
    public boolean supportZoom() {
        synchronized (mAwSettingsLock) {
            return mSupportZoom;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setBuiltInZoomControls}.
     */
    public void setBuiltInZoomControls(boolean enabled) {
        if (TRACE) Log.d(LOGTAG, "setBuiltInZoomControls=" + enabled);
        synchronized (mAwSettingsLock) {
            if (mBuiltInZoomControls != enabled) {
                mBuiltInZoomControls = enabled;
                onGestureZoomSupportChanged(
                        supportsDoubleTapZoomLocked(), supportsMultiTouchZoomLocked());
            }
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getBuiltInZoomControls}.
     */
    public boolean getBuiltInZoomControls() {
        synchronized (mAwSettingsLock) {
            return mBuiltInZoomControls;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#setDisplayZoomControls}.
     */
    public void setDisplayZoomControls(boolean enabled) {
        if (TRACE) Log.d(LOGTAG, "setDisplayZoomControls=" + enabled);
        synchronized (mAwSettingsLock) {
            mDisplayZoomControls = enabled;
        }
    }

    /**
     * See {@link android.webkit.WebSettings#getDisplayZoomControls}.
     */
    public boolean getDisplayZoomControls() {
        synchronized (mAwSettingsLock) {
            return mDisplayZoomControls;
        }
    }

    public void setMixedContentMode(int mode) {
        synchronized (mAwSettingsLock) {
            if (mMixedContentMode != mode) {
                mMixedContentMode = mode;
                mEventHandler.updateWebkitPreferencesLocked();
            }
        }
    }

    public int getMixedContentMode() {
        synchronized (mAwSettingsLock) {
            return mMixedContentMode;
        }
    }

    @CalledByNative
    private boolean getAllowRunningInsecureContentLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mMixedContentMode == WebSettings.MIXED_CONTENT_ALWAYS_ALLOW;
    }

    @CalledByNative
    private boolean getAllowDisplayingInsecureContentLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mMixedContentMode == WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
                || mMixedContentMode == WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE;
    }

    public boolean getOffscreenPreRaster() {
        synchronized (mAwSettingsLock) {
            return getOffscreenPreRasterLocked();
        }
    }

    @CalledByNative
    private boolean getOffscreenPreRasterLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mOffscreenPreRaster;
    }

    /**
     * Sets whether this WebView should raster tiles when it is
     * offscreen but attached to window. Turning this on can avoid
     * rendering artifacts when animating an offscreen WebView on-screen.
     * In particular, insertVisualStateCallback requires this mode to function.
     * Offscreen WebViews in this mode uses more memory. Please follow
     * these guidelines to limit memory usage:
     * - Webview size should be not be larger than the device screen size.
     * - Limit simple mode to a small number of webviews. Use it for
     *   visible webviews and webviews about to be animated to visible.
     */
    public void setOffscreenPreRaster(boolean enabled) {
        synchronized (mAwSettingsLock) {
            if (enabled != mOffscreenPreRaster) {
                mOffscreenPreRaster = enabled;
                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                    @Override
                    public void run() {
                        if (mNativeAwSettings != 0) {
                            nativeUpdateOffscreenPreRasterLocked(mNativeAwSettings);
                        }
                    }
                });
            }
        }
    }

    public int getDisabledActionModeMenuItems() {
        synchronized (mAwSettingsLock) {
            return mDisabledMenuItems;
        }
    }

    public void setDisabledActionModeMenuItems(int menuItems) {
        synchronized (mAwSettingsLock) {
            if (menuItems != mDisabledMenuItems) {
                mDisabledMenuItems = menuItems;
            }
        }
    }

    /**
     * Sets whether to use the video overlay for the embedded video.
     * @param flag whether to enable the video overlay for the embedded video.
     */
    public void setVideoOverlayForEmbeddedVideoEnabled(final boolean enabled) {
        synchronized (mAwSettingsLock) {
            if (mVideoOverlayForEmbeddedVideoEnabled != enabled) {
                mVideoOverlayForEmbeddedVideoEnabled = enabled;
                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                    @Override
                    public void run() {
                        if (mNativeAwSettings != 0) {
                            nativeUpdateRendererPreferencesLocked(mNativeAwSettings);
                        }
                    }
                });
            }
        }
    }

    /**
     * Gets whether to use the video overlay for the embedded video.
     * @return true if the WebView enables the video overlay for the embedded video.
     */
    public boolean getVideoOverlayForEmbeddedVideoEnabled() {
        synchronized (mAwSettingsLock) {
            return getVideoOverlayForEmbeddedVideoEnabledLocked();
        }
    }

    @CalledByNative
    private boolean getVideoOverlayForEmbeddedVideoEnabledLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mVideoOverlayForEmbeddedVideoEnabled;
    }

    @VisibleForTesting
    public void setForceVideoOverlayForTests(final boolean enabled) {
        synchronized (mAwSettingsLock) {
            if (mForceVideoOverlayForTests != enabled) {
                mForceVideoOverlayForTests = enabled;
                mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                    @Override
                    public void run() {
                        if (mNativeAwSettings != 0) {
                            nativeUpdateRendererPreferencesLocked(mNativeAwSettings);
                        }
                    }
                });
            }
        }
    }

    @VisibleForTesting
    public void updateAcceptLanguages() {
        synchronized (mAwSettingsLock) {
            mEventHandler.runOnUiThreadBlockingAndLocked(new Runnable() {
                @Override
                public void run() {
                    if (mNativeAwSettings != 0) {
                        nativeUpdateRendererPreferencesLocked(mNativeAwSettings);
                    }
                }
            });
        }
    }

    @CalledByNative
    private boolean getForceVideoOverlayForTests() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mForceVideoOverlayForTests;
    }

    @CalledByNative
    private boolean supportsDoubleTapZoomLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mSupportZoom && mBuiltInZoomControls && mUseWideViewport;
    }

    private boolean supportsMultiTouchZoomLocked() {
        assert Thread.holdsLock(mAwSettingsLock);
        return mSupportZoom && mBuiltInZoomControls;
    }

    boolean supportsMultiTouchZoom() {
        synchronized (mAwSettingsLock) {
            return supportsMultiTouchZoomLocked();
        }
    }

    boolean shouldDisplayZoomControls() {
        synchronized (mAwSettingsLock) {
            return supportsMultiTouchZoomLocked() && mDisplayZoomControls;
        }
    }

    private int clipFontSize(int size) {
        if (size < MINIMUM_FONT_SIZE) {
            return MINIMUM_FONT_SIZE;
        } else if (size > MAXIMUM_FONT_SIZE) {
            return MAXIMUM_FONT_SIZE;
        }
        return size;
    }

    @CalledByNative
    private boolean getRecordFullDocument() {
        assert Thread.holdsLock(mAwSettingsLock);
        return AwContentsStatics.getRecordFullDocument();
    }

    @CalledByNative
    private void updateEverything() {
        synchronized (mAwSettingsLock) {
            updateEverythingLocked();
        }
    }

    @CalledByNative
    private void populateWebPreferences(long webPrefsPtr) {
        synchronized (mAwSettingsLock) {
            assert mNativeAwSettings != 0;
            nativePopulateWebPreferencesLocked(mNativeAwSettings, webPrefsPtr);
        }
    }

    private void updateWebkitPreferencesOnUiThreadLocked() {
        assert mEventHandler.mHandler != null;
        ThreadUtils.assertOnUiThread();
        if (mNativeAwSettings != 0) {
            nativeUpdateWebkitPreferencesLocked(mNativeAwSettings);
        }
    }

    private native long nativeInit(WebContents webContents);

    private native void nativeDestroy(long nativeAwSettings);

    private native void nativePopulateWebPreferencesLocked(long nativeAwSettings, long webPrefsPtr);

    private native void nativeResetScrollAndScaleState(long nativeAwSettings);

    private native void nativeUpdateEverythingLocked(long nativeAwSettings);

    private native void nativeUpdateInitialPageScaleLocked(long nativeAwSettings);

    private native void nativeUpdateUserAgentLocked(long nativeAwSettings);

    private native void nativeUpdateWebkitPreferencesLocked(long nativeAwSettings);

    private static native String nativeGetDefaultUserAgent();

    private native void nativeUpdateFormDataPreferencesLocked(long nativeAwSettings);

    private native void nativeUpdateRendererPreferencesLocked(long nativeAwSettings);

    private native void nativeUpdateOffscreenPreRasterLocked(long nativeAwSettings);
}


text:
<resources>
    <string name="app_name">Android Calculator</string>

    <string name="cero">0</string>
    <string name="uno">1</string>
    <string name="dos">2</string>
    <string name="tres">3</string>
    <string name="cuatro">4</string>
    <string name="cinco">5</string>
    <string name="seis">6</string>
    <string name="siete">7</string>
    <string name="ocho">8</string>
    <string name="nueve">9</string>
    <string name="limpiar">C</string>
    <string name="raiz">√ </string>
    <string name="potencia">x^</string>
    <string name="mod">Mod</string>
    <string name="ac">AC</string>
    <string name="log">log</string>
    <string name="raizx">x√</string>
    <string name="fac">n!</string>
    <string name="seno">sen</string>
    <string name="coseno">cos</string>

    <string name="igual">=</string>

</resources>

redpajama_set_name: RedPajamaGithub


text:
function TabularVizDataRow(rowHash, columns) {
  this.data = {};
  this.cells = [];
  this.shown = true;

  // We store the entire data hash, not just the columns for this particular viz.
  // This is important because we may use non-column fields to evaluate a
  // dataShowfor.
  var hashKeys = Object.keys(rowHash);
  for(var i = 0; i < hashKeys.length; i++) {
    var key = hashKeys[i];
    this.data[key] = {
      'label': rowHash[key].label,
      'value': rowHash[key].value,
    };
  }

  // Then we construct the cells separately.
  for(var col = 0; col < columns.length; col++) {
    var column = columns[col];
    // If there's a column missing from the data, provide a helpful error message.
    if(typeof this.data[column.source] === 'undefined') {
      throw new Error('Worksheet is missing a field: "' + column.source + '"');
    }
    this.cells.push({
      'label': this.data[column.source].label,
      'value': this.data[column.source].value,
    });
  }
}


text:
package com.google.gerrit.httpd.rpc.account;

import static com.google.gerrit.reviewdb.AccountExternalId.SCHEME_USERNAME;

import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.AccountExternalId;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;

import java.util.Collections;
import java.util.List;

class ExternalIdDetailFactory extends Handler<List<AccountExternalId>> {
  interface Factory {
    ExternalIdDetailFactory create();
  }

  private final ReviewDb db;
  private final IdentifiedUser user;
  private final AuthConfig authConfig;
  private final WebSession session;

  @Inject
  ExternalIdDetailFactory(final ReviewDb db, final IdentifiedUser user,
      final AuthConfig authConfig, final WebSession session) {
    this.db = db;
    this.user = user;
    this.authConfig = authConfig;
    this.session = session;
  }

  @Override
  public List<AccountExternalId> call() throws OrmException {
    final AccountExternalId.Key last = session.getLastLoginExternalId();
    final List<AccountExternalId> ids =
        db.accountExternalIds().byAccount(user.getAccountId()).toList();

    for (final AccountExternalId e : ids) {
      e.setTrusted(authConfig.isIdentityTrustable(Collections.singleton(e)));

      // The identity can be deleted only if its not the one used to
      // establish this web session, and if only if an identity was
      // actually used to establish this web session.
      //
      if (e.isScheme(SCHEME_USERNAME)) {
        e.setCanDelete(false);
      } else {
        e.setCanDelete(last != null && !last.equals(e.getKey()));
      }
    }
    return ids;
  }
}


text:
APP_NAME = hello_world
SOC ?= quark_d2000
TARGET ?= x86
BASE_DIR := ../..
APP_DIR := .

### Make includes
include $(BASE_DIR)/examples/app.mk


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SocketIo.Core.Tests
{
	public class RandomPort : Random
	{

		public RandomPort() : base()
		{

		}

		public ushort NextPort()
		{
			return (ushort)Next(ushort.MinValue, ushort.MaxValue);
		}

		public static ushort Get()
		{
			return new RandomPort().NextPort();
		}
	}
}


text:
namespace hana = boost::hana;
using namespace std::literals;

int main() {
    auto m = hana::make_map(
        hana::make_pair(hana::int_c<1>, "foobar"s),
        hana::make_pair(hana::type_c<void>, 1234)
    );

    // The order of the values is unspecified.
    BOOST_HANA_RUNTIME_CHECK(
        hana::values(m) ^hana::in^ hana::permutations(hana::make_tuple("foobar"s, 1234))
    );
}


text: <header>Home Page</header>


text:
package blog.model;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import blog.sample.EvalContext;

/**
 * Represents a logical negation of an expression of type Formula.
 *
 * @see blog.model.Formula
 */
public class NegFormula extends Formula {

  public NegFormula(Formula neg) {

    this.neg = neg;

  }

  public Formula getNeg() {

    return neg;

  }

  public Object evaluate(EvalContext context) {
    Boolean negValue = (Boolean) neg.evaluate(context);
    if (negValue == null) {
      return null;
    }

    return Boolean.valueOf(!negValue.booleanValue());
  }

  /**
   * The standard form of a negation formula !psi is determined as follows. If
   * there is a formula equivalent to !psi that is not a negation formula, we
   * return the standard form of that formula. Otherwise, we just return !psi',
   * where psi' is the standard form of psi.
   */
  public Formula getStandardForm() {
    Formula equiv = neg.getEquivToNegation();
    if (equiv == null) {
      return new NegFormula(neg.getStandardForm());
    }
    return equiv.getStandardForm();
  }

  /**
   * A formula equivalent to the negation of !psi is psi itself.
   */
  protected Formula getEquivToNegationInternal() {
    return neg;
  }

  public List<Formula> getSubformulas() {
    return Collections.singletonList(neg);
  }

  /**
   * If this is a literal, then its CNF form is just a conjunction consisting of
   * one disjunction, whose sole disjunct is this formula. Otherwise, its CNF
   * form is the CNF form of the equivalent formula that is not a NegFormula.
   */
  public ConjFormula getPropCNF() {
    Formula equiv = neg.getEquivToNegation();
    if (equiv == null) {
      // can't push negation inside, so this is a literal
      return new ConjFormula(new DisjFormula(this));
    }
    return equiv.getPropCNF();
  }

  /**
   * If this is a literal, then its DNF form is just a disjunction consisting of
   * one conjunction, whose sole conjunct is this formula. Otherwise, its DNF
   * form is the DNF form of the equivalent formula that is not a NegFormula.
   */
  public DisjFormula getPropDNF() {
    Formula equiv = neg.getEquivToNegation();
    if (equiv == null) {
      // can't push negation inside, so this is a literal
      return new DisjFormula(new ConjFormula(this));
    }
    return equiv.getPropDNF();
  }

  /**
   * Returns true if the negated formula is an atomic formula or an equality
   * formula.
   */
  public boolean isLiteral() {
    return ((neg instanceof AtomicFormula) || (neg instanceof EqualityFormula));
  }

  public Set getSatisfiersIfExplicit(EvalContext context, LogicalVar subject,
      GenericObject genericObj) {
    return neg.getNonSatisfiersIfExplicit(context, subject, genericObj);
  }

  public Set getNonSatisfiersIfExplicit(EvalContext context,
      LogicalVar subject, GenericObject genericObj) {
    return neg.getSatisfiersIfExplicit(context, subject, genericObj);
  }

  /**
   * Two NegFormulas are equal if they have the same subformula.
   */
  public boolean equals(Object o) {
    if (o instanceof NegFormula) {
      NegFormula other = (NegFormula) o;
      return neg.equals(other.getNeg());
    }
    return false;
  }

  public int hashCode() {
    return (getClass().hashCode() ^ neg.hashCode());
  }

  /**
   * Returns a string of the form !psi where psi is the negated formula.
   */
  public String toString() {
    return ("!" + neg);
  }

  public boolean checkTypesAndScope(Model model, Map scope, Type childType) {
    return neg.checkTypesAndScope(model, scope, childType);
  }

  public ArgSpec replace(Term t, ArgSpec another) {
    Formula newNeg = (Formula) neg.replace(t, another);
    if (newNeg != neg)
      return compileAnotherIfCompiled(new NegFormula(newNeg));
    return this;
  }

  public ArgSpec getSubstResult(Substitution subst, Set<LogicalVar> boundVars) {
    return new NegFormula((Formula) neg.getSubstResult(subst, boundVars));
  }

  private Formula neg;

}


text:
package org.drools.base;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import org.drools.base.evaluators.Operator;
import org.drools.common.InternalFactHandle;
import org.drools.spi.Evaluator;
import org.drools.time.Interval;

/**
 * BaseEvaluator is an Object Comparator that is operator aware
 */
public abstract class BaseEvaluator
    implements
    Evaluator, Externalizable {

    private Operator  operator;

    private ValueType type;

    public BaseEvaluator() {
    }

    public BaseEvaluator(final ValueType type,
                         final Operator operator) {
        this.type = type;
        this.operator = operator;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        operator    = (Operator)in.readObject();
        type        = (ValueType)in.readObject();
        if (type != null) {
            type   = ValueType.determineValueType(type.getClassType());
        }
    }

    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(operator);
        out.writeObject(type);
    }

    public Operator getOperator() {
        return this.operator;
    }

    public ValueType getValueType() {
        return this.type;
    }

    public ValueType getCoercedValueType() {
        return this.type;
    }

    public boolean isTemporal() {
        return false;
    }

    public Interval getInterval() {
        // returns an open bound interval
        return new Interval();
    }

    public boolean equals(final Object object) {
        if ( this == object ) {
            return true;
        }
        if ( object == null || !(object instanceof BaseEvaluator) ) {
            return false;
        }

        final Evaluator other = (Evaluator) object;
        return this.getOperator() == other.getOperator() && this.getValueType() == other.getValueType();
    }

    public int hashCode() {
        return (this.getValueType().hashCode()) ^ (this.getOperator().hashCode()) ^ (this.getClass().hashCode());
    }

    public String toString() {
        return type.getName()+" "+operator.toString();
    }

}


text:
from plenum.server.observer.observer_sync_policy import ObserverSyncPolicyType
from plenum.test.spy_helpers import get_count

def test_can_process(policy_each_reply):
    assert policy_each_reply.can_process(ObserverSyncPolicyType.EACH_BATCH)
    assert not policy_each_reply.can_process("Unknown")
    assert not policy_each_reply.can_process("")
    assert not policy_each_reply.can_process(None)

def test_send_to_observers_each_reply_no_observers(observable, fake_msg_batch_committed):
    assert 0 == get_count(observable, observable.send_to_observers)
    observable.process_new_batch(fake_msg_batch_committed, "sender1")
    assert 0 == get_count(observable, observable.send_to_observers)
    assert 0 == len(observable._outbox)

def test_send_to_observers_each_reply_with_observers(observable, fake_msg_batch_committed):
    observable.add_observer("observer1", ObserverSyncPolicyType.EACH_BATCH)
    assert 0 == get_count(observable, observable.send_to_observers)
    observable.process_new_batch(fake_msg_batch_committed, "sender1")
    assert 1 == get_count(observable, observable.send_to_observers)
    assert 1 == len(observable._outbox)


text:
import { MdNode, Pos } from './node';
import { ParserOptions } from './parser';

export interface RemovedNodeRange {
  id: [number, number];
  line: [number, number];
}

export interface EditResult {
  nodes: MdNode[];
  removedNodeRange: RemovedNodeRange | null;
}

type EventName = 'change';

type EventHandlerMap = {
  [key in EventName]: Function[];
};

export class ToastMark {
  constructor(contents?: string, options?: Partial<ParserOptions>);

  lineTexts: string[];

  editMarkdown(startPos: Pos, endPos: Pos, newText: string): EditResult[];

  getLineTexts(): string[];

  getRootNode(): MdNode;

  findNodeAtPosition(pos: Pos): MdNode | null;

  findFirstNodeAtLine(line: number): MdNode | null;

  on(eventName: EventName, callback: () => void): void;

  off(eventName: EventName, callback: () => void): void;

  findNodeById(id: number): MdNode | null;

  removeAllNode(): void;
}


text:
//
//  WXZReportPreparationVC.m
//  rufangrongke
//
//  Created by 儒房融科 on 15/11/4.
//  Copyright (c) 2015年 王晓植. All rights reserved.
//

#import "WXZReportPreparationVC.h"
#import "AFNetworking.h"
#import "WXZPersonalCityVC.h"
#import "WXZRealEstateListCell.h"

@interface WXZReportPreparationVC () <UITableViewDataSource,UITableViewDelegate>

@property (weak, nonatomic) IBOutlet UILabel *allLouPanLabel; // 所有楼盘

@property (weak, nonatomic) IBOutlet UITableView *myTableView; // 列表

@end

@implementation WXZReportPreparationVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    // 视图整体背景色
    self.view.backgroundColor = WXZRGBColor(246, 246, 246);
    self.navigationItem.title = @"报备楼盘";
    // tableView代理方法
    self.myTableView.dataSource = self;
    self.myTableView.delegate = self;

//    [self reportPreparationRequest];
}

- (void)viewWillAppear:(BOOL)animated
{
    // 导航栏右侧按钮
    self.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImage:@"kh_loupanbaobeicity" highImage:@"" target:self action:@selector(cityAction:)];
}

// 进入城市页面事件
- (void)cityAction:(id)sender
{
    WXZPersonalCityVC *cityVC = [[WXZPersonalCityVC alloc] init];
    [self.navigationController pushViewController:cityVC animated:YES];
}

#pragma mark - Request
- (void)reportPreparationRequest
{
    [[AFHTTPSessionManager manager] POST:nil parameters:nil success:^(NSURLSessionDataTask *task, id responseObject)
    {

    } failure:^(NSURLSessionDataTask *task, NSError *error) {

    }];
}

#pragma mark - UITableViewDataSource,UITableViewDelegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    WXZRealEstateListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"RealEstateListCell"];
    if (!cell)
    {
        cell = [WXZRealEstateListCell initRealEstateListCell];
    }

    NSDictionary *dic = [NSDictionary dictionary];
    [cell modifyReportInfo:dic];

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 40;
}

// tap轻击手势,跳转到选择城市页面
- (IBAction)tapPushToCityPage:(id)sender
{
    WXZPersonalCityVC *cityVC = [[WXZPersonalCityVC alloc] init];
    cityVC.currentCity = @"";
    [self.navigationController pushViewController:cityVC animated:YES];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end


text:
<!DOCTYPE html>

    <title>Selection</title>
    <meta charset="utf-8">
    <link href="../content/shared/styles/examples-offline.css" rel="stylesheet">
    <link href="../../styles/kendo.common.min.css" rel="stylesheet">
    <link href="../../styles/kendo.rtl.min.css" rel="stylesheet">
    <link href="../../styles/kendo.default.min.css" rel="stylesheet">
    <link href="../../styles/kendo.dataviz.min.css" rel="stylesheet">
    <link href="../../styles/kendo.dataviz.default.min.css" rel="stylesheet">

        Back

Grid with multiple row selection enabled

Grid with multiple cell selection enabled


text: Comp Sci Final


text:
import sublime
import sublime_plugin
import base64
import os
import re

class SmilesPreview(sublime_plugin.EventListener):
    def on_hover(self, view, point, hover_zone):
        if (hover_zone == sublime.HOVER_TEXT):
            # locate smiles in the string. smiles string should be at the beginning and followed by tab (cxsmiles)
            hovered_line_text = view.substr(view.line(point)).strip()
            smiles_regex = re.compile(r'^([^J][A-Za-z0-9@+\-\[\]\(\)\\\/%=#$\.]+)\t', re.IGNORECASE)
            if (smiles_regex.match(hovered_line_text)):
                smiles_string = smiles_regex.match(hovered_line_text).group(0)
                file_name = "1.png"
                os.system("obabel -ismi -:" + smiles_string + "-opng -O " + file_name)
                # Check that file exists
                if (file_name and os.path.isfile(file_name)):
                    encoded = str(base64.b64encode(
                                    open(file_name, "rb").read()
                                ), "utf-8")
                    view.show_popup('<img src="data:image/png;base64,' +
                                        encoded +
                                    '">',
                                     flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
                                     location=point)
                    return
            return
        return


text:
package com.coltsoftware.liquidsledgehammer.cmd.commands;

import org.junit.Before;
import org.junit.Test;

import com.coltsoftware.liquidsledgehammer.cmd.Arguments;
import com.coltsoftware.liquidsledgehammer.cmd.ContextTestBase;
import com.coltsoftware.liquidsledgehammer.cmd.Context;
import com.coltsoftware.liquidsledgehammer.cmd.SourceFactory;

public final class BalanceTests extends ContextTestBase {

	private Context context;
	private SourceFactory mock1;
	private SourceFactory mock2;

	@Before
	public void setUp() {
		mock1 = createMockSourceFactory(1, "u1");
		mock2 = createMockSourceFactory(2, "u2");
		Context.registerSourceFactory("s1", mock1);
		Context.registerSourceFactory("s2", mock2);
		Arguments args = Arguments.fromString("-s1 thePath -s2 path2");
		context = Context.fromArgs(args);
	}

	@Test
	public void can_create_with_context() {
		new BalanceCommand(context);
	}

}


text:
package cofh.api.world;

import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandomItem;

/**
 * This class essentially allows for ores to be generated in clusters, with Features randomly choosing one or more blocks from a weighted list.
 *
 * @author King Lemming
 *
 */
public final class WeightedRandomBlock extends WeightedRandomItem {

	public final int blockId;
	public final int metadata;

	public WeightedRandomBlock(ItemStack ore) {

		super(100);
		this.blockId = ore.itemID;
		this.metadata = ore.getItemDamage();
	}

	public WeightedRandomBlock(ItemStack ore, int weight) {

		super(weight);
		this.blockId = ore.itemID;
		this.metadata = ore.getItemDamage();
	}

}


text:
var property = require("./property.js");

module.exports.evaluate = evaluate;

function evaluate(configTemplate, actualConfig, prefix) {

  actualConfig = actualConfig || {};

  var valid = true;
  var errors = [];
  var config = {};

  for(var key in configTemplate) {
    if(typeof(configTemplate[key]) == 'object') {
      // if it's an object then, recursively search through it.
      var results = evaluate(configTemplate[key], actualConfig[key], (prefix ? prefix + '.' : '') + key);
      if(!results.isValid)
        errors = errors.concat(results.errors);
      else
        config[key] = results.config;

      valid = valid && results.isValid;
    }
    else {
      var results = getPropertyValidationResult(configTemplate[key], actualConfig[key]);
      results.keyPath = (prefix ? prefix + '.' : '') + key;
      results['$leaf'] = true;
      if(!results.isValid) {
        delete results.isValid;
        errors.push(results);
        valid = false;
      } else {
        delete results.isValid;
        config[key] = results;
      }
    }
  }
  return new EvaluationResult(valid, (errors.length == 0 ? null : errors), config);
}

var EvaluationResult = function (isValid, errors, config) {
  this.isValid = isValid;
  this.errors = errors;
  this.config = config;
  this.compile = function () { return compileRecursive(this.config) };
  this.flatten = function (property1, property2) {
    return flattenRecursive(this.config, null, null, property1, property2)
  };
}

function flattenRecursive(object, keyValuePair, prefix, property1, property2) {
  keyValuePair = keyValuePair || {};
  for (var key in object) {
    if (object.hasOwnProperty(key)) {
      var currentValue = object[key];
      if(typeof(currentValue) == 'object' && !currentValue['$leaf']) {
        flattenRecursive(currentValue, keyValuePair, prefix?prefix+'.'+key:key, property1, property2);
      } else {
        if(currentValue[property1])
          keyValuePair[object[key][property1]] = object[key][property2];
      }
    }
  }
  return keyValuePair;
}

function compileRecursive (object) {
  var configObject = {};
  for(var key in object) {
    if(object[key]['$leaf']) {
      configObject[key] = object[key].value;
    } else {
      configObject[key] = compileRecursive(object[key]);
    }
  }
  return configObject;
};

function stringContains(string, value) {
  return string.indexOf(value) != -1;
}

if(!Object.setValueForKey){
  Object.defineProperty(Object.prototype, "setValueForKey", {
    value: function(key, value) {
      this[key] = value;
    }
  });

  Object.defineProperty(Object.prototype, "setValueForKeyPath", {
    value: function(keyPath, value) {
      if (keyPath == null) return;
      if (stringContains(keyPath, '.') == false) {
        this.setValueForKey(keyPath, value); return;
      }

      var chain = keyPath.split('.');
      var firstKey = chain.shift();
      var shiftedKeyPath = chain.join('.');

      if(!this.hasOwnProperty(firstKey)) this[firstKey] = {};
      this[firstKey].setValueForKeyPath(shiftedKeyPath, value);
    }
  });

  Object.defineProperty(Object.prototype, "getValueForKey", {
    value: function(key) { return this[key]; }
  });

  Object.defineProperty(Object.prototype, "getValueForKeyPath", {
    value: function(keyPath) {
      if (keyPath == null) return;
      if (stringContains(keyPath, '.') == false) { return this.getValueForKey(keyPath); }

      var chain = keyPath.split('.');
      var firstKey = chain.shift();
      var shiftedKeyPath = chain.join('.');

      if(!this.hasOwnProperty(firstKey)) return undefined;
      return this[firstKey].getValueForKeyPath(shiftedKeyPath);
  }});
}

var getPropertyValidationResult = function(propertyExpression, value) {
  var type = propertyExpression.split(".")[0];
  var code = "var " + type + "= new property(type, value);";
  return eval(code + propertyExpression + ".evaluate()");
}


text:
    Example link

<input class="form-control" type="text">