Update from https://crrev.com/311076 Includes updating DCHECK_IS_ON to a function-style macro and removing various dead skia-overriding code from Sky. Review URL: https://codereview.chromium.org/851503003
diff --git a/DEPS b/DEPS index e419390..96aab38 100644 --- a/DEPS +++ b/DEPS
@@ -19,10 +19,8 @@ vars = { 'chromium_git': 'https://chromium.googlesource.com', - 'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d', - 'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95', 'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac', - 'skia_revision': '9558f653877b982df415e4d075db55b7558f7654', + 'skia_revision': '0899696e9fec7d376b63655bedaed76871cb15c2', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and V8 without interference from each other. @@ -30,19 +28,19 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - "angle_revision": "cd1db9e6c937a69f8efb5f73a3fcad14a737c436", + 'angle_revision': '04184fb0465ea2692b90cf0fa8b203df6c31cebf', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. - 'buildtools_revision': '23a4e2f545c7b6340d7e5a2b74801941b0a86535', + 'buildtools_revision': '451dcd05a5b34936f5be67b2472cd63aaa508401', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'a48ead9b7e3dc01f1bde83f69062eebd960edfdc', + 'pdfium_revision': 'f8105c665856863ad95da37fee6c12b98b953e2c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': 'aac2f6a6a00921499ed85787aace287724fbc07e', + 'boringssl_revision': 'ca9a538aa0f2ebdd261783efa032e69a2ea17fbc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling lss # and whatever else without interference from each other. @@ -78,13 +76,7 @@ Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'), 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '51c1a4ce5f362676aa1f1cfdb5b7e52edabfa5aa', - - 'src/third_party/libc++/trunk': - Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' + Var('libcxx_revision'), - - 'src/third_party/libc++abi/trunk': - Var('chromium_git') + '/chromium/llvm-project/libcxxabi.git' + '@' + Var('libcxxabi_revision'), + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '4e3266f32c62d30a3f9e2232a753c60129d1e670', 'src/tools/grit': Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a5890a8118c0c80cc0560e6d8d5cf65e5d725509', # from svn revision 185 @@ -152,7 +144,7 @@ Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919', 'src/third_party/android_tools': - Var('chromium_git') + '/android_tools.git' + '@' + '8fe116f93f350dcf73c6fe70db893985bf1b91d5', + Var('chromium_git') + '/android_tools.git' + '@' + '56b3d3e8ce785e468eac3262cd6b107ebe569e94', 'src/third_party/appurify-python/src': Var('chromium_git') + '/external/github.com/appurify/appurify-python.git' + '@' + 'ee7abd5c5ae3106f72b2a0b9d2cb55094688e867',
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java index 37fea6c..5beb07d 100644 --- a/base/android/java/src/org/chromium/base/ResourceExtractor.java +++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -4,12 +4,15 @@ package org.chromium.base; +import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.os.AsyncTask; +import android.os.Build; +import android.os.Trace; import android.preference.PreferenceManager; import android.util.Log; @@ -52,15 +55,20 @@ public ExtractTask() { } - @Override - protected Void doInBackground(Void... unused) { + private void doInBackgroundImpl() { final File outputDir = getOutputDir(); if (!outputDir.exists() && !outputDir.mkdirs()) { Log.e(LOGTAG, "Unable to create pak resources directory!"); - return null; + return; } - String timestampFile = checkPakTimestamp(outputDir); + String timestampFile = null; + beginTraceSection("checkPakTimeStamp"); + try { + timestampFile = checkPakTimestamp(outputDir); + } finally { + endTraceSection(); + } if (timestampFile != null) { deleteFiles(); } @@ -72,7 +80,7 @@ String currentLanguage = currentLocale.split("-", 2)[0]; if (prefs.getString(LAST_LANGUAGE, "").equals(currentLanguage) - && filenames.size() >= sMandatoryPaks.length) { + && filenames.size() >= sMandatoryPaks.length) { boolean filesPresent = true; for (String file : filenames) { if (!new File(outputDir, file).exists()) { @@ -80,7 +88,7 @@ break; } } - if (filesPresent) return null; + if (filesPresent) return; } else { prefs.edit().putString(LAST_LANGUAGE, currentLanguage).apply(); } @@ -93,9 +101,9 @@ if (sExtractImplicitLocalePak) { if (p.length() > 0) p.append('|'); - // As well as the minimum required set of .paks above, we'll also add all .paks that - // we have for the user's currently selected language. - + // As well as the minimum required set of .paks above, we'll + // also add all .paks that we have for the user's currently + // selected language. p.append(currentLanguage); p.append("(-\\w+)?\\.pak"); } @@ -103,6 +111,7 @@ Pattern paksToInstall = Pattern.compile(p.toString()); AssetManager manager = mContext.getResources().getAssets(); + beginTraceSection("WalkAssets"); try { // Loop through every asset file that we have in the APK, and look for the // ones that we need to extract by trying to match the Patterns that we @@ -114,16 +123,16 @@ continue; } boolean isAppDataFile = file.equals(ICU_DATA_FILENAME) - || file.equals(V8_NATIVES_DATA_FILENAME) - || file.equals(V8_SNAPSHOT_DATA_FILENAME); - File output = new File(isAppDataFile - ? getAppDataDir() : outputDir, file); + || file.equals(V8_NATIVES_DATA_FILENAME) + || file.equals(V8_SNAPSHOT_DATA_FILENAME); + File output = new File(isAppDataFile ? getAppDataDir() : outputDir, file); if (output.exists()) { continue; } InputStream is = null; OutputStream os = null; + beginTraceSection("ExtractResource"); try { is = manager.open(file); os = new FileOutputStream(output); @@ -159,6 +168,7 @@ if (os != null) { os.close(); } + endTraceSection(); // ExtractResource } } } @@ -169,11 +179,12 @@ // this happens with regularity. Log.w(LOGTAG, "Exception unpacking required pak resources: " + e.getMessage()); deleteFiles(); - return null; + return; + } finally { + endTraceSection(); // WalkAssets } // Finished, write out a timestamp file if we need to. - if (timestampFile != null) { try { new File(outputDir, timestampFile).createNewFile(); @@ -186,6 +197,20 @@ // TODO(yusufo): Figure out why remove is required here. prefs.edit().remove(PAK_FILENAMES).apply(); prefs.edit().putStringSet(PAK_FILENAMES, filenames).apply(); + } + + @Override + protected Void doInBackground(Void... unused) { + // TODO(lizeb): Use chrome tracing here (and above in + // doInBackgroundImpl) when it will be possible. This is currently + // not doable since the native library is not loaded yet, and the + // TraceEvent calls are dropped before this point. + beginTraceSection("ResourceExtractor.ExtractTask.doInBackground"); + try { + doInBackgroundImpl(); + } finally { + endTraceSection(); + } return null; } @@ -233,6 +258,18 @@ // timestamp file is already up-to date. return null; } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) + private void beginTraceSection(String section) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return; + Trace.beginSection(section); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) + private void endTraceSection() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return; + Trace.endSection(); + } } private final Context mContext;
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc index 3c06413..a157354 100644 --- a/base/android/jni_array.cc +++ b/base/android/jni_array.cc
@@ -10,6 +10,20 @@ namespace base { namespace android { +namespace { + +// As |GetArrayLength| makes no guarantees about the returned value (e.g., it +// may be -1 if |array| is not a valid Java array), provide a safe wrapper +// that always returns a valid, non-negative size. +template <typename JavaArrayType> +size_t SafeGetArrayLength(JNIEnv* env, JavaArrayType jarray) { + DCHECK(jarray); + jsize length = env->GetArrayLength(jarray); + DCHECK_GE(length, 0) << "Invalid array length: " << length; + return static_cast<size_t>(std::max(0, length)); +} + +} // namespace ScopedJavaLocalRef<jbyteArray> ToJavaByteArray( JNIEnv* env, const uint8* bytes, size_t len) { @@ -108,10 +122,10 @@ DCHECK(out); if (!array) return; - jsize len = env->GetArrayLength(array); + size_t len = SafeGetArrayLength(env, array); size_t back = out->size(); out->resize(back + len); - for (jsize i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { ScopedJavaLocalRef<jstring> str(env, static_cast<jstring>(env->GetObjectArrayElement(array, i))); ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i])); @@ -124,10 +138,10 @@ DCHECK(out); if (!array) return; - jsize len = env->GetArrayLength(array); + size_t len = SafeGetArrayLength(env, array); size_t back = out->size(); out->resize(back + len); - for (jsize i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { ScopedJavaLocalRef<jstring> str(env, static_cast<jstring>(env->GetObjectArrayElement(array, i))); ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i])); @@ -140,16 +154,20 @@ DCHECK(out); if (!byte_array) return; - jsize len = env->GetArrayLength(byte_array); - jbyte* bytes = env->GetByteArrayElements(byte_array, NULL); - out->insert(out->end(), bytes, bytes + len); - env->ReleaseByteArrayElements(byte_array, bytes, JNI_ABORT); + size_t len = SafeGetArrayLength(env, byte_array); + if (!len) + return; + size_t back = out->size(); + out->resize(back + len); + env->GetByteArrayRegion(byte_array, 0, len, + reinterpret_cast<int8*>(&(*out)[back])); } void JavaByteArrayToByteVector(JNIEnv* env, jbyteArray byte_array, std::vector<uint8>* out) { DCHECK(out); + DCHECK(byte_array); out->clear(); AppendJavaByteArrayToByteVector(env, byte_array, out); } @@ -158,39 +176,35 @@ jintArray int_array, std::vector<int>* out) { DCHECK(out); - out->clear(); - jsize len = env->GetArrayLength(int_array); - jint* ints = env->GetIntArrayElements(int_array, NULL); - for (jsize i = 0; i < len; ++i) { - out->push_back(static_cast<int>(ints[i])); - } - env->ReleaseIntArrayElements(int_array, ints, JNI_ABORT); + size_t len = SafeGetArrayLength(env, int_array); + out->resize(len); + if (!len) + return; + // TODO(jdduke): Use |out->data()| for pointer access after switch to libc++, + // both here and in the other conversion routines. See crbug.com/427718. + env->GetIntArrayRegion(int_array, 0, len, &(*out)[0]); } void JavaLongArrayToLongVector(JNIEnv* env, jlongArray long_array, - std::vector<long>* out) { + std::vector<jlong>* out) { DCHECK(out); - out->clear(); - jsize len = env->GetArrayLength(long_array); - jlong* longs = env->GetLongArrayElements(long_array, NULL); - for (jsize i = 0; i < len; ++i) { - out->push_back(static_cast<long>(longs[i])); - } - env->ReleaseLongArrayElements(long_array, longs, JNI_ABORT); + size_t len = SafeGetArrayLength(env, long_array); + out->resize(len); + if (!len) + return; + env->GetLongArrayRegion(long_array, 0, len, &(*out)[0]); } void JavaFloatArrayToFloatVector(JNIEnv* env, jfloatArray float_array, std::vector<float>* out) { DCHECK(out); - out->clear(); - jsize len = env->GetArrayLength(float_array); - jfloat* floats = env->GetFloatArrayElements(float_array, NULL); - for (jsize i = 0; i < len; ++i) { - out->push_back(static_cast<float>(floats[i])); - } - env->ReleaseFloatArrayElements(float_array, floats, JNI_ABORT); + size_t len = SafeGetArrayLength(env, float_array); + out->resize(len); + if (!len) + return; + env->GetFloatArrayRegion(float_array, 0, len, &(*out)[0]); } void JavaArrayOfByteArrayToStringVector( @@ -198,10 +212,9 @@ jobjectArray array, std::vector<std::string>* out) { DCHECK(out); - out->clear(); - jsize len = env->GetArrayLength(array); + size_t len = SafeGetArrayLength(env, array); out->resize(len); - for (jsize i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { ScopedJavaLocalRef<jbyteArray> bytes_array( env, static_cast<jbyteArray>( env->GetObjectArrayElement(array, i)));
diff --git a/base/android/jni_array.h b/base/android/jni_array.h index 66b9422..0d7ec2e 100644 --- a/base/android/jni_array.h +++ b/base/android/jni_array.h
@@ -77,7 +77,7 @@ BASE_EXPORT void JavaLongArrayToLongVector( JNIEnv* env, jlongArray long_array, - std::vector<long>* out); + std::vector<jlong>* out); // Replaces the content of |out| with the Java floats in |float_array|. BASE_EXPORT void JavaFloatArrayToFloatVector(
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc index ef1225a..7cb896c 100644 --- a/base/android/jni_array_unittest.cc +++ b/base/android/jni_array_unittest.cc
@@ -21,10 +21,13 @@ std::vector<uint8> vec(5); JavaByteArrayToByteVector(env, bytes.obj(), &vec); EXPECT_EQ(4U, vec.size()); - EXPECT_EQ(std::vector<uint8>(kBytes, kBytes + kLen), vec); + std::vector<uint8> expected_vec(kBytes, kBytes + kLen); + EXPECT_EQ(expected_vec, vec); AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec); EXPECT_EQ(8U, vec.size()); + expected_vec.insert(expected_vec.end(), kBytes, kBytes + kLen); + EXPECT_EQ(expected_vec, vec); } void CheckIntConversion(
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py index 4342fed..53de365 100755 --- a/base/android/jni_generator/jni_generator.py +++ b/base/android/jni_generator/jni_generator.py
@@ -1037,10 +1037,8 @@ """ if self.options.native_exports: template_str += """ -__attribute__((visibility("default"))) -${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}) { - return ${NAME}(${PARAMS_IN_CALL}); -} +__attribute__((visibility("default"), alias("${NAME}"))) +${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}); """ template = Template(template_str) params_in_call = [] @@ -1267,7 +1265,7 @@ if self.options.native_exports: template = Template("""\ // Leaking this jclass as we cannot use LazyInstance from some threads. -base::subtle::AtomicWord g_${JAVA_CLASS}_clazz = 0; +base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0; #define ${JAVA_CLASS}_clazz(env) \ base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \ &g_${JAVA_CLASS}_clazz)""")
diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden index 5beaa82..a4953cc 100644 --- a/base/android/jni_generator/testNativeExportsOption.golden +++ b/base/android/jni_generator/testNativeExportsOption.golden
@@ -21,7 +21,7 @@ const char kSampleForTestsClassPath[] = "org/chromium/example/jni_generator/SampleForTests"; // Leaking this jclass as we cannot use LazyInstance from some threads. -base::subtle::AtomicWord g_SampleForTests_clazz = 0; +base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0; #define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz) } // namespace @@ -30,21 +30,17 @@ static jint Init(JNIEnv* env, jobject jcaller); -__attribute__((visibility("default"))) +__attribute__((visibility("default"), alias("Init"))) jint Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv* - env, jobject jcaller) { - return Init(env, jcaller); -} + env, jobject jcaller); static jint Init(JNIEnv* env, jobject jcaller); -__attribute__((visibility("default"))) +__attribute__((visibility("default"), alias("Init"))) jint Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv* - env, jobject jcaller) { - return Init(env, jcaller); -} + env, jobject jcaller); }; // extern "C"
diff --git a/base/files/memory_mapped_file.cc b/base/files/memory_mapped_file.cc index 745a5ff..891fcff 100644 --- a/base/files/memory_mapped_file.cc +++ b/base/files/memory_mapped_file.cc
@@ -31,6 +31,7 @@ CloseHandles(); } +#if !defined(OS_NACL) bool MemoryMappedFile::Initialize(const FilePath& file_name) { if (IsValid()) return false; @@ -85,5 +86,6 @@ *aligned_start = start & ~mask; *aligned_size = (size + *offset + mask) & ~mask; } +#endif } // namespace base
diff --git a/base/files/memory_mapped_file_posix.cc b/base/files/memory_mapped_file_posix.cc index ebf3877..168da92 100644 --- a/base/files/memory_mapped_file_posix.cc +++ b/base/files/memory_mapped_file_posix.cc
@@ -16,6 +16,7 @@ MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) { } +#if !defined(OS_NACL) bool MemoryMappedFile::MapFileRegionToMemory( const MemoryMappedFile::Region& region) { ThreadRestrictions::AssertIOAllowed(); @@ -74,6 +75,7 @@ data_ += data_offset; return true; } +#endif void MemoryMappedFile::CloseHandles() { ThreadRestrictions::AssertIOAllowed();
diff --git a/base/i18n/build_utf8_validator_tables.cc b/base/i18n/build_utf8_validator_tables.cc index 647c8d6..ae5b1a7 100644 --- a/base/i18n/build_utf8_validator_tables.cc +++ b/base/i18n/build_utf8_validator_tables.cc
@@ -248,7 +248,7 @@ for (int i = 0; i < 4; ++i) { MoveRightMostCharToSet(pairs); } -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (PairVector::const_iterator it = pairs->begin(); it != pairs->end(); ++it) { DCHECK(it->character.empty());
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc index e0bd62c..f1fdda7 100644 --- a/base/i18n/icu_util.cc +++ b/base/i18n/icu_util.cc
@@ -27,21 +27,21 @@ #define ICU_UTIL_DATA_SHARED 1 #define ICU_UTIL_DATA_STATIC 2 -#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE +namespace base { +namespace i18n { + // Use an unversioned file name to simplify a icu version update down the road. // No need to change the filename in multiple places (gyp files, windows // build pkg configurations, etc). 'l' stands for Little Endian. -#define ICU_UTIL_DATA_FILE_NAME "icudtl.dat" -#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED +// This variable is exported through the header file. +const char kIcuDataFileName[] = "icudtl.dat"; +#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED #define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat" #if defined(OS_WIN) #define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll" #endif #endif -namespace base { -namespace i18n { - namespace { #if !defined(NDEBUG) @@ -53,9 +53,10 @@ #endif } - #if defined(OS_ANDROID) -bool InitializeICUWithFileDescriptor(int data_fd) { +bool InitializeICUWithFileDescriptor( + int data_fd, + base::MemoryMappedFile::Region data_region) { #if !defined(NDEBUG) DCHECK(!g_check_called_once || !g_called_once); g_called_once = true; @@ -67,7 +68,7 @@ #elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) CR_DEFINE_STATIC_LOCAL(base::MemoryMappedFile, mapped_file, ()); if (!mapped_file.IsValid()) { - if (!mapped_file.Initialize(base::File(data_fd))) { + if (!mapped_file.Initialize(base::File(data_fd), data_region)) { LOG(ERROR) << "Couldn't mmap icu data file"; return false; } @@ -135,13 +136,15 @@ bool path_ok = PathService::Get(base::DIR_EXE, &data_path); #endif DCHECK(path_ok); - data_path = data_path.AppendASCII(ICU_UTIL_DATA_FILE_NAME); + data_path = data_path.AppendASCII(kIcuDataFileName); #else // Assume it is in the framework bundle's Resources directory. + base::ScopedCFTypeRef<CFStringRef> data_file_name( + SysUTF8ToCFStringRef(kIcuDataFileName)); FilePath data_path = - base::mac::PathForFrameworkBundleResource(CFSTR(ICU_UTIL_DATA_FILE_NAME)); + base::mac::PathForFrameworkBundleResource(data_file_name); if (data_path.empty()) { - LOG(ERROR) << ICU_UTIL_DATA_FILE_NAME << " not found in bundle"; + LOG(ERROR) << kIcuDataFileName << " not found in bundle"; return false; } #endif // OS check
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h index b0a5dbc..5094cb0 100644 --- a/base/i18n/icu_util.h +++ b/base/i18n/icu_util.h
@@ -5,12 +5,15 @@ #ifndef BASE_I18N_ICU_UTIL_H_ #define BASE_I18N_ICU_UTIL_H_ -#include "build/build_config.h" +#include "base/files/memory_mapped_file.h" #include "base/i18n/base_i18n_export.h" +#include "build/build_config.h" namespace base { namespace i18n { +BASE_I18N_EXPORT extern const char kIcuDataFileName[]; + // Call this function to load ICU's data tables for the current process. This // function should be called before ICU is used. BASE_I18N_EXPORT bool InitializeICU(); @@ -18,7 +21,9 @@ #if defined(OS_ANDROID) // Android uses a file descriptor passed by browser process to initialize ICU // in render processes. -BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(int data_fd); +BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor( + int data_fd, + base::MemoryMappedFile::Region data_region); #endif // In a test binary, the call above might occur twice.
diff --git a/base/logging.h b/base/logging.h index 6a1df76..aa243a9 100644 --- a/base/logging.h +++ b/base/logging.h
@@ -560,9 +560,9 @@ #endif #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) -#define DCHECK_IS_ON 0 +#define DCHECK_IS_ON() 0 #else -#define DCHECK_IS_ON 1 +#define DCHECK_IS_ON() 1 #endif // Definitions for DLOG et al. @@ -616,14 +616,14 @@ // Definitions for DCHECK et al. -#if DCHECK_IS_ON +#if DCHECK_IS_ON() #define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__) #define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL const LogSeverity LOG_DCHECK = LOG_FATAL; -#else // DCHECK_IS_ON +#else // DCHECK_IS_ON() // These are just dummy values. #define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ @@ -631,7 +631,7 @@ #define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO const LogSeverity LOG_DCHECK = LOG_INFO; -#endif // DCHECK_IS_ON +#endif // DCHECK_IS_ON() // DCHECK et al. make sure to reference |condition| regardless of // whether DCHECKs are enabled; this is so that we don't get unused @@ -653,26 +653,24 @@ #else // _PREFAST_ -#define DCHECK(condition) \ - LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \ - << "Check failed: " #condition ". " +#define DCHECK(condition) \ + LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \ + << "Check failed: " #condition ". " -#define DPCHECK(condition) \ - LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON ? !(condition) : false) \ - << "Check failed: " #condition ". " +#define DPCHECK(condition) \ + LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \ + << "Check failed: " #condition ". " #endif // _PREFAST_ // Helper macro for binary operators. // Don't use this macro directly in your code, use DCHECK_EQ et al below. -#define DCHECK_OP(name, op, val1, val2) \ - if (DCHECK_IS_ON) \ - if (std::string* _result = \ - logging::Check##name##Impl((val1), (val2), \ - #val1 " " #op " " #val2)) \ - logging::LogMessage( \ - __FILE__, __LINE__, ::logging::LOG_DCHECK, \ - _result).stream() +#define DCHECK_OP(name, op, val1, val2) \ + if (DCHECK_IS_ON()) \ + if (std::string* _result = logging::Check##name##Impl( \ + (val1), (val2), #val1 " " #op " " #val2)) \ + logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, _result) \ + .stream() // Equality/Inequality checks - compare two values, and log a // LOG_DCHECK message including the two values when the result is not @@ -701,7 +699,7 @@ #define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2) #define DCHECK_IMPLIES(val1, val2) DCHECK(!(val1) || (val2)) -#if !DCHECK_IS_ON && defined(OS_CHROMEOS) +#if !DCHECK_IS_ON() && defined(OS_CHROMEOS) #define NOTREACHED() LOG(ERROR) << "NOTREACHED() hit in " << \ __FUNCTION__ << ". " #else
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc index 6ee4e76..8b9701a 100644 --- a/base/logging_unittest.cc +++ b/base/logging_unittest.cc
@@ -187,7 +187,7 @@ TEST_F(LoggingTest, DcheckStreamsAreLazy) { MockLogSource mock_log_source; EXPECT_CALL(mock_log_source, Log()).Times(0); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(true) << mock_log_source.Log(); DCHECK_EQ(0, 0) << mock_log_source.Log(); #else @@ -202,27 +202,27 @@ TEST_F(LoggingTest, Dcheck) { #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) // Release build. - EXPECT_FALSE(DCHECK_IS_ON); + EXPECT_FALSE(DCHECK_IS_ON()); EXPECT_FALSE(DLOG_IS_ON(DCHECK)); #elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON) // Release build with real DCHECKS. SetLogAssertHandler(&LogSink); - EXPECT_TRUE(DCHECK_IS_ON); + EXPECT_TRUE(DCHECK_IS_ON()); EXPECT_FALSE(DLOG_IS_ON(DCHECK)); #else // Debug build. SetLogAssertHandler(&LogSink); - EXPECT_TRUE(DCHECK_IS_ON); + EXPECT_TRUE(DCHECK_IS_ON()); EXPECT_TRUE(DLOG_IS_ON(DCHECK)); #endif EXPECT_EQ(0, log_sink_call_count); DCHECK(false); - EXPECT_EQ(DCHECK_IS_ON ? 1 : 0, log_sink_call_count); + EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count); DPCHECK(false); - EXPECT_EQ(DCHECK_IS_ON ? 2 : 0, log_sink_call_count); + EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count); DCHECK_EQ(0, 1); - EXPECT_EQ(DCHECK_IS_ON ? 3 : 0, log_sink_call_count); + EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count); } TEST_F(LoggingTest, DcheckReleaseBehavior) {
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h index 46ea3c3..accc0d9 100644 --- a/base/mac/foundation_util.h +++ b/base/mac/foundation_util.h
@@ -64,6 +64,15 @@ BASE_EXPORT bool AmIBundled(); BASE_EXPORT void SetOverrideAmIBundled(bool value); +#if defined(UNIT_TEST) +// This is required because instantiating some tests requires checking the +// directory structure, which sets the AmIBundled cache state. Individual tests +// may or may not be bundled, and this would trip them up if the cache weren't +// cleared. This should not be called from individual tests, just from test +// instantiation code that gets a path from PathService. +BASE_EXPORT void ClearAmIBundledCache(); +#endif + // Returns true if this process is marked as a "Background only process". BASE_EXPORT bool IsBackgroundOnlyProcess();
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm index 4e9b224..2895b66 100644 --- a/base/mac/foundation_util.mm +++ b/base/mac/foundation_util.mm
@@ -26,6 +26,8 @@ namespace { +bool g_cached_am_i_bundled_called = false; +bool g_cached_am_i_bundled_value = false; bool g_override_am_i_bundled = false; bool g_override_am_i_bundled_value = false; @@ -48,12 +50,15 @@ // If the return value is not cached, this function will return different // values depending on when it's called. This confuses some client code, see // http://crbug.com/63183 . - static bool result = UncachedAmIBundled(); - DCHECK_EQ(result, UncachedAmIBundled()) + if (!g_cached_am_i_bundled_called) { + g_cached_am_i_bundled_called = true; + g_cached_am_i_bundled_value = UncachedAmIBundled(); + } + DCHECK_EQ(g_cached_am_i_bundled_value, UncachedAmIBundled()) << "The return value of AmIBundled() changed. This will confuse tests. " << "Call SetAmIBundled() override manually if your test binary " << "delay-loads the framework."; - return result; + return g_cached_am_i_bundled_value; } void SetOverrideAmIBundled(bool value) { @@ -66,6 +71,10 @@ g_override_am_i_bundled_value = value; } +BASE_EXPORT void ClearAmIBundledCache() { + g_cached_am_i_bundled_called = false; +} + bool IsBackgroundOnlyProcess() { // This function really does want to examine NSBundle's idea of the main // bundle dictionary. It needs to look at the actual running .app's
diff --git a/base/mac/libdispatch_task_runner_unittest.cc b/base/mac/libdispatch_task_runner_unittest.cc index cad0efa..49b0c9a 100644 --- a/base/mac/libdispatch_task_runner_unittest.cc +++ b/base/mac/libdispatch_task_runner_unittest.cc
@@ -12,7 +12,7 @@ class LibDispatchTaskRunnerTest : public testing::Test { public: - virtual void SetUp() override { + void SetUp() override { task_runner_ = new base::mac::LibDispatchTaskRunner( "org.chromium.LibDispatchTaskRunnerTest"); }
diff --git a/base/mac/mac_logging.h b/base/mac/mac_logging.h index 1081490..5192b20 100644 --- a/base/mac/mac_logging.h +++ b/base/mac/mac_logging.h
@@ -87,9 +87,9 @@ LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \ MAC_DVLOG_IS_ON(verbose_level) && (condition)) -#define OSSTATUS_DCHECK(condition, status) \ - LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \ - DCHECK_IS_ON && !(condition)) \ - << "Check failed: " # condition << ". " +#define OSSTATUS_DCHECK(condition, status) \ + LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \ + DCHECK_IS_ON() && !(condition)) \ + << "Check failed: " #condition << ". " #endif // BASE_MAC_MAC_LOGGING_H_
diff --git a/base/mac/mach_logging.h b/base/mac/mach_logging.h index a9b3b65..b12e274 100644 --- a/base/mac/mach_logging.h +++ b/base/mac/mach_logging.h
@@ -91,10 +91,10 @@ LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \ MACH_DVLOG_IS_ON(verbose_level) && (condition)) -#define MACH_DCHECK(condition, mach_err) \ - LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), \ - DCHECK_IS_ON && !(condition)) \ - << "Check failed: " # condition << ". " +#define MACH_DCHECK(condition, mach_err) \ + LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), \ + DCHECK_IS_ON() && !(condition)) \ + << "Check failed: " #condition << ". " #if !defined(OS_IOS) @@ -157,10 +157,10 @@ LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \ BOOTSTRAP_DVLOG_IS_ON(verbose_level) && (condition)) -#define BOOTSTRAP_DCHECK(condition, bootstrap_err) \ - LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), \ - DCHECK_IS_ON && !(condition)) \ - << "Check failed: " # condition << ". " +#define BOOTSTRAP_DCHECK(condition, bootstrap_err) \ + LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), \ + DCHECK_IS_ON() && !(condition)) \ + << "Check failed: " #condition << ". " #endif // !OS_IOS
diff --git a/base/mac/scoped_sending_event_unittest.mm b/base/mac/scoped_sending_event_unittest.mm index 95f6eba..02ef2db 100644 --- a/base/mac/scoped_sending_event_unittest.mm +++ b/base/mac/scoped_sending_event_unittest.mm
@@ -27,9 +27,7 @@ ScopedSendingEventTest() : app_([[ScopedSendingEventTestCrApp alloc] init]) { NSApp = app_.get(); } - virtual ~ScopedSendingEventTest() { - NSApp = nil; - } + ~ScopedSendingEventTest() override { NSApp = nil; } private: base::scoped_nsobject<ScopedSendingEventTestCrApp> app_;
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc index eb9e552..e04377e 100644 --- a/base/memory/discardable_shared_memory.cc +++ b/base/memory/discardable_shared_memory.cc
@@ -129,7 +129,7 @@ shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState)); locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (size_t page = 0; page < locked_page_count_; ++page) locked_pages_.insert(page); #endif @@ -149,7 +149,7 @@ shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState)); locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (size_t page = 0; page < locked_page_count_; ++page) locked_pages_.insert(page); #endif @@ -200,7 +200,7 @@ // Add pages to |locked_page_count_|. // Note: Locking a page that is already locked is an error. locked_page_count_ += end - start; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // Detect incorrect usage by keeping track of exactly what pages are locked. for (auto page = start; page < end; ++page) { auto result = locked_pages_.insert(page); @@ -252,7 +252,7 @@ // Note: Unlocking a page that is not locked is an error. DCHECK_GE(locked_page_count_, end - start); locked_page_count_ -= end - start; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // Detect incorrect usage by keeping track of exactly what pages are locked. for (auto page = start; page < end; ++page) { auto erased_count = locked_pages_.erase(page); @@ -353,6 +353,7 @@ void DiscardableSharedMemory::Close() { shared_memory_.Unmap(); shared_memory_.Close(); + mapped_size_ = 0; } Time DiscardableSharedMemory::Now() const {
diff --git a/base/memory/discardable_shared_memory.h b/base/memory/discardable_shared_memory.h index c69c970..abee868 100644 --- a/base/memory/discardable_shared_memory.h +++ b/base/memory/discardable_shared_memory.h
@@ -11,7 +11,7 @@ #include "base/threading/thread_collision_warner.h" #include "base/time/time.h" -#if DCHECK_IS_ON +#if DCHECK_IS_ON() #include <set> #endif @@ -119,7 +119,7 @@ SharedMemory shared_memory_; size_t mapped_size_; size_t locked_page_count_; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() std::set<size_t> locked_pages_; #endif // Implementation is not thread-safe but still usable if clients are
diff --git a/base/memory/discardable_shared_memory_unittest.cc b/base/memory/discardable_shared_memory_unittest.cc index 90441e1..896263d 100644 --- a/base/memory/discardable_shared_memory_unittest.cc +++ b/base/memory/discardable_shared_memory_unittest.cc
@@ -287,5 +287,19 @@ EXPECT_TRUE(rv); } +TEST(DiscardableSharedMemoryTest, MappedSize) { + const uint32 kDataSize = 1024; + + TestDiscardableSharedMemory memory; + bool rv = memory.CreateAndMap(kDataSize); + ASSERT_TRUE(rv); + + EXPECT_LE(kDataSize, memory.mapped_size()); + + // Mapped size should be 0 after memory segment has been closed. + memory.Close(); + EXPECT_EQ(0u, memory.mapped_size()); +} + } // namespace } // namespace base
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc index 733f5e5..ccf79c0 100644 --- a/base/message_loop/message_loop_unittest.cc +++ b/base/message_loop/message_loop_unittest.cc
@@ -668,14 +668,12 @@ void WillProcessTask(const PendingTask& pending_task) override { num_tasks_started_++; - EXPECT_TRUE(pending_task.time_posted != TimeTicks()); EXPECT_LE(num_tasks_started_, num_tasks_); EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1); } void DidProcessTask(const PendingTask& pending_task) override { num_tasks_processed_++; - EXPECT_TRUE(pending_task.time_posted != TimeTicks()); EXPECT_LE(num_tasks_started_, num_tasks_); EXPECT_EQ(num_tasks_started_, num_tasks_processed_); }
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h index a9996d1..e9a871c 100644 --- a/base/metrics/histogram_macros.h +++ b/base/metrics/histogram_macros.h
@@ -68,25 +68,25 @@ // a macro argument here. The name is only used in a DCHECK, to assure that // callers don't try to vary the name of the histogram (which would tend to be // ignored by the one-time initialization of the histogtram_pointer). -#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \ - histogram_add_method_invocation, \ - histogram_factory_get_invocation) \ - do { \ - static base::subtle::AtomicWord atomic_histogram_pointer = 0; \ - base::HistogramBase* histogram_pointer( \ - reinterpret_cast<base::HistogramBase*>( \ - base::subtle::Acquire_Load(&atomic_histogram_pointer))); \ - if (!histogram_pointer) { \ - histogram_pointer = histogram_factory_get_invocation; \ - base::subtle::Release_Store(&atomic_histogram_pointer, \ +#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \ + histogram_add_method_invocation, \ + histogram_factory_get_invocation) \ + do { \ + static base::subtle::AtomicWord atomic_histogram_pointer = 0; \ + base::HistogramBase* histogram_pointer( \ + reinterpret_cast<base::HistogramBase*>( \ + base::subtle::Acquire_Load(&atomic_histogram_pointer))); \ + if (!histogram_pointer) { \ + histogram_pointer = histogram_factory_get_invocation; \ + base::subtle::Release_Store( \ + &atomic_histogram_pointer, \ reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \ - } \ - if (DCHECK_IS_ON) \ - histogram_pointer->CheckName(constant_histogram_name); \ - histogram_pointer->histogram_add_method_invocation; \ + } \ + if (DCHECK_IS_ON()) \ + histogram_pointer->CheckName(constant_histogram_name); \ + histogram_pointer->histogram_add_method_invocation; \ } while (0) - //------------------------------------------------------------------------------ // Provide easy general purpose histogram in a macro, just like stats counters. // The first four macros use 50 buckets.
diff --git a/base/posix/global_descriptors.cc b/base/posix/global_descriptors.cc index bcca443..6c18783 100644 --- a/base/posix/global_descriptors.cc +++ b/base/posix/global_descriptors.cc
@@ -11,6 +11,16 @@ namespace base { +GlobalDescriptors::Descriptor::Descriptor(Key key, int fd) + : key(key), fd(fd), region(base::MemoryMappedFile::Region::kWholeFile) { +} + +GlobalDescriptors::Descriptor::Descriptor(Key key, + int fd, + base::MemoryMappedFile::Region region) + : key(key), fd(fd), region(region) { +} + // static GlobalDescriptors* GlobalDescriptors::GetInstance() { typedef Singleton<base::GlobalDescriptors, @@ -30,23 +40,38 @@ int GlobalDescriptors::MaybeGet(Key key) const { for (Mapping::const_iterator i = descriptors_.begin(); i != descriptors_.end(); ++i) { - if (i->first == key) - return i->second; + if (i->key == key) + return i->fd; } return -1; } void GlobalDescriptors::Set(Key key, int fd) { - for (Mapping::iterator - i = descriptors_.begin(); i != descriptors_.end(); ++i) { - if (i->first == key) { - i->second = fd; + Set(key, fd, base::MemoryMappedFile::Region::kWholeFile); +} + +void GlobalDescriptors::Set(Key key, + int fd, + base::MemoryMappedFile::Region region) { + for (auto& i : descriptors_) { + if (i.key == key) { + i.fd = fd; + i.region = region; return; } } - descriptors_.push_back(std::make_pair(key, fd)); + descriptors_.push_back(Descriptor(key, fd, region)); +} + +base::MemoryMappedFile::Region GlobalDescriptors::GetRegion(Key key) const { + for (const auto& i : descriptors_) { + if (i.key == key) + return i.region; + } + DLOG(FATAL) << "Unknown global descriptor: " << key; + return base::MemoryMappedFile::Region::kWholeFile; } void GlobalDescriptors::Reset(const Mapping& mapping) {
diff --git a/base/posix/global_descriptors.h b/base/posix/global_descriptors.h index 3d7369c31..c774634 100644 --- a/base/posix/global_descriptors.h +++ b/base/posix/global_descriptors.h
@@ -12,6 +12,7 @@ #include <stdint.h> +#include "base/files/memory_mapped_file.h" #include "base/memory/singleton.h" namespace base { @@ -36,8 +37,18 @@ class BASE_EXPORT GlobalDescriptors { public: typedef uint32_t Key; - typedef std::pair<Key, int> KeyFDPair; - typedef std::vector<KeyFDPair> Mapping; + struct Descriptor { + Descriptor(Key key, int fd); + Descriptor(Key key, int fd, base::MemoryMappedFile::Region region); + + // Globally unique key. + Key key; + // Actual FD. + int fd; + // Optional region, defaults to kWholeFile. + base::MemoryMappedFile::Region region; + }; + typedef std::vector<Descriptor> Mapping; // Often we want a canonical descriptor for a given Key. In this case, we add // the following constant to the key value: @@ -53,12 +64,19 @@ // Get a descriptor given a key. It is a fatal error if the key is not known. int Get(Key key) const; - // Get a descriptor give a key. Returns -1 on error. + // Get a descriptor given a key. Returns -1 on error. int MaybeGet(Key key) const; - // Set the descriptor for the given key. + // Get a region given a key. It is a fatal error if the key is not known. + base::MemoryMappedFile::Region GetRegion(Key key) const; + + // Set the descriptor for the given |key|. This sets the region associated + // with |key| to kWholeFile. void Set(Key key, int fd); + // Set the descriptor and |region| for the given |key|. + void Set(Key key, int fd, base::MemoryMappedFile::Region region); + void Reset(const Mapping& mapping); private:
diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc index 7d3dbe7..cafc1d8 100644 --- a/base/prefs/pref_value_map.cc +++ b/base/prefs/pref_value_map.cc
@@ -67,7 +67,6 @@ void PrefValueMap::Clear() { STLDeleteValues(&prefs_); - prefs_.clear(); } void PrefValueMap::Swap(PrefValueMap* other) {
diff --git a/base/process/launch.h b/base/process/launch.h index 0450ddf..6cd02d6 100644 --- a/base/process/launch.h +++ b/base/process/launch.h
@@ -189,6 +189,11 @@ // instead of a CommandLine. Useful for situations where you need to // control the command line arguments directly, but prefer the // CommandLine version if launching Chrome itself. +BASE_EXPORT Process LaunchProcess(const std::vector<std::string>& argv, + const LaunchOptions& options); + +// Deprecated version. +// TODO(rvargas) crbug.com/417532: Remove this after migrating all consumers. BASE_EXPORT bool LaunchProcess(const std::vector<std::string>& argv, const LaunchOptions& options, ProcessHandle* process_handle);
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc index 3322d26..c60cfdc 100644 --- a/base/process/launch_posix.cc +++ b/base/process/launch_posix.cc
@@ -473,6 +473,15 @@ return true; } +Process LaunchProcess(const std::vector<std::string>& argv, + const LaunchOptions& options) { + ProcessHandle process_handle; + if (LaunchProcess(argv, options, &process_handle)) + return Process(process_handle); + + return Process(); +} + bool LaunchProcess(const CommandLine& cmdline, const LaunchOptions& options,
diff --git a/base/test/expectations/expectation.cc b/base/test/expectations/expectation.cc index 9b06e28..3081779 100644 --- a/base/test/expectations/expectation.cc +++ b/base/test/expectations/expectation.cc
@@ -38,7 +38,7 @@ const std::string& variant = platform->variant; if (name == "Win") { - if (variant != "" && + if (!variant.empty() && variant != "XP" && variant != "Vista" && variant != "7" && @@ -46,7 +46,7 @@ return false; } } else if (name == "Mac") { - if (variant != "" && + if (!variant.empty() && variant != "10.6" && variant != "10.7" && variant != "10.8" && @@ -55,7 +55,7 @@ return false; } } else if (name == "Linux") { - if (variant != "" && + if (!variant.empty() && variant != "32" && variant != "64") { return false;
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc index fd22a63..af8bd76 100644 --- a/base/test/test_file_util_win.cc +++ b/base/test/test_file_util_win.cc
@@ -249,7 +249,7 @@ switch (lines.size()) { case 3: // optional empty line at end of file: - if (lines[2] != "") + if (!lines[2].empty()) return false; // fall through: case 2:
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc index cd3c9dc..bc0ae24 100644 --- a/base/threading/worker_pool_posix.cc +++ b/base/threading/worker_pool_posix.cc
@@ -102,8 +102,7 @@ stopwatch.Stop(); tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking( - pending_task.birth_tally, TrackedTime(pending_task.time_posted), - stopwatch); + pending_task.birth_tally, pending_task.time_posted, stopwatch); } // The WorkerThread is non-joinable, so it deletes itself.
diff --git a/base/threading/worker_pool_win.cc b/base/threading/worker_pool_win.cc index ff3cc83..bd976f7 100644 --- a/base/threading/worker_pool_win.cc +++ b/base/threading/worker_pool_win.cc
@@ -37,9 +37,7 @@ g_worker_pool_running_on_this_thread.Get().Set(false); tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking( - pending_task->birth_tally, - tracked_objects::TrackedTime(pending_task->time_posted), - stopwatch); + pending_task->birth_tally, pending_task->time_posted, stopwatch); delete pending_task; return 0;
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc index 4320509..fc29e2e 100644 --- a/base/tracked_objects.cc +++ b/base/tracked_objects.cc
@@ -873,21 +873,21 @@ current_thread_data_(NULL), excluded_duration_ms_(0), parent_(NULL) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() state_ = CREATED; child_ = NULL; #endif } TaskStopwatch::~TaskStopwatch() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(state_ != RUNNING); DCHECK(child_ == NULL); #endif } void TaskStopwatch::Start() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(state_ == CREATED); state_ = RUNNING; #endif @@ -899,7 +899,7 @@ return; parent_ = current_thread_data_->current_stopwatch_; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() if (parent_) { DCHECK(parent_->state_ == RUNNING); DCHECK(parent_->child_ == NULL); @@ -911,7 +911,7 @@ void TaskStopwatch::Stop() { const TrackedTime end_time = ThreadData::Now(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(state_ == RUNNING); state_ = STOPPED; DCHECK(child_ == NULL); @@ -929,7 +929,7 @@ if (!parent_) return; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(parent_->state_ == RUNNING); DCHECK(parent_->child_ == this); parent_->child_ = NULL; @@ -939,7 +939,7 @@ } TrackedTime TaskStopwatch::StartTime() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(state_ != CREATED); #endif @@ -947,7 +947,7 @@ } int32 TaskStopwatch::RunDurationMs() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(state_ == STOPPED); #endif @@ -955,7 +955,7 @@ } ThreadData* TaskStopwatch::GetThreadData() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(state_ != CREATED); #endif
diff --git a/base/tracked_objects.h b/base/tracked_objects.h index eb38df6..5196f19 100644 --- a/base/tracked_objects.h +++ b/base/tracked_objects.h
@@ -749,7 +749,7 @@ // duration of this stopwatch. TaskStopwatch* parent_; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // State of the stopwatch. Stopwatch is first constructed in a created state // state, then is optionally started/stopped, then destructed. enum { CREATED, RUNNING, STOPPED } state_;
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc index b6fc851..e2ea362 100644 --- a/base/tracked_objects_unittest.cc +++ b/base/tracked_objects_unittest.cc
@@ -382,8 +382,7 @@ Location location(kFunction, kFile, kLineNumber, NULL); TallyABirth(location, kMainThreadName); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -419,8 +418,7 @@ Location location(kFunction, kFile, kLineNumber, NULL); TallyABirth(location, kMainThreadName); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -458,8 +456,7 @@ Location location(kFunction, kFile, kLineNumber, NULL); TallyABirth(location, kMainThreadName); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -556,8 +553,7 @@ Location location(kFunction, kFile, kLineNumber, NULL); TallyABirth(location, kMainThreadName); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -601,8 +597,7 @@ const char kFunction[] = "DifferentLives"; Location location(kFunction, kFile, kLineNumber, NULL); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -668,8 +663,7 @@ Location location(kFunction, kFile, kLineNumber, NULL); TallyABirth(location, kMainThreadName); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -706,8 +700,7 @@ Location location(kFunction, kFile, kLineNumber, NULL); TallyABirth(location, kMainThreadName); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -753,8 +746,7 @@ TallyABirth(location, kMainThreadName); - const base::TimeTicks kTimePosted = base::TimeTicks() + - base::TimeDelta::FromMilliseconds(1); + const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1); const base::TimeTicks kDelayedStartTime = base::TimeTicks(); // TrackingInfo will call TallyABirth() during construction. base::TrackingInfo pending_task(location, kDelayedStartTime); @@ -771,8 +763,7 @@ Location second_location(kFunction, kFile, kSecondFakeLineNumber, NULL); base::TrackingInfo nested_task(second_location, kDelayedStartTime); // Overwrite implied Now(). - nested_task.time_posted = - base::TimeTicks() + base::TimeDelta::FromMilliseconds(8); + nested_task.time_posted = TrackedTime::FromMilliseconds(8); SetTestTime(9); TaskStopwatch nested_task_stopwatch; nested_task_stopwatch.Start();
diff --git a/base/tracking_info.cc b/base/tracking_info.cc index 0b091f8..c02b2f4 100644 --- a/base/tracking_info.cc +++ b/base/tracking_info.cc
@@ -18,7 +18,7 @@ base::TimeTicks delayed_run_time) : birth_tally( tracked_objects::ThreadData::TallyABirthIfActive(posted_from)), - time_posted(TimeTicks::Now()), + time_posted(tracked_objects::ThreadData::Now()), delayed_run_time(delayed_run_time) { }
diff --git a/base/tracking_info.h b/base/tracking_info.h index a1c6392..6c3bcd1 100644 --- a/base/tracking_info.h +++ b/base/tracking_info.h
@@ -36,15 +36,18 @@ // unserviced, after they *could* be serviced. This is the same stat as we // have for non-delayed tasks, and we consistently call it queuing delay. tracked_objects::TrackedTime EffectiveTimePosted() const { - return tracked_objects::TrackedTime( - delayed_run_time.is_null() ? time_posted : delayed_run_time); + return delayed_run_time.is_null() + ? time_posted + : tracked_objects::TrackedTime(delayed_run_time); } // Record of location and thread that the task came from. tracked_objects::Births* birth_tally; - // Time when the related task was posted. - base::TimeTicks time_posted; + // Time when the related task was posted. Note that this value may be empty + // if task profiling is disabled, and should only be used in conjunction with + // profiling-related reporting. + tracked_objects::TrackedTime time_posted; // The time when the task should be run. base::TimeTicks delayed_run_time;
diff --git a/build/OWNERS b/build/OWNERS index d1529af..da383a1 100644 --- a/build/OWNERS +++ b/build/OWNERS
@@ -1,3 +1,4 @@ cjhopman@chromium.org +jochen@chromium.org scottmg@chromium.org thakis@chromium.org
diff --git a/build/all.gyp b/build/all.gyp index 04e67c3..226eada 100644 --- a/build/all.gyp +++ b/build/all.gyp
@@ -311,6 +311,7 @@ '../components/components_tests.gyp:components_unittests', '../crypto/crypto.gyp:crypto_unittests', '../net/net.gyp:net_unittests', + '../skia/skia_tests.gyp:skia_unittests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', '../ui/base/ui_base_tests.gyp:ui_base_unittests', @@ -839,6 +840,7 @@ '../media/media.gyp:media_unittests', '../net/net.gyp:net_unittests', '../sandbox/sandbox.gyp:sandbox_linux_unittests_deps', + '../skia/skia_tests.gyp:skia_unittests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', '../testing/android/junit/junit_test.gyp:junit_unit_tests', @@ -873,6 +875,7 @@ '../media/media.gyp:media_unittests_apk', '../net/net.gyp:net_unittests_apk', '../sandbox/sandbox.gyp:sandbox_linux_jni_unittests_apk', + '../skia/skia_tests.gyp:skia_unittests_apk', '../sql/sql.gyp:sql_unittests_apk', '../sync/sync.gyp:sync_unit_tests_apk', '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk', @@ -945,6 +948,7 @@ '../printing/printing.gyp:printing_unittests', '../remoting/remoting.gyp:remoting_unittests', '../rlz/rlz.gyp:*', + '../skia/skia_tests.gyp:skia_unittests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', @@ -982,6 +986,7 @@ '../ppapi/ppapi_internal.gyp:ppapi_unittests', '../printing/printing.gyp:printing_unittests', '../remoting/remoting.gyp:remoting_unittests', + '../skia/skia_tests.gyp:skia_unittests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', @@ -1032,6 +1037,7 @@ '../google_apis/gcm/gcm.gyp:gcm_unit_tests', '../printing/printing.gyp:printing_unittests', '../remoting/remoting.gyp:remoting_unittests', + '../skia/skia_tests.gyp:skia_unittests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', @@ -1081,6 +1087,7 @@ '../ppapi/ppapi_internal.gyp:ppapi_unittests', '../printing/printing.gyp:printing_unittests', '../remoting/remoting.gyp:remoting_unittests', + '../skia/skia_tests.gyp:skia_unittests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', @@ -1181,6 +1188,7 @@ '../net/net.gyp:net_unittests', '../printing/printing.gyp:printing_unittests', '../remoting/remoting.gyp:remoting_unittests', + '../skia/skia_tests.gyp:skia_unittests', '../sql/sql.gyp:sql_unittests', '../sync/sync.gyp:sync_unit_tests', '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests', @@ -1277,6 +1285,7 @@ '../google_apis/gcm/gcm.gyp:gcm_unit_tests', '../ppapi/ppapi_internal.gyp:ppapi_unittests', '../remoting/remoting.gyp:remoting_unittests', + '../skia/skia_tests.gyp:skia_unittests', '../ui/app_list/app_list.gyp:*', '../ui/aura/aura.gyp:*', '../ui/base/ui_base_tests.gyp:ui_base_unittests',
diff --git a/build/android/adb_kill_chrome_shell b/build/android/adb_kill_chrome_shell new file mode 100755 index 0000000..2b63c9a --- /dev/null +++ b/build/android/adb_kill_chrome_shell
@@ -0,0 +1,24 @@ +#!/bin/bash +# +# Copyright (c) 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. +# +# Kill a running chrome shell. +# +# Assumes you have sourced the build/android/envsetup.sh script. + +SHELL_PID_LINES=$(adb shell ps | grep ' org.chromium.chrome.shell') +VAL=$(echo "$SHELL_PID_LINES" | wc -l) +if [ $VAL -lt 1 ] ; then + echo "Not running Chrome shell." +else + SHELL_PID=$(echo $SHELL_PID_LINES | awk '{print $2}') + if [ "$SHELL_PID" != "" ] ; then + set -x + adb shell kill $SHELL_PID + set - + else + echo "Chrome shell does not appear to be running." + fi +fi
diff --git a/build/android/gyp/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py index b10e7c5..46417ec 100755 --- a/build/android/gyp/java_cpp_enum.py +++ b/build/android/gyp/java_cpp_enum.py
@@ -124,6 +124,12 @@ enum_end_re = re.compile(r'^\s*}\s*;\.*$') generator_directive_re = re.compile( r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*([\.\w]+)$') + multi_line_generator_directive_start_re = re.compile( + r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*\(([\.\w]*)$') + multi_line_directive_continuation_re = re.compile( + r'^\s*//\s+([\.\w]+)$') + multi_line_directive_end_re = re.compile( + r'^\s*//\s+([\.\w]*)\)$') optional_class_or_struct_re = r'(class|struct)?' enum_name_re = r'(\w+)' @@ -131,12 +137,18 @@ enum_start_re = re.compile(r'^\s*enum\s+' + optional_class_or_struct_re + '\s*' + enum_name_re + '\s*' + optional_fixed_type_re + '\s*{\s*$') - def __init__(self, lines): + def __init__(self, lines, path=None): self._lines = lines + self._path = path self._enum_definitions = [] self._in_enum = False self._current_definition = None self._generator_directives = DirectiveSet() + self._multi_line_generator_directive = None + + def _ApplyGeneratorDirectives(self): + self._generator_directives.UpdateDefinition(self._current_definition) + self._generator_directives = DirectiveSet() def ParseDefinitions(self): for line in self._lines: @@ -144,7 +156,9 @@ return self._enum_definitions def _ParseLine(self, line): - if not self._in_enum: + if self._multi_line_generator_directive: + self._ParseMultiLineDirectiveLine(line) + elif not self._in_enum: self._ParseRegularLine(line) else: self._ParseEnumLine(line) @@ -153,7 +167,8 @@ if HeaderParser.single_line_comment_re.match(line): return if HeaderParser.multi_line_comment_start_re.match(line): - raise Exception('Multi-line comments in enums are not supported.') + raise Exception('Multi-line comments in enums are not supported in ' + + self._path) enum_end = HeaderParser.enum_end_re.match(line) enum_entry = HeaderParser.enum_line_re.match(line) if enum_end: @@ -166,25 +181,46 @@ enum_value = enum_entry.groups()[2] self._current_definition.AppendEntry(enum_key, enum_value) - def _ApplyGeneratorDirectives(self): - self._generator_directives.UpdateDefinition(self._current_definition) - self._generator_directives = DirectiveSet() + def _ParseMultiLineDirectiveLine(self, line): + multi_line_directive_continuation = ( + HeaderParser.multi_line_directive_continuation_re.match(line)) + multi_line_directive_end = ( + HeaderParser.multi_line_directive_end_re.match(line)) + + if multi_line_directive_continuation: + value_cont = multi_line_directive_continuation.groups()[0] + self._multi_line_generator_directive[1].append(value_cont) + elif multi_line_directive_end: + directive_name = self._multi_line_generator_directive[0] + directive_value = "".join(self._multi_line_generator_directive[1]) + directive_value += multi_line_directive_end.groups()[0] + self._multi_line_generator_directive = None + self._generator_directives.Update(directive_name, directive_value) + else: + raise Exception('Malformed multi-line directive declaration in ' + + self._path) def _ParseRegularLine(self, line): enum_start = HeaderParser.enum_start_re.match(line) generator_directive = HeaderParser.generator_directive_re.match(line) - if enum_start: + multi_line_generator_directive_start = ( + HeaderParser.multi_line_generator_directive_start_re.match(line)) + + if generator_directive: + directive_name = generator_directive.groups()[0] + directive_value = generator_directive.groups()[1] + self._generator_directives.Update(directive_name, directive_value) + elif multi_line_generator_directive_start: + directive_name = multi_line_generator_directive_start.groups()[0] + directive_value = multi_line_generator_directive_start.groups()[1] + self._multi_line_generator_directive = (directive_name, [directive_value]) + elif enum_start: if self._generator_directives.empty: return self._current_definition = EnumDefinition( original_enum_name=enum_start.groups()[1], fixed_type=enum_start.groups()[3]) self._in_enum = True - elif generator_directive: - directive_name = generator_directive.groups()[0] - directive_value = generator_directive.groups()[1] - self._generator_directives.Update(directive_name, directive_value) - def GetScriptName(): script_components = os.path.abspath(sys.argv[0]).split(os.path.sep) @@ -209,7 +245,7 @@ def DoParseHeaderFile(path): with open(path) as f: - return HeaderParser(f.readlines()).ParseDefinitions() + return HeaderParser(f.readlines(), path).ParseDefinitions() def GenerateOutput(source_path, enum_definition):
diff --git a/build/android/gyp/java_cpp_enum_tests.py b/build/android/gyp/java_cpp_enum_tests.py index 3aa386e..75e6671 100755 --- a/build/android/gyp/java_cpp_enum_tests.py +++ b/build/android/gyp/java_cpp_enum_tests.py
@@ -223,6 +223,82 @@ with self.assertRaises(Exception): HeaderParser(test_data).ParseDefinitions() + def testParseSimpleMultiLineDirective(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: ( + // test.namespace) + // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar + enum Foo { + FOO_A, + }; + """.split('\n') + definitions = HeaderParser(test_data).ParseDefinitions() + self.assertEqual('test.namespace', definitions[0].enum_package) + self.assertEqual('Bar', definitions[0].class_name) + + def testParseMultiLineDirective(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: (te + // st.name + // space) + enum Foo { + FOO_A, + }; + """.split('\n') + definitions = HeaderParser(test_data).ParseDefinitions() + self.assertEqual('test.namespace', definitions[0].enum_package) + + def testParseMultiLineDirectiveWithOtherDirective(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: ( + // test.namespace) + // GENERATED_JAVA_CLASS_NAME_OVERRIDE: ( + // Ba + // r + // ) + enum Foo { + FOO_A, + }; + """.split('\n') + definitions = HeaderParser(test_data).ParseDefinitions() + self.assertEqual('test.namespace', definitions[0].enum_package) + self.assertEqual('Bar', definitions[0].class_name) + + def testParseMalformedMultiLineDirectiveWithOtherDirective(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: ( + // test.name + // space + // GENERATED_JAVA_CLASS_NAME_OVERRIDE: Bar + enum Foo { + FOO_A, + }; + """.split('\n') + with self.assertRaises(Exception): + HeaderParser(test_data).ParseDefinitions() + + def testParseMalformedMultiLineDirective(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: ( + // test.name + // space + enum Foo { + FOO_A, + }; + """.split('\n') + with self.assertRaises(Exception): + HeaderParser(test_data).ParseDefinitions() + + def testParseMalformedMultiLineDirectiveShort(self): + test_data = """ + // GENERATED_JAVA_ENUM_PACKAGE: ( + enum Foo { + FOO_A, + }; + """.split('\n') + with self.assertRaises(Exception): + HeaderParser(test_data).ParseDefinitions() + def testEnumValueAssignmentNoneDefined(self): definition = EnumDefinition(original_enum_name='c', enum_package='p') definition.AppendEntry('A', None)
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py index 87ff73d..0e48ee6 100644 --- a/build/android/pylib/remote/device/remote_device_environment.py +++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -62,6 +62,12 @@ self._runner_type = args.runner_type self._device = '' self._verbose_count = args.verbose_count + self._timeouts = { + 'queueing': 60 * 10, + 'installing': 60 * 10, + 'in-progress': 60 * 30, + 'unknown': 60 * 5 + } if not args.trigger and not args.collect: self._trigger = True @@ -135,7 +141,8 @@ if (self._remote_device_os and device['os_version'] != self._remote_device_os): continue - if device['available_devices_count'] > 0: + if ((self._remote_device and self._remote_device_os) + or device['available_devices_count']): logging.info('Found device: %s %s', device['name'], device['os_version']) return device['device_type_id'] @@ -189,3 +196,7 @@ @property def verbose_count(self): return self._verbose_count + + @property + def timeouts(self): + return self._timeouts
diff --git a/build/android/pylib/remote/device/remote_device_gtest_run.py b/build/android/pylib/remote/device/remote_device_gtest_run.py index 49ddc91..3a6c447 100644 --- a/build/android/pylib/remote/device/remote_device_gtest_run.py +++ b/build/android/pylib/remote/device/remote_device_gtest_run.py
@@ -19,7 +19,7 @@ """Run gtests and uirobot tests on a remote device.""" DEFAULT_RUNNER_PACKAGE = ( - 'org.chromium.native_test.ChromiumNativeTestInstrumentationTestRunner') + 'org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner') #override def TestPackage(self): @@ -62,4 +62,8 @@ if l.startswith(self._INSTRUMENTATION_STREAM_LEADER)) results_list = self._test_instance.ParseGTestOutput(output) results.AddResults(results_list) + if not self._results['results']['pass']: + results.AddResult(base_test_result.BaseTestResult( + 'Remote Service detected error.', + base_test_result.ResultType.FAIL)) return results
diff --git a/build/android/pylib/remote/device/remote_device_test_run.py b/build/android/pylib/remote/device/remote_device_test_run.py index 2144e24..cdc8777 100644 --- a/build/android/pylib/remote/device/remote_device_test_run.py +++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -22,6 +22,7 @@ WAIT_TIME = 5 COMPLETE = 'complete' + HEARTBEAT_INTERVAL = 300 def __init__(self, env, test_instance): """Constructor. @@ -37,7 +38,6 @@ self._test_id = '' self._results = '' self._test_run_id = '' - self._current_status = '' #override def RunTests(self): @@ -63,8 +63,28 @@ 'File for storing test_run_id must be a string.') with open(self._env.collect, 'r') as test_run_id_file: self._test_run_id = test_run_id_file.read().strip() + current_status = '' + timeout_counter = 0 + heartbeat_counter = 0 while self._GetTestStatus(self._test_run_id) != self.COMPLETE: + if self._results['detailed_status'] != current_status: + logging.info('Test status: %s', self._results['detailed_status']) + current_status = self._results['detailed_status'] + timeout_counter = 0 + heartbeat_counter = 0 + if heartbeat_counter > self.HEARTBEAT_INTERVAL: + logging.info('Test status: %s', self._results['detailed_status']) + heartbeat_counter = 0 + + timeout = self._env.timeouts.get( + current_status, self._env.timeouts['unknown']) + if timeout_counter > timeout: + raise remote_device_helper.RemoteDeviceError( + 'Timeout while in %s state for %s seconds' + % (current_status, timeout)) time.sleep(self.WAIT_TIME) + timeout_counter += self.WAIT_TIME + heartbeat_counter += self.WAIT_TIME self._DownloadTestResults(self._env.results_path) return self._ParseTestResults() @@ -148,9 +168,6 @@ remote_device_helper.TestHttpResponse(test_check_res, 'Unable to get test status.') self._results = test_check_res.json()['response'] - if self._results['detailed_status'] != self._current_status: - logging.info('Test status: %s', self._results['detailed_status']) - self._current_status = self._results['detailed_status'] return self._results['status'] def _AmInstrumentTestSetup(self, app_path, test_path, runner_package): @@ -184,12 +201,11 @@ def _UploadAppToDevice(self, app_path): """Upload app to device.""" logging.info('Uploading %s to remote service.', app_path) - apk_name = os.path.basename(app_path) with open(app_path, 'rb') as apk_src: with appurify_sanitized.SanitizeLogging(self._env.verbose_count, logging.WARNING): upload_results = appurify_sanitized.api.apps_upload( - self._env.token, apk_src, 'raw', name=apk_name) + self._env.token, apk_src, 'raw', name=self._test_instance.suite) remote_device_helper.TestHttpResponse( upload_results, 'Unable to upload %s.' % app_path) return upload_results.json()['response']['app_id']
diff --git a/build/android/pylib/uirobot/uirobot_test_instance.py b/build/android/pylib/uirobot/uirobot_test_instance.py index 9eba0ac..a531b41 100644 --- a/build/android/pylib/uirobot/uirobot_test_instance.py +++ b/build/android/pylib/uirobot/uirobot_test_instance.py
@@ -21,6 +21,7 @@ constants.GetOutDirectory(), args.apk_under_test) self._minutes = args.minutes self._package_name = apk_helper.GetPackageName(self._apk_under_test) + self._suite = 'Android Uirobot' #override def TestType(self): @@ -51,3 +52,7 @@ def package_name(self): """Returns the name of the package in the APK.""" return self._package_name + + @property + def suite(self): + return self._suite
diff --git a/build/common.gypi b/build/common.gypi index 83a3df6..abfa247 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -161,10 +161,6 @@ # build system. 'android_webview_build%': 0, - # This is set when building the Android WebView in ninja for the - # telemetry bot. - 'android_webview_telemetry_build%': 0, - # Set ARM architecture version. 'arm_version%': 7, @@ -296,7 +292,6 @@ 'enable_hidpi%': '<(enable_hidpi)', 'android_channel%': '<(android_channel)', 'android_webview_build%': '<(android_webview_build)', - 'android_webview_telemetry_build%': '<(android_webview_telemetry_build)', 'use_goma%': '<(use_goma)', 'gomadir%': '<(gomadir)', 'enable_app_list%': '<(enable_app_list)', @@ -970,13 +965,13 @@ # except when building Android WebView. # TODO(jshin): Handle 'use_system_icu' on Linux (Chromium). # Set the data reduction proxy origin for Android Webview. - ['android_webview_build==0 and android_webview_telemetry_build==0', { + ['android_webview_build==0', { 'icu_use_data_file_flag%' : 1, }, { 'icu_use_data_file_flag%' : 0, }], ['OS=="win" or OS=="mac"', { - 'enable_wifi_bootstrapping%' : 1, + 'enable_wifi_bootstrapping%' : 1, }], # Path to sas.dll, which provides the SendSAS function. @@ -996,7 +991,7 @@ # TODO(baixo): Enable v8_use_external_startup_data # http://crbug.com/421063 - ['android_webview_build==0 and android_webview_telemetry_build==0 and chromecast==0 and chromeos==0 and (OS=="android" or OS=="linux" or OS=="mac")', { + ['android_webview_build==0 and chromecast==0 and chromeos==0 and (OS=="android" or OS=="linux" or OS=="mac")', { 'v8_use_external_startup_data%': 1, }, { 'v8_use_external_startup_data%': 0, @@ -1176,7 +1171,6 @@ 'use_system_libjpeg%': '<(use_system_libjpeg)', 'android_channel%': '<(android_channel)', 'android_webview_build%': '<(android_webview_build)', - 'android_webview_telemetry_build%': '<(android_webview_telemetry_build)', 'icu_use_data_file_flag%': '<(icu_use_data_file_flag)', 'gyp_managed_install%': 0, 'create_standalone_apk%': 1, @@ -1812,7 +1806,7 @@ }], ['chromecast==1', { 'enable_mpeg2ts_stream_parser%': 1, - 'ffmpeg_branding%': 'Chrome', + 'ffmpeg_branding%': 'ChromeOS', 'ozone_platform_ozonex%': 1, 'use_playready%': 0, 'conditions': [ @@ -4328,7 +4322,7 @@ }], ['use_custom_libcxx==1', { 'dependencies': [ - '<(DEPTH)/third_party/libc++/libc++.gyp:libcxx_proxy', + '<(DEPTH)/buildtools/third_party/libc++/libc++.gyp:libcxx_proxy', ], }], ['order_profiling!=0 and (chromeos==1 or OS=="linux" or OS=="android")', {
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 5417863..b33cd88 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1464,7 +1464,7 @@ final_apk_path = "$root_build_dir/${_apk_name}_apk/${_apk_name}-debug.apk" java_files = [ "//testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java", - "//testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java", + "//testing/android/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java", ] android_manifest = "//testing/android/java/AndroidManifest.xml" native_libs = [ unittests_binary ]
diff --git a/build/gdb-add-index b/build/gdb-add-index index 687e9f5..992ac16 100755 --- a/build/gdb-add-index +++ b/build/gdb-add-index
@@ -38,10 +38,10 @@ local basename=$(basename "$file") local should_index="${SHOULD_INDEX}" - local readelf_out=$(readelf -S "$file") + local readelf_out=$(${TOOLCHAIN_PREFIX}readelf -S "$file") if [[ $readelf_out =~ "gdb_index" ]]; then if [ "${REMOVE_INDEX}" = 1 ]; then - objcopy --remove-section .gdb_index "$file" + ${TOOLCHAIN_PREFIX}objcopy --remove-section .gdb_index "$file" echo "Removed index from $basename." else echo "Skipped $basename -- already contains index." @@ -53,14 +53,15 @@ local start=$(date +"%s%N") echo "Adding index to $basename..." - gdb -batch "$file" -ex "save gdb-index $DIRECTORY" -ex "quit" + ${TOOLCHAIN_PREFIX}gdb -batch "$file" -ex "save gdb-index $DIRECTORY" \ + -ex "quit" local index_file="$DIRECTORY/$basename.gdb-index" if [ -f "$index_file" ]; then - objcopy --add-section .gdb_index="$index_file" \ + ${TOOLCHAIN_PREFIX}objcopy --add-section .gdb_index="$index_file" \ --set-section-flags .gdb_index=readonly "$file" "$file" local finish=$(date +"%s%N") - local elappsed=$(((finish - start)/1000000)) - echo " ...$basename indexed. [${elappsed}ms]" + local elapsed=$(((finish - start)/1000000)) + echo " ...$basename indexed. [${elapsed}ms]" else echo " ...$basename unindexable." fi
diff --git a/build/get_sdk_extras_packages.py b/build/get_sdk_extras_packages.py new file mode 100755 index 0000000..32e5564 --- /dev/null +++ b/build/get_sdk_extras_packages.py
@@ -0,0 +1,21 @@ +#!/usr/bin/env python +# Copyright (c) 2014 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. + +import json +import os +import sys + +SDK_EXTRAS_JSON_FILE = os.path.join(os.path.dirname(sys.argv[0]), + 'android_sdk_extras.json') + +def main(): + with open(SDK_EXTRAS_JSON_FILE) as json_file: + packages = json.load(json_file) + for package in packages: + print package['package'].replace('_', ' ') + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/build/install-build-deps-android.sh b/build/install-build-deps-android.sh index 1fcf4fb..b61b033 100755 --- a/build/install-build-deps-android.sh +++ b/build/install-build-deps-android.sh
@@ -84,4 +84,16 @@ fi fi +# Get the SDK extras packages to install from the DEPS file 'sdkextras' hook. +packages="$(python -c 'execfile("./get_sdk_extras_packages.py")')" +for package in "${packages}"; do + package_num=$(../third_party/android_tools/sdk/tools/android list sdk | \ + grep -i "$package," | \ + awk '/^[ ]*[0-9]*- / {gsub("-",""); print $1}') + if [[ -n ${package_num} ]]; then + ../third_party/android_tools/sdk/tools/android update sdk --no-ui --filter \ + ${package_num} + fi +done + echo "install-build-deps-android.sh complete."
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt index 08eb9fe..f8cbd8f 100644 --- a/build/ios/grit_whitelist.txt +++ b/build/ios/grit_whitelist.txt
@@ -505,8 +505,6 @@ IDS_FLAGS_ENABLE IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_DESCRIPTION IDS_FLAGS_ENABLE_APPS_SHOW_ON_FIRST_PAINT_NAME -IDS_FLAGS_ENABLE_ASYNC_DNS_DESCRIPTION -IDS_FLAGS_ENABLE_ASYNC_DNS_NAME IDS_FLAGS_ENABLE_CARRIER_SWITCHING IDS_FLAGS_ENABLE_CARRIER_SWITCHING_DESCRIPTION IDS_FLAGS_ENABLE_CONTEXTUAL_SEARCH
diff --git a/build/sanitizers/sanitizers.gyp b/build/sanitizers/sanitizers.gyp index 64f7cdf..53cc298 100644 --- a/build/sanitizers/sanitizers.gyp +++ b/build/sanitizers/sanitizers.gyp
@@ -28,7 +28,7 @@ 'conditions': [ ['use_custom_libcxx==1', { 'dependencies!': [ - '../../third_party/libc++/libc++.gyp:libcxx_proxy', + '../../buildtools/third_party/libc++/libc++.gyp:libcxx_proxy', ], }], ['tsan==1', {
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index 7c10d6c..42c71b1 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -306,6 +306,12 @@ // Suppressing both AudioContext.{cpp,h}. "race:modules/webaudio/AudioContext\n" +// https://code.google.com/p/skia/issues/detail?id=3294 +"race:SkBaseMutex::acquire\n" + +// https://crbug.com/447461 +"race:net::SSLConfig::SSLConfig\n" + // End of suppressions. ; // Please keep this semicolon.
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 44896c1..82a5474 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -96,6 +96,8 @@ "debug/micro_benchmark_controller_impl.h", "debug/paint_time_counter.cc", "debug/paint_time_counter.h", + "debug/picture_debug_util.cc", + "debug/picture_debug_util.h", "debug/picture_record_benchmark.cc", "debug/picture_record_benchmark.h", "debug/rasterize_and_record_benchmark.cc",
diff --git a/cc/animation/keyframed_animation_curve_unittest.cc b/cc/animation/keyframed_animation_curve_unittest.cc index 0fd8da9..dc8537d 100644 --- a/cc/animation/keyframed_animation_curve_unittest.cc +++ b/cc/animation/keyframed_animation_curve_unittest.cc
@@ -725,6 +725,68 @@ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); } +// Tests that a linear timing function works as expected for inputs outside of +// range [0,1] +TEST(KeyframedAnimationCurveTest, LinearTimingInputsOutsideZeroOneRange) { + scoped_ptr<KeyframedFloatAnimationCurve> curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr)); + curve->AddKeyframe( + FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr)); + // Curve timing function producing timing outputs outside of range [0,1]. + curve->SetTimingFunction( + CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass()); + + EXPECT_NEAR(-0.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)), + 0.001f); + EXPECT_NEAR(2.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)), + 0.001f); +} + +// If a curve cubic-bezier timing function produces timing outputs outside +// the range [0, 1] then a keyframe cubic-bezier timing function +// should consume that input properly (using end-point gradients). +TEST(KeyframedAnimationCurveTest, CurveTimingInputsOutsideZeroOneRange) { + scoped_ptr<KeyframedFloatAnimationCurve> curve( + KeyframedFloatAnimationCurve::Create()); + // Keyframe timing function with 0.5 gradients at each end. + curve->AddKeyframe(FloatKeyframe::Create( + base::TimeDelta(), 0.f, + CubicBezierTimingFunction::Create(0.5f, 0.25f, 0.5f, 0.75f).Pass())); + curve->AddKeyframe( + FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr)); + // Curve timing function producing timing outputs outside of range [0,1]. + curve->SetTimingFunction( + CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass()); + + EXPECT_NEAR(-0.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)), + 0.002f); // c(.25)=-.04, -.04*0.5=-0.02 + EXPECT_NEAR(0.33f, curve->GetValue(base::TimeDelta::FromSecondsD(0.46f)), + 0.002f); // c(.46)=.38, k(.38)=.33 + + EXPECT_NEAR(0.67f, curve->GetValue(base::TimeDelta::FromSecondsD(0.54f)), + 0.002f); // c(.54)=.62, k(.62)=.67 + EXPECT_NEAR(1.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)), + 0.002f); // c(.75)=1.04 1+.04*0.5=1.02 +} + +// Tests that a step timing function works as expected for inputs outside of +// range [0,1] +TEST(KeyframedAnimationCurveTest, StepsTimingInputsOutsideZeroOneRange) { + scoped_ptr<KeyframedFloatAnimationCurve> curve( + KeyframedFloatAnimationCurve::Create()); + curve->AddKeyframe(FloatKeyframe::Create( + base::TimeDelta(), 0.f, StepsTimingFunction::Create(4, 0.5f))); + curve->AddKeyframe( + FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr)); + // Curve timing function producing timing outputs outside of range [0,1]. + curve->SetTimingFunction( + CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass()); + + EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f))); + EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f))); +} + // Tests that an animation with a curve timing function and multiple keyframes // works as expected. TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) {
diff --git a/cc/base/completion_event.h b/cc/base/completion_event.h index 96ccf54..6bae765 100644 --- a/cc/base/completion_event.h +++ b/cc/base/completion_event.h
@@ -19,21 +19,21 @@ public: CompletionEvent() : event_(false /* manual_reset */, false /* initially_signaled */) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() waited_ = false; signaled_ = false; #endif } ~CompletionEvent() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(waited_); DCHECK(signaled_); #endif } void Wait() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(!waited_); waited_ = true; #endif @@ -42,7 +42,7 @@ } void Signal() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(!signaled_); signaled_ = true; #endif @@ -51,7 +51,7 @@ private: base::WaitableEvent event_; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // Used to assert that Wait() and Signal() are each called exactly once. bool waited_; bool signaled_;
diff --git a/cc/cc.gyp b/cc/cc.gyp index f8da8e7..1393ae7 100644 --- a/cc/cc.gyp +++ b/cc/cc.gyp
@@ -124,6 +124,8 @@ 'debug/micro_benchmark_controller_impl.h', 'debug/paint_time_counter.cc', 'debug/paint_time_counter.h', + 'debug/picture_debug_util.cc', + 'debug/picture_debug_util.h', 'debug/picture_record_benchmark.cc', 'debug/picture_record_benchmark.h', 'debug/rasterize_and_record_benchmark.cc',
diff --git a/cc/debug/picture_debug_util.cc b/cc/debug/picture_debug_util.cc new file mode 100644 index 0000000..e653b78 --- /dev/null +++ b/cc/debug/picture_debug_util.cc
@@ -0,0 +1,73 @@ +// Copyright 2015 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. + +#include "cc/debug/picture_debug_util.h" + +#include <vector> + +#include "base/base64.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkData.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkPixelSerializer.h" +#include "third_party/skia/include/core/SkStream.h" +#include "ui/gfx/codec/jpeg_codec.h" +#include "ui/gfx/codec/png_codec.h" + +namespace { + +class BitmapSerializer : public SkPixelSerializer { + protected: + bool onUseEncodedData(const void* data, size_t len) override { return true; } + + SkData* onEncodePixels(const SkImageInfo& info, + const void* pixels, + size_t row_bytes) override { + const int kJpegQuality = 80; + std::vector<unsigned char> data; + + // If bitmap is opaque, encode as JPEG. + // Otherwise encode as PNG. + bool encoding_succeeded = false; + if (info.isOpaque()) { + encoding_succeeded = + gfx::JPEGCodec::Encode(reinterpret_cast<const unsigned char*>(pixels), + gfx::JPEGCodec::FORMAT_SkBitmap, info.width(), + info.height(), row_bytes, kJpegQuality, &data); + } else { + SkBitmap bm; + // The cast is ok, since we only read the bm. + if (!bm.installPixels(info, const_cast<void*>(pixels), row_bytes)) { + return nullptr; + } + encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data); + } + + if (encoding_succeeded) { + return SkData::NewWithCopy(&data.front(), data.size()); + } + return nullptr; + } +}; + +} // namespace + +namespace cc { + +void PictureDebugUtil::SerializeAsBase64(const SkPicture* picture, + std::string* output) { + SkDynamicMemoryWStream stream; + BitmapSerializer serializer; + picture->serialize(&stream, &serializer); + + size_t serialized_size = stream.bytesWritten(); + scoped_ptr<char[]> serialized_picture(new char[serialized_size]); + stream.copyTo(serialized_picture.get()); + base::Base64Encode(std::string(serialized_picture.get(), serialized_size), + output); +} + +} // namespace cc
diff --git a/cc/debug/picture_debug_util.h b/cc/debug/picture_debug_util.h new file mode 100644 index 0000000..1719ea2 --- /dev/null +++ b/cc/debug/picture_debug_util.h
@@ -0,0 +1,21 @@ +// Copyright 2015 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. + +#ifndef CC_DEBUG_PICTURE_DEBUG_UTIL_H_ +#define CC_DEBUG_PICTURE_DEBUG_UTIL_H_ + +#include <string> + +class SkPicture; + +namespace cc { + +class PictureDebugUtil { + public: + static void SerializeAsBase64(const SkPicture* picture, std::string* output); +}; + +} // namespace cc + +#endif // CC_DEBUG_PICTURE_DEBUG_UTIL_H_
diff --git a/cc/layers/delegated_frame_provider.cc b/cc/layers/delegated_frame_provider.cc index ce9ac59..bae5e43 100644 --- a/cc/layers/delegated_frame_provider.cc +++ b/cc/layers/delegated_frame_provider.cc
@@ -28,7 +28,7 @@ } void DelegatedFrameProvider::AddObserver(DelegatedRendererLayer* layer) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (size_t i = 0; i < observers_.size(); ++i) DCHECK(observers_[i].layer != layer); #endif
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 49e4d1f..718535b 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -1115,7 +1115,7 @@ } void PictureLayerImpl::SanityCheckTilingState() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // Recycle tree doesn't have any restrictions. if (layer_tree_impl()->IsRecycleTree()) return;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 9814cad..ebbec56 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -50,7 +50,7 @@ public: explicit MockCanvas(int w, int h) : SkCanvas(w, h) {} - void drawRect(const SkRect& rect, const SkPaint& paint) override { + void onDrawRect(const SkRect& rect, const SkPaint& paint) override { // Capture calls before SkCanvas quickReject() kicks in. rects_.push_back(rect); }
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc index f6e1eb6..285acee 100644 --- a/cc/layers/surface_layer_unittest.cc +++ b/cc/layers/surface_layer_unittest.cc
@@ -172,7 +172,7 @@ PostSetNeedsCommitToMainThread(); } - void DidCommit() override { + void DidCommitAndDrawFrame() override { base::MessageLoopProxy::current()->PostTask( FROM_HERE, base::Bind(&SurfaceLayerSwapPromise::ChangeTree, base::Unretained(this)));
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc index 786f41a..d08e60a 100644 --- a/cc/output/begin_frame_args.cc +++ b/cc/output/begin_frame_args.cc
@@ -92,8 +92,4 @@ return base::TimeDelta::FromMicroseconds(16666); } -base::TimeDelta BeginFrameArgs::DefaultRetroactiveBeginFramePeriod() { - return base::TimeDelta::FromMicroseconds(4444); -} - } // namespace cc
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h index efff695..53745f9 100644 --- a/cc/output/begin_frame_args.h +++ b/cc/output/begin_frame_args.h
@@ -75,12 +75,6 @@ // magic numbers. static base::TimeDelta DefaultInterval(); - // This is the default amount of time after the frame_time to retroactively - // send a BeginFrame that had been skipped. This only has an effect if the - // deadline has passed, since the deadline is also used to trigger BeginFrame - // retroactively. - static base::TimeDelta DefaultRetroactiveBeginFramePeriod(); - bool IsValid() const { return interval >= base::TimeDelta(); } scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc index c05c32f..75fc2d6c 100644 --- a/cc/output/delegating_renderer.cc +++ b/cc/output/delegating_renderer.cc
@@ -41,7 +41,8 @@ capabilities_.using_partial_swap = false; capabilities_.max_texture_size = resource_provider_->max_texture_size(); capabilities_.best_texture_format = resource_provider_->best_texture_format(); - capabilities_.allow_partial_texture_updates = false; + capabilities_.allow_partial_texture_updates = + output_surface->capabilities().can_force_reclaim_resources; if (!output_surface_->context_provider()) { capabilities_.using_shared_memory_resources = true;
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h index 04bd4a3..29e32a5 100644 --- a/cc/output/output_surface.h +++ b/cc/output/output_surface.h
@@ -64,7 +64,8 @@ draw_and_swap_full_viewport_every_frame(false), adjust_deadline_for_parent(true), uses_default_gl_framebuffer(true), - flipped_output_surface(false) {} + flipped_output_surface(false), + can_force_reclaim_resources(false) {} bool delegated_rendering; int max_frames_pending; bool deferred_gl_initialization; @@ -77,6 +78,9 @@ bool uses_default_gl_framebuffer; // Whether this OutputSurface is flipped or not. bool flipped_output_surface; + // Whether ForceReclaimResources can be called to reclaim all resources + // from the OutputSurface. + bool can_force_reclaim_resources; }; const Capabilities& capabilities() const { @@ -111,6 +115,10 @@ virtual void Reshape(const gfx::Size& size, float scale_factor); virtual gfx::Size SurfaceSize() const; + // If supported, this causes a ReclaimResources for all resources that are + // currently in use. + virtual void ForceReclaimResources() {} + virtual void BindFramebuffer(); // The implementation may destroy or steal the contents of the CompositorFrame
diff --git a/cc/resources/display_item.cc b/cc/resources/display_item.cc index 33069a5..52bdec1 100644 --- a/cc/resources/display_item.cc +++ b/cc/resources/display_item.cc
@@ -9,4 +9,8 @@ DisplayItem::DisplayItem() { } +void DisplayItem::RasterForTracing(SkCanvas* canvas) const { + Raster(canvas, nullptr); +} + } // namespace cc
diff --git a/cc/resources/display_item.h b/cc/resources/display_item.h index 9a4ce50..422bd43 100644 --- a/cc/resources/display_item.h +++ b/cc/resources/display_item.h
@@ -20,6 +20,7 @@ virtual void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const = 0; + virtual void RasterForTracing(SkCanvas* canvas) const; virtual bool IsSuitableForGpuRasterization() const = 0; virtual int ApproximateOpCount() const = 0;
diff --git a/cc/resources/display_item_list.cc b/cc/resources/display_item_list.cc index 2ead28d..6424fee 100644 --- a/cc/resources/display_item_list.cc +++ b/cc/resources/display_item_list.cc
@@ -4,9 +4,15 @@ #include "cc/resources/display_item_list.h" +#include <string> + #include "base/debug/trace_event.h" #include "base/debug/trace_event_argument.h" +#include "cc/base/math_util.h" +#include "cc/debug/picture_debug_util.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "ui/gfx/skia_util.h" namespace cc { @@ -64,8 +70,23 @@ scoped_refptr<base::debug::TracedValue> state = new base::debug::TracedValue(); - // TODO(ajuma): Include the value of each item. state->SetInteger("length", items_.size()); + state->SetValue("params.layer_rect", + MathUtil::AsValue(layer_rect_).release()); + + SkPictureRecorder recorder; + SkCanvas* canvas = + recorder.beginRecording(layer_rect_.width(), layer_rect_.height()); + canvas->translate(-layer_rect_.x(), -layer_rect_.y()); + canvas->clipRect(gfx::RectToSkRect(layer_rect_)); + for (size_t i = 0; i < items_.size(); ++i) + items_[i]->RasterForTracing(canvas); + skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording()); + + std::string b64_picture; + PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture); + state->SetString("skp64", b64_picture); + return state; }
diff --git a/cc/resources/display_item_list.h b/cc/resources/display_item_list.h index 43699dd..1076beb 100644 --- a/cc/resources/display_item_list.h +++ b/cc/resources/display_item_list.h
@@ -29,6 +29,9 @@ void AppendItem(scoped_ptr<DisplayItem> item); + void set_layer_rect(gfx::Rect layer_rect) { layer_rect_ = layer_rect; } + gfx::Rect layer_rect() const { return layer_rect_; } + bool IsSuitableForGpuRasterization() const; int ApproximateOpCount() const; size_t PictureMemoryUsage() const; @@ -41,6 +44,7 @@ DisplayItemList(); ~DisplayItemList(); ScopedPtrVector<DisplayItem> items_; + gfx::Rect layer_rect_; bool is_suitable_for_gpu_rasterization_; int approximate_op_count_;
diff --git a/cc/resources/display_list_recording_source.cc b/cc/resources/display_list_recording_source.cc index ab4c646..a3c3d47 100644 --- a/cc/resources/display_list_recording_source.cc +++ b/cc/resources/display_list_recording_source.cc
@@ -87,6 +87,7 @@ display_list_ = painter->PaintContentsToDisplayList( recorded_viewport_, ContentLayerClient::GRAPHICS_CONTEXT_ENABLED); } + display_list_->set_layer_rect(recorded_viewport_); is_suitable_for_gpu_rasterization_ = display_list_->IsSuitableForGpuRasterization();
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc index eb05e33..473cb77 100644 --- a/cc/resources/drawing_display_item.cc +++ b/cc/resources/drawing_display_item.cc
@@ -32,6 +32,18 @@ canvas->restore(); } +void DrawingDisplayItem::RasterForTracing(SkCanvas* canvas) const { + canvas->save(); + canvas->translate(location_.x(), location_.y()); + // The picture debugger in about:tracing doesn't drill down into |drawPicture| + // operations. Calling |playback()| rather than |drawPicture()| causes the + // skia operations in |picture_| to appear individually in the picture + // produced for tracing rather than being hidden inside a drawPicture + // operation. + picture_->playback(canvas); + canvas->restore(); +} + bool DrawingDisplayItem::IsSuitableForGpuRasterization() const { return picture_->suitableForGpuRasterization(NULL); }
diff --git a/cc/resources/drawing_display_item.h b/cc/resources/drawing_display_item.h index 5723dc4..b55e442 100644 --- a/cc/resources/drawing_display_item.h +++ b/cc/resources/drawing_display_item.h
@@ -27,6 +27,7 @@ } void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override; + void RasterForTracing(SkCanvas* canvas) const override; bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override;
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc index a8e2422..e0435dc 100644 --- a/cc/resources/picture.cc +++ b/cc/resources/picture.cc
@@ -14,17 +14,16 @@ #include "base/values.h" #include "cc/base/math_util.h" #include "cc/base/util.h" +#include "cc/debug/picture_debug_util.h" #include "cc/debug/traced_picture.h" #include "cc/debug/traced_value.h" #include "cc/layers/content_layer_client.h" #include "skia/ext/pixel_ref_utils.h" #include "third_party/skia/include/core/SkBBHFactory.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkDrawPictureCallback.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/core/SkPixelSerializer.h" #include "third_party/skia/include/core/SkStream.h" #include "third_party/skia/include/utils/SkNullCanvas.h" #include "third_party/skia/include/utils/SkPictureUtils.h" @@ -37,40 +36,6 @@ namespace { -class BitmapSerializer : public SkPixelSerializer { - protected: - bool onUseEncodedData(const void* data, size_t len) override { return true; } - - SkData* onEncodePixels(const SkImageInfo& info, - const void* pixels, - size_t row_bytes) override { - const int kJpegQuality = 80; - std::vector<unsigned char> data; - - // If bitmap is opaque, encode as JPEG. - // Otherwise encode as PNG. - bool encoding_succeeded = false; - if (info.isOpaque()) { - encoding_succeeded = - gfx::JPEGCodec::Encode(reinterpret_cast<const unsigned char*>(pixels), - gfx::JPEGCodec::FORMAT_SkBitmap, info.width(), - info.height(), row_bytes, kJpegQuality, &data); - } else { - SkBitmap bm; - // The cast is ok, since we only read the bm. - if (!bm.installPixels(info, const_cast<void*>(pixels), row_bytes)) { - return nullptr; - } - encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data); - } - - if (encoding_succeeded) { - return SkData::NewWithCopy(&data.front(), data.size()); - } - return nullptr; - } -}; - bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) { const unsigned char* data = static_cast<const unsigned char *>(buffer); @@ -177,7 +142,7 @@ Picture::~Picture() { TRACE_EVENT_OBJECT_DELETED_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this); + TRACE_DISABLED_BY_DEFAULT("cc.debug.picture"), "cc::Picture", this); } bool Picture::IsSuitableForGpuRasterization(const char** reason) const { @@ -371,28 +336,19 @@ } scoped_ptr<base::Value> Picture::AsValue() const { - SkDynamicMemoryWStream stream; - BitmapSerializer serializer; - picture_->serialize(&stream, &serializer); - // Encode the picture as base64. scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release()); - - size_t serialized_size = stream.bytesWritten(); - scoped_ptr<char[]> serialized_picture(new char[serialized_size]); - stream.copyTo(serialized_picture.get()); std::string b64_picture; - base::Base64Encode(std::string(serialized_picture.get(), serialized_size), - &b64_picture); + PictureDebugUtil::SerializeAsBase64(picture_.get(), &b64_picture); res->SetString("skp64", b64_picture); return res.Pass(); } void Picture::EmitTraceSnapshot() const { TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT( - "devtools.timeline.picture"), + TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") "," + TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"), "cc::Picture", this, TracedPicture::AsTraceablePicture(this)); @@ -400,8 +356,8 @@ void Picture::EmitTraceSnapshotAlias(Picture* original) const { TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( - TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT( - "devtools.timeline.picture"), + TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") "," + TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"), "cc::Picture", this, TracedPicture::AsTraceablePictureAlias(original));
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc index 01dca9e..341e6e3 100644 --- a/cc/resources/picture_layer_tiling.cc +++ b/cc/resources/picture_layer_tiling.cc
@@ -195,7 +195,7 @@ } DCHECK_EQ(twin_tiling.tiles_.size(), tiles_.size()); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (const auto& tile_map_pair : tiles_) DCHECK(tile_map_pair.second->is_shared()); VerifyLiveTilesRect(false); @@ -683,7 +683,7 @@ } void PictureLayerTiling::VerifyLiveTilesRect(bool is_on_recycle_tree) const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (auto it = tiles_.begin(); it != tiles_.end(); ++it) { if (!it->second.get()) continue;
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc index d868ba8..779e2c0 100644 --- a/cc/resources/picture_layer_tiling_set.cc +++ b/cc/resources/picture_layer_tiling_set.cc
@@ -105,7 +105,7 @@ tilings_.sort(LargestToSmallestScaleFunctor()); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (PictureLayerTiling* tiling : tilings_) { DCHECK(tiling->tile_size() == client_->CalculateTileSize(tiling->tiling_size()))
diff --git a/cc/resources/prioritized_resource.cc b/cc/resources/prioritized_resource.cc index 462f7f1..968083c 100644 --- a/cc/resources/prioritized_resource.cc +++ b/cc/resources/prioritized_resource.cc
@@ -126,7 +126,7 @@ was_above_priority_cutoff_at_last_priority_update_(false), in_drawing_impl_tree_(false), in_parent_compositor_(false), -#if !DCHECK_IS_ON +#if !DCHECK_IS_ON() resource_has_been_deleted_(false) { #else resource_has_been_deleted_(false), @@ -143,7 +143,7 @@ ResourceProvider* resource_provider) { DCHECK(!proxy() || proxy()->IsImplThread()); DCHECK(!resource_has_been_deleted_); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(resource_provider == resource_provider_); #endif
diff --git a/cc/resources/prioritized_resource.h b/cc/resources/prioritized_resource.h index e3bb2bc..3b6ecc0 100644 --- a/cc/resources/prioritized_resource.h +++ b/cc/resources/prioritized_resource.h
@@ -142,7 +142,7 @@ bool resource_has_been_deleted_; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() ResourceProvider* resource_provider_; #endif DISALLOW_COPY_AND_ASSIGN(Backing);
diff --git a/cc/resources/prioritized_resource_manager.cc b/cc/resources/prioritized_resource_manager.cc index 657c14f..4598446 100644 --- a/cc/resources/prioritized_resource_manager.cc +++ b/cc/resources/prioritized_resource_manager.cc
@@ -481,7 +481,7 @@ } void PrioritizedResourceManager::AssertInvariants() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked()); // If we hit any of these asserts, there is a bug in this class. To see @@ -540,7 +540,7 @@ DCHECK(backing->CanBeRecycledIfNotInExternalUse()); previous_backing = backing; } -#endif // DCHECK_IS_ON +#endif // DCHECK_IS_ON() } const Proxy* PrioritizedResourceManager::ProxyForDebug() const {
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 9c2e4a0..9d9b247 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -1259,14 +1259,14 @@ } DCHECK(gl); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // Check that all GL resources has been deleted. for (ResourceMap::const_iterator itr = resources_.begin(); itr != resources_.end(); ++itr) { DCHECK_NE(GLTexture, itr->second.type); } -#endif // DCHECK_IS_ON +#endif // DCHECK_IS_ON() texture_uploader_ = nullptr; texture_id_allocator_ = nullptr;
diff --git a/cc/resources/scoped_resource.cc b/cc/resources/scoped_resource.cc index c83efb5..3b13559 100644 --- a/cc/resources/scoped_resource.cc +++ b/cc/resources/scoped_resource.cc
@@ -25,7 +25,7 @@ set_id(resource_provider_->CreateResource( size, GL_CLAMP_TO_EDGE, hint, format)); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() allocate_thread_id_ = base::PlatformThread::CurrentId(); #endif } @@ -44,14 +44,14 @@ ResourceProvider::TextureHintImmutable, format)); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() allocate_thread_id_ = base::PlatformThread::CurrentId(); #endif } void ScopedResource::Free() { if (id()) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK(allocate_thread_id_ == base::PlatformThread::CurrentId()); #endif resource_provider_->DeleteResource(id());
diff --git a/cc/resources/scoped_resource.h b/cc/resources/scoped_resource.h index 4241b38..6f8c1cd 100644 --- a/cc/resources/scoped_resource.h +++ b/cc/resources/scoped_resource.h
@@ -11,7 +11,7 @@ #include "cc/base/cc_export.h" #include "cc/resources/resource.h" -#if DCHECK_IS_ON +#if DCHECK_IS_ON() #include "base/threading/platform_thread.h" #endif @@ -39,7 +39,7 @@ private: ResourceProvider* resource_provider_; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() base::PlatformThreadId allocate_thread_id_; #endif
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc index edbea9b..f6d08d1 100644 --- a/cc/resources/video_resource_updater.cc +++ b/cc/resources/video_resource_updater.cc
@@ -149,6 +149,7 @@ #if defined(VIDEO_HOLE) case media::VideoFrame::HOLE: #endif // defined(VIDEO_HOLE) + case media::VideoFrame::ARGB: return true; // Unacceptable inputs. ¯\(°_o)/¯
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc index 8833037..763b81c 100644 --- a/cc/surfaces/display.cc +++ b/cc/surfaces/display.cc
@@ -168,10 +168,16 @@ client_->SetMemoryPolicy(policy); } -void Display::OnSurfaceDamaged(SurfaceId surface) { +void Display::OnSurfaceDamaged(SurfaceId surface_id) { if (aggregator_ && - aggregator_->previous_contained_surfaces().count(surface)) { - aggregator_->ReleaseResources(surface); + aggregator_->previous_contained_surfaces().count(surface_id)) { + Surface* surface = manager_->GetSurfaceForId(surface_id); + if (surface) { + const CompositorFrame* current_frame = surface->GetEligibleFrame(); + if (!current_frame || !current_frame->delegated_frame_data || + !current_frame->delegated_frame_data->resource_list.size()) + aggregator_->ReleaseResources(surface_id); + } client_->DisplayDamaged(); } }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 66ee020..68a905e 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -293,6 +293,12 @@ void LayerTreeHostImpl::BeginCommit() { TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit"); + // Ensure all textures are returned so partial texture updates can happen + // during the commit. Impl-side-painting doesn't upload during commits, so + // is unaffected. + if (!settings_.impl_side_painting) + output_surface_->ForceReclaimResources(); + if (UsePendingTreeForSync()) CreatePendingTree(); } @@ -875,7 +881,7 @@ output_surface_->capabilities().draw_and_swap_full_viewport_every_frame) draw_result = DRAW_SUCCESS; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (const auto& render_pass : frame->render_passes) { for (const auto& quad : render_pass->quad_list) DCHECK(quad->shared_quad_state);
diff --git a/cc/trees/proxy.cc b/cc/trees/proxy.cc index e981a72..eb81e2e 100644 --- a/cc/trees/proxy.cc +++ b/cc/trees/proxy.cc
@@ -21,7 +21,7 @@ } bool Proxy::IsMainThread() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() if (impl_thread_is_overridden_) return false; @@ -36,7 +36,7 @@ } bool Proxy::IsImplThread() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() if (impl_thread_is_overridden_) return true; if (!impl_task_runner_.get()) @@ -47,21 +47,21 @@ #endif } -#if DCHECK_IS_ON +#if DCHECK_IS_ON() void Proxy::SetCurrentThreadIsImplThread(bool is_impl_thread) { impl_thread_is_overridden_ = is_impl_thread; } #endif bool Proxy::IsMainThreadBlocked() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() return is_main_thread_blocked_; #else return true; #endif } -#if DCHECK_IS_ON +#if DCHECK_IS_ON() void Proxy::SetMainThreadBlocked(bool is_main_thread_blocked) { is_main_thread_blocked_ = is_main_thread_blocked; } @@ -69,7 +69,7 @@ Proxy::Proxy(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) -#if !DCHECK_IS_ON +#if !DCHECK_IS_ON() : main_task_runner_(main_task_runner), impl_task_runner_(impl_task_runner), blocking_main_thread_task_runner_(
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h index e07e9a2..206af66 100644 --- a/cc/trees/proxy.h +++ b/cc/trees/proxy.h
@@ -46,7 +46,7 @@ bool IsMainThread() const; bool IsImplThread() const; bool IsMainThreadBlocked() const; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() void SetMainThreadBlocked(bool is_main_thread_blocked); void SetCurrentThreadIsImplThread(bool is_impl_thread); #endif @@ -127,7 +127,7 @@ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_; scoped_ptr<BlockingTaskRunner> blocking_main_thread_task_runner_; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() const base::PlatformThreadId main_thread_id_; bool impl_thread_is_overridden_; bool is_main_thread_blocked_; @@ -136,7 +136,7 @@ DISALLOW_COPY_AND_ASSIGN(Proxy); }; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() class DebugScopedSetMainThreadBlocked { public: explicit DebugScopedSetMainThreadBlocked(Proxy* proxy) : proxy_(proxy) {
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 7d3383a..adc42c9 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -236,7 +236,7 @@ layer_tree_host_impl_->CommitComplete(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // In the single-threaded case, the scale and scroll deltas should never be // touched on the impl layer tree. scoped_ptr<ScrollAndScaleSet> scroll_info =
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h index 4c1eac0..bdc1030 100644 --- a/cc/trees/single_thread_proxy.h +++ b/cc/trees/single_thread_proxy.h
@@ -176,13 +176,13 @@ class DebugScopedSetImplThread { public: explicit DebugScopedSetImplThread(Proxy* proxy) : proxy_(proxy) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() previous_value_ = proxy_->impl_thread_is_overridden_; proxy_->SetCurrentThreadIsImplThread(true); #endif } ~DebugScopedSetImplThread() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() proxy_->SetCurrentThreadIsImplThread(previous_value_); #endif } @@ -199,13 +199,13 @@ class DebugScopedSetMainThread { public: explicit DebugScopedSetMainThread(Proxy* proxy) : proxy_(proxy) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() previous_value_ = proxy_->impl_thread_is_overridden_; proxy_->SetCurrentThreadIsImplThread(false); #endif } ~DebugScopedSetMainThread() { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() proxy_->SetCurrentThreadIsImplThread(previous_value_); #endif }
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc index d17f017..2e29529 100644 --- a/cc/trees/tree_synchronizer.cc +++ b/cc/trees/tree_synchronizer.cc
@@ -297,7 +297,7 @@ size_t num_dependents_need_push_properties = 0; PushPropertiesInternal( layer, layer_impl, &num_dependents_need_push_properties); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() CheckScrollAndClipPointersRecursive(layer, layer_impl); #endif }
diff --git a/crypto/mock_apple_keychain.h b/crypto/mock_apple_keychain.h index d957316..28c77b8 100644 --- a/crypto/mock_apple_keychain.h +++ b/crypto/mock_apple_keychain.h
@@ -29,70 +29,67 @@ class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain { public: MockAppleKeychain(); - virtual ~MockAppleKeychain(); + ~MockAppleKeychain() override; // AppleKeychain implementation. - virtual OSStatus FindGenericPassword( - CFTypeRef keychainOrArray, - UInt32 serviceNameLength, - const char* serviceName, - UInt32 accountNameLength, - const char* accountName, - UInt32* passwordLength, - void** passwordData, - SecKeychainItemRef* itemRef) const override; - virtual OSStatus ItemFreeContent(SecKeychainAttributeList* attrList, - void* data) const override; - virtual OSStatus AddGenericPassword( - SecKeychainRef keychain, - UInt32 serviceNameLength, - const char* serviceName, - UInt32 accountNameLength, - const char* accountName, - UInt32 passwordLength, - const void* passwordData, - SecKeychainItemRef* itemRef) const override; + OSStatus FindGenericPassword(CFTypeRef keychainOrArray, + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + SecKeychainItemRef* itemRef) const override; + OSStatus ItemFreeContent(SecKeychainAttributeList* attrList, + void* data) const override; + OSStatus AddGenericPassword(SecKeychainRef keychain, + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + SecKeychainItemRef* itemRef) const override; #if !defined(OS_IOS) - virtual OSStatus ItemCopyAttributesAndData( - SecKeychainItemRef itemRef, - SecKeychainAttributeInfo* info, - SecItemClass* itemClass, - SecKeychainAttributeList** attrList, - UInt32* length, - void** outData) const override; + OSStatus ItemCopyAttributesAndData(SecKeychainItemRef itemRef, + SecKeychainAttributeInfo* info, + SecItemClass* itemClass, + SecKeychainAttributeList** attrList, + UInt32* length, + void** outData) const override; // Pass "fail_me" as the data to get errSecAuthFailed. - virtual OSStatus ItemModifyAttributesAndData( - SecKeychainItemRef itemRef, - const SecKeychainAttributeList* attrList, - UInt32 length, - const void* data) const override; - virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList, - void* data) const override; - virtual OSStatus ItemDelete(SecKeychainItemRef itemRef) const override; - virtual OSStatus SearchCreateFromAttributes( + OSStatus ItemModifyAttributesAndData(SecKeychainItemRef itemRef, + const SecKeychainAttributeList* attrList, + UInt32 length, + const void* data) const override; + OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList, + void* data) const override; + OSStatus ItemDelete(SecKeychainItemRef itemRef) const override; + OSStatus SearchCreateFromAttributes( CFTypeRef keychainOrArray, SecItemClass itemClass, const SecKeychainAttributeList* attrList, SecKeychainSearchRef* searchRef) const override; - virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef, - SecKeychainItemRef* itemRef) const override; + OSStatus SearchCopyNext(SecKeychainSearchRef searchRef, + SecKeychainItemRef* itemRef) const override; // Pass "some.domain.com" as the serverName to get errSecDuplicateItem. - virtual OSStatus AddInternetPassword( - SecKeychainRef keychain, - UInt32 serverNameLength, - const char* serverName, - UInt32 securityDomainLength, - const char* securityDomain, - UInt32 accountNameLength, - const char* accountName, - UInt32 pathLength, const char* path, - UInt16 port, SecProtocolType protocol, - SecAuthenticationType authenticationType, - UInt32 passwordLength, - const void* passwordData, - SecKeychainItemRef* itemRef) const override; - virtual void Free(CFTypeRef ref) const override; + OSStatus AddInternetPassword(SecKeychainRef keychain, + UInt32 serverNameLength, + const char* serverName, + UInt32 securityDomainLength, + const char* securityDomain, + UInt32 accountNameLength, + const char* accountName, + UInt32 pathLength, + const char* path, + UInt16 port, + SecProtocolType protocol, + SecAuthenticationType authenticationType, + UInt32 passwordLength, + const void* passwordData, + SecKeychainItemRef* itemRef) const override; + void Free(CFTypeRef ref) const override; // Return the counts of objects returned by Create/Copy functions but never // Free'd as they should have been.
diff --git a/crypto/signature_verifier_unittest.cc b/crypto/signature_verifier_unittest.cc index b521bd7..a661ff7 100644 --- a/crypto/signature_verifier_unittest.cc +++ b/crypto/signature_verifier_unittest.cc
@@ -1000,6 +1000,23 @@ return true; } +// PrependASN1Length prepends an ASN.1 serialized length to the beginning of +// |out|. +static void PrependASN1Length(std::vector<uint8>* out, size_t len) { + if (len < 128) { + out->insert(out->begin(), static_cast<uint8>(len)); + } else if (len < 256) { + out->insert(out->begin(), static_cast<uint8>(len)); + out->insert(out->begin(), 0x81); + } else if (len < 0x10000) { + out->insert(out->begin(), static_cast<uint8>(len)); + out->insert(out->begin(), static_cast<uint8>(len >> 8)); + out->insert(out->begin(), 0x82); + } else { + CHECK(false) << "ASN.1 length not handled: " << len; + } +} + static bool EncodeRSAPublicKey(const std::vector<uint8>& modulus_n, const std::vector<uint8>& public_exponent_e, std::vector<uint8>* public_key_info) { @@ -1027,37 +1044,28 @@ public_key_info->insert(public_key_info->begin(), public_exponent_e.begin(), public_exponent_e.end()); - uint8 exponent_size = base::checked_cast<uint8>(public_exponent_e.size()); - public_key_info->insert(public_key_info->begin(), exponent_size); + PrependASN1Length(public_key_info, public_exponent_e.size()); public_key_info->insert(public_key_info->begin(), kIntegerTag); // Encode the modulus n as an INTEGER. public_key_info->insert(public_key_info->begin(), modulus_n.begin(), modulus_n.end()); - uint16 modulus_size = base::checked_cast<uint16>(modulus_n.size()); + size_t modulus_size = modulus_n.size(); if (modulus_n[0] & 0x80) { public_key_info->insert(public_key_info->begin(), 0x00); modulus_size++; } - public_key_info->insert(public_key_info->begin(), modulus_size & 0xff); - public_key_info->insert(public_key_info->begin(), (modulus_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, modulus_size); public_key_info->insert(public_key_info->begin(), kIntegerTag); // Encode the RSAPublicKey SEQUENCE. - uint16 info_size = base::checked_cast<uint16>(public_key_info->size()); - public_key_info->insert(public_key_info->begin(), info_size & 0xff); - public_key_info->insert(public_key_info->begin(), (info_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, public_key_info->size()); public_key_info->insert(public_key_info->begin(), kSequenceTag); // Encode the BIT STRING. // Number of unused bits. public_key_info->insert(public_key_info->begin(), 0x00); - info_size = base::checked_cast<uint16>(public_key_info->size()); - public_key_info->insert(public_key_info->begin(), info_size & 0xff); - public_key_info->insert(public_key_info->begin(), (info_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, public_key_info->size()); public_key_info->insert(public_key_info->begin(), kBitStringTag); // Encode the AlgorithmIdentifier. @@ -1071,10 +1079,7 @@ algorithm, algorithm + sizeof(algorithm)); // Encode the outermost SEQUENCE. - info_size = base::checked_cast<uint16>(public_key_info->size()); - public_key_info->insert(public_key_info->begin(), info_size & 0xff); - public_key_info->insert(public_key_info->begin(), (info_size >> 8) & 0xff); - public_key_info->insert(public_key_info->begin(), 0x82); + PrependASN1Length(public_key_info, public_key_info->size()); public_key_info->insert(public_key_info->begin(), kSequenceTag); return true; @@ -1082,6 +1087,7 @@ TEST(SignatureVerifierTest, VerifyRSAPSS) { for (unsigned int i = 0; i < arraysize(pss_test); i++) { + SCOPED_TRACE(i); std::vector<uint8> modulus_n; std::vector<uint8> public_exponent_e; ASSERT_TRUE(DecodeTestInput(pss_test[i].modulus_n, &modulus_n)); @@ -1092,6 +1098,7 @@ &public_key_info)); for (unsigned int j = 0; j < arraysize(pss_test[i].example); j++) { + SCOPED_TRACE(j); std::vector<uint8> message; std::vector<uint8> salt; std::vector<uint8> signature;
diff --git a/gin/BUILD.gn b/gin/BUILD.gn index b352c3a..d389b84 100644 --- a/gin/BUILD.gn +++ b/gin/BUILD.gn
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/module_args/v8.gni") + component("gin") { sources = [ "arguments.cc", @@ -68,6 +70,40 @@ deps = [ "//base/third_party/dynamic_annotations", ] + if (v8_use_external_startup_data && is_win) { + deps += [ + ":gin_v8_snapshot_fingerprint", + "//crypto:crypto", + ] + sources += [ "$target_gen_dir/v8_snapshot_fingerprint.cc" ] + defines += [ "V8_VERIFY_EXTERNAL_STARTUP_DATA" ] + } +} + +if (v8_use_external_startup_data) { + action("gin_v8_snapshot_fingerprint") { + script = "//gin/fingerprint/fingerprint_v8_snapshot.py" + + snapshot_file = "$root_build_dir/snapshot_blob.bin" + natives_file = "$root_build_dir/natives_blob.bin" + output_file = "$target_gen_dir/v8_snapshot_fingerprint.cc" + + args = [ + "--snapshot_file", + rebase_path(snapshot_file, root_build_dir), + "--natives_file", + rebase_path(natives_file, root_build_dir), + "--output_file", + rebase_path(output_file, root_build_dir), + ] + inputs = [ + snapshot_file, + natives_file, + ] + outputs = [ + output_file, + ] + } } executable("gin_shell") {
diff --git a/gin/DEPS b/gin/DEPS index 4e3f30a..d4cc2ba 100644 --- a/gin/DEPS +++ b/gin/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+base", + "+crypto", "+v8", ]
diff --git a/gin/fingerprint/fingerprint_v8_snapshot.gypi b/gin/fingerprint/fingerprint_v8_snapshot.gypi new file mode 100644 index 0000000..ede0de3 --- /dev/null +++ b/gin/fingerprint/fingerprint_v8_snapshot.gypi
@@ -0,0 +1,47 @@ +# Copyright 2015 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. + +# This file is meant to be included into a target to provide a rule that +# fingerprints the v8 snapshot and generates a .cc file which includes this +# fingerprint. +# +# To use this, create a gyp target with the following form: +# { +# 'target_name': 'gin_v8_snapshot_fingerprint', +# 'type': 'none', +# 'variables': { +# 'snapshot_file': 'snapshot blob file to be fingerprinted', +# 'natives_file': 'natives blob file to be fingerprinted', +# 'output_file': 'output .cc file to generate with fingerprints', +# }, +# 'includes': [ '../gin/fingerprint/fingerprint_v8_snapshot.gypi' ], +# }, +# + +{ + 'conditions': [ + ['v8_use_external_startup_data==1', { + 'actions': [ + { + 'action_name': 'Generate V8 snapshot fingerprint', + 'message': 'Generating V8 snapshot fingerprint', + 'inputs': [ + '<(DEPTH)/gin/fingerprint/fingerprint_v8_snapshot.py', + '<(snapshot_file)', + '<(natives_file)', + ], + 'outputs': [ + '<(output_file)', + ], + 'action': [ + 'python', '<(DEPTH)/gin/fingerprint/fingerprint_v8_snapshot.py', + '--snapshot_file=<(snapshot_file)', + '--natives_file=<(natives_file)', + '--output_file=<(output_file)', + ], + } + ], + }], + ], +} \ No newline at end of file
diff --git a/gin/fingerprint/fingerprint_v8_snapshot.py b/gin/fingerprint/fingerprint_v8_snapshot.py new file mode 100755 index 0000000..d1f7092 --- /dev/null +++ b/gin/fingerprint/fingerprint_v8_snapshot.py
@@ -0,0 +1,86 @@ +#!/usr/bin/env python +# +# Copyright 2015 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. + +"""Fingerprints the V8 snapshot blob files. + +Constructs a SHA256 fingerprint of the V8 natives and snapshot blob files and +creates a .cc file which includes these fingerprint as variables. +""" + +import hashlib +import optparse +import os +import sys + +_HEADER = """// Copyright 2015 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. + +// This file was generated by fingerprint_v8_snapshot.py. + +namespace gin { +""" + +_FOOTER = """ +} // namespace gin +""" + + +def FingerprintFile(file_path): + input_file = open(file_path, 'rb') + sha256 = hashlib.sha256() + while True: + block = input_file.read(sha256.block_size) + if not block: + break + sha256.update(block) + return sha256.digest() + + +def WriteFingerprint(output_file, variable_name, fingerprint): + output_file.write('\nextern const unsigned char %s[] = { ' % variable_name) + for byte in fingerprint: + output_file.write(str(ord(byte)) + ', ') + output_file.write('};\n') + + +def WriteOutputFile(natives_fingerprint, + snapshot_fingerprint, + output_file_path): + output_dir_path = os.path.dirname(output_file_path) + if not os.path.exists(output_dir_path): + os.makedirs(output_dir_path) + output_file = open(output_file_path, 'w') + + output_file.write(_HEADER) + WriteFingerprint(output_file, 'g_natives_fingerprint', natives_fingerprint) + output_file.write('\n') + WriteFingerprint(output_file, 'g_snapshot_fingerprint', snapshot_fingerprint) + output_file.write(_FOOTER) + + +def main(): + parser = optparse.OptionParser() + + parser.add_option('--snapshot_file', + help='The input V8 snapshot blob file path.') + parser.add_option('--natives_file', + help='The input V8 natives blob file path.') + parser.add_option('--output_file', + help='The path for the output cc file which will be write.') + + options, _ = parser.parse_args() + + natives_fingerprint = FingerprintFile(options.natives_file) + snapshot_fingerprint = FingerprintFile(options.snapshot_file) + WriteOutputFile( + natives_fingerprint, snapshot_fingerprint, options.output_file) + + return 0 + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/gin/gin.gyp b/gin/gin.gyp index b38dc85..096c120 100644 --- a/gin/gin.gyp +++ b/gin/gin.gyp
@@ -5,6 +5,7 @@ { 'variables': { 'chromium_code': 1, + 'gin_gen_path': '<(SHARED_INTERMEDIATE_DIR)/gin/', }, 'targets': [ { @@ -14,7 +15,6 @@ '../base/base.gyp:base', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../v8/tools/gyp/v8.gyp:v8', - ], 'export_dependent_settings': [ '../base/base.gyp:base', @@ -78,6 +78,30 @@ 'wrappable.h', 'wrapper_info.cc', ], + 'conditions': [ + ['v8_use_external_startup_data==1 and OS=="win"', { + 'dependencies': [ + 'gin_v8_snapshot_fingerprint', + '../crypto/crypto.gyp:crypto', + ], + 'sources': [ + '<(gin_gen_path)/v8_snapshot_fingerprint.cc', + ], + 'defines': [ + 'V8_VERIFY_EXTERNAL_STARTUP_DATA', + ] + }], + ], + }, + { + 'target_name': 'gin_v8_snapshot_fingerprint', + 'type': 'none', + 'variables': { + 'snapshot_file': '<(PRODUCT_DIR)/snapshot_blob.bin', + 'natives_file': '<(PRODUCT_DIR)/natives_blob.bin', + 'output_file': '<(gin_gen_path)/v8_snapshot_fingerprint.cc', + }, + 'includes': [ '../gin/fingerprint/fingerprint_v8_snapshot.gypi' ], }, { 'target_name': 'gin_shell',
diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc index 2b6d64b..c666e29 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc
@@ -11,7 +11,9 @@ #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/rand_util.h" +#include "base/strings/sys_string_conversions.h" #include "base/sys_info.h" +#include "crypto/sha2.h" #include "gin/array_buffer.h" #include "gin/debug_impl.h" #include "gin/function_template.h" @@ -19,8 +21,8 @@ #include "gin/public/v8_platform.h" #include "gin/run_microtasks_observer.h" -#ifdef V8_USE_EXTERNAL_STARTUP_DATA -#ifdef OS_MACOSX +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) +#if defined(OS_MACOSX) #include "base/mac/foundation_util.h" #endif // OS_MACOSX #include "base/path_service.h" @@ -40,16 +42,29 @@ base::MemoryMappedFile* g_mapped_natives = NULL; base::MemoryMappedFile* g_mapped_snapshot = NULL; -#ifdef V8_USE_EXTERNAL_STARTUP_DATA -bool MapV8Files(base::FilePath* natives_path, base::FilePath* snapshot_path, - int natives_fd = -1, int snapshot_fd = -1) { +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) +bool MapV8Files(base::FilePath* natives_path, + base::FilePath* snapshot_path, + int natives_fd = -1, + int snapshot_fd = -1, + base::MemoryMappedFile::Region natives_region = + base::MemoryMappedFile::Region::kWholeFile, + base::MemoryMappedFile::Region snapshot_region = + base::MemoryMappedFile::Region::kWholeFile) { int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; g_mapped_natives = new base::MemoryMappedFile; if (!g_mapped_natives->IsValid()) { +#if !defined(OS_WIN) if (natives_fd == -1 - ? !g_mapped_natives->Initialize(base::File(*natives_path, flags)) - : !g_mapped_natives->Initialize(base::File(natives_fd))) { + ? !g_mapped_natives->Initialize(base::File(*natives_path, flags), + natives_region) + : !g_mapped_natives->Initialize(base::File(natives_fd), + natives_region)) { +#else + if (!g_mapped_natives->Initialize(base::File(*natives_path, flags), + natives_region)) { +#endif // !OS_WIN delete g_mapped_natives; g_mapped_natives = NULL; LOG(FATAL) << "Couldn't mmap v8 natives data file"; @@ -59,9 +74,16 @@ g_mapped_snapshot = new base::MemoryMappedFile; if (!g_mapped_snapshot->IsValid()) { +#if !defined(OS_WIN) if (snapshot_fd == -1 - ? !g_mapped_snapshot->Initialize(base::File(*snapshot_path, flags)) - : !g_mapped_snapshot->Initialize(base::File(snapshot_fd))) { + ? !g_mapped_snapshot->Initialize(base::File(*snapshot_path, flags), + snapshot_region) + : !g_mapped_snapshot->Initialize(base::File(snapshot_fd), + snapshot_region)) { +#else + if (!g_mapped_snapshot->Initialize(base::File(*snapshot_path, flags), + snapshot_region)) { +#endif // !OS_WIN delete g_mapped_snapshot; g_mapped_snapshot = NULL; LOG(ERROR) << "Couldn't mmap v8 snapshot data file"; @@ -72,21 +94,44 @@ return true; } +#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) +bool VerifyV8SnapshotFile(base::MemoryMappedFile* snapshot_file, + const unsigned char* fingerprint) { + unsigned char output[crypto::kSHA256Length]; + crypto::SHA256HashString( + base::StringPiece(reinterpret_cast<const char*>(snapshot_file->data()), + snapshot_file->length()), + output, sizeof(output)); + return !memcmp(fingerprint, output, sizeof(output)); +} +#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA + #if !defined(OS_MACOSX) const int v8_snapshot_dir = #if defined(OS_ANDROID) base::DIR_ANDROID_APP_DATA; #elif defined(OS_POSIX) base::DIR_EXE; -#endif // defined(OS_ANDROID) -#endif // !defined(OS_MACOSX) +#elif defined(OS_WIN) + base::DIR_MODULE; +#endif // OS_ANDROID +#endif // !OS_MACOSX #endif // V8_USE_EXTERNAL_STARTUP_DATA } // namespace +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) -#ifdef V8_USE_EXTERNAL_STARTUP_DATA +#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) +// Defined in gen/gin/v8_snapshot_fingerprint.cc +extern const unsigned char g_natives_fingerprint[]; +extern const unsigned char g_snapshot_fingerprint[]; +#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA + +const char IsolateHolder::kNativesFileName[] = "natives_blob.bin"; +const char IsolateHolder::kSnapshotFileName[] = "snapshot_blob.bin"; + // static bool IsolateHolder::LoadV8Snapshot() { if (g_mapped_natives && g_mapped_snapshot) @@ -97,26 +142,58 @@ PathService::Get(v8_snapshot_dir, &data_path); DCHECK(!data_path.empty()); - base::FilePath natives_path = data_path.AppendASCII("natives_blob.bin"); - base::FilePath snapshot_path = data_path.AppendASCII("snapshot_blob.bin"); + base::FilePath natives_path = data_path.AppendASCII(kNativesFileName); + base::FilePath snapshot_path = data_path.AppendASCII(kSnapshotFileName); #else // !defined(OS_MACOSX) + base::ScopedCFTypeRef<CFStringRef> natives_file_name( + base::SysUTF8ToCFStringRef(kNativesFileName)); base::FilePath natives_path = base::mac::PathForFrameworkBundleResource( - CFSTR("natives_blob.bin")); + natives_file_name); + base::ScopedCFTypeRef<CFStringRef> snapshot_file_name( + base::SysUTF8ToCFStringRef(kSnapshotFileName)); base::FilePath snapshot_path = base::mac::PathForFrameworkBundleResource( - CFSTR("snapshot_blob.bin")); + snapshot_file_name); DCHECK(!natives_path.empty()); DCHECK(!snapshot_path.empty()); #endif // !defined(OS_MACOSX) - return MapV8Files(&natives_path, &snapshot_path); + if (!MapV8Files(&natives_path, &snapshot_path)) + return false; + +#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA) + return VerifyV8SnapshotFile(g_mapped_natives, g_natives_fingerprint) && + VerifyV8SnapshotFile(g_mapped_snapshot, g_snapshot_fingerprint); +#else + return true; +#endif // V8_VERIFY_EXTERNAL_STARTUP_DATA } //static -bool IsolateHolder::LoadV8SnapshotFD(int natives_fd, int snapshot_fd) { +bool IsolateHolder::LoadV8SnapshotFd(int natives_fd, + int64 natives_offset, + int64 natives_size, + int snapshot_fd, + int64 snapshot_offset, + int64 snapshot_size) { if (g_mapped_natives && g_mapped_snapshot) return true; - return MapV8Files(NULL, NULL, natives_fd, snapshot_fd); + base::MemoryMappedFile::Region natives_region = + base::MemoryMappedFile::Region::kWholeFile; + if (natives_size != 0 || natives_offset != 0) { + natives_region = + base::MemoryMappedFile::Region(natives_offset, natives_size); + } + + base::MemoryMappedFile::Region snapshot_region = + base::MemoryMappedFile::Region::kWholeFile; + if (natives_size != 0 || natives_offset != 0) { + snapshot_region = + base::MemoryMappedFile::Region(snapshot_offset, snapshot_size); + } + + return MapV8Files( + NULL, NULL, natives_fd, snapshot_fd, natives_region, snapshot_region); } #endif // V8_USE_EXTERNAL_STARTUP_DATA @@ -193,7 +270,7 @@ v8::V8::SetFlagsFromString(v8_flags, sizeof(v8_flags) - 1); } v8::V8::SetEntropySource(&GenerateEntropy); -#ifdef V8_USE_EXTERNAL_STARTUP_DATA +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) v8::StartupData natives; natives.data = reinterpret_cast<const char*>(g_mapped_natives->data()); natives.raw_size = static_cast<int>(g_mapped_natives->length());
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h index b12734c..44d1d89 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h
@@ -33,7 +33,7 @@ // Should be invoked once before creating IsolateHolder instances to // initialize V8 and Gin. In case V8_USE_EXTERNAL_STARTUP_DATA is defined, // V8's initial snapshot should be loaded (by calling LoadV8Snapshot or - // LoadV8SnapshotFD) before calling Initialize. + // LoadV8SnapshotFd) before calling Initialize. static void Initialize(ScriptMode mode, v8::ArrayBuffer::Allocator* allocator); @@ -51,8 +51,16 @@ // thread. void RemoveRunMicrotasksObserver(); -#ifdef V8_USE_EXTERNAL_STARTUP_DATA - static bool LoadV8SnapshotFD(int natives_fd, int snapshot_fd); +#if defined(V8_USE_EXTERNAL_STARTUP_DATA) + static const char kNativesFileName[]; + static const char kSnapshotFileName[]; + + static bool LoadV8SnapshotFd(int natives_fd, + int64 natives_offset, + int64 natives_size, + int snapshot_fd, + int64 snapshot_offset, + int64 snapshot_size); static bool LoadV8Snapshot(); #endif // V8_USE_EXTERNAL_STARTUP_DATA static void GetV8ExternalSnapshotData(const char** natives_data_out,
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h index 5a506df..5a59ea1 100644 --- a/gpu/GLES2/gl2chromium_autogen.h +++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -17,6 +17,7 @@ #define glAttachShader GLES2_GET_FUN(AttachShader) #define glBindAttribLocation GLES2_GET_FUN(BindAttribLocation) #define glBindBuffer GLES2_GET_FUN(BindBuffer) +#define glBindBufferBase GLES2_GET_FUN(BindBufferBase) #define glBindFramebuffer GLES2_GET_FUN(BindFramebuffer) #define glBindRenderbuffer GLES2_GET_FUN(BindRenderbuffer) #define glBindSampler GLES2_GET_FUN(BindSampler) @@ -144,12 +145,14 @@ #define glStencilOp GLES2_GET_FUN(StencilOp) #define glStencilOpSeparate GLES2_GET_FUN(StencilOpSeparate) #define glTexImage2D GLES2_GET_FUN(TexImage2D) +#define glTexImage3D GLES2_GET_FUN(TexImage3D) #define glTexParameterf GLES2_GET_FUN(TexParameterf) #define glTexParameterfv GLES2_GET_FUN(TexParameterfv) #define glTexParameteri GLES2_GET_FUN(TexParameteri) #define glTexParameteriv GLES2_GET_FUN(TexParameteriv) #define glTexStorage3D GLES2_GET_FUN(TexStorage3D) #define glTexSubImage2D GLES2_GET_FUN(TexSubImage2D) +#define glTexSubImage3D GLES2_GET_FUN(TexSubImage3D) #define glUniform1f GLES2_GET_FUN(Uniform1f) #define glUniform1fv GLES2_GET_FUN(Uniform1fv) #define glUniform1i GLES2_GET_FUN(Uniform1i)
diff --git a/gpu/blink/BUILD.gn b/gpu/blink/BUILD.gn index 3d0e77a..464061c 100644 --- a/gpu/blink/BUILD.gn +++ b/gpu/blink/BUILD.gn
@@ -10,6 +10,8 @@ "gpu_blink_export.h", "webgraphicscontext3d_impl.cc", "webgraphicscontext3d_impl.h", + "webgraphicscontext3d_in_process_command_buffer_impl.cc", + "webgraphicscontext3d_in_process_command_buffer_impl.h", ] defines = [ "GPU_BLINK_IMPLEMENTATION" ]
diff --git a/gpu/blink/gpu_blink.gyp b/gpu/blink/gpu_blink.gyp index a1d3cb5..06a7c12 100644 --- a/gpu/blink/gpu_blink.gyp +++ b/gpu/blink/gpu_blink.gyp
@@ -35,6 +35,8 @@ 'gpu_blink_export.h', 'webgraphicscontext3d_impl.cc', 'webgraphicscontext3d_impl.h', + 'webgraphicscontext3d_in_process_command_buffer_impl.cc', + 'webgraphicscontext3d_in_process_command_buffer_impl.h', ], 'defines': [ 'GPU_BLINK_IMPLEMENTATION',
diff --git a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc new file mode 100644 index 0000000..386d349 --- /dev/null +++ b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -0,0 +1,178 @@ +// Copyright (c) 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. + +#include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h" + +#include <GLES2/gl2.h> +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES 1 +#endif +#include <GLES2/gl2ext.h> +#include <GLES2/gl2extchromium.h> + +#include <string> + +#include "base/atomicops.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/callback.h" +#include "base/logging.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/common/gles2_cmd_utils.h" +#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gl/gl_implementation.h" + +using gpu::gles2::GLES2Implementation; +using gpu::GLInProcessContext; + +namespace gpu_blink { + +// static +scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> +WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext( + const blink::WebGraphicsContext3D::Attributes& attributes, + bool lose_context_when_out_of_memory, + gfx::AcceleratedWidget window) { + DCHECK_NE(gfx::GetGLImplementation(), gfx::kGLImplementationNone); + bool is_offscreen = false; + return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl( + scoped_ptr< ::gpu::GLInProcessContext>(), + attributes, + lose_context_when_out_of_memory, + is_offscreen, + window)); +} + +// static +scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> +WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext( + const blink::WebGraphicsContext3D::Attributes& attributes, + bool lose_context_when_out_of_memory) { + bool is_offscreen = true; + return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl( + scoped_ptr< ::gpu::GLInProcessContext>(), + attributes, + lose_context_when_out_of_memory, + is_offscreen, + gfx::kNullAcceleratedWidget)); +} + +scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> +WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext( + scoped_ptr< ::gpu::GLInProcessContext> context, + const blink::WebGraphicsContext3D::Attributes& attributes) { + bool lose_context_when_out_of_memory = false; // Not used. + bool is_offscreen = true; // Not used. + return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl( + context.Pass(), + attributes, + lose_context_when_out_of_memory, + is_offscreen, + gfx::kNullAcceleratedWidget /* window. Not used. */)); +} + +WebGraphicsContext3DInProcessCommandBufferImpl:: + WebGraphicsContext3DInProcessCommandBufferImpl( + scoped_ptr< ::gpu::GLInProcessContext> context, + const blink::WebGraphicsContext3D::Attributes& attributes, + bool lose_context_when_out_of_memory, + bool is_offscreen, + gfx::AcceleratedWidget window) + : share_resources_(attributes.shareResources), + webgl_context_(attributes.webGL), + is_offscreen_(is_offscreen), + window_(window), + context_(context.Pass()) { + ConvertAttributes(attributes, &attribs_); + attribs_.lose_context_when_out_of_memory = lose_context_when_out_of_memory; +} + +WebGraphicsContext3DInProcessCommandBufferImpl:: + ~WebGraphicsContext3DInProcessCommandBufferImpl() { +} + +size_t WebGraphicsContext3DInProcessCommandBufferImpl::GetMappedMemoryLimit() { + return context_->GetMappedMemoryLimit(); +} + +bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() { + if (initialized_) + return true; + + if (initialize_failed_) + return false; + + if (!context_) { + // TODO(kbr): More work will be needed in this implementation to + // properly support GPU switching. Like in the out-of-process + // command buffer implementation, all previously created contexts + // will need to be lost either when the first context requesting the + // discrete GPU is created, or the last one is destroyed. + gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; + context_.reset(GLInProcessContext::Create( + NULL, /* service */ + NULL, /* surface */ + is_offscreen_, + window_, + gfx::Size(1, 1), + NULL, /* share_context */ + share_resources_, + attribs_, + gpu_preference, + ::gpu::GLInProcessContextSharedMemoryLimits(), + nullptr, + nullptr)); + } + + if (context_) { + base::Closure context_lost_callback = base::Bind( + &WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost, + base::Unretained(this)); + context_->SetContextLostCallback(context_lost_callback); + } else { + initialize_failed_ = true; + return false; + } + + real_gl_ = context_->GetImplementation(); + setGLInterface(real_gl_); + + if (real_gl_ && webgl_context_) + real_gl_->EnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation"); + + initialized_ = true; + return true; +} + +bool +WebGraphicsContext3DInProcessCommandBufferImpl::InitializeOnCurrentThread() { + if (!MaybeInitializeGL()) + return false; + return context_ && !isContextLost(); +} + +bool WebGraphicsContext3DInProcessCommandBufferImpl::isContextLost() { + return context_lost_reason_ != GL_NO_ERROR; +} + +WGC3Denum WebGraphicsContext3DInProcessCommandBufferImpl:: + getGraphicsResetStatusARB() { + return context_lost_reason_; +} + +::gpu::ContextSupport* +WebGraphicsContext3DInProcessCommandBufferImpl::GetContextSupport() { + return real_gl_; +} + +void WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost() { + // TODO(kbr): improve the precision here. + context_lost_reason_ = GL_UNKNOWN_CONTEXT_RESET_ARB; + if (context_lost_callback_) { + context_lost_callback_->onContextLost(); + } +} + +} // namespace gpu_blink
diff --git a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h new file mode 100644 index 0000000..94816a8 --- /dev/null +++ b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h
@@ -0,0 +1,105 @@ +// Copyright (c) 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. + +#ifndef GPU_BLINK_WEBGRAPHICSCONTEXT3D_IN_PROCESS_COMMAND_BUFFER_IMPL_H_ +#define GPU_BLINK_WEBGRAPHICSCONTEXT3D_IN_PROCESS_COMMAND_BUFFER_IMPL_H_ + +#include <vector> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "gpu/blink/gpu_blink_export.h" +#include "gpu/blink/webgraphicscontext3d_impl.h" +#include "gpu/command_buffer/client/gl_in_process_context.h" +#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" +#include "third_party/WebKit/public/platform/WebString.h" +#include "ui/gfx/native_widget_types.h" + +namespace gpu { +class ContextSupport; +class GLInProcessContext; + +namespace gles2 { +class GLES2Interface; +class GLES2Implementation; +struct ContextCreationAttribHelper; +} +} + +namespace gpu_blink { + +class GPU_BLINK_EXPORT WebGraphicsContext3DInProcessCommandBufferImpl + : public WebGraphicsContext3DImpl { + public: + enum MappedMemoryReclaimLimit { + kNoLimit = 0, + }; + + static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> + CreateViewContext( + const blink::WebGraphicsContext3D::Attributes& attributes, + bool lose_context_when_out_of_memory, + gfx::AcceleratedWidget window); + + static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> + CreateOffscreenContext( + const blink::WebGraphicsContext3D::Attributes& attributes, + bool lose_context_when_out_of_memory); + + static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> + WrapContext( + scoped_ptr< ::gpu::GLInProcessContext> context, + const blink::WebGraphicsContext3D::Attributes& attributes); + + virtual ~WebGraphicsContext3DInProcessCommandBufferImpl(); + + size_t GetMappedMemoryLimit(); + + bool InitializeOnCurrentThread(); + + //---------------------------------------------------------------------- + // WebGraphicsContext3D methods + virtual bool isContextLost(); + + virtual WGC3Denum getGraphicsResetStatusARB(); + + ::gpu::ContextSupport* GetContextSupport(); + + ::gpu::gles2::GLES2Implementation* GetImplementation() { + return real_gl_; + } + + private: + WebGraphicsContext3DInProcessCommandBufferImpl( + scoped_ptr< ::gpu::GLInProcessContext> context, + const blink::WebGraphicsContext3D::Attributes& attributes, + bool lose_context_when_out_of_memory, + bool is_offscreen, + gfx::AcceleratedWidget window); + + void OnContextLost(); + + bool MaybeInitializeGL(); + + // Used to try to find bugs in code that calls gl directly through the gl api + // instead of going through WebGraphicsContext3D. + void ClearContext(); + + ::gpu::gles2::ContextCreationAttribHelper attribs_; + bool share_resources_; + bool webgl_context_; + + bool is_offscreen_; + // Only used when not offscreen. + gfx::AcceleratedWidget window_; + + // The context we use for OpenGL rendering. + scoped_ptr< ::gpu::GLInProcessContext> context_; + // The GLES2Implementation we use for OpenGL rendering. + ::gpu::gles2::GLES2Implementation* real_gl_; +}; + +} // namespace gpu_blink + +#endif // GPU_BLINK_WEBGRAPHICSCONTEXT3D_IN_PROCESS_COMMAND_BUFFER_IMPL_H_
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 4acf8e3..f7f0c77 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -588,6 +588,16 @@ 'GL_RENDERBUFFER', ], }, + 'IndexedBufferTarget': { + 'type': 'GLenum', + 'valid': [ + 'GL_TRANSFORM_FEEDBACK_BUFFER', + 'GL_UNIFORM_BUFFER', + ], + 'invalid': [ + 'GL_RENDERBUFFER', + ], + }, 'BufferUsage': { 'type': 'GLenum', 'valid': [ @@ -1418,6 +1428,11 @@ 'decoder_func': 'DoBindBuffer', 'gen_func': 'GenBuffersARB', }, + 'BindBufferBase': { + 'type': 'Bind', + 'id_mapping': [ 'Buffer' ], + 'unsafe': True, + }, 'BindFramebuffer': { 'type': 'Bind', 'decoder_func': 'DoBindFramebuffer', @@ -2356,6 +2371,12 @@ 'data_transfer_methods': ['shm'], 'client_test': False, }, + 'TexImage3D': { + 'type': 'Manual', + 'data_transfer_methods': ['shm'], + 'client_test': False, + 'unsafe': True, + }, 'TexParameterf': { 'decoder_func': 'DoTexParameterf', 'valid_args': { @@ -2397,6 +2418,17 @@ 'GLenumTextureFormat format, GLenumPixelType type, ' 'const void* pixels, GLboolean internal' }, + 'TexSubImage3D': { + 'type': 'Manual', + 'data_transfer_methods': ['shm'], + 'client_test': False, + 'cmd_args': 'GLenumTextureTarget target, GLint level, ' + 'GLint xoffset, GLint yoffset, GLint zoffset, ' + 'GLsizei width, GLsizei height, GLsizei depth, ' + 'GLenumTextureFormat format, GLenumPixelType type, ' + 'const void* pixels, GLboolean internal', + 'unsafe': True, + }, 'Uniform1f': {'type': 'PUTXn', 'count': 1}, 'Uniform1fv': { 'type': 'PUTn', @@ -4383,7 +4415,7 @@ self.WriteValidUnitTest(func, file, valid_test, { 'first_arg': func.GetOriginalArgs()[0].GetValidArg(func), 'first_gl_arg': func.GetOriginalArgs()[0].GetValidGLArg(func), - 'resource_type': func.GetOriginalArgs()[1].resource_type, + 'resource_type': func.GetOriginalArgs()[-1].resource_type, 'gl_gen_func_name': func.GetInfo("gen_func"), }, *extras) @@ -4439,7 +4471,7 @@ name_arg = func.GetOriginalArgs()[0] else: # Bind functions that have both a target and a name (like BindTexture) - name_arg = func.GetOriginalArgs()[1] + name_arg = func.GetOriginalArgs()[-1] file.Write(code % { 'name': func.name,
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index bd41c8f..c28385d 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -24,6 +24,9 @@ void GLES2BindBuffer(GLenum target, GLuint buffer) { gles2::GetGLContext()->BindBuffer(target, buffer); } +void GLES2BindBufferBase(GLenum target, GLuint index, GLuint buffer) { + gles2::GetGLContext()->BindBufferBase(target, index, buffer); +} void GLES2BindFramebuffer(GLenum target, GLuint framebuffer) { gles2::GetGLContext()->BindFramebuffer(target, framebuffer); } @@ -561,6 +564,20 @@ gles2::GetGLContext()->TexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } +void GLES2TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void* pixels) { + gles2::GetGLContext()->TexImage3D(target, level, internalformat, width, + height, depth, border, format, type, + pixels); +} void GLES2TexParameterf(GLenum target, GLenum pname, GLfloat param) { gles2::GetGLContext()->TexParameterf(target, pname, param); } @@ -594,6 +611,21 @@ gles2::GetGLContext()->TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); } +void GLES2TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void* pixels) { + gles2::GetGLContext()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type, + pixels); +} void GLES2Uniform1f(GLint location, GLfloat x) { gles2::GetGLContext()->Uniform1f(location, x); } @@ -1174,6 +1206,10 @@ reinterpret_cast<GLES2FunctionPointer>(glBindBuffer), }, { + "glBindBufferBase", + reinterpret_cast<GLES2FunctionPointer>(glBindBufferBase), + }, + { "glBindFramebuffer", reinterpret_cast<GLES2FunctionPointer>(glBindFramebuffer), }, @@ -1679,6 +1715,10 @@ reinterpret_cast<GLES2FunctionPointer>(glTexImage2D), }, { + "glTexImage3D", + reinterpret_cast<GLES2FunctionPointer>(glTexImage3D), + }, + { "glTexParameterf", reinterpret_cast<GLES2FunctionPointer>(glTexParameterf), }, @@ -1703,6 +1743,10 @@ reinterpret_cast<GLES2FunctionPointer>(glTexSubImage2D), }, { + "glTexSubImage3D", + reinterpret_cast<GLES2FunctionPointer>(glTexSubImage3D), + }, + { "glUniform1f", reinterpret_cast<GLES2FunctionPointer>(glUniform1f), },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index 8d4553a..6a0acad 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -42,6 +42,13 @@ } } +void BindBufferBase(GLenum target, GLuint index, GLuint buffer) { + gles2::cmds::BindBufferBase* c = GetCmdSpace<gles2::cmds::BindBufferBase>(); + if (c) { + c->Init(target, index, buffer); + } +} + void BindFramebuffer(GLenum target, GLuint framebuffer) { gles2::cmds::BindFramebuffer* c = GetCmdSpace<gles2::cmds::BindFramebuffer>(); if (c) { @@ -1225,6 +1232,23 @@ } } +void TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + uint32_t pixels_shm_id, + uint32_t pixels_shm_offset) { + gles2::cmds::TexImage3D* c = GetCmdSpace<gles2::cmds::TexImage3D>(); + if (c) { + c->Init(target, level, internalformat, width, height, depth, format, type, + pixels_shm_id, pixels_shm_offset); + } +} + void TexParameterf(GLenum target, GLenum pname, GLfloat param) { gles2::cmds::TexParameterf* c = GetCmdSpace<gles2::cmds::TexParameterf>(); if (c) { @@ -1289,6 +1313,26 @@ } } +void TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + uint32_t pixels_shm_id, + uint32_t pixels_shm_offset, + GLboolean internal) { + gles2::cmds::TexSubImage3D* c = GetCmdSpace<gles2::cmds::TexSubImage3D>(); + if (c) { + c->Init(target, level, xoffset, yoffset, zoffset, width, height, depth, + format, type, pixels_shm_id, pixels_shm_offset, internal); + } +} + void Uniform1f(GLint location, GLfloat x) { gles2::cmds::Uniform1f* c = GetCmdSpace<gles2::cmds::Uniform1f>(); if (c) {
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index ccbb457..2b4cc9e 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -8,6 +8,7 @@ #include <GLES2/gl2ext.h> #include <GLES2/gl2extchromium.h> +#include <GLES3/gl3.h> #include <algorithm> #include <limits> #include <map> @@ -77,8 +78,10 @@ unpack_alignment_(4), unpack_flip_y_(false), unpack_row_length_(0), + unpack_image_height_(0), unpack_skip_rows_(0), unpack_skip_pixels_(0), + unpack_skip_images_(0), pack_reverse_row_order_(false), active_texture_unit_(0), bound_framebuffer_(0), @@ -99,6 +102,7 @@ support_client_side_arrays_(support_client_side_arrays), use_count_(0), error_message_callback_(NULL), + current_trace_stack_(0), gpu_control_(gpu_control), capabilities_(gpu_control->GetCapabilities()), weak_ptr_factory_(this) { @@ -1105,12 +1109,18 @@ case GL_UNPACK_ROW_LENGTH_EXT: unpack_row_length_ = param; return; + case GL_UNPACK_IMAGE_HEIGHT: + unpack_image_height_ = param; + return; case GL_UNPACK_SKIP_ROWS_EXT: unpack_skip_rows_ = param; return; case GL_UNPACK_SKIP_PIXELS_EXT: unpack_skip_pixels_ = param; return; + case GL_UNPACK_SKIP_IMAGES: + unpack_skip_images_ = param; + return; case GL_UNPACK_FLIP_Y_CHROMIUM: unpack_flip_y_ = (param != 0); break; @@ -1611,7 +1621,7 @@ uint32 unpadded_row_size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, unpack_alignment_, &size, + width, height, 1, format, type, unpack_alignment_, &size, &unpadded_row_size, &padded_row_size)) { SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large"); return; @@ -1692,6 +1702,126 @@ CheckGLError(); } +void GLES2Implementation::TexImage3D( + GLenum target, GLint level, GLint internalformat, GLsizei width, + GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, + const void* pixels) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage3D(" + << GLES2Util::GetStringTextureTarget(target) << ", " + << level << ", " + << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", " + << width << ", " << height << ", " << depth << ", " << border << ", " + << GLES2Util::GetStringTextureFormat(format) << ", " + << GLES2Util::GetStringPixelType(type) << ", " + << static_cast<const void*>(pixels) << ")"); + if (level < 0 || height < 0 || width < 0 || depth < 0) { + SetGLError(GL_INVALID_VALUE, "glTexImage3D", "dimension < 0"); + return; + } + if (border != 0) { + SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0"); + return; + } + uint32 size; + uint32 unpadded_row_size; + uint32 padded_row_size; + if (!GLES2Util::ComputeImageDataSizes( + width, height, depth, format, type, unpack_alignment_, &size, + &unpadded_row_size, &padded_row_size)) { + SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large"); + return; + } + + // If there's a pixel unpack buffer bound use it when issuing TexImage3D. + if (bound_pixel_unpack_transfer_buffer_id_) { + GLuint offset = ToGLuint(pixels); + BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( + bound_pixel_unpack_transfer_buffer_id_, + "glTexImage3D", offset, size); + if (buffer && buffer->shm_id() != -1) { + helper_->TexImage3D( + target, level, internalformat, width, height, depth, format, type, + buffer->shm_id(), buffer->shm_offset() + offset); + buffer->set_last_usage_token(helper_->InsertToken()); + CheckGLError(); + } + return; + } + + // If there's no data just issue TexImage3D + if (!pixels) { + helper_->TexImage3D( + target, level, internalformat, width, height, depth, format, type, + 0, 0); + CheckGLError(); + return; + } + + // compute the advance bytes per row for the src pixels + uint32 src_padded_row_size; + if (unpack_row_length_ > 0) { + if (!GLES2Util::ComputeImagePaddedRowSize( + unpack_row_length_, format, type, unpack_alignment_, + &src_padded_row_size)) { + SetGLError( + GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large"); + return; + } + } else { + src_padded_row_size = padded_row_size; + } + uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height; + + // advance pixels pointer past the skip images/rows/pixels + pixels = reinterpret_cast<const int8*>(pixels) + + unpack_skip_images_ * src_padded_row_size * src_height + + unpack_skip_rows_ * src_padded_row_size; + if (unpack_skip_pixels_) { + uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type); + pixels = reinterpret_cast<const int8*>(pixels) + + unpack_skip_pixels_ * group_size; + } + + // Check if we can send it all at once. + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); + if (!buffer.valid()) { + return; + } + + if (buffer.size() >= size) { + void* buffer_pointer = buffer.address(); + for (GLsizei z = 0; z < depth; ++z) { + // Only the last row of the last image is unpadded. + uint32 src_unpadded_row_size = + (z == depth - 1) ? unpadded_row_size : src_padded_row_size; + // TODO(zmo): Ignore flip_y flag for now. + CopyRectToBuffer( + pixels, height, src_unpadded_row_size, src_padded_row_size, false, + buffer_pointer, padded_row_size); + pixels = reinterpret_cast<const int8*>(pixels) + + src_padded_row_size * src_height; + buffer_pointer = reinterpret_cast<int8*>(buffer_pointer) + + padded_row_size * height; + } + helper_->TexImage3D( + target, level, internalformat, width, height, depth, format, type, + buffer.shm_id(), buffer.offset()); + CheckGLError(); + return; + } + + // No, so send it using TexSubImage3D. + helper_->TexImage3D( + target, level, internalformat, width, height, depth, format, type, + 0, 0); + TexSubImage3DImpl( + target, level, 0, 0, 0, width, height, depth, format, type, + unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &buffer, + padded_row_size); + CheckGLError(); +} + void GLES2Implementation::TexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) { @@ -1717,7 +1847,7 @@ uint32 unpadded_row_size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, unpack_alignment_, &temp_size, + width, height, 1, format, type, unpack_alignment_, &temp_size, &unpadded_row_size, &padded_row_size)) { SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large"); return; @@ -1770,15 +1900,100 @@ CheckGLError(); } +void GLES2Implementation::TexSubImage3D( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + const void* pixels) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage3D(" + << GLES2Util::GetStringTextureTarget(target) << ", " + << level << ", " + << xoffset << ", " << yoffset << ", " << zoffset << ", " + << width << ", " << height << ", " << depth << ", " + << GLES2Util::GetStringTextureFormat(format) << ", " + << GLES2Util::GetStringPixelType(type) << ", " + << static_cast<const void*>(pixels) << ")"); + + if (level < 0 || height < 0 || width < 0 || depth < 0) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0"); + return; + } + if (height == 0 || width == 0 || depth == 0) { + return; + } + + uint32 temp_size; + uint32 unpadded_row_size; + uint32 padded_row_size; + if (!GLES2Util::ComputeImageDataSizes( + width, height, depth, format, type, unpack_alignment_, &temp_size, + &unpadded_row_size, &padded_row_size)) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large"); + return; + } + + // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D. + if (bound_pixel_unpack_transfer_buffer_id_) { + GLuint offset = ToGLuint(pixels); + BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid( + bound_pixel_unpack_transfer_buffer_id_, + "glTexSubImage3D", offset, temp_size); + if (buffer && buffer->shm_id() != -1) { + helper_->TexSubImage3D( + target, level, xoffset, yoffset, zoffset, width, height, depth, + format, type, buffer->shm_id(), buffer->shm_offset() + offset, false); + buffer->set_last_usage_token(helper_->InsertToken()); + CheckGLError(); + } + return; + } + + // compute the advance bytes per row for the src pixels + uint32 src_padded_row_size; + if (unpack_row_length_ > 0) { + if (!GLES2Util::ComputeImagePaddedRowSize( + unpack_row_length_, format, type, unpack_alignment_, + &src_padded_row_size)) { + SetGLError( + GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large"); + return; + } + } else { + src_padded_row_size = padded_row_size; + } + uint32 src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height; + + // advance pixels pointer past the skip images/rows/pixels + pixels = reinterpret_cast<const int8*>(pixels) + + unpack_skip_images_ * src_padded_row_size * src_height + + unpack_skip_rows_ * src_padded_row_size; + if (unpack_skip_pixels_) { + uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type); + pixels = reinterpret_cast<const int8*>(pixels) + + unpack_skip_pixels_ * group_size; + } + + ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_); + TexSubImage3DImpl( + target, level, xoffset, yoffset, zoffset, width, height, depth, + format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, + &buffer, padded_row_size); + CheckGLError(); +} + static GLint ComputeNumRowsThatFitInBuffer( uint32 padded_row_size, uint32 unpadded_row_size, - unsigned int size) { + unsigned int size, GLsizei remaining_rows) { DCHECK_GE(unpadded_row_size, 0u); if (padded_row_size == 0) { return 1; } GLint num_rows = size / padded_row_size; - return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size; + if (num_rows + 1 == remaining_rows && + size - num_rows * padded_row_size >= unpadded_row_size) { + num_rows++; + } + return num_rows; } void GLES2Implementation::TexSubImage2DImpl( @@ -1805,7 +2020,7 @@ } GLint num_rows = ComputeNumRowsThatFitInBuffer( - buffer_padded_row_size, unpadded_row_size, buffer->size()); + buffer_padded_row_size, unpadded_row_size, buffer->size(), height); num_rows = std::min(num_rows, height); CopyRectToBuffer( source, num_rows, unpadded_row_size, pixels_padded_row_size, @@ -1821,6 +2036,119 @@ } } +void GLES2Implementation::TexSubImage3DImpl( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size, + GLboolean internal, ScopedTransferBufferPtr* buffer, + uint32 buffer_padded_row_size) { + DCHECK(buffer); + DCHECK_GE(level, 0); + DCHECK_GT(height, 0); + DCHECK_GT(width, 0); + DCHECK_GT(depth, 0); + const int8* source = reinterpret_cast<const int8*>(pixels); + GLsizei total_rows = height * depth; + GLint row_index = 0, depth_index = 0; + while (total_rows) { + // Each time, we either copy one or more images, or copy one or more rows + // within a single image, depending on the buffer size limit. + GLsizei max_rows; + unsigned int desired_size; + if (row_index > 0) { + // We are in the middle of an image. Send the remaining of the image. + max_rows = height - row_index; + if (total_rows <= height) { + // Last image, so last row is unpadded. + desired_size = buffer_padded_row_size * (max_rows - 1) + + unpadded_row_size; + } else { + desired_size = buffer_padded_row_size * max_rows; + } + } else { + // Send all the remaining data if possible. + max_rows = total_rows; + desired_size = + buffer_padded_row_size * (max_rows - 1) + unpadded_row_size; + } + if (!buffer->valid() || buffer->size() == 0) { + buffer->Reset(desired_size); + if (!buffer->valid()) { + return; + } + } + GLint num_rows = ComputeNumRowsThatFitInBuffer( + buffer_padded_row_size, unpadded_row_size, buffer->size(), total_rows); + num_rows = std::min(num_rows, max_rows); + GLint num_images = num_rows / height; + GLsizei my_height, my_depth; + if (num_images > 0) { + num_rows = num_images * height; + my_height = height; + my_depth = num_images; + } else { + my_height = num_rows; + my_depth = 1; + } + + // TODO(zmo): Ignore flip_y flag for now. + if (num_images > 0) { + int8* buffer_pointer = reinterpret_cast<int8*>(buffer->address()); + uint32 src_height = + unpack_image_height_ > 0 ? unpack_image_height_ : height; + uint32 image_size_dst = buffer_padded_row_size * height; + uint32 image_size_src = pixels_padded_row_size * src_height; + for (GLint ii = 0; ii < num_images; ++ii) { + uint32 my_unpadded_row_size; + if (total_rows == num_rows && ii + 1 == num_images) + my_unpadded_row_size = unpadded_row_size; + else + my_unpadded_row_size = pixels_padded_row_size; + CopyRectToBuffer( + source + ii * image_size_src, my_height, my_unpadded_row_size, + pixels_padded_row_size, false, buffer_pointer + ii * image_size_dst, + buffer_padded_row_size); + } + } else { + uint32 my_unpadded_row_size; + if (total_rows == num_rows) + my_unpadded_row_size = unpadded_row_size; + else + my_unpadded_row_size = pixels_padded_row_size; + CopyRectToBuffer( + source, my_height, my_unpadded_row_size, pixels_padded_row_size, + false, buffer->address(), buffer_padded_row_size); + } + helper_->TexSubImage3D( + target, level, xoffset, yoffset + row_index, zoffset + depth_index, + width, my_height, my_depth, + format, type, buffer->shm_id(), buffer->offset(), internal); + buffer->Release(); + + total_rows -= num_rows; + if (total_rows > 0) { + GLint num_image_paddings; + if (num_images > 0) { + DCHECK_EQ(row_index, 0); + depth_index += num_images; + num_image_paddings = num_images; + } else { + row_index = (row_index + my_height) % height; + num_image_paddings = 0; + if (my_height > 0 && row_index == 0) { + depth_index++; + num_image_paddings++; + } + } + source += num_rows * pixels_padded_row_size; + if (unpack_image_height_ > height && num_image_paddings > 0) { + source += num_image_paddings * (unpack_image_height_ - height) * + pixels_padded_row_size; + } + } + } +} + bool GLES2Implementation::GetActiveAttribHelper( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { @@ -2187,8 +2515,8 @@ uint32 unpadded_row_size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size, - &padded_row_size)) { + width, 2, 1, format, type, pack_alignment_, &temp_size, + &unpadded_row_size, &padded_row_size)) { SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large."); return; } @@ -2215,13 +2543,13 @@ // Transfer by rows. // The max rows we can transfer. while (height) { - GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size; + GLsizei desired_size = padded_row_size * (height - 1) + unpadded_row_size; ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_); if (!buffer.valid()) { return; } GLint num_rows = ComputeNumRowsThatFitInBuffer( - padded_row_size, unpadded_row_size, buffer.size()); + padded_row_size, unpadded_row_size, buffer.size(), height); num_rows = std::min(num_rows, height); // NOTE: We must look up the address of the result area AFTER allocation // of the transfer buffer since the transfer buffer may be reallocated. @@ -2986,7 +3314,7 @@ } uint32 size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, unpack_alignment_, &size, NULL, NULL)) { + width, height, 1, format, type, unpack_alignment_, &size, NULL, NULL)) { SetGLError( GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large"); return NULL; @@ -3530,34 +3858,24 @@ GPU_CLIENT_SINGLE_THREAD_CHECK(); GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM(" << category_name << ", " << trace_name << ")"); - if (current_trace_category_.get() || current_trace_name_.get()) { - SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM", - "trace already running"); - return; - } - TRACE_EVENT_COPY_ASYNC_BEGIN0(category_name, trace_name, this); SetBucketAsCString(kResultBucketId, category_name); - SetBucketAsCString(kResultBucketId + 1, category_name); + SetBucketAsCString(kResultBucketId + 1, trace_name); helper_->TraceBeginCHROMIUM(kResultBucketId, kResultBucketId + 1); helper_->SetBucketSize(kResultBucketId, 0); helper_->SetBucketSize(kResultBucketId + 1, 0); - current_trace_category_.reset(new std::string(category_name)); - current_trace_name_.reset(new std::string(trace_name)); + current_trace_stack_++; } void GLES2Implementation::TraceEndCHROMIUM() { GPU_CLIENT_SINGLE_THREAD_CHECK(); GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")"); - if (!current_trace_category_.get() || !current_trace_name_.get()) { + if (current_trace_stack_ == 0) { SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM", "missing begin trace"); return; } helper_->TraceEndCHROMIUM(); - TRACE_EVENT_COPY_ASYNC_END0(current_trace_category_->c_str(), - current_trace_name_->c_str(), this); - current_trace_category_.reset(); - current_trace_name_.reset(); + current_trace_stack_--; } void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) { @@ -3727,7 +4045,7 @@ uint32 unpadded_row_size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, unpack_alignment_, &size, + width, height, 1, format, type, unpack_alignment_, &size, &unpadded_row_size, &padded_row_size)) { SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large"); return; @@ -3787,7 +4105,7 @@ uint32 unpadded_row_size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, unpack_alignment_, &size, + width, height, 1, format, type, unpack_alignment_, &size, &unpadded_row_size, &padded_row_size)) { SetGLError( GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 7d17d64..25021fb 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -510,13 +510,19 @@ void RestoreElementAndArrayBuffers(bool restore); void RestoreArrayBuffer(bool restrore); - // The pixels pointer should already account for unpack skip rows and skip - // pixels. + // The pixels pointer should already account for unpack skip + // images/rows/pixels. void TexSubImage2DImpl( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size, const void* pixels, uint32 pixels_padded_row_size, GLboolean internal, ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size); + void TexSubImage3DImpl( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + uint32 unpadded_row_size, const void* pixels, + uint32 pixels_padded_row_size, GLboolean internal, + ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size); // Helpers for query functions. bool GetHelper(GLenum pname, GLint* params); @@ -640,12 +646,18 @@ // unpack row length as last set by glPixelStorei GLint unpack_row_length_; + // unpack image height as last set by glPixelStorei + GLint unpack_image_height_; + // unpack skip rows as last set by glPixelStorei GLint unpack_skip_rows_; // unpack skip pixels as last set by glPixelStorei GLint unpack_skip_pixels_; + // unpack skip images as last set by glPixelStorei + GLint unpack_skip_images_; + // pack reverse row order as last set by glPixelstorei bool pack_reverse_row_order_; @@ -731,8 +743,7 @@ GLES2ImplementationErrorMessageCallback* error_message_callback_; - scoped_ptr<std::string> current_trace_category_; - scoped_ptr<std::string> current_trace_name_; + int current_trace_stack_; GpuControl* gpu_control_;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 3a5253a..76e7b5e 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -23,6 +23,8 @@ void BindBuffer(GLenum target, GLuint buffer) override; +void BindBufferBase(GLenum target, GLuint index, GLuint buffer) override; + void BindFramebuffer(GLenum target, GLuint framebuffer) override; void BindRenderbuffer(GLenum target, GLuint renderbuffer) override; @@ -416,6 +418,17 @@ GLenum type, const void* pixels) override; +void TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void* pixels) override; + void TexParameterf(GLenum target, GLenum pname, GLfloat param) override; void TexParameterfv(GLenum target, @@ -443,6 +456,18 @@ GLenum type, const void* pixels) override; +void TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void* pixels) override; + void Uniform1f(GLint location, GLfloat x) override; void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) override;
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h index e7ef769..02551b4 100644 --- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -34,6 +34,17 @@ CheckGLError(); } +void GLES2Implementation::BindBufferBase(GLenum target, + GLuint index, + GLuint buffer) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindBufferBase(" + << GLES2Util::GetStringIndexedBufferTarget(target) << ", " + << index << ", " << buffer << ")"); + helper_->BindBufferBase(target, index, buffer); + CheckGLError(); +} + void GLES2Implementation::BindFramebuffer(GLenum target, GLuint framebuffer) { GPU_CLIENT_SINGLE_THREAD_CHECK(); GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFramebuffer("
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 3d0f1b0..0d49e42 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -2163,7 +2163,7 @@ uint32 unpadded_row_size = 0; uint32 padded_row_size = 0; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, alignment, &size, &unpadded_row_size, + width, height, 1, format, type, alignment, &size, &unpadded_row_size, &padded_row_size)) { return false; } @@ -2269,15 +2269,15 @@ uint32 unpadded_row_size = 0; uint32 padded_row_size = 0; ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment, + kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, &size, &unpadded_row_size, &padded_row_size)); const GLsizei kHeight = (MaxTransferBufferSize() / padded_row_size) * 2; ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, + kWidth, kHeight, 1, kFormat, kType, kPixelStoreUnpackAlignment, &size, NULL, NULL)); uint32 half_size = 0; ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment, + kWidth, kHeight / 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, &half_size, NULL, NULL)); scoped_ptr<uint8[]> pixels(new uint8[size]); @@ -2378,7 +2378,7 @@ uint32 sub_2_high_size = 0; ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( - kSubImageWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment, + kSubImageWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, &sub_2_high_size, NULL, NULL)); ExpectedMemoryInfo mem1 = GetExpectedMemory(sub_2_high_size); @@ -2460,7 +2460,7 @@ uint32 src_size; ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( - kSrcWidth, kSrcSubImageY1, kFormat, kType, 8, &src_size, NULL, NULL)); + kSrcWidth, kSrcSubImageY1, 1, kFormat, kType, 8, &src_size, NULL, NULL)); scoped_ptr<uint8[]> src_pixels; src_pixels.reset(new uint8[src_size]); for (size_t i = 0; i < src_size; ++i) { @@ -2475,7 +2475,7 @@ uint32 unpadded_row_size; uint32 padded_row_size; ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( - kSrcSubImageWidth, kSrcSubImageHeight, kFormat, kType, alignment, + kSrcSubImageWidth, kSrcSubImageHeight, 1, kFormat, kType, alignment, &size, &unpadded_row_size, &padded_row_size)); ASSERT_TRUE(size <= MaxTransferBufferSize()); ExpectedMemoryInfo mem = GetExpectedMemory(size); @@ -2626,6 +2626,181 @@ EXPECT_EQ(GL_INVALID_VALUE, CheckError()); } +TEST_F(GLES2ImplementationTest, TexImage3DSingleCommand) { + struct Cmds { + cmds::TexImage3D tex_image_3d; + }; + const GLenum kTarget = GL_TEXTURE_3D; + const GLint kLevel = 0; + const GLint kBorder = 0; + const GLenum kFormat = GL_RGB; + const GLenum kType = GL_UNSIGNED_BYTE; + const GLint kPixelStoreUnpackAlignment = 4; + const GLsizei kWidth = 3; + const GLsizei kDepth = 2; + + uint32 size = 0; + uint32 unpadded_row_size = 0; + uint32 padded_row_size = 0; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, 2, kDepth, kFormat, kType, kPixelStoreUnpackAlignment, + &size, &unpadded_row_size, &padded_row_size)); + // Makes sure we can just send over the data in one command. + const GLsizei kHeight = MaxTransferBufferSize() / padded_row_size / kDepth; + + scoped_ptr<uint8[]> pixels(new uint8[size]); + for (uint32 ii = 0; ii < size; ++ii) { + pixels[ii] = static_cast<uint8>(ii); + } + + ExpectedMemoryInfo mem = GetExpectedMemory(size); + + Cmds expected; + expected.tex_image_3d.Init( + kTarget, kLevel, kFormat, kWidth, kHeight, kDepth, + kFormat, kType, mem.id, mem.offset); + + gl_->TexImage3D( + kTarget, kLevel, kFormat, kWidth, kHeight, kDepth, kBorder, + kFormat, kType, pixels.get()); + + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); + EXPECT_TRUE(CheckRect( + kWidth, kHeight * kDepth, kFormat, kType, kPixelStoreUnpackAlignment, + false, reinterpret_cast<uint8*>(pixels.get()), mem.ptr)); +} + +TEST_F(GLES2ImplementationTest, TexImage3DViaTexSubImage3D) { + struct Cmds { + cmds::TexImage3D tex_image_3d; + cmds::TexSubImage3D tex_sub_image_3d1; + cmd::SetToken set_token; + cmds::TexSubImage3D tex_sub_image_3d2; + }; + const GLenum kTarget = GL_TEXTURE_3D; + const GLint kLevel = 0; + const GLint kBorder = 0; + const GLenum kFormat = GL_RGB; + const GLenum kType = GL_UNSIGNED_BYTE; + const GLint kPixelStoreUnpackAlignment = 4; + const GLsizei kWidth = 3; + + uint32 size = 0; + uint32 unpadded_row_size = 0; + uint32 padded_row_size = 0; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, + &size, &unpadded_row_size, &padded_row_size)); + // Makes sure the data is more than one command can hold. + const GLsizei kHeight = MaxTransferBufferSize() / padded_row_size + 3; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, kFormat, kType, kPixelStoreUnpackAlignment, + &size, NULL, NULL)); + uint32 first_size = padded_row_size * (kHeight - 3); + uint32 second_size = + padded_row_size * 3 - (padded_row_size - unpadded_row_size); + EXPECT_EQ(size, first_size + second_size); + ExpectedMemoryInfo mem1 = GetExpectedMemory(first_size); + ExpectedMemoryInfo mem2 = GetExpectedMemory(second_size); + scoped_ptr<uint8[]> pixels(new uint8[size]); + for (uint32 ii = 0; ii < size; ++ii) { + pixels[ii] = static_cast<uint8>(ii); + } + + Cmds expected; + expected.tex_image_3d.Init( + kTarget, kLevel, kFormat, kWidth, kHeight, 1, kFormat, kType, 0, 0); + expected.tex_sub_image_3d1.Init( + kTarget, kLevel, 0, 0, 0, kWidth, kHeight - 3, 1, kFormat, kType, + mem1.id, mem1.offset, GL_TRUE); + expected.tex_sub_image_3d2.Init( + kTarget, kLevel, 0, kHeight - 3, 0, kWidth, 3, 1, kFormat, kType, + mem2.id, mem2.offset, GL_TRUE); + expected.set_token.Init(GetNextToken()); + + gl_->TexImage3D( + kTarget, kLevel, kFormat, kWidth, kHeight, 1, kBorder, + kFormat, kType, pixels.get()); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +// Test TexSubImage3D with 4 writes +TEST_F(GLES2ImplementationTest, TexSubImage3D4Writes) { + struct Cmds { + cmds::TexSubImage3D tex_sub_image_3d1_1; + cmd::SetToken set_token1; + cmds::TexSubImage3D tex_sub_image_3d1_2; + cmd::SetToken set_token2; + cmds::TexSubImage3D tex_sub_image_3d2_1; + cmd::SetToken set_token3; + cmds::TexSubImage3D tex_sub_image_3d2_2; + }; + const GLenum kTarget = GL_TEXTURE_3D; + const GLint kLevel = 0; + const GLint kXOffset = 0; + const GLint kYOffset = 0; + const GLint kZOffset = 0; + const GLenum kFormat = GL_RGB; + const GLenum kType = GL_UNSIGNED_BYTE; + const GLint kPixelStoreUnpackAlignment = 4; + const GLsizei kWidth = 3; + const GLsizei kDepth = 2; + + uint32 size = 0; + uint32 unpadded_row_size = 0; + uint32 padded_row_size = 0; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, 2, 1, kFormat, kType, kPixelStoreUnpackAlignment, + &size, &unpadded_row_size, &padded_row_size)); + const GLsizei kHeight = MaxTransferBufferSize() / padded_row_size + 2; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, kDepth, kFormat, kType, kPixelStoreUnpackAlignment, + &size, NULL, NULL)); + uint32 first_size = (kHeight - 2) * padded_row_size; + uint32 second_size = 2 * padded_row_size; + uint32 third_size = first_size; + uint32 fourth_size = second_size - (padded_row_size - unpadded_row_size); + EXPECT_EQ(size, first_size + second_size + third_size + fourth_size); + + scoped_ptr<uint8[]> pixels(new uint8[size]); + for (uint32 ii = 0; ii < size; ++ii) { + pixels[ii] = static_cast<uint8>(ii); + } + + ExpectedMemoryInfo mem1_1 = GetExpectedMemory(first_size); + ExpectedMemoryInfo mem1_2 = GetExpectedMemory(second_size); + ExpectedMemoryInfo mem2_1 = GetExpectedMemory(third_size); + ExpectedMemoryInfo mem2_2 = GetExpectedMemory(fourth_size); + + Cmds expected; + expected.tex_sub_image_3d1_1.Init( + kTarget, kLevel, kXOffset, kYOffset, kZOffset, + kWidth, kHeight - 2, 1, kFormat, kType, + mem1_1.id, mem1_1.offset, GL_FALSE); + expected.tex_sub_image_3d1_2.Init( + kTarget, kLevel, kXOffset, kYOffset + kHeight - 2, kZOffset, + kWidth, 2, 1, kFormat, kType, mem1_2.id, mem1_2.offset, GL_FALSE); + expected.tex_sub_image_3d2_1.Init( + kTarget, kLevel, kXOffset, kYOffset, kZOffset + 1, + kWidth, kHeight - 2, 1, kFormat, kType, + mem2_1.id, mem2_1.offset, GL_FALSE); + expected.tex_sub_image_3d2_2.Init( + kTarget, kLevel, kXOffset, kYOffset + kHeight - 2, kZOffset + 1, + kWidth, 2, 1, kFormat, kType, mem2_2.id, mem2_2.offset, GL_FALSE); + expected.set_token1.Init(GetNextToken()); + expected.set_token2.Init(GetNextToken()); + expected.set_token3.Init(GetNextToken()); + + gl_->TexSubImage3D( + kTarget, kLevel, kXOffset, kYOffset, kZOffset, kWidth, kHeight, kDepth, + kFormat, kType, pixels.get()); + + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); + uint32 offset_to_last = first_size + second_size + third_size; + EXPECT_TRUE(CheckRect( + kWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment, false, + reinterpret_cast<uint8*>(pixels.get()) + offset_to_last, mem2_2.ptr)); +} // Binds can not be cached with bind_generates_resource = false because // our id might not be valid. More specifically if you bind on contextA then @@ -3266,6 +3441,76 @@ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str()); } +TEST_F(GLES2ImplementationTest, TraceBeginCHROMIUM) { + const uint32 kCategoryBucketId = GLES2Implementation::kResultBucketId; + const uint32 kNameBucketId = GLES2Implementation::kResultBucketId + 1; + const std::string category_name = "test category"; + const std::string trace_name = "test trace"; + const size_t kPaddedString1Size = + transfer_buffer_->RoundToAlignment(category_name.size() + 1); + const size_t kPaddedString2Size = + transfer_buffer_->RoundToAlignment(trace_name.size() + 1); + + gl_->TraceBeginCHROMIUM(category_name.c_str(), trace_name.c_str()); + EXPECT_EQ(GL_NO_ERROR, CheckError()); + + struct Cmds { + cmd::SetBucketSize category_size1; + cmd::SetBucketData category_data; + cmd::SetToken set_token1; + cmd::SetBucketSize name_size1; + cmd::SetBucketData name_data; + cmd::SetToken set_token2; + cmds::TraceBeginCHROMIUM trace_call_begin; + cmd::SetBucketSize category_size2; + cmd::SetBucketSize name_size2; + }; + + ExpectedMemoryInfo mem1 = GetExpectedMemory(kPaddedString1Size); + ExpectedMemoryInfo mem2 = GetExpectedMemory(kPaddedString2Size); + + ASSERT_STREQ(category_name.c_str(), reinterpret_cast<char*>(mem1.ptr)); + ASSERT_STREQ(trace_name.c_str(), reinterpret_cast<char*>(mem2.ptr)); + + Cmds expected; + expected.category_size1.Init(kCategoryBucketId, category_name.size() + 1); + expected.category_data.Init( + kCategoryBucketId, 0, category_name.size() + 1, mem1.id, mem1.offset); + expected.set_token1.Init(GetNextToken()); + expected.name_size1.Init(kNameBucketId, trace_name.size() + 1); + expected.name_data.Init( + kNameBucketId, 0, trace_name.size() + 1, mem2.id, mem2.offset); + expected.set_token2.Init(GetNextToken()); + expected.trace_call_begin.Init(kCategoryBucketId, kNameBucketId); + expected.category_size2.Init(kCategoryBucketId, 0); + expected.name_size2.Init(kNameBucketId, 0); + + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + +TEST_F(GLES2ImplementationTest, AllowNestedTracesCHROMIUM) { + const std::string category1_name = "test category 1"; + const std::string trace1_name = "test trace 1"; + const std::string category2_name = "test category 2"; + const std::string trace2_name = "test trace 2"; + + gl_->TraceBeginCHROMIUM(category1_name.c_str(), trace1_name.c_str()); + EXPECT_EQ(GL_NO_ERROR, CheckError()); + + gl_->TraceBeginCHROMIUM(category2_name.c_str(), trace2_name.c_str()); + EXPECT_EQ(GL_NO_ERROR, CheckError()); + + gl_->TraceEndCHROMIUM(); + EXPECT_EQ(GL_NO_ERROR, CheckError()); + + gl_->TraceEndCHROMIUM(); + EXPECT_EQ(GL_NO_ERROR, CheckError()); + + // No more corresponding begin tracer marker should error. + gl_->TraceEndCHROMIUM(); + EXPECT_EQ(GL_INVALID_OPERATION, CheckError()); +} + TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) { ContextInitOptions init_options; init_options.lose_context_when_out_of_memory = true;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h index f501cd9..744387d 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -39,6 +39,17 @@ EXPECT_TRUE(NoCommandsWritten()); } +TEST_F(GLES2ImplementationTest, BindBufferBase) { + struct Cmds { + cmds::BindBufferBase cmd; + }; + Cmds expected; + expected.cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, 3); + + gl_->BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, 3); + EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected))); +} + TEST_F(GLES2ImplementationTest, BindFramebuffer) { struct Cmds { cmds::BindFramebuffer cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index 5a5d289..f8417e6 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -19,6 +19,7 @@ GLuint index, const char* name) = 0; virtual void BindBuffer(GLenum target, GLuint buffer) = 0; +virtual void BindBufferBase(GLenum target, GLuint index, GLuint buffer) = 0; virtual void BindFramebuffer(GLenum target, GLuint framebuffer) = 0; virtual void BindRenderbuffer(GLenum target, GLuint renderbuffer) = 0; virtual void BindSampler(GLuint unit, GLuint sampler) = 0; @@ -298,6 +299,16 @@ GLenum format, GLenum type, const void* pixels) = 0; +virtual void TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void* pixels) = 0; virtual void TexParameterf(GLenum target, GLenum pname, GLfloat param) = 0; virtual void TexParameterfv(GLenum target, GLenum pname, @@ -321,6 +332,17 @@ GLenum format, GLenum type, const void* pixels) = 0; +virtual void TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void* pixels) = 0; virtual void Uniform1f(GLint location, GLfloat x) = 0; virtual void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) = 0; virtual void Uniform1i(GLint location, GLint x) = 0;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index c2f4920..d9f995e 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -18,6 +18,7 @@ GLuint index, const char* name) override; void BindBuffer(GLenum target, GLuint buffer) override; +void BindBufferBase(GLenum target, GLuint index, GLuint buffer) override; void BindFramebuffer(GLenum target, GLuint framebuffer) override; void BindRenderbuffer(GLenum target, GLuint renderbuffer) override; void BindSampler(GLuint unit, GLuint sampler) override; @@ -293,6 +294,16 @@ GLenum format, GLenum type, const void* pixels) override; +void TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void* pixels) override; void TexParameterf(GLenum target, GLenum pname, GLfloat param) override; void TexParameterfv(GLenum target, GLenum pname, @@ -314,6 +325,17 @@ GLenum format, GLenum type, const void* pixels) override; +void TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void* pixels) override; void Uniform1f(GLint location, GLfloat x) override; void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) override; void Uniform1i(GLint location, GLint x) override;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index fcd196d..9bc00eb 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -23,6 +23,10 @@ } void GLES2InterfaceStub::BindBuffer(GLenum /* target */, GLuint /* buffer */) { } +void GLES2InterfaceStub::BindBufferBase(GLenum /* target */, + GLuint /* index */, + GLuint /* buffer */) { +} void GLES2InterfaceStub::BindFramebuffer(GLenum /* target */, GLuint /* framebuffer */) { } @@ -499,6 +503,17 @@ GLenum /* type */, const void* /* pixels */) { } +void GLES2InterfaceStub::TexImage3D(GLenum /* target */, + GLint /* level */, + GLint /* internalformat */, + GLsizei /* width */, + GLsizei /* height */, + GLsizei /* depth */, + GLint /* border */, + GLenum /* format */, + GLenum /* type */, + const void* /* pixels */) { +} void GLES2InterfaceStub::TexParameterf(GLenum /* target */, GLenum /* pname */, GLfloat /* param */) { @@ -532,6 +547,18 @@ GLenum /* type */, const void* /* pixels */) { } +void GLES2InterfaceStub::TexSubImage3D(GLenum /* target */, + GLint /* level */, + GLint /* xoffset */, + GLint /* yoffset */, + GLint /* zoffset */, + GLsizei /* width */, + GLsizei /* height */, + GLsizei /* depth */, + GLenum /* format */, + GLenum /* type */, + const void* /* pixels */) { +} void GLES2InterfaceStub::Uniform1f(GLint /* location */, GLfloat /* x */) { } void GLES2InterfaceStub::Uniform1fv(GLint /* location */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index cd8ad7c..9989ff5 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -18,6 +18,7 @@ GLuint index, const char* name) override; void BindBuffer(GLenum target, GLuint buffer) override; +void BindBufferBase(GLenum target, GLuint index, GLuint buffer) override; void BindFramebuffer(GLenum target, GLuint framebuffer) override; void BindRenderbuffer(GLenum target, GLuint renderbuffer) override; void BindSampler(GLuint unit, GLuint sampler) override; @@ -293,6 +294,16 @@ GLenum format, GLenum type, const void* pixels) override; +void TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void* pixels) override; void TexParameterf(GLenum target, GLenum pname, GLfloat param) override; void TexParameterfv(GLenum target, GLenum pname, @@ -314,6 +325,17 @@ GLenum format, GLenum type, const void* pixels) override; +void TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void* pixels) override; void Uniform1f(GLint location, GLfloat x) override; void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) override; void Uniform1i(GLint location, GLint x) override;
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index 567dace..fd58cf8 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -34,6 +34,13 @@ gl_->BindBuffer(target, buffer); } +void GLES2TraceImplementation::BindBufferBase(GLenum target, + GLuint index, + GLuint buffer) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindBufferBase"); + gl_->BindBufferBase(target, index, buffer); +} + void GLES2TraceImplementation::BindFramebuffer(GLenum target, GLuint framebuffer) { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindFramebuffer"); @@ -873,6 +880,21 @@ type, pixels); } +void GLES2TraceImplementation::TexImage3D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLsizei depth, + GLint border, + GLenum format, + GLenum type, + const void* pixels) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexImage3D"); + gl_->TexImage3D(target, level, internalformat, width, height, depth, border, + format, type, pixels); +} + void GLES2TraceImplementation::TexParameterf(GLenum target, GLenum pname, GLfloat param) { @@ -925,6 +947,22 @@ type, pixels); } +void GLES2TraceImplementation::TexSubImage3D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint zoffset, + GLsizei width, + GLsizei height, + GLsizei depth, + GLenum format, + GLenum type, + const void* pixels) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexSubImage3D"); + gl_->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, + depth, format, type, pixels); +} + void GLES2TraceImplementation::Uniform1f(GLint location, GLfloat x) { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform1f"); gl_->Uniform1f(location, x);
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index d046748e..51cd4a1 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -8,6 +8,7 @@ GL_APICALL void GL_APIENTRY glAttachShader (GLidProgram program, GLidShader shader); GL_APICALL void GL_APIENTRY glBindAttribLocation (GLidProgram program, GLuint index, const char* name); GL_APICALL void GL_APIENTRY glBindBuffer (GLenumBufferTarget target, GLidBindBuffer buffer); +GL_APICALL void GL_APIENTRY glBindBufferBase (GLenumIndexedBufferTarget target, GLuint index, GLidBindBuffer buffer); GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenumFrameBufferTarget target, GLidBindFramebuffer framebuffer); GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenumRenderBufferTarget target, GLidBindRenderbuffer renderbuffer); GL_APICALL void GL_APIENTRY glBindSampler (GLuint unit, GLidBindSampler sampler); @@ -134,12 +135,14 @@ GL_APICALL void GL_APIENTRY glStencilOp (GLenumStencilOp fail, GLenumStencilOp zfail, GLenumStencilOp zpass); GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenumFaceType face, GLenumStencilOp fail, GLenumStencilOp zfail, GLenumStencilOp zpass); GL_APICALL void GL_APIENTRY glTexImage2D (GLenumTextureTarget target, GLint level, GLintTextureInternalFormat internalformat, GLsizei width, GLsizei height, GLintTextureBorder border, GLenumTextureFormat format, GLenumPixelType type, const void* pixels); +GL_APICALL void GL_APIENTRY glTexImage3D (GLenumTextureTarget target, GLint level, GLintTextureInternalFormat internalformat, GLsizei width, GLsizei height, GLsizei depth, GLintTextureBorder border, GLenumTextureFormat format, GLenumPixelType type, const void* pixels); GL_APICALL void GL_APIENTRY glTexParameterf (GLenumTextureBindTarget target, GLenumTextureParameter pname, GLfloat param); GL_APICALL void GL_APIENTRY glTexParameterfv (GLenumTextureBindTarget target, GLenumTextureParameter pname, const GLfloat* params); GL_APICALL void GL_APIENTRY glTexParameteri (GLenumTextureBindTarget target, GLenumTextureParameter pname, GLint param); GL_APICALL void GL_APIENTRY glTexParameteriv (GLenumTextureBindTarget target, GLenumTextureParameter pname, const GLint* params); GL_APICALL void GL_APIENTRY glTexStorage3D (GLenumTexture3DTarget target, GLsizei levels, GLenumTextureInternalFormatStorage internalFormat, GLsizei width, GLsizei height, GLsizei depth); GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenumTextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenumTextureFormat format, GLenumPixelType type, const void* pixels); +GL_APICALL void GL_APIENTRY glTexSubImage3D (GLenumTextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenumTextureFormat format, GLenumPixelType type, const void* pixels); GL_APICALL void GL_APIENTRY glUniform1f (GLintUniformLocation location, GLfloat x); GL_APICALL void GL_APIENTRY glUniform1fv (GLintUniformLocation location, GLsizeiNotNegative count, const GLfloat* v); GL_APICALL void GL_APIENTRY glUniform1i (GLintUniformLocation location, GLint x);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index 693d1ed..1c235f7 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -159,6 +159,47 @@ static_assert(offsetof(BindBuffer, buffer) == 8, "offset of BindBuffer buffer should be 8"); +struct BindBufferBase { + typedef BindBufferBase ValueType; + static const CommandId kCmdId = kBindBufferBase; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLenum _target, GLuint _index, GLuint _buffer) { + SetHeader(); + target = _target; + index = _index; + buffer = _buffer; + } + + void* Set(void* cmd, GLenum _target, GLuint _index, GLuint _buffer) { + static_cast<ValueType*>(cmd)->Init(_target, _index, _buffer); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t target; + uint32_t index; + uint32_t buffer; +}; + +static_assert(sizeof(BindBufferBase) == 16, + "size of BindBufferBase should be 16"); +static_assert(offsetof(BindBufferBase, header) == 0, + "offset of BindBufferBase header should be 0"); +static_assert(offsetof(BindBufferBase, target) == 4, + "offset of BindBufferBase target should be 4"); +static_assert(offsetof(BindBufferBase, index) == 8, + "offset of BindBufferBase index should be 8"); +static_assert(offsetof(BindBufferBase, buffer) == 12, + "offset of BindBufferBase buffer should be 12"); + struct BindFramebuffer { typedef BindFramebuffer ValueType; static const CommandId kCmdId = kBindFramebuffer; @@ -6008,6 +6049,96 @@ static_assert(offsetof(TexImage2D, pixels_shm_offset) == 36, "offset of TexImage2D pixels_shm_offset should be 36"); +struct TexImage3D { + typedef TexImage3D ValueType; + static const CommandId kCmdId = kTexImage3D; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLenum _target, + GLint _level, + GLint _internalformat, + GLsizei _width, + GLsizei _height, + GLsizei _depth, + GLenum _format, + GLenum _type, + uint32_t _pixels_shm_id, + uint32_t _pixels_shm_offset) { + SetHeader(); + target = _target; + level = _level; + internalformat = _internalformat; + width = _width; + height = _height; + depth = _depth; + format = _format; + type = _type; + pixels_shm_id = _pixels_shm_id; + pixels_shm_offset = _pixels_shm_offset; + } + + void* Set(void* cmd, + GLenum _target, + GLint _level, + GLint _internalformat, + GLsizei _width, + GLsizei _height, + GLsizei _depth, + GLenum _format, + GLenum _type, + uint32_t _pixels_shm_id, + uint32_t _pixels_shm_offset) { + static_cast<ValueType*>(cmd)->Init(_target, _level, _internalformat, _width, + _height, _depth, _format, _type, + _pixels_shm_id, _pixels_shm_offset); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t target; + int32_t level; + int32_t internalformat; + int32_t width; + int32_t height; + int32_t depth; + uint32_t format; + uint32_t type; + uint32_t pixels_shm_id; + uint32_t pixels_shm_offset; + static const int32_t border = 0; +}; + +static_assert(sizeof(TexImage3D) == 44, "size of TexImage3D should be 44"); +static_assert(offsetof(TexImage3D, header) == 0, + "offset of TexImage3D header should be 0"); +static_assert(offsetof(TexImage3D, target) == 4, + "offset of TexImage3D target should be 4"); +static_assert(offsetof(TexImage3D, level) == 8, + "offset of TexImage3D level should be 8"); +static_assert(offsetof(TexImage3D, internalformat) == 12, + "offset of TexImage3D internalformat should be 12"); +static_assert(offsetof(TexImage3D, width) == 16, + "offset of TexImage3D width should be 16"); +static_assert(offsetof(TexImage3D, height) == 20, + "offset of TexImage3D height should be 20"); +static_assert(offsetof(TexImage3D, depth) == 24, + "offset of TexImage3D depth should be 24"); +static_assert(offsetof(TexImage3D, format) == 28, + "offset of TexImage3D format should be 28"); +static_assert(offsetof(TexImage3D, type) == 32, + "offset of TexImage3D type should be 32"); +static_assert(offsetof(TexImage3D, pixels_shm_id) == 36, + "offset of TexImage3D pixels_shm_id should be 36"); +static_assert(offsetof(TexImage3D, pixels_shm_offset) == 40, + "offset of TexImage3D pixels_shm_offset should be 40"); + struct TexParameterf { typedef TexParameterf ValueType; static const CommandId kCmdId = kTexParameterf; @@ -6338,6 +6469,114 @@ static_assert(offsetof(TexSubImage2D, internal) == 44, "offset of TexSubImage2D internal should be 44"); +struct TexSubImage3D { + typedef TexSubImage3D ValueType; + static const CommandId kCmdId = kTexSubImage3D; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLenum _target, + GLint _level, + GLint _xoffset, + GLint _yoffset, + GLint _zoffset, + GLsizei _width, + GLsizei _height, + GLsizei _depth, + GLenum _format, + GLenum _type, + uint32_t _pixels_shm_id, + uint32_t _pixels_shm_offset, + GLboolean _internal) { + SetHeader(); + target = _target; + level = _level; + xoffset = _xoffset; + yoffset = _yoffset; + zoffset = _zoffset; + width = _width; + height = _height; + depth = _depth; + format = _format; + type = _type; + pixels_shm_id = _pixels_shm_id; + pixels_shm_offset = _pixels_shm_offset; + internal = _internal; + } + + void* Set(void* cmd, + GLenum _target, + GLint _level, + GLint _xoffset, + GLint _yoffset, + GLint _zoffset, + GLsizei _width, + GLsizei _height, + GLsizei _depth, + GLenum _format, + GLenum _type, + uint32_t _pixels_shm_id, + uint32_t _pixels_shm_offset, + GLboolean _internal) { + static_cast<ValueType*>(cmd)->Init( + _target, _level, _xoffset, _yoffset, _zoffset, _width, _height, _depth, + _format, _type, _pixels_shm_id, _pixels_shm_offset, _internal); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t target; + int32_t level; + int32_t xoffset; + int32_t yoffset; + int32_t zoffset; + int32_t width; + int32_t height; + int32_t depth; + uint32_t format; + uint32_t type; + uint32_t pixels_shm_id; + uint32_t pixels_shm_offset; + uint32_t internal; +}; + +static_assert(sizeof(TexSubImage3D) == 56, + "size of TexSubImage3D should be 56"); +static_assert(offsetof(TexSubImage3D, header) == 0, + "offset of TexSubImage3D header should be 0"); +static_assert(offsetof(TexSubImage3D, target) == 4, + "offset of TexSubImage3D target should be 4"); +static_assert(offsetof(TexSubImage3D, level) == 8, + "offset of TexSubImage3D level should be 8"); +static_assert(offsetof(TexSubImage3D, xoffset) == 12, + "offset of TexSubImage3D xoffset should be 12"); +static_assert(offsetof(TexSubImage3D, yoffset) == 16, + "offset of TexSubImage3D yoffset should be 16"); +static_assert(offsetof(TexSubImage3D, zoffset) == 20, + "offset of TexSubImage3D zoffset should be 20"); +static_assert(offsetof(TexSubImage3D, width) == 24, + "offset of TexSubImage3D width should be 24"); +static_assert(offsetof(TexSubImage3D, height) == 28, + "offset of TexSubImage3D height should be 28"); +static_assert(offsetof(TexSubImage3D, depth) == 32, + "offset of TexSubImage3D depth should be 32"); +static_assert(offsetof(TexSubImage3D, format) == 36, + "offset of TexSubImage3D format should be 36"); +static_assert(offsetof(TexSubImage3D, type) == 40, + "offset of TexSubImage3D type should be 40"); +static_assert(offsetof(TexSubImage3D, pixels_shm_id) == 44, + "offset of TexSubImage3D pixels_shm_id should be 44"); +static_assert(offsetof(TexSubImage3D, pixels_shm_offset) == 48, + "offset of TexSubImage3D pixels_shm_offset should be 48"); +static_assert(offsetof(TexSubImage3D, internal) == 52, + "offset of TexSubImage3D internal should be 52"); + struct Uniform1f { typedef Uniform1f ValueType; static const CommandId kCmdId = kUniform1f;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index ca81047..d664435 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -62,6 +62,19 @@ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, BindBufferBase) { + cmds::BindBufferBase& cmd = *GetBufferAs<cmds::BindBufferBase>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11), + static_cast<GLuint>(12), static_cast<GLuint>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::BindBufferBase::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.target); + EXPECT_EQ(static_cast<GLuint>(12), cmd.index); + EXPECT_EQ(static_cast<GLuint>(13), cmd.buffer); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + TEST_F(GLES2FormatTest, BindFramebuffer) { cmds::BindFramebuffer& cmd = *GetBufferAs<cmds::BindFramebuffer>(); void* next_cmd = @@ -1865,6 +1878,30 @@ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, TexImage3D) { + cmds::TexImage3D& cmd = *GetBufferAs<cmds::TexImage3D>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLint>(12), + static_cast<GLint>(13), static_cast<GLsizei>(14), + static_cast<GLsizei>(15), static_cast<GLsizei>(16), + static_cast<GLenum>(17), static_cast<GLenum>(18), + static_cast<uint32_t>(19), static_cast<uint32_t>(20)); + EXPECT_EQ(static_cast<uint32_t>(cmds::TexImage3D::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.target); + EXPECT_EQ(static_cast<GLint>(12), cmd.level); + EXPECT_EQ(static_cast<GLint>(13), cmd.internalformat); + EXPECT_EQ(static_cast<GLsizei>(14), cmd.width); + EXPECT_EQ(static_cast<GLsizei>(15), cmd.height); + EXPECT_EQ(static_cast<GLsizei>(16), cmd.depth); + EXPECT_EQ(static_cast<GLenum>(17), cmd.format); + EXPECT_EQ(static_cast<GLenum>(18), cmd.type); + EXPECT_EQ(static_cast<uint32_t>(19), cmd.pixels_shm_id); + EXPECT_EQ(static_cast<uint32_t>(20), cmd.pixels_shm_offset); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + TEST_F(GLES2FormatTest, TexParameterf) { cmds::TexParameterf& cmd = *GetBufferAs<cmds::TexParameterf>(); void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11), @@ -1974,6 +2011,34 @@ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, TexSubImage3D) { + cmds::TexSubImage3D& cmd = *GetBufferAs<cmds::TexSubImage3D>(); + void* next_cmd = cmd.Set( + &cmd, static_cast<GLenum>(11), static_cast<GLint>(12), + static_cast<GLint>(13), static_cast<GLint>(14), static_cast<GLint>(15), + static_cast<GLsizei>(16), static_cast<GLsizei>(17), + static_cast<GLsizei>(18), static_cast<GLenum>(19), + static_cast<GLenum>(20), static_cast<uint32_t>(21), + static_cast<uint32_t>(22), static_cast<GLboolean>(23)); + EXPECT_EQ(static_cast<uint32_t>(cmds::TexSubImage3D::kCmdId), + cmd.header.command); + EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u); + EXPECT_EQ(static_cast<GLenum>(11), cmd.target); + EXPECT_EQ(static_cast<GLint>(12), cmd.level); + EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset); + EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset); + EXPECT_EQ(static_cast<GLint>(15), cmd.zoffset); + EXPECT_EQ(static_cast<GLsizei>(16), cmd.width); + EXPECT_EQ(static_cast<GLsizei>(17), cmd.height); + EXPECT_EQ(static_cast<GLsizei>(18), cmd.depth); + EXPECT_EQ(static_cast<GLenum>(19), cmd.format); + EXPECT_EQ(static_cast<GLenum>(20), cmd.type); + EXPECT_EQ(static_cast<uint32_t>(21), cmd.pixels_shm_id); + EXPECT_EQ(static_cast<uint32_t>(22), cmd.pixels_shm_offset); + EXPECT_EQ(static_cast<GLboolean>(23), cmd.internal); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + TEST_F(GLES2FormatTest, Uniform1f) { cmds::Uniform1f& cmd = *GetBufferAs<cmds::Uniform1f>(); void* next_cmd =
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index 34957e4..943043f 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -16,252 +16,255 @@ OP(AttachShader) /* 257 */ \ OP(BindAttribLocationBucket) /* 258 */ \ OP(BindBuffer) /* 259 */ \ - OP(BindFramebuffer) /* 260 */ \ - OP(BindRenderbuffer) /* 261 */ \ - OP(BindSampler) /* 262 */ \ - OP(BindTexture) /* 263 */ \ - OP(BindTransformFeedback) /* 264 */ \ - OP(BlendColor) /* 265 */ \ - OP(BlendEquation) /* 266 */ \ - OP(BlendEquationSeparate) /* 267 */ \ - OP(BlendFunc) /* 268 */ \ - OP(BlendFuncSeparate) /* 269 */ \ - OP(BufferData) /* 270 */ \ - OP(BufferSubData) /* 271 */ \ - OP(CheckFramebufferStatus) /* 272 */ \ - OP(Clear) /* 273 */ \ - OP(ClearColor) /* 274 */ \ - OP(ClearDepthf) /* 275 */ \ - OP(ClearStencil) /* 276 */ \ - OP(ColorMask) /* 277 */ \ - OP(CompileShader) /* 278 */ \ - OP(CompressedTexImage2DBucket) /* 279 */ \ - OP(CompressedTexImage2D) /* 280 */ \ - OP(CompressedTexSubImage2DBucket) /* 281 */ \ - OP(CompressedTexSubImage2D) /* 282 */ \ - OP(CopyBufferSubData) /* 283 */ \ - OP(CopyTexImage2D) /* 284 */ \ - OP(CopyTexSubImage2D) /* 285 */ \ - OP(CreateProgram) /* 286 */ \ - OP(CreateShader) /* 287 */ \ - OP(CullFace) /* 288 */ \ - OP(DeleteBuffersImmediate) /* 289 */ \ - OP(DeleteFramebuffersImmediate) /* 290 */ \ - OP(DeleteProgram) /* 291 */ \ - OP(DeleteRenderbuffersImmediate) /* 292 */ \ - OP(DeleteSamplersImmediate) /* 293 */ \ - OP(DeleteShader) /* 294 */ \ - OP(DeleteTexturesImmediate) /* 295 */ \ - OP(DeleteTransformFeedbacksImmediate) /* 296 */ \ - OP(DepthFunc) /* 297 */ \ - OP(DepthMask) /* 298 */ \ - OP(DepthRangef) /* 299 */ \ - OP(DetachShader) /* 300 */ \ - OP(Disable) /* 301 */ \ - OP(DisableVertexAttribArray) /* 302 */ \ - OP(DrawArrays) /* 303 */ \ - OP(DrawElements) /* 304 */ \ - OP(Enable) /* 305 */ \ - OP(EnableVertexAttribArray) /* 306 */ \ - OP(Finish) /* 307 */ \ - OP(Flush) /* 308 */ \ - OP(FramebufferRenderbuffer) /* 309 */ \ - OP(FramebufferTexture2D) /* 310 */ \ - OP(FramebufferTextureLayer) /* 311 */ \ - OP(FrontFace) /* 312 */ \ - OP(GenBuffersImmediate) /* 313 */ \ - OP(GenerateMipmap) /* 314 */ \ - OP(GenFramebuffersImmediate) /* 315 */ \ - OP(GenRenderbuffersImmediate) /* 316 */ \ - OP(GenSamplersImmediate) /* 317 */ \ - OP(GenTexturesImmediate) /* 318 */ \ - OP(GenTransformFeedbacksImmediate) /* 319 */ \ - OP(GetActiveAttrib) /* 320 */ \ - OP(GetActiveUniform) /* 321 */ \ - OP(GetAttachedShaders) /* 322 */ \ - OP(GetAttribLocation) /* 323 */ \ - OP(GetBooleanv) /* 324 */ \ - OP(GetBufferParameteriv) /* 325 */ \ - OP(GetError) /* 326 */ \ - OP(GetFloatv) /* 327 */ \ - OP(GetFramebufferAttachmentParameteriv) /* 328 */ \ - OP(GetIntegerv) /* 329 */ \ - OP(GetInternalformativ) /* 330 */ \ - OP(GetProgramiv) /* 331 */ \ - OP(GetProgramInfoLog) /* 332 */ \ - OP(GetRenderbufferParameteriv) /* 333 */ \ - OP(GetSamplerParameterfv) /* 334 */ \ - OP(GetSamplerParameteriv) /* 335 */ \ - OP(GetShaderiv) /* 336 */ \ - OP(GetShaderInfoLog) /* 337 */ \ - OP(GetShaderPrecisionFormat) /* 338 */ \ - OP(GetShaderSource) /* 339 */ \ - OP(GetString) /* 340 */ \ - OP(GetTexParameterfv) /* 341 */ \ - OP(GetTexParameteriv) /* 342 */ \ - OP(GetUniformfv) /* 343 */ \ - OP(GetUniformiv) /* 344 */ \ - OP(GetUniformLocation) /* 345 */ \ - OP(GetVertexAttribfv) /* 346 */ \ - OP(GetVertexAttribiv) /* 347 */ \ - OP(GetVertexAttribPointerv) /* 348 */ \ - OP(Hint) /* 349 */ \ - OP(InvalidateFramebufferImmediate) /* 350 */ \ - OP(InvalidateSubFramebufferImmediate) /* 351 */ \ - OP(IsBuffer) /* 352 */ \ - OP(IsEnabled) /* 353 */ \ - OP(IsFramebuffer) /* 354 */ \ - OP(IsProgram) /* 355 */ \ - OP(IsRenderbuffer) /* 356 */ \ - OP(IsSampler) /* 357 */ \ - OP(IsShader) /* 358 */ \ - OP(IsTexture) /* 359 */ \ - OP(IsTransformFeedback) /* 360 */ \ - OP(LineWidth) /* 361 */ \ - OP(LinkProgram) /* 362 */ \ - OP(PauseTransformFeedback) /* 363 */ \ - OP(PixelStorei) /* 364 */ \ - OP(PolygonOffset) /* 365 */ \ - OP(ReadBuffer) /* 366 */ \ - OP(ReadPixels) /* 367 */ \ - OP(ReleaseShaderCompiler) /* 368 */ \ - OP(RenderbufferStorage) /* 369 */ \ - OP(ResumeTransformFeedback) /* 370 */ \ - OP(SampleCoverage) /* 371 */ \ - OP(SamplerParameterf) /* 372 */ \ - OP(SamplerParameterfvImmediate) /* 373 */ \ - OP(SamplerParameteri) /* 374 */ \ - OP(SamplerParameterivImmediate) /* 375 */ \ - OP(Scissor) /* 376 */ \ - OP(ShaderBinary) /* 377 */ \ - OP(ShaderSourceBucket) /* 378 */ \ - OP(StencilFunc) /* 379 */ \ - OP(StencilFuncSeparate) /* 380 */ \ - OP(StencilMask) /* 381 */ \ - OP(StencilMaskSeparate) /* 382 */ \ - OP(StencilOp) /* 383 */ \ - OP(StencilOpSeparate) /* 384 */ \ - OP(TexImage2D) /* 385 */ \ - OP(TexParameterf) /* 386 */ \ - OP(TexParameterfvImmediate) /* 387 */ \ - OP(TexParameteri) /* 388 */ \ - OP(TexParameterivImmediate) /* 389 */ \ - OP(TexStorage3D) /* 390 */ \ - OP(TexSubImage2D) /* 391 */ \ - OP(Uniform1f) /* 392 */ \ - OP(Uniform1fvImmediate) /* 393 */ \ - OP(Uniform1i) /* 394 */ \ - OP(Uniform1ivImmediate) /* 395 */ \ - OP(Uniform1ui) /* 396 */ \ - OP(Uniform1uivImmediate) /* 397 */ \ - OP(Uniform2f) /* 398 */ \ - OP(Uniform2fvImmediate) /* 399 */ \ - OP(Uniform2i) /* 400 */ \ - OP(Uniform2ivImmediate) /* 401 */ \ - OP(Uniform2ui) /* 402 */ \ - OP(Uniform2uivImmediate) /* 403 */ \ - OP(Uniform3f) /* 404 */ \ - OP(Uniform3fvImmediate) /* 405 */ \ - OP(Uniform3i) /* 406 */ \ - OP(Uniform3ivImmediate) /* 407 */ \ - OP(Uniform3ui) /* 408 */ \ - OP(Uniform3uivImmediate) /* 409 */ \ - OP(Uniform4f) /* 410 */ \ - OP(Uniform4fvImmediate) /* 411 */ \ - OP(Uniform4i) /* 412 */ \ - OP(Uniform4ivImmediate) /* 413 */ \ - OP(Uniform4ui) /* 414 */ \ - OP(Uniform4uivImmediate) /* 415 */ \ - OP(UniformMatrix2fvImmediate) /* 416 */ \ - OP(UniformMatrix2x3fvImmediate) /* 417 */ \ - OP(UniformMatrix2x4fvImmediate) /* 418 */ \ - OP(UniformMatrix3fvImmediate) /* 419 */ \ - OP(UniformMatrix3x2fvImmediate) /* 420 */ \ - OP(UniformMatrix3x4fvImmediate) /* 421 */ \ - OP(UniformMatrix4fvImmediate) /* 422 */ \ - OP(UniformMatrix4x2fvImmediate) /* 423 */ \ - OP(UniformMatrix4x3fvImmediate) /* 424 */ \ - OP(UseProgram) /* 425 */ \ - OP(ValidateProgram) /* 426 */ \ - OP(VertexAttrib1f) /* 427 */ \ - OP(VertexAttrib1fvImmediate) /* 428 */ \ - OP(VertexAttrib2f) /* 429 */ \ - OP(VertexAttrib2fvImmediate) /* 430 */ \ - OP(VertexAttrib3f) /* 431 */ \ - OP(VertexAttrib3fvImmediate) /* 432 */ \ - OP(VertexAttrib4f) /* 433 */ \ - OP(VertexAttrib4fvImmediate) /* 434 */ \ - OP(VertexAttribI4i) /* 435 */ \ - OP(VertexAttribI4ivImmediate) /* 436 */ \ - OP(VertexAttribI4ui) /* 437 */ \ - OP(VertexAttribI4uivImmediate) /* 438 */ \ - OP(VertexAttribIPointer) /* 439 */ \ - OP(VertexAttribPointer) /* 440 */ \ - OP(Viewport) /* 441 */ \ - OP(BlitFramebufferCHROMIUM) /* 442 */ \ - OP(RenderbufferStorageMultisampleCHROMIUM) /* 443 */ \ - OP(RenderbufferStorageMultisampleEXT) /* 444 */ \ - OP(FramebufferTexture2DMultisampleEXT) /* 445 */ \ - OP(TexStorage2DEXT) /* 446 */ \ - OP(GenQueriesEXTImmediate) /* 447 */ \ - OP(DeleteQueriesEXTImmediate) /* 448 */ \ - OP(BeginQueryEXT) /* 449 */ \ - OP(BeginTransformFeedback) /* 450 */ \ - OP(EndQueryEXT) /* 451 */ \ - OP(EndTransformFeedback) /* 452 */ \ - OP(InsertEventMarkerEXT) /* 453 */ \ - OP(PushGroupMarkerEXT) /* 454 */ \ - OP(PopGroupMarkerEXT) /* 455 */ \ - OP(GenVertexArraysOESImmediate) /* 456 */ \ - OP(DeleteVertexArraysOESImmediate) /* 457 */ \ - OP(IsVertexArrayOES) /* 458 */ \ - OP(BindVertexArrayOES) /* 459 */ \ - OP(SwapBuffers) /* 460 */ \ - OP(GetMaxValueInBufferCHROMIUM) /* 461 */ \ - OP(EnableFeatureCHROMIUM) /* 462 */ \ - OP(ResizeCHROMIUM) /* 463 */ \ - OP(GetRequestableExtensionsCHROMIUM) /* 464 */ \ - OP(RequestExtensionCHROMIUM) /* 465 */ \ - OP(GetProgramInfoCHROMIUM) /* 466 */ \ - OP(GetTranslatedShaderSourceANGLE) /* 467 */ \ - OP(PostSubBufferCHROMIUM) /* 468 */ \ - OP(TexImageIOSurface2DCHROMIUM) /* 469 */ \ - OP(CopyTextureCHROMIUM) /* 470 */ \ - OP(DrawArraysInstancedANGLE) /* 471 */ \ - OP(DrawElementsInstancedANGLE) /* 472 */ \ - OP(VertexAttribDivisorANGLE) /* 473 */ \ - OP(GenMailboxCHROMIUM) /* 474 */ \ - OP(ProduceTextureCHROMIUMImmediate) /* 475 */ \ - OP(ProduceTextureDirectCHROMIUMImmediate) /* 476 */ \ - OP(ConsumeTextureCHROMIUMImmediate) /* 477 */ \ - OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 478 */ \ - OP(BindUniformLocationCHROMIUMBucket) /* 479 */ \ - OP(GenValuebuffersCHROMIUMImmediate) /* 480 */ \ - OP(DeleteValuebuffersCHROMIUMImmediate) /* 481 */ \ - OP(IsValuebufferCHROMIUM) /* 482 */ \ - OP(BindValuebufferCHROMIUM) /* 483 */ \ - OP(SubscribeValueCHROMIUM) /* 484 */ \ - OP(PopulateSubscribedValuesCHROMIUM) /* 485 */ \ - OP(UniformValuebufferCHROMIUM) /* 486 */ \ - OP(BindTexImage2DCHROMIUM) /* 487 */ \ - OP(ReleaseTexImage2DCHROMIUM) /* 488 */ \ - OP(TraceBeginCHROMIUM) /* 489 */ \ - OP(TraceEndCHROMIUM) /* 490 */ \ - OP(AsyncTexSubImage2DCHROMIUM) /* 491 */ \ - OP(AsyncTexImage2DCHROMIUM) /* 492 */ \ - OP(WaitAsyncTexImage2DCHROMIUM) /* 493 */ \ - OP(WaitAllAsyncTexImage2DCHROMIUM) /* 494 */ \ - OP(DiscardFramebufferEXTImmediate) /* 495 */ \ - OP(LoseContextCHROMIUM) /* 496 */ \ - OP(InsertSyncPointCHROMIUM) /* 497 */ \ - OP(WaitSyncPointCHROMIUM) /* 498 */ \ - OP(DrawBuffersEXTImmediate) /* 499 */ \ - OP(DiscardBackbufferCHROMIUM) /* 500 */ \ - OP(ScheduleOverlayPlaneCHROMIUM) /* 501 */ \ - OP(SwapInterval) /* 502 */ \ - OP(MatrixLoadfCHROMIUMImmediate) /* 503 */ \ - OP(MatrixLoadIdentityCHROMIUM) /* 504 */ \ - OP(BlendBarrierKHR) /* 505 */ + OP(BindBufferBase) /* 260 */ \ + OP(BindFramebuffer) /* 261 */ \ + OP(BindRenderbuffer) /* 262 */ \ + OP(BindSampler) /* 263 */ \ + OP(BindTexture) /* 264 */ \ + OP(BindTransformFeedback) /* 265 */ \ + OP(BlendColor) /* 266 */ \ + OP(BlendEquation) /* 267 */ \ + OP(BlendEquationSeparate) /* 268 */ \ + OP(BlendFunc) /* 269 */ \ + OP(BlendFuncSeparate) /* 270 */ \ + OP(BufferData) /* 271 */ \ + OP(BufferSubData) /* 272 */ \ + OP(CheckFramebufferStatus) /* 273 */ \ + OP(Clear) /* 274 */ \ + OP(ClearColor) /* 275 */ \ + OP(ClearDepthf) /* 276 */ \ + OP(ClearStencil) /* 277 */ \ + OP(ColorMask) /* 278 */ \ + OP(CompileShader) /* 279 */ \ + OP(CompressedTexImage2DBucket) /* 280 */ \ + OP(CompressedTexImage2D) /* 281 */ \ + OP(CompressedTexSubImage2DBucket) /* 282 */ \ + OP(CompressedTexSubImage2D) /* 283 */ \ + OP(CopyBufferSubData) /* 284 */ \ + OP(CopyTexImage2D) /* 285 */ \ + OP(CopyTexSubImage2D) /* 286 */ \ + OP(CreateProgram) /* 287 */ \ + OP(CreateShader) /* 288 */ \ + OP(CullFace) /* 289 */ \ + OP(DeleteBuffersImmediate) /* 290 */ \ + OP(DeleteFramebuffersImmediate) /* 291 */ \ + OP(DeleteProgram) /* 292 */ \ + OP(DeleteRenderbuffersImmediate) /* 293 */ \ + OP(DeleteSamplersImmediate) /* 294 */ \ + OP(DeleteShader) /* 295 */ \ + OP(DeleteTexturesImmediate) /* 296 */ \ + OP(DeleteTransformFeedbacksImmediate) /* 297 */ \ + OP(DepthFunc) /* 298 */ \ + OP(DepthMask) /* 299 */ \ + OP(DepthRangef) /* 300 */ \ + OP(DetachShader) /* 301 */ \ + OP(Disable) /* 302 */ \ + OP(DisableVertexAttribArray) /* 303 */ \ + OP(DrawArrays) /* 304 */ \ + OP(DrawElements) /* 305 */ \ + OP(Enable) /* 306 */ \ + OP(EnableVertexAttribArray) /* 307 */ \ + OP(Finish) /* 308 */ \ + OP(Flush) /* 309 */ \ + OP(FramebufferRenderbuffer) /* 310 */ \ + OP(FramebufferTexture2D) /* 311 */ \ + OP(FramebufferTextureLayer) /* 312 */ \ + OP(FrontFace) /* 313 */ \ + OP(GenBuffersImmediate) /* 314 */ \ + OP(GenerateMipmap) /* 315 */ \ + OP(GenFramebuffersImmediate) /* 316 */ \ + OP(GenRenderbuffersImmediate) /* 317 */ \ + OP(GenSamplersImmediate) /* 318 */ \ + OP(GenTexturesImmediate) /* 319 */ \ + OP(GenTransformFeedbacksImmediate) /* 320 */ \ + OP(GetActiveAttrib) /* 321 */ \ + OP(GetActiveUniform) /* 322 */ \ + OP(GetAttachedShaders) /* 323 */ \ + OP(GetAttribLocation) /* 324 */ \ + OP(GetBooleanv) /* 325 */ \ + OP(GetBufferParameteriv) /* 326 */ \ + OP(GetError) /* 327 */ \ + OP(GetFloatv) /* 328 */ \ + OP(GetFramebufferAttachmentParameteriv) /* 329 */ \ + OP(GetIntegerv) /* 330 */ \ + OP(GetInternalformativ) /* 331 */ \ + OP(GetProgramiv) /* 332 */ \ + OP(GetProgramInfoLog) /* 333 */ \ + OP(GetRenderbufferParameteriv) /* 334 */ \ + OP(GetSamplerParameterfv) /* 335 */ \ + OP(GetSamplerParameteriv) /* 336 */ \ + OP(GetShaderiv) /* 337 */ \ + OP(GetShaderInfoLog) /* 338 */ \ + OP(GetShaderPrecisionFormat) /* 339 */ \ + OP(GetShaderSource) /* 340 */ \ + OP(GetString) /* 341 */ \ + OP(GetTexParameterfv) /* 342 */ \ + OP(GetTexParameteriv) /* 343 */ \ + OP(GetUniformfv) /* 344 */ \ + OP(GetUniformiv) /* 345 */ \ + OP(GetUniformLocation) /* 346 */ \ + OP(GetVertexAttribfv) /* 347 */ \ + OP(GetVertexAttribiv) /* 348 */ \ + OP(GetVertexAttribPointerv) /* 349 */ \ + OP(Hint) /* 350 */ \ + OP(InvalidateFramebufferImmediate) /* 351 */ \ + OP(InvalidateSubFramebufferImmediate) /* 352 */ \ + OP(IsBuffer) /* 353 */ \ + OP(IsEnabled) /* 354 */ \ + OP(IsFramebuffer) /* 355 */ \ + OP(IsProgram) /* 356 */ \ + OP(IsRenderbuffer) /* 357 */ \ + OP(IsSampler) /* 358 */ \ + OP(IsShader) /* 359 */ \ + OP(IsTexture) /* 360 */ \ + OP(IsTransformFeedback) /* 361 */ \ + OP(LineWidth) /* 362 */ \ + OP(LinkProgram) /* 363 */ \ + OP(PauseTransformFeedback) /* 364 */ \ + OP(PixelStorei) /* 365 */ \ + OP(PolygonOffset) /* 366 */ \ + OP(ReadBuffer) /* 367 */ \ + OP(ReadPixels) /* 368 */ \ + OP(ReleaseShaderCompiler) /* 369 */ \ + OP(RenderbufferStorage) /* 370 */ \ + OP(ResumeTransformFeedback) /* 371 */ \ + OP(SampleCoverage) /* 372 */ \ + OP(SamplerParameterf) /* 373 */ \ + OP(SamplerParameterfvImmediate) /* 374 */ \ + OP(SamplerParameteri) /* 375 */ \ + OP(SamplerParameterivImmediate) /* 376 */ \ + OP(Scissor) /* 377 */ \ + OP(ShaderBinary) /* 378 */ \ + OP(ShaderSourceBucket) /* 379 */ \ + OP(StencilFunc) /* 380 */ \ + OP(StencilFuncSeparate) /* 381 */ \ + OP(StencilMask) /* 382 */ \ + OP(StencilMaskSeparate) /* 383 */ \ + OP(StencilOp) /* 384 */ \ + OP(StencilOpSeparate) /* 385 */ \ + OP(TexImage2D) /* 386 */ \ + OP(TexImage3D) /* 387 */ \ + OP(TexParameterf) /* 388 */ \ + OP(TexParameterfvImmediate) /* 389 */ \ + OP(TexParameteri) /* 390 */ \ + OP(TexParameterivImmediate) /* 391 */ \ + OP(TexStorage3D) /* 392 */ \ + OP(TexSubImage2D) /* 393 */ \ + OP(TexSubImage3D) /* 394 */ \ + OP(Uniform1f) /* 395 */ \ + OP(Uniform1fvImmediate) /* 396 */ \ + OP(Uniform1i) /* 397 */ \ + OP(Uniform1ivImmediate) /* 398 */ \ + OP(Uniform1ui) /* 399 */ \ + OP(Uniform1uivImmediate) /* 400 */ \ + OP(Uniform2f) /* 401 */ \ + OP(Uniform2fvImmediate) /* 402 */ \ + OP(Uniform2i) /* 403 */ \ + OP(Uniform2ivImmediate) /* 404 */ \ + OP(Uniform2ui) /* 405 */ \ + OP(Uniform2uivImmediate) /* 406 */ \ + OP(Uniform3f) /* 407 */ \ + OP(Uniform3fvImmediate) /* 408 */ \ + OP(Uniform3i) /* 409 */ \ + OP(Uniform3ivImmediate) /* 410 */ \ + OP(Uniform3ui) /* 411 */ \ + OP(Uniform3uivImmediate) /* 412 */ \ + OP(Uniform4f) /* 413 */ \ + OP(Uniform4fvImmediate) /* 414 */ \ + OP(Uniform4i) /* 415 */ \ + OP(Uniform4ivImmediate) /* 416 */ \ + OP(Uniform4ui) /* 417 */ \ + OP(Uniform4uivImmediate) /* 418 */ \ + OP(UniformMatrix2fvImmediate) /* 419 */ \ + OP(UniformMatrix2x3fvImmediate) /* 420 */ \ + OP(UniformMatrix2x4fvImmediate) /* 421 */ \ + OP(UniformMatrix3fvImmediate) /* 422 */ \ + OP(UniformMatrix3x2fvImmediate) /* 423 */ \ + OP(UniformMatrix3x4fvImmediate) /* 424 */ \ + OP(UniformMatrix4fvImmediate) /* 425 */ \ + OP(UniformMatrix4x2fvImmediate) /* 426 */ \ + OP(UniformMatrix4x3fvImmediate) /* 427 */ \ + OP(UseProgram) /* 428 */ \ + OP(ValidateProgram) /* 429 */ \ + OP(VertexAttrib1f) /* 430 */ \ + OP(VertexAttrib1fvImmediate) /* 431 */ \ + OP(VertexAttrib2f) /* 432 */ \ + OP(VertexAttrib2fvImmediate) /* 433 */ \ + OP(VertexAttrib3f) /* 434 */ \ + OP(VertexAttrib3fvImmediate) /* 435 */ \ + OP(VertexAttrib4f) /* 436 */ \ + OP(VertexAttrib4fvImmediate) /* 437 */ \ + OP(VertexAttribI4i) /* 438 */ \ + OP(VertexAttribI4ivImmediate) /* 439 */ \ + OP(VertexAttribI4ui) /* 440 */ \ + OP(VertexAttribI4uivImmediate) /* 441 */ \ + OP(VertexAttribIPointer) /* 442 */ \ + OP(VertexAttribPointer) /* 443 */ \ + OP(Viewport) /* 444 */ \ + OP(BlitFramebufferCHROMIUM) /* 445 */ \ + OP(RenderbufferStorageMultisampleCHROMIUM) /* 446 */ \ + OP(RenderbufferStorageMultisampleEXT) /* 447 */ \ + OP(FramebufferTexture2DMultisampleEXT) /* 448 */ \ + OP(TexStorage2DEXT) /* 449 */ \ + OP(GenQueriesEXTImmediate) /* 450 */ \ + OP(DeleteQueriesEXTImmediate) /* 451 */ \ + OP(BeginQueryEXT) /* 452 */ \ + OP(BeginTransformFeedback) /* 453 */ \ + OP(EndQueryEXT) /* 454 */ \ + OP(EndTransformFeedback) /* 455 */ \ + OP(InsertEventMarkerEXT) /* 456 */ \ + OP(PushGroupMarkerEXT) /* 457 */ \ + OP(PopGroupMarkerEXT) /* 458 */ \ + OP(GenVertexArraysOESImmediate) /* 459 */ \ + OP(DeleteVertexArraysOESImmediate) /* 460 */ \ + OP(IsVertexArrayOES) /* 461 */ \ + OP(BindVertexArrayOES) /* 462 */ \ + OP(SwapBuffers) /* 463 */ \ + OP(GetMaxValueInBufferCHROMIUM) /* 464 */ \ + OP(EnableFeatureCHROMIUM) /* 465 */ \ + OP(ResizeCHROMIUM) /* 466 */ \ + OP(GetRequestableExtensionsCHROMIUM) /* 467 */ \ + OP(RequestExtensionCHROMIUM) /* 468 */ \ + OP(GetProgramInfoCHROMIUM) /* 469 */ \ + OP(GetTranslatedShaderSourceANGLE) /* 470 */ \ + OP(PostSubBufferCHROMIUM) /* 471 */ \ + OP(TexImageIOSurface2DCHROMIUM) /* 472 */ \ + OP(CopyTextureCHROMIUM) /* 473 */ \ + OP(DrawArraysInstancedANGLE) /* 474 */ \ + OP(DrawElementsInstancedANGLE) /* 475 */ \ + OP(VertexAttribDivisorANGLE) /* 476 */ \ + OP(GenMailboxCHROMIUM) /* 477 */ \ + OP(ProduceTextureCHROMIUMImmediate) /* 478 */ \ + OP(ProduceTextureDirectCHROMIUMImmediate) /* 479 */ \ + OP(ConsumeTextureCHROMIUMImmediate) /* 480 */ \ + OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 481 */ \ + OP(BindUniformLocationCHROMIUMBucket) /* 482 */ \ + OP(GenValuebuffersCHROMIUMImmediate) /* 483 */ \ + OP(DeleteValuebuffersCHROMIUMImmediate) /* 484 */ \ + OP(IsValuebufferCHROMIUM) /* 485 */ \ + OP(BindValuebufferCHROMIUM) /* 486 */ \ + OP(SubscribeValueCHROMIUM) /* 487 */ \ + OP(PopulateSubscribedValuesCHROMIUM) /* 488 */ \ + OP(UniformValuebufferCHROMIUM) /* 489 */ \ + OP(BindTexImage2DCHROMIUM) /* 490 */ \ + OP(ReleaseTexImage2DCHROMIUM) /* 491 */ \ + OP(TraceBeginCHROMIUM) /* 492 */ \ + OP(TraceEndCHROMIUM) /* 493 */ \ + OP(AsyncTexSubImage2DCHROMIUM) /* 494 */ \ + OP(AsyncTexImage2DCHROMIUM) /* 495 */ \ + OP(WaitAsyncTexImage2DCHROMIUM) /* 496 */ \ + OP(WaitAllAsyncTexImage2DCHROMIUM) /* 497 */ \ + OP(DiscardFramebufferEXTImmediate) /* 498 */ \ + OP(LoseContextCHROMIUM) /* 499 */ \ + OP(InsertSyncPointCHROMIUM) /* 500 */ \ + OP(WaitSyncPointCHROMIUM) /* 501 */ \ + OP(DrawBuffersEXTImmediate) /* 502 */ \ + OP(DiscardBackbufferCHROMIUM) /* 503 */ \ + OP(ScheduleOverlayPlaneCHROMIUM) /* 504 */ \ + OP(SwapInterval) /* 505 */ \ + OP(MatrixLoadfCHROMIUMImmediate) /* 506 */ \ + OP(MatrixLoadIdentityCHROMIUM) /* 507 */ \ + OP(BlendBarrierKHR) /* 508 */ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc index 0c2f493..1d31f70 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -352,6 +352,10 @@ case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_INT_24_8_OES: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return 1; default: break; @@ -359,12 +363,15 @@ switch (format) { case GL_RGB: + case GL_RGB_INTEGER: case GL_SRGB_EXT: return 3; case GL_LUMINANCE_ALPHA: case GL_RG_EXT: + case GL_RG_INTEGER: return 2; case GL_RGBA: + case GL_RGBA_INTEGER: case GL_BGRA_EXT: case GL_SRGB_ALPHA_EXT: return 4; @@ -377,6 +384,7 @@ case GL_DEPTH24_STENCIL8_OES: case GL_DEPTH_STENCIL_OES: case GL_RED_EXT: + case GL_RED_INTEGER: return 1; default: return 0; @@ -389,6 +397,10 @@ case GL_FLOAT: case GL_UNSIGNED_INT_24_8_OES: case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_2_10_10_10_REV: + case GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL_UNSIGNED_INT_5_9_9_9_REV: + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return 4; case GL_HALF_FLOAT_OES: case GL_UNSIGNED_SHORT: @@ -427,23 +439,28 @@ return true; } -// Returns the amount of data glTexImage2D or glTexSubImage2D will access. +// Returns the amount of data glTexImage*D or glTexSubImage*D will access. bool GLES2Util::ComputeImageDataSizes( - int width, int height, int format, int type, int unpack_alignment, - uint32* size, uint32* ret_unpadded_row_size, uint32* ret_padded_row_size) { + int width, int height, int depth, int format, int type, + int unpack_alignment, uint32* size, uint32* ret_unpadded_row_size, + uint32* ret_padded_row_size) { uint32 bytes_per_group = ComputeImageGroupSize(format, type); uint32 row_size; if (!SafeMultiplyUint32(width, bytes_per_group, &row_size)) { return false; } - if (height > 1) { + uint32 num_of_rows; + if (!SafeMultiplyUint32(height, depth, &num_of_rows)) { + return false; + } + if (num_of_rows > 1) { uint32 temp; if (!SafeAddUint32(row_size, unpack_alignment - 1, &temp)) { return false; } uint32 padded_row_size = (temp / unpack_alignment) * unpack_alignment; uint32 size_of_all_but_last_row; - if (!SafeMultiplyUint32((height - 1), padded_row_size, + if (!SafeMultiplyUint32((num_of_rows - 1), padded_row_size, &size_of_all_but_last_row)) { return false; } @@ -454,9 +471,7 @@ *ret_padded_row_size = padded_row_size; } } else { - if (!SafeMultiplyUint32(height, row_size, size)) { - return false; - } + *size = row_size; if (ret_padded_row_size) { *ret_padded_row_size = row_size; }
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h index 163ffc0..414e140 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.h +++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -126,8 +126,9 @@ // then the padded_row_size will be the same as the unpadded_row_size since // padding is not necessary. static bool ComputeImageDataSizes( - int width, int height, int format, int type, int unpack_alignment, - uint32_t* size, uint32_t* unpadded_row_size, uint32_t* padded_row_size); + int width, int height, int depth, int format, int type, + int unpack_alignment, uint32_t* size, uint32_t* unpadded_row_size, + uint32_t* padded_row_size); static size_t RenderbufferBytesPerPixel(int format);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h index e4ccbe7..e6a26fe 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -35,6 +35,7 @@ static std::string GetStringImageInternalFormat(uint32_t value); static std::string GetStringImageUsage(uint32_t value); static std::string GetStringIndexType(uint32_t value); +static std::string GetStringIndexedBufferTarget(uint32_t value); static std::string GetStringMatrixMode(uint32_t value); static std::string GetStringPixelStore(uint32_t value); static std::string GetStringPixelType(uint32_t value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 03a6d4d..3fafbcb 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -4789,6 +4789,15 @@ arraysize(string_table), value); } +std::string GLES2Util::GetStringIndexedBufferTarget(uint32_t value) { + static const EnumToString string_table[] = { + {GL_TRANSFORM_FEEDBACK_BUFFER, "GL_TRANSFORM_FEEDBACK_BUFFER"}, + {GL_UNIFORM_BUFFER, "GL_UNIFORM_BUFFER"}, + }; + return GLES2Util::GetQualifiedEnumString(string_table, + arraysize(string_table), value); +} + std::string GLES2Util::GetStringMatrixMode(uint32_t value) { static const EnumToString string_table[] = { {GL_PATH_PROJECTION_CHROMIUM, "GL_PATH_PROJECTION_CHROMIUM"},
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc b/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc index d0e7e03..2b1c93e 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
@@ -8,6 +8,7 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <GLES2/gl2extchromium.h> +#include <GLES3/gl3.h> #include "testing/gtest/include/gtest/gtest.h" @@ -95,54 +96,83 @@ uint32_t unpadded_row_size; uint32_t padded_row_size; EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_RGB, GL_UNSIGNED_BYTE, 1, + &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 3, size); EXPECT_EQ(kWidth * 3, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, &size, + &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 4, size); EXPECT_EQ(kWidth * 4, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, &size, + kWidth, kHeight, 1, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 1, size); EXPECT_EQ(kWidth * 1, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &size, + kWidth, kHeight, 1, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 2, size); EXPECT_EQ(kWidth * 2, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 1, &size, + kWidth, kHeight, 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 4, size); EXPECT_EQ(kWidth * 4, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_ALPHA, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_ALPHA, GL_UNSIGNED_BYTE, 1, &size, + &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 1, size); EXPECT_EQ(kWidth * 1, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 1, &size, + kWidth, kHeight, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 2, size); EXPECT_EQ(kWidth * 2, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, 1, - &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, 1, + &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 4, size); EXPECT_EQ(kWidth * 4, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, 1, + &size, &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 3, size); + EXPECT_EQ(kWidth * 3, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RG, GL_UNSIGNED_BYTE, 1, + &size, &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 2, size); + EXPECT_EQ(kWidth * 2, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RG_INTEGER, GL_UNSIGNED_BYTE, 1, + &size, &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 2, size); + EXPECT_EQ(kWidth * 2, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RED, GL_UNSIGNED_BYTE, 1, + &size, &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 1, size); + EXPECT_EQ(kWidth * 1, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 1, + &size, &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 1, size); + EXPECT_EQ(kWidth * 1, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); } TEST_F(GLES2UtilTest, ComputeImageDataSizeTypes) { @@ -152,35 +182,59 @@ uint32_t unpadded_row_size; uint32_t padded_row_size; EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, &size, + &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 4, size); EXPECT_EQ(kWidth * 4, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 1, &size, + kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 2, size); EXPECT_EQ(kWidth * 2, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 1, &size, + kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 2, size); EXPECT_EQ(kWidth * 2, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, &size, + kWidth, kHeight, 1, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 2, size); EXPECT_EQ(kWidth * 2, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 1, &size, + kWidth, kHeight, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 1, &size, &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 4, size); EXPECT_EQ(kWidth * 4, padded_row_size); EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, 1, &size, + &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 4, size); + EXPECT_EQ(kWidth * 4, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, 1, &size, + &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 4, size); + EXPECT_EQ(kWidth * 4, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_RGBA, GL_UNSIGNED_INT_5_9_9_9_REV, 1, &size, + &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 4, size); + EXPECT_EQ(kWidth * 4, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, 1, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, + 1, &size, &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * 4, size); + EXPECT_EQ(kWidth * 4, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); } TEST_F(GLES2UtilTest, ComputeImageDataSizesUnpackAlignment) { @@ -190,34 +244,70 @@ uint32_t unpadded_row_size; uint32_t padded_row_size; EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_RGB, GL_UNSIGNED_BYTE, 1, &size, + &unpadded_row_size, &padded_row_size)); EXPECT_EQ(kWidth * kHeight * 3, size); EXPECT_EQ(kWidth * 3, unpadded_row_size); EXPECT_EQ(kWidth * 3, padded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 2, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_RGB, GL_UNSIGNED_BYTE, 2, &size, + &unpadded_row_size, &padded_row_size)); EXPECT_EQ((kWidth * 3 + 1) * (kHeight - 1) + kWidth * 3, size); EXPECT_EQ(kWidth * 3, unpadded_row_size); EXPECT_EQ(kWidth * 3 + 1, padded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 4, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_RGB, GL_UNSIGNED_BYTE, 4, &size, + &unpadded_row_size, &padded_row_size)); EXPECT_EQ((kWidth * 3 + 3) * (kHeight - 1) + kWidth * 3, size); EXPECT_EQ(kWidth * 3, unpadded_row_size); EXPECT_EQ(kWidth * 3 + 3, padded_row_size); EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( - kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 8, &size, &unpadded_row_size, - &padded_row_size)); + kWidth, kHeight, 1, GL_RGB, GL_UNSIGNED_BYTE, 8, &size, + &unpadded_row_size, &padded_row_size)); EXPECT_EQ((kWidth * 3 + 7) * (kHeight - 1) + kWidth * 3, size); EXPECT_EQ(kWidth * 3, unpadded_row_size); EXPECT_EQ(kWidth * 3 + 7, padded_row_size); } +TEST_F(GLES2UtilTest, ComputeImageDataSizeDepth) { + const uint32_t kWidth = 19; + const uint32_t kHeight = 12; + const uint32_t kDepth = 3; + uint32_t size; + uint32_t unpadded_row_size; + uint32_t padded_row_size; + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, 1, &size, + &unpadded_row_size, &padded_row_size)); + EXPECT_EQ(kWidth * kHeight * kDepth * 3, size); + EXPECT_EQ(kWidth * 3, padded_row_size); + EXPECT_EQ(padded_row_size, unpadded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, 2, &size, + &unpadded_row_size, &padded_row_size)); + EXPECT_EQ((kWidth * 3 + 1) * (kHeight * kDepth - 1) + + kWidth * 3, size); + EXPECT_EQ(kWidth * 3, unpadded_row_size); + EXPECT_EQ(kWidth * 3 + 1, padded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, 4, &size, + &unpadded_row_size, &padded_row_size)); + EXPECT_EQ((kWidth * 3 + 3) * (kHeight * kDepth - 1) + + kWidth * 3, size); + EXPECT_EQ(kWidth * 3, unpadded_row_size); + EXPECT_EQ(kWidth * 3 + 3, padded_row_size); + EXPECT_TRUE(GLES2Util::ComputeImageDataSizes( + kWidth, kHeight, kDepth, GL_RGB, GL_UNSIGNED_BYTE, 8, &size, + &unpadded_row_size, &padded_row_size)); + EXPECT_EQ((kWidth * 3 + 7) * (kHeight * kDepth - 1) + + kWidth * 3, size); + EXPECT_EQ(kWidth * 3, unpadded_row_size); + EXPECT_EQ(kWidth * 3 + 7, padded_row_size); +} + TEST_F(GLES2UtilTest, RenderbufferBytesPerPixel) { EXPECT_EQ(1u, GLES2Util::RenderbufferBytesPerPixel(GL_STENCIL_INDEX8)); EXPECT_EQ(2u, GLES2Util::RenderbufferBytesPerPixel(GL_RGBA4));
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h index 1e56829..63e9a34 100644 --- a/gpu/command_buffer/service/context_group.h +++ b/gpu/command_buffer/service/context_group.h
@@ -177,6 +177,24 @@ draw_buffer_ = buf; } + void AddBufferId(GLuint client_id, GLuint service_id) { + buffers_id_map_[client_id] = service_id; + } + + bool GetBufferServiceId(GLuint client_id, GLuint* service_id) const { + std::map<GLuint, GLuint>::const_iterator iter = + buffers_id_map_.find(client_id); + if (iter == buffers_id_map_.end()) + return false; + if (service_id) + *service_id = iter->second; + return true; + } + + void RemoveBufferId(GLuint client_id) { + buffers_id_map_.erase(client_id); + } + void AddSamplerId(GLuint client_id, GLuint service_id) { samplers_id_map_[client_id] = service_id; } @@ -265,6 +283,7 @@ std::vector<base::WeakPtr<gles2::GLES2Decoder> > decoders_; // Mappings from client side IDs to service side IDs. + std::map<GLuint, GLuint> buffers_id_map_; std::map<GLuint, GLuint> samplers_id_map_; std::map<GLuint, GLuint> transformfeedbacks_id_map_;
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc index 45eeb80..4a9aaa7 100644 --- a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc +++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
@@ -37,7 +37,7 @@ void CompileShader(GLuint shader, const char* shader_source) { glShaderSource(shader, 1, &shader_source, 0); glCompileShader(shader); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() GLint compile_status = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); if (GL_TRUE != compile_status) { @@ -119,7 +119,7 @@ glAttachShader(program_, fragment_shader); glBindAttribLocation(program_, kVertexPositionAttrib, "a_position"); glLinkProgram(program_); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() GLint linked = GL_FALSE; glGetProgramiv(program_, GL_LINK_STATUS, &linked); if (GL_TRUE != linked) @@ -132,7 +132,7 @@ } glUseProgram(program_); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() glValidateProgram(program_); GLint validation_status = GL_FALSE; glGetProgramiv(program_, GL_VALIDATE_STATUS, &validation_status);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 7f9166e..0870c36 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2129,7 +2129,7 @@ ScopedTextureBinder binder(state_, id_, GL_TEXTURE_2D); uint32 image_size = 0; GLES2Util::ComputeImageDataSizes( - size.width(), size.height(), format, GL_UNSIGNED_BYTE, 8, &image_size, + size.width(), size.height(), 1, format, GL_UNSIGNED_BYTE, 8, &image_size, NULL, NULL); if (!memory_tracker_.EnsureGPUMemoryAvailable(image_size)) { @@ -7682,7 +7682,7 @@ } } GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.pack_alignment, &pixels_size, + width, height, 1, format, type, state_.pack_alignment, &pixels_size, NULL, NULL); void* pixels = GetSharedMemoryAs<void*>( c.pixels_shm_id, c.pixels_shm_offset, pixels_size); @@ -7729,7 +7729,7 @@ uint32 unpadded_row_size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, 2, format, type, state_.pack_alignment, &temp_size, + width, 2, 1, format, type, state_.pack_alignment, &temp_size, &unpadded_row_size, &padded_row_size)) { return; } @@ -7792,7 +7792,7 @@ typedef cmds::ReadPixels::Result Result; uint32 pixels_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.pack_alignment, &pixels_size, + width, height, 1, format, type, state_.pack_alignment, &pixels_size, NULL, NULL)) { return error::kOutOfBounds; } @@ -7868,7 +7868,7 @@ uint32 unpadded_row_size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, 2, format, type, state_.pack_alignment, &temp_size, + width, 2, 1, format, type, state_.pack_alignment, &temp_size, &unpadded_row_size, &padded_row_size)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glReadPixels", "dimensions out of range"); @@ -7878,8 +7878,8 @@ GLint dest_x_offset = std::max(-x, 0); uint32 dest_row_offset; if (!GLES2Util::ComputeImageDataSizes( - dest_x_offset, 1, format, type, state_.pack_alignment, &dest_row_offset, - NULL, NULL)) { + dest_x_offset, 1, 1, format, type, state_.pack_alignment, + &dest_row_offset, NULL, NULL)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glReadPixels", "dimensions out of range"); return error::kNoError; @@ -8321,7 +8321,7 @@ uint32 size; uint32 padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &size, + width, height, 1, format, type, state_.unpack_alignment, &size, NULL, &padded_row_size)) { return false; } @@ -8339,7 +8339,7 @@ DCHECK_GT(padded_row_size, 0U); tile_height = kMaxZeroSize / padded_row_size; if (!GLES2Util::ComputeImageDataSizes( - width, tile_height, format, type, state_.unpack_alignment, &size, + width, tile_height, 1, format, type, state_.unpack_alignment, &size, NULL, NULL)) { return false; } @@ -8775,8 +8775,8 @@ uint32 pixels_shm_offset = static_cast<uint32>(c.pixels_shm_offset); uint32 pixels_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &pixels_size, NULL, - NULL)) { + width, height, 1, format, type, state_.unpack_alignment, &pixels_size, + NULL, NULL)) { return error::kOutOfBounds; } const void* pixels = NULL; @@ -8800,6 +8800,51 @@ return error::kNoError; } +error::Error GLES2DecoderImpl::HandleTexImage3D(uint32 immediate_data_size, + const void* cmd_data) { + // TODO(zmo): Unsafe ES3 API. + if (!unsafe_es3_apis_enabled()) + return error::kUnknownCommand; + + const gles2::cmds::TexImage3D& c = + *static_cast<const gles2::cmds::TexImage3D*>(cmd_data); + TRACE_EVENT2("gpu", "GLES2DecoderImpl::HandleTexImage3D", + "widthXheight", c.width * c.height, "depth", c.depth); + GLenum target = static_cast<GLenum>(c.target); + GLint level = static_cast<GLint>(c.level); + GLenum internal_format = static_cast<GLenum>(c.internalformat); + GLsizei width = static_cast<GLsizei>(c.width); + GLsizei height = static_cast<GLsizei>(c.height); + GLsizei depth = static_cast<GLsizei>(c.depth); + GLint border = static_cast<GLint>(c.border); + GLenum format = static_cast<GLenum>(c.format); + GLenum type = static_cast<GLenum>(c.type); + uint32 pixels_shm_id = static_cast<uint32>(c.pixels_shm_id); + uint32 pixels_shm_offset = static_cast<uint32>(c.pixels_shm_offset); + uint32 pixels_size; + if (!GLES2Util::ComputeImageDataSizes( + width, height, depth, format, type, state_.unpack_alignment, &pixels_size, + NULL, NULL)) { + return error::kOutOfBounds; + } + const void* pixels = NULL; + if (pixels_shm_id != 0 || pixels_shm_offset != 0) { + pixels = GetSharedMemoryAs<const void*>( + pixels_shm_id, pixels_shm_offset, pixels_size); + if (!pixels) { + return error::kOutOfBounds; + } + } + + glTexImage3D(target, level, internal_format, width, height, depth, border, + format, type, pixels); + + // This may be a slow command. Exit command processing to allow for + // context preemption and GPU watchdog checks. + ExitCommandProcessingEarly(); + return error::kNoError; +} + void GLES2DecoderImpl::DoCompressedTexSubImage2D( GLenum target, GLint level, @@ -8934,8 +8979,8 @@ uint32 estimated_size = 0; if (!GLES2Util::ComputeImageDataSizes( - width, height, internal_format, GL_UNSIGNED_BYTE, state_.unpack_alignment, - &estimated_size, NULL, NULL)) { + width, height, 1, internal_format, GL_UNSIGNED_BYTE, + state_.unpack_alignment, &estimated_size, NULL, NULL)) { LOCAL_SET_GL_ERROR( GL_OUT_OF_MEMORY, "glCopyTexImage2D", "dimensions too large"); return; @@ -9108,7 +9153,7 @@ // some part was clipped so clear the sub rect. uint32 pixels_size = 0; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &pixels_size, + width, height, 1, format, type, state_.unpack_alignment, &pixels_size, NULL, NULL)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glCopyTexSubImage2D", "dimensions too large"); @@ -9293,7 +9338,7 @@ GLenum type = static_cast<GLenum>(c.type); uint32 data_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &data_size, + width, height, 1, format, type, state_.unpack_alignment, &data_size, NULL, NULL)) { return error::kOutOfBounds; } @@ -9303,6 +9348,48 @@ target, level, xoffset, yoffset, width, height, format, type, pixels); } +// TODO(zmo): Remove the below stub once we add the real function binding. +// Currently it's missing due to a gmock limitation. +static void glTexSubImage3D( + GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei height, GLsizei width, GLsizei depth, GLenum format, GLenum type, + const void* pixels) { + NOTIMPLEMENTED(); +} + +error::Error GLES2DecoderImpl::HandleTexSubImage3D(uint32 immediate_data_size, + const void* cmd_data) { + // TODO(zmo): Unsafe ES3 API. + if (!unsafe_es3_apis_enabled()) + return error::kUnknownCommand; + + const gles2::cmds::TexSubImage3D& c = + *static_cast<const gles2::cmds::TexSubImage3D*>(cmd_data); + TRACE_EVENT2("gpu", "GLES2DecoderImpl::HandleTexSubImage3D", + "widthXheight", c.width * c.height, "depth", c.depth); + GLenum target = static_cast<GLenum>(c.target); + GLint level = static_cast<GLint>(c.level); + GLint xoffset = static_cast<GLint>(c.xoffset); + GLint yoffset = static_cast<GLint>(c.yoffset); + GLint zoffset = static_cast<GLint>(c.zoffset); + GLsizei width = static_cast<GLsizei>(c.width); + GLsizei height = static_cast<GLsizei>(c.height); + GLsizei depth = static_cast<GLsizei>(c.depth); + GLenum format = static_cast<GLenum>(c.format); + GLenum type = static_cast<GLenum>(c.type); + uint32 data_size; + if (!GLES2Util::ComputeImageDataSizes( + width, height, depth, format, type, state_.unpack_alignment, &data_size, + NULL, NULL)) { + return error::kOutOfBounds; + } + const void* pixels = GetSharedMemoryAs<const void*>( + c.pixels_shm_id, c.pixels_shm_offset, data_size); + glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, + depth, format, type, pixels); + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleGetVertexAttribPointerv( uint32 immediate_data_size, const void* cmd_data) { @@ -10702,7 +10789,7 @@ for (int ii = 0; ii < levels; ++ii) { uint32 level_size = 0; if (!GLES2Util::ComputeImageDataSizes( - level_width, level_height, format, type, state_.unpack_alignment, + level_width, level_height, 1, format, type, state_.unpack_alignment, &estimated_size, NULL, NULL) || !SafeAddUint32(estimated_size, level_size, &estimated_size)) { LOCAL_SET_GL_ERROR( @@ -11317,8 +11404,8 @@ // TODO(epenner): Move this and copies of this memory validation // into ValidateTexImage2D step. if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &pixels_size, NULL, - NULL)) { + width, height, 1, format, type, state_.unpack_alignment, &pixels_size, + NULL, NULL)) { return error::kOutOfBounds; } const void* pixels = NULL; @@ -11422,7 +11509,7 @@ // into ValidateTexSubImage2D step. uint32 data_size; if (!GLES2Util::ComputeImageDataSizes( - width, height, format, type, state_.unpack_alignment, &data_size, + width, height, 1, format, type, state_.unpack_alignment, &data_size, NULL, NULL)) { return error::kOutOfBounds; }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index b7877ff..82a519b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -48,6 +48,22 @@ return error::kNoError; } +error::Error GLES2DecoderImpl::HandleBindBufferBase( + uint32_t immediate_data_size, + const void* cmd_data) { + if (!unsafe_es3_apis_enabled()) + return error::kUnknownCommand; + const gles2::cmds::BindBufferBase& c = + *static_cast<const gles2::cmds::BindBufferBase*>(cmd_data); + (void)c; + GLenum target = static_cast<GLenum>(c.target); + GLuint index = static_cast<GLuint>(c.index); + GLuint buffer = c.buffer; + group_->GetBufferServiceId(buffer, &buffer); + glBindBufferBase(target, index, buffer); + return error::kNoError; +} + error::Error GLES2DecoderImpl::HandleBindFramebuffer( uint32_t immediate_data_size, const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 390107f..8794e42 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -455,7 +455,7 @@ EXPECT_CALL(*gl, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) .WillOnce(Return(kGlSync)) .RetiresOnSaturation(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl, IsSync(kGlSync)) .WillOnce(Return(GL_TRUE)) .RetiresOnSaturation(); @@ -476,7 +476,7 @@ .RetiresOnSaturation(); } if (query_type.type == GL_COMMANDS_COMPLETED_CHROMIUM) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl, IsSync(kGlSync)) .WillOnce(Return(GL_TRUE)) .RetiresOnSaturation(); @@ -497,7 +497,7 @@ EXPECT_CALL(*gl, DeleteQueriesARB(1, _)).Times(1).RetiresOnSaturation(); } if (query_type.type == GL_COMMANDS_COMPLETED_CHROMIUM) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl, IsSync(kGlSync)) .WillOnce(Return(GL_TRUE)) .RetiresOnSaturation(); @@ -629,7 +629,7 @@ EXPECT_CALL(*gl_, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) .WillOnce(Return(kGlSync)) .RetiresOnSaturation(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl_, IsSync(kGlSync)) .WillOnce(Return(GL_TRUE)) .RetiresOnSaturation(); @@ -641,7 +641,7 @@ EXPECT_EQ(GL_NO_ERROR, GetGLError()); EXPECT_TRUE(query->pending()); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl_, IsSync(kGlSync)) .WillOnce(Return(GL_TRUE)) .RetiresOnSaturation(); @@ -654,7 +654,7 @@ EXPECT_TRUE(process_success); EXPECT_TRUE(query->pending()); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl_, IsSync(kGlSync)) .WillOnce(Return(GL_TRUE)) .RetiresOnSaturation(); @@ -667,7 +667,7 @@ EXPECT_TRUE(process_success); EXPECT_FALSE(query->pending()); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl_, IsSync(kGlSync)) .WillOnce(Return(GL_TRUE)) .RetiresOnSaturation();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc index db1c62f..2e7f4fc 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
@@ -41,6 +41,15 @@ INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderTest1, ::testing::Bool()); template <> +void GLES2DecoderTestBase::SpecializedSetup<cmds::BindBufferBase, 0>( + bool valid) { + if (valid) { + // TODO(zmo): This might affect the states of later tests. + group_->AddBufferId(client_buffer_id_, kServiceBufferId); + } +}; + +template <> void GLES2DecoderTestBase::SpecializedSetup<cmds::GenerateMipmap, 0>( bool valid) { DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h index 2bc23a0..6ab1a88 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -54,6 +54,19 @@ EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); } +TEST_P(GLES2DecoderTest1, BindBufferBaseValidArgs) { + EXPECT_CALL( + *gl_, BindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 2, kServiceBufferId)); + SpecializedSetup<cmds::BindBufferBase, 0>(true); + cmds::BindBufferBase cmd; + cmd.Init(GL_TRANSFORM_FEEDBACK_BUFFER, 2, client_buffer_id_); + decoder_->set_unsafe_es3_apis_enabled(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + decoder_->set_unsafe_es3_apis_enabled(false); + EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); +} + TEST_P(GLES2DecoderTest1, BindFramebufferValidArgs) { EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER, kServiceFramebufferId)); SpecializedSetup<cmds::BindFramebuffer, 0>(true); @@ -1910,39 +1923,4 @@ cmd.Init(client_buffer_id_, shared_memory_id_, kInvalidSharedMemoryOffset); EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); } - -TEST_P(GLES2DecoderTest1, IsEnabledValidArgs) { - SpecializedSetup<cmds::IsEnabled, 0>(true); - cmds::IsEnabled cmd; - cmd.Init(GL_BLEND, shared_memory_id_, shared_memory_offset_); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); -} - -TEST_P(GLES2DecoderTest1, IsEnabledInvalidArgs0_0) { - EXPECT_CALL(*gl_, IsEnabled(_)).Times(0); - SpecializedSetup<cmds::IsEnabled, 0>(false); - cmds::IsEnabled cmd; - cmd.Init(GL_CLIP_PLANE0, shared_memory_id_, shared_memory_offset_); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); -} - -TEST_P(GLES2DecoderTest1, IsEnabledInvalidArgs0_1) { - EXPECT_CALL(*gl_, IsEnabled(_)).Times(0); - SpecializedSetup<cmds::IsEnabled, 0>(false); - cmds::IsEnabled cmd; - cmd.Init(GL_POINT_SPRITE, shared_memory_id_, shared_memory_offset_); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); -} - -TEST_P(GLES2DecoderTest1, IsEnabledInvalidArgsBadSharedMemoryId) { - SpecializedSetup<cmds::IsEnabled, 0>(false); - cmds::IsEnabled cmd; - cmd.Init(GL_BLEND, kInvalidSharedMemoryId, shared_memory_offset_); - EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); - cmd.Init(GL_BLEND, shared_memory_id_, kInvalidSharedMemoryOffset); - EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); -} #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h index 6f8b706..59cf54e 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -12,6 +12,41 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_ #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_ +TEST_P(GLES2DecoderTest2, IsEnabledValidArgs) { + SpecializedSetup<cmds::IsEnabled, 0>(true); + cmds::IsEnabled cmd; + cmd.Init(GL_BLEND, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_P(GLES2DecoderTest2, IsEnabledInvalidArgs0_0) { + EXPECT_CALL(*gl_, IsEnabled(_)).Times(0); + SpecializedSetup<cmds::IsEnabled, 0>(false); + cmds::IsEnabled cmd; + cmd.Init(GL_CLIP_PLANE0, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); +} + +TEST_P(GLES2DecoderTest2, IsEnabledInvalidArgs0_1) { + EXPECT_CALL(*gl_, IsEnabled(_)).Times(0); + SpecializedSetup<cmds::IsEnabled, 0>(false); + cmds::IsEnabled cmd; + cmd.Init(GL_POINT_SPRITE, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_INVALID_ENUM, GetGLError()); +} + +TEST_P(GLES2DecoderTest2, IsEnabledInvalidArgsBadSharedMemoryId) { + SpecializedSetup<cmds::IsEnabled, 0>(false); + cmds::IsEnabled cmd; + cmd.Init(GL_BLEND, kInvalidSharedMemoryId, shared_memory_offset_); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); + cmd.Init(GL_BLEND, shared_memory_id_, kInvalidSharedMemoryOffset); + EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); +} + TEST_P(GLES2DecoderTest2, IsFramebufferValidArgs) { SpecializedSetup<cmds::IsFramebuffer, 0>(true); cmds::IsFramebuffer cmd; @@ -424,6 +459,8 @@ } // TODO(gman): TexImage2D +// TODO(gman): TexImage3D + TEST_P(GLES2DecoderTest2, TexParameterfValidArgs) { EXPECT_CALL(*gl_, TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); @@ -632,6 +669,8 @@ } // TODO(gman): TexSubImage2D +// TODO(gman): TexSubImage3D + TEST_P(GLES2DecoderTest2, Uniform1fValidArgs) { EXPECT_CALL(*gl_, Uniform1fv(1, 1, _)); SpecializedSetup<cmds::Uniform1f, 0>(true); @@ -1277,19 +1316,4 @@ // TODO(gman): TexStorage2DEXT // TODO(gman): GenQueriesEXTImmediate // TODO(gman): DeleteQueriesEXTImmediate -// TODO(gman): BeginQueryEXT - -TEST_P(GLES2DecoderTest2, BeginTransformFeedbackValidArgs) { - EXPECT_CALL(*gl_, BeginTransformFeedback(GL_POINTS)); - SpecializedSetup<cmds::BeginTransformFeedback, 0>(true); - cmds::BeginTransformFeedback cmd; - cmd.Init(GL_POINTS); - decoder_->set_unsafe_es3_apis_enabled(true); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); - decoder_->set_unsafe_es3_apis_enabled(false); - EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); -} -// TODO(gman): EndQueryEXT - #endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h index 506e045..e1685cd 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -12,6 +12,21 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_ +// TODO(gman): BeginQueryEXT + +TEST_P(GLES2DecoderTest3, BeginTransformFeedbackValidArgs) { + EXPECT_CALL(*gl_, BeginTransformFeedback(GL_POINTS)); + SpecializedSetup<cmds::BeginTransformFeedback, 0>(true); + cmds::BeginTransformFeedback cmd; + cmd.Init(GL_POINTS); + decoder_->set_unsafe_es3_apis_enabled(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + decoder_->set_unsafe_es3_apis_enabled(false); + EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); +} +// TODO(gman): EndQueryEXT + TEST_P(GLES2DecoderTest3, EndTransformFeedbackValidArgs) { EXPECT_CALL(*gl_, EndTransformFeedback()); SpecializedSetup<cmds::EndTransformFeedback, 0>(true);
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h index fc650d2..5692847 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -35,6 +35,7 @@ ValueValidator<GLenum> image_internal_format; ValueValidator<GLenum> image_usage; ValueValidator<GLenum> index_type; +ValueValidator<GLenum> indexed_buffer_target; ValueValidator<GLenum> matrix_mode; ValueValidator<GLenum> pixel_store; ValueValidator<GLint> pixel_store_alignment;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h index a1e5c74..d81b896 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -252,6 +252,11 @@ GL_UNSIGNED_SHORT, }; +static const GLenum valid_indexed_buffer_target_table[] = { + GL_TRANSFORM_FEEDBACK_BUFFER, + GL_UNIFORM_BUFFER, +}; + static const GLenum valid_matrix_mode_table[] = { GL_PATH_PROJECTION_CHROMIUM, GL_PATH_MODELVIEW_CHROMIUM, @@ -593,6 +598,8 @@ arraysize(valid_image_internal_format_table)), image_usage(valid_image_usage_table, arraysize(valid_image_usage_table)), index_type(valid_index_type_table, arraysize(valid_index_type_table)), + indexed_buffer_target(valid_indexed_buffer_target_table, + arraysize(valid_indexed_buffer_target_table)), matrix_mode(valid_matrix_mode_table, arraysize(valid_matrix_mode_table)), pixel_store(valid_pixel_store_table, arraysize(valid_pixel_store_table)), pixel_store_alignment(valid_pixel_store_alignment_table,
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index f0deec2..550e0cd 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc
@@ -411,7 +411,7 @@ EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[0])) .Times(1) .RetiresOnSaturation(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl, GetError()) .WillOnce(Return(GL_NO_ERROR)) .RetiresOnSaturation(); @@ -475,7 +475,7 @@ EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[0])) .Times(1) .RetiresOnSaturation(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() EXPECT_CALL(*gl, GetError()) .WillOnce(Return(GL_NO_ERROR)) .RetiresOnSaturation();
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 829d4e0..b914f6d 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -626,7 +626,7 @@ estimated_size_ -= info.estimated_size; GLES2Util::ComputeImageDataSizes( - width, height, format, type, 4, &info.estimated_size, NULL, NULL); + width, height, 1, format, type, 4, &info.estimated_size, NULL, NULL); estimated_size_ += info.estimated_size; UpdateMipCleared(&info, cleared);
diff --git a/gpu/tools/compositor_model_bench/compositor_model_bench.cc b/gpu/tools/compositor_model_bench/compositor_model_bench.cc index 8042392..1160ff7 100644 --- a/gpu/tools/compositor_model_bench/compositor_model_bench.cc +++ b/gpu/tools/compositor_model_bench/compositor_model_bench.cc
@@ -86,7 +86,7 @@ // If the name of the file wasn't ASCII, this will give an empty simulation // name, but that's not really harmful (we'll still warn about it though.) spec.simulation_name = path.BaseName().RemoveExtension().MaybeAsASCII(); - if (spec.simulation_name == "") { + if (spec.simulation_name.empty()) { LOG(WARNING) << "Simulation for path " << path.LossyDisplayName() << " will have a blank simulation name, since the file name isn't ASCII"; }
diff --git a/mojo/edk/system/transport_data.cc b/mojo/edk/system/transport_data.cc index 300b731..c80a98a 100644 --- a/mojo/edk/system/transport_data.cc +++ b/mojo/edk/system/transport_data.cc
@@ -78,7 +78,7 @@ // It must be at least as big as the (eventual) actual size. size_t estimated_size = serialized_dispatcher_start_offset; size_t estimated_num_platform_handles = 0; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() std::vector<size_t> all_max_sizes(num_handles); std::vector<size_t> all_max_platform_handles(num_handles); #endif @@ -97,7 +97,7 @@ estimated_num_platform_handles += max_platform_handles; DCHECK_LE(estimated_num_platform_handles, GetMaxPlatformHandles()); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() all_max_sizes[i] = max_size; all_max_platform_handles[i] = max_platform_handles; #endif @@ -141,7 +141,7 @@ continue; } -#if DCHECK_IS_ON +#if DCHECK_IS_ON() size_t old_platform_handles_size = platform_handles_ ? platform_handles_->size() : 0; #endif @@ -156,7 +156,7 @@ handle_table[i].size = static_cast<uint32_t>(actual_size); // (Okay to not set |unused| since we cleared the entire buffer.) -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK_LE(actual_size, all_max_sizes[i]); DCHECK_LE(platform_handles_ ? (platform_handles_->size() - old_platform_handles_size)
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 87063b7..f151b3c 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h
@@ -618,6 +618,12 @@ // Proxy Auth Requested without a valid Client Socket Handle. NET_ERROR(PROXY_AUTH_REQUESTED_WITH_NO_CONNECTION, -364) +// HTTP_1_1_REQUIRED error code received on HTTP/2 session. +NET_ERROR(HTTP_1_1_REQUIRED, -365) + +// HTTP_1_1_REQUIRED error code received on HTTP/2 session to proxy. +NET_ERROR(PROXY_HTTP_1_1_REQUIRED, -366) + // The cache does not have the requested entry. NET_ERROR(CACHE_MISS, -400)
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc index 7429149..05787f3 100644 --- a/net/base/sdch_manager.cc +++ b/net/base/sdch_manager.cc
@@ -39,17 +39,6 @@ namespace net { -// Adjust SDCH limits downwards for mobile. -#if defined(OS_ANDROID) || defined(OS_IOS) -// static -const size_t SdchManager::kMaxDictionaryCount = 1; -const size_t SdchManager::kMaxDictionarySize = 500 * 1000; -#else -// static -const size_t SdchManager::kMaxDictionaryCount = 20; -const size_t SdchManager::kMaxDictionarySize = 1000 * 1000; -#endif - // Workaround for http://crbug.com/437794; remove when fixed. #if defined(OS_IOS) // static @@ -65,6 +54,7 @@ SdchManager::Dictionary::Dictionary(const std::string& dictionary_text, size_t offset, const std::string& client_hash, + const std::string& server_hash, const GURL& gurl, const std::string& domain, const std::string& path, @@ -72,6 +62,7 @@ const std::set<int>& ports) : text_(dictionary_text, offset), client_hash_(client_hash), + server_hash_(server_hash), url_(gurl), domain_(domain), path_(path), @@ -83,12 +74,14 @@ SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& rhs) : text_(rhs.text_), client_hash_(rhs.client_hash_), + server_hash_(rhs.server_hash_), url_(rhs.url_), domain_(rhs.domain_), path_(rhs.path_), expiration_(rhs.expiration_), ports_(rhs.ports_), - clock_(new base::DefaultClock) {} + clock_(new base::DefaultClock) { +} SdchManager::Dictionary::~Dictionary() {} @@ -271,13 +264,7 @@ void SdchManager::ClearData() { blacklisted_domains_.clear(); allow_latency_experiment_.clear(); - - // Note that this may result in not having dictionaries we've advertised - // for incoming responses. The window is relatively small (as ClearData() - // is not expected to be called frequently), so we rely on meta-refresh - // to handle this case. dictionaries_.clear(); - FOR_EACH_OBSERVER(SdchObserver, observers_, OnClearDictionaries(this)); } @@ -400,6 +387,11 @@ return SDCH_OK; } +void SdchManager::OnDictionaryUsed(const std::string& server_hash) { + FOR_EACH_OBSERVER(SdchObserver, observers_, + OnDictionaryUsed(this, server_hash)); +} + SdchProblemCode SdchManager::CanFetchDictionary( const GURL& referring_url, const GURL& dictionary_url) const { @@ -521,7 +513,8 @@ SdchProblemCode SdchManager::AddSdchDictionary( const std::string& dictionary_text, - const GURL& dictionary_url) { + const GURL& dictionary_url, + std::string* server_hash_p) { DCHECK(thread_checker_.CalledOnValidThread()); std::string client_hash; std::string server_hash; @@ -598,28 +591,29 @@ if (rv != SDCH_OK) return rv; - // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of - // useless dictionaries. We should probably have a cache eviction plan, - // instead of just blocking additions. For now, with the spec in flux, it - // is probably not worth doing eviction handling. - if (kMaxDictionarySize < dictionary_text.size()) - return SDCH_DICTIONARY_IS_TOO_LARGE; - - if (kMaxDictionaryCount <= dictionaries_.size()) - return SDCH_DICTIONARY_COUNT_EXCEEDED; - UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size()); DVLOG(1) << "Loaded dictionary with client hash " << client_hash << " and server hash " << server_hash; Dictionary dictionary(dictionary_text, header_end + 2, client_hash, - dictionary_url_normalized, domain, path, expiration, - ports); + server_hash, dictionary_url_normalized, domain, path, + expiration, ports); dictionaries_[server_hash] = new base::RefCountedData<Dictionary>(dictionary); + if (server_hash_p) + *server_hash_p = server_hash; return SDCH_OK; } +SdchProblemCode SdchManager::RemoveSdchDictionary( + const std::string& server_hash) { + if (dictionaries_.find(server_hash) == dictionaries_.end()) + return SDCH_DICTIONARY_HASH_NOT_FOUND; + + dictionaries_.erase(server_hash); + return SDCH_OK; +} + // static scoped_ptr<SdchManager::DictionarySet> SdchManager::CreateEmptyDictionarySetForTesting() {
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h index 0948b4c..c83d3a4 100644 --- a/net/base/sdch_manager.h +++ b/net/base/sdch_manager.h
@@ -59,11 +59,6 @@ typedef std::map<std::string, scoped_refptr<base::RefCountedData<Dictionary>>> DictionaryMap; - // Use the following static limits to block DOS attacks until we implement - // a cached dictionary evicition strategy. - static const size_t kMaxDictionarySize; - static const size_t kMaxDictionaryCount; - class NET_EXPORT_PRIVATE Dictionary { public: // Construct a vc-diff usable dictionary from the dictionary_text starting @@ -72,6 +67,7 @@ Dictionary(const std::string& dictionary_text, size_t offset, const std::string& client_hash, + const std::string& server_hash, const GURL& url, const std::string& domain, const std::string& path, @@ -85,6 +81,7 @@ const GURL& url() const { return url_; } const std::string& client_hash() const { return client_hash_; } + const std::string& server_hash() const { return server_hash_; } const std::string& domain() const { return domain_; } const std::string& path() const { return path_; } const base::Time& expiration() const { return expiration_; } @@ -128,6 +125,10 @@ // it has a specific dictionary pre-cached. std::string client_hash_; + // Part of the hash of text_ that the server uses to identify the + // dictionary it wants used for decoding. + std::string server_hash_; + // The GURL that arrived with the text_ in a URL request to specify where // this dictionary may be used. const GURL url_; @@ -233,6 +234,10 @@ SdchProblemCode OnGetDictionary(const GURL& request_url, const GURL& dictionary_url); + // Send out appropriate events notifying observers that a dictionary + // was successfully used to decode a request. + void OnDictionaryUsed(const std::string& server_hash); + // Get a handle to the available dictionaries that might be used // for encoding responses for the given URL. The return set will not // include expired dictionaries. If no dictionaries @@ -270,10 +275,16 @@ // dictionaries. This addition will fail if addition is illegal // (data in the dictionary is not acceptable from the // dictionary_url; dictionary already added, etc.). + // If |server_hash| is non-null, returns the server hash that may be + // used as an argument to GetDictionarySetByHash. // Returns SDCH_OK if the addition was successfull, and corresponding error // code otherwise. SdchProblemCode AddSdchDictionary(const std::string& dictionary_text, - const GURL& dictionary_url); + const GURL& dictionary_url, + std::string* server_hash_p); + + // Remove an SDCH dictionary + SdchProblemCode RemoveSdchDictionary(const std::string& server_hash); // Registration for events generated by the SDCH subsystem. void AddObserver(SdchObserver* observer);
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc index 3587084..d2baa4b 100644 --- a/net/base/sdch_manager_unittest.cc +++ b/net/base/sdch_manager_unittest.cc
@@ -31,15 +31,34 @@ class MockSdchObserver : public SdchObserver { public: - MockSdchObserver() : get_dictionary_notifications_(0) {} + MockSdchObserver() + : dictionary_used_notifications_(0), + get_dictionary_notifications_(0), + clear_dictionaries_notifications_(0) {} - const GURL& last_dictionary_request_url() { + std::string last_server_hash() const { return last_server_hash_; } + int dictionary_used_notifications() const { + return dictionary_used_notifications_; + } + const GURL& last_dictionary_request_url() const { return last_dictionary_request_url_; } - const GURL& last_dictionary_url() { return last_dictionary_url_; } - int get_dictionary_notifications() { return get_dictionary_notifications_; } + const GURL& last_dictionary_url() const { return last_dictionary_url_; } + int get_dictionary_notifications() const { + return get_dictionary_notifications_; + } + + int clear_dictionary_notifications() const { + return clear_dictionaries_notifications_; + } // SdchObserver implementation + void OnDictionaryUsed(SdchManager* manager, + const std::string& server_hash) override { + last_server_hash_ = server_hash; + ++dictionary_used_notifications_; + } + void OnGetDictionary(SdchManager* manager, const GURL& request_url, const GURL& dictionary_url) override { @@ -47,12 +66,20 @@ last_dictionary_request_url_ = request_url; last_dictionary_url_ = dictionary_url; } - void OnClearDictionaries(SdchManager* manager) override {} + void OnClearDictionaries(SdchManager* manager) override { + ++clear_dictionaries_notifications_; + } private: + int dictionary_used_notifications_; int get_dictionary_notifications_; + int clear_dictionaries_notifications_; + + std::string last_server_hash_; GURL last_dictionary_request_url_; GURL last_dictionary_url_; + + DISALLOW_COPY_AND_ASSIGN(MockSdchObserver); }; class SdchManagerTest : public testing::Test { @@ -79,7 +106,8 @@ // failure. bool AddSdchDictionary(const std::string& dictionary_text, const GURL& gurl) { - return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK; + return sdch_manager_->AddSdchDictionary(dictionary_text, gurl, nullptr) == + SDCH_OK; } private: @@ -394,40 +422,6 @@ GURL("http://" + dictionary_domain))); } -// Make sure the DOS protection precludes the addition of too many dictionaries. -TEST_F(SdchManagerTest, TooManyDictionaries) { - std::string dictionary_domain(".google.com"); - std::string dictionary_text(NewSdchDictionary(dictionary_domain)); - - for (size_t count = 0; count < SdchManager::kMaxDictionaryCount; ++count) { - EXPECT_TRUE(AddSdchDictionary(dictionary_text, - GURL("http://www.google.com"))); - dictionary_text += " "; // Create dictionary with different SHA signature. - } - EXPECT_FALSE( - AddSdchDictionary(dictionary_text, GURL("http://www.google.com"))); -} - -TEST_F(SdchManagerTest, DictionaryNotTooLarge) { - std::string dictionary_domain(".google.com"); - std::string dictionary_text(NewSdchDictionary(dictionary_domain)); - - dictionary_text.append( - SdchManager::kMaxDictionarySize - dictionary_text.size(), ' '); - EXPECT_TRUE(AddSdchDictionary(dictionary_text, - GURL("http://" + dictionary_domain))); -} - -TEST_F(SdchManagerTest, DictionaryTooLarge) { - std::string dictionary_domain(".google.com"); - std::string dictionary_text(NewSdchDictionary(dictionary_domain)); - - dictionary_text.append( - SdchManager::kMaxDictionarySize + 1 - dictionary_text.size(), ' '); - EXPECT_FALSE(AddSdchDictionary(dictionary_text, - GURL("http://" + dictionary_domain))); -} - TEST_F(SdchManagerTest, PathMatch) { bool (*PathMatch)(const std::string& path, const std::string& restriction) = SdchManager::Dictionary::PathMatch; @@ -528,7 +522,7 @@ EXPECT_EQ(SDCH_OK, problem_code); second_manager.AddSdchDictionary( - dictionary_text_2, GURL("http://" + dictionary_domain_2)); + dictionary_text_2, GURL("http://" + dictionary_domain_2), nullptr); dict_set = second_manager.GetDictionarySetByHash( GURL("http://" + dictionary_domain_2 + "/random_url"), server_hash_2, &problem_code); @@ -666,6 +660,38 @@ EXPECT_EQ(SDCH_DISABLED, sdch_manager->IsInSupportedDomain(google_url)); } +// Confirm dispatch of notification. +TEST_F(SdchManagerTest, SdchDictionaryUsed) { + MockSdchObserver observer; + sdch_manager()->AddObserver(&observer); + + EXPECT_EQ(0, observer.dictionary_used_notifications()); + sdch_manager()->OnDictionaryUsed("xyzzy"); + EXPECT_EQ(1, observer.dictionary_used_notifications()); + EXPECT_EQ("xyzzy", observer.last_server_hash()); + + std::string dictionary_domain("x.y.z.google.com"); + GURL target_gurl("http://" + dictionary_domain); + std::string dictionary_text(NewSdchDictionary(dictionary_domain)); + std::string client_hash; + std::string server_hash; + SdchManager::GenerateHash(dictionary_text, &client_hash, &server_hash); + EXPECT_TRUE(AddSdchDictionary(dictionary_text, target_gurl)); + EXPECT_EQ("xyzzy", observer.last_server_hash()); + EXPECT_EQ(1, observer.dictionary_used_notifications()); + + EXPECT_TRUE(sdch_manager()->GetDictionarySet(target_gurl)); + EXPECT_EQ("xyzzy", observer.last_server_hash()); + EXPECT_EQ(1, observer.dictionary_used_notifications()); + + sdch_manager()->RemoveObserver(&observer); + EXPECT_EQ(1, observer.dictionary_used_notifications()); + EXPECT_EQ("xyzzy", observer.last_server_hash()); + sdch_manager()->OnDictionaryUsed("plugh"); + EXPECT_EQ(1, observer.dictionary_used_notifications()); + EXPECT_EQ("xyzzy", observer.last_server_hash()); +} + #else TEST(SdchManagerTest, SdchOffByDefault) {
diff --git a/net/base/sdch_observer.h b/net/base/sdch_observer.h index 2c5987d..61603b0 100644 --- a/net/base/sdch_observer.h +++ b/net/base/sdch_observer.h
@@ -5,6 +5,9 @@ #ifndef NET_BASE_SDCH_OBSERVER_H_ #define NET_BASE_SDCH_OBSERVER_H_ +#include <iosfwd> +#include <string> + #include "net/base/net_export.h" class GURL; @@ -19,7 +22,24 @@ public: virtual ~SdchObserver(); - // Notification that SDCH has seen a "Get-Dictionary" header. + // TODO(rdsmith): Add Added/Removed signals. These are only needed if + // we end up with an implementation in which more than one observer + // generates Add/Removed events; otherwise, tracking can be done internally. + + // TODO(rdsmith): Add signal that an Avail-Dictionary header was generated. + // Should be added if/when an observer wants to use it to fine-tune + // dictionary deprecation (e.g. if Avail-Dictionary is generated and + // the remote *doesn't* use it, that should deprecate the dictionary faster) + + // A SDCH encoded response was received and the specified dictionary + // was used to decode it. This notification only occurs for successful + // decodes. + // TODO(rdsmith): Should this notification indicate how much + // compression the dictionary provided? + virtual void OnDictionaryUsed(SdchManager* manager, + const std::string& server_hash) = 0; + + // A "Get-Dictionary" header has been seen. virtual void OnGetDictionary(SdchManager* manager, const GURL& request_url, const GURL& dictionary_url) = 0;
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h index 0eef912..1fe58fd 100644 --- a/net/base/sdch_problem_code_list.h +++ b/net/base/sdch_problem_code_list.h
@@ -51,8 +51,8 @@ SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FOR_SSL, 31) SDCH_PROBLEM_CODE(DICTIONARY_ALREADY_LOADED, 32) SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FROM_NON_HTTP, 33) -SDCH_PROBLEM_CODE(DICTIONARY_IS_TOO_LARGE, 34) -SDCH_PROBLEM_CODE(DICTIONARY_COUNT_EXCEEDED, 35) +// defunct = 34, // Now recorded in separate histogram; see sdch_owner.cc. +// defunct = 35, // Now recorded in separate histogram; see sdch_owner.cc. // defunct = 36, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead. // defunct = 37, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead. // defunct = 38, // No longer paying attention to URLRequest::Read return. @@ -61,6 +61,9 @@ // Failsafe hack. SDCH_PROBLEM_CODE(ATTEMPT_TO_DECODE_NON_HTTP_DATA, 40) +// More dictionary loading problems. +SDCH_PROBLEM_CODE(DICTIONARY_NO_ROOM, 44) + // Content-Encoding problems detected, with no action taken. SDCH_PROBLEM_CODE(MULTIENCODING_FOR_NON_SDCH_REQUEST, 50) SDCH_PROBLEM_CODE(SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST, 51)
diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h index b8f128c..50eb037 100644 --- a/net/cert/nss_cert_database.h +++ b/net/cert/nss_cert_database.h
@@ -263,6 +263,12 @@ // in tests (see SetSlowTaskRunnerForTest). scoped_refptr<base::TaskRunner> GetSlowTaskRunner() const; + protected: + // Broadcasts notifications to all registered observers. + void NotifyObserversOfCertAdded(const X509Certificate* cert); + void NotifyObserversOfCertRemoved(const X509Certificate* cert); + void NotifyObserversOfCACertChanged(const X509Certificate* cert); + private: // Registers |observer| to receive notifications of certificate changes. The // thread on which this is called is the thread on which |observer| will be @@ -282,11 +288,6 @@ const DeleteCertCallback& callback, bool success); - // Broadcasts notifications to all registered observers. - void NotifyObserversOfCertAdded(const X509Certificate* cert); - void NotifyObserversOfCertRemoved(const X509Certificate* cert); - void NotifyObserversOfCACertChanged(const X509Certificate* cert); - // Certificate removal implementation used by |DeleteCertAndKey*|. Static so // it may safely be used on the worker thread. static bool DeleteCertAndKeyImpl(scoped_refptr<X509Certificate> cert);
diff --git a/net/cookies/parsed_cookie.h b/net/cookies/parsed_cookie.h index 8a8e135..115ca1f 100644 --- a/net/cookies/parsed_cookie.h +++ b/net/cookies/parsed_cookie.h
@@ -128,7 +128,6 @@ void ClearAttributePair(size_t index); PairList pairs_; - bool is_valid_; // These will default to 0, but that should never be valid since the // 0th index is the user supplied token/value, not an attribute. // We're really never going to have more than like 8 attributes, so we
diff --git a/net/dns/dns_config_service_unittest.cc b/net/dns/dns_config_service_unittest.cc index 45a803d..e3abafd 100644 --- a/net/dns/dns_config_service_unittest.cc +++ b/net/dns/dns_config_service_unittest.cc
@@ -41,7 +41,7 @@ for (std::vector<std::string>::const_iterator it = server_strings.begin(); it != server_strings.end(); ++it) { - if (*it == "") + if (it->empty()) continue; IPAddressNumber address;
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc index 622bca9..66873ab 100644 --- a/net/dns/mdns_client_impl.cc +++ b/net/dns/mdns_client_impl.cc
@@ -195,8 +195,7 @@ delegate_->HandlePacket(response, bytes_read); } -MDnsClientImpl::Core::Core(MDnsClientImpl* client) - : client_(client), connection_(new MDnsConnection(this)) { +MDnsClientImpl::Core::Core() : connection_(new MDnsConnection(this)) { } MDnsClientImpl::Core::~Core() { @@ -424,7 +423,7 @@ bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) { DCHECK(!core_.get()); - core_.reset(new Core(this)); + core_.reset(new Core()); if (!core_->Init(socket_factory)) { core_.reset(); return false;
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h index 0dfedf9..4ed85f2 100644 --- a/net/dns/mdns_client_impl.h +++ b/net/dns/mdns_client_impl.h
@@ -109,7 +109,7 @@ // invalidate the core. class Core : public base::SupportsWeakPtr<Core>, MDnsConnection::Delegate { public: - explicit Core(MDnsClientImpl* client); + Core(); ~Core() override; // Initialize the core. Returns true on success. @@ -157,7 +157,6 @@ ListenerMap listeners_; - MDnsClientImpl* client_; MDnsCache cache_; base::CancelableClosure cleanup_callback_;
diff --git a/net/docs/bug-triage-labels.txt b/net/docs/bug-triage-labels.txt new file mode 100644 index 0000000..c5d5505 --- /dev/null +++ b/net/docs/bug-triage-labels.txt
@@ -0,0 +1,87 @@ +Some network label caveats +* Cr-UI-Browser-Downloads: Despite the name, this covers all issues related to + downloading a file except saving entire pages (Which is Cr-Blink-SavePage), + not just UI issues. Most downloads bugs will have the word "download" or + "save as" in the description. Issues with the HTTP server for the Chrome + binaries are not downloads bugs. +* Cr-UI-Browser-SafeBrowsing: Bugs that have to do with the process by which a + URL or file is determined to be dangerous based on our databases, or the + resulting interstitials. Determination of danger based purely on + content-type or file extension belongs in Cr-UI-Browser-Downloads, not + SafeBrowsing. +* Cr-Internals-Network-SSL: This includes issues that should be also tagged as + Cr-Security-UX (certificate error pages or other security interstitials, + omnibox indicators that a page is secure), and more general SSL issues. If + you see requests that die in the SSL negotiation phase, in particular, this + is often the correct label. +* Cr-Internals-Network-DataProxy: Flywheel / the Data Reduction Proxy. Issues + require "Reduce Data Usage" be turned on. Proxy url is + https://proxy.googlezip.net:443, with compress.googlezip.net:80 as a + fallback. Currently Android and iOS only. +* Cr-Internals-Network-Cache: The cache is the layer that handles most range + request logic (Though range requests may also be issued by the PDF plugin, + XHRs, or other components). +* Cr-Internals-Network-SPDY: Covers HTTP2 as well. +* Cr-Internals-Network-HTTP: Typically not used. Unclear what it covers, and + there's no specific HTTP owner. +* Cr-Internals-Network-Logging: Covers about:net-internals, about:net-export as + well as the what's sent to the NetLog. +* Cr-Internals-Network-Connectivity: Issues related to switching between + networks, ERR_NETWORK_CHANGED, Chrome thinking it's online when it's not / + navigator.onLine inaccuracies, etc. +* Cr-Internals-Network-Filters: Covers SDCH and gzip issues. + ERR_CONTENT_DECODING_FAILED indicates a problem at this layer, and bugs here + can also cause response body corruption. + + +Common non-network label reference. Bugs in these areas often receive the +Cr-Internals-Network label, though they fall largely outside the purview of the +network stack team: +* Cr-Blink-Forms: Issues submitting forms, forms having weird data, forms + sending the wrong method, etc. +* Cr-Blink-Loader: Cross origin issues are sometimes loader related. Blink + also has an in-memory cache, and when it's used, requests don't appear in + about:net-internals. Requests for the same URL are also often merged there + as well. This does *not* cover issues with content/browser/loader/ files. +* Cr-Blink-ServiceWorker +* Cr-Blink-Storage-AppCache +* Cr-Blink-WebSockets +* Cr-Blink-XHR: Generic issues with sync/async XHR requests - missing request + or response headers, multiple headers, etc. These will often run into + issues in certain corner cases (Cross origin / CORS, proxy, whatever). + Attach all labels that seem appropriate. +* Cr-Services-Sync: Sharing data/tabs/history/passwords/etc between machines + not working. +* Cr-Services-Chromoting +* Cr-Platform-Extensions: Issues extensions loading / not loading / hanging. +* Cr-Platform-Extensions-API: Issues with network related extension APIs should + have this label. chrome.webRequest is the big one, I believe, but there are + others. +* Cr-Internals-Plugins-Pepper[-SDK] +* Cr-UI-Browser-Omnibox: Basically any issue with the omnibox. URLs being + treated as search queries rather than navigations, dropdown results being + weird, not handling certain unicode characters, etc. If the issue is new + TLDs not being recognized by the omnibox, that's due to Chrome's TLD list + being out of date, and not an omnibox issue. Such TLD issues should be + duped against http://crbug.com/37436. +* Cr-Internals-Media-Network: Issues related to media. These often run into + the 6 requests per hostname issue, and also have fun interactions with the + cache, particularly in the range request case. +* Cr-Internals-Plugins-PDF: Issues loading pdf files. These are often related + to range requests, which also have some logic at the Internals-Network-Cache + layer. +* Cr-UI-Browser-Navigation +* Cr-UI-Browser-History: Issues which only appear with forward/back navigation. +* Cr-OS-Systems-Network / Cr-OS-Systems-Mobile / Cr-OS-Systems-Bluetooth: These + should be used for issues with ChromeOS's platform network code, and not + net/ issues on ChromeOS. +* Cr-Blink-SecurityFeature: CORS / Cross origin issues. Main frame + cross-origin navigation issues are often actually Cr-UI-Browser-Navigation + issues. +* Cr-Privacy: Privacy related bug (History, cookies discoverable by an entity + that shouldn't be able to do so, incognito state being saved in memory or on + disk beyond the lifetime of incognito tabs, etc). Generally used in + conjunction with other labels. +* Type-Bug-Security: Security related bug (Allows for code execution from + remote site, allows crossing security boundaries, unchecked array bounds, + etc).
diff --git a/net/docs/bug-triage-suggested-workflow.txt b/net/docs/bug-triage-suggested-workflow.txt new file mode 100644 index 0000000..c54e912 --- /dev/null +++ b/net/docs/bug-triage-suggested-workflow.txt
@@ -0,0 +1,118 @@ +Identifying unlabeled network bugs on the tracker: +* Look at new uncomfirmed bugs since noon PST on the last triager's rotation: + https://code.google.com/p/chromium/issues/list?can=2&q=status%3Aunconfirmed&sort=-id&num=1000 +* Press "h" to bring up a preview of the bug text. +* Use "j" and "k" to advance through bugs. +* If a bug looks like it might be network/download/safe-browsing related, middle + click [or command-click on OSX] to open in new tab. +* If a user provides a crash ID for a crasher for a bug that could be + net-related, look at the crash stack at go/crash, and see if it looks to be + network related. Be sure to check if other bug reports have that stack + trace, and mark as a dupe if so. Even if the bug isn't network related, + paste the stack trace in the bug, so no one else has to look up the crash + stack from the ID. + * If there's no other information than the crash ID, ask for more details and + add the Needs-Feedback label. +* If network causes are possible, ask for a net-internals log (If it's not a + browser crash) and attach the most specific internals-network label that's + applicable. If there isn't an applicable narrower label, a clear owner for + the issue, or there are multiple possibilities, attach the internals-network + label and proceed with further investigation. +* If non-network causes also seem possible, attach those labels as well. + +Investigating Cr-Internals-Network bugs: +* Look through uncomfirmed and untriaged Cr-Internals-Network bugs, prioritizing + those updated within the last week: + https://code.google.com/p/chromium/issues/list?can=2&q=Cr%3DInternals-Network+-status%3AAssigned+-status%3AStarted+-status%3AAvailable+&sort=-modified +* While investigating a new issue, change the status to Untriaged. +* If a bug is a potential security issue (Allows for code execution from remote + site, allows crossing security boundaries, unchecked array bounds, etc) mark + it Type-Bug-Security. If it has privacy implication (History, cookies + discoverable by an entity that shouldn't be able to do so, incognito state + being saved in memory or on disk beyond the lifetime of incognito tabs, + etc), mark it Cr-Privacy. +* For bugs that already have a more specific network label, go ahead and remove + the Cr-Internals-Network label and move on. +* Try to figure out if it's really a network bug. See common non-network labels + section for description of common labels needed for issues incorrectly + tagged as Cr-Internals-Network. +* If it's not, attach appropriate labels and go no further. +* If it may be a network bug, attach additional possibly relevant labels if any, + and continue investigating. Once you either determine it's a non-network + bug, or figure out accurate more specific network labels, your job is done, + though you should still ask for a net-internals dump if it seems likely to + be useful. +* Note that ChromeOS-specific network-related code (Captive portal detection, + connectivity detection, login, etc) may not all have appropriate more + specific labels, but are not in areas handled by the network stack team. + Just make sure those have the OS-Chrome label, and any more specific labels + if applicable, and then move on. +* Gather data and investigate. + * Remember to add the Needs-Feedback label whenever waiting for the user to + respond with more information, and remove it when not waiting on the user. + * Try to reproduce locally. If you can, and it's a regression, use + src/tools/bisect-builds.py to figure out when it regressed. + * Ask more data from the user as needed (net-internals dumps, repro case, + crash ID from about:crashes, run tests, etc). + * If asking for an about:net-internals dump, provide this link: + https://sites.google.com/a/chromium.org/dev/for-testers/providing-network-details. + Can just grab the link from about:net-internals, as needed. +* Try to figure out what's going on, and which more specific network label is + most appropriate. +* If you are having trouble with an issue, particularly for help understanding + net-internals logs, email the public net-dev@chromium.org list for help + debugging. If it's a crasher, or for some other reason discussion needs to + be done in private, use chrome-network-debugging@google.com. + TODO(mmenke): Write up a net-internals tips and tricks docs. +* If it appears to be a bug in the unowned core of the network stack (i.e. no + sublabel applies, or only the Cr-Internals-Network-HTTP sublabel applies, + and there's no clear owner), try to figure out the exact cause. + +Look for new crashers: +* Go to go/chromecrash. +* For each platform, go to the latest canary. Click on browser -> limit 1000. + Search the page for "net::". Ignore crashes that only occur once, as + memory corruption can easily cause one-off failures when the sample size is + large enough. + * Look at the stack trace to confirm it's a network bug. + * If it is, and there's no associated bug filed, file a new bug directly from + chromecrash, looking at earlier canaries to determine if it's a recent + regression. Use the most specific label possible. +* The most recent Canary may not yet have a full day of crashes, so it may be + worth looking at more than one version. +* If there's been a dev, beta, or stable release in the last couple days, should + also look at those. + +Investigating crashers: +* Only investigate crashers that are still occurring, as identified by above + section. +* Particularly for Windows, look for weird dlls associated with the crashes. + If there are some, it may be caused by malware. You can often figure out if + a dll is malware by a search, though it's harder to figure out if a dll is + definitively not malware. +* See if the same users are repeatedly running into the same issue. This can be + accomplished by search for (Or clicking on) the client ID associated with a + crash report, and seeing if there are multiple reports for the same crash. + If this is the case, it may be also be malware, or an issue with an unusual + system/chrome/network config. +* Dig through crash reports to figure out when the crash first appeared, and dig + through revision history in related files to try and locate a suspect CL. + TODO(mmenke): Add more detail here. +* Load crash dumps, try to figure out a cause. + See http://www.chromium.org/developers/crash-reports for more information + +Dealing with old bugs: +* For all network issues (Even those with owners, or a more specific labels): + * If the issue has had the Needs-Feedback label for over two weeks, verify it + is waiting on feedback from the user. If not, remove the label. + Otherwise, go ahead and mark the issue WontFix due to lack of response and + suggest the user file a new bug if the issue is still present. + Needs-feedback issues: https://code.google.com/p/chromium/issues/list?can=2&q=Cr=Internals-Network%20Needs=Feedback&sort=modified + * If a bug is over 2 months old, and the underlying problem was never really + understood, ask reporters if the issue is still present, and attach the + Needs-Feedback label. +* Old unconfirmed or untriaged Cr-Internals-Network issues can be investigated + just like newer ones. Crashers should generally be given higher priority, + since we can verify if they still occur, and then newer issues, as they're + more likely to still be present, and more likely to have a still responsive + bug reporter.
diff --git a/net/docs/bug-triage.txt b/net/docs/bug-triage.txt new file mode 100644 index 0000000..e2d7380 --- /dev/null +++ b/net/docs/bug-triage.txt
@@ -0,0 +1,61 @@ +The Chrome network team uses a two day bug triage rotation. The main goals are +to identify and label new network bugs, and investigate network bugs when no +label seems suitable. + +Responsibilities + +To be done on each rotation. These responsibilities should be tracked, and +anything left undone at the end of a rotation should be handed off to the next +triager. The downside to passing along bug investigations like this is each new +triager has to get back up to speed on bugs the previous triager was +investigating. The upside is that triagers don't get stuck investigating issues +after their time after their rotation, and it results in a uniform, predictable +two day commitment for all triagers. + +Primary Responsibilities: +* Identify new crashers that are potentially network related. You should check + the most recent canary, the previous canary (if the most recent less than a + day old), and any of dev/beta/stable that were released in the last couple + of days, for each platform. File Cr-Internals-Network bugs on the tracker + when new crashers are found. +* Identify new network bugs, both on the bug tracker and on the crash server. + All Unconfirmed issues filed during your triage rotation should be scanned, + and, for suspected network bugs, a network label assigned. A triager is + responsible for looking at bugs reported from noon PST / 3:00 pm EST of the + last day of the previous triager's rotation until the same time on the last + day of his rotation. +* Request data about recent unassigned Cr-Internals-Network bugs from reporters. + "Recent" means issues updated in the past week or so. +* Investigate each recent (New comment within the past week or so) + Cr-Internals-Network issue until you can do one of the following: + * Mark it as WontFix (working as intended, obsolete issue) or a duplicate. + * Mark it as a feature request. + * Remove the Cr-Internals-Network label, replacing it with at least one more + specific network label or non-network label. Promptly adding non-network + labels when appropriate is important to get new bugs in front of someone + familiar with the relevant code, and to remove them from the next triager's + radar. Because of the way the bug report wizard works, a lot of bugs + incorrectly end up with the network label. + * The issue is assigned to an appropriate owner. + * If there is no more specific label for a bug, it should be investigated + until we have a good understanding of the cause of the problem, and some + idea how it should be fixed, at which point its status should be set to + Available. Future triagers should ignore bugs with this status, unless + investigating stale bugs. +* Monitor UMA histograms and gasper alerts. + TODO (mmenke): Add a suggested workflow. + +Best Effort (As you time): +* Investigate unowned and owned but forgotten net/ crashers that are still + occurring (As indicated by go/chromecrash), prioritizing frequent and long + standing crashers. +* Investigate old bugs, prioritizing the most recent. +* Close obsolete bugs. + +If you've investigated an issue (in code you don't normally work on) to an +extent that you know how to fix it, and the fix is simple, feel free to take +ownership of the issue and create a patch while on triage duty, but other tasks +should take priority. + +See bug-triage-suggested-workflow.txt for suggested workflows. +See bug-triage-labels.txt for labeling tips for network and non-network bugs.
diff --git a/net/filter/mock_filter_context.h b/net/filter/mock_filter_context.h index 776a237..f66939d 100644 --- a/net/filter/mock_filter_context.h +++ b/net/filter/mock_filter_context.h
@@ -78,7 +78,6 @@ const BoundNetLog& GetNetLog() const override; private: - int buffer_size_; std::string mime_type_; std::string content_disposition_; GURL gurl_;
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc index 30392cd..cb3150c 100644 --- a/net/filter/sdch_filter.cc +++ b/net/filter/sdch_filter.cc
@@ -177,6 +177,11 @@ // Allow latency experiments to proceed. url_request_context_->sdch_manager()->SetAllowLatencyExperiment( url_, true); + + // Notify successful dictionary usage. + url_request_context_->sdch_manager()->OnDictionaryUsed( + dictionary_->server_hash()); + return; } case PASS_THROUGH: {
diff --git a/net/filter/sdch_filter_unittest.cc b/net/filter/sdch_filter_unittest.cc index be9790d..4ba38d5 100644 --- a/net/filter/sdch_filter_unittest.cc +++ b/net/filter/sdch_filter_unittest.cc
@@ -12,6 +12,7 @@ #include "base/memory/scoped_ptr.h" #include "base/test/simple_test_clock.h" #include "net/base/io_buffer.h" +#include "net/base/sdch_observer.h" #include "net/filter/mock_filter_context.h" #include "net/filter/sdch_filter.h" #include "net/url_request/url_request_context.h" @@ -68,7 +69,8 @@ // failure. bool AddSdchDictionary(const std::string& dictionary_text, const GURL& gurl) { - return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK; + return sdch_manager_->AddSdchDictionary(dictionary_text, gurl, nullptr) == + SDCH_OK; } MockFilterContext* filter_context() { return filter_context_.get(); } @@ -100,9 +102,6 @@ scoped_ptr<MockFilterContext> filter_context_; }; -//------------------------------------------------------------------------------ - - TEST_F(SdchFilterTest, Hashing) { std::string client_hash, server_hash; std::string dictionary("test contents"); @@ -112,7 +111,6 @@ EXPECT_EQ(server_hash, "MyciMVll"); } - //------------------------------------------------------------------------------ // Provide a generic helper function for trying to filter data. // This function repeatedly calls the filter to process data, until the entire @@ -154,7 +152,7 @@ return true; } while (1); } -//------------------------------------------------------------------------------ + static std::string NewSdchDictionary(const std::string& domain) { std::string dictionary; if (!domain.empty()) { @@ -180,8 +178,6 @@ return dictionary; } -//------------------------------------------------------------------------------ - TEST_F(SdchFilterTest, EmptyInputOk) { std::vector<Filter::FilterType> filter_types; filter_types.push_back(Filter::FILTER_TYPE_SDCH); @@ -446,15 +442,12 @@ const std::string kSampleDomain2 = "sdchtest2.com"; - // Don't test adding a second dictionary if our limits are tight. - if (SdchManager::kMaxDictionaryCount > 1) { - // Construct a second SDCH dictionary from a VCDIFF dictionary. - std::string dictionary2(NewSdchDictionary(kSampleDomain2)); + // Construct a second SDCH dictionary from a VCDIFF dictionary. + std::string dictionary2(NewSdchDictionary(kSampleDomain2)); - std::string url_string2 = "http://" + kSampleDomain2; - GURL url2(url_string2); - EXPECT_TRUE(AddSdchDictionary(dictionary2, url2)); - } + std::string url_string2 = "http://" + kSampleDomain2; + GURL url2(url_string2); + EXPECT_TRUE(AddSdchDictionary(dictionary2, url2)); } TEST_F(SdchFilterTest, BasicDictionary) { @@ -691,11 +684,6 @@ } TEST_F(SdchFilterTest, DictionaryPathValidation) { - // Can't test path distinction between dictionaries if we aren't allowed - // more than one dictionary. - if (SdchManager::kMaxDictionaryCount <= 1) - return; - // Construct a valid SDCH dictionary from a VCDIFF dictionary. const std::string kSampleDomain = "sdchtest.com"; std::string dictionary(NewSdchDictionary(kSampleDomain)); @@ -747,11 +735,6 @@ } TEST_F(SdchFilterTest, DictionaryPortValidation) { - // Can't test port distinction between dictionaries if we aren't allowed - // more than one dictionary. - if (SdchManager::kMaxDictionaryCount <= 1) - return; - // Construct a valid SDCH dictionary from a VCDIFF dictionary. const std::string kSampleDomain = "sdchtest.com"; std::string dictionary(NewSdchDictionary(kSampleDomain)); @@ -813,9 +796,7 @@ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string))); } -//------------------------------------------------------------------------------ // Helper function to perform gzip compression of data. - static std::string gzip_compress(const std::string &input) { z_stream zlib_stream; memset(&zlib_stream, 0, sizeof(zlib_stream)); @@ -992,7 +973,7 @@ EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH); // First try with a large buffer (larger than test input, or compressed data). - scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); + scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); // Verify that chained filter is waiting for data. char tiny_output_buffer[10]; @@ -1213,7 +1194,7 @@ // Don't use the Helper function since its insertion check is indeterminate // for a Max-Age: 0 dictionary. - sdch_manager_->AddSdchDictionary(expired_dictionary, url); + sdch_manager_->AddSdchDictionary(expired_dictionary, url, nullptr); std::string client_hash; std::string server_hash; @@ -1243,4 +1224,74 @@ EXPECT_EQ(expanded_, output); } +class SimpleSdchObserver : public SdchObserver { + public: + explicit SimpleSdchObserver(SdchManager* manager) + : dictionary_used_(0), manager_(manager) { + manager_->AddObserver(this); + } + ~SimpleSdchObserver() override { manager_->RemoveObserver(this); } + + // SdchObserver + void OnDictionaryUsed(SdchManager* manager, + const std::string& server_hash) override { + dictionary_used_++; + last_server_hash_ = server_hash; + } + + int dictionary_used_calls() const { return dictionary_used_; } + std::string last_server_hash() const { return last_server_hash_; } + + void OnGetDictionary(SdchManager* /* manager */, + const GURL& /* request_url */, + const GURL& /* dictionary_url */) override {} + void OnClearDictionaries(SdchManager* /* manager */) override {} + + private: + int dictionary_used_; + std::string last_server_hash_; + SdchManager* manager_; + + DISALLOW_COPY_AND_ASSIGN(SimpleSdchObserver); +}; + +TEST_F(SdchFilterTest, DictionaryUsedSignaled) { + // Construct a valid SDCH dictionary from a VCDIFF dictionary. + const std::string kSampleDomain = "sdchtest.com"; + std::string dictionary(NewSdchDictionary(kSampleDomain)); + SimpleSdchObserver observer(sdch_manager_.get()); + + std::string url_string = "http://" + kSampleDomain; + + GURL url(url_string); + EXPECT_TRUE(AddSdchDictionary(dictionary, url)); + + std::string client_hash; + std::string server_hash; + SdchManager::GenerateHash(dictionary, &client_hash, &server_hash); + + std::string compressed(NewSdchCompressedData(dictionary)); + + std::vector<Filter::FilterType> filter_types; + filter_types.push_back(Filter::FILTER_TYPE_SDCH); + + SetupFilterContextWithGURL(url); + + scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context())); + + size_t feed_block_size = 100; + size_t output_block_size = 100; + std::string output; + EXPECT_TRUE(FilterTestData(compressed, feed_block_size, output_block_size, + filter.get(), &output)); + EXPECT_EQ(output, expanded_); + + filter.reset(nullptr); + + // Confirm that we got a "DictionaryUsed" signal from the SdchManager + // for our dictionary. + EXPECT_EQ(1, observer.dictionary_used_calls()); + EXPECT_EQ(server_hash, observer.last_server_hash()); +} + } // namespace net
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index a071baa..ed36200 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -29,6 +29,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/threading/worker_pool.h" +#include "base/time/default_clock.h" #include "base/time/time.h" #include "net/base/cache_type.h" #include "net/base/io_buffer.h" @@ -361,7 +362,7 @@ DCHECK_EQ(0, request_.load_flags & LOAD_ASYNC_REVALIDATION); request_.load_flags |= LOAD_ASYNC_REVALIDATION; - start_time_ = base::Time::Now(); + start_time_ = cache_->clock()->Now(); // This use of base::Unretained is safe because |transaction_| is owned by // this object. read_callback_ = base::Bind(&AsyncValidation::OnRead, base::Unretained(this)); @@ -439,7 +440,7 @@ // anyway. cache_->DoomEntry(transaction_->key(), transaction_.get()); } - base::TimeDelta duration = base::Time::Now() - start_time_; + base::TimeDelta duration = cache_->clock()->Now() - start_time_; UMA_HISTOGRAM_TIMES("HttpCache.AsyncValidationDuration", duration); transaction_->net_log().EndEventWithNetErrorCode( NetLog::TYPE_ASYNC_REVALIDATION, result); @@ -458,6 +459,7 @@ use_stale_while_revalidate_(params.use_stale_while_revalidate), mode_(NORMAL), network_layer_(new HttpNetworkLayer(new HttpNetworkSession(params))), + clock_(new base::DefaultClock()), weak_factory_(this) { SetupQuicServerInfoFactory(network_layer_->GetSession()); } @@ -475,6 +477,7 @@ use_stale_while_revalidate_(session->params().use_stale_while_revalidate), mode_(NORMAL), network_layer_(new HttpNetworkLayer(session)), + clock_(new base::DefaultClock()), weak_factory_(this) { } @@ -489,6 +492,7 @@ use_stale_while_revalidate_(false), mode_(NORMAL), network_layer_(network_layer), + clock_(new base::DefaultClock()), weak_factory_(this) { SetupQuicServerInfoFactory(network_layer_->GetSession()); HttpNetworkSession* session = network_layer_->GetSession();
diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 8fa1640..33b89f3 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h
@@ -25,6 +25,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/non_thread_safe.h" +#include "base/time/clock.h" #include "base/time/time.h" #include "net/base/cache_type.h" #include "net/base/completion_callback.h" @@ -126,6 +127,10 @@ scoped_refptr<base::SingleThreadTaskRunner> thread_; }; + // The number of minutes after a resource is prefetched that it can be used + // again without validation. + static const int kPrefetchReuseMins = 5; + // The disk cache is initialized lazily (by CreateTransaction) in this case. // The HttpCache takes ownership of the |backend_factory|. HttpCache(const net::HttpNetworkSession::Params& params, @@ -181,6 +186,12 @@ void set_mode(Mode value) { mode_ = value; } Mode mode() { return mode_; } + // Get/Set the cache's clock. These are public only for testing. + void SetClockForTesting(scoped_ptr<base::Clock> clock) { + clock_.reset(clock.release()); + } + base::Clock* clock() const { return clock_.get(); } + // Close currently active sockets so that fresh page loads will not use any // recycled connections. For sockets currently in use, they may not close // immediately, but they will not be reusable. This is for debugging. @@ -462,6 +473,9 @@ // The async validations currently in progress, keyed by URL. AsyncValidationMap async_validations_; + // A clock that can be swapped out for testing. + scoped_ptr<base::Clock> clock_; + base::WeakPtrFactory<HttpCache> weak_factory_; DISALLOW_COPY_AND_ASSIGN(HttpCache);
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 0a84680..a5275f7 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -27,6 +27,7 @@ #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/time/clock.h" #include "base/time/time.h" #include "base/values.h" #include "net/base/completion_callback.h" @@ -755,8 +756,8 @@ // 2. Cached entry, no validation: // Start(): // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* -// -> BeginPartialCacheValidation() -> BeginCacheValidation() -> -// SetupEntryForRead() +// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> +// BeginCacheValidation() -> SetupEntryForRead() // // Read(): // CacheReadData* @@ -764,10 +765,10 @@ // 3. Cached entry, validation (304): // Start(): // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* -// -> BeginPartialCacheValidation() -> BeginCacheValidation() -> -// SendRequest* -> SuccessfulSendRequest -> UpdateCachedResponse -> -// CacheWriteResponse* -> UpdateCachedResponseComplete -> -// OverwriteCachedResponse -> PartialHeadersReceived +// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> +// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> +// UpdateCachedResponse -> CacheWriteResponse* -> UpdateCachedResponseComplete +// -> OverwriteCachedResponse -> PartialHeadersReceived // // Read(): // CacheReadData* @@ -775,10 +776,10 @@ // 4. Cached entry, validation and replace (200): // Start(): // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* -// -> BeginPartialCacheValidation() -> BeginCacheValidation() -> -// SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse -> -// CacheWriteResponse* -> DoTruncateCachedData* -> TruncateCachedMetadata* -> -// PartialHeadersReceived +// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> +// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> +// OverwriteCachedResponse -> CacheWriteResponse* -> DoTruncateCachedData* -> +// TruncateCachedMetadata* -> PartialHeadersReceived // // Read(): // NetworkRead* -> CacheWriteData* @@ -786,12 +787,12 @@ // 5. Sparse entry, partially cached, byte range request: // Start(): // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* -// -> BeginPartialCacheValidation() -> CacheQueryData* -> -// ValidateEntryHeadersAndContinue() -> StartPartialCacheValidation -> -// CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* -> -// SuccessfulSendRequest -> UpdateCachedResponse -> CacheWriteResponse* -> -// UpdateCachedResponseComplete -> OverwriteCachedResponse -> -// PartialHeadersReceived +// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> +// CacheQueryData* -> ValidateEntryHeadersAndContinue() -> +// StartPartialCacheValidation -> CompletePartialCacheValidation -> +// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> +// UpdateCachedResponse -> CacheWriteResponse* -> UpdateCachedResponseComplete +// -> OverwriteCachedResponse -> PartialHeadersReceived // // Read() 1: // NetworkRead* -> CacheWriteData* @@ -830,8 +831,9 @@ // itself. // Start(): // GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* -// -> BeginPartialCacheValidation() -> BeginCacheValidation() -> -// SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse +// -> CacheDispatchValidation -> BeginPartialCacheValidation() -> +// BeginCacheValidation() -> SendRequest* -> SuccessfulSendRequest -> +// OverwriteCachedResponse // // 10. HEAD. Sparse entry, partially cached: // Serve the request from the cache, as long as it doesn't require @@ -842,6 +844,28 @@ // Start(): Basically the same as example 7, as we never create a partial_ // object for this request. // +// 11. Prefetch, not-cached entry: +// The same as example 1. The "unused_since_prefetch" bit is stored as true in +// UpdateCachedResponse. +// +// 12. Prefetch, cached entry: +// Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between +// CacheReadResponse* and CacheDispatchValidation if the unused_since_prefetch +// bit is unset. +// +// 13. Cached entry less than 5 minutes old, unused_since_prefetch is true: +// Skip validation, similar to example 2. +// GetBackend* -> InitEntry -> OpenEntry* -> AddToEntry* -> CacheReadResponse* +// -> CacheToggleUnusedSincePrefetch* -> CacheDispatchValidation -> +// BeginPartialCacheValidation() -> BeginCacheValidation() -> +// SetupEntryForRead() +// +// Read(): +// CacheReadData* +// +// 14. Cached entry more than 5 minutes old, unused_since_prefetch is true: +// Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between +// CacheReadResponse* and CacheDispatchValidation. int HttpCache::Transaction::DoLoop(int result) { DCHECK(next_state_ != STATE_NONE); @@ -950,6 +974,17 @@ case STATE_CACHE_READ_RESPONSE_COMPLETE: rv = DoCacheReadResponseComplete(rv); break; + case STATE_CACHE_DISPATCH_VALIDATION: + DCHECK_EQ(OK, rv); + rv = DoCacheDispatchValidation(); + break; + case STATE_TOGGLE_UNUSED_SINCE_PREFETCH: + DCHECK_EQ(OK, rv); + rv = DoCacheToggleUnusedSincePrefetch(); + break; + case STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE: + rv = DoCacheToggleUnusedSincePrefetchComplete(rv); + break; case STATE_CACHE_WRITE_RESPONSE: DCHECK_EQ(OK, rv); rv = DoCacheWriteResponse(); @@ -1629,6 +1664,7 @@ response_.response_time = new_response_->response_time; response_.request_time = new_response_->request_time; response_.network_accessed = new_response_->network_accessed; + response_.unused_since_prefetch = new_response_->unused_since_prefetch; if (response_.headers->HasHeaderValue("cache-control", "no-store")) { if (!entry_->doomed) { @@ -1857,6 +1893,22 @@ if (response_.headers->GetContentLength() == current_size) truncated_ = false; + if ((response_.unused_since_prefetch && + !(request_->load_flags & LOAD_PREFETCH)) || + (!response_.unused_since_prefetch && + (request_->load_flags & LOAD_PREFETCH))) { + // Either this is the first use of an entry since it was prefetched or + // this is a prefetch. The value of response.unused_since_prefetch is valid + // for this transaction but the bit needs to be flipped in storage. + next_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH; + return OK; + } + + next_state_ = STATE_CACHE_DISPATCH_VALIDATION; + return OK; +} + +int HttpCache::Transaction::DoCacheDispatchValidation() { // We now have access to the cache entry. // // o if we are a reader for the transaction, then we can start reading the @@ -1870,6 +1922,7 @@ // conditionalized request (if-modified-since / if-none-match). We check // if the request headers define a validation request. // + int result = ERR_FAILED; switch (mode_) { case READ: UpdateTransactionPattern(PATTERN_ENTRY_USED); @@ -1884,11 +1937,30 @@ case WRITE: default: NOTREACHED(); - result = ERR_FAILED; } return result; } +int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetch() { + // Write back the toggled value for the next use of this entry. + response_.unused_since_prefetch = !response_.unused_since_prefetch; + + // TODO(jkarlin): If DoUpdateCachedResponse is also called for this + // transaction then metadata will be written to cache twice. If prefetching + // becomes more common, consider combining the writes. + target_state_ = STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE; + next_state_ = STATE_CACHE_WRITE_RESPONSE; + return OK; +} + +int HttpCache::Transaction::DoCacheToggleUnusedSincePrefetchComplete( + int result) { + // Restore the original value for this transaction. + response_.unused_since_prefetch = !response_.unused_since_prefetch; + next_state_ = STATE_CACHE_DISPATCH_VALIDATION; + return OK; +} + int HttpCache::Transaction::DoCacheWriteResponse() { // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed. tracked_objects::ScopedTracker tracking_profile( @@ -2554,6 +2626,16 @@ if (effective_load_flags_ & LOAD_PREFERRING_CACHE) return VALIDATION_NONE; + if (response_.unused_since_prefetch && + !(effective_load_flags_ & LOAD_PREFETCH) && + response_.headers->GetCurrentAge( + response_.request_time, response_.response_time, + cache_->clock_->Now()) < TimeDelta::FromMinutes(kPrefetchReuseMins)) { + // The first use of a resource after prefetch within a short window skips + // validation. + return VALIDATION_NONE; + } + if (effective_load_flags_ & (LOAD_VALIDATE_CACHE | LOAD_ASYNC_REVALIDATION)) return VALIDATION_SYNCHRONOUS; @@ -2561,8 +2643,9 @@ return VALIDATION_SYNCHRONOUS; ValidationType validation_required_by_headers = - response_.headers->RequiresValidation( - response_.request_time, response_.response_time, Time::Now()); + response_.headers->RequiresValidation(response_.request_time, + response_.response_time, + cache_->clock_->Now()); if (validation_required_by_headers == VALIDATION_ASYNCHRONOUS) { // Asynchronous revalidation is only supported for GET and HEAD methods. @@ -2624,7 +2707,8 @@ response_.headers->GetFreshnessLifetimes(response_.response_time); if (lifetimes.staleness > TimeDelta()) { TimeDelta current_age = response_.headers->GetCurrentAge( - response_.request_time, response_.response_time, Time::Now()); + response_.request_time, response_.response_time, + cache_->clock_->Now()); custom_request_->extra_headers.SetHeader( kFreshnessHeader,
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index 35ca6e4..8e2a62f 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h
@@ -186,6 +186,9 @@ STATE_PARTIAL_HEADERS_RECEIVED, STATE_CACHE_READ_RESPONSE, STATE_CACHE_READ_RESPONSE_COMPLETE, + STATE_CACHE_DISPATCH_VALIDATION, + STATE_TOGGLE_UNUSED_SINCE_PREFETCH, + STATE_TOGGLE_UNUSED_SINCE_PREFETCH_COMPLETE, STATE_CACHE_WRITE_RESPONSE, STATE_CACHE_WRITE_TRUNCATED_RESPONSE, STATE_CACHE_WRITE_RESPONSE_COMPLETE, @@ -257,6 +260,9 @@ int DoPartialHeadersReceived(); int DoCacheReadResponse(); int DoCacheReadResponseComplete(int result); + int DoCacheDispatchValidation(); + int DoCacheToggleUnusedSincePrefetch(); + int DoCacheToggleUnusedSincePrefetchComplete(int result); int DoCacheWriteResponse(); int DoCacheWriteTruncatedResponse(); int DoCacheWriteResponseComplete(int result);
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 30720ae..16a5523 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -13,6 +13,7 @@ #include "base/run_loop.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/test/simple_test_clock.h" #include "net/base/cache_type.h" #include "net/base/elements_upload_data_stream.h" #include "net/base/host_port_pair.h" @@ -25,6 +26,7 @@ #include "net/cert/cert_status_flags.h" #include "net/disk_cache/disk_cache.h" #include "net/http/http_byte_range.h" +#include "net/http/http_cache_transaction.h" #include "net/http/http_request_headers.h" #include "net/http/http_request_info.h" #include "net/http/http_response_headers.h" @@ -7096,6 +7098,115 @@ RemoveMockTransaction(&kRangeGET_TransactionOK); } +class HttpCachePrefetchValidationTest : public ::testing::Test { + protected: + static const int kMaxAgeSecs = 100; + static const int kRequireValidationSecs = kMaxAgeSecs + 1; + + HttpCachePrefetchValidationTest() : transaction_(kSimpleGET_Transaction) { + DCHECK_LT(kMaxAgeSecs, prefetch_reuse_mins() * net::kNumSecondsPerMinute); + + clock_ = new base::SimpleTestClock(); + cache_.http_cache()->SetClockForTesting(make_scoped_ptr(clock_)); + cache_.network_layer()->SetClock(clock_); + + transaction_.response_headers = "Cache-Control: max-age=100\n"; + } + + bool TransactionRequiredNetwork(int load_flags) { + int pre_transaction_count = transaction_count(); + transaction_.load_flags = load_flags; + RunTransactionTest(cache_.http_cache(), transaction_); + return pre_transaction_count != transaction_count(); + } + + void AdvanceTime(int seconds) { + clock_->Advance(base::TimeDelta::FromSeconds(seconds)); + } + + int prefetch_reuse_mins() { return net::HttpCache::kPrefetchReuseMins; } + + // How many times this test has sent requests to the (fake) origin + // server. Every test case needs to make at least one request to initialise + // the cache. + int transaction_count() { + return cache_.network_layer()->transaction_count(); + } + + MockHttpCache cache_; + ScopedMockTransaction transaction_; + std::string response_headers_; + base::SimpleTestClock* clock_; +}; + +TEST_F(HttpCachePrefetchValidationTest, SkipValidationShortlyAfterPrefetch) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, ValidateLongAfterPrefetch) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(prefetch_reuse_mins() * net::kNumSecondsPerMinute); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, SkipValidationOnceOnly) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_NORMAL)); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, SkipValidationOnceReadOnly) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_ONLY_FROM_CACHE)); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, BypassCacheOverwritesPrefetch) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_BYPASS_CACHE)); + AdvanceTime(kRequireValidationSecs); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, + SkipValidationOnExistingEntryThatNeedsValidation) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); + AdvanceTime(kRequireValidationSecs); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_NORMAL)); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, + SkipValidationOnExistingEntryThatDoesNotNeedValidation) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_NORMAL)); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, PrefetchMultipleTimes) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + +TEST_F(HttpCachePrefetchValidationTest, ValidateOnDelayedSecondPrefetch) { + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_TRUE(TransactionRequiredNetwork(net::LOAD_PREFETCH)); + AdvanceTime(kRequireValidationSecs); + EXPECT_FALSE(TransactionRequiredNetwork(net::LOAD_NORMAL)); +} + // Framework for tests of stale-while-revalidate related functionality. With // the default settings (age=3601,stale-while-revalidate=7200,max-age=3600) it // will trigger the stale-while-revalidate asynchronous revalidation. Setting
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index 12620cb..50420db 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -44,8 +44,8 @@ params.host_resolver, params.cert_verifier, params.channel_id_service, params.transport_security_state, params.cert_transparency_verifier, params.cert_policy_enforcer, params.ssl_session_cache_shard, - params.proxy_service, params.ssl_config_service, - params.enable_ssl_connect_job_waiting, params.proxy_delegate, pool_type); + params.ssl_config_service, params.enable_ssl_connect_job_waiting, + pool_type); } } // unnamed namespace @@ -91,6 +91,7 @@ quic_load_server_info_timeout_ms(0), quic_disable_loading_server_info_for_new_servers(false), quic_load_server_info_timeout_srtt_multiplier(0.0f), + quic_enable_truncated_connection_ids(false), quic_clock(NULL), quic_random(NULL), quic_max_packet_length(kDefaultMaxPacketSize), @@ -136,6 +137,7 @@ params.quic_load_server_info_timeout_ms, params.quic_disable_loading_server_info_for_new_servers, params.quic_load_server_info_timeout_srtt_multiplier, + params.quic_enable_truncated_connection_ids, params.quic_connection_options), spdy_session_pool_(params.host_resolver, params.ssl_config_service,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 2850a0c..d22a197 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -119,6 +119,7 @@ int quic_load_server_info_timeout_ms; bool quic_disable_loading_server_info_for_new_servers; float quic_load_server_info_timeout_srtt_multiplier; + bool quic_enable_truncated_connection_ids; HostPortPair origin_to_force_quic_on; QuicClock* quic_clock; // Will be owned by QuicStreamFactory. QuicRandom* quic_random;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index b4ef356..97fc7db 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -173,6 +173,9 @@ proxy_ssl_config_.rev_checking_enabled = false; } + if (request_->load_flags & LOAD_PREFETCH) + response_.unused_since_prefetch = true; + // Channel ID is disabled if privacy mode is enabled for this request. if (request_->privacy_mode == PRIVACY_MODE_ENABLED) server_ssl_config_.channel_id_enabled = false; @@ -746,6 +749,9 @@ // Return OK and let the caller read the proxy's error page next_state_ = STATE_NONE; return OK; + } else if (result == ERR_HTTP_1_1_REQUIRED || + result == ERR_PROXY_HTTP_1_1_REQUIRED) { + return HandleHttp11Required(result); } // Handle possible handshake errors that may have occurred if the stream @@ -961,6 +967,11 @@ return result; } + if (result == ERR_HTTP_1_1_REQUIRED || + result == ERR_PROXY_HTTP_1_1_REQUIRED) { + return HandleHttp11Required(result); + } + // ERR_CONNECTION_CLOSED is treated differently at this point; if partial // response headers were received, we do the best we can to make sense of it // and send it back up the stack. @@ -1195,6 +1206,19 @@ return OK; } +int HttpNetworkTransaction::HandleHttp11Required(int error) { + DCHECK(error == ERR_HTTP_1_1_REQUIRED || + error == ERR_PROXY_HTTP_1_1_REQUIRED); + + if (error == ERR_HTTP_1_1_REQUIRED) { + HttpServerProperties::ForceHTTP11(&server_ssl_config_); + } else { + HttpServerProperties::ForceHTTP11(&proxy_ssl_config_); + } + ResetConnectionAndRequestForResend(); + return OK; +} + void HttpNetworkTransaction::HandleClientAuthError(int error) { if (server_ssl_config_.send_client_cert && (error == ERR_SSL_PROTOCOL_ERROR || IsClientCertificateError(error))) {
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index e69e550..229d397 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h
@@ -185,6 +185,10 @@ // Called to handle a client certificate request. int HandleCertificateRequest(int error); + // Called wherever ERR_HTTP_1_1_REQUIRED or + // ERR_PROXY_HTTP_1_1_REQUIRED has to be handled. + int HandleHttp11Required(int error); + // Called to possibly handle a client authentication error. void HandleClientAuthError(int error);
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 21a8c00..136791e 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc
@@ -562,12 +562,12 @@ CertVerifier* /* cert_verifier */) : ParentPool(0, 0, NULL, host_resolver, NULL, NULL) {} -template<> +template <> CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool( HostResolver* host_resolver, CertVerifier* /* cert_verifier */) - : HttpProxyClientSocketPool( - 0, 0, NULL, host_resolver, NULL, NULL, NULL, NULL) {} + : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL) { +} template <> CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc index 1f45882..6c421c5 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc
@@ -86,7 +86,6 @@ const base::TimeDelta& timeout_duration, TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, - HostResolver* host_resolver, Delegate* delegate, NetLog* net_log) : ConnectJob(group_name, timeout_duration, priority, delegate, @@ -94,7 +93,6 @@ params_(params), transport_pool_(transport_pool), ssl_pool_(ssl_pool), - resolver_(host_resolver), using_spdy_(false), protocol_negotiated_(kProtoUnknown), weak_ptr_factory_(this) { @@ -308,6 +306,9 @@ SetSocket(transport_socket_.Pass()); } + if (result == ERR_HTTP_1_1_REQUIRED) + return ERR_PROXY_HTTP_1_1_REQUIRED; + return result; } @@ -395,12 +396,10 @@ TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, HostResolver* host_resolver, - const ProxyDelegate* proxy_delegate, NetLog* net_log) : transport_pool_(transport_pool), ssl_pool_(ssl_pool), host_resolver_(host_resolver), - proxy_delegate_(proxy_delegate), net_log_(net_log) { base::TimeDelta max_pool_timeout = base::TimeDelta(); @@ -430,7 +429,6 @@ ConnectionTimeout(), transport_pool_, ssl_pool_, - host_resolver_, delegate, net_log_)); } @@ -448,7 +446,6 @@ HostResolver* host_resolver, TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, - const ProxyDelegate* proxy_delegate, NetLog* net_log) : transport_pool_(transport_pool), ssl_pool_(ssl_pool), @@ -458,7 +455,6 @@ new HttpProxyConnectJobFactory(transport_pool, ssl_pool, host_resolver, - proxy_delegate, net_log)) { // We should always have a |transport_pool_| except in unit tests. if (transport_pool_)
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index 8bdbfc2..b42f628 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h
@@ -108,7 +108,6 @@ const base::TimeDelta& timeout_duration, TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, - HostResolver* host_resolver, Delegate* delegate, NetLog* net_log); ~HttpProxyConnectJob() override; @@ -164,7 +163,6 @@ scoped_refptr<HttpProxySocketParams> params_; TransportClientSocketPool* const transport_pool_; SSLClientSocketPool* const ssl_pool_; - HostResolver* const resolver_; State next_state_; CompletionCallback callback_; @@ -196,7 +194,6 @@ HostResolver* host_resolver, TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, - const ProxyDelegate* proxy_delegate, NetLog* net_log); ~HttpProxyClientSocketPool() override; @@ -260,7 +257,6 @@ TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, HostResolver* host_resolver, - const ProxyDelegate* proxy_delegate, NetLog* net_log); // ClientSocketPoolBase::ConnectJobFactory methods. @@ -275,7 +271,6 @@ TransportClientSocketPool* const transport_pool_; SSLClientSocketPool* const ssl_pool_; HostResolver* const host_resolver_; - const ProxyDelegate* proxy_delegate_; NetLog* net_log_; base::TimeDelta timeout_;
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 909da62..cef53e9 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -189,7 +189,6 @@ NULL, &transport_socket_pool_, &ssl_socket_pool_, - NULL, NULL) {} virtual ~HttpProxyClientSocketPoolTest() {
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc index 630a59e..b5b94c4 100644 --- a/net/http/http_response_info.cc +++ b/net/http/http_response_info.cc
@@ -91,6 +91,8 @@ // This bit is set if ssl_info has SCTs. RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS = 1 << 20, + RESPONSE_INFO_UNUSED_SINCE_PREFETCH = 1 << 21, + // TODO(darin): Add other bits to indicate alternate request methods. // For now, we don't support storing those. }; @@ -103,6 +105,7 @@ was_npn_negotiated(false), was_fetched_via_proxy(false), did_use_http_auth(false), + unused_since_prefetch(false), connection_info(CONNECTION_INFO_UNKNOWN) { } @@ -115,6 +118,7 @@ was_fetched_via_proxy(rhs.was_fetched_via_proxy), proxy_server(rhs.proxy_server), did_use_http_auth(rhs.did_use_http_auth), + unused_since_prefetch(rhs.unused_since_prefetch), socket_address(rhs.socket_address), npn_negotiated_protocol(rhs.npn_negotiated_protocol), connection_info(rhs.connection_info), @@ -140,6 +144,7 @@ was_npn_negotiated = rhs.was_npn_negotiated; was_fetched_via_proxy = rhs.was_fetched_via_proxy; did_use_http_auth = rhs.did_use_http_auth; + unused_since_prefetch = rhs.unused_since_prefetch; socket_address = rhs.socket_address; npn_negotiated_protocol = rhs.npn_negotiated_protocol; connection_info = rhs.connection_info; @@ -277,6 +282,8 @@ did_use_http_auth = (flags & RESPONSE_INFO_USE_HTTP_AUTHENTICATION) != 0; + unused_since_prefetch = (flags & RESPONSE_INFO_UNUSED_SINCE_PREFETCH) != 0; + return true; } @@ -308,6 +315,8 @@ flags |= RESPONSE_INFO_HAS_CONNECTION_INFO; if (did_use_http_auth) flags |= RESPONSE_INFO_USE_HTTP_AUTHENTICATION; + if (unused_since_prefetch) + flags |= RESPONSE_INFO_UNUSED_SINCE_PREFETCH; if (!ssl_info.signed_certificate_timestamps.empty()) flags |= RESPONSE_INFO_HAS_SIGNED_CERTIFICATE_TIMESTAMPS;
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h index df3e300..a7a35f9 100644 --- a/net/http/http_response_info.h +++ b/net/http/http_response_info.h
@@ -95,6 +95,10 @@ // Whether the request use http proxy or server authentication. bool did_use_http_auth; + // True if the resource was originally fetched for a prefetch and has not been + // used since. + bool unused_since_prefetch; + // Remote address of the socket which fetched this resource. // // NOTE: If the response was served from the cache (was_cached is true),
diff --git a/net/http/http_response_info_unittest.cc b/net/http/http_response_info_unittest.cc new file mode 100644 index 0000000..07e4b6d --- /dev/null +++ b/net/http/http_response_info_unittest.cc
@@ -0,0 +1,49 @@ +// Copyright 2015 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. + +#include "net/http/http_response_info.h" + +#include "base/pickle.h" +#include "net/http/http_response_headers.h" +#include "testing/gtest/include/gtest/gtest.h" + +class HttpResponseInfoTest : public testing::Test { + protected: + void SetUp() override { + response_info_.headers = new net::HttpResponseHeaders(""); + } + + void PickleAndRestore(const net::HttpResponseInfo& response_info, + net::HttpResponseInfo* restored_response_info) const { + Pickle pickle; + response_info.Persist(&pickle, false, false); + bool truncated = false; + restored_response_info->InitFromPickle(pickle, &truncated); + } + + net::HttpResponseInfo response_info_; +}; + +TEST_F(HttpResponseInfoTest, UnusedSincePrefetchDefault) { + EXPECT_FALSE(response_info_.unused_since_prefetch); +} + +TEST_F(HttpResponseInfoTest, UnusedSincePrefetchCopy) { + response_info_.unused_since_prefetch = true; + net::HttpResponseInfo response_info_clone(response_info_); + EXPECT_TRUE(response_info_clone.unused_since_prefetch); +} + +TEST_F(HttpResponseInfoTest, UnusedSincePrefetchPersistFalse) { + net::HttpResponseInfo restored_response_info; + PickleAndRestore(response_info_, &restored_response_info); + EXPECT_FALSE(restored_response_info.unused_since_prefetch); +} + +TEST_F(HttpResponseInfoTest, UnusedSincePrefetchPersistTrue) { + response_info_.unused_since_prefetch = true; + net::HttpResponseInfo restored_response_info; + PickleAndRestore(response_info_, &restored_response_info); + EXPECT_TRUE(restored_response_info.unused_since_prefetch); +}
diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc index 25725a8..514278c 100644 --- a/net/http/http_server_properties.cc +++ b/net/http/http_server_properties.cc
@@ -7,6 +7,8 @@ #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/strings/stringprintf.h" +#include "net/socket/ssl_client_socket.h" +#include "net/ssl/ssl_config.h" namespace net { @@ -106,4 +108,10 @@ is_broken ? " (broken)" : ""); } +// static +void HttpServerProperties::ForceHTTP11(SSLConfig* ssl_config) { + ssl_config->next_protos.clear(); + ssl_config->next_protos.push_back(kProtoHTTP11); +} + } // namespace net
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h index ce939e1..79ce33d 100644 --- a/net/http/http_server_properties.h +++ b/net/http/http_server_properties.h
@@ -20,6 +20,8 @@ namespace net { +struct SSLConfig; + enum AlternateProtocolUsage { // Alternate Protocol was used without racing a normal connection. ALTERNATE_PROTOCOL_USAGE_NO_RACE = 0, @@ -168,6 +170,19 @@ virtual void SetSupportsSpdy(const HostPortPair& server, bool support_spdy) = 0; + // Returns true if |server| has required HTTP/1.1 via HTTP/2 error code. + virtual bool RequiresHTTP11(const HostPortPair& server) = 0; + + // Require HTTP/1.1 on subsequent connections. Not persisted. + virtual void SetHTTP11Required(const HostPortPair& server) = 0; + + // Modify SSLConfig to force HTTP/1.1. + static void ForceHTTP11(SSLConfig* ssl_config); + + // Modify SSLConfig to force HTTP/1.1 if necessary. + virtual void MaybeForceHTTP11(const HostPortPair& server, + SSLConfig* ssl_config) = 0; + // Returns true if |server| has an Alternate-Protocol header. virtual bool HasAlternateProtocol(const HostPortPair& server) = 0;
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc index f571c11..a8bc04a 100644 --- a/net/http/http_server_properties_impl.cc +++ b/net/http/http_server_properties_impl.cc
@@ -198,6 +198,31 @@ spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy); } +bool HttpServerPropertiesImpl::RequiresHTTP11( + const net::HostPortPair& host_port_pair) { + DCHECK(CalledOnValidThread()); + if (host_port_pair.host().empty()) + return false; + + return (http11_servers_.find(host_port_pair) != http11_servers_.end()); +} + +void HttpServerPropertiesImpl::SetHTTP11Required( + const net::HostPortPair& host_port_pair) { + DCHECK(CalledOnValidThread()); + if (host_port_pair.host().empty()) + return; + + http11_servers_.insert(host_port_pair); +} + +void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server, + SSLConfig* ssl_config) { + if (RequiresHTTP11(server)) { + ForceHTTP11(ssl_config); + } +} + bool HttpServerPropertiesImpl::HasAlternateProtocol( const HostPortPair& server) { if (g_forced_alternate_protocol)
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h index fc98689..5ff6f48 100644 --- a/net/http/http_server_properties_impl.h +++ b/net/http/http_server_properties_impl.h
@@ -6,6 +6,7 @@ #define NET_HTTP_HTTP_SERVER_PROPERTIES_IMPL_H_ #include <map> +#include <set> #include <string> #include <vector> @@ -82,6 +83,16 @@ // Add |server| into the persistent store. void SetSupportsSpdy(const HostPortPair& server, bool support_spdy) override; + // Returns true if |server| has required HTTP/1.1 via HTTP/2 error code. + bool RequiresHTTP11(const HostPortPair& server) override; + + // Require HTTP/1.1 on subsequent connections. Not persisted. + void SetHTTP11Required(const HostPortPair& server) override; + + // Modify SSLConfig to force HTTP/1.1 if necessary. + void MaybeForceHTTP11(const HostPortPair& server, + SSLConfig* ssl_config) override; + // Returns true if |server| has an Alternate-Protocol header. bool HasAlternateProtocol(const HostPortPair& server) override; @@ -159,6 +170,7 @@ typedef base::MRUCache<std::string, bool> SpdyServerHostPortMap; typedef std::map<HostPortPair, HostPortPair> CanonicalHostMap; typedef std::vector<std::string> CanonicalSufficList; + typedef std::set<HostPortPair> Http11ServerHostPortSet; // List of broken host:ports and the times when they can be expired. struct BrokenAlternateProtocolEntry { HostPortPair server; @@ -178,6 +190,7 @@ void ScheduleBrokenAlternateProtocolMappingsExpiration(); SpdyServerHostPortMap spdy_servers_map_; + Http11ServerHostPortSet http11_servers_; AlternateProtocolMap alternate_protocol_map_; BrokenAlternateProtocolList broken_alternate_protocol_list_;
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc index af72884..873c8ca 100644 --- a/net/http/http_server_properties_manager.cc +++ b/net/http/http_server_properties_manager.cc
@@ -146,6 +146,26 @@ ScheduleUpdatePrefsOnNetworkThread(); } +bool HttpServerPropertiesManager::RequiresHTTP11( + const net::HostPortPair& server) { + DCHECK(network_task_runner_->RunsTasksOnCurrentThread()); + return http_server_properties_impl_->RequiresHTTP11(server); +} + +void HttpServerPropertiesManager::SetHTTP11Required( + const net::HostPortPair& server) { + DCHECK(network_task_runner_->RunsTasksOnCurrentThread()); + + http_server_properties_impl_->SetHTTP11Required(server); + ScheduleUpdatePrefsOnNetworkThread(); +} + +void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair& server, + SSLConfig* ssl_config) { + DCHECK(network_task_runner_->RunsTasksOnCurrentThread()); + http_server_properties_impl_->MaybeForceHTTP11(server, ssl_config); +} + bool HttpServerPropertiesManager::HasAlternateProtocol( const HostPortPair& server) { DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h index 4a8c71b..5be571f 100644 --- a/net/http/http_server_properties_manager.h +++ b/net/http/http_server_properties_manager.h
@@ -92,6 +92,16 @@ // persisitent store. Should only be called from IO thread. void SetSupportsSpdy(const HostPortPair& server, bool support_spdy) override; + // Returns true if |server| has required HTTP/1.1 via HTTP/2 error code. + bool RequiresHTTP11(const HostPortPair& server) override; + + // Require HTTP/1.1 on subsequent connections. Not persisted. + void SetHTTP11Required(const HostPortPair& server) override; + + // Modify SSLConfig to force HTTP/1.1 if necessary. + void MaybeForceHTTP11(const HostPortPair& server, + SSLConfig* ssl_config) override; + // Returns true if |server| has an Alternate-Protocol header. bool HasAlternateProtocol(const HostPortPair& server) override;
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 8369443..d531476 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -817,6 +817,16 @@ false /* not a proxy server */); } + base::WeakPtr<HttpServerProperties> http_server_properties = + session_->http_server_properties(); + if (http_server_properties) { + http_server_properties->MaybeForceHTTP11(origin_, &server_ssl_config_); + if (proxy_info_.is_http() || proxy_info_.is_https()) { + http_server_properties->MaybeForceHTTP11( + proxy_info_.proxy_server().host_port_pair(), &proxy_ssl_config_); + } + } + if (IsPreconnecting()) { DCHECK(!stream_factory_->for_websockets_); return PreconnectSocketsForHttpRequest(
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc index beac733..ff07a0e 100644 --- a/net/http/http_stream_factory_impl_unittest.cc +++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -387,12 +387,19 @@ : ParentPool(0, 0, nullptr, host_resolver, nullptr, nullptr), last_num_streams_(-1) {} -template<> +template <> CapturePreconnectsHttpProxySocketPool::CapturePreconnectsSocketPool( - HostResolver* host_resolver, CertVerifier* /* cert_verifier */) - : HttpProxyClientSocketPool( - 0, 0, nullptr, host_resolver, nullptr, nullptr, nullptr, nullptr), - last_num_streams_(-1) {} + HostResolver* host_resolver, + CertVerifier* /* cert_verifier */) + : HttpProxyClientSocketPool(0, + 0, + nullptr, + host_resolver, + nullptr, + nullptr, + nullptr), + last_num_streams_(-1) { +} template <> CapturePreconnectsSSLSocketPool::CapturePreconnectsSocketPool(
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc index dbbca6c..f3bbf98 100644 --- a/net/http/http_transaction_test_util.cc +++ b/net/http/http_transaction_test_util.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "base/strings/stringprintf.h" +#include "base/time/clock.h" #include "base/time/time.h" #include "net/base/load_flags.h" #include "net/base/load_timing_info.h" @@ -399,14 +400,14 @@ "%s\n%s\n", resp_status.c_str(), resp_headers.c_str()); std::replace(header_data.begin(), header_data.end(), '\n', '\0'); - response_.request_time = base::Time::Now(); + response_.request_time = transaction_factory_->Now(); if (!t->request_time.is_null()) response_.request_time = t->request_time; response_.was_cached = false; response_.network_accessed = true; - response_.response_time = base::Time::Now(); + response_.response_time = transaction_factory_->Now(); if (!t->response_time.is_null()) response_.response_time = t->response_time; @@ -418,6 +419,9 @@ if (net_log.net_log()) socket_log_id_ = net_log.net_log()->NextID(); + if (request_->load_flags & net::LOAD_PREFETCH) + response_.unused_since_prefetch = true; + if (test_mode_ & TEST_MODE_SYNC_NET_START) return net::OK; @@ -454,7 +458,9 @@ : transaction_count_(0), done_reading_called_(false), stop_caching_called_(false), - last_create_transaction_priority_(net::DEFAULT_PRIORITY) {} + last_create_transaction_priority_(net::DEFAULT_PRIORITY), + clock_(nullptr) { +} MockNetworkLayer::~MockNetworkLayer() {} @@ -486,6 +492,17 @@ return NULL; } +void MockNetworkLayer::SetClock(base::Clock* clock) { + DCHECK(!clock_); + clock_ = clock; +} + +base::Time MockNetworkLayer::Now() { + if (clock_) + return clock_->Now(); + return base::Time::Now(); +} + //----------------------------------------------------------------------------- // helpers
diff --git a/net/http/http_transaction_test_util.h b/net/http/http_transaction_test_util.h index e6e8312..ce3bb97 100644 --- a/net/http/http_transaction_test_util.h +++ b/net/http/http_transaction_test_util.h
@@ -291,11 +291,23 @@ net::HttpCache* GetCache() override; net::HttpNetworkSession* GetSession() override; + // The caller must guarantee that |clock| will outlive this object. + void SetClock(base::Clock* clock); + base::Clock* clock() const { return clock_; } + + // The current time (will use clock_ if it is non NULL). + base::Time Now(); + private: int transaction_count_; bool done_reading_called_; bool stop_caching_called_; net::RequestPriority last_create_transaction_priority_; + + // By default clock_ is NULL but it can be set to a custom clock by test + // frameworks using SetClock. + base::Clock* clock_; + base::WeakPtr<MockNetworkTransaction> last_transaction_; };
diff --git a/net/http/transport_security_state_static.certs b/net/http/transport_security_state_static.certs index 48a0a3f..a41c28e 100644 --- a/net/http/transport_security_state_static.certs +++ b/net/http/transport_security_state_static.certs
@@ -1044,100 +1044,6 @@ R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- -Tor2web ------BEGIN CERTIFICATE----- -MIIEgjCCA2qgAwIBAgISESHiIwbyj8tbXjvCF3lADzOxMA0GCSqGSIb3DQEBBQUA -MC4xETAPBgNVBAoTCEFscGhhU1NMMRkwFwYDVQQDExBBbHBoYVNTTCBDQSAtIEcy -MB4XDTExMTIwNTEyMzYzMVoXDTE2MTIwNTA0NTk1OFowSDELMAkGA1UEBhMCREUx -ITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEWMBQGA1UEAxQNKi50 -b3Iyd2ViLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJZ/olAy -7o+W0soGoxD5xWXGVKa3cQdv/daqwDyFhGINhVgsm3GS3Oo2XLAYvyvlUFceuy2v -fRecb431lh7xtLhPpr5nZL/T0cjUxffstxSt5HI5BQ5Q/TFLA4iJQDzJgiNld0DJ -RYd8gGADwh5cVBjvAtRouUbFw75b1/4hR3kJnQsHutvglLjWHmZtf/ZoZ39CbR1a -LBJpEPoWkVqJ9LrvgA+aJ1wmi+oKLfSYQkDEn30DBeVxBZBp6tRc93eGqK1skzpG -2Sof9cmlRNIXp8plYBvtsV3LKrFlBXvQRr+hhpjrqGNib02ynyJdRij7tOCLHfqW -UitjVQVOWoGs49MCAwEAAaOCAX4wggF6MA4GA1UdDwEB/wQEAwIFoDBNBgNVHSAE -RjBEMEIGCisGAQQBoDIBCgowNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv -YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wJQYDVR0RBB4wHIINKi50b3Iyd2ViLm9y -Z4ILdG9yMndlYi5vcmcwCQYDVR0TBAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYI -KwYBBQUHAwIwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDIuYWxwaGFzc2wu -Y29tL2dzL2dzYWxwaGFnMi5jcmwwTAYIKwYBBQUHAQEEQDA+MDwGCCsGAQUFBzAC -hjBodHRwOi8vc2VjdXJlMi5hbHBoYXNzbC5jb20vY2FjZXJ0L2dzYWxwaGFnMi5j -cnQwHQYDVR0OBBYEFLE3Bo2XTl90LORxYwgr2pPD06tSMB8GA1UdIwQYMBaAFBTq -GVXwDg0yxh90M7eOZhpMEjEeMA0GCSqGSIb3DQEBBQUAA4IBAQAyOUFr9R7EKzPP -B8UsWT5ckA/TNlOqbdo6fvqshQfH/FHUQja28IbYcpBiC2XsMov+r7WNiH3lh1CF -WKT1SwfO6a0I/58CL36pL/asWv/onlDYgAsCwr1j7qcSiROZlpLD+tehiCE70afa -+3VlyoGsbKVZ2A7MrXnxIaYhmhe4Y+238PwyBT74fpBvwoFIcbccwWEST8J2y2YW -4+SWm4pJtcJxJH/uJ8qzvZLwjzcgFKQbBLVtl+SRAblFSj64YuO9Xu97+nta1HuL -fmLvlwIO/yvONapjePASH6prPdmWvj3Clqz381mkU1pLpxTgHQqeoP87DYi8z084 -+maO9AY4 ------END CERTIFICATE----- - -AlphaSSL_G2 ------BEGIN CERTIFICATE----- -MIIELzCCAxegAwIBAgILBAAAAAABL07hNwIwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMTA0MTMxMDAw -MDBaFw0yMjA0MTMxMDAwMDBaMC4xETAPBgNVBAoTCEFscGhhU1NMMRkwFwYDVQQD -ExBBbHBoYVNTTCBDQSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAw/BliN8b3caChy/JC7pUxmM/RnWsSxQfmHKLHBD/CalSbi9l32WEP1+Bstjx -T9fwWrvJr9Ax3SZGKpme2KmjtrgHxMlx95WE79LqH1Sg5b7kQSFWMRBkfR5jjpxx -XDygLt5n3MiaIPB1yLC2J4Hrlw3uIkWlwi80J+zgWRJRsx4F5Tgg0mlZelkXvhpL -OQgSeTObZGj+WIHdiAxqulm0ryRPYeDK/Bda0jxyq6dMt7nqLeP0P5miTcgdWPh/ -UzWO1yKIt2F2CBMTaWawV1kTMQpwgiuT1/biQBXQHQFyxxNYalrsGYkWPODIjYYq -+jfwNTLd7OX+gI73BWe0i0J1NQIDAQABo4IBIzCCAR8wDgYDVR0PAQH/BAQDAgEG -MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFBTqGVXwDg0yxh90M7eOZhpM -EjEeMEUGA1UdIAQ+MDwwOgYEVR0gADAyMDAGCCsGAQUFBwIBFiRodHRwczovL3d3 -dy5hbHBoYXNzbC5jb20vcmVwb3NpdG9yeS8wMwYDVR0fBCwwKjAooCagJIYiaHR0 -cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LmNybDA9BggrBgEFBQcBAQQxMC8w -LQYIKwYBBQUHMAGGIWh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL3Jvb3RyMTAf -BgNVHSMEGDAWgBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUFAAOC -AQEABjBCm89JAn6J6fWDWj0C87yyRt5KUO65mpBz2qBcJsqCrA6ts5T6KC6y5kk/ -UHcOlS9o82U8nxTyaGCStvwEDfakGKFpYA3jnWhbvJ4LOFmNIdoj+pmKCbkfpy61 -VWxH50Hs5uJ/r1VEOeCsdO5l0/qrUUgw8T53be3kD0CY7kd/jbZYJ82Sb2AjzAKb -WSh4olGd0Eqc5ZNemI/L7z/K/uCvpMlbbkBYpZItvV1lVcW/fARB2aS1gOmUYAIQ -OGoICNdTHC2Tr8kTe9RsxDrE+4CsuzpOVHrNTrM+7fH8EU6f9fMUvLmxMc72qi+l -+MPpZqmyIJ3E+LgDYqeF0RhjWw== ------END CERTIFICATE----- - -Libertylavabitcom ------BEGIN CERTIFICATE----- -MIIGWjCCBUKgAwIBAgIHAMn6RGIIgjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE -BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY -BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm -aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5 -IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky -ODcwHhcNMTMxMDExMDgzNjAyWhcNMTQxMDExMDgzNjAyWjBBMSEwHwYDVQQLExhE -b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxHDAaBgNVBAMTE2xpYmVydHkubGF2YWJp -dC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo/gQ2t5YtS2dj -BhIo2ke667uC2qhnUbnroyuqyf+GZafWZC/cmPYpkAWclu14ETBsR3u+6QtDHhOe -q3OBN0+IVLu5QwYSB2sqYUwyOHZ342uHQktWpPvNiwNHyfl1LsHL4WLuvQw3stK4 -DR+l6H/Ex11bl4KVvfk8uy+kXawcIQv7gr69OwEFEmGqeLSqr+fZdegLKPY20Ujx -WHSe8ErtW0eMY2A/DvrDrnfw+rVX5sxJIKk77AutIoyt+Ce2TwMVQtfbeQVWy91g -ST+sqC69wI5BOSguV5zECqIP1zxo939VVVciNGA3+3gyLJa+NDDpbT8xCwXClXN4 -3iektxfP7OgPjPwhDueZNhq54mA5mBY+qdkLyCmvURiczSNeoDTWouqaJq1lKjuh -CgkAhgoaLueAQv+uGNlVFtbQHApEvYcdz8XTqoL24wf3kadu6vxhrYVS+hguVVEE -YOc7LJsiQ3ERDjh1naFlL9h5khn6qhjw77oS6PWaCIJT8GfD8bjqCozdOdS1e+Sh -Bbp2Yg48m/XyQ3ocpEUmTt7n3fRv41XOY4tmBhloqkdPIDccl5deUhI//1VgycJv -uDqsMgRhyZvdS1kxhDAwbi1GtomURGdB/9kptYshUrR6xk1EP60pjWNxuvB7HMPg -seGNxPa15U/4z+5h8iSFdKa2TLkk7wIDAQABo4IByzCCAccwDwYDVR0TAQH/BAUw -AwEBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDgYDVR0PAQH/BAQD -AgWgMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Rz -MS0xMDAuY3JsMFMGA1UdIARMMEowSAYLYIZIAYb9bQEHFwEwOTA3BggrBgEFBQcC -ARYraHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzCB -gAYIKwYBBQUHAQEEdDByMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nb2RhZGR5 -LmNvbS8wSgYIKwYBBQUHMAKGPmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j -b20vcmVwb3NpdG9yeS9nZF9pbnRlcm1lZGlhdGUuY3J0MB8GA1UdIwQYMBaAFP2s -YTKTbEXW4u6FX5q653aZaMznMDcGA1UdEQQwMC6CE2xpYmVydHkubGF2YWJpdC5j -b22CF3d3dy5saWJlcnR5LmxhdmFiaXQuY29tMB0GA1UdDgQWBBSVRSbXCJKN6lms -ZtlccHBz/xVLwDANBgkqhkiG9w0BAQUFAAOCAQEAKja1YxyoTuHD1RV4L7wULpiy -ot4Z3OEuoOZTPJsoHfUCtOtKlUu2ZSwp5+IpaLnC3iCIxy1Yb6qu6Li5dqgtOkxl -4JqrOooQ9IUzuTLhSzPf6rEtw9gnYN/dpQ2q0YLh+K5SgRUm9y0PHBV4acfSh2TJ -vyaXDmuonX5zG7u3nz/oCo/qziW46Phz/leMhCAgLnZUYcAv6KPET+RMRmt4n8gg -C0xlOcCQbMh9VIPZ0WSnmdFn5DUCW+oVlwhxDB/3CvWIa0k/WI6NNW8vg+VdSyW7 -p/dp4mikGH37Tc5VAhcYMbAem69nSg7Qfrs35tak/JPJlx1LWayERGHLvTy7Ag== ------END CERTIFICATE----- - GlobalSignRootCA -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h index ae9834e..c512902 100644 --- a/net/http/transport_security_state_static.h +++ b/net/http/transport_security_state_static.h
@@ -460,18 +460,6 @@ "\x30\xa4\xe6\x4f\xde\x76\x8a\xfc\xed\x5a" "\x90\x84\x28\x30\x46\x79\x2c\x29\x15\x70"; -static const char kSPKIHash_Tor2web[] = - "\x19\xe5\xb5\x87\x1b\xd4\x83\x2e\xc8\xf5" - "\x94\x97\xfe\xc6\x5e\xfb\x48\xe3\x33\xb1"; - -static const char kSPKIHash_AlphaSSL_G2[] = - "\xe5\x24\xe9\x8e\x31\x7d\xc8\xfc\xad\x90" - "\x53\x7c\x91\xe7\x0d\xa4\x70\x93\x90\x5f"; - -static const char kSPKIHash_Libertylavabitcom[] = - "\x41\xbb\x3b\x8b\xc7\xcf\x3d\x13\x3f\x17" - "\xb3\x25\x7e\xe4\x03\xca\x8a\x5c\x6d\x36"; - static const char kSPKIHash_GlobalSignRootCA[] = "\x87\xdb\xd4\x5f\xb0\x92\x8d\x4e\x1d\xf8" "\x15\x67\xe7\xf2\xab\xaf\xd6\x2b\x67\x75"; @@ -632,15 +620,6 @@ kSPKIHash_GlobalSignRootCA_R3, NULL, }; -static const char* const kTor2webAcceptableCerts[] = { - kSPKIHash_AlphaSSL_G2, - kSPKIHash_Tor2web, - NULL, -}; -static const char* const kLavabitAcceptableCerts[] = { - kSPKIHash_Libertylavabitcom, - NULL, -}; static const char* const kDropboxAcceptableCerts[] = { kSPKIHash_DigiCertAssuredIDRoot, kSPKIHash_DigiCertGlobalRoot, @@ -687,8 +666,6 @@ {kTorAcceptableCerts, kNoRejectedPublicKeys}, {kTwitterComAcceptableCerts, kNoRejectedPublicKeys}, {kTwitterCDNAcceptableCerts, kNoRejectedPublicKeys}, - {kTor2webAcceptableCerts, kNoRejectedPublicKeys}, - {kLavabitAcceptableCerts, kNoRejectedPublicKeys}, {kDropboxAcceptableCerts, kNoRejectedPublicKeys}, {kFacebookAcceptableCerts, kNoRejectedPublicKeys}, {kSpideroakAcceptableCerts, kNoRejectedPublicKeys}, @@ -700,1212 +677,1807 @@ // value has the MSB set then it represents a literal leaf value. Otherwise // it's a pointer to the n'th element of the array. static const uint8 kHSTSHuffmanTree[] = { - 0xec, 0xf2, 0x00, 0x80, 0xed, 0xae, 0xe7, 0x02, 0xb5, 0xb1, 0xf1, 0x04, - 0xb3, 0xb2, 0x05, 0x06, 0xfa, 0x07, 0xf6, 0x08, 0xeb, 0x09, 0x0a, 0xe3, - 0xe1, 0x0b, 0x03, 0x0c, 0x01, 0x0d, 0xe2, 0xe8, 0x0f, 0xf3, 0x10, 0xe5, - 0xff, 0x11, 0xee, 0xf4, 0xef, 0x13, 0xf7, 0xe4, 0xb9, 0xb7, 0xb6, 0x16, - 0xb8, 0x17, 0x18, 0xb0, 0xb4, 0x19, 0x1a, 0xea, 0xf8, 0x1b, 0xad, 0x1c, - 0x1d, 0xf0, 0x15, 0x1e, 0xf9, 0xe6, 0x20, 0xf5, 0x21, 0xe9, 0x1f, 0x22, - 0x14, 0x23, 0x12, 0x24, 0x0e, 0x25, + 0xec, 0xf2, 0x00, 0x80, 0xed, 0xae, 0xe7, 0x02, + 0xb5, 0xb1, 0xf1, 0x04, 0xb3, 0xb2, 0x05, 0x06, + 0xfa, 0x07, 0xf6, 0x08, 0xeb, 0x09, 0x0a, 0xe3, + 0xe1, 0x0b, 0x03, 0x0c, 0x01, 0x0d, 0xe2, 0xe8, + 0x0f, 0xf3, 0x10, 0xe5, 0xff, 0x11, 0xf4, 0xee, + 0xef, 0x13, 0xf7, 0xe4, 0xb9, 0xb7, 0xb6, 0x16, + 0xb8, 0x17, 0x18, 0xb0, 0xb4, 0x19, 0x1a, 0xea, + 0xf8, 0x1b, 0xad, 0x1c, 0xf9, 0xe6, 0x1d, 0x1e, + 0x15, 0x1f, 0xf0, 0xf5, 0x21, 0xe9, 0x20, 0x22, + 0x14, 0x23, 0x12, 0x24, 0x0e, 0x25, }; static const uint8 kPreloadedHSTSData[] = { - 0xfe, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x25, 0x9f, 0x02, 0x66, 0x21, 0xa2, - 0x2d, 0x9a, 0xe9, 0x2a, 0x4c, 0x54, 0xbb, 0x03, 0x4b, 0xd8, 0xb4, 0xfe, - 0xdd, 0x87, 0x6a, 0xfd, 0x4a, 0x59, 0xa8, 0x9f, 0x9f, 0xaf, 0xba, 0xb7, - 0x0e, 0x86, 0x3f, 0x3c, 0x43, 0x9f, 0xe1, 0x6d, 0x7d, 0x19, 0x5f, 0x3a, - 0x4b, 0xb4, 0xd1, 0xba, 0xa1, 0xe1, 0xe0, 0x82, 0x7f, 0x2e, 0xc1, 0x33, - 0x10, 0xd1, 0x51, 0x4f, 0xff, 0x6b, 0xfa, 0x5f, 0x9b, 0xba, 0x39, 0x6b, - 0xe4, 0xe9, 0xf0, 0x26, 0x62, 0x1a, 0x2b, 0xd9, 0xf7, 0xdd, 0x93, 0xda, - 0x0e, 0x92, 0xec, 0xf7, 0x00, 0xc2, 0x7f, 0xe5, 0xe3, 0xd7, 0x60, 0x99, - 0x88, 0x68, 0x91, 0xa7, 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, - 0x27, 0x89, 0xff, 0xcb, 0x56, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0xfe, - 0x7f, 0xf2, 0xd5, 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x86, 0x9f, 0xfc, - 0xb5, 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, 0xa2, 0x27, 0xfd, 0x8f, 0x5d, - 0x82, 0x66, 0x21, 0xa2, 0x91, 0x9f, 0xff, 0xaf, 0x9d, 0x37, 0x85, 0xec, - 0x73, 0xba, 0xd5, 0xbb, 0x2a, 0x4b, 0x52, 0x29, 0x3a, 0x91, 0xa7, 0xfe, - 0x5e, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0x42, 0x28, 0x5d, 0x81, 0x7c, - 0x70, 0x28, 0x81, 0xd7, 0x3b, 0x08, 0x57, 0xa8, 0x9b, 0x49, 0x9d, 0xa9, - 0x3b, 0x8a, 0x55, 0x52, 0xf6, 0x1e, 0xce, 0xc5, 0x93, 0xff, 0x96, 0xac, - 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x13, 0x9c, 0xff, 0xe5, 0xab, 0x1e, 0xbb, - 0x04, 0xcc, 0x43, 0x45, 0x13, 0x3f, 0xf0, 0x3d, 0x7a, 0xfd, 0x5c, 0x7f, - 0xfb, 0x3a, 0x01, 0x1d, 0x75, 0x52, 0xf5, 0x4a, 0x7f, 0x2e, 0xc1, 0x33, - 0x10, 0xd1, 0x0e, 0x4f, 0x81, 0x33, 0x10, 0xd1, 0x17, 0xcf, 0xea, 0xdf, - 0x3a, 0xbe, 0xf0, 0xe9, 0xab, 0x49, 0xd3, 0xdb, 0x7b, 0x79, 0x2a, 0x14, - 0x6e, 0xb0, 0x5e, 0x4b, 0xb4, 0x5e, 0xb8, 0x60, 0x2d, 0xb3, 0xff, 0x96, - 0xac, 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x13, 0x24, 0xfe, 0x5d, 0x82, 0x66, - 0x21, 0xa2, 0xde, 0x9f, 0xfc, 0xb5, 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, - 0xa4, 0xe7, 0xda, 0x5b, 0xbf, 0xd6, 0xdd, 0xe3, 0xa1, 0x95, 0x22, 0x3e, - 0x1f, 0x16, 0x6b, 0x55, 0x27, 0x47, 0x7e, 0x14, 0xa7, 0xf2, 0xec, 0x13, - 0x31, 0x0d, 0x10, 0xec, 0xff, 0xe5, 0xab, 0x1e, 0xbb, 0x04, 0xcc, 0x43, - 0x44, 0xb1, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0x8c, 0x27, 0xc0, 0x99, - 0x88, 0x68, 0x8f, 0x67, 0xab, 0x94, 0xba, 0x3a, 0x79, 0x78, 0xf5, 0xd9, - 0xea, 0x6c, 0xc2, 0x7f, 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x61, 0xcf, 0xe5, - 0xd8, 0x26, 0x62, 0x1a, 0x2e, 0x78, 0x64, 0xf2, 0xa8, 0x3b, 0x7a, 0x97, - 0xe1, 0x1e, 0xa3, 0x8d, 0x9d, 0xcf, 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x21, - 0xe9, 0xf0, 0x26, 0x62, 0x1a, 0x22, 0x69, 0xff, 0xd7, 0xbc, 0xd6, 0x99, - 0xd3, 0xec, 0x18, 0xe9, 0xb6, 0xa3, 0xa7, 0xff, 0x5e, 0xbc, 0x51, 0x56, - 0xfd, 0x3b, 0x65, 0x1d, 0x14, 0x9f, 0x1e, 0x85, 0xa7, 0xb7, 0xee, 0x78, - 0x34, 0x42, 0xf2, 0x5d, 0xa6, 0x5f, 0xa3, 0x0a, 0xc2, 0xaf, 0xd2, 0x39, - 0xc1, 0x88, 0x74, 0xb4, 0x74, 0x79, 0x35, 0x3e, 0x8c, 0xcf, 0x6f, 0x5f, - 0xd9, 0xd3, 0xff, 0xbe, 0xe3, 0xee, 0x97, 0xf4, 0x56, 0x60, 0x9d, 0x36, - 0x3b, 0x1d, 0x16, 0x88, 0x6d, 0x11, 0x62, 0x64, 0xe0, 0xc4, 0x3a, 0x1d, - 0xf3, 0xc7, 0xf2, 0x5d, 0x3e, 0xd6, 0x6f, 0x1e, 0x74, 0xfe, 0x7d, 0x5a, - 0xbd, 0x6b, 0xf5, 0xbe, 0xb6, 0x74, 0xf7, 0xeb, 0xfe, 0xce, 0x9d, 0xc7, - 0x1c, 0x15, 0x3e, 0xc1, 0xde, 0xac, 0xa5, 0x97, 0xf3, 0xec, 0xdb, 0x97, - 0xb3, 0xa3, 0x94, 0x4e, 0xf6, 0x84, 0x26, 0x93, 0xda, 0xcc, 0xc3, 0xa7, - 0xfe, 0xef, 0xee, 0x74, 0xd3, 0x7c, 0x3d, 0xeb, 0x9d, 0x3f, 0xef, 0xf9, - 0x61, 0x6a, 0xb7, 0xd4, 0x74, 0xfd, 0x6e, 0xbd, 0x7d, 0xd4, 0xe9, 0xeb, - 0xe6, 0xe8, 0x3a, 0x2d, 0x51, 0xbd, 0x24, 0xdf, 0x87, 0x2f, 0x5c, 0xc5, - 0xc1, 0xfd, 0x26, 0x89, 0xf6, 0xcb, 0xe7, 0xeb, 0xe1, 0xaf, 0x9f, 0x9d, - 0x39, 0xbd, 0xec, 0xe9, 0xff, 0xff, 0xc2, 0x34, 0xb7, 0x91, 0xbe, 0x75, - 0xf7, 0x3a, 0x56, 0xe9, 0x78, 0x5f, 0x07, 0x4f, 0xbf, 0xbf, 0x5a, 0x83, - 0xa7, 0xff, 0xf5, 0xd2, 0xfa, 0xaa, 0xc7, 0xa3, 0xb7, 0xf5, 0x47, 0xec, - 0x0e, 0x9f, 0xff, 0xf7, 0x1d, 0x06, 0xd3, 0x5f, 0x1b, 0xf6, 0x9d, 0xf4, - 0xce, 0x2f, 0xc9, 0xd3, 0xfa, 0x97, 0xd7, 0xcf, 0xad, 0x49, 0xd3, 0xfb, - 0x38, 0xf5, 0xc6, 0xde, 0x1d, 0x0c, 0x8d, 0xff, 0xb9, 0x89, 0xc4, 0xf7, - 0x7b, 0xfd, 0x07, 0x4f, 0xf9, 0xb2, 0x86, 0x50, 0xb5, 0x3d, 0x9d, 0x0c, - 0xa9, 0xee, 0xdf, 0x7e, 0x52, 0x11, 0xa2, 0xe1, 0x70, 0x92, 0x4d, 0xeb, - 0xce, 0x9d, 0x9b, 0xa9, 0xd3, 0x7b, 0x41, 0xd3, 0xcc, 0x3b, 0x71, 0xe6, - 0xcc, 0x06, 0xe7, 0xff, 0xde, 0xb6, 0xfa, 0x0f, 0xae, 0xdd, 0x2f, 0x7d, - 0x57, 0xb3, 0xa7, 0xfe, 0xd3, 0x79, 0xe9, 0xb1, 0xcd, 0xb6, 0xce, 0x9f, - 0xdd, 0x29, 0x7f, 0xf5, 0xea, 0x8e, 0x8e, 0xcf, 0xf8, 0x51, 0xa7, 0xfc, - 0x0e, 0x74, 0xab, 0x7e, 0x8c, 0xd9, 0xd0, 0xc7, 0xc7, 0xe9, 0x14, 0xff, - 0xff, 0xf7, 0xa3, 0x50, 0x16, 0x73, 0xa7, 0x8d, 0xfd, 0xf7, 0x4e, 0xed, - 0xd0, 0xdd, 0x4e, 0x93, 0x1d, 0x3f, 0x9f, 0x81, 0xfa, 0xb5, 0x27, 0x4f, - 0xff, 0xff, 0xef, 0xf7, 0x51, 0xbc, 0xa7, 0xa7, 0x3a, 0xf7, 0xa0, 0xdd, - 0x2f, 0xbf, 0x68, 0x1b, 0xca, 0x4e, 0x9d, 0x98, 0x86, 0x8a, 0x62, 0x2d, - 0x17, 0xa9, 0x09, 0x79, 0xff, 0x58, 0xd2, 0xfa, 0xed, 0x81, 0xc3, 0xa7, - 0x5f, 0xfb, 0x3a, 0x56, 0x74, 0xea, 0x46, 0xfb, 0x35, 0x6e, 0x87, 0x23, - 0xe8, 0x9e, 0xc6, 0x99, 0xfe, 0xc5, 0x73, 0xa6, 0xa2, 0xf8, 0x3a, 0x7f, - 0xff, 0x0d, 0xa6, 0xf6, 0xdb, 0xab, 0x83, 0x7c, 0x74, 0x67, 0x76, 0x74, - 0xff, 0x91, 0x95, 0xab, 0xad, 0xfc, 0x4e, 0x86, 0x45, 0x16, 0x99, 0xe7, - 0xc0, 0xce, 0x98, 0x0e, 0x9f, 0xb0, 0x7a, 0x72, 0xc2, 0x74, 0x59, 0xfa, - 0xfc, 0x8b, 0xd2, 0x68, 0xa1, 0x77, 0x2f, 0x94, 0xaf, 0x26, 0xe9, 0x1a, - 0x0d, 0x24, 0x5f, 0x84, 0x1b, 0x81, 0xe1, 0x0e, 0xf5, 0x43, 0x10, 0x48, - 0xb7, 0x1a, 0x8c, 0xff, 0xbc, 0x86, 0x71, 0xd3, 0x39, 0xca, 0x0e, 0x9e, - 0xb1, 0xf3, 0xd7, 0x3a, 0x7f, 0xff, 0xfd, 0xaf, 0xef, 0x56, 0x0c, 0xeb, - 0xa2, 0xbd, 0x76, 0xe9, 0x74, 0xbe, 0xfd, 0x1e, 0xea, 0x74, 0xb7, 0xf4, - 0x5a, 0xd4, 0x9a, 0x7f, 0xfd, 0x77, 0xaf, 0xa6, 0xaf, 0xa5, 0x7d, 0xd3, - 0x75, 0xce, 0x9f, 0xfe, 0xde, 0xaf, 0xbe, 0x8a, 0x6b, 0xdf, 0x36, 0x27, - 0x4f, 0xf5, 0x3d, 0x14, 0xd6, 0x3b, 0xea, 0x3a, 0x55, 0xb4, 0x47, 0x62, - 0x8c, 0xbe, 0x29, 0x87, 0xee, 0x1d, 0x13, 0xe7, 0xb5, 0x2f, 0xa9, 0xd3, - 0xff, 0xff, 0xfe, 0xb1, 0xf3, 0xd3, 0xfa, 0xf5, 0x6e, 0x7f, 0x6c, 0xa1, - 0xcf, 0x3a, 0xfa, 0xef, 0x54, 0xf6, 0xdc, 0x95, 0x3f, 0xff, 0xf2, 0x7f, - 0x8e, 0x7d, 0x0e, 0x9e, 0xb5, 0x15, 0x4d, 0x7b, 0xaa, 0x73, 0x83, 0xa6, - 0xf6, 0x8a, 0x53, 0x47, 0xf9, 0x45, 0x61, 0x49, 0x0c, 0xab, 0xcb, 0x51, - 0x9c, 0x0c, 0x6e, 0xb3, 0xff, 0x94, 0x9d, 0x35, 0x8f, 0xb5, 0x60, 0xf6, - 0x74, 0xff, 0xfb, 0xe3, 0xbd, 0x5b, 0xb6, 0xdc, 0xbe, 0xbe, 0x0f, 0x67, - 0x4f, 0xfc, 0xc3, 0x40, 0xdb, 0xaa, 0xfa, 0xd4, 0x9d, 0x15, 0x45, 0x17, - 0xab, 0x93, 0xd7, 0xbb, 0x77, 0x0e, 0x9d, 0xd5, 0x7a, 0x3a, 0x6b, 0xe4, - 0xe8, 0xa1, 0x36, 0x97, 0xc3, 0xb2, 0xa4, 0x9b, 0x25, 0x74, 0x3d, 0x3e, - 0xfe, 0xeb, 0x7d, 0x9d, 0x3f, 0x72, 0xc3, 0xac, 0x79, 0xd3, 0x9b, 0x96, - 0x3a, 0x7e, 0x7d, 0xee, 0xb8, 0xe7, 0x43, 0xc7, 0x51, 0x64, 0x3d, 0x16, - 0xce, 0x37, 0xcf, 0xce, 0xda, 0xce, 0xbb, 0x76, 0x74, 0xfe, 0x07, 0x06, - 0xf5, 0x9b, 0x3a, 0x2c, 0xf9, 0x7e, 0x69, 0x3f, 0x37, 0x77, 0xbf, 0x14, - 0x1d, 0x0f, 0x3d, 0x11, 0x21, 0x9f, 0xff, 0xf6, 0xc7, 0x3b, 0xad, 0x17, - 0xf1, 0xd8, 0xdb, 0xae, 0x95, 0xe0, 0x4e, 0x9f, 0xf7, 0xed, 0xce, 0x95, - 0x6d, 0x67, 0x5c, 0xe9, 0xfd, 0x94, 0xd7, 0x57, 0x80, 0x74, 0x72, 0x7e, - 0xbb, 0x44, 0x9f, 0xeb, 0x0a, 0x1b, 0xe1, 0x62, 0x74, 0x94, 0x77, 0x43, - 0x6b, 0x38, 0x6f, 0x93, 0xa1, 0x8d, 0xed, 0x24, 0x53, 0xf5, 0x35, 0xbb, - 0x1f, 0x27, 0x4f, 0x2b, 0xc3, 0x76, 0x74, 0x59, 0xe9, 0x7c, 0xba, 0x77, - 0xb4, 0xf6, 0x74, 0x32, 0xa2, 0xdb, 0x87, 0x2f, 0xe1, 0x2a, 0x0e, 0x62, - 0x43, 0x3f, 0xb7, 0xfa, 0x2f, 0x5e, 0xec, 0xe9, 0x38, 0x74, 0xfd, 0x7e, - 0xde, 0x92, 0x83, 0xa6, 0xba, 0x58, 0xdf, 0x54, 0x46, 0x7e, 0xd6, 0x3d, - 0x41, 0xf3, 0xa7, 0xdf, 0xec, 0x2e, 0x93, 0xa3, 0xca, 0x3c, 0xfe, 0xe7, - 0xd9, 0x67, 0xa5, 0x93, 0xff, 0xf0, 0x3f, 0x56, 0xe6, 0x98, 0x7c, 0x8d, - 0xef, 0x5e, 0x9d, 0x3f, 0xff, 0xbf, 0x74, 0xbe, 0xbb, 0xd3, 0x29, 0xbf, - 0xcf, 0x46, 0x77, 0x67, 0x4f, 0xff, 0xff, 0xbd, 0x1e, 0x9c, 0x65, 0x2f, - 0x0c, 0xef, 0xa5, 0x7d, 0x6a, 0x75, 0x7f, 0x1b, 0xf2, 0x74, 0xff, 0xfb, - 0xd0, 0x0b, 0xdd, 0x75, 0xfb, 0xe9, 0xae, 0xd8, 0xe8, 0xb4, 0x71, 0xea, - 0x11, 0x93, 0xff, 0xcf, 0x76, 0xd5, 0xb0, 0xb8, 0x37, 0xba, 0xe1, 0xd3, - 0xff, 0xee, 0x6d, 0x5d, 0x1d, 0xb6, 0xd5, 0x71, 0xf8, 0x14, 0x1d, 0x3f, - 0xd6, 0x34, 0x74, 0xef, 0x31, 0xc3, 0xa7, 0xf8, 0x28, 0x6a, 0x28, 0xf4, - 0x28, 0x3a, 0x7f, 0xbd, 0x1e, 0x95, 0xf7, 0xab, 0xd0, 0x3a, 0x18, 0xff, - 0x2a, 0x79, 0x3f, 0xfa, 0x8e, 0x95, 0xd7, 0xbd, 0x37, 0x5a, 0xb0, 0x1d, - 0x3f, 0xff, 0xeb, 0xa6, 0xbf, 0xbe, 0x3a, 0x6a, 0xf7, 0x5b, 0xa3, 0xa5, - 0xff, 0x93, 0xa2, 0xd1, 0x87, 0xf5, 0x08, 0xa1, 0x5e, 0xea, 0x46, 0x9b, - 0x49, 0x3f, 0xd4, 0x14, 0xb9, 0x58, 0x5b, 0xee, 0x1c, 0x93, 0xfe, 0xc0, - 0xd5, 0xed, 0x87, 0xfd, 0x9d, 0x3f, 0xd7, 0xc5, 0x2f, 0xaf, 0x4d, 0xfc, - 0xe9, 0xff, 0xff, 0x32, 0x32, 0xba, 0x39, 0xaf, 0x8f, 0x3d, 0x3c, 0x20, - 0xde, 0xac, 0xe8, 0x44, 0x74, 0x89, 0xe3, 0xb1, 0xec, 0xf7, 0xf7, 0xf6, - 0x3a, 0x7f, 0xff, 0xfe, 0xdb, 0x28, 0x7f, 0xe7, 0x58, 0xe7, 0x41, 0xf5, - 0xdb, 0xa5, 0xd2, 0xfb, 0xf4, 0x7b, 0xa9, 0xd0, 0xf4, 0x5b, 0x7c, 0x86, - 0x19, 0x7a, 0x8e, 0xe7, 0x0e, 0x7f, 0x1b, 0x06, 0x43, 0x9e, 0x7b, 0x75, - 0xce, 0xce, 0x9f, 0xfb, 0x5f, 0xe9, 0xf0, 0xf6, 0x8c, 0x04, 0x3a, 0x7b, - 0xfa, 0xca, 0x0e, 0x9e, 0x74, 0xdb, 0x63, 0xa7, 0xed, 0x65, 0x1d, 0x1f, - 0xb3, 0xa7, 0xd8, 0x03, 0x4f, 0xce, 0x8f, 0x9e, 0xb6, 0xcc, 0x22, 0xd3, - 0x24, 0xf2, 0x44, 0x88, 0xdf, 0x22, 0xdb, 0xc4, 0xf7, 0x8f, 0x72, 0xa7, - 0x4f, 0xff, 0xdf, 0x0e, 0x97, 0xfb, 0x1f, 0x3a, 0xfd, 0xaa, 0xd0, 0xe9, - 0xff, 0xfe, 0xfd, 0x00, 0xca, 0xaf, 0xad, 0xd1, 0x81, 0xb9, 0xd3, 0x28, - 0xe8, 0xb4, 0x61, 0x82, 0xdc, 0xff, 0xff, 0xe0, 0x0f, 0xd1, 0xd3, 0x57, - 0xb1, 0x67, 0x35, 0x74, 0x35, 0x3b, 0xf5, 0x0e, 0x9f, 0xff, 0xf9, 0xbc, - 0xe9, 0xba, 0x0d, 0xfb, 0xe7, 0xa5, 0x2f, 0xaf, 0xc7, 0xc3, 0x50, 0x74, - 0xfa, 0x9a, 0xfe, 0xc4, 0xe8, 0xb4, 0x52, 0x7a, 0xfb, 0x1f, 0x4d, 0x0b, - 0x51, 0x8f, 0xcf, 0xfc, 0xfa, 0xff, 0xce, 0x9b, 0xf4, 0x37, 0x93, 0xa7, - 0xf8, 0x7d, 0x70, 0x6f, 0x59, 0xb3, 0xa7, 0xfb, 0x9d, 0x37, 0x1c, 0xeb, - 0x14, 0x74, 0xff, 0xff, 0x60, 0x6a, 0xf7, 0xfb, 0x1a, 0x2a, 0xd6, 0x3c, - 0xe9, 0x8e, 0x9e, 0xdf, 0x4a, 0x00, 0xe8, 0xa5, 0x10, 0xf8, 0xc7, 0x3f, - 0x39, 0x4b, 0xfd, 0x6d, 0x9d, 0x3f, 0xda, 0xc5, 0x0d, 0xeb, 0x36, 0x74, - 0xf5, 0x87, 0x7c, 0x1d, 0x0c, 0x88, 0x8a, 0x98, 0x6c, 0xda, 0x7e, 0xbd, - 0x80, 0x5b, 0xce, 0x9f, 0x86, 0xf4, 0x36, 0x87, 0x4f, 0x0d, 0xd7, 0xa3, - 0x87, 0xa7, 0xb2, 0xa8, 0xe5, 0x70, 0xe1, 0x23, 0x63, 0xa4, 0xab, 0xe9, - 0x20, 0x71, 0xa8, 0x61, 0x6e, 0x15, 0x6e, 0xa1, 0x05, 0x3f, 0xf0, 0x8d, - 0xf4, 0x0b, 0xd0, 0xdb, 0x87, 0x43, 0x2e, 0xf6, 0x5c, 0xe8, 0xfe, 0x42, - 0x2e, 0x7c, 0x2c, 0xac, 0xe4, 0xe9, 0xfd, 0x6e, 0x6a, 0xf6, 0xdc, 0x9d, - 0x3f, 0xff, 0xfd, 0xab, 0xdd, 0x71, 0xce, 0x83, 0x74, 0xbe, 0xfd, 0xa0, - 0x6f, 0x9d, 0x7d, 0xc3, 0xa6, 0xf7, 0xc9, 0xd0, 0x08, 0x9c, 0xdc, 0x20, - 0xe7, 0xeb, 0xa0, 0x6e, 0x9a, 0x9d, 0x3f, 0xf8, 0x29, 0x7d, 0x6d, 0x54, - 0xb6, 0xb4, 0xc7, 0x4a, 0xa7, 0x47, 0xa7, 0xb5, 0xe1, 0x2a, 0x7f, 0x32, - 0x86, 0xf5, 0x9b, 0x3a, 0x7b, 0xa2, 0x51, 0xc1, 0xd3, 0xff, 0xfe, 0xd8, - 0xb7, 0x74, 0xbe, 0xbe, 0xb6, 0xc6, 0xf9, 0xfd, 0x83, 0x87, 0x47, 0xd5, - 0x45, 0xb8, 0x4d, 0x90, 0xcf, 0x12, 0x7a, 0xc2, 0x1f, 0xd2, 0x57, 0x46, - 0x1e, 0x09, 0x67, 0xcf, 0xf8, 0x5d, 0x27, 0x4f, 0xae, 0xb4, 0x5f, 0x07, - 0x45, 0x27, 0x9f, 0xa2, 0x79, 0xff, 0xf7, 0xe8, 0xb4, 0xe7, 0x5f, 0xbf, - 0x3d, 0x3c, 0xfa, 0xc7, 0x4f, 0x3b, 0x6e, 0xf4, 0x74, 0xff, 0xff, 0xce, - 0xd4, 0xbf, 0x29, 0xe8, 0x3e, 0xbb, 0x74, 0xba, 0x5f, 0x7e, 0x8f, 0x75, - 0x3a, 0x28, 0x45, 0x2d, 0x92, 0x4f, 0xff, 0xff, 0x9a, 0x9a, 0xfa, 0xd4, - 0xf4, 0xd5, 0xf3, 0xd0, 0x6f, 0xdf, 0x3d, 0x2b, 0xdf, 0x7f, 0xd9, 0xd3, - 0xe6, 0x1a, 0x72, 0x83, 0xa7, 0xff, 0xff, 0xff, 0x5a, 0xad, 0x1b, 0x4c, - 0xad, 0xdd, 0x6a, 0xc0, 0x0c, 0x37, 0x45, 0xfb, 0x5f, 0x5c, 0x16, 0x51, - 0xd3, 0xfd, 0xdd, 0xf2, 0x37, 0xac, 0xd9, 0xd3, 0xfa, 0x8f, 0x5b, 0x6a, - 0xfe, 0xce, 0x9f, 0xf3, 0x79, 0x76, 0xf6, 0xc5, 0xcf, 0x0a, 0x3a, 0x2c, - 0xfe, 0xe9, 0x35, 0x9f, 0xfe, 0xbd, 0xf3, 0x77, 0xdd, 0x7a, 0x05, 0x79, - 0xa9, 0xd3, 0xd4, 0x7c, 0x76, 0x74, 0x32, 0xbe, 0xcb, 0x23, 0xfc, 0x60, - 0x40, 0x46, 0xa8, 0x49, 0x68, 0x9f, 0x21, 0x42, 0x30, 0xb3, 0xa9, 0x17, - 0xaa, 0x73, 0xb9, 0xe8, 0xe1, 0xd3, 0xff, 0xd4, 0xbc, 0x5b, 0xa2, 0x85, - 0xbc, 0xef, 0xf4, 0x1d, 0x16, 0x7e, 0x9f, 0x20, 0x9f, 0xa8, 0x71, 0xfd, - 0x60, 0x50, 0x74, 0xf9, 0x5f, 0xe6, 0xf9, 0x3a, 0x4e, 0x1d, 0x33, 0x28, - 0xe9, 0x6c, 0xe8, 0x03, 0x4b, 0x82, 0xb1, 0xc9, 0xea, 0xe8, 0xda, 0x7b, - 0x75, 0xca, 0x4e, 0x99, 0xcc, 0x3a, 0x7f, 0x6b, 0xe1, 0x4b, 0xc5, 0x8e, - 0x8e, 0xb6, 0x9a, 0x03, 0x1a, 0xdb, 0xf7, 0xc8, 0xd4, 0x45, 0xe8, 0xb4, - 0xfe, 0xaf, 0xe9, 0xe3, 0x07, 0xb3, 0xa7, 0xff, 0xcc, 0x0c, 0x96, 0xa6, - 0x47, 0xfe, 0xbe, 0xa8, 0xe8, 0x71, 0x10, 0xfd, 0x46, 0xb3, 0xf0, 0x5b, - 0x79, 0x61, 0x3a, 0x70, 0xe2, 0x8e, 0x9b, 0xb6, 0x3a, 0x1e, 0x7b, 0x7f, - 0x2b, 0x11, 0xa8, 0x77, 0x9d, 0x94, 0x7f, 0x59, 0x0f, 0x16, 0x94, 0xc1, - 0x43, 0xe3, 0xcb, 0x79, 0x95, 0x31, 0x73, 0xc4, 0xbe, 0x61, 0x72, 0x92, - 0xfa, 0xa9, 0x8e, 0x97, 0xf1, 0x84, 0xb9, 0x0d, 0xa0, 0x94, 0x9c, 0xa8, - 0xd1, 0x75, 0x3d, 0xc9, 0x91, 0xba, 0x0c, 0xf1, 0xbd, 0x65, 0x64, 0x6e, - 0x72, 0xf1, 0xd4, 0x62, 0x5d, 0x51, 0xb0, 0xf8, 0x87, 0x23, 0xb4, 0x20, - 0xa7, 0xff, 0xef, 0x51, 0x74, 0xec, 0x1a, 0xe9, 0xeb, 0x39, 0xcc, 0xf2, - 0x74, 0x2d, 0x51, 0x8f, 0xe3, 0xce, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, 0x34, - 0x53, 0xb3, 0xe0, 0x4c, 0xc4, 0x34, 0x54, 0x73, 0xfe, 0xc7, 0xae, 0xc1, - 0x33, 0x10, 0xd1, 0x34, 0x49, 0x76, 0x7e, 0xca, 0x30, 0x9f, 0xcb, 0xb0, - 0x4c, 0xc4, 0x34, 0x55, 0xf3, 0xe0, 0x4c, 0xc4, 0x34, 0x56, 0xd3, 0xfc, - 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x24, 0x19, 0x2e, 0xcf, 0xc7, 0x0c, 0x27, - 0xfe, 0x5e, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0x0e, 0x7f, 0xcf, 0xd3, - 0x6e, 0xae, 0xee, 0xae, 0xf0, 0x9d, 0x3e, 0xbb, 0x1e, 0xea, 0x74, 0xf8, - 0x13, 0x31, 0x0d, 0x16, 0x24, 0xfa, 0xc1, 0x87, 0xc9, 0xd3, 0xef, 0x1d, - 0x56, 0x0c, 0x74, 0xea, 0xb0, 0x9d, 0x2d, 0x31, 0xe2, 0x7c, 0xaa, 0x7f, - 0xe6, 0xba, 0xd8, 0xf3, 0xfe, 0xd8, 0x4e, 0x9c, 0x2d, 0x41, 0xd2, 0x78, - 0x9e, 0xef, 0xa8, 0x53, 0xba, 0xbf, 0xd9, 0xd3, 0xef, 0xba, 0xf7, 0x2a, - 0x74, 0xff, 0xce, 0xbd, 0xba, 0x79, 0x75, 0xab, 0xc7, 0x0e, 0x99, 0x9e, - 0x74, 0x59, 0xf0, 0x02, 0x5c, 0xfe, 0xb0, 0x7f, 0x77, 0x6e, 0x1d, 0x3e, - 0xc7, 0xf8, 0xd3, 0x1d, 0x3f, 0x56, 0xa1, 0xfe, 0x3a, 0xe7, 0x43, 0x22, - 0x33, 0xe6, 0x58, 0x51, 0x3f, 0xfc, 0xf6, 0x53, 0x3f, 0x91, 0x6d, 0x65, - 0x81, 0xd3, 0xf9, 0x06, 0xdd, 0x0d, 0xd4, 0xe8, 0xa4, 0xff, 0x74, 0x99, - 0x3f, 0xbb, 0x6b, 0xdf, 0xc7, 0x82, 0xa7, 0xd7, 0xaa, 0x73, 0xae, 0x74, - 0xf7, 0x75, 0x61, 0x3a, 0x7f, 0x06, 0xb3, 0xf5, 0xfb, 0xa3, 0xa1, 0x8f, - 0x56, 0xc8, 0x60, 0x51, 0x41, 0x58, 0x40, 0x4f, 0xd9, 0x46, 0xda, 0x97, - 0x9d, 0x3f, 0xe1, 0x6f, 0xf3, 0xb1, 0xca, 0x6a, 0x74, 0x3b, 0xcb, 0xa7, - 0xfc, 0xa4, 0xd9, 0x37, 0x93, 0x04, 0x6a, 0xa6, 0x10, 0x9f, 0x28, 0x70, - 0x80, 0x21, 0x15, 0xa8, 0x56, 0x64, 0x2a, 0xfb, 0x23, 0xac, 0x34, 0xf6, - 0x4f, 0xe0, 0xba, 0x7f, 0xed, 0x7d, 0xb7, 0xac, 0xf3, 0x63, 0xd9, 0xd3, - 0xff, 0xd7, 0x4b, 0xf7, 0xed, 0x0b, 0xd6, 0x2b, 0xf5, 0x3a, 0x6d, 0x2e, - 0xd1, 0x30, 0x28, 0xb0, 0xb4, 0xed, 0x9a, 0x38, 0x99, 0xfc, 0xbb, 0x04, - 0xcc, 0x43, 0x45, 0x9b, 0x35, 0xf2, 0x74, 0xff, 0xb1, 0xeb, 0xb0, 0x4c, - 0xc4, 0x34, 0x50, 0x12, 0x5d, 0x9e, 0xe2, 0x85, 0xa6, 0xf7, 0x47, 0x4f, - 0xd5, 0x65, 0x0b, 0x38, 0x74, 0xfd, 0x7b, 0xef, 0xc0, 0xb8, 0x74, 0x76, - 0x7b, 0x82, 0x59, 0x37, 0x4a, 0x9d, 0x3f, 0xda, 0xb0, 0xd8, 0xb2, 0xaa, - 0x74, 0xf2, 0x66, 0x21, 0xa2, 0xdf, 0x9f, 0xbc, 0x6f, 0x13, 0x00, 0xe8, - 0x03, 0xd7, 0xec, 0xae, 0x7d, 0xb7, 0xd7, 0xc5, 0x4e, 0x9f, 0x9d, 0x78, - 0xd8, 0xb7, 0x67, 0x4f, 0xb9, 0x6e, 0xbf, 0xaa, 0x3a, 0x18, 0xf7, 0xbe, - 0x63, 0x3d, 0x9f, 0x1d, 0x9d, 0x3f, 0xbd, 0xa6, 0xac, 0x96, 0xa3, 0xa7, - 0xb5, 0xe7, 0x95, 0x1d, 0x35, 0xbc, 0xe8, 0xb3, 0x74, 0x24, 0xb2, 0x5b, - 0xbc, 0xaa, 0xc5, 0x9c, 0xde, 0x45, 0xc8, 0xc5, 0xc2, 0x34, 0x08, 0xb5, - 0x08, 0x8e, 0xc8, 0x44, 0x83, 0x6d, 0xb3, 0xfe, 0xc7, 0xae, 0xc1, 0x33, - 0x10, 0xd1, 0x4a, 0x4f, 0xf3, 0xd7, 0x60, 0x99, 0x88, 0x68, 0x93, 0xa4, - 0xb5, 0x22, 0x1f, 0x11, 0xa1, 0x9f, 0x12, 0x66, 0x88, 0xda, 0xb9, 0xb6, - 0xa6, 0x56, 0x56, 0x90, 0xb1, 0xf9, 0x3f, 0x5e, 0x15, 0x8e, 0x13, 0x2a, - 0x7d, 0x07, 0x45, 0x3d, 0xc2, 0x5e, 0xb2, 0xb6, 0x1d, 0x46, 0x4f, 0x3e, - 0x04, 0xcc, 0x43, 0x44, 0x3f, 0x3f, 0xec, 0x7a, 0xec, 0x13, 0x31, 0x0d, - 0x12, 0x9c, 0x97, 0x67, 0xec, 0xa3, 0x09, 0xfc, 0xbb, 0x04, 0xcc, 0x43, - 0x44, 0x4f, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0x8c, 0x67, 0xff, 0x2d, - 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x27, 0x98, 0x64, 0x77, 0xd0, 0x4e, - 0xf3, 0xbd, 0x1d, 0xcf, 0x81, 0x33, 0x10, 0xd1, 0x10, 0x4f, 0xfb, 0x1e, - 0xbb, 0x04, 0xcc, 0x43, 0x44, 0xa9, 0x25, 0xd9, 0xfb, 0x28, 0xc2, 0x7f, - 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x14, 0x4f, 0xe5, 0xd8, 0x26, 0x62, 0x1a, - 0x23, 0x29, 0xff, 0xcb, 0x56, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0x96, - 0x7f, 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x52, 0x4f, 0xe5, 0xd8, 0x26, 0x62, - 0x1a, 0x2b, 0xa9, 0xfc, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0x8b, 0x3f, 0xf2, - 0xb1, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x4f, 0x53, 0xfd, 0xc2, 0xf1, 0xbf, - 0xd5, 0xf7, 0x63, 0xa1, 0x68, 0x8b, 0x64, 0xc9, 0xfb, 0xad, 0x7b, 0xdf, - 0xfd, 0xa9, 0xd3, 0xc0, 0xad, 0xd2, 0x74, 0xe4, 0xbd, 0x15, 0x39, 0x4d, - 0x53, 0xa7, 0xff, 0xed, 0x0e, 0x79, 0xf8, 0x33, 0xdf, 0x75, 0xef, 0xb6, - 0x3a, 0x7f, 0xfe, 0x0f, 0xbb, 0x62, 0x96, 0xc0, 0x1f, 0x76, 0x4f, 0x68, - 0x3a, 0x7c, 0x9f, 0xd7, 0x85, 0x1d, 0x3f, 0xfb, 0x2a, 0x37, 0xda, 0xf5, - 0xf4, 0xc0, 0x3a, 0x7d, 0xbd, 0x32, 0x90, 0xe9, 0xff, 0xc3, 0xd1, 0x98, - 0x59, 0x5d, 0x3a, 0x6b, 0xa8, 0xe9, 0xb2, 0x93, 0xa7, 0xf6, 0x57, 0x35, - 0xe8, 0xd0, 0x74, 0x09, 0xe4, 0xfa, 0x2d, 0x14, 0x2a, 0x28, 0xf8, 0xd8, - 0x2e, 0x29, 0x83, 0x45, 0x22, 0x8f, 0xb2, 0x67, 0x68, 0x4c, 0xce, 0x1c, - 0xd9, 0xaa, 0x16, 0x9c, 0x3f, 0xa9, 0xd2, 0xe1, 0xdf, 0x3c, 0x26, 0x27, - 0x9e, 0x07, 0x58, 0xa3, 0xa2, 0xcf, 0x3f, 0xe5, 0xb3, 0xfe, 0xfe, 0xb3, - 0x6c, 0xe5, 0x7e, 0xa3, 0xa7, 0xc3, 0xe7, 0xf7, 0x53, 0xa7, 0xfe, 0xbe, - 0x33, 0xbb, 0x4d, 0x67, 0x75, 0x3a, 0x3e, 0x7d, 0x82, 0x51, 0x39, 0x4d, - 0xa3, 0xa7, 0x87, 0x9e, 0x9e, 0x4e, 0x9f, 0xae, 0xbc, 0x60, 0xd0, 0x74, - 0x59, 0xf7, 0x60, 0xd8, 0x93, 0x4f, 0xbd, 0xf3, 0x5e, 0x58, 0xe8, 0xb4, - 0x73, 0x7e, 0x11, 0xfa, 0x2c, 0x9f, 0xff, 0xfd, 0xa6, 0xf8, 0x03, 0x78, - 0xdf, 0xc7, 0xd7, 0xdd, 0x79, 0xf7, 0x01, 0xe7, 0x4f, 0xa8, 0xe4, 0x3f, - 0xc1, 0xd3, 0xf7, 0x38, 0x1d, 0xf5, 0x59, 0xd3, 0xfe, 0x1f, 0xbf, 0x7a, - 0xb0, 0xfd, 0x4e, 0x9f, 0xf6, 0x5f, 0x6c, 0x39, 0xcd, 0xf9, 0x3a, 0x1e, - 0x7f, 0x7d, 0x9e, 0xcf, 0xec, 0xa6, 0xbb, 0xdd, 0xf5, 0xce, 0x9f, 0xfc, - 0xd7, 0x4e, 0xf4, 0xdb, 0x16, 0xee, 0xa7, 0x4e, 0xae, 0x94, 0x74, 0x6c, - 0xf9, 0x7d, 0x49, 0x9f, 0xbd, 0xae, 0xeb, 0x7b, 0x3a, 0x77, 0x1c, 0x70, - 0x54, 0xff, 0xed, 0xff, 0x75, 0xd7, 0xfa, 0xbc, 0x03, 0x3c, 0xa5, 0x97, - 0xf1, 0xf4, 0x55, 0xfa, 0x9b, 0x0f, 0x55, 0xff, 0x6f, 0x3f, 0x2a, 0x08, - 0x55, 0xa8, 0x8c, 0x61, 0x39, 0xb8, 0x67, 0x4f, 0xf5, 0x2f, 0xad, 0x6f, - 0x9c, 0xd9, 0xd2, 0xb3, 0xa1, 0x8f, 0x27, 0xc9, 0xd4, 0xfb, 0x8d, 0xb5, - 0x3c, 0x1d, 0x39, 0x38, 0xd1, 0xd3, 0xf9, 0xb0, 0x35, 0xc6, 0x72, 0x54, - 0xdc, 0x70, 0x54, 0x72, 0x79, 0x5c, 0x19, 0x4e, 0xdf, 0xfa, 0xe5, 0x2c, - 0xd2, 0x4f, 0x7a, 0xff, 0x76, 0x74, 0x54, 0xf5, 0x3a, 0x8c, 0x26, 0xe2, - 0xa7, 0x4a, 0xce, 0x95, 0x36, 0x69, 0xb6, 0x2f, 0x3f, 0xf5, 0x6b, 0xc8, - 0xb7, 0x3a, 0x6d, 0xd4, 0xe8, 0x63, 0xec, 0xf4, 0x9e, 0x7f, 0xdb, 0xf8, - 0x67, 0x6e, 0xdb, 0xbd, 0x1d, 0x3f, 0xb0, 0x37, 0x51, 0xff, 0x93, 0xa1, - 0xe8, 0x96, 0xf9, 0x16, 0x20, 0xcf, 0x51, 0x7f, 0x03, 0xa7, 0xfc, 0xd4, - 0xe9, 0x94, 0x9a, 0xfb, 0x87, 0x45, 0x9f, 0x00, 0x10, 0xcf, 0xdb, 0x60, - 0xe6, 0xc4, 0xe9, 0xfd, 0xce, 0x98, 0x78, 0xca, 0x4e, 0x9f, 0xfb, 0xfc, - 0xe9, 0x91, 0xbb, 0xc1, 0xec, 0xe9, 0xff, 0xff, 0x7d, 0x58, 0x34, 0xbd, - 0x7c, 0x5f, 0xdd, 0x58, 0xdf, 0x38, 0xf3, 0xc5, 0xeb, 0x0c, 0x98, 0xf6, - 0x15, 0xd4, 0xd3, 0xd4, 0x49, 0xff, 0xeb, 0xdd, 0x6d, 0xcd, 0x33, 0xab, - 0xd6, 0x98, 0xe9, 0xff, 0xff, 0xf7, 0xee, 0x9a, 0xfe, 0xf8, 0xe9, 0x74, - 0xbe, 0xbf, 0xdd, 0x7f, 0x4f, 0x3c, 0xfb, 0x41, 0xd3, 0xff, 0xef, 0x8f, - 0x3d, 0x3c, 0x6f, 0xf5, 0xcf, 0x8f, 0xaf, 0x3a, 0x05, 0x33, 0xad, 0xa8, - 0x3a, 0x84, 0x7c, 0xd9, 0xc9, 0xd3, 0xf0, 0x65, 0x75, 0x8f, 0x3a, 0x54, - 0x9d, 0x37, 0xf8, 0x3a, 0x6f, 0x1d, 0x9d, 0x0e, 0x1b, 0x0e, 0xc5, 0xe7, - 0x3f, 0x39, 0x3a, 0x6e, 0x38, 0x3a, 0x1e, 0x8d, 0x9b, 0x16, 0x42, 0xbf, - 0xa0, 0xd4, 0x8f, 0x81, 0xc9, 0xdb, 0xf1, 0xd9, 0x4b, 0x3d, 0x69, 0xff, - 0xff, 0xdb, 0x6e, 0x75, 0xee, 0x79, 0x56, 0x73, 0x76, 0x3e, 0x6b, 0x5b, - 0x1e, 0xce, 0x8a, 0x51, 0x59, 0xf3, 0x09, 0xfe, 0xbd, 0xe9, 0x83, 0x76, - 0x87, 0x4e, 0x60, 0x70, 0xe8, 0xb5, 0x50, 0xd9, 0x28, 0x48, 0x49, 0x3a, - 0x8d, 0x67, 0x57, 0x1c, 0x3a, 0x7a, 0xf7, 0x8e, 0xc7, 0x45, 0x26, 0xfc, - 0x47, 0x27, 0xfe, 0xb0, 0x0b, 0x73, 0x57, 0x5c, 0x13, 0xa7, 0xf0, 0xb0, - 0x7a, 0x9a, 0x63, 0xa7, 0xdf, 0xf3, 0xac, 0x79, 0xd3, 0xf7, 0xd9, 0x54, - 0x5f, 0x07, 0x4d, 0xc7, 0x07, 0x42, 0x1f, 0x78, 0x14, 0xf0, 0x5d, 0x3f, - 0xd6, 0xe6, 0x39, 0x94, 0xbe, 0xa5, 0x2c, 0xd7, 0x4f, 0xf5, 0xdf, 0x76, - 0xe3, 0x53, 0x53, 0xa7, 0xff, 0x58, 0xf7, 0x7a, 0xfd, 0x35, 0xd7, 0xb5, - 0x3a, 0x7e, 0x1c, 0xef, 0x9b, 0x13, 0xa7, 0xe5, 0x7f, 0xaa, 0xc3, 0xc9, - 0xd3, 0xb8, 0xe3, 0x82, 0xa7, 0xfe, 0x60, 0x1f, 0x73, 0xc5, 0xb8, 0xca, - 0x39, 0x65, 0xfc, 0x75, 0xd5, 0x35, 0xb9, 0x0c, 0xd1, 0x4a, 0xa9, 0xce, - 0xd3, 0x3d, 0x2c, 0xe1, 0x42, 0x7f, 0xfd, 0x9c, 0xdd, 0x8f, 0x9f, 0x02, - 0xc3, 0x47, 0xc0, 0xe9, 0xd8, 0x14, 0x1e, 0x41, 0x29, 0xe7, 0xdd, 0x2f, - 0x3c, 0x82, 0x53, 0xab, 0xfe, 0x4f, 0x20, 0x94, 0xdc, 0x70, 0x79, 0x04, - 0xa1, 0x11, 0x4c, 0xe1, 0x46, 0xcb, 0xf8, 0x2a, 0x9b, 0x36, 0x59, 0x04, - 0x8b, 0x37, 0xd3, 0xf5, 0xea, 0xec, 0x7c, 0x9d, 0x3b, 0x07, 0xb5, 0x27, - 0x32, 0x31, 0x9d, 0x6c, 0xce, 0x7b, 0xaa, 0xf3, 0x47, 0x4a, 0xfa, 0xe7, - 0xd5, 0xda, 0x3c, 0xfe, 0x71, 0xfe, 0xd1, 0xbf, 0xd0, 0x54, 0xfe, 0xfb, - 0xfd, 0xca, 0xeb, 0xe7, 0x49, 0xe5, 0x4e, 0xc0, 0xa0, 0xa8, 0x2a, 0x18, - 0xda, 0xa0, 0x82, 0x86, 0xe7, 0x85, 0xbb, 0x42, 0x96, 0x6b, 0x21, 0x91, - 0x8b, 0x70, 0x95, 0x9e, 0xf7, 0x01, 0xe7, 0x49, 0x47, 0x4d, 0x6f, 0xe4, - 0xd8, 0xb8, 0x43, 0x3e, 0xe2, 0xdc, 0xfa, 0x8e, 0x9f, 0x91, 0x9c, 0x7b, - 0x76, 0x54, 0xbe, 0x74, 0xff, 0x51, 0xeb, 0xf9, 0xd7, 0xb8, 0x27, 0x4f, - 0xdf, 0x65, 0x51, 0x7c, 0x1d, 0x3e, 0xba, 0x15, 0x6a, 0x3a, 0x75, 0x7e, - 0x07, 0x40, 0x9e, 0x16, 0xc9, 0xe7, 0xe1, 0xce, 0xfb, 0xf6, 0xa7, 0x4f, - 0xdf, 0xf3, 0xe1, 0x94, 0xbe, 0x53, 0x0c, 0xb1, 0x00, 0x3c, 0xab, 0x86, - 0xc8, 0x62, 0xd3, 0xd3, 0xf9, 0x48, 0xc6, 0x73, 0x3c, 0x37, 0x47, 0xa7, - 0x43, 0xd5, 0xec, 0x59, 0x66, 0xa1, 0xfa, 0x2a, 0xf5, 0x94, 0x03, 0xb3, - 0x59, 0xff, 0xf5, 0x00, 0x17, 0xce, 0x2b, 0x59, 0xb1, 0x67, 0x0e, 0x9f, - 0xff, 0xfd, 0xe8, 0x7a, 0xe0, 0xe7, 0x75, 0xad, 0xf9, 0xbf, 0x43, 0x39, - 0x6d, 0x31, 0xd3, 0xb8, 0xe3, 0x82, 0xa6, 0x7b, 0x14, 0xb2, 0xfe, 0x19, - 0x31, 0x2a, 0x15, 0x02, 0x13, 0x53, 0xf5, 0x0e, 0x3f, 0xac, 0x0a, 0x0e, - 0x9e, 0xd6, 0x53, 0xc1, 0xd3, 0xea, 0x03, 0xec, 0xa3, 0xa7, 0xff, 0x9b, - 0xc6, 0xc5, 0xbb, 0xcd, 0xf7, 0xe0, 0x5e, 0x74, 0x75, 0xb4, 0x69, 0x7c, - 0xd7, 0x08, 0xf6, 0x4f, 0x3b, 0xc7, 0x2e, 0x1d, 0x39, 0xff, 0x13, 0xa7, - 0xed, 0xb3, 0x83, 0xed, 0x4e, 0x8a, 0x0f, 0xa5, 0xe4, 0x1b, 0x1b, 0x9b, - 0x2a, 0x74, 0xde, 0xbb, 0x87, 0x40, 0x9b, 0x1f, 0x45, 0x66, 0xc5, 0xbb, - 0xcd, 0xf6, 0x73, 0xba, 0x37, 0xeb, 0x58, 0x89, 0xa5, 0x21, 0x51, 0x18, - 0x5b, 0xc8, 0x79, 0x8e, 0x46, 0xe5, 0x99, 0xf9, 0x85, 0xda, 0x11, 0xd2, - 0x55, 0xf8, 0x6f, 0x39, 0x1a, 0x68, 0x42, 0x3d, 0x51, 0x9f, 0x6a, 0x5f, - 0xee, 0x42, 0x14, 0x48, 0x6b, 0x2a, 0xaf, 0x73, 0xc9, 0x9e, 0xc6, 0xeb, - 0xd5, 0x18, 0x3f, 0x88, 0x55, 0xbb, 0x30, 0xcf, 0xfe, 0x5a, 0xb1, 0xeb, - 0xb0, 0x4c, 0xc4, 0x34, 0x51, 0x53, 0xf9, 0x76, 0x09, 0x98, 0x86, 0x8b, - 0xa2, 0x7f, 0xe5, 0xe3, 0xd7, 0x60, 0x99, 0x88, 0x68, 0x92, 0xe7, 0xf2, - 0xec, 0x13, 0x31, 0x0d, 0x17, 0x94, 0x33, 0xa3, 0xfe, 0xa0, 0x9d, 0xe7, - 0x76, 0x76, 0x8a, 0x4e, 0x1d, 0xa8, 0xef, 0x50, 0xc6, 0x1a, 0xfb, 0xc2, - 0xb1, 0xe7, 0xed, 0x4b, 0xd3, 0xb7, 0x49, 0x93, 0xff, 0x96, 0xac, 0x7a, - 0xec, 0x13, 0x31, 0x0d, 0x12, 0xcc, 0xde, 0xe8, 0xe9, 0xe4, 0xcc, 0x43, - 0x44, 0x67, 0x3f, 0x7d, 0x95, 0x45, 0xf0, 0x74, 0xc2, 0xf3, 0xa4, 0xa3, - 0xa7, 0xdf, 0x0d, 0x62, 0xc0, 0xf4, 0xd4, 0x5d, 0xe0, 0x56, 0x7e, 0xc7, - 0xfc, 0x30, 0x0e, 0x9f, 0xfa, 0xbf, 0xf6, 0xb6, 0x3e, 0xbe, 0xea, 0x74, - 0xea, 0xb5, 0x27, 0x40, 0x26, 0xaa, 0xa7, 0xe1, 0x4c, 0xa9, 0x56, 0xd1, - 0x67, 0xfe, 0xdf, 0xc3, 0x3b, 0xe9, 0x4b, 0xd9, 0x47, 0x4f, 0x85, 0x9f, - 0x5c, 0x3a, 0x3e, 0x7d, 0x8e, 0x91, 0xe7, 0x67, 0x87, 0x9d, 0x3f, 0xfd, - 0xee, 0xeb, 0x4b, 0xd8, 0x7b, 0xaf, 0x4f, 0x44, 0xe9, 0xcd, 0xb6, 0x3a, - 0x5f, 0xe4, 0xfb, 0xdd, 0x2a, 0xcf, 0xfd, 0x6a, 0xdf, 0xf8, 0xab, 0x6b, - 0x3a, 0xe7, 0x4f, 0xfb, 0x4d, 0xfd, 0x7d, 0x85, 0xcf, 0x4e, 0x9f, 0xd7, - 0x56, 0xdd, 0x75, 0xf3, 0xa4, 0xb7, 0x79, 0x5d, 0xad, 0xc6, 0xd8, 0xe4, - 0x2d, 0x74, 0x49, 0x90, 0x8c, 0x12, 0xba, 0xa4, 0x75, 0x1f, 0xcf, 0xfe, - 0x5a, 0xb1, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x4d, 0x33, 0xff, 0x96, 0xac, - 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x13, 0x8c, 0xff, 0xe5, 0xab, 0x1e, 0xbb, - 0x04, 0xcc, 0x43, 0x45, 0x03, 0x3e, 0x04, 0xcc, 0x43, 0x45, 0xc1, 0x33, - 0x7c, 0xe9, 0xfc, 0x2f, 0x6f, 0xf3, 0x6a, 0x3a, 0x4b, 0xb3, 0xf7, 0xd1, - 0x87, 0xa2, 0xb3, 0xfb, 0xeb, 0xf0, 0xdd, 0xdf, 0x07, 0x4f, 0xf3, 0xd7, - 0x60, 0x99, 0x88, 0x68, 0x92, 0x64, 0xbd, 0x1f, 0xbe, 0x1b, 0x45, 0x0b, - 0xda, 0xcf, 0x9c, 0x07, 0x48, 0x47, 0xb8, 0xa5, 0xda, 0x95, 0x61, 0x93, - 0xb8, 0x56, 0x4f, 0xfb, 0xce, 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x6a, 0x4f, - 0xfb, 0x1e, 0xbb, 0x04, 0xcc, 0x43, 0x44, 0xab, 0x07, 0x49, 0x7e, 0x51, - 0x30, 0xa4, 0x87, 0x64, 0x69, 0xfc, 0xbb, 0x04, 0xcc, 0x43, 0x44, 0x53, - 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0x8d, 0x26, 0xf7, 0x47, 0x4f, 0x26, - 0x62, 0x1a, 0x29, 0xf9, 0xb6, 0xc7, 0x40, 0x1e, 0x06, 0xca, 0xe7, 0xfe, - 0xf7, 0x61, 0xeb, 0x95, 0x4c, 0x72, 0xa7, 0x4f, 0xfd, 0x6e, 0x7a, 0x34, - 0x55, 0x31, 0xca, 0x9d, 0x25, 0xbb, 0xc9, 0x82, 0xda, 0xb8, 0x90, 0xed, - 0x1e, 0x7f, 0xf2, 0xd5, 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x6a, 0x9f, - 0xcb, 0xb0, 0x4c, 0xc4, 0x34, 0x57, 0x73, 0xc9, 0x98, 0x86, 0x8a, 0xfa, - 0x77, 0x1c, 0x70, 0x54, 0x84, 0xa5, 0x97, 0xf0, 0x07, 0xd0, 0xa4, 0xa9, - 0xcf, 0x6a, 0x4e, 0x9f, 0xf5, 0xeb, 0x8c, 0xdd, 0x5a, 0xe8, 0x3a, 0x5b, - 0x3a, 0x7f, 0xbe, 0x17, 0x47, 0xdf, 0x7c, 0x9d, 0x00, 0x79, 0x38, 0x21, - 0x25, 0xda, 0x39, 0x1c, 0x21, 0x11, 0xca, 0xc2, 0x1e, 0x7f, 0xf2, 0xd5, - 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x7b, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, - 0x34, 0x5c, 0x33, 0xff, 0x2f, 0x1e, 0xbb, 0x04, 0xcc, 0x43, 0x44, 0x9f, - 0x0c, 0xb9, 0xed, 0x41, 0xdb, 0xce, 0xfc, 0xc6, 0x80, 0x88, 0xee, 0x29, - 0x04, 0x70, 0xfa, 0x47, 0xaa, 0x93, 0xa3, 0xb9, 0xfc, 0xbb, 0x04, 0xcc, - 0x43, 0x44, 0x55, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0xa6, 0x67, 0xff, - 0x2d, 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x26, 0x79, 0xff, 0xcb, 0x56, - 0x3d, 0x76, 0x09, 0x98, 0x86, 0x8a, 0x36, 0x28, 0x4c, 0x6b, 0x93, 0xbf, - 0x27, 0x7b, 0x52, 0x9f, 0xf9, 0x78, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x23, - 0xa9, 0xbd, 0xd1, 0xd3, 0xf7, 0xec, 0x79, 0xba, 0x0e, 0x9f, 0x02, 0x66, - 0x21, 0xa2, 0x9a, 0x9f, 0xfd, 0xaf, 0xee, 0xb9, 0x4d, 0xb8, 0xda, 0xa9, - 0xd3, 0xff, 0x3f, 0x5f, 0x1a, 0x2b, 0xeb, 0x03, 0x87, 0x4c, 0xde, 0x4e, - 0x9f, 0xbe, 0xca, 0xa2, 0xf8, 0x3a, 0x7f, 0xfa, 0xf7, 0xab, 0x78, 0x60, - 0xef, 0x58, 0xf3, 0xa6, 0x6e, 0xce, 0x9f, 0xd9, 0x4b, 0x27, 0xd1, 0x60, - 0x89, 0x01, 0x2e, 0xf0, 0x99, 0x1a, 0x47, 0xf5, 0x61, 0x4f, 0x25, 0xbb, - 0xca, 0x8a, 0xf9, 0x17, 0xb2, 0xd4, 0x30, 0xa5, 0x2f, 0x71, 0xa2, 0x4f, - 0x81, 0x33, 0x10, 0xd1, 0x55, 0x4f, 0xfb, 0x1e, 0xbb, 0x04, 0xcc, 0x43, - 0x44, 0xdb, 0x25, 0xd9, 0xfb, 0x28, 0xc2, 0x7f, 0x2e, 0xc1, 0x33, 0x10, - 0xd1, 0x5f, 0xcf, 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x2c, 0x69, 0xf0, 0x26, - 0x62, 0x1a, 0x2d, 0x59, 0xff, 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, 0xa0, - 0xa4, 0xbb, 0x3f, 0x65, 0x18, 0x4f, 0x81, 0x33, 0x10, 0xd1, 0x71, 0x4f, - 0x63, 0xb7, 0xe8, 0x3a, 0x79, 0xd9, 0xdb, 0xe8, 0x74, 0xfe, 0x65, 0x63, - 0xa6, 0x07, 0x63, 0xa4, 0xbb, 0x45, 0x8e, 0x8c, 0x30, 0x97, 0x64, 0xf3, - 0xe0, 0x4c, 0xc4, 0x34, 0x5d, 0x33, 0xe6, 0x1c, 0xe5, 0x8e, 0x92, 0xec, - 0xf5, 0x7e, 0x61, 0x3f, 0xff, 0x29, 0x76, 0xf6, 0x0e, 0xfa, 0x57, 0x4c, - 0xac, 0x13, 0xa7, 0xff, 0xed, 0x0f, 0xb9, 0xd7, 0xb7, 0xea, 0xfc, 0xdf, - 0x2e, 0x7a, 0x74, 0xc9, 0x67, 0x43, 0x1f, 0xbf, 0x96, 0x39, 0xff, 0x3e, - 0xc0, 0x31, 0xf4, 0x5f, 0x07, 0x4e, 0x1c, 0x58, 0x1f, 0x06, 0xc8, 0xe7, - 0xfc, 0x0d, 0x4e, 0xb2, 0xbb, 0x6e, 0x0e, 0x9b, 0xdd, 0x1d, 0x3e, 0x1b, - 0xd6, 0x6c, 0xe9, 0xf9, 0xf9, 0x6e, 0x9b, 0x93, 0xa1, 0xdf, 0x3d, 0x3e, - 0xb5, 0x12, 0xcf, 0xdd, 0xe3, 0x8f, 0xfe, 0xce, 0x9f, 0xff, 0xe6, 0xe7, - 0x57, 0x4e, 0xc7, 0x35, 0xde, 0x56, 0xb8, 0x08, 0x74, 0xfe, 0xbb, 0xbf, - 0x3e, 0x71, 0xe7, 0x47, 0x94, 0x4c, 0xed, 0x96, 0x7f, 0xff, 0xb4, 0xc3, - 0xed, 0x75, 0xfa, 0xef, 0x57, 0xcf, 0xeb, 0x62, 0x74, 0xf2, 0x66, 0x21, - 0xa2, 0x4c, 0x9f, 0x27, 0x5a, 0x75, 0x9d, 0x6d, 0xdf, 0x3a, 0x7f, 0x5d, - 0x3b, 0xde, 0x3e, 0xa7, 0x43, 0x1f, 0x88, 0x1f, 0x43, 0xd3, 0x23, 0x06, - 0x75, 0x42, 0x72, 0x7e, 0xe7, 0xb7, 0x7e, 0xbd, 0xf5, 0x1d, 0x3f, 0xfb, - 0x5f, 0xdd, 0x29, 0xf0, 0xab, 0x8d, 0x87, 0x4f, 0xaf, 0x7f, 0x56, 0x1d, - 0x3f, 0xfe, 0xc4, 0x06, 0xd0, 0xde, 0xed, 0x7c, 0x71, 0xc1, 0x50, 0xf3, - 0xfa, 0xd9, 0x34, 0xfc, 0x89, 0xea, 0x0b, 0x1d, 0x3f, 0xfb, 0xd1, 0xcd, - 0xb0, 0x57, 0x4c, 0x3b, 0x3a, 0x77, 0x1c, 0x70, 0x54, 0xfc, 0x19, 0x42, - 0xbf, 0x52, 0x96, 0x5f, 0xcf, 0xad, 0x41, 0x7d, 0x73, 0xa7, 0xdf, 0xdd, - 0x17, 0xc1, 0xd3, 0xfc, 0xc9, 0xa1, 0xf7, 0x6d, 0x53, 0xa7, 0xff, 0xdb, - 0xd5, 0xbf, 0xa2, 0x6b, 0xfb, 0xa5, 0x3e, 0x07, 0x40, 0x22, 0xdd, 0x45, - 0x22, 0x6f, 0x3f, 0xd7, 0x9d, 0xf4, 0xbe, 0x71, 0xe7, 0x4f, 0xfe, 0xca, - 0x35, 0xf6, 0x1b, 0x73, 0xe1, 0xf3, 0xa2, 0xd1, 0x63, 0xb2, 0xee, 0x0e, - 0xa7, 0xc3, 0x7a, 0xcd, 0x9d, 0x3f, 0xe7, 0xb0, 0xd1, 0xe0, 0x07, 0xd7, - 0x9d, 0x1d, 0x73, 0xe5, 0x70, 0x96, 0x7b, 0x74, 0x5f, 0x27, 0x4f, 0xf7, - 0xfc, 0xf8, 0x0e, 0xd5, 0xfa, 0x9d, 0x0e, 0x1f, 0x0f, 0x51, 0x1c, 0xee, - 0x38, 0xe0, 0xe9, 0xff, 0xf5, 0xab, 0x62, 0xdd, 0xdf, 0x35, 0xb5, 0x32, - 0x14, 0xb2, 0xfe, 0x2d, 0x32, 0xff, 0xc2, 0x23, 0x48, 0xb2, 0xf9, 0xd3, - 0xf6, 0x9b, 0xa2, 0x7e, 0x83, 0xa7, 0xe0, 0xc0, 0x16, 0x79, 0xd0, 0xee, - 0x8f, 0xa3, 0x91, 0x00, 0x2f, 0x99, 0xeb, 0x77, 0x99, 0x1e, 0x1d, 0x63, - 0x53, 0x17, 0xbe, 0x19, 0x17, 0x1a, 0x47, 0x93, 0x54, 0x39, 0xa6, 0x18, - 0x9f, 0x22, 0x70, 0xab, 0x19, 0x84, 0xf2, 0xb1, 0xc8, 0xee, 0x3c, 0x4f, - 0x10, 0x9d, 0x9f, 0xfc, 0x17, 0xc7, 0x3a, 0xb7, 0x06, 0xc1, 0xe7, 0x4e, - 0x0b, 0xeb, 0x9d, 0x2b, 0x03, 0xe7, 0x52, 0x4c, 0xff, 0xd7, 0xa1, 0x6a, - 0x3c, 0x6b, 0x59, 0xd7, 0x3a, 0x7e, 0xc4, 0x5f, 0x1c, 0x70, 0x74, 0x97, - 0x6c, 0xc9, 0xe4, 0x8c, 0xc8, 0x0c, 0x72, 0x92, 0x5c, 0x31, 0xb7, 0xd4, - 0x99, 0xd2, 0x4c, 0x3d, 0xb3, 0x1d, 0xe6, 0x53, 0xbd, 0x30, 0xe0, 0x02, - 0x75, 0x1d, 0xf7, 0x0b, 0x1a, 0xc3, 0x63, 0x70, 0x96, 0xf6, 0x99, 0x8b, - 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0x8d, 0x67, 0xc0, 0x99, 0x88, 0x68, - 0xa9, 0x66, 0xc4, 0x34, 0x43, 0x52, 0x5d, 0x9e, 0x8e, 0x18, 0x4f, 0xfc, - 0xbc, 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x11, 0xf4, 0xfe, 0x5d, 0x82, 0x66, - 0x21, 0xa2, 0xc7, 0x9d, 0xd6, 0x8a, 0xf2, 0x74, 0xfc, 0xef, 0x8d, 0xeb, - 0x36, 0x74, 0xff, 0x0e, 0x77, 0x5c, 0xde, 0xf0, 0xe9, 0xee, 0xd5, 0xf0, - 0x3a, 0x7f, 0xff, 0x98, 0x06, 0xf9, 0xbd, 0x6b, 0xe9, 0xaf, 0xee, 0xb9, - 0x49, 0xd1, 0xf4, 0x43, 0xe8, 0x8a, 0x76, 0x62, 0x1a, 0x2d, 0x09, 0xff, - 0x67, 0x0e, 0xc9, 0x81, 0x45, 0xf0, 0x74, 0x21, 0xf3, 0x81, 0x34, 0xff, - 0xff, 0xf7, 0xc3, 0x58, 0x3f, 0x6d, 0xff, 0x4d, 0x5d, 0x5d, 0x42, 0xd2, - 0xf6, 0x74, 0x02, 0x26, 0x34, 0x41, 0x3f, 0x3a, 0xf1, 0xb1, 0x6e, 0xce, - 0x9f, 0x36, 0xef, 0x4c, 0x74, 0xff, 0xf5, 0xee, 0xb6, 0xe6, 0x99, 0xd5, - 0xeb, 0x4c, 0x74, 0x50, 0x7e, 0xa2, 0x4b, 0x0c, 0x8c, 0x8b, 0x85, 0x34, - 0xff, 0xbb, 0x64, 0xd7, 0xdc, 0xcc, 0xa0, 0xe9, 0xfe, 0xff, 0xa2, 0xf0, - 0x6b, 0xe4, 0xe9, 0xff, 0xfe, 0xd5, 0xbd, 0x35, 0xfd, 0x35, 0x83, 0xf6, - 0x2c, 0xaa, 0x9d, 0x2b, 0xaa, 0x26, 0xf6, 0x71, 0x3e, 0xde, 0xb0, 0x7c, - 0x9d, 0x3f, 0xc3, 0xed, 0x1c, 0xea, 0xc5, 0x8e, 0x98, 0x6e, 0xcf, 0x85, - 0x0a, 0x27, 0xf5, 0xe9, 0xcf, 0xeb, 0xea, 0x3a, 0x7f, 0x3e, 0xc2, 0xa2, - 0xd4, 0x1d, 0x3a, 0xf5, 0x87, 0x4f, 0x9c, 0xe7, 0xdf, 0x44, 0xe8, 0xe4, - 0xf1, 0x70, 0x6a, 0x7f, 0xae, 0xf8, 0xb4, 0x4b, 0xe0, 0xe8, 0xb4, 0xc0, - 0xa9, 0x34, 0xc7, 0x6a, 0x91, 0x4f, 0x5e, 0xb3, 0x67, 0x4f, 0xdf, 0x1f, - 0x5f, 0x75, 0x3a, 0x7f, 0xff, 0xbe, 0x3e, 0xbe, 0xeb, 0xd2, 0xf6, 0xd4, - 0xf7, 0x9a, 0xd7, 0xce, 0x8f, 0x28, 0x97, 0xd9, 0x6c, 0x96, 0xef, 0x2f, - 0x76, 0xf5, 0x84, 0xac, 0x61, 0xcc, 0x2f, 0xae, 0x32, 0x2d, 0x43, 0xab, - 0xb2, 0x61, 0x86, 0xd5, 0x61, 0x13, 0xb8, 0xcb, 0x3a, 0x8f, 0x7c, 0x42, - 0xde, 0x7e, 0x76, 0xff, 0x22, 0xce, 0x1d, 0x3d, 0x7a, 0xcd, 0x9d, 0x27, - 0x7e, 0xcf, 0x44, 0x4c, 0x67, 0xc0, 0x99, 0x88, 0x68, 0xb5, 0xa7, 0xfd, - 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x83, 0x92, 0xfa, 0xc4, 0x50, 0xd9, - 0x5a, 0x8c, 0x27, 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x28, - 0xb9, 0xfc, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0xd5, 0x0f, 0x65, 0x60, 0x24, - 0x23, 0x3e, 0x4c, 0xa4, 0xcd, 0x4f, 0x94, 0x77, 0x1e, 0x9d, 0x4e, 0xb6, - 0xa5, 0x3e, 0x04, 0xcc, 0x43, 0x44, 0x43, 0x3b, 0x57, 0xc9, 0xd2, 0x5d, - 0x9e, 0x65, 0x26, 0x13, 0xf9, 0x76, 0x09, 0x98, 0x86, 0x88, 0xda, 0x7f, - 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x4d, 0xcf, 0xe5, 0xd8, 0x26, 0x62, 0x1a, - 0x2a, 0x09, 0xfc, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0x4d, 0x3e, 0x04, 0xcc, - 0x43, 0x45, 0x61, 0x3e, 0xff, 0x1c, 0xfa, 0x07, 0x4f, 0xf3, 0xd7, 0x60, - 0x99, 0x88, 0x68, 0x8f, 0xe7, 0x5b, 0x50, 0x74, 0x97, 0x68, 0xb6, 0x43, - 0x0c, 0x2a, 0x14, 0x19, 0xff, 0xcb, 0x56, 0x3d, 0x76, 0x09, 0x98, 0x86, - 0x89, 0xbe, 0x7f, 0xe5, 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, 0x9f, 0xa7, - 0xdd, 0x6d, 0xdf, 0xea, 0xba, 0x4e, 0x96, 0x8e, 0x87, 0x76, 0x78, 0xde, - 0x9b, 0x4f, 0xba, 0x79, 0x0c, 0x43, 0xa7, 0xdd, 0x63, 0xba, 0xef, 0xcb, - 0x1d, 0x3f, 0xfc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcd, 0x4d, 0x4e, 0x9f, 0x07, - 0xe8, 0xc5, 0x15, 0x37, 0x1c, 0x15, 0x16, 0x6f, 0xf8, 0x27, 0x97, 0xa5, - 0x2c, 0xd0, 0xc3, 0x23, 0x2a, 0xb0, 0xa9, 0x9f, 0xff, 0xad, 0x55, 0xd8, - 0x65, 0x1c, 0xe9, 0xab, 0xbf, 0x74, 0x74, 0xfb, 0x13, 0x5f, 0x03, 0xa7, - 0xff, 0xff, 0x0e, 0x79, 0xf8, 0x33, 0xfa, 0x6b, 0xea, 0xe5, 0xba, 0x75, - 0x7b, 0xaf, 0x81, 0xd1, 0xca, 0x60, 0x60, 0xbb, 0xa2, 0x59, 0xff, 0xf3, - 0xb3, 0x52, 0xfc, 0x1e, 0xfa, 0x77, 0xf0, 0xff, 0x93, 0xa7, 0xa8, 0x57, - 0xde, 0x74, 0xfa, 0xa3, 0xee, 0x3c, 0xe9, 0xfd, 0xa6, 0x52, 0xfb, 0xed, - 0x8e, 0x90, 0x31, 0xff, 0x59, 0x1f, 0xc9, 0xe7, 0xfc, 0xd4, 0xf3, 0xe1, - 0xba, 0xfa, 0xf6, 0xa7, 0x4e, 0xee, 0xb6, 0x74, 0xff, 0xdc, 0xb6, 0xf2, - 0xb7, 0xad, 0x7d, 0x47, 0x4e, 0xdf, 0xdc, 0x3a, 0x18, 0xf8, 0x6a, 0x89, - 0x0c, 0xad, 0x3b, 0xf1, 0x95, 0x38, 0x62, 0x10, 0xdc, 0x51, 0x90, 0xa3, - 0xed, 0xf6, 0x73, 0x9e, 0x14, 0x74, 0xff, 0x5e, 0xeb, 0x7b, 0xd5, 0xf6, - 0x74, 0x61, 0xeb, 0x88, 0xfc, 0xd8, 0x27, 0x40, 0x1b, 0x45, 0x10, 0x4e, - 0xe3, 0x8e, 0x0e, 0x9e, 0xa0, 0x7e, 0xc5, 0x2c, 0xbf, 0x9a, 0x97, 0x9d, - 0x37, 0xd0, 0xe9, 0x52, 0xc6, 0xb3, 0x62, 0xf0, 0xc8, 0xc2, 0xd1, 0xff, - 0xab, 0x93, 0xff, 0x51, 0xef, 0x76, 0x3e, 0xb8, 0xdb, 0xc3, 0xa7, 0xfe, - 0x6d, 0x78, 0xe7, 0x7f, 0xb7, 0x19, 0x47, 0x4f, 0x36, 0xea, 0x86, 0x88, - 0x3a, 0x7e, 0xcd, 0x37, 0x5f, 0xd7, 0x9d, 0x00, 0x8e, 0xc5, 0x23, 0xed, - 0x1d, 0xd1, 0x6c, 0xc1, 0xc9, 0xd3, 0x71, 0xc1, 0xd0, 0xf3, 0x5d, 0xc0, - 0xb4, 0xf5, 0x5b, 0xee, 0x8a, 0x59, 0xa2, 0x9f, 0x57, 0xc7, 0x3d, 0xd4, - 0xe8, 0xf9, 0xef, 0xf8, 0x33, 0x9d, 0xc7, 0x1c, 0x15, 0x05, 0x2c, 0xbf, - 0x9e, 0xff, 0x1f, 0x70, 0xa8, 0x43, 0x7b, 0xf1, 0x98, 0xfa, 0x71, 0xba, - 0x87, 0x68, 0xc2, 0x02, 0x70, 0xfe, 0xa7, 0x4f, 0x73, 0x83, 0xd9, 0xd3, - 0xff, 0x30, 0xf6, 0x2d, 0x4b, 0x8c, 0x3d, 0x9d, 0x1f, 0x44, 0x0f, 0x63, - 0x75, 0x22, 0x9f, 0x35, 0x86, 0xbe, 0x74, 0xf7, 0x36, 0xae, 0xb9, 0xd0, - 0xe1, 0xe5, 0xba, 0x25, 0x9f, 0xb7, 0x6e, 0x0b, 0x28, 0xf1, 0x01, 0x4f, - 0xb0, 0x79, 0xd3, 0x1a, 0x20, 0x25, 0x9b, 0x99, 0xfe, 0x60, 0xa3, 0xa5, - 0xb9, 0xf5, 0x1d, 0x3c, 0xa6, 0xb5, 0x1d, 0x3e, 0x6e, 0xff, 0x4d, 0x4e, - 0x9f, 0xc0, 0xe5, 0x7e, 0x3b, 0xf9, 0xd3, 0xd4, 0xf6, 0x0c, 0x54, 0xdc, - 0x70, 0x54, 0x31, 0xba, 0xe0, 0x8a, 0x7e, 0xc0, 0x7b, 0xc7, 0xe5, 0x2c, - 0xd0, 0xc3, 0x2a, 0x6a, 0xb7, 0xcf, 0xaf, 0x69, 0x0f, 0x0e, 0xc4, 0x83, - 0x65, 0x3e, 0xc2, 0x3a, 0x7d, 0xee, 0xfd, 0xcf, 0x06, 0x88, 0x1e, 0x7f, - 0xda, 0xf6, 0x86, 0xe8, 0xdb, 0x6e, 0x4e, 0x9d, 0x81, 0x41, 0xd3, 0x71, - 0xc1, 0xd3, 0xf8, 0x3f, 0x6e, 0xbc, 0x3d, 0x68, 0x6c, 0xf8, 0x1b, 0x8e, - 0x51, 0x84, 0x0e, 0xb3, 0xff, 0x0d, 0xf9, 0xd6, 0x3f, 0xc6, 0x52, 0xc7, - 0x43, 0x1f, 0x4d, 0x91, 0xcf, 0xfe, 0xb5, 0x2b, 0x1f, 0x60, 0x99, 0x88, - 0x68, 0x86, 0x23, 0x47, 0xe2, 0x24, 0x13, 0xe0, 0x4c, 0xc4, 0x34, 0x41, - 0x53, 0xb4, 0xca, 0x3a, 0x2c, 0xf2, 0xfe, 0x61, 0x3d, 0xba, 0xb7, 0x65, - 0x4e, 0xc0, 0xa0, 0xa9, 0xef, 0x47, 0x3c, 0x95, 0x3f, 0xbf, 0x45, 0xee, - 0xad, 0xd9, 0x50, 0x54, 0xfd, 0x68, 0xda, 0x65, 0x15, 0x37, 0x1c, 0x15, - 0x3f, 0x0b, 0x0d, 0x1f, 0x02, 0xa2, 0xd3, 0x0b, 0x42, 0x25, 0x0d, 0xe8, - 0x8f, 0xb3, 0x41, 0x0a, 0xe0, 0xab, 0xc0, 0xc4, 0xdf, 0x02, 0x96, 0x7e, - 0x72, 0xc7, 0xa7, 0x8b, 0xa8, 0xe7, 0xe7, 0xfc, 0xcf, 0xc1, 0xba, 0x83, - 0x54, 0xe9, 0xfe, 0xde, 0x99, 0xd7, 0x2d, 0xdb, 0x1d, 0x3f, 0xcd, 0x4b, - 0xfa, 0x99, 0x2d, 0x47, 0x43, 0x1f, 0xae, 0x8e, 0xe7, 0xff, 0xe7, 0x33, - 0x1f, 0x9a, 0xe9, 0x74, 0x7b, 0xbf, 0x73, 0xc1, 0xa2, 0xfb, 0x9f, 0x7f, - 0x63, 0x6f, 0x3a, 0x7f, 0xc3, 0xf7, 0xef, 0x56, 0x1f, 0xa9, 0xd3, 0xfb, - 0x7d, 0xf8, 0x17, 0xea, 0xcf, 0x10, 0x0c, 0xec, 0x07, 0x9e, 0x20, 0x18, - 0xb3, 0xe9, 0xf5, 0x0a, 0x6c, 0x79, 0xe2, 0x01, 0x9e, 0xc1, 0xa5, 0xe7, - 0x88, 0x06, 0x7f, 0x7d, 0x35, 0x7d, 0xf6, 0xc7, 0x88, 0x06, 0x77, 0xc7, - 0x93, 0xc4, 0x03, 0x1c, 0xa2, 0xe5, 0x44, 0x5a, 0x2e, 0x74, 0x81, 0x38, - 0x1b, 0x67, 0x88, 0x06, 0x0f, 0x10, 0x0c, 0xcc, 0xa3, 0xc4, 0x03, 0x1c, - 0x9b, 0x9f, 0x8b, 0xcf, 0x7d, 0x5c, 0xb1, 0xe2, 0x01, 0x9d, 0xbc, 0x43, - 0xc4, 0x03, 0x3f, 0xe1, 0xc7, 0xaf, 0x5f, 0x4c, 0x03, 0xc4, 0x03, 0x36, - 0x72, 0x78, 0x80, 0x67, 0xf0, 0xe7, 0x15, 0xab, 0x76, 0x78, 0x80, 0x67, - 0xdf, 0xf3, 0x83, 0xd9, 0xe2, 0x01, 0x9b, 0xf5, 0x3c, 0x40, 0x30, 0x07, - 0xb3, 0xb3, 0x69, 0xf6, 0xc5, 0xa9, 0x79, 0xa2, 0x01, 0x9b, 0xb6, 0x3c, - 0x40, 0x2b, 0x36, 0x93, 0xef, 0xb2, 0xb3, 0x93, 0xc4, 0x03, 0x3d, 0xee, - 0x0a, 0x1e, 0x20, 0x19, 0xcc, 0x08, 0x78, 0x80, 0x67, 0xfd, 0x74, 0xd7, - 0x96, 0xb1, 0xee, 0xa7, 0x88, 0x06, 0x7d, 0xee, 0x3d, 0xec, 0x78, 0x80, - 0x62, 0xd1, 0x01, 0xa4, 0xc9, 0x83, 0xb3, 0xc4, 0x03, 0x0f, 0x55, 0x21, - 0xc9, 0x1d, 0xc2, 0x67, 0xea, 0xba, 0x33, 0xec, 0xd2, 0xa5, 0xbb, 0x85, - 0x37, 0xa4, 0x53, 0xeb, 0xdd, 0x72, 0x93, 0xc4, 0x03, 0x3f, 0xb9, 0x64, - 0x70, 0x1b, 0x67, 0x88, 0x07, 0x93, 0x69, 0x38, 0x1b, 0x83, 0xc4, 0x03, - 0x08, 0x7f, 0x00, 0xa1, 0x3d, 0xf1, 0x7d, 0x4f, 0x10, 0x0c, 0xfd, 0x8e, - 0x3e, 0xe9, 0x79, 0xe2, 0x01, 0x8b, 0x44, 0x4f, 0x64, 0x1e, 0x97, 0x4f, - 0xf6, 0x9a, 0xab, 0xaf, 0xa1, 0xd9, 0xe2, 0x01, 0x97, 0xcf, 0x10, 0x0c, - 0xd9, 0x47, 0x27, 0xc9, 0xa4, 0x79, 0x83, 0xb3, 0xc4, 0x03, 0x3e, 0xcd, - 0xd7, 0xf4, 0x9e, 0x20, 0x19, 0xfb, 0xe3, 0xeb, 0xee, 0xa7, 0x88, 0x06, - 0x19, 0x12, 0x42, 0x47, 0xb3, 0x58, 0xe5, 0x90, 0x21, 0x70, 0xdb, 0x71, - 0x00, 0x18, 0x34, 0x45, 0x85, 0xfd, 0x93, 0xd6, 0x56, 0xc6, 0xe3, 0xc1, - 0xea, 0x84, 0xaf, 0x88, 0x60, 0xce, 0xcc, 0x43, 0x44, 0x02, 0xb4, 0x5e, - 0xcf, 0x79, 0x77, 0x5c, 0xa8, 0xe9, 0xbb, 0x62, 0xa5, 0xe4, 0xa9, 0xda, - 0x6a, 0x0e, 0x9b, 0x8e, 0x0a, 0x8f, 0x9e, 0xe7, 0x5c, 0x59, 0xc1, 0x2e, - 0x07, 0x27, 0x2b, 0xf5, 0x29, 0x67, 0x85, 0x14, 0x32, 0xb1, 0xde, 0x4c, - 0x94, 0x97, 0x3f, 0x9c, 0x77, 0x0c, 0x99, 0xfd, 0xfd, 0xf8, 0x74, 0xe9, - 0xaa, 0x74, 0xfc, 0x0e, 0x3d, 0x82, 0x83, 0xa7, 0xfc, 0xfa, 0xf4, 0x1b, - 0x53, 0x07, 0x93, 0xa7, 0xfe, 0x0d, 0x65, 0xbd, 0x83, 0xbf, 0x0a, 0x3a, - 0x7e, 0xf1, 0xc0, 0x7e, 0xf4, 0x54, 0xf3, 0x9a, 0xc7, 0x0e, 0x9f, 0x5b, - 0x8f, 0x6a, 0x4e, 0x9e, 0xb1, 0x67, 0x95, 0x00, 0x7d, 0x42, 0x46, 0xec, - 0x51, 0x0c, 0x9b, 0xd5, 0x96, 0xfd, 0x03, 0x48, 0x99, 0x09, 0x99, 0xef, - 0x8e, 0xea, 0x74, 0xef, 0x5d, 0xca, 0x9d, 0x3f, 0xf7, 0x6a, 0xb4, 0xd7, - 0xf9, 0xd7, 0xbe, 0x4e, 0x9f, 0xdc, 0xb5, 0x35, 0xba, 0x76, 0x74, 0xff, - 0x36, 0xfe, 0x9f, 0xe5, 0xb6, 0x74, 0xdb, 0xad, 0x9f, 0x68, 0x1a, 0xcf, - 0xe7, 0xdd, 0x7c, 0x57, 0x76, 0x74, 0x32, 0x67, 0x1f, 0x22, 0xc8, 0x5b, - 0x7a, 0x59, 0x3e, 0xc7, 0x5c, 0xf2, 0xc7, 0x4d, 0x5a, 0x9d, 0x3b, 0x8e, - 0x38, 0x3a, 0x6e, 0xf0, 0xa5, 0x97, 0xf0, 0x07, 0xb5, 0x53, 0x59, 0xff, - 0x5d, 0x47, 0x3c, 0xb8, 0x3f, 0x70, 0xe9, 0xd9, 0xdd, 0x95, 0x0f, 0x4c, - 0x01, 0x50, 0x84, 0xd1, 0x0f, 0x52, 0x04, 0xfe, 0xd8, 0xdd, 0x3d, 0xf8, - 0x79, 0xd3, 0xfc, 0x36, 0xea, 0xd7, 0xc7, 0x1c, 0x15, 0x39, 0x59, 0xb3, - 0xa3, 0x47, 0xae, 0xe8, 0xf2, 0x7d, 0x6e, 0x3d, 0x9e, 0x74, 0x32, 0x63, - 0xdf, 0x46, 0xc8, 0x46, 0xec, 0x92, 0x7e, 0x77, 0x3e, 0x0c, 0x02, 0x74, - 0xff, 0xeb, 0xe7, 0x15, 0x74, 0xbe, 0xfb, 0xbe, 0x4e, 0x9b, 0x58, 0x74, - 0xce, 0x54, 0xe9, 0xf5, 0xba, 0xf8, 0xf3, 0x66, 0xb3, 0xc0, 0xac, 0x74, - 0x45, 0xc2, 0xdd, 0xe7, 0xb9, 0xbd, 0x61, 0xd3, 0xff, 0x35, 0x8b, 0xf5, - 0x62, 0x2d, 0xc1, 0xd2, 0xf8, 0x22, 0x18, 0x49, 0x76, 0x43, 0x14, 0x37, - 0x06, 0x2f, 0x8f, 0x53, 0x99, 0x46, 0x3e, 0x4b, 0xd2, 0x15, 0xff, 0x21, - 0x0a, 0x59, 0xaa, 0x97, 0x75, 0x1d, 0x9f, 0x69, 0xa3, 0x1a, 0xce, 0xe5, - 0x30, 0x7a, 0x82, 0xea, 0x36, 0xd9, 0xfe, 0xb0, 0x16, 0xdb, 0xef, 0x47, - 0x4f, 0xc3, 0xdd, 0xf3, 0x8f, 0x3a, 0x7d, 0xe1, 0xc7, 0xb7, 0x5c, 0xa8, - 0x64, 0x48, 0x59, 0xaf, 0x82, 0xd9, 0xff, 0xc1, 0xe4, 0x7d, 0xcf, 0x17, - 0x5f, 0xb0, 0x9d, 0x2f, 0x06, 0x88, 0x16, 0x5b, 0x35, 0x02, 0x92, 0xfe, - 0xcd, 0xe7, 0x03, 0xf3, 0xfe, 0xff, 0x56, 0xbf, 0xe1, 0x7d, 0xf6, 0xc5, - 0x4f, 0xff, 0xed, 0x30, 0x77, 0x6e, 0xbf, 0x5a, 0xd8, 0xa6, 0x0f, 0x67, - 0x4f, 0xfd, 0x5c, 0xa7, 0xa2, 0x9a, 0xc7, 0x7d, 0x47, 0x46, 0x91, 0x51, - 0xb6, 0x08, 0x64, 0xc4, 0x7f, 0x0e, 0xe9, 0xff, 0xfe, 0x0a, 0x2f, 0xee, - 0x66, 0x3e, 0xac, 0xae, 0x74, 0xc2, 0x87, 0x4e, 0xa0, 0x5e, 0x74, 0x32, - 0xa6, 0x95, 0x42, 0x1f, 0x51, 0x9c, 0xe1, 0x47, 0xac, 0xb3, 0xf9, 0xee, - 0x58, 0xe6, 0xac, 0xe9, 0xff, 0xc0, 0x83, 0x6e, 0x86, 0xd8, 0x1a, 0xa7, - 0x4f, 0xec, 0x73, 0x56, 0xab, 0xa9, 0xd1, 0x67, 0xee, 0xe9, 0x16, 0x7e, - 0xff, 0x9d, 0xdd, 0xa8, 0xe9, 0xf5, 0xf3, 0xf0, 0xa9, 0xd3, 0xff, 0xd5, - 0xdd, 0x29, 0xfd, 0x74, 0x76, 0xbd, 0x7d, 0x47, 0x49, 0xa8, 0x3f, 0xde, - 0x09, 0xe3, 0xe8, 0xf7, 0xd1, 0x1e, 0xe1, 0x57, 0x3f, 0xe1, 0xff, 0x8a, - 0x6d, 0xd5, 0x2d, 0xe0, 0xe9, 0xdc, 0xe0, 0x1d, 0x3e, 0xef, 0x06, 0xdd, - 0x8e, 0x86, 0x3c, 0x4f, 0x46, 0xe7, 0x99, 0x54, 0xb8, 0x74, 0x32, 0xaa, - 0x27, 0xc7, 0x3f, 0x66, 0xb5, 0x84, 0x4e, 0xc8, 0xa7, 0xcd, 0x43, 0x3b, - 0x31, 0xd3, 0xf7, 0xbe, 0x35, 0x74, 0xd4, 0xe9, 0xff, 0xff, 0xf9, 0x81, - 0xb6, 0x38, 0x9f, 0xab, 0x9f, 0x04, 0x6a, 0xed, 0xa9, 0x6f, 0x17, 0x53, - 0xa7, 0xbb, 0xca, 0x6a, 0x74, 0xdc, 0x70, 0x74, 0x54, 0xdd, 0xf0, 0x47, - 0x3e, 0xfe, 0xb2, 0xf4, 0x52, 0xcd, 0x14, 0x69, 0x37, 0x37, 0x70, 0xa4, - 0x4c, 0x6b, 0x0e, 0x39, 0xdc, 0x71, 0xc1, 0x53, 0xcf, 0xdd, 0xa1, 0x4b, - 0x2f, 0xe7, 0xd7, 0xcf, 0xfb, 0xa9, 0xf2, 0xfe, 0x96, 0x01, 0xf2, 0x89, - 0x7c, 0xe6, 0x0a, 0x9d, 0x3f, 0x0d, 0x35, 0x72, 0xf6, 0x74, 0xff, 0xf0, - 0xed, 0xcb, 0x0b, 0xc5, 0x36, 0xbf, 0xc9, 0xd3, 0xea, 0x3a, 0xff, 0xba, - 0x4e, 0x9f, 0x7e, 0xad, 0x42, 0x8f, 0x87, 0xec, 0xf9, 0xb0, 0x3b, 0xf4, - 0xf8, 0x7e, 0xcd, 0x8f, 0x3e, 0x1f, 0xb3, 0xde, 0xbe, 0xea, 0x7c, 0x3f, - 0x63, 0x93, 0xd1, 0x12, 0x29, 0xf3, 0x5d, 0x6c, 0x4f, 0x87, 0xec, 0x1f, - 0x0f, 0xd9, 0xb3, 0x67, 0xc3, 0xf5, 0x45, 0xbc, 0x9e, 0x27, 0xf3, 0xea, - 0x44, 0xf5, 0xf5, 0x7f, 0xb3, 0xe1, 0xfb, 0x07, 0xc3, 0xf6, 0x6e, 0xd8, - 0xf8, 0x7e, 0xcf, 0xf5, 0xf7, 0x81, 0x6e, 0xaf, 0x93, 0xe1, 0xfb, 0x3f, - 0x5e, 0xbf, 0x5f, 0x68, 0x3e, 0x1f, 0xb1, 0xda, 0x29, 0x44, 0x8e, 0xa8, - 0xd3, 0xc1, 0x43, 0x6c, 0xf8, 0x7e, 0xc1, 0xf0, 0xfd, 0xb3, 0x5d, 0x37, - 0x1c, 0x1f, 0x0f, 0xd8, 0x7a, 0xb1, 0x4e, 0x4d, 0x6e, 0x10, 0xb4, 0xc2, - 0x6c, 0x0a, 0x14, 0x65, 0x58, 0x5e, 0x6d, 0x7b, 0x82, 0x69, 0xeb, 0x7b, - 0x79, 0x2e, 0x1f, 0xa5, 0xa2, 0x42, 0x7f, 0xd6, 0x9c, 0xd8, 0x71, 0x9a, - 0x70, 0xe9, 0x9f, 0x41, 0x51, 0x42, 0x25, 0xe9, 0x42, 0x13, 0xe8, 0x05, - 0xc9, 0x9c, 0x9c, 0x68, 0x9f, 0xff, 0x3c, 0x19, 0xd6, 0x38, 0xdc, 0xe9, - 0x95, 0x8e, 0x1d, 0x3f, 0x9d, 0xb2, 0xbf, 0xab, 0x96, 0x74, 0x52, 0x88, - 0xd0, 0x57, 0x86, 0x5e, 0x30, 0x79, 0x2d, 0x8d, 0x7c, 0xbb, 0x27, 0x39, - 0xfd, 0x85, 0xcc, 0xff, 0xbc, 0xb5, 0x22, 0xda, 0xd7, 0xa8, 0x74, 0xfc, - 0x39, 0xe7, 0x58, 0xf3, 0xa7, 0x71, 0xc7, 0x05, 0x4e, 0xf0, 0xdd, 0x94, - 0xb2, 0xfe, 0x7f, 0xc3, 0x8f, 0xf0, 0x16, 0xeb, 0x00, 0xe9, 0xfe, 0x1c, - 0xef, 0xa3, 0xdb, 0xba, 0x4e, 0x8e, 0x53, 0x33, 0x52, 0x07, 0x69, 0x82, - 0x5b, 0xb3, 0xe9, 0xff, 0x08, 0xff, 0xd7, 0x72, 0xbd, 0x4d, 0xb3, 0xa7, - 0x71, 0xc7, 0x05, 0x88, 0x41, 0x3e, 0x04, 0xcc, 0x42, 0xc4, 0x20, 0x59, - 0xad, 0x9d, 0xc7, 0x1c, 0x16, 0x20, 0xf4, 0x16, 0x20, 0xf2, 0xcd, 0x6c, - 0xcc, 0xab, 0x44, 0xb2, 0x37, 0x4f, 0xb6, 0xdb, 0x65, 0x1d, 0x3c, 0x3f, - 0x6f, 0x27, 0x4e, 0xf0, 0xdd, 0x9d, 0x14, 0x1e, 0x02, 0x88, 0xa7, 0xc8, - 0xda, 0x65, 0x15, 0x3e, 0x1c, 0x11, 0xb2, 0xa6, 0xb4, 0x2a, 0x6e, 0x38, - 0x2a, 0x2c, 0xfd, 0x2a, 0x4b, 0xb2, 0x3e, 0x05, 0x27, 0xf0, 0xf8, 0x6e, - 0xf5, 0x6e, 0xc5, 0x2c, 0xde, 0x43, 0x27, 0x01, 0xf6, 0x6c, 0x86, 0x9c, - 0xff, 0xcd, 0xdd, 0x6e, 0xf9, 0xc1, 0xcf, 0x27, 0x4f, 0xff, 0xa9, 0x7d, - 0x78, 0x60, 0xd3, 0x7f, 0x4c, 0x3f, 0x3a, 0x34, 0x89, 0x9c, 0x44, 0x9f, - 0xd5, 0xf0, 0xaa, 0xf1, 0x94, 0x9d, 0x0c, 0xb8, 0x4f, 0x69, 0x9f, 0x8c, - 0x24, 0x23, 0xac, 0xc8, 0x66, 0xd4, 0x8a, 0x77, 0x1c, 0x70, 0x54, 0xf7, - 0x78, 0x3c, 0x94, 0xb2, 0xfe, 0x7e, 0xf1, 0x61, 0x76, 0xe1, 0xd0, 0xf3, - 0xde, 0xa9, 0x8c, 0xff, 0xf0, 0xd3, 0xd2, 0x9e, 0xd8, 0x53, 0x28, 0x1c, - 0x3a, 0x7f, 0xff, 0xff, 0xb7, 0x5f, 0x15, 0xe9, 0xac, 0xfe, 0xff, 0xa4, - 0xff, 0x47, 0xff, 0x58, 0x3b, 0x7d, 0x85, 0x9d, 0x3f, 0xfd, 0x6c, 0xbe, - 0x45, 0xbd, 0x4b, 0xf3, 0xf0, 0x3a, 0x79, 0xdb, 0x5d, 0xba, 0x3a, 0x1e, - 0x7e, 0xf8, 0x9f, 0x3f, 0xf9, 0xf6, 0x1d, 0xab, 0xf5, 0xf1, 0x56, 0xb3, - 0xa7, 0xbf, 0xcd, 0xa8, 0xe8, 0x65, 0x42, 0x2f, 0x22, 0xb5, 0x1c, 0x8c, - 0x40, 0x48, 0x7d, 0x4b, 0x9f, 0xba, 0xf5, 0xf8, 0xd2, 0xf3, 0xa7, 0xfd, - 0x81, 0xd5, 0xfd, 0x5e, 0x53, 0xd9, 0xd3, 0xfe, 0xad, 0x58, 0x36, 0xcb, - 0xe7, 0xe7, 0x4f, 0xf8, 0x71, 0xcd, 0x60, 0x07, 0xf9, 0x3a, 0x2d, 0x1d, - 0xc8, 0x65, 0xf4, 0x15, 0x1f, 0x4f, 0x3f, 0xc5, 0xb8, 0x74, 0xf8, 0x39, - 0xbb, 0x13, 0xa7, 0xfe, 0xeb, 0xfe, 0xf4, 0xce, 0xab, 0xa6, 0xa4, 0xe8, - 0xc3, 0xef, 0xa9, 0x2c, 0xff, 0xf5, 0xee, 0xb6, 0xe6, 0x99, 0xd5, 0xeb, - 0x4c, 0x74, 0xf5, 0xef, 0xf5, 0x3a, 0x7e, 0x77, 0x6e, 0x0b, 0xbd, 0x47, - 0xa7, 0x45, 0x4f, 0x73, 0x64, 0x31, 0xca, 0x3b, 0xc4, 0x87, 0x70, 0xac, - 0x9f, 0xfe, 0xfd, 0x6f, 0x9d, 0xd7, 0xfe, 0x75, 0x83, 0xf3, 0xa7, 0xff, - 0xf0, 0xee, 0xf5, 0xf6, 0xdf, 0xfb, 0x67, 0xaf, 0x8e, 0x38, 0x2a, 0x7b, - 0x9b, 0xbf, 0x25, 0x4f, 0x67, 0x79, 0xb3, 0xa7, 0x3c, 0x7d, 0x34, 0x43, - 0x33, 0xb8, 0xe3, 0x82, 0xa7, 0x58, 0xa1, 0x4b, 0x2f, 0xe7, 0xfd, 0x74, - 0x5f, 0x38, 0xf1, 0x6a, 0x0e, 0x8e, 0xcf, 0x98, 0x4a, 0x27, 0xf3, 0xc6, - 0xf7, 0xbf, 0x68, 0x3a, 0x19, 0x3a, 0xca, 0x19, 0x39, 0x23, 0xa4, 0x84, - 0x21, 0x5d, 0x84, 0x53, 0xdf, 0xdf, 0xd8, 0xe9, 0xfd, 0xed, 0x87, 0x7d, - 0xfc, 0x4e, 0x9f, 0xfe, 0x7f, 0xf9, 0xd7, 0x8a, 0xd8, 0x26, 0x62, 0x1a, - 0x20, 0xc9, 0xff, 0xc1, 0x8e, 0xac, 0x53, 0x5f, 0xef, 0xc6, 0xce, 0x86, - 0x45, 0x47, 0xab, 0x91, 0xa4, 0x7f, 0xee, 0x1b, 0x93, 0x6b, 0xd3, 0xa7, - 0x83, 0xfc, 0x75, 0xce, 0x8f, 0x9b, 0xda, 0x8b, 0xcf, 0xee, 0xab, 0xaf, - 0x55, 0x83, 0x1d, 0x0f, 0x4f, 0x73, 0xf1, 0x90, 0x55, 0x97, 0x64, 0x33, - 0xff, 0xcc, 0x34, 0x74, 0x73, 0xe3, 0x7c, 0xd8, 0xf9, 0x3a, 0x73, 0x03, - 0x87, 0x43, 0x2f, 0x6d, 0xf2, 0x77, 0x71, 0xc1, 0x21, 0xaf, 0xe3, 0xfe, - 0xc9, 0x47, 0x3e, 0xa2, 0x75, 0x29, 0xcf, 0xb1, 0x59, 0x75, 0x3a, 0x7f, - 0xf9, 0x1a, 0xb5, 0x65, 0x5e, 0xff, 0x5d, 0x61, 0xd3, 0xf8, 0x45, 0x9e, - 0xa6, 0xf9, 0xd3, 0xfb, 0x7f, 0x75, 0xfd, 0xbd, 0x8a, 0x92, 0x8e, 0x9f, - 0xac, 0x7c, 0x83, 0x2f, 0xe7, 0x8b, 0xe0, 0xd6, 0x2d, 0x30, 0x8f, 0xa6, - 0xd5, 0xd6, 0x78, 0x3d, 0xa5, 0xe7, 0x4f, 0xe1, 0x78, 0xda, 0x99, 0x0e, - 0x9c, 0xae, 0x6c, 0xe8, 0x63, 0xee, 0xb2, 0x3c, 0x2f, 0x9d, 0xbf, 0xd0, - 0x74, 0xff, 0xbd, 0xdd, 0x7c, 0x07, 0x6a, 0xfd, 0x4e, 0x9f, 0xf9, 0x87, - 0x34, 0xdd, 0xac, 0x2b, 0x52, 0xa3, 0x94, 0x42, 0xa9, 0x0e, 0x7d, 0xaf, - 0xfe, 0x9a, 0x9d, 0x05, 0x4f, 0xd5, 0xf0, 0xc0, 0xca, 0x2a, 0x0a, 0x82, - 0xa0, 0xa8, 0x2a, 0x1e, 0x7b, 0xff, 0x0a, 0xec, 0xb7, 0xd0, 0xae, 0xa0, - 0xa7, 0x60, 0xa9, 0xb5, 0x65, 0x4f, 0xd9, 0x9b, 0x71, 0x94, 0x57, 0x42, - 0xd6, 0x4e, 0xe1, 0x50, 0x54, 0x15, 0x0f, 0x2d, 0x3e, 0x15, 0x05, 0x41, - 0x50, 0x54, 0x15, 0x05, 0x41, 0x51, 0x41, 0xbc, 0xe4, 0x2b, 0xe1, 0x5d, - 0x85, 0x54, 0x29, 0xd0, 0x54, 0x15, 0x05, 0x43, 0xcb, 0x4a, 0x85, 0x41, - 0x50, 0x54, 0x15, 0x05, 0x43, 0xcd, 0x47, 0x61, 0x5b, 0x0a, 0x76, 0x0a, - 0x82, 0xa0, 0xa8, 0x2a, 0x0a, 0x8a, 0x0d, 0x47, 0x90, 0xa0, 0x0a, 0xd0, - 0x54, 0xbc, 0x95, 0x05, 0x41, 0x50, 0x54, 0x15, 0x1c, 0x9a, 0x8a, 0x42, - 0xbb, 0x0a, 0xf4, 0x2a, 0x0a, 0x82, 0xa0, 0xa9, 0xf6, 0x9b, 0xba, 0xd9, - 0x50, 0x54, 0x3c, 0xf3, 0xd0, 0x2b, 0x41, 0x58, 0x15, 0xd9, 0x3c, 0x90, - 0xa8, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0x79, 0xa8, 0xa4, 0x2b, 0xe1, 0x4e, - 0x82, 0xa0, 0xa8, 0x2a, 0x0a, 0x82, 0xa1, 0xe6, 0xa3, 0x90, 0xad, 0x05, - 0x08, 0x54, 0xb4, 0x54, 0x15, 0x05, 0x49, 0xe5, 0x41, 0x54, 0x96, 0x10, - 0x54, 0x15, 0x05, 0x41, 0x51, 0x41, 0xf3, 0x3c, 0x2b, 0xc8, 0xd2, 0x0d, - 0x38, 0x15, 0xd8, 0x56, 0xc2, 0xa5, 0x65, 0x41, 0x50, 0x54, 0x9e, 0x54, - 0x15, 0x49, 0x61, 0x05, 0x41, 0x50, 0xc7, 0xa4, 0xf0, 0xaf, 0x8d, 0x00, - 0xd2, 0x82, 0xa0, 0xa8, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0x63, 0x65, 0x48, - 0x50, 0x05, 0x28, 0x28, 0x42, 0xa0, 0xa8, 0x2a, 0x0a, 0x80, 0x2f, 0xaa, - 0x15, 0xb0, 0xa8, 0x2a, 0x0a, 0x82, 0xa1, 0x45, 0xf0, 0x85, 0x6c, 0x2a, - 0x4a, 0x2a, 0x0a, 0x82, 0xa3, 0xb2, 0xd3, 0xd0, 0xa8, 0x2a, 0x0a, 0x82, - 0xa0, 0xa8, 0x63, 0x50, 0xe0, 0x56, 0x82, 0xbd, 0x0a, 0x86, 0x5f, 0xb2, - 0xa1, 0xcd, 0xe7, 0xbc, 0x94, 0xda, 0xe2, 0x37, 0x52, 0x91, 0xf6, 0x7e, - 0xb9, 0xeb, 0x87, 0x41, 0x08, 0xe5, 0x24, 0x68, 0xdf, 0x19, 0xbb, 0x3b, - 0x17, 0x6a, 0xb3, 0xed, 0x87, 0xd7, 0x97, 0x4c, 0x9c, 0x25, 0x75, 0x16, - 0x78, 0x24, 0x76, 0x4a, 0x9f, 0x3c, 0x5a, 0xea, 0x52, 0xd3, 0x58, 0x9d, - 0xf6, 0x51, 0x53, 0xdf, 0x4c, 0x03, 0xa7, 0x7f, 0x9b, 0x3a, 0x73, 0x78, - 0x5d, 0x28, 0x8e, 0x03, 0x8d, 0x0d, 0xec, 0x7e, 0x7f, 0x6b, 0xfc, 0x72, - 0x0d, 0x41, 0xd1, 0x4a, 0x21, 0x5c, 0x50, 0x9b, 0xb6, 0x3a, 0x7e, 0x0c, - 0x1f, 0x0d, 0xd9, 0xd3, 0x60, 0x1d, 0x2f, 0x9c, 0x85, 0xa4, 0x90, 0xe9, - 0x28, 0xe9, 0xba, 0x97, 0xf4, 0x4a, 0x00, 0xb6, 0x90, 0x70, 0x7b, 0xc0, - 0x7c, 0xff, 0x69, 0x95, 0x6e, 0x30, 0xd0, 0x74, 0x5a, 0x24, 0x7b, 0x59, - 0x9f, 0x95, 0xfe, 0xac, 0x1e, 0xce, 0x9f, 0xfe, 0x6e, 0x98, 0x01, 0x9d, - 0xb2, 0xf8, 0xe3, 0x83, 0xa1, 0x91, 0x05, 0xe9, 0x84, 0x50, 0xcf, 0x74, - 0x7c, 0x65, 0xbc, 0xc2, 0x79, 0x0b, 0x3f, 0x0a, 0x27, 0x09, 0x32, 0x95, - 0x4a, 0x31, 0xa5, 0x6e, 0x14, 0xb3, 0xf9, 0x87, 0x78, 0x3e, 0xd9, 0xd3, - 0xf3, 0xc7, 0xef, 0xd5, 0x9d, 0x3e, 0xa3, 0xe0, 0xcf, 0x3a, 0x00, 0xf4, - 0xc4, 0xb2, 0x7f, 0xda, 0x60, 0xec, 0x6f, 0x8c, 0xec, 0xe9, 0xd7, 0x6e, - 0x1d, 0x2b, 0xd1, 0xec, 0xf6, 0x7d, 0x3f, 0x7a, 0x1e, 0xab, 0x04, 0xe9, - 0xe5, 0x35, 0xd0, 0x74, 0xfa, 0xdd, 0x0b, 0x52, 0x74, 0x7c, 0xf2, 0x6a, - 0x43, 0x3c, 0xc3, 0xb4, 0x3a, 0x4d, 0x69, 0xac, 0x0b, 0xcd, 0x4a, 0x36, - 0xed, 0xd4, 0x45, 0x3d, 0xee, 0x03, 0xce, 0x9e, 0x6f, 0x5d, 0xca, 0x95, - 0x3e, 0x7a, 0xf8, 0xe3, 0x83, 0xa0, 0x4f, 0x4b, 0xd2, 0x78, 0xe5, 0x12, - 0xb6, 0xe7, 0x0a, 0x55, 0xc9, 0xdc, 0x7b, 0x7e, 0xc3, 0x9a, 0x7e, 0x0f, - 0x7b, 0xb1, 0x43, 0xa7, 0xfa, 0x81, 0xb7, 0xea, 0xfb, 0xa9, 0xd3, 0xdc, - 0xf2, 0xce, 0x8e, 0x9f, 0xfe, 0xd3, 0x29, 0x1b, 0x76, 0x09, 0x98, 0x86, - 0x8b, 0xe2, 0x76, 0x05, 0x06, 0x8b, 0xfe, 0x18, 0xff, 0x91, 0x5a, 0x7f, - 0x71, 0x9b, 0xab, 0x5d, 0x07, 0x4f, 0xfc, 0xeb, 0x7e, 0x58, 0x5f, 0x7a, - 0xfa, 0x8e, 0x9f, 0xaf, 0x8f, 0x1a, 0xcd, 0x9d, 0x3f, 0xfe, 0xdf, 0x87, - 0xb3, 0xaf, 0x8f, 0x61, 0xf6, 0x55, 0x95, 0x3d, 0xaf, 0x14, 0xec, 0xe8, - 0xa1, 0x15, 0x96, 0x5e, 0x8b, 0x13, 0x6e, 0xce, 0x9f, 0x07, 0xe8, 0xc5, - 0x1a, 0x61, 0x39, 0xed, 0xfa, 0xd8, 0x69, 0x84, 0xe6, 0xed, 0x8d, 0x40, - 0x9c, 0xfe, 0x1c, 0xf3, 0xb6, 0x0e, 0xcd, 0x40, 0x9c, 0xfe, 0xad, 0xeb, - 0xf5, 0xf6, 0x83, 0x4c, 0x27, 0x35, 0xf2, 0x69, 0x84, 0xe6, 0xe3, 0x83, - 0xcc, 0x27, 0x16, 0x9a, 0x7d, 0x26, 0x9f, 0x2e, 0x51, 0x1d, 0x50, 0x1d, - 0x21, 0x70, 0x47, 0x2d, 0x96, 0x61, 0x32, 0xcf, 0xa2, 0x5f, 0xa5, 0x3f, - 0xbe, 0x23, 0xcc, 0x8c, 0x56, 0x9f, 0x58, 0x79, 0xee, 0x51, 0x54, 0xff, - 0xf0, 0xdd, 0x41, 0xbd, 0xd8, 0xfd, 0xd7, 0x85, 0x1d, 0x0c, 0xba, 0x1b, - 0xc9, 0xca, 0x42, 0x8f, 0x44, 0x1b, 0x97, 0x04, 0xe8, 0xf6, 0x7d, 0xcd, - 0x87, 0xfc, 0x9d, 0x3e, 0x1b, 0xf1, 0x6e, 0x1d, 0x3f, 0xda, 0xc5, 0x6b, - 0xed, 0x4b, 0xce, 0x9f, 0xbc, 0x0b, 0xfa, 0xb2, 0x83, 0xa3, 0xe7, 0xd7, - 0xd9, 0xcc, 0x0a, 0x2d, 0xb7, 0x09, 0x39, 0xff, 0x5e, 0x69, 0xcf, 0x8e, - 0xae, 0x93, 0xa1, 0x97, 0xb9, 0x2e, 0x74, 0xe7, 0xec, 0xf9, 0x0d, 0xf1, - 0x27, 0x9f, 0xfc, 0xad, 0xd7, 0xe3, 0x4b, 0xf7, 0xfa, 0xfc, 0xe9, 0xff, - 0xfc, 0x37, 0x4d, 0xd7, 0x07, 0x5f, 0x6d, 0xeb, 0xdc, 0x51, 0xd3, 0xf0, - 0xfa, 0xaf, 0xe9, 0x8e, 0x9f, 0xff, 0x60, 0xef, 0x33, 0x42, 0xdb, 0xaf, - 0x17, 0xa3, 0xa7, 0x05, 0x6a, 0x78, 0x80, 0xe7, 0xff, 0xbc, 0x03, 0x69, - 0xba, 0x58, 0x26, 0x62, 0x1a, 0x20, 0x35, 0x9a, 0x88, 0xed, 0x1c, 0x9b, - 0x7a, 0x8b, 0x4c, 0xd7, 0xf1, 0x88, 0xcf, 0x0e, 0xfb, 0xf4, 0xe9, 0xff, - 0xf9, 0xf7, 0x5f, 0x80, 0x7d, 0x5e, 0x37, 0xab, 0xe3, 0x67, 0x45, 0xa2, - 0x03, 0x08, 0xe7, 0xff, 0xfb, 0x1f, 0x62, 0xe3, 0xee, 0x97, 0xf8, 0x6e, - 0xd7, 0xc7, 0x1c, 0x15, 0x1a, 0x44, 0x70, 0x90, 0xcf, 0xe6, 0xb0, 0x4c, - 0xc4, 0x34, 0x41, 0x33, 0xfc, 0xdb, 0xb0, 0x4c, 0xc4, 0x34, 0x5f, 0x33, - 0xef, 0xba, 0x1b, 0xaf, 0x27, 0xf4, 0x87, 0x53, 0xfb, 0xdd, 0x75, 0x6b, - 0xe9, 0xa3, 0xa7, 0xfd, 0x46, 0x53, 0xd5, 0x7b, 0x1c, 0x74, 0x74, 0xee, - 0x38, 0xe0, 0xa9, 0xfb, 0x7a, 0xb4, 0xc0, 0x29, 0x65, 0xfc, 0x50, 0x89, - 0xb1, 0x62, 0x9f, 0xfa, 0x85, 0x35, 0x35, 0x1b, 0xa3, 0xc3, 0xce, 0x9f, - 0xfe, 0xf1, 0x48, 0xf4, 0x4d, 0x7f, 0xbe, 0xd8, 0x1e, 0x74, 0xff, 0xbd, - 0xab, 0x58, 0xed, 0xdf, 0xe1, 0x0e, 0x9d, 0xc7, 0x1c, 0x15, 0x3f, 0xbc, - 0x76, 0xc3, 0x74, 0xec, 0xa5, 0x97, 0xf3, 0xff, 0xf3, 0xb9, 0xd1, 0x35, - 0xfe, 0x79, 0xbe, 0x3a, 0x6e, 0xb7, 0x41, 0xd2, 0xcd, 0x22, 0xb3, 0xd4, - 0x48, 0x7a, 0xb0, 0x9e, 0x50, 0x3f, 0x0d, 0x20, 0x23, 0x52, 0x40, 0xaa, - 0xee, 0x30, 0xe9, 0xf6, 0xaf, 0x6e, 0x3c, 0xe9, 0xff, 0x5e, 0xd8, 0x2b, - 0xa6, 0x1d, 0x9e, 0x20, 0x89, 0xfc, 0xd6, 0x09, 0x98, 0x86, 0x88, 0x21, - 0x67, 0x91, 0x3f, 0x66, 0x80, 0x3f, 0xc1, 0xd3, 0xf7, 0x5f, 0x9e, 0x30, - 0x5e, 0x74, 0x09, 0xef, 0x7a, 0x59, 0x1a, 0x4c, 0xef, 0xb7, 0x01, 0x85, - 0x4c, 0xff, 0x30, 0xef, 0xc5, 0xeb, 0x29, 0x3a, 0x7f, 0xfb, 0x38, 0xdd, - 0xe9, 0xbf, 0xb1, 0xbd, 0x7c, 0xe8, 0x7a, 0x21, 0xc4, 0xe6, 0x7f, 0xb4, - 0xc1, 0xb1, 0x6b, 0xa4, 0xe9, 0xff, 0xfe, 0xfd, 0x0c, 0xfa, 0x80, 0x7e, - 0x97, 0x1f, 0x80, 0xab, 0xa4, 0xe9, 0xed, 0xea, 0xc7, 0x94, 0x4f, 0x68, - 0xda, 0x7e, 0xf0, 0xaa, 0xf1, 0x94, 0x9d, 0x0c, 0x7d, 0x7b, 0x3a, 0x9e, - 0xfb, 0x9f, 0xe0, 0xe9, 0xff, 0xf7, 0xb4, 0x0b, 0x5e, 0x96, 0xdb, 0xbd, - 0x7a, 0x07, 0x4f, 0xaf, 0x75, 0xf1, 0x5e, 0x4f, 0xe7, 0xc1, 0x24, 0xfc, - 0x9a, 0xff, 0x57, 0xfc, 0x9d, 0x3f, 0x29, 0xba, 0xfa, 0xba, 0x0e, 0x9f, - 0xff, 0xfe, 0xfe, 0xf1, 0x58, 0x3d, 0xbf, 0xf5, 0xf5, 0x5a, 0xfb, 0x6f, - 0x5e, 0xe2, 0x8e, 0x8e, 0x51, 0xc7, 0xf3, 0x2c, 0x31, 0x9c, 0x1e, 0x2a, - 0x74, 0xff, 0xb0, 0x52, 0xc1, 0x33, 0x10, 0xd1, 0x08, 0xc3, 0x1f, 0x0f, - 0xa3, 0xb3, 0xff, 0x9a, 0xe9, 0xf1, 0xbf, 0x8f, 0xaf, 0xba, 0x9d, 0x3f, - 0xfd, 0x99, 0x47, 0x8b, 0xd6, 0x29, 0x7c, 0x71, 0xc1, 0xd1, 0xca, 0x28, - 0x1c, 0x4c, 0x9f, 0xee, 0x5a, 0xb5, 0x6a, 0x2f, 0x83, 0xa2, 0xcf, 0x7f, - 0x09, 0x67, 0x71, 0xc7, 0x05, 0x4f, 0xf5, 0xf7, 0x81, 0x6e, 0xaf, 0x92, - 0x96, 0x5f, 0xcd, 0xc7, 0x05, 0x4e, 0xe3, 0x8e, 0x0a, 0x9f, 0xb2, 0x8e, - 0x74, 0xd5, 0x29, 0x65, 0xfc, 0x0a, 0x2f, 0x38, 0x48, 0xea, 0x37, 0x9f, - 0x27, 0xf9, 0xf0, 0xa2, 0x96, 0x6c, 0xe7, 0x71, 0xc7, 0x05, 0x4e, 0xab, - 0x01, 0x4b, 0x2f, 0xe5, 0xdf, 0xd1, 0x05, 0xb5, 0x99, 0xfb, 0x91, 0x67, - 0xe2, 0x1d, 0x3f, 0xbc, 0x07, 0x3f, 0x74, 0xdc, 0x9d, 0x3f, 0xf6, 0xb1, - 0xe3, 0x9e, 0x5c, 0x1f, 0xb8, 0x74, 0xfd, 0xab, 0x75, 0x7b, 0xa9, 0xd0, - 0x87, 0xe9, 0xb4, 0x68, 0x04, 0x7c, 0x68, 0xac, 0x61, 0x59, 0x0c, 0x9a, - 0xad, 0xc6, 0x45, 0x3a, 0x9e, 0xb5, 0xdd, 0xd9, 0xd3, 0xff, 0xaf, 0xaf, - 0x83, 0xdd, 0xa3, 0x69, 0x94, 0x74, 0xfc, 0x9f, 0xae, 0xbe, 0xe1, 0x53, - 0xf8, 0x6e, 0x97, 0xd7, 0xfe, 0x4e, 0x9e, 0xcc, 0x0f, 0x27, 0x47, 0x43, - 0xd6, 0xa0, 0xd6, 0x79, 0xb1, 0x4e, 0x8a, 0x9d, 0xc7, 0x1c, 0x15, 0x3f, - 0xfd, 0xe1, 0xbb, 0xbb, 0x1d, 0xeb, 0xec, 0x34, 0x14, 0xb2, 0xfe, 0x56, - 0x88, 0xa0, 0x52, 0x0c, 0x32, 0x7c, 0xcf, 0x2c, 0xa5, 0x2b, 0xf0, 0x84, - 0xd4, 0x31, 0x67, 0xff, 0xca, 0xb4, 0x61, 0xcd, 0xd7, 0x9f, 0x70, 0x1e, - 0x74, 0xf9, 0xb7, 0x57, 0x56, 0x74, 0x31, 0xfd, 0xed, 0x4e, 0x7f, 0xfb, - 0xee, 0xac, 0x79, 0x1c, 0xe2, 0xc7, 0x3c, 0x9d, 0x3f, 0xff, 0xdc, 0xeb, - 0xfc, 0x5b, 0xb7, 0xd5, 0x9b, 0xaf, 0xaf, 0xba, 0x76, 0x74, 0x5a, 0x2f, - 0xf1, 0x46, 0x19, 0xb4, 0xa6, 0xa1, 0x31, 0xf1, 0xca, 0x73, 0x19, 0xbd, - 0xcb, 0xa5, 0xfc, 0x75, 0x6e, 0x42, 0xf4, 0x23, 0x2b, 0x54, 0x26, 0xb5, - 0x19, 0x3f, 0x70, 0x91, 0x18, 0xc8, 0x6b, 0x2c, 0x17, 0x72, 0x83, 0xbd, - 0x86, 0x87, 0x10, 0xe0, 0x9c, 0xe9, 0x84, 0xe9, 0xff, 0xeb, 0x15, 0xef, - 0xcf, 0xe9, 0xae, 0xaf, 0xbc, 0x3a, 0x54, 0xbc, 0xfb, 0xb9, 0x1c, 0x9f, - 0xb4, 0xe7, 0xf5, 0xf5, 0x1d, 0x3f, 0xe1, 0x6d, 0xeb, 0x3b, 0xca, 0x6a, - 0x74, 0xe7, 0x3d, 0x03, 0xa7, 0xfd, 0x9f, 0x0b, 0xa5, 0x7c, 0x71, 0xc1, - 0xd1, 0x87, 0xbd, 0x51, 0xd9, 0xff, 0xe1, 0x67, 0xf4, 0xf1, 0xbf, 0x8f, - 0xaf, 0xba, 0x9d, 0x16, 0x99, 0xfa, 0x17, 0xea, 0x13, 0x9d, 0x90, 0xcf, - 0xe6, 0x17, 0x8d, 0xdf, 0x67, 0x4f, 0xe7, 0xd8, 0x54, 0x5a, 0x83, 0xa7, - 0xff, 0x99, 0xd3, 0x02, 0xfc, 0x6c, 0x6e, 0x8f, 0x81, 0xec, 0xf7, 0x9f, - 0xfe, 0xbd, 0xb0, 0xa5, 0xef, 0x5f, 0x0e, 0xd0, 0xe9, 0xf6, 0x56, 0xc7, - 0x67, 0x4e, 0xde, 0x75, 0xce, 0x9f, 0xdb, 0xd7, 0xd7, 0xde, 0x7c, 0xe8, - 0xa1, 0x32, 0x2e, 0x57, 0x85, 0x33, 0x64, 0xbe, 0x8f, 0xcf, 0xef, 0x7b, - 0x6d, 0x7f, 0x1e, 0x74, 0xff, 0x25, 0xed, 0x9d, 0x7c, 0x7b, 0x3a, 0x7f, - 0xfe, 0xf5, 0xb7, 0x5b, 0x1e, 0x80, 0xdf, 0xe4, 0x71, 0xe7, 0x47, 0xd1, - 0x28, 0x27, 0x33, 0xff, 0xf0, 0xdd, 0x7d, 0xe9, 0x7a, 0xc1, 0xb7, 0x1e, - 0xd4, 0x9d, 0x3f, 0xeb, 0xaf, 0xb6, 0x09, 0x98, 0x86, 0x88, 0x1a, 0x7b, - 0x7a, 0xc7, 0xf4, 0x45, 0x18, 0xae, 0x43, 0x26, 0x01, 0x70, 0xc5, 0x9f, - 0xf6, 0x05, 0x8f, 0x75, 0xdd, 0x69, 0x3a, 0x7f, 0xff, 0xfe, 0xbd, 0xeb, - 0x07, 0xcf, 0x4a, 0x86, 0x66, 0xdd, 0x5f, 0x3d, 0x2d, 0x58, 0x34, 0xbc, - 0xf1, 0x05, 0xcf, 0xfb, 0x33, 0xca, 0x67, 0x3d, 0x3c, 0xf0, 0x78, 0x82, - 0xe7, 0xfe, 0xd7, 0xf5, 0xf6, 0x1d, 0xf4, 0xf3, 0xc1, 0xe2, 0x0b, 0x9f, - 0xcd, 0xf1, 0xdf, 0x4f, 0x3c, 0x1e, 0x20, 0xb9, 0xf9, 0x57, 0xcf, 0x4f, - 0x3c, 0x1e, 0x20, 0xb9, 0xff, 0xfe, 0xc1, 0x1f, 0xab, 0xa5, 0x53, 0x5f, - 0x0f, 0xf9, 0xa2, 0xf8, 0x3c, 0x41, 0x73, 0x53, 0xd3, 0x94, 0xe8, 0x91, - 0x44, 0x15, 0xb1, 0x10, 0x50, 0x21, 0x95, 0x69, 0x68, 0xf8, 0x65, 0x1e, - 0xcf, 0xef, 0xb7, 0x9a, 0xee, 0xb4, 0x9d, 0x3d, 0x81, 0xde, 0x1d, 0x3f, - 0xf6, 0xbf, 0xaf, 0xb0, 0xef, 0xa7, 0x9e, 0x0f, 0x10, 0x5c, 0xff, 0x39, - 0x54, 0xfd, 0x1d, 0x3c, 0xf0, 0x78, 0x82, 0xe7, 0xdb, 0xab, 0x2b, 0xa2, - 0x22, 0x8f, 0xc2, 0xb4, 0xff, 0xee, 0x89, 0xaf, 0xa3, 0x6e, 0xbd, 0x3c, - 0xf0, 0x78, 0x82, 0xe7, 0xff, 0xfe, 0x11, 0xfa, 0xba, 0x7b, 0x7d, 0x2a, - 0x9a, 0xf8, 0x7f, 0xcd, 0x17, 0xc1, 0xe2, 0x0b, 0x8b, 0x4c, 0x9a, 0x94, - 0x3c, 0x5d, 0x9f, 0xed, 0x7c, 0x3f, 0xe6, 0x8b, 0xe0, 0xf1, 0x05, 0xcf, - 0xff, 0x66, 0x52, 0xfa, 0xeb, 0xfc, 0xf2, 0xc0, 0xc5, 0x4f, 0xfa, 0xde, - 0xff, 0x6a, 0x03, 0x47, 0x51, 0xe2, 0x0b, 0x84, 0x47, 0x40, 0x24, 0xd5, - 0x42, 0x7f, 0xc9, 0xf0, 0xde, 0x77, 0x5e, 0x9c, 0x1e, 0x20, 0xb9, 0xfb, - 0x5f, 0xd6, 0xbf, 0xd9, 0xa0, 0x0b, 0x9f, 0x5f, 0x7d, 0x3c, 0xf0, 0x78, - 0x82, 0xe6, 0xbd, 0xa1, 0xfb, 0x68, 0xf2, 0x29, 0x47, 0x85, 0x61, 0x89, - 0x3f, 0x2a, 0xf9, 0xe9, 0xe7, 0x83, 0xc4, 0x17, 0x3f, 0xe4, 0xd7, 0xc3, - 0xfe, 0x68, 0xbe, 0x0f, 0x10, 0x5c, 0xd7, 0xd3, 0x11, 0x1d, 0x54, 0x09, - 0xfd, 0xef, 0xd5, 0x83, 0x4b, 0xcf, 0x10, 0x5c, 0xff, 0xaf, 0xee, 0xac, - 0x6f, 0x9c, 0x79, 0xe2, 0x0b, 0x51, 0xe0, 0xc7, 0x2b, 0xc1, 0xe0, 0x6f, - 0xd9, 0xb0, 0xc7, 0xd3, 0x58, 0xc6, 0x37, 0x18, 0xf7, 0xb0, 0xb7, 0xe1, - 0xc2, 0x7d, 0xdd, 0x7b, 0xed, 0x8d, 0x10, 0x5a, 0xd1, 0x1b, 0x3f, 0xeb, - 0x7e, 0xb1, 0xee, 0xce, 0xde, 0xd0, 0x74, 0xe5, 0x33, 0xce, 0x9f, 0x5f, - 0x3a, 0xf7, 0x83, 0xa4, 0x18, 0x78, 0xa2, 0x37, 0x3b, 0xfd, 0x56, 0x74, - 0xec, 0x0e, 0xce, 0x95, 0x2c, 0x6e, 0x76, 0x3d, 0x3f, 0x5d, 0x19, 0xa6, - 0xeb, 0x9d, 0x1f, 0x45, 0xae, 0x2f, 0x09, 0x3c, 0xec, 0x0a, 0x0e, 0x9b, - 0xb6, 0x3a, 0x7b, 0xec, 0xab, 0x3a, 0x0e, 0x9f, 0xb3, 0xce, 0xd8, 0x3b, - 0x3a, 0x39, 0x37, 0x02, 0x15, 0x3f, 0xff, 0x9b, 0xfc, 0x8b, 0x7a, 0x9b, - 0xb4, 0xe5, 0x93, 0xc2, 0x8e, 0x9b, 0xb6, 0x3a, 0x66, 0xf2, 0x74, 0xff, - 0x5e, 0xea, 0xca, 0xf1, 0x6e, 0x1d, 0x3f, 0xab, 0x7a, 0xfd, 0x7d, 0xa0, - 0xe9, 0xb8, 0xe0, 0xa9, 0xfe, 0x1b, 0x75, 0x8f, 0xaf, 0xf9, 0x3a, 0x11, - 0x3f, 0x9f, 0x8d, 0x80, 0xb2, 0x96, 0x34, 0x43, 0xdb, 0x0b, 0xb8, 0x2c, - 0x22, 0xf5, 0x3a, 0xe0, 0xd7, 0xc0, 0xc4, 0xee, 0x38, 0xe0, 0xa9, 0x28, - 0xa5, 0x97, 0xf3, 0xec, 0x73, 0x30, 0x0a, 0x5a, 0x37, 0x7c, 0x42, 0xfa, - 0x7f, 0x53, 0xb6, 0xbd, 0x5d, 0x07, 0x43, 0x36, 0x7c, 0x77, 0x1b, 0x4f, - 0x94, 0x2a, 0x4c, 0x3f, 0x1a, 0x98, 0x26, 0xea, 0x3c, 0x8c, 0xa4, 0xca, - 0x8a, 0x4d, 0x63, 0x40, 0xf6, 0x58, 0x23, 0xa4, 0xb9, 0xeb, 0x46, 0xd9, - 0xd3, 0xd6, 0xab, 0xd9, 0xd3, 0xff, 0x6b, 0xda, 0x3d, 0x5e, 0xbe, 0x98, - 0x07, 0x4f, 0x65, 0x1e, 0x1e, 0x74, 0x32, 0x2a, 0x69, 0x1f, 0xd9, 0x03, - 0xb2, 0x34, 0xfc, 0x3e, 0xf2, 0xac, 0x79, 0xd3, 0xff, 0xd4, 0xbc, 0x5b, - 0xa2, 0x85, 0xbc, 0xef, 0xf4, 0x1d, 0x3f, 0xab, 0xb7, 0x56, 0x37, 0xc9, - 0xd0, 0xc8, 0xb6, 0xf9, 0x76, 0x2a, 0x4e, 0xce, 0x9e, 0x0e, 0x9f, 0xfe, - 0x17, 0xf4, 0xbe, 0x7f, 0x5a, 0x77, 0xee, 0x54, 0xe8, 0xe8, 0x7e, 0x76, - 0x3f, 0x3f, 0x50, 0xe3, 0xfa, 0xc0, 0xa0, 0xe9, 0x9f, 0x41, 0xd3, 0xed, - 0x5f, 0xdf, 0x53, 0xa7, 0xff, 0xb4, 0xde, 0x17, 0xb1, 0xce, 0xeb, 0x56, - 0xec, 0xa9, 0xfd, 0xdd, 0x82, 0x66, 0x21, 0xe2, 0x04, 0x9d, 0xbf, 0xd0, - 0x74, 0x3d, 0x1a, 0x5c, 0x93, 0x82, 0x92, 0x8f, 0x26, 0x76, 0x79, 0xd3, - 0xdb, 0xa3, 0x04, 0xe9, 0xea, 0x6b, 0x9b, 0x3a, 0x28, 0x3d, 0xcb, 0x19, - 0xd1, 0x0c, 0xfe, 0x1c, 0xe2, 0xb5, 0x6e, 0xce, 0x9d, 0xc7, 0x1c, 0x1e, - 0xef, 0xa9, 0xd8, 0x3c, 0x96, 0xef, 0xa2, 0xcd, 0x64, 0x72, 0x89, 0x8e, - 0xd7, 0xe7, 0xff, 0xd6, 0x3f, 0xf2, 0xba, 0xef, 0x5e, 0xe3, 0xde, 0xc7, - 0x45, 0x07, 0xf9, 0xe4, 0x96, 0x7d, 0x82, 0x3f, 0x51, 0xd1, 0xd6, 0xd5, - 0xa2, 0x3c, 0xd6, 0xe1, 0xd3, 0xf8, 0x4c, 0xe4, 0x68, 0x62, 0x4b, 0x3e, - 0xfe, 0xdb, 0x75, 0x2a, 0x79, 0x1b, 0x75, 0x2a, 0x6e, 0x38, 0x2a, 0x1e, - 0x7b, 0xf6, 0x4f, 0xc1, 0x04, 0xd7, 0xc1, 0x4b, 0x35, 0xf3, 0xff, 0xeb, - 0xdb, 0x25, 0xd8, 0xef, 0x5f, 0x61, 0xa0, 0xe8, 0xec, 0xfd, 0xf8, 0x26, - 0x9f, 0xff, 0xcc, 0xeb, 0xe3, 0xdf, 0x4d, 0xd6, 0xd3, 0x58, 0x3b, 0xa9, - 0xd3, 0xf9, 0xca, 0x5f, 0xaf, 0x58, 0x0e, 0x9c, 0xfc, 0x03, 0xa7, 0xcf, - 0xbd, 0xdf, 0x25, 0x4b, 0xee, 0x1e, 0x0e, 0xc6, 0xa7, 0xb7, 0xe6, 0xf4, - 0x74, 0xdd, 0xb1, 0xd3, 0x76, 0xc7, 0x4f, 0xbd, 0x7d, 0x8a, 0xfe, 0x6b, - 0x3b, 0x16, 0x86, 0x44, 0x70, 0xa7, 0xcf, 0xfd, 0xbd, 0x5a, 0xbc, 0x37, - 0x77, 0x4e, 0xce, 0x9f, 0xd4, 0xa7, 0xc3, 0xc3, 0x72, 0x74, 0xf7, 0x6a, - 0xc7, 0xd4, 0xff, 0x36, 0x8f, 0x3b, 0xaa, 0xe9, 0x3a, 0x7b, 0xb0, 0xf8, - 0x1d, 0x0c, 0x7f, 0x58, 0x75, 0xc0, 0xfc, 0xf5, 0x7d, 0xa7, 0x67, 0x4e, - 0xe3, 0x8e, 0x0a, 0x9f, 0x5f, 0x91, 0xf6, 0xa5, 0x2c, 0xbf, 0x9f, 0x5a, - 0xf8, 0xe3, 0x83, 0xa1, 0x8f, 0x8b, 0x67, 0x13, 0xdc, 0x60, 0xbc, 0xe9, - 0xfe, 0xdb, 0x53, 0xde, 0x6b, 0x5f, 0x3a, 0x5a, 0x3a, 0x2c, 0xf2, 0x90, - 0xea, 0x77, 0x1c, 0x70, 0x54, 0xfd, 0xfc, 0xf3, 0xaf, 0xec, 0xa5, 0x97, - 0xf3, 0xeb, 0xee, 0xed, 0xc3, 0xa5, 0x5e, 0x88, 0xa4, 0x03, 0xf1, 0x3e, - 0x9e, 0xf8, 0xfa, 0xfe, 0x53, 0x45, 0xb8, 0xc3, 0xe1, 0x97, 0x51, 0x9e, - 0x49, 0x6c, 0x7e, 0x5d, 0x82, 0x16, 0xfa, 0x8c, 0x5f, 0x0b, 0xab, 0x0a, - 0x5d, 0xc6, 0xcd, 0x3f, 0x32, 0x80, 0x33, 0x67, 0x4f, 0xff, 0x7d, 0x54, - 0xbe, 0xbd, 0x2c, 0x46, 0xff, 0xd9, 0xd1, 0xa3, 0xfc, 0xd9, 0x54, 0x96, - 0xef, 0x42, 0x64, 0x57, 0xad, 0x45, 0x3d, 0x68, 0x52, 0xd3, 0x89, 0xb4, - 0x47, 0x78, 0xf9, 0x55, 0x3c, 0xcb, 0x25, 0xba, 0xe2, 0x9b, 0xcc, 0x71, - 0xa9, 0x2a, 0x66, 0x99, 0x5f, 0x1f, 0x8f, 0x21, 0xc9, 0xef, 0xb0, 0x9d, - 0xbf, 0x54, 0xaf, 0x5d, 0x52, 0x09, 0x72, 0x9f, 0xf9, 0xdc, 0xb8, 0xa1, - 0x9f, 0x23, 0xad, 0x69, 0xf9, 0xba, 0xd6, 0x0f, 0xd8, 0xdf, 0x1d, 0x43, - 0xdb, 0x88, 0x50, 0xf5, 0x4b, 0x67, 0xf1, 0x3d, 0x6e, 0xed, 0x18, 0x8c, - 0x2e, 0x13, 0x7d, 0xef, 0xc4, 0xcd, 0x3c, 0xfe, 0x5d, 0x82, 0x66, 0x21, - 0xa2, 0xe3, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, 0x34, 0x5d, 0x73, 0xff, 0x2f, - 0x1e, 0xbb, 0x04, 0xcc, 0x43, 0x44, 0xa3, 0x0d, 0x09, 0xf4, 0x47, 0x94, - 0x72, 0x77, 0xe4, 0xed, 0x0e, 0xff, 0x0f, 0x1e, 0xb9, 0xfe, 0x62, 0x71, - 0x06, 0xa7, 0x1b, 0x3b, 0x76, 0x3b, 0x9f, 0xfc, 0xb5, 0x63, 0xd7, 0x60, - 0x99, 0x88, 0x68, 0x96, 0xa7, 0xc0, 0x99, 0x88, 0x68, 0x8d, 0xe7, 0xfd, - 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x5f, 0x92, 0xec, 0xfd, 0x94, 0x61, - 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0xaa, 0xe7, 0xfb, 0xcd, 0x8d, 0xd3, - 0xbc, 0x51, 0xd3, 0x73, 0xf3, 0xa7, 0xeb, 0x04, 0xcc, 0x43, 0x44, 0x81, - 0x1d, 0x0f, 0x31, 0x62, 0xf3, 0xea, 0xe0, 0xe5, 0x27, 0x43, 0xcf, 0x2a, - 0x92, 0x49, 0xff, 0xd6, 0xe6, 0xb1, 0x5b, 0xd3, 0x6f, 0xd5, 0x1d, 0x1e, - 0x53, 0x3d, 0xc8, 0x67, 0xf8, 0x23, 0x9f, 0xf8, 0x6e, 0x85, 0xf5, 0x30, - 0x8d, 0xec, 0xe8, 0x59, 0xfe, 0x81, 0xcc, 0xfe, 0x5d, 0x82, 0x66, 0x21, - 0xa2, 0xc8, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, 0x34, 0x5a, 0xf3, 0xf9, 0x76, - 0x09, 0x98, 0x86, 0x8b, 0x92, 0x7c, 0x09, 0x98, 0x86, 0x8b, 0xb2, 0x7f, - 0xd8, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x28, 0xe9, 0x2e, 0xcf, 0xd9, 0x46, - 0x13, 0xe0, 0x4c, 0xc4, 0x34, 0x52, 0xb3, 0xff, 0xff, 0xda, 0x6a, 0x1b, - 0x5f, 0x75, 0x9c, 0xeb, 0xeb, 0x4d, 0x7d, 0xcd, 0x35, 0x16, 0x74, 0xf9, - 0x6a, 0xc7, 0xae, 0xd1, 0x64, 0xe1, 0x84, 0x50, 0xba, 0x8a, 0xf8, 0x64, - 0x52, 0x4f, 0xf8, 0xfd, 0x54, 0x43, 0xd9, 0xdd, 0x4e, 0xf7, 0x0b, 0x17, - 0x50, 0xd9, 0x9f, 0xe7, 0xae, 0xc1, 0x33, 0x10, 0xd1, 0x1c, 0x4f, 0xf7, - 0xd7, 0x60, 0x99, 0x88, 0x68, 0xad, 0x64, 0xbc, 0x44, 0x16, 0xd0, 0x67, - 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x25, 0xb9, 0xae, 0x93, - 0xa7, 0xf7, 0x36, 0xa5, 0x37, 0xea, 0x74, 0x52, 0x79, 0x3f, 0x16, 0x9d, - 0xae, 0x5e, 0x74, 0xe7, 0xa9, 0x0e, 0x9f, 0xff, 0xb5, 0x94, 0xf7, 0xce, - 0xb1, 0xf7, 0x51, 0xf7, 0x3c, 0x1d, 0x06, 0x88, 0x6e, 0x7f, 0xd8, 0xf5, - 0xd8, 0x26, 0x62, 0x1a, 0x26, 0x09, 0xc1, 0xef, 0x65, 0x4f, 0xe1, 0xbd, - 0xed, 0x82, 0xa7, 0x49, 0x6c, 0x9b, 0x25, 0x04, 0x7c, 0x8e, 0xd8, 0xda, - 0x2f, 0xa8, 0x5f, 0x68, 0xde, 0x07, 0x67, 0x2b, 0xd0, 0x2a, 0x7f, 0xd8, - 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x26, 0x39, 0x2f, 0xe7, 0xc4, 0xa1, 0xc9, - 0xf9, 0xab, 0xd3, 0x77, 0xa3, 0xa7, 0x30, 0xd0, 0x74, 0xff, 0xff, 0xf3, - 0xeb, 0xab, 0xf7, 0x8a, 0xea, 0xd2, 0xeb, 0xd2, 0xe9, 0x7d, 0x7e, 0x3f, - 0x3a, 0x79, 0x33, 0x10, 0xd1, 0x58, 0xcf, 0xfb, 0xaa, 0xf6, 0x37, 0xeb, - 0x0e, 0xce, 0x8f, 0x29, 0x9a, 0x21, 0x75, 0x23, 0x61, 0x08, 0x1d, 0x95, - 0xcf, 0xfe, 0x61, 0xdf, 0x9f, 0x58, 0x6d, 0x18, 0x0e, 0x9f, 0xee, 0x75, - 0x75, 0xa5, 0xed, 0xa3, 0xa7, 0xf9, 0xa9, 0x7b, 0x8f, 0xc0, 0xa0, 0xe8, - 0xb3, 0xf4, 0xf9, 0xd4, 0xff, 0xaf, 0x90, 0xff, 0xb4, 0x77, 0x57, 0x9d, - 0x3f, 0xff, 0xf0, 0xfb, 0x45, 0xa7, 0x41, 0xf5, 0xdb, 0xa5, 0xd2, 0xfb, - 0xf4, 0x7b, 0xa9, 0xd3, 0xfb, 0xad, 0xd0, 0xe3, 0xfa, 0xc0, 0xa0, 0xe9, - 0xff, 0xd6, 0xe6, 0xb1, 0x5b, 0xd3, 0x6f, 0xd5, 0x1d, 0x3b, 0x5f, 0x5d, - 0xaa, 0x77, 0x45, 0x1d, 0x42, 0xec, 0x48, 0x76, 0x85, 0xd4, 0xf9, 0xe1, - 0x06, 0x6f, 0x1d, 0x9d, 0x37, 0xae, 0x1d, 0x3e, 0xc1, 0xa3, 0xda, 0x9d, - 0x1d, 0x9e, 0xc8, 0x8c, 0xd4, 0x62, 0x7d, 0xed, 0x34, 0x37, 0x93, 0xa7, - 0xca, 0xb1, 0x67, 0x9d, 0x3c, 0xc1, 0x82, 0x74, 0xf5, 0x6a, 0xdd, 0x9d, - 0x0c, 0x7c, 0xba, 0x25, 0xe0, 0x7a, 0x7c, 0xcf, 0xef, 0xd7, 0x9d, 0x39, - 0x85, 0xe7, 0x43, 0x87, 0x87, 0xb2, 0x99, 0xda, 0xf0, 0xa3, 0xa7, 0xe6, - 0x55, 0x8f, 0xfc, 0x9d, 0x2a, 0x9d, 0x1f, 0x37, 0xb8, 0x5b, 0x37, 0x6c, - 0x54, 0xdc, 0x70, 0x54, 0x7c, 0xd7, 0x70, 0x2d, 0x3f, 0xb1, 0xe3, 0x7b, - 0xd7, 0xca, 0x59, 0xa2, 0x9e, 0xe7, 0x29, 0xa9, 0xd3, 0x98, 0x5c, 0x3a, - 0x61, 0x63, 0xa1, 0xc3, 0x5e, 0x03, 0x73, 0xff, 0x79, 0xf8, 0xa5, 0x59, - 0x59, 0x4e, 0xce, 0x9d, 0xdd, 0xbb, 0x1d, 0x1e, 0x4f, 0x90, 0x11, 0x65, - 0xe4, 0xe9, 0x83, 0xc9, 0xd1, 0xf3, 0x53, 0xe0, 0x4a, 0x19, 0x34, 0x6b, - 0x52, 0xfc, 0x21, 0x74, 0x99, 0x36, 0xb6, 0x74, 0xfd, 0xdb, 0x6a, 0xdd, - 0x61, 0xd3, 0xf7, 0xf7, 0x7a, 0xcf, 0x27, 0x4e, 0xe3, 0x8e, 0x0a, 0x9f, - 0xfa, 0xd3, 0x96, 0xa3, 0xc5, 0xeb, 0x29, 0x29, 0x65, 0xfc, 0xf7, 0xc1, - 0xdb, 0x93, 0xa4, 0x07, 0x4f, 0x95, 0xfd, 0xf7, 0x87, 0x45, 0x07, 0xb9, - 0xd7, 0x25, 0xf4, 0x3e, 0x7f, 0x27, 0xea, 0x36, 0xeb, 0x0e, 0x9a, 0xf6, - 0x74, 0x52, 0x78, 0xfa, 0x32, 0x9e, 0xd8, 0xdb, 0xce, 0x9f, 0xfd, 0xfa, - 0xea, 0xf9, 0x1b, 0x74, 0x37, 0x53, 0xa0, 0x0f, 0xab, 0x64, 0x12, 0x5b, - 0x2f, 0x2a, 0x50, 0x5f, 0xcc, 0x24, 0x6d, 0xcb, 0xe4, 0x60, 0xb6, 0xa7, - 0x0d, 0x47, 0x0f, 0x88, 0x3d, 0x8b, 0x3b, 0x85, 0xc2, 0x9b, 0x58, 0x58, - 0xed, 0xf3, 0xc4, 0x23, 0x67, 0xc0, 0x99, 0x88, 0x68, 0xad, 0xe7, 0xfd, - 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x70, 0x92, 0xec, 0xfd, 0x94, 0x61, - 0x37, 0xba, 0x3a, 0x7c, 0x09, 0x98, 0x86, 0x8b, 0x46, 0x6f, 0xf9, 0x3a, - 0x7f, 0xfd, 0x43, 0x6d, 0xb9, 0x06, 0xd6, 0x54, 0x6f, 0xb3, 0xa7, 0xfc, - 0xd4, 0xe7, 0x5f, 0x43, 0x9d, 0x7a, 0x0e, 0x86, 0x44, 0xd6, 0x95, 0x25, - 0x6e, 0x23, 0x52, 0xb0, 0xb2, 0x92, 0xdd, 0xe4, 0xd2, 0x6c, 0x5f, 0x51, - 0x82, 0x4f, 0x26, 0x62, 0x1a, 0x2d, 0xa9, 0xfb, 0x4c, 0xa6, 0xff, 0x27, - 0x4a, 0xc0, 0xf6, 0x36, 0x57, 0x3f, 0xcb, 0xf3, 0xe7, 0x03, 0x9f, 0x44, - 0xe8, 0x59, 0xf1, 0xf6, 0x4d, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0xb9, - 0x67, 0xf2, 0xec, 0x13, 0x31, 0x0d, 0x17, 0x6c, 0x33, 0x64, 0xd7, 0x41, - 0x43, 0xe3, 0xff, 0xe6, 0x1b, 0x7e, 0x65, 0xe9, 0xfe, 0x7c, 0xb3, 0xaf, - 0x1b, 0x2e, 0xa3, 0x70, 0x18, 0x7e, 0x54, 0x8f, 0x67, 0x73, 0xf9, 0x76, - 0x09, 0x98, 0x86, 0x8a, 0x9e, 0x6f, 0xec, 0xe9, 0xe4, 0xcc, 0x43, 0x45, - 0x73, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0xb3, 0xa0, 0x0f, 0x9b, 0x45, - 0x73, 0xe0, 0x4c, 0xc4, 0x34, 0x48, 0x53, 0xfd, 0xfa, 0x6b, 0xb1, 0x65, - 0x54, 0xe9, 0x9e, 0xbb, 0x3e, 0x9e, 0xcc, 0x27, 0x9d, 0xed, 0x32, 0x8e, - 0x9f, 0xd7, 0xaa, 0xd6, 0xc2, 0x83, 0xa4, 0xbe, 0x53, 0x8c, 0xb7, 0xcc, - 0x84, 0x55, 0x4b, 0xb6, 0x4d, 0x3f, 0xf9, 0x6a, 0xc7, 0xae, 0xc1, 0x33, - 0x10, 0xd1, 0x3e, 0x42, 0x2a, 0x6e, 0xeb, 0xc7, 0x8f, 0xa5, 0x59, 0xf0, - 0x26, 0x62, 0x1a, 0x2b, 0x29, 0xff, 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, - 0x9b, 0xa6, 0xfa, 0xec, 0xfd, 0x94, 0x61, 0x3e, 0x04, 0xcc, 0x43, 0x44, - 0xad, 0x3f, 0xde, 0x75, 0xfe, 0x9e, 0xa5, 0xd4, 0xe9, 0xf2, 0xd5, 0x8f, - 0x5d, 0x9f, 0x6e, 0x18, 0x4f, 0xfb, 0xf5, 0xf5, 0x43, 0xf7, 0x5e, 0xe1, - 0xd3, 0xf8, 0x58, 0x2d, 0xd6, 0x28, 0xe8, 0x79, 0xf9, 0xfd, 0x0a, 0x7c, - 0x09, 0x98, 0x86, 0x89, 0x72, 0x7f, 0xbf, 0x8f, 0xd8, 0xb2, 0xaa, 0x74, - 0xf3, 0xaf, 0x8b, 0x1d, 0x3e, 0x5a, 0xb1, 0xeb, 0x64, 0x55, 0xd9, 0x16, - 0x8c, 0x30, 0xde, 0x7f, 0xe5, 0xe3, 0xd7, 0x60, 0x99, 0x88, 0x68, 0x8e, - 0xe7, 0xfb, 0x7a, 0xb7, 0xaf, 0x06, 0xa7, 0x4f, 0xdd, 0x60, 0xb2, 0x58, - 0x9d, 0x37, 0xba, 0x3a, 0x7e, 0x77, 0xc6, 0xf5, 0x9b, 0x3a, 0x7f, 0x5f, - 0x15, 0x61, 0xdd, 0x4e, 0x9f, 0x02, 0x66, 0x21, 0xa2, 0xa1, 0x9e, 0xd6, - 0xee, 0x83, 0xa7, 0xd7, 0x46, 0x0b, 0xa3, 0xa7, 0xff, 0xff, 0xf3, 0x3f, - 0xa6, 0xf5, 0xf6, 0xaf, 0x4b, 0xf5, 0x19, 0xd7, 0x4b, 0x00, 0xb7, 0x5e, - 0xe6, 0x8e, 0x8b, 0x47, 0x00, 0x91, 0x54, 0xa2, 0x7f, 0xff, 0xbd, 0xce, - 0xbf, 0xe8, 0xd6, 0x7f, 0x6d, 0xaf, 0xee, 0xb7, 0xc9, 0xd2, 0x5b, 0xbe, - 0xa9, 0x49, 0xde, 0x2e, 0xeb, 0x05, 0xe8, 0x30, 0xb3, 0x2d, 0xc6, 0x21, - 0xd4, 0x5d, 0x3e, 0x04, 0xcc, 0x43, 0x45, 0x51, 0x3f, 0xec, 0x7a, 0xec, - 0x13, 0x31, 0x0d, 0x13, 0x5c, 0x97, 0x67, 0xec, 0xa3, 0x09, 0xfc, 0xbb, - 0x04, 0xcc, 0x43, 0x45, 0x59, 0x3f, 0xf2, 0xf1, 0xeb, 0xb0, 0x4c, 0xc4, - 0x34, 0x48, 0x93, 0xe0, 0x4c, 0xc4, 0x34, 0x5a, 0x53, 0xfe, 0xc7, 0xae, - 0xc1, 0x33, 0x10, 0xd1, 0x3e, 0xc9, 0x76, 0x7e, 0xca, 0x30, 0x9f, 0xfc, - 0xb5, 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, 0xa1, 0x27, 0xda, 0xfd, 0x0c, - 0x07, 0x4f, 0x81, 0x33, 0x10, 0xd1, 0x47, 0xcf, 0xf8, 0x59, 0xc6, 0x16, - 0x73, 0x4c, 0x74, 0xff, 0xfd, 0x7c, 0xe9, 0xbc, 0x2f, 0x63, 0x9d, 0xd6, - 0xad, 0xd9, 0x53, 0xe5, 0xab, 0x1e, 0xb6, 0x47, 0x8d, 0x93, 0xec, 0xc3, - 0xa8, 0xf2, 0x19, 0x90, 0xd5, 0x44, 0x6b, 0x6f, 0x57, 0xb4, 0xcf, 0x32, - 0xa2, 0x52, 0x1f, 0x54, 0x93, 0xb8, 0x77, 0xa8, 0x61, 0x76, 0x4f, 0xb8, - 0xd0, 0xe7, 0xf2, 0xec, 0x13, 0x31, 0x0d, 0x11, 0x14, 0xfd, 0x60, 0x99, - 0x88, 0x68, 0x8a, 0xe7, 0xfb, 0xae, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0x71, - 0x0b, 0x3f, 0xac, 0x35, 0x9e, 0xbd, 0x66, 0xce, 0x9f, 0xd7, 0xf0, 0xef, - 0xbf, 0x6a, 0x74, 0x9d, 0xf1, 0x3d, 0x5a, 0x90, 0x4f, 0xff, 0xdb, 0xaf, - 0xf5, 0x9f, 0x7f, 0xc7, 0x7e, 0xe8, 0x2c, 0xe9, 0xf0, 0x26, 0x62, 0x1a, - 0x29, 0xe9, 0xfa, 0xeb, 0xd0, 0x71, 0xe7, 0x47, 0x58, 0x8e, 0x46, 0x2c, - 0xb5, 0xb1, 0x30, 0x9f, 0xfd, 0x8f, 0x5f, 0x23, 0x9c, 0x56, 0xad, 0xd9, - 0xd0, 0xb4, 0x45, 0x72, 0x7f, 0x39, 0x7c, 0xd9, 0xd3, 0xe6, 0x7f, 0x7e, - 0xbc, 0xe9, 0xe4, 0xcc, 0x43, 0x45, 0x67, 0x0e, 0x1e, 0xa0, 0x14, 0xcf, - 0xd4, 0x29, 0x85, 0xf5, 0x3a, 0x73, 0x51, 0xf3, 0xa7, 0xdb, 0xef, 0xc0, - 0xbc, 0xe9, 0xde, 0xe5, 0x4e, 0x9f, 0x5b, 0x94, 0x7b, 0xd9, 0xd2, 0x5d, - 0xa3, 0x70, 0x08, 0xb4, 0x5b, 0x83, 0x82, 0x55, 0xe0, 0x72, 0x7f, 0xe5, - 0xe3, 0xd7, 0x60, 0x99, 0x88, 0x68, 0x91, 0x67, 0xeb, 0x04, 0xcc, 0x43, - 0x45, 0x93, 0x3f, 0xfb, 0x75, 0xf1, 0x55, 0xdd, 0x1f, 0x17, 0xd4, 0xe8, - 0x5a, 0x20, 0xac, 0xd6, 0x7f, 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x6c, 0x4e, - 0xba, 0xd9, 0xd3, 0xc9, 0x98, 0x86, 0x8b, 0x6e, 0x7a, 0xb4, 0x60, 0x1d, - 0x00, 0x79, 0x9b, 0x2b, 0x92, 0xde, 0x88, 0x7b, 0x66, 0x9d, 0x46, 0xbe, - 0x74, 0xff, 0xba, 0xce, 0xb1, 0xdd, 0x6f, 0x56, 0x2d, 0xd9, 0xd3, 0xf3, - 0x0b, 0xf9, 0xf5, 0x47, 0x4f, 0x81, 0x33, 0x10, 0xd1, 0x78, 0x4f, 0x6f, - 0xaa, 0xf4, 0x74, 0xff, 0xcd, 0xe1, 0x54, 0xbf, 0x76, 0x3b, 0xa9, 0xd3, - 0xeb, 0x1e, 0xdd, 0x98, 0xe9, 0xf3, 0x78, 0xf7, 0x2a, 0x74, 0xed, 0xb7, - 0x67, 0x49, 0x7d, 0x62, 0x74, 0x3d, 0x6a, 0x1d, 0xa1, 0x3a, 0xcb, 0xa9, - 0x30, 0xd1, 0x27, 0x68, 0xc2, 0x53, 0xb2, 0x99, 0xdf, 0xba, 0x4e, 0x9f, - 0x02, 0x66, 0x21, 0xa2, 0xf4, 0x9f, 0xf0, 0xe6, 0xde, 0xde, 0x77, 0xfa, - 0x0e, 0x9f, 0x5a, 0xb5, 0x9c, 0x9d, 0x25, 0xf2, 0x8b, 0x3b, 0x1c, 0xf0, - 0x60, 0xec, 0x81, 0x0c, 0xc9, 0x6d, 0xa2, 0x16, 0xb7, 0x1f, 0x22, 0x12, - 0x7e, 0x34, 0xc0, 0x5b, 0x54, 0x33, 0xbb, 0x22, 0x18, 0x61, 0x7b, 0x1e, - 0x4f, 0x11, 0xa3, 0x4d, 0xee, 0x8e, 0x9e, 0xbd, 0x66, 0xce, 0x9f, 0xd7, - 0xf0, 0xef, 0xbf, 0x6a, 0x74, 0x9d, 0xf1, 0x3d, 0x5a, 0x90, 0x4f, 0xbf, - 0xb6, 0xa6, 0x83, 0xa7, 0xc0, 0x99, 0x88, 0x68, 0x88, 0xe7, 0xff, 0xb5, - 0xed, 0x6b, 0x6a, 0x1b, 0x75, 0xd1, 0x9d, 0xd9, 0xd3, 0xfe, 0x7b, 0x50, - 0x17, 0xbd, 0xff, 0x67, 0x4f, 0xf5, 0x85, 0xd6, 0xf0, 0x68, 0x3a, 0x7f, - 0xff, 0x9b, 0x59, 0xfd, 0xb6, 0x86, 0xf7, 0xaf, 0xea, 0xff, 0xc1, 0xd3, - 0x50, 0xa2, 0xa6, 0xe3, 0x82, 0xa7, 0xfc, 0xb4, 0xd7, 0xdc, 0xd3, 0x50, - 0xbe, 0xcd, 0x7f, 0x02, 0xf3, 0xce, 0x9b, 0x6c, 0x74, 0x3c, 0xfe, 0xfe, - 0xb3, 0x3f, 0x75, 0xc6, 0xf5, 0x9b, 0x3a, 0x7e, 0x6f, 0x36, 0x3f, 0xf2, - 0x74, 0xfd, 0x7b, 0x76, 0xdd, 0xe8, 0xe8, 0xb4, 0x46, 0x89, 0x7d, 0x4b, - 0xe7, 0xff, 0xe4, 0x58, 0x60, 0xff, 0x6b, 0x06, 0xd8, 0xe7, 0x67, 0x43, - 0xbc, 0xb8, 0x01, 0xd6, 0x36, 0x31, 0x65, 0x94, 0xa1, 0x85, 0x2b, 0x3f, - 0x3e, 0x03, 0x5c, 0x8c, 0x3f, 0x70, 0xaf, 0x74, 0x5d, 0x3e, 0x04, 0xcc, - 0x43, 0x44, 0x5d, 0x3e, 0xdf, 0x7e, 0x05, 0xe5, 0x49, 0x76, 0x7b, 0x58, - 0x61, 0x0b, 0x4c, 0xb9, 0xf1, 0x84, 0x4f, 0xfc, 0xac, 0x7a, 0xec, 0x13, - 0x31, 0x0d, 0x13, 0x34, 0xfd, 0xd6, 0x8e, 0xe9, 0xdf, 0xab, 0x6c, 0xe9, - 0xd4, 0xb5, 0x4e, 0x9c, 0x9f, 0x51, 0xd3, 0x75, 0x75, 0xb3, 0xa7, 0xed, - 0xdd, 0x17, 0xdb, 0x87, 0x47, 0x5b, 0x3c, 0xe7, 0x07, 0xe7, 0xc9, 0x9a, - 0xfb, 0x87, 0x4f, 0xff, 0xbb, 0xa5, 0xfa, 0xf5, 0x81, 0x7a, 0xfa, 0x60, - 0x1d, 0x3f, 0xf3, 0xb7, 0xf7, 0xf4, 0xff, 0x3b, 0xb4, 0x3a, 0x7f, 0xff, - 0xbd, 0xc1, 0x41, 0xbe, 0x75, 0xef, 0x4d, 0x33, 0xc1, 0xa8, 0x3a, 0x19, - 0x30, 0x5b, 0x56, 0xd2, 0x3c, 0xff, 0xfb, 0x9f, 0x8d, 0x17, 0x5f, 0xe6, - 0x97, 0xc7, 0x1c, 0x15, 0x3f, 0x52, 0xfa, 0xf7, 0xeb, 0x87, 0x4f, 0x26, - 0x62, 0x1a, 0x2c, 0xf9, 0xff, 0x7f, 0x4c, 0xff, 0xed, 0xb7, 0x53, 0xa7, - 0xff, 0xbe, 0x1a, 0xce, 0x96, 0xe8, 0x6e, 0xb6, 0x27, 0x4e, 0xe3, 0x8e, - 0x0a, 0x9f, 0xf6, 0x3e, 0xa3, 0x69, 0xcd, 0x81, 0x4b, 0x2f, 0xe7, 0xf9, - 0xb5, 0xfe, 0x47, 0x31, 0xc3, 0xa7, 0xfb, 0xe3, 0xcf, 0x8e, 0x7d, 0xdd, - 0x4e, 0x84, 0x54, 0x46, 0xe2, 0xd0, 0x19, 0x28, 0xaf, 0x47, 0xdd, 0xb7, - 0x6d, 0x29, 0xd1, 0xc4, 0xff, 0x06, 0x71, 0xaf, 0xb0, 0x31, 0xd3, 0xff, - 0xff, 0xf5, 0xdf, 0x75, 0xbb, 0x1f, 0x3e, 0x00, 0x5a, 0xf4, 0xba, 0x8d, - 0xd0, 0xab, 0x51, 0xd3, 0xaa, 0xd4, 0x1d, 0x3b, 0xaa, 0xf4, 0x74, 0x3d, - 0x18, 0x55, 0x84, 0x46, 0xc7, 0x27, 0x6b, 0xde, 0x0e, 0x9d, 0xdf, 0xa8, - 0x74, 0xed, 0xdf, 0x83, 0xa3, 0x93, 0xd8, 0xa4, 0x7b, 0xe3, 0xb3, 0xf0, - 0x7d, 0xd5, 0x8d, 0x4e, 0x9f, 0x68, 0x5a, 0xc0, 0xc9, 0xff, 0x7c, 0x1f, - 0x61, 0x47, 0xb9, 0xc9, 0xa2, 0x0d, 0x59, 0xa4, 0x9f, 0x62, 0x7d, 0x4c, - 0x74, 0xfc, 0xfd, 0x0e, 0x53, 0xb3, 0xa5, 0x68, 0x7a, 0x42, 0x4b, 0x3f, - 0xf5, 0x8d, 0x3b, 0xb0, 0xfd, 0x18, 0xa3, 0xa6, 0xf8, 0x9d, 0x3f, 0x67, - 0x1b, 0xbd, 0x6d, 0x8f, 0x63, 0xca, 0x1c, 0x32, 0x78, 0x4f, 0x51, 0xb8, - 0x57, 0x0b, 0xec, 0xfc, 0x17, 0xcd, 0x74, 0xc7, 0x4f, 0xff, 0xef, 0x47, - 0x3c, 0xf4, 0xf0, 0x39, 0xba, 0xfe, 0x9d, 0x7f, 0x83, 0xa7, 0xfc, 0xab, - 0xdd, 0x7c, 0x57, 0x1f, 0x67, 0x4f, 0xd5, 0xab, 0x06, 0xd8, 0xe5, 0x9b, - 0xf9, 0xed, 0x5f, 0xdd, 0x1d, 0x3f, 0x57, 0xe1, 0x7e, 0x81, 0xd1, 0xf4, - 0x45, 0x68, 0xef, 0x64, 0x73, 0x29, 0xdf, 0x34, 0x5f, 0x93, 0xff, 0x3f, - 0x7e, 0xbd, 0xea, 0xde, 0xd9, 0x47, 0x4f, 0xfd, 0xfb, 0x1b, 0xba, 0xf4, - 0x7d, 0x54, 0x74, 0x52, 0x88, 0xaa, 0xa3, 0x4d, 0xf7, 0x0e, 0x9d, 0xbf, - 0xd0, 0x74, 0xe1, 0x64, 0x3a, 0x3a, 0x1e, 0x6a, 0x85, 0xc4, 0x76, 0x19, - 0x38, 0x3e, 0x4c, 0x2e, 0x16, 0x58, 0xe3, 0x3f, 0xff, 0xf3, 0xb3, 0x6b, - 0xea, 0x5b, 0x8f, 0xc0, 0xf1, 0xaf, 0xd3, 0x54, 0xfd, 0x07, 0x4f, 0x71, - 0x97, 0x53, 0xa7, 0xf9, 0xea, 0xc7, 0xee, 0xad, 0xe4, 0xe8, 0x63, 0xdb, - 0xc2, 0x19, 0xeb, 0xaf, 0xc4, 0xe8, 0x13, 0xc0, 0xf4, 0x82, 0x7b, 0xc7, - 0xb9, 0x53, 0xa7, 0xe7, 0x6d, 0xde, 0x0a, 0x1d, 0x3f, 0xd5, 0xef, 0xf4, - 0xd2, 0xfb, 0xd9, 0xd1, 0xa3, 0xe9, 0xd9, 0x6c, 0x32, 0x2b, 0xee, 0x11, - 0xb3, 0x39, 0xe9, 0xd2, 0x51, 0xd1, 0x49, 0xa8, 0x77, 0x06, 0x27, 0xf6, - 0x65, 0x2f, 0x16, 0xe4, 0xe9, 0xff, 0xc3, 0xf6, 0xa8, 0xe3, 0xfa, 0x56, - 0xc0, 0xe9, 0xff, 0xff, 0x6b, 0xf4, 0xee, 0xe9, 0xd8, 0x03, 0x6f, 0xbf, - 0x02, 0xfd, 0x59, 0xd3, 0xdc, 0xf3, 0x82, 0x74, 0xff, 0xb3, 0x49, 0xfc, - 0xe9, 0x5c, 0xd1, 0xd0, 0xc9, 0xb8, 0x72, 0x4f, 0x66, 0x48, 0x91, 0xf6, - 0xfd, 0x11, 0x4f, 0xfd, 0x63, 0x4e, 0xec, 0x3f, 0x46, 0x28, 0xe9, 0xf5, - 0xed, 0xea, 0xd1, 0xd3, 0xea, 0x6a, 0x2c, 0xa3, 0xa1, 0x91, 0x23, 0x54, - 0x3f, 0x49, 0xe6, 0xef, 0x47, 0x4f, 0xd4, 0x38, 0xfe, 0xb0, 0x28, 0x3a, - 0x7f, 0x79, 0xd5, 0xef, 0x5f, 0xd9, 0xd3, 0x7c, 0x0e, 0x8e, 0xb6, 0x7f, - 0xff, 0x35, 0xd1, 0xac, 0xff, 0xdc, 0xb7, 0x20, 0xdb, 0xfa, 0x7f, 0x93, - 0xa7, 0xed, 0x7b, 0x43, 0x9a, 0xf9, 0xd1, 0xc9, 0xfb, 0x69, 0x16, 0x4b, - 0xeb, 0x6d, 0x8e, 0xcb, 0xbc, 0x7e, 0xee, 0x87, 0x19, 0xa6, 0x82, 0x9e, - 0x63, 0x2c, 0xb9, 0x4a, 0x5e, 0x5d, 0x69, 0x87, 0xc7, 0xe1, 0x1a, 0xe4, - 0x7e, 0x60, 0x80, 0xa2, 0xcd, 0x4a, 0xb5, 0xc4, 0x1e, 0xe3, 0x15, 0x18, - 0x68, 0xd6, 0x3b, 0xed, 0xc3, 0x9f, 0x83, 0x0e, 0xa8, 0x4b, 0x78, 0x85, - 0x5c, 0x2d, 0xb3, 0xb4, 0xd5, 0x64, 0x4b, 0x3f, 0xf9, 0x6a, 0xc7, 0xae, - 0xc1, 0x33, 0x10, 0xd1, 0x36, 0x4f, 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x2a, - 0xd9, 0xfc, 0xf7, 0xfb, 0xb1, 0x67, 0x9d, 0x3d, 0x7a, 0xcd, 0x9d, 0x27, - 0x7e, 0xcf, 0x4c, 0x4c, 0xe7, 0xc0, 0x99, 0x88, 0x68, 0xad, 0x27, 0xff, - 0x91, 0x82, 0xfb, 0xc5, 0x63, 0xdb, 0xe8, 0x74, 0xff, 0xf3, 0xeb, 0x62, - 0xca, 0xcb, 0xde, 0xd9, 0x47, 0x4d, 0xbd, 0xb2, 0x25, 0xf1, 0x2e, 0x7f, - 0x33, 0xaf, 0x1b, 0x16, 0xec, 0xe9, 0xfa, 0x8b, 0xd7, 0xed, 0x47, 0x4f, - 0xf5, 0xbb, 0x0b, 0x71, 0x4b, 0xea, 0x74, 0xfe, 0x7d, 0xef, 0x07, 0xbf, - 0x4e, 0x92, 0xfa, 0xc4, 0xfc, 0x6c, 0xaf, 0xf0, 0xc7, 0xd1, 0x6e, 0x1b, - 0x09, 0x6e, 0xcf, 0x27, 0xf2, 0xec, 0x13, 0x31, 0x0d, 0x16, 0x04, 0xf8, - 0x13, 0x31, 0x0d, 0x13, 0xac, 0xff, 0xfe, 0xd3, 0x51, 0xcd, 0xa9, 0x75, - 0xad, 0xeb, 0xf5, 0xf6, 0x83, 0xa7, 0xcb, 0x56, 0x3d, 0x76, 0x89, 0x57, - 0x0c, 0x27, 0xc0, 0x99, 0x88, 0x68, 0xb6, 0x67, 0xfd, 0xdb, 0x55, 0x7a, - 0xfa, 0x60, 0x1d, 0x25, 0xd9, 0xf6, 0xe1, 0x84, 0xf2, 0x66, 0x21, 0xa2, - 0xe6, 0x92, 0x8e, 0x80, 0x37, 0x7c, 0x15, 0xcc, 0xe2, 0x8e, 0x92, 0xec, - 0xdc, 0x70, 0x43, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0xbb, 0xe7, 0x97, - 0xe7, 0x9e, 0xce, 0x86, 0x6e, 0x7c, 0x6e, 0xb3, 0xde, 0x43, 0x2a, 0x54, - 0xbf, 0x29, 0xfc, 0x1c, 0x95, 0x0d, 0x0e, 0xe1, 0x5b, 0x58, 0x4c, 0xec, - 0x9f, 0xc1, 0xdc, 0xfa, 0xb5, 0x56, 0x3c, 0xe9, 0xff, 0xa9, 0x4f, 0x72, - 0x9d, 0xdd, 0x8f, 0x93, 0xa7, 0x0e, 0x2d, 0x8f, 0xb7, 0x64, 0xf3, 0xf8, - 0x68, 0xb7, 0x6d, 0xb7, 0x93, 0xa7, 0xc0, 0x99, 0x88, 0x68, 0x95, 0xe7, - 0xfc, 0x39, 0xc7, 0x3a, 0x6a, 0x2f, 0x83, 0xa7, 0xbd, 0xc0, 0x79, 0xd3, - 0xff, 0xfb, 0xfb, 0xc5, 0x60, 0xf7, 0xae, 0x30, 0x68, 0x4f, 0xd0, 0x74, - 0x72, 0x88, 0x3c, 0x21, 0x8e, 0x51, 0xcd, 0xa8, 0x61, 0xce, 0xc7, 0xad, - 0x93, 0x76, 0xb3, 0x7a, 0xc6, 0x2d, 0x3b, 0x6d, 0xc9, 0x53, 0xff, 0xb5, - 0x9f, 0xdb, 0x3f, 0xe1, 0x47, 0xbd, 0x95, 0x3f, 0xb1, 0x17, 0xc8, 0x3b, - 0x8b, 0x63, 0xe8, 0xa8, 0xe4, 0x96, 0x8a, 0xa8, 0xd5, 0x1d, 0x3b, 0xa8, - 0x57, 0x4f, 0xfe, 0x5a, 0xb1, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x4c, 0x33, - 0xff, 0x85, 0x9d, 0x0b, 0x52, 0xbe, 0xb6, 0xee, 0xaa, 0xf3, 0xa7, 0xff, - 0x06, 0x76, 0xbf, 0x3b, 0x7f, 0x0d, 0x57, 0x9d, 0x35, 0xaf, 0x94, 0x52, - 0x78, 0x57, 0x9f, 0xf9, 0xdf, 0xba, 0x5f, 0xee, 0x6c, 0x59, 0xe7, 0x4f, - 0xe6, 0xca, 0x37, 0xe7, 0x00, 0xe9, 0xf6, 0x03, 0xf1, 0x47, 0x40, 0x9e, - 0xc7, 0xa6, 0x73, 0xf2, 0x9a, 0xc7, 0x7d, 0x47, 0x4a, 0xa7, 0x4f, 0x9a, - 0xc7, 0x7d, 0x47, 0x4f, 0xda, 0xfe, 0xeb, 0x94, 0xf4, 0x3e, 0x67, 0x0b, - 0x94, 0x21, 0x3f, 0xff, 0xe1, 0xbe, 0x1d, 0xb7, 0x7a, 0xe8, 0x37, 0x47, - 0xec, 0x69, 0x7d, 0x4e, 0x9f, 0xfe, 0x6d, 0x8e, 0x77, 0xab, 0xff, 0x3e, - 0xee, 0xa7, 0x4f, 0xce, 0xbc, 0x6c, 0x5b, 0xb3, 0xa7, 0xff, 0x36, 0xfb, - 0x67, 0xdd, 0x3b, 0xa3, 0xde, 0x0e, 0x86, 0x3f, 0xff, 0x98, 0xcf, 0xd5, - 0xff, 0x95, 0x66, 0xce, 0x9f, 0xff, 0xf0, 0x5b, 0xa6, 0x1d, 0xf4, 0xf0, - 0x2d, 0xac, 0xfe, 0xdb, 0x75, 0x3a, 0x57, 0x4a, 0x27, 0x40, 0xbe, 0x7f, - 0xfd, 0xa1, 0xbd, 0xeb, 0xf7, 0x4e, 0xed, 0xd3, 0x54, 0xe9, 0xcd, 0xdf, - 0x83, 0xa2, 0xcf, 0xd0, 0x55, 0xa7, 0xb3, 0xc7, 0x36, 0x74, 0x97, 0xd6, - 0x2e, 0x2e, 0xf3, 0x0a, 0x14, 0x84, 0x43, 0x8a, 0xc0, 0xe3, 0xa8, 0x68, - 0x0c, 0x2f, 0xb7, 0x09, 0xcf, 0x48, 0x27, 0xc0, 0x99, 0x88, 0x68, 0xab, - 0xa7, 0xf9, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x47, 0x92, 0x5d, 0x9f, 0x8e, - 0x18, 0x4f, 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x2c, 0x19, 0xfc, 0xbb, 0x04, - 0xcc, 0x43, 0x45, 0x95, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, 0xb4, 0xe7, - 0xf5, 0xd7, 0xa0, 0x07, 0xba, 0x3a, 0x79, 0x33, 0x10, 0xd1, 0x6e, 0x4f, - 0xfc, 0xd6, 0x16, 0x3d, 0x35, 0x74, 0xf0, 0x74, 0x01, 0xf7, 0xd4, 0xae, - 0x7f, 0x98, 0x7d, 0x53, 0x57, 0x7f, 0x3a, 0x7f, 0x66, 0x51, 0xcb, 0x58, - 0x1d, 0x3f, 0xec, 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x14, 0x3c, 0xff, 0xca, - 0xce, 0x5b, 0x9d, 0x7c, 0x7e, 0xa3, 0xa7, 0xfe, 0xf5, 0xfa, 0xc0, 0xa7, - 0x6d, 0xfa, 0x0e, 0x9f, 0xf7, 0xa1, 0xd8, 0x60, 0xee, 0xfb, 0x3a, 0x7e, - 0xae, 0x53, 0x5d, 0xfc, 0xe9, 0xf8, 0x7a, 0xcb, 0x06, 0xa9, 0xd3, 0xff, - 0xf5, 0xf3, 0xa6, 0xf0, 0xbd, 0x8e, 0x77, 0x5a, 0xb7, 0x65, 0x49, 0x6f, - 0x55, 0xef, 0x70, 0xa3, 0xf9, 0x0b, 0x87, 0x0a, 0x31, 0xc4, 0x6e, 0xd1, - 0x6a, 0x8d, 0xb3, 0xef, 0x4b, 0xba, 0x8b, 0xe7, 0xf2, 0xec, 0x13, 0x31, - 0x0d, 0x17, 0x9c, 0x33, 0x2e, 0x41, 0xe8, 0x9c, 0xc3, 0xda, 0xe7, 0x23, - 0xa9, 0x8c, 0x58, 0x09, 0x94, 0x77, 0xa3, 0xb1, 0x96, 0x64, 0xea, 0x15, - 0x33, 0xf9, 0x76, 0x09, 0x98, 0x86, 0x8a, 0x5a, 0x7f, 0x2e, 0xc1, 0x33, - 0x10, 0xd1, 0x61, 0x4f, 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x2c, 0xb9, 0xe5, - 0xf9, 0xeb, 0x47, 0x76, 0x74, 0xe5, 0xf8, 0x51, 0xd3, 0xc8, 0xb6, 0xaa, - 0x1e, 0x7f, 0xa6, 0x33, 0xff, 0x96, 0xac, 0x7a, 0xec, 0x13, 0x31, 0x0d, - 0x14, 0x64, 0xfe, 0x5b, 0x3a, 0x60, 0x6e, 0xce, 0x87, 0xa7, 0x7a, 0x07, - 0x6a, 0x3b, 0xc8, 0x45, 0x54, 0xe3, 0x6a, 0x53, 0xff, 0x2f, 0x1e, 0xbb, - 0x04, 0xcc, 0x43, 0x44, 0x73, 0x3f, 0xf9, 0x6a, 0xc7, 0xae, 0xc1, 0x33, - 0x10, 0xd1, 0x39, 0x4f, 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x2c, 0xc9, 0xff, - 0x96, 0xdd, 0x83, 0x6f, 0x59, 0x4b, 0xce, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, - 0x34, 0x5b, 0xb3, 0xff, 0x96, 0xac, 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x14, - 0x84, 0xff, 0xcb, 0xc7, 0xae, 0xc1, 0x33, 0x10, 0xd1, 0x29, 0x45, 0x09, - 0xfb, 0x38, 0x98, 0xa5, 0x2e, 0xce, 0xc5, 0x13, 0x67, 0x6e, 0xca, 0x53, - 0xfe, 0xc7, 0xae, 0xc1, 0x33, 0x10, 0xd1, 0x3b, 0x4f, 0xff, 0xbf, 0xcf, - 0xaa, 0x67, 0x6c, 0xe4, 0x58, 0x6d, 0x0e, 0x92, 0xd4, 0x89, 0xdc, 0x46, - 0x9f, 0xfb, 0x15, 0xab, 0x4c, 0xd3, 0x78, 0x79, 0xd3, 0xff, 0x0d, 0xeb, - 0x28, 0xba, 0x8e, 0x52, 0x74, 0xdd, 0x4b, 0xe5, 0x10, 0xb5, 0x43, 0x85, - 0x23, 0x83, 0xaa, 0x15, 0xb3, 0xe0, 0x4c, 0xc4, 0x34, 0x45, 0x93, 0xfe, - 0xc7, 0xae, 0xc1, 0x33, 0x10, 0xd1, 0x2e, 0xcf, 0xff, 0xd7, 0xce, 0x9b, - 0xc2, 0xf6, 0x39, 0xdd, 0x6a, 0xdd, 0x95, 0x25, 0xda, 0x35, 0x14, 0x61, - 0xd4, 0x8d, 0x3f, 0xf9, 0x6a, 0xc7, 0xae, 0xc1, 0x33, 0x10, 0xd1, 0x31, - 0x4f, 0x81, 0x33, 0x10, 0xd1, 0x54, 0xca, 0xce, 0x8b, 0x37, 0xfe, 0x4c, - 0x27, 0xff, 0xff, 0x06, 0x6a, 0x97, 0xde, 0xd7, 0xac, 0xa8, 0x7f, 0x8d, - 0xeb, 0xe0, 0xf3, 0xa1, 0x68, 0x9a, 0xc2, 0x29, 0xff, 0xcb, 0x56, 0x3d, - 0x76, 0x09, 0x98, 0x86, 0x89, 0xd2, 0x7f, 0x7f, 0x01, 0x9f, 0x8e, 0x8e, - 0x9f, 0x38, 0xce, 0x35, 0x4e, 0x9f, 0xb8, 0xbf, 0xba, 0xb1, 0x3a, 0x3e, - 0x7a, 0xd5, 0x28, 0x9d, 0xfd, 0x31, 0xcb, 0x34, 0x53, 0xff, 0x7b, 0x5d, - 0xb5, 0x2b, 0xf5, 0xcf, 0xa8, 0xe8, 0x51, 0xfa, 0x68, 0xae, 0x7f, 0xd8, - 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x27, 0x79, 0xf6, 0xfd, 0xc5, 0x7c, 0xa9, - 0x2f, 0x94, 0xeb, 0xae, 0x31, 0xe5, 0x11, 0x62, 0x34, 0xff, 0xe5, 0xab, - 0x1e, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0x0b, 0x3f, 0xf9, 0x6a, 0xc7, 0xae, - 0xc1, 0x33, 0x10, 0xd1, 0x49, 0x4f, 0xff, 0xeb, 0xaa, 0xfc, 0x5b, 0x9a, - 0xc5, 0x6f, 0x4d, 0xbf, 0x54, 0x74, 0x50, 0xb9, 0xac, 0xf3, 0x84, 0x8c, - 0xac, 0x08, 0x95, 0x28, 0x03, 0xb4, 0x9f, 0x54, 0xba, 0x94, 0xa7, 0xf2, - 0xec, 0x13, 0x31, 0x0d, 0x11, 0x24, 0xff, 0xe5, 0xab, 0x1e, 0xbb, 0x04, - 0xcc, 0x43, 0x44, 0xbd, 0x3e, 0x0e, 0xd5, 0xfa, 0x9d, 0x3b, 0xb6, 0xd9, - 0xd3, 0xff, 0x63, 0x95, 0x67, 0x59, 0xa6, 0xa5, 0xc3, 0xa3, 0xe8, 0x8b, - 0x70, 0xa0, 0x07, 0x27, 0xfb, 0xf8, 0x3e, 0xed, 0xc6, 0xf2, 0x74, 0xf8, - 0x13, 0x31, 0x0d, 0x14, 0xbc, 0x94, 0x74, 0xf8, 0x77, 0x45, 0xf0, 0x74, - 0xff, 0x77, 0x50, 0x6a, 0x5f, 0xf5, 0x1d, 0x3f, 0xd9, 0x47, 0x4a, 0x3d, - 0x71, 0xba, 0xe7, 0x4d, 0x6f, 0x63, 0xfc, 0xf4, 0xea, 0x67, 0xd9, 0xd3, - 0x9b, 0xba, 0x9d, 0x1c, 0x9b, 0x1e, 0x05, 0x67, 0xfe, 0xfa, 0xb3, 0x9f, - 0x0e, 0x3d, 0x86, 0x93, 0xa7, 0xab, 0xfe, 0x36, 0x74, 0x68, 0xfa, 0xf6, - 0x91, 0x3f, 0xd9, 0xac, 0x73, 0xe0, 0xd4, 0x1d, 0x3e, 0x76, 0xfa, 0x9a, - 0xa7, 0x4f, 0xb1, 0xd5, 0x85, 0x4e, 0x93, 0x72, 0x7a, 0x2a, 0x2a, 0x92, - 0xd9, 0x58, 0x77, 0x26, 0x16, 0x77, 0xe4, 0xc2, 0x91, 0x07, 0x21, 0x49, - 0xa5, 0xec, 0x84, 0x75, 0x48, 0xb7, 0x08, 0x99, 0xfc, 0xbb, 0x04, 0xcc, - 0x43, 0x45, 0x39, 0x3f, 0xef, 0x86, 0x57, 0x57, 0x62, 0x87, 0x4f, 0xfa, - 0xf4, 0xc1, 0x6b, 0xe3, 0x8e, 0x0a, 0x9b, 0xfc, 0x1d, 0x35, 0x0b, 0xe5, - 0x12, 0x1d, 0x47, 0x4e, 0xc7, 0xf3, 0xe0, 0x4c, 0xc4, 0x34, 0x57, 0x93, - 0xff, 0xf5, 0xf3, 0xa6, 0xf0, 0xbd, 0x8e, 0x77, 0x5a, 0xb7, 0x65, 0x49, - 0x76, 0x88, 0xee, 0xa3, 0x09, 0xff, 0x97, 0x8f, 0x5d, 0x82, 0x66, 0x21, - 0xa2, 0x47, 0x9d, 0xfe, 0xd8, 0xe9, 0xc9, 0x6a, 0x29, 0x65, 0xe4, 0xf8, - 0x13, 0x31, 0x0d, 0x12, 0x44, 0xf2, 0xf1, 0xeb, 0x63, 0xd9, 0xb2, 0x99, - 0xff, 0x97, 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x4a, 0x9f, 0x02, 0x66, - 0x21, 0xa2, 0xf1, 0x9f, 0xbd, 0x1a, 0x72, 0x9a, 0x9d, 0x3e, 0xad, 0x77, - 0x68, 0x74, 0xff, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0x36, 0x4b, 0xb4, - 0x63, 0x52, 0x60, 0x05, 0xf8, 0x4d, 0x0c, 0xc8, 0xdd, 0xa0, 0xed, 0xf2, - 0xfa, 0xf9, 0x85, 0x27, 0xe1, 0x96, 0xe4, 0x34, 0x94, 0x57, 0xa8, 0x60, - 0xec, 0xdf, 0xd8, 0xc4, 0xa1, 0xa3, 0xb7, 0x04, 0xa2, 0x3b, 0x07, 0xca, - 0x74, 0xe6, 0x51, 0x55, 0xde, 0x27, 0xb7, 0x99, 0x4b, 0x49, 0x69, 0x2c, - 0x69, 0x9f, 0xa4, 0xfc, 0xf0, 0x77, 0x5e, 0x3b, 0x77, 0x2b, 0x35, 0xf0, - 0xa5, 0xb5, 0x2b, 0x14, 0x03, 0x1a, 0x9d, 0xfe, 0xca, 0xce, 0x23, 0xb9, - 0x67, 0x8e, 0xe4, 0x2c, 0x46, 0x92, 0x09, 0x5a, 0x51, 0x4e, 0xeb, 0xfe, - 0x1f, 0x69, 0xeb, 0xae, 0xa5, 0x35, 0xf1, 0x29, 0x47, 0xaa, 0x3e, 0x7f, - 0x13, 0xba, 0xae, 0xd4, 0x96, 0x28, + 0xfe, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x25, 0x9f, + 0x02, 0x66, 0x21, 0xa2, 0x2d, 0x9a, 0xe9, 0x2a, + 0x4c, 0x54, 0xbc, 0x03, 0x4b, 0xe0, 0xb4, 0xfe, + 0xd5, 0x87, 0x8a, 0xfd, 0x4a, 0x59, 0xa8, 0x9f, + 0x9f, 0xbf, 0xba, 0xb7, 0x0e, 0x86, 0x3f, 0x3c, + 0x43, 0x9f, 0xe1, 0x6d, 0xfd, 0x19, 0x5f, 0x3a, + 0x4b, 0xb4, 0xd1, 0xba, 0xa1, 0xe1, 0xd8, 0x82, + 0x7f, 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x51, 0x4f, + 0xff, 0x6f, 0xfb, 0x5f, 0x7b, 0xba, 0x39, 0x6b, + 0xe4, 0xe9, 0xf0, 0x26, 0x62, 0x1a, 0x2b, 0xd9, + 0xf7, 0xdd, 0x93, 0xda, 0x0e, 0x92, 0xec, 0xf7, + 0x00, 0xc2, 0x7f, 0xe5, 0xe3, 0xd7, 0x60, 0x99, + 0x88, 0x68, 0x91, 0xa7, 0xff, 0x2d, 0x58, 0xf5, + 0xd8, 0x26, 0x62, 0x1a, 0x27, 0x89, 0xff, 0xcb, + 0x56, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0xfe, + 0x7f, 0xf2, 0xd5, 0x8f, 0x5d, 0x82, 0x66, 0x21, + 0xa2, 0x86, 0x9f, 0xfc, 0xb5, 0x63, 0xd7, 0x60, + 0x99, 0x88, 0x68, 0xa2, 0x27, 0xfd, 0x8f, 0x5d, + 0x82, 0x66, 0x21, 0xa2, 0x91, 0x9f, 0xff, 0xaf, + 0x9d, 0xb7, 0x65, 0xe8, 0x73, 0xca, 0xd5, 0xbc, + 0x2a, 0x4b, 0x52, 0x29, 0x3a, 0x91, 0xa7, 0xfe, + 0x5e, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0x42, + 0x28, 0x5d, 0x81, 0x7c, 0x70, 0x28, 0x81, 0xd7, + 0x3b, 0x08, 0x57, 0xa8, 0x9b, 0x69, 0x9e, 0x29, + 0x3b, 0x8a, 0x55, 0x52, 0xf6, 0x1e, 0xce, 0xc5, + 0x93, 0xff, 0x96, 0xac, 0x7a, 0xec, 0x13, 0x31, + 0x0d, 0x13, 0x9c, 0xff, 0xe5, 0xab, 0x1e, 0xbb, + 0x04, 0xcc, 0x43, 0x45, 0x13, 0x3f, 0xf0, 0x3d, + 0x7b, 0xfd, 0x5c, 0x7f, 0xfc, 0x3a, 0x01, 0x1d, + 0x75, 0x52, 0xf5, 0x4a, 0x7f, 0x2e, 0xc1, 0x33, + 0x10, 0xd1, 0x0e, 0x4f, 0x81, 0x33, 0x10, 0xd1, + 0x17, 0xcf, 0xea, 0xdf, 0x3b, 0xbf, 0x30, 0xe9, + 0xab, 0x49, 0xd3, 0xda, 0x7b, 0x77, 0x2a, 0x14, + 0x6e, 0xb0, 0x5e, 0x4b, 0xb4, 0x5e, 0xb8, 0x60, + 0x2d, 0xb3, 0xff, 0x96, 0xac, 0x7a, 0xec, 0x13, + 0x31, 0x0d, 0x13, 0x24, 0xfe, 0x5d, 0x82, 0x66, + 0x21, 0xa2, 0xde, 0x9f, 0xfc, 0xb5, 0x63, 0xd7, + 0x60, 0x99, 0x88, 0x68, 0xa4, 0xe7, 0xdb, 0x5b, + 0xbf, 0xd6, 0xdd, 0xe3, 0xa1, 0x95, 0x22, 0x3e, + 0x1f, 0x16, 0x6b, 0x55, 0x27, 0x47, 0x7d, 0x94, + 0xa7, 0xf2, 0xec, 0x13, 0x31, 0x0d, 0x10, 0xec, + 0xff, 0xe5, 0xab, 0x1e, 0xbb, 0x04, 0xcc, 0x43, + 0x44, 0xb1, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, + 0x8c, 0x27, 0xc0, 0x99, 0x88, 0x68, 0x8f, 0x67, + 0xab, 0x94, 0xba, 0x3a, 0x79, 0x78, 0xf5, 0xd9, + 0xea, 0x68, 0xc2, 0x7f, 0x2e, 0xc1, 0x33, 0x10, + 0xd1, 0x61, 0xcf, 0xe5, 0xd8, 0x26, 0x62, 0x1a, + 0x2e, 0x78, 0x64, 0xf2, 0xa8, 0x3b, 0x7a, 0x97, + 0xe1, 0x1e, 0xa3, 0x8d, 0x1d, 0xcf, 0xe5, 0xd8, + 0x26, 0x62, 0x1a, 0x21, 0xe9, 0xf0, 0x26, 0x62, + 0x1a, 0x22, 0x69, 0xff, 0xd7, 0xac, 0xde, 0xd9, + 0xd3, 0xec, 0x18, 0xe9, 0xb4, 0xa3, 0xa7, 0xff, + 0x5e, 0xfb, 0x51, 0x56, 0xfd, 0x3a, 0x65, 0x1d, + 0x14, 0x9f, 0x1e, 0xc5, 0xa7, 0xb5, 0xee, 0x76, + 0x34, 0x42, 0xf2, 0x5d, 0xa6, 0x5f, 0xb3, 0x0a, + 0xc2, 0xaf, 0xd2, 0x39, 0xc1, 0x88, 0x74, 0xb6, + 0x74, 0x77, 0x35, 0x3e, 0x8c, 0xcf, 0x6b, 0x7f, + 0xd1, 0xd3, 0xff, 0xbe, 0xe3, 0xee, 0x97, 0xf4, + 0x56, 0x60, 0x9d, 0x36, 0x3b, 0x1d, 0x16, 0x88, + 0x6d, 0x91, 0x62, 0x64, 0xe0, 0xc4, 0x3a, 0x1d, + 0xf3, 0xc7, 0xee, 0x5d, 0x3e, 0xde, 0x6b, 0x1e, + 0x74, 0xfe, 0x7d, 0x5a, 0xbd, 0x6b, 0xf5, 0xbe, + 0xb6, 0x74, 0xf7, 0xeb, 0xff, 0x0e, 0x9d, 0xc7, + 0x1c, 0x15, 0x3e, 0xc1, 0xd6, 0xec, 0xa5, 0x97, + 0xf3, 0xec, 0xd3, 0x97, 0xa3, 0xa3, 0x94, 0x4e, + 0xf8, 0x84, 0x26, 0x93, 0xdb, 0xcc, 0xc3, 0xa7, + 0xfe, 0xf3, 0xee, 0x74, 0xdb, 0x7c, 0x3d, 0xeb, + 0x9d, 0x3f, 0xef, 0xf7, 0x61, 0x6a, 0xb7, 0xd4, + 0x74, 0xfd, 0x6e, 0xbd, 0x7d, 0xd4, 0xe9, 0xeb, + 0xe6, 0xe8, 0x3a, 0x2d, 0x51, 0xbd, 0x24, 0xdf, + 0x87, 0x2f, 0x5c, 0xc5, 0xc1, 0xfd, 0xa6, 0x89, + 0xf6, 0x8b, 0xe7, 0xeb, 0xe1, 0xaf, 0x9f, 0x9d, + 0x39, 0xbd, 0xf0, 0xe9, 0xff, 0xff, 0xc2, 0x34, + 0xb7, 0x71, 0xbe, 0x77, 0xf7, 0x3a, 0x56, 0xe9, + 0x78, 0x5f, 0x07, 0x4f, 0xbf, 0xaf, 0x5a, 0x83, + 0xa7, 0xff, 0xf5, 0xd2, 0xfa, 0xaa, 0xc7, 0xa3, + 0xb7, 0xf7, 0x47, 0xec, 0x0e, 0x9f, 0xff, 0xf7, + 0x1d, 0x06, 0xd3, 0x7f, 0x1b, 0xf6, 0x9d, 0x74, + 0xce, 0x2f, 0xb9, 0xd3, 0xfa, 0x97, 0xd7, 0xbf, + 0xad, 0x49, 0xd3, 0xfb, 0x38, 0xf5, 0xc6, 0xd6, + 0x1d, 0x0c, 0x8d, 0xff, 0xb9, 0x89, 0xc4, 0xf7, + 0x9a, 0xfd, 0x07, 0x4f, 0xf9, 0xb2, 0x86, 0x50, + 0xb5, 0x3e, 0x1d, 0x0c, 0xa9, 0xee, 0xdf, 0x7e, + 0x52, 0x11, 0xa2, 0xe1, 0x70, 0x92, 0x4d, 0xeb, + 0xce, 0x9d, 0x9a, 0xa9, 0xd3, 0x7b, 0x41, 0xd3, + 0xcc, 0x3a, 0x71, 0xe6, 0xcc, 0x06, 0xe7, 0xff, + 0xde, 0xb6, 0xba, 0x0f, 0xae, 0xdd, 0x2f, 0x5d, + 0x57, 0xa3, 0xa7, 0xfe, 0xdb, 0x77, 0xe9, 0xa1, + 0xcd, 0x36, 0x8e, 0x9f, 0xdd, 0x29, 0x7f, 0xf7, + 0xea, 0x8e, 0x8f, 0x0f, 0xf8, 0x51, 0xa7, 0xfc, + 0x0e, 0x74, 0xab, 0x7e, 0x8c, 0xd1, 0xd0, 0xc7, + 0xc7, 0xe9, 0x14, 0xff, 0xff, 0xf7, 0xa3, 0x50, + 0x16, 0x73, 0xa7, 0x6d, 0x7d, 0xf7, 0x4e, 0xad, + 0xd0, 0xdd, 0x4e, 0x93, 0x1d, 0x3f, 0x9f, 0x81, + 0xfa, 0xb5, 0x27, 0x4f, 0xff, 0xff, 0xef, 0xf9, + 0x51, 0xbc, 0xa7, 0xa7, 0x3b, 0xf7, 0xa0, 0xdd, + 0x2f, 0xbf, 0x68, 0x1b, 0xca, 0x4e, 0x9d, 0x98, + 0x86, 0x8a, 0x62, 0x2d, 0x17, 0xa9, 0x09, 0x79, + 0xff, 0x58, 0xd2, 0xfa, 0xe9, 0x81, 0xc3, 0xa7, + 0x5f, 0xfc, 0x3a, 0x56, 0x74, 0xea, 0x46, 0xfc, + 0x35, 0x6e, 0x87, 0x23, 0xe8, 0x9e, 0xc6, 0x99, + 0xfe, 0xc5, 0x73, 0xb6, 0xa2, 0xf8, 0x3a, 0x7f, + 0xff, 0x0d, 0xa6, 0xb4, 0xda, 0xab, 0x83, 0x7c, + 0x74, 0x67, 0x76, 0x74, 0xff, 0x91, 0x95, 0xbb, + 0xad, 0xfc, 0x4e, 0x86, 0x45, 0x16, 0xd9, 0xe7, + 0xc0, 0xce, 0x98, 0x0e, 0x9f, 0xb0, 0x7a, 0x72, + 0xc2, 0x74, 0x59, 0xfa, 0xfc, 0x8b, 0xd2, 0x68, + 0xa1, 0x77, 0x2f, 0x94, 0xae, 0xe6, 0xe9, 0x1a, + 0x0d, 0x24, 0x5f, 0x84, 0x1b, 0x81, 0xe1, 0x0e, + 0xf5, 0x43, 0x10, 0x48, 0xb5, 0x1a, 0x8c, 0xff, + 0xbb, 0x86, 0x71, 0xd3, 0x39, 0xca, 0x0e, 0x9e, + 0xb1, 0xef, 0xd7, 0x3a, 0x7f, 0xff, 0xfd, 0xbf, + 0xeb, 0x76, 0x0c, 0xeb, 0xa2, 0xbd, 0x76, 0xe9, + 0x74, 0xbe, 0xfd, 0x1f, 0x2a, 0x74, 0xb5, 0xf4, + 0x5a, 0xd4, 0x9a, 0x7f, 0xfd, 0x77, 0xbf, 0xa6, + 0xef, 0xa5, 0x7d, 0xdb, 0x75, 0xce, 0x9f, 0xfe, + 0xd6, 0xef, 0xce, 0x8a, 0x6b, 0xd7, 0x36, 0x27, + 0x4f, 0xf5, 0x3d, 0x14, 0xd6, 0x3a, 0xea, 0x3a, + 0x55, 0xb4, 0x47, 0x62, 0x8c, 0xbe, 0x29, 0x87, + 0xea, 0x1d, 0x13, 0xe7, 0xb5, 0x2f, 0xa9, 0xd3, + 0xff, 0xff, 0xfe, 0xb1, 0xef, 0xd3, 0xfb, 0xf5, + 0x6e, 0x7f, 0x4c, 0xa1, 0xce, 0xfb, 0xfa, 0xef, + 0x74, 0xf8, 0xdc, 0x95, 0x3f, 0xff, 0xf2, 0x7f, + 0x8e, 0x7d, 0x0e, 0x9e, 0xb5, 0x15, 0x4d, 0xfb, + 0xba, 0x73, 0x83, 0xa6, 0xf6, 0x8a, 0x53, 0x47, + 0xf9, 0x45, 0x61, 0x49, 0x0c, 0xab, 0xcb, 0x71, + 0x9c, 0x0c, 0x6e, 0xb3, 0xff, 0x94, 0x9d, 0x37, + 0x8f, 0xb5, 0x60, 0xf8, 0x74, 0xff, 0xfb, 0xe3, + 0xad, 0xdb, 0xb6, 0x9c, 0xbe, 0xbe, 0x0f, 0x87, + 0x4f, 0xfc, 0xc3, 0x40, 0xdb, 0xaa, 0xfa, 0xd4, + 0x9d, 0x15, 0x45, 0x17, 0xab, 0x93, 0xd7, 0xab, + 0x77, 0x0e, 0x9d, 0xd5, 0x7b, 0x3a, 0x6b, 0xe4, + 0xe8, 0xa1, 0x36, 0x97, 0xc3, 0xb2, 0xa4, 0x9a, + 0x25, 0x74, 0x3d, 0x3e, 0xfe, 0xab, 0x7e, 0x1d, + 0x3f, 0x72, 0xc3, 0xbc, 0x79, 0xd3, 0x9b, 0x96, + 0x3a, 0x7e, 0x7d, 0xea, 0xb8, 0xe7, 0x43, 0xc7, + 0x51, 0x64, 0x3d, 0x16, 0xce, 0x37, 0xcf, 0xce, + 0xdb, 0xce, 0xbb, 0x78, 0x74, 0xfe, 0x07, 0x06, + 0xf7, 0x9a, 0x3a, 0x2c, 0xf9, 0x7e, 0x69, 0x3f, + 0x37, 0x97, 0xae, 0xd4, 0x1d, 0x0f, 0x3d, 0x11, + 0x21, 0x9f, 0xff, 0xf6, 0x87, 0x3c, 0xad, 0x17, + 0xf1, 0xd0, 0xdb, 0xae, 0x95, 0xe0, 0x4e, 0x9f, + 0xf7, 0xed, 0xce, 0x95, 0x6d, 0xe7, 0x5c, 0xe9, + 0xfd, 0x94, 0xd7, 0x77, 0x80, 0x74, 0x72, 0x7e, + 0xba, 0x44, 0x9f, 0xeb, 0x0a, 0x1b, 0xe1, 0x62, + 0x74, 0x94, 0x77, 0x43, 0x6b, 0x38, 0x6f, 0x93, + 0xa1, 0x8d, 0xed, 0x24, 0x53, 0xf5, 0x35, 0xbb, + 0x1e, 0xe7, 0x4f, 0x2b, 0xb3, 0x78, 0x74, 0x59, + 0xe9, 0x7c, 0xba, 0x77, 0xb4, 0xf8, 0x74, 0x32, + 0xa2, 0xdb, 0x87, 0x2f, 0xe1, 0x2a, 0x0e, 0x62, + 0x43, 0x3f, 0xb5, 0xfa, 0x2f, 0x7e, 0xe8, 0xe9, + 0x38, 0x74, 0xfd, 0x7e, 0xde, 0xd2, 0x83, 0xa6, + 0xba, 0x58, 0xdf, 0x54, 0x46, 0x7e, 0xde, 0x3d, + 0x41, 0xf3, 0xa7, 0xdf, 0xf0, 0x2e, 0x93, 0xa3, + 0xba, 0x3c, 0xfe, 0xe7, 0xe1, 0x67, 0xa5, 0x93, + 0xff, 0xf0, 0x3f, 0x76, 0xe6, 0xd8, 0x7b, 0x8d, + 0xeb, 0x7e, 0x9d, 0x3f, 0xff, 0xbf, 0x74, 0xbe, + 0xba, 0xdb, 0x29, 0xbf, 0xcf, 0x46, 0x77, 0x67, + 0x4f, 0xff, 0xff, 0xbd, 0x1e, 0x9c, 0x65, 0x2f, + 0x0c, 0xf3, 0xa5, 0x7d, 0x6a, 0x77, 0x7f, 0x1b, + 0xee, 0x74, 0xff, 0xfb, 0xd0, 0x0b, 0xd5, 0x77, + 0xfb, 0xe9, 0xbf, 0x18, 0xe8, 0xb4, 0x71, 0xee, + 0x11, 0x93, 0xff, 0xcf, 0x76, 0xdd, 0xb0, 0xb8, + 0x37, 0xaa, 0xe1, 0xd3, 0xff, 0xee, 0x6d, 0x5d, + 0x1d, 0xb4, 0xd5, 0x71, 0xf8, 0x14, 0x1d, 0x3f, + 0xd6, 0x34, 0x74, 0xf3, 0x31, 0xc3, 0xa7, 0xf8, + 0x28, 0x6a, 0x28, 0xf4, 0x28, 0x3a, 0x7f, 0xbd, + 0x1e, 0x95, 0xf7, 0xab, 0xd0, 0x3a, 0x18, 0xff, + 0x2a, 0x79, 0x3f, 0xfa, 0x8e, 0x95, 0xdf, 0xbd, + 0x35, 0x5a, 0xb0, 0x1d, 0x3f, 0xff, 0xeb, 0xa6, + 0xbf, 0xbe, 0x3a, 0x6e, 0xf5, 0x5b, 0xa3, 0xa5, + 0xff, 0x93, 0xa2, 0xd1, 0x87, 0xf5, 0x08, 0xa1, + 0x5e, 0xea, 0x46, 0x9b, 0x49, 0x3f, 0xd4, 0x14, + 0xb9, 0x58, 0x5b, 0xea, 0x1c, 0x93, 0xfe, 0xc0, + 0xdd, 0xe9, 0x87, 0xfe, 0x1d, 0x3f, 0xd7, 0xc5, + 0x2f, 0xaf, 0x4d, 0x7c, 0xe9, 0xff, 0xff, 0x32, + 0x32, 0xba, 0x39, 0xbf, 0x8f, 0x3d, 0x3b, 0x20, + 0xde, 0xec, 0xe8, 0x44, 0x74, 0x89, 0xe3, 0xb1, + 0xec, 0xf7, 0xf5, 0xf6, 0x3a, 0x7f, 0xff, 0xfe, + 0xd3, 0x28, 0x7f, 0xdf, 0x78, 0xe7, 0x41, 0xf5, + 0xdb, 0xa5, 0xd2, 0xfb, 0xf4, 0x7c, 0xa9, 0xd0, + 0xf4, 0x5b, 0x7c, 0x86, 0x19, 0x7a, 0x8e, 0xe7, + 0x0e, 0x7f, 0x1b, 0x06, 0x43, 0x9e, 0x7b, 0x55, + 0xcf, 0x0e, 0x9f, 0xfb, 0x7f, 0xe9, 0xf0, 0xf6, + 0x8c, 0x04, 0x3a, 0x7b, 0xfb, 0xca, 0x0e, 0x9e, + 0x74, 0xda, 0x63, 0xa7, 0xed, 0xe5, 0x1d, 0x1f, + 0xa3, 0xa7, 0xd8, 0x03, 0x4f, 0xce, 0x8f, 0x9e, + 0xb6, 0x8c, 0x22, 0xd3, 0x24, 0xee, 0x44, 0x88, + 0xdf, 0x22, 0xd3, 0xc4, 0xf7, 0x6f, 0x72, 0xa7, + 0x4f, 0xff, 0xdf, 0x0e, 0x97, 0xfb, 0x1e, 0xfb, + 0xfd, 0xaa, 0xd0, 0xe9, 0xff, 0xfe, 0xfd, 0x00, + 0xca, 0xaf, 0xad, 0xd1, 0x81, 0xb9, 0xdb, 0x28, + 0xe8, 0xb4, 0x61, 0x82, 0xdc, 0xff, 0xff, 0xe0, + 0x0f, 0xd1, 0xd3, 0x77, 0xa1, 0x67, 0x37, 0x74, + 0x35, 0x3a, 0xf5, 0x0e, 0x9f, 0xff, 0xf9, 0xbb, + 0xed, 0xba, 0x0d, 0xfb, 0xdf, 0xa5, 0x2f, 0xaf, + 0xc7, 0xb3, 0x50, 0x74, 0xfa, 0x9a, 0xfe, 0xc4, + 0xe8, 0xb4, 0x52, 0x7a, 0xfb, 0x1f, 0x4d, 0x0b, + 0x71, 0x8f, 0xcf, 0xfc, 0xfa, 0xff, 0xbe, 0xdb, + 0xf4, 0x37, 0x73, 0xa7, 0xf8, 0x7d, 0x70, 0x6f, + 0x79, 0xa3, 0xa7, 0xfb, 0x9d, 0xb7, 0x1c, 0xef, + 0x14, 0x74, 0xff, 0xff, 0x60, 0x6e, 0xf5, 0xfb, + 0x1a, 0x2a, 0xd6, 0x3c, 0xed, 0x8e, 0x9e, 0xd7, + 0x4a, 0x00, 0xe8, 0xa5, 0x10, 0xf8, 0xc7, 0x3f, + 0x39, 0x4b, 0xfd, 0x6d, 0x1d, 0x3f, 0xdb, 0xc5, + 0x0d, 0xef, 0x34, 0x74, 0xf5, 0x87, 0x9c, 0x1d, + 0x0c, 0x88, 0x8a, 0x98, 0x68, 0xda, 0x7e, 0xbd, + 0x00, 0x5b, 0xce, 0x9f, 0x86, 0xf6, 0x36, 0x87, + 0x4f, 0x0d, 0xd7, 0xa3, 0x87, 0xa7, 0xa2, 0xa8, + 0xe5, 0x70, 0xe1, 0x23, 0x63, 0xa4, 0xab, 0xe9, + 0x20, 0x71, 0xb8, 0x61, 0x6a, 0x15, 0x6e, 0xa1, + 0x05, 0x3f, 0xf0, 0x8d, 0xf4, 0x0b, 0xd8, 0xdb, + 0x87, 0x43, 0x2e, 0xf6, 0x5c, 0xe8, 0xfe, 0x42, + 0x2e, 0x7c, 0x2c, 0xac, 0xe4, 0xe9, 0xfd, 0x6e, + 0x6e, 0xf4, 0xdc, 0x9d, 0x3f, 0xff, 0xfd, 0xbb, + 0xd5, 0x71, 0xce, 0x83, 0x74, 0xbe, 0xfd, 0xa0, + 0x6f, 0x9d, 0xfd, 0xc3, 0xa6, 0xf7, 0xb9, 0xd0, + 0x08, 0x9c, 0xd4, 0x20, 0xe7, 0xeb, 0xa0, 0x6e, + 0x9a, 0x9d, 0x3f, 0xf8, 0x29, 0x7d, 0x6d, 0x54, + 0xb6, 0xf6, 0xc7, 0x4a, 0xa7, 0x47, 0xa7, 0xb5, + 0xd9, 0x2a, 0x7f, 0x32, 0x86, 0xf7, 0x9a, 0x3a, + 0x7b, 0xa2, 0x51, 0xc1, 0xd3, 0xff, 0xfe, 0xd0, + 0xb7, 0x94, 0xbe, 0xbe, 0xb6, 0x86, 0xf9, 0xfd, + 0x83, 0x87, 0x47, 0xd5, 0x45, 0xb8, 0x4d, 0x90, + 0xcf, 0x12, 0x7a, 0xc2, 0x1f, 0xd2, 0x57, 0x46, + 0x1d, 0x89, 0x67, 0xcf, 0xf8, 0x5d, 0x27, 0x4f, + 0xae, 0xb4, 0x5f, 0x07, 0x45, 0x27, 0x9f, 0xb2, + 0x79, 0xff, 0xf7, 0xe8, 0xb4, 0xe7, 0x7f, 0xbe, + 0xfd, 0x3b, 0xfa, 0xc7, 0x4f, 0x3b, 0x6a, 0xf6, + 0x74, 0xff, 0xff, 0xce, 0xd4, 0xbf, 0x29, 0xe8, + 0x3e, 0xbb, 0x74, 0xba, 0x5f, 0x7e, 0x8f, 0x95, + 0x3a, 0x28, 0x45, 0x2d, 0x92, 0x4f, 0xff, 0xff, + 0x9a, 0x9a, 0xfa, 0xd4, 0xf4, 0xdd, 0xf3, 0xd0, + 0x6f, 0xde, 0xfd, 0x2b, 0xe7, 0x9f, 0xd1, 0xd3, + 0xe6, 0x1a, 0x72, 0x83, 0xa7, 0xff, 0xff, 0xff, + 0x5a, 0xad, 0x1b, 0x6c, 0xad, 0x5d, 0x6a, 0xc0, + 0x0c, 0x37, 0x45, 0xfb, 0x5f, 0x5c, 0x16, 0x51, + 0xd3, 0xfd, 0xe5, 0xf2, 0x37, 0xbc, 0xd1, 0xd3, + 0xfa, 0x8f, 0x5b, 0x4a, 0xfe, 0x8e, 0x9f, 0xf3, + 0x77, 0x76, 0xf6, 0xc5, 0xce, 0xca, 0x3a, 0x2c, + 0xfe, 0xe9, 0x35, 0x9f, 0xfe, 0xbd, 0x73, 0x77, + 0xe5, 0x7a, 0x05, 0x79, 0xa9, 0xd3, 0xd4, 0x7c, + 0x74, 0x74, 0x32, 0xbe, 0xcb, 0x23, 0xfc, 0x60, + 0x40, 0x46, 0xa8, 0x49, 0x6c, 0x9f, 0x21, 0x42, + 0x30, 0xb3, 0xa9, 0x17, 0xaa, 0x73, 0xb9, 0xe8, + 0xe1, 0xd3, 0xff, 0xd4, 0xbc, 0x5b, 0xa2, 0x85, + 0xbb, 0xeb, 0xf4, 0x1d, 0x16, 0x7e, 0x9f, 0x20, + 0x9f, 0xa8, 0x71, 0xfd, 0x60, 0x50, 0x74, 0xf9, + 0x5f, 0xe6, 0xf9, 0x3a, 0x4e, 0x1d, 0x33, 0x28, + 0xe9, 0x68, 0xe8, 0x03, 0x4b, 0x82, 0xb1, 0xc9, + 0xea, 0xec, 0xda, 0x7b, 0x55, 0xca, 0x4e, 0x99, + 0xcc, 0x3a, 0x7f, 0x6f, 0xe1, 0x4b, 0xc5, 0x8e, + 0x8e, 0xb6, 0x9a, 0x03, 0x1a, 0xdb, 0xf7, 0xc8, + 0xd4, 0x45, 0xe8, 0xb4, 0xfe, 0xaf, 0xe9, 0xe3, + 0x07, 0xc3, 0xa7, 0xff, 0xcc, 0x0c, 0x96, 0xa6, + 0x47, 0xfe, 0xbe, 0xa8, 0xe8, 0x71, 0x10, 0xfd, + 0x46, 0xb3, 0xf0, 0x5b, 0x77, 0x61, 0x3a, 0x70, + 0xe2, 0x8e, 0x9b, 0xc6, 0x3a, 0x1e, 0x7b, 0x7f, + 0x2b, 0x11, 0xa8, 0x77, 0x9d, 0x94, 0x7f, 0x59, + 0x0f, 0x16, 0x94, 0xc1, 0x43, 0xe3, 0xcb, 0x79, + 0x95, 0x31, 0x73, 0xc4, 0xbd, 0xe1, 0x72, 0x92, + 0xfa, 0xa9, 0x8e, 0x97, 0xf1, 0x84, 0xb9, 0x0d, + 0xa0, 0x94, 0x9c, 0xa8, 0xd1, 0x77, 0x3d, 0xc9, + 0x91, 0xba, 0x0c, 0xf1, 0xbd, 0x65, 0x64, 0x6a, + 0x72, 0xf1, 0xd4, 0x62, 0x5d, 0x51, 0xb0, 0xf6, + 0x87, 0x23, 0xb4, 0x20, 0xa7, 0xff, 0xef, 0x51, + 0x74, 0xe8, 0x1a, 0xe9, 0xeb, 0x39, 0xcc, 0xee, + 0x74, 0x2d, 0x51, 0x8f, 0xe3, 0xce, 0x9f, 0xcb, + 0xb0, 0x4c, 0xc4, 0x34, 0x53, 0xb3, 0xe0, 0x4c, + 0xc4, 0x34, 0x54, 0x73, 0xfe, 0xc7, 0xae, 0xc1, + 0x33, 0x10, 0xd1, 0x34, 0x49, 0x76, 0x7e, 0xca, + 0x30, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, 0x34, 0x55, + 0xf3, 0xe0, 0x4c, 0xc4, 0x34, 0x56, 0xd3, 0xfc, + 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x24, 0x19, 0x2e, + 0xcf, 0xc7, 0x0c, 0x27, 0xfe, 0x5e, 0x3d, 0x76, + 0x09, 0x98, 0x86, 0x89, 0x0e, 0x7f, 0xcf, 0xdb, + 0x6a, 0xae, 0xee, 0xae, 0xf0, 0x9d, 0x3e, 0xbb, + 0x1f, 0x2a, 0x74, 0xf8, 0x13, 0x31, 0x0d, 0x16, + 0x24, 0xfa, 0xc1, 0x87, 0xb9, 0xd3, 0xee, 0xdd, + 0x56, 0x0c, 0x74, 0xea, 0xb0, 0x9d, 0x2d, 0xb1, + 0xe2, 0x7c, 0xaa, 0x7f, 0xe6, 0xba, 0xd8, 0xf3, + 0xff, 0x18, 0x4e, 0x9c, 0x2d, 0x41, 0xd2, 0x78, + 0x9e, 0xef, 0xa8, 0x53, 0xba, 0xbf, 0xe1, 0xd3, + 0xef, 0xba, 0xf7, 0x2a, 0x74, 0xff, 0xce, 0xbd, + 0xba, 0x79, 0x75, 0xbb, 0xc7, 0x0e, 0x99, 0x9e, + 0x74, 0x59, 0xf0, 0x02, 0x5c, 0xfe, 0xb0, 0x7f, + 0x97, 0x6e, 0x1d, 0x3e, 0xc7, 0xf6, 0xdb, 0x1d, + 0x3f, 0x56, 0xa1, 0xfe, 0x3a, 0xe7, 0x43, 0x22, + 0x33, 0xe6, 0x58, 0x51, 0x3f, 0xfc, 0xf6, 0x53, + 0x3f, 0x91, 0x6d, 0xe5, 0x81, 0xd3, 0xf9, 0x06, + 0xdd, 0x0d, 0xd4, 0xe8, 0xa4, 0xff, 0x76, 0x99, + 0x3f, 0xbc, 0x6b, 0xd7, 0xc7, 0x82, 0xa7, 0xd7, + 0xba, 0x73, 0xae, 0x74, 0xf7, 0x95, 0x61, 0x3a, + 0x7f, 0x06, 0xf3, 0xf5, 0xfb, 0xa3, 0xa1, 0x8f, + 0x56, 0xc8, 0x60, 0x51, 0x41, 0x58, 0x40, 0x4f, + 0xd9, 0x46, 0x9a, 0x97, 0x9d, 0x3f, 0xe1, 0x6f, + 0xf3, 0xa1, 0xca, 0x6a, 0x74, 0x3b, 0xcb, 0xa7, + 0xfc, 0xa4, 0xd9, 0x37, 0x73, 0x04, 0x6a, 0xa6, + 0x10, 0x9f, 0x28, 0x70, 0x80, 0x21, 0x15, 0xb8, + 0x56, 0x64, 0x2a, 0xfc, 0x23, 0xac, 0x34, 0xf4, + 0x4f, 0xd8, 0xba, 0x7f, 0xed, 0xfd, 0xb5, 0xbc, + 0xef, 0x63, 0xe1, 0xd3, 0xff, 0xd7, 0x4b, 0xf5, + 0xed, 0x0b, 0xde, 0x2b, 0xf5, 0x3a, 0x6d, 0xae, + 0xd1, 0x30, 0x28, 0xb0, 0xb4, 0xed, 0x9a, 0x38, + 0x99, 0xfc, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0x9b, + 0x35, 0xf2, 0x74, 0xff, 0xb1, 0xeb, 0xb0, 0x4c, + 0xc4, 0x34, 0x50, 0x12, 0x5d, 0x9e, 0xe2, 0x85, + 0xa6, 0xf7, 0x67, 0x4f, 0xd5, 0x65, 0x0b, 0x38, + 0x74, 0xfd, 0x7a, 0xf3, 0xb0, 0xb8, 0x74, 0x78, + 0x7b, 0x82, 0x59, 0x37, 0x4a, 0x9d, 0x3f, 0xdb, + 0xb0, 0xd0, 0xb2, 0xaa, 0x74, 0xf2, 0x66, 0x21, + 0xa2, 0xdf, 0x9f, 0xbb, 0x6b, 0x13, 0x00, 0xe8, + 0x03, 0xd7, 0xf0, 0xae, 0x7d, 0xa7, 0xd7, 0xb5, + 0x4e, 0x9f, 0x9d, 0x76, 0xd0, 0xb7, 0x87, 0x4f, + 0xb9, 0x6e, 0xbf, 0xaa, 0x3a, 0x18, 0xf7, 0xbe, + 0x63, 0x3d, 0x9f, 0x1d, 0x1d, 0x3f, 0xbd, 0xa6, + 0xac, 0x96, 0xa3, 0xa7, 0xb7, 0xdf, 0x95, 0x1d, + 0x35, 0xbc, 0xe8, 0xb3, 0x74, 0x24, 0xb2, 0x5b, + 0xbc, 0xaa, 0xc5, 0x9c, 0xde, 0x45, 0xc8, 0xc5, + 0xc2, 0x34, 0x08, 0xb7, 0x08, 0x8f, 0x08, 0x44, + 0x83, 0x4d, 0xb3, 0xfe, 0xc7, 0xae, 0xc1, 0x33, + 0x10, 0xd1, 0x4a, 0x4f, 0xf3, 0xd7, 0x60, 0x99, + 0x88, 0x68, 0x93, 0xa4, 0xb5, 0x22, 0x1f, 0x11, + 0xa1, 0x9f, 0x12, 0x66, 0x88, 0xda, 0xb9, 0xb6, + 0xa6, 0x56, 0x56, 0x90, 0xb1, 0xf9, 0x3f, 0x5e, + 0x15, 0x8e, 0x13, 0x2a, 0x7d, 0x07, 0x65, 0x3e, + 0x42, 0x5e, 0xb2, 0xb6, 0x1d, 0x46, 0x4f, 0x3e, + 0x04, 0xcc, 0x43, 0x44, 0x3f, 0x3f, 0xec, 0x7a, + 0xec, 0x13, 0x31, 0x0d, 0x12, 0x9c, 0x97, 0x67, + 0xec, 0xa3, 0x09, 0xfc, 0xbb, 0x04, 0xcc, 0x43, + 0x44, 0x4f, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, + 0x8c, 0x67, 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, + 0x62, 0x1a, 0x27, 0x98, 0x64, 0x77, 0xd0, 0x4e, + 0xf3, 0xbd, 0x9d, 0xcf, 0x81, 0x33, 0x10, 0xd1, + 0x10, 0x4f, 0xfb, 0x1e, 0xbb, 0x04, 0xcc, 0x43, + 0x44, 0xa9, 0x25, 0xd9, 0xfb, 0x28, 0xc2, 0x7f, + 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x14, 0x4f, 0xe5, + 0xd8, 0x26, 0x62, 0x1a, 0x23, 0x29, 0xff, 0xcb, + 0x56, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0x96, + 0x7f, 0x2e, 0xc1, 0x33, 0x10, 0xd1, 0x52, 0x4f, + 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x2b, 0xa9, 0xfc, + 0xbb, 0x04, 0xcc, 0x43, 0x45, 0x8b, 0x3f, 0xf2, + 0xb1, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x4f, 0x53, + 0xfd, 0xc2, 0xf1, 0xbf, 0xd5, 0xf7, 0x63, 0xa1, + 0x68, 0x8b, 0x64, 0xc9, 0xfb, 0xad, 0x7b, 0xd7, + 0xfd, 0xa9, 0xd3, 0xc0, 0xad, 0x52, 0x74, 0xe4, + 0xbd, 0x95, 0x39, 0x4d, 0x53, 0xa7, 0xff, 0xed, + 0x8e, 0x77, 0xf8, 0x33, 0xdf, 0x75, 0xf3, 0xc6, + 0x3a, 0x7f, 0xfe, 0x0f, 0xbb, 0x62, 0x96, 0xc0, + 0x1f, 0x76, 0x4f, 0x68, 0x3a, 0x7c, 0x9f, 0xdf, + 0x65, 0x1d, 0x3f, 0xfb, 0x2a, 0x37, 0xe2, 0xf7, + 0xf4, 0xc0, 0x3a, 0x7d, 0xad, 0xb2, 0x90, 0xe9, + 0xff, 0xc3, 0xd1, 0x98, 0x59, 0x5d, 0x3a, 0x6f, + 0xa8, 0xe9, 0xb2, 0x93, 0xa7, 0xf6, 0x57, 0x37, + 0xe8, 0xd0, 0x74, 0x09, 0xe4, 0xfa, 0x2d, 0x14, + 0x2a, 0x28, 0xf8, 0xd8, 0x2e, 0x29, 0x83, 0x65, + 0x22, 0x8f, 0xa2, 0x67, 0x68, 0x4c, 0xce, 0x1c, + 0xd1, 0xd3, 0x87, 0xf5, 0x3a, 0x5c, 0x3b, 0xe6, + 0xd5, 0x86, 0xa7, 0x81, 0xd6, 0x28, 0xe8, 0xb3, + 0xce, 0xf9, 0x64, 0xff, 0xbf, 0xbc, 0xd3, 0x39, + 0x5f, 0xa8, 0xe9, 0xf0, 0xf7, 0xfd, 0xd4, 0xe9, + 0xff, 0xaf, 0x8c, 0xf2, 0xd3, 0x79, 0xe5, 0x4e, + 0x8f, 0x9f, 0x60, 0x94, 0x4e, 0x53, 0x6c, 0xe9, + 0xe1, 0xe7, 0xa7, 0x73, 0xa7, 0xeb, 0xaf, 0x18, + 0x34, 0x1d, 0x16, 0x7d, 0xd8, 0x36, 0x24, 0xd3, + 0xef, 0x7b, 0xd7, 0x96, 0x3a, 0x2d, 0x1c, 0xdf, + 0x84, 0x7e, 0xcb, 0x27, 0xff, 0xff, 0x6d, 0xbe, + 0x00, 0xdd, 0xb5, 0xf1, 0xf5, 0xf7, 0x5e, 0x7d, + 0xc0, 0x79, 0xd3, 0xea, 0x39, 0x0f, 0xf0, 0x74, + 0xfd, 0xce, 0x07, 0x9d, 0x56, 0x74, 0xff, 0x87, + 0xef, 0xd6, 0xec, 0x3f, 0x53, 0xa7, 0xfd, 0x97, + 0xe3, 0x0e, 0x73, 0x7d, 0xce, 0x87, 0x9f, 0xdf, + 0x87, 0xb3, 0xfb, 0x29, 0xae, 0xb5, 0x7d, 0x73, + 0xa7, 0xff, 0x35, 0xd3, 0xad, 0xb6, 0x85, 0xbc, + 0xa9, 0xd3, 0xab, 0xb5, 0x1d, 0x1a, 0x3e, 0x5f, + 0x52, 0x67, 0xef, 0x6b, 0xaa, 0xde, 0x8e, 0x9d, + 0xc7, 0x1c, 0x15, 0x3f, 0xfb, 0x5f, 0xd5, 0x77, + 0xfe, 0xae, 0xc0, 0xcf, 0x29, 0x65, 0xfc, 0x7d, + 0x15, 0x7e, 0xa6, 0xc3, 0xd5, 0x7f, 0xdb, 0xcf, + 0xca, 0x82, 0x15, 0x6a, 0x23, 0x18, 0x4e, 0x6a, + 0x19, 0xd3, 0xfd, 0x4b, 0xeb, 0x5b, 0xe7, 0x34, + 0x74, 0xac, 0xe8, 0x63, 0xc9, 0xee, 0x75, 0x3e, + 0xe3, 0x4d, 0x4f, 0x07, 0x4e, 0x4e, 0x36, 0x74, + 0xfe, 0x6c, 0x0d, 0xf1, 0x9c, 0x95, 0x37, 0x1c, + 0x15, 0x1c, 0x9e, 0x57, 0x06, 0x53, 0xb5, 0xfe, + 0xb9, 0x4b, 0x34, 0x93, 0xde, 0xbf, 0xdd, 0x1d, + 0x15, 0x3d, 0x4e, 0xa3, 0x09, 0xb8, 0xa9, 0xd2, + 0xb3, 0xa5, 0x4d, 0x9a, 0x6d, 0x0b, 0xcf, 0xfd, + 0x5a, 0xf2, 0x2d, 0xce, 0xdb, 0x55, 0x3a, 0x18, + 0xfb, 0x3d, 0x27, 0x9f, 0xf6, 0xbe, 0x19, 0xe3, + 0xb6, 0xaf, 0x67, 0x4f, 0xec, 0x0d, 0x54, 0x7f, + 0xdc, 0xe8, 0x7a, 0x25, 0xbe, 0x45, 0x88, 0x33, + 0xd4, 0x5f, 0xc0, 0xe9, 0xff, 0x35, 0x3b, 0x65, + 0x26, 0xfe, 0xe1, 0xd1, 0x67, 0xc0, 0x04, 0x33, + 0xf6, 0x98, 0x39, 0xb1, 0x3a, 0x7f, 0x73, 0xb6, + 0x1e, 0x32, 0x93, 0xa7, 0xfe, 0xff, 0x3b, 0x64, + 0x6f, 0x30, 0x7c, 0x3a, 0x7f, 0xff, 0xdf, 0x56, + 0x0d, 0x2f, 0x5f, 0x17, 0xf7, 0x56, 0x37, 0xce, + 0x3c, 0xf1, 0x7a, 0xc3, 0x26, 0x3d, 0x85, 0x75, + 0x34, 0xf5, 0x12, 0x7f, 0xfa, 0xf5, 0x5b, 0x73, + 0x6c, 0xea, 0xf7, 0xb6, 0x3a, 0x7f, 0xff, 0xfd, + 0xfb, 0xa6, 0xbf, 0xbe, 0x3a, 0x5d, 0x2f, 0xaf, + 0xf5, 0x5f, 0xd3, 0xcf, 0x3e, 0xd0, 0x74, 0xff, + 0xfb, 0xe3, 0xcf, 0x4e, 0xda, 0xfd, 0x73, 0xe3, + 0xeb, 0xce, 0x81, 0x4c, 0xeb, 0x4a, 0x0e, 0xa1, + 0x1f, 0x36, 0x72, 0x74, 0xfc, 0x19, 0x5d, 0xe3, + 0xce, 0x95, 0x27, 0x4d, 0xfe, 0x0e, 0x9b, 0xb7, + 0x87, 0x43, 0x86, 0xc3, 0xc1, 0x79, 0xcf, 0xce, + 0x4e, 0x9b, 0x8e, 0x0e, 0x87, 0xa3, 0x66, 0xc5, + 0x90, 0xaf, 0xe8, 0x35, 0x23, 0xe0, 0x72, 0x76, + 0xbb, 0x78, 0x52, 0xcf, 0x5a, 0x7f, 0xff, 0xf6, + 0x9b, 0x9d, 0xfb, 0x9d, 0xd5, 0x9c, 0xdd, 0x8f, + 0x7a, 0xd6, 0xc7, 0xc3, 0xa2, 0x94, 0x56, 0x7c, + 0xc2, 0x7f, 0xaf, 0x5b, 0x60, 0xd5, 0xa1, 0xd3, + 0x98, 0x1c, 0x3a, 0x2d, 0x54, 0x36, 0x4a, 0x12, + 0x12, 0x4e, 0xa3, 0x59, 0xd5, 0xc7, 0x0e, 0x9e, + 0xbd, 0x63, 0xb1, 0xd1, 0x49, 0xbf, 0x11, 0xc9, + 0xff, 0xac, 0x02, 0xdc, 0xdd, 0xd7, 0x04, 0xe9, + 0xfc, 0x2c, 0x1e, 0xa6, 0xd8, 0xe9, 0xf7, 0xfb, + 0xef, 0x1e, 0x74, 0xfd, 0xf6, 0x55, 0x17, 0xc1, + 0xd3, 0x71, 0xc1, 0xd0, 0x87, 0xde, 0x05, 0x3c, + 0x17, 0x4f, 0xf5, 0xb9, 0x8e, 0x65, 0x2f, 0xa9, + 0x4b, 0x35, 0xd3, 0xfd, 0x77, 0xe5, 0xb8, 0xd4, + 0xd4, 0xe9, 0xff, 0xd6, 0x3e, 0x5e, 0xff, 0x4d, + 0x77, 0xed, 0x4e, 0x9f, 0x87, 0x3c, 0xe6, 0xc4, + 0xe9, 0xf9, 0x5f, 0xea, 0xb0, 0xee, 0x74, 0xee, + 0x38, 0xe0, 0xa9, 0xff, 0x98, 0x07, 0xdc, 0xed, + 0x6e, 0x32, 0x8e, 0x59, 0x7f, 0x1d, 0x75, 0x4d, + 0x6e, 0x43, 0x34, 0x52, 0xaa, 0x73, 0xa4, 0xcf, + 0x4b, 0x38, 0x50, 0x9f, 0xff, 0x67, 0x37, 0x63, + 0xdf, 0xb0, 0xb0, 0xd1, 0xf0, 0x3a, 0x76, 0x05, + 0x07, 0x90, 0x4a, 0x79, 0xf7, 0x4b, 0xcf, 0x20, + 0x94, 0xea, 0xff, 0x93, 0xc8, 0x25, 0x37, 0x1c, + 0x1e, 0x41, 0x28, 0x44, 0x53, 0x38, 0x51, 0xa2, + 0xfe, 0x0a, 0xa6, 0xcd, 0x16, 0x41, 0x22, 0xcd, + 0xf4, 0xfd, 0x7b, 0xbb, 0x1e, 0xe7, 0x4e, 0xc1, + 0xf1, 0x49, 0xcc, 0x8c, 0x67, 0x5a, 0x33, 0x9e, + 0xea, 0xbc, 0xd9, 0xd2, 0xbe, 0xb9, 0xf5, 0x78, + 0x8f, 0x3f, 0x9c, 0x7f, 0xb4, 0x6b, 0xf4, 0x15, + 0x3f, 0xbe, 0xff, 0x72, 0xbb, 0xf9, 0xd2, 0x79, + 0x53, 0xb0, 0x28, 0x2a, 0x0a, 0x86, 0x36, 0xa8, + 0x20, 0xa1, 0xb9, 0xe1, 0x6f, 0x10, 0xa5, 0x9a, + 0xc8, 0x64, 0x62, 0xdc, 0x25, 0x67, 0xbd, 0xc0, + 0x79, 0xd2, 0x51, 0xd3, 0x5b, 0xf9, 0x36, 0x2e, + 0x10, 0xcf, 0xb8, 0xb7, 0x3e, 0xa3, 0xa7, 0xe4, + 0x67, 0x1e, 0xde, 0x15, 0x2f, 0x9d, 0x3f, 0xd4, + 0x7a, 0xfe, 0x77, 0xee, 0x09, 0xd3, 0xf7, 0xd9, + 0x54, 0x5f, 0x07, 0x4f, 0xae, 0x85, 0x5a, 0x8e, + 0x9d, 0x5f, 0x81, 0xd0, 0x27, 0x85, 0xa2, 0x79, + 0xf8, 0x73, 0xcf, 0x3d, 0xa9, 0xd3, 0xf7, 0xfb, + 0xf6, 0x65, 0x2f, 0x94, 0xc3, 0x2c, 0x40, 0x0f, + 0x2a, 0xe1, 0xa2, 0x18, 0xb4, 0xf4, 0xfe, 0x52, + 0x31, 0x9c, 0xcf, 0x0d, 0xd1, 0xe9, 0xd0, 0xf5, + 0x7b, 0x16, 0x59, 0xb8, 0x7e, 0x8a, 0xbd, 0x65, + 0x00, 0xe8, 0xd6, 0x7f, 0xfd, 0x40, 0x05, 0xf3, + 0x8a, 0xde, 0x68, 0x59, 0xc3, 0xa7, 0xff, 0xff, + 0x7a, 0x1e, 0xb8, 0x39, 0xe5, 0x6b, 0x7d, 0xef, + 0xd0, 0xce, 0x5b, 0x6c, 0x74, 0xee, 0x38, 0xe0, + 0xa9, 0x9e, 0xc5, 0x2c, 0xbf, 0x86, 0x4c, 0x4a, + 0x85, 0x40, 0x84, 0xd4, 0xfd, 0x43, 0x8f, 0xeb, + 0x02, 0x83, 0xa7, 0xb7, 0x94, 0xf0, 0x74, 0xfa, + 0x80, 0xfb, 0x28, 0xe9, 0xff, 0xe6, 0xed, 0xa1, + 0x6f, 0x33, 0x5e, 0x76, 0x17, 0x9d, 0x1d, 0x6d, + 0x1a, 0x5f, 0x35, 0xc2, 0x3d, 0x13, 0xce, 0xed, + 0xcb, 0x87, 0x4e, 0x7f, 0xc4, 0xe9, 0xfb, 0x4c, + 0xe0, 0xfb, 0x53, 0xa2, 0x83, 0xe9, 0x79, 0x06, + 0x86, 0xe6, 0xca, 0x9d, 0x37, 0xae, 0xe1, 0xd0, + 0x26, 0xc7, 0xd1, 0x59, 0xb1, 0x6e, 0xf3, 0x7d, + 0x80, 0xee, 0x8d, 0xfa, 0xd6, 0x22, 0x69, 0x48, + 0x54, 0x43, 0xf5, 0xe4, 0x3c, 0xc7, 0x23, 0x72, + 0xcc, 0xfb, 0xc2, 0xed, 0x08, 0xe9, 0x2a, 0xfc, + 0x37, 0x9c, 0x8d, 0x34, 0x21, 0x1e, 0xa8, 0xcf, + 0xb7, 0x2f, 0xf7, 0x21, 0x0a, 0x24, 0x35, 0x95, + 0x57, 0xa9, 0xe4, 0xcf, 0x63, 0x75, 0xea, 0x8c, + 0x1f, 0xb4, 0x2a, 0xdd, 0x98, 0x67, 0xff, 0x2d, + 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x28, 0xa9, + 0xfc, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0xd1, 0x3f, + 0xf2, 0xf1, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x49, + 0x73, 0xf9, 0x76, 0x09, 0x98, 0x86, 0x8b, 0xca, + 0x19, 0xd1, 0xf7, 0xd0, 0x4e, 0xf3, 0xbb, 0x3b, + 0x45, 0x27, 0x0e, 0xd4, 0x77, 0xb8, 0x63, 0x0d, + 0x7d, 0xc5, 0x58, 0xf3, 0xb4, 0xa5, 0xe9, 0xdb, + 0xa4, 0xc9, 0xff, 0xcb, 0x56, 0x3d, 0x76, 0x09, + 0x98, 0x86, 0x89, 0x66, 0x6f, 0x76, 0x74, 0xf2, + 0x66, 0x21, 0xa2, 0x33, 0x9f, 0xbe, 0xca, 0xa2, + 0xf8, 0x3a, 0x61, 0x79, 0xd2, 0x51, 0xd3, 0xef, + 0x86, 0xf1, 0x60, 0x7a, 0x6a, 0x2e, 0xec, 0x2b, + 0x3f, 0x63, 0xfe, 0x18, 0x07, 0x4f, 0xfd, 0x5f, + 0xfb, 0x5b, 0x1f, 0x5f, 0x75, 0x3a, 0x75, 0x5a, + 0x93, 0xa0, 0x13, 0x55, 0x53, 0xf0, 0xa6, 0x54, + 0xab, 0x48, 0xb3, 0xff, 0x6b, 0xe1, 0x9e, 0x74, + 0xa5, 0xec, 0xa3, 0xa7, 0xc2, 0xcf, 0xae, 0x1d, + 0x1f, 0x3e, 0xc7, 0x48, 0xf3, 0xb3, 0xb3, 0xce, + 0x9f, 0xfe, 0xf7, 0x55, 0xa5, 0xec, 0x3e, 0x57, + 0xa7, 0xa2, 0x74, 0xe6, 0xd3, 0x1d, 0x2f, 0xf2, + 0x7d, 0xee, 0x95, 0x67, 0xfe, 0xb5, 0x6b, 0xfc, + 0x55, 0xb7, 0x9d, 0x73, 0xa7, 0xfd, 0xb6, 0xfe, + 0xfe, 0xc2, 0xe7, 0xa7, 0x4f, 0xeb, 0xab, 0x6a, + 0xbb, 0xf9, 0xd2, 0x5b, 0xbc, 0xae, 0xd6, 0xe3, + 0x6c, 0x72, 0x16, 0xbb, 0x24, 0xc8, 0x46, 0x09, + 0x5d, 0x52, 0x3a, 0x8f, 0xe7, 0xff, 0x2d, 0x58, + 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x26, 0x99, 0xff, + 0xcb, 0x56, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, + 0xc6, 0x7f, 0xf2, 0xd5, 0x8f, 0x5d, 0x82, 0x66, + 0x21, 0xa2, 0x81, 0x9f, 0x02, 0x66, 0x21, 0xa2, + 0xe0, 0x99, 0xbe, 0x74, 0xfe, 0x17, 0xb7, 0xf9, + 0xb5, 0x1d, 0x25, 0xd9, 0xfb, 0xec, 0xc3, 0xd1, + 0x59, 0xfd, 0xf5, 0xf6, 0x6f, 0x2f, 0x83, 0xa7, + 0xf9, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x49, 0x32, + 0x5e, 0xcf, 0xdf, 0x0d, 0xa2, 0x85, 0xed, 0x67, + 0xce, 0x03, 0xa4, 0x23, 0xdc, 0x52, 0xf1, 0x4a, + 0xb0, 0xc9, 0xd4, 0x2b, 0x27, 0xfd, 0xdf, 0x17, + 0x60, 0x99, 0x88, 0x68, 0xb5, 0x27, 0xfd, 0x8f, + 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x55, 0x83, 0xa4, + 0xbe, 0xe8, 0x98, 0x52, 0x43, 0xb2, 0x34, 0xfe, + 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x29, 0x9f, 0xcb, + 0xb0, 0x4c, 0xc4, 0x34, 0x46, 0x93, 0x7b, 0xb3, + 0xa7, 0x93, 0x31, 0x0d, 0x14, 0xfc, 0xda, 0x63, + 0xa0, 0x0f, 0x03, 0x45, 0x73, 0xff, 0x7b, 0xa0, + 0xf5, 0xca, 0xa6, 0x39, 0x53, 0xa7, 0xfe, 0xb7, + 0x3d, 0x1a, 0x2a, 0x98, 0xe5, 0x4e, 0x92, 0xdd, + 0xe4, 0xc1, 0x6d, 0x5c, 0x48, 0x74, 0x8f, 0x3f, + 0xf9, 0x6a, 0xc7, 0xae, 0xc1, 0x33, 0x10, 0xd1, + 0x35, 0x4f, 0xe5, 0xd8, 0x26, 0x62, 0x1a, 0x2b, + 0xb9, 0xe4, 0xcc, 0x43, 0x45, 0x7d, 0x3b, 0x8e, + 0x38, 0x2a, 0x42, 0x52, 0xcb, 0xf8, 0x03, 0xe8, + 0x52, 0x54, 0xe7, 0xb5, 0x27, 0x4f, 0xfa, 0xf7, + 0xc6, 0x6a, 0xad, 0x74, 0x1d, 0x2d, 0x1d, 0x3f, + 0xdf, 0x0b, 0xa3, 0xef, 0xbe, 0x4e, 0x80, 0x3c, + 0x9c, 0x10, 0x92, 0xed, 0x1c, 0x8e, 0x10, 0x88, + 0xe5, 0x61, 0x0f, 0x3f, 0xf9, 0x6a, 0xc7, 0xae, + 0xc1, 0x33, 0x10, 0xd1, 0x3d, 0xcf, 0xe5, 0xd8, + 0x26, 0x62, 0x1a, 0x2e, 0x19, 0xff, 0x97, 0x8f, + 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x4f, 0x86, 0x5c, + 0xf6, 0xa0, 0xed, 0xe7, 0x7d, 0xe3, 0x40, 0x44, + 0x77, 0x14, 0x82, 0x38, 0x7d, 0xa3, 0xd5, 0x49, + 0xd1, 0xdc, 0xfe, 0x5d, 0x82, 0x66, 0x21, 0xa2, + 0x2a, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, 0x34, 0x53, + 0x33, 0xff, 0x96, 0xac, 0x7a, 0xec, 0x13, 0x31, + 0x0d, 0x13, 0x3c, 0xff, 0xe5, 0xab, 0x1e, 0xbb, + 0x04, 0xcc, 0x43, 0x45, 0x1b, 0x14, 0x26, 0x35, + 0xc9, 0xdf, 0x73, 0xbd, 0x29, 0x4f, 0xfc, 0xbc, + 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x11, 0xd4, 0xde, + 0xec, 0xe9, 0xfb, 0xf6, 0x3c, 0xdd, 0x07, 0x4f, + 0x81, 0x33, 0x10, 0xd1, 0x4d, 0x4f, 0xfe, 0xdf, + 0xf5, 0x5c, 0xa6, 0xdc, 0x6d, 0xd4, 0xe9, 0xff, + 0x9f, 0xbf, 0x8d, 0x15, 0xf5, 0x81, 0xc3, 0xa6, + 0x6e, 0xe7, 0x4f, 0xdf, 0x65, 0x51, 0x7c, 0x1d, + 0x3f, 0xfd, 0x7a, 0xdd, 0xbc, 0x30, 0x75, 0xbc, + 0x79, 0xd3, 0x37, 0x87, 0x4f, 0xec, 0xa5, 0x93, + 0xe8, 0xb0, 0x44, 0x80, 0x97, 0x76, 0x4c, 0x8d, + 0xa3, 0xfa, 0xb0, 0xa7, 0x92, 0xdd, 0xe5, 0x45, + 0x7c, 0x8b, 0xd9, 0x6a, 0x18, 0x52, 0x97, 0xa8, + 0xd1, 0x27, 0xc0, 0x99, 0x88, 0x68, 0xaa, 0xa7, + 0xfd, 0x8f, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x6d, + 0x92, 0xec, 0xfd, 0x94, 0x61, 0x3f, 0x97, 0x60, + 0x99, 0x88, 0x68, 0xaf, 0xe7, 0xf2, 0xec, 0x13, + 0x31, 0x0d, 0x16, 0x34, 0xf8, 0x13, 0x31, 0x0d, + 0x16, 0xac, 0xff, 0xb1, 0xeb, 0xb0, 0x4c, 0xc4, + 0x34, 0x50, 0x52, 0x5d, 0x9f, 0xb2, 0x8c, 0x27, + 0xc0, 0x99, 0x88, 0x68, 0xb8, 0xa7, 0xb1, 0xdb, + 0xf4, 0x1d, 0x3c, 0xec, 0xed, 0xf4, 0x3a, 0x7f, + 0x32, 0xb1, 0xd3, 0x03, 0xb1, 0xd2, 0x5d, 0xa2, + 0xc7, 0x66, 0x18, 0x4b, 0xa2, 0x79, 0xf0, 0x26, + 0x62, 0x1a, 0x2e, 0x99, 0xf3, 0x0e, 0x72, 0xc7, + 0x49, 0x76, 0x7a, 0xbf, 0x30, 0x9f, 0xff, 0x94, + 0xbb, 0x7b, 0x07, 0x9d, 0x2b, 0xb6, 0x56, 0x09, + 0xd3, 0xff, 0xf6, 0xc7, 0xdc, 0xeb, 0xdb, 0xf7, + 0x7d, 0xef, 0x97, 0x3d, 0x3a, 0x64, 0xb3, 0xa1, + 0x8f, 0xdf, 0xbb, 0x1c, 0xff, 0x9f, 0x60, 0x18, + 0xfa, 0x2f, 0x83, 0xa7, 0x0e, 0x2c, 0x0f, 0x83, + 0x44, 0x73, 0xfe, 0x06, 0xa7, 0x79, 0x5d, 0x37, + 0x07, 0x4d, 0xee, 0xce, 0x9f, 0x0d, 0xef, 0x34, + 0x74, 0xfc, 0xfc, 0xb7, 0x4d, 0xc9, 0xd0, 0xef, + 0x9e, 0x9f, 0x5a, 0x89, 0x67, 0xef, 0x31, 0xc7, + 0xff, 0x47, 0x4f, 0xff, 0xf3, 0x73, 0xbb, 0xa7, + 0x43, 0x9b, 0xf3, 0x2b, 0x5c, 0x04, 0x3a, 0x7f, + 0x5d, 0xdf, 0x7e, 0xf8, 0xf3, 0xa3, 0xba, 0x26, + 0x74, 0xcb, 0x3f, 0xff, 0xdb, 0x61, 0xf6, 0xbb, + 0xfd, 0x75, 0xbb, 0xe7, 0xf5, 0xb1, 0x3a, 0x79, + 0x33, 0x10, 0xd1, 0x26, 0x4f, 0x93, 0xad, 0x3a, + 0xce, 0xb6, 0xef, 0x9d, 0x3f, 0xae, 0x9d, 0x6b, + 0x1f, 0x53, 0xa1, 0x8f, 0xc4, 0x0f, 0xa1, 0xe9, + 0x91, 0x83, 0x3a, 0xa1, 0x39, 0x3f, 0x73, 0xe3, + 0xbf, 0x5f, 0x3a, 0x8e, 0x9f, 0xfd, 0xbf, 0xea, + 0x94, 0xf8, 0x55, 0xc6, 0xc3, 0xa7, 0xd7, 0xaf, + 0xab, 0x0e, 0x9f, 0xff, 0x62, 0x03, 0x6c, 0x6f, + 0x56, 0xbe, 0x38, 0xe0, 0xa8, 0x79, 0xfd, 0x68, + 0x9a, 0x7e, 0x44, 0xf5, 0x05, 0x8e, 0x9f, 0xfd, + 0xe8, 0xe6, 0x98, 0x2b, 0xb6, 0x1d, 0x1d, 0x3b, + 0x8e, 0x38, 0x2a, 0x7e, 0x0c, 0xa1, 0x5f, 0xa9, + 0x4b, 0x2f, 0xe7, 0xd6, 0xa0, 0xbe, 0xb9, 0xd3, + 0xef, 0xea, 0x8b, 0xe0, 0xe9, 0xfe, 0x64, 0xd8, + 0xfb, 0xa6, 0xa9, 0xd3, 0xff, 0xed, 0x6e, 0xdf, + 0xd1, 0x37, 0xfd, 0x52, 0x9f, 0x03, 0xa0, 0x11, + 0x6e, 0xa2, 0x91, 0x37, 0x9f, 0xeb, 0xcf, 0x3a, + 0x5f, 0x38, 0xf3, 0xa7, 0xff, 0x65, 0x1b, 0xfb, + 0x0d, 0xb9, 0xf0, 0xf9, 0xd1, 0x68, 0xb1, 0xd1, + 0x77, 0x07, 0x53, 0xe1, 0xbd, 0xe6, 0x8e, 0x9f, + 0xf3, 0xd8, 0x68, 0xec, 0x03, 0xeb, 0xce, 0x8e, + 0xb9, 0xf2, 0xb8, 0x4b, 0x3d, 0xaa, 0x2f, 0x93, + 0xa7, 0xfb, 0xfd, 0xfb, 0x07, 0x8a, 0xfd, 0x4e, + 0x87, 0x0f, 0x87, 0xa8, 0x8e, 0x77, 0x1c, 0x70, + 0x74, 0xff, 0xfa, 0xd5, 0xa1, 0x6f, 0x2f, 0x9a, + 0xda, 0x99, 0x0a, 0x59, 0x7f, 0x16, 0x99, 0x7f, + 0xe1, 0x11, 0xb4, 0x59, 0x7c, 0xe9, 0xfb, 0x6d, + 0xd1, 0x3f, 0x41, 0xd3, 0xf0, 0x60, 0x0b, 0x3c, + 0xe8, 0x77, 0x47, 0xd1, 0xc8, 0x80, 0x17, 0xcc, + 0xf5, 0xbb, 0xcc, 0x8f, 0x0e, 0xb1, 0xa9, 0x8b, + 0xdf, 0x0c, 0x8b, 0x8d, 0x23, 0xb9, 0xaa, 0x1c, + 0xd3, 0x0c, 0x4f, 0x91, 0x38, 0x55, 0x8c, 0xc2, + 0x79, 0x58, 0xe4, 0x75, 0x1e, 0x27, 0x68, 0x4e, + 0xcf, 0xfe, 0x0b, 0xe3, 0x9d, 0xdb, 0x83, 0x60, + 0xf3, 0xa7, 0x05, 0xf5, 0xce, 0x95, 0x81, 0xf3, + 0xa9, 0x26, 0x7f, 0xeb, 0xd8, 0xb5, 0x1d, 0xb7, + 0xbc, 0xeb, 0x9d, 0x3f, 0x62, 0x2f, 0x8e, 0x38, + 0x3a, 0x4b, 0xb6, 0x64, 0xf2, 0x46, 0x64, 0x06, + 0x39, 0x49, 0x2e, 0x18, 0xdb, 0xea, 0x4c, 0xe9, + 0x26, 0x1e, 0xd9, 0x8e, 0xf3, 0x29, 0xde, 0x98, + 0x70, 0x01, 0x3a, 0x8e, 0xfc, 0x85, 0x8d, 0x61, + 0xb1, 0xa8, 0x4b, 0x7b, 0x4c, 0xc5, 0x9f, 0xcb, + 0xb0, 0x4c, 0xc4, 0x34, 0x46, 0xb3, 0xe0, 0x4c, + 0xc4, 0x34, 0x54, 0xb3, 0x62, 0x1a, 0x21, 0xa9, + 0x2e, 0xcf, 0x47, 0x0c, 0x27, 0xfe, 0x5e, 0x3d, + 0x76, 0x09, 0x98, 0x86, 0x88, 0xfa, 0x7f, 0x2e, + 0xc1, 0x33, 0x10, 0xd1, 0x63, 0xce, 0xeb, 0x45, + 0x77, 0x3a, 0x7e, 0x77, 0xc6, 0xf7, 0x9a, 0x3a, + 0x7f, 0x87, 0x3c, 0xae, 0x6b, 0x58, 0x74, 0xf7, + 0x8a, 0xf8, 0x1d, 0x3f, 0xff, 0xcc, 0x03, 0x7c, + 0xde, 0xf7, 0xf4, 0xdf, 0xf5, 0x5c, 0xa4, 0xe8, + 0xfa, 0x21, 0xf6, 0x45, 0x3b, 0x31, 0x0d, 0x16, + 0x84, 0xff, 0xb3, 0x87, 0x64, 0xc0, 0xa2, 0xf8, + 0x3a, 0x10, 0xf9, 0xc0, 0x9a, 0x7f, 0xff, 0xfb, + 0xe1, 0xbc, 0x1f, 0xb6, 0xbf, 0xb6, 0xae, 0xee, + 0xa1, 0x69, 0x7a, 0x3a, 0x01, 0x13, 0x1b, 0x20, + 0x9f, 0x9d, 0x76, 0xd0, 0xb7, 0x87, 0x4f, 0x9b, + 0x57, 0xb6, 0x3a, 0x7f, 0xfa, 0xf5, 0x5b, 0x73, + 0x6c, 0xea, 0xf7, 0xb6, 0x3a, 0x28, 0x3f, 0x51, + 0x25, 0x86, 0x46, 0x45, 0xc2, 0x9a, 0x7f, 0xde, + 0x32, 0x6f, 0xee, 0x66, 0x50, 0x74, 0xff, 0x7f, + 0xd1, 0x78, 0x35, 0xf2, 0x74, 0xff, 0xff, 0x6e, + 0xde, 0x9b, 0xfe, 0xda, 0xc1, 0xfa, 0x16, 0x55, + 0x4e, 0x95, 0xd5, 0x13, 0x7a, 0x38, 0x9f, 0x6b, + 0x78, 0x3d, 0xce, 0x9f, 0xe1, 0xf6, 0x8e, 0x77, + 0x62, 0xc7, 0x4c, 0x37, 0x67, 0xc2, 0x85, 0x13, + 0xfa, 0xf6, 0xe7, 0xf7, 0xf5, 0x1d, 0x3f, 0x9f, + 0x61, 0x51, 0x6a, 0x0e, 0x9d, 0x7b, 0xc3, 0xa7, + 0xce, 0x73, 0xef, 0xa2, 0x74, 0x72, 0x78, 0xb8, + 0x35, 0x3f, 0xd7, 0x7c, 0x5a, 0x25, 0xf0, 0x74, + 0x5a, 0x60, 0x54, 0x9a, 0x63, 0xb5, 0x48, 0xa7, + 0xaf, 0x79, 0xa3, 0xa7, 0xef, 0x8f, 0xaf, 0xba, + 0x9d, 0x3f, 0xff, 0xdf, 0x1f, 0x5f, 0x75, 0xe9, + 0x7a, 0x6a, 0x7c, 0xcd, 0xef, 0xe7, 0x47, 0x74, + 0x4b, 0xe8, 0xb6, 0x4b, 0x77, 0x97, 0xbb, 0x7a, + 0xc2, 0x56, 0x30, 0xe6, 0x17, 0xd7, 0x19, 0x16, + 0xe1, 0xd5, 0xe1, 0x30, 0xc3, 0x6a, 0xb0, 0x89, + 0xd4, 0x65, 0x9d, 0x47, 0xbd, 0xa1, 0x6f, 0x3f, + 0x3b, 0x7f, 0x91, 0x67, 0x0e, 0x9e, 0xbd, 0xe6, + 0x8e, 0x93, 0xbf, 0x67, 0xa2, 0x26, 0x33, 0xe0, + 0x4c, 0xc4, 0x34, 0x5a, 0xd3, 0xfe, 0xc7, 0xae, + 0xc1, 0x33, 0x10, 0xd1, 0x41, 0xc9, 0x7d, 0x62, + 0x28, 0x6c, 0xad, 0x46, 0x13, 0xff, 0x96, 0xac, + 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x14, 0x5c, 0xfe, + 0x5d, 0x82, 0x66, 0x21, 0xa2, 0xea, 0x87, 0xb2, + 0xb0, 0x12, 0x11, 0x9f, 0x26, 0x52, 0x66, 0xe7, + 0xca, 0x3c, 0x8f, 0x4e, 0xa7, 0x5a, 0x52, 0x9f, + 0x02, 0x66, 0x21, 0xa2, 0x21, 0x9d, 0xbb, 0xe4, + 0xe9, 0x2e, 0xcf, 0x32, 0x93, 0x09, 0xfc, 0xbb, + 0x04, 0xcc, 0x43, 0x44, 0x6d, 0x3f, 0x97, 0x60, + 0x99, 0x88, 0x68, 0xa6, 0xe7, 0xf2, 0xec, 0x13, + 0x31, 0x0d, 0x15, 0x04, 0xfe, 0x5d, 0x82, 0x66, + 0x21, 0xa2, 0xa6, 0x9f, 0x02, 0x66, 0x21, 0xa2, + 0xb0, 0x9f, 0x7f, 0x8e, 0x7d, 0x03, 0xa7, 0xf9, + 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x47, 0xf3, 0xad, + 0xa8, 0x3a, 0x4b, 0xb4, 0x5b, 0x21, 0x86, 0x15, + 0x0a, 0x0c, 0xff, 0xe5, 0xab, 0x1e, 0xbb, 0x04, + 0xcc, 0x43, 0x44, 0xdf, 0x3f, 0xf2, 0xb1, 0xeb, + 0xb0, 0x4c, 0xc4, 0x34, 0x4f, 0xd3, 0xee, 0xb6, + 0xef, 0xf5, 0x5d, 0x27, 0x4b, 0x67, 0x43, 0xbb, + 0x3c, 0x6f, 0x4d, 0xa7, 0xdd, 0x3b, 0x86, 0x21, + 0xd3, 0xee, 0xb1, 0xdd, 0x79, 0xdd, 0x8e, 0x9f, + 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0xa6, 0xa7, + 0x4f, 0x83, 0xf4, 0x62, 0x8a, 0x9b, 0x8e, 0x0a, + 0x8b, 0x37, 0xfc, 0x13, 0xcb, 0xd2, 0x96, 0x68, + 0x61, 0x91, 0x95, 0x58, 0x54, 0xcf, 0xff, 0xd6, + 0xaa, 0xe8, 0x32, 0x8e, 0x76, 0xd5, 0xd7, 0xbb, + 0x3a, 0x7d, 0x89, 0xbf, 0x81, 0xd3, 0xff, 0xff, + 0x87, 0x3b, 0xfc, 0x19, 0xfd, 0x37, 0xf5, 0x72, + 0xdd, 0x3a, 0xbd, 0xdf, 0xc0, 0xe8, 0xe5, 0x30, + 0x30, 0x5d, 0xd9, 0x2c, 0xff, 0xf9, 0xd9, 0xa9, + 0x7e, 0x0f, 0x9d, 0x3c, 0xf8, 0x7f, 0xb9, 0xd3, + 0xd4, 0x2b, 0xef, 0x3a, 0x7d, 0x51, 0xf7, 0x1e, + 0x74, 0xfe, 0xdb, 0x29, 0x7e, 0x78, 0xc7, 0x48, + 0x18, 0xff, 0xac, 0x8f, 0xe4, 0xf3, 0xfe, 0x6a, + 0x79, 0xec, 0xdd, 0x7d, 0xfb, 0x53, 0xa7, 0x79, + 0x5b, 0x3a, 0x7f, 0xee, 0x5b, 0x59, 0x5b, 0xde, + 0xfe, 0xa3, 0xa7, 0x6b, 0xee, 0x1d, 0x0c, 0x7c, + 0x35, 0x44, 0x86, 0x56, 0x9d, 0xf8, 0xca, 0x9c, + 0x31, 0x08, 0x6e, 0x28, 0xc8, 0x51, 0xf4, 0xfb, + 0x39, 0xce, 0xca, 0x3a, 0x7f, 0xaf, 0x55, 0xbd, + 0x6e, 0xfc, 0x3a, 0x30, 0xf5, 0xc4, 0x7e, 0x6c, + 0x13, 0xa0, 0x0d, 0xa2, 0x88, 0x27, 0x71, 0xc7, + 0x07, 0x4f, 0x50, 0x3f, 0x62, 0x96, 0x5f, 0xcd, + 0x4b, 0xce, 0x9b, 0xe8, 0x74, 0xa9, 0x63, 0x59, + 0xa1, 0x78, 0x64, 0x61, 0x6c, 0xff, 0xd5, 0xc9, + 0xff, 0xa8, 0xf7, 0xcb, 0x1f, 0x5c, 0x6d, 0x61, + 0xd3, 0xff, 0x36, 0xfb, 0x73, 0xaf, 0xdb, 0x8c, + 0xa3, 0xa7, 0x9b, 0x55, 0x43, 0x44, 0x1d, 0x3f, + 0x66, 0xdb, 0xaf, 0xeb, 0xce, 0x80, 0x47, 0x62, + 0x91, 0xf4, 0x8e, 0xe8, 0xb6, 0x60, 0xe4, 0xe9, + 0xb8, 0xe0, 0xe8, 0x79, 0xae, 0xe0, 0x5a, 0x7a, + 0xad, 0xf7, 0x45, 0x2c, 0xd1, 0x4f, 0xab, 0xdb, + 0x9f, 0x2a, 0x74, 0x7c, 0xf7, 0xfb, 0x19, 0xce, + 0xe3, 0x8e, 0x0a, 0x82, 0x96, 0x5f, 0xcf, 0x7f, + 0x8f, 0xb8, 0x54, 0x21, 0xbd, 0xf8, 0xcc, 0x7d, + 0x38, 0xdd, 0xc3, 0xb4, 0x61, 0x01, 0x38, 0x7f, + 0x53, 0xa7, 0xb9, 0xc1, 0xf0, 0xe9, 0xff, 0x98, + 0x7c, 0x16, 0xa5, 0xc6, 0x1f, 0x0e, 0x8f, 0xa2, + 0x07, 0xc1, 0xba, 0x91, 0x4f, 0x9a, 0xc3, 0x7f, + 0x3a, 0x7b, 0x9b, 0x57, 0x5c, 0xe8, 0x70, 0xf2, + 0xdd, 0x12, 0xcf, 0xda, 0xb7, 0x05, 0x94, 0x78, + 0x80, 0xa7, 0xd8, 0x3c, 0xed, 0x8d, 0x10, 0x12, + 0xcd, 0xcc, 0xff, 0x30, 0x51, 0xd2, 0xdc, 0xfa, + 0x8e, 0x9e, 0x53, 0x5a, 0x8e, 0x9f, 0x37, 0x9f, + 0xa6, 0xa7, 0x4f, 0xe0, 0x72, 0xbf, 0x1d, 0x7c, + 0xe9, 0xea, 0x7c, 0x06, 0x2a, 0x6e, 0x38, 0x2a, + 0x18, 0xdd, 0x70, 0x45, 0x3f, 0x60, 0x3d, 0xe3, + 0xf2, 0x96, 0x68, 0x61, 0x95, 0x35, 0x5b, 0xe7, + 0xd7, 0xb6, 0x87, 0x87, 0x62, 0x41, 0xa2, 0x9f, + 0x61, 0x1d, 0x3e, 0xf7, 0x5e, 0xe7, 0x63, 0x44, + 0x0f, 0x3f, 0xed, 0xfb, 0x43, 0x74, 0x6d, 0x37, + 0x27, 0x4e, 0xc0, 0xa0, 0xe9, 0xb8, 0xe0, 0xe9, + 0xfc, 0x1f, 0xb7, 0x5d, 0x9e, 0xb4, 0x36, 0x7c, + 0x0d, 0xc7, 0x28, 0xc2, 0x07, 0x59, 0xff, 0x86, + 0xfb, 0xef, 0x1f, 0xdb, 0x29, 0x63, 0xa1, 0x8f, + 0xa6, 0xc8, 0xe7, 0xff, 0x5a, 0x95, 0x8f, 0xb0, + 0x4c, 0xc4, 0x34, 0x43, 0x11, 0xb3, 0xf1, 0x12, + 0x09, 0xf0, 0x26, 0x62, 0x1a, 0x20, 0xa9, 0xdb, + 0x65, 0x1d, 0x16, 0x79, 0x7f, 0x30, 0x9e, 0xd5, + 0x5b, 0xc2, 0xa7, 0x60, 0x50, 0x54, 0xf7, 0xa3, + 0x9d, 0xca, 0x9f, 0xdf, 0xa2, 0xf5, 0x56, 0xf0, + 0xa8, 0x2a, 0x7e, 0xb4, 0x6d, 0xb2, 0x8a, 0x9b, + 0x8e, 0x0a, 0x9f, 0x85, 0x86, 0x8f, 0x81, 0x51, + 0x69, 0x85, 0xa1, 0x12, 0x86, 0xf6, 0x47, 0xe1, + 0xa0, 0x85, 0x70, 0x55, 0xd8, 0x62, 0x6f, 0x81, + 0x4b, 0x3f, 0x39, 0x63, 0xd3, 0xc5, 0xdc, 0x73, + 0xf3, 0xfe, 0x67, 0xe0, 0xdd, 0x41, 0xaa, 0x74, + 0xff, 0x6b, 0x6c, 0xeb, 0x96, 0xf1, 0x8e, 0x9f, + 0xe6, 0xa5, 0xfd, 0x4c, 0x96, 0xa3, 0xa1, 0x8f, + 0xd7, 0x67, 0x73, 0xff, 0xf3, 0x99, 0x8f, 0xcd, + 0xf4, 0xba, 0x3d, 0xd7, 0xb9, 0xd8, 0xd1, 0x7d, + 0xcf, 0xbf, 0xa1, 0xb7, 0x9d, 0x3f, 0xe1, 0xfb, + 0xf5, 0xbb, 0x0f, 0xd4, 0xe9, 0xfd, 0xaf, 0x3b, + 0x0b, 0xf7, 0x67, 0x88, 0x06, 0x76, 0x03, 0xcf, + 0x10, 0x0c, 0x59, 0xf4, 0xfa, 0x85, 0x36, 0x3c, + 0xf1, 0x00, 0xcf, 0x60, 0xd2, 0xf3, 0xc4, 0x03, + 0x3f, 0xbe, 0x9b, 0xbf, 0x3c, 0x63, 0xc4, 0x03, + 0x3b, 0xe3, 0xc9, 0xe2, 0x01, 0x8e, 0x51, 0x72, + 0xa2, 0x2d, 0x97, 0x3a, 0x40, 0x9c, 0x0d, 0xa3, + 0xc4, 0x03, 0x07, 0x88, 0x06, 0x66, 0x51, 0xe2, + 0x01, 0x8e, 0x4d, 0xcf, 0xc5, 0xe7, 0xbe, 0xae, + 0x58, 0xf1, 0x00, 0xce, 0xd6, 0x21, 0xe2, 0x01, + 0x9f, 0xf0, 0xe3, 0xd7, 0xbf, 0xa6, 0x01, 0xe2, + 0x01, 0x9b, 0x39, 0x3c, 0x40, 0x33, 0xf8, 0x73, + 0x8a, 0xd5, 0xbc, 0x3c, 0x40, 0x33, 0xef, 0xf7, + 0xc1, 0xf0, 0xf1, 0x00, 0xcd, 0xfa, 0x9e, 0x20, + 0x18, 0x03, 0xd9, 0xd1, 0xb4, 0xfb, 0x42, 0xd4, + 0xbc, 0xd1, 0x00, 0xcd, 0xe3, 0x1e, 0x20, 0x15, + 0x9b, 0x49, 0xf7, 0xd9, 0x59, 0xc9, 0xe2, 0x01, + 0x9e, 0xf7, 0x05, 0x0f, 0x10, 0x0c, 0xe6, 0x04, + 0x3c, 0x40, 0x33, 0xfe, 0xba, 0x6b, 0xcb, 0x58, + 0xf9, 0x53, 0xc4, 0x03, 0x3e, 0xf7, 0x1e, 0xf6, + 0x3c, 0x40, 0x31, 0x68, 0x80, 0xda, 0x64, 0xc1, + 0xe1, 0xe2, 0x01, 0x87, 0xaa, 0x90, 0xe4, 0x8e, + 0xe1, 0x33, 0xf5, 0x5d, 0x99, 0xf8, 0x69, 0x52, + 0xdd, 0x42, 0x9b, 0xd2, 0x29, 0xf5, 0xea, 0xb9, + 0x49, 0xe2, 0x01, 0x9f, 0xdc, 0xb2, 0x38, 0x0d, + 0xa3, 0xc4, 0x03, 0xc9, 0xb4, 0x9c, 0x0d, 0xc1, + 0xe2, 0x01, 0x84, 0x3f, 0x80, 0x50, 0x9e, 0xf8, + 0xbe, 0xa7, 0x88, 0x06, 0x7e, 0xc7, 0x1f, 0x74, + 0xbc, 0xf1, 0x00, 0xc5, 0xa2, 0x27, 0xc2, 0x0f, + 0x4b, 0xa7, 0xfb, 0x6d, 0x55, 0xd7, 0xd0, 0xf0, + 0xf1, 0x00, 0xcb, 0xe7, 0x88, 0x06, 0x6c, 0xa3, + 0x93, 0xe4, 0xda, 0x3c, 0xc1, 0xe1, 0xe2, 0x01, + 0x9f, 0x66, 0xab, 0xfa, 0x4f, 0x10, 0x0c, 0xfd, + 0xf1, 0xf5, 0xf7, 0x53, 0xc4, 0x03, 0x0c, 0x89, + 0x21, 0x23, 0xd1, 0xac, 0x72, 0xc8, 0x10, 0xb8, + 0x6d, 0xb8, 0x80, 0x0c, 0x1b, 0x22, 0xc2, 0xff, + 0x09, 0xeb, 0x2b, 0x63, 0x51, 0xe0, 0xf5, 0x42, + 0x57, 0xb4, 0x30, 0x67, 0x66, 0x21, 0xa2, 0x01, + 0x5a, 0x2f, 0x67, 0xbb, 0xbb, 0xae, 0x54, 0x74, + 0xde, 0x31, 0x52, 0xee, 0x54, 0xed, 0xb5, 0x07, + 0x4d, 0xc7, 0x05, 0x47, 0xcf, 0x73, 0xae, 0x2c, + 0xe0, 0x97, 0x03, 0x93, 0x95, 0xfa, 0x94, 0xb3, + 0xc2, 0x8a, 0x19, 0x58, 0xef, 0x26, 0x4a, 0x4b, + 0x9f, 0xce, 0x3c, 0x86, 0x4c, 0xfe, 0xfe, 0xbb, + 0x3a, 0x74, 0xd5, 0x3a, 0x7e, 0x07, 0x1e, 0xc1, + 0x41, 0xd3, 0xfe, 0x7d, 0x7a, 0x0d, 0xa9, 0x83, + 0xb9, 0xd3, 0xff, 0x06, 0xf2, 0xde, 0xc1, 0xe7, + 0x65, 0x1d, 0x3f, 0x76, 0xe0, 0x3f, 0x7b, 0x2a, + 0x79, 0xcd, 0xe3, 0x87, 0x4f, 0xad, 0xc7, 0xb5, + 0x27, 0x4f, 0x58, 0xb3, 0xca, 0x80, 0x3e, 0xa1, + 0x23, 0x76, 0x28, 0x86, 0x4d, 0xea, 0xcb, 0x7e, + 0x81, 0xb4, 0x4c, 0x84, 0xcc, 0xf7, 0xc7, 0x55, + 0x3a, 0x77, 0xae, 0xe5, 0x4e, 0x9f, 0xfb, 0xc5, + 0x5a, 0x6f, 0xfc, 0xef, 0xde, 0xe7, 0x4f, 0xee, + 0x5a, 0x9a, 0xdd, 0x3a, 0x3a, 0x7f, 0x9b, 0x5f, + 0x4f, 0xf2, 0xda, 0x3a, 0x6d, 0x56, 0xcf, 0xb4, + 0x0d, 0x67, 0xf3, 0xee, 0xbd, 0xab, 0xab, 0x3a, + 0x19, 0x33, 0x8f, 0x91, 0x64, 0x2d, 0xbd, 0x2c, + 0x9f, 0x63, 0xae, 0x79, 0x63, 0xa6, 0xad, 0x4e, + 0x9d, 0xc7, 0x1c, 0x1d, 0x37, 0x98, 0x52, 0xcb, + 0xf8, 0x03, 0xda, 0xa9, 0xac, 0xff, 0xae, 0xa3, + 0x9d, 0xdc, 0x1f, 0xb8, 0x74, 0xec, 0xf2, 0xca, + 0x87, 0xa6, 0x00, 0xa8, 0x42, 0x6c, 0x87, 0xa9, + 0x02, 0x7f, 0x68, 0x6e, 0x9f, 0x3b, 0x3c, 0xe9, + 0xfe, 0x1b, 0x75, 0x6b, 0xe3, 0x8e, 0x0a, 0x9c, + 0xac, 0xd1, 0xd1, 0xb3, 0xd7, 0x74, 0x79, 0x3e, + 0xb7, 0x1e, 0xcf, 0x3a, 0x19, 0x31, 0xef, 0xa3, + 0x64, 0x23, 0x74, 0x49, 0x3f, 0x3b, 0x9f, 0x06, + 0x01, 0x3a, 0x7f, 0xf5, 0xf3, 0x8a, 0xba, 0x5f, + 0x7e, 0x5f, 0x27, 0x4d, 0xbc, 0x3a, 0x67, 0x2a, + 0x74, 0xfa, 0xdd, 0x7c, 0x79, 0xb3, 0x59, 0xd8, + 0x56, 0x3a, 0x22, 0xe1, 0x6e, 0xf3, 0xdc, 0xde, + 0xf0, 0xe9, 0xff, 0x9a, 0xc5, 0xfb, 0xb1, 0x16, + 0xe0, 0xe9, 0x7c, 0x11, 0x0c, 0x24, 0xba, 0x21, + 0x8a, 0x1b, 0x83, 0x17, 0xc7, 0xa9, 0xcc, 0xa3, + 0x1e, 0xe5, 0xe9, 0x0a, 0xff, 0x90, 0x85, 0x2c, + 0xd5, 0x4b, 0xbb, 0x8e, 0xcf, 0xc4, 0xd1, 0x8d, + 0x67, 0x52, 0x98, 0x3d, 0x41, 0x75, 0x1b, 0x6c, + 0xff, 0x58, 0x0b, 0x69, 0xf7, 0xb3, 0xa7, 0xe1, + 0xf2, 0xf9, 0xc7, 0x9d, 0x3e, 0xec, 0xe3, 0xdb, + 0xae, 0x54, 0x32, 0x24, 0x2c, 0xd7, 0xb1, 0x6c, + 0xff, 0xe0, 0xee, 0x3e, 0xe7, 0x6b, 0xaf, 0xd8, + 0x4e, 0x97, 0x63, 0x44, 0x0b, 0x2d, 0x1a, 0x81, + 0x49, 0x7f, 0x46, 0xf3, 0x81, 0xf9, 0xff, 0x7f, + 0xab, 0x7f, 0xec, 0xbf, 0x3c, 0x62, 0xa7, 0xff, + 0xf6, 0xd8, 0x3c, 0xb7, 0x5f, 0xad, 0x6c, 0x53, + 0x07, 0xc3, 0xa7, 0xfe, 0xae, 0x53, 0xd1, 0x4d, + 0x63, 0xae, 0xa3, 0xa3, 0x68, 0xa8, 0xd3, 0x04, + 0x32, 0x62, 0x3f, 0x87, 0x74, 0xff, 0xff, 0x05, + 0x17, 0xf7, 0x33, 0x1f, 0x56, 0x57, 0x3b, 0x61, + 0x43, 0xa7, 0x50, 0x2f, 0x3a, 0x19, 0x53, 0x4a, + 0xa1, 0x0f, 0xb8, 0xce, 0x70, 0xa3, 0xd6, 0x59, + 0xfc, 0xf7, 0x2c, 0x73, 0x76, 0x74, 0xff, 0xe0, + 0x41, 0xb7, 0x43, 0x6c, 0x0d, 0x53, 0xa7, 0xf6, + 0x39, 0xbb, 0x55, 0xd4, 0xe8, 0xb3, 0xf7, 0x74, + 0x8b, 0x3f, 0x7f, 0xbe, 0xae, 0xd4, 0x74, 0xfa, + 0xf9, 0xf8, 0x54, 0xe9, 0xff, 0xea, 0xea, 0x94, + 0xfe, 0xfa, 0x3b, 0x5e, 0xfe, 0xa3, 0xa4, 0xd4, + 0x1f, 0xef, 0x04, 0xf1, 0xf4, 0x7b, 0xec, 0x8f, + 0x50, 0xab, 0x9f, 0xf0, 0xff, 0xb5, 0x36, 0xea, + 0x96, 0xec, 0x74, 0xee, 0x70, 0x0e, 0x9f, 0x79, + 0x83, 0x6e, 0xc7, 0x43, 0x1e, 0x27, 0xa3, 0x73, + 0xcc, 0xaa, 0x5c, 0x3a, 0x19, 0x55, 0x13, 0xe3, + 0x9f, 0xb3, 0x5a, 0xc2, 0x27, 0x44, 0x53, 0xe6, + 0xa1, 0x9d, 0x98, 0xe9, 0xfb, 0xde, 0xdb, 0xba, + 0x6a, 0x74, 0xff, 0xff, 0xfc, 0xc0, 0xda, 0x1c, + 0x4f, 0xd5, 0xcf, 0x82, 0x35, 0x74, 0xd4, 0xb7, + 0x6b, 0xa9, 0xd3, 0xde, 0x65, 0x35, 0x3a, 0x6e, + 0x38, 0x3a, 0x2a, 0x6e, 0xf8, 0x23, 0x9f, 0x7f, + 0x79, 0x7b, 0x29, 0x66, 0x8a, 0x36, 0x9b, 0x9b, + 0xb8, 0x52, 0x26, 0x35, 0x87, 0x1c, 0xee, 0x38, + 0xe0, 0xa9, 0xe7, 0xea, 0xd0, 0xa5, 0x97, 0xf3, + 0xeb, 0xe7, 0xfe, 0x54, 0xf7, 0x7f, 0x4b, 0x00, + 0xf9, 0x44, 0xbe, 0x73, 0x05, 0x4e, 0x9f, 0x86, + 0x9a, 0xb9, 0x7a, 0x3a, 0x7f, 0xf8, 0x74, 0xe5, + 0x85, 0xe2, 0x9b, 0x7f, 0xe4, 0xe9, 0xf5, 0x1d, + 0x7f, 0xdd, 0x27, 0x4f, 0xbf, 0x56, 0xa1, 0x47, + 0xb3, 0xf6, 0x7c, 0xd8, 0x1e, 0x7a, 0x7b, 0x3f, + 0x66, 0xc7, 0x9e, 0xcf, 0xd9, 0xef, 0x5f, 0x75, + 0x3d, 0x9f, 0xb1, 0xc9, 0xe8, 0x89, 0x14, 0xf9, + 0xae, 0xb6, 0x27, 0xb3, 0xf6, 0x0f, 0x67, 0xec, + 0xd9, 0xa3, 0xd9, 0xfa, 0xa2, 0xde, 0x4f, 0x13, + 0xf9, 0xf5, 0x22, 0x7a, 0xfa, 0xbf, 0xe1, 0xec, + 0xfd, 0x83, 0xd9, 0xfb, 0x37, 0x8c, 0x7b, 0x3f, + 0x67, 0xfa, 0xfc, 0xc0, 0xb7, 0x57, 0xc9, 0xec, + 0xfd, 0x9f, 0xaf, 0x7f, 0xaf, 0xb4, 0x1e, 0xcf, + 0xd8, 0xf1, 0x14, 0xa2, 0x47, 0x54, 0x69, 0xe0, + 0xa1, 0xb4, 0x7b, 0x3f, 0x60, 0xf6, 0x7e, 0xd9, + 0xae, 0x9b, 0x8e, 0x0f, 0x67, 0xec, 0x3d, 0x58, + 0xa7, 0x26, 0xb7, 0x08, 0x5a, 0x61, 0x36, 0x05, + 0x0a, 0x32, 0xac, 0x2f, 0x34, 0xbd, 0xc1, 0x34, + 0xf5, 0xbd, 0xbb, 0x96, 0xcf, 0xd2, 0xd1, 0x21, + 0x3f, 0xeb, 0x4e, 0x6c, 0x38, 0xcd, 0xb8, 0x74, + 0xcf, 0xa0, 0xa8, 0xa1, 0x12, 0xf4, 0xa1, 0x09, + 0xf4, 0x02, 0xe4, 0xce, 0x4e, 0x34, 0x4f, 0xff, + 0x9e, 0x0c, 0xeb, 0x1c, 0x6e, 0x76, 0xca, 0xc7, + 0x0e, 0x9f, 0xce, 0xd9, 0x5f, 0xd5, 0xcb, 0x3a, + 0x29, 0x44, 0x68, 0x2b, 0xc3, 0x2f, 0x18, 0x3c, + 0x96, 0xc6, 0xbe, 0x5d, 0x93, 0x9c, 0xfe, 0xc2, + 0xe6, 0x7f, 0xdd, 0xda, 0x91, 0x6d, 0xef, 0xd4, + 0x3a, 0x7e, 0x1c, 0xef, 0xbc, 0x79, 0xd3, 0xb8, + 0xe3, 0x82, 0xa7, 0x76, 0x6f, 0x0a, 0x59, 0x7f, + 0x3f, 0xe1, 0xc7, 0xf6, 0x0b, 0x75, 0x80, 0x74, + 0xff, 0x0e, 0x79, 0xd1, 0xed, 0xe5, 0x27, 0x47, + 0x29, 0x99, 0xa9, 0x03, 0xc4, 0xc1, 0x2d, 0xd1, + 0xf4, 0xff, 0x84, 0x7f, 0xeb, 0xb9, 0x5e, 0xa6, + 0xd1, 0xd3, 0xb8, 0xe3, 0x82, 0xc4, 0x20, 0x9f, + 0x02, 0x66, 0x21, 0x62, 0x10, 0x2c, 0xd6, 0xce, + 0xe3, 0x8e, 0x0b, 0x10, 0x7a, 0x0b, 0x10, 0x79, + 0x66, 0xb6, 0x66, 0x55, 0xa2, 0x59, 0x1b, 0xa7, + 0xda, 0x6d, 0x32, 0x8e, 0x9e, 0x1f, 0xb7, 0x73, + 0xa7, 0x76, 0x6f, 0x0e, 0x8a, 0x0f, 0x01, 0x44, + 0x53, 0xe4, 0x6d, 0xb2, 0x8a, 0x9f, 0x0e, 0x08, + 0xd9, 0x53, 0x5a, 0x15, 0x37, 0x1c, 0x15, 0x16, + 0x7e, 0x95, 0x25, 0xd1, 0x1f, 0x02, 0x93, 0xf8, + 0x7b, 0x37, 0x9b, 0xb7, 0x62, 0x96, 0x6f, 0x21, + 0x93, 0x80, 0xfb, 0x36, 0x43, 0x4e, 0x7f, 0xe6, + 0xf2, 0xb7, 0x7c, 0xe0, 0xe7, 0x73, 0xa7, 0xff, + 0xd4, 0xbe, 0xbc, 0x30, 0x6d, 0xbf, 0xb6, 0x1f, + 0x9d, 0x1b, 0x44, 0xce, 0x22, 0x4f, 0xea, 0xf6, + 0x55, 0x78, 0xca, 0x4e, 0x86, 0x5c, 0x27, 0xb4, + 0xcf, 0xc6, 0x12, 0x11, 0xd6, 0x64, 0x33, 0x6a, + 0x45, 0x3b, 0x8e, 0x38, 0x2a, 0x7b, 0xcc, 0x1e, + 0x4a, 0x59, 0x7f, 0x3f, 0x76, 0xb0, 0xbb, 0x70, + 0xe8, 0x79, 0xef, 0x54, 0xc6, 0x7f, 0xf8, 0x69, + 0xe9, 0x4f, 0x8c, 0x29, 0x94, 0x0e, 0x1d, 0x3f, + 0xff, 0xff, 0xda, 0xaf, 0x6a, 0xf4, 0xde, 0x7f, + 0x5f, 0xda, 0x7f, 0xa3, 0xff, 0xbc, 0x1d, 0x3e, + 0xc2, 0xce, 0x9f, 0xfe, 0xb6, 0x5f, 0x22, 0xde, + 0xa5, 0xf7, 0xf8, 0x1d, 0x3c, 0xed, 0xbf, 0x1d, + 0x1d, 0x0f, 0x3f, 0x7c, 0x4f, 0x9f, 0xfc, 0xfb, + 0x0f, 0x15, 0xfa, 0xf6, 0xab, 0x59, 0xd3, 0xdf, + 0xe6, 0xd4, 0x74, 0x32, 0xa1, 0x17, 0x91, 0x5a, + 0x8e, 0x46, 0x20, 0x24, 0x3e, 0xa5, 0xcf, 0xdd, + 0x7a, 0xfc, 0x69, 0x79, 0xd3, 0xfe, 0xc0, 0xea, + 0xfe, 0xef, 0x29, 0xf0, 0xe9, 0xff, 0x56, 0xac, + 0x1a, 0x65, 0xf3, 0xf3, 0xa7, 0xfc, 0x38, 0xe6, + 0xf0, 0x03, 0xfc, 0x9d, 0x16, 0x8e, 0xe4, 0x32, + 0xfa, 0x0a, 0x8f, 0xa7, 0x9f, 0xda, 0xdc, 0x3a, + 0x7c, 0x1c, 0xdd, 0x89, 0xd3, 0xff, 0x75, 0xff, + 0x7b, 0x67, 0x55, 0xdb, 0x52, 0x74, 0x61, 0xf7, + 0xd4, 0x96, 0x7f, 0xfa, 0xf5, 0x5b, 0x73, 0x6c, + 0xea, 0xf7, 0xb6, 0x3a, 0x7a, 0xf5, 0xfa, 0x9d, + 0x3f, 0x3b, 0xb7, 0x05, 0xde, 0xa3, 0xd3, 0xa2, + 0xa7, 0xb9, 0xa2, 0x18, 0xe5, 0x1d, 0xe2, 0x43, + 0xa8, 0x56, 0x4f, 0xff, 0x7e, 0xb7, 0xce, 0xab, + 0xfe, 0xfb, 0xc1, 0xf9, 0xd3, 0xff, 0xf8, 0x75, + 0x7b, 0xfb, 0x6b, 0xfe, 0x33, 0xd7, 0xc7, 0x1c, + 0x15, 0x3d, 0xcd, 0xdf, 0x72, 0xa7, 0xb3, 0xcc, + 0xd1, 0xd3, 0x9e, 0x3e, 0x9a, 0x21, 0x99, 0xdc, + 0x71, 0xc1, 0x53, 0xac, 0x50, 0xa5, 0x97, 0xf3, + 0xfe, 0xba, 0x2f, 0x9c, 0x78, 0xb5, 0x07, 0x47, + 0x87, 0xcc, 0x25, 0x13, 0xf9, 0xe3, 0x7a, 0xd7, + 0xb4, 0x1d, 0x0c, 0x9d, 0x65, 0x0c, 0x9c, 0x91, + 0xd2, 0x42, 0x10, 0xae, 0xc2, 0x29, 0xef, 0xeb, + 0xec, 0x74, 0xfe, 0xf6, 0xc3, 0xcf, 0x3e, 0x27, + 0x4f, 0xff, 0x3f, 0xfc, 0xef, 0xb5, 0x6c, 0x13, + 0x31, 0x0d, 0x10, 0x64, 0xff, 0xe0, 0xc7, 0x56, + 0x29, 0xbf, 0xf9, 0xdb, 0x47, 0x43, 0x22, 0xa3, + 0xd5, 0xc8, 0xda, 0x3f, 0xf5, 0x0d, 0xc9, 0xb7, + 0xe9, 0xd3, 0xc1, 0xfe, 0x3a, 0xe7, 0x47, 0xcd, + 0xed, 0x45, 0xe7, 0xf7, 0x55, 0xd7, 0xaa, 0xc1, + 0x8e, 0x87, 0xa7, 0xb9, 0xf8, 0xc8, 0x2a, 0xcb, + 0xa2, 0x19, 0xff, 0xe6, 0x1a, 0x3a, 0x39, 0xf1, + 0xbe, 0x6c, 0x7b, 0x9d, 0x39, 0x81, 0xc3, 0xa1, + 0x97, 0xb6, 0xf9, 0x3b, 0xb8, 0xe0, 0x90, 0xd7, + 0xf1, 0xff, 0x64, 0xa3, 0x9f, 0x51, 0x3a, 0x94, + 0xe7, 0xd8, 0xac, 0xba, 0x9d, 0x3f, 0xfc, 0x8d, + 0x5a, 0xb2, 0xaf, 0x5f, 0xae, 0xf0, 0xe9, 0xfc, + 0x22, 0xcf, 0x53, 0x7c, 0xe9, 0xfd, 0xaf, 0xba, + 0xfe, 0x9e, 0xc5, 0x49, 0x47, 0x4f, 0xd6, 0x3d, + 0xc1, 0x97, 0xf3, 0xc5, 0xec, 0x6b, 0x16, 0x98, + 0x47, 0xd3, 0x6a, 0xeb, 0x3c, 0x1e, 0xd2, 0xf3, + 0xa7, 0xf0, 0xbc, 0x6d, 0x4c, 0x87, 0x4e, 0x57, + 0x36, 0x74, 0x31, 0xf7, 0x59, 0x1e, 0x17, 0xce, + 0xd7, 0xe8, 0x3a, 0x7f, 0xde, 0xea, 0xbd, 0x83, + 0xc5, 0x7e, 0xa7, 0x4f, 0xfc, 0xc3, 0x9b, 0x6f, + 0x16, 0x15, 0xa9, 0x51, 0xca, 0x21, 0x54, 0x87, + 0x3e, 0xdf, 0xff, 0x4d, 0x4e, 0x82, 0xa7, 0xea, + 0xf6, 0x60, 0x65, 0x15, 0x05, 0x41, 0x50, 0x54, + 0x15, 0x0f, 0x3d, 0xff, 0x85, 0x78, 0x5b, 0xe8, + 0x57, 0x50, 0x53, 0xb0, 0x54, 0xdb, 0xb2, 0xa7, + 0xec, 0xcd, 0x38, 0xca, 0x2b, 0xa1, 0x6b, 0x27, + 0x70, 0xa8, 0x2a, 0x0a, 0x87, 0x96, 0x9f, 0x0a, + 0x82, 0xa0, 0xa8, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, + 0xa0, 0xde, 0x72, 0x15, 0xf0, 0xaf, 0x02, 0xaa, + 0x14, 0xe8, 0x2a, 0x0a, 0x82, 0xa1, 0xe5, 0xa5, + 0x42, 0xa0, 0xa8, 0x2a, 0x0a, 0x82, 0xa1, 0xe6, + 0xa3, 0xc0, 0xad, 0x05, 0x3b, 0x05, 0x41, 0x50, + 0x54, 0x15, 0x05, 0x45, 0x06, 0xa3, 0xb8, 0x50, + 0x05, 0x6c, 0x2a, 0x5d, 0xca, 0x82, 0xa0, 0xa8, + 0x2a, 0x0a, 0x8e, 0x4d, 0x45, 0x21, 0x5e, 0x05, + 0x7a, 0x15, 0x05, 0x41, 0x50, 0x54, 0xfb, 0x6d, + 0xe5, 0x6c, 0xa8, 0x2a, 0x1e, 0x79, 0xe8, 0x15, + 0xb0, 0xac, 0x0a, 0xf0, 0x9e, 0x48, 0x54, 0x15, + 0x05, 0x41, 0x50, 0x54, 0x3c, 0xd4, 0x52, 0x15, + 0xf0, 0xa7, 0x41, 0x50, 0x54, 0x15, 0x05, 0x41, + 0x50, 0xf3, 0x51, 0xc8, 0x56, 0xc2, 0x84, 0x2a, + 0x5b, 0x2a, 0x0a, 0x82, 0xa4, 0xf2, 0xa0, 0xaa, + 0x4b, 0x08, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0xa0, + 0xf9, 0x9e, 0x15, 0xdc, 0x69, 0x06, 0x9c, 0x0a, + 0xf0, 0x2b, 0x41, 0x52, 0xb2, 0xa0, 0xa8, 0x2a, + 0x4f, 0x2a, 0x0a, 0xa4, 0xb0, 0x82, 0xa0, 0xa8, + 0x63, 0xd2, 0x78, 0x57, 0xc6, 0x80, 0x69, 0x41, + 0x50, 0x54, 0x15, 0x05, 0x41, 0x50, 0x54, 0x31, + 0xb2, 0xa4, 0x28, 0x02, 0x94, 0x14, 0x21, 0x50, + 0x54, 0x15, 0x05, 0x40, 0x17, 0xd5, 0x0a, 0xd0, + 0x54, 0x15, 0x05, 0x41, 0x50, 0xa2, 0xf8, 0x42, + 0xb4, 0x15, 0x25, 0x15, 0x05, 0x41, 0x51, 0xe1, + 0x69, 0xe8, 0x54, 0x15, 0x05, 0x41, 0x50, 0x54, + 0x31, 0xa8, 0x70, 0x2b, 0x61, 0x5e, 0x85, 0x43, + 0x2f, 0xd9, 0x50, 0xe6, 0xf3, 0xde, 0x4a, 0x6d, + 0x71, 0x1b, 0xa9, 0x48, 0xfb, 0x3f, 0x5c, 0xf5, + 0xc3, 0xa0, 0x84, 0x72, 0x92, 0x36, 0x6f, 0x8c, + 0xde, 0x1d, 0x8b, 0xb5, 0x59, 0xf4, 0xc3, 0xeb, + 0xcb, 0xa6, 0x4e, 0x12, 0xba, 0x8b, 0x3b, 0x12, + 0x3b, 0x25, 0x4f, 0x9e, 0x2d, 0x75, 0x29, 0x69, + 0xac, 0x4e, 0xfb, 0x28, 0xa9, 0xef, 0xa6, 0x01, + 0xd3, 0xbf, 0xcd, 0x9d, 0x39, 0xbb, 0x2e, 0x94, + 0x47, 0x01, 0xc6, 0xc6, 0xf4, 0x3f, 0x3f, 0xb7, + 0xfe, 0x39, 0x06, 0xa0, 0xe8, 0xa5, 0x10, 0xae, + 0x28, 0x4d, 0xe3, 0x1d, 0x3f, 0x06, 0x0f, 0x66, + 0xf0, 0xe9, 0xb0, 0x0e, 0x97, 0xce, 0x42, 0xd2, + 0x48, 0x74, 0x94, 0x74, 0xdd, 0x4b, 0xfa, 0x25, + 0x00, 0x5b, 0x68, 0x38, 0x3d, 0xd8, 0x3e, 0x7f, + 0xb6, 0xca, 0xb7, 0x18, 0x68, 0x3a, 0x2d, 0x12, + 0x3e, 0x2c, 0xcf, 0xca, 0xff, 0x56, 0x0f, 0x87, + 0x4f, 0xff, 0x37, 0x4c, 0x00, 0xcf, 0x19, 0x7c, + 0x71, 0xc1, 0xd0, 0xc8, 0x82, 0xf4, 0xc2, 0x28, + 0x67, 0xba, 0x3e, 0x32, 0xde, 0x61, 0x3c, 0x85, + 0x9f, 0x85, 0x13, 0x84, 0x99, 0x4a, 0xa5, 0x18, + 0xd2, 0xb5, 0x0a, 0x59, 0xfc, 0xc3, 0xac, 0x1f, + 0x6c, 0xe9, 0xf9, 0xe3, 0xf7, 0xee, 0xce, 0x9f, + 0x51, 0xf0, 0x67, 0x9d, 0x00, 0x7a, 0x62, 0x59, + 0x3f, 0xed, 0xb0, 0x78, 0x37, 0xc6, 0x78, 0x74, + 0xeb, 0xb7, 0x0e, 0x95, 0xec, 0xf6, 0x7c, 0x3e, + 0x9f, 0xbd, 0x0f, 0x55, 0x82, 0x74, 0xf2, 0x9a, + 0xe8, 0x3a, 0x7d, 0x6e, 0x85, 0xa9, 0x3a, 0x3e, + 0x79, 0x35, 0x21, 0x9e, 0x61, 0xd2, 0x1d, 0x26, + 0xb4, 0xd6, 0x05, 0xe6, 0xa5, 0x1a, 0x76, 0xea, + 0x22, 0x9e, 0xf7, 0x01, 0xe7, 0x4f, 0x37, 0xae, + 0xe5, 0x4a, 0x9f, 0x3d, 0x7c, 0x71, 0xc1, 0xd0, + 0x27, 0xa5, 0xe9, 0x3c, 0x72, 0x89, 0x5b, 0x73, + 0x85, 0x2a, 0xe4, 0xf2, 0x3d, 0xbf, 0x61, 0xcd, + 0x3f, 0x07, 0xbe, 0x58, 0xa1, 0xd3, 0xfd, 0x40, + 0xdb, 0xf7, 0x7e, 0x54, 0xe9, 0xee, 0x79, 0x67, + 0x47, 0x4f, 0xff, 0x6d, 0x94, 0x8d, 0xab, 0x04, + 0xcc, 0x43, 0x45, 0xf1, 0x3b, 0x02, 0x83, 0x45, + 0xff, 0x0c, 0x7f, 0xc8, 0xad, 0x3f, 0xb8, 0xcd, + 0x55, 0xae, 0x83, 0xa7, 0xfe, 0x75, 0xae, 0xec, + 0x2f, 0xbd, 0xfd, 0x47, 0x4f, 0xd7, 0xc7, 0x6d, + 0xe6, 0x8e, 0x9f, 0xff, 0x6b, 0xb3, 0xd9, 0xd7, + 0xc7, 0xc0, 0xfb, 0x2a, 0xca, 0x9e, 0xdf, 0x6a, + 0x74, 0x74, 0x50, 0x8a, 0xcb, 0x2f, 0x45, 0x89, + 0xb5, 0x67, 0x4f, 0x83, 0xf4, 0x62, 0x8d, 0x30, + 0x9c, 0xf6, 0xbd, 0x6c, 0x34, 0xc2, 0x73, 0x78, + 0xc6, 0xa0, 0x4e, 0x7f, 0x0e, 0x77, 0xd3, 0x07, + 0x86, 0xa0, 0x4e, 0x7f, 0x56, 0xf7, 0xfa, 0xfb, + 0x41, 0xa6, 0x13, 0x9a, 0xf9, 0x34, 0xc2, 0x73, + 0x71, 0xc1, 0xe6, 0x13, 0x8b, 0x4d, 0x3e, 0x93, + 0x4f, 0x97, 0x28, 0x8e, 0xa8, 0x0e, 0x90, 0xb8, + 0x23, 0x96, 0x8b, 0x30, 0x99, 0x67, 0xd1, 0x2f, + 0xd2, 0x9f, 0xdf, 0x11, 0xe6, 0x46, 0x2b, 0x4f, + 0xac, 0x3c, 0xf5, 0x28, 0xaa, 0x7f, 0xf8, 0x6e, + 0xa0, 0xde, 0xe8, 0x7e, 0xeb, 0xb2, 0x8e, 0x86, + 0x5d, 0x0d, 0xe4, 0xe5, 0x21, 0x47, 0xb2, 0x0d, + 0x4b, 0x82, 0x74, 0x7b, 0x3e, 0xe6, 0xc3, 0xfd, + 0xce, 0x9f, 0x0d, 0xf6, 0xb7, 0x0e, 0x9f, 0xed, + 0xe2, 0xb7, 0xf6, 0xa5, 0xe7, 0x4f, 0xdd, 0x85, + 0xfd, 0x59, 0x41, 0xd1, 0xf3, 0xeb, 0xf0, 0xe6, + 0x05, 0x16, 0xda, 0x84, 0x9c, 0xff, 0xaf, 0x36, + 0xe7, 0xc7, 0x77, 0x49, 0xd0, 0xcb, 0xdc, 0x97, + 0x3a, 0x73, 0xf6, 0x7c, 0x86, 0xf8, 0x93, 0xcf, + 0xfe, 0x56, 0xab, 0xf1, 0xa5, 0xfa, 0xfd, 0x7e, + 0x74, 0xff, 0xfe, 0x1b, 0xa6, 0xeb, 0x83, 0xbf, + 0xb6, 0xb7, 0xee, 0x28, 0xe9, 0xf8, 0x7d, 0x57, + 0xf6, 0xc7, 0x4f, 0xff, 0xb0, 0x75, 0x99, 0xb1, + 0x6d, 0x57, 0x8b, 0xd9, 0xd3, 0x82, 0xb5, 0x3c, + 0x40, 0x73, 0xff, 0xdd, 0x81, 0xb6, 0xdd, 0x2c, + 0x13, 0x31, 0x0d, 0x10, 0x1a, 0xcd, 0x44, 0x78, + 0x8e, 0x4d, 0x3d, 0x45, 0xa6, 0x6b, 0xf8, 0xc4, + 0x67, 0x87, 0x5e, 0x7a, 0x74, 0xff, 0xfc, 0xfb, + 0xaf, 0xc0, 0x3e, 0xae, 0xda, 0xdd, 0xf1, 0xa3, + 0xa2, 0xd1, 0x01, 0x84, 0x73, 0xff, 0xfd, 0x8f, + 0xb1, 0x71, 0xf7, 0x4b, 0xfb, 0x37, 0x8b, 0xe3, + 0x8e, 0x0a, 0x8d, 0xa2, 0x38, 0x48, 0x67, 0xf3, + 0x58, 0x26, 0x62, 0x1a, 0x20, 0x99, 0xfe, 0x6d, + 0x58, 0x26, 0x62, 0x1a, 0x2f, 0x99, 0xf7, 0xdd, + 0x0d, 0xd7, 0x93, 0xfa, 0x43, 0xa9, 0xfd, 0xee, + 0xfa, 0xb7, 0xf4, 0xd9, 0xd3, 0xfe, 0xa3, 0x29, + 0xea, 0xbd, 0x0e, 0x3a, 0x3a, 0x77, 0x1c, 0x70, + 0x54, 0xfd, 0xad, 0xda, 0x60, 0x14, 0xb2, 0xfe, + 0x28, 0x44, 0xd8, 0xb1, 0x4f, 0xfd, 0x42, 0x9a, + 0x9a, 0x8d, 0xd1, 0xd9, 0xe7, 0x4f, 0xff, 0x76, + 0xa4, 0x7a, 0x26, 0xff, 0xe7, 0x8c, 0x0f, 0x3a, + 0x7f, 0xde, 0xd5, 0xac, 0x74, 0xef, 0xf0, 0x87, + 0x4e, 0xe3, 0x8e, 0x0a, 0x9f, 0xdd, 0xbc, 0x61, + 0xba, 0x74, 0x52, 0xcb, 0xf9, 0xff, 0xf9, 0xdc, + 0xe8, 0x9b, 0xff, 0x3c, 0xdf, 0x1d, 0x35, 0x5b, + 0xa0, 0xe9, 0x66, 0xd1, 0x59, 0xea, 0x24, 0x3d, + 0x58, 0x4f, 0x28, 0x1f, 0x86, 0x90, 0x11, 0xa9, + 0x20, 0x55, 0x75, 0x18, 0x74, 0xfb, 0x77, 0xa7, + 0x1e, 0x74, 0xff, 0xaf, 0x4c, 0x15, 0xdb, 0x0e, + 0x8f, 0x10, 0x44, 0xfe, 0x6b, 0x04, 0xcc, 0x43, + 0x44, 0x10, 0xb3, 0xc8, 0x9f, 0xb3, 0x60, 0x1f, + 0xe0, 0xe9, 0xfb, 0xaf, 0xcf, 0x18, 0x2f, 0x3a, + 0x04, 0xf7, 0xbd, 0x2c, 0x8d, 0xa6, 0x77, 0xe3, + 0x80, 0xc2, 0xa6, 0x7f, 0x98, 0x75, 0xda, 0xf7, + 0x94, 0x9d, 0x3f, 0xfd, 0x9c, 0x6a, 0xf6, 0xdf, + 0xd0, 0xde, 0xfe, 0x74, 0x3d, 0x10, 0xe2, 0x73, + 0x3f, 0xdb, 0x60, 0xd0, 0xb5, 0xd2, 0x74, 0xff, + 0xff, 0x7e, 0x86, 0x7d, 0x40, 0x3f, 0x4b, 0x8f, + 0xc0, 0x55, 0xd2, 0x74, 0xf6, 0xb7, 0x63, 0xca, + 0x27, 0xb6, 0x6d, 0x3f, 0x76, 0x55, 0x78, 0xca, + 0x4e, 0x86, 0x3e, 0xbd, 0x1d, 0x4f, 0x7d, 0xcf, + 0xf0, 0x74, 0xff, 0xfb, 0xda, 0x05, 0xaf, 0x6b, + 0x6d, 0x5e, 0xfd, 0x03, 0xa7, 0xd7, 0xaa, 0xf6, + 0xaf, 0x27, 0xf3, 0xd8, 0x92, 0x7e, 0x4d, 0xff, + 0xab, 0xfd, 0xce, 0x9f, 0x94, 0xdd, 0x7d, 0xdd, + 0x07, 0x4f, 0xff, 0xff, 0x7f, 0x58, 0xac, 0x1f, + 0x1f, 0xfa, 0xfa, 0xad, 0xfd, 0xb5, 0xbf, 0x71, + 0x47, 0x47, 0x28, 0xe3, 0xf9, 0x96, 0x18, 0xce, + 0x0e, 0xd5, 0x3a, 0x7f, 0xd8, 0x29, 0x60, 0x99, + 0x88, 0x68, 0x84, 0x61, 0x8f, 0x87, 0xd1, 0xd9, + 0xff, 0xcd, 0x74, 0xf6, 0xd7, 0xc7, 0xd7, 0xdd, + 0x4e, 0x9f, 0xfe, 0xcc, 0xa3, 0xb5, 0xef, 0x14, + 0xbe, 0x38, 0xe0, 0xe8, 0xe5, 0x14, 0x0e, 0x26, + 0x4f, 0xf7, 0x2d, 0x5a, 0xb5, 0x17, 0xc1, 0xd1, + 0x67, 0xbf, 0x84, 0xb3, 0xb8, 0xe3, 0x82, 0xa7, + 0xfa, 0xfc, 0xc0, 0xb7, 0x57, 0xc9, 0x4b, 0x2f, + 0xe6, 0xe3, 0x82, 0xa7, 0x71, 0xc7, 0x05, 0x4f, + 0xd9, 0x47, 0x3b, 0x6a, 0x94, 0xb2, 0xfe, 0x05, + 0x17, 0x9c, 0x24, 0x75, 0x1b, 0xcf, 0x93, 0xfc, + 0xf6, 0x51, 0x4b, 0x36, 0x73, 0xb8, 0xe3, 0x82, + 0xa7, 0x55, 0x80, 0xa5, 0x97, 0xf2, 0xf3, 0xe8, + 0x82, 0xd2, 0xcc, 0xfd, 0xc8, 0xb3, 0xf1, 0x0e, + 0x9f, 0xdd, 0x83, 0x9f, 0xba, 0x6e, 0x4e, 0x9f, + 0xfb, 0x78, 0xf1, 0xce, 0xee, 0x0f, 0xdc, 0x3a, + 0x7e, 0xdd, 0xba, 0xbd, 0x54, 0xe8, 0x43, 0xf4, + 0xd2, 0x34, 0x02, 0x3e, 0x36, 0x56, 0x30, 0xac, + 0x86, 0x4d, 0x56, 0xe3, 0x22, 0x9d, 0x4f, 0x5a, + 0xee, 0xec, 0xe9, 0xff, 0xd7, 0xd7, 0xc1, 0xf2, + 0xd1, 0xb6, 0xca, 0x3a, 0x7e, 0x4f, 0xd7, 0x7f, + 0x70, 0xa9, 0xfc, 0x37, 0x4b, 0xeb, 0xfe, 0xe7, + 0x4f, 0x66, 0x07, 0x73, 0xa3, 0xa1, 0xeb, 0x50, + 0x6b, 0x3c, 0xd8, 0xa7, 0x45, 0x4e, 0xe3, 0x8e, + 0x0a, 0x9f, 0xfe, 0xec, 0xde, 0x5d, 0x8e, 0xb7, + 0xf6, 0x1a, 0x0a, 0x59, 0x7f, 0x2b, 0x44, 0x50, + 0x29, 0x06, 0x19, 0x3e, 0x67, 0x96, 0x52, 0x95, + 0xf8, 0x42, 0x6e, 0x18, 0xb3, 0xff, 0xe5, 0x5a, + 0x30, 0xe6, 0xab, 0xcf, 0xb8, 0x0f, 0x3a, 0x7c, + 0xda, 0xab, 0xab, 0x3a, 0x18, 0xfe, 0xf4, 0xa7, + 0x3f, 0xfd, 0xf7, 0x56, 0x3c, 0x8e, 0x71, 0x63, + 0x9d, 0xce, 0x9f, 0xff, 0xee, 0x77, 0xfe, 0x2d, + 0xdb, 0xea, 0xcd, 0x57, 0xd7, 0xdd, 0x3a, 0x3a, + 0x2d, 0x17, 0xf8, 0xa3, 0x0c, 0xda, 0x53, 0x50, + 0x98, 0xf8, 0xe5, 0x39, 0x8c, 0xde, 0xe5, 0xd2, + 0xfe, 0x3a, 0xb7, 0x21, 0x7a, 0x11, 0x95, 0xaa, + 0x13, 0x5b, 0x8c, 0x9f, 0xc8, 0x48, 0x8c, 0x64, + 0x35, 0x96, 0x0b, 0xa9, 0x41, 0xde, 0xc3, 0x43, + 0x88, 0x70, 0x4e, 0x74, 0xc2, 0x74, 0xff, 0xf5, + 0x8a, 0xf5, 0xdf, 0xf4, 0xd7, 0x77, 0xe6, 0x1d, + 0x2a, 0x5e, 0x7d, 0xdc, 0x8e, 0x4f, 0xdb, 0x73, + 0xfb, 0xfa, 0x8e, 0x9f, 0xf0, 0xb6, 0xb7, 0x9e, + 0x65, 0x35, 0x3a, 0x73, 0x9e, 0x81, 0xd3, 0xfe, + 0xcf, 0x85, 0xd2, 0xbe, 0x38, 0xe0, 0xe8, 0xc3, + 0xde, 0xa8, 0xec, 0xff, 0xf0, 0xb3, 0xfa, 0x76, + 0xd7, 0xc7, 0xd7, 0xdd, 0x4e, 0x8b, 0x4c, 0xfd, + 0x0b, 0xf7, 0x09, 0xcf, 0x08, 0x67, 0xf3, 0x0b, + 0xc6, 0xef, 0xc3, 0xa7, 0xf3, 0xec, 0x2a, 0x2d, + 0x41, 0xd3, 0xff, 0xd7, 0xa6, 0x14, 0xbd, 0x6f, + 0xe1, 0xe2, 0x1d, 0x3e, 0xca, 0xd8, 0xe8, 0xe9, + 0xda, 0xce, 0xb9, 0xd3, 0xfb, 0x5b, 0xfa, 0xfc, + 0xcf, 0x9d, 0x1c, 0xa3, 0x10, 0x53, 0x34, 0x4b, + 0xe8, 0xfc, 0xfe, 0xf7, 0xc6, 0xdf, 0xf1, 0xe7, + 0x4f, 0xf2, 0x5e, 0x99, 0xd7, 0xc7, 0xc3, 0xa7, + 0xff, 0xef, 0x5b, 0x55, 0xb1, 0xe8, 0x0d, 0xfe, + 0x47, 0x1e, 0x74, 0x7d, 0x12, 0x82, 0x73, 0x3f, + 0xff, 0x0d, 0xd7, 0xde, 0x97, 0xbc, 0x1b, 0x71, + 0xed, 0x49, 0xd3, 0xfe, 0xba, 0xfb, 0x60, 0x99, + 0x88, 0x68, 0x81, 0xa7, 0xb5, 0xbc, 0x7f, 0x44, + 0x51, 0x8a, 0xe4, 0x32, 0x60, 0x17, 0x0c, 0x59, + 0xff, 0x60, 0x58, 0xf9, 0x5d, 0x56, 0x93, 0xa7, + 0xff, 0xff, 0xeb, 0xd6, 0xf0, 0x7b, 0xf4, 0xa8, + 0x66, 0x69, 0xd5, 0xf3, 0xd2, 0xd5, 0x83, 0x4b, + 0xcf, 0x10, 0x5c, 0xff, 0xb3, 0x3b, 0xa6, 0x73, + 0xd3, 0xbf, 0x07, 0x88, 0x2e, 0x7f, 0xed, 0xff, + 0x7f, 0x61, 0xd7, 0x4e, 0xfc, 0x1e, 0x20, 0xb9, + 0xfc, 0xdf, 0x1d, 0x74, 0xef, 0xc1, 0xe2, 0x0b, + 0x9f, 0x95, 0x7c, 0xf4, 0xef, 0xc1, 0xe2, 0x0b, + 0x9f, 0xff, 0xec, 0x11, 0xfa, 0xba, 0x55, 0x37, + 0xf0, 0xff, 0x7a, 0x2f, 0x83, 0xc4, 0x17, 0x35, + 0x3d, 0x39, 0x4e, 0x89, 0x14, 0x41, 0x5b, 0x11, + 0x05, 0x02, 0x19, 0x56, 0x96, 0xcf, 0x86, 0x51, + 0xec, 0xfe, 0xfb, 0x77, 0xae, 0xab, 0x49, 0xd3, + 0xd8, 0x1e, 0x61, 0xd3, 0xff, 0x6f, 0xfb, 0xfb, + 0x0e, 0xba, 0x77, 0xe0, 0xf1, 0x05, 0xcf, 0xf3, + 0x95, 0x4f, 0xd1, 0xd3, 0xbf, 0x07, 0x88, 0x2e, + 0x7d, 0xaa, 0xb2, 0xba, 0x22, 0x28, 0xfb, 0x2b, + 0x4f, 0xfe, 0xe8, 0x9b, 0xfa, 0x36, 0xab, 0xd3, + 0xbf, 0x07, 0x88, 0x2e, 0x7f, 0xff, 0xe1, 0x1f, + 0xab, 0xa7, 0xb7, 0xd2, 0xa9, 0xbf, 0x87, 0xfb, + 0xd1, 0x7c, 0x1e, 0x20, 0xb8, 0xb4, 0xc9, 0xa9, + 0x43, 0xc5, 0xd9, 0xfe, 0xdf, 0xc3, 0xfd, 0xe8, + 0xbe, 0x0f, 0x10, 0x5c, 0xff, 0xf6, 0x65, 0x2f, + 0xae, 0xff, 0xcf, 0x2c, 0x0c, 0x54, 0xff, 0xad, + 0xef, 0xf6, 0xa0, 0x34, 0x75, 0x1e, 0x20, 0xb8, + 0x44, 0x74, 0x02, 0x4d, 0x54, 0x27, 0xfc, 0x9f, + 0x0d, 0x67, 0x95, 0xe9, 0xc1, 0xe2, 0x0b, 0x9f, + 0xb7, 0xfd, 0xef, 0xfe, 0x1a, 0x00, 0xb9, 0xf5, + 0xf9, 0xd3, 0xbf, 0x07, 0x88, 0x2e, 0x6b, 0xd2, + 0x1f, 0xb6, 0xcf, 0x22, 0x94, 0x78, 0x56, 0x18, + 0x93, 0xf2, 0xaf, 0x9e, 0x9d, 0xf8, 0x3c, 0x41, + 0x73, 0xfe, 0x4d, 0xfc, 0x3f, 0xde, 0x8b, 0xe0, + 0xf1, 0x05, 0xcd, 0x7d, 0x31, 0x11, 0xd5, 0x40, + 0x9f, 0xde, 0xfd, 0x58, 0x34, 0xbc, 0xf1, 0x05, + 0xcf, 0xfa, 0xfe, 0xea, 0xc6, 0xf9, 0xc7, 0x9e, + 0x20, 0xb5, 0x1e, 0x0c, 0x72, 0xbc, 0x1e, 0x06, + 0xfe, 0x1b, 0x0c, 0x7d, 0x35, 0x8c, 0x63, 0x51, + 0x8f, 0x7b, 0x0b, 0x7e, 0x1c, 0x27, 0xde, 0x57, + 0xcf, 0x18, 0xd1, 0x05, 0xad, 0x11, 0xb3, 0xfe, + 0xb7, 0xef, 0x1e, 0xec, 0xed, 0xed, 0x07, 0x4e, + 0x53, 0x3c, 0xe9, 0xf5, 0xf3, 0xbf, 0x78, 0x3a, + 0x41, 0x87, 0x8a, 0x23, 0x73, 0xbf, 0xd5, 0x67, + 0x4e, 0xc0, 0xf0, 0xe9, 0x52, 0xc6, 0xe7, 0x43, + 0xd3, 0xf5, 0xd1, 0x9b, 0x6e, 0xb9, 0xd1, 0xf4, + 0x5a, 0xe2, 0xf0, 0x93, 0xce, 0xc0, 0xa0, 0xe9, + 0xbc, 0x63, 0xa7, 0xbe, 0xca, 0xb3, 0xa0, 0xe9, + 0xfb, 0x3b, 0xe9, 0x83, 0xc3, 0xa3, 0x93, 0x70, + 0x21, 0x53, 0xff, 0xf9, 0xbf, 0xc8, 0xb7, 0xa9, + 0xab, 0x4e, 0x59, 0x3b, 0x28, 0xe9, 0xbc, 0x63, + 0xa6, 0x6e, 0xe7, 0x4f, 0xf5, 0xea, 0xac, 0xae, + 0xd6, 0xe1, 0xd3, 0xfa, 0xb7, 0xbf, 0xd7, 0xda, + 0x0e, 0x9b, 0x8e, 0x0a, 0x9f, 0xe1, 0xb7, 0x58, + 0xfa, 0xff, 0x93, 0xa1, 0x13, 0xf9, 0xf8, 0xd8, + 0x0b, 0x29, 0x63, 0x64, 0x3e, 0x30, 0xbb, 0x82, + 0xc2, 0x2f, 0x53, 0xae, 0x0d, 0x7b, 0x0c, 0x4e, + 0xe3, 0x8e, 0x0a, 0x92, 0x8a, 0x59, 0x7f, 0x3e, + 0xc7, 0x33, 0x00, 0xa5, 0xa3, 0x77, 0xb4, 0x2f, + 0xa7, 0xf5, 0x3a, 0x6b, 0xdd, 0xd0, 0x74, 0x33, + 0x66, 0xed, 0x71, 0xb4, 0xf7, 0x42, 0xa4, 0xc3, + 0xf0, 0xf5, 0x03, 0xed, 0xc7, 0x91, 0x94, 0x99, + 0x51, 0x49, 0xac, 0x68, 0x1e, 0xcb, 0x04, 0x74, + 0x97, 0x3d, 0x68, 0xda, 0x3a, 0x7a, 0xd5, 0x7a, + 0x3a, 0x7f, 0xed, 0xfb, 0x47, 0xab, 0xdf, 0xd3, + 0x00, 0xe9, 0xec, 0xa3, 0xb3, 0xce, 0x86, 0x45, + 0x4d, 0x23, 0xfa, 0x20, 0x76, 0x46, 0x9f, 0x87, + 0xde, 0x55, 0x8f, 0x3a, 0x7f, 0xfa, 0x97, 0x8b, + 0x74, 0x50, 0xb7, 0x7d, 0x7e, 0x83, 0xa7, 0xf5, + 0x74, 0xea, 0xc6, 0xf9, 0x3a, 0x19, 0x16, 0xdf, + 0x2e, 0xc5, 0x49, 0xd9, 0xd3, 0xb1, 0xd3, 0xff, + 0xc2, 0xfe, 0x97, 0xcf, 0xeb, 0x4e, 0xbd, 0xca, + 0x9d, 0x1d, 0x0f, 0xce, 0xc7, 0xe7, 0xea, 0x1c, + 0x7f, 0x58, 0x14, 0x1d, 0x33, 0xe8, 0x3a, 0x7d, + 0xbb, 0xfb, 0xea, 0x74, 0xff, 0xf6, 0xdb, 0xb2, + 0xf4, 0x39, 0xe5, 0x6a, 0xde, 0x15, 0x3f, 0xbc, + 0xb0, 0x4c, 0xc4, 0x3c, 0x40, 0x93, 0xb5, 0xfa, + 0x0e, 0x87, 0xa3, 0x4b, 0x92, 0x70, 0x52, 0x51, + 0xe4, 0xce, 0xcf, 0x3a, 0x7b, 0x54, 0x60, 0x9d, + 0x3d, 0x4d, 0x73, 0x47, 0x45, 0x07, 0xb9, 0x63, + 0x3b, 0x21, 0x9f, 0xc3, 0x9c, 0x56, 0xad, 0xe1, + 0xd3, 0xb8, 0xe3, 0x83, 0xd5, 0xf5, 0x3b, 0x07, + 0x92, 0xd5, 0xf4, 0x59, 0xac, 0x8e, 0x51, 0x31, + 0xe2, 0xfc, 0xff, 0xfa, 0xc7, 0xfd, 0xd7, 0x5d, + 0x6f, 0xdc, 0x7b, 0xd8, 0xe8, 0xa0, 0xff, 0x3b, + 0x92, 0xcf, 0xb0, 0x47, 0xea, 0x3a, 0x3a, 0xda, + 0xb4, 0x47, 0x9a, 0xdc, 0x3a, 0x7f, 0x09, 0x9c, + 0x8d, 0x0c, 0x49, 0x67, 0xdf, 0xd3, 0x6a, 0xa5, + 0x4f, 0x23, 0x6a, 0xa5, 0x4d, 0xc7, 0x05, 0x43, + 0xcf, 0x7e, 0xc9, 0xf8, 0x20, 0x9a, 0xf8, 0x29, + 0x66, 0xbe, 0x7f, 0xfd, 0x7a, 0x64, 0xbb, 0x1d, + 0x6f, 0xec, 0x34, 0x1d, 0x1e, 0x1f, 0xbf, 0x04, + 0xd3, 0xff, 0xf9, 0x9d, 0x7c, 0x7c, 0xe9, 0xaa, + 0xda, 0x6f, 0x07, 0x55, 0x3a, 0x7f, 0x39, 0x4b, + 0xf7, 0xeb, 0x01, 0xd3, 0x9f, 0x80, 0x74, 0xf9, + 0xf7, 0xab, 0xe4, 0xa9, 0x7d, 0xc3, 0xc1, 0xd0, + 0xd4, 0xf6, 0xbb, 0xde, 0xce, 0x9b, 0xc6, 0x3a, + 0x6f, 0x18, 0xe9, 0xf7, 0xaf, 0xb1, 0x5f, 0xcd, + 0x67, 0x82, 0xd0, 0xc8, 0x8e, 0x14, 0xf9, 0xff, + 0xb5, 0xbb, 0x57, 0x66, 0xf2, 0xe9, 0xd1, 0xd3, + 0xfa, 0x94, 0xf8, 0x76, 0x6e, 0x4e, 0x9e, 0xf1, + 0x58, 0xfa, 0x9f, 0xe6, 0x91, 0xe7, 0x75, 0x5d, + 0x27, 0x4f, 0x78, 0x1f, 0x03, 0xa1, 0x8f, 0xeb, + 0x0e, 0xb8, 0x1f, 0x9e, 0xaf, 0xb4, 0xe8, 0xe9, + 0xdc, 0x71, 0xc1, 0x53, 0xeb, 0xee, 0x3e, 0xd4, + 0xa5, 0x97, 0xf3, 0xeb, 0x5f, 0x1c, 0x70, 0x74, + 0x31, 0xf1, 0x68, 0xe2, 0x7b, 0x8c, 0x17, 0x9d, + 0x3f, 0xda, 0x6a, 0x7c, 0xcd, 0xef, 0xe7, 0x4b, + 0x67, 0x45, 0x9e, 0x52, 0x1d, 0x4e, 0xe3, 0x8e, + 0x0a, 0x9f, 0xbf, 0x9d, 0xf7, 0xfd, 0x14, 0xb2, + 0xfe, 0x7d, 0x7e, 0x5d, 0xb8, 0x74, 0xab, 0xd1, + 0x14, 0x80, 0x7e, 0x27, 0xd3, 0xdf, 0x1f, 0x5f, + 0xca, 0x68, 0xb7, 0x18, 0x7c, 0x32, 0xea, 0x33, + 0xc9, 0x2d, 0x8f, 0xbb, 0xb0, 0x42, 0xdf, 0x71, + 0x8b, 0xe1, 0x75, 0x61, 0x4b, 0xa8, 0xd9, 0xa7, + 0xe6, 0x50, 0x06, 0x68, 0xe9, 0xff, 0xef, 0xaa, + 0x97, 0xd7, 0xa5, 0x88, 0xdf, 0xfc, 0x3a, 0x36, + 0x7f, 0x9a, 0x2a, 0x92, 0xdd, 0xe8, 0x4c, 0x53, + 0xf5, 0xa8, 0xa7, 0xad, 0x0a, 0x5a, 0x71, 0x36, + 0x88, 0xef, 0x1f, 0x2a, 0xa7, 0x99, 0x64, 0xb7, + 0x5c, 0x53, 0x77, 0x8e, 0x35, 0x25, 0x4c, 0xd3, + 0x2b, 0xe3, 0xf1, 0xe4, 0x39, 0x3d, 0xf6, 0x13, + 0xb7, 0xea, 0x95, 0xeb, 0xba, 0x41, 0x2e, 0x53, + 0xff, 0x3c, 0x97, 0x14, 0x33, 0xe4, 0x75, 0xad, + 0x3f, 0x35, 0x5a, 0x8b, 0x7b, 0x1b, 0xdb, 0xa8, + 0x7b, 0x71, 0x0a, 0x1e, 0xa9, 0x6c, 0xfd, 0xa7, + 0xad, 0xdd, 0xa3, 0x11, 0x85, 0xc2, 0x6e, 0x05, + 0xf8, 0x99, 0x39, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, + 0x34, 0x5c, 0x73, 0xf9, 0x76, 0x09, 0x98, 0x86, + 0x8b, 0xae, 0x7f, 0xe5, 0xe3, 0xd7, 0x60, 0x99, + 0x88, 0x68, 0x94, 0x61, 0xa1, 0x3d, 0xac, 0xf2, + 0x8e, 0x4e, 0xfb, 0x9d, 0xa1, 0xdf, 0xe1, 0xe3, + 0xd7, 0x3f, 0xcc, 0x4d, 0xe9, 0xd4, 0xe3, 0x47, + 0x6e, 0xc7, 0x73, 0xff, 0x96, 0xac, 0x7a, 0xec, + 0x13, 0x31, 0x0d, 0x12, 0xd4, 0xf8, 0x13, 0x31, + 0x0d, 0x11, 0xbc, 0xff, 0xb1, 0xeb, 0xb0, 0x4c, + 0xc4, 0x34, 0x4b, 0xf2, 0x5d, 0x9f, 0xb2, 0x8c, + 0x27, 0xf2, 0xec, 0x13, 0x31, 0x0d, 0x15, 0x5c, + 0xff, 0x77, 0xb1, 0xba, 0x75, 0x8a, 0x3a, 0x6e, + 0x7e, 0x74, 0xfd, 0x60, 0x99, 0x88, 0x68, 0x90, + 0x23, 0xa1, 0xe6, 0x2c, 0x5e, 0x7d, 0x5c, 0x1c, + 0xa4, 0xe8, 0x79, 0xe5, 0x52, 0x49, 0x3f, 0xfa, + 0xdc, 0xde, 0x2b, 0x5b, 0x6d, 0x7a, 0xa3, 0xa3, + 0xba, 0x67, 0xb9, 0x0c, 0xfe, 0xc4, 0x73, 0xff, + 0x0d, 0xd0, 0xbe, 0xa6, 0x11, 0xbd, 0x1d, 0x0b, + 0x3f, 0xd0, 0x39, 0x9f, 0xcb, 0xb0, 0x4c, 0xc4, + 0x34, 0x59, 0x13, 0xf9, 0x76, 0x09, 0x98, 0x86, + 0x8b, 0x5e, 0x7f, 0x2e, 0xc1, 0x33, 0x10, 0xd1, + 0x72, 0x4f, 0x81, 0x33, 0x10, 0xd1, 0x76, 0x4f, + 0xfb, 0x1e, 0xbb, 0x04, 0xcc, 0x43, 0x45, 0x1d, + 0x25, 0xd9, 0xfb, 0x28, 0xc2, 0x7c, 0x09, 0x98, + 0x86, 0x8a, 0x56, 0x7f, 0xff, 0xfb, 0x6d, 0x43, + 0x6f, 0xee, 0xb3, 0x9d, 0xfd, 0x69, 0xbf, 0xb9, + 0xb6, 0xa2, 0xce, 0x9f, 0x2d, 0x58, 0xf5, 0xda, + 0x2c, 0x9c, 0x30, 0x8a, 0x17, 0x51, 0x5f, 0x0c, + 0x8a, 0x49, 0xff, 0x1f, 0xaa, 0x88, 0x7c, 0x3b, + 0xa9, 0xde, 0xa1, 0x62, 0xea, 0x1b, 0x33, 0xfc, + 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x23, 0x89, 0xfe, + 0xfa, 0xec, 0x13, 0x31, 0x0d, 0x15, 0xac, 0x97, + 0x88, 0x82, 0xd2, 0x0c, 0xff, 0xe5, 0xab, 0x1e, + 0xbb, 0x04, 0xcc, 0x43, 0x44, 0xb7, 0x35, 0xd2, + 0x74, 0xfe, 0xe6, 0xd4, 0xa6, 0xfd, 0x4e, 0x8a, + 0x4f, 0x27, 0xe2, 0xd3, 0xb7, 0xcb, 0xce, 0x9c, + 0xf5, 0x21, 0xd3, 0xff, 0xf6, 0xf2, 0x9f, 0x39, + 0xde, 0x3e, 0xea, 0x3e, 0xe7, 0x63, 0xa0, 0xd1, + 0x0d, 0xcf, 0xfb, 0x1e, 0xbb, 0x04, 0xcc, 0x43, + 0x44, 0xc1, 0x38, 0x3d, 0xf0, 0xa9, 0xfc, 0x37, + 0xad, 0x30, 0x54, 0xe9, 0x2d, 0x93, 0x64, 0xa0, + 0x8f, 0x91, 0xdb, 0x1b, 0x45, 0xf5, 0x0b, 0xe9, + 0x1b, 0xb0, 0xec, 0xe5, 0x7a, 0x05, 0x4f, 0xfb, + 0x1e, 0xbb, 0x04, 0xcc, 0x43, 0x44, 0xc7, 0x25, + 0xfc, 0xf8, 0x94, 0x39, 0x3f, 0x35, 0x7a, 0x6a, + 0xf6, 0x74, 0xe6, 0x1a, 0x0e, 0x9f, 0xff, 0xfe, + 0x7d, 0x77, 0x7e, 0xf1, 0x5d, 0xda, 0x5d, 0x7a, + 0x5d, 0x2f, 0xaf, 0xc7, 0xe7, 0x4f, 0x26, 0x62, + 0x1a, 0x2b, 0x19, 0xff, 0x75, 0x5e, 0x86, 0xfd, + 0x61, 0xd1, 0xd1, 0xdd, 0x33, 0x44, 0x2e, 0xa4, + 0x6c, 0x21, 0x03, 0xa2, 0xb9, 0xff, 0xcc, 0x3a, + 0xef, 0xeb, 0x0d, 0xa3, 0x01, 0xd3, 0xfd, 0xce, + 0xee, 0xb4, 0xbd, 0xb6, 0x74, 0xff, 0x35, 0x2f, + 0x71, 0xf8, 0x14, 0x1d, 0x16, 0x7e, 0x9f, 0x3a, + 0x9f, 0xf5, 0xf2, 0x1f, 0xf6, 0x8f, 0x2a, 0xf3, + 0xa7, 0xff, 0xfe, 0x1f, 0x68, 0xb4, 0xe8, 0x3e, + 0xbb, 0x74, 0xba, 0x5f, 0x7e, 0x8f, 0x95, 0x3a, + 0x7f, 0x75, 0xba, 0x1c, 0x7f, 0x58, 0x14, 0x1d, + 0x3f, 0xfa, 0xdc, 0xde, 0x2b, 0x5b, 0x6d, 0x7a, + 0xa3, 0xa7, 0x6f, 0xeb, 0xb5, 0x4e, 0xe8, 0xa3, + 0xb8, 0x5d, 0x89, 0x0e, 0x90, 0xba, 0x9f, 0x3b, + 0x20, 0xcd, 0xdb, 0xc3, 0xa6, 0xf5, 0xc3, 0xa7, + 0xd8, 0x34, 0x7b, 0x53, 0xa3, 0xc3, 0xd9, 0x11, + 0x9a, 0x8c, 0x4f, 0xbd, 0xa6, 0x86, 0xee, 0x74, + 0xf9, 0x56, 0x2c, 0xf3, 0xa7, 0x98, 0x30, 0x4e, + 0x9e, 0xad, 0x5b, 0xc3, 0xa1, 0x8f, 0x97, 0x64, + 0xbc, 0x0f, 0x4f, 0x99, 0xfe, 0x7a, 0xf3, 0xa7, + 0x30, 0xbc, 0xe8, 0x70, 0xf0, 0xf4, 0x53, 0x3b, + 0x7d, 0x94, 0x74, 0xfc, 0xca, 0xb1, 0xff, 0x73, + 0xa5, 0x53, 0xa3, 0xe6, 0xf7, 0x0b, 0x66, 0xf1, + 0x8a, 0x9b, 0x8e, 0x0a, 0x8f, 0x9a, 0xee, 0x05, + 0xa7, 0xf6, 0x3c, 0x6f, 0x5b, 0xf9, 0x4b, 0x34, + 0x53, 0xdc, 0xe5, 0x35, 0x3a, 0x73, 0x0b, 0x87, + 0x4c, 0x2c, 0x74, 0x38, 0x6b, 0xc0, 0x6e, 0x7f, + 0xee, 0xff, 0x14, 0xab, 0x2b, 0x29, 0xd1, 0xd3, + 0xbc, 0xb7, 0x63, 0xa3, 0xb9, 0xf2, 0x02, 0x2c, + 0xbb, 0x9d, 0x30, 0x77, 0x3a, 0x3e, 0x6a, 0x7b, + 0x09, 0x43, 0x26, 0x8d, 0x6a, 0x5f, 0x84, 0x2e, + 0xd3, 0x26, 0xde, 0x8e, 0x9f, 0xbc, 0x6d, 0xdb, + 0xac, 0x3a, 0x7e, 0xfe, 0xaf, 0x79, 0xdc, 0xe9, + 0xdc, 0x71, 0xc1, 0x53, 0xff, 0x5a, 0x72, 0xd4, + 0x76, 0xbd, 0xe5, 0x25, 0x2c, 0xbf, 0x9e, 0xf8, + 0x3b, 0x72, 0x74, 0x80, 0xe9, 0xf2, 0xbf, 0xaf, + 0x30, 0xe8, 0xa0, 0xf7, 0x3a, 0xe4, 0xbe, 0x87, + 0xcf, 0xe4, 0xfd, 0x46, 0xdd, 0x61, 0xd3, 0x5e, + 0x8e, 0x8a, 0x4f, 0x1f, 0x66, 0x53, 0xda, 0x1b, + 0x79, 0xd3, 0xff, 0xbf, 0x5d, 0xdf, 0x23, 0x6e, + 0x86, 0xea, 0x74, 0x01, 0xf5, 0x68, 0x82, 0x4b, + 0x65, 0xe5, 0x4a, 0x0b, 0xf9, 0x84, 0x8d, 0xb9, + 0x7c, 0x8c, 0x16, 0xd4, 0xe1, 0xb8, 0xe1, 0xf1, + 0x07, 0xc1, 0x67, 0x70, 0xb8, 0x53, 0x6b, 0x0b, + 0x1d, 0x3e, 0x76, 0x84, 0x6c, 0xf8, 0x13, 0x31, + 0x0d, 0x15, 0xbc, 0xff, 0xb1, 0xeb, 0xb0, 0x4c, + 0xc4, 0x34, 0x4e, 0x12, 0x5d, 0x9f, 0xb2, 0x8c, + 0x26, 0xf7, 0x67, 0x4f, 0x81, 0x33, 0x10, 0xd1, + 0x68, 0xcd, 0xfe, 0xe7, 0x4f, 0xff, 0xa8, 0x6d, + 0x37, 0x20, 0xdb, 0xca, 0x8d, 0xf8, 0x74, 0xff, + 0x9a, 0x9c, 0xeb, 0xec, 0x73, 0xaf, 0x41, 0xd0, + 0xc8, 0x9a, 0xda, 0xa4, 0xad, 0xc4, 0x6a, 0x56, + 0x16, 0x52, 0x5b, 0xbc, 0x9a, 0x4d, 0x8b, 0xee, + 0x30, 0x49, 0xe4, 0xcc, 0x43, 0x45, 0xb5, 0x3f, + 0x6d, 0x94, 0xdf, 0xe4, 0xe9, 0x58, 0x1e, 0xc6, + 0x8a, 0xe7, 0xf9, 0x7d, 0xfb, 0xe0, 0x73, 0xe8, + 0x9d, 0x0b, 0x3e, 0x3f, 0x09, 0xa7, 0xf2, 0xec, + 0x13, 0x31, 0x0d, 0x17, 0x2c, 0xfe, 0x5d, 0x82, + 0x66, 0x21, 0xa2, 0xed, 0x86, 0x6c, 0x9a, 0xe8, + 0x28, 0x7c, 0x7f, 0xfc, 0xc3, 0x6f, 0xbc, 0xbd, + 0x3f, 0xcf, 0x96, 0x75, 0xe3, 0x65, 0xdc, 0x6e, + 0x03, 0x0f, 0xca, 0x91, 0xe8, 0xee, 0x7f, 0x2e, + 0xc1, 0x33, 0x10, 0xd1, 0x53, 0xcd, 0xfd, 0x1d, + 0x3c, 0x99, 0x88, 0x68, 0xae, 0x67, 0xf2, 0xec, + 0x13, 0x31, 0x0d, 0x16, 0x74, 0x01, 0xf3, 0x6c, + 0xae, 0x7c, 0x09, 0x98, 0x86, 0x89, 0x0a, 0x7f, + 0xbf, 0x4d, 0x74, 0x2c, 0xaa, 0x9d, 0x33, 0xd7, + 0x67, 0xd3, 0xe1, 0x84, 0xf3, 0xbd, 0xb6, 0x51, + 0xd3, 0xfa, 0xf7, 0x5a, 0xd8, 0x50, 0x74, 0x97, + 0xca, 0x71, 0x96, 0xf9, 0x90, 0x8a, 0xa9, 0x76, + 0x89, 0xa7, 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, + 0x62, 0x1a, 0x27, 0xc8, 0x45, 0x4d, 0xdd, 0x78, + 0xf1, 0xf6, 0xab, 0x3e, 0x04, 0xcc, 0x43, 0x45, + 0x65, 0x3f, 0xec, 0x7a, 0xec, 0x13, 0x31, 0x0d, + 0x13, 0x74, 0xdf, 0x5d, 0x9f, 0xb2, 0x8c, 0x27, + 0xc0, 0x99, 0x88, 0x68, 0x95, 0xa7, 0xfb, 0xbe, + 0xff, 0xd3, 0xd4, 0xba, 0x9d, 0x3e, 0x5a, 0xb1, + 0xeb, 0xb3, 0xed, 0xc3, 0x09, 0xff, 0x7e, 0xbe, + 0xa8, 0x7e, 0xeb, 0xdc, 0x3a, 0x7f, 0x0b, 0x05, + 0xba, 0xc5, 0x1d, 0x0f, 0x3f, 0x3f, 0xa1, 0x4f, + 0x81, 0x33, 0x10, 0xd1, 0x2e, 0x4f, 0xf7, 0xf1, + 0xfa, 0x16, 0x55, 0x4e, 0x9e, 0x75, 0xf1, 0x63, + 0xa7, 0xcb, 0x56, 0x3d, 0x6c, 0x8a, 0xbb, 0x22, + 0xd9, 0x86, 0x1b, 0xcf, 0xfc, 0xbc, 0x7a, 0xec, + 0x13, 0x31, 0x0d, 0x11, 0xdc, 0xff, 0x6b, 0x76, + 0xf5, 0xe0, 0xd4, 0xe9, 0xfb, 0xac, 0x16, 0x4b, + 0x13, 0xa6, 0xf7, 0x67, 0x4f, 0xce, 0xf8, 0xde, + 0xf3, 0x47, 0x4f, 0xeb, 0xe2, 0xac, 0x3a, 0xa9, + 0xd3, 0xe0, 0x4c, 0xc4, 0x34, 0x54, 0x33, 0xdb, + 0xd5, 0xd0, 0x74, 0xfa, 0xe8, 0xc1, 0x74, 0x74, + 0xff, 0xff, 0xfe, 0x67, 0xf4, 0xd6, 0xfe, 0xd5, + 0xe9, 0x7e, 0xa3, 0x3a, 0xe9, 0x60, 0x16, 0xeb, + 0xdc, 0xd9, 0xd1, 0x68, 0xe0, 0x12, 0x2a, 0x94, + 0x4f, 0xff, 0xf7, 0xb9, 0xd7, 0xfd, 0x1b, 0xcf, + 0xe9, 0xb7, 0xfd, 0x56, 0xf9, 0x3a, 0x4b, 0x77, + 0xd5, 0x29, 0x3b, 0xc5, 0xdd, 0x60, 0xbd, 0x06, + 0x16, 0x65, 0xa8, 0xc4, 0x3a, 0x8b, 0xa7, 0xc0, + 0x99, 0x88, 0x68, 0xaa, 0x27, 0xfd, 0x8f, 0x5d, + 0x82, 0x66, 0x21, 0xa2, 0x6b, 0x92, 0xec, 0xfd, + 0x94, 0x61, 0x3f, 0x97, 0x60, 0x99, 0x88, 0x68, + 0xab, 0x27, 0xfe, 0x5e, 0x3d, 0x76, 0x09, 0x98, + 0x86, 0x89, 0x12, 0x7c, 0x09, 0x98, 0x86, 0x8b, + 0x4a, 0x7f, 0xd8, 0xf5, 0xd8, 0x26, 0x62, 0x1a, + 0x27, 0xd9, 0x2e, 0xcf, 0xd9, 0x46, 0x13, 0xff, + 0x96, 0xac, 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x14, + 0x24, 0xfb, 0x7f, 0xa1, 0x80, 0xe9, 0xf0, 0x26, + 0x62, 0x1a, 0x28, 0xf9, 0xff, 0x0b, 0x38, 0xc2, + 0xce, 0x6d, 0x8e, 0x9f, 0xff, 0xaf, 0x9d, 0xb7, + 0x65, 0xe8, 0x73, 0xca, 0xd5, 0xbc, 0x2a, 0x7c, + 0xb5, 0x63, 0xd6, 0xc8, 0xf1, 0xb2, 0x7d, 0x18, + 0x75, 0x1e, 0x43, 0x32, 0x1a, 0xa8, 0x8d, 0x6d, + 0xea, 0xf6, 0x99, 0xde, 0x54, 0x4a, 0x43, 0xea, + 0x92, 0x77, 0x0e, 0xf7, 0x0c, 0x2f, 0x09, 0xf5, + 0x1a, 0x1c, 0xfe, 0x5d, 0x82, 0x66, 0x21, 0xa2, + 0x22, 0x9f, 0xac, 0x13, 0x31, 0x0d, 0x11, 0x5c, + 0xff, 0x75, 0xd7, 0x60, 0x99, 0x88, 0x68, 0xae, + 0x21, 0x67, 0xf5, 0x86, 0xb3, 0xd7, 0xbc, 0xd1, + 0xd3, 0xfa, 0xfe, 0x1e, 0x79, 0xed, 0x4e, 0x93, + 0xbe, 0x27, 0xab, 0x52, 0x09, 0xff, 0xfb, 0x55, + 0xfe, 0xf3, 0xef, 0xf8, 0xeb, 0xdd, 0x85, 0x9d, + 0x3e, 0x04, 0xcc, 0x43, 0x45, 0x3d, 0x3f, 0x5d, + 0x7a, 0x0e, 0x3c, 0xe8, 0xeb, 0x11, 0xc8, 0xc5, + 0x96, 0xb6, 0x26, 0x13, 0xff, 0xb1, 0xeb, 0xe4, + 0x73, 0x8a, 0xd5, 0xbc, 0x3a, 0x16, 0x88, 0xae, + 0x4f, 0xe7, 0x2f, 0x9b, 0x3a, 0x7c, 0xcf, 0xf3, + 0xd7, 0x9d, 0x3c, 0x99, 0x88, 0x68, 0xac, 0xe1, + 0xc3, 0xd4, 0x02, 0x99, 0xfa, 0x85, 0x30, 0xbe, + 0xa7, 0x4e, 0x6a, 0x3e, 0x74, 0xfb, 0x5e, 0x76, + 0x17, 0x9d, 0x3b, 0xdc, 0xa9, 0xd3, 0xeb, 0x72, + 0x8f, 0x7c, 0x3a, 0x4b, 0xb4, 0x6e, 0x01, 0x16, + 0xcb, 0x70, 0x70, 0x4a, 0xbb, 0x0e, 0x4f, 0xfc, + 0xbc, 0x7a, 0xec, 0x13, 0x31, 0x0d, 0x12, 0x2c, + 0xfd, 0x60, 0x99, 0x88, 0x68, 0xb2, 0x67, 0xff, + 0x6a, 0xbd, 0xaa, 0xbb, 0xa3, 0xe2, 0xfa, 0x9d, + 0x0b, 0x44, 0x15, 0x9a, 0xcf, 0xe5, 0xd8, 0x26, + 0x62, 0x1a, 0x2d, 0x89, 0xd7, 0x5b, 0x3a, 0x79, + 0x33, 0x10, 0xd1, 0x6d, 0xcf, 0x56, 0x8c, 0x03, + 0xa0, 0x0f, 0x33, 0x45, 0x72, 0x5b, 0xd1, 0x0f, + 0x6c, 0xd3, 0xa8, 0xdf, 0xce, 0x9f, 0xf7, 0x59, + 0xd6, 0x3b, 0xad, 0x6e, 0xc5, 0xbc, 0x3a, 0x7e, + 0x61, 0x7f, 0x3e, 0xa8, 0xe9, 0xf0, 0x26, 0x62, + 0x1a, 0x2f, 0x09, 0xed, 0x75, 0x5e, 0xce, 0x9f, + 0xf9, 0xbb, 0x2a, 0x97, 0xea, 0xc7, 0x55, 0x3a, + 0x7d, 0x63, 0xe3, 0xb3, 0x1d, 0x3e, 0x6e, 0xde, + 0xe5, 0x4e, 0x9d, 0xa6, 0xf0, 0xe9, 0x2f, 0xac, + 0x4e, 0x87, 0xad, 0x43, 0xb4, 0x27, 0x59, 0x75, + 0x26, 0x1b, 0x24, 0xf1, 0x18, 0x4a, 0x74, 0x53, + 0x3b, 0xf7, 0x49, 0xd3, 0xe0, 0x4c, 0xc4, 0x34, + 0x5e, 0x93, 0xfe, 0x1c, 0xd3, 0xdb, 0xbe, 0xbf, + 0x41, 0xd3, 0xeb, 0x56, 0xf3, 0x93, 0xa4, 0xbe, + 0x51, 0x67, 0x63, 0x9d, 0x8c, 0x1d, 0x90, 0x21, + 0x99, 0x2d, 0xb4, 0x42, 0xd6, 0xe3, 0xe4, 0x42, + 0x4f, 0xc6, 0x98, 0x0b, 0x6a, 0x86, 0x77, 0x84, + 0x43, 0x0c, 0x2f, 0x63, 0xc9, 0xe2, 0x34, 0x69, + 0xbd, 0xd9, 0xd3, 0xd7, 0xbc, 0xd1, 0xd3, 0xfa, + 0xfe, 0x1e, 0x79, 0xed, 0x4e, 0x93, 0xbe, 0x27, + 0xab, 0x52, 0x09, 0xf7, 0xf4, 0xd4, 0xd0, 0x74, + 0xf8, 0x13, 0x31, 0x0d, 0x11, 0x1c, 0xff, 0xf6, + 0xfd, 0xad, 0x6d, 0x43, 0x6e, 0xba, 0x33, 0xbb, + 0x3a, 0x7f, 0xcf, 0x6a, 0x02, 0xf5, 0xaf, 0xe8, + 0xe9, 0xfe, 0xb0, 0xba, 0xde, 0x0d, 0x07, 0x4f, + 0xff, 0xf3, 0x6f, 0x3f, 0xa6, 0xd8, 0xde, 0xb7, + 0xfd, 0xdf, 0xf8, 0x3a, 0x6a, 0x14, 0x54, 0xdc, + 0x70, 0x54, 0xff, 0x96, 0x9b, 0xfb, 0x9b, 0x6a, + 0x17, 0xe1, 0xaf, 0xe0, 0x5e, 0x79, 0xd3, 0x69, + 0x8e, 0x87, 0x9f, 0xdf, 0xd6, 0x67, 0xee, 0xb8, + 0xde, 0xf3, 0x47, 0x4f, 0xcd, 0xde, 0xc7, 0xfd, + 0xce, 0x9f, 0xaf, 0x4e, 0xda, 0xbd, 0x9d, 0x16, + 0x88, 0xd1, 0x2f, 0xa9, 0x7c, 0xff, 0xfc, 0x8b, + 0x0c, 0x1f, 0xe9, 0x60, 0xda, 0x1c, 0xf0, 0xe8, + 0x77, 0x97, 0x00, 0x3a, 0xc6, 0xc6, 0x2c, 0xb2, + 0x94, 0x30, 0xa5, 0x67, 0xe7, 0xc0, 0x6b, 0x91, + 0x87, 0xea, 0x15, 0xee, 0x8b, 0xa7, 0xc0, 0x99, + 0x88, 0x68, 0x8b, 0xa7, 0xda, 0xf3, 0xb0, 0xbc, + 0xa9, 0x2e, 0xcf, 0x6b, 0x0c, 0x21, 0x69, 0x97, + 0x3e, 0x30, 0x89, 0xff, 0x95, 0x8f, 0x5d, 0x82, + 0x66, 0x21, 0xa2, 0x66, 0x9f, 0xba, 0xd1, 0xdd, + 0x3b, 0xf5, 0x6d, 0x1d, 0x3a, 0x96, 0xa9, 0xd3, + 0x93, 0xea, 0x3a, 0x6e, 0xae, 0xb6, 0x74, 0xfd, + 0xab, 0xa2, 0xfc, 0x70, 0xe8, 0xeb, 0x67, 0x9c, + 0xe0, 0xfc, 0xf9, 0x33, 0x7f, 0x70, 0xe9, 0xff, + 0xf7, 0x94, 0xbf, 0x7e, 0xb0, 0x2f, 0x7f, 0x4c, + 0x03, 0xa7, 0xfe, 0x76, 0xfe, 0xbe, 0x9f, 0xe7, + 0x56, 0x87, 0x4f, 0xff, 0xf7, 0xb8, 0x28, 0x37, + 0xce, 0xfd, 0xe9, 0xb6, 0x78, 0x35, 0x07, 0x43, + 0x26, 0x0b, 0x6a, 0xdb, 0x47, 0x9f, 0xff, 0x73, + 0xf1, 0xa2, 0xeb, 0xfc, 0xda, 0xf8, 0xe3, 0x82, + 0xa7, 0xea, 0x5f, 0x5f, 0x3d, 0x70, 0xe9, 0xe4, + 0xcc, 0x43, 0x45, 0x9f, 0x3f, 0xef, 0xed, 0x9f, + 0xfd, 0x36, 0xaa, 0x74, 0xff, 0xf7, 0xc3, 0x79, + 0xd2, 0xdd, 0x0d, 0xd6, 0xc4, 0xe9, 0xdc, 0x71, + 0xc1, 0x53, 0xfe, 0xc7, 0xd4, 0x6d, 0x39, 0xb0, + 0x29, 0x65, 0xfc, 0xff, 0x36, 0xff, 0xc8, 0xe6, + 0x38, 0x74, 0xff, 0x7c, 0x79, 0xed, 0xcf, 0xba, + 0xa9, 0xd0, 0x8a, 0x88, 0xdc, 0x5a, 0x03, 0x25, + 0x15, 0xec, 0xfb, 0xc6, 0xed, 0x25, 0x3a, 0x38, + 0x9f, 0xe0, 0xce, 0x37, 0xf6, 0x06, 0x3a, 0x7f, + 0xff, 0xfe, 0xbb, 0xf2, 0xb7, 0x63, 0xdf, 0xb0, + 0x0b, 0x5e, 0xd7, 0x51, 0xba, 0x15, 0x6a, 0x3a, + 0x75, 0x5a, 0x83, 0xa7, 0x75, 0x5e, 0xce, 0x87, + 0xa3, 0x0a, 0xb0, 0x88, 0xd0, 0xe4, 0xed, 0xfb, + 0xc1, 0xd3, 0xbc, 0xf5, 0x0e, 0x9d, 0xab, 0xec, + 0x74, 0x72, 0x7b, 0x14, 0x8f, 0x7c, 0x76, 0x7e, + 0x0f, 0xba, 0xb1, 0xa9, 0xd3, 0xed, 0x8b, 0x58, + 0x19, 0x3f, 0xef, 0x83, 0xec, 0x28, 0xf7, 0x39, + 0x34, 0x41, 0xab, 0x34, 0x93, 0xec, 0x4f, 0xa9, + 0x8e, 0x9f, 0x9f, 0xb1, 0xca, 0x74, 0x74, 0xad, + 0x0f, 0x48, 0x49, 0x67, 0xfe, 0xb1, 0xa7, 0x56, + 0x1f, 0xa3, 0x14, 0x74, 0xdf, 0x13, 0xa7, 0xec, + 0xe3, 0x57, 0xbd, 0x31, 0xec, 0x77, 0x43, 0x86, + 0x4f, 0x09, 0xea, 0x37, 0x0a, 0xe1, 0x7d, 0x9f, + 0x82, 0xf9, 0xae, 0xd8, 0xe9, 0xff, 0xfd, 0xe8, + 0xe7, 0x7e, 0x9d, 0x87, 0x35, 0x5f, 0xd3, 0xbf, + 0xf0, 0x74, 0xff, 0x95, 0x7a, 0xaf, 0x6a, 0xe3, + 0xec, 0xe9, 0xfa, 0xb5, 0x60, 0xd3, 0x1c, 0xb3, + 0x7f, 0x3d, 0xbb, 0xfb, 0xa3, 0xa7, 0xea, 0xfc, + 0x2f, 0xd0, 0x3a, 0x3e, 0x88, 0xad, 0x9d, 0xe8, + 0x8e, 0x65, 0x3b, 0xe6, 0x8b, 0xf2, 0x7f, 0xe7, + 0xeb, 0xd7, 0xbd, 0x5a, 0xd3, 0x28, 0xe9, 0xff, + 0xbf, 0x63, 0x77, 0x5e, 0x8f, 0xaa, 0x8e, 0x8a, + 0x51, 0x15, 0x54, 0x69, 0xbe, 0xe1, 0xd3, 0xb5, + 0xfa, 0x0e, 0x9c, 0x2c, 0x87, 0x47, 0x43, 0xcd, + 0x50, 0xb8, 0x8e, 0xc3, 0x27, 0x07, 0xc9, 0x85, + 0xc2, 0xcb, 0x1c, 0x67, 0xff, 0xfe, 0x76, 0x6d, + 0xfd, 0x4b, 0x71, 0xf8, 0x1d, 0xb7, 0xfa, 0x6a, + 0x9f, 0xa0, 0xe9, 0xee, 0x32, 0xea, 0x74, 0xff, + 0x3d, 0x58, 0xfd, 0x55, 0xbb, 0x9d, 0x0c, 0x7b, + 0x78, 0x43, 0x3d, 0x75, 0xf8, 0x9d, 0x02, 0x78, + 0x1e, 0x90, 0x4f, 0x76, 0xf7, 0x2a, 0x74, 0xfc, + 0xed, 0xab, 0xc1, 0x43, 0xa7, 0xfa, 0xbe, 0x7e, + 0x9a, 0x5f, 0x7a, 0x3a, 0x36, 0x7d, 0x3a, 0x2d, + 0x86, 0x45, 0x7d, 0xc2, 0x36, 0x67, 0x3d, 0x3a, + 0x4a, 0x3a, 0x29, 0x35, 0x0e, 0xe0, 0xc4, 0xfe, + 0xcc, 0xa5, 0xe2, 0xdc, 0x9d, 0x3f, 0xf8, 0x7e, + 0xd5, 0x1c, 0x7f, 0x4a, 0xd8, 0x1d, 0x3f, 0xff, + 0xed, 0xfe, 0x9d, 0x5d, 0x3a, 0x00, 0x6d, 0x79, + 0xd8, 0x5f, 0xbb, 0x3a, 0x7b, 0x9e, 0x70, 0x4e, + 0x9f, 0xf6, 0x6d, 0x3f, 0x9d, 0x2b, 0x9b, 0x3a, + 0x19, 0x37, 0x0e, 0x49, 0xec, 0xc9, 0x12, 0x3e, + 0xdf, 0xb2, 0x29, 0xff, 0xac, 0x69, 0xd5, 0x87, + 0xe8, 0xc5, 0x1d, 0x3e, 0xbd, 0x3d, 0x5b, 0x3a, + 0x7d, 0x4d, 0x45, 0x94, 0x74, 0x32, 0x24, 0x6a, + 0x87, 0xe9, 0x3c, 0xde, 0x6c, 0xe9, 0xfa, 0x87, + 0x1f, 0xd6, 0x05, 0x07, 0x4f, 0xee, 0xfb, 0xbd, + 0x6f, 0xfa, 0x3a, 0x6f, 0x81, 0xd1, 0xd6, 0xcf, + 0xff, 0xe6, 0xbb, 0x35, 0x9f, 0xfb, 0x96, 0xe4, + 0x1b, 0x5f, 0x4f, 0xf2, 0x74, 0xfd, 0xbf, 0x68, + 0x73, 0x7f, 0x3a, 0x39, 0x3f, 0x6d, 0xa2, 0xc9, + 0x7d, 0x6d, 0xb1, 0xd9, 0x77, 0x8f, 0xdd, 0xd0, + 0xe3, 0x34, 0xd0, 0x53, 0xcc, 0x65, 0x97, 0x29, + 0x4b, 0xbb, 0xad, 0x30, 0xf8, 0xfc, 0x23, 0x5c, + 0x8f, 0xcc, 0x10, 0x14, 0x59, 0xb9, 0x56, 0xb8, + 0x83, 0xe4, 0x62, 0xa3, 0x0d, 0x1a, 0xc7, 0x7d, + 0xa8, 0x73, 0xf0, 0x61, 0xd5, 0x09, 0x6e, 0xd0, + 0xab, 0x85, 0xb6, 0x76, 0x9b, 0xac, 0x89, 0x67, + 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, + 0x26, 0xc9, 0xfc, 0xbb, 0x04, 0xcc, 0x43, 0x45, + 0x5b, 0x3f, 0x9e, 0xff, 0x74, 0x2c, 0xf3, 0xa7, + 0xaf, 0x79, 0xa3, 0xa4, 0xef, 0xd9, 0xe9, 0x89, + 0x9c, 0xf8, 0x13, 0x31, 0x0d, 0x15, 0xa4, 0xff, + 0xf2, 0x30, 0x5f, 0x98, 0xac, 0x7b, 0x7d, 0x0e, + 0x9f, 0xfe, 0x7d, 0x6c, 0x59, 0x59, 0x7a, 0xd3, + 0x28, 0xe9, 0xb5, 0xa6, 0x44, 0xbe, 0x25, 0xcf, + 0xe6, 0x75, 0xdb, 0x42, 0xde, 0x1d, 0x3f, 0x51, + 0x7b, 0xfd, 0xa8, 0xe9, 0xfe, 0xb7, 0x61, 0x6e, + 0x29, 0x7d, 0x4e, 0x9f, 0xcf, 0xbd, 0x60, 0xf9, + 0xe9, 0xd2, 0x5f, 0x58, 0x9f, 0x8d, 0x95, 0xfe, + 0x18, 0xfb, 0x2d, 0xc3, 0x61, 0x2d, 0xd1, 0xe4, + 0xfe, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0xc0, 0x9f, + 0x02, 0x66, 0x21, 0xa2, 0x75, 0x9f, 0xff, 0xdb, + 0x6a, 0x39, 0xb5, 0x2e, 0xb5, 0xbd, 0xfe, 0xbe, + 0xd0, 0x74, 0xf9, 0x6a, 0xc7, 0xae, 0xd1, 0x2a, + 0xe1, 0x84, 0xf8, 0x13, 0x31, 0x0d, 0x16, 0xcc, + 0xff, 0xbc, 0x6a, 0xaf, 0x7f, 0x4c, 0x03, 0xa4, + 0xbb, 0x3e, 0xdc, 0x30, 0x9e, 0x4c, 0xc4, 0x34, + 0x5c, 0xd2, 0x51, 0xd0, 0x06, 0xef, 0x82, 0xb9, + 0x9c, 0x51, 0xd2, 0x5d, 0x9b, 0x8e, 0x08, 0x67, + 0xf2, 0xec, 0x13, 0x31, 0x0d, 0x17, 0x7c, 0xf2, + 0xfb, 0xf3, 0xe1, 0xd0, 0xcd, 0xcf, 0x8d, 0xd6, + 0x7b, 0xc8, 0x65, 0x4a, 0x97, 0xe5, 0x3f, 0x83, + 0x92, 0xa1, 0xa1, 0xe4, 0x2b, 0x6b, 0x09, 0x9d, + 0x13, 0xf6, 0x3b, 0x9f, 0x56, 0xaa, 0xc7, 0x9d, + 0x3f, 0xf5, 0x29, 0xee, 0x53, 0xab, 0xb1, 0xee, + 0x74, 0xe1, 0xc5, 0xb1, 0xf6, 0xe8, 0x9e, 0x7f, + 0x0d, 0x16, 0xed, 0xa6, 0xee, 0x74, 0xf8, 0x13, + 0x31, 0x0d, 0x12, 0xbc, 0xff, 0x87, 0x38, 0xe7, + 0x6d, 0x45, 0xf0, 0x74, 0xf7, 0xb8, 0x0f, 0x3a, + 0x7f, 0xff, 0x7f, 0x58, 0xac, 0x1f, 0x37, 0xc6, + 0x0d, 0x09, 0xfa, 0x0e, 0x8e, 0x51, 0x07, 0x84, + 0x31, 0xca, 0x39, 0xb7, 0x0c, 0x39, 0xd8, 0xf5, + 0xb2, 0x6e, 0xd6, 0x6f, 0x58, 0xc5, 0xa7, 0x69, + 0xb9, 0x2a, 0x7f, 0xf6, 0xf3, 0xfa, 0x67, 0xfc, + 0x28, 0xf7, 0xc2, 0xa7, 0xf6, 0x22, 0xf9, 0x07, + 0x71, 0x6c, 0x7d, 0x15, 0x1c, 0x92, 0xd1, 0x55, + 0x1a, 0xa3, 0xa7, 0x75, 0x0a, 0xe9, 0xff, 0xcb, + 0x56, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x89, 0x86, + 0x7f, 0xf0, 0xb3, 0xa1, 0x6a, 0x57, 0xd6, 0xdd, + 0xd5, 0x5e, 0x74, 0xff, 0xe0, 0xcf, 0x17, 0xdf, + 0x4f, 0xe1, 0xaa, 0xf3, 0xa6, 0xb5, 0xf2, 0x8a, + 0x4e, 0xca, 0xf3, 0xff, 0x3b, 0xf7, 0x4b, 0xfd, + 0xcd, 0x0b, 0x3c, 0xe9, 0xfc, 0xd9, 0x46, 0xbb, + 0xe0, 0x1d, 0x3e, 0xc0, 0x7e, 0x28, 0xe8, 0x13, + 0xd8, 0xf4, 0xce, 0x7e, 0x53, 0x58, 0xeb, 0xa8, + 0xe9, 0x54, 0xe9, 0xf3, 0x58, 0xeb, 0xa8, 0xe9, + 0xfb, 0x7f, 0xd5, 0x72, 0x9e, 0x87, 0xcc, 0xe1, + 0x72, 0x84, 0x27, 0xff, 0xfc, 0x37, 0xc3, 0xb6, + 0xaf, 0x7d, 0x06, 0xe8, 0xfd, 0x8d, 0x2f, 0xa9, + 0xd3, 0xff, 0xcd, 0xa1, 0xcf, 0x37, 0x7f, 0xe7, + 0xdd, 0x54, 0xe9, 0xf9, 0xd7, 0x6d, 0x0b, 0x78, + 0x74, 0xff, 0xe6, 0xd7, 0x8c, 0xfb, 0xa7, 0x54, + 0x7b, 0xc1, 0xd0, 0xc7, 0xff, 0xf3, 0x19, 0xfa, + 0xbf, 0xee, 0xac, 0xd1, 0xd3, 0xff, 0xfe, 0x0b, + 0x74, 0xc3, 0xae, 0x9d, 0x85, 0xb7, 0x9f, 0xd3, + 0x6a, 0xa7, 0x4a, 0xe9, 0x44, 0xe8, 0x17, 0xcf, + 0xff, 0xb6, 0x37, 0xad, 0xfe, 0xe9, 0xd5, 0xba, + 0x6a, 0x9d, 0x39, 0xbc, 0xec, 0x74, 0x59, 0xfa, + 0x0a, 0xb4, 0xf6, 0x76, 0xe6, 0xce, 0x92, 0xfa, + 0xc5, 0xc5, 0xde, 0x61, 0x42, 0x90, 0x88, 0x71, + 0x58, 0x1c, 0x77, 0x0d, 0x01, 0x85, 0xf6, 0xa1, + 0x39, 0xe9, 0x04, 0xf8, 0x13, 0x31, 0x0d, 0x15, + 0x74, 0xff, 0x3d, 0x76, 0x09, 0x98, 0x86, 0x88, + 0xf2, 0x4b, 0xb3, 0xf1, 0xc3, 0x09, 0xfc, 0xbb, + 0x04, 0xcc, 0x43, 0x45, 0x83, 0x3f, 0x97, 0x60, + 0x99, 0x88, 0x68, 0xb2, 0xa7, 0xf2, 0xec, 0x13, + 0x31, 0x0d, 0x16, 0x9c, 0xfe, 0xba, 0xf4, 0x00, + 0xf7, 0x67, 0x4f, 0x26, 0x62, 0x1a, 0x2d, 0xc9, + 0xff, 0x9a, 0xc2, 0xc7, 0xa6, 0xee, 0x9e, 0x0e, + 0x80, 0x3e, 0xfa, 0x95, 0xcf, 0xf3, 0x0f, 0xaa, + 0x6a, 0xeb, 0xe7, 0x4f, 0xec, 0xca, 0x39, 0x6b, + 0x03, 0xa7, 0xfd, 0x8f, 0x5d, 0x82, 0x66, 0x21, + 0xa2, 0x87, 0x9f, 0xf9, 0x59, 0xcb, 0x73, 0xbf, + 0x8f, 0xd4, 0x74, 0xff, 0xde, 0xbf, 0x78, 0x14, + 0xe9, 0xbf, 0x41, 0xd3, 0xfe, 0xf4, 0x3c, 0x0c, + 0x1d, 0x5f, 0x87, 0x4f, 0xd5, 0xca, 0x6b, 0xaf, + 0x9d, 0x3f, 0x0f, 0x59, 0x60, 0xd5, 0x3a, 0x7f, + 0xfe, 0xbe, 0x76, 0xdd, 0x97, 0xa1, 0xcf, 0x2b, + 0x56, 0xf0, 0xa9, 0x2d, 0xea, 0xbd, 0xee, 0x14, + 0x7f, 0x21, 0x70, 0xe1, 0x46, 0x38, 0x8d, 0xe2, + 0x2d, 0x51, 0xb4, 0x7d, 0xe9, 0x77, 0x51, 0x7c, + 0xfe, 0x5d, 0x82, 0x66, 0x21, 0xa2, 0xf3, 0x86, + 0x65, 0xc8, 0x3d, 0x13, 0x98, 0x7b, 0x5c, 0xe4, + 0x75, 0x31, 0x8b, 0x01, 0x32, 0x8e, 0xf6, 0x76, + 0x32, 0xcc, 0x9d, 0x42, 0xa6, 0x7f, 0x2e, 0xc1, + 0x33, 0x10, 0xd1, 0x4b, 0x4f, 0xe5, 0xd8, 0x26, + 0x62, 0x1a, 0x2c, 0x29, 0xfc, 0xbb, 0x04, 0xcc, + 0x43, 0x45, 0x97, 0x3c, 0xbe, 0xfd, 0x68, 0xee, + 0xce, 0x9c, 0xbe, 0xca, 0x3a, 0x79, 0x16, 0xd5, + 0x43, 0xcf, 0xf4, 0xc6, 0x7f, 0xf2, 0xd5, 0x8f, + 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x8c, 0x9f, 0xcb, + 0x67, 0x4c, 0x0d, 0xe1, 0xd0, 0xf4, 0xef, 0x40, + 0xed, 0x47, 0x79, 0x08, 0xaa, 0x9c, 0x69, 0x4a, + 0x7f, 0xe5, 0xe3, 0xd7, 0x60, 0x99, 0x88, 0x68, + 0x8e, 0x67, 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, + 0x62, 0x1a, 0x27, 0x29, 0xfc, 0xbb, 0x04, 0xcc, + 0x43, 0x45, 0x99, 0x3f, 0xf2, 0xdb, 0xc0, 0x6d, + 0x6f, 0x29, 0x79, 0xd3, 0xf9, 0x76, 0x09, 0x98, + 0x86, 0x8b, 0x76, 0x7f, 0xf2, 0xd5, 0x8f, 0x5d, + 0x82, 0x66, 0x21, 0xa2, 0x90, 0x9f, 0xf9, 0x78, + 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x25, 0x28, 0xa1, + 0x3f, 0x67, 0x13, 0x14, 0xa5, 0xe1, 0xd8, 0xa2, + 0x68, 0xed, 0xd9, 0x4a, 0x7f, 0xd8, 0xf5, 0xd8, + 0x26, 0x62, 0x1a, 0x27, 0x69, 0xff, 0xf7, 0xf9, + 0xf5, 0x4c, 0xed, 0x9c, 0x8b, 0x0d, 0xa1, 0xd2, + 0x5a, 0x91, 0x3b, 0x88, 0xd3, 0xff, 0x62, 0xb7, + 0x69, 0x9b, 0x6e, 0xcf, 0x3a, 0x7f, 0xe1, 0xbd, + 0xe5, 0x17, 0x51, 0xca, 0x4e, 0x9b, 0xa9, 0x7c, + 0xa2, 0x16, 0xa8, 0x70, 0xa4, 0x70, 0x75, 0x42, + 0xb6, 0x7c, 0x09, 0x98, 0x86, 0x88, 0xb2, 0x7f, + 0xd8, 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x25, 0xd9, + 0xff, 0xfa, 0xf9, 0xdb, 0x76, 0x5e, 0x87, 0x3c, + 0xad, 0x5b, 0xc2, 0xa4, 0xbb, 0x46, 0xa2, 0x8c, + 0x3a, 0x91, 0xa7, 0xff, 0x2d, 0x58, 0xf5, 0xd8, + 0x26, 0x62, 0x1a, 0x26, 0x29, 0xf0, 0x26, 0x62, + 0x1a, 0x2a, 0x99, 0x59, 0xd1, 0x66, 0xff, 0xb9, + 0x84, 0xff, 0xff, 0xe0, 0xcd, 0xd2, 0xfb, 0xd2, + 0xf7, 0x95, 0x0f, 0xf1, 0xad, 0xfc, 0x1e, 0x74, + 0x2d, 0x13, 0x58, 0x45, 0x3f, 0xf9, 0x6a, 0xc7, + 0xae, 0xc1, 0x33, 0x10, 0xd1, 0x3a, 0x4f, 0xef, + 0xe0, 0x33, 0xf1, 0xd1, 0xd3, 0xe7, 0x19, 0xc6, + 0xa9, 0xd3, 0xf7, 0x17, 0xf7, 0x56, 0x27, 0x47, + 0xcf, 0x5a, 0xa5, 0x13, 0xbf, 0xb6, 0x39, 0x66, + 0x8a, 0x7f, 0xef, 0x6b, 0xa6, 0xa5, 0x7e, 0xb9, + 0xf5, 0x1d, 0x0a, 0x3f, 0x4d, 0x95, 0xcf, 0xfb, + 0x1e, 0xbb, 0x04, 0xcc, 0x43, 0x44, 0xef, 0x3e, + 0xd7, 0xb8, 0xaf, 0x95, 0x25, 0xf2, 0x9d, 0x75, + 0xc6, 0x3c, 0xa2, 0x2c, 0x46, 0x9f, 0xfc, 0xb5, + 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, 0xa1, 0x67, + 0xff, 0x2d, 0x58, 0xf5, 0xd8, 0x26, 0x62, 0x1a, + 0x29, 0x29, 0xff, 0xfd, 0x75, 0x5f, 0x6b, 0x73, + 0x78, 0xad, 0x6d, 0xb5, 0xea, 0x8e, 0x8a, 0x17, + 0x35, 0x9e, 0x70, 0x91, 0x95, 0x81, 0x12, 0xa5, + 0x00, 0x78, 0x93, 0xea, 0x97, 0x52, 0x94, 0xfe, + 0x5d, 0x82, 0x66, 0x21, 0xa2, 0x24, 0x9f, 0xfc, + 0xb5, 0x63, 0xd7, 0x60, 0x99, 0x88, 0x68, 0x97, + 0xa7, 0xc1, 0xe2, 0xbf, 0x53, 0xa7, 0x78, 0xda, + 0x3a, 0x7f, 0xec, 0x72, 0xac, 0xeb, 0x36, 0xd4, + 0xb8, 0x74, 0x7d, 0x11, 0x6e, 0x14, 0x00, 0xe4, + 0xff, 0x7f, 0x07, 0xdd, 0x38, 0xdd, 0xce, 0x9f, + 0x02, 0x66, 0x21, 0xa2, 0x97, 0x9f, 0x0e, 0xa8, + 0xbe, 0x0e, 0x9f, 0xef, 0x2a, 0x0d, 0x4b, 0xfe, + 0xa3, 0xa7, 0xfb, 0x28, 0xe9, 0x47, 0xae, 0x37, + 0x5c, 0xe9, 0xad, 0xec, 0x7f, 0x9e, 0x9d, 0x4c, + 0xfb, 0x3a, 0x73, 0x79, 0x53, 0xa3, 0x93, 0x63, + 0xc0, 0xac, 0xff, 0xdf, 0x56, 0x73, 0xd9, 0xc7, + 0xb0, 0xd2, 0x74, 0xf5, 0x7f, 0xc6, 0x8e, 0x8d, + 0x9f, 0x5e, 0x92, 0x27, 0xfb, 0x37, 0x8e, 0x7c, + 0x1a, 0x83, 0xa7, 0xce, 0xdf, 0x53, 0x54, 0xe9, + 0xf6, 0x3a, 0xb0, 0xa9, 0xd2, 0x6e, 0x4f, 0x45, + 0x45, 0x52, 0x5b, 0x2a, 0xfe, 0xe4, 0xc2, 0xce, + 0xe9, 0x30, 0x72, 0x14, 0x9b, 0x5e, 0xc8, 0x47, + 0x54, 0x8b, 0x50, 0x89, 0x9f, 0xcb, 0xb0, 0x4c, + 0xc4, 0x34, 0x53, 0x93, 0xfe, 0xf8, 0x65, 0x77, + 0x76, 0x28, 0x74, 0xff, 0xaf, 0x6c, 0x16, 0xbe, + 0x38, 0xe0, 0xa9, 0xbf, 0xc1, 0xd3, 0x50, 0xbe, + 0x51, 0x21, 0xd4, 0x74, 0xec, 0x7f, 0x3e, 0x04, + 0xcc, 0x43, 0x45, 0x79, 0x3f, 0xff, 0x5f, 0x3b, + 0x6e, 0xcb, 0xd0, 0xe7, 0x95, 0xab, 0x78, 0x54, + 0x97, 0x68, 0x8e, 0xea, 0x30, 0x9f, 0xf9, 0x78, + 0xf5, 0xd8, 0x26, 0x62, 0x1a, 0x24, 0x79, 0xdf, + 0xf1, 0x8e, 0x9c, 0x96, 0xa2, 0x96, 0x5e, 0x4f, + 0x81, 0x33, 0x10, 0xd1, 0x24, 0x4f, 0x2f, 0x1e, + 0xb6, 0x3d, 0x9b, 0x29, 0x9f, 0xf9, 0x78, 0xf5, + 0xd8, 0x26, 0x62, 0x1a, 0x24, 0xa9, 0xf0, 0x26, + 0x62, 0x1a, 0x2f, 0x19, 0xf5, 0x6b, 0xab, 0x43, + 0xa7, 0xf9, 0xeb, 0xb0, 0x4c, 0xc4, 0x34, 0x49, + 0xb2, 0x5d, 0xa2, 0x5c, 0x0c, 0x30, 0x9a, 0x19, + 0x91, 0x03, 0x41, 0xdb, 0xe5, 0xed, 0xf3, 0x09, + 0x5f, 0xc3, 0x2d, 0xc8, 0x69, 0x28, 0xaf, 0x70, + 0xc1, 0xd1, 0xbf, 0xb0, 0xe3, 0x86, 0x8e, 0xd8, + 0xaa, 0x88, 0xec, 0x1f, 0x29, 0xd3, 0x99, 0x45, + 0x57, 0x78, 0x9e, 0xdd, 0xe5, 0x2d, 0x25, 0xa4, + 0xa2, 0xa6, 0x7e, 0x93, 0xf3, 0xc1, 0xdd, 0x78, + 0xed, 0xdc, 0xac, 0xd7, 0xc2, 0x96, 0xd4, 0xac, + 0x4f, 0xd5, 0x6e, 0x77, 0xfb, 0x2b, 0x38, 0x8f, + 0x25, 0x9e, 0x3b, 0x90, 0xb1, 0x1a, 0x48, 0x25, + 0x69, 0x45, 0x3a, 0xaf, 0xf8, 0x7d, 0xa7, 0xae, + 0xba, 0x94, 0xd7, 0xc4, 0xa5, 0x1e, 0xa8, 0xf9, + 0xfb, 0x4e, 0xea, 0xbb, 0x52, 0x41, 0xa0, }; -static const unsigned kPreloadedHSTSBits = 114383; +static const unsigned kPreloadedHSTSBits = 114165; -static const unsigned kHSTSRootPosition = 113797; +static const unsigned kHSTSRootPosition = 113579; #endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 426abb4..c941427 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -136,19 +136,6 @@ ] }, { - "name": "tor2web", - "static_spki_hashes": [ - "AlphaSSL_G2", - "Tor2web" - ] - }, - { - "name": "lavabit", - "static_spki_hashes": [ - "Libertylavabitcom" - ] - }, - { "name": "dropbox", "static_spki_hashes": [ "DigiCertAssuredIDRoot", @@ -593,7 +580,7 @@ { "name": "braintreepayments.com", "mode": "force-https" }, { "name": "www.braintreepayments.com", "mode": "force-https" }, { "name": "emailprivacytester.com", "mode": "force-https" }, - { "name": "tor2web.org", "include_subdomains": true, "pins": "tor2web" }, + { "name": "tor2web.org", "include_subdomains": true, "mode": "force-https" }, { "name": "business.medbank.com.mt", "include_subdomains": true, "mode": "force-https" }, { "name": "arivo.com.br", "include_subdomains": true, "mode": "force-https" }, { "name": "www.apollo-auto.com", "include_subdomains": true, "mode": "force-https" }, @@ -726,7 +713,6 @@ { "name": "cybozu.com", "include_subdomains": true, "mode": "force-https" }, { "name": "davidlyness.com", "include_subdomains": true, "mode": "force-https" }, { "name": "medium.com", "include_subdomains": true, "mode": "force-https" }, - { "name": "liberty.lavabit.com", "include_subdomains": true, "mode": "force-https", "pins": "lavabit" }, { "name": "getlantern.org", "include_subdomains": true, "mode": "force-https" }, { "name": "kinsights.com", "mode": "force-https" }, { "name": "simbolo.co.uk", "mode": "force-https" }, @@ -1222,7 +1208,6 @@ { "name": "quuz.org", "include_subdomains": true, "mode": "force-https" }, { "name": "sale4ru.ru", "include_subdomains": true, "mode": "force-https" }, { "name": "shipard.com", "include_subdomains": true, "mode": "force-https" }, - { "name": "shohruh.uz", "include_subdomains": true, "mode": "force-https" }, { "name": "sro.center", "include_subdomains": true, "mode": "force-https" }, { "name": "standardssuck.org", "include_subdomains": true, "mode": "force-https" }, { "name": "testsuite.org", "include_subdomains": true, "mode": "force-https" }, @@ -1628,7 +1613,6 @@ { "name": "koenvdheuvel.me", "include_subdomains": true, "mode": "force-https" }, { "name": "leadbook.ru", "include_subdomains": true, "mode": "force-https" }, { "name": "lilpwny.com", "include_subdomains": true, "mode": "force-https" }, - { "name": "mf.cz", "include_subdomains": true, "mode": "force-https" }, { "name": "mirrorx.com", "include_subdomains": true, "mode": "force-https" }, { "name": "pentesterlab.com", "include_subdomains": true, "mode": "force-https" }, { "name": "pypa.io", "include_subdomains": true, "mode": "force-https" },
diff --git a/net/net.gypi b/net/net.gypi index 5ca70f7..6da22e3 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -970,6 +970,8 @@ 'quic/reliable_quic_stream.h', 'quic/spdy_utils.cc', 'quic/spdy_utils.h', + 'sdch/sdch_owner.cc', + 'sdch/sdch_owner.h', 'socket/client_socket_factory.cc', 'socket/client_socket_factory.h', 'socket/client_socket_pool.cc', @@ -1415,6 +1417,7 @@ 'http/http_request_headers_unittest.cc', 'http/http_response_body_drainer_unittest.cc', 'http/http_response_headers_unittest.cc', + 'http/http_response_info_unittest.cc', 'http/http_security_headers_unittest.cc', 'http/http_server_properties_impl_unittest.cc', 'http/http_server_properties_manager_unittest.cc', @@ -1584,6 +1587,7 @@ 'quic/quic_utils_test.cc', 'quic/quic_write_blocked_list_test.cc', 'quic/reliable_quic_stream_test.cc', + 'sdch/sdch_owner_unittest.cc', 'server/http_connection_unittest.cc', 'server/http_server_response_info_unittest.cc', 'server/http_server_unittest.cc', @@ -1729,6 +1733,7 @@ 'quic/quic_end_to_end_unittest.cc', 'tools/quic/end_to_end_test.cc', 'tools/quic/quic_client_session_test.cc', + 'tools/quic/quic_client_test.cc', 'tools/quic/quic_dispatcher_test.cc', 'tools/quic/quic_epoll_clock_test.cc', 'tools/quic/quic_epoll_connection_helper_test.cc',
diff --git a/net/proxy/proxy_info.cc b/net/proxy/proxy_info.cc index 96ae3ce..b659d67 100644 --- a/net/proxy/proxy_info.cc +++ b/net/proxy/proxy_info.cc
@@ -59,6 +59,10 @@ proxy_list_ = proxy_list; } +void ProxyInfo::OverrideProxyList(const ProxyList& proxy_list) { + proxy_list_ = proxy_list; +} + std::string ProxyInfo::ToPacString() const { return proxy_list_.ToPacString(); }
diff --git a/net/proxy/proxy_info.h b/net/proxy/proxy_info.h index 8424c51..e1c9389 100644 --- a/net/proxy/proxy_info.h +++ b/net/proxy/proxy_info.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/gtest_prod_util.h" #include "base/time/time.h" #include "net/base/net_export.h" #include "net/base/net_log.h" @@ -46,9 +47,13 @@ // Parses from the given PAC result. void UsePacString(const std::string& pac_string); - // Use the proxies from the given list. + // Uses the proxies from the given list. void UseProxyList(const ProxyList& proxy_list); + // Uses the proxies from the given list, but does not otherwise reset the + // proxy configuration. + void OverrideProxyList(const ProxyList& proxy_list); + // Returns true if this proxy info specifies a direct connection. bool is_direct() const { // We don't implicitly fallback to DIRECT unless it was added to the list. @@ -146,6 +151,7 @@ private: friend class ProxyService; + FRIEND_TEST_ALL_PREFIXES(ProxyInfoTest, UseVsOverrideProxyList); const ProxyRetryInfoMap& proxy_retry_info() const { return proxy_retry_info_;
diff --git a/net/proxy/proxy_info_unittest.cc b/net/proxy/proxy_info_unittest.cc index 09f5ef6..06a0497 100644 --- a/net/proxy/proxy_info_unittest.cc +++ b/net/proxy/proxy_info_unittest.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "net/base/net_errors.h" +#include "net/proxy/proxy_config.h" #include "net/proxy/proxy_info.h" +#include "net/proxy/proxy_list.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -41,4 +43,19 @@ } } // namespace + +TEST(ProxyInfoTest, UseVsOverrideProxyList) { + ProxyInfo info; + info.config_id_ = 99; + ProxyList proxy_list; + proxy_list.Set("http://foo.com"); + info.OverrideProxyList(proxy_list); + EXPECT_EQ(99, info.config_id_); + EXPECT_EQ("PROXY foo.com:80", info.proxy_list().ToPacString()); + proxy_list.Set("http://bar.com"); + info.UseProxyList(proxy_list); + EXPECT_EQ(0, info.config_id_); + EXPECT_EQ("PROXY bar.com:80", info.proxy_list().ToPacString()); +} + } // namespace net
diff --git a/net/proxy/proxy_script_decider.cc b/net/proxy/proxy_script_decider.cc index 47e6ca8..00b9119 100644 --- a/net/proxy/proxy_script_decider.cc +++ b/net/proxy/proxy_script_decider.cc
@@ -80,14 +80,12 @@ ProxyScriptFetcher* proxy_script_fetcher, DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher, NetLog* net_log) - : resolver_(NULL), - proxy_script_fetcher_(proxy_script_fetcher), + : proxy_script_fetcher_(proxy_script_fetcher), dhcp_proxy_script_fetcher_(dhcp_proxy_script_fetcher), current_pac_source_index_(0u), pac_mandatory_(false), next_state_(STATE_NONE), - net_log_(BoundNetLog::Make( - net_log, NetLog::SOURCE_PROXY_SCRIPT_DECIDER)), + net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_PROXY_SCRIPT_DECIDER)), fetch_pac_bytes_(false), quick_check_enabled_(true) { if (proxy_script_fetcher &&
diff --git a/net/proxy/proxy_script_decider.h b/net/proxy/proxy_script_decider.h index d579080..99bb995 100644 --- a/net/proxy/proxy_script_decider.h +++ b/net/proxy/proxy_script_decider.h
@@ -160,7 +160,6 @@ void DidComplete(); void Cancel(); - ProxyResolver* resolver_; ProxyScriptFetcher* proxy_script_fetcher_; DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher_;
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc index 2378eeb..8abedc8 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -138,6 +138,8 @@ QuicByteCount bytes_in_flight) { largest_acked_sequence_number_ = max(acked_sequence_number, largest_acked_sequence_number_); + // As soon as a packet is acked, ensure we're no longer in RTO mode. + previous_congestion_window_ = 0; if (InRecovery()) { // PRR is used when in recovery. prr_.OnPacketAcked(acked_bytes); @@ -345,6 +347,10 @@ } cubic_.Reset(); hybrid_slow_start_.Restart(); + // Only reduce ssthresh once over multiple retransmissions. + if (previous_congestion_window_ != 0) { + return; + } previous_slowstart_threshold_ = slowstart_threshold_; slowstart_threshold_ = congestion_window_ / 2; previous_congestion_window_ = congestion_window_;
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index e07e480..a919d02 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -117,7 +117,8 @@ // Congestion window in packets. QuicPacketCount congestion_window_; - // Congestion window before the last loss event or RTO. + // Congestion window before the last RTO. + // Must be 0 before or after RTO recovery. QuicPacketCount previous_congestion_window_; // Slow start congestion window in packets, aka ssthresh.
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc index ebea8ae..8df0ea8 100644 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -450,6 +450,27 @@ EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); } +TEST_F(TcpCubicSenderTest, RTOTwiceOnlyHalvesSsthresh) { + EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); + + sender_->OnRetransmissionTimeout(true); + EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow()); + EXPECT_EQ(5u, sender_->slowstart_threshold()); + + sender_->OnRetransmissionTimeout(true); + EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow()); + EXPECT_EQ(5u, sender_->slowstart_threshold()); + + AckNPackets(2); + + EXPECT_EQ(4 * kDefaultTCPMSS, sender_->GetCongestionWindow()); + EXPECT_EQ(5u, sender_->slowstart_threshold()); + + sender_->OnRetransmissionTimeout(true); + EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow()); + EXPECT_EQ(2u, sender_->slowstart_threshold()); +} + TEST_F(TcpCubicSenderTest, RetransmissionDelay) { const int64 kRttMs = 10; const int64 kDeviationMs = 3;
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.cc b/net/quic/congestion_control/tcp_loss_algorithm.cc index 9366105..f657cc2 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm.cc +++ b/net/quic/congestion_control/tcp_loss_algorithm.cc
@@ -10,10 +10,17 @@ namespace net { namespace { + +// The minimum delay before a packet will be considered lost, +// regardless of SRTT. Half of the minimum TLP, since the loss algorithm only +// triggers when a nack has been receieved for the packet. +static const size_t kMinLossDelayMs = 5; + // How many RTTs the algorithm waits before determining a packet is lost due // to early retransmission. static const double kEarlyRetransmitLossDelayMultiplier = 1.25; -} + +} // namespace TCPLossAlgorithm::TCPLossAlgorithm() : loss_detection_timeout_(QuicTime::Zero()) { } @@ -30,8 +37,10 @@ const RttStats& rtt_stats) { SequenceNumberSet lost_packets; loss_detection_timeout_ = QuicTime::Zero(); - QuicTime::Delta loss_delay = - rtt_stats.smoothed_rtt().Multiply(kEarlyRetransmitLossDelayMultiplier); + QuicTime::Delta early_retransmit_delay = QuicTime::Delta::Max( + QuicTime::Delta::FromMilliseconds(kMinLossDelayMs), + rtt_stats.smoothed_rtt().Multiply(kEarlyRetransmitLossDelayMultiplier)); + QuicPacketSequenceNumber sequence_number = unacked_packets.GetLeastUnacked(); for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin(); it != unacked_packets.end() && sequence_number <= largest_observed; @@ -49,6 +58,16 @@ continue; } + // Immediately lose the packet if it's been an srtt between the sent time + // of it and the largest observed. This speeds recovery from timer based + // retransmissions, such as TLP and RTO, when there may be fewer than + // kNumberOfNacksBeforeRetransmission nacks. + if (it->sent_time.Add(rtt_stats.smoothed_rtt()) < + unacked_packets.GetTransmissionInfo(largest_observed).sent_time) { + lost_packets.insert(sequence_number); + continue; + } + // Only early retransmit(RFC5827) when the last packet gets acked and // there are retransmittable packets in flight. // This also implements a timer-protected variant of FACK. @@ -56,12 +75,12 @@ unacked_packets.largest_sent_packet() == largest_observed) { // Early retransmit marks the packet as lost once 1.25RTTs have passed // since the packet was sent and otherwise sets an alarm. - if (time >= it->sent_time.Add(loss_delay)) { + if (time >= it->sent_time.Add(early_retransmit_delay)) { lost_packets.insert(sequence_number); } else { // Set the timeout for the earliest retransmittable packet where early // retransmit applies. - loss_detection_timeout_ = it->sent_time.Add(loss_delay); + loss_detection_timeout_ = it->sent_time.Add(early_retransmit_delay); break; } }
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc index fe6a6ea..bb56d88 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc +++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -193,6 +193,25 @@ EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); } +TEST_F(TcpLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) { + // Transmit 1 packet and then wait an rtt plus 1ms. + SendDataPacket(1); + clock_.AdvanceTime( + rtt_stats_.smoothed_rtt().Add(QuicTime::Delta::FromMilliseconds(1))); + + // Transmit 2 packets. + SendDataPacket(2); + SendDataPacket(3); + + // Wait another RTT and ack 2. + clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); + unacked_packets_.IncreaseLargestObserved(2); + unacked_packets_.RemoveFromInFlight(2); + unacked_packets_.NackPacket(1, 1); + QuicPacketSequenceNumber lost[] = {1}; + VerifyLosses(2, lost, arraysize(lost)); +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc index 6ed8014..cc39286 100644 --- a/net/quic/crypto/crypto_handshake_message.cc +++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -240,7 +240,6 @@ bool done = false; switch (it->first) { case kICSL: - case kIFCW: case kCFCW: case kSFCW: case kIRTT:
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index a9337a5..9a7f6c6 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h
@@ -109,9 +109,6 @@ const QuicTag kCCS = TAG('C', 'C', 'S', 0); // Common certificate set const QuicTag kCCRT = TAG('C', 'C', 'R', 'T'); // Cached certificate const QuicTag kEXPY = TAG('E', 'X', 'P', 'Y'); // Expiry -// TODO(rjshade): Remove kIFCW when removing QUIC_VERSION_19. -const QuicTag kIFCW = TAG('I', 'F', 'C', 'W'); // Initial flow control receive - // window. const QuicTag kSFCW = TAG('S', 'F', 'C', 'W'); // Initial stream flow control // receive window. const QuicTag kCFCW = TAG('C', 'F', 'C', 'W'); // Initial session/connection
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index 82d05f3..e83b8b8 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc
@@ -435,13 +435,7 @@ max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED), bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL), initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), - // TODO(rjshade): Remove this when retiring QUIC_VERSION_19. - initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL), - // TODO(rjshade): Make this PRESENCE_REQUIRED when retiring - // QUIC_VERSION_19. initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL), - // TODO(rjshade): Make this PRESENCE_REQUIRED when retiring - // QUIC_VERSION_19. initial_session_flow_control_window_bytes_(kCFCW, PRESENCE_OPTIONAL), socket_receive_buffer_(kSRBF, PRESENCE_OPTIONAL) { SetDefaults(); @@ -546,28 +540,6 @@ return initial_round_trip_time_us_.GetSendValue(); } -void QuicConfig::SetInitialFlowControlWindowToSend(uint32 window_bytes) { - if (window_bytes < kMinimumFlowControlSendWindow) { - LOG(DFATAL) << "Initial flow control receive window (" << window_bytes - << ") cannot be set lower than default (" - << kMinimumFlowControlSendWindow << ")."; - window_bytes = kMinimumFlowControlSendWindow; - } - initial_flow_control_window_bytes_.SetSendValue(window_bytes); -} - -uint32 QuicConfig::GetInitialFlowControlWindowToSend() const { - return initial_flow_control_window_bytes_.GetSendValue(); -} - -bool QuicConfig::HasReceivedInitialFlowControlWindowBytes() const { - return initial_flow_control_window_bytes_.HasReceivedValue(); -} - -uint32 QuicConfig::ReceivedInitialFlowControlWindowBytes() const { - return initial_flow_control_window_bytes_.GetReceivedValue(); -} - void QuicConfig::SetInitialStreamFlowControlWindowToSend(uint32 window_bytes) { if (window_bytes < kMinimumFlowControlSendWindow) { LOG(DFATAL) << "Initial stream flow control receive window (" @@ -656,7 +628,6 @@ QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs); max_undecryptable_packets_ = kDefaultMaxUndecryptablePackets; - SetInitialFlowControlWindowToSend(kMinimumFlowControlSendWindow); SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow); SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow); } @@ -668,7 +639,6 @@ max_streams_per_connection_.ToHandshakeMessage(out); bytes_for_connection_id_.ToHandshakeMessage(out); initial_round_trip_time_us_.ToHandshakeMessage(out); - initial_flow_control_window_bytes_.ToHandshakeMessage(out); initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out); initial_session_flow_control_window_bytes_.ToHandshakeMessage(out); socket_receive_buffer_.ToHandshakeMessage(out); @@ -707,10 +677,6 @@ peer_hello, hello_type, error_details); } if (error == QUIC_NO_ERROR) { - error = initial_flow_control_window_bytes_.ProcessPeerHello( - peer_hello, hello_type, error_details); - } - if (error == QUIC_NO_ERROR) { error = initial_stream_flow_control_window_bytes_.ProcessPeerHello( peer_hello, hello_type, error_details); }
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index 12097f8..b8d7dd1 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h
@@ -332,17 +332,6 @@ uint32 GetInitialRoundTripTimeUsToSend() const; - // TODO(rjshade): Remove all InitialFlowControlWindow methods when removing - // QUIC_VERSION_19. - // Sets an initial stream flow control window size to transmit to the peer. - void SetInitialFlowControlWindowToSend(uint32 window_bytes); - - uint32 GetInitialFlowControlWindowToSend() const; - - bool HasReceivedInitialFlowControlWindowBytes() const; - - uint32 ReceivedInitialFlowControlWindowBytes() const; - // Sets an initial stream flow control window size to transmit to the peer. void SetInitialStreamFlowControlWindowToSend(uint32 window_bytes); @@ -411,10 +400,6 @@ // Initial round trip time estimate in microseconds. QuicFixedUint32 initial_round_trip_time_us_; - // TODO(rjshade): Remove when removing QUIC_VERSION_19. - // Initial flow control receive window in bytes. - QuicFixedUint32 initial_flow_control_window_bytes_; - // Initial stream flow control receive window in bytes. QuicFixedUint32 initial_stream_flow_control_window_bytes_; // Initial session flow control receive window in bytes.
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc index 1bdc456..8e2b34b 100644 --- a/net/quic/quic_config_test.cc +++ b/net/quic/quic_config_test.cc
@@ -26,8 +26,6 @@ }; TEST_F(QuicConfigTest, ToHandshakeMessage) { - config_.SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend( @@ -48,10 +46,6 @@ EXPECT_EQ(QUIC_NO_ERROR, error); EXPECT_EQ(4u, value); - error = msg.GetUint32(kIFCW, &value); - EXPECT_EQ(QUIC_NO_ERROR, error); - EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value); - error = msg.GetUint32(kSFCW, &value); EXPECT_EQ(QUIC_NO_ERROR, error); EXPECT_EQ(kInitialStreamFlowControlWindowForTest, value); @@ -82,8 +76,6 @@ client_config.SetMaxStreamsPerConnection( 2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection); client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); - client_config.SetInitialFlowControlWindowToSend( - 2 * kInitialSessionFlowControlWindowForTest); client_config.SetInitialStreamFlowControlWindowToSend( 2 * kInitialStreamFlowControlWindowForTest); client_config.SetInitialSessionFlowControlWindowToSend( @@ -111,8 +103,6 @@ EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size()); EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kTBBR); EXPECT_EQ(config_.ReceivedConnectionOptions()[1], kFHDR); - EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(), - 2 * kInitialSessionFlowControlWindowForTest); EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(), 2 * kInitialStreamFlowControlWindowForTest); EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), @@ -133,8 +123,6 @@ kDefaultMaxStreamsPerConnection / 2, kDefaultMaxStreamsPerConnection / 2); server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli); - server_config.SetInitialFlowControlWindowToSend( - 2 * kInitialSessionFlowControlWindowForTest); server_config.SetInitialStreamFlowControlWindowToSend( 2 * kInitialStreamFlowControlWindowForTest); server_config.SetInitialSessionFlowControlWindowToSend( @@ -153,8 +141,6 @@ EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2, config_.MaxStreamsPerConnection()); EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); - EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(), - 2 * kInitialSessionFlowControlWindowForTest); EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(), 2 * kInitialStreamFlowControlWindowForTest); EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), @@ -179,8 +165,6 @@ config_.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); EXPECT_TRUE(config_.negotiated()); - - EXPECT_FALSE(config_.HasReceivedInitialFlowControlWindowBytes()); } TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) { @@ -197,8 +181,6 @@ config_.ProcessPeerHello(msg, SERVER, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); EXPECT_TRUE(config_.negotiated()); - - EXPECT_FALSE(config_.HasReceivedInitialFlowControlWindowBytes()); } TEST_F(QuicConfigTest, MissingValueInCHLO) { @@ -272,11 +254,11 @@ // peer: the receive window must be at least the default of 16 Kb. QuicConfig config; const uint64 kInvalidWindow = kMinimumFlowControlSendWindow - 1; - EXPECT_DFATAL(config.SetInitialFlowControlWindowToSend(kInvalidWindow), - "Initial flow control receive window"); + EXPECT_DFATAL(config.SetInitialStreamFlowControlWindowToSend(kInvalidWindow), + "Initial stream flow control receive window"); EXPECT_EQ(kMinimumFlowControlSendWindow, - config.GetInitialFlowControlWindowToSend()); + config.GetInitialStreamFlowControlWindowToSend()); } } // namespace
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index 4ac9284..fc27219 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc
@@ -1682,92 +1682,134 @@ EXPECT_EQ(2u, connection_.NumQueuedPackets()); } -TEST_P(QuicConnectionTest, AbandonFECFromCongestionWindow) { +TEST_P(QuicConnectionTest, RemoveFECFromInflightOnRetransmissionTimeout) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator( &connection_)->IsFecEnabled()); + QuicSentPacketManager* manager = + QuicConnectionPeer::GetSentPacketManager(&connection_); + EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager)); // 1 Data and 1 FEC packet. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(2); connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); + size_t data_and_fec = QuicSentPacketManagerPeer::GetBytesInFlight(manager); + EXPECT_LT(0u, data_and_fec); - const QuicTime::Delta retransmission_time = - QuicTime::Delta::FromMilliseconds(5000); - clock_.AdvanceTime(retransmission_time); - - // Abandon FEC packet and data packet. - EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - EXPECT_CALL(visitor_, OnCanWrite()); - connection_.OnRetransmissionTimeout(); -} - -TEST_P(QuicConnectionTest, DontAbandonAckedFEC) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator( - &connection_)->IsFecEnabled()); - - // 3 Data and 3 FEC packets. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); - // Send some more data afterwards to ensure early retransmit doesn't trigger. - connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr); - connection_.SendStreamDataWithStringWithFec(3, "foo", 6, !kFin, nullptr); - - QuicAckFrame ack_fec = InitAckFrame(2); - // Data packet missing. - // TODO(ianswett): Note that this is not a sensible ack, since if the FEC was - // received, it would cause the covered packet to be acked as well. - NackPacket(1, &ack_fec); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - ProcessAckPacket(&ack_fec); clock_.AdvanceTime(DefaultRetransmissionTime()); - // Don't abandon the acked FEC packet, but it will abandon 2 the subsequent - // FEC packets. + // On RTO, both data and FEC packets are removed from inflight, + // and retransmission of the data (but not FEC) gets added into the inflight. EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); connection_.GetRetransmissionAlarm()->Fire(); -} + ; -TEST_P(QuicConnectionTest, AbandonAllFEC) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator( - &connection_)->IsFecEnabled()); + size_t data_only = QuicSentPacketManagerPeer::GetBytesInFlight(manager); + EXPECT_LT(0u, data_only); + EXPECT_GE(data_and_fec, 2 * data_only); - // 3 Data and 3 FEC packet. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); - // Send some more data afterwards to ensure early retransmit doesn't trigger. - connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr); - // Advance the time so not all the FEC packets are abandoned. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - connection_.SendStreamDataWithStringWithFec(3, "foo", 6, !kFin, nullptr); - - QuicAckFrame ack_fec = InitAckFrame(5); - // Ack all data packets, but no fec packets. - NackPacket(2, &ack_fec); - NackPacket(4, &ack_fec); - - // Lose the first FEC packet and ack the three data packets. + // Receive ack for the retransmission. No data should be outstanding. + QuicAckFrame ack = InitAckFrame(3); + NackPacket(1, &ack); + NackPacket(2, &ack); SequenceNumberSet lost_packets; - lost_packets.insert(2); EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _)) .WillOnce(Return(lost_packets)); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - ProcessAckPacket(&ack_fec); + ProcessAckPacket(&ack); + EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager)); - clock_.AdvanceTime(DefaultRetransmissionTime().Subtract( - QuicTime::Delta::FromMilliseconds(1))); - - // Abandon all packets - EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(false)); - connection_.GetRetransmissionAlarm()->Fire(); - - // Ensure the alarm is not set since all packets have been abandoned. + // Ensure the alarm is not set since all packets have been acked or abandoned. EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); + EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager)); +} + +TEST_P(QuicConnectionTest, RemoveFECFromInflightOnLossRetransmission) { + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator( + &connection_)->IsFecEnabled()); + QuicSentPacketManager* manager = + QuicConnectionPeer::GetSentPacketManager(&connection_); + + // 1 Data packet and 1 FEC packet, followed by more data to trigger NACKs. + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6); + connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); + connection_.SendStreamDataWithString(3, "foo", 3, !kFin, nullptr); + connection_.SendStreamDataWithString(3, "foo", 6, !kFin, nullptr); + connection_.SendStreamDataWithString(3, "foo", 9, !kFin, nullptr); + connection_.SendStreamDataWithString(3, "foo", 12, !kFin, nullptr); + size_t multiple_data_and_fec = + QuicSentPacketManagerPeer::GetBytesInFlight(manager); + EXPECT_LT(0u, multiple_data_and_fec); + + // Ack data packets, and NACK 1 data packet and FEC packet. Triggers + // NACK-based loss detection of data and FEC packet, but only data is + // retransmitted and considered oustanding. + QuicAckFrame ack = InitAckFrame(6); + NackPacket(2, &ack); + NackPacket(3, &ack); + SequenceNumberSet lost_packets; + lost_packets.insert(2); + lost_packets.insert(3); + EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _)) + .WillOnce(Return(lost_packets)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(1); + ProcessAckPacket(&ack); + size_t data_only = QuicSentPacketManagerPeer::GetBytesInFlight(manager); + EXPECT_GT(multiple_data_and_fec, data_only); + EXPECT_LT(0u, data_only); + + // Receive ack for the retransmission. No data should be outstanding. + QuicAckFrame ack2 = InitAckFrame(7); + NackPacket(2, &ack2); + NackPacket(3, &ack2); + SequenceNumberSet lost_packets2; + EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _)) + .WillOnce(Return(lost_packets2)); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); + ProcessAckPacket(&ack2); + EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager)); +} + +TEST_P(QuicConnectionTest, NoTLPForFECPacket) { + // Turn on TLP for this test. + QuicSentPacketManagerPeer::SetMaxTailLossProbes( + QuicConnectionPeer::GetSentPacketManager(&connection_), 1); + + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator( + &connection_)->IsFecEnabled()); + QuicSentPacketManager* manager = + QuicConnectionPeer::GetSentPacketManager(&connection_); + + // 1 Data packet and 1 FEC packet. + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(2); + connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); + + // Ack data packet, but not FEC packet. + QuicAckFrame ack = InitAckFrame(1); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); + ProcessAckPacket(&ack); + + // No TLP alarm for FEC, so when retransmission alarm fires, it is an RTO. + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); + EXPECT_LT(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager)); + QuicTime rto_time = connection_.GetRetransmissionAlarm()->deadline(); + EXPECT_NE(QuicTime::Zero(), rto_time); + + // Simulate the retransmission alarm firing. FEC packet is no longer + // outstanding. + EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(false)); + clock_.AdvanceTime(rto_time.Subtract(clock_.Now())); + connection_.GetRetransmissionAlarm()->Fire(); + EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); + EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager)); } TEST_P(QuicConnectionTest, FramePacking) { @@ -3026,8 +3068,6 @@ CryptoHandshakeMessage msg; string error_details; QuicConfig client_config; - client_config.SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); client_config.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); client_config.SetInitialSessionFlowControlWindowToSend(
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc index bef06aa..6d9358d 100644 --- a/net/quic/quic_crypto_stream.cc +++ b/net/quic/quic_crypto_stream.cc
@@ -25,11 +25,6 @@ encryption_established_(false), handshake_confirmed_(false) { crypto_framer_.set_visitor(this); - if (version() < QUIC_VERSION_21) { - // Prior to QUIC_VERSION_21 the crypto stream is not subject to any flow - // control. - DisableFlowControl(); - } // The crypto stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); }
diff --git a/net/quic/quic_crypto_stream_test.cc b/net/quic/quic_crypto_stream_test.cc index a491235..3c62644 100644 --- a/net/quic/quic_crypto_stream_test.cc +++ b/net/quic/quic_crypto_stream_test.cc
@@ -102,11 +102,7 @@ } TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) { - if (connection_->version() < QUIC_VERSION_21) { - EXPECT_FALSE(stream_.flow_controller()->IsEnabled()); - } else { - EXPECT_TRUE(stream_.flow_controller()->IsEnabled()); - } + EXPECT_TRUE(stream_.flow_controller()->IsEnabled()); EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( &stream_)); }
diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc index a3fa12b..0e3b76e 100644 --- a/net/quic/quic_end_to_end_unittest.cc +++ b/net/quic/quic_end_to_end_unittest.cc
@@ -130,8 +130,6 @@ net::IPAddressNumber ip; CHECK(net::ParseIPLiteralToNumber("127.0.0.1", &ip)); server_address_ = IPEndPoint(ip, 0); - server_config_.SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); server_config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); server_config_.SetInitialSessionFlowControlWindowToSend(
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index 3146a58..d7c54b1 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc
@@ -4,14 +4,6 @@ #include "net/quic/quic_flags.h" -// TODO(rtenneti): Remove this. -// Do not flip this flag until the flakiness of the -// net/tools/quic/end_to_end_test is fixed. -// If true, then QUIC connections will track the retransmission history of a -// packet so that an ack of a previous transmission will ack the data of all -// other transmissions. -bool FLAGS_track_retransmission_history = false; - bool FLAGS_quic_allow_oversized_packets_for_test = false; // When true, the use time based loss detection instead of nack. @@ -37,7 +29,7 @@ bool FLAGS_quic_allow_bbr = false; // If true, truncate QUIC connection IDs if the client requests it. -bool FLAGS_allow_truncated_connection_ids_for_quic = false; +bool FLAGS_allow_truncated_connection_ids_for_quic = true; // Do not flip this flag. jokulik plans more testing and additional monitoring // before the flag can go the auto-flip process. @@ -76,3 +68,6 @@ // If true, if min RTT and/or SRTT have not yet been set then initial RTT is // used to initialize them in a call to QuicConnection::GetStats. bool FLAGS_quic_use_initial_rtt_for_stats = true; + +// If true, uses the last sent packet for the RTO timer instead of the earliest. +bool FLAGS_quic_rto_uses_last_sent = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index 08d1f96..72789fb 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h
@@ -7,7 +7,6 @@ #include "net/base/net_export.h" -NET_EXPORT_PRIVATE extern bool FLAGS_track_retransmission_history; NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_oversized_packets_for_test; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_time_loss_detection; NET_EXPORT_PRIVATE extern bool FLAGS_use_early_return_when_verifying_chlo; @@ -27,5 +26,6 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_multiple_address_in_source_tokens; NET_EXPORT_PRIVATE extern bool FLAGS_quic_empty_data_no_fin_early_return; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_initial_rtt_for_stats; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_rto_uses_last_sent; #endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc index e8c8b58..676c82a 100644 --- a/net/quic/quic_headers_stream.cc +++ b/net/quic/quic_headers_stream.cc
@@ -185,11 +185,6 @@ spdy_framer_visitor_(new SpdyFramerVisitor(this)) { spdy_framer_.set_visitor(spdy_framer_visitor_.get()); spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); - if (version() < QUIC_VERSION_21) { - // Prior to QUIC_VERSION_21 the headers stream is not subject to any flow - // control. - DisableFlowControl(); - } // The headers stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); }
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc index 446b73f..89c87f2 100644 --- a/net/quic/quic_headers_stream_test.cc +++ b/net/quic/quic_headers_stream_test.cc
@@ -336,11 +336,7 @@ } TEST_P(QuicHeadersStreamTest, NoConnectionLevelFlowControl) { - if (connection_->version() < QUIC_VERSION_21) { - EXPECT_FALSE(headers_stream_->flow_controller()->IsEnabled()); - } else { - EXPECT_TRUE(headers_stream_->flow_controller()->IsEnabled()); - } + EXPECT_TRUE(headers_stream_->flow_controller()->IsEnabled()); EXPECT_FALSE(ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( headers_stream_)); }
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index b631b07..1d5a312 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc
@@ -158,8 +158,6 @@ QuicTag QuicVersionToQuicTag(const QuicVersion version) { switch (version) { - case QUIC_VERSION_19: - return MakeQuicTag('Q', '0', '1', '9'); case QUIC_VERSION_21: return MakeQuicTag('Q', '0', '2', '1'); case QUIC_VERSION_22: @@ -192,7 +190,6 @@ string QuicVersionToString(const QuicVersion version) { switch (version) { - RETURN_STRING_LITERAL(QUIC_VERSION_19); RETURN_STRING_LITERAL(QUIC_VERSION_21); RETURN_STRING_LITERAL(QUIC_VERSION_22); RETURN_STRING_LITERAL(QUIC_VERSION_23);
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index ee2c7e1..81c87c7 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h
@@ -310,7 +310,6 @@ // Special case to indicate unknown/unsupported QUIC version. QUIC_VERSION_UNSUPPORTED = 0, - QUIC_VERSION_19 = 19, // Connection level flow control. QUIC_VERSION_21 = 21, // Headers/crypto streams are flow controlled. QUIC_VERSION_22 = 22, // Send Server Config Update messages on crypto stream. QUIC_VERSION_23 = 23, // Timestamp in the ack frame. @@ -324,8 +323,7 @@ // IMPORTANT: if you are adding to this list, follow the instructions at // http://sites/quic/adding-and-removing-versions static const QuicVersion kSupportedQuicVersions[] = {QUIC_VERSION_23, - QUIC_VERSION_22, - QUIC_VERSION_19}; + QUIC_VERSION_22}; typedef std::vector<QuicVersion> QuicVersionVector;
diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc index 9460906..646c099 100644 --- a/net/quic/quic_protocol_test.cc +++ b/net/quic/quic_protocol_test.cc
@@ -68,8 +68,8 @@ #endif // Explicitly test a specific version. - EXPECT_EQ(MakeQuicTag('Q', '0', '1', '9'), - QuicVersionToQuicTag(QUIC_VERSION_19)); + EXPECT_EQ(MakeQuicTag('Q', '0', '2', '3'), + QuicVersionToQuicTag(QUIC_VERSION_23)); // Loop over all supported versions and make sure that we never hit the // default case (i.e. all supported versions should be successfully converted @@ -107,8 +107,8 @@ #endif // Explicitly test specific versions. - EXPECT_EQ(QUIC_VERSION_19, - QuicTagToQuicVersion(MakeQuicTag('Q', '0', '1', '9'))); + EXPECT_EQ(QUIC_VERSION_23, + QuicTagToQuicVersion(MakeQuicTag('Q', '0', '2', '3'))); for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) { QuicVersion version = kSupportedQuicVersions[i]; @@ -139,23 +139,23 @@ } TEST(QuicProtocolTest, QuicVersionToString) { - EXPECT_EQ("QUIC_VERSION_19", QuicVersionToString(QUIC_VERSION_19)); + EXPECT_EQ("QUIC_VERSION_23", QuicVersionToString(QUIC_VERSION_23)); EXPECT_EQ("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(QUIC_VERSION_UNSUPPORTED)); - QuicVersion single_version[] = {QUIC_VERSION_19}; + QuicVersion single_version[] = {QUIC_VERSION_23}; QuicVersionVector versions_vector; for (size_t i = 0; i < arraysize(single_version); ++i) { versions_vector.push_back(single_version[i]); } - EXPECT_EQ("QUIC_VERSION_19", QuicVersionVectorToString(versions_vector)); + EXPECT_EQ("QUIC_VERSION_23", QuicVersionVectorToString(versions_vector)); - QuicVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED, QUIC_VERSION_19}; + QuicVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED, QUIC_VERSION_23}; versions_vector.clear(); for (size_t i = 0; i < arraysize(multiple_versions); ++i) { versions_vector.push_back(multiple_versions[i]); } - EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_19", + EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_23", QuicVersionVectorToString(versions_vector)); // Make sure that all supported versions are present in QuicVersionToString.
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index f1804f9..b71b300 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc
@@ -848,7 +848,9 @@ case RTO_MODE: { // The RTO is based on the first outstanding packet. const QuicTime sent_time = - unacked_packets_.GetFirstInFlightPacketSentTime(); + FLAGS_quic_rto_uses_last_sent + ? unacked_packets_.GetLastPacketSentTime() + : unacked_packets_.GetFirstInFlightPacketSentTime(); QuicTime rto_time = sent_time.Add(GetRetransmissionDelay()); // Wait for TLP packets to be acked before an RTO fires. QuicTime tlp_time =
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index 92ce1dc..756c21a 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -799,6 +799,9 @@ for (size_t i = 1; i <= kNumSentPackets; ++i) { SendDataPacket(i); } + QuicTime rto_packet_time = clock_.Now(); + // Advance the time. + clock_.AdvanceTime(manager_.GetRetransmissionTime().Subtract(clock_.Now())); // The first tail loss probe retransmits 1 packet. manager_.OnRetransmissionTimeout(); @@ -813,6 +816,7 @@ EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA)); EXPECT_FALSE(manager_.HasPendingRetransmissions()); + clock_.AdvanceTime(manager_.GetRetransmissionTime().Subtract(clock_.Now())); // The second tail loss probe retransmits 1 packet. manager_.OnRetransmissionTimeout(); @@ -827,6 +831,15 @@ EXPECT_EQ(QuicTime::Delta::Infinite(), manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA)); + // Ensure the RTO is set based on the correct packet. + if (FLAGS_quic_rto_uses_last_sent) { + rto_packet_time = clock_.Now(); + } + EXPECT_CALL(*send_algorithm_, RetransmissionDelay()) + .WillOnce(Return(QuicTime::Delta::FromSeconds(1))); + EXPECT_EQ(rto_packet_time.Add(QuicTime::Delta::FromSeconds(1)), + manager_.GetRetransmissionTime()); + // Advance the time enough to ensure all packets are RTO'd. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
diff --git a/net/quic/quic_server.cc b/net/quic/quic_server.cc index e8262a8..2e2d5b2 100644 --- a/net/quic/quic_server.cc +++ b/net/quic/quic_server.cc
@@ -55,10 +55,6 @@ // sensible value for a server: 1 MB for session, 64 KB for each stream. const uint32 kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB const uint32 kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB - if (config_.GetInitialFlowControlWindowToSend() == - kMinimumFlowControlSendWindow) { - config_.SetInitialFlowControlWindowToSend(kInitialSessionFlowControlWindow); - } if (config_.GetInitialStreamFlowControlWindowToSend() == kMinimumFlowControlSendWindow) { config_.SetInitialStreamFlowControlWindowToSend(
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index 20fd983..865af07 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc
@@ -104,20 +104,16 @@ next_stream_id_(is_server() ? 2 : 5), largest_peer_created_stream_id_(0), error_(QUIC_NO_ERROR), + flow_controller_(new QuicFlowController( + connection_.get(), + 0, + is_server(), + kMinimumFlowControlSendWindow, + config_.GetInitialSessionFlowControlWindowToSend(), + config_.GetInitialSessionFlowControlWindowToSend())), goaway_received_(false), goaway_sent_(false), has_pending_handshake_(false) { - if (connection_->version() == QUIC_VERSION_19) { - flow_controller_.reset(new QuicFlowController( - connection_.get(), 0, is_server(), kMinimumFlowControlSendWindow, - config_.GetInitialFlowControlWindowToSend(), - config_.GetInitialFlowControlWindowToSend())); - } else { - flow_controller_.reset(new QuicFlowController( - connection_.get(), 0, is_server(), kMinimumFlowControlSendWindow, - config_.GetInitialSessionFlowControlWindowToSend(), - config_.GetInitialSessionFlowControlWindowToSend())); - } } void QuicSession::InitializeSession() { @@ -464,7 +460,6 @@ void QuicSession::OnConfigNegotiated() { connection_->SetFromConfig(config_); - QuicVersion version = connection()->version(); uint32 max_streams = config_.MaxStreamsPerConnection(); if (is_server()) { @@ -479,23 +474,6 @@ } set_max_open_streams(max_streams); - if (version == QUIC_VERSION_19) { - // QUIC_VERSION_19 doesn't support independent stream/session flow - // control windows. - if (config_.HasReceivedInitialFlowControlWindowBytes()) { - // Streams which were created before the SHLO was received (0-RTT - // requests) are now informed of the peer's initial flow control window. - QuicStreamOffset new_window = - config_.ReceivedInitialFlowControlWindowBytes(); - OnNewStreamFlowControlWindow(new_window); - OnNewSessionFlowControlWindow(new_window); - } - - return; - } - - // QUIC_VERSION_21 and higher can have independent stream and session flow - // control windows. if (config_.HasReceivedInitialStreamFlowControlWindowBytes()) { // Streams which were created before the SHLO was received (0-RTT // requests) are now informed of the peer's initial flow control window. @@ -748,7 +726,6 @@ void QuicSession::PostProcessAfterData() { STLDeleteElements(&closed_streams_); - closed_streams_.clear(); if (connection()->connected() && locally_closed_streams_highest_offset_.size() > max_open_streams_) { @@ -757,15 +734,6 @@ } } -void QuicSession::OnSuccessfulVersionNegotiation(const QuicVersion& version) { - // Disable stream level flow control based on negotiated version. Streams may - // have been created with a different version. - if (version < QUIC_VERSION_21) { - GetCryptoStream()->flow_controller()->Disable(); - headers_stream_->flow_controller()->Disable(); - } -} - bool QuicSession::IsConnectionFlowControlBlocked() const { return flow_controller_->IsBlocked(); }
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 3339d42..34fa2f4 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h
@@ -68,7 +68,7 @@ void OnBlockedFrames(const std::vector<QuicBlockedFrame>& frames) override; void OnConnectionClosed(QuicErrorCode error, bool from_peer) override; void OnWriteBlocked() override {} - void OnSuccessfulVersionNegotiation(const QuicVersion& version) override; + void OnSuccessfulVersionNegotiation(const QuicVersion& version) override {} void OnCanWrite() override; void OnCongestionWindowChange(QuicTime now) override {} bool WillingAndAbleToWrite() const override; @@ -322,6 +322,9 @@ // The latched error with which the connection was closed. QuicErrorCode error_; + // Used for session level flow control. + scoped_ptr<QuicFlowController> flow_controller_; + // Whether a GoAway has been received. bool goaway_received_; // Whether a GoAway has been sent. @@ -330,12 +333,6 @@ // Indicate if there is pending data for the crypto stream. bool has_pending_handshake_; - // Used for session level flow control. - scoped_ptr<QuicFlowController> flow_controller_; - - // True if this is a secure (HTTPS) QUIC session. - bool is_secure_; - DISALLOW_COPY_AND_ASSIGN(QuicSession); };
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index 1c14c99..96d30b8 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc
@@ -59,8 +59,6 @@ handshake_confirmed_ = true; CryptoHandshakeMessage msg; string error_details; - session()->config()->SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); session()->config()->SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( @@ -188,8 +186,6 @@ QuicSessionTest() : connection_(new MockConnection(true, SupportedVersions(GetParam()))), session_(connection_) { - session_.config()->SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); session_.config()->SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); session_.config()->SetInitialSessionFlowControlWindowToSend( @@ -661,9 +657,6 @@ } TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedCryptoStream) { - if (version() <= QUIC_VERSION_19) { - return; - } // Test that if the crypto stream is flow control blocked, then if the SHLO // contains a larger send window offset, the stream becomes unblocked. session_.set_writev_consumes_all_data(true); @@ -709,9 +702,6 @@ } TEST_P(QuicSessionTest, HandshakeUnblocksFlowControlBlockedHeadersStream) { - if (version() <= QUIC_VERSION_19) { - return; - } // Test that if the header stream is flow control blocked, then if the SHLO // contains a larger send window offset, the stream becomes unblocked. session_.set_writev_consumes_all_data(true); @@ -759,23 +749,6 @@ EXPECT_FALSE(headers_stream->HasBufferedData()); } -TEST_P(QuicSessionTest, InvalidFlowControlWindowInHandshake) { - // TODO(rjshade): Remove this test when removing QUIC_VERSION_19. - // Test that receipt of an invalid (< default) flow control window from - // the peer results in the connection being torn down. - if (version() > QUIC_VERSION_19) { - return; - } - - uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1; - QuicConfigPeer::SetReceivedInitialFlowControlWindow(session_.config(), - kInvalidWindow); - - EXPECT_CALL(*connection_, - SendConnectionClose(QUIC_FLOW_CONTROL_INVALID_WINDOW)).Times(2); - session_.OnConfigNegotiated(); -} - TEST_P(QuicSessionTest, ConnectionFlowControlAccountingRstOutOfOrder) { // Test that when we receive an out of order stream RST we correctly adjust // our connection level flow control receive window. @@ -820,20 +793,6 @@ EXPECT_EQ(kByteOffset, stream->flow_controller()->highest_received_byte_offset()); - // We only expect to see a connection WINDOW_UPDATE when talking - // QUIC_VERSION_19, as in this case both stream and session flow control - // windows are the same size. In later versions we will not see a connection - // level WINDOW_UPDATE when exhausting a stream, as the stream flow control - // limit is much lower than the connection flow control limit. - if (version() == QUIC_VERSION_19) { - // Expect no stream WINDOW_UPDATE frames, as stream read side closed. - EXPECT_CALL(*connection_, SendWindowUpdate(stream->id(), _)).Times(0); - // We do expect a connection level WINDOW_UPDATE when the stream is reset. - EXPECT_CALL(*connection_, - SendWindowUpdate(0, kInitialSessionFlowControlWindowForTest + - kByteOffset)).Times(1); - } - // Reset stream locally. stream->Reset(QUIC_STREAM_CANCELLED); EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed()); @@ -914,10 +873,6 @@ TEST_P(QuicSessionTest, InvalidStreamFlowControlWindowInHandshake) { // Test that receipt of an invalid (< default) stream flow control window from // the peer results in the connection being torn down. - if (version() <= QUIC_VERSION_19) { - return; - } - uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1; QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(session_.config(), kInvalidWindow); @@ -930,10 +885,6 @@ TEST_P(QuicSessionTest, InvalidSessionFlowControlWindowInHandshake) { // Test that receipt of an invalid (< default) session flow control window // from the peer results in the connection being torn down. - if (version() == QUIC_VERSION_19) { - return; - } - uint32 kInvalidWindow = kMinimumFlowControlSendWindow - 1; QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(session_.config(), kInvalidWindow); @@ -968,9 +919,6 @@ TEST_P(QuicSessionTest, WindowUpdateUnblocksHeadersStream) { // Test that a flow control blocked headers stream gets unblocked on recipt of // a WINDOW_UPDATE frame. Regression test for b/17413860. - if (version() < QUIC_VERSION_21) { - return; - } // Set the headers stream to be flow control blocked. QuicHeadersStream* headers_stream =
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 8343f89..5c0d2f9 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -9,6 +9,7 @@ #include "base/cpu.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/profiler/scoped_tracker.h" #include "base/rand_util.h" @@ -32,6 +33,7 @@ #include "net/quic/quic_connection_helper.h" #include "net/quic/quic_crypto_client_stream_factory.h" #include "net/quic/quic_default_packet_writer.h" +#include "net/quic/quic_flags.h" #include "net/quic/quic_http_stream.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_server_id.h" @@ -565,6 +567,7 @@ int load_server_info_timeout, bool disable_loading_server_info_for_new_servers, float load_server_info_timeout_srtt_multiplier, + bool enable_truncated_connection_ids, const QuicTagVector& connection_options) : require_confirmation_(true), host_resolver_(host_resolver), @@ -587,6 +590,7 @@ disable_loading_server_info_for_new_servers), load_server_info_timeout_srtt_multiplier_( load_server_info_timeout_srtt_multiplier), + enable_truncated_connection_ids_(enable_truncated_connection_ids), port_seed_(random_generator_->RandUint64()), check_persisted_supports_quic_(true), task_runner_(nullptr), @@ -1045,12 +1049,14 @@ QuicConfig config = config_; config.set_max_undecryptable_packets(kMaxUndecryptablePackets); - config.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize); config.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize); config.SetInitialSessionFlowControlWindowToSend(kInitialReceiveWindowSize); int64 srtt = GetServerNetworkStatsSmoothedRttInMicroseconds(server_id); if (srtt > 0) config.SetInitialRoundTripTimeUsToSend(static_cast<uint32>(srtt)); + if (FLAGS_allow_truncated_connection_ids_for_quic && + enable_truncated_connection_ids_) + config.SetBytesForConnectionIdToSend(0); if (quic_server_info_factory_ && !server_info) { // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index b862309..ed5a930 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h
@@ -107,6 +107,7 @@ int load_server_info_timeout, bool disable_loading_server_info_for_new_servers, float load_server_info_timeout_srtt_multiplier, + bool enable_truncated_connection_ids, const QuicTagVector& connection_options); ~QuicStreamFactory() override; @@ -307,6 +308,9 @@ // want to timeout, set |load_server_info_timeout_srtt_multiplier_| to 0. float load_server_info_timeout_srtt_multiplier_; + // Set this for setting config's BytesForConnectionIdToSend (TCID param) to 0. + bool enable_truncated_connection_ids_; + // Each profile will (probably) have a unique port_seed_ value. This value is // used to help seed a pseudo-random number generator (PortSuggester) so that // we consistently (within this profile) suggest the same ephemeral port when
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 9248dcf..345b818 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -165,6 +165,7 @@ /*load_server_info_timeout=*/0u, /*disable_loading_server_info_for_new_servers=*/false, /*load_server_info_timeout_srtt_multiplier=*/0.0f, + /*enable_truncated_connection_ids=*/true, QuicTagVector()), host_port_pair_(kDefaultServerHostName, kDefaultServerPort), is_https_(false), @@ -1093,8 +1094,8 @@ HttpRequestInfo request_info; std::vector<QuicHttpStream*> streams; // The MockCryptoClientStream sets max_open_streams to be - // 2 * kDefaultMaxStreamsPerConnection. - for (size_t i = 0; i < 2 * kDefaultMaxStreamsPerConnection; i++) { + // kDefaultMaxStreamsPerConnection / 2. + for (size_t i = 0; i < kDefaultMaxStreamsPerConnection / 2; i++) { QuicStreamRequest request(&factory_); int rv = request.Request(host_port_pair_, is_https_,
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 6a2b8c7..e6abe76 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc
@@ -27,26 +27,10 @@ } size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session) { - QuicVersion version = session->connection()->version(); - if (version <= QUIC_VERSION_19) { - return session->config()->GetInitialFlowControlWindowToSend(); - } - return session->config()->GetInitialStreamFlowControlWindowToSend(); } size_t GetReceivedFlowControlWindow(QuicSession* session) { - QuicVersion version = session->connection()->version(); - if (version <= QUIC_VERSION_19) { - if (session->config()->HasReceivedInitialFlowControlWindowBytes()) { - return session->config()->ReceivedInitialFlowControlWindowBytes(); - } - - return kMinimumFlowControlSendWindow; - } - - // Version must be >= QUIC_VERSION_21, so we check for stream specific flow - // control window. if (session->config()->HasReceivedInitialStreamFlowControlWindowBytes()) { return session->config()->ReceivedInitialStreamFlowControlWindowBytes(); } @@ -365,10 +349,7 @@ if (flow_controller_.IsEnabled()) { // How much data we are allowed to write from flow control. QuicByteCount send_window = flow_controller_.SendWindowSize(); - // TODO(rjshade): Remove connection_flow_controller_->IsEnabled() check when - // removing QUIC_VERSION_19. - if (stream_contributes_to_connection_flow_control_ && - connection_flow_controller_->IsEnabled()) { + if (stream_contributes_to_connection_flow_control_) { send_window = min(send_window, connection_flow_controller_->SendWindowSize()); }
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 1de6004..93ad0c6 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h
@@ -167,11 +167,6 @@ const QuicStreamSequencer* sequencer() const { return &sequencer_; } QuicStreamSequencer* sequencer() { return &sequencer_; } - // TODO(rjshade): Remove this method when removing QUIC_VERSION_19. - void DisableFlowControl() { - flow_controller_.Disable(); - } - void DisableConnectionFlowControlForThisStream() { stream_contributes_to_connection_flow_control_ = false; }
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index 4a77aa0..c50cbb4 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc
@@ -116,8 +116,6 @@ // New streams rely on having the peer's flow control receive window // negotiated in the config. - QuicConfigPeer::SetReceivedInitialFlowControlWindow( - session_->config(), initial_flow_control_window_bytes_); QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow( session_->config(), initial_flow_control_window_bytes_);
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc index 8650eb9..c6e6780 100644 --- a/net/quic/test_tools/mock_crypto_client_stream.cc +++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -87,15 +87,17 @@ cgst.push_back(kTBBR); #endif cgst.push_back(kQBIC); - session()->config()->SetCongestionFeedback(cgst, kQBIC); - session()->config()->SetIdleConnectionStateLifetime( + QuicConfig config; + config.SetCongestionFeedback(cgst, kQBIC); + config.SetIdleConnectionStateLifetime( QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs), QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs)); - session()->config()->SetMaxStreamsPerConnection( - 2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection); + config.SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection / 2, + kDefaultMaxStreamsPerConnection / 2); + config.SetBytesForConnectionIdToSend(PACKET_8BYTE_CONNECTION_ID); CryptoHandshakeMessage msg; - session()->config()->ToHandshakeMessage(&msg); + config.ToHandshakeMessage(&msg); string error_details; const QuicErrorCode error = session()->config()->ProcessPeerHello(msg, CLIENT, &error_details);
diff --git a/net/quic/test_tools/quic_config_peer.cc b/net/quic/test_tools/quic_config_peer.cc index d0f5bfd..05f7538 100644 --- a/net/quic/test_tools/quic_config_peer.cc +++ b/net/quic/test_tools/quic_config_peer.cc
@@ -17,12 +17,6 @@ } // static -void QuicConfigPeer::SetReceivedInitialFlowControlWindow(QuicConfig* config, - uint32 window_bytes) { - config->initial_flow_control_window_bytes_.SetReceivedValue(window_bytes); -} - -// static void QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow( QuicConfig* config, uint32 window_bytes) {
diff --git a/net/quic/test_tools/quic_config_peer.h b/net/quic/test_tools/quic_config_peer.h index 32e6bff..46726eb 100644 --- a/net/quic/test_tools/quic_config_peer.h +++ b/net/quic/test_tools/quic_config_peer.h
@@ -18,10 +18,6 @@ static void SetReceivedSocketReceiveBuffer(QuicConfig* config, uint32 receive_buffer_bytes); - // TODO(rjshade): Remove when removing QUIC_VERSION_19. - static void SetReceivedInitialFlowControlWindow(QuicConfig* config, - uint32 window_bytes); - static void SetReceivedInitialStreamFlowControlWindow(QuicConfig* config, uint32 window_bytes);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 13e5eb1..27020d3 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc
@@ -619,8 +619,6 @@ QuicConfig DefaultQuicConfig() { QuicConfig config; - config.SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); config.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config.SetInitialSessionFlowControlWindowToSend(
diff --git a/net/sdch/sdch_owner.cc b/net/sdch/sdch_owner.cc new file mode 100644 index 0000000..b0e4405 --- /dev/null +++ b/net/sdch/sdch_owner.cc
@@ -0,0 +1,265 @@ +// Copyright 2014 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. + +#include "net/sdch/sdch_owner.h" + +#include "base/bind.h" +#include "base/metrics/histogram_macros.h" +#include "base/time/default_clock.h" +#include "net/base/sdch_manager.h" +#include "net/base/sdch_net_log_params.h" + +namespace { + +enum DictionaryFate { + // A Get-Dictionary header wasn't acted on. + DICTIONARY_FATE_GET_IGNORED = 1, + + // A fetch was attempted, but failed. + // TODO(rdsmith): Actually record this case. + DICTIONARY_FATE_FETCH_FAILED = 2, + + // A successful fetch was dropped on the floor, no space. + DICTIONARY_FATE_FETCH_IGNORED_NO_SPACE = 3, + + // A successful fetch was refused by the SdchManager. + DICTIONARY_FATE_FETCH_MANAGER_REFUSED = 4, + + // A dictionary was successfully added. + DICTIONARY_FATE_ADDED = 5, + + // A dictionary was evicted by an incoming dict. + DICTIONARY_FATE_EVICT_FOR_DICT = 6, + + // A dictionary was evicted by memory pressure. + DICTIONARY_FATE_EVICT_FOR_MEMORY = 7, + + // A dictionary was evicted on destruction. + DICTIONARY_FATE_EVICT_FOR_DESTRUCTION = 8, + + DICTIONARY_FATE_MAX = 9 +}; + +void RecordDictionaryFate(enum DictionaryFate fate) { + UMA_HISTOGRAM_ENUMERATION("Sdch3.DictionaryFate", fate, DICTIONARY_FATE_MAX); +} + +void RecordDictionaryEviction(int use_count, DictionaryFate fate) { + DCHECK(fate == DICTIONARY_FATE_EVICT_FOR_DICT || + fate == DICTIONARY_FATE_EVICT_FOR_MEMORY || + fate == DICTIONARY_FATE_EVICT_FOR_DESTRUCTION); + + UMA_HISTOGRAM_COUNTS_100("Sdch3.DictionaryUseCount", use_count); + RecordDictionaryFate(fate); +} + +} // namespace + +namespace net { + +// Adjust SDCH limits downwards for mobile. +#if defined(OS_ANDROID) || defined(OS_IOS) +// static +const size_t SdchOwner::kMaxTotalDictionarySize = 1000 * 1000; +#else +// static +const size_t SdchOwner::kMaxTotalDictionarySize = 20 * 1000 * 1000; +#endif + +// Somewhat arbitrary, but we assume a dictionary smaller than +// 50K isn't going to do anyone any good. Note that this still doesn't +// prevent download and addition unless there is less than this +// amount of space available in storage. +const size_t SdchOwner::kMinSpaceForDictionaryFetch = 50 * 1000; + +SdchOwner::SdchOwner(net::SdchManager* sdch_manager, + net::URLRequestContext* context) + : manager_(sdch_manager), + fetcher_(context, + base::Bind(&SdchOwner::OnDictionaryFetched, + // Because |fetcher_| is owned by SdchOwner, the + // SdchOwner object will be available for the lifetime + // of |fetcher_|. + base::Unretained(this))), + total_dictionary_bytes_(0), + clock_(new base::DefaultClock), + max_total_dictionary_size_(kMaxTotalDictionarySize), + min_space_for_dictionary_fetch_(kMinSpaceForDictionaryFetch), + memory_pressure_listener_( + base::Bind(&SdchOwner::OnMemoryPressure, + // Because |memory_pressure_listener_| is owned by + // SdchOwner, the SdchOwner object will be available + // for the lifetime of |memory_pressure_listener_|. + base::Unretained(this))) { + manager_->AddObserver(this); +} + +SdchOwner::~SdchOwner() { + for (auto it = local_dictionary_info_.begin(); + it != local_dictionary_info_.end(); ++it) { + RecordDictionaryEviction(it->second.use_count, + DICTIONARY_FATE_EVICT_FOR_DESTRUCTION); + } + manager_->RemoveObserver(this); +} + +void SdchOwner::SetMaxTotalDictionarySize(size_t max_total_dictionary_size) { + max_total_dictionary_size_ = max_total_dictionary_size; +} + +void SdchOwner::SetMinSpaceForDictionaryFetch( + size_t min_space_for_dictionary_fetch) { + min_space_for_dictionary_fetch_ = min_space_for_dictionary_fetch; +} + +void SdchOwner::OnDictionaryFetched(const std::string& dictionary_text, + const GURL& dictionary_url, + const net::BoundNetLog& net_log) { + struct DictionaryItem { + base::Time last_used; + std::string server_hash; + int use_count; + size_t dictionary_size; + + DictionaryItem() : use_count(0), dictionary_size(0) {} + DictionaryItem(const base::Time& last_used, + const std::string& server_hash, + int use_count, + size_t dictionary_size) + : last_used(last_used), + server_hash(server_hash), + use_count(use_count), + dictionary_size(dictionary_size) {} + DictionaryItem(const DictionaryItem& rhs) = default; + DictionaryItem& operator=(const DictionaryItem& rhs) = default; + bool operator<(const DictionaryItem& rhs) const { + return last_used < rhs.last_used; + } + }; + + std::vector<DictionaryItem> stale_dictionary_list; + size_t recoverable_bytes = 0; + base::Time stale_boundary(clock_->Now() - base::TimeDelta::FromDays(1)); + for (auto used_it = local_dictionary_info_.begin(); + used_it != local_dictionary_info_.end(); ++used_it) { + if (used_it->second.last_used < stale_boundary) { + stale_dictionary_list.push_back( + DictionaryItem(used_it->second.last_used, used_it->first, + used_it->second.use_count, used_it->second.size)); + recoverable_bytes += used_it->second.size; + } + } + + if (total_dictionary_bytes_ + dictionary_text.size() - recoverable_bytes > + max_total_dictionary_size_) { + RecordDictionaryFate(DICTIONARY_FATE_FETCH_IGNORED_NO_SPACE); + net::SdchManager::SdchErrorRecovery(SDCH_DICTIONARY_NO_ROOM); + net_log.AddEvent(net::NetLog::TYPE_SDCH_DICTIONARY_ERROR, + base::Bind(&net::NetLogSdchDictionaryFetchProblemCallback, + SDCH_DICTIONARY_NO_ROOM, dictionary_url, true)); + return; + } + + // Evict from oldest to youngest until we have space. + std::sort(stale_dictionary_list.begin(), stale_dictionary_list.end()); + size_t avail_bytes = max_total_dictionary_size_ - total_dictionary_bytes_; + auto stale_it = stale_dictionary_list.begin(); + while (avail_bytes < dictionary_text.size() && + stale_it != stale_dictionary_list.end()) { + manager_->RemoveSdchDictionary(stale_it->server_hash); + RecordDictionaryEviction(stale_it->use_count, + DICTIONARY_FATE_EVICT_FOR_DICT); + local_dictionary_info_.erase(stale_it->server_hash); + avail_bytes += stale_it->dictionary_size; + ++stale_it; + } + DCHECK(avail_bytes >= dictionary_text.size()); + + std::string server_hash; + net::SdchProblemCode rv = manager_->AddSdchDictionary( + dictionary_text, dictionary_url, &server_hash); + if (rv != net::SDCH_OK) { + RecordDictionaryFate(DICTIONARY_FATE_FETCH_MANAGER_REFUSED); + net::SdchManager::SdchErrorRecovery(rv); + net_log.AddEvent(net::NetLog::TYPE_SDCH_DICTIONARY_ERROR, + base::Bind(&net::NetLogSdchDictionaryFetchProblemCallback, + rv, dictionary_url, true)); + return; + } + + RecordDictionaryFate(DICTIONARY_FATE_ADDED); + + DCHECK(local_dictionary_info_.end() == + local_dictionary_info_.find(server_hash)); + total_dictionary_bytes_ += dictionary_text.size(); + local_dictionary_info_[server_hash] = DictionaryInfo( + // Set the time last used to something to avoid thrashing, but not recent, + // to avoid taking too much time/space with useless dictionaries/one-off + // visits to web sites. + clock_->Now() - base::TimeDelta::FromHours(23), dictionary_text.size()); +} + +void SdchOwner::OnDictionaryUsed(SdchManager* manager, + const std::string& server_hash) { + auto it = local_dictionary_info_.find(server_hash); + DCHECK(local_dictionary_info_.end() != it); + + it->second.last_used = clock_->Now(); + it->second.use_count++; +} + +void SdchOwner::OnGetDictionary(net::SdchManager* manager, + const GURL& request_url, + const GURL& dictionary_url) { + base::Time stale_boundary(clock_->Now() - base::TimeDelta::FromDays(1)); + size_t avail_bytes = 0; + for (auto it = local_dictionary_info_.begin(); + it != local_dictionary_info_.end(); ++it) { + if (it->second.last_used < stale_boundary) + avail_bytes += it->second.size; + } + + // Don't initiate the fetch if we wouldn't be able to store any + // reasonable dictionary. + // TODO(rdsmith): Maybe do a HEAD request to figure out how much + // storage we'd actually need? + if (max_total_dictionary_size_ < (total_dictionary_bytes_ - avail_bytes + + min_space_for_dictionary_fetch_)) { + RecordDictionaryFate(DICTIONARY_FATE_GET_IGNORED); + // TODO(rdsmith): Log a net-internals error. This requires + // SdchManager to forward the URLRequest that detected the + // Get-Dictionary header to its observers, which is tricky + // because SdchManager is layered underneath URLRequest. + return; + } + + fetcher_.Schedule(dictionary_url); +} + +void SdchOwner::OnClearDictionaries(net::SdchManager* manager) { + total_dictionary_bytes_ = 0; + local_dictionary_info_.clear(); + fetcher_.Cancel(); +} + +void SdchOwner::SetClockForTesting(scoped_ptr<base::Clock> clock) { + clock_ = clock.Pass(); +} + +void SdchOwner::OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level) { + DCHECK_NE(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, level); + + for (auto it = local_dictionary_info_.begin(); + it != local_dictionary_info_.end(); ++it) { + RecordDictionaryEviction(it->second.use_count, + DICTIONARY_FATE_EVICT_FOR_MEMORY); + } + + // TODO(rdsmith): Make a distinction between moderate and critical + // memory pressure. + manager_->ClearData(); +} + +} // namespace net
diff --git a/net/sdch/sdch_owner.h b/net/sdch/sdch_owner.h new file mode 100644 index 0000000..9620326 --- /dev/null +++ b/net/sdch/sdch_owner.h
@@ -0,0 +1,97 @@ +// Copyright 2014 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. + +#ifndef NET_SDCH_SDCH_OWNER_H_ +#define NET_SDCH_SDCH_OWNER_H_ + +#include <string> + +#include "base/memory/memory_pressure_listener.h" +#include "net/base/sdch_observer.h" +#include "net/url_request/sdch_dictionary_fetcher.h" + +class GURL; + +namespace base { +class Clock; +} + +namespace net { +class SdchManager; +class URLRequestContext; + +// This class owns the SDCH objects not owned as part of URLRequestContext, and +// exposes interface for setting SDCH policy. It should be instantiated by +// the net/ embedder. +// TODO(rdsmith): Implement dictionary prioritization. +class NET_EXPORT SdchOwner : public net::SdchObserver { + public: + static const size_t kMaxTotalDictionarySize; + static const size_t kMinSpaceForDictionaryFetch; + + // Consumer must guarantee that |sdch_manager| and |context| outlive + // this object. + SdchOwner(net::SdchManager* sdch_manager, net::URLRequestContext* context); + ~SdchOwner() override; + + // Defaults to kMaxTotalDictionarySize. + void SetMaxTotalDictionarySize(size_t max_total_dictionary_size); + + // Defaults to kMinSpaceForDictionaryFetch. + void SetMinSpaceForDictionaryFetch(size_t min_space_for_dictionary_fetch); + + // SdchObserver implementation. + void OnDictionaryUsed(SdchManager* manager, + const std::string& server_hash) override; + void OnGetDictionary(net::SdchManager* manager, + const GURL& request_url, + const GURL& dictionary_url) override; + void OnClearDictionaries(net::SdchManager* manager) override; + + // Implementation detail--this is the pathway through which the + // fetcher informs the SdchOwner that it's gotten the dictionary. + // Public for testing. + void OnDictionaryFetched(const std::string& dictionary_text, + const GURL& dictionary_url, + const net::BoundNetLog& net_log); + + void SetClockForTesting(scoped_ptr<base::Clock> clock); + + private: + // For each active dictionary, stores local info. + // Indexed by server hash. + struct DictionaryInfo { + base::Time last_used; + int use_count; + size_t size; + + DictionaryInfo() : use_count(0), size(0) {} + DictionaryInfo(const base::Time& last_used, size_t size) + : last_used(last_used), use_count(0), size(size) {} + DictionaryInfo(const DictionaryInfo& rhs) = default; + DictionaryInfo& operator=(const DictionaryInfo& rhs) = default; + }; + + void OnMemoryPressure( + base::MemoryPressureListener::MemoryPressureLevel level); + + net::SdchManager* manager_; + net::SdchDictionaryFetcher fetcher_; + + std::map<std::string, DictionaryInfo> local_dictionary_info_; + size_t total_dictionary_bytes_; + + scoped_ptr<base::Clock> clock_; + + size_t max_total_dictionary_size_; + size_t min_space_for_dictionary_fetch_; + + base::MemoryPressureListener memory_pressure_listener_; + + DISALLOW_COPY_AND_ASSIGN(SdchOwner); +}; + +} // namespace net + +#endif // NET_SDCH_SDCH_OWNER_H_
diff --git a/net/sdch/sdch_owner_unittest.cc b/net/sdch/sdch_owner_unittest.cc new file mode 100644 index 0000000..e89533a --- /dev/null +++ b/net/sdch/sdch_owner_unittest.cc
@@ -0,0 +1,491 @@ +// Copyright 2014 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. + +#include "base/memory/memory_pressure_listener.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/test/simple_test_clock.h" +#include "net/base/net_log.h" +#include "net/base/sdch_manager.h" +#include "net/sdch/sdch_owner.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_error_job.h" +#include "net/url_request/url_request_job.h" +#include "net/url_request/url_request_job_factory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +static const char generic_url[] = "http://www.example.com"; +static const char generic_domain[] = "www.example.com"; + +static std::string NewSdchDictionary(size_t dictionary_size) { + std::string dictionary; + dictionary.append("Domain: "); + dictionary.append(generic_domain); + dictionary.append("\n"); + dictionary.append("\n"); + + size_t original_dictionary_size = dictionary.size(); + dictionary.resize(dictionary_size); + for (size_t i = original_dictionary_size; i < dictionary_size; ++i) + dictionary[i] = static_cast<char>((i % 127) + 1); + + return dictionary; +} + +int outstanding_url_request_error_counting_jobs = 0; +base::Closure* empty_url_request_jobs_callback = 0; + +// Variation of URLRequestErrorJob to count number of outstanding +// instances and notify when that goes to zero. +class URLRequestErrorCountingJob : public URLRequestJob { + public: + URLRequestErrorCountingJob(URLRequest* request, + NetworkDelegate* network_delegate, + int error) + : URLRequestJob(request, network_delegate), + error_(error), + weak_factory_(this) { + ++outstanding_url_request_error_counting_jobs; + } + + void Start() override { + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(&URLRequestErrorCountingJob::StartAsync, + weak_factory_.GetWeakPtr())); + } + + private: + ~URLRequestErrorCountingJob() override { + --outstanding_url_request_error_counting_jobs; + if (0 == outstanding_url_request_error_counting_jobs && + empty_url_request_jobs_callback) { + empty_url_request_jobs_callback->Run(); + } + } + + void StartAsync() { + NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, error_)); + } + + int error_; + + base::WeakPtrFactory<URLRequestErrorCountingJob> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestErrorCountingJob); +}; + +static int error_jobs_created = 0; + +class MockURLRequestJobFactory : public URLRequestJobFactory { + public: + MockURLRequestJobFactory() {} + + ~MockURLRequestJobFactory() override {} + + URLRequestJob* MaybeCreateJobWithProtocolHandler( + const std::string& scheme, + URLRequest* request, + NetworkDelegate* network_delegate) const override { + ++error_jobs_created; + return new URLRequestErrorCountingJob(request, network_delegate, + ERR_INTERNET_DISCONNECTED); + } + + URLRequestJob* MaybeInterceptRedirect(URLRequest* request, + NetworkDelegate* network_delegate, + const GURL& location) const override { + return nullptr; + } + + URLRequestJob* MaybeInterceptResponse( + URLRequest* request, + NetworkDelegate* network_delegate) const override { + return nullptr; + } + + bool IsHandledProtocol(const std::string& scheme) const override { + return scheme == "http"; + }; + + bool IsHandledURL(const GURL& url) const override { + return url.SchemeIs("http"); + } + + bool IsSafeRedirectTarget(const GURL& location) const override { + return false; + } +}; + +class SdchOwnerTest : public testing::Test { + public: + static const size_t kMaxSizeForTesting = 1000 * 50; + static const size_t kMinFetchSpaceForTesting = 500; + + SdchOwnerTest() + : last_jobs_created_(error_jobs_created), + dictionary_creation_index_(0), + sdch_owner_(&sdch_manager_, &url_request_context_) { + // Any jobs created on this context will immediately error, + // which leaves the test in control of signals to SdchOwner. + url_request_context_.set_job_factory(&job_factory_); + + // Reduce sizes to reduce time for string operations. + sdch_owner_.SetMaxTotalDictionarySize(kMaxSizeForTesting); + sdch_owner_.SetMinSpaceForDictionaryFetch(kMinFetchSpaceForTesting); + } + + SdchManager& sdch_manager() { return sdch_manager_; } + SdchOwner& sdch_owner() { return sdch_owner_; } + BoundNetLog& bound_net_log() { return net_log_; } + + int JobsRecentlyCreated() { + int result = error_jobs_created - last_jobs_created_; + last_jobs_created_ = error_jobs_created; + return result; + } + + bool DictionaryPresentInManager(const std::string& server_hash) { + // Presumes all tests use generic url. + SdchProblemCode tmp; + scoped_ptr<SdchManager::DictionarySet> set( + sdch_manager_.GetDictionarySetByHash(GURL(generic_url), server_hash, + &tmp)); + return !!set.get(); + } + + void SignalGetDictionaryAndClearJobs(GURL request_url, GURL dictionary_url) { + sdch_owner().OnGetDictionary(&sdch_manager_, request_url, dictionary_url); + if (outstanding_url_request_error_counting_jobs == 0) + return; + base::RunLoop run_loop; + base::Closure quit_closure(run_loop.QuitClosure()); + empty_url_request_jobs_callback = &quit_closure; + run_loop.Run(); + empty_url_request_jobs_callback = NULL; + } + + // Create a unique (by hash) dictionary of the given size, + // associate it with a unique URL, add it to the manager through + // SdchOwner::OnDictionaryFetched(), and return whether that + // addition was successful or not. + bool CreateAndAddDictionary(size_t size, std::string* server_hash_p) { + GURL dictionary_url( + base::StringPrintf("%s/d%d", generic_url, dictionary_creation_index_)); + std::string dictionary_text(NewSdchDictionary(size - 4)); + dictionary_text += base::StringPrintf("%04d", dictionary_creation_index_); + ++dictionary_creation_index_; + std::string client_hash; + std::string server_hash; + SdchManager::GenerateHash(dictionary_text, &client_hash, &server_hash); + + if (DictionaryPresentInManager(server_hash)) + return false; + sdch_owner().OnDictionaryFetched(dictionary_text, dictionary_url, net_log_); + if (server_hash_p) + *server_hash_p = server_hash; + return DictionaryPresentInManager(server_hash); + } + + private: + int last_jobs_created_; + BoundNetLog net_log_; + int dictionary_creation_index_; + + // The dependencies of these objects (sdch_owner_ -> {sdch_manager_, + // url_request_context_}, url_request_context_->job_factory_) require + // this order for correct destruction semantics. + MockURLRequestJobFactory job_factory_; + URLRequestContext url_request_context_; + SdchManager sdch_manager_; + SdchOwner sdch_owner_; + + DISALLOW_COPY_AND_ASSIGN(SdchOwnerTest); +}; + +// Does OnGetDictionary result in a fetch when there's enough space, and not +// when there's not? +TEST_F(SdchOwnerTest, OnGetDictionary_Fetching) { + GURL request_url(std::string(generic_url) + "/r1"); + + // Fetch generated when empty. + GURL dict_url1(std::string(generic_url) + "/d1"); + EXPECT_EQ(0, JobsRecentlyCreated()); + SignalGetDictionaryAndClearJobs(request_url, dict_url1); + EXPECT_EQ(1, JobsRecentlyCreated()); + + // Fetch generated when half full. + GURL dict_url2(std::string(generic_url) + "/d2"); + std::string dictionary1(NewSdchDictionary(kMaxSizeForTesting / 2)); + sdch_owner().OnDictionaryFetched(dictionary1, dict_url1, bound_net_log()); + EXPECT_EQ(0, JobsRecentlyCreated()); + SignalGetDictionaryAndClearJobs(request_url, dict_url2); + EXPECT_EQ(1, JobsRecentlyCreated()); + + // Fetch not generated when close to completely full. + GURL dict_url3(std::string(generic_url) + "/d3"); + std::string dictionary2(NewSdchDictionary( + (kMaxSizeForTesting / 2 - kMinFetchSpaceForTesting / 2))); + sdch_owner().OnDictionaryFetched(dictionary2, dict_url2, bound_net_log()); + EXPECT_EQ(0, JobsRecentlyCreated()); + SignalGetDictionaryAndClearJobs(request_url, dict_url3); + EXPECT_EQ(0, JobsRecentlyCreated()); +} + +// Make sure attempts to add dictionaries do what they should. +TEST_F(SdchOwnerTest, OnDictionaryFetched_Fetching) { + GURL request_url(std::string(generic_url) + "/r1"); + std::string client_hash; + std::string server_hash; + + // Add successful when empty. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, nullptr)); + EXPECT_EQ(0, JobsRecentlyCreated()); + + // Add successful when half full. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, nullptr)); + EXPECT_EQ(0, JobsRecentlyCreated()); + + // Add unsuccessful when full. + EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting / 2, nullptr)); + EXPECT_EQ(0, JobsRecentlyCreated()); +} + +// Confirm auto-eviction happens if space is needed. +TEST_F(SdchOwnerTest, ConfirmAutoEviction) { + std::string server_hash_d1; + std::string server_hash_d2; + std::string server_hash_d3; + + // Add two dictionaries, one recent, one more than a day in the past. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d1)); + + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(2)); + sdch_owner().SetClockForTesting(clock.Pass()); + + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d2)); + + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); + + // The addition of a new dictionary should succeed, evicting the old one. + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now()); + sdch_owner().SetClockForTesting(clock.Pass()); + + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d3)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); +} + +// Confirm auto-eviction happens if space is needed, with a more complicated +// situation +TEST_F(SdchOwnerTest, ConfirmAutoEviction_2) { + std::string server_hash_d1; + std::string server_hash_d2; + std::string server_hash_d3; + + // Add dictionaries, one recent, two more than a day in the past that + // between them add up to the space needed. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d1)); + + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(2)); + sdch_owner().SetClockForTesting(clock.Pass()); + + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2)); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3)); + + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); + + // The addition of a new dictionary should succeed, evicting the old one. + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now()); + sdch_owner().SetClockForTesting(clock.Pass()); + + std::string server_hash_d4; + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d3)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d4)); +} + +// Confirm if only one dictionary needs to be evicted it's the oldest. +TEST_F(SdchOwnerTest, ConfirmAutoEviction_Oldest) { + std::string server_hash_d1; + std::string server_hash_d2; + std::string server_hash_d3; + + // Add dictionaries, one recent, one two days in the past, and one + // four days in the past. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d1)); + + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(2)); + sdch_owner().SetClockForTesting(clock.Pass()); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2)); + + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(4)); + sdch_owner().SetClockForTesting(clock.Pass()); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3)); + + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); + + // The addition of a new dictionary should succeed, evicting only the + // oldest one. + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now()); + sdch_owner().SetClockForTesting(clock.Pass()); + + std::string server_hash_d4; + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d3)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d4)); +} + +// Confirm using a dictionary changes eviction behavior properly. +TEST_F(SdchOwnerTest, UseChangesEviction) { + std::string server_hash_d1; + std::string server_hash_d2; + std::string server_hash_d3; + + // Add dictionaries, one recent, one two days in the past, and one + // four days in the past. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d1)); + + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(2)); + sdch_owner().SetClockForTesting(clock.Pass()); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2)); + + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(4)); + sdch_owner().SetClockForTesting(clock.Pass()); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3)); + + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); + + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now()); + sdch_owner().SetClockForTesting(clock.Pass()); + + // Use the oldest dictionary. + sdch_owner().OnDictionaryUsed(&sdch_manager(), server_hash_d3); + + // The addition of a new dictionary should succeed, evicting only the + // newer stale one. + std::string server_hash_d4; + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d4)); +} + +// Confirm using a dictionary can prevent the addition of a new dictionary. +TEST_F(SdchOwnerTest, UsePreventsAddition) { + std::string server_hash_d1; + std::string server_hash_d2; + std::string server_hash_d3; + + // Add dictionaries, one recent, one two days in the past, and one + // four days in the past. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d1)); + + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(2)); + sdch_owner().SetClockForTesting(clock.Pass()); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d2)); + + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now() - base::TimeDelta::FromDays(4)); + sdch_owner().SetClockForTesting(clock.Pass()); + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting / 4, &server_hash_d3)); + + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); + + clock.reset(new base::SimpleTestClock); + clock->SetNow(base::Time::Now()); + sdch_owner().SetClockForTesting(clock.Pass()); + + // Use the older dictionaries. + sdch_owner().OnDictionaryUsed(&sdch_manager(), server_hash_d2); + sdch_owner().OnDictionaryUsed(&sdch_manager(), server_hash_d3); + + // The addition of a new dictionary should fail, not evicting anything. + std::string server_hash_d4; + EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting / 2, &server_hash_d4)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d2)); + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d3)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d4)); +} + +// Confirm clear gets all the space back. +TEST_F(SdchOwnerTest, ClearReturnsSpace) { + std::string server_hash_d1; + std::string server_hash_d2; + + // Take up all the space. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d1)); + + // Addition should fail. + EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d2)); + + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); + + sdch_manager().ClearData(); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); + + // Addition should now succeed. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, nullptr)); +} + +// Confirm memory pressure gets all the space back. +TEST_F(SdchOwnerTest, MemoryPressureReturnsSpace) { + std::string server_hash_d1; + std::string server_hash_d2; + + // Take up all the space. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d1)); + + // Addition should fail. + EXPECT_FALSE(CreateAndAddDictionary(kMaxSizeForTesting, &server_hash_d2)); + + EXPECT_TRUE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); + + base::MemoryPressureListener::NotifyMemoryPressure( + base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE); + // The notification may have (implementation note: does :-}) use a PostTask, + // so we drain the local message queue. This should be safe (i.e. not have + // an inifinite number of messages) in a unit test. + base::RunLoop().RunUntilIdle(); + + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d1)); + EXPECT_FALSE(DictionaryPresentInManager(server_hash_d2)); + + // Addition should now succeed. + EXPECT_TRUE(CreateAndAddDictionary(kMaxSizeForTesting, nullptr)); +} + +} // namespace net
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc index 190023c..2a8caf5 100644 --- a/net/socket/client_socket_pool_manager_impl.cc +++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -44,10 +44,8 @@ CTVerifier* cert_transparency_verifier, CertPolicyEnforcer* cert_policy_enforcer, const std::string& ssl_session_cache_shard, - ProxyService* proxy_service, SSLConfigService* ssl_config_service, bool enable_ssl_connect_job_waiting, - ProxyDelegate* proxy_delegate, HttpNetworkSession::SocketPoolType pool_type) : net_log_(net_log), socket_factory_(socket_factory), @@ -58,7 +56,6 @@ cert_transparency_verifier_(cert_transparency_verifier), cert_policy_enforcer_(cert_policy_enforcer), ssl_session_cache_shard_(ssl_session_cache_shard), - proxy_service_(proxy_service), ssl_config_service_(ssl_config_service), enable_ssl_connect_job_waiting_(enable_ssl_connect_job_waiting), pool_type_(pool_type), @@ -102,8 +99,7 @@ transport_for_https_proxy_pool_histograms_("TCPforHTTPSProxy"), ssl_for_https_proxy_pool_histograms_("SSLforHTTPSProxy"), http_proxy_pool_histograms_("HTTPProxy"), - ssl_socket_pool_for_proxies_histograms_("SSLForProxies"), - proxy_delegate_(proxy_delegate) { + ssl_socket_pool_for_proxies_histograms_("SSLForProxies") { CertDatabase::GetInstance()->AddObserver(this); } @@ -324,7 +320,6 @@ host_resolver_, tcp_http_ret.first->second, ssl_https_ret.first->second, - proxy_delegate_, net_log_))); return ret.first->second;
diff --git a/net/socket/client_socket_pool_manager_impl.h b/net/socket/client_socket_pool_manager_impl.h index ca609d5..515b1e1 100644 --- a/net/socket/client_socket_pool_manager_impl.h +++ b/net/socket/client_socket_pool_manager_impl.h
@@ -28,8 +28,6 @@ class HttpProxyClientSocketPool; class HostResolver; class NetLog; -class ProxyDelegate; -class ProxyService; class SOCKSClientSocketPool; class SSLClientSocketPool; class SSLConfigService; @@ -67,10 +65,8 @@ CTVerifier* cert_transparency_verifier, CertPolicyEnforcer* cert_policy_enforcer, const std::string& ssl_session_cache_shard, - ProxyService* proxy_service, SSLConfigService* ssl_config_service, bool enable_ssl_connect_job_waiting, - ProxyDelegate* proxy_delegate, HttpNetworkSession::SocketPoolType pool_type); ~ClientSocketPoolManagerImpl() override; @@ -117,7 +113,6 @@ CTVerifier* const cert_transparency_verifier_; CertPolicyEnforcer* const cert_policy_enforcer_; const std::string ssl_session_cache_shard_; - ProxyService* const proxy_service_; const scoped_refptr<SSLConfigService> ssl_config_service_; bool enable_ssl_connect_job_waiting_; const HttpNetworkSession::SocketPoolType pool_type_; @@ -151,8 +146,6 @@ ClientSocketPoolHistograms ssl_socket_pool_for_proxies_histograms_; SSLSocketPoolMap ssl_socket_pools_for_proxies_; - const ProxyDelegate* proxy_delegate_; - DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolManagerImpl); };
diff --git a/net/socket/next_proto.cc b/net/socket/next_proto.cc index 0d1b400..6d6f563 100644 --- a/net/socket/next_proto.cc +++ b/net/socket/next_proto.cc
@@ -17,7 +17,6 @@ next_protos.push_back(kProtoHTTP11); next_protos.push_back(kProtoSPDY31); next_protos.push_back(kProtoSPDY4_14); - next_protos.push_back(kProtoSPDY4_15); return next_protos; } @@ -30,7 +29,6 @@ if (spdy_enabled) { next_protos.push_back(kProtoSPDY31); next_protos.push_back(kProtoSPDY4_14); - next_protos.push_back(kProtoSPDY4_15); } return next_protos; } @@ -49,7 +47,6 @@ next_protos.push_back(kProtoQUIC1SPDY3); next_protos.push_back(kProtoSPDY31); next_protos.push_back(kProtoSPDY4_14); - next_protos.push_back(kProtoSPDY4_15); return next_protos; }
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index 308de2e..658182b 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc
@@ -702,11 +702,17 @@ const HostPortPair& host_and_port, const SSLConfig& ssl_config, const SSLClientSocketContext& context) { - scoped_ptr<MockSSLClientSocket> socket( - new MockSSLClientSocket(transport_socket.Pass(), - host_and_port, - ssl_config, - mock_ssl_data_.GetNext())); + SSLSocketDataProvider* next_ssl_data = mock_ssl_data_.GetNext(); + if (!next_ssl_data->next_protos_expected_in_ssl_config.empty()) { + EXPECT_EQ(next_ssl_data->next_protos_expected_in_ssl_config.size(), + ssl_config.next_protos.size()); + EXPECT_TRUE( + std::equal(next_ssl_data->next_protos_expected_in_ssl_config.begin(), + next_ssl_data->next_protos_expected_in_ssl_config.end(), + ssl_config.next_protos.begin())); + } + scoped_ptr<MockSSLClientSocket> socket(new MockSSLClientSocket( + transport_socket.Pass(), host_and_port, ssl_config, next_ssl_data)); ssl_client_sockets_.push_back(socket.get()); return socket.Pass(); }
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index 55e269c..6d3162b 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h
@@ -328,6 +328,7 @@ std::string next_proto; bool was_npn_negotiated; NextProto protocol_negotiated; + NextProtoVector next_protos_expected_in_ssl_config; bool client_cert_sent; SSLCertRequestInfo* cert_request_info; scoped_refptr<X509Certificate> cert;
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index c3b98b8..0e75a20 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc
@@ -177,7 +177,6 @@ SOCKSClientSocketPool* socks_pool, HttpProxyClientSocketPool* http_proxy_pool, ClientSocketFactory* client_socket_factory, - HostResolver* host_resolver, const SSLClientSocketContext& context, const GetMessengerCallback& get_messenger_callback, Delegate* delegate, @@ -192,7 +191,6 @@ socks_pool_(socks_pool), http_proxy_pool_(http_proxy_pool), client_socket_factory_(client_socket_factory), - host_resolver_(host_resolver), context_(context.cert_verifier, context.channel_id_service, context.transport_security_state, @@ -700,7 +698,6 @@ socks_pool_, http_proxy_pool_, client_socket_factory_, - host_resolver_, context_, get_messenger_callback_, delegate,
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h index 59e754a..7556488 100644 --- a/net/socket/ssl_client_socket_pool.h +++ b/net/socket/ssl_client_socket_pool.h
@@ -190,7 +190,6 @@ SOCKSClientSocketPool* socks_pool, HttpProxyClientSocketPool* http_proxy_pool, ClientSocketFactory* client_socket_factory, - HostResolver* host_resolver, const SSLClientSocketContext& context, const GetMessengerCallback& get_messenger_callback, Delegate* delegate, @@ -250,7 +249,6 @@ SOCKSClientSocketPool* const socks_pool_; HttpProxyClientSocketPool* const http_proxy_pool_; ClientSocketFactory* const client_socket_factory_; - HostResolver* const host_resolver_; const SSLClientSocketContext context_;
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc index 1e4a14f..0131a5f 100644 --- a/net/socket/ssl_client_socket_pool_unittest.cc +++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -132,7 +132,6 @@ &host_resolver_, &transport_socket_pool_, NULL, - NULL, NULL), enable_ssl_connect_job_waiting_(false) { scoped_refptr<SSLConfigService> ssl_config_service(
diff --git a/net/socket/unix_domain_client_socket_posix.cc b/net/socket/unix_domain_client_socket_posix.cc index 5adbca9..70ad42b 100644 --- a/net/socket/unix_domain_client_socket_posix.cc +++ b/net/socket/unix_domain_client_socket_posix.cc
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/posix/eintr_wrapper.h" +#include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" #include "net/socket/socket_libevent.h" @@ -98,13 +99,25 @@ } int UnixDomainClientSocket::GetPeerAddress(IPEndPoint* address) const { - NOTIMPLEMENTED(); - return ERR_NOT_IMPLEMENTED; + // Unix domain sockets have no valid associated addr/port; + // return either not connected or address invalid. + DCHECK(address); + + if (!IsConnected()) + return ERR_SOCKET_NOT_CONNECTED; + + return ERR_ADDRESS_INVALID; } int UnixDomainClientSocket::GetLocalAddress(IPEndPoint* address) const { - NOTIMPLEMENTED(); - return ERR_NOT_IMPLEMENTED; + // Unix domain sockets have no valid associated addr/port; + // return either not connected or address invalid. + DCHECK(address); + + if (!socket_) + return ERR_SOCKET_NOT_CONNECTED; + + return ERR_ADDRESS_INVALID; } const BoundNetLog& UnixDomainClientSocket::NetLog() const {
diff --git a/net/spdy/spdy_buffer.cc b/net/spdy/spdy_buffer.cc index c1a602e..f7cd378 100644 --- a/net/spdy/spdy_buffer.cc +++ b/net/spdy/spdy_buffer.cc
@@ -41,8 +41,7 @@ SharedFrameIOBuffer(const scoped_refptr<SharedFrame>& shared_frame, size_t offset) : IOBuffer(shared_frame->data->data() + offset), - shared_frame_(shared_frame), - offset_(offset) {} + shared_frame_(shared_frame) {} private: ~SharedFrameIOBuffer() override { @@ -51,7 +50,6 @@ } const scoped_refptr<SharedFrame> shared_frame_; - const size_t offset_; DISALLOW_COPY_AND_ASSIGN(SharedFrameIOBuffer); };
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index 4c6c205..21401b5 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -263,6 +263,12 @@ output_.rv = ReadTransaction(trans_.get(), &output_.response_data); } + void FinishDefaultTestWithoutVerification() { + output_.rv = callback_.WaitForResult(); + if (output_.rv != OK) + session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED); + } + // Most tests will want to call this function. In particular, the MockReads // should end with an empty read, and that read needs to be processed to // ensure proper deletion of the spdy_session_pool. @@ -4550,6 +4556,208 @@ helper.VerifyDataConsumed(); } +// Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual +// protocol negotiation happens, instead this test forces protocols for both +// sockets. +TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) { + // HTTP_1_1_REQUIRED is only supported by SPDY4. + if (spdy_util_.spdy_version() < SPDY4) + return; + // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is + // only spoken over SSL. + if (GetParam().ssl_type != SPDYSSL) + return; + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + scoped_ptr<SpdySessionDependencies> session_deps( + CreateSpdySessionDependencies(GetParam())); + // Do not force SPDY so that second socket can negotiate HTTP/1.1. + session_deps->force_spdy_over_ssl = false; + session_deps->force_spdy_always = false; + session_deps->next_protos = SpdyNextProtos(); + NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), + GetParam(), session_deps.release()); + + // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED. + const char* url = "https://www.google.com/"; + scoped_ptr<SpdyHeaderBlock> headers(spdy_util_.ConstructGetHeaderBlock(url)); + scoped_ptr<SpdyFrame> req( + spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); + MockWrite writes0[] = {CreateMockWrite(*req)}; + scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( + 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); + MockRead reads0[] = {CreateMockRead(*go_away)}; + DelayedSocketData data0(1, reads0, arraysize(reads0), writes0, + arraysize(writes0)); + + scoped_ptr<SSLSocketDataProvider> ssl_provider0( + new SSLSocketDataProvider(ASYNC, OK)); + // Expect HTTP/2 protocols too in SSLConfig. + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31); + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_14); + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_15); + // Force SPDY. + ssl_provider0->SetNextProto(GetParam().protocol); + helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass()); + + // Second socket: falling back to HTTP/1.1. + MockWrite writes1[] = {MockWrite( + "GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n")}; + MockRead reads1[] = {MockRead( + "HTTP/1.1 200 OK\r\n" + "Content-Length: 5\r\n\r\n" + "hello")}; + DelayedSocketData data1(1, reads1, arraysize(reads1), writes1, + arraysize(writes1)); + + scoped_ptr<SSLSocketDataProvider> ssl_provider1( + new SSLSocketDataProvider(ASYNC, OK)); + // Expect only HTTP/1.1 protocol in SSLConfig. + ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); + // Force HTTP/1.1. + ssl_provider1->SetNextProto(kProtoHTTP11); + helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass()); + + base::WeakPtr<HttpServerProperties> http_server_properties = + helper.session()->spdy_session_pool()->http_server_properties(); + const HostPortPair host_port_pair = HostPortPair::FromURL(GURL(url)); + EXPECT_FALSE(http_server_properties->RequiresHTTP11(host_port_pair)); + + helper.RunPreTestSetup(); + helper.StartDefaultTest(); + helper.FinishDefaultTestWithoutVerification(); + helper.VerifyDataConsumed(); + EXPECT_TRUE(http_server_properties->RequiresHTTP11(host_port_pair)); + + const HttpResponseInfo* response = helper.trans()->GetResponseInfo(); + ASSERT_TRUE(response != nullptr); + ASSERT_TRUE(response->headers.get() != nullptr); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + EXPECT_FALSE(response->was_fetched_via_spdy); + EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info); + EXPECT_TRUE(response->was_npn_negotiated); + EXPECT_TRUE(request.url.SchemeIs("https")); + EXPECT_EQ("127.0.0.1", response->socket_address.host()); + EXPECT_EQ(443, response->socket_address.port()); + std::string response_data; + ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data)); + EXPECT_EQ("hello", response_data); +} + +// Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the +// proxy. Note that no actual protocol negotiation happens, instead this test +// forces protocols for both sockets. +TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) { + // HTTP_1_1_REQUIRED is only supported by SPDY4. + if (spdy_util_.spdy_version() < SPDY4) + return; + // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is + // only spoken over SSL. + if (GetParam().ssl_type != SPDYSSL) + return; + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + scoped_ptr<SpdySessionDependencies> session_deps( + CreateSpdySessionDependencies( + GetParam(), + ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70"))); + // Do not force SPDY so that second socket can negotiate HTTP/1.1. + session_deps->force_spdy_over_ssl = false; + session_deps->force_spdy_always = false; + session_deps->next_protos = SpdyNextProtos(); + NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), + GetParam(), session_deps.release()); + + // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED. + scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect( + nullptr, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); + MockWrite writes0[] = {CreateMockWrite(*req)}; + scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( + 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); + MockRead reads0[] = {CreateMockRead(*go_away)}; + DelayedSocketData data0(1, reads0, arraysize(reads0), writes0, + arraysize(writes0)); + + scoped_ptr<SSLSocketDataProvider> ssl_provider0( + new SSLSocketDataProvider(ASYNC, OK)); + // Expect HTTP/2 protocols too in SSLConfig. + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31); + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_14); + ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_15); + // Force SPDY. + ssl_provider0->SetNextProto(GetParam().protocol); + helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass()); + + // Second socket: retry using HTTP/1.1. + MockWrite writes1[] = { + MockWrite(ASYNC, 1, + "CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + MockWrite(ASYNC, 3, + "GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + + MockRead reads1[] = { + MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n\r\n"), + MockRead(ASYNC, 4, + "HTTP/1.1 200 OK\r\n" + "Content-Length: 5\r\n\r\n" + "hello"), + }; + DelayedSocketData data1(1, reads1, arraysize(reads1), writes1, + arraysize(writes1)); + + scoped_ptr<SSLSocketDataProvider> ssl_provider1( + new SSLSocketDataProvider(ASYNC, OK)); + // Expect only HTTP/1.1 protocol in SSLConfig. + ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); + // Force HTTP/1.1. + ssl_provider1->SetNextProto(kProtoHTTP11); + helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass()); + + // A third socket is needed for the tunnelled connection. + scoped_ptr<SSLSocketDataProvider> ssl_provider2( + new SSLSocketDataProvider(ASYNC, OK)); + helper.session_deps()->socket_factory->AddSSLSocketDataProvider( + ssl_provider2.get()); + + base::WeakPtr<HttpServerProperties> http_server_properties = + helper.session()->spdy_session_pool()->http_server_properties(); + const HostPortPair proxy_host_port_pair = HostPortPair("myproxy", 70); + EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_host_port_pair)); + + helper.RunPreTestSetup(); + helper.StartDefaultTest(); + helper.FinishDefaultTestWithoutVerification(); + helper.VerifyDataConsumed(); + EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_host_port_pair)); + + const HttpResponseInfo* response = helper.trans()->GetResponseInfo(); + ASSERT_TRUE(response != nullptr); + ASSERT_TRUE(response->headers.get() != nullptr); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + EXPECT_FALSE(response->was_fetched_via_spdy); + EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info); + EXPECT_FALSE(response->was_npn_negotiated); + EXPECT_TRUE(request.url.SchemeIs("https")); + EXPECT_EQ("127.0.0.1", response->socket_address.host()); + EXPECT_EQ(70, response->socket_address.port()); + std::string response_data; + ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data)); + EXPECT_EQ("hello", response_data); +} + // Test to make sure we can correctly connect through a proxy. TEST_P(SpdyNetworkTransactionTest, ProxyConnect) { NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
diff --git a/net/spdy/spdy_protocol.cc b/net/spdy/spdy_protocol.cc index bf33d43..a0e8313 100644 --- a/net/spdy/spdy_protocol.cc +++ b/net/spdy/spdy_protocol.cc
@@ -542,9 +542,9 @@ return false; } - // GOAWAY_INADEQUATE_SECURITY is the last valid status. + // GOAWAY_HTTP_1_1_REQUIRED is the last valid status. if (goaway_status_field > - SerializeGoAwayStatus(version, GOAWAY_INADEQUATE_SECURITY)) { + SerializeGoAwayStatus(version, GOAWAY_HTTP_1_1_REQUIRED)) { return false; }
diff --git a/net/spdy/spdy_read_queue.cc b/net/spdy/spdy_read_queue.cc index 36f1e06..627bf5b 100644 --- a/net/spdy/spdy_read_queue.cc +++ b/net/spdy/spdy_read_queue.cc
@@ -53,7 +53,6 @@ void SpdyReadQueue::Clear() { STLDeleteElements(&queue_); - queue_.clear(); } -} // namespace +} // namespace net
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index a2e239e..01911b3 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -918,7 +918,7 @@ CHECK_GE(priority, MINIMUM_PRIORITY); CHECK_LE(priority, MAXIMUM_PRIORITY); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // |request| should not be in a queue not matching its priority. for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) { if (priority == i) @@ -1631,7 +1631,7 @@ } void SpdySession::DcheckGoingAway() const { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() DCHECK_GE(availability_state_, STATE_GOING_AWAY); for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) { DCHECK(pending_create_stream_queues_[i].empty()); @@ -1705,6 +1705,11 @@ } MakeUnavailable(); + // Mark host_port_pair requiring HTTP/1.1 for subsequent connections. + if (err == ERR_HTTP_1_1_REQUIRED) { + http_server_properties_->SetHTTP11Required(host_port_pair()); + } + // If |err| indicates an error occurred, inform the peer that we're closing // and why. Don't GOAWAY on a graceful or idle close, as that may // unnecessarily wake the radio. We could technically GOAWAY on network errors @@ -1713,7 +1718,7 @@ if (err != OK && err != ERR_ABORTED && // Used by SpdySessionPool to close idle sessions. err != ERR_NETWORK_CHANGED && // Used to deprecate sessions on IP change. - err != ERR_SOCKET_NOT_CONNECTED && + err != ERR_SOCKET_NOT_CONNECTED && err != ERR_HTTP_1_1_REQUIRED && err != ERR_CONNECTION_CLOSED && err != ERR_CONNECTION_RESET) { // Enqueue a GOAWAY to inform the peer of why we're closing the connection. SpdyGoAwayIR goaway_ir(last_accepted_push_stream_id_, @@ -2432,6 +2437,13 @@ it->second.stream->OnDataReceived(scoped_ptr<SpdyBuffer>()); } else if (status == RST_STREAM_REFUSED_STREAM) { CloseActiveStreamIterator(it, ERR_SPDY_SERVER_REFUSED_STREAM); + } else if (status == RST_STREAM_HTTP_1_1_REQUIRED) { + // TODO(bnc): Record histogram with number of open streams capped at 50. + it->second.stream->LogStreamError( + ERR_HTTP_1_1_REQUIRED, + base::StringPrintf( + "SPDY session closed because of stream with status: %d", status)); + DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream."); } else { RecordProtocolErrorHistogram( PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM); @@ -2457,7 +2469,12 @@ unclaimed_pushed_streams_.size(), status)); MakeUnavailable(); - StartGoingAway(last_accepted_stream_id, ERR_ABORTED); + if (status == GOAWAY_HTTP_1_1_REQUIRED) { + // TODO(bnc): Record histogram with number of open streams capped at 50. + DoDrainSession(ERR_HTTP_1_1_REQUIRED, "HTTP_1_1_REQUIRED for stream."); + } else { + StartGoingAway(last_accepted_stream_id, ERR_ABORTED); + } // This is to handle the case when we already don't have any active // streams (i.e., StartGoingAway() did nothing). Otherwise, we have // active streams and so the last one being closed will finish the @@ -3248,7 +3265,7 @@ while (!IsSendStalled()) { size_t old_size = 0; -#if DCHECK_IS_ON +#if DCHECK_IS_ON() old_size = GetTotalSize(stream_send_unstall_queue_); #endif
diff --git a/net/spdy/spdy_write_queue.cc b/net/spdy/spdy_write_queue.cc index 05b965d..ab25eae 100644 --- a/net/spdy/spdy_write_queue.cc +++ b/net/spdy/spdy_write_queue.cc
@@ -83,7 +83,7 @@ CHECK_LE(priority, MAXIMUM_PRIORITY); DCHECK(stream.get()); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() // |stream| should not have pending writes in a queue not matching // its priority. for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 65005f6..f7afb50 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -201,14 +201,10 @@ VLOG(1) << "Using Configuration: " << GetParam(); // Use different flow control windows for client/server. - client_config_.SetInitialFlowControlWindowToSend( - 2 * kInitialSessionFlowControlWindowForTest); client_config_.SetInitialStreamFlowControlWindowToSend( 2 * kInitialStreamFlowControlWindowForTest); client_config_.SetInitialSessionFlowControlWindowToSend( 2 * kInitialSessionFlowControlWindowForTest); - server_config_.SetInitialFlowControlWindowToSend( - 3 * kInitialSessionFlowControlWindowForTest); server_config_.SetInitialStreamFlowControlWindowToSend( 3 * kInitialStreamFlowControlWindowForTest); server_config_.SetInitialSessionFlowControlWindowToSend( @@ -239,12 +235,6 @@ return client; } - void set_client_initial_flow_control_receive_window(uint32 window) { - CHECK(client_.get() == nullptr); - DVLOG(1) << "Setting client initial flow control window: " << window; - client_config_.SetInitialFlowControlWindowToSend(window); - } - void set_client_initial_stream_flow_control_receive_window(uint32 window) { CHECK(client_.get() == nullptr); DVLOG(1) << "Setting client initial stream flow control window: " << window; @@ -258,12 +248,6 @@ client_config_.SetInitialSessionFlowControlWindowToSend(window); } - void set_server_initial_flow_control_receive_window(uint32 window) { - CHECK(server_thread_.get() == nullptr); - DVLOG(1) << "Setting server initial flow control window: " << window; - server_config_.SetInitialFlowControlWindowToSend(window); - } - void set_server_initial_stream_flow_control_receive_window(uint32 window) { CHECK(server_thread_.get() == nullptr); DVLOG(1) << "Setting server initial stream flow control window: " @@ -766,7 +750,7 @@ // Ensure both stream and connection level are flow control blocked by setting // the send window offset to 0. const uint64 kFlowControlWindow = - server_config_.GetInitialFlowControlWindowToSend(); + server_config_.GetInitialStreamFlowControlWindowToSend(); QuicSpdyClientStream* stream = client_->GetOrCreateStream(); QuicSession* session = client_->client()->session(); QuicFlowControllerPeer::SetSendWindowOffset(stream->flow_controller(), 0); @@ -1017,6 +1001,78 @@ server_thread_->Resume(); } +TEST_P(EndToEndTest, 0ByteConnectionId) { + ValueRestore<bool> old_flag(&FLAGS_allow_truncated_connection_ids_for_quic, + true); + client_config_.SetBytesForConnectionIdToSend(0); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ(200u, client_->response_headers()->parsed_response_code()); + + QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader( + client_->client()->session()->connection()); + EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, + header->public_header.connection_id_length); +} + +TEST_P(EndToEndTest, 1ByteConnectionId) { + ValueRestore<bool> old_flag(&FLAGS_allow_truncated_connection_ids_for_quic, + true); + client_config_.SetBytesForConnectionIdToSend(1); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ(200u, client_->response_headers()->parsed_response_code()); + QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader( + client_->client()->session()->connection()); + EXPECT_EQ(PACKET_1BYTE_CONNECTION_ID, + header->public_header.connection_id_length); +} + +TEST_P(EndToEndTest, 4ByteConnectionId) { + ValueRestore<bool> old_flag(&FLAGS_allow_truncated_connection_ids_for_quic, + true); + client_config_.SetBytesForConnectionIdToSend(4); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ(200u, client_->response_headers()->parsed_response_code()); + QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader( + client_->client()->session()->connection()); + EXPECT_EQ(PACKET_4BYTE_CONNECTION_ID, + header->public_header.connection_id_length); +} + +TEST_P(EndToEndTest, 8ByteConnectionId) { + ValueRestore<bool> old_flag(&FLAGS_allow_truncated_connection_ids_for_quic, + true); + client_config_.SetBytesForConnectionIdToSend(8); + ASSERT_TRUE(Initialize()); + + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ(200u, client_->response_headers()->parsed_response_code()); + QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader( + client_->client()->session()->connection()); + EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, + header->public_header.connection_id_length); +} + +TEST_P(EndToEndTest, 15ByteConnectionId) { + ValueRestore<bool> old_flag(&FLAGS_allow_truncated_connection_ids_for_quic, + true); + client_config_.SetBytesForConnectionIdToSend(15); + ASSERT_TRUE(Initialize()); + + // Our server is permissive and allows for out of bounds values. + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + EXPECT_EQ(200u, client_->response_headers()->parsed_response_code()); + QuicPacketHeader* header = QuicConnectionPeer::GetLastHeader( + client_->client()->session()->connection()); + EXPECT_EQ(PACKET_8BYTE_CONNECTION_ID, + header->public_header.connection_id_length); +} + TEST_P(EndToEndTest, ResetConnection) { ASSERT_TRUE(Initialize()); client_->client()->WaitForCryptoHandshakeConfirmed(); @@ -1173,47 +1229,7 @@ EXPECT_NE(old_address.port(), new_address.port()); } - -TEST_P(EndToEndTest, DifferentFlowControlWindowsQ019) { - // TODO(rjshade): Remove this test when removing QUIC_VERSION_19. - // Client and server can set different initial flow control receive windows. - // These are sent in CHLO/SHLO. Tests that these values are exchanged properly - // in the crypto handshake. - - const uint32 kClientIFCW = 123456; - set_client_initial_flow_control_receive_window(kClientIFCW); - - const uint32 kServerIFCW = 654321; - set_server_initial_flow_control_receive_window(kServerIFCW); - - ASSERT_TRUE(Initialize()); - if (negotiated_version_ > QUIC_VERSION_19) { - return; - } - - // Values are exchanged during crypto handshake, so wait for that to finish. - client_->client()->WaitForCryptoHandshakeConfirmed(); - server_thread_->WaitForCryptoHandshakeConfirmed(); - - // Client should have the right value for server's receive window. - EXPECT_EQ(kServerIFCW, client_->client() - ->session() - ->config() - ->ReceivedInitialFlowControlWindowBytes()); - - // Server should have the right value for client's receive window. - server_thread_->Pause(); - QuicDispatcher* dispatcher = - QuicServerPeer::GetDispatcher(server_thread_->server()); - QuicSession* session = dispatcher->session_map().begin()->second; - EXPECT_EQ(kClientIFCW, - session->config()->ReceivedInitialFlowControlWindowBytes()); - server_thread_->Resume(); -} - -TEST_P(EndToEndTest, DifferentFlowControlWindowsQ020) { - // TODO(rjshade): Rename to DifferentFlowControlWindows when removing - // QUIC_VERSION_19. +TEST_P(EndToEndTest, DifferentFlowControlWindows) { // Client and server can set different initial flow control receive windows. // These are sent in CHLO/SHLO. Tests that these values are exchanged properly // in the crypto handshake. @@ -1228,9 +1244,6 @@ set_server_initial_session_flow_control_receive_window(kServerSessionIFCW); ASSERT_TRUE(Initialize()); - if (negotiated_version_ == QUIC_VERSION_19) { - return; - } // Values are exchanged during crypto handshake, so wait for that to finish. client_->client()->WaitForCryptoHandshakeConfirmed(); @@ -1282,9 +1295,6 @@ set_server_initial_session_flow_control_receive_window(kSessionIFCW); ASSERT_TRUE(Initialize()); - if (negotiated_version_ < QUIC_VERSION_21) { - return; - } // Wait for crypto handshake to finish. This should have contributed to the // crypto stream flow control window, but not affected the session flow
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index d7d35c8..eb86c7f 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc
@@ -76,9 +76,8 @@ session()->connection()->SendConnectionClosePacket( QUIC_PEER_GOING_AWAY, ""); } - if (fd_ > 0) { - epoll_server_->UnregisterFD(fd_); - } + + CleanUpUDPSocket(); } bool QuicClient::Initialize() { @@ -87,10 +86,6 @@ // If an initial flow control window has not explicitly been set, then use the // same value that Chrome uses: 10 Mb. const uint32 kInitialFlowControlWindow = 10 * 1024 * 1024; // 10 Mb - if (config_.GetInitialFlowControlWindowToSend() == - kMinimumFlowControlSendWindow) { - config_.SetInitialFlowControlWindowToSend(kInitialFlowControlWindow); - } if (config_.GetInitialStreamFlowControlWindowToSend() == kMinimumFlowControlSendWindow) { config_.SetInitialStreamFlowControlWindowToSend(kInitialFlowControlWindow); @@ -236,12 +231,20 @@ if (connected()) { session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY); } - epoll_server_->UnregisterFD(fd_); - close(fd_); - fd_ = -1; + + CleanUpUDPSocket(); + initialized_ = false; } +void QuicClient::CleanUpUDPSocket() { + if (fd_ > -1) { + epoll_server_->UnregisterFD(fd_); + close(fd_); + fd_ = -1; + } +} + void QuicClient::SendRequestsAndWaitForResponse( const base::CommandLine::StringVector& args) { for (size_t i = 0; i < args.size(); ++i) {
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h index 47d4cec..ba824d2 100644 --- a/net/tools/quic/quic_client.h +++ b/net/tools/quic/quic_client.h
@@ -204,6 +204,9 @@ // and binds the socket to our address. bool CreateUDPSocket(); + // If the socket has been created, then unregister and close() the FD. + void CleanUpUDPSocket(); + // Read a UDP packet and hand it to the framer. bool ReadAndProcessPacket();
diff --git a/net/tools/quic/quic_client_test.cc b/net/tools/quic/quic_client_test.cc new file mode 100644 index 0000000..793518b --- /dev/null +++ b/net/tools/quic/quic_client_test.cc
@@ -0,0 +1,75 @@ +// Copyright (c) 2014 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. + +#include <dirent.h> +#include <stdio.h> + +#include "base/basictypes.h" +#include "base/strings/string_util.h" +#include "net/quic/test_tools/quic_test_utils.h" +#include "net/tools/epoll_server/epoll_server.h" +#include "net/tools/quic/quic_client.h" +#include "testing/gtest/include/gtest/gtest.h" + +using net::EpollServer; + +namespace net { +namespace tools { +namespace test { +namespace { + +int NumOpenFDs() { + int number_of_open_fds = 0; + char buf[256]; + struct dirent* dp; + + base::snprintf(buf, arraysize(buf), "/proc/%i/fd/", getpid()); + DIR* dir = opendir(buf); + while ((dp = readdir(dir)) != NULL) + number_of_open_fds++; + closedir(dir); + + return number_of_open_fds; +} + +// Creates a new QuicClient and Initializes it. Caller is responsible for +// deletion. +QuicClient* CreateAndInitializeQuicClient(EpollServer* eps, uint16 port) { + IPEndPoint server_address(IPEndPoint(net::test::Loopback4(), port)); + QuicServerId server_id("hostname", server_address.port(), false, + PRIVACY_MODE_DISABLED); + QuicVersionVector versions = QuicSupportedVersions(); + QuicClient* client = + new QuicClient(server_address, server_id, versions, false, eps); + EXPECT_TRUE(client->Initialize()); + return client; +} + +TEST(QuicClientTest, DoNotLeakFDs) { + // Make sure that the QuicClient doesn't leak FDs. Doing so could cause port + // exhaustion in long running processes which repeatedly create clients. + + // Record initial number of FDs, after creation of EpollServer. + EpollServer eps; + int number_of_open_fds = NumOpenFDs(); + + // Create a number of clients, initialize them, and verify this has resulted + // in additional FDs being opened. + const int kNumClients = 5; + for (int i = 0; i < kNumClients; ++i) { + std::unique_ptr<QuicClient> client( + CreateAndInitializeQuicClient(&eps, net::test::kTestPort + i)); + + // Initializing the client will create a new FD. + EXPECT_LT(number_of_open_fds, NumOpenFDs()); + } + + // The FDs created by the QuicClients should now be closed. + EXPECT_EQ(number_of_open_fds, NumOpenFDs()); +} + +} // namespace +} // namespace test +} // namespace tools +} // namespace net
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc index 779f62c..7635b53 100644 --- a/net/tools/quic/quic_server.cc +++ b/net/tools/quic/quic_server.cc
@@ -72,10 +72,6 @@ // sensible value for a server: 1 MB for session, 64 KB for each stream. const uint32 kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB const uint32 kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB - if (config_.GetInitialFlowControlWindowToSend() == - kMinimumFlowControlSendWindow) { - config_.SetInitialFlowControlWindowToSend(kInitialSessionFlowControlWindow); - } if (config_.GetInitialStreamFlowControlWindowToSend() == kMinimumFlowControlSendWindow) { config_.SetInitialStreamFlowControlWindowToSend(
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc index c8f8bce..c093b54 100644 --- a/net/tools/quic/quic_server_session_test.cc +++ b/net/tools/quic/quic_server_session_test.cc
@@ -71,8 +71,6 @@ QuicRandom::GetInstance()) { config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest); - config_.SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend(
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc index 94ba5aa..09795da 100644 --- a/net/tools/quic/quic_spdy_client_stream_test.cc +++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -43,8 +43,6 @@ // New streams rely on having the peer's flow control receive window // negotiated in the config. - session_.config()->SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); session_.config()->SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); session_.config()->SetInitialSessionFlowControlWindowToSend(
diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc index 8a3600c..8681735 100644 --- a/net/tools/quic/quic_spdy_server_stream_test.cc +++ b/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -84,8 +84,6 @@ // New streams rely on having the peer's flow control receive window // negotiated in the config. - session_.config()->SetInitialFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); session_.config()->SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); session_.config()->SetInitialSessionFlowControlWindowToSend(
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 8531dd3..68858c1 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -9,6 +9,7 @@ #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/compiler_specific.h" +#include "base/debug/alias.h" #include "base/file_version_info.h" #include "base/message_loop/message_loop.h" #include "base/metrics/field_trial.h" @@ -207,11 +208,18 @@ base::Unretained(this))), awaiting_callback_(false), http_user_agent_settings_(http_user_agent_settings), + transaction_state_(TRANSACTION_WAS_NOT_INITIALIZED), weak_factory_(this) { URLRequestThrottlerManager* manager = request->context()->throttler_manager(); if (manager) throttling_entry_ = manager->RegisterRequestUrl(request->url()); + // TODO(battre) Remove this overriding once crbug.com/289715 has been + // resolved. + on_headers_received_callback_ = + base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallbackForDebugging, + weak_factory_.GetWeakPtr()); + ResetTimer(); } @@ -407,6 +415,7 @@ DoneWithRequest(ABORTED); transaction_.reset(); + transaction_state_ = TRANSACTION_WAS_DESTROYED; response_info_ = NULL; receive_headers_end_ = base::TimeTicks(); } @@ -468,6 +477,8 @@ rv = request_->context()->http_transaction_factory()->CreateTransaction( priority_, &transaction_); + if (rv == OK) + transaction_state_ = TRANSACTION_WAS_INITIALIZED; if (rv == OK && request_info_.url.SchemeIsWSOrWSS()) { base::SupportsUserData::Data* data = request_->GetUserData( @@ -933,6 +944,19 @@ } } +// TODO(battre) Use URLRequestHttpJob::OnHeadersReceivedCallback again, once +// crbug.com/289715 has been resolved. +// static +void URLRequestHttpJob::OnHeadersReceivedCallbackForDebugging( + base::WeakPtr<net::URLRequestHttpJob> job, + int result) { + CHECK(job.get()); + net::URLRequestHttpJob::TransactionState state = job->transaction_state_; + base::debug::Alias(&state); + CHECK(job->transaction_.get()); + job->OnHeadersReceivedCallback(result); +} + void URLRequestHttpJob::OnHeadersReceivedCallback(int result) { awaiting_callback_ = false;
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index 3a23e8a..d222357 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h
@@ -88,6 +88,11 @@ // Processes the Public-Key-Pins header, if one exists. void ProcessPublicKeyPinsHeader(); + // TODO(battre) Remove this when crbug.com/289715 is fixed. + static void OnHeadersReceivedCallbackForDebugging( + base::WeakPtr<URLRequestHttpJob> job, + int result); + // |result| should be net::OK, or the request is canceled. void OnHeadersReceivedCallback(int result); void OnStartCompleted(int result); @@ -267,6 +272,14 @@ const HttpUserAgentSettings* http_user_agent_settings_; + // TODO(battre) Remove this when crbug.com/289715 is fixed. + enum TransactionState { + TRANSACTION_WAS_NOT_INITIALIZED, + TRANSACTION_WAS_INITIALIZED, + TRANSACTION_WAS_DESTROYED + }; + TransactionState transaction_state_; + base::WeakPtrFactory<URLRequestHttpJob> weak_factory_; DISALLOW_COPY_AND_ASSIGN(URLRequestHttpJob);
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc index a1540fa..9fc963d 100644 --- a/net/url_request/url_request_job_manager.cc +++ b/net/url_request/url_request_job_manager.cc
@@ -150,9 +150,7 @@ return false; } -URLRequestJobManager::URLRequestJobManager() - : allowed_thread_(0), - allowed_thread_initialized_(false) { +URLRequestJobManager::URLRequestJobManager() { } URLRequestJobManager::~URLRequestJobManager() {}
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h index 6329eab..7729abb 100644 --- a/net/url_request/url_request_job_manager.h +++ b/net/url_request/url_request_job_manager.h
@@ -6,10 +6,8 @@ #define NET_URL_REQUEST_URL_REQUEST_JOB_MANAGER_H_ #include <string> -#include <vector> -#include "base/synchronization/lock.h" -#include "base/threading/platform_thread.h" +#include "base/threading/thread_checker.h" #include "net/base/net_export.h" #include "net/url_request/url_request.h" @@ -64,11 +62,12 @@ // set the allowed thread. bool IsAllowedThread() const { #if 0 - if (!allowed_thread_initialized_) { - allowed_thread_ = base::PlatformThread::CurrentId(); - allowed_thread_initialized_ = true; - } - return allowed_thread_ == base::PlatformThread::CurrentId(); + return thread_checker_.CalledOnValidThread(); + } + + // We use this to assert that CreateJob and the registration functions all + // run on the same thread. + base::ThreadChecker thread_checker_; #else // The previous version of this check used GetCurrentThread on Windows to // get thread handles to compare. Unfortunately, GetCurrentThread returns @@ -80,15 +79,8 @@ // check back on. return true; } - - // We use this to assert that CreateJob and the registration functions all - // run on the same thread. - mutable base::PlatformThreadId allowed_thread_; - mutable bool allowed_thread_initialized_; #endif - mutable base::Lock lock_; - DISALLOW_COPY_AND_ASSIGN(URLRequestJobManager); };
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc index c1283ea..06e1a64 100644 --- a/sandbox/linux/services/credentials.cc +++ b/sandbox/linux/services/credentials.cc
@@ -157,21 +157,16 @@ namespace sandbox { -Credentials::Credentials() { -} - -Credentials::~Credentials() { -} - bool Credentials::DropAllCapabilities() { ScopedCap cap(cap_init()); CHECK(cap); PCHECK(0 == cap_set_proc(cap.get())); + CHECK(!HasAnyCapability()); // We never let this function fail. return true; } -bool Credentials::HasAnyCapability() const { +bool Credentials::HasAnyCapability() { ScopedCap current_cap(cap_get_proc()); CHECK(current_cap); ScopedCap empty_cap(cap_init()); @@ -179,7 +174,7 @@ return cap_compare(current_cap.get(), empty_cap.get()) != 0; } -scoped_ptr<std::string> Credentials::GetCurrentCapString() const { +scoped_ptr<std::string> Credentials::GetCurrentCapString() { ScopedCap current_cap(cap_get_proc()); CHECK(current_cap); ScopedCapText cap_text(cap_to_text(current_cap.get(), NULL));
diff --git a/sandbox/linux/services/credentials.h b/sandbox/linux/services/credentials.h index ddc54db..fc65afc 100644 --- a/sandbox/linux/services/credentials.h +++ b/sandbox/linux/services/credentials.h
@@ -25,19 +25,16 @@ // implemented by the Linux kernel. class SANDBOX_EXPORT Credentials { public: - Credentials(); - ~Credentials(); - // Drop all capabilities in the effective, inheritable and permitted sets for // the current process. - bool DropAllCapabilities() WARN_UNUSED_RESULT; + static bool DropAllCapabilities() WARN_UNUSED_RESULT; // Return true iff there is any capability in any of the capabilities sets // of the current process. - bool HasAnyCapability() const; + static bool HasAnyCapability(); // Returns the capabilities of the current process in textual form, as // documented in libcap2's cap_to_text(3). This is mostly useful for // debugging and tests. - scoped_ptr<std::string> GetCurrentCapString() const; + static scoped_ptr<std::string> GetCurrentCapString(); // Returns whether the kernel supports CLONE_NEWUSER and whether it would be // possible to immediately move to a new user namespace. There is no point @@ -52,7 +49,7 @@ // change. // If this call succeeds, the current process will be granted a full set of // capabilities in the new namespace. - bool MoveToNewUserNS() WARN_UNUSED_RESULT; + static bool MoveToNewUserNS() WARN_UNUSED_RESULT; // Remove the ability of the process to access the file system. File // descriptors which are already open prior to calling this API remain @@ -65,10 +62,10 @@ // are closed (for example, by checking the result of // ProcUtil::HasOpenDirectory with a file descriptor for /proc, then closing // that file descriptor). Otherwise it may be possible to escape the chroot. - bool DropFileSystemAccess() WARN_UNUSED_RESULT; + static bool DropFileSystemAccess() WARN_UNUSED_RESULT; private: - DISALLOW_COPY_AND_ASSIGN(Credentials); + DISALLOW_IMPLICIT_CONSTRUCTORS(Credentials); }; } // namespace sandbox.
diff --git a/sandbox/linux/services/credentials_unittest.cc b/sandbox/linux/services/credentials_unittest.cc index 5d1ebba..92f199a 100644 --- a/sandbox/linux/services/credentials_unittest.cc +++ b/sandbox/linux/services/credentials_unittest.cc
@@ -48,32 +48,20 @@ return true; } -// Give dynamic tools a simple thing to test. -TEST(Credentials, CreateAndDestroy) { - { - Credentials cred1; - (void) cred1; - } - scoped_ptr<Credentials> cred2(new Credentials); -} - SANDBOX_TEST(Credentials, DropAllCaps) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); - CHECK(!creds.HasAnyCapability()); + CHECK(Credentials::DropAllCapabilities()); + CHECK(!Credentials::HasAnyCapability()); } SANDBOX_TEST(Credentials, GetCurrentCapString) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); + CHECK(Credentials::DropAllCapabilities()); const char kNoCapabilityText[] = "="; - CHECK(*creds.GetCurrentCapString() == kNoCapabilityText); + CHECK(*Credentials::GetCurrentCapString() == kNoCapabilityText); } SANDBOX_TEST(Credentials, MoveToNewUserNS) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); - bool moved_to_new_ns = creds.MoveToNewUserNS(); + CHECK(Credentials::DropAllCapabilities()); + bool moved_to_new_ns = Credentials::MoveToNewUserNS(); fprintf(stdout, "Unprivileged CLONE_NEWUSER supported: %s\n", moved_to_new_ns ? "true." : "false."); @@ -84,28 +72,26 @@ fflush(stdout); return; } - CHECK(creds.HasAnyCapability()); - CHECK(creds.DropAllCapabilities()); - CHECK(!creds.HasAnyCapability()); + CHECK(Credentials::HasAnyCapability()); + CHECK(Credentials::DropAllCapabilities()); + CHECK(!Credentials::HasAnyCapability()); } SANDBOX_TEST(Credentials, SupportsUserNS) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); + CHECK(Credentials::DropAllCapabilities()); bool user_ns_supported = Credentials::SupportsNewUserNS(); - bool moved_to_new_ns = creds.MoveToNewUserNS(); + bool moved_to_new_ns = Credentials::MoveToNewUserNS(); CHECK_EQ(user_ns_supported, moved_to_new_ns); } SANDBOX_TEST(Credentials, UidIsPreserved) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); + CHECK(Credentials::DropAllCapabilities()); uid_t old_ruid, old_euid, old_suid; gid_t old_rgid, old_egid, old_sgid; PCHECK(0 == getresuid(&old_ruid, &old_euid, &old_suid)); PCHECK(0 == getresgid(&old_rgid, &old_egid, &old_sgid)); // Probably missing kernel support. - if (!creds.MoveToNewUserNS()) return; + if (!Credentials::MoveToNewUserNS()) return; uid_t new_ruid, new_euid, new_suid; PCHECK(0 == getresuid(&new_ruid, &new_euid, &new_suid)); CHECK(old_ruid == new_ruid); @@ -119,27 +105,25 @@ CHECK(old_sgid == new_sgid); } -bool NewUserNSCycle(Credentials* creds) { - DCHECK(creds); - if (!creds->MoveToNewUserNS() || - !creds->HasAnyCapability() || - !creds->DropAllCapabilities() || - creds->HasAnyCapability()) { +bool NewUserNSCycle() { + if (!Credentials::MoveToNewUserNS() || + !Credentials::HasAnyCapability() || + !Credentials::DropAllCapabilities() || + Credentials::HasAnyCapability()) { return false; } return true; } SANDBOX_TEST(Credentials, NestedUserNS) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); + CHECK(Credentials::DropAllCapabilities()); // Probably missing kernel support. - if (!creds.MoveToNewUserNS()) return; - CHECK(creds.DropAllCapabilities()); + if (!Credentials::MoveToNewUserNS()) return; + CHECK(Credentials::DropAllCapabilities()); // As of 3.12, the kernel has a limit of 32. See create_user_ns(). const int kNestLevel = 10; for (int i = 0; i < kNestLevel; ++i) { - CHECK(NewUserNSCycle(&creds)) << "Creating new user NS failed at iteration " + CHECK(NewUserNSCycle()) << "Creating new user NS failed at iteration " << i << "."; } } @@ -153,11 +137,10 @@ } SANDBOX_TEST(Credentials, DISABLE_ON_LSAN(DropFileSystemAccessIsSafe)) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); + CHECK(Credentials::DropAllCapabilities()); // Probably missing kernel support. - if (!creds.MoveToNewUserNS()) return; - CHECK(creds.DropFileSystemAccess()); + if (!Credentials::MoveToNewUserNS()) return; + CHECK(Credentials::DropFileSystemAccess()); CHECK(!DirectoryExists("/proc")); CHECK(WorkingDirectoryIsRoot()); // We want the chroot to never have a subdirectory. A subdirectory @@ -168,17 +151,16 @@ // Check that after dropping filesystem access and dropping privileges // it is not possible to regain capabilities. SANDBOX_TEST(Credentials, DISABLE_ON_LSAN(CannotRegainPrivileges)) { - Credentials creds; - CHECK(creds.DropAllCapabilities()); + CHECK(Credentials::DropAllCapabilities()); // Probably missing kernel support. - if (!creds.MoveToNewUserNS()) return; - CHECK(creds.DropFileSystemAccess()); - CHECK(creds.DropAllCapabilities()); + if (!Credentials::MoveToNewUserNS()) return; + CHECK(Credentials::DropFileSystemAccess()); + CHECK(Credentials::DropAllCapabilities()); // The kernel should now prevent us from regaining capabilities because we // are in a chroot. CHECK(!Credentials::SupportsNewUserNS()); - CHECK(!creds.MoveToNewUserNS()); + CHECK(!Credentials::MoveToNewUserNS()); } } // namespace.
diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 8351a71..2f15a59 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn
@@ -7,6 +7,9 @@ if (cpu_arch == "arm") { import("//build/config/arm.gni") } +if (is_android) { + import("//build/config/android/rules.gni") +} skia_support_gpu = !is_ios skia_support_pdf = !is_ios && (enable_basic_printing || enable_print_preview) @@ -697,3 +700,46 @@ visibility = [ ":skia" ] } + +test("skia_unittests") { + sources = [ + "ext/analysis_canvas_unittest.cc", + "ext/bitmap_platform_device_mac_unittest.cc", + "ext/convolver_unittest.cc", + "ext/image_operations_unittest.cc", + "ext/pixel_ref_utils_unittest.cc", + "ext/platform_canvas_unittest.cc", + "ext/recursive_gaussian_convolution_unittest.cc", + "ext/refptr_unittest.cc", + "ext/skia_utils_ios_unittest.mm", + "ext/skia_utils_mac_unittest.mm", + "ext/vector_canvas_unittest.cc", + ] + + if (!is_win) { + sources -= [ "ext/vector_canvas_unittest.cc" ] + } + + if (!is_win && !is_mac) { + sources -= [ "ext/platform_canvas_unittest.cc" ] + } + + deps = [ + ":skia", + "//base", + "//base/test:run_all_unittests", + "//testing/gtest", + "//ui/gfx", + "//ui/gfx/geometry", + ] +} + +if (is_android) { + # GYP: //skia/skia_tests.gyp:skia_unittests_apk + unittest_apk("skia_unittests_apk") { + unittests_dep = ":skia_unittests" + deps = [ + ":skia_unittests", + ] + } +}
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index cb19ff5..f86a1f7 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -207,14 +207,14 @@ #define SK_CPU_LENDIAN #undef SK_CPU_BENDIAN -#elif defined(SK_BUILD_FOR_UNIX) +#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID) // Prefer FreeType's emboldening algorithm to Skia's // TODO: skia used to just use hairline, but has improved since then, so // we should revisit this choice... #define SK_USE_FREETYPE_EMBOLDEN -#ifdef SK_CPU_BENDIAN +#if defined(SK_BUILD_FOR_UNIX) && defined(SK_CPU_BENDIAN) // Above we set the order for ARGB channels in registers. I suspect that, on // big endian machines, you can keep this the same and everything will work. // The in-memory order will be different, of course, but as long as everything @@ -267,10 +267,6 @@ # define SK_SUPPORT_LEGACY_PUBLIC_IMAGEINFO_FIELDS #endif -#ifndef SK_SUPPORT_LEGACY_GRADIENT_PRECISION -# define SK_SUPPORT_LEGACY_GRADIENT_PRECISION -#endif - #ifndef SK_IGNORE_ETC1_SUPPORT # define SK_IGNORE_ETC1_SUPPORT #endif @@ -291,14 +287,6 @@ # define SK_IGNORE_GPU_LAYER_HOISTING #endif -#ifndef SK_SUPPORT_LEGACY_DRAWDATA -# define SK_SUPPORT_LEGACY_DRAWDATA -#endif - -#ifndef SK_SUPPORT_LEGACY_CANVAS_VIRTUAL -# define SK_SUPPORT_LEGACY_CANVAS_VIRTUAL -#endif - // If this goes well, we can have Skia respect DYNAMIC_ANNOTATIONS_ENABLED directly. #if DYNAMIC_ANNOTATIONS_ENABLED # define SK_DYNAMIC_ANNOTATIONS_ENABLED 1
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc index d26b453..eefd8f3 100644 --- a/skia/ext/analysis_canvas.cc +++ b/skia/ext/analysis_canvas.cc
@@ -95,22 +95,22 @@ is_transparent_ = false; } -void AnalysisCanvas::drawPaint(const SkPaint& paint) { +void AnalysisCanvas::onDrawPaint(const SkPaint& paint) { SkRect rect; getClipBounds(&rect); drawRect(rect, paint); } -void AnalysisCanvas::drawPoints(SkCanvas::PointMode mode, - size_t count, - const SkPoint points[], - const SkPaint& paint) { +void AnalysisCanvas::onDrawPoints(SkCanvas::PointMode mode, + size_t count, + const SkPoint points[], + const SkPaint& paint) { is_solid_color_ = false; is_transparent_ = false; ++draw_op_count_; } -void AnalysisCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { +void AnalysisCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { // This recreates the early-exit logic in SkCanvas.cpp. SkRect scratch; if (paint.canComputeFastBounds() && @@ -158,13 +158,13 @@ ++draw_op_count_; } -void AnalysisCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { +void AnalysisCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { is_solid_color_ = false; is_transparent_ = false; ++draw_op_count_; } -void AnalysisCanvas::drawRRect(const SkRRect& rr, const SkPaint& paint) { +void AnalysisCanvas::onDrawRRect(const SkRRect& rr, const SkPaint& paint) { // This should add the SkRRect to an SkPath, and call // drawPath, but since drawPath ignores the SkPath, just // do the same work here. @@ -173,26 +173,26 @@ ++draw_op_count_; } -void AnalysisCanvas::drawPath(const SkPath& path, const SkPaint& paint) { +void AnalysisCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { is_solid_color_ = false; is_transparent_ = false; ++draw_op_count_; } -void AnalysisCanvas::drawBitmap(const SkBitmap& bitmap, - SkScalar left, - SkScalar top, - const SkPaint*) { +void AnalysisCanvas::onDrawBitmap(const SkBitmap& bitmap, + SkScalar left, + SkScalar top, + const SkPaint*) { is_solid_color_ = false; is_transparent_ = false; ++draw_op_count_; } -void AnalysisCanvas::drawBitmapRectToRect(const SkBitmap&, - const SkRect* src, - const SkRect& dst, - const SkPaint* paint, - DrawBitmapRectFlags flags) { +void AnalysisCanvas::onDrawBitmapRect(const SkBitmap&, + const SkRect* src, + const SkRect& dst, + const SkPaint* paint, + DrawBitmapRectFlags flags) { // Call drawRect to determine transparency, // but reset solid color to false. SkPaint tmpPaint; @@ -203,19 +203,19 @@ ++draw_op_count_; } -void AnalysisCanvas::drawBitmapNine(const SkBitmap& bitmap, - const SkIRect& center, - const SkRect& dst, - const SkPaint* paint) { +void AnalysisCanvas::onDrawBitmapNine(const SkBitmap& bitmap, + const SkIRect& center, + const SkRect& dst, + const SkPaint* paint) { is_solid_color_ = false; is_transparent_ = false; ++draw_op_count_; } -void AnalysisCanvas::drawSprite(const SkBitmap& bitmap, - int left, - int top, - const SkPaint* paint) { +void AnalysisCanvas::onDrawSprite(const SkBitmap& bitmap, + int left, + int top, + const SkPaint* paint) { is_solid_color_ = false; is_transparent_ = false; ++draw_op_count_; @@ -277,15 +277,15 @@ ++draw_op_count_; } -void AnalysisCanvas::drawVertices(SkCanvas::VertexMode, - int vertex_count, - const SkPoint verts[], - const SkPoint texs[], - const SkColor colors[], - SkXfermode* xmode, - const uint16_t indices[], - int index_count, - const SkPaint& paint) { +void AnalysisCanvas::onDrawVertices(SkCanvas::VertexMode, + int vertex_count, + const SkPoint verts[], + const SkPoint texs[], + const SkColor colors[], + SkXfermode* xmode, + const uint16_t indices[], + int index_count, + const SkPaint& paint) { is_solid_color_ = false; is_transparent_ = false; ++draw_op_count_;
diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h index 66186c0..6af139f 100644 --- a/skia/ext/analysis_canvas.h +++ b/skia/ext/analysis_canvas.h
@@ -30,41 +30,41 @@ bool abortDrawing() override; // SkCanvas overrides. - void drawPaint(const SkPaint& paint) override; - void drawPoints(PointMode, + void onDrawPaint(const SkPaint& paint) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; - void drawOval(const SkRect&, const SkPaint&) override; - void drawRect(const SkRect&, const SkPaint&) override; - void drawRRect(const SkRRect&, const SkPaint&) override; - void drawPath(const SkPath& path, const SkPaint&) override; - void drawBitmap(const SkBitmap&, - SkScalar left, - SkScalar top, - const SkPaint* paint = NULL) override; - void drawBitmapRectToRect(const SkBitmap&, - const SkRect* src, - const SkRect& dst, - const SkPaint* paint, - DrawBitmapRectFlags flags) override; - void drawBitmapNine(const SkBitmap& bitmap, - const SkIRect& center, - const SkRect& dst, - const SkPaint* paint = NULL) override; - void drawSprite(const SkBitmap&, - int left, - int top, - const SkPaint* paint = NULL) override; - void drawVertices(VertexMode, - int vertexCount, - const SkPoint vertices[], - const SkPoint texs[], - const SkColor colors[], - SkXfermode*, - const uint16_t indices[], - int indexCount, - const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPath(const SkPath& path, const SkPaint&) override; + void onDrawBitmap(const SkBitmap&, + SkScalar left, + SkScalar top, + const SkPaint* paint = NULL) override; + void onDrawBitmapRect(const SkBitmap&, + const SkRect* src, + const SkRect& dst, + const SkPaint* paint, + DrawBitmapRectFlags flags) override; + void onDrawBitmapNine(const SkBitmap& bitmap, + const SkIRect& center, + const SkRect& dst, + const SkPaint* paint = NULL) override; + void onDrawSprite(const SkBitmap&, + int left, + int top, + const SkPaint* paint = NULL) override; + void onDrawVertices(VertexMode, + int vertexCount, + const SkPoint vertices[], + const SkPoint texs[], + const SkColor colors[], + SkXfermode*, + const uint16_t indices[], + int indexCount, + const SkPaint&) override; protected: void willSave() override;
diff --git a/skia/ext/analysis_canvas_unittest.cc b/skia/ext/analysis_canvas_unittest.cc index 3bf0e97..5bb18eb 100644 --- a/skia/ext/analysis_canvas_unittest.cc +++ b/skia/ext/analysis_canvas_unittest.cc
@@ -199,7 +199,7 @@ // this optimization and truly test clipPath's behavior. SkPath path; path.moveTo(0, 0); - path.lineTo(128, 50); + path.lineTo(128, 50); path.lineTo(255, 0); path.lineTo(255, 255); path.lineTo(0, 255); @@ -228,7 +228,7 @@ SkColor outputColor; SolidColorFill(canvas); EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor)); - + SkRect bounds = SkRect::MakeWH(255, 255); SkPaint paint; paint.setColor(SkColorSetARGB(255, 255, 255, 255)); @@ -257,7 +257,7 @@ SolidColorFill(canvas); EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor)); - + canvas.restore(); EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor)); @@ -282,11 +282,7 @@ } TEST(AnalysisCanvasTest, EarlyOutNotSolid) { - SkTileGridFactory::TileGridInfo tile_grid_info; - tile_grid_info.fTileInterval.set(256, 256); - tile_grid_info.fOffset.setZero(); - tile_grid_info.fMargin.setEmpty(); - SkTileGridFactory factory(tile_grid_info); + SkRTreeFactory factory; SkPictureRecorder recorder; // Create a picture with 3 commands, last of which is non-solid.
diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc index b2bc0d0..5e00327 100644 --- a/skia/ext/benchmarking_canvas.cc +++ b/skia/ext/benchmarking_canvas.cc
@@ -57,81 +57,76 @@ SkProxyCanvas::willRestore(); } - void drawPaint(const SkPaint& paint) override { + void onDrawPaint(const SkPaint& paint) override { AutoStamper stamper(this); - SkProxyCanvas::drawPaint(paint); + SkProxyCanvas::onDrawPaint(paint); } - void drawPoints(PointMode mode, - size_t count, - const SkPoint pts[], - const SkPaint& paint) override { - AutoStamper stamper(this); - SkProxyCanvas::drawPoints(mode, count, pts, paint); - } - - void drawOval(const SkRect& rect, const SkPaint& paint) override { - AutoStamper stamper(this); - SkProxyCanvas::drawOval(rect, paint); - } - - void drawRect(const SkRect& rect, const SkPaint& paint) override { - AutoStamper stamper(this); - SkProxyCanvas::drawRect(rect, paint); - } - - void drawRRect(const SkRRect& rrect, const SkPaint& paint) override { - AutoStamper stamper(this); - SkProxyCanvas::drawRRect(rrect, paint); - } - - void drawPath(const SkPath& path, const SkPaint& paint) override { - AutoStamper stamper(this); - SkProxyCanvas::drawPath(path, paint); - } - - void drawBitmap(const SkBitmap& bitmap, - SkScalar left, - SkScalar top, - const SkPaint* paint = NULL) override { - AutoStamper stamper(this); - SkProxyCanvas::drawBitmap(bitmap, left, top, paint); - } - - void drawBitmapRectToRect(const SkBitmap& bitmap, - const SkRect* src, - const SkRect& dst, - const SkPaint* paint, - DrawBitmapRectFlags flags) override { - AutoStamper stamper(this); - SkProxyCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags); - } - - void drawSprite(const SkBitmap& bitmap, - int left, - int top, - const SkPaint* paint = NULL) override { - AutoStamper stamper(this); - SkProxyCanvas::drawSprite(bitmap, left, top, paint); - } - - void drawVertices(VertexMode vmode, - int vertexCount, - const SkPoint vertices[], - const SkPoint texs[], - const SkColor colors[], - SkXfermode* xmode, - const uint16_t indices[], - int indexCount, + void onDrawPoints(PointMode mode, + size_t count, + const SkPoint pts[], const SkPaint& paint) override { AutoStamper stamper(this); - SkProxyCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors, - xmode, indices, indexCount, paint); + SkProxyCanvas::onDrawPoints(mode, count, pts, paint); } - void drawData(const void* data, size_t length) override { + void onDrawOval(const SkRect& rect, const SkPaint& paint) override { AutoStamper stamper(this); - SkProxyCanvas::drawData(data, length); + SkProxyCanvas::onDrawOval(rect, paint); + } + + void onDrawRect(const SkRect& rect, const SkPaint& paint) override { + AutoStamper stamper(this); + SkProxyCanvas::onDrawRect(rect, paint); + } + + void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override { + AutoStamper stamper(this); + SkProxyCanvas::onDrawRRect(rrect, paint); + } + + void onDrawPath(const SkPath& path, const SkPaint& paint) override { + AutoStamper stamper(this); + SkProxyCanvas::onDrawPath(path, paint); + } + + void onDrawBitmap(const SkBitmap& bitmap, + SkScalar left, + SkScalar top, + const SkPaint* paint) override { + AutoStamper stamper(this); + SkProxyCanvas::onDrawBitmap(bitmap, left, top, paint); + } + + void onDrawBitmapRect(const SkBitmap& bitmap, + const SkRect* src, + const SkRect& dst, + const SkPaint* paint, + DrawBitmapRectFlags flags) override { + AutoStamper stamper(this); + SkProxyCanvas::onDrawBitmapRect(bitmap, src, dst, paint, flags); + } + + void onDrawSprite(const SkBitmap& bitmap, + int left, + int top, + const SkPaint* paint) override { + AutoStamper stamper(this); + SkProxyCanvas::onDrawSprite(bitmap, left, top, paint); + } + + void onDrawVertices(VertexMode vmode, + int vertexCount, + const SkPoint vertices[], + const SkPoint texs[], + const SkColor colors[], + SkXfermode* xmode, + const uint16_t indices[], + int indexCount, + const SkPaint& paint) override { + AutoStamper stamper(this); + SkProxyCanvas::onDrawVertices(vmode, vertexCount, vertices, texs, colors, + xmode, indices, indexCount, paint); } protected:
diff --git a/skia/ext/platform_canvas_unittest.cc b/skia/ext/platform_canvas_unittest.cc index 3b39b44..9ab5667 100644 --- a/skia/ext/platform_canvas_unittest.cc +++ b/skia/ext/platform_canvas_unittest.cc
@@ -4,7 +4,17 @@ // TODO(awalker): clean up the const/non-const reference handling in this test +#include "skia/ext/platform_canvas.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "build/build_config.h" +#include "skia/ext/platform_device.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkColorPriv.h" +#include "third_party/skia/include/core/SkPixelRef.h" #if defined(OS_MACOSX) #import <ApplicationServices/ApplicationServices.h> @@ -14,15 +24,6 @@ #include <unistd.h> #endif -#include "base/memory/scoped_ptr.h" -#include "skia/ext/platform_canvas.h" -#include "skia/ext/platform_device.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkColorPriv.h" -#include "third_party/skia/include/core/SkPixelRef.h" - namespace skia { namespace { @@ -67,8 +68,12 @@ // rectangle. Basically, we're just checking to make sure that the pixels in the // middle are of rect_color and pixels in the corners are of canvas_color. bool VerifyRoundedRect(const PlatformCanvas& canvas, - uint32_t canvas_color, uint32_t rect_color, - int x, int y, int w, int h) { + uint32_t canvas_color, + uint32_t rect_color, + int x, + int y, + int w, + int h) { SkBaseDevice* device = skia::GetTopDevice(canvas); const SkBitmap& bitmap = device->accessBitmap(false); SkAutoLockPixels lock(bitmap); @@ -126,7 +131,7 @@ } #else void DrawNativeRect(PlatformCanvas& canvas, int x, int y, int w, int h) { - notImplemented(); + NOTIMPLEMENTED(); } #endif
diff --git a/skia/ext/vector_platform_device_emf_win.cc b/skia/ext/vector_platform_device_emf_win.cc index 85795b6..90e4a20 100644 --- a/skia/ext/vector_platform_device_emf_win.cc +++ b/skia/ext/vector_platform_device_emf_win.cc
@@ -10,7 +10,6 @@ #include "base/strings/string16.h" #include "skia/ext/bitmap_platform_device.h" #include "skia/ext/skia_utils_win.h" -#include "third_party/skia/include/core/SkFontHost.h" #include "third_party/skia/include/core/SkPathEffect.h" #include "third_party/skia/include/core/SkTemplates.h" #include "third_party/skia/include/core/SkUtils.h"
diff --git a/skia/skia_tests.gyp b/skia/skia_tests.gyp new file mode 100644 index 0000000..250ff1f --- /dev/null +++ b/skia/skia_tests.gyp
@@ -0,0 +1,65 @@ +# Copyright 2014 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. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'skia_unittests', + 'type': '<(gtest_target_type)', + 'dependencies': [ + '../base/base.gyp:base', + '../base/base.gyp:run_all_unittests', + '../testing/gtest.gyp:gtest', + '../skia/skia.gyp:skia', + '../ui/gfx/gfx.gyp:gfx', + '../ui/gfx/gfx.gyp:gfx_geometry', + ], + 'sources': [ + 'ext/analysis_canvas_unittest.cc', + 'ext/bitmap_platform_device_mac_unittest.cc', + 'ext/convolver_unittest.cc', + 'ext/image_operations_unittest.cc', + 'ext/pixel_ref_utils_unittest.cc', + 'ext/platform_canvas_unittest.cc', + 'ext/recursive_gaussian_convolution_unittest.cc', + 'ext/refptr_unittest.cc', + 'ext/skia_utils_ios_unittest.mm', + 'ext/skia_utils_mac_unittest.mm', + 'ext/vector_canvas_unittest.cc', + ], + 'conditions': [ + ['OS != "win"', { + 'sources!': [ + 'ext/vector_canvas_unittest.cc', + ], + }], + ['OS != "win" and OS != "mac"', { + 'sources!': [ + 'ext/platform_canvas_unittest.cc', + ], + }], + ], + }, + ], + 'conditions': [ + ['OS == "android"', { + 'targets': [ + { + 'target_name': 'skia_unittests_apk', + 'type': 'none', + 'dependencies': [ + 'skia_unittests', + ], + 'variables': { + 'test_suite_name': 'skia_unittests', + }, + 'includes': [ '../build/apk_test.gypi' ], + }, + ], + }], + ], +}
diff --git a/sky/engine/platform/BUILD.gn b/sky/engine/platform/BUILD.gn index 6e03149..93537b4 100644 --- a/sky/engine/platform/BUILD.gn +++ b/sky/engine/platform/BUILD.gn
@@ -353,8 +353,6 @@ "graphics/GraphicsContext.cpp", "graphics/GraphicsContext.h", "graphics/GraphicsContextAnnotation.h", - "graphics/GraphicsContextRecorder.cpp", - "graphics/GraphicsContextRecorder.h", "graphics/GraphicsContextState.cpp", "graphics/GraphicsContextState.h", "graphics/GraphicsContextStateSaver.h", @@ -381,8 +379,6 @@ "graphics/ImageSource.cpp", "graphics/ImageSource.h", "graphics/InterceptingCanvas.h", - "graphics/LoggingCanvas.cpp", - "graphics/LoggingCanvas.h", "graphics/OpaqueRectTrackingContentLayerDelegate.cpp", "graphics/OpaqueRectTrackingContentLayerDelegate.h", "graphics/Path.cpp", @@ -391,12 +387,8 @@ "graphics/PathTraversalState.h", "graphics/Pattern.cpp", "graphics/Pattern.h", - "graphics/ProfilingCanvas.cpp", - "graphics/ProfilingCanvas.h", "graphics/RegionTracker.cpp", "graphics/RegionTracker.h", - "graphics/ReplayingCanvas.cpp", - "graphics/ReplayingCanvas.h", "graphics/skia/GaneshUtils.cpp", "graphics/skia/GaneshUtils.h", "graphics/skia/NativeImageSkia.cpp",
diff --git a/sky/engine/platform/graphics/GraphicsContextRecorder.cpp b/sky/engine/platform/graphics/GraphicsContextRecorder.cpp deleted file mode 100644 index b093f3f..0000000 --- a/sky/engine/platform/graphics/GraphicsContextRecorder.cpp +++ /dev/null
@@ -1,153 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sky/engine/config.h" -#include "sky/engine/platform/graphics/GraphicsContextRecorder.h" - -#include "platform/image-decoders/ImageDecoder.h" -#include "platform/image-decoders/ImageFrame.h" -#include "platform/image-encoders/skia/PNGImageEncoder.h" -#include "sky/engine/platform/graphics/ImageBuffer.h" -#include "sky/engine/platform/graphics/ImageSource.h" -#include "sky/engine/platform/graphics/LoggingCanvas.h" -#include "sky/engine/platform/graphics/ProfilingCanvas.h" -#include "sky/engine/platform/graphics/ReplayingCanvas.h" -#include "sky/engine/wtf/HexNumber.h" -#include "sky/engine/wtf/text/Base64.h" -#include "sky/engine/wtf/text/TextEncoding.h" -#include "third_party/skia/include/core/SkBitmapDevice.h" -#include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/core/SkStream.h" - -namespace blink { - -GraphicsContext* GraphicsContextRecorder::record(const IntSize& size, bool isCertainlyOpaque) -{ - ASSERT(!m_picture); - ASSERT(!m_recorder); - ASSERT(!m_context); - m_isCertainlyOpaque = isCertainlyOpaque; - m_recorder = adoptPtr(new SkPictureRecorder); - SkCanvas* canvas = m_recorder->beginRecording(size.width(), size.height(), 0, 0); - m_context = adoptPtr(new GraphicsContext(canvas)); - m_context->setRegionTrackingMode(isCertainlyOpaque ? GraphicsContext::RegionTrackingOpaque : GraphicsContext::RegionTrackingDisabled); - m_context->setCertainlyOpaque(isCertainlyOpaque); - return m_context.get(); -} - -PassRefPtr<GraphicsContextSnapshot> GraphicsContextRecorder::stop() -{ - m_context.clear(); - m_picture = adoptRef(m_recorder->endRecording()); - m_recorder.clear(); - return adoptRef(new GraphicsContextSnapshot(m_picture.release())); -} - -GraphicsContextSnapshot::GraphicsContextSnapshot(PassRefPtr<SkPicture> picture) - : m_picture(picture) -{ -} - -static bool decodeBitmap(const void* data, size_t length, SkBitmap* result) -{ - RefPtr<SharedBuffer> buffer = SharedBuffer::create(static_cast<const char*>(data), length); - OwnPtr<ImageDecoder> imageDecoder = ImageDecoder::create(*buffer, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored); - if (!imageDecoder) - return false; - imageDecoder->setData(buffer.get(), true); - ImageFrame* frame = imageDecoder->frameBufferAtIndex(0); - if (!frame) - return true; - *result = frame->getSkBitmap(); - return true; -} - -PassRefPtr<GraphicsContextSnapshot> GraphicsContextSnapshot::load(const char* data, size_t size) -{ - SkMemoryStream stream(data, size); - RefPtr<SkPicture> picture = adoptRef(SkPicture::CreateFromStream(&stream, decodeBitmap)); - if (!picture) - return nullptr; - return adoptRef(new GraphicsContextSnapshot(picture)); -} - -PassOwnPtr<Vector<char> > GraphicsContextSnapshot::replay(unsigned fromStep, unsigned toStep, double scale) const -{ - const SkIRect bounds = m_picture->cullRect().roundOut(); - SkBitmap bitmap; - bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounds.width(), bounds.height())); - { - ReplayingCanvas canvas(bitmap, fromStep, toStep); - canvas.scale(scale, scale); - canvas.resetStepCount(); - m_picture->playback(&canvas, &canvas); - } - OwnPtr<Vector<char> > base64Data = adoptPtr(new Vector<char>()); - Vector<char> encodedImage; - if (!PNGImageEncoder::encode(bitmap, reinterpret_cast<Vector<unsigned char>*>(&encodedImage))) - return nullptr; - base64Encode(encodedImage, *base64Data); - return base64Data.release(); -} - -PassOwnPtr<GraphicsContextSnapshot::Timings> GraphicsContextSnapshot::profile(unsigned minRepeatCount, double minDuration) const -{ - OwnPtr<GraphicsContextSnapshot::Timings> timings = adoptPtr(new GraphicsContextSnapshot::Timings()); - timings->reserveCapacity(minRepeatCount); - const SkIRect bounds = m_picture->cullRect().roundOut(); - SkBitmap bitmap; - bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounds.width(), bounds.height())); - OwnPtr<ProfilingCanvas> canvas = adoptPtr(new ProfilingCanvas(bitmap)); - - double now = WTF::monotonicallyIncreasingTime(); - double stopTime = now + minDuration; - for (unsigned step = 0; step < minRepeatCount || now < stopTime; ++step) { - timings->append(Vector<double>()); - Vector<double>* currentTimings = &timings->last(); - if (timings->size() > 1) - currentTimings->reserveCapacity(timings->begin()->size()); - if (step) - canvas = adoptPtr(new ProfilingCanvas(bitmap)); - canvas->setTimings(currentTimings); - m_picture->playback(canvas.get()); - now = WTF::monotonicallyIncreasingTime(); - } - return timings.release(); -} - -PassRefPtr<JSONArray> GraphicsContextSnapshot::snapshotCommandLog() const -{ - const SkIRect bounds = m_picture->cullRect().roundOut(); - LoggingCanvas canvas(bounds.width(), bounds.height()); - m_picture->playback(&canvas); - return canvas.log(); -} - -} // namespace blink
diff --git a/sky/engine/platform/graphics/GraphicsContextRecorder.h b/sky/engine/platform/graphics/GraphicsContextRecorder.h deleted file mode 100644 index b8777e4..0000000 --- a/sky/engine/platform/graphics/GraphicsContextRecorder.h +++ /dev/null
@@ -1,79 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SKY_ENGINE_PLATFORM_GRAPHICS_GRAPHICSCONTEXTRECORDER_H_ -#define SKY_ENGINE_PLATFORM_GRAPHICS_GRAPHICSCONTEXTRECORDER_H_ - -#include "sky/engine/platform/JSONValues.h" -#include "sky/engine/platform/PlatformExport.h" -#include "sky/engine/platform/graphics/GraphicsContext.h" -#include "sky/engine/wtf/RefCounted.h" -#include "third_party/skia/include/core/SkPicture.h" -#include "third_party/skia/include/core/SkPictureRecorder.h" - -namespace blink { - -class PLATFORM_EXPORT GraphicsContextSnapshot : public RefCounted<GraphicsContextSnapshot> { -WTF_MAKE_NONCOPYABLE(GraphicsContextSnapshot); -public: - typedef Vector<Vector<double> > Timings; - - static PassRefPtr<GraphicsContextSnapshot> load(const char*, size_t); - - PassOwnPtr<Vector<char> > replay(unsigned fromStep = 0, unsigned toStep = 0, double scale = 1.0) const; - PassOwnPtr<Timings> profile(unsigned minIterations, double minDuration) const; - PassRefPtr<JSONArray> snapshotCommandLog() const; - -private: - friend class GraphicsContextRecorder; - GraphicsContextSnapshot(PassRefPtr<SkPicture>); - - PassOwnPtr<SkBitmap> createBitmap() const; - - RefPtr<SkPicture> m_picture; -}; - -class PLATFORM_EXPORT GraphicsContextRecorder { -WTF_MAKE_NONCOPYABLE(GraphicsContextRecorder); -public: - GraphicsContextRecorder() { } - GraphicsContext* record(const IntSize&, bool isCertainlyOpaque); - PassRefPtr<GraphicsContextSnapshot> stop(); - -private: - RefPtr<SkPicture> m_picture; - OwnPtr<GraphicsContext> m_context; - OwnPtr<SkPictureRecorder> m_recorder; - bool m_isCertainlyOpaque; -}; - -} // namespace blink - -#endif // SKY_ENGINE_PLATFORM_GRAPHICS_GRAPHICSCONTEXTRECORDER_H_
diff --git a/sky/engine/platform/graphics/LoggingCanvas.cpp b/sky/engine/platform/graphics/LoggingCanvas.cpp deleted file mode 100644 index 8cb941f..0000000 --- a/sky/engine/platform/graphics/LoggingCanvas.cpp +++ /dev/null
@@ -1,845 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sky/engine/config.h" -#include "sky/engine/platform/graphics/LoggingCanvas.h" - -#include "platform/image-encoders/skia/PNGImageEncoder.h" -#include "sky/engine/wtf/HexNumber.h" -#include "sky/engine/wtf/text/Base64.h" -#include "sky/engine/wtf/text/TextEncoding.h" -#include "third_party/skia/include/core/SkPicture.h" - -namespace blink { - -class AutoLogger { -public: - explicit AutoLogger(LoggingCanvas*); - PassRefPtr<JSONObject> logItem(const String& name); - PassRefPtr<JSONObject> logItemWithParams(const String& name); - ~AutoLogger(); - -private: - LoggingCanvas* m_canvas; - RefPtr<JSONObject> m_logItem; -}; - -AutoLogger::AutoLogger(LoggingCanvas* loggingCanvas) : m_canvas(loggingCanvas) -{ - loggingCanvas->m_depthCount++; -} - -PassRefPtr<JSONObject> AutoLogger::logItem(const String& name) -{ - RefPtr<JSONObject> item = JSONObject::create(); - item->setString("method", name); - m_logItem = item; - return item.release(); -} - -PassRefPtr<JSONObject> AutoLogger::logItemWithParams(const String& name) -{ - RefPtr<JSONObject> item = logItem(name); - RefPtr<JSONObject> params = JSONObject::create(); - item->setObject("params", params); - return params.release(); -} - -AutoLogger::~AutoLogger() -{ - m_canvas->m_depthCount--; - if (!m_canvas->m_depthCount) - m_canvas->m_log->pushObject(m_logItem); -} - -LoggingCanvas::LoggingCanvas(int width, int height) : InterceptingCanvas(width, height) -{ - m_log = JSONArray::create(); -} - -void LoggingCanvas::drawPaint(const SkPaint& paint) -{ - AutoLogger logger(this); - logger.logItemWithParams("drawPaint")->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::drawPaint(paint); -} - -void LoggingCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawPoints"); - params->setString("pointMode", pointModeName(mode)); - params->setArray("points", arrayForSkPoints(count, pts)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::drawPoints(mode, count, pts, paint); -} - -void LoggingCanvas::drawRect(const SkRect& rect, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawRect"); - params->setObject("rect", objectForSkRect(rect)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::drawRect(rect, paint); -} - -void LoggingCanvas::drawOval(const SkRect& oval, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawOval"); - params->setObject("oval", objectForSkRect(oval)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::drawOval(oval, paint); -} - -void LoggingCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawRRect"); - params->setObject("rrect", objectForSkRRect(rrect)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::drawRRect(rrect, paint); -} - -void LoggingCanvas::drawPath(const SkPath& path, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawPath"); - params->setObject("path", objectForSkPath(path)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::drawPath(path, paint); -} - -void LoggingCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmap"); - params->setNumber("left", left); - params->setNumber("top", top); - params->setObject("bitmap", objectForSkBitmap(bitmap)); - params->setObject("paint", objectForSkPaint(*paint)); - this->SkCanvas::drawBitmap(bitmap, left, top, paint); -} - -void LoggingCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags flags) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapRectToRect"); - params->setObject("bitmap", objectForSkBitmap(bitmap)); - params->setObject("src", objectForSkRect(*src)); - params->setObject("dst", objectForSkRect(dst)); - params->setObject("paint", objectForSkPaint(*paint)); - params->setNumber("flags", flags); - this->SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags); -} - -void LoggingCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapNine"); - params->setObject("bitmap", objectForSkBitmap(bitmap)); - params->setObject("center", objectForSkIRect(center)); - params->setObject("dst", objectForSkRect(dst)); - params->setObject("paint", objectForSkPaint(*paint)); - this->SkCanvas::drawBitmapNine(bitmap, center, dst, paint); -} - -void LoggingCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawSprite"); - params->setObject("bitmap", objectForSkBitmap(bitmap)); - params->setNumber("left", left); - params->setNumber("top", top); - params->setObject("paint", objectForSkPaint(*paint)); - this->SkCanvas::drawSprite(bitmap, left, top, paint); -} - -void LoggingCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode, - const uint16_t indices[], int indexCount, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawVertices"); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, indexCount, paint); -} - -void LoggingCanvas::drawData(const void* data, size_t length) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawData"); - params->setNumber("length", length); - this->SkCanvas::drawData(data, length); -} - -void LoggingCanvas::beginCommentGroup(const char* description) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("beginCommentGroup"); - params->setString("description", description); - this->SkCanvas::beginCommentGroup(description); -} - -void LoggingCanvas::addComment(const char* keyword, const char* value) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("addComment"); - params->setString("key", keyword); - params->setString("value", value); - this->SkCanvas::addComment(keyword, value); -} - -void LoggingCanvas::endCommentGroup() -{ - AutoLogger logger(this); - logger.logItem("endCommentGroup"); - this->SkCanvas::endCommentGroup(); -} - -void LoggingCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawDRRect"); - params->setObject("outer", objectForSkRRect(outer)); - params->setObject("inner", objectForSkRRect(inner)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::onDrawDRRect(outer, inner, paint); -} - -void LoggingCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawText"); - params->setString("text", stringForText(text, byteLength, paint)); - params->setNumber("x", x); - params->setNumber("y", y); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::onDrawText(text, byteLength, x, y, paint); -} - -void LoggingCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawPosText"); - params->setString("text", stringForText(text, byteLength, paint)); - size_t pointsCount = paint.countText(text, byteLength); - params->setArray("pos", arrayForSkPoints(pointsCount, pos)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::onDrawPosText(text, byteLength, pos, paint); -} - -void LoggingCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawPosTextH"); - params->setString("text", stringForText(text, byteLength, paint)); - size_t pointsCount = paint.countText(text, byteLength); - params->setArray("xpos", arrayForSkScalars(pointsCount, xpos)); - params->setNumber("constY", constY); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint); -} - -void LoggingCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("drawTextOnPath"); - params->setString("text", stringForText(text, byteLength, paint)); - params->setObject("path", objectForSkPath(path)); - params->setArray("matrix", arrayForSkMatrix(*matrix)); - params->setObject("paint", objectForSkPaint(paint)); - this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint); -} - -void LoggingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("clipRect"); - params->setObject("rect", objectForSkRect(rect)); - params->setString("SkRegion::Op", regionOpName(op)); - params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style); - this->SkCanvas::onClipRect(rect, op, style); -} - -void LoggingCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle style) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("clipRRect"); - params->setObject("rrect", objectForSkRRect(rrect)); - params->setString("SkRegion::Op", regionOpName(op)); - params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style); - this->SkCanvas::onClipRRect(rrect, op, style); -} - -void LoggingCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle style) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("clipPath"); - params->setObject("path", objectForSkPath(path)); - params->setString("SkRegion::Op", regionOpName(op)); - params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style); - this->SkCanvas::onClipPath(path, op, style); -} - -void LoggingCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("clipRegion"); - params->setString("op", regionOpName(op)); - this->SkCanvas::onClipRegion(region, op); -} - -void LoggingCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) -{ - AutoLogger logger(this); - logger.logItemWithParams("drawPicture")->setObject("picture", objectForSkPicture(*picture)); - this->SkCanvas::onDrawPicture(picture, matrix, paint); -} - -void LoggingCanvas::didSetMatrix(const SkMatrix& matrix) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("setMatrix"); - params->setArray("matrix", arrayForSkMatrix(matrix)); - this->SkCanvas::didSetMatrix(matrix); -} - -void LoggingCanvas::didConcat(const SkMatrix& matrix) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params; - - switch (matrix.getType()) { - case SkMatrix::kTranslate_Mask: - params = logger.logItemWithParams("translate"); - params->setNumber("dx", matrix.getTranslateX()); - params->setNumber("dy", matrix.getTranslateY()); - break; - - case SkMatrix::kScale_Mask: - params = logger.logItemWithParams("scale"); - params->setNumber("scaleX", matrix.getScaleX()); - params->setNumber("scaleY", matrix.getScaleY()); - break; - - default: - params = logger.logItemWithParams("concat"); - params->setArray("matrix", arrayForSkMatrix(matrix)); - } - this->SkCanvas::didConcat(matrix); -} - -void LoggingCanvas::willSave() -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItem("save"); - this->SkCanvas::willSave(); -} - -SkCanvas::SaveLayerStrategy LoggingCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) -{ - AutoLogger logger(this); - RefPtr<JSONObject> params = logger.logItemWithParams("saveLayer"); - if (bounds) - params->setObject("bounds", objectForSkRect(*bounds)); - params->setObject("paint", objectForSkPaint(*paint)); - params->setString("saveFlags", saveFlagsToString(flags)); - return this->SkCanvas::willSaveLayer(bounds, paint, flags); -} - -void LoggingCanvas::willRestore() -{ - AutoLogger logger(this); - logger.logItem("restore"); - this->SkCanvas::willRestore(); -} - -PassRefPtr<JSONArray> LoggingCanvas::log() -{ - return m_log; -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkRect(const SkRect& rect) -{ - RefPtr<JSONObject> rectItem = JSONObject::create(); - rectItem->setNumber("left", rect.left()); - rectItem->setNumber("top", rect.top()); - rectItem->setNumber("right", rect.right()); - rectItem->setNumber("bottom", rect.bottom()); - return rectItem.release(); -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkIRect(const SkIRect& rect) -{ - RefPtr<JSONObject> rectItem = JSONObject::create(); - rectItem->setNumber("left", rect.left()); - rectItem->setNumber("top", rect.top()); - rectItem->setNumber("right", rect.right()); - rectItem->setNumber("bottom", rect.bottom()); - return rectItem.release(); -} - -String LoggingCanvas::pointModeName(PointMode mode) -{ - switch (mode) { - case SkCanvas::kPoints_PointMode: return "Points"; - case SkCanvas::kLines_PointMode: return "Lines"; - case SkCanvas::kPolygon_PointMode: return "Polygon"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkPoint(const SkPoint& point) -{ - RefPtr<JSONObject> pointItem = JSONObject::create(); - pointItem->setNumber("x", point.x()); - pointItem->setNumber("y", point.y()); - return pointItem.release(); -} - -PassRefPtr<JSONArray> LoggingCanvas::arrayForSkPoints(size_t count, const SkPoint points[]) -{ - RefPtr<JSONArray> pointsArrayItem = JSONArray::create(); - for (size_t i = 0; i < count; ++i) - pointsArrayItem->pushObject(objectForSkPoint(points[i])); - return pointsArrayItem.release(); -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkPicture(const SkPicture& picture) -{ - const SkIRect bounds = picture.cullRect().roundOut(); - RefPtr<JSONObject> pictureItem = JSONObject::create(); - pictureItem->setNumber("width", bounds.width()); - pictureItem->setNumber("height", bounds.height()); - return pictureItem.release(); -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForRadius(const SkRRect& rrect, SkRRect::Corner corner) -{ - RefPtr<JSONObject> radiusItem = JSONObject::create(); - SkVector radius = rrect.radii(corner); - radiusItem->setNumber("xRadius", radius.x()); - radiusItem->setNumber("yRadius", radius.y()); - return radiusItem.release(); -} - -String LoggingCanvas::rrectTypeName(SkRRect::Type type) -{ - switch (type) { - case SkRRect::kEmpty_Type: return "Empty"; - case SkRRect::kRect_Type: return "Rect"; - case SkRRect::kOval_Type: return "Oval"; - case SkRRect::kSimple_Type: return "Simple"; - case SkRRect::kNinePatch_Type: return "Nine-patch"; - case SkRRect::kComplex_Type: return "Complex"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::radiusName(SkRRect::Corner corner) -{ - switch (corner) { - case SkRRect::kUpperLeft_Corner: return "upperLeftRadius"; - case SkRRect::kUpperRight_Corner: return "upperRightRadius"; - case SkRRect::kLowerRight_Corner: return "lowerRightRadius"; - case SkRRect::kLowerLeft_Corner: return "lowerLeftRadius"; - default: - ASSERT_NOT_REACHED(); - return "?"; - } -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkRRect(const SkRRect& rrect) -{ - RefPtr<JSONObject> rrectItem = JSONObject::create(); - rrectItem->setString("type", rrectTypeName(rrect.type())); - rrectItem->setNumber("left", rrect.rect().left()); - rrectItem->setNumber("top", rrect.rect().top()); - rrectItem->setNumber("right", rrect.rect().right()); - rrectItem->setNumber("bottom", rrect.rect().bottom()); - for (int i = 0; i < 4; ++i) - rrectItem->setObject(radiusName((SkRRect::Corner) i), objectForRadius(rrect, (SkRRect::Corner) i)); - return rrectItem.release(); -} - -String LoggingCanvas::fillTypeName(SkPath::FillType type) -{ - switch (type) { - case SkPath::kWinding_FillType: return "Winding"; - case SkPath::kEvenOdd_FillType: return "EvenOdd"; - case SkPath::kInverseWinding_FillType: return "InverseWinding"; - case SkPath::kInverseEvenOdd_FillType: return "InverseEvenOdd"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::convexityName(SkPath::Convexity convexity) -{ - switch (convexity) { - case SkPath::kUnknown_Convexity: return "Unknown"; - case SkPath::kConvex_Convexity: return "Convex"; - case SkPath::kConcave_Convexity: return "Concave"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::verbName(SkPath::Verb verb) -{ - switch (verb) { - case SkPath::kMove_Verb: return "Move"; - case SkPath::kLine_Verb: return "Line"; - case SkPath::kQuad_Verb: return "Quad"; - case SkPath::kConic_Verb: return "Conic"; - case SkPath::kCubic_Verb: return "Cubic"; - case SkPath::kClose_Verb: return "Close"; - case SkPath::kDone_Verb: return "Done"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -LoggingCanvas::VerbParams LoggingCanvas::segmentParams(SkPath::Verb verb) -{ - switch (verb) { - case SkPath::kMove_Verb: return VerbParams("Move", 1, 0); - case SkPath::kLine_Verb: return VerbParams("Line", 1, 1); - case SkPath::kQuad_Verb: return VerbParams("Quad", 2, 1); - case SkPath::kConic_Verb: return VerbParams("Conic", 2, 1); - case SkPath::kCubic_Verb: return VerbParams("Cubic", 3, 1); - case SkPath::kClose_Verb: return VerbParams("Close", 0, 0); - case SkPath::kDone_Verb: return VerbParams("Done", 0, 0); - default: - ASSERT_NOT_REACHED(); - return VerbParams("?", 0, 0); - }; -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkPath(const SkPath& path) -{ - RefPtr<JSONObject> pathItem = JSONObject::create(); - pathItem->setString("fillType", fillTypeName(path.getFillType())); - pathItem->setString("convexity", convexityName(path.getConvexity())); - pathItem->setBoolean("isRect", path.isRect(0)); - SkPath::Iter iter(path, false); - SkPoint points[4]; - RefPtr<JSONArray> pathPointsArray = JSONArray::create(); - for (SkPath::Verb verb = iter.next(points, false); verb != SkPath::kDone_Verb; verb = iter.next(points, false)) { - VerbParams verbParams = segmentParams(verb); - RefPtr<JSONObject> pathPointItem = JSONObject::create(); - pathPointItem->setString("verb", verbParams.name); - ASSERT(verbParams.pointCount + verbParams.pointOffset <= WTF_ARRAY_LENGTH(points)); - pathPointItem->setArray("points", arrayForSkPoints(verbParams.pointCount, points + verbParams.pointOffset)); - if (SkPath::kConic_Verb == verb) - pathPointItem->setNumber("conicWeight", iter.conicWeight()); - pathPointsArray->pushObject(pathPointItem); - } - pathItem->setArray("pathPoints", pathPointsArray); - pathItem->setObject("bounds", objectForSkRect(path.getBounds())); - return pathItem.release(); -} - -String LoggingCanvas::colorTypeName(SkColorType colorType) -{ - switch (colorType) { - case kUnknown_SkColorType: return "None"; - case kAlpha_8_SkColorType: return "A8"; - case kIndex_8_SkColorType: return "Index8"; - case kRGB_565_SkColorType: return "RGB565"; - case kARGB_4444_SkColorType: return "ARGB4444"; - case kN32_SkColorType: return "ARGB8888"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForBitmapData(const SkBitmap& bitmap) -{ - RefPtr<JSONObject> dataItem = JSONObject::create(); - Vector<unsigned char> output; - PNGImageEncoder::encode(bitmap, &output); - dataItem->setString("base64", WTF::base64Encode(reinterpret_cast<char*>(output.data()), output.size())); - dataItem->setString("mimeType", "image/png"); - return dataItem.release(); -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkBitmap(const SkBitmap& bitmap) -{ - RefPtr<JSONObject> bitmapItem = JSONObject::create(); - bitmapItem->setNumber("width", bitmap.width()); - bitmapItem->setNumber("height", bitmap.height()); - bitmapItem->setString("config", colorTypeName(bitmap.colorType())); - bitmapItem->setBoolean("opaque", bitmap.isOpaque()); - bitmapItem->setBoolean("immutable", bitmap.isImmutable()); - bitmapItem->setBoolean("volatile", bitmap.isVolatile()); - bitmapItem->setNumber("genID", bitmap.getGenerationID()); - bitmapItem->setObject("data", objectForBitmapData(bitmap)); - return bitmapItem.release(); -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkShader(const SkShader& shader) -{ - RefPtr<JSONObject> shaderItem = JSONObject::create(); - const SkMatrix localMatrix = shader.getLocalMatrix(); - if (!localMatrix.isIdentity()) - shaderItem->setArray("localMatrix", arrayForSkMatrix(localMatrix)); - return shaderItem.release(); -} - -String LoggingCanvas::stringForSkColor(const SkColor& color) -{ - String colorString = "#"; - appendUnsignedAsHex(color, colorString); - return colorString; -} - -void LoggingCanvas::appendFlagToString(String* flagsString, bool isSet, const String& name) -{ - if (!isSet) - return; - if (flagsString->length()) - flagsString->append("|"); - flagsString->append(name); -} - -String LoggingCanvas::stringForSkPaintFlags(const SkPaint& paint) -{ - if (!paint.getFlags()) - return "none"; - String flagsString = ""; - appendFlagToString(&flagsString, paint.isAntiAlias(), "AntiAlias"); - appendFlagToString(&flagsString, paint.isDither(), "Dither"); - appendFlagToString(&flagsString, paint.isUnderlineText(), "UnderlinText"); - appendFlagToString(&flagsString, paint.isStrikeThruText(), "StrikeThruText"); - appendFlagToString(&flagsString, paint.isFakeBoldText(), "FakeBoldText"); - appendFlagToString(&flagsString, paint.isLinearText(), "LinearText"); - appendFlagToString(&flagsString, paint.isSubpixelText(), "SubpixelText"); - appendFlagToString(&flagsString, paint.isDevKernText(), "DevKernText"); - appendFlagToString(&flagsString, paint.isLCDRenderText(), "LCDRenderText"); - appendFlagToString(&flagsString, paint.isEmbeddedBitmapText(), "EmbeddedBitmapText"); - appendFlagToString(&flagsString, paint.isAutohinted(), "Autohinted"); - appendFlagToString(&flagsString, paint.isVerticalText(), "VerticalText"); - appendFlagToString(&flagsString, paint.getFlags() & SkPaint::kGenA8FromLCD_Flag, "GenA8FromLCD"); - return flagsString; -} - -String LoggingCanvas::filterLevelName(SkPaint::FilterLevel filterLevel) -{ - switch (filterLevel) { - case SkPaint::kNone_FilterLevel: return "None"; - case SkPaint::kLow_FilterLevel: return "Low"; - case SkPaint::kMedium_FilterLevel: return "Medium"; - case SkPaint::kHigh_FilterLevel: return "High"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::textAlignName(SkPaint::Align align) -{ - switch (align) { - case SkPaint::kLeft_Align: return "Left"; - case SkPaint::kCenter_Align: return "Center"; - case SkPaint::kRight_Align: return "Right"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::strokeCapName(SkPaint::Cap cap) -{ - switch (cap) { - case SkPaint::kButt_Cap: return "Butt"; - case SkPaint::kRound_Cap: return "Round"; - case SkPaint::kSquare_Cap: return "Square"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::strokeJoinName(SkPaint::Join join) -{ - switch (join) { - case SkPaint::kMiter_Join: return "Miter"; - case SkPaint::kRound_Join: return "Round"; - case SkPaint::kBevel_Join: return "Bevel"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::styleName(SkPaint::Style style) -{ - switch (style) { - case SkPaint::kFill_Style: return "Fill"; - case SkPaint::kStroke_Style: return "Stroke"; - case SkPaint::kStrokeAndFill_Style: return "StrokeAndFill"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::textEncodingName(SkPaint::TextEncoding encoding) -{ - switch (encoding) { - case SkPaint::kUTF8_TextEncoding: return "UTF-8"; - case SkPaint::kUTF16_TextEncoding: return "UTF-16"; - case SkPaint::kUTF32_TextEncoding: return "UTF-32"; - case SkPaint::kGlyphID_TextEncoding: return "GlyphID"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -String LoggingCanvas::hintingName(SkPaint::Hinting hinting) -{ - switch (hinting) { - case SkPaint::kNo_Hinting: return "None"; - case SkPaint::kSlight_Hinting: return "Slight"; - case SkPaint::kNormal_Hinting: return "Normal"; - case SkPaint::kFull_Hinting: return "Full"; - default: - ASSERT_NOT_REACHED(); - return "?"; - }; -} - -PassRefPtr<JSONObject> LoggingCanvas::objectForSkPaint(const SkPaint& paint) -{ - RefPtr<JSONObject> paintItem = JSONObject::create(); - paintItem->setNumber("textSize", paint.getTextSize()); - paintItem->setNumber("textScaleX", paint.getTextScaleX()); - paintItem->setNumber("textSkewX", paint.getTextSkewX()); - if (SkShader* shader = paint.getShader()) - paintItem->setObject("shader", objectForSkShader(*shader)); - paintItem->setString("color", stringForSkColor(paint.getColor())); - paintItem->setNumber("strokeWidth", paint.getStrokeWidth()); - paintItem->setNumber("strokeMiter", paint.getStrokeMiter()); - paintItem->setString("flags", stringForSkPaintFlags(paint)); - paintItem->setString("filterLevel", filterLevelName(paint.getFilterLevel())); - paintItem->setString("textAlign", textAlignName(paint.getTextAlign())); - paintItem->setString("strokeCap", strokeCapName(paint.getStrokeCap())); - paintItem->setString("strokeJoin", strokeJoinName(paint.getStrokeJoin())); - paintItem->setString("styleName", styleName(paint.getStyle())); - paintItem->setString("textEncoding", textEncodingName(paint.getTextEncoding())); - paintItem->setString("hinting", hintingName(paint.getHinting())); - return paintItem.release(); -} - -PassRefPtr<JSONArray> LoggingCanvas::arrayForSkMatrix(const SkMatrix& matrix) -{ - RefPtr<JSONArray> matrixArray = JSONArray::create(); - for (int i = 0; i < 9; ++i) - matrixArray->pushNumber(matrix[i]); - return matrixArray.release(); -} - -PassRefPtr<JSONArray> LoggingCanvas::arrayForSkScalars(size_t n, const SkScalar scalars[]) -{ - RefPtr<JSONArray> scalarsArray = JSONArray::create(); - for (size_t i = 0; i < n; ++i) - scalarsArray->pushNumber(scalars[i]); - return scalarsArray.release(); -} - -String LoggingCanvas::regionOpName(SkRegion::Op op) -{ - switch (op) { - case SkRegion::kDifference_Op: return "kDifference_Op"; - case SkRegion::kIntersect_Op: return "kIntersect_Op"; - case SkRegion::kUnion_Op: return "kUnion_Op"; - case SkRegion::kXOR_Op: return "kXOR_Op"; - case SkRegion::kReverseDifference_Op: return "kReverseDifference_Op"; - case SkRegion::kReplace_Op: return "kReplace_Op"; - default: return "Unknown type"; - }; -} - -String LoggingCanvas::saveFlagsToString(SkCanvas::SaveFlags flags) -{ - String flagsString = ""; - if (flags & SkCanvas::kHasAlphaLayer_SaveFlag) - flagsString.append("kHasAlphaLayer_SaveFlag "); - if (flags & SkCanvas::kFullColorLayer_SaveFlag) - flagsString.append("kFullColorLayer_SaveFlag "); - if (flags & SkCanvas::kClipToLayer_SaveFlag) - flagsString.append("kClipToLayer_SaveFlag "); - return flagsString; -} - -String LoggingCanvas::textEncodingCanonicalName(SkPaint::TextEncoding encoding) -{ - String name = textEncodingName(encoding); - if (encoding == SkPaint::kUTF16_TextEncoding || encoding == SkPaint::kUTF32_TextEncoding) - name.append("LE"); - return name; -} - -String LoggingCanvas::stringForUTFText(const void* text, size_t length, SkPaint::TextEncoding encoding) -{ - return WTF::TextEncoding(textEncodingCanonicalName(encoding)).decode((const char*)text, length); -} - -String LoggingCanvas::stringForText(const void* text, size_t byteLength, const SkPaint& paint) -{ - SkPaint::TextEncoding encoding = paint.getTextEncoding(); - switch (encoding) { - case SkPaint::kUTF8_TextEncoding: - case SkPaint::kUTF16_TextEncoding: - case SkPaint::kUTF32_TextEncoding: - return stringForUTFText(text, byteLength, encoding); - case SkPaint::kGlyphID_TextEncoding: { - WTF::Vector<SkUnichar> dataVector(byteLength / 2); - SkUnichar* textData = dataVector.data(); - paint.glyphsToUnichars(static_cast<const uint16_t*>(text), byteLength / 2, textData); - return WTF::UTF32LittleEndianEncoding().decode(reinterpret_cast<const char*>(textData), byteLength * 2); - } - default: - ASSERT_NOT_REACHED(); - return "?"; - } -} - -} // namespace blink
diff --git a/sky/engine/platform/graphics/LoggingCanvas.h b/sky/engine/platform/graphics/LoggingCanvas.h deleted file mode 100644 index 6abb7a3..0000000 --- a/sky/engine/platform/graphics/LoggingCanvas.h +++ /dev/null
@@ -1,135 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SKY_ENGINE_PLATFORM_GRAPHICS_LOGGINGCANVAS_H_ -#define SKY_ENGINE_PLATFORM_GRAPHICS_LOGGINGCANVAS_H_ - -#include "sky/engine/platform/JSONValues.h" -#include "sky/engine/platform/graphics/InterceptingCanvas.h" - -namespace blink { - -class LoggingCanvas : public InterceptingCanvas { -public: - LoggingCanvas(int width, int height); - PassRefPtr<JSONArray> log(); - - virtual void drawPaint(const SkPaint&) override; - virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; - virtual void drawRect(const SkRect&, const SkPaint&) override; - virtual void drawOval(const SkRect&, const SkPaint&) override; - virtual void drawRRect(const SkRRect&, const SkPaint&) override; - virtual void drawPath(const SkPath&, const SkPaint&) override; - virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint* = 0) override; - virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags) override; - virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - virtual void drawSprite(const SkBitmap&, int left, int top, const SkPaint* = 0) override; - virtual void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint&) override; - virtual void drawData(const void* data, size_t length) override; - virtual void beginCommentGroup(const char* description) override; - virtual void addComment(const char* keyword, const char* value) override; - virtual void endCommentGroup() override; - - virtual void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&) override; - virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint&) override; - virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint&) override; - virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint&) override; - virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*, const SkPaint&) override; - virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipRegion(const SkRegion&, SkRegion::Op) override; - virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); - virtual void didSetMatrix(const SkMatrix&) override; - virtual void didConcat(const SkMatrix&) override; - virtual void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint*, SaveFlags) override; - virtual void willRestore() override; - -private: - RefPtr<JSONArray> m_log; - friend class AutoLogger; - - struct VerbParams { - String name; - unsigned pointCount; - unsigned pointOffset; - - VerbParams(const String& name, unsigned pointCount, unsigned pointOffset) - : name(name) - , pointCount(pointCount) - , pointOffset(pointOffset) { } - }; - - PassRefPtr<JSONObject> addItem(const String& name); - PassRefPtr<JSONObject> addItemWithParams(const String& name); - PassRefPtr<JSONObject> objectForSkRect(const SkRect&); - PassRefPtr<JSONObject> objectForSkIRect(const SkIRect&); - String pointModeName(PointMode); - PassRefPtr<JSONObject> objectForSkPoint(const SkPoint&); - PassRefPtr<JSONArray> arrayForSkPoints(size_t count, const SkPoint points[]); - PassRefPtr<JSONObject> objectForSkPicture(const SkPicture&); - PassRefPtr<JSONObject> objectForRadius(const SkRRect& rrect, SkRRect::Corner); - String rrectTypeName(SkRRect::Type); - String radiusName(SkRRect::Corner); - PassRefPtr<JSONObject> objectForSkRRect(const SkRRect&); - String fillTypeName(SkPath::FillType); - String convexityName(SkPath::Convexity); - String verbName(SkPath::Verb); - VerbParams segmentParams(SkPath::Verb); - PassRefPtr<JSONObject> objectForSkPath(const SkPath&); - String colorTypeName(SkColorType); - PassRefPtr<JSONObject> objectForBitmapData(const SkBitmap&); - PassRefPtr<JSONObject> objectForSkBitmap(const SkBitmap&); - PassRefPtr<JSONObject> objectForSkShader(const SkShader&); - String stringForSkColor(const SkColor&); - void appendFlagToString(String* flagsString, bool isSet, const String& name); - String stringForSkPaintFlags(const SkPaint&); - String filterLevelName(SkPaint::FilterLevel); - String textAlignName(SkPaint::Align); - String strokeCapName(SkPaint::Cap); - String strokeJoinName(SkPaint::Join); - String styleName(SkPaint::Style); - String textEncodingName(SkPaint::TextEncoding); - String hintingName(SkPaint::Hinting); - PassRefPtr<JSONObject> objectForSkPaint(const SkPaint&); - PassRefPtr<JSONArray> arrayForSkMatrix(const SkMatrix&); - PassRefPtr<JSONArray> arrayForSkScalars(size_t n, const SkScalar scalars[]); - String regionOpName(SkRegion::Op); - String saveFlagsToString(SkCanvas::SaveFlags); - String textEncodingCanonicalName(SkPaint::TextEncoding); - String stringForUTFText(const void* text, size_t length, SkPaint::TextEncoding); - String stringForText(const void* text, size_t byteLength, const SkPaint&); -}; - -} // namespace blink - -#endif // SKY_ENGINE_PLATFORM_GRAPHICS_LOGGINGCANVAS_H_
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.cpp b/sky/engine/platform/graphics/ProfilingCanvas.cpp deleted file mode 100644 index 728a5c0..0000000 --- a/sky/engine/platform/graphics/ProfilingCanvas.cpp +++ /dev/null
@@ -1,254 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sky/engine/config.h" -#include "sky/engine/platform/graphics/ProfilingCanvas.h" - -#include "sky/engine/wtf/CurrentTime.h" - -namespace blink { - -class AutoStamper { -public: - explicit AutoStamper(ProfilingCanvas*); - ~AutoStamper(); - -private: - ProfilingCanvas* m_profilingCanvas; - double m_startTime; -}; - -AutoStamper::AutoStamper(ProfilingCanvas* profilingCanvas) : m_profilingCanvas(profilingCanvas) -{ - profilingCanvas->m_depthCount++; - m_startTime = WTF::monotonicallyIncreasingTime(); -} - -AutoStamper::~AutoStamper() -{ - m_profilingCanvas->m_depthCount--; - if (m_profilingCanvas->m_depthCount) - return; - double delta = WTF::monotonicallyIncreasingTime() - m_startTime; - m_profilingCanvas->m_timings->append(delta); -} - -ProfilingCanvas::ProfilingCanvas(SkBitmap bitmap) : InterceptingCanvas(bitmap) -{ -} - -void ProfilingCanvas::setTimings(Vector<double>* timings) -{ - m_timings = timings; -} - -void ProfilingCanvas::drawPaint(const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawPaint(paint); -} - -void ProfilingCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawPoints(mode, count, pts, paint); -} - -void ProfilingCanvas::drawRect(const SkRect& rect, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawRect(rect, paint); -} - -void ProfilingCanvas::drawOval(const SkRect& rect, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawOval(rect, paint); -} - -void ProfilingCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawRRect(rrect, paint); -} - -void ProfilingCanvas::drawPath(const SkPath& path, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawPath(path, paint); -} - -void ProfilingCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawBitmap(bitmap, left, top, paint); -} - -void ProfilingCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, - const SkPaint* paint, DrawBitmapRectFlags flags) -{ - AutoStamper stamper(this); - this->SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags); -} - -void ProfilingCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawBitmapNine(bitmap, center, dst, paint); -} - -void ProfilingCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawSprite(bitmap, left, top, paint); -} - -void ProfilingCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, indexCount, paint); -} - -void ProfilingCanvas::drawData(const void* data, size_t length) -{ - AutoStamper stamper(this); - this->SkCanvas::drawData(data, length); -} - -void ProfilingCanvas::beginCommentGroup(const char* description) -{ - AutoStamper stamper(this); - this->SkCanvas::beginCommentGroup(description); -} - -void ProfilingCanvas::addComment(const char* keyword, const char* value) -{ - AutoStamper stamper(this); - this->SkCanvas::addComment(keyword, value); -} - -void ProfilingCanvas::endCommentGroup() -{ - AutoStamper stamper(this); - this->SkCanvas::endCommentGroup(); -} - -void ProfilingCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::onDrawDRRect(outer, inner, paint); -} - -void ProfilingCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::onDrawText(text, byteLength, x, y, paint); -} - -void ProfilingCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::onDrawPosText(text, byteLength, pos, paint); -} - -void ProfilingCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint); -} - -void ProfilingCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) -{ - AutoStamper stamper(this); - this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint); -} - -void ProfilingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) -{ - AutoStamper stamper(this); - this->SkCanvas::onClipRect(rect, op, edgeStyle); -} - -void ProfilingCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) -{ - AutoStamper stamper(this); - this->SkCanvas::onClipRRect(rrect, op, edgeStyle); -} - -void ProfilingCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) -{ - AutoStamper stamper(this); - this->SkCanvas::onClipPath(path, op, edgeStyle); -} - -void ProfilingCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) -{ - AutoStamper stamper(this); - this->SkCanvas::onClipRegion(region, op); -} - -void ProfilingCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) -{ - AutoStamper stamper(this); - this->SkCanvas::onDrawPicture(picture, matrix, paint); -} - -void ProfilingCanvas::didSetMatrix(const SkMatrix& matrix) -{ - AutoStamper stamper(this); - this->SkCanvas::didSetMatrix(matrix); -} - -void ProfilingCanvas::didConcat(const SkMatrix& matrix) -{ - AutoStamper stamper(this); - this->SkCanvas::didConcat(matrix); -} - -void ProfilingCanvas::willSave() -{ - AutoStamper stamper(this); - this->SkCanvas::willSave(); -} - -SkCanvas::SaveLayerStrategy ProfilingCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) -{ - AutoStamper stamper(this); - return this->SkCanvas::willSaveLayer(bounds, paint, flags); -} - -void ProfilingCanvas::willRestore() -{ - AutoStamper stamper(this); - this->SkCanvas::willRestore(); -} - -} // namespace blink
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.h b/sky/engine/platform/graphics/ProfilingCanvas.h deleted file mode 100644 index 4ec11f2..0000000 --- a/sky/engine/platform/graphics/ProfilingCanvas.h +++ /dev/null
@@ -1,84 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SKY_ENGINE_PLATFORM_GRAPHICS_PROFILINGCANVAS_H_ -#define SKY_ENGINE_PLATFORM_GRAPHICS_PROFILINGCANVAS_H_ - -#include "sky/engine/platform/graphics/InterceptingCanvas.h" -#include "sky/engine/wtf/Vector.h" - -namespace blink { - -class ProfilingCanvas : public InterceptingCanvas { -public: - ProfilingCanvas(SkBitmap); - void setTimings(Vector<double>*); - - virtual void drawPaint(const SkPaint&) override; - virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; - virtual void drawRect(const SkRect&, const SkPaint&) override; - virtual void drawOval(const SkRect&, const SkPaint&) override; - virtual void drawRRect(const SkRRect&, const SkPaint&) override; - virtual void drawPath(const SkPath&, const SkPaint&) override; - virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint* = 0) override; - virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags) override; - virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - virtual void drawSprite(const SkBitmap&, int left, int top, const SkPaint* = 0) override; - virtual void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint&) override; - virtual void drawData(const void* data, size_t length) override; - virtual void beginCommentGroup(const char* description) override; - virtual void addComment(const char* keyword, const char* value) override; - virtual void endCommentGroup() override; - - virtual void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&) override; - virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint&) override; - virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint&) override; - virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint&) override; - virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*, const SkPaint&) override; - virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipRegion(const SkRegion&, SkRegion::Op) override; - virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); - virtual void didSetMatrix(const SkMatrix&) override; - virtual void didConcat(const SkMatrix&) override; - virtual void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint*, SaveFlags) override; - virtual void willRestore() override; - -private: - Vector<double>* m_timings; - friend class AutoStamper; -}; - -} // namespace blink - -#endif // SKY_ENGINE_PLATFORM_GRAPHICS_PROFILINGCANVAS_H_
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.cpp b/sky/engine/platform/graphics/ReplayingCanvas.cpp deleted file mode 100644 index dbb2d19..0000000 --- a/sky/engine/platform/graphics/ReplayingCanvas.cpp +++ /dev/null
@@ -1,273 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "sky/engine/config.h" -#include "sky/engine/platform/graphics/ReplayingCanvas.h" - -#include "third_party/skia/include/core/SkBitmapDevice.h" - -namespace blink { - -class AutoReplayer { -public: - explicit AutoReplayer(ReplayingCanvas*); - ~AutoReplayer(); - -private: - ReplayingCanvas* m_canvas; -}; - -AutoReplayer::AutoReplayer(ReplayingCanvas* replayingCanvas) : m_canvas(replayingCanvas) -{ - replayingCanvas->m_depthCount++; -} - -AutoReplayer::~AutoReplayer() -{ - m_canvas->m_depthCount--; - if (m_canvas->m_depthCount) - return; - m_canvas->m_stepCount++; - m_canvas->updateInRange(); -} - -ReplayingCanvas::ReplayingCanvas(SkBitmap bitmap, unsigned fromStep, unsigned toStep) - : InterceptingCanvas(bitmap), m_fromStep(fromStep), m_toStep(toStep), m_stepCount(0), m_abortDrawing(false) -{ -} - -void ReplayingCanvas::resetStepCount() -{ - m_stepCount = 0; -} - -void ReplayingCanvas::updateInRange() -{ - if (m_abortDrawing) - return; - if (m_toStep && m_stepCount > m_toStep) - m_abortDrawing = true; - if (m_stepCount == m_fromStep) - this->SkCanvas::clear(SkColorSetARGB(255, 255, 255, 255)); // FIXME: fill with nine patch instead. -} - -bool ReplayingCanvas::abortDrawing() -{ - return m_abortDrawing; -} - -void ReplayingCanvas::drawPaint(const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawPaint(paint); -} - -void ReplayingCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawPoints(mode, count, pts, paint); -} - -void ReplayingCanvas::drawRect(const SkRect& rect, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawRect(rect, paint); -} - -void ReplayingCanvas::drawOval(const SkRect& rect, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawOval(rect, paint); -} - -void ReplayingCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawRRect(rrect, paint); -} - -void ReplayingCanvas::drawPath(const SkPath& path, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawPath(path, paint); -} - -void ReplayingCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawBitmap(bitmap, left, top, paint); -} - -void ReplayingCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, - const SkPaint* paint, DrawBitmapRectFlags flags) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags); -} - -void ReplayingCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawBitmapNine(bitmap, center, dst, paint); -} - -void ReplayingCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawSprite(bitmap, left, top, paint); -} - -void ReplayingCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, indexCount, paint); -} - -void ReplayingCanvas::drawData(const void* data, size_t length) -{ - AutoReplayer replayer(this); - this->SkCanvas::drawData(data, length); -} - -void ReplayingCanvas::beginCommentGroup(const char* description) -{ - AutoReplayer replayer(this); - this->SkCanvas::beginCommentGroup(description); -} - -void ReplayingCanvas::addComment(const char* keyword, const char* value) -{ - AutoReplayer replayer(this); - this->SkCanvas::addComment(keyword, value); -} - -void ReplayingCanvas::endCommentGroup() -{ - AutoReplayer replayer(this); - this->SkCanvas::endCommentGroup(); -} - -void ReplayingCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::onDrawDRRect(outer, inner, paint); -} - -void ReplayingCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::onDrawText(text, byteLength, x, y, paint); -} - -void ReplayingCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::onDrawPosText(text, byteLength, pos, paint); -} - -void ReplayingCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint); -} - -void ReplayingCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint); -} - -void ReplayingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) -{ - AutoReplayer replayer(this); - this->SkCanvas::onClipRect(rect, op, edgeStyle); -} - -void ReplayingCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) -{ - AutoReplayer replayer(this); - this->SkCanvas::onClipRRect(rrect, op, edgeStyle); -} - -void ReplayingCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) -{ - AutoReplayer replayer(this); - this->SkCanvas::onClipPath(path, op, edgeStyle); -} - -void ReplayingCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) -{ - AutoReplayer replayer(this); - this->SkCanvas::onClipRegion(region, op); -} - -void ReplayingCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) -{ - AutoReplayer replayer(this); - this->SkCanvas::onDrawPicture(picture, matrix, paint); -} - -void ReplayingCanvas::didSetMatrix(const SkMatrix& matrix) -{ - AutoReplayer replayer(this); - this->SkCanvas::didSetMatrix(matrix); -} - -void ReplayingCanvas::didConcat(const SkMatrix& matrix) -{ - AutoReplayer replayer(this); - this->SkCanvas::didConcat(matrix); -} - -void ReplayingCanvas::willSave() -{ - AutoReplayer replayer(this); - this->SkCanvas::willSave(); -} - -SkCanvas::SaveLayerStrategy ReplayingCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) -{ - AutoReplayer replayer(this); - // We're about to create a layer and we have not cleared the device yet. - // Let's clear now, so it has effect on all layers. - if (m_stepCount < m_fromStep) - this->SkCanvas::clear(SkColorSetARGB(255, 255, 255, 255)); // FIXME: fill with nine patch instead. - - return this->SkCanvas::willSaveLayer(bounds, paint, flags); -} - -void ReplayingCanvas::willRestore() -{ - AutoReplayer replayer(this); - this->SkCanvas::willRestore(); -} - -} // namespace blink
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.h b/sky/engine/platform/graphics/ReplayingCanvas.h deleted file mode 100644 index 3f977d5..0000000 --- a/sky/engine/platform/graphics/ReplayingCanvas.h +++ /dev/null
@@ -1,91 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SKY_ENGINE_PLATFORM_GRAPHICS_REPLAYINGCANVAS_H_ -#define SKY_ENGINE_PLATFORM_GRAPHICS_REPLAYINGCANVAS_H_ - -#include "sky/engine/platform/graphics/InterceptingCanvas.h" -#include "third_party/skia/include/core/SkDrawPictureCallback.h" -#include "third_party/skia/include/core/SkPictureRecorder.h" - -namespace blink { - -class ReplayingCanvas : public InterceptingCanvas, public SkDrawPictureCallback { -public: - ReplayingCanvas(SkBitmap, unsigned fromStep, unsigned toStep); - void resetStepCount(); - - virtual bool abortDrawing() override; - - virtual void drawPaint(const SkPaint&) override; - virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; - virtual void drawRect(const SkRect&, const SkPaint&) override; - virtual void drawOval(const SkRect&, const SkPaint&) override; - virtual void drawRRect(const SkRRect&, const SkPaint&) override; - virtual void drawPath(const SkPath&, const SkPaint&) override; - virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint* = 0) override; - virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags) override; - virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override; - virtual void drawSprite(const SkBitmap&, int left, int top, const SkPaint* = 0) override; - virtual void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], - const SkColor colors[], SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint&) override; - virtual void drawData(const void* data, size_t length) override; - virtual void beginCommentGroup(const char* description) override; - virtual void addComment(const char* keyword, const char* value) override; - virtual void endCommentGroup() override; - - virtual void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&) override; - virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint&) override; - virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint&) override; - virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint&) override; - virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*, const SkPaint&) override; - virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - virtual void onClipRegion(const SkRegion&, SkRegion::Op) override; - virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); - virtual void didSetMatrix(const SkMatrix&) override; - virtual void didConcat(const SkMatrix&) override; - virtual void willSave() override; - SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint*, SaveFlags) override; - virtual void willRestore() override; - -private: - unsigned m_fromStep; - unsigned m_toStep; - unsigned m_stepCount; - bool m_abortDrawing; - void updateInRange(); - friend class AutoReplayer; -}; - -} // namespace blink - -#endif // SKY_ENGINE_PLATFORM_GRAPHICS_REPLAYINGCANVAS_H_
diff --git a/testing/android/java/AndroidManifest.xml b/testing/android/java/AndroidManifest.xml index a561f0c..93dd71b 100644 --- a/testing/android/java/AndroidManifest.xml +++ b/testing/android/java/AndroidManifest.xml
@@ -24,7 +24,7 @@ </activity> </application> - <instrumentation android:name="org.chromium.native_test.ChromiumNativeTestInstrumentationTestRunner" + <instrumentation android:name="org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner" android:targetPackage="org.chromium.native_test" android:label="Instrumentation entry point for org.chromium.native_test"/>
diff --git a/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java similarity index 97% rename from testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java rename to testing/android/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java index 8fe5d6c..a5cf485 100644 --- a/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java +++ b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestInstrumentationTestRunner.java
@@ -26,9 +26,9 @@ /** * An Instrumentation that runs tests based on ChromeNativeTestActivity. */ -public class ChromiumNativeTestInstrumentationTestRunner extends Instrumentation { +public class ChromeNativeTestInstrumentationTestRunner extends Instrumentation { - private static final String TAG = "ChromiumNativeTestInstrumentationTestRunner"; + private static final String TAG = "ChromeNativeTestInstrumentationTestRunner"; private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]*) .*"); private static interface ResultsBundleGenerator {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 62ecaa0..3e0535e 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -89,7 +89,8 @@ "athena_unittests", "app_shell_browsertests", "app_shell_unittests", - "chromevox_tests" + "chromevox_tests", + "skia_unittests" ] }, "Linux ChromiumOS Ozone Tests (1)": { @@ -149,6 +150,7 @@ "test": "sandbox_linux_unittests", "args": ["--test-launcher-print-test-stdio=always"] }, + "skia_unittests", "sql_unittests", "sync_unit_tests", "ui_base_unittests", @@ -250,6 +252,7 @@ }, "athena_unittests", "gcm_unit_tests", + "skia_unittests", { "test": "interactive_ui_tests", "swarming": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 0db9d9c..68fb55b 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -32,6 +32,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "ui_base_unittests", "ui_touch_selection_unittests", "ipc_tests", @@ -98,6 +99,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "ui_base_unittests", "ui_touch_selection_unittests", "ipc_tests", @@ -164,6 +166,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "ui_base_unittests", "ui_touch_selection_unittests", "ipc_tests", @@ -230,6 +233,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "ui_base_unittests", "ui_touch_selection_unittests", "ipc_tests", @@ -305,6 +309,7 @@ "printing_unittests", "remoting_unittests", "sandbox_mac_unittests", + "skia_unittests", "sql_unittests", "sync_integration_tests", "sync_unit_tests",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 7e97897..3c05ad7 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -122,7 +122,8 @@ }, "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ { @@ -262,7 +263,8 @@ }, "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ { @@ -398,7 +400,8 @@ }, "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ { @@ -440,7 +443,8 @@ "sql_unittests", "sync_unit_tests", "ui_base_unittests", - "unit_tests" + "unit_tests", + "skia_unittests" ] } }
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json index c74cd86..cfc0a2a 100644 --- a/testing/buildbot/chromium.mac.json +++ b/testing/buildbot/chromium.mac.json
@@ -105,7 +105,8 @@ "can_use_on_swarming_builders": true } }, - "url_unittests" + "url_unittests", + "skia_unittests" ], "scripts": [ { @@ -228,7 +229,8 @@ "can_use_on_swarming_builders": true } }, - "url_unittests" + "url_unittests", + "skia_unittests" ], "scripts": [ { @@ -351,7 +353,8 @@ "can_use_on_swarming_builders": true } }, - "url_unittests" + "url_unittests", + "skia_unittests" ], "scripts": [ { @@ -475,7 +478,8 @@ "can_use_on_swarming_builders": true } }, - "url_unittests" + "url_unittests", + "skia_unittests" ], "scripts": [ {
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json index 3852f7a..04b74f6 100644 --- a/testing/buildbot/chromium.memory.fyi.json +++ b/testing/buildbot/chromium.memory.fyi.json
@@ -40,6 +40,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "sql_unittests", "sync_unit_tests", "ui_base_unittests", @@ -106,6 +107,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "sql_unittests", "sync_unit_tests", "ui_base_unittests",
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 40583de..296c0a7 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -60,6 +60,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "sql_unittests", "sync_unit_tests", "ui_base_unittests", @@ -209,6 +210,7 @@ "ppapi_unittests", "printing_unittests", "remoting_unittests", + "skia_unittests", "sql_unittests", "sync_unit_tests", "ui_base_unittests", @@ -294,6 +296,7 @@ "printing_unittests", "remoting_unittests", "sandbox_linux_unittests", + "skia_unittests", "sql_unittests", "sync_unit_tests", {
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json index 145df59..47f4c49 100644 --- a/testing/buildbot/chromium.webkit.json +++ b/testing/buildbot/chromium.webkit.json
@@ -86,7 +86,8 @@ "athena_unittests", "app_shell_browsertests", "app_shell_unittests", - "chromevox_tests" + "chromevox_tests", + "skia_unittests" ] }, "Linux ChromiumOS Tests (2)": { @@ -174,6 +175,7 @@ }, "athena_unittests", "gcm_unit_tests", + "skia_unittests", { "test": "interactive_ui_tests", "swarming": {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index c7ae0d4..a138a36 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -86,7 +86,8 @@ "ui_touch_selection_unittests", "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ { @@ -196,7 +197,8 @@ "ui_touch_selection_unittests", "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ { @@ -314,7 +316,8 @@ }, "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ { @@ -436,7 +439,8 @@ }, "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ { @@ -552,7 +556,8 @@ }, "url_unittests", "views_unittests", - "wm_unittests" + "wm_unittests", + "skia_unittests" ], "scripts": [ {
diff --git a/testing/buildbot/chromium_memory_trybot.json b/testing/buildbot/chromium_memory_trybot.json index 357735f..2b8564e 100644 --- a/testing/buildbot/chromium_memory_trybot.json +++ b/testing/buildbot/chromium_memory_trybot.json
@@ -63,6 +63,7 @@ "test": "sandbox_linux_unittests", "platforms": ["linux"] }, + "skia_unittests", "sql_unittests", "sync_unit_tests", "ui_base_unittests",
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json index edfcad2..cdf0ea1 100644 --- a/testing/buildbot/chromium_trybot.json +++ b/testing/buildbot/chromium_trybot.json
@@ -211,6 +211,7 @@ ] }, "url_unittests", + "skia_unittests", { "test": "wm_unittests", "platforms": ["linux", "win"]
diff --git a/testing/chromoting/browser_test_commands_linux.txt b/testing/chromoting/browser_test_commands_linux.txt index ed8455b..2f5f2be 100644 --- a/testing/chromoting/browser_test_commands_linux.txt +++ b/testing/chromoting/browser_test_commands_linux.txt
@@ -3,5 +3,4 @@ /usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd /usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail /usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting -/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=20000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail /usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile \ No newline at end of file
diff --git a/testing/commit_queue/config.json b/testing/commit_queue/config.json index 2459757..3e39bf3 100644 --- a/testing/commit_queue/config.json +++ b/testing/commit_queue/config.json
@@ -79,8 +79,8 @@ "sync_unit_tests", "gfx_unittests" ], - "ios_rel_device": ["compile"], - "ios_rel_device_ninja": ["compile"] + "ios_rel_device_ng": ["defaulttests"], + "ios_rel_device_ninja_ng": ["defaulttests"] }, "tryserver.chromium.win": { "win_chromium_compile_dbg": ["defaulttests"],
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium index 4c5b3fc..73893d0 100644 --- a/third_party/qcms/README.chromium +++ b/third_party/qcms/README.chromium
@@ -41,5 +41,7 @@ - https://bugzilla.mozilla.org/show_bug.cgi?id=701348 - Add qcms_profile_match api - https://code.google.com/p/chromium/issues/detail?id=401971 + - Add qcms_profile_get_decription api + - https://code.google.com/p/chromium/issues/detail?id=401971 To regenerate google.patch: git diff b8456f38 src > google.patch
diff --git a/third_party/qcms/google.patch b/third_party/qcms/google.patch index 78dc928..ce60f9f 100644 --- a/third_party/qcms/google.patch +++ b/third_party/qcms/google.patch
@@ -1,5 +1,5 @@ diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c -index 36b7011..69b7141 100644 +index 36b7011..aca19d3 100644 --- a/third_party/qcms/src/iccread.c +++ b/third_party/qcms/src/iccread.c @@ -266,7 +266,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile) @@ -164,7 +164,7 @@ if (find_tag(index, TAG_CHAD)) { profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD); } else { -@@ -1098,6 +1162,11 @@ invalid_profile: +@@ -1098,6 +1162,16 @@ invalid_profile: return INVALID_PROFILE; } @@ -173,11 +173,16 @@ + return memcmp(p1->description, p2->description, sizeof p1->description) == 0; +} + ++const char* qcms_profile_get_description(qcms_profile *profile) ++{ ++ return profile->description; ++} ++ qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) { return profile->rendering_intent; diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h -index 7d83623..e59528a 100644 +index 7d83623..c69a772 100644 --- a/third_party/qcms/src/qcms.h +++ b/third_party/qcms/src/qcms.h @@ -40,6 +40,12 @@ sale, use or other dealings in this Software without written @@ -206,16 +211,17 @@ /* the names for the following two types are sort of ugly */ typedef struct { -@@ -136,6 +148,8 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile); +@@ -136,6 +148,9 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile); qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile); icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile); +qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2); ++const char* qcms_profile_get_description(qcms_profile *profile); + void qcms_profile_precache_output_transform(qcms_profile *profile); qcms_transform* qcms_transform_create( -@@ -146,6 +160,7 @@ qcms_transform* qcms_transform_create( +@@ -146,6 +161,7 @@ qcms_transform* qcms_transform_create( void qcms_transform_release(qcms_transform *); void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length);
diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c index 69b7141..aca19d3 100644 --- a/third_party/qcms/src/iccread.c +++ b/third_party/qcms/src/iccread.c
@@ -1167,6 +1167,11 @@ return memcmp(p1->description, p2->description, sizeof p1->description) == 0; } +const char* qcms_profile_get_description(qcms_profile *profile) +{ + return profile->description; +} + qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) { return profile->rendering_intent;
diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h index e59528a..c69a772 100644 --- a/third_party/qcms/src/qcms.h +++ b/third_party/qcms/src/qcms.h
@@ -149,6 +149,7 @@ icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile); qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2); +const char* qcms_profile_get_description(qcms_profile *profile); void qcms_profile_precache_output_transform(qcms_profile *profile);
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 172f969..8502b1c 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -24,7 +24,7 @@ # in bringup. Use a pinned revision to make it slightly more stable. if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and not 'LLVM_FORCE_HEAD_REVISION' in os.environ): - LLVM_WIN_REVISION = '217738' + LLVM_WIN_REVISION = '225621' # Path constants. (All of these should be absolute paths.) THIS_DIR = os.path.abspath(os.path.dirname(__file__))
diff --git a/tools/git/move_source_file.py b/tools/git/move_source_file.py index 2de0b5b..117b3eb 100755 --- a/tools/git/move_source_file.py +++ b/tools/git/move_source_file.py
@@ -50,6 +50,10 @@ raise Exception('Only intended to move individual source files ' '(%s does not have a recognized extension).' % from_path) + + # Remove '.', '..', etc. + to_path = os.path.normpath(to_path) + if os.path.isdir(to_path): to_path = os.path.join(to_path, os.path.basename(from_path)) else:
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py index eef3175..40ef7ba 100755 --- a/tools/valgrind/chrome_tests.py +++ b/tools/valgrind/chrome_tests.py
@@ -446,6 +446,9 @@ "--ui-test-action-timeout=60000", "--ui-test-action-max-timeout=150000"]) + def TestSkia(self): + return self.SimpleTest("skia", "skia_unittests") + def TestSql(self): return self.SimpleTest("chrome", "sql_unittests") @@ -706,6 +709,7 @@ "remoting": TestRemoting, "remoting_unittests": TestRemoting, "safe_browsing": TestSafeBrowsing, "safe_browsing_tests": TestSafeBrowsing, "sandbox": TestLinuxSandbox, "sandbox_linux_unittests": TestLinuxSandbox, + "skia": TestSkia, "skia_unittests": TestSkia, "sql": TestSql, "sql_unittests": TestSql, "sync": TestSync, "sync_unit_tests": TestSync, "sync_integration_tests": TestSyncIntegration,
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt index f2eccdf..2c5c454 100644 --- a/tools/valgrind/drmemory/suppressions.txt +++ b/tools/valgrind/drmemory/suppressions.txt
@@ -704,3 +704,8 @@ content.dll!base::internal::BindState<>::`scalar deleting destructor' base.dll!scoped_refptr<>::Release base.dll!base::internal::CallbackBase::~CallbackBase + +UNADDRESSABLE ACCESS +name=https://crbug.com/447788 +... +*!gpu::gles2::GLES2ImplementationTest_TexImage3DSingleCommand_Test::TestBody
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt index 2f315fa..f9d510a 100644 --- a/tools/valgrind/drmemory/suppressions_full.txt +++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1888,3 +1888,8 @@ *!ash::test::ShelfViewTestAPI::GetPreferredSize *!ash::test::ShelfViewTest_OverflowBubbleSize_Test::TestBody *!testing::internal::HandleExceptionsInMethodIfSupported<> + +UNINITIALIZED READ +name=bug_447788 +... +*!gpu::gles2::GLES2ImplementationTest_TexImage3DSingleCommand_Test::TestBody
diff --git a/tools/valgrind/gtest_exclude/components_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/components_unittests.gtest-drmemory_win32.txt deleted file mode 100644 index a8edd28..0000000 --- a/tools/valgrind/gtest_exclude/components_unittests.gtest-drmemory_win32.txt +++ /dev/null
@@ -1,3 +0,0 @@ -# http://crbug.com/435320 -MetricsServiceTest.InitialStabilityLogAfterCrash -MetricsServiceTest.InitialStabilityLogAtProviderRequest
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt index f2c5fef..0637422 100644 --- a/tools/valgrind/memcheck/suppressions.txt +++ b/tools/valgrind/memcheck/suppressions.txt
@@ -3524,3 +3524,9 @@ fun:avcodec_decode_* fun:avcodec_decode_* } +{ + bug_447788 + Memcheck:Unaddressable + ... + fun:_ZN3gpu5gles252GLES2ImplementationTest_TexImage3DSingleCommand_Test8TestBodyEv +}
diff --git a/ui/compositor/dip_util.cc b/ui/compositor/dip_util.cc index 4db8bcf..69a33a7 100644 --- a/ui/compositor/dip_util.cc +++ b/ui/compositor/dip_util.cc
@@ -18,7 +18,7 @@ #include "ui/gfx/size.h" #include "ui/gfx/size_conversions.h" -#if DCHECK_IS_ON +#if DCHECK_IS_ON() #include "ui/compositor/layer_animator.h" #endif @@ -76,7 +76,7 @@ gfx::ScaleSize(rect_in_dip.size(), scale))); } -#if DCHECK_IS_ON +#if DCHECK_IS_ON() namespace { void CheckSnapped(float snapped_position) { @@ -107,7 +107,7 @@ gfx::Vector2dF fudge = view_offset_snapped - view_offset; fudge.Scale(1.0 / scale_factor); layer_to_snap->SetSubpixelPositionOffset(fudge); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() gfx::Point layer_offset; gfx::PointF origin; Layer::ConvertPointToLayer(
diff --git a/ui/gfx/font_list_impl.cc b/ui/gfx/font_list_impl.cc index 8c00fcc..ec67832 100644 --- a/ui/gfx/font_list_impl.cc +++ b/ui/gfx/font_list_impl.cc
@@ -104,7 +104,7 @@ DCHECK(!fonts.empty()); font_style_ = fonts[0].GetStyle(); font_size_ = fonts[0].GetFontSize(); -#if DCHECK_IS_ON +#if DCHECK_IS_ON() for (size_t i = 1; i < fonts.size(); ++i) { DCHECK_EQ(fonts[i].GetStyle(), font_style_); DCHECK_EQ(fonts[i].GetFontSize(), font_size_);
diff --git a/ui/gl/gl_gl_api_implementation.cc b/ui/gl/gl_gl_api_implementation.cc index ab3e48c..3b8c534 100644 --- a/ui/gl/gl_gl_api_implementation.cc +++ b/ui/gl/gl_gl_api_implementation.cc
@@ -478,7 +478,7 @@ DCHECK(virtual_context->IsCurrent(surface)); if (switched_contexts || virtual_context != current_context_) { -#if DCHECK_IS_ON +#if DCHECK_IS_ON() GLenum error = glGetErrorFn(); // Accepting a context loss error here enables using debug mode to work on // context loss handling in virtual context mode.