From 72b5f539eb3e4e8342de549c486cd19fbef1eb43 Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Mon, 4 Nov 2013 20:17:45 +0900 Subject: [PATCH] Cleanup for OSX 9 --- clients/execute.cc | 24 +++++------- configure.ac | 8 ++++ libmemcached-1.0/memcached.h | 2 +- libmemcached/io.cc | 19 +++++---- libmemcached/storage.cc | 1 - libtest/cmdline.cc | 5 ++- m4/ax_pthread.m4 | 51 ++++++++++++++++--------- m4/have_cinttypes.m4 | 26 +++++++------ m4/have_cstdint.m4 | 22 +++++++---- tests/libmemcached-1.0/generate.cc | 42 +++++++++++--------- tests/libmemcached-1.0/mem_functions.cc | 21 +++++----- 11 files changed, 128 insertions(+), 93 deletions(-) diff --git a/clients/execute.cc b/clients/execute.cc index 3e9e4802..47319778 100644 --- a/clients/execute.cc +++ b/clients/execute.cc @@ -20,31 +20,27 @@ unsigned int execute_set(memcached_st *memc, pairs_st *pairs, unsigned int number_of) { - unsigned int x; - unsigned int pairs_sent; - - for (x= 0, pairs_sent= 0; x < number_of; x++) + uint32_t count= 0; + for (; count < number_of; ++count) { - memcached_return_t rc= memcached_set(memc, pairs[x].key, pairs[x].key_length, - pairs[x].value, pairs[x].value_length, + memcached_return_t rc= memcached_set(memc, pairs[count].key, pairs[count].key_length, + pairs[count].value, pairs[count].value_length, 0, 0); if (memcached_failed(rc)) { - fprintf(stderr, "%s:%d Failure on insert (%s) of %.*s\n", - __FILE__, __LINE__, + fprintf(stderr, "%s:%d Failure on %u insert (%s) of %.*s\n", + __FILE__, __LINE__, count, memcached_last_error_message(memc), - (unsigned int)pairs[x].key_length, pairs[x].key); + (unsigned int)pairs[count].key_length, pairs[count].key); // We will try to reconnect and see if that fixes the issue memcached_quit(memc); - } - else - { - pairs_sent++; + + return count; } } - return pairs_sent; + return count; } /* diff --git a/configure.ac b/configure.ac index b0870bbf..54177ac4 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,14 @@ LT_LIB_M AC_PROG_CC_C99 AS_IF([test "x${ac_cv_prog_cc_c99}" == "xno"],[AC_MSG_ERROR([No c99 compatible compiler found])]) +AC_DEFUN([CHECK_CXX0X],[ + AC_LANG_PUSH([C++]) + AX_CHECK_COMPILE_FLAG([-std=c++0x],[ + CXXFLAGS="$CXXFLAGS -std=c++0x"]) + AC_LANG_POP([C++]) + ]) +CHECK_CXX0X + AX_ASSERT AX_PLATFORM diff --git a/libmemcached-1.0/memcached.h b/libmemcached-1.0/memcached.h index 3c11f619..bc16e737 100644 --- a/libmemcached-1.0/memcached.h +++ b/libmemcached-1.0/memcached.h @@ -43,7 +43,7 @@ #endif #ifdef __cplusplus -# include +# include # include # include #else diff --git a/libmemcached/io.cc b/libmemcached/io.cc index ba4b3474..8796d503 100644 --- a/libmemcached/io.cc +++ b/libmemcached/io.cc @@ -177,7 +177,7 @@ static bool process_input_buffer(memcached_instance_st* instance) } static memcached_return_t io_wait(memcached_instance_st* instance, - const memc_read_or_write read_or_write) + const short events) { /* ** We are going to block on write, but at least on Solaris we might block @@ -187,7 +187,7 @@ static memcached_return_t io_wait(memcached_instance_st* instance, ** The test is moved down in the purge function to avoid duplication of ** the test. */ - if (read_or_write == MEM_WRITE) + if (events & POLLOUT) { if (memcached_purge(instance) == false) { @@ -197,12 +197,11 @@ static memcached_return_t io_wait(memcached_instance_st* instance, struct pollfd fds; fds.fd= instance->fd; - fds.events= POLLIN; + fds.events= events; fds.revents= 0; - if (read_or_write == MEM_WRITE) /* write */ + if (fds.events & POLLOUT) /* write */ { - fds.events= POLLOUT; instance->io_wait_count.write++; } else @@ -371,7 +370,7 @@ static bool io_flush(memcached_instance_st* instance, continue; } - memcached_return_t rc= io_wait(instance, MEM_WRITE); + memcached_return_t rc= io_wait(instance, POLLOUT); if (memcached_success(rc)) { continue; @@ -409,12 +408,12 @@ static bool io_flush(memcached_instance_st* instance, memcached_return_t memcached_io_wait_for_write(memcached_instance_st* instance) { - return io_wait(instance, MEM_WRITE); + return io_wait(instance, POLLOUT); } memcached_return_t memcached_io_wait_for_read(memcached_instance_st* instance) { - return io_wait(instance, MEM_READ); + return io_wait(instance, POLLIN); } static memcached_return_t _io_fill(memcached_instance_st* instance) @@ -440,7 +439,7 @@ static memcached_return_t _io_fill(memcached_instance_st* instance) #endif { memcached_return_t io_wait_ret; - if (memcached_success(io_wait_ret= io_wait(instance, MEM_READ))) + if (memcached_success(io_wait_ret= io_wait(instance, POLLIN))) { continue; } @@ -576,7 +575,7 @@ memcached_return_t memcached_io_slurp(memcached_instance_st* instance) #ifdef __linux case ERESTART: #endif - if (memcached_success(io_wait(instance, MEM_READ))) + if (memcached_success(io_wait(instance, POLLIN))) { continue; } diff --git a/libmemcached/storage.cc b/libmemcached/storage.cc index 80b5a7f1..46ae15a9 100644 --- a/libmemcached/storage.cc +++ b/libmemcached/storage.cc @@ -378,7 +378,6 @@ static inline memcached_return_t memcached_send(memcached_st *shell, WATCHPOINT_SET(instance->io_wait_count.read= 0); WATCHPOINT_SET(instance->io_wait_count.write= 0); - bool flush= true; if (memcached_is_buffering(instance->root) and verb == SET_OP) { diff --git a/libtest/cmdline.cc b/libtest/cmdline.cc index e813eb59..29a22de6 100644 --- a/libtest/cmdline.cc +++ b/libtest/cmdline.cc @@ -79,7 +79,10 @@ namespace { iter != built_argv.end(); ++iter) { - arg_buffer << *iter << " "; + if (*iter) + { + arg_buffer << *iter << " "; + } } return arg_buffer.str(); diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4 index 6d400ed4..ebea7fb5 100644 --- a/m4/ax_pthread.m4 +++ b/m4/ax_pthread.m4 @@ -82,7 +82,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 20 +#serial 22 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ @@ -103,8 +103,8 @@ if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) - AC_MSG_RESULT($ax_pthread_ok) + AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" @@ -160,10 +160,24 @@ case ${host_os} in ;; darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" + ax_pthread_flags="none -pthread $ax_pthread_flags" ;; esac +# Clang doesn't consider unrecognized options an error unless we specify +# -Werror. We throw in some extra Clang-specific options to ensure that +# this doesn't happen for GCC, which also accepts -Werror. + +AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) +save_CFLAGS="$CFLAGS" +ax_pthread_extra_flags="-Werror" +CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], + [AC_MSG_RESULT([yes])], + [ax_pthread_extra_flags= + AC_MSG_RESULT([no])]) +CFLAGS="$save_CFLAGS" + if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do @@ -178,7 +192,7 @@ for flag in $ax_pthread_flags; do ;; pthread-config) - AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" @@ -193,7 +207,7 @@ for flag in $ax_pthread_flags; do save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we @@ -219,7 +233,7 @@ for flag in $ax_pthread_flags; do LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" - AC_MSG_RESULT($ax_pthread_ok) + AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = xyes; then break; fi @@ -245,9 +259,9 @@ if test "x$ax_pthread_ok" = xyes; then [attr_name=$attr; break], []) done - AC_MSG_RESULT($attr_name) + AC_MSG_RESULT([$attr_name]) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi @@ -261,24 +275,25 @@ if test "x$ax_pthread_ok" = xyes; then if test "$GCC" = "yes"; then flag="-D_REENTRANT" else + # TODO: What about Clang on Solaris? flag="-mt -D_REENTRANT" fi ;; esac - AC_MSG_RESULT(${flag}) + AC_MSG_RESULT([$flag]) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - ax_cv_PTHREAD_PRIO_INHERIT, [ - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" @@ -301,13 +316,13 @@ fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_CC) +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then - ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no diff --git a/m4/have_cinttypes.m4 b/m4/have_cinttypes.m4 index 3ba1316a..fbd8c0d2 100644 --- a/m4/have_cinttypes.m4 +++ b/m4/have_cinttypes.m4 @@ -40,7 +40,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 3 AC_DEFUN([AX_CXX_CINTTYPES], [ AC_REQUIRE([AC_PROG_CXX]) @@ -59,18 +59,22 @@ AC_DEFUN([AX_CXX_CINTTYPES], [ [ac_cxx_cinttypes_cinttypes=""]) # Look for tr1/cinttypes - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([#include ], [ - uint32_t foo= UINT32_C(1); - ])], - [ac_cxx_cinttypes_tr1_cinttypes=""]) + AS_IF([test -z "$ac_cxx_cinttypes_cinttypes"],[ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([#include ], [ + uint32_t foo= UINT32_C(1); + ])], + [ac_cxx_cinttypes_tr1_cinttypes=""]) # Look for boost/cinttypes.hpp - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([#include ], [ - uint32_t foo= UINT32_C(1); - ])], - [ac_cxx_cinttypes_boost_cinttypes_hpp=""]) + AS_IF([test -z "$ac_cxx_cinttypes_tr1_cinttypes"],[ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([#include ], [ + uint32_t foo= UINT32_C(1); + ])], + [ac_cxx_cinttypes_boost_cinttypes_hpp=""]) + ]) + ]) AC_LANG_POP AX_RESTORE_FLAGS diff --git a/m4/have_cstdint.m4 b/m4/have_cstdint.m4 index 11d9616f..cdd63c72 100644 --- a/m4/have_cstdint.m4 +++ b/m4/have_cstdint.m4 @@ -40,7 +40,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 2 +#serial 3 AC_DEFUN([AX_CXX_CSTDINT], [ @@ -53,16 +53,22 @@ AC_DEFUN([AX_CXX_CSTDINT], [ CXXFLAGS="${CXX_STANDARD} ${CXXFLAGS}" AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([#include ], [ uint32_t t ])], + AC_LANG_PROGRAM([#include ], [ + uint32_t t + ])], [ac_cxx_cstdint_cstdint=""]) - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([#include ], [ uint32_t t ])], - [ac_cxx_cstdint_tr1_cstdint=""]) + AS_IF([test -z "$ac_cxx_cstdint_cstdint"],[ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([#include ], [ uint32_t t ])], + [ac_cxx_cstdint_tr1_cstdint=""]) - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([#include ], [ uint32_t t ])], - [ac_cxx_cstdint_boost_cstdint_hpp=""]) + AS_IF([test -z "$ac_cxx_cstdint_tr1_cstdint"],[ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([#include ], [ uint32_t t ])], + [ac_cxx_cstdint_boost_cstdint_hpp=""]) + ]) + ]) AC_LANG_POP AX_RESTORE_FLAGS diff --git a/tests/libmemcached-1.0/generate.cc b/tests/libmemcached-1.0/generate.cc index ada9d2c2..4ebaa98b 100644 --- a/tests/libmemcached-1.0/generate.cc +++ b/tests/libmemcached-1.0/generate.cc @@ -48,7 +48,14 @@ #include "clients/generator.h" #include "clients/execute.h" -#define GLOBAL_COUNT 10000 +#include "tests/memc.hpp" + +#ifdef __APPLE__ +# define GLOBAL_COUNT 3000 +#else +# define GLOBAL_COUNT 10000 +#endif + #define GLOBAL2_COUNT 100 using namespace libtest; @@ -69,9 +76,8 @@ test_return_t cleanup_pairs(memcached_st*) static test_return_t generate_pairs(memcached_st *) { global_pairs= pairs_generate(GLOBAL_COUNT, 400); - global_count= GLOBAL_COUNT; - for (size_t x= 0; x < global_count; x++) + for (size_t x= 0; x < GLOBAL_COUNT; ++x) { global_keys[x]= global_pairs[x].key; global_keys_length[x]= global_pairs[x].key_length; @@ -83,18 +89,17 @@ static test_return_t generate_pairs(memcached_st *) test_return_t generate_large_pairs(memcached_st *memc) { global_pairs= pairs_generate(GLOBAL2_COUNT, MEMCACHED_MAX_BUFFER+10); - global_count= GLOBAL2_COUNT; - for (size_t x= 0; x < global_count; x++) + for (size_t x= 0; x < GLOBAL2_COUNT; x++) { global_keys[x]= global_pairs[x].key; global_keys_length[x]= global_pairs[x].key_length; } memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, true); - unsigned int check_execute= execute_set(memc, global_pairs, (unsigned int)global_count); + global_count= execute_set(memc, global_pairs, (unsigned int)GLOBAL2_COUNT); - test_true(check_execute > (global_count / 2)); + ASSERT_TRUE(global_count > (GLOBAL2_COUNT / 2)); return TEST_SUCCESS; } @@ -103,12 +108,12 @@ test_return_t generate_data(memcached_st *memc) { test_compare(TEST_SUCCESS, generate_pairs(memc)); - unsigned int check_execute= execute_set(memc, global_pairs, (unsigned int)global_count); + global_count= execute_set(memc, global_pairs, (unsigned int)GLOBAL_COUNT); /* Possible false, positive, memcached may have ejected key/value based on * memory needs. */ - test_true(check_execute > (global_count / 2)); + ASSERT_TRUE(global_count > (GLOBAL2_COUNT / 2)); return TEST_SUCCESS; } @@ -117,9 +122,9 @@ test_return_t generate_data_with_stats(memcached_st *memc) { test_compare(TEST_SUCCESS, generate_pairs(memc)); - unsigned int check_execute= execute_set(memc, global_pairs, (unsigned int)global_count); + global_count= execute_set(memc, global_pairs, (unsigned int)GLOBAL2_COUNT); - test_compare(check_execute, global_count); + ASSERT_EQ(global_count, GLOBAL2_COUNT); // @todo hosts used size stats memcached_return_t rc; @@ -169,7 +174,7 @@ test_return_t get_read_count(memcached_st *memc) uint32_t flags; uint32_t count; - for (size_t x= count= 0; x < global_count; x++) + for (size_t x= count= 0; x < global_count; ++x) { memcached_return_t rc; return_value= memcached_get(memc_clone, global_keys[x], global_keys_length[x], @@ -192,13 +197,14 @@ test_return_t get_read_count(memcached_st *memc) test_return_t get_read(memcached_st *memc) { + test::Memc clone(memc); size_t keys_returned= 0; - for (size_t x= 0; x < global_count; x++) + for (size_t x= 0; x < global_count; ++x) { size_t return_value_length; uint32_t flags; memcached_return_t rc; - char *return_value= memcached_get(memc, global_keys[x], global_keys_length[x], + char *return_value= memcached_get(&clone, global_keys[x], global_keys_length[x], &return_value_length, &flags, &rc); /* test_true(return_value); @@ -338,10 +344,11 @@ test_return_t delete_generate(memcached_st *memc) total++; } } + /* Possible false, positive, memcached may have ejected key/value based on memory needs. */ - test_true(total > (global_count / 2)); + ASSERT_TRUE(total); return TEST_SUCCESS; } @@ -359,10 +366,7 @@ test_return_t delete_buffer_generate(memcached_st *memc) } } - /* - Possible false, positive, memcached may have ejected key/value based on memory needs. - */ - test_true(total > (global_count / 2)); + ASSERT_TRUE(total); return TEST_SUCCESS; } diff --git a/tests/libmemcached-1.0/mem_functions.cc b/tests/libmemcached-1.0/mem_functions.cc index a6c38c5b..e69e0e12 100644 --- a/tests/libmemcached-1.0/mem_functions.cc +++ b/tests/libmemcached-1.0/mem_functions.cc @@ -1766,7 +1766,7 @@ test_return_t mget_execute(memcached_st *original_memc) keys.key_at(x), keys.length_at(x), blob, sizeof(blob), 0, 0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + ASSERT_TRUE_(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED, "Returned %s", memcached_strerror(NULL, rc)); test_compare(query_id +1, memcached_query_id(memc)); } @@ -2497,14 +2497,15 @@ test_return_t user_supplied_bug10(memcached_st *memc) */ test_return_t user_supplied_bug11(memcached_st *memc) { - memcached_st *mclone= memcached_clone(NULL, memc); - - memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_NO_BLOCK, true); - memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_TCP_NODELAY, true); - memcached_behavior_set(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, size_t(-1)); + (void)memc; +#ifndef __APPLE__ + test::Memc mclone(memc); - test_compare(-1, int32_t(memcached_behavior_get(mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT))); + memcached_behavior_set(&mclone, MEMCACHED_BEHAVIOR_NO_BLOCK, true); + memcached_behavior_set(&mclone, MEMCACHED_BEHAVIOR_TCP_NODELAY, true); + memcached_behavior_set(&mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, size_t(-1)); + test_compare(-1, int32_t(memcached_behavior_get(&mclone, MEMCACHED_BEHAVIOR_POLL_TIMEOUT))); libtest::vchar_t value; value.reserve(512); @@ -2515,11 +2516,11 @@ test_return_t user_supplied_bug11(memcached_st *memc) for (unsigned int x= 1; x <= 100000; ++x) { - memcached_return_t rc= memcached_set(mclone, test_literal_param("foo"), &value[0], value.size(), 0, 0); + memcached_return_t rc= memcached_set(&mclone, test_literal_param("foo"), &value[0], value.size(), 0, 0); (void)rc; } - memcached_free(mclone); +#endif return TEST_SUCCESS; } @@ -2621,7 +2622,7 @@ test_return_t user_supplied_bug14(memcached_st *memc) memcached_return_t rc= memcached_set(memc, test_literal_param("foo"), &value[0], current_length, (time_t)0, (uint32_t)0); - test_true(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED); + ASSERT_TRUE_(rc == MEMCACHED_SUCCESS or rc == MEMCACHED_BUFFERED, "Instead got %s", memcached_strerror(NULL, rc)); size_t string_length; uint32_t flags; -- 2.30.2